mod create;
mod device;
mod parser;
mod print;
mod vm_fdt;
use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use ax_lazyinit::LazyInit;
use axvm::config::{AxVMConfig, AxVMCrateConfig};
use fdt_parser::Fdt;
use spin::Mutex;
pub use parser::*;
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
pub use create::update_fdt;
pub use device::build_all_node_paths;
#[cfg(any(target_arch = "aarch64", test))]
pub use device::build_node_path;
use crate::vmm::config::{config, get_vm_dtb_arc};
static GENERATED_DTB_CACHE: LazyInit<Mutex<BTreeMap<usize, Vec<u8>>>> = LazyInit::new();
pub fn init_dtb_cache() {
GENERATED_DTB_CACHE.init_once(Mutex::new(BTreeMap::new()));
}
pub fn dtb_cache() -> &'static Mutex<BTreeMap<usize, Vec<u8>>> {
GENERATED_DTB_CACHE.get().unwrap()
}
pub fn crate_guest_fdt_with_cache(dtb_data: Vec<u8>, crate_config: &AxVMCrateConfig) {
let mut cache_lock = dtb_cache().lock();
cache_lock.insert(crate_config.base.id, dtb_data);
}
pub fn handle_fdt_operations(vm_config: &mut AxVMConfig, vm_create_config: &mut AxVMCrateConfig) {
let host_fdt_bytes = get_host_fdt();
let host_fdt = Fdt::from_bytes(host_fdt_bytes)
.map_err(|e| format!("Failed to parse FDT: {e:#?}"))
.expect("Failed to parse FDT");
set_phys_cpu_sets(vm_config, &host_fdt, vm_create_config);
if let Some(provided_dtb) = get_developer_provided_dtb(vm_config, vm_create_config) {
info!("VM[{}] found DTB , parsing...", vm_config.id());
update_provided_fdt(&provided_dtb, host_fdt_bytes, vm_create_config);
} else {
info!(
"VM[{}] DTB not found, generating based on the configuration file.",
vm_config.id()
);
setup_guest_fdt_from_vmm(host_fdt_bytes, vm_config, vm_create_config);
}
if let Some(dtb_arc) = get_vm_dtb_arc(vm_config) {
let dtb = dtb_arc.as_ref();
parse_reserved_memory_regions(vm_create_config, dtb);
parse_passthrough_devices_address(vm_config, vm_create_config, dtb);
#[cfg(target_arch = "aarch64")]
parse_vm_interrupt(vm_config, dtb);
} else {
error!(
"VM[{}] DTB not found in memory, skipping...",
vm_config.id()
);
}
}
pub fn get_developer_provided_dtb(
vm_cfg: &AxVMConfig,
crate_config: &AxVMCrateConfig,
) -> Option<Vec<u8>> {
match crate_config.kernel.image_location.as_deref() {
Some("memory") => {
let vm_imags = config::get_memory_images()
.iter()
.find(|&v| v.id == vm_cfg.id())?;
if let Some(dtb) = vm_imags.dtb {
info!("DTB file in memory, size: 0x{:x}", dtb.len());
return Some(dtb.to_vec());
}
}
#[cfg(feature = "fs")]
Some("fs") => {
use ax_errno::ax_err_type;
use std::io::{BufReader, Read};
if let Some(dtb_path) = &crate_config.kernel.dtb_path {
let (dtb_file, dtb_size) =
crate::vmm::images::fs::open_image_file(dtb_path).unwrap();
info!("DTB file in fs, size: 0x{:x}", dtb_size);
let mut file = BufReader::new(dtb_file);
let mut dtb_buffer = vec![0; dtb_size];
file.read_exact(&mut dtb_buffer)
.map_err(|err| {
ax_err_type!(
Io,
format!("Failed in reading from file {}, err {:?}", dtb_path, err)
)
})
.unwrap();
return Some(dtb_buffer);
}
}
_ => unimplemented!(
"Check your \"image_location\" in config.toml, \"memory\" and \"fs\" are supported,\n."
),
}
None
}