Skip to content

Commit 3ef7480

Browse files
authored
[feat] support smc proxy, add dtb in vcpu_create_cfg (#23)
1 parent f7ccb6d commit 3ef7480

File tree

4 files changed

+81
-17
lines changed

4 files changed

+81
-17
lines changed

src/exception.rs

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,12 @@ core::arch::global_asm!(
7171
///
7272
pub fn handle_exception_sync(ctx: &mut TrapFrame) -> AxResult<AxVCpuExitReason> {
7373
match exception_class() {
74-
Some(ESR_EL2::EC::Value::DataAbortLowerEL) => handle_data_abort(ctx),
74+
Some(ESR_EL2::EC::Value::DataAbortLowerEL) => {
75+
let elr = ctx.exception_pc();
76+
let val = elr + exception_next_instruction_step();
77+
ctx.set_exception_pc(val);
78+
handle_data_abort(ctx)
79+
}
7580
Some(ESR_EL2::EC::Value::HVC64) => {
7681
// The `#imm`` argument when triggering a hvc call, currently not used.
7782
let _hvc_arg_imm16 = ESR_EL2.read(ESR_EL2::ISS);
@@ -96,6 +101,12 @@ pub fn handle_exception_sync(ctx: &mut TrapFrame) -> AxResult<AxVCpuExitReason>
96101
})
97102
}
98103
Some(ESR_EL2::EC::Value::TrappedMsrMrs) => handle_system_register(ctx),
104+
Some(ESR_EL2::EC::Value::SMC64) => {
105+
let elr = ctx.exception_pc();
106+
let val = elr + exception_next_instruction_step();
107+
ctx.set_exception_pc(val);
108+
handle_smc64_exception(ctx)
109+
}
99110
_ => {
100111
panic!(
101112
"handler not presents for EC_{} @ipa 0x{:x}, @pc 0x{:x}, @esr 0x{:x},
@@ -116,17 +127,18 @@ pub fn handle_exception_sync(ctx: &mut TrapFrame) -> AxResult<AxVCpuExitReason>
116127

117128
fn handle_data_abort(context_frame: &mut TrapFrame) -> AxResult<AxVCpuExitReason> {
118129
let addr = exception_fault_addr()?;
119-
debug!("data fault addr {:?}, esr: 0x{:x}", addr, exception_esr());
120-
121130
let access_width = exception_data_abort_access_width();
122131
let is_write = exception_data_abort_access_is_write();
123132
//let sign_ext = exception_data_abort_access_is_sign_ext();
124133
let reg = exception_data_abort_access_reg();
125134
let reg_width = exception_data_abort_access_reg_width();
126135

127-
let elr = context_frame.exception_pc();
128-
let val = elr + exception_next_instruction_step();
129-
context_frame.set_exception_pc(val);
136+
trace!(
137+
"Data fault @{:?}, ELR {:#x}, esr: 0x{:x}",
138+
addr,
139+
context_frame.exception_pc(),
140+
exception_esr(),
141+
);
130142

131143
let width = match AccessWidth::try_from(access_width) {
132144
Ok(access_width) => access_width,
@@ -209,12 +221,14 @@ fn handle_psci_call(ctx: &mut TrapFrame) -> Option<AxResult<AxVCpuExitReason>> {
209221
const PSCI_FN_RANGE_32: core::ops::RangeInclusive<u64> = 0x8400_0000..=0x8400_001F;
210222
const PSCI_FN_RANGE_64: core::ops::RangeInclusive<u64> = 0xC400_0000..=0xC400_001F;
211223

224+
const PSCI_FN_VERSION: u64 = 0x0;
212225
const _PSCI_FN_CPU_SUSPEND: u64 = 0x1;
213226
const PSCI_FN_CPU_OFF: u64 = 0x2;
214227
const PSCI_FN_CPU_ON: u64 = 0x3;
215228
const _PSCI_FN_MIGRATE: u64 = 0x5;
216229
const PSCI_FN_SYSTEM_OFF: u64 = 0x8;
217230
const _PSCI_FN_SYSTEM_RESET: u64 = 0x9;
231+
const PSCI_FN_END: u64 = 0x1f;
218232

219233
let fn_ = ctx.gpr[0];
220234
let fn_offset = if PSCI_FN_RANGE_32.contains(&fn_) {
@@ -225,16 +239,35 @@ fn handle_psci_call(ctx: &mut TrapFrame) -> Option<AxResult<AxVCpuExitReason>> {
225239
None
226240
};
227241

228-
fn_offset.map(|fn_offset| match fn_offset {
229-
PSCI_FN_CPU_OFF => Ok(AxVCpuExitReason::CpuDown { _state: ctx.gpr[1] }),
230-
PSCI_FN_CPU_ON => Ok(AxVCpuExitReason::CpuUp {
242+
match fn_offset {
243+
Some(PSCI_FN_CPU_OFF) => Some(Ok(AxVCpuExitReason::CpuDown { _state: ctx.gpr[1] })),
244+
Some(PSCI_FN_CPU_ON) => Some(Ok(AxVCpuExitReason::CpuUp {
231245
target_cpu: ctx.gpr[1],
232246
entry_point: GuestPhysAddr::from(ctx.gpr[2] as usize),
233247
arg: ctx.gpr[3],
234-
}),
235-
PSCI_FN_SYSTEM_OFF => Ok(AxVCpuExitReason::SystemDown),
236-
_ => Err(AxError::Unsupported),
237-
})
248+
})),
249+
Some(PSCI_FN_SYSTEM_OFF) => Some(Ok(AxVCpuExitReason::SystemDown)),
250+
// We just forward these request to the ATF directly.
251+
Some(PSCI_FN_VERSION..PSCI_FN_END) => None,
252+
_ => None,
253+
}
254+
}
255+
256+
/// Handles SMC (Secure Monitor Call) exceptions.
257+
///
258+
/// This function will judge if the SMC call is a PSCI call, if so, it will handle it as a PSCI call.
259+
/// Otherwise, it will forward the SMC call to the ATF directly.
260+
fn handle_smc64_exception(ctx: &mut TrapFrame) -> AxResult<AxVCpuExitReason> {
261+
// Is this a psci call?
262+
if let Some(result) = handle_psci_call(ctx) {
263+
return result;
264+
} else {
265+
// We just forward the SMC call to the ATF directly.
266+
// The args are from lower EL, so it is safe to call the ATF.
267+
(ctx.gpr[0], ctx.gpr[1], ctx.gpr[2], ctx.gpr[3]) =
268+
unsafe { crate::smc::smc_call(ctx.gpr[0], ctx.gpr[1], ctx.gpr[2], ctx.gpr[3]) };
269+
Ok(AxVCpuExitReason::Nothing)
270+
}
238271
}
239272

240273
/// Dispatches IRQs to the appropriate handler provided by the underlying host OS,

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![feature(naked_functions)]
33
#![feature(doc_cfg)]
44
#![feature(asm_const)]
5+
#![feature(exclusive_range_pattern)]
56
#![doc = include_str!("../README.md")]
67

78
#[macro_use]
@@ -12,6 +13,7 @@ mod context_frame;
1213
mod exception_utils;
1314
mod exception;
1415
mod pcpu;
16+
mod smc;
1517
mod vcpu;
1618

1719
pub use self::pcpu::Aarch64PerCpu;

src/smc.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use core::arch::asm;
2+
3+
#[inline(never)]
4+
/// invoke a secure monitor call
5+
/// # Safety:
6+
/// It is unsafe to call this function directly.
7+
/// The caller must ensure that
8+
/// x0 is defined as the SMC function number referenced in the SMC Calling Convention
9+
/// than the args later must be valid for the specified SMC function.
10+
pub unsafe fn smc_call(x0: u64, x1: u64, x2: u64, x3: u64) -> (u64, u64, u64, u64) {
11+
let r0;
12+
let r1;
13+
let r2;
14+
let r3;
15+
asm!(
16+
"smc #0",
17+
inout("x0") x0 => r0,
18+
inout("x1") x1 => r1,
19+
inout("x2") x2 => r2,
20+
inout("x3") x3 => r3,
21+
options(nomem, nostack)
22+
);
23+
(r0, r1, r2, r3)
24+
}

src/vcpu.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ pub struct Aarch64VCpuCreateConfig {
7575
/// which is used to identify the CPU in a multiprocessor system.
7676
/// Note: mind CPU cluster.
7777
pub mpidr_el1: u64,
78+
/// The address of the device tree blob.
79+
pub dtb_addr: usize,
7880
}
7981

8082
impl<H: AxVCpuHal> axvcpu::AxArchVCpu for Aarch64VCpu<H> {
@@ -83,8 +85,11 @@ impl<H: AxVCpuHal> axvcpu::AxArchVCpu for Aarch64VCpu<H> {
8385
type SetupConfig = ();
8486

8587
fn new(config: Self::CreateConfig) -> AxResult<Self> {
88+
let mut ctx = TrapFrame::default();
89+
ctx.set_argument(config.dtb_addr);
90+
8691
Ok(Self {
87-
ctx: TrapFrame::default(),
92+
ctx,
8893
host_stack_top: 0,
8994
guest_system_regs: GuestSystemRegisters::default(),
9095
mpidr: config.mpidr_el1,
@@ -168,11 +173,11 @@ impl<H: AxVCpuHal> Aarch64VCpu<H> {
168173
+ VTCR_EL2::SL0.val(0b01)
169174
+ VTCR_EL2::T0SZ.val(64 - 39))
170175
.into();
171-
self.guest_system_regs.hcr_el2 = (HCR_EL2::VM::Enable + HCR_EL2::RW::EL1IsAarch64).into();
176+
self.guest_system_regs.hcr_el2 =
177+
(HCR_EL2::VM::Enable + HCR_EL2::RW::EL1IsAarch64 + HCR_EL2::TSC::EnableTrapEl1SmcToEl2)
178+
.into();
172179
// self.system_regs.hcr_el2 |= 1<<27;
173180
// + HCR_EL2::IMO::EnableVirtualIRQ).into();
174-
// trap el1 smc to el2
175-
// self.system_regs.hcr_el2 |= HCR_TSC_TRAP as u64;
176181

177182
// Set VMPIDR_EL2, which provides the value of the Virtualization Multiprocessor ID.
178183
// This is the value returned by Non-secure EL1 reads of MPIDR.

0 commit comments

Comments
 (0)