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