Skip to content

Commit 3d2cf05

Browse files
authored
Merge pull request #45 from arceos-hypervisor/dev1
Refactor: Move all arch-related code into
2 parents d759685 + 574ed36 commit 3d2cf05

File tree

33 files changed

+3291
-950
lines changed

33 files changed

+3291
-950
lines changed

Cargo.toml

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,73 @@
11
[package]
2-
name = "axvm"
32
authors = ["aarkegz <aarkegz@gmail.com>"]
4-
version = "0.2.0"
5-
edition = "2024"
63
categories = ["virtualization", "no-std"]
74
description = "Virtual Machine resource management crate for ArceOS's hypervisor variant."
8-
repository = "https://github.com/arceos-hypervisor/axvm"
5+
edition = "2024"
96
keywords = ["vm", "hypervisor", "arceos"]
107
license = "Apache-2.0"
8+
name = "axvm"
9+
repository = "https://github.com/arceos-hypervisor/axvm"
10+
version = "0.2.0"
1111

1212
[features]
1313
default = ["vmx"]
1414
vmx = []
15-
4-level-ept = ["arm_vcpu/4-level-ept"] # TODO: Realize 4-level-ept on x86_64 and riscv64.
1615

1716
[dependencies]
18-
log = "0.4"
17+
anyhow = {version = "1.0", default-features = false}
1918
cfg-if = "1.0"
20-
spin = "0.9"
19+
lazyinit = "0.2"
20+
log = "0.4"
21+
ranges-ext.workspace = true
22+
spin = "0.10"
23+
thiserror = {version = "2", default-features = false}
24+
timer_list = "0.1"
2125

2226
# System independent crates provided by ArceOS.
2327
axerrno = "0.1.0"
28+
bitmap-allocator = "0.2.1"
2429
cpumask = "0.1.0"
25-
# kspin = "0.1.0"
30+
derive_more = {version = "2", default-features = false, features = ["full"]}
31+
kspin = "0.1"
2632
memory_addr = "0.4"
27-
page_table_entry = { version = "0.5", features = ["arm-el2"] }
33+
page_table_entry = {version = "0.5", features = ["arm-el2"]}
2834
page_table_multiarch = "0.5"
29-
percpu = { version = "0.2.0", features = ["arm-el2"] }
35+
rdif-intc = "0.12"
36+
vm-allocator.workspace = true
3037

3138
# System dependent modules provided by ArceOS-Hypervisor.
32-
axvcpu = "0.1"
33-
axaddrspace = "0.1"
34-
axdevice = "0.2"
35-
axdevice_base = "0.1"
36-
axvmconfig = { version = "0.1", default-features = false }
39+
axaddrspace = "0.2"
40+
41+
axhal.workspace = true
42+
axklib.workspace = true
43+
axruntime.workspace = true
44+
axstd.workspace = true
45+
axvm-types.workspace = true
46+
axvmconfig = {version = "0.1", default-features = false}
47+
fdt-edit = "0.1"
48+
mmio-api = "0.1"
49+
rdrive.workspace = true
50+
51+
axvdev = {version = "0.1"}
52+
53+
ringbuf = {version = "0.4", default-features = false}
3754

3855
[target.'cfg(target_arch = "x86_64")'.dependencies]
56+
axplat-x86-qemu-q35.workspace = true
57+
raw-cpuid = "11"
3958
x86_vcpu = "0.1"
4059

4160
[target.'cfg(target_arch = "riscv64")'.dependencies]
42-
riscv_vcpu = "0.1"
61+
# riscv_vcpu = "0.1"
4362

4463
[target.'cfg(target_arch = "aarch64")'.dependencies]
45-
arm_vcpu = "0.1"
46-
arm_vgic = { version = "0.1", features = ["vgicv3"] }
64+
aarch64-cpu = "11.0"
65+
aarch64-cpu-ext = "0.1"
66+
arm-gic-driver = {version = "0.15", features = ["rdif"]}
67+
arm_vcpu = "0.3"
68+
arm_vgic = {version = "0.3"}
69+
70+
[patch.crates-io]
71+
arm_vcpu = {git = "https://github.com/arceos-hypervisor/arm_vcpu", branch = "next"}
72+
axvcpu = {git = "https://github.com/arceos-hypervisor/axvcpu.git", branch = "next"}
73+
axvmconfig = {git = "https://github.com/arceos-hypervisor/axvmconfig.git", branch = "next"}

src/arch/aarch64/cpu.rs

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
use alloc::vec::Vec;
2+
use axvmconfig::VMInterruptMode;
3+
use core::fmt::{self, Debug, Display};
4+
5+
use aarch64_cpu::registers::*;
6+
use arm_vcpu::{Aarch64PerCpu, Aarch64VCpuCreateConfig, Aarch64VCpuSetupConfig};
7+
8+
use crate::{
9+
RunError, Vm, VmWeak,
10+
arch::{Hal, PlatData},
11+
hal::{
12+
HCpuOp,
13+
cpu::{CpuHardId, CpuId},
14+
},
15+
vcpu::{CpuBootInfo, VCpuOp},
16+
};
17+
18+
pub struct HCpu {
19+
pub id: CpuId,
20+
pub hard_id: CpuHardId,
21+
vpercpu: Aarch64PerCpu,
22+
max_guest_page_table_levels: usize,
23+
pub pa_range: core::ops::Range<usize>,
24+
pub pa_bits: usize,
25+
}
26+
27+
impl HCpuOp for HCpu {
28+
fn hard_id(&self) -> CpuHardId {
29+
self.hard_id
30+
}
31+
32+
fn max_guest_page_table_levels(&self) -> usize {
33+
self.max_guest_page_table_levels
34+
}
35+
36+
fn pa_range(&self) -> core::ops::Range<usize> {
37+
self.pa_range.clone()
38+
}
39+
40+
fn pa_bits(&self) -> usize {
41+
self.pa_bits
42+
}
43+
}
44+
45+
impl HCpu {
46+
pub fn new(id: CpuId) -> Self {
47+
let mpidr = MPIDR_EL1.get() as usize;
48+
let hard_id = mpidr & 0xff_ff_ff;
49+
50+
let vpercpu = Aarch64PerCpu::new();
51+
52+
HCpu {
53+
id,
54+
hard_id: CpuHardId::new(hard_id),
55+
vpercpu,
56+
max_guest_page_table_levels: 0,
57+
pa_range: 0..0,
58+
pa_bits: 0,
59+
}
60+
}
61+
62+
pub fn init(&mut self) -> anyhow::Result<()> {
63+
self.vpercpu.hardware_enable();
64+
self.max_guest_page_table_levels = self.vpercpu.max_guest_page_table_levels();
65+
self.pa_range = self.vpercpu.pa_range();
66+
self.pa_bits = self.vpercpu.pa_bits();
67+
Ok(())
68+
}
69+
70+
pub fn max_guest_page_table_levels(&self) -> usize {
71+
self.max_guest_page_table_levels
72+
}
73+
}
74+
75+
impl Display for HCpu {
76+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
77+
write!(
78+
f,
79+
"
80+
CPU {}:
81+
Hard ID: {}
82+
PT Levels: {}",
83+
self.id, self.hard_id, self.max_guest_page_table_levels
84+
)
85+
}
86+
}
87+
88+
pub(super) struct VCpuHal;
89+
90+
impl arm_vcpu::CpuHal for VCpuHal {
91+
fn irq_hanlder(&self) {
92+
axhal::irq::irq_handler(0);
93+
}
94+
95+
fn inject_interrupt(&self, irq: usize) {
96+
todo!()
97+
}
98+
99+
fn cpu_list(&self) -> Vec<usize> {
100+
crate::hal::cpu::list()
101+
.into_iter()
102+
.map(|id| id.raw())
103+
.collect()
104+
}
105+
}
106+
107+
pub struct CPUState {
108+
pub vcpu: arm_vcpu::Aarch64VCpu,
109+
mpidr_el1: u64,
110+
boot: Option<CpuBootInfo>,
111+
}
112+
113+
impl CPUState {
114+
pub fn new(id: CpuHardId, vm: VmWeak) -> anyhow::Result<Self> {
115+
let vcpu = arm_vcpu::Aarch64VCpu::new(Aarch64VCpuCreateConfig {
116+
mpidr_el1: id.raw() as u64,
117+
dtb_addr: 0,
118+
})
119+
.unwrap();
120+
Ok(CPUState {
121+
vcpu,
122+
mpidr_el1: id.raw() as u64,
123+
boot: None,
124+
})
125+
}
126+
127+
pub fn set_pt_level(&mut self, level: usize) {
128+
self.vcpu.pt_level = level;
129+
}
130+
131+
pub fn set_pa_bits(&mut self, pa_bits: usize) {
132+
self.vcpu.pa_bits = pa_bits;
133+
}
134+
}
135+
136+
impl VCpuOp for CPUState {
137+
fn run(&mut self, vm: &Vm) -> Result<(), RunError> {
138+
info!("Starting vCPU {}", self.mpidr_el1);
139+
140+
self.vcpu
141+
.setup_current_cpu(vm.id().into())
142+
.map_err(|e| anyhow!("{e}"))?;
143+
while vm.is_active() {
144+
debug!("vCPU {:#x} entering guest", self.mpidr_el1);
145+
let exit_reason = self.vcpu.run().map_err(|e| anyhow!("{e}"))?;
146+
debug!(
147+
"vCPU {:#x} exited with reason: {:?}",
148+
self.mpidr_el1, exit_reason
149+
);
150+
match exit_reason {
151+
arm_vcpu::AxVCpuExitReason::Hypercall { nr, args } => todo!(),
152+
arm_vcpu::AxVCpuExitReason::MmioRead {
153+
addr,
154+
width,
155+
reg,
156+
reg_width,
157+
signed_ext,
158+
} => {
159+
debug!("vCPU {:#x} MMIO read at addr {:#x}", self.mpidr_el1, addr);
160+
161+
let val = vm.handle_mmio_read(addr, width);
162+
163+
if let Some(val) = val {
164+
debug!(
165+
"vCPU {:#x} MMIO read returned value {:#x}",
166+
self.mpidr_el1, val
167+
);
168+
169+
self.vcpu.set_gpr(reg, val);
170+
} else {
171+
// TODO handle MMIO read failure
172+
warn!(
173+
"vCPU {:#x} MMIO read failed at addr {:#x}",
174+
self.mpidr_el1, addr
175+
);
176+
}
177+
}
178+
arm_vcpu::AxVCpuExitReason::MmioWrite { addr, width, data } => {
179+
debug!("vCPU {:#x} MMIO write at addr {:#x}", self.mpidr_el1, addr);
180+
let res = vm.handle_mmio_write(addr, width, data as _);
181+
if res.is_none() {
182+
warn!(
183+
"vCPU {:#x} MMIO write failed at addr {:#x}",
184+
self.mpidr_el1, addr
185+
);
186+
}
187+
}
188+
arm_vcpu::AxVCpuExitReason::SysRegRead { addr, reg } => {
189+
todo!()
190+
}
191+
arm_vcpu::AxVCpuExitReason::SysRegWrite { addr, value } => todo!(),
192+
arm_vcpu::AxVCpuExitReason::ExternalInterrupt => {
193+
axhal::irq::irq_handler(0);
194+
}
195+
arm_vcpu::AxVCpuExitReason::CpuUp {
196+
target_cpu,
197+
entry_point,
198+
arg,
199+
} => {
200+
debug!("vCPU {:#x} requested CPU {} up", self.mpidr_el1, target_cpu);
201+
vm.cpu_up(CpuHardId::new(target_cpu as _), entry_point, arg as _)?;
202+
self.vcpu.set_gpr(0, 0);
203+
}
204+
arm_vcpu::AxVCpuExitReason::CpuDown { _state } => todo!(),
205+
arm_vcpu::AxVCpuExitReason::SystemDown => {
206+
info!("vCPU {:#x} requested system shutdown", self.mpidr_el1);
207+
// self.vm()?.stop()?;
208+
vm.set_exit(None);
209+
}
210+
arm_vcpu::AxVCpuExitReason::Nothing => {}
211+
arm_vcpu::AxVCpuExitReason::SendIPI {
212+
target_cpu,
213+
target_cpu_aux,
214+
send_to_all,
215+
send_to_self,
216+
vector,
217+
} => todo!(),
218+
_ => todo!(),
219+
}
220+
}
221+
222+
Ok(())
223+
}
224+
225+
fn set_boot_info(&mut self, info: &crate::vcpu::CpuBootInfo) -> anyhow::Result<()> {
226+
self.vcpu
227+
.set_entry(info.kernel_entry.as_usize().into())
228+
.map_err(|e| anyhow!("Failed to set entry {e}"))?;
229+
self.vcpu
230+
.set_dtb_addr(info.dtb_addr.as_usize().into())
231+
.map_err(|e| anyhow!("Failed to set dtb addr {e}"))?;
232+
self.vcpu.pt_level = info.pt_levels;
233+
self.vcpu.pa_bits = info.pa_bits;
234+
235+
let setup_config = Aarch64VCpuSetupConfig {
236+
passthrough_interrupt: info.irq_mode == axvmconfig::VMInterruptMode::Passthrough,
237+
passthrough_timer: info.irq_mode == axvmconfig::VMInterruptMode::Passthrough,
238+
};
239+
240+
self.vcpu
241+
.setup(setup_config)
242+
.map_err(|e| anyhow!("Failed to setup vCPU : {e:?}"))?;
243+
244+
// Set EPT root
245+
self.vcpu
246+
.set_ept_root(info.gpt_root.as_usize().into())
247+
.map_err(|e| anyhow!("Failed to set EPT root for vCPU : {e:?}"))?;
248+
249+
if let Some(arg) = info.secondary_boot_arg {
250+
self.vcpu.set_gpr(0, arg);
251+
}
252+
253+
self.boot = Some(info.clone());
254+
Ok(())
255+
}
256+
257+
fn get_boot_info(&self) -> crate::vcpu::CpuBootInfo {
258+
self.boot.as_ref().unwrap().clone()
259+
}
260+
261+
type PLAT = PlatData;
262+
263+
fn setup_plat(&mut self, plat: &Self::PLAT) -> anyhow::Result<()> {
264+
todo!()
265+
}
266+
}
267+
268+
impl Debug for CPUState {
269+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
270+
f.debug_struct("VCpu").field("vcpu", &self.vcpu).finish()
271+
}
272+
}

0 commit comments

Comments
 (0)