Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions plat/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ max_level_debug = ["log/max_level_debug", "islet_rmm/max_level_debug"]
max_level_trace = ["log/max_level_trace", "islet_rmm/max_level_trace"]
stat = ["islet_rmm/stat"]
gst_page_table = ["islet_rmm/gst_page_table"]
ns_state_save = ["islet_rmm/ns_state_save"]
fvp = ["islet_rmm/fvp"]
qemu = ["islet_rmm/qemu"]

Expand Down
23 changes: 13 additions & 10 deletions plat/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ extern crate log;
mod entry;
mod plat;

use aarch64_cpu::registers::*;
use islet_rmm::allocator;
use islet_rmm::config::PlatformMemoryLayout;
use islet_rmm::cpu;
Expand All @@ -24,15 +23,19 @@ extern "C" {
#[no_mangle]
pub unsafe fn main(x0: u64, x1: u64, x2: u64, x3: u64) -> ! {
let cpuid: usize = x0 as usize;
info!(
"booted on core {:2} with EL{}!",
cpuid,
CurrentEL.read(CurrentEL::EL) as u8
);
info!(
"boot args: x0:0x{:X}, x1:0x{:X}, x2:0x{:X}, x3:0x{:X}",
x0, x1, x2, x3
);
// Do not print here until MMU is turned on, except on cpu0.
// Cores other than cpu0 at this point are still in its mmu
// off state with d-cache disabled and i-cache enabled.
// This may cause incosistencies between cpus with mmu enabled
// and cpus with mmu disabled.
// Logging involves buffer allocation and its internal data struct
// for heap (linked_list) could be corrupted due to the reason above.
if x0 == 0 {
info!(
"boot args: x0:0x{:X}, x1:0x{:X}, x2:0x{:X}, x3:0x{:X}",
x0, x1, x2, x3
);
}

if cpuid != cpu::get_cpu_id() {
panic!(
Expand Down
1 change: 1 addition & 0 deletions rmm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ stat = []
gst_page_table = []
fvp = []
qemu = []
ns_state_save = []

# The below are features relevant for model checking
mc_rmi_features = []
Expand Down
11 changes: 11 additions & 0 deletions rmm/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,14 @@ pub fn dcache_flush(addr: usize, len: usize) {
}
}
}

#[inline(always)]
pub fn isb() {
#[cfg(target_arch = "aarch64")]
unsafe {
core::arch::asm!("isb", options(nomem, nostack))
}

#[cfg(not(target_arch = "aarch64"))]
unimplemented!()
}
5 changes: 5 additions & 0 deletions rmm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ use core::ptr::addr_of;
pub unsafe fn start(cpu_id: usize, layout: PlatformMemoryLayout) {
let el3_shared_buf = layout.el3_shared_buf;
setup_mmu_cfg(layout);
info!(
"booted on core {:2} with EL{}!",
cpu_id,
CurrentEL.read(CurrentEL::EL) as u8
);
setup_el2();
#[cfg(feature = "gst_page_table")]
setup_gst();
Expand Down
17 changes: 17 additions & 0 deletions rmm/src/rec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ pub fn run_prepare(rd: &Rd, vcpu: usize, rec: &mut Rec<'_>, incr_pc: usize) -> R
if incr_pc == 1 {
rec.context.elr_el2 += 4;
}
timer::update_timer_assertion(rec);
debug!("resuming: {:#x}", rec.context.elr_el2);
rec.into_current();

Expand All @@ -391,3 +392,19 @@ pub fn run() -> Result<[usize; 4], Error> {
pub fn max_recs_order() -> usize {
MAX_RECS_ORDER_VALUE as usize
}

// Note: Islet intends to manage states only for the realm world.
// Handling the ns state here does not align Islet's desgin.
// Save the host state only if necessary.
pub fn save_host_state(rec: &Rec<'_>) {
pmu::save_host_state(rec);
// TODO: Apply 'ns_state_save' feature to the save_host_state func.
// For that, we need to move the code here from the corresponding patches
// in the nw-linux.
timer::save_host_state(rec);
}

pub fn restore_host_state(rec: &Rec<'_>) {
pmu::restore_host_state(rec);
timer::restore_host_state(rec);
}
87 changes: 87 additions & 0 deletions rmm/src/rec/timer.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,48 @@
use super::Rec;
use crate::asm::isb;
use crate::rmi::error::Error;
use crate::rmi::rec::run::Run;

use aarch64_cpu::registers::*;

#[cfg(feature = "ns_state_save")]
mod ns_timer {
use super::*;
use crate::config::NUM_OF_CPU;
use crate::cpu::get_cpu_id;
use crate::rec::context::TimerRegister;
use core::array::from_fn;
use lazy_static::lazy_static;
use spin::mutex::Mutex;

lazy_static! {
static ref NS_TIMER: [Mutex<TimerRegister>; NUM_OF_CPU] =
from_fn(|_| Mutex::new(TimerRegister::default()));
}

pub(super) fn restore() {
let ns_timer = NS_TIMER[get_cpu_id()].lock();
CNTVOFF_EL2.set(ns_timer.cntvoff_el2);
CNTPOFF_EL2.set(ns_timer.cntpoff_el2);
CNTV_CVAL_EL0.set(ns_timer.cntv_cval_el0);
CNTV_CTL_EL0.set(ns_timer.cntv_ctl_el0);
CNTP_CVAL_EL0.set(ns_timer.cntp_cval_el0);
CNTP_CTL_EL0.set(ns_timer.cntp_ctl_el0);
CNTHCTL_EL2.set(ns_timer.cnthctl_el2);
}

pub(super) fn save() {
let mut timer = NS_TIMER[get_cpu_id()].lock();
timer.cntvoff_el2 = CNTVOFF_EL2.get();
timer.cntv_cval_el0 = CNTV_CVAL_EL0.get();
timer.cntv_ctl_el0 = CNTV_CTL_EL0.get();
timer.cntpoff_el2 = CNTPOFF_EL2.get();
timer.cntp_cval_el0 = CNTP_CVAL_EL0.get();
timer.cntp_ctl_el0 = CNTP_CTL_EL0.get();
timer.cnthctl_el2 = CNTHCTL_EL2.get();
}
}

pub fn init_timer(rec: &mut Rec<'_>) {
let timer = &mut rec.context.timer;
timer.cnthctl_el2 = (CNTHCTL_EL2::EL1PCEN::SET + CNTHCTL_EL2::EL1PCTEN::SET).into();
Expand Down Expand Up @@ -49,3 +88,51 @@ pub fn send_state_to_host(rec: &Rec<'_>, run: &mut Run) -> Result<(), Error> {
run.set_cntp_cval(timer.cntp_cval_el0 - timer.cntpoff_el2);
Ok(())
}

pub fn save_host_state(_rec: &Rec<'_>) {
#[cfg(feature = "ns_state_save")]
ns_timer::save();
}

pub fn restore_host_state(_rec: &Rec<'_>) {
#[cfg(feature = "ns_state_save")]
ns_timer::restore();
}

// RMM spec A6.2 Realm timers, I<VRWGS>
// On REC entry, for both the EL1 Virtual Timer and the EL1 Physical Timer,
// if the EL1 timer asserts its output in the state described in the REC exit
// structure from the previous REC exit then the RMM masks the hardware timer
// signal before returning to the Realm.
pub fn update_timer_assertion(rec: &mut Rec<'_>) {
const CNTHCTL_EL2_CNTVMASK: u64 = 0x1 << 18;
const CNTHCTL_EL2_CNTPMASK: u64 = 0x1 << 19;
let timer = &mut rec.context.timer;

// Get recently saved timer control registers
let cnthctl_old = timer.cnthctl_el2;

// Check if virtual timer is asserted
if CNTV_CTL_EL0.matches_all(
CNTV_CTL_EL0::ISTATUS::SET + CNTV_CTL_EL0::IMASK::CLEAR + CNTV_CTL_EL0::ENABLE::SET,
) {
timer.cnthctl_el2 |= CNTHCTL_EL2_CNTVMASK;
} else {
timer.cnthctl_el2 &= !CNTHCTL_EL2_CNTVMASK; // Clear MASK
}

// Check if physical timer is asserted
if CNTP_CTL_EL0.matches_all(
CNTP_CTL_EL0::ISTATUS::SET + CNTP_CTL_EL0::IMASK::CLEAR + CNTP_CTL_EL0::ENABLE::SET,
) {
timer.cnthctl_el2 |= CNTHCTL_EL2_CNTPMASK;
} else {
timer.cnthctl_el2 &= !CNTHCTL_EL2_CNTPMASK; // Clear MASK
}

// If cnthctl changed, write it back and ensure synchronization
if cnthctl_old != timer.cnthctl_el2 {
CNTHCTL_EL2.set(timer.cnthctl_el2);
isb();
}
}
19 changes: 14 additions & 5 deletions rmm/src/rmi/rec/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,15 +233,24 @@ pub fn set_event_handler(rmi: &mut RmiHandle) {
crate::rsi::ripas::complete_ripas(&mut rec, &run)?;

let wfx_flag = run.entry_flags();
if wfx_flag.get_masked(EntryFlag::TRAP_WFI | EntryFlag::TRAP_WFE) != 0 {
warn!("Islet does not support re-configuring the WFI(E) trap");
warn!("TWI(E) in HCR_EL2 is currently fixed to 'no trap'");
#[cfg(not(any(miri, test, fuzzing)))]
{
let hcr_el2 = HCR_EL2.get();
let mut wfx = 0;
let wfx_mask = !(3 << 13);
if wfx_flag.get_masked(EntryFlag::TRAP_WFI) != 0 {
wfx |= 1 << 13;
}
if wfx_flag.get_masked(EntryFlag::TRAP_WFE) != 0 {
wfx |= 1 << 14;
}
HCR_EL2.set((hcr_el2 & wfx_mask) | wfx);
}

#[cfg(not(any(miri, test, fuzzing)))]
activate_stage2_mmu(&rec);

crate::rec::pmu::save_host_state(&rec);
crate::rec::save_host_state(&rec);
let mut ret_ns;
loop {
ret_ns = true;
Expand Down Expand Up @@ -305,7 +314,7 @@ pub fn set_event_handler(rmi: &mut RmiHandle) {
crate::rec::gic::send_state_to_host(&rec, &mut run)?;
crate::rec::timer::send_state_to_host(&rec, &mut run)?;
crate::rec::pmu::send_state_to_host(&rec, &mut run)?;
crate::rec::pmu::restore_host_state(&rec);
crate::rec::restore_host_state(&rec);

// NOTICE: do not modify `run` after copy_to_ptr(). it won't have any effect.
rmm.page_table.map(run_pa, false);
Expand Down
1 change: 1 addition & 0 deletions scripts/cca_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ def get_rmm_features(self):
features += ["--features", "stat"]
if args.normal_world == "acs":
features += ["--features", "gst_page_table"]
features += ["--features", "ns_state_save"]

features += ["--features", self.platform_name]

Expand Down
2 changes: 1 addition & 1 deletion scripts/tests/acs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
set -e

# Control these variables
EXPECTED=95
EXPECTED=97
TIMEOUT=30

ROOT=$(git rev-parse --show-toplevel)
Expand Down
2 changes: 0 additions & 2 deletions skipped-tests.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
cmd_multithread_realm_mp
exception_rec_exit_wfi
exception_rec_exit_wfe
attestation_rec_exit_irq
gic_timer_rel1_trig
mm_gpf_exception
cmd_secure_test
Loading