Skip to main content

islet_rmm/mm/
translation.rs

1use 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    // We will set the translation granule with 4KB.
57    // To reduce the level of page lookup, initial lookup will start from L1.
58    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        // UART
115        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        //TODO Set dirty only if pages are updated, not added
129        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}