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