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