1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | |
3 | #include "mos/mm/paging/pmlx/pml4.hpp" |
4 | |
5 | #include "mos/mm/mm.hpp" |
6 | #include "mos/mm/paging/pml_types.hpp" |
7 | #include "mos/mm/paging/pmlx/pml3.hpp" |
8 | #include "mos/platform/platform.hpp" |
9 | #include "mos/platform/platform_defs.hpp" |
10 | |
11 | #include <algorithm> |
12 | #include <mos/mos_global.h> |
13 | #include <mos_stdlib.hpp> |
14 | #include <mos_string.hpp> |
15 | |
16 | #if MOS_PLATFORM_PAGING_LEVELS < 4 |
17 | void pml4_traverse(pml4_t pml4, ptr_t *vaddr, size_t *n_pages, pagetable_walk_options_t callback, void *data) |
18 | { |
19 | pml3_traverse(pml4.pml3, vaddr, n_pages, callback, data); |
20 | } |
21 | |
22 | pml4e_t *pml4_entry(pml4_t pml4, ptr_t vaddr) |
23 | { |
24 | MOS_UNUSED(vaddr); |
25 | return pml4.pml3.table; |
26 | } |
27 | |
28 | bool pml4e_is_present(const pml4e_t *pml4e) |
29 | { |
30 | return pml3e_is_present(pml4e); |
31 | } |
32 | |
33 | pml3_t pml4e_get_pml3(const pml4e_t *pml4e) |
34 | { |
35 | return (pml3_t) { .table = (pml3e_t *) pml4e }; |
36 | } |
37 | |
38 | #else |
39 | void pml4_traverse(pml4_t pml4, ptr_t *vaddr, size_t *n_pages, pagetable_walk_options_t options, void *data) |
40 | { |
41 | for (size_t i = pml4_index(*vaddr); i < PML4_ENTRIES && *n_pages; i++) |
42 | { |
43 | pml4e_t *pml4e = pml4_entry(pml4, vaddr: *vaddr); |
44 | pml3_t pml3 = { .table: 0 }; |
45 | |
46 | if (pml4e_is_present(pml4e)) |
47 | { |
48 | pml3 = pml4e_get_or_create_pml3(pml4e); |
49 | } |
50 | else |
51 | { |
52 | if (options.readonly) |
53 | { |
54 | // skip to the next pml3e |
55 | *vaddr += std::min(a: *n_pages, b: (size_t) PML4E_NPAGES) * MOS_PAGE_SIZE; |
56 | *n_pages -= std::min(a: *n_pages, b: (size_t) PML4E_NPAGES); |
57 | continue; |
58 | } |
59 | |
60 | pml3 = pml_create_table(pml3); |
61 | platform_pml4e_set_pml3(pml4: pml4e, pml3, va_pfn(pml3.table)); |
62 | } |
63 | |
64 | if (options.pml4e_pre_traverse) |
65 | options.pml4e_pre_traverse(pml4, pml4e, *vaddr, data); |
66 | pml3_traverse(pml3, vaddr, n_pages, callback: options, data); |
67 | } |
68 | } |
69 | |
70 | bool pml4_destroy_range(pml4_t pml4, ptr_t *vaddr, size_t *n_pages) |
71 | { |
72 | #if MOS_PLATFORM_PAGING_LEVELS <= 4 |
73 | const bool should_zap_this_pml4 = pml4_index(*vaddr) == 0 && *n_pages == (MOS_USER_END_VADDR + 1) / MOS_PAGE_SIZE; |
74 | #else |
75 | const bool should_zap_this_pml4 = pml4_index(*vaddr) == 0 && *n_pages >= PML4_ENTRIES * PML4E_NPAGES; |
76 | #endif |
77 | |
78 | for (size_t i = pml4_index(*vaddr); i < PML4_ENTRIES && *n_pages; i++) |
79 | { |
80 | pml4e_t *pml4e = pml4_entry(pml4, vaddr: *vaddr); |
81 | |
82 | if (pml4e_is_present(pml4e)) |
83 | { |
84 | pml3_t pml3 = platform_pml4e_get_pml3(pml4: pml4e); |
85 | if (pml3_destroy_range(pml3, vaddr, n_pages)) |
86 | pmlxe_destroy(pml4e); // pml3 was destroyed |
87 | } |
88 | else |
89 | { |
90 | // skip to the next pml3e |
91 | *vaddr += std::min(a: *n_pages, b: (size_t) PML4E_NPAGES) * MOS_PAGE_SIZE; |
92 | *n_pages -= std::min(a: *n_pages, b: (size_t) PML4E_NPAGES); |
93 | continue; |
94 | } |
95 | } |
96 | |
97 | if (should_zap_this_pml4) |
98 | pml_destroy_table(pml4); |
99 | |
100 | return should_zap_this_pml4; |
101 | } |
102 | |
103 | pml4e_t *pml4_entry(pml4_t pml4, ptr_t vaddr) |
104 | { |
105 | return &pml4.table[pml4_index(vaddr)]; |
106 | } |
107 | |
108 | bool pml4e_is_present(const pml4e_t *pml4e) |
109 | { |
110 | return platform_pml4e_get_present(pml4: pml4e); |
111 | } |
112 | |
113 | pml3_t pml4e_get_or_create_pml3(pml4e_t *pml4e) |
114 | { |
115 | if (pml4e_is_present(pml4e)) |
116 | return platform_pml4e_get_pml3(pml4: pml4e); |
117 | |
118 | pml3_t pml3 = pml_create_table(pml3); |
119 | platform_pml4e_set_pml3(pml4: pml4e, pml3, va_pfn(pml3.table)); |
120 | return pml3; |
121 | } |
122 | #endif |
123 | |