mod hvc;
mod ivc;
pub mod config;
pub mod images;
pub mod timer;
pub mod vcpus;
pub mod vm_list;
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
pub mod fdt;
use core::sync::atomic::{AtomicUsize, Ordering};
use std::os::arceos::{
api::task::{self, AxWaitQueueHandle},
modules::ax_task,
};
use ax_errno::{AxResult, ax_err_type};
use crate::task::AsVCpuTask;
pub use timer::init_percpu as init_timer_percpu;
pub type VM = axvm::AxVM;
pub type VMRef = axvm::AxVMRef;
pub type VCpuRef = axvm::AxVCpuRef;
static VMM: AxWaitQueueHandle = AxWaitQueueHandle::new();
static RUNNING_VM_COUNT: AtomicUsize = AtomicUsize::new(0);
pub fn init() {
info!("Initializing VMM...");
config::init_guest_vms();
info!("Setting up vcpus...");
for vm in vm_list::get_vm_list() {
vcpus::setup_vm_primary_vcpu(vm);
}
}
pub fn start() {
info!("VMM starting, booting VMs...");
for vm in vm_list::get_vm_list() {
match vm.boot() {
Ok(_) => {
vcpus::notify_primary_vcpu(vm.id());
RUNNING_VM_COUNT.fetch_add(1, Ordering::Release);
info!("VM[{}] boot success", vm.id())
}
Err(err) => warn!("VM[{}] boot failed, error {:?}", vm.id(), err),
}
}
task::ax_wait_queue_wait_until(
&VMM,
|| {
let vm_count = RUNNING_VM_COUNT.load(Ordering::Acquire);
info!("a VM exited, current running VM count: {vm_count}");
vm_count == 0
},
None,
);
}
#[allow(unused_imports)]
pub use vcpus::with_vcpu_task;
pub fn with_vm<T>(vm_id: usize, f: impl FnOnce(VMRef) -> T) -> Option<T> {
let vm = vm_list::get_vm_by_id(vm_id)?;
Some(f(vm))
}
pub fn with_vm_and_vcpu<T>(
vm_id: usize,
vcpu_id: usize,
f: impl FnOnce(VMRef, VCpuRef) -> T,
) -> Option<T> {
let vm = vm_list::get_vm_by_id(vm_id)?;
let vcpu = vm.vcpu(vcpu_id)?;
Some(f(vm, vcpu))
}
pub fn with_vm_and_vcpu_on_pcpu(
vm_id: usize,
vcpu_id: usize,
f: impl FnOnce(VMRef, VCpuRef) + 'static,
) -> AxResult {
let guard = ax_kernel_guard::NoPreemptIrqSave::new();
let current_vm = ax_task::current().as_vcpu_task().vm().id();
let current_vcpu = ax_task::current().as_vcpu_task().vcpu.id();
if current_vm == vm_id && current_vcpu == vcpu_id {
with_vm_and_vcpu(vm_id, vcpu_id, f).unwrap(); return Ok(());
}
drop(guard);
let _pcpu_id = vcpus::with_vcpu_task(vm_id, vcpu_id, |task| task.cpu_id())
.ok_or_else(|| ax_err_type!(NotFound))?;
unimplemented!();
}
pub fn add_running_vm_count(count: usize) {
RUNNING_VM_COUNT.fetch_add(count, Ordering::Release);
}
pub fn sub_running_vm_count(count: usize) {
RUNNING_VM_COUNT.fetch_sub(count, Ordering::Release);
}