Skip to content

Commit d5d8ae9

Browse files
committed
feat(vcpu): add interrupt injection support and enhance system register handling
- Add interrupt injection support to Aarch64VCpu - Implement get_sysreg_device function for system register access - Update GuestSystemRegisters to include CNTHCTL_EL2 - Modify exception handling to use SysRegAddr - Adjust vcpu initialization to enable virtual IRQ and FIQ
1 parent 5adab4c commit d5d8ae9

File tree

9 files changed

+240
-14
lines changed

9 files changed

+240
-14
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@ aarch64_sysreg = "0.1.1"
1717

1818
axaddrspace = { git = "https://github.com/arceos-hypervisor/axaddrspace.git" }
1919
axvcpu = { git = "https://github.com/arceos-hypervisor/axvcpu.git" }
20+
axhal = { git = "https://github.com/arceos-hypervisor/arceos.git", branch = "vmm_inject_interrupt" }
21+
axdevice_base = { git = "https://github.com/arceos-hypervisor/axdevice_crates.git"}
22+
axvisor_api = { git = "https://github.com/arceos-hypervisor/axvisor_api.git", branch = "inject_interrupt" }

src/context_frame.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ pub struct GuestSystemRegisters {
156156
cntv_ctl_el0: u32,
157157
cntp_tval_el0: u32,
158158
cntv_tval_el0: u32,
159+
pub cnthctl_el2: u64,
159160

160161
// vpidr and vmpidr
161162
vpidr_el2: u32,
@@ -220,6 +221,7 @@ impl GuestSystemRegisters {
220221
asm!("mrs {0:x}, CNTP_TVAL_EL0", out(reg) self.cntp_tval_el0);
221222
asm!("mrs {0:x}, CNTV_TVAL_EL0", out(reg) self.cntv_tval_el0);
222223
asm!("mrs {0}, CNTVCT_EL0", out(reg) self.cntvct_el0);
224+
asm!("mrs {0}, CNTHCTL_EL2", out(reg) self.cnthctl_el2);
223225
// MRS!("self.vpidr_el2, VPIDR_EL2, "x");
224226
asm!("mrs {0}, VMPIDR_EL2", out(reg) self.vmpidr_el2);
225227

@@ -265,6 +267,7 @@ impl GuestSystemRegisters {
265267
asm!("msr CNTV_CVAL_EL0, {0}", in(reg) self.cntv_cval_el0);
266268
asm!("msr CNTKCTL_EL1, {0:x}", in (reg) self.cntkctl_el1);
267269
asm!("msr CNTV_CTL_EL0, {0:x}", in (reg) self.cntv_ctl_el0);
270+
asm!("msr CNTHCTL_EL2, {0}", in(reg) self.cnthctl_el2);
268271
// The restoration of SP_EL0 is done in `exception_return_el2`,
269272
// which move the value from `self.ctx.sp_el0` to `SP_EL0`.
270273
// asm!("msr SP_EL0, {0}", in(reg) self.sp_el0);

src/exception.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
use aarch64_cpu::registers::{ESR_EL2, HCR_EL2, Readable, SCTLR_EL1, VTCR_EL2, VTTBR_EL2};
22

3-
use axaddrspace::GuestPhysAddr;
4-
use axerrno::{AxError, AxResult};
5-
use axvcpu::{AccessWidth, AxVCpuExitReason};
6-
73
use crate::TrapFrame;
84
use crate::exception_utils::{
95
exception_class, exception_class_value, exception_data_abort_access_is_write,
@@ -13,6 +9,10 @@ use crate::exception_utils::{
139
exception_esr, exception_fault_addr, exception_next_instruction_step, exception_sysreg_addr,
1410
exception_sysreg_direction_write, exception_sysreg_gpr,
1511
};
12+
use axaddrspace::GuestPhysAddr;
13+
use axaddrspace::device::{AccessWidth, SysRegAddr};
14+
use axerrno::{AxError, AxResult};
15+
use axvcpu::AxVCpuExitReason;
1616

1717
numeric_enum_macro::numeric_enum! {
1818
#[repr(u8)]
@@ -203,11 +203,14 @@ fn handle_system_register(context_frame: &mut TrapFrame) -> AxResult<AxVCpuExitR
203203
context_frame.set_exception_pc(val);
204204
if write {
205205
return Ok(AxVCpuExitReason::SysRegWrite {
206-
addr,
206+
addr: SysRegAddr::new(addr),
207207
value: context_frame.gpr(reg as usize) as u64,
208208
});
209209
}
210-
Ok(AxVCpuExitReason::SysRegRead { addr, reg })
210+
Ok(AxVCpuExitReason::SysRegRead {
211+
addr: SysRegAddr::new(addr),
212+
reg,
213+
})
211214
}
212215

213216
/// Handles HVC or SMC exceptions that serve as psci (Power State Coordination Interface) calls.

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ mod exception;
1313
mod pcpu;
1414
mod smc;
1515
mod vcpu;
16+
mod sysreg;
1617

18+
pub use self::sysreg::get_sysreg_device;
1719
pub use self::pcpu::Aarch64PerCpu;
1820
pub use self::vcpu::{Aarch64VCpu, Aarch64VCpuCreateConfig};
1921

src/sysreg/cntp_ctl_el0.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use aarch64_sysreg::SystemRegType;
2+
3+
use axaddrspace::GuestPhysAddrRange;
4+
use axaddrspace::device::{AccessWidth, DeviceAddrRange, SysRegAddr, SysRegAddrRange};
5+
use axdevice_base::EmuDeviceType;
6+
use axdevice_base::{BaseDeviceOps, BaseMmioDeviceOps};
7+
use axerrno::AxResult;
8+
9+
impl BaseDeviceOps<SysRegAddrRange> for SysCntpCtlEl0 {
10+
fn emu_type(&self) -> EmuDeviceType {
11+
EmuDeviceType::EmuDeviceTConsole
12+
}
13+
14+
fn address_range(&self) -> SysRegAddrRange {
15+
SysRegAddrRange {
16+
start: SysRegAddr::new(SystemRegType::CNTP_CTL_EL0 as usize),
17+
end: SysRegAddr::new(SystemRegType::CNTP_CTL_EL0 as usize),
18+
}
19+
}
20+
21+
fn handle_read(
22+
&self,
23+
addr: <SysRegAddrRange as DeviceAddrRange>::Addr,
24+
width: AccessWidth,
25+
) -> AxResult<usize> {
26+
todo!()
27+
}
28+
29+
fn handle_write(
30+
&self,
31+
addr: <SysRegAddrRange as DeviceAddrRange>::Addr,
32+
width: AccessWidth,
33+
val: usize,
34+
) -> AxResult {
35+
info!("Write to emulator register: {:?}, value: {}", addr, val);
36+
Ok(())
37+
}
38+
}
39+
40+
pub struct SysCntpCtlEl0 {
41+
// Fields
42+
}
43+
44+
impl SysCntpCtlEl0 {
45+
pub fn new() -> Self {
46+
Self {
47+
// Initialize fields
48+
}
49+
}
50+
}

src/sysreg/cntp_tval_el0.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
extern crate alloc;
2+
3+
use aarch64_sysreg::SystemRegType;
4+
5+
use aarch64_cpu::registers::{CNTPCT_EL0, Readable};
6+
7+
use axaddrspace::{
8+
GuestPhysAddrRange,
9+
device::{AccessWidth, DeviceAddrRange, SysRegAddr, SysRegAddrRange},
10+
};
11+
12+
use axdevice_base::{BaseDeviceOps, EmuDeviceType};
13+
14+
use axhal::irq::inject_interrupt;
15+
use axvisor_api::time::{current_time_nanos, register_timer};
16+
17+
use core::time::Duration;
18+
19+
use alloc::boxed::Box;
20+
21+
use axerrno::AxResult;
22+
23+
impl BaseDeviceOps<SysRegAddrRange> for SysCntpTvalEl0 {
24+
fn emu_type(&self) -> EmuDeviceType {
25+
EmuDeviceType::EmuDeviceTConsole
26+
}
27+
28+
fn address_range(&self) -> SysRegAddrRange {
29+
SysRegAddrRange {
30+
start: SysRegAddr::new(SystemRegType::CNTP_TVAL_EL0 as usize),
31+
end: SysRegAddr::new(SystemRegType::CNTP_TVAL_EL0 as usize),
32+
}
33+
}
34+
35+
fn handle_read(
36+
&self,
37+
addr: <SysRegAddrRange as DeviceAddrRange>::Addr,
38+
width: AccessWidth,
39+
) -> AxResult<usize> {
40+
todo!()
41+
}
42+
43+
fn handle_write(
44+
&self,
45+
addr: <SysRegAddrRange as DeviceAddrRange>::Addr,
46+
width: AccessWidth,
47+
val: usize,
48+
) -> AxResult {
49+
info!("Write to emulator register: {:?}, value: {}", addr, val);
50+
let now = current_time_nanos();
51+
info!("Current time: {}, deadline: {}", now, now + val as u64);
52+
register_timer(
53+
Duration::from_nanos(now + val as u64),
54+
Box::new(|_| {
55+
inject_interrupt(30);
56+
}),
57+
);
58+
Ok(())
59+
}
60+
}
61+
62+
pub struct SysCntpTvalEl0 {
63+
// Fields
64+
}
65+
66+
impl SysCntpTvalEl0 {
67+
pub fn new() -> Self {
68+
Self {
69+
// Initialize fields
70+
}
71+
}
72+
}

src/sysreg/cntpct_el0.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use aarch64_sysreg::SystemRegType;
2+
3+
use aarch64_cpu::registers::{CNTPCT_EL0, Readable};
4+
5+
use axaddrspace::{
6+
GuestPhysAddrRange,
7+
device::{AccessWidth, DeviceAddrRange, SysRegAddr, SysRegAddrRange},
8+
};
9+
10+
use axdevice_base::{BaseDeviceOps, EmuDeviceType};
11+
12+
use axerrno::AxResult;
13+
14+
impl BaseDeviceOps<SysRegAddrRange> for SysCntpctEl0 {
15+
fn emu_type(&self) -> EmuDeviceType {
16+
EmuDeviceType::EmuDeviceTConsole
17+
}
18+
19+
fn address_range(&self) -> SysRegAddrRange {
20+
SysRegAddrRange {
21+
start: SysRegAddr::new(SystemRegType::CNTPCT_EL0 as usize),
22+
end: SysRegAddr::new(SystemRegType::CNTPCT_EL0 as usize),
23+
}
24+
}
25+
26+
fn handle_read(
27+
&self,
28+
addr: <SysRegAddrRange as DeviceAddrRange>::Addr,
29+
width: AccessWidth,
30+
) -> AxResult<usize> {
31+
Ok(CNTPCT_EL0.get() as usize)
32+
}
33+
34+
fn handle_write(
35+
&self,
36+
addr: <SysRegAddrRange as DeviceAddrRange>::Addr,
37+
width: AccessWidth,
38+
val: usize,
39+
) -> AxResult {
40+
info!("Write to emulator register: {:?}, value: {}", addr, val);
41+
Ok(())
42+
}
43+
}
44+
45+
pub struct SysCntpctEl0 {
46+
// Fields
47+
}
48+
49+
impl SysCntpctEl0 {
50+
pub fn new() -> Self {
51+
Self {
52+
// Initialize fields
53+
}
54+
}
55+
}

src/sysreg/mod.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
extern crate alloc;
2+
3+
use alloc::sync::Arc;
4+
use alloc::{vec, vec::Vec};
5+
use axdevice_base::BaseSysRegDeviceOps;
6+
7+
mod cntp_ctl_el0;
8+
pub use cntp_ctl_el0::SysCntpCtlEl0;
9+
10+
mod cntpct_el0;
11+
pub use cntpct_el0::SysCntpctEl0;
12+
13+
mod cntp_tval_el0;
14+
pub use cntp_tval_el0::SysCntpTvalEl0;
15+
16+
pub fn get_sysreg_device() -> Vec<Arc<dyn BaseSysRegDeviceOps>> {
17+
vec![
18+
Arc::new(SysCntpCtlEl0::new()),
19+
Arc::new(SysCntpctEl0::new()),
20+
Arc::new(SysCntpTvalEl0::new()),
21+
]
22+
}

src/vcpu.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ use core::marker::PhantomData;
33
use aarch64_cpu::registers::{CNTHCTL_EL2, HCR_EL2, SP_EL0, SPSR_EL1, VTCR_EL2};
44
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
55

6-
use axaddrspace::{GuestPhysAddr, HostPhysAddr};
7-
use axerrno::AxResult;
8-
use axvcpu::{AxVCpuExitReason, AxVCpuHal};
9-
106
use crate::TrapFrame;
117
use crate::context_frame::GuestSystemRegisters;
128
use crate::exception::{TrapKind, handle_exception_sync};
139
use crate::exception_utils::exception_class_value;
10+
use axaddrspace::{GuestPhysAddr, HostPhysAddr};
11+
use axerrno::AxResult;
12+
use axhal::irq::inject_interrupt;
13+
use axvcpu::{AxVCpuExitReason, AxVCpuHal};
1414

1515
#[percpu::def_percpu]
1616
static HOST_SP_EL0: u64 = 0;
@@ -121,6 +121,11 @@ impl<H: AxVCpuHal> axvcpu::AxArchVCpu for Aarch64VCpu<H> {
121121
fn set_gpr(&mut self, idx: usize, val: usize) {
122122
self.ctx.set_gpr(idx, val);
123123
}
124+
125+
fn inject_interrupt(&mut self, vector: usize) -> AxResult {
126+
inject_interrupt(vector);
127+
Ok(())
128+
}
124129
}
125130

126131
// Private function
@@ -151,9 +156,13 @@ impl<H: AxVCpuHal> Aarch64VCpu<H> {
151156
+ VTCR_EL2::SL0.val(0b01)
152157
+ VTCR_EL2::T0SZ.val(64 - 39))
153158
.into();
154-
self.guest_system_regs.hcr_el2 =
155-
(HCR_EL2::VM::Enable + HCR_EL2::RW::EL1IsAarch64 + HCR_EL2::TSC::EnableTrapEl1SmcToEl2)
156-
.into();
159+
self.guest_system_regs.hcr_el2 = (HCR_EL2::VM::Enable
160+
+ HCR_EL2::RW::EL1IsAarch64
161+
+ HCR_EL2::IMO::EnableVirtualIRQ
162+
+ HCR_EL2::FMO::EnableVirtualFIQ
163+
+ HCR_EL2::TSC::EnableTrapEl1SmcToEl2
164+
+ HCR_EL2::RW::EL1IsAarch64)
165+
.into();
157166
// self.system_regs.hcr_el2 |= 1<<27;
158167
// + HCR_EL2::IMO::EnableVirtualIRQ).into();
159168

@@ -203,7 +212,14 @@ impl<H: AxVCpuHal> Aarch64VCpu<H> {
203212
}
204213

205214
// the dummy return value, the real return value is in x0 when `return_run_guest` returns
206-
0
215+
let exit_reason: usize;
216+
core::arch::asm!(
217+
"mov {}, x0",
218+
out(reg) exit_reason,
219+
options(nostack)
220+
);
221+
exit_reason
222+
207223
}
208224

209225
/// Restores guest system control registers.

0 commit comments

Comments
 (0)