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