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