Skip to main content

islet_rmm/
lib.rs

1#![no_std]
2#![allow(incomplete_features)]
3#![feature(alloc_error_handler)]
4#![feature(specialization)]
5#![warn(rust_2018_idioms)]
6
7#[cfg(not(any(test, fuzzing)))]
8pub mod allocator;
9pub mod asm;
10pub mod config;
11pub(crate) mod cose;
12pub mod cpu;
13pub(crate) mod event;
14pub mod exception;
15pub mod gic;
16#[macro_use]
17pub mod granule;
18#[macro_use]
19pub(crate) mod host;
20pub mod logger;
21pub mod mm;
22#[cfg(not(any(test, kani, miri, fuzzing)))]
23pub mod panic;
24pub mod pmu;
25pub mod realm;
26pub mod rec;
27pub mod rmi;
28pub mod rsi;
29pub mod simd;
30#[cfg(feature = "stat")]
31pub mod stat;
32#[cfg(any(test, miri))]
33pub(crate) mod test_utils;
34#[cfg(fuzzing)]
35pub mod test_utils;
36#[macro_use]
37pub mod r#macro;
38mod measurement;
39#[cfg(kani)]
40// we declare monitor as `pub` in model checking, so that
41// its member can be accessed freely outside the rmm crate
42pub mod monitor;
43#[cfg(not(kani))]
44mod monitor;
45mod rmm_el3;
46
47extern crate alloc;
48
49#[macro_use]
50extern crate lazy_static;
51
52#[macro_use]
53extern crate log;
54
55use crate::config::PlatformMemoryLayout;
56use crate::exception::vectors;
57#[cfg(feature = "gst_page_table")]
58use crate::granule::create_granule_status_table as setup_gst;
59use crate::mm::translation::{get_page_table, init_page_table};
60use crate::monitor::Monitor;
61use crate::rmm_el3::setup_el3_ifc;
62
63use aarch64_cpu::registers::*;
64use armv9a::{MDCR_EL2, PMCR_EL0};
65use core::ptr::addr_of;
66
67#[cfg(not(kani))]
68// model checking harnesses do not use this function, instead
69// they use their own entry points marked with #[kani::proof]
70// where slightly adjusted `Monitor` is used
71/// Starts the RMM on the specified CPU with the given memory layout.
72///
73/// # Safety
74///
75/// The caller must ensure that:
76/// - The caller must ensure that `cpu_id` corresponds to a valid and initialized CPU.
77/// - The `layout` must be a valid `PlatformMemoryLayout` appropriate for the platform.
78/// - Calling this function may alter system-level configurations and should be done with caution.
79pub unsafe fn start(cpu_id: usize, layout: PlatformMemoryLayout) {
80    let el3_shared_buf = layout.el3_shared_buf;
81    setup_mmu_cfg(layout);
82    info!(
83        "booted on core {:2} with EL{}!",
84        cpu_id,
85        CurrentEL.read(CurrentEL::EL) as u8
86    );
87    setup_el2();
88    #[cfg(feature = "gst_page_table")]
89    setup_gst();
90    // TODO: call once or with every start?
91    if cpu_id == 0 {
92        setup_el3_ifc(el3_shared_buf);
93    }
94
95    Monitor::new().run();
96}
97
98/// # Safety
99///
100/// This function performs several operations that involve writing to system control registers
101/// at the EL2.
102///
103/// The caller must ensure that:
104/// - The function is called at EL2 with the required privileges.
105/// - The `vectors` variable points to a valid exception vector table in memory.
106/// - The system is in a state where modifying these control registers is safe and will not
107///   interfere with other critical operations.
108///
109/// Failing to meet these requirements can result in system crashes, security vulnerabilities,
110/// or other undefined behavior.
111unsafe fn setup_el2() {
112    HCR_EL2.write(
113        HCR_EL2::FWB::SET
114            + HCR_EL2::TEA::SET
115            + HCR_EL2::TERR::SET
116            + HCR_EL2::TLOR::SET
117            + HCR_EL2::RW::SET
118            + HCR_EL2::TSW::SET
119            + HCR_EL2::TACR::SET
120            + HCR_EL2::TIDCP::SET
121            + HCR_EL2::TSC::SET
122            + HCR_EL2::TID3::SET
123            + HCR_EL2::BSU::InnerShareable
124            + HCR_EL2::FB::SET
125            + HCR_EL2::AMO::SET
126            + HCR_EL2::IMO::SET
127            + HCR_EL2::FMO::SET
128            + HCR_EL2::VM::SET
129            + HCR_EL2::API::SET
130            + HCR_EL2::APK::SET,
131        // HCR_EL2::TWI::SET,
132    );
133    VBAR_EL2.set(addr_of!(vectors) as u64);
134    SCTLR_EL2
135        .write(SCTLR_EL2::C::SET + SCTLR_EL2::I::SET + SCTLR_EL2::M::SET + SCTLR_EL2::EOS::SET);
136    CPTR_EL2.write(CPTR_EL2::TAM::SET);
137    ICC_SRE_EL2.write(
138        ICC_SRE_EL2::ENABLE::SET
139            + ICC_SRE_EL2::DIB::SET
140            + ICC_SRE_EL2::DFB::SET
141            + ICC_SRE_EL2::SRE::SET,
142    );
143    MDCR_EL2.write(
144        MDCR_EL2::MTPME::SET
145            + MDCR_EL2::HCCD::SET
146            + MDCR_EL2::HPMD::SET
147            + MDCR_EL2::TDA::SET
148            + MDCR_EL2::TPM::SET
149            + MDCR_EL2::TPMCR::SET
150            + MDCR_EL2::HPMN.val(PMCR_EL0.read(PMCR_EL0::N)),
151    );
152}
153
154/// # Safety
155///
156/// This function configures the Memory Management Unit (MMU) at the EL2.
157///
158/// The caller must ensure:
159/// - The function is called at EL2 with the appropriate privileges.
160/// - The translation table base address (`ttbl_base`) is valid and correctly initialized.
161/// - Modifying these registers and executing these assembly instructions will not interfere
162///   with other critical operations.
163///
164/// Failing to meet these requirements can result in system crashes, memory corruption, security
165/// vulnerabilities, or other undefined behavior.
166unsafe fn setup_mmu_cfg(layout: PlatformMemoryLayout) {
167    core::arch::asm!("tlbi alle2is", "dsb ish", "isb",);
168
169    // /* Set attributes in the right indices of the MAIR. */
170    let mair_el2 = MAIR_EL2::Attr0_Normal_Outer::WriteBack_NonTransient_ReadWriteAlloc
171        + MAIR_EL2::Attr0_Normal_Inner::WriteBack_NonTransient_ReadWriteAlloc
172        + MAIR_EL2::Attr1_Device::nonGathering_nonReordering_noEarlyWriteAck
173        + MAIR_EL2::Attr2_Device::nonGathering_nonReordering_EarlyWriteAck;
174
175    /*
176     * The size of the virtual address space is configured as 64 – T0SZ.
177     * In this, 64 – 0x19 gives 39 bits of virtual address space.
178     * This equates to 512GB (2^39), which means that the entire virtual address
179     * space is covered by a single L1 table.
180     * Therefore, our starting level of translation is level 1.
181     */
182    let tcr_el2 = TCR_EL2::T0SZ.val(0x19)
183        + TCR_EL2::PS::Bits_40
184        + TCR_EL2::TG0::KiB_4
185        + TCR_EL2::SH0::Inner
186        + TCR_EL2::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable
187        + TCR_EL2::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable;
188
189    // set the ttbl base address, this is where the memory address translation
190    // table walk starts
191    init_page_table(layout);
192    let ttbl_base = get_page_table();
193
194    // Invalidate the local I-cache so that any instructions fetched
195    // speculatively are discarded.
196    MAIR_EL2.write(mair_el2);
197    TCR_EL2.write(tcr_el2);
198    TTBR0_EL2.set(ttbl_base);
199    core::arch::asm!("dsb ish", "isb",);
200}
201
202/// Call `rmm_exit` within `exception/vectors.s` and jumps to EL1.
203///
204/// Currently, this function gets [0usize; 3] as an argument to initialize
205/// x0, x1 and x2 registers.
206///
207/// When an exception occurs and the flow comes back to EL2 through `rmm_enter`,
208/// x0, x1 and x2 registers might be changed to contain additional information
209/// set from `handle_lower_exception`.
210/// These are the return values of this function.
211/// The return value encodes: [rmi::RET_XXX, ret_val1, ret_val2]
212/// In most cases, the function returns [rmi::RET_SUCCESS, _, _]
213/// pagefault returns [rmi::RET_PAGE_FAULT, faulted address, _]
214///
215/// # Safety
216///
217/// - This function alters the processor's execution level by jumping to EL1;
218///   the caller must ensure that the system is in a correct state for this transition.
219#[cfg(not(kani))]
220pub unsafe fn rmm_exit(args: [usize; 4]) -> [usize; 4] {
221    let mut ret: [usize; 4] = [0usize; 4];
222
223    core::arch::asm!(
224        "bl rmm_exit",
225        inlateout("x0") args[0] => ret[0],
226        inlateout("x1") args[1] => ret[1],
227        inlateout("x2") args[2] => ret[2],
228        inlateout("x3") args[3] => ret[3],
229    );
230
231    ret
232}
233
234#[cfg(kani)]
235pub unsafe fn rmm_exit(_args: [usize; 4]) -> [usize; 4] {
236    let ret: [usize; 4] = [0usize; 4];
237    ret
238}