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
16void 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
21pml4e_t *pml4_entry(pml4_t pml4, ptr_t vaddr)
22{
23 MOS_UNUSED(vaddr);
24 return pml4.pml3.table;
25}
26
27bool pml4e_is_present(const pml4e_t *pml4e)
28{
29 return pml3e_is_present(pml4e);
30}
31
32pml3_t pml4e_get_pml3(const pml4e_t *pml4e)
33{
34 return (pml3_t){ .table = (pml3e_t *) pml4e };
35}
36
37#else
38void 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
69bool 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
102pml4e_t *pml4_entry(pml4_t pml4, ptr_t vaddr)
103{
104 return &pml4.table[pml4_index(vaddr)];
105}
106
107bool pml4e_is_present(const pml4e_t *pml4e)
108{
109 return platform_pml4e_get_present(pml4: pml4e);
110}
111
112pml3_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