islet_rmm/mm/
translation.rs1use super::page_table::entry::Entry;
2use super::page_table::{attr, L1Table};
3use crate::config::{PlatformMemoryLayout, PAGE_SIZE, RMM_STACK_GUARD_SIZE, RMM_STACK_SIZE};
4use crate::mm::page::BasePageSize;
5use crate::mm::page_table::entry::PTDesc;
6
7use vmsa::address::{PhysAddr, VirtAddr};
8use vmsa::page::Page;
9use vmsa::page_table::PageTable as RootPageTable;
10use vmsa::page_table::{DefaultMemAlloc, Level, PageTableMethods};
11
12use armv9a::bits_in_reg;
13use core::ffi::c_void;
14use core::fmt;
15use lazy_static::lazy_static;
16use spin::mutex::Mutex;
17
18pub struct PageTable {
19 page_table: &'static Mutex<Inner<'static>>,
20}
21
22impl PageTable {
23 pub fn get_ref() -> Self {
24 Self {
25 page_table: &RMM_PAGE_TABLE,
26 }
27 }
28
29 pub fn map(&self, addr: usize, secure: bool) -> bool {
30 self.page_table.lock().set_pages_for_rmi(addr, secure)
31 }
32
33 pub fn unmap(&self, addr: usize) -> bool {
34 self.page_table.lock().unset_pages_for_rmi(addr)
35 }
36}
37
38lazy_static! {
39 static ref RMM_PAGE_TABLE: Mutex<Inner<'static>> = Mutex::new(Inner::new());
40}
41
42pub fn init_page_table(layout: PlatformMemoryLayout) {
43 let mut page_table = RMM_PAGE_TABLE.lock();
44 page_table.fill(layout);
45}
46
47pub fn get_page_table() -> u64 {
48 RMM_PAGE_TABLE.lock().get_base_address() as u64
49}
50
51pub fn drop_page_table() {
52 RMM_PAGE_TABLE.lock().root_pgtbl.drop();
53}
54
55struct Inner<'a> {
56 root_pgtbl:
59 &'a mut RootPageTable<VirtAddr, L1Table, Entry, { <L1Table as Level>::NUM_ENTRIES }>,
60 dirty: bool,
61}
62
63impl Inner<'_> {
64 pub fn new() -> Self {
65 let root_pgtbl =
66 RootPageTable::<VirtAddr, L1Table, Entry, { <L1Table as Level>::NUM_ENTRIES }>::new_in(
67 &DefaultMemAlloc {},
68 )
69 .unwrap();
70
71 Self {
72 root_pgtbl,
73 dirty: false,
74 }
75 }
76
77 fn fill(&mut self, layout: PlatformMemoryLayout) {
78 if self.dirty {
79 return;
80 }
81
82 let ro_flags = bits_in_reg(PTDesc::AP, attr::permission::RO);
83 let rw_flags = bits_in_reg(PTDesc::AP, attr::permission::RW);
84 let rmm_flags = bits_in_reg(PTDesc::INDX, attr::mair_idx::RMM_MEM);
85 let device_flags = bits_in_reg(PTDesc::INDX, attr::mair_idx::DEVICE_MEM);
86 let base_address = layout.rmm_base;
87 let rw_start = layout.rw_start;
88 let ro_size = rw_start - base_address;
89 let rw_size = layout.rw_end - rw_start;
90 let uart_phys = layout.uart_phys;
91 let el3_shared_page = layout.el3_shared_buf;
92 self.set_pages(
93 VirtAddr::from(base_address),
94 PhysAddr::from(base_address),
95 ro_size as usize,
96 ro_flags | rmm_flags,
97 );
98 self.set_pages(
99 VirtAddr::from(rw_start),
100 PhysAddr::from(rw_start),
101 rw_size as usize,
102 rw_flags | rmm_flags,
103 );
104 let per_cpu = RMM_STACK_GUARD_SIZE + RMM_STACK_SIZE;
105 for i in 0..crate::config::NUM_OF_CPU {
106 let stack_base = layout.stack_base + (per_cpu * i) as u64;
107 self.set_pages(
108 VirtAddr::from(stack_base),
109 PhysAddr::from(stack_base),
110 RMM_STACK_SIZE,
111 rw_flags | rmm_flags,
112 );
113 }
114 self.set_pages(
116 VirtAddr::from(uart_phys),
117 PhysAddr::from(uart_phys),
118 PAGE_SIZE,
119 rw_flags | device_flags,
120 );
121 self.set_pages(
122 VirtAddr::from(el3_shared_page),
123 PhysAddr::from(el3_shared_page),
124 PAGE_SIZE,
125 rw_flags | rmm_flags,
126 );
127
128 self.dirty = true;
130 }
131
132 fn get_base_address(&self) -> *const c_void {
133 self.root_pgtbl as *const _ as *const c_void
134 }
135
136 fn set_pages(&mut self, va: VirtAddr, phys: PhysAddr, size: usize, flags: u64) {
137 let virtaddr = Page::<BasePageSize, VirtAddr>::range_with_size(va, size);
138 let phyaddr = Page::<BasePageSize, PhysAddr>::range_with_size(phys, size);
139
140 if self.root_pgtbl.set_pages(virtaddr, phyaddr, flags).is_err() {
141 warn!("set_pages error");
142 }
143 }
144
145 fn unset_page(&mut self, addr: usize) {
146 let va = VirtAddr::from(addr);
147 let page = Page::<BasePageSize, VirtAddr>::including_address(va);
148 self.root_pgtbl.unset_page(page);
149 }
150
151 fn set_pages_for_rmi(&mut self, addr: usize, secure: bool) -> bool {
152 if addr == 0 {
153 warn!("map address is empty");
154 return false;
155 }
156
157 let rw_flags = bits_in_reg(PTDesc::AP, attr::permission::RW);
158 let memattr_flags = bits_in_reg(PTDesc::INDX, attr::mair_idx::RMM_MEM);
159 let sh_flags = bits_in_reg(PTDesc::SH, attr::shareable::INNER);
160 let secure_flags = bits_in_reg(PTDesc::NS, !secure as u64);
161 let xn_flags = bits_in_reg(PTDesc::UXN, 1) | bits_in_reg(PTDesc::PXN, 1);
162 let valid_flags = bits_in_reg(PTDesc::VALID, 1);
163
164 let va = VirtAddr::from(addr);
165 let phys = PhysAddr::from(addr);
166
167 self.set_pages(
168 va,
169 phys,
170 PAGE_SIZE,
171 rw_flags | memattr_flags | secure_flags | sh_flags | xn_flags | valid_flags,
172 );
173
174 true
175 }
176
177 fn unset_pages_for_rmi(&mut self, addr: usize) -> bool {
178 if addr == 0 {
179 warn!("map address is empty");
180 return false;
181 }
182
183 self.unset_page(addr);
184 true
185 }
186}
187
188impl fmt::Debug for Inner<'_> {
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 f.debug_struct(stringify!(Self)).finish()
191 }
192}
193
194impl Drop for Inner<'_> {
195 fn drop(&mut self) {
196 info!("drop PageTable");
197 self.root_pgtbl.drop();
198 }
199}