Skip to content

Commit e8a7fea

Browse files
committed
更新 Cargo.toml,添加新的依赖项并调整现有依赖项;重构 vhal 模块,新增定时器功能并移除旧的 vhal 实现
1 parent f14b41c commit e8a7fea

File tree

6 files changed

+242
-74
lines changed

6 files changed

+242
-74
lines changed

Cargo.toml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,18 @@ anyhow = {version = "1.0", default-features = false}
1515
cfg-if = "1.0"
1616
log = "0.4"
1717
spin = "0.10"
18-
axhal.workspace = true
19-
axruntime.workspace = true
18+
timer_list = "0.1"
2019
fdt-parser = "0.5"
20+
lazyinit = "0.2"
2121

2222
# System independent crates provided by ArceOS.
2323
axerrno = "0.1.0"
2424
cpumask = "0.1.0"
25-
# kspin = "0.1.0"
25+
kspin = "0.1"
2626
memory_addr = "0.4"
2727
page_table_entry = {version = "0.5", features = ["arm-el2"]}
2828
page_table_multiarch = "0.5"
29-
# percpu = {version = "0.2.0", features = ["arm-el2"]}
29+
percpu = {version = "0.2", features = ["arm-el2"]}
3030

3131
# System dependent modules provided by ArceOS-Hypervisor.
3232
axaddrspace = "0.2"
@@ -35,6 +35,12 @@ axaddrspace = "0.2"
3535
# axvcpu = "0.1"
3636
axvmconfig = {version = "0.1", default-features = false}
3737

38+
axhal.workspace = true
39+
axruntime.workspace = true
40+
axtask.workspace = true
41+
42+
43+
3844
[target.'cfg(target_arch = "x86_64")'.dependencies]
3945
# x86_vcpu = "0.1"
4046

src/arch/aarch64/cpu.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,5 @@ struct PreCpu;
1111

1212
pub fn init() -> anyhow::Result<()> {
1313
PRE_CPU.init();
14-
todo!();
1514
Ok(())
1615
}

src/lib.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,30 @@
99
//! This crate contains:
1010
//! - [`AxVM`]: The main structure representing a VM.
1111
12+
#[macro_use]
1213
extern crate alloc;
1314
#[macro_use]
1415
extern crate log;
16+
#[macro_use]
17+
extern crate anyhow;
18+
19+
const TASK_STACK_SIZE: usize = 0x4000; // 16KB
1520

1621
#[cfg_attr(target_arch = "aarch64", path = "arch/aarch64/mod.rs")]
1722
#[cfg_attr(target_arch = "x86_64", path = "arch/x86_64/mod.rs")]
1823
pub mod arch;
1924

2025
mod fdt;
21-
2226
mod vcpu;
2327
mod vm;
2428

2529
pub mod config;
2630
pub mod vhal;
2731

28-
use anyhow::bail;
29-
3032

3133
pub fn enable_viretualization() -> anyhow::Result<()> {
3234
vhal::init()?;
35+
36+
panic!();
3337
Ok(())
3438
}

src/vhal.rs

Lines changed: 0 additions & 66 deletions
This file was deleted.

src/vhal/mod.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
use core::{
2+
cell::UnsafeCell,
3+
sync::atomic::{AtomicUsize, Ordering},
4+
};
5+
6+
use alloc::{collections::btree_map::BTreeMap, vec::Vec};
7+
use axtask::AxCpuMask;
8+
9+
use crate::{
10+
TASK_STACK_SIZE,
11+
arch::{self, Hal},
12+
};
13+
14+
mod timer;
15+
16+
pub fn init() -> anyhow::Result<()> {
17+
Hal::init();
18+
19+
static CORES: AtomicUsize = AtomicUsize::new(0);
20+
21+
let cpu_count = cpu_count();
22+
23+
info!("Initializing VHal for {cpu_count} CPUs...");
24+
25+
for cpu_id in 0..cpu_count {
26+
let _handle = axtask::spawn_raw(
27+
move || {
28+
info!("Core {cpu_id} is initializing hardware virtualization support...");
29+
// Initialize cpu affinity here.
30+
assert!(
31+
axtask::set_current_affinity(AxCpuMask::one_shot(cpu_id)),
32+
"Initialize CPU affinity failed!"
33+
);
34+
info!("Enabling hardware virtualization support on core {cpu_id}");
35+
timer::init_percpu();
36+
37+
let _ = CORES.fetch_add(1, Ordering::Release);
38+
},
39+
format!("init-cpu-{}", cpu_id),
40+
TASK_STACK_SIZE,
41+
);
42+
}
43+
info!("Waiting for all cores to enable hardware virtualization...");
44+
45+
// Wait for all cores to enable virtualization.
46+
while CORES.load(Ordering::Acquire) != cpu_count {
47+
// Use `yield_now` instead of `core::hint::spin_loop` to avoid deadlock.
48+
axtask::yield_now();
49+
}
50+
51+
info!("All cores have enabled hardware virtualization support.");
52+
Ok(())
53+
}
54+
55+
pub fn cpu_count() -> usize {
56+
axruntime::cpu_count()
57+
}
58+
59+
pub(crate) trait ArchHal {
60+
fn init() -> anyhow::Result<()>;
61+
fn cpu_list() -> Vec<CpuHardId>;
62+
fn current_enable_viretualization() -> anyhow::Result<()>;
63+
}
64+
65+
pub fn current_enable_viretualization() -> anyhow::Result<()> {
66+
Hal::current_enable_viretualization()
67+
}
68+
69+
pub(crate) struct PreCpuSet<T>(UnsafeCell<BTreeMap<usize, Option<T>>>);
70+
71+
unsafe impl<T> Sync for PreCpuSet<T> {}
72+
unsafe impl<T> Send for PreCpuSet<T> {}
73+
74+
impl<T> PreCpuSet<T> {
75+
pub const fn new() -> Self {
76+
PreCpuSet(UnsafeCell::new(BTreeMap::new()))
77+
}
78+
79+
unsafe fn set(&self, cpu_id: usize, val: T) {
80+
let pre_cpu_map = unsafe { &mut *self.0.get() };
81+
pre_cpu_map.insert(cpu_id, Some(val));
82+
}
83+
84+
pub fn get(&self, cpu_id: usize) -> Option<&T> {
85+
let pre_cpu_map = unsafe { &*self.0.get() };
86+
let v = pre_cpu_map.get(&cpu_id)?;
87+
Some(v.as_ref().expect("init not called"))
88+
}
89+
90+
pub fn init(&self) {
91+
let cpu_list = Hal::cpu_list();
92+
debug!("Initializing PreCpuSet for CPUs: {:?}", cpu_list);
93+
for cpu_id in cpu_list {
94+
let v = unsafe { &mut *self.0.get() };
95+
v.insert(cpu_id.raw(), None);
96+
}
97+
}
98+
}
99+
100+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
101+
#[repr(transparent)]
102+
pub struct CpuHardId(usize);
103+
104+
impl CpuHardId {
105+
pub fn new(id: usize) -> Self {
106+
CpuHardId(id)
107+
}
108+
109+
pub fn raw(&self) -> usize {
110+
self.0
111+
}
112+
}

src/vhal/timer.rs

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
use core::sync::atomic::AtomicUsize;
2+
use core::sync::atomic::Ordering;
3+
4+
use axhal;
5+
6+
use alloc::boxed::Box;
7+
use kspin::SpinNoIrq;
8+
use lazyinit::LazyInit;
9+
use timer_list::{TimeValue, TimerEvent, TimerList};
10+
11+
static TOKEN: AtomicUsize = AtomicUsize::new(0);
12+
// const PERIODIC_INTERVAL_NANOS: u64 = axhal::time::NANOS_PER_SEC / axconfig::TICKS_PER_SEC as u64;
13+
14+
/// Represents a timer event in the virtual machine monitor (VMM).
15+
///
16+
/// This struct holds a unique token for the timer and a callback function
17+
/// that will be executed when the timer expires.
18+
pub struct VmmTimerEvent {
19+
// Unique identifier for the timer event
20+
token: usize,
21+
// Callback function to be executed when the timer expires
22+
timer_callback: Box<dyn FnOnce(TimeValue) + Send + 'static>,
23+
}
24+
25+
impl VmmTimerEvent {
26+
fn new<F>(token: usize, f: F) -> Self
27+
where
28+
F: FnOnce(TimeValue) + Send + 'static,
29+
{
30+
Self {
31+
token,
32+
timer_callback: Box::new(f),
33+
}
34+
}
35+
}
36+
37+
impl TimerEvent for VmmTimerEvent {
38+
fn callback(self, now: TimeValue) {
39+
(self.timer_callback)(now)
40+
}
41+
}
42+
43+
#[percpu::def_percpu]
44+
static TIMER_LIST: LazyInit<SpinNoIrq<TimerList<VmmTimerEvent>>> = LazyInit::new();
45+
46+
/// Registers a new timer that will execute at the specified deadline
47+
///
48+
/// # Arguments
49+
/// - `deadline`: The absolute time in nanoseconds when the timer should trigger
50+
/// - `handler`: The callback function to execute when the timer expires
51+
///
52+
/// # Returns
53+
/// A unique token that can be used to cancel this timer later
54+
pub fn register_timer<F>(deadline: u64, handler: F) -> usize
55+
where
56+
F: FnOnce(TimeValue) + Send + 'static,
57+
{
58+
trace!("Registering timer...");
59+
trace!(
60+
"deadline is {:#?} = {:#?}",
61+
deadline,
62+
TimeValue::from_nanos(deadline)
63+
);
64+
let timer_list = unsafe { TIMER_LIST.current_ref_mut_raw() };
65+
let mut timers = timer_list.lock();
66+
let token = TOKEN.fetch_add(1, Ordering::Release);
67+
let event = VmmTimerEvent::new(token, handler);
68+
timers.set(TimeValue::from_nanos(deadline), event);
69+
token
70+
}
71+
72+
/// Cancels a timer with the specified token.
73+
///
74+
/// # Parameters
75+
/// - `token`: The unique token of the timer to cancel.
76+
pub fn cancel_timer(token: usize) {
77+
let timer_list = unsafe { TIMER_LIST.current_ref_mut_raw() };
78+
let mut timers = timer_list.lock();
79+
timers.cancel(|event| event.token == token);
80+
}
81+
82+
/// Check and process any pending timer events
83+
pub fn check_events() {
84+
// info!("Checking timer events...");
85+
// info!("now is {:#?}", axhal::time::wall_time());
86+
let timer_list = unsafe { TIMER_LIST.current_ref_mut_raw() };
87+
loop {
88+
let now = axhal::time::wall_time();
89+
let event = timer_list.lock().expire_one(now);
90+
if let Some((_deadline, event)) = event {
91+
trace!("pick one {_deadline:#?} to handle!!!");
92+
event.callback(now);
93+
} else {
94+
break;
95+
}
96+
}
97+
}
98+
99+
// /// Schedule the next timer event based on the periodic interval
100+
// pub fn scheduler_next_event() {
101+
// trace!("Scheduling next event...");
102+
// let now_ns = axhal::time::monotonic_time_nanos();
103+
// let deadline = now_ns + PERIODIC_INTERVAL_NANOS;
104+
// debug!("PHY deadline {} !!!", deadline);
105+
// axhal::time::set_oneshot_timer(deadline);
106+
// }
107+
108+
/// Initialize the hypervisor timer system
109+
pub fn init_percpu() {
110+
info!("Initing HV Timer...");
111+
let timer_list = unsafe { TIMER_LIST.current_ref_mut_raw() };
112+
timer_list.init_once(SpinNoIrq::new(TimerList::new()));
113+
}

0 commit comments

Comments
 (0)