1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | |
3 | #include "mos/mm/paging/pmlx/pml2.h" |
4 | |
5 | #include "mos/mm/mm.h" |
6 | #include "mos/mm/paging/pmlx/pml1.h" |
7 | #include "mos/platform/platform.h" |
8 | #include "mos/platform/platform_defs.h" |
9 | |
10 | #include <mos_stdlib.h> |
11 | #include <mos_string.h> |
12 | |
13 | void pml2_traverse(pml2_t pml2, ptr_t *vaddr, size_t *n_pages, pagetable_walk_options_t options, void *data) |
14 | { |
15 | for (size_t i = pml2_index(*vaddr); i < PML2_ENTRIES && *n_pages; i++) |
16 | { |
17 | pml2e_t *pml2e = pml2_entry(pml2, vaddr: *vaddr); |
18 | pml1_t pml1 = { 0 }; |
19 | |
20 | if (pml2e_is_present(pml2e)) |
21 | { |
22 | pml1 = pml2e_get_or_create_pml1(pml2e); |
23 | } |
24 | else |
25 | { |
26 | if (options.readonly) |
27 | { |
28 | // skip to the next pml2e, but don't go past the end of the range |
29 | *vaddr += MIN(*n_pages, PML2E_NPAGES) * MOS_PAGE_SIZE; |
30 | *n_pages -= MIN(*n_pages, PML2E_NPAGES); |
31 | continue; |
32 | } |
33 | |
34 | pml1 = pml_create_table(pml1); |
35 | platform_pml2e_set_pml1(pml2: pml2e, pml1, va_pfn(pml1.table)); |
36 | } |
37 | |
38 | if (options.pml2e_pre_traverse) |
39 | options.pml2e_pre_traverse(pml2, pml2e, *vaddr, data); |
40 | pml1_traverse(pml1, vaddr, n_pages, callback: options, data); |
41 | } |
42 | } |
43 | |
44 | bool pml2_destroy_range(pml2_t pml2, ptr_t *vaddr, size_t *n_pages) |
45 | { |
46 | const bool should_zap_this_pml2 = pml2_index(*vaddr) == 0 && *n_pages >= PML2_ENTRIES * PML2E_NPAGES; |
47 | |
48 | for (size_t i = pml2_index(*vaddr); i < PML2_ENTRIES && *n_pages; i++) |
49 | { |
50 | pml2e_t *pml2e = pml2_entry(pml2, vaddr: *vaddr); |
51 | |
52 | if (pml2e_is_present(pml2e)) |
53 | { |
54 | pml1_t pml1 = platform_pml2e_get_pml1(pml2: pml2e); |
55 | if (pml1_destroy_range(pml1, vaddr, n_pages)) |
56 | pmlxe_destroy(pml2e); // pml1 was destroyed |
57 | } |
58 | else |
59 | { |
60 | // skip to the next pml2e |
61 | *vaddr += MIN(*n_pages, PML2E_NPAGES) * MOS_PAGE_SIZE; |
62 | *n_pages -= MIN(*n_pages, PML2E_NPAGES); |
63 | continue; |
64 | } |
65 | } |
66 | |
67 | if (should_zap_this_pml2) |
68 | pml_destroy_table(pml2); |
69 | |
70 | return should_zap_this_pml2; |
71 | } |
72 | |
73 | pml2e_t *pml2_entry(pml2_t pml2, ptr_t vaddr) |
74 | { |
75 | return &pml2.table[pml2_index(vaddr)]; |
76 | } |
77 | |
78 | bool pml2e_is_present(const pml2e_t *pml2e) |
79 | { |
80 | return platform_pml2e_get_present(pml2: pml2e); |
81 | } |
82 | |
83 | pml1_t pml2e_get_or_create_pml1(pml2e_t *pml2e) |
84 | { |
85 | if (pml2e_is_present(pml2e)) |
86 | return platform_pml2e_get_pml1(pml2: pml2e); |
87 | |
88 | pml1_t pml1 = pml_create_table(pml1); |
89 | platform_pml2e_set_pml1(pml2: pml2e, pml1, va_pfn(pml1.table)); |
90 | return pml1; |
91 | } |
92 | |