Skip to content

Commit 7a253de

Browse files
authored
Improve interaction with OpenSBI (#96)
Signed-off-by: Wojciech Ozga <[email protected]>
1 parent 11c47f6 commit 7a253de

File tree

5 files changed

+69
-39
lines changed

5 files changed

+69
-39
lines changed

security-monitor/src/confidential_flow/finite_state_machine.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ use crate::core::architecture::riscv::sbi::IpiExtension::*;
2525
use crate::core::architecture::riscv::sbi::RfenceExtension::*;
2626
use crate::core::architecture::riscv::sbi::SbiExtension::*;
2727
use crate::core::architecture::riscv::sbi::SrstExtension::*;
28+
use crate::core::architecture::specification::CSR_MSTATUS_MPV;
2829
use crate::core::architecture::TrapCause::*;
29-
use crate::core::architecture::{HartLifecycleState, TrapCause};
30+
use crate::core::architecture::{is_bit_enabled, HartLifecycleState, TrapCause, CSR};
3031
use crate::core::control_data::{
3132
ConfidentialHart, ConfidentialHartRemoteCommand, ConfidentialVm, ConfidentialVmId, ControlDataStorage, HardwareHart, HypervisorHart,
3233
ResumableOperation,
@@ -55,7 +56,6 @@ pub struct ConfidentialFlow<'a> {
5556
}
5657

5758
impl<'a> ConfidentialFlow<'a> {
58-
const CTX_SWITCH_ERROR_MSG: &'static str = "Bug: Invalid argument provided by the assembly context switch";
5959
const DUMMY_HART_ERROR_MSG: &'static str = "Bug: Found dummy hart instead of a confidential hart";
6060

6161
/// Routes the control flow to a handler that will process the confidential hart interrupt or exception. This is an entry point to
@@ -66,8 +66,18 @@ impl<'a> ConfidentialFlow<'a> {
6666
/// ConfidentialFlow but accessible to the assembly code performing the context switch.
6767
#[no_mangle]
6868
unsafe extern "C" fn route_trap_from_confidential_hart(hardware_hart_pointer: *mut HardwareHart) -> ! {
69-
let flow = Self { hardware_hart: unsafe { hardware_hart_pointer.as_mut().expect(Self::CTX_SWITCH_ERROR_MSG) } };
69+
let flow = Self { hardware_hart: unsafe { &mut *hardware_hart_pointer } };
7070
assert!(!flow.hardware_hart.confidential_hart().is_dummy());
71+
72+
if !is_bit_enabled(CSR.mstatus.read(), CSR_MSTATUS_MPV) {
73+
debug!(
74+
"TSM exception {} when executing confidential hart {}",
75+
flow.confidential_hart().confidential_hart_state().csrs().mcause.read(),
76+
flow.confidential_hart().confidential_hart_id(),
77+
);
78+
ShutdownRequest::from_confidential_hart(flow.confidential_hart()).handle(flow)
79+
}
80+
7181
match TrapCause::from_hart_architectural_state(flow.confidential_hart().confidential_hart_state()) {
7282
Interrupt => HandleInterrupt::from_confidential_hart(flow.confidential_hart()).handle(flow),
7383
VsEcall(Base(GetSpecVersion)) => SbiGetSpecVersion::from_confidential_hart(flow.confidential_hart()).handle(flow),
@@ -101,13 +111,7 @@ impl<'a> ConfidentialFlow<'a> {
101111
VirtualInstruction => VirtualInstruction::from_confidential_hart(flow.confidential_hart()).handle(flow),
102112
GuestStorePageFault => MmioStoreRequest::from_confidential_hart(flow.confidential_hart()).handle(flow),
103113
trap_reason => {
104-
debug!(
105-
"Bug when executing confidential hart {}. Not supported trap cause {:?}. mepc={:x} mtval={:x}",
106-
flow.confidential_hart().confidential_hart_id(),
107-
trap_reason,
108-
flow.confidential_hart().csrs().mepc.read_from_main_memory(),
109-
flow.confidential_hart().csrs().mtval.read()
110-
);
114+
debug!("Not supported trap cause {:?}", trap_reason);
111115
ShutdownRequest::from_confidential_hart(flow.confidential_hart()).handle(flow)
112116
}
113117
}

security-monitor/src/core/architecture/riscv/control_status_registers.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,8 @@ pub struct ControlStatusRegister {
289289
pub mvendorid: ReadWriteRiscvCsr<CSR_MVENDORID>,
290290
pub marchid: ReadWriteRiscvCsr<CSR_MARCHID>,
291291
pub mimpid: ReadWriteRiscvCsr<CSR_MIMPID>,
292+
pub mcause: ReadWriteRiscvCsr<CSR_MCAUSE>,
293+
pub mstatus: ReadWriteRiscvCsr<CSR_MSTATUS>,
292294
pub mscratch: ReadWriteRiscvCsr<CSR_MSCRATCH>,
293295
pub hgatp: ReadWriteRiscvCsr<CSR_HGATP>,
294296
pub pmpcfg0: ReadWriteRiscvCsr<CSR_PMPCFG0>,
@@ -302,6 +304,8 @@ pub const CSR: &ControlStatusRegister = &ControlStatusRegister {
302304
mvendorid: ReadWriteRiscvCsr::new(),
303305
marchid: ReadWriteRiscvCsr::new(),
304306
mimpid: ReadWriteRiscvCsr::new(),
307+
mcause: ReadWriteRiscvCsr::new(),
308+
mstatus: ReadWriteRiscvCsr::new(),
305309
mscratch: ReadWriteRiscvCsr::new(),
306310
hgatp: ReadWriteRiscvCsr::new(),
307311
pmpcfg0: ReadWriteRiscvCsr::new(),
@@ -412,4 +416,15 @@ impl<const V: u16> ReadWriteRiscvCsr<V> {
412416
}
413417
r
414418
}
419+
420+
pub fn swap(&self, value: usize) -> usize {
421+
let r: usize;
422+
unsafe {
423+
asm!("csrrw {rd}, {csr}, {rs1}",
424+
rd = out(reg) r,
425+
csr = const V,
426+
rs1 = in(reg) value);
427+
}
428+
r
429+
}
415430
}

security-monitor/src/core/control_data/hardware_hart.rs

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ use crate::core::architecture::CSR;
55
use crate::core::control_data::{ConfidentialHart, HypervisorHart};
66
use crate::core::memory_protector::HypervisorMemoryProtector;
77
use crate::core::page_allocator::{Allocated, Page, UnAllocated};
8+
use opensbi_sys::sbi_trap_regs;
9+
10+
extern "C" {
11+
/// Currently, we rely on OpenSBI to handle some of the interrupts or exceptions. Below function is the entry point
12+
/// to OpenSBI trap handler.
13+
fn sbi_trap_handler(regs: *mut sbi_trap_regs) -> *mut sbi_trap_regs;
14+
}
815

916
pub const HART_STACK_ADDRESS_OFFSET: usize = memoffset::offset_of!(HardwareHart, stack_address);
1017

@@ -46,24 +53,33 @@ impl HardwareHart {
4653
}
4754
}
4855

49-
/// Calling OpenSBI handler to process the SBI call requires setting the mscratch register to a specific value which
50-
/// we replaced during the system initialization. We store the original mscratch value expected by the OpenSBI in
51-
/// the previous_mscratch field.
52-
pub fn swap_mscratch(&mut self) {
53-
let previous_mscratch = self.previous_mscratch;
54-
let current_mscratch = CSR.mscratch.read();
55-
CSR.mscratch.write(previous_mscratch);
56-
self.previous_mscratch = current_mscratch;
56+
// Safety: this function can be called only once during initialization. We cannot do it in constructor, because physical harts art not
57+
// initialized yet then.
58+
pub fn set_ace_mscratch(&mut self, value: usize) {
59+
self.previous_mscratch = CSR.mscratch.swap(value);
5760
}
5861

62+
#[inline(always)]
5963
pub fn opensbi_context<F>(&mut self, function: F) -> Result<(), crate::error::Error>
6064
where F: FnOnce() -> Result<(), crate::error::Error> {
61-
self.swap_mscratch();
65+
let ace_mscratch = CSR.mscratch.swap(self.previous_mscratch);
6266
let result = function();
63-
self.swap_mscratch();
67+
CSR.mscratch.write(ace_mscratch);
6468
result
6569
}
6670

71+
#[inline(always)]
72+
pub fn call_opensbi_trap_handler(&mut self) {
73+
// Safety: We play with fire here. We must make sure statically that the OpenSBI's input structure is bitwise same as the ACE's hart
74+
// state.
75+
let trap_regs = self.hypervisor_hart_mut().hypervisor_hart_state_mut() as *mut _ as *mut sbi_trap_regs;
76+
let _ = self.opensbi_context(|| {
77+
Ok(unsafe {
78+
sbi_trap_handler(trap_regs);
79+
})
80+
});
81+
}
82+
6783
pub fn confidential_hart(&self) -> &ConfidentialHart {
6884
&self.confidential_hart
6985
}

security-monitor/src/core/initialization/mod.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,10 +229,8 @@ extern "C" fn ace_setup_this_hart() {
229229
// opensbi_mscratch in the internal hart state. OpenSBI stored in mscratch a pointer to the
230230
// `opensbi_mscratch` region of this hart before calling the security monitor's initialization
231231
// procedure. Thus, the swap will move the mscratch register value into the dump state of the hart
232-
hart.swap_mscratch();
233-
let hart_address = hart.hypervisor_hart().address();
234-
hart.hypervisor_hart_mut().csrs_mut().mscratch.write(hart_address);
235-
debug!("Hardware hart id={} has state area region at {:x}", hart_id, hart_address);
232+
hart.set_ace_mscratch(hart.hypervisor_hart().address());
233+
debug!("Hardware hart id={} has state area region at {:x}", hart_id, hart.hypervisor_hart().address());
236234

237235
// Configure the memory isolation mechanism that can limit memory view of the hypervisor to the memory region
238236
// owned by the hypervisor. The setup method enables the memory isolation. It is safe to call it because

security-monitor/src/non_confidential_flow/finite_state_machine.rs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ use crate::core::architecture::riscv::sbi::CovhExtension::*;
77
use crate::core::architecture::riscv::sbi::NaclExtension::*;
88
use crate::core::architecture::riscv::sbi::NaclSharedMemory;
99
use crate::core::architecture::riscv::sbi::SbiExtension::*;
10-
use crate::core::architecture::TrapCause;
10+
use crate::core::architecture::specification::CAUSE_SUPERVISOR_ECALL;
1111
use crate::core::architecture::TrapCause::*;
12+
use crate::core::architecture::{TrapCause, CSR};
1213
use crate::core::control_data::{ConfidentialVmId, HardwareHart, HypervisorHart};
1314
use crate::error::Error;
1415
use crate::non_confidential_flow::handlers::cove_host_extension::{
@@ -24,10 +25,6 @@ extern "C" {
2425
/// never returns to KVM with other state. For example, only a subset of exceptions/interrupts can be handled by KVM.
2526
/// KVM kill the vcpu if it receives unexpected exception because it does not know what to do with it.
2627
fn exit_to_hypervisor_asm() -> !;
27-
28-
/// Currently, we rely on OpenSBI to handle some of the interrupts or exceptions. Below function is the entry point
29-
/// to OpenSBI trap handler.
30-
fn sbi_trap_handler(regs: *mut sbi_trap_regs) -> *mut sbi_trap_regs;
3128
}
3229

3330
/// Represents the non-confidential part of the finite state machine (FSM), implementing router and exit nodes. It encapsulates the
@@ -37,8 +34,6 @@ pub struct NonConfidentialFlow<'a> {
3734
}
3835

3936
impl<'a> NonConfidentialFlow<'a> {
40-
const CTX_SWITCH_ERROR_MSG: &'static str = "Bug: invalid argument provided by the assembly context switch";
41-
4237
/// Creates an instance of the `NonConfidentialFlow`. A confidential hart must not be assigned to the hardware hart.
4338
pub fn create(hardware_hart: &'a mut HardwareHart) -> Self {
4439
assert!(hardware_hart.confidential_hart().is_dummy());
@@ -59,7 +54,15 @@ impl<'a> NonConfidentialFlow<'a> {
5954
// hardware hart's dump area in main memory. This area in main memory is exclusively owned by the physical hart executing this code.
6055
// Specifically, every physical hart has its own are in the main memory and its `mscratch` register stores the address. See the
6156
// `initialization` procedure for more details.
62-
let mut flow = unsafe { Self::create(hart_ptr.as_mut().expect(Self::CTX_SWITCH_ERROR_MSG)) };
57+
let hardware_hart = unsafe { &mut *hart_ptr };
58+
// Performance optimziation: we do not want to add overhead when delegating calls to OpenSBI, thus make sure we do not
59+
// create extra objects on heap or make unnecessary load/stores.
60+
if CSR.mcause.read() != CAUSE_SUPERVISOR_ECALL.into() {
61+
hardware_hart.call_opensbi_trap_handler();
62+
unsafe { exit_to_hypervisor_asm() };
63+
}
64+
65+
let mut flow = Self::create(hardware_hart);
6366
match TrapCause::from_hart_architectural_state(flow.hypervisor_hart().hypervisor_hart_state()) {
6467
HsEcall(Base(ProbeExtension)) => ProbeSbiExtension::from_hypervisor_hart(flow.hypervisor_hart_mut()).handle(flow),
6568
HsEcall(Covh(TsmGetInfo)) => GetSecurityMonitorInfo::from_hypervisor_hart(flow.hypervisor_hart()).handle(flow),
@@ -75,13 +78,7 @@ impl<'a> NonConfidentialFlow<'a> {
7578
}
7679

7780
pub fn delegate_to_opensbi(self) -> ! {
78-
// Safety: We play with fire here. We must statically make sure that OpenSBI's input structure is bitwise same as ACE's hart state.
79-
let trap_regs = self.hardware_hart.hypervisor_hart_mut().hypervisor_hart_state_mut() as *mut _ as *mut sbi_trap_regs;
80-
let _ = self.hardware_hart.opensbi_context(|| {
81-
Ok(unsafe {
82-
sbi_trap_handler(trap_regs);
83-
})
84-
});
81+
self.hardware_hart.call_opensbi_trap_handler();
8582
unsafe { exit_to_hypervisor_asm() }
8683
}
8784

0 commit comments

Comments
 (0)