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