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
16void 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
21pml3e_t *pml3_entry(pml3_t pml3, ptr_t vaddr)
22{
23 MOS_UNUSED(vaddr);
24 return pml3.pml2.table;
25}
26
27bool pml3e_is_present(const pml3e_t *pml3e)
28{
29 return pml2e_is_present(pml3e);
30}
31
32pml2_t pml3e_get_pml2(const pml3e_t *pml3e)
33{
34 return (pml2_t) { .table = (pml2e_t *) pml3e };
35}
36
37#else
38void 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
69bool 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
98pml3e_t *pml3_entry(pml3_t pml3, ptr_t vaddr)
99{
100 return &pml3.table[pml3_index(vaddr)];
101}
102
103bool pml3e_is_present(const pml3e_t *pml3e)
104{
105 return platform_pml3e_get_present(pml3e);
106}
107
108pml2_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