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
13void 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
44bool 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
73pml2e_t *pml2_entry(pml2_t pml2, ptr_t vaddr)
74{
75 return &pml2.table[pml2_index(vaddr)];
76}
77
78bool pml2e_is_present(const pml2e_t *pml2e)
79{
80 return platform_pml2e_get_present(pml2: pml2e);
81}
82
83pml1_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