Skip to content

Commit 9b0f9a7

Browse files
committed
feat(vcpu): add support for emulated system registers and update exception handling
- Add axdevice and axhal dependencies in Cargo.toml - Implement CNTHCTL_EL2 register in GuestSystemRegisters - Update exception handling to use LOWER_SYNC_VCPU - Add Aarch64EmuRegs and update vcpu.rs for emulated registers - Modify HCR_EL2 configuration in vcpu initialization
1 parent 5adab4c commit 9b0f9a7

File tree

6 files changed

+179
-8
lines changed

6 files changed

+179
-8
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ 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+
axdevice = { git = "https://github.com/arceos-hypervisor/axdevice.git" }
21+
axhal = { git = "https://github.com/arceos-hypervisor/arceos.git", branch = "vmm_rebase" }

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.S

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ exception_vector_base_vcpu:
110110
INVALID_EXCP_EL2 3 0
111111

112112
// current EL, with SP_ELx
113-
HANDLE_CURRENT_SYNC
113+
HANDLE_LOWER_SYNC_VCPU
114114
HANDLE_CURRENT_IRQ
115115
INVALID_EXCP_EL2 2 1
116116
INVALID_EXCP_EL2 3 1

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ mod exception_utils;
1212
mod exception;
1313
mod pcpu;
1414
mod smc;
15+
mod system_registers;
1516
mod vcpu;
1617

1718
pub use self::pcpu::Aarch64PerCpu;
19+
pub use self::system_registers::Aarch64EmuRegs;
1820
pub use self::vcpu::{Aarch64VCpu, Aarch64VCpuCreateConfig};
1921

2022
/// context frame for aarch64

src/system_registers.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
extern crate alloc;
2+
use crate::vcpu::Aarch64VCpu;
3+
use aarch64_cpu::registers::{Readable, Writeable};
4+
use aarch64_cpu::registers::{CNTFRQ_EL0, CNTPCT_EL0, CNTP_CTL_EL0, CNTP_TVAL_EL0};
5+
use aarch64_sysreg::SystemRegType;
6+
use alloc::sync::Arc;
7+
use alloc::vec::Vec;
8+
use axdevice::timer::{register_timer, VmmTimerEvent};
9+
use axvcpu::{AxVCpu, AxVCpuHal};
10+
use spin::RwLock;
11+
12+
use axhal::irq::MyVgic;
13+
14+
type RegVcpu<H> = Arc<AxVCpu<Aarch64VCpu<H>>>;
15+
16+
use core::arch::asm;
17+
fn get_mpidr() -> u64 {
18+
let mpidr: u64;
19+
unsafe {
20+
asm!(
21+
"mrs {mpidr}, MPIDR_EL1", // 从 MPIDR_EL1 读取
22+
mpidr = out(reg) mpidr
23+
);
24+
}
25+
mpidr
26+
}
27+
28+
/// Struct representing an entry in the emulator register list.
29+
pub struct EmuRegEntry<H: AxVCpuHal> {
30+
/// The type of the emulator register.
31+
pub emu_type: EmuRegType,
32+
/// The address associated with the emulator register.
33+
pub addr: SystemRegType,
34+
/// The handler write function for the emulator register.
35+
pub handle_write: fn(SystemRegType, u64, RegVcpu<H>) -> bool,
36+
/// The handler read function for the emulator register.
37+
pub handle_read: fn(SystemRegType, usize, RegVcpu<H>) -> bool,
38+
}
39+
40+
/// Enumeration representing the type of emulator registers.
41+
pub enum EmuRegType {
42+
/// System register type for emulator registers.
43+
SysReg,
44+
}
45+
46+
/// Struct representing the emulator registers.
47+
pub struct Aarch64EmuRegs<H: AxVCpuHal> {
48+
/// The list of emulator registers.
49+
pub emu_regs: RwLock<Vec<EmuRegEntry<H>>>,
50+
}
51+
52+
impl<H: AxVCpuHal> Aarch64EmuRegs<H> {
53+
const EMU_REGISTERS: [EmuRegEntry<H>; 3] = [
54+
EmuRegEntry {
55+
emu_type: EmuRegType::SysReg,
56+
addr: SystemRegType::CNTP_TVAL_EL0,
57+
handle_write: |addr, value, vcpu| {
58+
debug!(
59+
"Write to emulator register: {:?}, value: {}, vcpu: {}, {}",
60+
addr,
61+
value,
62+
vcpu.id(),
63+
get_mpidr()
64+
);
65+
// CNTP_TVAL_EL0.set(value);
66+
let now = axhal::time::monotonic_time_nanos();
67+
trace!("Current time: {}", now);
68+
let gich = MyVgic::get_gich();
69+
register_timer(
70+
value + now,
71+
VmmTimerEvent::new(|_| {
72+
debug!("Timer expired");
73+
let gich = MyVgic::get_gich();
74+
let hcr = gich.get_hcr();
75+
gich.set_hcr(hcr | 1 << 0);
76+
let mut lr = 0;
77+
lr |= 30 << 0;
78+
lr |= 1 << 19;
79+
lr |= 1 << 28;
80+
gich.set_lr(0, lr);
81+
}),
82+
);
83+
true
84+
},
85+
handle_read: |_, _, _| true,
86+
},
87+
EmuRegEntry {
88+
emu_type: EmuRegType::SysReg,
89+
addr: SystemRegType::CNTP_CTL_EL0,
90+
handle_write: |addr, value, _| {
91+
trace!("Write to emulator register: {:?}, value: {}", addr, value);
92+
// if value & 0x1 != 0 {
93+
// axhal::irq::set_enable(30, true);
94+
// } else {
95+
// axhal::irq::set_enable(30, false);
96+
// }
97+
98+
// let gich = MyVgic::get_gich();
99+
// let gicd = MyVgic::get_gicd();
100+
// let gicc = MyVgic::get_gicv();
101+
// CNTP_CTL_EL0.set(value);
102+
// let hcr = gich.get_hcr();
103+
// gich.set_hcr(hcr | 1 << 0);
104+
// let mut lr = 0;
105+
// lr |= 30 << 0;
106+
// lr |= 1 << 19;
107+
// lr |= 1 << 28;
108+
// gich.set_lr(0, lr);
109+
// gicd.lock().set_pend(30, true, 0);
110+
// gicc.set_ctlr(ctlr);
111+
112+
true
113+
},
114+
handle_read: |_, _, _| true,
115+
},
116+
EmuRegEntry {
117+
emu_type: EmuRegType::SysReg,
118+
addr: SystemRegType::CNTPCT_EL0,
119+
handle_write: |_, _, _| true,
120+
handle_read: |addr, reg, vcpu| {
121+
let val = CNTPCT_EL0.get();
122+
trace!("Read from emulator register: {:?}, value: {}", addr, val);
123+
vcpu.set_gpr(reg, val as usize);
124+
true
125+
},
126+
},
127+
];
128+
129+
/// Handle a write to an emulator register.
130+
pub fn emu_register_handle_write(addr: SystemRegType, value: u64, vcpu: RegVcpu<H>) -> bool {
131+
let emu_reg = Self::EMU_REGISTERS;
132+
133+
for entry in emu_reg.iter() {
134+
if entry.addr == addr {
135+
return (entry.handle_write)(addr, value, vcpu);
136+
}
137+
}
138+
error!("Invalid emulated register write: {}", addr);
139+
false
140+
}
141+
142+
/// Handle a read from an emulator register.
143+
pub fn emu_register_handle_read(addr: SystemRegType, reg: usize, vcpu: RegVcpu<H>) -> bool {
144+
let emu_reg = Self::EMU_REGISTERS;
145+
146+
for entry in emu_reg.iter() {
147+
if entry.addr == addr {
148+
return (entry.handle_read)(addr, reg, vcpu);
149+
}
150+
}
151+
error!("Invalid emulated register read: {}", addr);
152+
false
153+
}
154+
}

src/vcpu.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
use core::marker::PhantomData;
22

3-
use aarch64_cpu::registers::{CNTHCTL_EL2, HCR_EL2, SP_EL0, SPSR_EL1, VTCR_EL2};
3+
use aarch64_cpu::registers::{CNTHCTL_EL2, HCR_EL2, SPSR_EL1, SP_EL0, VTCR_EL2};
44
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
55

66
use axaddrspace::{GuestPhysAddr, HostPhysAddr};
77
use axerrno::AxResult;
88
use axvcpu::{AxVCpuExitReason, AxVCpuHal};
99

10-
use crate::TrapFrame;
1110
use crate::context_frame::GuestSystemRegisters;
12-
use crate::exception::{TrapKind, handle_exception_sync};
11+
use crate::exception::{handle_exception_sync, TrapKind};
1312
use crate::exception_utils::exception_class_value;
13+
use crate::TrapFrame;
1414

1515
#[percpu::def_percpu]
1616
static HOST_SP_EL0: u64 = 0;
@@ -151,9 +151,13 @@ impl<H: AxVCpuHal> Aarch64VCpu<H> {
151151
+ VTCR_EL2::SL0.val(0b01)
152152
+ VTCR_EL2::T0SZ.val(64 - 39))
153153
.into();
154-
self.guest_system_regs.hcr_el2 =
155-
(HCR_EL2::VM::Enable + HCR_EL2::RW::EL1IsAarch64 + HCR_EL2::TSC::EnableTrapEl1SmcToEl2)
156-
.into();
154+
self.guest_system_regs.hcr_el2 = (HCR_EL2::VM::Enable
155+
+ HCR_EL2::RW::EL1IsAarch64
156+
+ HCR_EL2::IMO::EnableVirtualIRQ
157+
+ HCR_EL2::FMO::EnableVirtualFIQ
158+
+ HCR_EL2::TSC::EnableTrapEl1SmcToEl2
159+
+ HCR_EL2::RW::EL1IsAarch64)
160+
.into();
157161
// self.system_regs.hcr_el2 |= 1<<27;
158162
// + HCR_EL2::IMO::EnableVirtualIRQ).into();
159163

@@ -203,7 +207,13 @@ impl<H: AxVCpuHal> Aarch64VCpu<H> {
203207
}
204208

205209
// the dummy return value, the real return value is in x0 when `return_run_guest` returns
206-
0
210+
let exit_reason: usize;
211+
core::arch::asm!(
212+
"mov {}, x0",
213+
out(reg) exit_reason,
214+
options(nostack)
215+
);
216+
exit_reason
207217
}
208218

209219
/// Restores guest system control registers.

0 commit comments

Comments
 (0)