From e1f628eab22c9a4dc64dda7cbcb681275a6daa32 Mon Sep 17 00:00:00 2001 From: szy Date: Wed, 17 Sep 2025 09:58:25 +0800 Subject: [PATCH 01/30] init --- Cargo.lock | 1 - src/vmm/config.rs | 28 +++ src/vmm/fdt.rs | 97 --------- src/vmm/fdt/create.rs | 241 +++++++++++++++++++++ src/vmm/fdt/device.rs | 483 ++++++++++++++++++++++++++++++++++++++++++ src/vmm/fdt/mod.rs | 14 ++ src/vmm/fdt/parser.rs | 119 +++++++++++ src/vmm/fdt/test.rs | 129 +++++++++++ src/vmm/images/mod.rs | 49 +---- src/vmm/mod.rs | 4 +- 10 files changed, 1024 insertions(+), 141 deletions(-) delete mode 100644 src/vmm/fdt.rs create mode 100644 src/vmm/fdt/create.rs create mode 100644 src/vmm/fdt/device.rs create mode 100644 src/vmm/fdt/mod.rs create mode 100644 src/vmm/fdt/parser.rs create mode 100644 src/vmm/fdt/test.rs diff --git a/Cargo.lock b/Cargo.lock index df99e246..dff00be6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -984,7 +984,6 @@ dependencies = [ [[package]] name = "axvm" version = "0.1.0" -source = "git+https://github.com/arceos-hypervisor/axvm.git?branch=next#b4f561f568536078b02a58572cae5f442102782c" dependencies = [ "arm_vcpu", "arm_vgic 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/vmm/config.rs b/src/vmm/config.rs index 3f5bb196..0efcd7df 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -201,6 +201,33 @@ pub fn init_guest_vms() { let mut vm_config = AxVMConfig::from(vm_create_config.clone()); + // info!("vm_create_config: {:#?}", vm_create_config); + // info!("before parse_vm_dtb, crate VM[{}] with config: {:#?}", vm_config.id(), vm_config); + + // let bootarg: usize = unsafe { std::os::arceos::modules::axhal::get_bootarg() }; + // if bootarg != 0 { + // crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config); + // } + if let Some(dtb) = get_vm_dtb(&vm_config) { + info!("VM[{}] found DTB , parsing...", vm_config.id()); + + // crate::vmm::fdt::parse_vm_fdt(&mut vm_config, dtb); + //test + let bootarg = dtb.as_ptr() as usize; + crate::vmm::fdt::print_fdt(bootarg); + crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config); + //test + + + } else { + info!("VM[{}] DTB not found, generating based on the configuration file.", vm_config.id()); + + let bootarg: usize = std::os::arceos::modules::axhal::get_bootarg(); + if bootarg != 0 { + crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config); + } + } + // Overlay VM config with the given DTB. if let Some(dtb) = get_vm_dtb(&vm_config) { parse_vm_dtb(&mut vm_config, dtb); @@ -211,6 +238,7 @@ pub fn init_guest_vms() { ); } + // info!("after parse_vm_dtb, crate VM[{}] with config: {:#?}", vm_config.id(), vm_config); info!("Creating VM[{}] {:?}", vm_config.id(), vm_config.name()); // Create VM. diff --git a/src/vmm/fdt.rs b/src/vmm/fdt.rs deleted file mode 100644 index 2dd0e338..00000000 --- a/src/vmm/fdt.rs +++ /dev/null @@ -1,97 +0,0 @@ -use core::ptr::NonNull; - -use crate::vmm::{VMRef, images::load_vm_image_from_memory}; -use alloc::vec::Vec; -use axaddrspace::GuestPhysAddr; -use axvm::VMMemoryRegion; -use fdt_parser::Fdt; -use vm_fdt::{FdtWriter, FdtWriterNode}; - -#[allow(dead_code)] -pub fn print_fdt(fdt_addr: NonNull) { - let fdt = Fdt::from_ptr(fdt_addr) - .map_err(|e| format!("Failed to parse FDT: {e:#?}")) - .expect("Failed to parse FDT"); - - for rsv in fdt.memory_reservation_block() { - info!( - "Reserved memory: addr={:#p}, size={:#x}", - rsv.address, rsv.size - ); - } - - for node in fdt.all_nodes() { - info!("node.name: {}", node.name()); - for prop in node.propertys() { - info!("prop.name: {}, node.name: {}", prop.name, node.name()); - } - } -} - -pub fn updated_fdt(dest_addr: GuestPhysAddr, fdt_src: NonNull, dtb_size: usize, vm: VMRef) { - let mut new_fdt = FdtWriter::new().unwrap(); - let mut old_node_level = 0; - let mut child_node: Vec = Vec::new(); - - let fdt_bytes = unsafe { core::slice::from_raw_parts(fdt_src.as_ptr(), dtb_size) }; - let fdt = Fdt::from_bytes(fdt_bytes) - .map_err(|e| format!("Failed to parse FDT: {e:#?}")) - .expect("Failed to parse FDT"); - - for node in fdt.all_nodes() { - if node.name() == "/" { - child_node.push(new_fdt.begin_node("").unwrap()); - } else if node.name().starts_with("memory") { - // Skip memory nodes, will add them later - continue; - } else { - if node.level <= old_node_level { - for _ in node.level..=old_node_level { - let end_node = child_node.pop().unwrap(); - new_fdt.end_node(end_node).unwrap(); - } - } - child_node.push(new_fdt.begin_node(node.name()).unwrap()); - } - - old_node_level = node.level; - - for prop in node.propertys() { - new_fdt.property(prop.name, prop.raw_value()).unwrap(); - } - } - while let Some(node) = child_node.pop() { - old_node_level -= 1; - new_fdt.end_node(node).unwrap(); - - // add memory node - if old_node_level == 1 { - let memory_regions = vm.memory_regions(); - info!("Adding memory node with regions: {:?}", memory_regions); - let memory_node = new_fdt.begin_node("memory").unwrap(); - add_memory_node(&memory_regions, &mut new_fdt); - new_fdt.end_node(memory_node).unwrap(); - } - } - assert_eq!(old_node_level, 0); - let new_fdt = new_fdt.finish().unwrap(); - // print_fdt(NonNull::new(new_fdt.as_ptr() as usize as _).unwrap()); - load_vm_image_from_memory(&new_fdt, dest_addr, vm.clone()).expect("Failed to load VM images"); -} - -fn add_memory_node(new_memory: &[VMMemoryRegion], new_fdt: &mut FdtWriter) { - let mut new_value: Vec = Vec::new(); - for mem in new_memory { - let gpa = mem.gpa.as_usize() as u64; - let size = mem.size() as u64; - new_value.push((gpa >> 32) as u32); - new_value.push((gpa & 0xFFFFFFFF) as u32); - new_value.push((size >> 32) as u32); - new_value.push((size & 0xFFFFFFFF) as u32); - } - info!("new_value: {:#x?}", new_value); - new_fdt - .property_array_u32("reg", new_value.as_ref()) - .unwrap(); - new_fdt.property_string("device_type", "memory").unwrap(); -} diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs new file mode 100644 index 00000000..df206098 --- /dev/null +++ b/src/vmm/fdt/create.rs @@ -0,0 +1,241 @@ +use alloc::string::String; +use alloc::string::ToString; +use alloc::vec::Vec; +use fdt_parser::{Fdt, Node}; +use vm_fdt::{FdtWriter, FdtWriterNode}; +use axvm::config::AxVMConfig; + + +pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, vm_cfg: &AxVMConfig) { + let mut fdt_writer = FdtWriter::new().unwrap(); + // 跟踪上一个处理节点的层级,用于层级变化处理 + let mut previous_node_level = 0; + // 维护FDT节点栈,用于正确开始和结束节点 + let mut node_stack: Vec = Vec::new(); + let phys_cpu_ids = get_phys_cpu_ids(vm_cfg); + + let all_nodes: Vec = fdt.all_nodes().collect(); + + for (index, node) in all_nodes.iter().enumerate() { + // 使用独立函数构建节点路径 + let node_path = super::build_node_path(&all_nodes, index); + // 处理不同类型的节点 + let node_action = determine_node_action( + node, + &node_path, + passthrough_device_names, + ); + + match node_action { + NodeAction::RootNode => { + node_stack.push(fdt_writer.begin_node("").unwrap()); + }, + NodeAction::CpuNode => { + let need = need_cpu_node(&phys_cpu_ids, node, &node_path); + if need { + handle_node_level_change(&mut fdt_writer, &mut node_stack, node.level, previous_node_level); + node_stack.push(fdt_writer.begin_node(node.name()).unwrap()); + } else { + continue; + } + }, + NodeAction::Skip => { + // 不需要包含在客户机FDT中的节点 + continue; + }, + _ => { + // 完全匹配的直通设备节点 + trace!("Found exact passthrough device node: {}, path: {}", node.name(), node_path); + handle_node_level_change(&mut fdt_writer, &mut node_stack, node.level, previous_node_level); + node_stack.push(fdt_writer.begin_node(node.name()).unwrap()); + }, + } + + previous_node_level = node.level; + + // 复制节点的所有属性 + for prop in node.propertys() { + fdt_writer.property(prop.name, prop.raw_value()).unwrap(); + } + } + + // 结束所有未关闭的节点 + while let Some(node) = node_stack.pop() { + previous_node_level -= 1; + fdt_writer.end_node(node).unwrap(); + + // add memory node + if previous_node_level == 1 { + info!("Adding memory node with regions: {:x?}", vm_cfg.memory_regions()); + let memory_node = fdt_writer.begin_node("memory").unwrap(); + add_memory_node(vm_cfg, &mut fdt_writer); + fdt_writer.end_node(memory_node).unwrap(); + } + } + assert_eq!(previous_node_level , 0); + + + use std::io::Write; + use std::fs::File; + let guest_fdt_bytes = fdt_writer.finish().unwrap(); + let mut file = File::create("guest_fdt.dtb").expect("Failed to create file"); + file.write_all(&guest_fdt_bytes).unwrap(); +} + +/// 节点处理动作枚举 +enum NodeAction { + /// 跳过节点,不包含在客户机FDT中 + Skip, + /// 根节点 + RootNode, + /// cpu节点 + CpuNode, + /// 包含节点作为直通设备节点 + IncludeAsPassthroughDevice, + /// 包含节点作为直通设备的子节点 + IncludeAsChildNode, + /// 包含节点作为直通设备的祖先节点 + IncludeAsAncestorNode, +} + +/// 确定节点的处理动作 +fn determine_node_action( + node: &Node, + node_path: &str, + passthrough_device_names: &Vec, +) -> NodeAction { + if node.name() == "/" { + // 根节点特殊处理 + return NodeAction::RootNode; + } else if node.name().starts_with("memory") { + // 跳过memory节点,稍后会单独添加 + return NodeAction::Skip; + } else if node_path.starts_with("/cpus"){ + return NodeAction::CpuNode; + } else if passthrough_device_names.contains(&node_path.to_string()) { + // 完全匹配的直通设备节点 + return NodeAction::IncludeAsPassthroughDevice; + } + // 检查是否为直通设备的后代节点(通过路径包含关系和层级验证) + else if is_descendant_of_passthrough_device(node_path, node.level, passthrough_device_names) { + return NodeAction::IncludeAsChildNode; + } + // 检查是否为直通设备的祖先节点(通过路径包含关系和层级验证) + else if is_ancestor_of_passthrough_device(node_path, passthrough_device_names) { + return NodeAction::IncludeAsAncestorNode; + } else { + return NodeAction::Skip; + } +} + +/// 判断节点是否为直通设备的后代节点 +/// 当节点路径包含passthrough_device_names中某个节点路径,且比其长时,即为其后代节点 +/// 同时使用node_level作为验证条件 +fn is_descendant_of_passthrough_device(node_path: &str, node_level: usize, passthrough_device_names: &Vec) -> bool { + for passthrough_path in passthrough_device_names { + // 检查当前节点是否为直通设备的后代节点 + if node_path.starts_with(passthrough_path) && node_path.len() > passthrough_path.len() { + // 确保是真正的后代路径(以/分隔) + if passthrough_path == "/" || node_path.chars().nth(passthrough_path.len()) == Some('/') { + // 使用层级关系进行验证:后代节点的层级应该比父节点高 + // 注意:根节点的层级为1,其直接子节点层级为2,以此类推 + let expected_parent_level = passthrough_path.matches('/').count(); + let current_node_level = node_level; + + // 如果passthrough_path是根节点"/",则其子节点层级应为2 + // 否则,子节点层级应比父节点层级高 + if passthrough_path == "/" && current_node_level >= 2 { + return true; + } else if passthrough_path != "/" && current_node_level > expected_parent_level { + return true; + } + } + } + } + false +} + +/// 处理节点层级变化,确保FDT结构正确 +fn handle_node_level_change( + fdt_writer: &mut FdtWriter, + node_stack: &mut Vec, + current_level: usize, + previous_level: usize, +) { + if current_level <= previous_level { + for _ in current_level..=previous_level { + if let Some(end_node) = node_stack.pop() { + fdt_writer.end_node(end_node).unwrap(); + } + } + } +} + +/// 判断节点是否为直通设备的祖先节点 +fn is_ancestor_of_passthrough_device(node_path: &str, passthrough_device_names: &Vec) -> bool { + for passthrough_path in passthrough_device_names { + // 检查当前节点是否为直通设备的祖先节点 + if passthrough_path.starts_with(&node_path) && passthrough_path.len() > node_path.len() { + // 确保是真正的祖先路径(以/分隔) + let next_char = passthrough_path.chars().nth(node_path.len()).unwrap_or(' '); + if next_char == '/' || node_path == "/" { + return true; + } + } + } + false +} + +fn add_memory_node(vm_cfg: &AxVMConfig, fdt_writer: &mut FdtWriter) { + let new_memory = vm_cfg.memory_regions(); + let mut new_value: Vec = Vec::new(); + for mem in new_memory { + let gpa = mem.gpa as u64; + let size = mem.size as u64; + new_value.push((gpa >> 32) as u32); + new_value.push((gpa & 0xFFFFFFFF) as u32); + new_value.push((size >> 32) as u32); + new_value.push((size & 0xFFFFFFFF) as u32); + } + debug!("new_value: {:#?}", new_value); + fdt_writer + .property_array_u32("reg", new_value.as_ref()) + .unwrap(); + fdt_writer + .property_string("device_type", "memory") + .unwrap(); +} + +fn need_cpu_node(phys_cpu_ids: &Vec, node: &Node, node_path: &str) -> bool{ + let mut should_include_node = false; + + if !node_path.starts_with("/cpus/cpu@") { + should_include_node = true; + } else { + if let Some(mut cpu_reg) = node.reg() { + if let Some(reg_entry) = cpu_reg.next() { + let cpu_address = reg_entry.address as usize; + debug!("Checking CPU node {} with address 0x{:x}", node.name(), cpu_address); + // 检查这个CPU地址是否在配置的phys_cpu_ids中 + if phys_cpu_ids.contains(&&cpu_address) { + should_include_node = true; + info!("CPU node {} with address 0x{:x} is in phys_cpu_ids, including in guest FDT", node.name(), cpu_address); + } else { + info!("CPU node {} with address 0x{:x} is NOT in phys_cpu_ids, skipping", node.name(), cpu_address); + } + } + } + } + should_include_node +} + +fn get_phys_cpu_ids(vm_cfg: &AxVMConfig) -> Vec { + let vcpu_mappings = vm_cfg.get_vcpu_affinities_pcpu_ids(); + debug!("vcpu_mappings: {:?}", vcpu_mappings); + + let mut phys_cpu_ids = Vec::new(); + for (_vcpu_id, _phys_cpu_set, phys_cpu_id) in vcpu_mappings { + phys_cpu_ids.push(phys_cpu_id); + } + phys_cpu_ids +} \ No newline at end of file diff --git a/src/vmm/fdt/device.rs b/src/vmm/fdt/device.rs new file mode 100644 index 00000000..93ff3b0a --- /dev/null +++ b/src/vmm/fdt/device.rs @@ -0,0 +1,483 @@ +//! Device passthrough and dependency analysis for FDT processing. + +use alloc::collections::{BTreeMap, BTreeSet}; +use alloc::string::String; +use alloc::string::ToString; +use alloc::vec::Vec; +use fdt_parser::{Fdt, Node}; +use axvm::config::{AxVMConfig}; + +/// 完善直通设备配置 +/// 修改为返回配置文件中所有直通设备和查找到的新添加设备的合集,而不是直接修改VM配置 +/// 优化版本:预构建节点缓存以提高性能 +pub fn find_all_passthrough_devices(vm_cfg: &mut AxVMConfig, fdt: &Fdt) -> Vec { + // 先获取初始设备数量,避免借用冲突 + let initial_device_count = vm_cfg.pass_through_devices().len(); + info!("Starting passthrough devices analysis..."); + info!( + "Original passthrough_devices count: {}", + initial_device_count + ); + + // 预构建节点缓存,将所有节点按路径存储以提高查找性能 + let node_cache: BTreeMap> = build_optimized_node_cache(fdt); + + + // 获取已配置设备的名称列表 + let initial_device_names: Vec = vm_cfg + .pass_through_devices() + .iter() + .map(|dev| dev.name.clone()) + .collect(); + + // 第一阶段:发现所有配置文件中直通设备的后代节点 + // 构建已配置设备的集合,使用BTreeSet提高查找效率 + let mut configured_device_names: BTreeSet = + initial_device_names.iter().cloned().collect(); + + // 用于存储新发现的相关设备名称 + let mut additional_device_names = Vec::new(); + + // 第一阶段:处理初始设备及其后代节点 + // 注意:这里我们直接使用设备路径而不是设备名称 + for device_name in &initial_device_names { + // 获取该设备的所有后代节点路径 + let descendant_paths = get_descendant_nodes_by_path(&node_cache, device_name); + trace!( + "Found {} descendant paths for {}", + descendant_paths.len(), + device_name + ); + + // 直接使用路径而不是通过节点获取路径 + for descendant_path in descendant_paths { + if !configured_device_names.contains(&descendant_path) { + trace!( + "Found descendant device: {}", + descendant_path + ); + configured_device_names.insert(descendant_path.clone()); + + // 收集后代节点路径 + additional_device_names.push(descendant_path.clone()); + } else { + trace!("Device already exists: {}", descendant_path); + } + } + } + + info!( + "Phase 1 completed: Found {} new descendant device names", + additional_device_names.len() + ); + + // 第二阶段:发现所有已有设备(包括后代设备)的依赖节点 + let mut dependency_device_names = Vec::new(); + // 使用设备名称的工作队列,包含初始设备和后代设备的名称 + let mut devices_to_process: Vec = configured_device_names.iter().cloned().collect(); + let mut processed_devices: BTreeSet = BTreeSet::new(); + + // 构建phandle映射表 + let phandle_map = build_phandle_map(fdt); + + // 使用工作队列递归查找所有依赖设备 + while let Some(device_node_path) = devices_to_process.pop() { + // 避免重复处理同一设备 + if processed_devices.contains(&device_node_path) { + continue; + } + processed_devices.insert(device_node_path.clone()); + + trace!("Analyzing dependencies for device: {}", device_node_path); + + // 查找当前设备的直接依赖 + let dependencies = find_device_dependencies(&device_node_path, &phandle_map, &node_cache); + trace!("Found {} dependencies: {:?}", dependencies.len(), dependencies); + for dep_node_name in dependencies { + // 检查依赖是否已经在配置中 + if !configured_device_names.contains(&dep_node_name) { + trace!("Found new dependency device: {}", dep_node_name); + dependency_device_names.push(dep_node_name.clone()); + + // 将依赖设备名称添加到工作队列中,以便进一步查找其依赖 + devices_to_process.push(dep_node_name.clone()); + configured_device_names.insert(dep_node_name.clone()); + } + } + } + + info!( + "Phase 2 completed: Found {} new dependency device names", + dependency_device_names.len() + ); + + // 合并所有设备名称列表 + let mut all_device_names = initial_device_names.clone(); + all_device_names.extend(additional_device_names); + all_device_names.extend(dependency_device_names); + + let final_device_count = all_device_names.len(); + info!( + "Passthrough devices analysis completed. Total devices: {} (added: {})", + final_device_count, + final_device_count - initial_device_count + ); + + // 打印最终的设备列表 + for (i, device_name) in all_device_names.iter().enumerate() { + trace!("Final passthrough device[{}]: {}", i, device_name); + } + + // 返回所有设备名称的合集 + all_device_names +} + +/// 根据节点的level关系构建节点的完整路径 +/// 通过遍历所有节点并根据level关系构建路径,避免同名节点路径冲突问题 +pub fn build_node_path(all_nodes: &Vec, target_index: usize) -> String { + // 用于维护路径栈 + let mut path_stack: Vec = Vec::new(); + + // 遍历从根节点到目标节点的所有节点 + for i in 0..=target_index { + let node = &all_nodes[i]; + let level = node.level; + + if level == 1 { + // 根节点特殊处理 + path_stack.clear(); + if node.name() != "/" { + path_stack.push(node.name().to_string()); + } + } else { + // 根据level关系处理节点 + while path_stack.len() >= level - 1 { + path_stack.pop(); + } + path_stack.push(node.name().to_string()); + } + } + + // 构建当前节点的完整路径 + if path_stack.is_empty() || (path_stack.len() == 1 && path_stack[0] == "/") { + "/".to_string() + } else { + "/".to_string() + &path_stack.join("/") + } +} + +/// 构建简化的节点缓存表,一次性遍历所有节点并按全路径分组 +/// 使用level关系直接构建路径,避免同名节点路径冲突问题 +pub fn build_optimized_node_cache<'a>(fdt: &'a Fdt) -> BTreeMap>> { + let mut node_cache: BTreeMap>> = BTreeMap::new(); + + // 收集所有节点 + let all_nodes: Vec = fdt.all_nodes().collect(); + + // 遍历所有节点,根据level关系构建路径 + for (index, node) in all_nodes.iter().enumerate() { + // 使用独立函数构建节点路径 + let node_path = build_node_path(&all_nodes, index); + + // 检查是否有相同的node_path,如果有则报错 + if let Some(existing_nodes) = node_cache.get(&node_path) { + if !existing_nodes.is_empty() { + error!( + "Duplicate node path found: {} for node '{}' at level {}, existing node: '{}'", + node_path, + node.name(), + node.level, + existing_nodes[0].name() + ); + } + } + + trace!("Adding node to cache: {} (level: {}, index: {})", node_path, node.level, index); + node_cache + .entry(node_path) + .or_insert_with(Vec::new) + .push(node.clone()); + } + + debug!( + "Built simplified node cache with {} unique device paths", + node_cache.len() + ); + node_cache +} + +/// 构建phandle到节点信息的映射表,优化版本使用fdt-parser的便利方法 +/// 使用完整路径而不是节点名称 +/// 使用level关系直接构建路径,避免同名节点路径冲突问题 +fn build_phandle_map(fdt: &Fdt) -> BTreeMap)> { + let mut phandle_map = BTreeMap::new(); + + // 收集所有节点 + let all_nodes: Vec = fdt.all_nodes().collect(); + + // 遍历所有节点,根据level关系构建路径 + for (index, node) in all_nodes.iter().enumerate() { + // 使用独立函数构建节点路径 + let node_path = build_node_path(&all_nodes, index); + + let mut phandle = None; + let mut cells_map = BTreeMap::new(); + + // 收集节点的属性 + for prop in node.propertys() { + match prop.name { + "phandle" | "linux,phandle" => { + phandle = Some(prop.u32()); + } + "#address-cells" + | "#size-cells" + | "#clock-cells" + | "#reset-cells" + | "#gpio-cells" + | "#interrupt-cells" + | "#power-domain-cells" + | "#thermal-sensor-cells" + | "#phy-cells" + | "#dma-cells" + | "#sound-dai-cells" + | "#mbox-cells" + | "#pwm-cells" + | "#iommu-cells" => { + cells_map.insert(prop.name.to_string(), prop.u32()); + } + _ => {} + } + } + + // 如果找到phandle,将其与节点完整路径一起存储 + if let Some(ph) = phandle { + phandle_map.insert(ph, (node_path, cells_map)); + } + } + phandle_map +} + +/// 根据#*-cells属性智能解析包含phandle引用的属性 +/// 支持多种格式: +/// - 单个phandle: +/// - phandle+specifier: +/// - 多个phandle引用: +fn parse_phandle_property_with_cells( + prop_data: &[u8], + prop_name: &str, + phandle_map: &BTreeMap)>, +) -> Vec<(u32, Vec)> { + let mut results = Vec::new(); + + debug!( + "Parsing property '{}' with cells info, data length: {} bytes", + prop_name, + prop_data.len() + ); + + // 检查数据长度是否有效 + if prop_data.is_empty() || prop_data.len() % 4 != 0 { + warn!( + "Property '{}' data length ({} bytes) is invalid", + prop_name, + prop_data.len() + ); + return results; + } + + let u32_values: Vec = prop_data + .chunks(4) + .map(|chunk| u32::from_be_bytes([chunk[0], chunk[1], chunk[2], chunk[3]])) + .collect(); + + let mut i = 0; + while i < u32_values.len() { + let potential_phandle = u32_values[i]; + + // 检查是否为有效的phandle + if let Some((device_name, cells_info)) = phandle_map.get(&potential_phandle) { + // 根据属性名确定需要的cells数量 + let cells_count = get_cells_count_for_property(prop_name, cells_info); + trace!( + "Property '{}' requires {} cells for device '{}'", + prop_name, cells_count, device_name + ); + + // 检查是否有足够的数据 + if i + cells_count < u32_values.len() { + let specifiers: Vec = u32_values[i + 1..=i + cells_count].to_vec(); + debug!( + "Parsed phandle reference: phandle={:#x}, specifiers={:?}", + potential_phandle, specifiers + ); + results.push((potential_phandle, specifiers)); + i += cells_count + 1; // 跳过phandle和所有specifier + } else { + warn!( + "Property:{} not enough data for phandle {:#x}, expected {} cells but only {} values remaining", + prop_name, + potential_phandle, + cells_count, + u32_values.len() - i - 1 + ); + break; + } + } else { + // 如果不是有效phandle,跳过这个值 + i += 1; + } + } + + results +} + +/// 根据属性名和目标节点的cells信息确定需要的cells数量 +fn get_cells_count_for_property(prop_name: &str, cells_info: &BTreeMap) -> usize { + let cells_property = match prop_name { + "clocks" | "assigned-clocks" => "#clock-cells", + "resets" => "#reset-cells", + "power-domains" => "#power-domain-cells", + "phys" => "#phy-cells", + "interrupts" | "interrupts-extended" => "#interrupt-cells", + "gpios" | _ if prop_name.ends_with("-gpios") || prop_name.ends_with("-gpio") => { + "#gpio-cells" + } + "dmas" => "#dma-cells", + "thermal-sensors" => "#thermal-sensor-cells", + "sound-dai" => "#sound-dai-cells", + "mboxes" => "#mbox-cells", + "pwms" => "#pwm-cells", + _ => { + debug!("Unknown property '{}', defaulting to 0 cell", prop_name); + return 0; + } + }; + + cells_info.get(cells_property).copied().unwrap_or(0) as usize +} + +/// 通用的phandle属性解析函数 +/// 根据cells信息按正确的块大小解析phandle引用 +/// 支持单个phandle和多个phandle+specifier格式 +/// 返回完整路径而不是节点名称 +fn parse_phandle_property( + prop_data: &[u8], + prop_name: &str, + phandle_map: &BTreeMap)>, +) -> Vec { + let mut dependencies = Vec::new(); + + let phandle_refs = parse_phandle_property_with_cells(prop_data, prop_name, phandle_map); + + for (phandle, specifiers) in phandle_refs { + if let Some((device_path, _cells_info)) = phandle_map.get(&phandle) { + let spec_info = if !specifiers.is_empty() { + format!(" (specifiers: {:?})", specifiers) + } else { + String::new() + }; + debug!( + "Found {} dependency: phandle={:#x}, device={}{}", + prop_name, phandle, device_path, spec_info + ); + dependencies.push(device_path.clone()); + } + } + + dependencies +} + +/// 设备属性分类器 - 用于识别需要特殊处理的属性 +struct DevicePropertyClassifier; + +impl DevicePropertyClassifier { + /// 需要特殊处理的phandle属性 - 包含所有需要解析依赖关系的属性 + const PHANDLE_PROPERTIES: &'static [&'static str] = &[ + "clocks", + "power-domains", + "phys", + "resets", + "dmas", + "thermal-sensors", + "mboxes", + "assigned-clocks", + "interrupt-parent", + "phy-handle", + "msi-parent", + "memory-region", + "syscon", + "regmap", + "iommus", + "interconnects", + "nvmem-cells", + "sound-dai", + "pinctrl-0", + "pinctrl-1", + "pinctrl-2", + "pinctrl-3", + "pinctrl-4", + ]; + + /// 判断是否为需要处理的phandle属性 + fn is_phandle_property(prop_name: &str) -> bool { + Self::PHANDLE_PROPERTIES.contains(&prop_name) + || prop_name.ends_with("-supply") + || prop_name == "gpios" + || prop_name.ends_with("-gpios") + || prop_name.ends_with("-gpio") + || (prop_name.contains("cells") && !prop_name.starts_with("#") && prop_name.len() >= 4) + } +} + +/// 查找设备的依赖关系 +/// 现在接受设备节点路径而不是节点引用 +/// 优化版本:使用node_cache而不是遍历所有节点 +fn find_device_dependencies( + device_node_path: &str, + phandle_map: &BTreeMap)>, + node_cache: &BTreeMap>, // 添加node_cache参数 +) -> Vec { + let mut dependencies = Vec::new(); + + // 直接从node_cache中查找节点,避免遍历所有节点 + if let Some(nodes) = node_cache.get(device_node_path) { + // 遍历节点的所有属性查找依赖关系 + for node in nodes { + for prop in node.propertys() { + // 判断是否为需要处理的phandle属性 + if DevicePropertyClassifier::is_phandle_property(prop.name) { + let mut prop_deps = parse_phandle_property(prop.raw_value(), prop.name, phandle_map); + dependencies.append(&mut prop_deps); + } + } + } + } + + dependencies +} + +/// 根据父节点路径获取所有后代节点(包括子节点、孙节点等) +/// 通过在node_cache中查找以父节点路径为前缀的节点来获取所有后代节点 +/// 这种方法比get_all_descendant_nodes更高效,因为它直接使用缓存 +fn get_descendant_nodes_by_path<'a>(node_cache: &'a BTreeMap>>, parent_path: &str) -> Vec { + let mut descendant_paths = Vec::new(); + + // 如果父路径是根路径,特殊处理 + let search_prefix = if parent_path == "/" { + "/".to_string() + } else { + parent_path.to_string() + "/" + }; + + // 遍历node_cache,查找所有以父路径为前缀的节点 + for (path, _nodes) in node_cache { + // 检查路径是否以父路径为前缀(并且不是父路径本身) + if path.starts_with(&search_prefix) && path.len() > search_prefix.len() { + // 这是后代节点的路径,添加到结果中 + descendant_paths.push(path.clone()); + } + } + + descendant_paths +} + diff --git a/src/vmm/fdt/mod.rs b/src/vmm/fdt/mod.rs new file mode 100644 index 00000000..fa5cf9fa --- /dev/null +++ b/src/vmm/fdt/mod.rs @@ -0,0 +1,14 @@ +//! FDT (Flattened Device Tree) processing module for AxVisor. +//! +//! This module provides functionality for parsing and processing device tree blobs, +//! including CPU configuration, passthrough device detection, and FDT generation. + +mod device; +mod parser; +mod create; +mod test; + +// Re-export public functions +pub use parser::parse_fdt; +pub use test::print_fdt; +pub use device::{build_node_path}; \ No newline at end of file diff --git a/src/vmm/fdt/parser.rs b/src/vmm/fdt/parser.rs new file mode 100644 index 00000000..0bc7cc9a --- /dev/null +++ b/src/vmm/fdt/parser.rs @@ -0,0 +1,119 @@ +//! FDT parsing and processing functionality. +use alloc::vec::Vec; +use alloc::string::ToString; +use fdt_parser::{Fdt, FdtHeader}; +use axvm::config::AxVMConfig; + +pub fn parse_fdt(fdt_addr: usize, vm_cfg: &mut AxVMConfig) { + const FDT_VALID_MAGIC: u32 = 0xd00d_feed; + let header = unsafe { + core::slice::from_raw_parts(fdt_addr as *const u8, core::mem::size_of::()) + }; + let fdt_header = FdtHeader::from_bytes(header) + .map_err(|e| format!("Failed to parse FDT header: {:#?}", e)) + .unwrap(); + + if fdt_header.magic.get() != FDT_VALID_MAGIC { + error!( + "FDT magic is invalid, expected {:#x}, got {:#x}", + FDT_VALID_MAGIC, + fdt_header.magic.get() + ); + return; + } + + let fdt_bytes = + unsafe { core::slice::from_raw_parts(fdt_addr as *const u8, fdt_header.total_size()) }; + + let fdt = Fdt::from_bytes(fdt_bytes) + .map_err(|e| format!("Failed to parse FDT: {:#?}", e)) + .expect("Failed to parse FDT"); + + set_phys_cpu_sets(vm_cfg, &fdt); + // 调用修改后的函数并获取返回的设备名称列表 + let passthrough_device_names = super::device::find_all_passthrough_devices(vm_cfg, &fdt); + + super::create::crate_guest_fdt(&fdt, &passthrough_device_names, vm_cfg); + // 注意:这里我们不再需要将设备添加到VM配置中,因为函数已经返回了设备名称列表 +} + +pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt) { + // Find and parse CPU information from host DTB + let host_cpus: Vec<_> = fdt.find_nodes("/cpus/cpu").collect(); + info!("Found {} host CPU nodes", &host_cpus.len()); + + //get phys_cpu_ids in guest config.toml + let vcpu_mappings = vm_cfg.get_vcpu_affinities_pcpu_ids(); + debug!("vcpu_mappings: {:?}", vcpu_mappings); + + // 收集所有CPU节点信息到Vec中,避免多次使用迭代器 + let cpu_nodes_info: Vec<_> = host_cpus + .iter() + .filter_map(|cpu_node| { + if let Some(mut cpu_reg) = cpu_node.reg() { + if let Some(r) = cpu_reg.next() { + Some((cpu_node.name().to_string(), r.address as usize)) + } else { + None + } + } else { + None + } + }) + .collect(); + debug!("cpu_nodes_info: {:?}", cpu_nodes_info); + // 创建从phys_cpu_id到物理CPU索引的映射 + // 收集所有唯一的CPU地址,保持设备树中的出现顺序 + let mut unique_cpu_addresses = Vec::new(); + for (_, cpu_address) in &cpu_nodes_info { + if !unique_cpu_addresses.contains(cpu_address) { + unique_cpu_addresses.push(*cpu_address); + } else { + panic!("Duplicate CPU address found"); + } + } + + // 为设备树中的每个CPU地址分配索引,并打印详细信息 + for (index, &cpu_address) in unique_cpu_addresses.iter().enumerate() { + // 找到所有使用这个地址的CPU节点 + for (cpu_name, node_address) in &cpu_nodes_info { + if *node_address == cpu_address { + debug!( + " CPU node: {}, address: 0x{:x}, assigned index: {}", + cpu_name, cpu_address, index + ); + break; // 每个地址只打印一次 + } + } + } + + // 根据vcpu_mappings中的phys_cpu_ids计算phys_cpu_sets + let mut new_phys_cpu_sets = Vec::new(); + for (vcpu_id, _phys_cpu_set, phys_cpu_id) in &vcpu_mappings { + // 在unique_cpu_addresses中查找phys_cpu_id对应的索引 + if let Some(cpu_index) = unique_cpu_addresses + .iter() + .position(|&addr| addr == *phys_cpu_id) + { + let cpu_mask = 1usize << cpu_index; // 将索引转换为掩码位 + new_phys_cpu_sets.push(cpu_mask); + debug!( + "vCPU {} with phys_cpu_id 0x{:x} mapped to CPU index {} (mask: 0x{:x})", + vcpu_id, phys_cpu_id, cpu_index, cpu_mask + ); + } else { + error!( + "vCPU {} with phys_cpu_id 0x{:x} not found in device tree!", + vcpu_id, phys_cpu_id + ); + } + } + + // 更新VM配置中的phys_cpu_sets(如果VM配置支持设置的话) + info!("Calculated phys_cpu_sets: {:?}", new_phys_cpu_sets); + + vm_cfg.set_guest_cpu_sets(new_phys_cpu_sets); + + let vcpu_mappings = vm_cfg.get_vcpu_affinities_pcpu_ids(); + info!("vcpu_mappings: {:?}", vcpu_mappings); +} \ No newline at end of file diff --git a/src/vmm/fdt/test.rs b/src/vmm/fdt/test.rs new file mode 100644 index 00000000..32e8529b --- /dev/null +++ b/src/vmm/fdt/test.rs @@ -0,0 +1,129 @@ +//! FDT parsing and processing functionality. + +use fdt_parser::{Fdt, FdtHeader}; + +#[allow(dead_code)] +pub fn print_fdt(fdt_addr: usize) { + const FDT_VALID_MAGIC: u32 = 0xd00d_feed; + let header = unsafe { + core::slice::from_raw_parts(fdt_addr as *const u8, core::mem::size_of::()) + }; + let fdt_header = FdtHeader::from_bytes(header) + .map_err(|e| format!("Failed to parse FDT header: {:#?}", e)) + .unwrap(); + + if fdt_header.magic.get() != FDT_VALID_MAGIC { + error!( + "FDT magic is invalid, expected {:#x}, got {:#x}", + FDT_VALID_MAGIC, + fdt_header.magic.get() + ); + return; + } + + let fdt_bytes = + unsafe { core::slice::from_raw_parts(fdt_addr as *const u8, fdt_header.total_size()) }; + + let fdt = Fdt::from_bytes(fdt_bytes) + .map_err(|e| format!("Failed to parse FDT: {:#?}", e)) + .expect("Failed to parse FDT"); + + // 统计节点数量和层级分布 + let mut node_count = 0; + let mut level_counts = alloc::collections::BTreeMap::new(); + let mut max_level = 0; + + info!("=== FDT节点信息统计 ==="); + + // 一次性遍历所有节点进行统计(遵循优化策略) + for node in fdt.all_nodes() { + node_count += 1; + + // 按层级统计节点数量 + *level_counts.entry(node.level).or_insert(0) += 1; + + // 记录最大层级 + if node.level > max_level { + max_level = node.level; + } + + // 统计属性数量 + let node_properties_count = node.propertys().count(); + + trace!( + "节点[{}]: {} (层级: {}, 属性: {})", + node_count, + node.name(), + node.level, + node_properties_count + ); + + for _prop in node.propertys() { + // info!("属性: {}, 节点: {}", prop.name, node.name()); + } + } + + info!("=== FDT统计结果 ==="); + info!("总节点数量: {}", node_count); + info!("FDT总大小: {} 字节", fdt_header.total_size()); + info!("最大层级深度: {}", max_level); + + info!("各层级节点分布:"); + for (level, count) in level_counts { + let percentage = (count as f32 / node_count as f32) * 100.0; + info!(" 层级 {}: {} 个节点 ({:.1}%)", level, count, percentage); + } +} + + +#[allow(dead_code)] +pub fn print_guest_fdt(fdt_bytes: &[u8]) { + + let fdt = Fdt::from_bytes(fdt_bytes) + .map_err(|e| format!("Failed to parse FDT: {:#?}", e)) + .expect("Failed to parse FDT"); + // 统计节点数量和层级分布 + let mut node_count = 0; + let mut level_counts = alloc::collections::BTreeMap::new(); + let mut max_level = 0; + + info!("=== FDT节点信息统计 ==="); + + // 一次性遍历所有节点进行统计(遵循优化策略) + for node in fdt.all_nodes() { + node_count += 1; + + // 按层级统计节点数量 + *level_counts.entry(node.level).or_insert(0) += 1; + + // 记录最大层级 + if node.level > max_level { + max_level = node.level; + } + + // 统计属性数量 + let node_properties_count = node.propertys().count(); + + trace!( + "节点[{}]: {} (层级: {}, 属性: {})", + node_count, + node.name(), + node.level, + node_properties_count + ); + + for _prop in node.propertys() { + trace!("属性: {}, 节点: {}", _prop.name, node.name()); + } + } + + info!("=== FDT统计结果 ==="); + info!("总节点数量: {}", node_count); + info!("最大层级深度: {}", max_level); + + info!("各层级节点分布:"); + for (level, count) in level_counts { + let percentage = (count as f32 / node_count as f32) * 100.0; + info!(" 层级 {}: {} 个节点 ({:.1}%)", level, count, percentage); + } +} \ No newline at end of file diff --git a/src/vmm/images/mod.rs b/src/vmm/images/mod.rs index 39e71a53..2119e2b2 100644 --- a/src/vmm/images/mod.rs +++ b/src/vmm/images/mod.rs @@ -7,8 +7,6 @@ use axvm::VMMemoryRegion; use axvm::config::AxVMCrateConfig; use byte_unit::Byte; -use crate::vmm::fdt::updated_fdt; - use crate::hal::CacheOp; use crate::vmm::VMRef; use crate::vmm::config::config; @@ -105,18 +103,8 @@ impl ImageLoader { .expect("Failed to load VM images"); // Load DTB image if let Some(buffer) = vm_imags.dtb { - debug!( - "DTB buffer addr: {:x}, size: {:#}", - self.dtb_load_gpa.unwrap(), - Byte::from(buffer.len()) - ); - - updated_fdt( - self.dtb_load_gpa.unwrap(), - NonNull::new(buffer.as_ptr() as *mut u8).unwrap(), - buffer.len(), - self.vm.clone(), - ); + load_vm_image_from_memory(buffer, self.dtb_load_gpa.unwrap(), self.vm.clone()) + .expect("Failed to load BIOS images"); } // Load BIOS image @@ -194,8 +182,6 @@ mod fs { use super::*; - use std::io::{BufReader, Read}; - pub fn kernal_read(config: &AxVMCrateConfig, read_size: usize) -> AxResult> { use std::fs::File; use std::io::Read; @@ -255,32 +241,11 @@ mod fs { // Load DTB image if needed. // Todo: generate DTB file for guest VM. if let Some(dtb_path) = &loader.config.kernel.dtb_path { - let (dtb_file, dtb_size) = open_image_file(dtb_path)?; - info!("DTB file size {}", 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) - ) - })?; - - let dtb_addr = loader.dtb_load_gpa.unwrap(); - - info!( - "DTB buffer addr: {:x}, size: {:#}", - dtb_addr, - Byte::from(dtb_size) - ); - updated_fdt( - dtb_addr, - NonNull::new(dtb_buffer.as_mut_ptr()).unwrap(), - dtb_size, - loader.vm.clone(), - ); + if let Some(dtb_load_addr) = loader.dtb_load_gpa { + load_vm_image(dtb_path, dtb_load_addr, loader.vm.clone())?; + } else { + return ax_err!(NotFound, "DTB load addr is missed"); + } }; Ok(()) } diff --git a/src/vmm/mod.rs b/src/vmm/mod.rs index 09cb27c6..0c228bad 100644 --- a/src/vmm/mod.rs +++ b/src/vmm/mod.rs @@ -1,5 +1,4 @@ mod config; -mod fdt; mod hvc; mod images; mod ivc; @@ -7,6 +6,9 @@ pub mod timer; mod vcpus; mod vm_list; +#[cfg(target_arch = "aarch64")] +pub mod fdt; + use core::sync::atomic::{AtomicUsize, Ordering}; use std::os::arceos::{ api::task::{self, AxWaitQueueHandle}, From 5b72b6754c4270b34b1c2a420529441adb9e524c Mon Sep 17 00:00:00 2001 From: szy Date: Wed, 17 Sep 2025 13:53:36 +0800 Subject: [PATCH 02/30] update --- Cargo.lock | 2 -- Cargo.toml | 3 +++ src/vmm/config.rs | 30 +++++++++++++++--------------- src/vmm/fdt/create.rs | 40 ++++++++++++++++------------------------ src/vmm/fdt/parser.rs | 26 +++++++++++++------------- src/vmm/fdt/test.rs | 8 ++++---- 6 files changed, 51 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dff00be6..8e27f8e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1008,8 +1008,6 @@ dependencies = [ [[package]] name = "axvmconfig" version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3618f2ebd9b25027b70f423c48a8482dc2883ca17f76d2a8d1fdac377e762f02" dependencies = [ "axerrno", "enumerable", diff --git a/Cargo.toml b/Cargo.toml index 038cf1f3..b8656f0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,3 +85,6 @@ toml = {version = "0.9"} [patch.crates-io] axvcpu = {git = "https://github.com/arceos-hypervisor/axvcpu.git", branch = "next"} + +[patch.crates-io.axvmconfig] +path = "/home/szy/work/hypervisor/fdt/axvmconfig" \ No newline at end of file diff --git a/src/vmm/config.rs b/src/vmm/config.rs index 0efcd7df..1689644f 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -208,25 +208,25 @@ pub fn init_guest_vms() { // if bootarg != 0 { // crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config); // } - if let Some(dtb) = get_vm_dtb(&vm_config) { - info!("VM[{}] found DTB , parsing...", vm_config.id()); + // if let Some(dtb) = get_vm_dtb(&vm_config) { + // info!("VM[{}] found DTB , parsing...", vm_config.id()); - // crate::vmm::fdt::parse_vm_fdt(&mut vm_config, dtb); - //test - let bootarg = dtb.as_ptr() as usize; - crate::vmm::fdt::print_fdt(bootarg); - crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config); - //test + // // crate::vmm::fdt::parse_vm_fdt(&mut vm_config, dtb); + // //test + // let bootarg = dtb.as_ptr() as usize; + // crate::vmm::fdt::print_fdt(bootarg); + // crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config, &vm_create_config); + // //test - } else { - info!("VM[{}] DTB not found, generating based on the configuration file.", vm_config.id()); + // } else { + // info!("VM[{}] DTB not found, generating based on the configuration file.", vm_config.id()); - let bootarg: usize = std::os::arceos::modules::axhal::get_bootarg(); - if bootarg != 0 { - crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config); - } - } + // let bootarg: usize = std::os::arceos::modules::axhal::get_bootarg(); + // if bootarg != 0 { + // crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config, &vm_create_config); + // } + // } // Overlay VM config with the given DTB. if let Some(dtb) = get_vm_dtb(&vm_config) { diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index df206098..a705c6b4 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -3,16 +3,19 @@ use alloc::string::ToString; use alloc::vec::Vec; use fdt_parser::{Fdt, Node}; use vm_fdt::{FdtWriter, FdtWriterNode}; -use axvm::config::AxVMConfig; +use axvm::config::{AxVMConfig, AxVMCrateConfig}; +use crate::vmm::fdt::print_fdt; +use crate::vmm::fdt::test::print_guest_fdt; -pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, vm_cfg: &AxVMConfig) { + +pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, vm_cfg: &AxVMConfig, crate_config: &AxVMCrateConfig) { let mut fdt_writer = FdtWriter::new().unwrap(); // 跟踪上一个处理节点的层级,用于层级变化处理 let mut previous_node_level = 0; // 维护FDT节点栈,用于正确开始和结束节点 let mut node_stack: Vec = Vec::new(); - let phys_cpu_ids = get_phys_cpu_ids(vm_cfg); + let phys_cpu_ids = crate_config.base.phys_cpu_ids.clone().expect("ERROR: phys_cpu_ids is None"); let all_nodes: Vec = fdt.all_nodes().collect(); @@ -66,20 +69,20 @@ pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, vm_cfg // add memory node if previous_node_level == 1 { - info!("Adding memory node with regions: {:x?}", vm_cfg.memory_regions()); + info!("Adding memory node:{:x?}", crate_config.kernel.memory_regions); let memory_node = fdt_writer.begin_node("memory").unwrap(); - add_memory_node(vm_cfg, &mut fdt_writer); + add_memory_node(&mut fdt_writer, crate_config); fdt_writer.end_node(memory_node).unwrap(); } } assert_eq!(previous_node_level , 0); - - use std::io::Write; - use std::fs::File; - let guest_fdt_bytes = fdt_writer.finish().unwrap(); - let mut file = File::create("guest_fdt.dtb").expect("Failed to create file"); - file.write_all(&guest_fdt_bytes).unwrap(); + print_guest_fdt(fdt_writer.finish().unwrap().as_slice()); + // use std::io::Write; + // use std::fs::File; + // let guest_fdt_bytes = fdt_writer.finish().unwrap(); + // let mut file = File::create("guest_fdt.dtb").expect("Failed to create file"); + // file.write_all(&guest_fdt_bytes).unwrap(); } /// 节点处理动作枚举 @@ -186,8 +189,8 @@ fn is_ancestor_of_passthrough_device(node_path: &str, passthrough_device_names: false } -fn add_memory_node(vm_cfg: &AxVMConfig, fdt_writer: &mut FdtWriter) { - let new_memory = vm_cfg.memory_regions(); +fn add_memory_node(fdt_writer: &mut FdtWriter, crate_config: &AxVMCrateConfig) { + let new_memory = &crate_config.kernel.memory_regions; let mut new_value: Vec = Vec::new(); for mem in new_memory { let gpa = mem.gpa as u64; @@ -228,14 +231,3 @@ fn need_cpu_node(phys_cpu_ids: &Vec, node: &Node, node_path: &str) -> boo } should_include_node } - -fn get_phys_cpu_ids(vm_cfg: &AxVMConfig) -> Vec { - let vcpu_mappings = vm_cfg.get_vcpu_affinities_pcpu_ids(); - debug!("vcpu_mappings: {:?}", vcpu_mappings); - - let mut phys_cpu_ids = Vec::new(); - for (_vcpu_id, _phys_cpu_set, phys_cpu_id) in vcpu_mappings { - phys_cpu_ids.push(phys_cpu_id); - } - phys_cpu_ids -} \ No newline at end of file diff --git a/src/vmm/fdt/parser.rs b/src/vmm/fdt/parser.rs index 0bc7cc9a..1bc27863 100644 --- a/src/vmm/fdt/parser.rs +++ b/src/vmm/fdt/parser.rs @@ -2,9 +2,10 @@ use alloc::vec::Vec; use alloc::string::ToString; use fdt_parser::{Fdt, FdtHeader}; -use axvm::config::AxVMConfig; +use axvm::config::{AxVMConfig, AxVMCrateConfig}; -pub fn parse_fdt(fdt_addr: usize, vm_cfg: &mut AxVMConfig) { + +pub fn parse_fdt(fdt_addr: usize, vm_cfg: &mut AxVMConfig, crate_config: &AxVMCrateConfig) { const FDT_VALID_MAGIC: u32 = 0xd00d_feed; let header = unsafe { core::slice::from_raw_parts(fdt_addr as *const u8, core::mem::size_of::()) @@ -29,22 +30,21 @@ pub fn parse_fdt(fdt_addr: usize, vm_cfg: &mut AxVMConfig) { .map_err(|e| format!("Failed to parse FDT: {:#?}", e)) .expect("Failed to parse FDT"); - set_phys_cpu_sets(vm_cfg, &fdt); + set_phys_cpu_sets(vm_cfg, &fdt, crate_config); // 调用修改后的函数并获取返回的设备名称列表 let passthrough_device_names = super::device::find_all_passthrough_devices(vm_cfg, &fdt); - super::create::crate_guest_fdt(&fdt, &passthrough_device_names, vm_cfg); + super::create::crate_guest_fdt(&fdt, &passthrough_device_names, vm_cfg, crate_config); // 注意:这里我们不再需要将设备添加到VM配置中,因为函数已经返回了设备名称列表 } -pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt) { +pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVMCrateConfig) { // Find and parse CPU information from host DTB let host_cpus: Vec<_> = fdt.find_nodes("/cpus/cpu").collect(); info!("Found {} host CPU nodes", &host_cpus.len()); - //get phys_cpu_ids in guest config.toml - let vcpu_mappings = vm_cfg.get_vcpu_affinities_pcpu_ids(); - debug!("vcpu_mappings: {:?}", vcpu_mappings); + let phys_cpu_ids = crate_config.base.phys_cpu_ids.as_ref().expect("ERROR: phys_cpu_ids not found in config.toml"); + debug!("phys_cpu_ids: {:?}", phys_cpu_ids); // 收集所有CPU节点信息到Vec中,避免多次使用迭代器 let cpu_nodes_info: Vec<_> = host_cpus @@ -89,7 +89,7 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt) { // 根据vcpu_mappings中的phys_cpu_ids计算phys_cpu_sets let mut new_phys_cpu_sets = Vec::new(); - for (vcpu_id, _phys_cpu_set, phys_cpu_id) in &vcpu_mappings { + for phys_cpu_id in phys_cpu_ids { // 在unique_cpu_addresses中查找phys_cpu_id对应的索引 if let Some(cpu_index) = unique_cpu_addresses .iter() @@ -99,12 +99,12 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt) { new_phys_cpu_sets.push(cpu_mask); debug!( "vCPU {} with phys_cpu_id 0x{:x} mapped to CPU index {} (mask: 0x{:x})", - vcpu_id, phys_cpu_id, cpu_index, cpu_mask + vm_cfg.id(), phys_cpu_id, cpu_index, cpu_mask ); } else { error!( "vCPU {} with phys_cpu_id 0x{:x} not found in device tree!", - vcpu_id, phys_cpu_id + vm_cfg.id(), phys_cpu_id ); } } @@ -112,8 +112,8 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt) { // 更新VM配置中的phys_cpu_sets(如果VM配置支持设置的话) info!("Calculated phys_cpu_sets: {:?}", new_phys_cpu_sets); - vm_cfg.set_guest_cpu_sets(new_phys_cpu_sets); + vm_cfg.phys_cpu_ls_mut().set_guest_cpu_sets(new_phys_cpu_sets); - let vcpu_mappings = vm_cfg.get_vcpu_affinities_pcpu_ids(); + let vcpu_mappings = vm_cfg.phys_cpu_ls_mut().get_vcpu_affinities_pcpu_ids(); info!("vcpu_mappings: {:?}", vcpu_mappings); } \ No newline at end of file diff --git a/src/vmm/fdt/test.rs b/src/vmm/fdt/test.rs index 32e8529b..e558fd62 100644 --- a/src/vmm/fdt/test.rs +++ b/src/vmm/fdt/test.rs @@ -58,8 +58,8 @@ pub fn print_fdt(fdt_addr: usize) { node_properties_count ); - for _prop in node.propertys() { - // info!("属性: {}, 节点: {}", prop.name, node.name()); + for prop in node.propertys() { + trace!("属性: {}, 节点: {:x?}", prop.name, prop.raw_value()); } } @@ -112,8 +112,8 @@ pub fn print_guest_fdt(fdt_bytes: &[u8]) { node_properties_count ); - for _prop in node.propertys() { - trace!("属性: {}, 节点: {}", _prop.name, node.name()); + for prop in node.propertys() { + trace!("属性: {}, 节点: {:x?}", prop.name, prop.raw_value()); } } From e877e02736f7081ee08f1089af789757d65d62e6 Mon Sep 17 00:00:00 2001 From: szy Date: Wed, 17 Sep 2025 14:04:30 +0800 Subject: [PATCH 03/30] log --- src/vmm/images/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vmm/images/mod.rs b/src/vmm/images/mod.rs index 2119e2b2..ae43203b 100644 --- a/src/vmm/images/mod.rs +++ b/src/vmm/images/mod.rs @@ -104,7 +104,7 @@ impl ImageLoader { // Load DTB image if let Some(buffer) = vm_imags.dtb { load_vm_image_from_memory(buffer, self.dtb_load_gpa.unwrap(), self.vm.clone()) - .expect("Failed to load BIOS images"); + .expect("Failed to load DTB images"); } // Load BIOS image @@ -132,7 +132,7 @@ pub fn load_vm_image_from_memory( let image_size = image_buffer.len(); - debug!( + info!( "loading VM image from memory {:?} {}", load_addr, image_buffer.len() From 13a0a3c96be625f41dced64e48e2bbacb913633a Mon Sep 17 00:00:00 2001 From: szy Date: Wed, 17 Sep 2025 15:59:11 +0800 Subject: [PATCH 04/30] update --- src/vmm/config.rs | 31 +++++++------ src/vmm/fdt/create.rs | 105 ++++++++++++++++++++++++++++++------------ src/vmm/fdt/mod.rs | 3 +- src/vmm/fdt/parser.rs | 2 +- src/vmm/images/mod.rs | 54 +++++++++++++++++----- 5 files changed, 136 insertions(+), 59 deletions(-) diff --git a/src/vmm/config.rs b/src/vmm/config.rs index 1689644f..a947d93c 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -208,25 +208,26 @@ pub fn init_guest_vms() { // if bootarg != 0 { // crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config); // } - // if let Some(dtb) = get_vm_dtb(&vm_config) { - // info!("VM[{}] found DTB , parsing...", vm_config.id()); + if let Some(dtb) = get_vm_dtb(&vm_config) { + info!("VM[{}] found DTB , parsing...", vm_config.id()); - // // crate::vmm::fdt::parse_vm_fdt(&mut vm_config, dtb); - // //test - // let bootarg = dtb.as_ptr() as usize; - // crate::vmm::fdt::print_fdt(bootarg); - // crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config, &vm_create_config); - // //test + // crate::vmm::fdt::parse_vm_fdt(&mut vm_config, dtb); + //test + let bootarg = dtb.as_ptr() as usize; + crate::vmm::fdt::print_fdt(bootarg); + crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config, &vm_create_config); + //test - // } else { - // info!("VM[{}] DTB not found, generating based on the configuration file.", vm_config.id()); + } else { + info!("VM[{}] DTB not found, generating based on the configuration file.", vm_config.id()); - // let bootarg: usize = std::os::arceos::modules::axhal::get_bootarg(); - // if bootarg != 0 { - // crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config, &vm_create_config); - // } - // } + let bootarg: usize = std::os::arceos::modules::axhal::get_bootarg(); + if bootarg != 0 { + crate::vmm::fdt::print_fdt(bootarg); + crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config, &vm_create_config); + } + } // Overlay VM config with the given DTB. if let Some(dtb) = get_vm_dtb(&vm_config) { diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index a705c6b4..f7966d0e 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -4,12 +4,15 @@ use alloc::vec::Vec; use fdt_parser::{Fdt, Node}; use vm_fdt::{FdtWriter, FdtWriterNode}; use axvm::config::{AxVMConfig, AxVMCrateConfig}; - +use crate::vmm::{VMRef, images::load_vm_image_from_memory}; +use axaddrspace::GuestPhysAddr; +use core::ptr::NonNull; +use axvm::VMMemoryRegion; use crate::vmm::fdt::print_fdt; use crate::vmm::fdt::test::print_guest_fdt; -pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, vm_cfg: &AxVMConfig, crate_config: &AxVMCrateConfig) { +pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, crate_config: &AxVMCrateConfig) { let mut fdt_writer = FdtWriter::new().unwrap(); // 跟踪上一个处理节点的层级,用于层级变化处理 let mut previous_node_level = 0; @@ -66,18 +69,11 @@ pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, vm_cfg while let Some(node) = node_stack.pop() { previous_node_level -= 1; fdt_writer.end_node(node).unwrap(); - - // add memory node - if previous_node_level == 1 { - info!("Adding memory node:{:x?}", crate_config.kernel.memory_regions); - let memory_node = fdt_writer.begin_node("memory").unwrap(); - add_memory_node(&mut fdt_writer, crate_config); - fdt_writer.end_node(memory_node).unwrap(); - } } assert_eq!(previous_node_level , 0); print_guest_fdt(fdt_writer.finish().unwrap().as_slice()); + let guest_fdt_bytes = fdt_writer.finish().unwrap(); // use std::io::Write; // use std::fs::File; // let guest_fdt_bytes = fdt_writer.finish().unwrap(); @@ -189,26 +185,6 @@ fn is_ancestor_of_passthrough_device(node_path: &str, passthrough_device_names: false } -fn add_memory_node(fdt_writer: &mut FdtWriter, crate_config: &AxVMCrateConfig) { - let new_memory = &crate_config.kernel.memory_regions; - let mut new_value: Vec = Vec::new(); - for mem in new_memory { - let gpa = mem.gpa as u64; - let size = mem.size as u64; - new_value.push((gpa >> 32) as u32); - new_value.push((gpa & 0xFFFFFFFF) as u32); - new_value.push((size >> 32) as u32); - new_value.push((size & 0xFFFFFFFF) as u32); - } - debug!("new_value: {:#?}", new_value); - fdt_writer - .property_array_u32("reg", new_value.as_ref()) - .unwrap(); - fdt_writer - .property_string("device_type", "memory") - .unwrap(); -} - fn need_cpu_node(phys_cpu_ids: &Vec, node: &Node, node_path: &str) -> bool{ let mut should_include_node = false; @@ -231,3 +207,72 @@ fn need_cpu_node(phys_cpu_ids: &Vec, node: &Node, node_path: &str) -> boo } should_include_node } + +fn add_memory_node(new_memory: &[VMMemoryRegion], new_fdt: &mut FdtWriter) { + let mut new_value: Vec = Vec::new(); + for mem in new_memory { + let gpa = mem.gpa.as_usize() as u64; + let size = mem.size() as u64; + new_value.push((gpa >> 32) as u32); + new_value.push((gpa & 0xFFFFFFFF) as u32); + new_value.push((size >> 32) as u32); + new_value.push((size & 0xFFFFFFFF) as u32); + } + info!("new_value: {:#x?}", new_value); + new_fdt + .property_array_u32("reg", new_value.as_ref()) + .unwrap(); + new_fdt.property_string("device_type", "memory").unwrap(); +} + +pub fn update_fdt(dest_addr: GuestPhysAddr, fdt_src: NonNull, dtb_size: usize, vm: VMRef) { + let mut new_fdt = FdtWriter::new().unwrap(); + let mut previous_node_level = 0; + let mut node_stack: Vec = Vec::new(); + + let fdt_bytes = unsafe { core::slice::from_raw_parts(fdt_src.as_ptr(), dtb_size) }; + let fdt = Fdt::from_bytes(fdt_bytes) + .map_err(|e| format!("Failed to parse FDT: {e:#?}")) + .expect("Failed to parse FDT"); + + for node in fdt.all_nodes() { + if node.name() == "/" { + // 根节点处理 + node_stack.push(new_fdt.begin_node("").unwrap()); + } else if node.name().starts_with("memory") { + // Skip memory nodes, will add them later + continue; + } else { + // 处理节点层级变化 + handle_node_level_change(&mut new_fdt, &mut node_stack, node.level, previous_node_level); + // 开始新节点 + node_stack.push(new_fdt.begin_node(node.name()).unwrap()); + } + + previous_node_level = node.level; + + for prop in node.propertys() { + new_fdt.property(prop.name, prop.raw_value()).unwrap(); + } + } + + // 结束所有未关闭的节点,并在适当位置添加内存节点 + while let Some(node) = node_stack.pop() { + previous_node_level -= 1; + new_fdt.end_node(node).unwrap(); + + // add memory node + if previous_node_level == 1 { + let memory_regions = vm.memory_regions(); + info!("Adding memory node with regions: {:?}", memory_regions); + let memory_node = new_fdt.begin_node("memory").unwrap(); + add_memory_node(&memory_regions, &mut new_fdt); + new_fdt.end_node(memory_node).unwrap(); + } + } + + assert_eq!(previous_node_level, 0); + let new_fdt_bytes = new_fdt.finish().unwrap(); + // 加载更新后的FDT到VM + load_vm_image_from_memory(&new_fdt_bytes, dest_addr, vm.clone()).expect("Failed to load VM images"); +} diff --git a/src/vmm/fdt/mod.rs b/src/vmm/fdt/mod.rs index fa5cf9fa..d320429c 100644 --- a/src/vmm/fdt/mod.rs +++ b/src/vmm/fdt/mod.rs @@ -11,4 +11,5 @@ mod test; // Re-export public functions pub use parser::parse_fdt; pub use test::print_fdt; -pub use device::{build_node_path}; \ No newline at end of file +pub use device::{build_node_path}; +pub use create::update_fdt; \ No newline at end of file diff --git a/src/vmm/fdt/parser.rs b/src/vmm/fdt/parser.rs index 1bc27863..a4bea99c 100644 --- a/src/vmm/fdt/parser.rs +++ b/src/vmm/fdt/parser.rs @@ -34,7 +34,7 @@ pub fn parse_fdt(fdt_addr: usize, vm_cfg: &mut AxVMConfig, crate_config: &AxVMCr // 调用修改后的函数并获取返回的设备名称列表 let passthrough_device_names = super::device::find_all_passthrough_devices(vm_cfg, &fdt); - super::create::crate_guest_fdt(&fdt, &passthrough_device_names, vm_cfg, crate_config); + super::create::crate_guest_fdt(&fdt, &passthrough_device_names, crate_config); // 注意:这里我们不再需要将设备添加到VM配置中,因为函数已经返回了设备名称列表 } diff --git a/src/vmm/images/mod.rs b/src/vmm/images/mod.rs index ae43203b..8cd1dee8 100644 --- a/src/vmm/images/mod.rs +++ b/src/vmm/images/mod.rs @@ -11,6 +11,8 @@ use crate::hal::CacheOp; use crate::vmm::VMRef; use crate::vmm::config::config; +use crate::vmm::fdt::update_fdt; + mod linux; pub fn get_image_header(config: &AxVMCrateConfig) -> Option { @@ -103,8 +105,18 @@ impl ImageLoader { .expect("Failed to load VM images"); // Load DTB image if let Some(buffer) = vm_imags.dtb { - load_vm_image_from_memory(buffer, self.dtb_load_gpa.unwrap(), self.vm.clone()) - .expect("Failed to load DTB images"); + debug!( + "DTB buffer addr: {:x}, size: {:#}", + self.dtb_load_gpa.unwrap(), + Byte::from(buffer.len()) + ); + + update_fdt( + self.dtb_load_gpa.unwrap(), + NonNull::new(buffer.as_ptr() as *mut u8).unwrap(), + buffer.len(), + self.vm.clone(), + ); } // Load BIOS image @@ -132,7 +144,7 @@ pub fn load_vm_image_from_memory( let image_size = image_buffer.len(); - info!( + debug!( "loading VM image from memory {:?} {}", load_addr, image_buffer.len() @@ -175,11 +187,9 @@ pub fn load_vm_image_from_memory( #[cfg(feature = "fs")] mod fs { use std::{fs::File, vec::Vec}; - use axerrno::{AxResult, ax_err, ax_err_type}; - use crate::hal::CacheOp; - + use std::io::{BufReader, Read}; use super::*; pub fn kernal_read(config: &AxVMCrateConfig, read_size: usize) -> AxResult> { @@ -239,13 +249,33 @@ mod fs { } }; // Load DTB image if needed. - // Todo: generate DTB file for guest VM. if let Some(dtb_path) = &loader.config.kernel.dtb_path { - if let Some(dtb_load_addr) = loader.dtb_load_gpa { - load_vm_image(dtb_path, dtb_load_addr, loader.vm.clone())?; - } else { - return ax_err!(NotFound, "DTB load addr is missed"); - } + let (dtb_file, dtb_size) = open_image_file(dtb_path)?; + info!("DTB file size {}", 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) + ) + })?; + + let dtb_addr = loader.dtb_load_gpa.unwrap(); + + info!( + "DTB buffer addr: {:x}, size: {:#}", + dtb_addr, + Byte::from(dtb_size) + ); + updated_fdt( + dtb_addr, + NonNull::new(dtb_buffer.as_mut_ptr()).unwrap(), + dtb_size, + loader.vm.clone(), + ); }; Ok(()) } From c7f0ee370d20f08f926938ccc7f9d9fe24283b26 Mon Sep 17 00:00:00 2001 From: szy Date: Wed, 17 Sep 2025 17:39:14 +0800 Subject: [PATCH 05/30] dtb load ok, now need to pt address --- src/vmm/config.rs | 47 +++++++++++++++++++++++++++++++++++++--- src/vmm/fdt/create.rs | 50 +++++++++++++++++++++++++++++++++++++------ src/vmm/fdt/parser.rs | 2 +- src/vmm/images/mod.rs | 12 ++++++----- 4 files changed, 95 insertions(+), 16 deletions(-) diff --git a/src/vmm/config.rs b/src/vmm/config.rs index a947d93c..ba398114 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -11,6 +11,15 @@ use memory_addr::MemoryAddr; use crate::vmm::{VM, images::ImageLoader, vm_list::push_vm}; +// 添加用于存储生成的DTB的全局静态变量 +use alloc::collections::BTreeMap; +use alloc::sync::Arc; +use lazyinit::LazyInit; +use spin::Mutex; + +// 用于存储生成的DTB数据的全局缓存 +pub static GENERATED_DTB_CACHE: LazyInit>>> = LazyInit::new(); + #[allow(clippy::module_inception)] pub mod config { use alloc::vec::Vec; @@ -35,8 +44,36 @@ pub fn get_vm_dtb(vm_cfg: &AxVMConfig) -> Option<&'static [u8]> { let vm_imags = config::get_memory_images() .iter() .find(|&v| v.id == vm_cfg.id())?; - // .expect("VM images is missed, Perhaps add `VM_CONFIGS=PATH/CONFIGS/FILE` command."); - vm_imags.dtb + + if let Some(dtb) = vm_imags.dtb { + return Some(dtb); + } + + None +} + +/// 获取VM的DTB数据(返回Arc<[u8]>,支持缓存数据) +pub fn get_vm_dtb_arc(vm_cfg: &AxVMConfig) -> Option> { + // 首先尝试返回静态DTB数据 + let vm_imags = config::get_memory_images() + .iter() + .find(|&v| v.id == vm_cfg.id())?; + + if let Some(dtb) = vm_imags.dtb { + // 将&'static [u8]转换为Arc<[u8]> + return Some(Arc::from(dtb)); + } + + // 如果内存镜像中没有DTB,则尝试从生成的DTB缓存中获取 + if let Some(cache) = GENERATED_DTB_CACHE.get() { + let cache_lock = cache.lock(); + if let Some(dtb) = cache_lock.get(&vm_cfg.id()) { + // 返回缓存中的Arc引用 + return Some(dtb.clone()); + } + } + + None } pub fn parse_vm_dtb(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { @@ -186,6 +223,9 @@ pub fn parse_vm_dtb(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { } pub fn init_guest_vms() { + // 初始化DTB缓存 + GENERATED_DTB_CACHE.init_once(Mutex::new(BTreeMap::new())); + let gvm_raw_configs = config::static_vm_configs(); for raw_cfg_str in gvm_raw_configs { @@ -230,7 +270,8 @@ pub fn init_guest_vms() { } // Overlay VM config with the given DTB. - if let Some(dtb) = get_vm_dtb(&vm_config) { + if let Some(dtb_arc) = get_vm_dtb_arc(&vm_config) { + let dtb = dtb_arc.as_ref(); parse_vm_dtb(&mut vm_config, dtb); } else { warn!( diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index f7966d0e..3221c21a 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -10,9 +10,23 @@ use core::ptr::NonNull; use axvm::VMMemoryRegion; use crate::vmm::fdt::print_fdt; use crate::vmm::fdt::test::print_guest_fdt; +// 引入缓存相关的模块 +use alloc::collections::BTreeMap; +use alloc::sync::Arc; +use spin::Mutex; +use lazyinit::LazyInit; -pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, crate_config: &AxVMCrateConfig) { +/// 生成客户机FDT并返回DTB数据 +/// +/// # 参数 +/// * `fdt` - 源FDT数据 +/// * `passthrough_device_names` - 直通设备名称列表 +/// * `crate_config` - VM创建配置 +/// +/// # 返回值 +/// 返回生成的DTB数据 +pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, crate_config: &AxVMCrateConfig) -> Vec { let mut fdt_writer = FdtWriter::new().unwrap(); // 跟踪上一个处理节点的层级,用于层级变化处理 let mut previous_node_level = 0; @@ -72,13 +86,35 @@ pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, crate_ } assert_eq!(previous_node_level , 0); - print_guest_fdt(fdt_writer.finish().unwrap().as_slice()); let guest_fdt_bytes = fdt_writer.finish().unwrap(); - // use std::io::Write; - // use std::fs::File; - // let guest_fdt_bytes = fdt_writer.finish().unwrap(); - // let mut file = File::create("guest_fdt.dtb").expect("Failed to create file"); - // file.write_all(&guest_fdt_bytes).unwrap(); + + print_guest_fdt(guest_fdt_bytes.as_slice()); + + // 返回生成的DTB数据,让调用者决定如何使用 + guest_fdt_bytes +} + +/// 生成客户机FDT并缓存结果 +/// +/// # 参数 +/// * `fdt` - 源FDT数据 +/// * `passthrough_device_names` - 直通设备名称列表 +/// * `crate_config` - VM创建配置 +/// +/// # 返回值 +/// 返回生成的DTB数据,并将其存储在全局缓存中 +pub fn crate_guest_fdt_with_cache(fdt: &Fdt, passthrough_device_names: &Vec, crate_config: &AxVMCrateConfig) -> Vec { + // 生成DTB数据 + let dtb_data = crate_guest_fdt(fdt, passthrough_device_names, crate_config); + + // 将数据存储到全局缓存中 + if let Some(cache) = crate::vmm::config::GENERATED_DTB_CACHE.get() { + let mut cache_lock = cache.lock(); + let dtb_arc: Arc<[u8]> = Arc::from(dtb_data.clone()); + cache_lock.insert(crate_config.base.id, dtb_arc); + } + + dtb_data } /// 节点处理动作枚举 diff --git a/src/vmm/fdt/parser.rs b/src/vmm/fdt/parser.rs index a4bea99c..9571a074 100644 --- a/src/vmm/fdt/parser.rs +++ b/src/vmm/fdt/parser.rs @@ -34,7 +34,7 @@ pub fn parse_fdt(fdt_addr: usize, vm_cfg: &mut AxVMConfig, crate_config: &AxVMCr // 调用修改后的函数并获取返回的设备名称列表 let passthrough_device_names = super::device::find_all_passthrough_devices(vm_cfg, &fdt); - super::create::crate_guest_fdt(&fdt, &passthrough_device_names, crate_config); + let _ = super::create::crate_guest_fdt_with_cache(&fdt, &passthrough_device_names, crate_config); // 注意:这里我们不再需要将设备添加到VM配置中,因为函数已经返回了设备名称列表 } diff --git a/src/vmm/images/mod.rs b/src/vmm/images/mod.rs index 8cd1dee8..70699aea 100644 --- a/src/vmm/images/mod.rs +++ b/src/vmm/images/mod.rs @@ -9,7 +9,7 @@ use byte_unit::Byte; use crate::hal::CacheOp; use crate::vmm::VMRef; -use crate::vmm::config::config; +use crate::vmm::config::{config, get_vm_dtb_arc}; use crate::vmm::fdt::update_fdt; @@ -104,17 +104,19 @@ impl ImageLoader { load_vm_image_from_memory(vm_imags.kernel, self.kernel_load_gpa, self.vm.clone()) .expect("Failed to load VM images"); // Load DTB image - if let Some(buffer) = vm_imags.dtb { + let vm_config = axvm::config::AxVMConfig::from(self.config.clone()); + if let Some(dtb_arc) = get_vm_dtb_arc(&vm_config) { + let dtb_slice: &[u8] = &*dtb_arc; debug!( "DTB buffer addr: {:x}, size: {:#}", self.dtb_load_gpa.unwrap(), - Byte::from(buffer.len()) + Byte::from(dtb_slice.len()) ); update_fdt( self.dtb_load_gpa.unwrap(), - NonNull::new(buffer.as_ptr() as *mut u8).unwrap(), - buffer.len(), + NonNull::new(dtb_slice.as_ptr() as *mut u8).unwrap(), + dtb_slice.len(), self.vm.clone(), ); } From a08d5478a440bb9bf4d54e86ff896fb3769c74aa Mon Sep 17 00:00:00 2001 From: szy Date: Thu, 18 Sep 2025 10:15:20 +0800 Subject: [PATCH 06/30] add pt addr --- Cargo.toml | 2 +- src/vmm/config.rs | 3 +- src/vmm/fdt/mod.rs | 2 +- src/vmm/fdt/parser.rs | 109 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 111 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b8656f0d..726febb1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,4 +87,4 @@ toml = {version = "0.9"} axvcpu = {git = "https://github.com/arceos-hypervisor/axvcpu.git", branch = "next"} [patch.crates-io.axvmconfig] -path = "/home/szy/work/hypervisor/fdt/axvmconfig" \ No newline at end of file +path = "./axvmconfig" \ No newline at end of file diff --git a/src/vmm/config.rs b/src/vmm/config.rs index ba398114..943e7873 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -9,7 +9,7 @@ use axvm::{ }; use memory_addr::MemoryAddr; -use crate::vmm::{VM, images::ImageLoader, vm_list::push_vm}; +use crate::vmm::{fdt::parse_passthrough_devices_address, images::ImageLoader, vm_list::push_vm, VM}; // 添加用于存储生成的DTB的全局静态变量 use alloc::collections::BTreeMap; @@ -272,6 +272,7 @@ pub fn init_guest_vms() { // Overlay VM config with the given DTB. if let Some(dtb_arc) = get_vm_dtb_arc(&vm_config) { let dtb = dtb_arc.as_ref(); + parse_passthrough_devices_address(&mut vm_config, dtb); parse_vm_dtb(&mut vm_config, dtb); } else { warn!( diff --git a/src/vmm/fdt/mod.rs b/src/vmm/fdt/mod.rs index d320429c..e698f436 100644 --- a/src/vmm/fdt/mod.rs +++ b/src/vmm/fdt/mod.rs @@ -9,7 +9,7 @@ mod create; mod test; // Re-export public functions -pub use parser::parse_fdt; +pub use parser::{parse_fdt, parse_passthrough_devices_address}; pub use test::print_fdt; pub use device::{build_node_path}; pub use create::update_fdt; \ No newline at end of file diff --git a/src/vmm/fdt/parser.rs b/src/vmm/fdt/parser.rs index 9571a074..bf181333 100644 --- a/src/vmm/fdt/parser.rs +++ b/src/vmm/fdt/parser.rs @@ -1,7 +1,7 @@ //! FDT parsing and processing functionality. use alloc::vec::Vec; use alloc::string::ToString; -use fdt_parser::{Fdt, FdtHeader}; +use fdt_parser::{Fdt, FdtHeader, PciSpace}; use axvm::config::{AxVMConfig, AxVMCrateConfig}; @@ -116,4 +116,109 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM let vcpu_mappings = vm_cfg.phys_cpu_ls_mut().get_vcpu_affinities_pcpu_ids(); info!("vcpu_mappings: {:?}", vcpu_mappings); -} \ No newline at end of file +} + +pub fn parse_passthrough_devices_address(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { + let fdt = Fdt::from_bytes(dtb) + .expect("Failed to parse DTB image, perhaps the DTB is invalid or corrupted"); + + info!("before clear, all: {:?}", vm_cfg.pass_through_devices()); + // 清空现有的直通设备配置 + vm_cfg.clear_pass_through_devices(); + + info!("after clear, all: {:?}", vm_cfg.pass_through_devices()); + + // 遍历所有设备树节点 + for node in fdt.all_nodes() { + // 跳过根节点 + if node.name() == "/" { + continue; + } + + let node_name = node.name().to_string(); + + // 检查是否为PCIe设备节点 + if node_name.starts_with("pcie@") || node_name.contains("pci") { + // 处理PCIe设备的ranges属性 + if let Some(pci) = node.into_pci() { + if let Ok(ranges) = pci.ranges() { + for (index, range) in ranges.enumerate() { + let base_address = range.cpu_address as usize; + let size = range.size as usize; + + // 只处理有地址信息的设备 + if size > 0 { + // 为每个地址段创建一个设备配置 + let device_name = if index == 0 { + format!("{}-{}", node_name, match range.space { + PciSpace::Configuration => "config", + PciSpace::IO => "io", + PciSpace::Memory32 => "mem32", + PciSpace::Memory64 => "mem64", + }) + } else { + format!("{}-{}-region{}", node_name, match range.space { + PciSpace::Configuration => "config", + PciSpace::IO => "io", + PciSpace::Memory32 => "mem32", + PciSpace::Memory64 => "mem64", + }, index) + }; + + // 添加新的设备配置 + let pt_dev = axvm::config::PassThroughDeviceConfig { + name: device_name, + base_gpa: base_address, + base_hpa: base_address, + length: size, + irq_id: 0, + }; + vm_cfg.add_pass_through_device(pt_dev); + + trace!("Added PCIe passthrough device {}: base=0x{:x}, size=0x{:x}, space={:?}", + node_name, base_address, size, range.space); + } + } + } + } + } else { + // 获取设备的reg属性(处理普通设备) + if let Some(mut reg_iter) = node.reg() { + // 处理设备的所有地址段 + let mut index = 0; + while let Some(reg) = reg_iter.next() { + // 获取设备的地址和大小信息 + let base_address = reg.address as usize; + let size = reg.size.unwrap_or(0) as usize; + + // 只处理有地址信息的设备 + if size > 0 { + // 为每个地址段创建一个设备配置 + // 如果设备有多个地址段,使用索引来区分 + let device_name = if index == 0 { + node_name.clone() + } else { + format!("{}-region{}", node_name, index) + }; + + // 添加新的设备配置 + let pt_dev = axvm::config::PassThroughDeviceConfig { + name: device_name, + base_gpa: base_address, + base_hpa: base_address, + length: size, + irq_id: 0, + }; + vm_cfg.add_pass_through_device(pt_dev); + + trace!("Added passthrough device {}: base=0x{:x}, size=0x{:x}", node_name, base_address, size); + } + + index += 1; + } + } + } + } + info!("All passthrough devices: {:#x?}", vm_cfg.pass_through_devices()); + info!("Finished parsing passthrough devices, total: {}", vm_cfg.pass_through_devices().len()); +} From 6a6d923700c279a42d3fa9e5791b96fb1ae3ff64 Mon Sep 17 00:00:00 2001 From: szy Date: Fri, 19 Sep 2025 10:24:10 +0800 Subject: [PATCH 07/30] update --- .gitignore | 1 + src/vmm/config.rs | 177 ++++-------------------------------------- src/vmm/fdt/create.rs | 2 +- src/vmm/fdt/mod.rs | 2 +- src/vmm/fdt/parser.rs | 101 +++++++++++++++++++++--- 5 files changed, 111 insertions(+), 172 deletions(-) diff --git a/.gitignore b/.gitignore index a229e4bc..4cce7fb1 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ actual.out qemu.log rusty-tags.vi +/axvmconfig # Python virtual environment venv/ __pycache__/ diff --git a/src/vmm/config.rs b/src/vmm/config.rs index 943e7873..39ef26f7 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -9,7 +9,9 @@ use axvm::{ }; use memory_addr::MemoryAddr; -use crate::vmm::{fdt::parse_passthrough_devices_address, images::ImageLoader, vm_list::push_vm, VM}; +use crate::vmm::{ + VM, fdt::{parse_passthrough_devices_address, parse_vm_interrupt}, images::ImageLoader, vm_list::push_vm, +}; // 添加用于存储生成的DTB的全局静态变量 use alloc::collections::BTreeMap; @@ -44,11 +46,11 @@ pub fn get_vm_dtb(vm_cfg: &AxVMConfig) -> Option<&'static [u8]> { let vm_imags = config::get_memory_images() .iter() .find(|&v| v.id == vm_cfg.id())?; - + if let Some(dtb) = vm_imags.dtb { return Some(dtb); } - + None } @@ -58,12 +60,12 @@ pub fn get_vm_dtb_arc(vm_cfg: &AxVMConfig) -> Option> { let vm_imags = config::get_memory_images() .iter() .find(|&v| v.id == vm_cfg.id())?; - + if let Some(dtb) = vm_imags.dtb { // 将&'static [u8]转换为Arc<[u8]> return Some(Arc::from(dtb)); } - + // 如果内存镜像中没有DTB,则尝试从生成的DTB缓存中获取 if let Some(cache) = GENERATED_DTB_CACHE.get() { let cache_lock = cache.lock(); @@ -72,160 +74,14 @@ pub fn get_vm_dtb_arc(vm_cfg: &AxVMConfig) -> Option> { return Some(dtb.clone()); } } - - None -} - -pub fn parse_vm_dtb(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { - use fdt_parser::{Fdt, Status}; - - let fdt = Fdt::from_bytes(dtb) - .expect("Failed to parse DTB image, perhaps the DTB is invalid or corrupted"); - - for reserved in fdt.reserved_memory() { - warn!("Find reserved memory: {:?}", reserved.name()); - } - for mem_reserved in fdt.memory_reservation_block() { - warn!("Find memory reservation block: {:?}", mem_reserved); - } - - for node in fdt.all_nodes() { - trace!("DTB node: {:?}", node.name()); - let name = node.name(); - if name.starts_with("memory") { - // Skip the memory node, as we handle memory regions separately. - continue; - } - - if let Some(status) = node.status() - && status == Status::Disabled - { - // Skip disabled nodes - trace!("DTB node: {} is disabled", name); - // continue; - } - - // Skip the interrupt controller, as we will use vGIC - // TODO: filter with compatible property and parse its phandle from DT; maybe needs a second pass? - const GIC_PHANDLE: usize = 1; - if name.starts_with("interrupt-controller") - || name.starts_with("intc") - || name.starts_with("its") - { - info!("skipping node {} to use vGIC", name); - continue; - } - - // Collect all GIC_SPI interrupts and add them to vGIC - if let Some(interrupts) = node.interrupts() { - // TODO: skip non-GIC interrupt - if let Some(parent) = node.interrupt_parent() { - trace!("node: {}, intr parent: {}", name, parent.node.name()); - if let Some(phandle) = parent.node.phandle() { - if phandle.as_usize() != GIC_PHANDLE { - warn!( - "node: {}, intr parent: {}, phandle: 0x{:x} is not GIC!", - name, - parent.node.name(), - phandle.as_usize() - ); - } - } else { - warn!( - "node: {}, intr parent: {} no phandle!", - name, - parent.node.name(), - ); - } - } else { - warn!("node: {} no interrupt parent!", name); - } - - trace!("node: {} interrupts:", name); - - for interrupt in interrupts { - // - for (k, v) in interrupt.enumerate() { - match k { - 0 => { - if v == 0 { - trace!("node: {}, GIC_SPI", name); - } else { - warn!( - "node: {}, intr type: {}, not GIC_SPI, not supported!", - name, v - ); - break; - } - } - 1 => { - trace!("node: {}, interrupt id: 0x{:x}", name, v); - vm_cfg.add_pass_through_spi(v); - } - 2 => { - trace!("node: {}, interrupt mode: 0x{:x}", name, v); - } - _ => { - warn!("unknown interrupt property {}:0x{:x}", k, v) - } - } - } - } - } - - if let Some(regs) = node.reg() { - for reg in regs { - if reg.address < 0x1000 { - // Skip registers with address less than 0x10000. - trace!( - "Skipping DTB node {} with register address {:#x} < 0x10000", - node.name(), - reg.address - ); - continue; - } - - if let Some(size) = reg.size { - let start = reg.address as usize; - // let end = start + size; - // if vm_cfg.contains_memory_range(&(start..end)) { - // trace!( - // "Skipping DTB node {} with register address {:#x} and size {:#x} as it overlaps with existing memory regions", - // node.name(), - // reg.address, - // size - // ); - // continue; - // } - - let pt_dev = PassThroughDeviceConfig { - name: node.name().to_string(), - base_gpa: start, - base_hpa: start, - length: size as _, - irq_id: 0, - }; - trace!("Adding {:x?}", pt_dev); - vm_cfg.add_pass_through_device(pt_dev); - } - } - } - } - - vm_cfg.add_pass_through_device(PassThroughDeviceConfig { - name: "Fake Node".to_string(), - base_gpa: 0x0, - base_hpa: 0x0, - length: 0x20_0000, - irq_id: 0, - }); + None } pub fn init_guest_vms() { // 初始化DTB缓存 GENERATED_DTB_CACHE.init_once(Mutex::new(BTreeMap::new())); - + let gvm_raw_configs = config::static_vm_configs(); for raw_cfg_str in gvm_raw_configs { @@ -242,7 +98,7 @@ pub fn init_guest_vms() { let mut vm_config = AxVMConfig::from(vm_create_config.clone()); // info!("vm_create_config: {:#?}", vm_create_config); - // info!("before parse_vm_dtb, crate VM[{}] with config: {:#?}", vm_config.id(), vm_config); + // info!("before parse_vm_interrupt, crate VM[{}] with config: {:#?}", vm_config.id(), vm_config); // let bootarg: usize = unsafe { std::os::arceos::modules::axhal::get_bootarg() }; // if bootarg != 0 { @@ -254,17 +110,16 @@ pub fn init_guest_vms() { // crate::vmm::fdt::parse_vm_fdt(&mut vm_config, dtb); //test let bootarg = dtb.as_ptr() as usize; - crate::vmm::fdt::print_fdt(bootarg); crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config, &vm_create_config); //test - - } else { - info!("VM[{}] DTB not found, generating based on the configuration file.", vm_config.id()); + info!( + "VM[{}] DTB not found, generating based on the configuration file.", + vm_config.id() + ); let bootarg: usize = std::os::arceos::modules::axhal::get_bootarg(); if bootarg != 0 { - crate::vmm::fdt::print_fdt(bootarg); crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config, &vm_create_config); } } @@ -273,7 +128,7 @@ pub fn init_guest_vms() { if let Some(dtb_arc) = get_vm_dtb_arc(&vm_config) { let dtb = dtb_arc.as_ref(); parse_passthrough_devices_address(&mut vm_config, dtb); - parse_vm_dtb(&mut vm_config, dtb); + parse_vm_interrupt(&mut vm_config, dtb); } else { warn!( "VM[{}] DTB not found in memory, skipping...", @@ -281,7 +136,7 @@ pub fn init_guest_vms() { ); } - // info!("after parse_vm_dtb, crate VM[{}] with config: {:#?}", vm_config.id(), vm_config); + // info!("after parse_vm_interrupt, crate VM[{}] with config: {:#?}", vm_config.id(), vm_config); info!("Creating VM[{}] {:?}", vm_config.id(), vm_config.name()); // Create VM. diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index 3221c21a..f8c628b5 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -254,7 +254,7 @@ fn add_memory_node(new_memory: &[VMMemoryRegion], new_fdt: &mut FdtWriter) { new_value.push((size >> 32) as u32); new_value.push((size & 0xFFFFFFFF) as u32); } - info!("new_value: {:#x?}", new_value); + trace!("new_value: {:x?}", new_value); new_fdt .property_array_u32("reg", new_value.as_ref()) .unwrap(); diff --git a/src/vmm/fdt/mod.rs b/src/vmm/fdt/mod.rs index e698f436..3c62ad46 100644 --- a/src/vmm/fdt/mod.rs +++ b/src/vmm/fdt/mod.rs @@ -9,7 +9,7 @@ mod create; mod test; // Re-export public functions -pub use parser::{parse_fdt, parse_passthrough_devices_address}; +pub use parser::{parse_fdt, parse_passthrough_devices_address, parse_vm_interrupt}; pub use test::print_fdt; pub use device::{build_node_path}; pub use create::update_fdt; \ No newline at end of file diff --git a/src/vmm/fdt/parser.rs b/src/vmm/fdt/parser.rs index bf181333..f85bd052 100644 --- a/src/vmm/fdt/parser.rs +++ b/src/vmm/fdt/parser.rs @@ -44,7 +44,6 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM info!("Found {} host CPU nodes", &host_cpus.len()); let phys_cpu_ids = crate_config.base.phys_cpu_ids.as_ref().expect("ERROR: phys_cpu_ids not found in config.toml"); - debug!("phys_cpu_ids: {:?}", phys_cpu_ids); // 收集所有CPU节点信息到Vec中,避免多次使用迭代器 let cpu_nodes_info: Vec<_> = host_cpus @@ -61,7 +60,7 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM } }) .collect(); - debug!("cpu_nodes_info: {:?}", cpu_nodes_info); + info!("cpu_nodes_info: {:?}", cpu_nodes_info); // 创建从phys_cpu_id到物理CPU索引的映射 // 收集所有唯一的CPU地址,保持设备树中的出现顺序 let mut unique_cpu_addresses = Vec::new(); @@ -114,24 +113,20 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM vm_cfg.phys_cpu_ls_mut().set_guest_cpu_sets(new_phys_cpu_sets); - let vcpu_mappings = vm_cfg.phys_cpu_ls_mut().get_vcpu_affinities_pcpu_ids(); - info!("vcpu_mappings: {:?}", vcpu_mappings); + debug!("vcpu_mappings: {:?}", vm_cfg.phys_cpu_ls_mut().get_vcpu_affinities_pcpu_ids()); } pub fn parse_passthrough_devices_address(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { let fdt = Fdt::from_bytes(dtb) .expect("Failed to parse DTB image, perhaps the DTB is invalid or corrupted"); - info!("before clear, all: {:?}", vm_cfg.pass_through_devices()); // 清空现有的直通设备配置 vm_cfg.clear_pass_through_devices(); - info!("after clear, all: {:?}", vm_cfg.pass_through_devices()); - // 遍历所有设备树节点 for node in fdt.all_nodes() { // 跳过根节点 - if node.name() == "/" { + if node.name() == "/" || node.name().starts_with("memory") { continue; } @@ -219,6 +214,94 @@ pub fn parse_passthrough_devices_address(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { } } } - info!("All passthrough devices: {:#x?}", vm_cfg.pass_through_devices()); + trace!("All passthrough devices: {:#x?}", vm_cfg.pass_through_devices()); info!("Finished parsing passthrough devices, total: {}", vm_cfg.pass_through_devices().len()); } + +pub fn parse_vm_interrupt(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { + + let fdt = Fdt::from_bytes(dtb) + .expect("Failed to parse DTB image, perhaps the DTB is invalid or corrupted"); + + for node in fdt.all_nodes() { + trace!("DTB node: {:?}", node.name()); + let name = node.name(); + if name.starts_with("memory") { + continue; + } + + // Skip the interrupt controller, as we will use vGIC + // TODO: filter with compatible property and parse its phandle from DT; maybe needs a second pass? + const GIC_PHANDLE: usize = 1; + if name.starts_with("interrupt-controller") + || name.starts_with("intc") + || name.starts_with("its") + { + debug!("skipping node {} to use vGIC", name); + continue; + } + + // Collect all GIC_SPI interrupts and add them to vGIC + if let Some(interrupts) = node.interrupts() { + // skip non-GIC interrupt + if let Some(parent) = node.interrupt_parent() { + trace!("node: {}, intr parent: {}", name, parent.node.name()); + if let Some(phandle) = parent.node.phandle() { + if phandle.as_usize() != GIC_PHANDLE { + warn!( + "node: {}, intr parent: {}, phandle: 0x{:x} is not GIC!", + name, + parent.node.name(), + phandle.as_usize() + ); + } + } else { + warn!( + "node: {}, intr parent: {} no phandle!", + name, + parent.node.name(), + ); + } + } else { + trace!("node: {} no interrupt parent!", name); + } + + for interrupt in interrupts { + // + for (k, v) in interrupt.enumerate() { + match k { + 0 => { + if v == 0 { + trace!("node: {}, GIC_SPI", name); + } else { + warn!( + "node: {}, intr type: {}, not GIC_SPI, not supported!", + name, v + ); + break; + } + } + 1 => { + trace!("node: {}, interrupt id: 0x{:x}", name, v); + vm_cfg.add_pass_through_spi(v); + } + 2 => { + trace!("node: {}, interrupt mode: 0x{:x}", name, v); + } + _ => { + warn!("unknown interrupt property {}:0x{:x}", k, v) + } + } + } + } + } + } + + vm_cfg.add_pass_through_device(axvm::config::PassThroughDeviceConfig { + name: "Fake Node".to_string(), + base_gpa: 0x0, + base_hpa: 0x0, + length: 0x20_0000, + irq_id: 0, + }); +} \ No newline at end of file From 45f9173ecdcb596c5c4833f159ae562ea989eb67 Mon Sep 17 00:00:00 2001 From: szy Date: Fri, 19 Sep 2025 11:16:16 +0800 Subject: [PATCH 08/30] memory ok --- src/vmm/fdt/create.rs | 3 - src/vmm/fdt/parser.rs | 228 ++++++++++++++++++++++++++---------------- 2 files changed, 142 insertions(+), 89 deletions(-) diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index f8c628b5..dd2845a4 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -87,10 +87,7 @@ pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, crate_ assert_eq!(previous_node_level , 0); let guest_fdt_bytes = fdt_writer.finish().unwrap(); - - print_guest_fdt(guest_fdt_bytes.as_slice()); - // 返回生成的DTB数据,让调用者决定如何使用 guest_fdt_bytes } diff --git a/src/vmm/fdt/parser.rs b/src/vmm/fdt/parser.rs index f85bd052..071b0050 100644 --- a/src/vmm/fdt/parser.rs +++ b/src/vmm/fdt/parser.rs @@ -1,9 +1,8 @@ //! FDT parsing and processing functionality. -use alloc::vec::Vec; use alloc::string::ToString; -use fdt_parser::{Fdt, FdtHeader, PciSpace}; -use axvm::config::{AxVMConfig, AxVMCrateConfig}; - +use alloc::vec::Vec; +use axvm::config::{AxVMConfig, AxVMCrateConfig, PassThroughDeviceConfig}; +use fdt_parser::{Fdt, FdtHeader, PciSpace, PciRange}; pub fn parse_fdt(fdt_addr: usize, vm_cfg: &mut AxVMConfig, crate_config: &AxVMCrateConfig) { const FDT_VALID_MAGIC: u32 = 0xd00d_feed; @@ -34,7 +33,8 @@ pub fn parse_fdt(fdt_addr: usize, vm_cfg: &mut AxVMConfig, crate_config: &AxVMCr // 调用修改后的函数并获取返回的设备名称列表 let passthrough_device_names = super::device::find_all_passthrough_devices(vm_cfg, &fdt); - let _ = super::create::crate_guest_fdt_with_cache(&fdt, &passthrough_device_names, crate_config); + let _ = + super::create::crate_guest_fdt_with_cache(&fdt, &passthrough_device_names, crate_config); // 注意:这里我们不再需要将设备添加到VM配置中,因为函数已经返回了设备名称列表 } @@ -43,7 +43,11 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM let host_cpus: Vec<_> = fdt.find_nodes("/cpus/cpu").collect(); info!("Found {} host CPU nodes", &host_cpus.len()); - let phys_cpu_ids = crate_config.base.phys_cpu_ids.as_ref().expect("ERROR: phys_cpu_ids not found in config.toml"); + let phys_cpu_ids = crate_config + .base + .phys_cpu_ids + .as_ref() + .expect("ERROR: phys_cpu_ids not found in config.toml"); // 收集所有CPU节点信息到Vec中,避免多次使用迭代器 let cpu_nodes_info: Vec<_> = host_cpus @@ -98,12 +102,16 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM new_phys_cpu_sets.push(cpu_mask); debug!( "vCPU {} with phys_cpu_id 0x{:x} mapped to CPU index {} (mask: 0x{:x})", - vm_cfg.id(), phys_cpu_id, cpu_index, cpu_mask + vm_cfg.id(), + phys_cpu_id, + cpu_index, + cpu_mask ); } else { error!( "vCPU {} with phys_cpu_id 0x{:x} not found in device tree!", - vm_cfg.id(), phys_cpu_id + vm_cfg.id(), + phys_cpu_id ); } } @@ -111,12 +119,100 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM // 更新VM配置中的phys_cpu_sets(如果VM配置支持设置的话) info!("Calculated phys_cpu_sets: {:?}", new_phys_cpu_sets); - vm_cfg.phys_cpu_ls_mut().set_guest_cpu_sets(new_phys_cpu_sets); + vm_cfg + .phys_cpu_ls_mut() + .set_guest_cpu_sets(new_phys_cpu_sets); - debug!("vcpu_mappings: {:?}", vm_cfg.phys_cpu_ls_mut().get_vcpu_affinities_pcpu_ids()); + debug!( + "vcpu_mappings: {:?}", + vm_cfg.phys_cpu_ls_mut().get_vcpu_affinities_pcpu_ids() + ); } -pub fn parse_passthrough_devices_address(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { +/// 为设备添加地址映射配置 +fn add_device_address_config( + vm_cfg: &mut AxVMConfig, + node_name: &str, + base_address: usize, + size: usize, + index: usize, + prefix: Option<&str>, +) { + // 只处理有地址信息的设备 + if size == 0 { + return; + } + + // 为每个地址段创建一个设备配置 + let device_name = if index == 0 { + match prefix { + Some(p) => format!("{}-{}", node_name, p), + None => node_name.to_string(), + } + } else { + match prefix { + Some(p) => format!("{}-{}-region{}", node_name, p, index), + None => format!("{}-region{}", node_name, index), + } + }; + + // 添加新的设备配置 + let pt_dev = axvm::config::PassThroughDeviceConfig { + name: device_name, + base_gpa: base_address, + base_hpa: base_address, + length: size, + irq_id: 0, + }; + vm_cfg.add_pass_through_device(pt_dev); +} + +/// 为PCIe设备添加ranges属性配置 +fn add_pci_ranges_config( + vm_cfg: &mut AxVMConfig, + node_name: &str, + range: &PciRange, + index: usize, +) { + let base_address = range.cpu_address as usize; + let size = range.size as usize; + + // 只处理有地址信息的设备 + if size == 0 { + return; + } + + // 为每个地址段创建一个设备配置 + let prefix = match range.space { + PciSpace::Configuration => "config", + PciSpace::IO => "io", + PciSpace::Memory32 => "mem32", + PciSpace::Memory64 => "mem64", + }; + + let device_name = if index == 0 { + format!("{}-{}", node_name, prefix) + } else { + format!("{}-{}-region{}", node_name, prefix, index) + }; + + // 添加新的设备配置 + let pt_dev = axvm::config::PassThroughDeviceConfig { + name: device_name, + base_gpa: base_address, + base_hpa: base_address, + length: size, + irq_id: 0, + }; + vm_cfg.add_pass_through_device(pt_dev); + + trace!( + "Added PCIe passthrough device {}: base=0x{:x}, size=0x{:x}, space={:?}", + node_name, base_address, size, range.space + ); +} + +pub fn parse_passthrough_devices_address(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { let fdt = Fdt::from_bytes(dtb) .expect("Failed to parse DTB image, perhaps the DTB is invalid or corrupted"); @@ -129,53 +225,31 @@ pub fn parse_passthrough_devices_address(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { if node.name() == "/" || node.name().starts_with("memory") { continue; } - + let node_name = node.name().to_string(); - + // 检查是否为PCIe设备节点 if node_name.starts_with("pcie@") || node_name.contains("pci") { // 处理PCIe设备的ranges属性 - if let Some(pci) = node.into_pci() { + if let Some(pci) = node.clone().into_pci() { if let Ok(ranges) = pci.ranges() { for (index, range) in ranges.enumerate() { - let base_address = range.cpu_address as usize; - let size = range.size as usize; - - // 只处理有地址信息的设备 - if size > 0 { - // 为每个地址段创建一个设备配置 - let device_name = if index == 0 { - format!("{}-{}", node_name, match range.space { - PciSpace::Configuration => "config", - PciSpace::IO => "io", - PciSpace::Memory32 => "mem32", - PciSpace::Memory64 => "mem64", - }) - } else { - format!("{}-{}-region{}", node_name, match range.space { - PciSpace::Configuration => "config", - PciSpace::IO => "io", - PciSpace::Memory32 => "mem32", - PciSpace::Memory64 => "mem64", - }, index) - }; - - // 添加新的设备配置 - let pt_dev = axvm::config::PassThroughDeviceConfig { - name: device_name, - base_gpa: base_address, - base_hpa: base_address, - length: size, - irq_id: 0, - }; - vm_cfg.add_pass_through_device(pt_dev); - - trace!("Added PCIe passthrough device {}: base=0x{:x}, size=0x{:x}, space={:?}", - node_name, base_address, size, range.space); - } + add_pci_ranges_config(vm_cfg, &node_name, &range, index); } } } + + // 处理PCIe设备的reg属性(ECAM空间) + if let Some(mut reg_iter) = node.reg() { + let mut index = 0; + while let Some(reg) = reg_iter.next() { + let base_address = reg.address as usize; + let size = reg.size.unwrap_or(0) as usize; + + add_device_address_config(vm_cfg, &node_name, base_address, size, index, Some("ecam")); + index += 1; + } + } } else { // 获取设备的reg属性(处理普通设备) if let Some(mut reg_iter) = node.reg() { @@ -185,65 +259,47 @@ pub fn parse_passthrough_devices_address(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { // 获取设备的地址和大小信息 let base_address = reg.address as usize; let size = reg.size.unwrap_or(0) as usize; - - // 只处理有地址信息的设备 - if size > 0 { - // 为每个地址段创建一个设备配置 - // 如果设备有多个地址段,使用索引来区分 - let device_name = if index == 0 { - node_name.clone() - } else { - format!("{}-region{}", node_name, index) - }; - - // 添加新的设备配置 - let pt_dev = axvm::config::PassThroughDeviceConfig { - name: device_name, - base_gpa: base_address, - base_hpa: base_address, - length: size, - irq_id: 0, - }; - vm_cfg.add_pass_through_device(pt_dev); - - trace!("Added passthrough device {}: base=0x{:x}, size=0x{:x}", node_name, base_address, size); - } - + + add_device_address_config(vm_cfg, &node_name, base_address, size, index, None); index += 1; } } } } - trace!("All passthrough devices: {:#x?}", vm_cfg.pass_through_devices()); - info!("Finished parsing passthrough devices, total: {}", vm_cfg.pass_through_devices().len()); + trace!( + "All passthrough devices: {:#x?}", + vm_cfg.pass_through_devices() + ); + info!( + "Finished parsing passthrough devices, total: {}", + vm_cfg.pass_through_devices().len() + ); } pub fn parse_vm_interrupt(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { - + const GIC_PHANDLE: usize = 1; let fdt = Fdt::from_bytes(dtb) .expect("Failed to parse DTB image, perhaps the DTB is invalid or corrupted"); for node in fdt.all_nodes() { - trace!("DTB node: {:?}", node.name()); let name = node.name(); + if name.starts_with("memory") { continue; - } - + } // Skip the interrupt controller, as we will use vGIC // TODO: filter with compatible property and parse its phandle from DT; maybe needs a second pass? - const GIC_PHANDLE: usize = 1; - if name.starts_with("interrupt-controller") + else if name.starts_with("interrupt-controller") || name.starts_with("intc") || name.starts_with("its") { - debug!("skipping node {} to use vGIC", name); + info!("skipping node {} to use vGIC", name); continue; } // Collect all GIC_SPI interrupts and add them to vGIC if let Some(interrupts) = node.interrupts() { - // skip non-GIC interrupt + // TODO: skip non-GIC interrupt if let Some(parent) = node.interrupt_parent() { trace!("node: {}, intr parent: {}", name, parent.node.name()); if let Some(phandle) = parent.node.phandle() { @@ -263,7 +319,7 @@ pub fn parse_vm_interrupt(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { ); } } else { - trace!("node: {} no interrupt parent!", name); + warn!("node: {} no interrupt parent!", name); } for interrupt in interrupts { @@ -297,11 +353,11 @@ pub fn parse_vm_interrupt(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { } } - vm_cfg.add_pass_through_device(axvm::config::PassThroughDeviceConfig { + vm_cfg.add_pass_through_device(PassThroughDeviceConfig { name: "Fake Node".to_string(), base_gpa: 0x0, base_hpa: 0x0, length: 0x20_0000, irq_id: 0, }); -} \ No newline at end of file +} From 2de29c3638ae7f987ddcb90c8c99ba3bc0cc8825 Mon Sep 17 00:00:00 2001 From: szy Date: Fri, 19 Sep 2025 15:22:53 +0800 Subject: [PATCH 09/30] log --- src/vmm/config.rs | 5 +- src/vmm/fdt/create.rs | 145 +++++++++++++++++++-------------------- src/vmm/fdt/device.rs | 156 +++++++++++++++++------------------------- src/vmm/fdt/mod.rs | 2 +- src/vmm/fdt/parser.rs | 83 ++++++++++------------ src/vmm/fdt/test.rs | 54 +++++++-------- 6 files changed, 198 insertions(+), 247 deletions(-) diff --git a/src/vmm/config.rs b/src/vmm/config.rs index 39ef26f7..f42624a0 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -1,11 +1,8 @@ use core::alloc::Layout; - -use alloc::string::ToString; - use axaddrspace::GuestPhysAddr; use axvm::{ VMMemoryRegion, - config::{AxVMConfig, AxVMCrateConfig, PassThroughDeviceConfig, VmMemMappingType}, + config::{AxVMConfig, AxVMCrateConfig, VmMemMappingType}, }; use memory_addr::MemoryAddr; diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index dd2845a4..5f0b67c8 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -1,45 +1,41 @@ -use alloc::string::String; -use alloc::string::ToString; -use alloc::vec::Vec; +use alloc::{ + string::{String, ToString}, + sync::Arc, + vec::Vec, +}; +use core::ptr::NonNull; + +use axaddrspace::GuestPhysAddr; +use axvm::{ + config::AxVMCrateConfig, + VMMemoryRegion, +}; use fdt_parser::{Fdt, Node}; use vm_fdt::{FdtWriter, FdtWriterNode}; -use axvm::config::{AxVMConfig, AxVMCrateConfig}; -use crate::vmm::{VMRef, images::load_vm_image_from_memory}; -use axaddrspace::GuestPhysAddr; -use core::ptr::NonNull; -use axvm::VMMemoryRegion; -use crate::vmm::fdt::print_fdt; -use crate::vmm::fdt::test::print_guest_fdt; -// 引入缓存相关的模块 -use alloc::collections::BTreeMap; -use alloc::sync::Arc; -use spin::Mutex; -use lazyinit::LazyInit; +use crate::vmm::{images::load_vm_image_from_memory, VMRef}; -/// 生成客户机FDT并返回DTB数据 +/// Generate guest FDT and return DTB data /// -/// # 参数 -/// * `fdt` - 源FDT数据 -/// * `passthrough_device_names` - 直通设备名称列表 -/// * `crate_config` - VM创建配置 +/// # Parameters +/// * `fdt` - Source FDT data +/// * `passthrough_device_names` - Passthrough device name list +/// * `crate_config` - VM creation configuration /// -/// # 返回值 -/// 返回生成的DTB数据 +/// # Return Value +/// Returns the generated DTB data pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, crate_config: &AxVMCrateConfig) -> Vec { let mut fdt_writer = FdtWriter::new().unwrap(); - // 跟踪上一个处理节点的层级,用于层级变化处理 + // Track the level of the previously processed node for level change handling let mut previous_node_level = 0; - // 维护FDT节点栈,用于正确开始和结束节点 + // Maintain a stack of FDT nodes to correctly start and end nodes let mut node_stack: Vec = Vec::new(); let phys_cpu_ids = crate_config.base.phys_cpu_ids.clone().expect("ERROR: phys_cpu_ids is None"); let all_nodes: Vec = fdt.all_nodes().collect(); for (index, node) in all_nodes.iter().enumerate() { - // 使用独立函数构建节点路径 let node_path = super::build_node_path(&all_nodes, index); - // 处理不同类型的节点 let node_action = determine_node_action( node, &node_path, @@ -60,11 +56,9 @@ pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, crate_ } }, NodeAction::Skip => { - // 不需要包含在客户机FDT中的节点 continue; }, _ => { - // 完全匹配的直通设备节点 trace!("Found exact passthrough device node: {}, path: {}", node.name(), node_path); handle_node_level_change(&mut fdt_writer, &mut node_stack, node.level, previous_node_level); node_stack.push(fdt_writer.begin_node(node.name()).unwrap()); @@ -73,13 +67,13 @@ pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, crate_ previous_node_level = node.level; - // 复制节点的所有属性 + // Copy all properties of the node for prop in node.propertys() { fdt_writer.property(prop.name, prop.raw_value()).unwrap(); } } - // 结束所有未关闭的节点 + // End all unclosed nodes while let Some(node) = node_stack.pop() { previous_node_level -= 1; fdt_writer.end_node(node).unwrap(); @@ -87,24 +81,24 @@ pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, crate_ assert_eq!(previous_node_level , 0); let guest_fdt_bytes = fdt_writer.finish().unwrap(); - + guest_fdt_bytes } -/// 生成客户机FDT并缓存结果 +/// Generate guest FDT and cache the result /// -/// # 参数 -/// * `fdt` - 源FDT数据 -/// * `passthrough_device_names` - 直通设备名称列表 -/// * `crate_config` - VM创建配置 +/// # Parameters +/// * `fdt` - Source FDT data +/// * `passthrough_device_names` - Passthrough device name list +/// * `crate_config` - VM creation configuration /// -/// # 返回值 -/// 返回生成的DTB数据,并将其存储在全局缓存中 +/// # Return Value +/// Returns the generated DTB data and stores it in the global cache pub fn crate_guest_fdt_with_cache(fdt: &Fdt, passthrough_device_names: &Vec, crate_config: &AxVMCrateConfig) -> Vec { - // 生成DTB数据 + // Generate DTB data let dtb_data = crate_guest_fdt(fdt, passthrough_device_names, crate_config); - // 将数据存储到全局缓存中 + // Store data in global cache if let Some(cache) = crate::vmm::config::GENERATED_DTB_CACHE.get() { let mut cache_lock = cache.lock(); let dtb_arc: Arc<[u8]> = Arc::from(dtb_data.clone()); @@ -114,45 +108,45 @@ pub fn crate_guest_fdt_with_cache(fdt: &Fdt, passthrough_device_names: &Vec, ) -> NodeAction { if node.name() == "/" { - // 根节点特殊处理 + // Special handling for root node return NodeAction::RootNode; } else if node.name().starts_with("memory") { - // 跳过memory节点,稍后会单独添加 + // Skip memory nodes, will add them later return NodeAction::Skip; } else if node_path.starts_with("/cpus"){ return NodeAction::CpuNode; } else if passthrough_device_names.contains(&node_path.to_string()) { - // 完全匹配的直通设备节点 + // Fully matched passthrough device node return NodeAction::IncludeAsPassthroughDevice; } - // 检查是否为直通设备的后代节点(通过路径包含关系和层级验证) + // Check if the node is a descendant of a passthrough device (by path inclusion and level validation) else if is_descendant_of_passthrough_device(node_path, node.level, passthrough_device_names) { return NodeAction::IncludeAsChildNode; } - // 检查是否为直通设备的祖先节点(通过路径包含关系和层级验证) + // Check if the node is an ancestor of a passthrough device (by path inclusion and level validation) else if is_ancestor_of_passthrough_device(node_path, passthrough_device_names) { return NodeAction::IncludeAsAncestorNode; } else { @@ -160,22 +154,22 @@ fn determine_node_action( } } -/// 判断节点是否为直通设备的后代节点 -/// 当节点路径包含passthrough_device_names中某个节点路径,且比其长时,即为其后代节点 -/// 同时使用node_level作为验证条件 +/// Determine if node is a descendant of passthrough device +/// When node path contains a path from passthrough_device_names and is longer than it, it is its descendant node +/// Also use node_level as validation condition fn is_descendant_of_passthrough_device(node_path: &str, node_level: usize, passthrough_device_names: &Vec) -> bool { for passthrough_path in passthrough_device_names { - // 检查当前节点是否为直通设备的后代节点 + // Check if the current node is a descendant of a passthrough device if node_path.starts_with(passthrough_path) && node_path.len() > passthrough_path.len() { - // 确保是真正的后代路径(以/分隔) + // Ensure it is a true descendant path (separated by /) if passthrough_path == "/" || node_path.chars().nth(passthrough_path.len()) == Some('/') { - // 使用层级关系进行验证:后代节点的层级应该比父节点高 - // 注意:根节点的层级为1,其直接子节点层级为2,以此类推 + // Use level relationship for validation: the level of a descendant node should be higher than its parent + // Note: The level of the root node is 1, its direct child node level is 2, and so on let expected_parent_level = passthrough_path.matches('/').count(); let current_node_level = node_level; - // 如果passthrough_path是根节点"/",则其子节点层级应为2 - // 否则,子节点层级应比父节点层级高 + // If passthrough_path is the root node "/", then its child node level should be 2 + // Otherwise, the child node level should be higher than the parent node level if passthrough_path == "/" && current_node_level >= 2 { return true; } else if passthrough_path != "/" && current_node_level > expected_parent_level { @@ -187,7 +181,7 @@ fn is_descendant_of_passthrough_device(node_path: &str, node_level: usize, passt false } -/// 处理节点层级变化,确保FDT结构正确 +/// Handle node level changes to ensure correct FDT structure fn handle_node_level_change( fdt_writer: &mut FdtWriter, node_stack: &mut Vec, @@ -203,12 +197,12 @@ fn handle_node_level_change( } } -/// 判断节点是否为直通设备的祖先节点 +/// Determine if node is an ancestor of passthrough device fn is_ancestor_of_passthrough_device(node_path: &str, passthrough_device_names: &Vec) -> bool { for passthrough_path in passthrough_device_names { - // 检查当前节点是否为直通设备的祖先节点 + // Check if the current node is an ancestor of a passthrough device if passthrough_path.starts_with(&node_path) && passthrough_path.len() > node_path.len() { - // 确保是真正的祖先路径(以/分隔) + // Ensure it is a true ancestor path (separated by /) let next_char = passthrough_path.chars().nth(node_path.len()).unwrap_or(' '); if next_char == '/' || node_path == "/" { return true; @@ -218,6 +212,7 @@ fn is_ancestor_of_passthrough_device(node_path: &str, passthrough_device_names: false } +/// Determine if CPU node is needed fn need_cpu_node(phys_cpu_ids: &Vec, node: &Node, node_path: &str) -> bool{ let mut should_include_node = false; @@ -228,12 +223,12 @@ fn need_cpu_node(phys_cpu_ids: &Vec, node: &Node, node_path: &str) -> boo if let Some(reg_entry) = cpu_reg.next() { let cpu_address = reg_entry.address as usize; debug!("Checking CPU node {} with address 0x{:x}", node.name(), cpu_address); - // 检查这个CPU地址是否在配置的phys_cpu_ids中 - if phys_cpu_ids.contains(&&cpu_address) { + // Check if this CPU address is in the configured phys_cpu_ids + if phys_cpu_ids.contains(&cpu_address) { should_include_node = true; - info!("CPU node {} with address 0x{:x} is in phys_cpu_ids, including in guest FDT", node.name(), cpu_address); + debug!("CPU node {} with address 0x{:x} is in phys_cpu_ids, including in guest FDT", node.name(), cpu_address); } else { - info!("CPU node {} with address 0x{:x} is NOT in phys_cpu_ids, skipping", node.name(), cpu_address); + debug!("CPU node {} with address 0x{:x} is NOT in phys_cpu_ids, skipping", node.name(), cpu_address); } } } @@ -241,6 +236,7 @@ fn need_cpu_node(phys_cpu_ids: &Vec, node: &Node, node_path: &str) -> boo should_include_node } +/// Add memory node fn add_memory_node(new_memory: &[VMMemoryRegion], new_fdt: &mut FdtWriter) { let mut new_value: Vec = Vec::new(); for mem in new_memory { @@ -251,7 +247,6 @@ fn add_memory_node(new_memory: &[VMMemoryRegion], new_fdt: &mut FdtWriter) { new_value.push((size >> 32) as u32); new_value.push((size & 0xFFFFFFFF) as u32); } - trace!("new_value: {:x?}", new_value); new_fdt .property_array_u32("reg", new_value.as_ref()) .unwrap(); @@ -270,15 +265,13 @@ pub fn update_fdt(dest_addr: GuestPhysAddr, fdt_src: NonNull, dtb_size: usiz for node in fdt.all_nodes() { if node.name() == "/" { - // 根节点处理 node_stack.push(new_fdt.begin_node("").unwrap()); } else if node.name().starts_with("memory") { // Skip memory nodes, will add them later continue; } else { - // 处理节点层级变化 handle_node_level_change(&mut new_fdt, &mut node_stack, node.level, previous_node_level); - // 开始新节点 + // Start new node node_stack.push(new_fdt.begin_node(node.name()).unwrap()); } @@ -289,7 +282,7 @@ pub fn update_fdt(dest_addr: GuestPhysAddr, fdt_src: NonNull, dtb_size: usiz } } - // 结束所有未关闭的节点,并在适当位置添加内存节点 + // End all unclosed nodes, and add memory nodes at appropriate positions while let Some(node) = node_stack.pop() { previous_node_level -= 1; new_fdt.end_node(node).unwrap(); @@ -306,6 +299,6 @@ pub fn update_fdt(dest_addr: GuestPhysAddr, fdt_src: NonNull, dtb_size: usiz assert_eq!(previous_node_level, 0); let new_fdt_bytes = new_fdt.finish().unwrap(); - // 加载更新后的FDT到VM + // Load the updated FDT into VM load_vm_image_from_memory(&new_fdt_bytes, dest_addr, vm.clone()).expect("Failed to load VM images"); } diff --git a/src/vmm/fdt/device.rs b/src/vmm/fdt/device.rs index 93ff3b0a..ffe165bf 100644 --- a/src/vmm/fdt/device.rs +++ b/src/vmm/fdt/device.rs @@ -1,47 +1,39 @@ //! Device passthrough and dependency analysis for FDT processing. -use alloc::collections::{BTreeMap, BTreeSet}; -use alloc::string::String; -use alloc::string::ToString; -use alloc::vec::Vec; +use alloc::{ + collections::{BTreeMap, BTreeSet}, + string::{String, ToString}, + vec::Vec, +}; use fdt_parser::{Fdt, Node}; use axvm::config::{AxVMConfig}; -/// 完善直通设备配置 -/// 修改为返回配置文件中所有直通设备和查找到的新添加设备的合集,而不是直接修改VM配置 -/// 优化版本:预构建节点缓存以提高性能 +/// Return the collection of all passthrough devices in the configuration file and newly added devices found pub fn find_all_passthrough_devices(vm_cfg: &mut AxVMConfig, fdt: &Fdt) -> Vec { - // 先获取初始设备数量,避免借用冲突 let initial_device_count = vm_cfg.pass_through_devices().len(); - info!("Starting passthrough devices analysis..."); - info!( - "Original passthrough_devices count: {}", - initial_device_count - ); - // 预构建节点缓存,将所有节点按路径存储以提高查找性能 + // Pre-build node cache, store all nodes by path to improve lookup performance let node_cache: BTreeMap> = build_optimized_node_cache(fdt); - - // 获取已配置设备的名称列表 + // Get the list of configured device names let initial_device_names: Vec = vm_cfg .pass_through_devices() .iter() .map(|dev| dev.name.clone()) .collect(); - // 第一阶段:发现所有配置文件中直通设备的后代节点 - // 构建已配置设备的集合,使用BTreeSet提高查找效率 + // Phase 1: Discover descendant nodes of all passthrough devices in the configuration file + // Build a set of configured devices, using BTreeSet to improve lookup efficiency let mut configured_device_names: BTreeSet = initial_device_names.iter().cloned().collect(); - // 用于存储新发现的相关设备名称 + // Used to store newly discovered related device names let mut additional_device_names = Vec::new(); - // 第一阶段:处理初始设备及其后代节点 - // 注意:这里我们直接使用设备路径而不是设备名称 + // Phase 1: Process initial devices and their descendant nodes + // Note: Directly use device paths instead of device names for device_name in &initial_device_names { - // 获取该设备的所有后代节点路径 + // Get all descendant node paths for this device let descendant_paths = get_descendant_nodes_by_path(&node_cache, device_name); trace!( "Found {} descendant paths for {}", @@ -49,7 +41,6 @@ pub fn find_all_passthrough_devices(vm_cfg: &mut AxVMConfig, fdt: &Fdt) -> Vec Vec Vec = configured_device_names.iter().cloned().collect(); let mut processed_devices: BTreeSet = BTreeSet::new(); - // 构建phandle映射表 + // Build phandle mapping table let phandle_map = build_phandle_map(fdt); - // 使用工作队列递归查找所有依赖设备 + // Use work queue to recursively find all dependent devices while let Some(device_node_path) = devices_to_process.pop() { - // 避免重复处理同一设备 + // Avoid processing the same device repeatedly if processed_devices.contains(&device_node_path) { continue; } @@ -90,16 +80,16 @@ pub fn find_all_passthrough_devices(vm_cfg: &mut AxVMConfig, fdt: &Fdt) -> Vec Vec Vec, target_index: usize) -> String { - // 用于维护路径栈 let mut path_stack: Vec = Vec::new(); - - // 遍历从根节点到目标节点的所有节点 + for i in 0..=target_index { let node = &all_nodes[i]; let level = node.level; if level == 1 { - // 根节点特殊处理 path_stack.clear(); if node.name() != "/" { path_stack.push(node.name().to_string()); } } else { - // 根据level关系处理节点 while path_stack.len() >= level - 1 { path_stack.pop(); } @@ -158,7 +143,7 @@ pub fn build_node_path(all_nodes: &Vec, target_index: usize) -> String { } } - // 构建当前节点的完整路径 + // Build the full path of the current node if path_stack.is_empty() || (path_stack.len() == 1 && path_stack[0] == "/") { "/".to_string() } else { @@ -166,20 +151,15 @@ pub fn build_node_path(all_nodes: &Vec, target_index: usize) -> String { } } -/// 构建简化的节点缓存表,一次性遍历所有节点并按全路径分组 -/// 使用level关系直接构建路径,避免同名节点路径冲突问题 +/// Build a simplified node cache table, traverse all nodes once and group by full path +/// Use level relationships to directly build paths, avoiding path conflicts for nodes with the same name pub fn build_optimized_node_cache<'a>(fdt: &'a Fdt) -> BTreeMap>> { let mut node_cache: BTreeMap>> = BTreeMap::new(); - // 收集所有节点 let all_nodes: Vec = fdt.all_nodes().collect(); - // 遍历所有节点,根据level关系构建路径 for (index, node) in all_nodes.iter().enumerate() { - // 使用独立函数构建节点路径 let node_path = build_node_path(&all_nodes, index); - - // 检查是否有相同的node_path,如果有则报错 if let Some(existing_nodes) = node_cache.get(&node_path) { if !existing_nodes.is_empty() { error!( @@ -206,24 +186,20 @@ pub fn build_optimized_node_cache<'a>(fdt: &'a Fdt) -> BTreeMap BTreeMap)> { let mut phandle_map = BTreeMap::new(); - - // 收集所有节点 + let all_nodes: Vec = fdt.all_nodes().collect(); - // 遍历所有节点,根据level关系构建路径 for (index, node) in all_nodes.iter().enumerate() { - // 使用独立函数构建节点路径 let node_path = build_node_path(&all_nodes, index); + // Collect node properties let mut phandle = None; let mut cells_map = BTreeMap::new(); - - // 收集节点的属性 for prop in node.propertys() { match prop.name { "phandle" | "linux,phandle" => { @@ -249,7 +225,7 @@ fn build_phandle_map(fdt: &Fdt) -> BTreeMap) } } - // 如果找到phandle,将其与节点完整路径一起存储 + // If phandle is found, store it together with the node's full path if let Some(ph) = phandle { phandle_map.insert(ph, (node_path, cells_map)); } @@ -257,11 +233,11 @@ fn build_phandle_map(fdt: &Fdt) -> BTreeMap) phandle_map } -/// 根据#*-cells属性智能解析包含phandle引用的属性 -/// 支持多种格式: -/// - 单个phandle: +/// Parse properties containing phandle references intelligently based on #*-cells properties +/// Supports multiple formats: +/// - Single phandle: /// - phandle+specifier: -/// - 多个phandle引用: +/// - Multiple phandle references: fn parse_phandle_property_with_cells( prop_data: &[u8], prop_name: &str, @@ -275,7 +251,6 @@ fn parse_phandle_property_with_cells( prop_data.len() ); - // 检查数据长度是否有效 if prop_data.is_empty() || prop_data.len() % 4 != 0 { warn!( "Property '{}' data length ({} bytes) is invalid", @@ -294,16 +269,16 @@ fn parse_phandle_property_with_cells( while i < u32_values.len() { let potential_phandle = u32_values[i]; - // 检查是否为有效的phandle + // Check if it's a valid phandle if let Some((device_name, cells_info)) = phandle_map.get(&potential_phandle) { - // 根据属性名确定需要的cells数量 + // Determine the number of cells required based on property name let cells_count = get_cells_count_for_property(prop_name, cells_info); trace!( "Property '{}' requires {} cells for device '{}'", prop_name, cells_count, device_name ); - // 检查是否有足够的数据 + // Check if there's enough data if i + cells_count < u32_values.len() { let specifiers: Vec = u32_values[i + 1..=i + cells_count].to_vec(); debug!( @@ -311,7 +286,7 @@ fn parse_phandle_property_with_cells( potential_phandle, specifiers ); results.push((potential_phandle, specifiers)); - i += cells_count + 1; // 跳过phandle和所有specifier + i += cells_count + 1; // Skip phandle and all specifiers } else { warn!( "Property:{} not enough data for phandle {:#x}, expected {} cells but only {} values remaining", @@ -323,7 +298,7 @@ fn parse_phandle_property_with_cells( break; } } else { - // 如果不是有效phandle,跳过这个值 + // If not a valid phandle, skip this value i += 1; } } @@ -331,7 +306,7 @@ fn parse_phandle_property_with_cells( results } -/// 根据属性名和目标节点的cells信息确定需要的cells数量 +/// Determine the required number of cells based on property name and target node's cells information fn get_cells_count_for_property(prop_name: &str, cells_info: &BTreeMap) -> usize { let cells_property = match prop_name { "clocks" | "assigned-clocks" => "#clock-cells", @@ -356,10 +331,10 @@ fn get_cells_count_for_property(prop_name: &str, cells_info: &BTreeMap bool { Self::PHANDLE_PROPERTIES.contains(&prop_name) || prop_name.ends_with("-supply") @@ -429,22 +404,20 @@ impl DevicePropertyClassifier { } } -/// 查找设备的依赖关系 -/// 现在接受设备节点路径而不是节点引用 -/// 优化版本:使用node_cache而不是遍历所有节点 +/// Find device dependencies fn find_device_dependencies( device_node_path: &str, phandle_map: &BTreeMap)>, - node_cache: &BTreeMap>, // 添加node_cache参数 + node_cache: &BTreeMap>, // Add node_cache parameter ) -> Vec { let mut dependencies = Vec::new(); - // 直接从node_cache中查找节点,避免遍历所有节点 + // Directly find nodes from node_cache, avoiding traversing all nodes if let Some(nodes) = node_cache.get(device_node_path) { - // 遍历节点的所有属性查找依赖关系 + // Traverse all properties of nodes to find dependencies for node in nodes { for prop in node.propertys() { - // 判断是否为需要处理的phandle属性 + // Determine if it's a phandle property that needs to be processed if DevicePropertyClassifier::is_phandle_property(prop.name) { let mut prop_deps = parse_phandle_property(prop.raw_value(), prop.name, phandle_map); dependencies.append(&mut prop_deps); @@ -456,24 +429,23 @@ fn find_device_dependencies( dependencies } -/// 根据父节点路径获取所有后代节点(包括子节点、孙节点等) -/// 通过在node_cache中查找以父节点路径为前缀的节点来获取所有后代节点 -/// 这种方法比get_all_descendant_nodes更高效,因为它直接使用缓存 +/// Get all descendant nodes based on parent node path (including child nodes, grandchild nodes, etc.) +/// Find all descendant nodes by looking up nodes with parent node path as prefix in node_cache fn get_descendant_nodes_by_path<'a>(node_cache: &'a BTreeMap>>, parent_path: &str) -> Vec { let mut descendant_paths = Vec::new(); - // 如果父路径是根路径,特殊处理 + // Special handling if parent path is root path let search_prefix = if parent_path == "/" { "/".to_string() } else { parent_path.to_string() + "/" }; - // 遍历node_cache,查找所有以父路径为前缀的节点 + // Traverse node_cache, find all nodes with parent path as prefix for (path, _nodes) in node_cache { - // 检查路径是否以父路径为前缀(并且不是父路径本身) + // Check if path has parent path as prefix (and is not the parent path itself) if path.starts_with(&search_prefix) && path.len() > search_prefix.len() { - // 这是后代节点的路径,添加到结果中 + // This is a descendant node path, add to results descendant_paths.push(path.clone()); } } diff --git a/src/vmm/fdt/mod.rs b/src/vmm/fdt/mod.rs index 3c62ad46..926efe3c 100644 --- a/src/vmm/fdt/mod.rs +++ b/src/vmm/fdt/mod.rs @@ -10,6 +10,6 @@ mod test; // Re-export public functions pub use parser::{parse_fdt, parse_passthrough_devices_address, parse_vm_interrupt}; -pub use test::print_fdt; +// pub use test::print_fdt; pub use device::{build_node_path}; pub use create::update_fdt; \ No newline at end of file diff --git a/src/vmm/fdt/parser.rs b/src/vmm/fdt/parser.rs index 071b0050..cba9a319 100644 --- a/src/vmm/fdt/parser.rs +++ b/src/vmm/fdt/parser.rs @@ -1,8 +1,8 @@ //! FDT parsing and processing functionality. -use alloc::string::ToString; -use alloc::vec::Vec; + +use alloc::{string::ToString, vec::Vec}; use axvm::config::{AxVMConfig, AxVMCrateConfig, PassThroughDeviceConfig}; -use fdt_parser::{Fdt, FdtHeader, PciSpace, PciRange}; +use fdt_parser::{Fdt, FdtHeader, PciRange, PciSpace}; pub fn parse_fdt(fdt_addr: usize, vm_cfg: &mut AxVMConfig, crate_config: &AxVMCrateConfig) { const FDT_VALID_MAGIC: u32 = 0xd00d_feed; @@ -30,12 +30,11 @@ pub fn parse_fdt(fdt_addr: usize, vm_cfg: &mut AxVMConfig, crate_config: &AxVMCr .expect("Failed to parse FDT"); set_phys_cpu_sets(vm_cfg, &fdt, crate_config); - // 调用修改后的函数并获取返回的设备名称列表 + // Call the modified function and get the returned device name list let passthrough_device_names = super::device::find_all_passthrough_devices(vm_cfg, &fdt); let _ = super::create::crate_guest_fdt_with_cache(&fdt, &passthrough_device_names, crate_config); - // 注意:这里我们不再需要将设备添加到VM配置中,因为函数已经返回了设备名称列表 } pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVMCrateConfig) { @@ -43,13 +42,9 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM let host_cpus: Vec<_> = fdt.find_nodes("/cpus/cpu").collect(); info!("Found {} host CPU nodes", &host_cpus.len()); - let phys_cpu_ids = crate_config - .base - .phys_cpu_ids - .as_ref() - .expect("ERROR: phys_cpu_ids not found in config.toml"); + let phys_cpu_ids = crate_config.base.phys_cpu_ids.as_ref().expect("ERROR: phys_cpu_ids not found in config.toml"); - // 收集所有CPU节点信息到Vec中,避免多次使用迭代器 + // Collect all CPU node information into Vec to avoid using iterators multiple times let cpu_nodes_info: Vec<_> = host_cpus .iter() .filter_map(|cpu_node| { @@ -65,8 +60,8 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM }) .collect(); info!("cpu_nodes_info: {:?}", cpu_nodes_info); - // 创建从phys_cpu_id到物理CPU索引的映射 - // 收集所有唯一的CPU地址,保持设备树中的出现顺序 + // Create mapping from phys_cpu_id to physical CPU index + // Collect all unique CPU addresses, maintaining the order of appearance in the device tree let mut unique_cpu_addresses = Vec::new(); for (_, cpu_address) in &cpu_nodes_info { if !unique_cpu_addresses.contains(cpu_address) { @@ -76,52 +71,46 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM } } - // 为设备树中的每个CPU地址分配索引,并打印详细信息 + // Assign index to each CPU address in the device tree and print detailed information for (index, &cpu_address) in unique_cpu_addresses.iter().enumerate() { - // 找到所有使用这个地址的CPU节点 + // Find all CPU nodes using this address for (cpu_name, node_address) in &cpu_nodes_info { if *node_address == cpu_address { debug!( " CPU node: {}, address: 0x{:x}, assigned index: {}", cpu_name, cpu_address, index ); - break; // 每个地址只打印一次 + break; // Print each address only once } } } - // 根据vcpu_mappings中的phys_cpu_ids计算phys_cpu_sets + // Calculate phys_cpu_sets based on phys_cpu_ids in vcpu_mappings let mut new_phys_cpu_sets = Vec::new(); for phys_cpu_id in phys_cpu_ids { - // 在unique_cpu_addresses中查找phys_cpu_id对应的索引 + // Find the index corresponding to phys_cpu_id in unique_cpu_addresses if let Some(cpu_index) = unique_cpu_addresses .iter() .position(|&addr| addr == *phys_cpu_id) { - let cpu_mask = 1usize << cpu_index; // 将索引转换为掩码位 + let cpu_mask = 1usize << cpu_index; // Convert index to mask bit new_phys_cpu_sets.push(cpu_mask); debug!( "vCPU {} with phys_cpu_id 0x{:x} mapped to CPU index {} (mask: 0x{:x})", - vm_cfg.id(), - phys_cpu_id, - cpu_index, - cpu_mask + vm_cfg.id(), phys_cpu_id, cpu_index, cpu_mask ); } else { error!( "vCPU {} with phys_cpu_id 0x{:x} not found in device tree!", - vm_cfg.id(), - phys_cpu_id + vm_cfg.id(), phys_cpu_id ); } } - // 更新VM配置中的phys_cpu_sets(如果VM配置支持设置的话) + // Update phys_cpu_sets in VM configuration (if VM configuration supports setting) info!("Calculated phys_cpu_sets: {:?}", new_phys_cpu_sets); - vm_cfg - .phys_cpu_ls_mut() - .set_guest_cpu_sets(new_phys_cpu_sets); + vm_cfg.phys_cpu_ls_mut().set_guest_cpu_sets(new_phys_cpu_sets); debug!( "vcpu_mappings: {:?}", @@ -129,7 +118,7 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM ); } -/// 为设备添加地址映射配置 +/// Add address mapping configuration for a device fn add_device_address_config( vm_cfg: &mut AxVMConfig, node_name: &str, @@ -138,12 +127,12 @@ fn add_device_address_config( index: usize, prefix: Option<&str>, ) { - // 只处理有地址信息的设备 + // Only process devices with address information if size == 0 { return; } - // 为每个地址段创建一个设备配置 + // Create a device configuration for each address segment let device_name = if index == 0 { match prefix { Some(p) => format!("{}-{}", node_name, p), @@ -156,7 +145,7 @@ fn add_device_address_config( } }; - // 添加新的设备配置 + // Add new device configuration let pt_dev = axvm::config::PassThroughDeviceConfig { name: device_name, base_gpa: base_address, @@ -167,7 +156,7 @@ fn add_device_address_config( vm_cfg.add_pass_through_device(pt_dev); } -/// 为PCIe设备添加ranges属性配置 +/// Add ranges property configuration for PCIe devices fn add_pci_ranges_config( vm_cfg: &mut AxVMConfig, node_name: &str, @@ -177,12 +166,12 @@ fn add_pci_ranges_config( let base_address = range.cpu_address as usize; let size = range.size as usize; - // 只处理有地址信息的设备 + // Only process devices with address information if size == 0 { return; } - // 为每个地址段创建一个设备配置 + // Create a device configuration for each address segment let prefix = match range.space { PciSpace::Configuration => "config", PciSpace::IO => "io", @@ -196,7 +185,7 @@ fn add_pci_ranges_config( format!("{}-{}-region{}", node_name, prefix, index) }; - // 添加新的设备配置 + // Add new device configuration let pt_dev = axvm::config::PassThroughDeviceConfig { name: device_name, base_gpa: base_address, @@ -216,21 +205,21 @@ pub fn parse_passthrough_devices_address(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { let fdt = Fdt::from_bytes(dtb) .expect("Failed to parse DTB image, perhaps the DTB is invalid or corrupted"); - // 清空现有的直通设备配置 + // Clear existing passthrough device configurations vm_cfg.clear_pass_through_devices(); - // 遍历所有设备树节点 + // Traverse all device tree nodes for node in fdt.all_nodes() { - // 跳过根节点 + // Skip root node if node.name() == "/" || node.name().starts_with("memory") { continue; } let node_name = node.name().to_string(); - // 检查是否为PCIe设备节点 + // Check if it's a PCIe device node if node_name.starts_with("pcie@") || node_name.contains("pci") { - // 处理PCIe设备的ranges属性 + // Process PCIe device's ranges property if let Some(pci) = node.clone().into_pci() { if let Ok(ranges) = pci.ranges() { for (index, range) in ranges.enumerate() { @@ -239,7 +228,7 @@ pub fn parse_passthrough_devices_address(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { } } - // 处理PCIe设备的reg属性(ECAM空间) + // Process PCIe device's reg property (ECAM space) if let Some(mut reg_iter) = node.reg() { let mut index = 0; while let Some(reg) = reg_iter.next() { @@ -251,12 +240,12 @@ pub fn parse_passthrough_devices_address(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { } } } else { - // 获取设备的reg属性(处理普通设备) + // Get device's reg property (process regular devices) if let Some(mut reg_iter) = node.reg() { - // 处理设备的所有地址段 + // Process all address segments of the device let mut index = 0; while let Some(reg) = reg_iter.next() { - // 获取设备的地址和大小信息 + // Get device's address and size information let base_address = reg.address as usize; let size = reg.size.unwrap_or(0) as usize; @@ -270,7 +259,7 @@ pub fn parse_passthrough_devices_address(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { "All passthrough devices: {:#x?}", vm_cfg.pass_through_devices() ); - info!( + debug!( "Finished parsing passthrough devices, total: {}", vm_cfg.pass_through_devices().len() ); diff --git a/src/vmm/fdt/test.rs b/src/vmm/fdt/test.rs index e558fd62..88af35e8 100644 --- a/src/vmm/fdt/test.rs +++ b/src/vmm/fdt/test.rs @@ -28,30 +28,30 @@ pub fn print_fdt(fdt_addr: usize) { .map_err(|e| format!("Failed to parse FDT: {:#?}", e)) .expect("Failed to parse FDT"); - // 统计节点数量和层级分布 + // Statistics of node count and level distribution let mut node_count = 0; let mut level_counts = alloc::collections::BTreeMap::new(); let mut max_level = 0; - info!("=== FDT节点信息统计 ==="); + info!("=== FDT Node Information Statistics ==="); - // 一次性遍历所有节点进行统计(遵循优化策略) + // Traverse all nodes once for statistics (following optimization strategy) for node in fdt.all_nodes() { node_count += 1; - // 按层级统计节点数量 + // Count nodes by level *level_counts.entry(node.level).or_insert(0) += 1; - // 记录最大层级 + // Record maximum level if node.level > max_level { max_level = node.level; } - // 统计属性数量 + // Count property numbers let node_properties_count = node.propertys().count(); trace!( - "节点[{}]: {} (层级: {}, 属性: {})", + "Node[{}]: {} (Level: {}, Properties: {})", node_count, node.name(), node.level, @@ -59,19 +59,19 @@ pub fn print_fdt(fdt_addr: usize) { ); for prop in node.propertys() { - trace!("属性: {}, 节点: {:x?}", prop.name, prop.raw_value()); + trace!("Properties: {}, Node: {:x?}", prop.name, prop.raw_value()); } } - info!("=== FDT统计结果 ==="); - info!("总节点数量: {}", node_count); - info!("FDT总大小: {} 字节", fdt_header.total_size()); - info!("最大层级深度: {}", max_level); + info!("=== FDT Statistics Results ==="); + info!("Total node count: {}", node_count); + info!("FDT total size: {} bytes", fdt_header.total_size()); + info!("Maximum level depth: {}", max_level); - info!("各层级节点分布:"); + info!("Node distribution by level:"); for (level, count) in level_counts { let percentage = (count as f32 / node_count as f32) * 100.0; - info!(" 层级 {}: {} 个节点 ({:.1}%)", level, count, percentage); + info!(" Level {}: {} nodes ({:.1}%)", level, count, percentage); } } @@ -82,30 +82,30 @@ pub fn print_guest_fdt(fdt_bytes: &[u8]) { let fdt = Fdt::from_bytes(fdt_bytes) .map_err(|e| format!("Failed to parse FDT: {:#?}", e)) .expect("Failed to parse FDT"); - // 统计节点数量和层级分布 + // Statistics of node count and level distribution let mut node_count = 0; let mut level_counts = alloc::collections::BTreeMap::new(); let mut max_level = 0; - info!("=== FDT节点信息统计 ==="); + info!("=== FDT Node Information Statistics ==="); - // 一次性遍历所有节点进行统计(遵循优化策略) + // Traverse all nodes once for statistics (following optimization strategy) for node in fdt.all_nodes() { node_count += 1; - // 按层级统计节点数量 + // Count nodes by level *level_counts.entry(node.level).or_insert(0) += 1; - // 记录最大层级 + // Record maximum level if node.level > max_level { max_level = node.level; } - // 统计属性数量 + // Count property numbers let node_properties_count = node.propertys().count(); trace!( - "节点[{}]: {} (层级: {}, 属性: {})", + "Node[{}]: {} (Level: {}, Properties: {})", node_count, node.name(), node.level, @@ -113,17 +113,17 @@ pub fn print_guest_fdt(fdt_bytes: &[u8]) { ); for prop in node.propertys() { - trace!("属性: {}, 节点: {:x?}", prop.name, prop.raw_value()); + trace!("Properties: {}, Node: {:x?}", prop.name, prop.raw_value()); } } - info!("=== FDT统计结果 ==="); - info!("总节点数量: {}", node_count); - info!("最大层级深度: {}", max_level); + info!("=== FDT Statistics Results ==="); + info!("Total node count: {}", node_count); + info!("Maximum level depth: {}", max_level); - info!("各层级节点分布:"); + info!("Node distribution by level:"); for (level, count) in level_counts { let percentage = (count as f32 / node_count as f32) * 100.0; - info!(" 层级 {}: {} 个节点 ({:.1}%)", level, count, percentage); + info!(" Level {}: {} nodes ({:.1}%)", level, count, percentage); } } \ No newline at end of file From eaa44357e7b687c38893e868f1af578653fdc981 Mon Sep 17 00:00:00 2001 From: szy Date: Fri, 19 Sep 2025 16:48:34 +0800 Subject: [PATCH 10/30] optimize --- src/vmm/config.rs | 48 +++++++++------------------------- src/vmm/fdt/create.rs | 61 +++++++++++++++++++++++++++++++++---------- src/vmm/fdt/mod.rs | 4 +-- src/vmm/fdt/parser.rs | 26 +++++++++++++----- 4 files changed, 81 insertions(+), 58 deletions(-) diff --git a/src/vmm/config.rs b/src/vmm/config.rs index f42624a0..21a94f8e 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -4,10 +4,11 @@ use axvm::{ VMMemoryRegion, config::{AxVMConfig, AxVMCrateConfig, VmMemMappingType}, }; +use fdt_parser::Fdt; use memory_addr::MemoryAddr; use crate::vmm::{ - VM, fdt::{parse_passthrough_devices_address, parse_vm_interrupt}, images::ImageLoader, vm_list::push_vm, + fdt::*, images::ImageLoader, vm_list::push_vm, VM }; // 添加用于存储生成的DTB的全局静态变量 @@ -39,7 +40,7 @@ pub mod config { include!(concat!(env!("OUT_DIR"), "/vm_configs.rs")); } -pub fn get_vm_dtb(vm_cfg: &AxVMConfig) -> Option<&'static [u8]> { +pub fn get_developer_provided_dtb(vm_cfg: &AxVMConfig) -> Option<&'static [u8]> { let vm_imags = config::get_memory_images() .iter() .find(|&v| v.id == vm_cfg.id())?; @@ -51,32 +52,17 @@ pub fn get_vm_dtb(vm_cfg: &AxVMConfig) -> Option<&'static [u8]> { None } -/// 获取VM的DTB数据(返回Arc<[u8]>,支持缓存数据) pub fn get_vm_dtb_arc(vm_cfg: &AxVMConfig) -> Option> { - // 首先尝试返回静态DTB数据 - let vm_imags = config::get_memory_images() - .iter() - .find(|&v| v.id == vm_cfg.id())?; - - if let Some(dtb) = vm_imags.dtb { - // 将&'static [u8]转换为Arc<[u8]> - return Some(Arc::from(dtb)); - } - - // 如果内存镜像中没有DTB,则尝试从生成的DTB缓存中获取 if let Some(cache) = GENERATED_DTB_CACHE.get() { let cache_lock = cache.lock(); if let Some(dtb) = cache_lock.get(&vm_cfg.id()) { - // 返回缓存中的Arc引用 return Some(dtb.clone()); } } - None } pub fn init_guest_vms() { - // 初始化DTB缓存 GENERATED_DTB_CACHE.init_once(Mutex::new(BTreeMap::new())); let gvm_raw_configs = config::static_vm_configs(); @@ -94,31 +80,21 @@ pub fn init_guest_vms() { let mut vm_config = AxVMConfig::from(vm_create_config.clone()); - // info!("vm_create_config: {:#?}", vm_create_config); - // info!("before parse_vm_interrupt, crate VM[{}] with config: {:#?}", vm_config.id(), vm_config); + 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(&mut vm_config, &host_fdt, &vm_create_config); - // let bootarg: usize = unsafe { std::os::arceos::modules::axhal::get_bootarg() }; - // if bootarg != 0 { - // crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config); - // } - if let Some(dtb) = get_vm_dtb(&vm_config) { + if let Some(dtb) = get_developer_provided_dtb(&vm_config) { info!("VM[{}] found DTB , parsing...", vm_config.id()); - - // crate::vmm::fdt::parse_vm_fdt(&mut vm_config, dtb); - //test - let bootarg = dtb.as_ptr() as usize; - crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config, &vm_create_config); - //test + update_provided_fdt(dtb, &vm_create_config); } else { info!( "VM[{}] DTB not found, generating based on the configuration file.", vm_config.id() ); - - let bootarg: usize = std::os::arceos::modules::axhal::get_bootarg(); - if bootarg != 0 { - crate::vmm::fdt::parse_fdt(bootarg, &mut vm_config, &vm_create_config); - } + setup_guest_fdt_from_vmm(host_fdt_bytes, &mut vm_config, &vm_create_config); } // Overlay VM config with the given DTB. @@ -127,7 +103,7 @@ pub fn init_guest_vms() { parse_passthrough_devices_address(&mut vm_config, dtb); parse_vm_interrupt(&mut vm_config, dtb); } else { - warn!( + error!( "VM[{}] DTB not found in memory, skipping...", vm_config.id() ); diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index 5f0b67c8..5685f8d4 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -85,27 +85,16 @@ pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, crate_ guest_fdt_bytes } -/// Generate guest FDT and cache the result -/// -/// # Parameters -/// * `fdt` - Source FDT data -/// * `passthrough_device_names` - Passthrough device name list -/// * `crate_config` - VM creation configuration -/// +/// Generate guest FDT cache the result /// # Return Value /// Returns the generated DTB data and stores it in the global cache -pub fn crate_guest_fdt_with_cache(fdt: &Fdt, passthrough_device_names: &Vec, crate_config: &AxVMCrateConfig) -> Vec { - // Generate DTB data - let dtb_data = crate_guest_fdt(fdt, passthrough_device_names, crate_config); - +pub fn crate_guest_fdt_with_cache(dtb_data: Vec, crate_config: &AxVMCrateConfig) { // Store data in global cache if let Some(cache) = crate::vmm::config::GENERATED_DTB_CACHE.get() { let mut cache_lock = cache.lock(); - let dtb_arc: Arc<[u8]> = Arc::from(dtb_data.clone()); + let dtb_arc: Arc<[u8]> = Arc::from(dtb_data); cache_lock.insert(crate_config.base.id, dtb_arc); } - - dtb_data } /// Node processing action enumeration @@ -302,3 +291,47 @@ pub fn update_fdt(dest_addr: GuestPhysAddr, fdt_src: NonNull, dtb_size: usiz // Load the updated FDT into VM load_vm_image_from_memory(&new_fdt_bytes, dest_addr, vm.clone()).expect("Failed to load VM images"); } + +pub fn update_cpu_node(fdt: &Fdt, crate_config: &AxVMCrateConfig) -> Vec{ + let mut new_fdt = FdtWriter::new().unwrap(); + let mut previous_node_level = 0; + let mut node_stack: Vec = Vec::new(); + let phys_cpu_ids = crate_config.base.phys_cpu_ids.clone().expect("ERROR: phys_cpu_ids is None"); + + let all_nodes: Vec = fdt.all_nodes().collect(); + + for (index, node) in all_nodes.iter().enumerate() { + let node_path = super::build_node_path(&all_nodes, index); + + if node.name() == "/" { + node_stack.push(new_fdt.begin_node("").unwrap()); + } else if node_path.starts_with("/cpus") { + let need = need_cpu_node(&phys_cpu_ids, node, &node_path); + if need { + handle_node_level_change(&mut new_fdt, &mut node_stack, node.level, previous_node_level); + node_stack.push(new_fdt.begin_node(node.name()).unwrap()); + } else { + continue; + } + } else { + handle_node_level_change(&mut new_fdt, &mut node_stack, node.level, previous_node_level); + node_stack.push(new_fdt.begin_node(node.name()).unwrap()); + } + + previous_node_level = node.level; + + for prop in node.propertys() { + new_fdt.property(prop.name, prop.raw_value()).unwrap(); + } + } + + while let Some(node) = node_stack.pop() { + previous_node_level -= 1; + new_fdt.end_node(node).unwrap(); + } + assert_eq!(previous_node_level , 0); + + let guest_fdt_bytes = new_fdt.finish().unwrap(); + + guest_fdt_bytes +} diff --git a/src/vmm/fdt/mod.rs b/src/vmm/fdt/mod.rs index 926efe3c..7037ae27 100644 --- a/src/vmm/fdt/mod.rs +++ b/src/vmm/fdt/mod.rs @@ -9,7 +9,7 @@ mod create; mod test; // Re-export public functions -pub use parser::{parse_fdt, parse_passthrough_devices_address, parse_vm_interrupt}; +pub use parser::*; // pub use test::print_fdt; pub use device::{build_node_path}; -pub use create::update_fdt; \ No newline at end of file +pub use create::*; \ No newline at end of file diff --git a/src/vmm/fdt/parser.rs b/src/vmm/fdt/parser.rs index cba9a319..535e1b2c 100644 --- a/src/vmm/fdt/parser.rs +++ b/src/vmm/fdt/parser.rs @@ -4,10 +4,13 @@ use alloc::{string::ToString, vec::Vec}; use axvm::config::{AxVMConfig, AxVMCrateConfig, PassThroughDeviceConfig}; use fdt_parser::{Fdt, FdtHeader, PciRange, PciSpace}; -pub fn parse_fdt(fdt_addr: usize, vm_cfg: &mut AxVMConfig, crate_config: &AxVMCrateConfig) { +use crate::vmm::fdt::create::update_cpu_node; + +pub fn get_host_fdt() -> &'static [u8] { const FDT_VALID_MAGIC: u32 = 0xd00d_feed; + let bootarg: usize = std::os::arceos::modules::axhal::get_bootarg(); let header = unsafe { - core::slice::from_raw_parts(fdt_addr as *const u8, core::mem::size_of::()) + core::slice::from_raw_parts(bootarg as *const u8, core::mem::size_of::()) }; let fdt_header = FdtHeader::from_bytes(header) .map_err(|e| format!("Failed to parse FDT header: {:#?}", e)) @@ -19,11 +22,15 @@ pub fn parse_fdt(fdt_addr: usize, vm_cfg: &mut AxVMConfig, crate_config: &AxVMCr FDT_VALID_MAGIC, fdt_header.magic.get() ); - return; } let fdt_bytes = - unsafe { core::slice::from_raw_parts(fdt_addr as *const u8, fdt_header.total_size()) }; + unsafe { core::slice::from_raw_parts(bootarg as *const u8, fdt_header.total_size()) }; + + fdt_bytes +} + +pub fn setup_guest_fdt_from_vmm(fdt_bytes: &[u8], vm_cfg: &mut AxVMConfig, crate_config: &AxVMCrateConfig) { let fdt = Fdt::from_bytes(fdt_bytes) .map_err(|e| format!("Failed to parse FDT: {:#?}", e)) @@ -33,8 +40,8 @@ pub fn parse_fdt(fdt_addr: usize, vm_cfg: &mut AxVMConfig, crate_config: &AxVMCr // Call the modified function and get the returned device name list let passthrough_device_names = super::device::find_all_passthrough_devices(vm_cfg, &fdt); - let _ = - super::create::crate_guest_fdt_with_cache(&fdt, &passthrough_device_names, crate_config); + let dtb_data = super::create::crate_guest_fdt(&fdt, &passthrough_device_names, crate_config); + super::create::crate_guest_fdt_with_cache(dtb_data, crate_config); } pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVMCrateConfig) { @@ -350,3 +357,10 @@ pub fn parse_vm_interrupt(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { irq_id: 0, }); } + +pub fn update_provided_fdt(dtb: &[u8], crate_config: &AxVMCrateConfig) { + let fdt = Fdt::from_bytes(dtb) + .expect("Failed to parse DTB image, perhaps the DTB is invalid or corrupted"); + let dtb_data = update_cpu_node(&fdt, crate_config); + super::create::crate_guest_fdt_with_cache(dtb_data, crate_config); +} \ No newline at end of file From ed678d7814c7e16b5bed477d4b087beef1281565 Mon Sep 17 00:00:00 2001 From: szy Date: Fri, 19 Sep 2025 17:51:20 +0800 Subject: [PATCH 11/30] elcluded devices --- src/vmm/fdt/device.rs | 52 +++++++++++++++++++++++++++++++++++++++++++ src/vmm/fdt/parser.rs | 1 - 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/vmm/fdt/device.rs b/src/vmm/fdt/device.rs index ffe165bf..ed6476a6 100644 --- a/src/vmm/fdt/device.rs +++ b/src/vmm/fdt/device.rs @@ -101,11 +101,63 @@ pub fn find_all_passthrough_devices(vm_cfg: &mut AxVMConfig, fdt: &Fdt) -> Vec> to Vec + let excluded_device_path: Vec = vm_cfg + .excluded_devices() + .iter() + .flatten() + .cloned() + .collect(); + let mut all_excludes_devices = excluded_device_path.clone(); + let mut process_excludeds: BTreeSet = + excluded_device_path.iter().cloned().collect(); + + for device_path in &excluded_device_path { + // Get all descendant node paths for this device + let descendant_paths = get_descendant_nodes_by_path(&node_cache, device_path); + info!( + "Found {} descendant paths for {}", + descendant_paths.len(), + device_path + ); + + for descendant_path in descendant_paths { + if !process_excludeds.contains(&descendant_path) { + trace!( + "Found descendant device: {}", + descendant_path + ); + process_excludeds.insert(descendant_path.clone()); + + all_excludes_devices.push(descendant_path.clone()); + } else { + trace!("Device already exists: {}", descendant_path); + } + } + } + info!("Found excluded devices: {:?}", all_excludes_devices); + // Merge all device name lists let mut all_device_names = initial_device_names.clone(); all_device_names.extend(additional_device_names); all_device_names.extend(dependency_device_names); + // Remove excluded devices from the final list + if !all_excludes_devices.is_empty() { + info!("Removing {} excluded devices from the list", all_excludes_devices.len()); + let excluded_set: BTreeSet = all_excludes_devices.into_iter().collect(); + + // Filter out excluded devices + all_device_names.retain(|device_name| { + let should_keep = !excluded_set.contains(device_name); + if !should_keep { + info!("Excluding device: {}", device_name); + } + should_keep + }); + } + let final_device_count = all_device_names.len(); info!( "Passthrough devices analysis completed. Total devices: {} (added: {})", diff --git a/src/vmm/fdt/parser.rs b/src/vmm/fdt/parser.rs index 535e1b2c..022c1f90 100644 --- a/src/vmm/fdt/parser.rs +++ b/src/vmm/fdt/parser.rs @@ -36,7 +36,6 @@ pub fn setup_guest_fdt_from_vmm(fdt_bytes: &[u8], vm_cfg: &mut AxVMConfig, crate .map_err(|e| format!("Failed to parse FDT: {:#?}", e)) .expect("Failed to parse FDT"); - set_phys_cpu_sets(vm_cfg, &fdt, crate_config); // Call the modified function and get the returned device name list let passthrough_device_names = super::device::find_all_passthrough_devices(vm_cfg, &fdt); From 26d4bf7f34b40f9f147dd62ec1268806a1511a46 Mon Sep 17 00:00:00 2001 From: szy Date: Mon, 22 Sep 2025 17:46:11 +0800 Subject: [PATCH 12/30] add fs --- src/vmm/config.rs | 47 +++++++++++++++++++++++++++++--------- src/vmm/fdt/create.rs | 53 ++++++++++++++++++++++++++++++++----------- src/vmm/fdt/parser.rs | 10 ++++---- src/vmm/fdt/test.rs | 2 +- src/vmm/images/mod.rs | 7 ++++-- 5 files changed, 88 insertions(+), 31 deletions(-) diff --git a/src/vmm/config.rs b/src/vmm/config.rs index 21a94f8e..8e9510c7 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -11,13 +11,12 @@ use crate::vmm::{ fdt::*, images::ImageLoader, vm_list::push_vm, VM }; -// 添加用于存储生成的DTB的全局静态变量 use alloc::collections::BTreeMap; use alloc::sync::Arc; +use alloc::vec::Vec; use lazyinit::LazyInit; use spin::Mutex; -// 用于存储生成的DTB数据的全局缓存 pub static GENERATED_DTB_CACHE: LazyInit>>> = LazyInit::new(); #[allow(clippy::module_inception)] @@ -40,15 +39,41 @@ pub mod config { include!(concat!(env!("OUT_DIR"), "/vm_configs.rs")); } -pub fn get_developer_provided_dtb(vm_cfg: &AxVMConfig) -> Option<&'static [u8]> { - let vm_imags = config::get_memory_images() - .iter() - .find(|&v| v.id == vm_cfg.id())?; +pub fn get_developer_provided_dtb(vm_cfg: &AxVMConfig, crate_config: &AxVMCrateConfig) -> Option> { + 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 { - return Some(dtb); + if let Some(dtb) = vm_imags.dtb { + return Some(dtb.to_vec()); + } + }, + #[cfg(feature = "fs")] + Some("fs") => { + use std::io::{BufReader, Read}; + use axerrno::ax_err_type; + if let Some(dtb_path) = &crate_config.kernel.dtb_path { + let (dtb_file, dtb_size) = crate::vmm::images::open_image_file(&dtb_path).unwrap(); + info!("DTB file in fs, size: {: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 } @@ -86,9 +111,9 @@ pub fn init_guest_vms() { .expect("Failed to parse FDT"); set_phys_cpu_sets(&mut vm_config, &host_fdt, &vm_create_config); - if let Some(dtb) = get_developer_provided_dtb(&vm_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(dtb, &vm_create_config); + update_provided_fdt(&provided_dtb, host_fdt_bytes, &vm_create_config); } else { info!( "VM[{}] DTB not found, generating based on the configuration file.", diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index 5685f8d4..211842a6 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -13,7 +13,7 @@ use axvm::{ use fdt_parser::{Fdt, Node}; use vm_fdt::{FdtWriter, FdtWriterNode}; -use crate::vmm::{images::load_vm_image_from_memory, VMRef}; +use crate::vmm::{fdt::test::{print_fdt, print_guest_fdt}, images::load_vm_image_from_memory, VMRef}; /// Generate guest FDT and return DTB data /// @@ -287,44 +287,71 @@ pub fn update_fdt(dest_addr: GuestPhysAddr, fdt_src: NonNull, dtb_size: usiz } assert_eq!(previous_node_level, 0); + + info!("Updating FDT memory successfully"); + let new_fdt_bytes = new_fdt.finish().unwrap(); + + print_guest_fdt(new_fdt_bytes.as_slice()); + // Load the updated FDT into VM load_vm_image_from_memory(&new_fdt_bytes, dest_addr, vm.clone()).expect("Failed to load VM images"); } -pub fn update_cpu_node(fdt: &Fdt, crate_config: &AxVMCrateConfig) -> Vec{ +pub fn update_cpu_node(fdt: &Fdt, host_fdt: &Fdt, crate_config: &AxVMCrateConfig) -> Vec{ let mut new_fdt = FdtWriter::new().unwrap(); let mut previous_node_level = 0; let mut node_stack: Vec = Vec::new(); let phys_cpu_ids = crate_config.base.phys_cpu_ids.clone().expect("ERROR: phys_cpu_ids is None"); - let all_nodes: Vec = fdt.all_nodes().collect(); - - for (index, node) in all_nodes.iter().enumerate() { - let node_path = super::build_node_path(&all_nodes, index); + // Collect all nodes from both FDTs + let fdt_all_nodes: Vec = fdt.all_nodes().collect(); + let host_fdt_all_nodes: Vec = host_fdt.all_nodes().collect(); + + for (index, node) in fdt_all_nodes.iter().enumerate() { + let node_path = super::build_node_path(&fdt_all_nodes, index); if node.name() == "/" { node_stack.push(new_fdt.begin_node("").unwrap()); } else if node_path.starts_with("/cpus") { - let need = need_cpu_node(&phys_cpu_ids, node, &node_path); - if need { - handle_node_level_change(&mut new_fdt, &mut node_stack, node.level, previous_node_level); - node_stack.push(new_fdt.begin_node(node.name()).unwrap()); - } else { - continue; - } + // Skip CPU nodes from fdt, we'll process them from host_fdt later + continue; } else { + // For all other nodes, include them from fdt as-is without filtering handle_node_level_change(&mut new_fdt, &mut node_stack, node.level, previous_node_level); node_stack.push(new_fdt.begin_node(node.name()).unwrap()); } previous_node_level = node.level; + // Copy all properties of the node (for non-CPU nodes) for prop in node.propertys() { new_fdt.property(prop.name, prop.raw_value()).unwrap(); } } + + // Process all CPU nodes from host_fdt + for (index, node) in host_fdt_all_nodes.iter().enumerate() { + let node_path = super::build_node_path(&host_fdt_all_nodes, index); + + if node_path.starts_with("/cpus") { + // For CPU nodes, apply filtering based on host_fdt nodes + let need = need_cpu_node(&phys_cpu_ids, node, &node_path); + if need { + handle_node_level_change(&mut new_fdt, &mut node_stack, node.level, previous_node_level); + node_stack.push(new_fdt.begin_node(node.name()).unwrap()); + + // Copy properties from host CPU node + for prop in node.propertys() { + new_fdt.property(prop.name, prop.raw_value()).unwrap(); + } + + previous_node_level = node.level; + } + } + } + // End all unclosed nodes while let Some(node) = node_stack.pop() { previous_node_level -= 1; new_fdt.end_node(node).unwrap(); diff --git a/src/vmm/fdt/parser.rs b/src/vmm/fdt/parser.rs index 022c1f90..832ffe5c 100644 --- a/src/vmm/fdt/parser.rs +++ b/src/vmm/fdt/parser.rs @@ -357,9 +357,11 @@ pub fn parse_vm_interrupt(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { }); } -pub fn update_provided_fdt(dtb: &[u8], crate_config: &AxVMCrateConfig) { - let fdt = Fdt::from_bytes(dtb) +pub fn update_provided_fdt(provided_dtb: &[u8], host_dtb: &[u8], crate_config: &AxVMCrateConfig) { + let provided_fdt = Fdt::from_bytes(provided_dtb) .expect("Failed to parse DTB image, perhaps the DTB is invalid or corrupted"); - let dtb_data = update_cpu_node(&fdt, crate_config); - super::create::crate_guest_fdt_with_cache(dtb_data, crate_config); + let host_fdt = Fdt::from_bytes(host_dtb) + .expect("Failed to parse DTB image, perhaps the DTB is invalid or corrupted"); + let provided_dtb_data = update_cpu_node(&provided_fdt, &host_fdt, crate_config); + super::create::crate_guest_fdt_with_cache(provided_dtb_data, crate_config); } \ No newline at end of file diff --git a/src/vmm/fdt/test.rs b/src/vmm/fdt/test.rs index 88af35e8..dba94120 100644 --- a/src/vmm/fdt/test.rs +++ b/src/vmm/fdt/test.rs @@ -104,7 +104,7 @@ pub fn print_guest_fdt(fdt_bytes: &[u8]) { // Count property numbers let node_properties_count = node.propertys().count(); - trace!( + info!( "Node[{}]: {} (Level: {}, Properties: {})", node_count, node.name(), diff --git a/src/vmm/images/mod.rs b/src/vmm/images/mod.rs index 70699aea..5d705dd4 100644 --- a/src/vmm/images/mod.rs +++ b/src/vmm/images/mod.rs @@ -272,7 +272,7 @@ mod fs { dtb_addr, Byte::from(dtb_size) ); - updated_fdt( + update_fdt( dtb_addr, NonNull::new(dtb_buffer.as_mut_ptr()).unwrap(), dtb_size, @@ -307,7 +307,7 @@ mod fs { Ok(()) } - fn open_image_file(file_name: &str) -> AxResult<(File, usize)> { + pub fn open_image_file(file_name: &str) -> AxResult<(File, usize)> { let file = File::open(file_name).map_err(|err| { ax_err_type!( NotFound, @@ -332,3 +332,6 @@ mod fs { Ok((file, file_size)) } } + +#[cfg(feature = "fs")] +pub use fs::open_image_file; From 2ba3c5a9dd3eecd78d89eddc2a49c4d356ffa369 Mon Sep 17 00:00:00 2001 From: szy Date: Mon, 22 Sep 2025 17:57:48 +0800 Subject: [PATCH 13/30] debug --- src/vmm/config.rs | 1 + src/vmm/images/mod.rs | 36 ++++++++++++------------------------ 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/vmm/config.rs b/src/vmm/config.rs index 8e9510c7..8dfa4e59 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -47,6 +47,7 @@ pub fn get_developer_provided_dtb(vm_cfg: &AxVMConfig, crate_config: &AxVMCrateC .find(|&v| v.id == vm_cfg.id())?; if let Some(dtb) = vm_imags.dtb { + info!("DTB file in memory, size: {:x}", dtb.len()); return Some(dtb.to_vec()); } }, diff --git a/src/vmm/images/mod.rs b/src/vmm/images/mod.rs index 5d705dd4..b3658b24 100644 --- a/src/vmm/images/mod.rs +++ b/src/vmm/images/mod.rs @@ -191,7 +191,6 @@ mod fs { use std::{fs::File, vec::Vec}; use axerrno::{AxResult, ax_err, ax_err_type}; use crate::hal::CacheOp; - use std::io::{BufReader, Read}; use super::*; pub fn kernal_read(config: &AxVMCrateConfig, read_size: usize) -> AxResult> { @@ -251,34 +250,23 @@ mod fs { } }; // Load DTB image if needed. - if let Some(dtb_path) = &loader.config.kernel.dtb_path { - let (dtb_file, dtb_size) = open_image_file(dtb_path)?; - info!("DTB file size {}", 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) - ) - })?; - - let dtb_addr = loader.dtb_load_gpa.unwrap(); - - info!( + let vm_config = axvm::config::AxVMConfig::from(loader.config.clone()); + if let Some(dtb_arc) = get_vm_dtb_arc(&vm_config) { + let dtb_slice: &[u8] = &*dtb_arc; + debug!( "DTB buffer addr: {:x}, size: {:#}", - dtb_addr, - Byte::from(dtb_size) + loader.dtb_load_gpa.unwrap(), + Byte::from(dtb_slice.len()) ); + update_fdt( - dtb_addr, - NonNull::new(dtb_buffer.as_mut_ptr()).unwrap(), - dtb_size, + loader.dtb_load_gpa.unwrap(), + NonNull::new(dtb_slice.as_ptr() as *mut u8).unwrap(), + dtb_slice.len(), loader.vm.clone(), ); - }; + } + Ok(()) } From c9b87bced1fe05e03e45b00d1c1820645278a1c9 Mon Sep 17 00:00:00 2001 From: szy Date: Tue, 23 Sep 2025 10:03:05 +0800 Subject: [PATCH 14/30] stage2 init --- src/vmm/config.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/vmm/config.rs b/src/vmm/config.rs index 8dfa4e59..4e5520f7 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -22,6 +22,7 @@ pub static GENERATED_DTB_CACHE: LazyInit>>> = La #[allow(clippy::module_inception)] pub mod config { use alloc::vec::Vec; + use alloc::string::String; /// Default static VM configs. Used when no VM config is provided. #[allow(dead_code)] @@ -36,6 +37,39 @@ pub mod config { ] } + /// Read VM configs from filesystem + #[cfg(feature = "fs")] + pub fn filesystem_vm_configs() -> Vec { + use axstd::fs; + + // Try to read config files from a predefined directory + let config_dir = "configs/vms"; + let mut configs = Vec::new(); + + if let Ok(entries) = fs::read_dir(config_dir) { + for entry in entries { + if let Ok(entry) = entry { + let path = entry.path(); + // Check if the file has a .toml extension + let path_str = path.as_str(); + if path_str.ends_with(".toml") { + if let Ok(content) = fs::read_to_string(path_str) { + configs.push(content); + } + } + } + } + } + + configs + } + + /// Fallback function for when "fs" feature is not enabled + #[cfg(not(feature = "fs"))] + pub fn filesystem_vm_configs() -> Vec { + Vec::new() + } + include!(concat!(env!("OUT_DIR"), "/vm_configs.rs")); } @@ -91,11 +125,19 @@ pub fn get_vm_dtb_arc(vm_cfg: &AxVMConfig) -> Option> { pub fn init_guest_vms() { GENERATED_DTB_CACHE.init_once(Mutex::new(BTreeMap::new())); - let gvm_raw_configs = config::static_vm_configs(); + // First try to get configs from filesystem if fs feature is enabled + let mut gvm_raw_configs = config::filesystem_vm_configs(); + + // If no filesystem configs found, fallback to static configs + if gvm_raw_configs.is_empty() { + let static_configs = config::static_vm_configs(); + // Convert static configs to String type + gvm_raw_configs.extend(static_configs.into_iter().map(|s| s.into())); + } for raw_cfg_str in gvm_raw_configs { let vm_create_config = - AxVMCrateConfig::from_toml(raw_cfg_str).expect("Failed to resolve VM config"); + AxVMCrateConfig::from_toml(&raw_cfg_str).expect("Failed to resolve VM config"); if let Some(linux) = super::images::get_image_header(&vm_create_config) { debug!( From 5e9ba1674cbe6c6d2697fe58c141d030ee68f6e2 Mon Sep 17 00:00:00 2001 From: szy Date: Wed, 24 Sep 2025 16:54:10 +0800 Subject: [PATCH 15/30] add guide --- configs/vms/arceos-aarch64-e2000-smp1.toml | 32 +-- configs/vms/arceos-aarch64-e2000-smp2.toml | 33 +-- doc/FDT_Configuration_Guide.md | 242 +++++++++++++++++++++ src/vmm/fdt/create.rs | 3 +- src/vmm/fdt/parser.rs | 6 +- src/vmm/images/mod.rs | 2 +- 6 files changed, 264 insertions(+), 54 deletions(-) create mode 100644 doc/FDT_Configuration_Guide.md diff --git a/configs/vms/arceos-aarch64-e2000-smp1.toml b/configs/vms/arceos-aarch64-e2000-smp1.toml index dbbae96e..7e4ecdb9 100644 --- a/configs/vms/arceos-aarch64-e2000-smp1.toml +++ b/configs/vms/arceos-aarch64-e2000-smp1.toml @@ -11,8 +11,6 @@ vm_type = 1 cpu_num = 1 # The physical CPU ids. phys_cpu_ids = [0x00] -# Guest vm physical cpu sets. -phys_cpu_sets = [4] # # Vm kernel configs @@ -29,7 +27,7 @@ kernel_load_addr = 0x20_2008_0000 kernel_path = "/path/to/arceos_aarch64-dyn_smp1.bin" ## The file path of the device tree blob (DTB). dtb_load_addr = 0x20_2000_0000 -dtb_path = "/path/to/axvisor/configs/vms/arceos-aarch64-e2000_smp1.dtb" +#dtb_path = "/path/to/axvisor/configs/vms/arceos-aarch64-e2000_smp1.dtb" # Memory regions with format (`base_paddr`, `size`, `flags`, `map_type`). # For `map_type`, 0 means `MAP_ALLOC`, 1 means `MAP_IDENTICAL`. memory_regions = [ @@ -47,25 +45,11 @@ emu_devices = [] # Pass-through devices. # Name Base-Ipa Base-Pa Length Alloc-Irq. passthrough_devices = [ - [ - "UART1", - 0x2800_d000, - 0x2800_d000, - 0x1000, - 0x1, - ], - [ - "gic-v3", - 0x3080_0000, - 0x3080_0000, - 0x10000, - 0x1, - ], - [ - "gic-v3-its", - 0x3082_0000, - 0x3082_0000, - 0x100000, - 0x1, - ], + ["/"], + #["/timer"], ] + +# Devices that are not desired to be passed through to the guest +excluded_devices = [ + # ["/gic-v3"], +] \ No newline at end of file diff --git a/configs/vms/arceos-aarch64-e2000-smp2.toml b/configs/vms/arceos-aarch64-e2000-smp2.toml index 4f69f198..fffae98d 100644 --- a/configs/vms/arceos-aarch64-e2000-smp2.toml +++ b/configs/vms/arceos-aarch64-e2000-smp2.toml @@ -11,9 +11,6 @@ vm_type = 1 cpu_num = 2 # The physical CPU ids. phys_cpu_ids = [0x201, 0x100] -# Guest vm physical cpu sets. -phys_cpu_sets = [2, 8] - # # Vm kernel configs # @@ -29,7 +26,7 @@ kernel_load_addr = 0x20_2008_0000 kernel_path = "/path/to/arceos_aarch64-dyn_smp1.bin" ## The file path of the device tree blob (DTB). dtb_load_addr = 0x20_2000_0000 -dtb_path = "/path/to/axvisor/configs/vms/arceos-aarch64-e2000_smp2.dtb" +#dtb_path = "/path/to/axvisor/configs/vms/arceos-aarch64-e2000_smp2.dtb" # Memory regions with format (`base_paddr`, `size`, `flags`, `map_type`). # For `map_type`, 0 means `MAP_ALLOC`, 1 means `MAP_IDENTICAL`. memory_regions = [ @@ -47,25 +44,11 @@ emu_devices = [] # Pass-through devices. # Name Base-Ipa Base-Pa Length Alloc-Irq. passthrough_devices = [ - [ - "UART1", - 0x2800_d000, - 0x2800_d000, - 0x1000, - 0x1, - ], - [ - "gic-v3", - 0x3080_0000, - 0x3080_0000, - 0x10000, - 0x1, - ], - [ - "gic-v3-its", - 0x3082_0000, - 0x3082_0000, - 0x100000, - 0x1, - ], + ["/"], + #["/timer"], ] + +# Devices that are not desired to be passed through to the guest +excluded_devices = [ + # ["/gic-v3"], +] \ No newline at end of file diff --git a/doc/FDT_Configuration_Guide.md b/doc/FDT_Configuration_Guide.md new file mode 100644 index 00000000..eb8ea2a3 --- /dev/null +++ b/doc/FDT_Configuration_Guide.md @@ -0,0 +1,242 @@ +# AxVisor 设备树配置使用说明 + +本文档详细说明了在 AxVisor 中如何配置和使用设备树(FDT)来生成客户机 VM 的设备树。 + +## 1. 概述 + +AxVisor 支持两种方式生成客户机 VM 的设备树: + +1. **使用预定义的设备树文件**:通过 [kernel] 部分的 `dtb_path` 指定设备树文件路径 +2. **动态生成设备树**:当 `dtb_path` 为空时,根据配置文件中的参数动态生成设备树 + +无论采用哪种方式,CPU 节点和内存节点都会根据配置进行更新。 + +## 2. 配置文件结构 + +配置文件采用 TOML 格式,主要包含以下几个部分: + +```toml +[base] +# 基本配置信息 + +[kernel] +# 内核和设备树配置 + +[devices] +# 设备配置信息 +``` + +## 3. 设备树处理机制 + +### 3.1 使用预定义设备树文件 + +当 [kernel] 部分的 `dtb_path` 配置了设备树文件路径时: + +```toml +[kernel] +dtb_path = "/path/to/device-tree.dtb" +``` + +AxVisor 会优先使用提供的设备树文件,并根据以下配置更新其中的 CPU 节点和内存节点: + +- CPU 节点根据 [base] 部分的 `phys_cpu_ids` 更新 +- 内存节点根据 [kernel] 部分的 `memory_regions` 更新 + +注意:当使用预定义设备树文件时,[devices] 部分的 `passthrough_devices` 和 `excluded_devices` 配置将被忽略。 + +### 3.2 动态生成设备树 + +当 [kernel] 部分的 `dtb_path` 为空字符串时: + +```toml +[kernel] +dtb_path = "" +``` + +AxVisor 会根据配置文件中的参数动态生成客户机设备树: + +1. **CPU 节点**:根据 [base] 部分的 `phys_cpu_ids` 生成 +2. **内存节点**:根据 [kernel] 部分的 `memory_regions` 生成 +3. **其他设备节点**:根据 [devices] 部分的 `passthrough_devices` 和 `excluded_devices` 生成 + +## 4. 配置参数详解 + +### 4.1 基本配置 [base] + +```toml +[base] +id = 1 # 客户机 VM ID +name = "linux-qemu" # 客户机 VM 名称 +vm_type = 1 # 虚拟化类型 +cpu_num = 1 # 虚拟 CPU 数量 +phys_cpu_ids = [0] # 客户机 VM 物理 CPU 集合 +``` + +注意:配置文件中的 `phys_cpu_sets` 字段已不再需要手动配置。AxVisor 会根据主机设备树和 `phys_cpu_ids` 自动识别并生成相应的 CPU 集合掩码。 + +### 4.2 内核配置 [kernel] + +```toml +[kernel] +entry_point = 0x8020_0000 # 内核镜像入口点 +image_location = "memory" # 镜像位置 ("memory" | "fs") +kernel_path = "tmp/Image" # 内核镜像文件路径 +kernel_load_addr = 0x8020_0000 # 内核镜像加载地址 +dtb_path = "tmp/linux.dtb" # 设备树文件路径(空字符串表示动态生成) +dtb_load_addr = 0x8000_0000 # 设备树加载地址 + +# 内存区域配置,格式为 (基地址, 大小, 标志, 映射类型) +memory_regions = [ + [0x8000_0000, 0x1000_0000, 0x7, 0], # 系统 RAM 1G MAP_IDENTICAL +] +``` + +### 4.3 设备配置 [devices] + +```toml +[devices] +# 直通设备配置(仅在动态生成设备树时生效) +passthrough_devices = [ + ["/intc"], +] + +# 排除设备配置(仅在动态生成设备树时生效) +excluded_devices = [ + ["/intc"], +] +``` + +注意:直通设备配置已简化,现在只需要提供从根节点开始的完整路径即可,如 ["/intc"]。设备的地址、大小等信息会根据设备树自动识别并直通,无需手动填写。 + +## 5. 设备直通机制 + +### 5.1 直通设备配置 + +`passthrough_devices` 定义了需要直通给客户机的设备节点: + +```toml +passthrough_devices = [ + ["/"], # 直通根节点及其所有子节点 + ["/intc"], # 直通 /intc 节点及其子节点 +] +``` + +设备节点格式为从根节点开始的全局路径(如 `/intc`),在直通时会将以下节点包含在客户机设备树中: + +1. 指定的直通节点本身 +2. 直通节点的所有后代节点 +3. 与直通设备相关的依赖节点 + +注意: +1. 此配置仅在动态生成设备树时生效,当使用预定义设备树文件时将被忽略。 +2. 直通设备配置已简化,现在只需要提供从根节点开始的完整路径即可,设备的地址、大小等信息会根据设备树自动识别并直通。 + +### 5.2 排除设备配置 + +`excluded_devices` 定义了不希望直通给客户机的设备节点: + +```toml +excluded_devices = [ + ["/timer"], # 排除 /timer 节点及其子节点 +] +``` + +在查找所有直通节点后,会将排除的节点及其后代节点从最终的客户机设备树中移除。 + +注意:此配置仅在动态生成设备树时生效,当使用预定义设备树文件时将被忽略。 + +## 6. 示例配置 + +### 6.1 使用预定义设备树文件的配置 + +```toml +[base] +id = 1 +name = "linux-qemu" +vm_type = 1 +cpu_num = 2 +phys_cpu_ids = [0, 1] +# phys_cpu_sets 不再需要手动配置,会自动根据 phys_cpu_ids 生成 + +[kernel] +entry_point = 0x8020_0000 +image_location = "memory" +kernel_path = "tmp/Image" +kernel_load_addr = 0x8020_0000 +dtb_path = "/home/user/device-tree.dtb" # 使用预定义设备树文件 +dtb_load_addr = 0x8000_0000 + +memory_regions = [ + [0x8000_0000, 0x1000_0000, 0x7, 1], # System RAM 1G MAP_IDENTICAL +] + +[devices] +# 注意:以下配置在使用预定义设备树时将被忽略 +passthrough_devices = [ + ["/intc"], +] +excluded_devices = [ + ["/timer"], +] +``` + +### 6.2 动态生成设备树的配置 + +```toml +[base] +id = 1 +name = "linux-qemu" +vm_type = 1 +cpu_num = 2 +phys_cpu_ids = [0, 1] +# phys_cpu_sets 不再需要手动配置,会自动根据 phys_cpu_ids 生成 + +[kernel] +entry_point = 0x8020_0000 +image_location = "memory" +kernel_path = "tmp/Image" +kernel_load_addr = 0x8020_0000 +dtb_path = "" # 空字符串表示动态生成设备树 +dtb_load_addr = 0x8000_0000 + +memory_regions = [ + [0x8000_0000, 0x1000_0000, 0x7, 1], # System RAM 1G MAP_IDENTICAL +] + +[devices] +# 以下配置仅在动态生成设备树时生效 +# 注意:直通设备配置已简化,现在只需要提供从根节点开始的完整路径即可 +passthrough_devices = [ + ["/"], + ["/intc"], +] + +excluded_devices = [ + ["/timer"], + ["/watchdog"], +] +``` + +## 7. 处理流程 + +1. **检查 dtb_path**: + - 如果 `dtb_path` 非空,则加载并使用预定义的设备树文件,此时 `passthrough_devices` 和 `excluded_devices` 配置将被忽略 + - 如果 `dtb_path` 为空,则动态生成设备树,此时 `passthrough_devices` 和 `excluded_devices` 配置生效 + +2. **CPU 节点处理**: + - 根据 `phys_cpu_ids` 配置更新或生成 CPU 节点 + - 只包含配置中指定的 CPU + - 自动根据 `phys_cpu_ids` 生成 `phys_cpu_sets`,无需手动配置 + +3. **内存节点处理**: + - 根据 `memory_regions` 配置更新或生成内存节点 + - 按照指定的地址和大小创建内存区域 + +4. **设备节点处理**(仅在动态生成时): + - 根据 `passthrough_devices` 确定需要包含的设备节点 + - 包括直通节点、其后代节点以及相关依赖节点 + - 根据 `excluded_devices` 排除指定的设备节点及其后代节点 + +5. **生成最终设备树**: + - 将处理后的节点组合成完整的设备树 + - 存储在全局缓存中供后续使用 \ No newline at end of file diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index 211842a6..d06b6878 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -236,6 +236,7 @@ fn add_memory_node(new_memory: &[VMMemoryRegion], new_fdt: &mut FdtWriter) { new_value.push((size >> 32) as u32); new_value.push((size & 0xFFFFFFFF) as u32); } + info!("Adding memory node with value: 0x{:x?}", new_value); new_fdt .property_array_u32("reg", new_value.as_ref()) .unwrap(); @@ -279,7 +280,7 @@ pub fn update_fdt(dest_addr: GuestPhysAddr, fdt_src: NonNull, dtb_size: usiz // add memory node if previous_node_level == 1 { let memory_regions = vm.memory_regions(); - info!("Adding memory node with regions: {:?}", memory_regions); + debug!("Adding memory node with regions: {:?}", memory_regions); let memory_node = new_fdt.begin_node("memory").unwrap(); add_memory_node(&memory_regions, &mut new_fdt); new_fdt.end_node(memory_node).unwrap(); diff --git a/src/vmm/fdt/parser.rs b/src/vmm/fdt/parser.rs index 832ffe5c..35711a18 100644 --- a/src/vmm/fdt/parser.rs +++ b/src/vmm/fdt/parser.rs @@ -56,6 +56,7 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM .filter_map(|cpu_node| { if let Some(mut cpu_reg) = cpu_node.reg() { if let Some(r) = cpu_reg.next() { + info!("CPU node: {}, phys_cpu_id: 0x{:x}", cpu_node.name(), r.address); Some((cpu_node.name().to_string(), r.address as usize)) } else { None @@ -65,7 +66,6 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM } }) .collect(); - info!("cpu_nodes_info: {:?}", cpu_nodes_info); // Create mapping from phys_cpu_id to physical CPU index // Collect all unique CPU addresses, maintaining the order of appearance in the device tree let mut unique_cpu_addresses = Vec::new(); @@ -299,7 +299,7 @@ pub fn parse_vm_interrupt(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { trace!("node: {}, intr parent: {}", name, parent.node.name()); if let Some(phandle) = parent.node.phandle() { if phandle.as_usize() != GIC_PHANDLE { - warn!( + debug!( "node: {}, intr parent: {}, phandle: 0x{:x} is not GIC!", name, parent.node.name(), @@ -325,7 +325,7 @@ pub fn parse_vm_interrupt(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { if v == 0 { trace!("node: {}, GIC_SPI", name); } else { - warn!( + debug!( "node: {}, intr type: {}, not GIC_SPI, not supported!", name, v ); diff --git a/src/vmm/images/mod.rs b/src/vmm/images/mod.rs index b3658b24..b5e8abf6 100644 --- a/src/vmm/images/mod.rs +++ b/src/vmm/images/mod.rs @@ -94,7 +94,7 @@ impl ImageLoader { /// Load VM images from memory /// into the guest VM's memory space based on the VM configuration. fn load_vm_images_from_memory(&self) -> AxResult { - info!("Loading VM[{}] images from memory", self.config.base.id); + trace!("Loading VM[{}] images from memory", self.config.base.id); let vm_imags = config::get_memory_images() .iter() From 960d2d88d4830226aed7439f1b867b4cf20c2cb2 Mon Sep 17 00:00:00 2001 From: szy Date: Thu, 25 Sep 2025 10:02:48 +0800 Subject: [PATCH 16/30] opt --- doc/FDT_Configuration_Guide.md | 21 +++++++++++++++------ src/vmm/config.rs | 4 ++-- src/vmm/fdt/create.rs | 2 +- src/vmm/fdt/device.rs | 3 +++ src/vmm/fdt/test.rs | 4 ++-- 5 files changed, 23 insertions(+), 11 deletions(-) diff --git a/doc/FDT_Configuration_Guide.md b/doc/FDT_Configuration_Guide.md index eb8ea2a3..84f53379 100644 --- a/doc/FDT_Configuration_Guide.md +++ b/doc/FDT_Configuration_Guide.md @@ -46,11 +46,11 @@ AxVisor 会优先使用提供的设备树文件,并根据以下配置更新其 ### 3.2 动态生成设备树 -当 [kernel] 部分的 `dtb_path` 为空字符串时: +当 [kernel] 部分的 `dtb_path` 未添加时: ```toml [kernel] -dtb_path = "" +# dtb_path = "" ``` AxVisor 会根据配置文件中的参数动态生成客户机设备树: @@ -196,7 +196,7 @@ entry_point = 0x8020_0000 image_location = "memory" kernel_path = "tmp/Image" kernel_load_addr = 0x8020_0000 -dtb_path = "" # 空字符串表示动态生成设备树 +# dtb_path = "" # 不使用该字段表示动态生成设备树 dtb_load_addr = 0x8000_0000 memory_regions = [ @@ -220,8 +220,8 @@ excluded_devices = [ ## 7. 处理流程 1. **检查 dtb_path**: - - 如果 `dtb_path` 非空,则加载并使用预定义的设备树文件,此时 `passthrough_devices` 和 `excluded_devices` 配置将被忽略 - - 如果 `dtb_path` 为空,则动态生成设备树,此时 `passthrough_devices` 和 `excluded_devices` 配置生效 + - 如果使用 `dtb_path` 字段,则加载并使用预定义的设备树文件,此时 `passthrough_devices` 和 `excluded_devices` 配置将被忽略 + - 如果未使用 `dtb_path` 字段,则动态生成设备树,此时 `passthrough_devices` 和 `excluded_devices` 配置生效 2. **CPU 节点处理**: - 根据 `phys_cpu_ids` 配置更新或生成 CPU 节点 @@ -239,4 +239,13 @@ excluded_devices = [ 5. **生成最终设备树**: - 将处理后的节点组合成完整的设备树 - - 存储在全局缓存中供后续使用 \ No newline at end of file + - 存储在全局缓存中供后续使用 + +## 8. 特别配置 +1. **qemu 启动参数**: +``` + arceos_args = ["BUS=mmio", "BLK=y", "LOG=info", "SMP=4", "MEM=8g", + "QEMU_ARGS=\"-machine gic-version=3 -cpu cortex-a72 -append 'root=/dev/vda rw init=/init' \"", + "DISK_IMG=\"tmp/qemu/rootfs.img\"",] +``` +其中当不提供设备树时 `-append 'root=/dev/vda rw init=/init'`参数必须添加,目的是在主机设备树中添加chosen节点的bootargs属性。 \ No newline at end of file diff --git a/src/vmm/config.rs b/src/vmm/config.rs index 4e5520f7..de0d3a7c 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -81,7 +81,7 @@ pub fn get_developer_provided_dtb(vm_cfg: &AxVMConfig, crate_config: &AxVMCrateC .find(|&v| v.id == vm_cfg.id())?; if let Some(dtb) = vm_imags.dtb { - info!("DTB file in memory, size: {:x}", dtb.len()); + info!("DTB file in memory, size: 0x{:x}", dtb.len()); return Some(dtb.to_vec()); } }, @@ -91,7 +91,7 @@ pub fn get_developer_provided_dtb(vm_cfg: &AxVMConfig, crate_config: &AxVMCrateC use axerrno::ax_err_type; if let Some(dtb_path) = &crate_config.kernel.dtb_path { let (dtb_file, dtb_size) = crate::vmm::images::open_image_file(&dtb_path).unwrap(); - info!("DTB file in fs, size: {:x}", dtb_size); + 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]; diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index d06b6878..4fe5fdda 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -293,7 +293,7 @@ pub fn update_fdt(dest_addr: GuestPhysAddr, fdt_src: NonNull, dtb_size: usiz let new_fdt_bytes = new_fdt.finish().unwrap(); - print_guest_fdt(new_fdt_bytes.as_slice()); + // print_guest_fdt(new_fdt_bytes.as_slice()); // Load the updated FDT into VM load_vm_image_from_memory(&new_fdt_bytes, dest_addr, vm.clone()).expect("Failed to load VM images"); diff --git a/src/vmm/fdt/device.rs b/src/vmm/fdt/device.rs index ed6476a6..97b40085 100644 --- a/src/vmm/fdt/device.rs +++ b/src/vmm/fdt/device.rs @@ -158,6 +158,9 @@ pub fn find_all_passthrough_devices(vm_cfg: &mut AxVMConfig, fdt: &Fdt) -> Vec Date: Thu, 25 Sep 2025 11:15:40 +0800 Subject: [PATCH 17/30] config.toml --- configs/vms/arceos-aarch64-rk3568-smp1.toml | 32 ++------ configs/vms/arceos-aarch64-rk3568-smp2.toml | 32 ++------ configs/vms/arceos-aarch64-tac_e400-smp1.toml | 32 ++------ configs/vms/linux-aarch64-e2000-smp1.toml | 74 ++----------------- configs/vms/linux-aarch64-e2000-smp2.toml | 74 ++----------------- configs/vms/linux-aarch64-qemu-smp1.toml | 23 +++--- configs/vms/linux-aarch64-rk3568-smp1.toml | 46 ++---------- configs/vms/linux-aarch64-rk3568-smp2.toml | 46 ++---------- configs/vms/linux-aarch64-tac_e400-smp1.toml | 74 ++----------------- configs/vms/nimbos-aarch64-qemu-smp1.toml | 15 ++-- 10 files changed, 81 insertions(+), 367 deletions(-) diff --git a/configs/vms/arceos-aarch64-rk3568-smp1.toml b/configs/vms/arceos-aarch64-rk3568-smp1.toml index eddf9ca4..92ab9acc 100644 --- a/configs/vms/arceos-aarch64-rk3568-smp1.toml +++ b/configs/vms/arceos-aarch64-rk3568-smp1.toml @@ -11,8 +11,6 @@ vm_type = 1 cpu_num = 1 # The physical CPU ids. phys_cpu_ids = [0x200] -# Guest vm physical cpu sets. -phys_cpu_sets = [1] # # Vm kernel configs @@ -29,7 +27,7 @@ kernel_load_addr = 0x7008_0000 kernel_path = "/path/arceos-aarch64-dyn.bin" ## The file path of the device tree blob (DTB). dtb_load_addr = 0x7000_0000 -dtb_path = "/path/arceos-rk3568.dtb" +#dtb_path = "/path/arceos-rk3568.dtb" # Memory regions with format (`base_paddr`, `size`, `flags`, `map_type`). # For `map_type`, 0 means `MAP_ALLOC`, 1 means `MAP_IDENTICAL`. memory_regions = [ @@ -49,25 +47,11 @@ emu_devices = [] # Pass-through devices. # Name Base-Ipa Base-Pa Length Alloc-Irq. passthrough_devices = [ - [ - "UART2", - 0xfe66_0000, - 0xfe66_0000, - 0x10000, - 0x1, - ], - [ - "gic-v3", - 0xfd40_0000, - 0xfd40_0000, - 0x10000, - 0x1, - ], - [ - "gic-v3-its", - 0xfd44_0000, - 0xfd44_0000, - 0x100000, - 0x1, - ], + ["/"], + #["/timer"], +] + +# Devices that are not desired to be passed through to the guest +excluded_devices = [ + # ["/gic-v3"], ] diff --git a/configs/vms/arceos-aarch64-rk3568-smp2.toml b/configs/vms/arceos-aarch64-rk3568-smp2.toml index b70a70ee..e1a1c26a 100644 --- a/configs/vms/arceos-aarch64-rk3568-smp2.toml +++ b/configs/vms/arceos-aarch64-rk3568-smp2.toml @@ -11,8 +11,6 @@ vm_type = 1 cpu_num = 2 # The physical CPU ids. phys_cpu_ids = [0x00, 0x100] -# Guest vm physical cpu sets. -phys_cpu_sets = [1, 2] # # Vm kernel configs @@ -29,7 +27,7 @@ kernel_load_addr = 0x7008_0000 kernel_path = "/path/arceos-aarch64-dyn.bin" ## The file path of the device tree blob (DTB). dtb_load_addr = 0x7000_0000 -dtb_path = "/path/arceos-aarch64-rk3568_smp2.dtb" +#dtb_path = "/path/arceos-aarch64-rk3568_smp2.dtb" # Memory regions with format (`base_paddr`, `size`, `flags`, `map_type`). # For `map_type`, 0 means `MAP_ALLOC`, 1 means `MAP_IDENTICAL`. memory_regions = [ @@ -49,25 +47,11 @@ emu_devices = [] # Pass-through devices. # Name Base-Ipa Base-Pa Length Alloc-Irq. passthrough_devices = [ - [ - "UART2", - 0xfe66_0000, - 0xfe66_0000, - 0x10000, - 0x1, - ], - [ - "gic-v3", - 0xfd40_0000, - 0xfd40_0000, - 0x10000, - 0x1, - ], - [ - "gic-v3-its", - 0xfd44_0000, - 0xfd44_0000, - 0x100000, - 0x1, - ], + ["/"], + #["/timer"], +] + +# Devices that are not desired to be passed through to the guest +excluded_devices = [ + # ["/gic-v3"], ] diff --git a/configs/vms/arceos-aarch64-tac_e400-smp1.toml b/configs/vms/arceos-aarch64-tac_e400-smp1.toml index c81e7bba..ccf474fc 100644 --- a/configs/vms/arceos-aarch64-tac_e400-smp1.toml +++ b/configs/vms/arceos-aarch64-tac_e400-smp1.toml @@ -11,8 +11,6 @@ vm_type = 1 cpu_num = 1 # The physical CPU ids. phys_cpu_ids = [0x200] -# Guest vm physical cpu sets. -phys_cpu_sets = [1] # # Vm kernel configs @@ -29,7 +27,7 @@ kernel_load_addr = 0x20_2008_0000 kernel_path = "/path/to/arceos_aarch64-dyn_smp1.bin" ## The file path of the device tree blob (DTB). dtb_load_addr = 0x20_2000_0000 -dtb_path = "/path/to/arceos-aarch64-tac_e400-smp1.dtb" +#dtb_path = "/path/to/arceos-aarch64-tac_e400-smp1.dtb" # Memory regions with format (`base_paddr`, `size`, `flags`, `map_type`). # For `map_type`, 0 means `MAP_ALLOC`, 1 means `MAP_IDENTICAL`. memory_regions = [ @@ -47,25 +45,11 @@ emu_devices = [] # Pass-through devices. # Name Base-Ipa Base-Pa Length Alloc-Irq. passthrough_devices = [ - [ - "UART1", - 0x2800_d000, - 0x2800_d000, - 0x1000, - 0x1, - ], - [ - "gic-v3", - 0x3080_0000, - 0x3080_0000, - 0x10000, - 0x1, - ], - [ - "gic-v3-its", - 0x3082_0000, - 0x3082_0000, - 0x100000, - 0x1, - ], + ["/"], + #["/timer"], ] + +# Devices that are not desired to be passed through to the guest +excluded_devices = [ + # ["/gic-v3"], +] \ No newline at end of file diff --git a/configs/vms/linux-aarch64-e2000-smp1.toml b/configs/vms/linux-aarch64-e2000-smp1.toml index 52017828..ece732d1 100644 --- a/configs/vms/linux-aarch64-e2000-smp1.toml +++ b/configs/vms/linux-aarch64-e2000-smp1.toml @@ -11,8 +11,6 @@ vm_type = 1 cpu_num = 1 # The physical CPU ids. phys_cpu_ids = [0x100] -# Guest vm physical cpu sets. -phys_cpu_sets = [8] # # Vm kernel configs @@ -29,7 +27,7 @@ kernel_load_addr = 0x20_4008_0000 kernel_path = "/path/to/Image" ## The file path of the device tree blob (DTB). dtb_load_addr = 0x20_4000_0000 -dtb_path = "/path/to/axvisor/configs/vms/linux-aarch64-e2000_smp1.dtb" +#dtb_path = "/path/to/axvisor/configs/vms/linux-aarch64-e2000_smp1.dtb" # Memory regions with format (`base_paddr`, `size`, `flags`, `map_type`). # For `map_type`, 0 means `MAP_ALLOC`, 1 means `MAP_IDENTICAL`. memory_regions = [ @@ -48,67 +46,11 @@ emu_devices = [] # Pass-through devices. # Name Base-Ipa Base-Pa Length Alloc-Irq. passthrough_devices = [ - [ - "QSPI", - 0x0000_0000, - 0x0000_0000, - 0x1000_0000, - 0x1, - ], - [ - "LocalBus", - 0x1000_0000, - 0x1000_0000, - 0x1000_0000, - 0x1, - ], - [ - "low speed peripherals", - 0x2800_0000, - 0x2800_0000, - 0x0800_0000, - 0x1, - ], - [ - "other peripherals", - 0x3000_0000, - 0x3000_0000, - 0x0800_0000, - 0x1, - ], - [ - "IACC", - 0x3800_0000, - 0x3800_0000, - 0x0800_0000, - 0x1, - ], - [ - "PCIE", - 0x4000_0000, - 0x4000_0000, - 0x4000_0000, - 0x1, - ], - [ - "QSPI high address", - 0x01_0000_0000, - 0x01_0000_0000, - 0x8000_0000, - 0x1, - ], - [ - "LocalBus high address", - 0x01_8000_0000, - 0x01_8000_0000, - 0x8000_0000, - 0x1, - ], - [ - "PCIe MEM64", - 0x10_0000_0000, - 0x10_0000_0000, - 0x01_0000_0000, - 0x1, - ], + ["/"], + #["/timer"], ] + +# Devices that are not desired to be passed through to the guest +excluded_devices = [ + # ["/gic-v3"], +] \ No newline at end of file diff --git a/configs/vms/linux-aarch64-e2000-smp2.toml b/configs/vms/linux-aarch64-e2000-smp2.toml index bf409a0b..054954d4 100644 --- a/configs/vms/linux-aarch64-e2000-smp2.toml +++ b/configs/vms/linux-aarch64-e2000-smp2.toml @@ -11,8 +11,6 @@ vm_type = 1 cpu_num = 2 # The physical CPU ids. phys_cpu_ids = [0x200, 0x00] -# Guest vm physical cpu sets. -phys_cpu_sets = [1, 4] # # Vm kernel configs @@ -29,7 +27,7 @@ kernel_load_addr = 0x20_4008_0000 kernel_path = "/path/to/Image" ## The file path of the device tree blob (DTB). dtb_load_addr = 0x20_4000_0000 -dtb_path = "/path/to/axvisor/configs/vms/linux-aarch64-e2000_smp2.dtb" +#dtb_path = "/path/to/axvisor/configs/vms/linux-aarch64-e2000_smp2.dtb" # Memory regions with format (`base_paddr`, `size`, `flags`, `map_type`). # For `map_type`, 0 means `MAP_ALLOC`, 1 means `MAP_IDENTICAL`. memory_regions = [ @@ -49,67 +47,11 @@ emu_devices = [] # Pass-through devices. # Name Base-Ipa Base-Pa Length Alloc-Irq. passthrough_devices = [ - [ - "QSPI", - 0x0000_0000, - 0x0000_0000, - 0x1000_0000, - 0x1, - ], - [ - "LocalBus", - 0x1000_0000, - 0x1000_0000, - 0x1000_0000, - 0x1, - ], - [ - "low speed peripherals", - 0x2800_0000, - 0x2800_0000, - 0x0800_0000, - 0x1, - ], - [ - "other peripherals", - 0x3000_0000, - 0x3000_0000, - 0x0800_0000, - 0x1, - ], - [ - "IACC", - 0x3800_0000, - 0x3800_0000, - 0x0800_0000, - 0x1, - ], - [ - "PCIE", - 0x4000_0000, - 0x4000_0000, - 0x4000_0000, - 0x1, - ], - [ - "QSPI high address", - 0x01_0000_0000, - 0x01_0000_0000, - 0x8000_0000, - 0x1, - ], - [ - "LocalBus high address", - 0x01_8000_0000, - 0x01_8000_0000, - 0x8000_0000, - 0x1, - ], - [ - "PCIe MEM64", - 0x10_0000_0000, - 0x10_0000_0000, - 0x01_0000_0000, - 0x1, - ], + ["/"], + #["/timer"], ] + +# Devices that are not desired to be passed through to the guest +excluded_devices = [ + # ["/gic-v3"], +] \ No newline at end of file diff --git a/configs/vms/linux-aarch64-qemu-smp1.toml b/configs/vms/linux-aarch64-qemu-smp1.toml index be50f924..3accc1b3 100644 --- a/configs/vms/linux-aarch64-qemu-smp1.toml +++ b/configs/vms/linux-aarch64-qemu-smp1.toml @@ -11,7 +11,6 @@ vm_type = 1 cpu_num = 1 # Guest vm physical cpu sets. phys_cpu_ids = [0] -phys_cpu_sets = [1] # # Vm kernel configs @@ -28,7 +27,7 @@ kernel_path = "tmp/Image" # The load address of the kernel image. kernel_load_addr = 0x8020_0000 # The file path of the device tree blob (DTB). -dtb_path = "tmp/linux-aarch64-qemu-smp1.dtb" +#dtb_path = "tmp/linux-aarch64-qemu-smp1.dtb" # The load address of the device tree blob (DTB). dtb_load_addr = 0x8000_0000 @@ -43,19 +42,15 @@ memory_regions = [ # [devices] # Pass-through devices. +# Name Base-Ipa Base-Pa Length Alloc-Irq. passthrough_devices = [ - ["intc@8000000", 0x800_0000, 0x800_0000, 0x100_0000, 0x1], - # ["pl011@9000000", 0x900_0000, 0x900_0000, 0x1000, 0x1], - # ["pl031@9010000", 0x901_0000, 0x901_0000, 0x1000, 0x1], - # ["pl061@9030000", 0x903_0000, 0x903_0000, 0x1000, 0x1], - # a003000.virtio_mmio virtio_mmio@a003000 - # a003200.virtio_mmio virtio_mmio@a003200 - # ["virtio_mmio", 0xa00_0000, 0xa00_0000, 0x4000, 0x1], - # ["low-devices", 0x0, 0x0, 0x0800_0000, 0x1], - # ["low-devices2", 0x09000000, 0x09000000, 0x1000_0000, 0x1], - # ["pci@10000000", 0x10000000, 0x10000000, 0x10000000, 0x1], - # ["pci", 0x4010000000, 0x4010000000, 0x100000, 0x1], - # ["pci-range", 0x8000000000, 0x8000000000, 0x10000, 0x1], + ["/"], + #["/timer"], +] + +# Devices that are not desired to be passed through to the guest +excluded_devices = [ + # ["/gic-v3"], ] # Emu_devices. diff --git a/configs/vms/linux-aarch64-rk3568-smp1.toml b/configs/vms/linux-aarch64-rk3568-smp1.toml index 69217e45..8301b575 100644 --- a/configs/vms/linux-aarch64-rk3568-smp1.toml +++ b/configs/vms/linux-aarch64-rk3568-smp1.toml @@ -11,8 +11,6 @@ vm_type = 1 cpu_num = 1 # The physical CPU ids. phys_cpu_ids = [0x00] -# Guest vm physical cpu sets. -phys_cpu_sets = [1] # # Vm kernel configs @@ -29,7 +27,7 @@ kernel_load_addr = 0x8008_0000 kernel_path = "/path/Image" ## The file path of the device tree blob (DTB). dtb_load_addr = 0x8000_0000 -dtb_path = "/path/linux-aarch64-rk3568_smp1.dtb" +#dtb_path = "/path/linux-aarch64-rk3568_smp1.dtb" # Memory regions with format (`base_paddr`, `size`, `flags`, `map_type`). # For `map_type`, 0 means `MAP_ALLOC`, 1 means `MAP_IDENTICAL`. memory_regions = [ @@ -48,39 +46,11 @@ emu_devices = [] # Pass-through devices. # Name Base-Ipa Base-Pa Length Alloc-Irq. passthrough_devices = [ - # [ - # "peripherals 1", - # 0xf000_0000, - # 0xf000_0000, - # 0xe66_0000, - # 0x1, - # ], - # [ - # "peripherals 2", - # 0xfe67_0000, - # 0xfe67_0000, - # 0x99_0000, - # 0x1, - # ], - [ - "all peripherals", - 0xf0000000, - 0xf0000000, - 0xf000000, - 0x1, - ], - [ - "PCIe related", - 0x3_0000_0000, - 0x3_0000_0000, - 0xd000_0000, - 0x1, - ], - [ - "ramoops, scmi-shmem, etc.", - 0x100000, - 0x100000, - 0x200000, - 0x1, - ], + ["/"], + #["/timer"], +] + +# Devices that are not desired to be passed through to the guest +excluded_devices = [ + # ["/gic-v3"], ] diff --git a/configs/vms/linux-aarch64-rk3568-smp2.toml b/configs/vms/linux-aarch64-rk3568-smp2.toml index 411b7fdc..70ae7ed4 100644 --- a/configs/vms/linux-aarch64-rk3568-smp2.toml +++ b/configs/vms/linux-aarch64-rk3568-smp2.toml @@ -11,8 +11,6 @@ vm_type = 1 cpu_num = 2 # The physical CPU ids. phys_cpu_ids = [0x200, 0x300] -# Guest vm physical cpu sets. -phys_cpu_sets = [4, 8] # # Vm kernel configs @@ -29,7 +27,7 @@ kernel_load_addr = 0x8008_0000 kernel_path = "/code/axvisor/rk3568-linux/Image" ## The file path of the device tree blob (DTB). dtb_load_addr = 0x8000_0000 -dtb_path = "/code/axvisor/configs/vms/linux-aarch64-rk3568_smp2.dtb" +#dtb_path = "/code/axvisor/configs/vms/linux-aarch64-rk3568_smp2.dtb" # Memory regions with format (`base_paddr`, `size`, `flags`, `map_type`). # For `map_type`, 0 means `MAP_ALLOC`, 1 means `MAP_IDENTICAL`. memory_regions = [ @@ -48,39 +46,11 @@ emu_devices = [] # Pass-through devices. # Name Base-Ipa Base-Pa Length Alloc-Irq. passthrough_devices = [ - # [ - # "peripherals 1", - # 0xf000_0000, - # 0xf000_0000, - # 0xe66_0000, - # 0x1, - # ], - # [ - # "peripherals 2", - # 0xfe67_0000, - # 0xfe67_0000, - # 0x99_0000, - # 0x1, - # ], - [ - "all peripherals", - 0xf0000000, - 0xf0000000, - 0xf000000, - 0x1, - ], - [ - "PCIe related", - 0x300000000, - 0x300000000, - 0xd0000000, - 0x1, - ], - [ - "ramoops, scmi-shmem, etc.", - 0x100000, - 0x100000, - 0x200000, - 0x1, - ], + ["/"], + #["/timer"], ] + +# Devices that are not desired to be passed through to the guest +excluded_devices = [ + # ["/gic-v3"], +] \ No newline at end of file diff --git a/configs/vms/linux-aarch64-tac_e400-smp1.toml b/configs/vms/linux-aarch64-tac_e400-smp1.toml index 107afe64..17784330 100644 --- a/configs/vms/linux-aarch64-tac_e400-smp1.toml +++ b/configs/vms/linux-aarch64-tac_e400-smp1.toml @@ -11,8 +11,6 @@ vm_type = 1 cpu_num = 1 # The physical CPU ids. phys_cpu_ids = [0x100] -# Guest vm physical cpu sets. -phys_cpu_sets = [8] # # Vm kernel configs @@ -29,7 +27,7 @@ kernel_load_addr = 0x20_4008_0000 kernel_path = "/path/to/Image" ## The file path of the device tree blob (DTB). dtb_load_addr = 0x20_4000_0000 -dtb_path = "/path/to/linux-aarch64-tac_e400-smp1.dtb" +#dtb_path = "/path/to/linux-aarch64-tac_e400-smp1.dtb" # Memory regions with format (`base_paddr`, `size`, `flags`, `map_type`). # For `map_type`, 0 means `MAP_ALLOC`, 1 means `MAP_IDENTICAL`. memory_regions = [ @@ -48,67 +46,11 @@ emu_devices = [] # Pass-through devices. # Name Base-Ipa Base-Pa Length Alloc-Irq. passthrough_devices = [ - [ - "QSPI", - 0x0000_0000, - 0x0000_0000, - 0x1000_0000, - 0x1, - ], - [ - "LocalBus", - 0x1000_0000, - 0x1000_0000, - 0x1000_0000, - 0x1, - ], - [ - "low speed peripherals", - 0x2800_0000, - 0x2800_0000, - 0x0800_0000, - 0x1, - ], - [ - "other peripherals", - 0x3000_0000, - 0x3000_0000, - 0x0800_0000, - 0x1, - ], - [ - "IACC", - 0x3800_0000, - 0x3800_0000, - 0x0800_0000, - 0x1, - ], - [ - "PCIE", - 0x4000_0000, - 0x4000_0000, - 0x4000_0000, - 0x1, - ], - [ - "QSPI high address", - 0x01_0000_0000, - 0x01_0000_0000, - 0x8000_0000, - 0x1, - ], - [ - "LocalBus high address", - 0x01_8000_0000, - 0x01_8000_0000, - 0x8000_0000, - 0x1, - ], - [ - "PCIe MEM64", - 0x10_0000_0000, - 0x10_0000_0000, - 0x01_0000_0000, - 0x1, - ], + ["/"], + #["/timer"], ] + +# Devices that are not desired to be passed through to the guest +excluded_devices = [ + # ["/gic-v3"], +] \ No newline at end of file diff --git a/configs/vms/nimbos-aarch64-qemu-smp1.toml b/configs/vms/nimbos-aarch64-qemu-smp1.toml index 52ee179d..7106afea 100644 --- a/configs/vms/nimbos-aarch64-qemu-smp1.toml +++ b/configs/vms/nimbos-aarch64-qemu-smp1.toml @@ -10,7 +10,7 @@ vm_type = 1 # The number of virtual CPUs. cpu_num = 1 # Guest vm physical cpu sets. -phys_cpu_sets = [1] +phys_cpu_ids = [0] # # Vm kernel configs @@ -65,10 +65,11 @@ emu_devices = [ # Pass-through devices. # Name Base-Ipa Base-Pa Length Alloc-Irq. passthrough_devices = [ - # ["intc@8000000", 0x801_0000, 0x804_0000, 0x2_000, 0x1], - ["intc@8000000", 0x800_0000, 0x800_0000, 0x40000, 0x1], - ["pl011@9000000", 0x900_0000, 0x904_0000, 0x1000, 0x1], - ["pl031@9010000", 0x901_0000, 0x901_0000, 0x1000, 0x1], - ["pl061@9030000", 0x903_0000, 0x903_0000, 0x1000, 0x1], # a003000.virtio_mmio virtio_mmio@a003000 # a003200.virtio_mmio virtio_mmio@a003200 - ["virtio_mmio", 0xa00_0000, 0xa00_0000, 0x4000, 0x1], + ["/"], + #["/timer"], ] + +# Devices that are not desired to be passed through to the guest +excluded_devices = [ + # ["/gic-v3"], +] \ No newline at end of file From 911d50d636c04928694426103be6c7ebe4fbc742 Mon Sep 17 00:00:00 2001 From: szy Date: Thu, 25 Sep 2025 13:33:27 +0800 Subject: [PATCH 18/30] fix fmt bug --- src/vmm/config.rs | 43 ++++++------ src/vmm/fdt/create.rs | 151 +++++++++++++++++++++++++++++------------- src/vmm/fdt/device.rs | 68 ++++++++++--------- src/vmm/fdt/mod.rs | 6 +- src/vmm/fdt/parser.rs | 57 ++++++++++------ src/vmm/fdt/test.rs | 16 +++-- src/vmm/images/mod.rs | 6 +- 7 files changed, 220 insertions(+), 127 deletions(-) diff --git a/src/vmm/config.rs b/src/vmm/config.rs index de0d3a7c..8ac4d5de 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -1,15 +1,13 @@ -use core::alloc::Layout; use axaddrspace::GuestPhysAddr; use axvm::{ VMMemoryRegion, config::{AxVMConfig, AxVMCrateConfig, VmMemMappingType}, }; +use core::alloc::Layout; use fdt_parser::Fdt; use memory_addr::MemoryAddr; -use crate::vmm::{ - fdt::*, images::ImageLoader, vm_list::push_vm, VM -}; +use crate::vmm::{VM, fdt::*, images::ImageLoader, vm_list::push_vm}; use alloc::collections::BTreeMap; use alloc::sync::Arc; @@ -21,8 +19,8 @@ pub static GENERATED_DTB_CACHE: LazyInit>>> = La #[allow(clippy::module_inception)] pub mod config { - use alloc::vec::Vec; use alloc::string::String; + use alloc::vec::Vec; /// Default static VM configs. Used when no VM config is provided. #[allow(dead_code)] @@ -41,11 +39,11 @@ pub mod config { #[cfg(feature = "fs")] pub fn filesystem_vm_configs() -> Vec { use axstd::fs; - + // Try to read config files from a predefined directory let config_dir = "configs/vms"; let mut configs = Vec::new(); - + if let Ok(entries) = fs::read_dir(config_dir) { for entry in entries { if let Ok(entry) = entry { @@ -60,10 +58,10 @@ pub mod config { } } } - + configs } - + /// Fallback function for when "fs" feature is not enabled #[cfg(not(feature = "fs"))] pub fn filesystem_vm_configs() -> Vec { @@ -73,7 +71,10 @@ pub mod config { include!(concat!(env!("OUT_DIR"), "/vm_configs.rs")); } -pub fn get_developer_provided_dtb(vm_cfg: &AxVMConfig, crate_config: &AxVMCrateConfig) -> Option> { +pub fn get_developer_provided_dtb( + vm_cfg: &AxVMConfig, + crate_config: &AxVMCrateConfig, +) -> Option> { match crate_config.kernel.image_location.as_deref() { Some("memory") => { let vm_imags = config::get_memory_images() @@ -84,11 +85,11 @@ pub fn get_developer_provided_dtb(vm_cfg: &AxVMConfig, crate_config: &AxVMCrateC info!("DTB file in memory, size: 0x{:x}", dtb.len()); return Some(dtb.to_vec()); } - }, + } #[cfg(feature = "fs")] Some("fs") => { - use std::io::{BufReader, Read}; use axerrno::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::open_image_file(&dtb_path).unwrap(); info!("DTB file in fs, size: 0x{:x}", dtb_size); @@ -96,15 +97,17 @@ pub fn get_developer_provided_dtb(vm_cfg: &AxVMConfig, crate_config: &AxVMCrateC 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(); + 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." ), @@ -127,7 +130,7 @@ pub fn init_guest_vms() { // First try to get configs from filesystem if fs feature is enabled let mut gvm_raw_configs = config::filesystem_vm_configs(); - + // If no filesystem configs found, fallback to static configs if gvm_raw_configs.is_empty() { let static_configs = config::static_vm_configs(); diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index 4fe5fdda..dc3678ad 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -6,63 +6,82 @@ use alloc::{ use core::ptr::NonNull; use axaddrspace::GuestPhysAddr; -use axvm::{ - config::AxVMCrateConfig, - VMMemoryRegion, -}; +use axvm::{VMMemoryRegion, config::AxVMCrateConfig}; use fdt_parser::{Fdt, Node}; use vm_fdt::{FdtWriter, FdtWriterNode}; -use crate::vmm::{fdt::test::{print_fdt, print_guest_fdt}, images::load_vm_image_from_memory, VMRef}; +use crate::vmm::{ + VMRef, + fdt::test::{print_fdt, print_guest_fdt}, + images::load_vm_image_from_memory, +}; /// Generate guest FDT and return DTB data -/// +/// /// # Parameters /// * `fdt` - Source FDT data /// * `passthrough_device_names` - Passthrough device name list /// * `crate_config` - VM creation configuration -/// +/// /// # Return Value /// Returns the generated DTB data -pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, crate_config: &AxVMCrateConfig) -> Vec { +pub fn crate_guest_fdt( + fdt: &Fdt, + passthrough_device_names: &Vec, + crate_config: &AxVMCrateConfig, +) -> Vec { let mut fdt_writer = FdtWriter::new().unwrap(); // Track the level of the previously processed node for level change handling let mut previous_node_level = 0; // Maintain a stack of FDT nodes to correctly start and end nodes let mut node_stack: Vec = Vec::new(); - let phys_cpu_ids = crate_config.base.phys_cpu_ids.clone().expect("ERROR: phys_cpu_ids is None"); + let phys_cpu_ids = crate_config + .base + .phys_cpu_ids + .clone() + .expect("ERROR: phys_cpu_ids is None"); let all_nodes: Vec = fdt.all_nodes().collect(); for (index, node) in all_nodes.iter().enumerate() { let node_path = super::build_node_path(&all_nodes, index); - let node_action = determine_node_action( - node, - &node_path, - passthrough_device_names, - ); + let node_action = determine_node_action(node, &node_path, passthrough_device_names); match node_action { NodeAction::RootNode => { node_stack.push(fdt_writer.begin_node("").unwrap()); - }, + } NodeAction::CpuNode => { let need = need_cpu_node(&phys_cpu_ids, node, &node_path); if need { - handle_node_level_change(&mut fdt_writer, &mut node_stack, node.level, previous_node_level); + handle_node_level_change( + &mut fdt_writer, + &mut node_stack, + node.level, + previous_node_level, + ); node_stack.push(fdt_writer.begin_node(node.name()).unwrap()); } else { continue; } - }, + } NodeAction::Skip => { continue; - }, + } _ => { - trace!("Found exact passthrough device node: {}, path: {}", node.name(), node_path); - handle_node_level_change(&mut fdt_writer, &mut node_stack, node.level, previous_node_level); + trace!( + "Found exact passthrough device node: {}, path: {}", + node.name(), + node_path + ); + handle_node_level_change( + &mut fdt_writer, + &mut node_stack, + node.level, + previous_node_level, + ); node_stack.push(fdt_writer.begin_node(node.name()).unwrap()); - }, + } } previous_node_level = node.level; @@ -78,7 +97,7 @@ pub fn crate_guest_fdt(fdt: &Fdt, passthrough_device_names: &Vec, crate_ previous_node_level -= 1; fdt_writer.end_node(node).unwrap(); } - assert_eq!(previous_node_level , 0); + assert_eq!(previous_node_level, 0); let guest_fdt_bytes = fdt_writer.finish().unwrap(); @@ -125,16 +144,16 @@ fn determine_node_action( } else if node.name().starts_with("memory") { // Skip memory nodes, will add them later return NodeAction::Skip; - } else if node_path.starts_with("/cpus"){ + } else if node_path.starts_with("/cpus") { return NodeAction::CpuNode; } else if passthrough_device_names.contains(&node_path.to_string()) { // Fully matched passthrough device node return NodeAction::IncludeAsPassthroughDevice; - } + } // Check if the node is a descendant of a passthrough device (by path inclusion and level validation) else if is_descendant_of_passthrough_device(node_path, node.level, passthrough_device_names) { return NodeAction::IncludeAsChildNode; - } + } // Check if the node is an ancestor of a passthrough device (by path inclusion and level validation) else if is_ancestor_of_passthrough_device(node_path, passthrough_device_names) { return NodeAction::IncludeAsAncestorNode; @@ -146,17 +165,22 @@ fn determine_node_action( /// Determine if node is a descendant of passthrough device /// When node path contains a path from passthrough_device_names and is longer than it, it is its descendant node /// Also use node_level as validation condition -fn is_descendant_of_passthrough_device(node_path: &str, node_level: usize, passthrough_device_names: &Vec) -> bool { +fn is_descendant_of_passthrough_device( + node_path: &str, + node_level: usize, + passthrough_device_names: &Vec, +) -> bool { for passthrough_path in passthrough_device_names { // Check if the current node is a descendant of a passthrough device if node_path.starts_with(passthrough_path) && node_path.len() > passthrough_path.len() { // Ensure it is a true descendant path (separated by /) - if passthrough_path == "/" || node_path.chars().nth(passthrough_path.len()) == Some('/') { + if passthrough_path == "/" || node_path.chars().nth(passthrough_path.len()) == Some('/') + { // Use level relationship for validation: the level of a descendant node should be higher than its parent // Note: The level of the root node is 1, its direct child node level is 2, and so on let expected_parent_level = passthrough_path.matches('/').count(); let current_node_level = node_level; - + // If passthrough_path is the root node "/", then its child node level should be 2 // Otherwise, the child node level should be higher than the parent node level if passthrough_path == "/" && current_node_level >= 2 { @@ -187,7 +211,10 @@ fn handle_node_level_change( } /// Determine if node is an ancestor of passthrough device -fn is_ancestor_of_passthrough_device(node_path: &str, passthrough_device_names: &Vec) -> bool { +fn is_ancestor_of_passthrough_device( + node_path: &str, + passthrough_device_names: &Vec, +) -> bool { for passthrough_path in passthrough_device_names { // Check if the current node is an ancestor of a passthrough device if passthrough_path.starts_with(&node_path) && passthrough_path.len() > node_path.len() { @@ -202,22 +229,34 @@ fn is_ancestor_of_passthrough_device(node_path: &str, passthrough_device_names: } /// Determine if CPU node is needed -fn need_cpu_node(phys_cpu_ids: &Vec, node: &Node, node_path: &str) -> bool{ +fn need_cpu_node(phys_cpu_ids: &Vec, node: &Node, node_path: &str) -> bool { let mut should_include_node = false; - + if !node_path.starts_with("/cpus/cpu@") { should_include_node = true; } else { if let Some(mut cpu_reg) = node.reg() { if let Some(reg_entry) = cpu_reg.next() { let cpu_address = reg_entry.address as usize; - debug!("Checking CPU node {} with address 0x{:x}", node.name(), cpu_address); + debug!( + "Checking CPU node {} with address 0x{:x}", + node.name(), + cpu_address + ); // Check if this CPU address is in the configured phys_cpu_ids if phys_cpu_ids.contains(&cpu_address) { should_include_node = true; - debug!("CPU node {} with address 0x{:x} is in phys_cpu_ids, including in guest FDT", node.name(), cpu_address); + debug!( + "CPU node {} with address 0x{:x} is in phys_cpu_ids, including in guest FDT", + node.name(), + cpu_address + ); } else { - debug!("CPU node {} with address 0x{:x} is NOT in phys_cpu_ids, skipping", node.name(), cpu_address); + debug!( + "CPU node {} with address 0x{:x} is NOT in phys_cpu_ids, skipping", + node.name(), + cpu_address + ); } } } @@ -260,7 +299,12 @@ pub fn update_fdt(dest_addr: GuestPhysAddr, fdt_src: NonNull, dtb_size: usiz // Skip memory nodes, will add them later continue; } else { - handle_node_level_change(&mut new_fdt, &mut node_stack, node.level, previous_node_level); + handle_node_level_change( + &mut new_fdt, + &mut node_stack, + node.level, + previous_node_level, + ); // Start new node node_stack.push(new_fdt.begin_node(node.name()).unwrap()); } @@ -286,7 +330,7 @@ pub fn update_fdt(dest_addr: GuestPhysAddr, fdt_src: NonNull, dtb_size: usiz new_fdt.end_node(memory_node).unwrap(); } } - + assert_eq!(previous_node_level, 0); info!("Updating FDT memory successfully"); @@ -296,19 +340,24 @@ pub fn update_fdt(dest_addr: GuestPhysAddr, fdt_src: NonNull, dtb_size: usiz // print_guest_fdt(new_fdt_bytes.as_slice()); // Load the updated FDT into VM - load_vm_image_from_memory(&new_fdt_bytes, dest_addr, vm.clone()).expect("Failed to load VM images"); + load_vm_image_from_memory(&new_fdt_bytes, dest_addr, vm.clone()) + .expect("Failed to load VM images"); } -pub fn update_cpu_node(fdt: &Fdt, host_fdt: &Fdt, crate_config: &AxVMCrateConfig) -> Vec{ +pub fn update_cpu_node(fdt: &Fdt, host_fdt: &Fdt, crate_config: &AxVMCrateConfig) -> Vec { let mut new_fdt = FdtWriter::new().unwrap(); let mut previous_node_level = 0; let mut node_stack: Vec = Vec::new(); - let phys_cpu_ids = crate_config.base.phys_cpu_ids.clone().expect("ERROR: phys_cpu_ids is None"); + let phys_cpu_ids = crate_config + .base + .phys_cpu_ids + .clone() + .expect("ERROR: phys_cpu_ids is None"); // Collect all nodes from both FDTs let fdt_all_nodes: Vec = fdt.all_nodes().collect(); let host_fdt_all_nodes: Vec = host_fdt.all_nodes().collect(); - + for (index, node) in fdt_all_nodes.iter().enumerate() { let node_path = super::build_node_path(&fdt_all_nodes, index); @@ -319,7 +368,12 @@ pub fn update_cpu_node(fdt: &Fdt, host_fdt: &Fdt, crate_config: &AxVMCrateConfig continue; } else { // For all other nodes, include them from fdt as-is without filtering - handle_node_level_change(&mut new_fdt, &mut node_stack, node.level, previous_node_level); + handle_node_level_change( + &mut new_fdt, + &mut node_stack, + node.level, + previous_node_level, + ); node_stack.push(new_fdt.begin_node(node.name()).unwrap()); } @@ -330,7 +384,7 @@ pub fn update_cpu_node(fdt: &Fdt, host_fdt: &Fdt, crate_config: &AxVMCrateConfig new_fdt.property(prop.name, prop.raw_value()).unwrap(); } } - + // Process all CPU nodes from host_fdt for (index, node) in host_fdt_all_nodes.iter().enumerate() { let node_path = super::build_node_path(&host_fdt_all_nodes, index); @@ -339,14 +393,19 @@ pub fn update_cpu_node(fdt: &Fdt, host_fdt: &Fdt, crate_config: &AxVMCrateConfig // For CPU nodes, apply filtering based on host_fdt nodes let need = need_cpu_node(&phys_cpu_ids, node, &node_path); if need { - handle_node_level_change(&mut new_fdt, &mut node_stack, node.level, previous_node_level); + handle_node_level_change( + &mut new_fdt, + &mut node_stack, + node.level, + previous_node_level, + ); node_stack.push(new_fdt.begin_node(node.name()).unwrap()); - + // Copy properties from host CPU node for prop in node.propertys() { new_fdt.property(prop.name, prop.raw_value()).unwrap(); } - + previous_node_level = node.level; } } @@ -357,7 +416,7 @@ pub fn update_cpu_node(fdt: &Fdt, host_fdt: &Fdt, crate_config: &AxVMCrateConfig previous_node_level -= 1; new_fdt.end_node(node).unwrap(); } - assert_eq!(previous_node_level , 0); + assert_eq!(previous_node_level, 0); let guest_fdt_bytes = new_fdt.finish().unwrap(); diff --git a/src/vmm/fdt/device.rs b/src/vmm/fdt/device.rs index 97b40085..fb369d90 100644 --- a/src/vmm/fdt/device.rs +++ b/src/vmm/fdt/device.rs @@ -5,8 +5,8 @@ use alloc::{ string::{String, ToString}, vec::Vec, }; +use axvm::config::AxVMConfig; use fdt_parser::{Fdt, Node}; -use axvm::config::{AxVMConfig}; /// Return the collection of all passthrough devices in the configuration file and newly added devices found pub fn find_all_passthrough_devices(vm_cfg: &mut AxVMConfig, fdt: &Fdt) -> Vec { @@ -14,7 +14,7 @@ pub fn find_all_passthrough_devices(vm_cfg: &mut AxVMConfig, fdt: &Fdt) -> Vec> = build_optimized_node_cache(fdt); - + // Get the list of configured device names let initial_device_names: Vec = vm_cfg .pass_through_devices() @@ -43,10 +43,7 @@ pub fn find_all_passthrough_devices(vm_cfg: &mut AxVMConfig, fdt: &Fdt) -> Vec Vec Vec = - excluded_device_path.iter().cloned().collect(); + let mut process_excludeds: BTreeSet = excluded_device_path.iter().cloned().collect(); for device_path in &excluded_device_path { // Get all descendant node paths for this device @@ -124,10 +124,7 @@ pub fn find_all_passthrough_devices(vm_cfg: &mut AxVMConfig, fdt: &Fdt) -> Vec Vec = all_excludes_devices.into_iter().collect(); - + // Filter out excluded devices all_device_names.retain(|device_name| { let should_keep = !excluded_set.contains(device_name); @@ -167,7 +167,7 @@ pub fn find_all_passthrough_devices(vm_cfg: &mut AxVMConfig, fdt: &Fdt) -> Vec, target_index: usize) -> String { for i in 0..=target_index { let node = &all_nodes[i]; let level = node.level; - + if level == 1 { path_stack.clear(); if node.name() != "/" { @@ -197,7 +197,7 @@ pub fn build_node_path(all_nodes: &Vec, target_index: usize) -> String { path_stack.push(node.name().to_string()); } } - + // Build the full path of the current node if path_stack.is_empty() || (path_stack.len() == 1 && path_stack[0] == "/") { "/".to_string() @@ -210,9 +210,9 @@ pub fn build_node_path(all_nodes: &Vec, target_index: usize) -> String { /// Use level relationships to directly build paths, avoiding path conflicts for nodes with the same name pub fn build_optimized_node_cache<'a>(fdt: &'a Fdt) -> BTreeMap>> { let mut node_cache: BTreeMap>> = BTreeMap::new(); - + let all_nodes: Vec = fdt.all_nodes().collect(); - + for (index, node) in all_nodes.iter().enumerate() { let node_path = build_node_path(&all_nodes, index); if let Some(existing_nodes) = node_cache.get(&node_path) { @@ -226,8 +226,11 @@ pub fn build_optimized_node_cache<'a>(fdt: &'a Fdt) -> BTreeMap BTreeMap) let mut phandle_map = BTreeMap::new(); let all_nodes: Vec = fdt.all_nodes().collect(); - + for (index, node) in all_nodes.iter().enumerate() { let node_path = build_node_path(&all_nodes, index); - + // Collect node properties let mut phandle = None; let mut cells_map = BTreeMap::new(); @@ -463,7 +466,7 @@ impl DevicePropertyClassifier { fn find_device_dependencies( device_node_path: &str, phandle_map: &BTreeMap)>, - node_cache: &BTreeMap>, // Add node_cache parameter + node_cache: &BTreeMap>, // Add node_cache parameter ) -> Vec { let mut dependencies = Vec::new(); @@ -474,7 +477,8 @@ fn find_device_dependencies( for prop in node.propertys() { // Determine if it's a phandle property that needs to be processed if DevicePropertyClassifier::is_phandle_property(prop.name) { - let mut prop_deps = parse_phandle_property(prop.raw_value(), prop.name, phandle_map); + let mut prop_deps = + parse_phandle_property(prop.raw_value(), prop.name, phandle_map); dependencies.append(&mut prop_deps); } } @@ -486,16 +490,19 @@ fn find_device_dependencies( /// Get all descendant nodes based on parent node path (including child nodes, grandchild nodes, etc.) /// Find all descendant nodes by looking up nodes with parent node path as prefix in node_cache -fn get_descendant_nodes_by_path<'a>(node_cache: &'a BTreeMap>>, parent_path: &str) -> Vec { +fn get_descendant_nodes_by_path<'a>( + node_cache: &'a BTreeMap>>, + parent_path: &str, +) -> Vec { let mut descendant_paths = Vec::new(); - + // Special handling if parent path is root path let search_prefix = if parent_path == "/" { "/".to_string() } else { parent_path.to_string() + "/" }; - + // Traverse node_cache, find all nodes with parent path as prefix for (path, _nodes) in node_cache { // Check if path has parent path as prefix (and is not the parent path itself) @@ -504,7 +511,6 @@ fn get_descendant_nodes_by_path<'a>(node_cache: &'a BTreeMap &'static [u8] { fdt_bytes } -pub fn setup_guest_fdt_from_vmm(fdt_bytes: &[u8], vm_cfg: &mut AxVMConfig, crate_config: &AxVMCrateConfig) { - +pub fn setup_guest_fdt_from_vmm( + fdt_bytes: &[u8], + vm_cfg: &mut AxVMConfig, + crate_config: &AxVMCrateConfig, +) { let fdt = Fdt::from_bytes(fdt_bytes) .map_err(|e| format!("Failed to parse FDT: {:#?}", e)) .expect("Failed to parse FDT"); @@ -48,7 +51,11 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM let host_cpus: Vec<_> = fdt.find_nodes("/cpus/cpu").collect(); info!("Found {} host CPU nodes", &host_cpus.len()); - let phys_cpu_ids = crate_config.base.phys_cpu_ids.as_ref().expect("ERROR: phys_cpu_ids not found in config.toml"); + let phys_cpu_ids = crate_config + .base + .phys_cpu_ids + .as_ref() + .expect("ERROR: phys_cpu_ids not found in config.toml"); // Collect all CPU node information into Vec to avoid using iterators multiple times let cpu_nodes_info: Vec<_> = host_cpus @@ -56,7 +63,11 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM .filter_map(|cpu_node| { if let Some(mut cpu_reg) = cpu_node.reg() { if let Some(r) = cpu_reg.next() { - info!("CPU node: {}, phys_cpu_id: 0x{:x}", cpu_node.name(), r.address); + info!( + "CPU node: {}, phys_cpu_id: 0x{:x}", + cpu_node.name(), + r.address + ); Some((cpu_node.name().to_string(), r.address as usize)) } else { None @@ -103,12 +114,16 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM new_phys_cpu_sets.push(cpu_mask); debug!( "vCPU {} with phys_cpu_id 0x{:x} mapped to CPU index {} (mask: 0x{:x})", - vm_cfg.id(), phys_cpu_id, cpu_index, cpu_mask + vm_cfg.id(), + phys_cpu_id, + cpu_index, + cpu_mask ); } else { error!( "vCPU {} with phys_cpu_id 0x{:x} not found in device tree!", - vm_cfg.id(), phys_cpu_id + vm_cfg.id(), + phys_cpu_id ); } } @@ -116,7 +131,9 @@ pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVM // Update phys_cpu_sets in VM configuration (if VM configuration supports setting) info!("Calculated phys_cpu_sets: {:?}", new_phys_cpu_sets); - vm_cfg.phys_cpu_ls_mut().set_guest_cpu_sets(new_phys_cpu_sets); + vm_cfg + .phys_cpu_ls_mut() + .set_guest_cpu_sets(new_phys_cpu_sets); debug!( "vcpu_mappings: {:?}", @@ -163,12 +180,7 @@ fn add_device_address_config( } /// Add ranges property configuration for PCIe devices -fn add_pci_ranges_config( - vm_cfg: &mut AxVMConfig, - node_name: &str, - range: &PciRange, - index: usize, -) { +fn add_pci_ranges_config(vm_cfg: &mut AxVMConfig, node_name: &str, range: &PciRange, index: usize) { let base_address = range.cpu_address as usize; let size = range.size as usize; @@ -233,7 +245,7 @@ pub fn parse_passthrough_devices_address(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { } } } - + // Process PCIe device's reg property (ECAM space) if let Some(mut reg_iter) = node.reg() { let mut index = 0; @@ -241,7 +253,14 @@ pub fn parse_passthrough_devices_address(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { let base_address = reg.address as usize; let size = reg.size.unwrap_or(0) as usize; - add_device_address_config(vm_cfg, &node_name, base_address, size, index, Some("ecam")); + add_device_address_config( + vm_cfg, + &node_name, + base_address, + size, + index, + Some("ecam"), + ); index += 1; } } @@ -278,10 +297,10 @@ pub fn parse_vm_interrupt(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { for node in fdt.all_nodes() { let name = node.name(); - + if name.starts_with("memory") { continue; - } + } // Skip the interrupt controller, as we will use vGIC // TODO: filter with compatible property and parse its phandle from DT; maybe needs a second pass? else if name.starts_with("interrupt-controller") @@ -357,11 +376,11 @@ pub fn parse_vm_interrupt(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { }); } -pub fn update_provided_fdt(provided_dtb: &[u8], host_dtb: &[u8], crate_config: &AxVMCrateConfig) { +pub fn update_provided_fdt(provided_dtb: &[u8], host_dtb: &[u8], crate_config: &AxVMCrateConfig) { let provided_fdt = Fdt::from_bytes(provided_dtb) .expect("Failed to parse DTB image, perhaps the DTB is invalid or corrupted"); let host_fdt = Fdt::from_bytes(host_dtb) .expect("Failed to parse DTB image, perhaps the DTB is invalid or corrupted"); let provided_dtb_data = update_cpu_node(&provided_fdt, &host_fdt, crate_config); super::create::crate_guest_fdt_with_cache(provided_dtb_data, crate_config); -} \ No newline at end of file +} diff --git a/src/vmm/fdt/test.rs b/src/vmm/fdt/test.rs index 078e38c2..dd96c026 100644 --- a/src/vmm/fdt/test.rs +++ b/src/vmm/fdt/test.rs @@ -59,7 +59,11 @@ pub fn print_fdt(fdt_addr: usize) { ); for prop in node.propertys() { - trace!("Properties: {}, Raw_value: {:x?}", prop.name, prop.raw_value()); + trace!( + "Properties: {}, Raw_value: {:x?}", + prop.name, + prop.raw_value() + ); } } @@ -75,10 +79,8 @@ pub fn print_fdt(fdt_addr: usize) { } } - #[allow(dead_code)] pub fn print_guest_fdt(fdt_bytes: &[u8]) { - let fdt = Fdt::from_bytes(fdt_bytes) .map_err(|e| format!("Failed to parse FDT: {:#?}", e)) .expect("Failed to parse FDT"); @@ -113,7 +115,11 @@ pub fn print_guest_fdt(fdt_bytes: &[u8]) { ); for prop in node.propertys() { - info!("Properties: {}, Raw_value: {:x?}", prop.name, prop.raw_value()); + info!( + "Properties: {}, Raw_value: {:x?}", + prop.name, + prop.raw_value() + ); } } @@ -126,4 +132,4 @@ pub fn print_guest_fdt(fdt_bytes: &[u8]) { let percentage = (count as f32 / node_count as f32) * 100.0; info!(" Level {}: {} nodes ({:.1}%)", level, count, percentage); } -} \ No newline at end of file +} diff --git a/src/vmm/images/mod.rs b/src/vmm/images/mod.rs index b5e8abf6..8611aa7e 100644 --- a/src/vmm/images/mod.rs +++ b/src/vmm/images/mod.rs @@ -188,10 +188,10 @@ pub fn load_vm_image_from_memory( #[cfg(feature = "fs")] mod fs { - use std::{fs::File, vec::Vec}; - use axerrno::{AxResult, ax_err, ax_err_type}; - use crate::hal::CacheOp; use super::*; + use crate::hal::CacheOp; + use axerrno::{AxResult, ax_err, ax_err_type}; + use std::{fs::File, vec::Vec}; pub fn kernal_read(config: &AxVMCrateConfig, read_size: usize) -> AxResult> { use std::fs::File; From 177bc152c537c0ebca9028704ee01df545f69d28 Mon Sep 17 00:00:00 2001 From: szy Date: Thu, 25 Sep 2025 15:06:21 +0800 Subject: [PATCH 19/30] update --- Cargo.lock | 2 ++ Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 8e27f8e0..d3bfcfb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -984,6 +984,7 @@ dependencies = [ [[package]] name = "axvm" version = "0.1.0" +source = "git+https://github.com/arceos-hypervisor/axvm.git?branch=next#d0b1e63004d6a6b3caf47abe0f3b7020ffbacb72" dependencies = [ "arm_vcpu", "arm_vgic 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1008,6 +1009,7 @@ dependencies = [ [[package]] name = "axvmconfig" version = "0.1.0" +source = "git+https://github.com/bullhh/axvmconfig.git#d549c224fc80768685f90fb8d24706c238281708" dependencies = [ "axerrno", "enumerable", diff --git a/Cargo.toml b/Cargo.toml index 726febb1..ca419e19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,4 +87,4 @@ toml = {version = "0.9"} axvcpu = {git = "https://github.com/arceos-hypervisor/axvcpu.git", branch = "next"} [patch.crates-io.axvmconfig] -path = "./axvmconfig" \ No newline at end of file +git = "https://github.com/bullhh/axvmconfig.git" From 5c9c4ad9cee118356e9e6866d5cc4b1b9a62f368 Mon Sep 17 00:00:00 2001 From: szy Date: Fri, 26 Sep 2025 10:01:26 +0800 Subject: [PATCH 20/30] update --- .gitignore | 1 - Cargo.lock | 111 +- Cargo.toml | 3 +- platform/aarch64-phytium-pi/Cargo.lock | 3562 ++++++++++++++++++++++++ src/vmm/images/mod.rs | 2 +- 5 files changed, 3645 insertions(+), 34 deletions(-) create mode 100644 platform/aarch64-phytium-pi/Cargo.lock diff --git a/.gitignore b/.gitignore index 4cce7fb1..a229e4bc 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,6 @@ actual.out qemu.log rusty-tags.vi -/axvmconfig # Python virtual environment venv/ __pycache__/ diff --git a/Cargo.lock b/Cargo.lock index eccf146f..d07a6723 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -316,7 +316,7 @@ dependencies = [ [[package]] name = "axbsp-phytium-pi" version = "0.1.0" -source = "git+https://github.com/drivercraft/axbsp.git#a5a374e142d83501cadfbcfa3b39cfc719d47afe" +source = "git+https://github.com/drivercraft/axbsp.git#5dce480c619b6435135808c764aff818c4e891a1" dependencies = [ "axklib 0.2.0 (git+https://github.com/arceos-hypervisor/arceos.git?branch=hypervisor)", "axplat-aarch64-dyn", @@ -332,7 +332,7 @@ dependencies = [ [[package]] name = "axbsp-roc-rk3568-pc" version = "0.1.0" -source = "git+https://github.com/drivercraft/axbsp.git#a5a374e142d83501cadfbcfa3b39cfc719d47afe" +source = "git+https://github.com/drivercraft/axbsp.git#5dce480c619b6435135808c764aff818c4e891a1" dependencies = [ "axklib 0.2.0 (git+https://github.com/arceos-hypervisor/arceos.git?branch=hypervisor)", "axplat-aarch64-dyn", @@ -635,7 +635,7 @@ dependencies = [ [[package]] name = "axklib" version = "0.2.0" -source = "git+https://github.com/arceos-hypervisor/arceos.git?branch=hypervisor#db2153869c2efb0ef768eb9ec9adfaa5c35215be" +source = "git+https://github.com/arceos-hypervisor/arceos.git?branch=hypervisor#96049da415c9b8f54caea54fdd98f4d69ca01670" dependencies = [ "axerrno", "memory_addr", @@ -1070,7 +1070,6 @@ dependencies = [ [[package]] name = "axvm" version = "0.1.0" -source = "git+https://github.com/arceos-hypervisor/axvm.git?branch=next#d0b1e63004d6a6b3caf47abe0f3b7020ffbacb72" dependencies = [ "arm_vcpu", "arm_vgic 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1095,7 +1094,7 @@ dependencies = [ [[package]] name = "axvmconfig" version = "0.1.0" -source = "git+https://github.com/bullhh/axvmconfig.git#d549c224fc80768685f90fb8d24706c238281708" +source = "git+https://github.com/arceos-hypervisor/axvmconfig.git?branch=next#34c0e6473b057a697c48cc37c5b25853c1ea2826" dependencies = [ "axerrno", "enumerable", @@ -1224,6 +1223,12 @@ dependencies = [ "utf8-width", ] +[[package]] +name = "bytemuck" +version = "1.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" + [[package]] name = "byteorder" version = "1.5.0" @@ -1503,6 +1508,12 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "dma-api" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624f4a84cc1031cfceb56780b82570a785f6cfdcee4f34c06c4e8f1fba25c970" + [[package]] name = "dma-api" version = "0.3.1" @@ -1606,7 +1617,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -2435,9 +2446,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memoffset" @@ -2689,6 +2700,31 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pci_types" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4325c6aa3cca3373503b1527e75756f9fbfe5fd76be4b4c8a143ee47430b8e0" +dependencies = [ + "bit_field", + "bitflags 2.9.4", +] + +[[package]] +name = "pcie" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225c81c0f672afbdd95e55abebe56541870e64e350eba9f7eabfb392112229ab" +dependencies = [ + "bare-test-macros", + "bit_field", + "bitflags 2.9.4", + "log", + "pci_types", + "rdif-pcie", + "thiserror 2.0.16", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -2721,15 +2757,18 @@ dependencies = [ [[package]] name = "phytium-mci" version = "0.1.0" -source = "git+https://github.com/YanQD/phytium-mci.git?rev=d4657ae#d4657ae9c7c27df552fcbc2f8287633ea8522e63" +source = "git+https://github.com/YanQD/phytium-mci.git?rev=99c9ee5#99c9ee5f66490fbf41370be3b3d7a42cf4406b0c" dependencies = [ "bare-test-macros", "bitflags 2.9.4", - "dma-api 0.3.1", + "bytemuck", + "dma-api 0.2.2", "lazy_static", "log", + "nb", "rlsf", "spin 0.10.0", + "tock-registers 0.9.0", ] [[package]] @@ -2964,17 +3003,29 @@ dependencies = [ "thiserror 2.0.16", ] +[[package]] +name = "rdif-pcie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0abf057b17ca5ead0ee41c485bf3c2781fd9bbf88cc678539fa361aa5db3ed8d" +dependencies = [ + "pci_types", + "rdif-base", + "thiserror 2.0.16", +] + [[package]] name = "rdrive" -version = "0.18.1" +version = "0.18.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa9e5db203ff078c7422ce20bb3144111c3a88b58f93d759d0c86edb89df2133" +checksum = "27096bc91e156403ba3be9c7fef8d4379ea12d96d9d1725bdb197104a4fe1010" dependencies = [ - "enum_dispatch", "fdt-parser", "log", "paste", + "pcie", "rdif-base", + "rdif-pcie", "rdrive-macros", "spin 0.10.0", "thiserror 2.0.16", @@ -3238,7 +3289,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -3338,7 +3389,7 @@ version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -3401,9 +3452,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.226" +version = "1.0.227" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" +checksum = "80ece43fc6fbed4eb5392ab50c07334d3e577cbf40997ee896fe7af40bba4245" dependencies = [ "serde_core", "serde_derive", @@ -3433,18 +3484,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.226" +version = "1.0.227" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" +checksum = "7a576275b607a2c86ea29e410193df32bc680303c82f31e275bbfcafe8b33be5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.226" +version = "1.0.227" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" +checksum = "51e694923b8824cf0e9b382adf0f60d4e05f348f357b38833a3fa5ed7c2ede04" dependencies = [ "proc-macro2", "quote", @@ -3765,7 +3816,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.61.0", + "windows-sys 0.61.1", ] [[package]] @@ -4064,9 +4115,9 @@ dependencies = [ [[package]] name = "trait-ffi" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "603471aac0a50dcf4cfbcdb0edb49a2d734b33d2b84a0d6b714ed8b06b811e25" +checksum = "d87d49469ee333631b3130bec28965c47dcf0d4f3a792f8ed425dd036cf84be7" dependencies = [ "convert_case", "lenient_semver", @@ -4384,14 +4435,14 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.4", ] [[package]] name = "windows-sys" -version = "0.61.0" +version = "0.61.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" dependencies = [ "windows-link 0.2.0", ] @@ -4429,11 +4480,11 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" dependencies = [ - "windows-link 0.1.3", + "windows-link 0.2.0", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", diff --git a/Cargo.toml b/Cargo.toml index c531f96c..ce33f192 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,6 +89,5 @@ toml = {version = "0.9"} [patch.crates-io] axvcpu = {git = "https://github.com/arceos-hypervisor/axvcpu.git", branch = "next"} +axvmconfig = { git = "https://github.com/arceos-hypervisor/axvmconfig.git", branch = "next" } -[patch.crates-io.axvmconfig] -git = "https://github.com/bullhh/axvmconfig.git" diff --git a/platform/aarch64-phytium-pi/Cargo.lock b/platform/aarch64-phytium-pi/Cargo.lock new file mode 100644 index 00000000..73e1dbc1 --- /dev/null +++ b/platform/aarch64-phytium-pi/Cargo.lock @@ -0,0 +1,3562 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aarch64-cpu" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a21cd0131c25c438e19cd6a774adf7e3f64f7f4d723022882facc2dee0f8bc9" +dependencies = [ + "tock-registers 0.9.0", +] + +[[package]] +name = "aarch64-cpu-ext" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52dad5cf7342926ce1c375ec680834e56dd3cdbe8b7adf8a6f99b2854cc52c17" +dependencies = [ + "aarch64-cpu", + "tock-registers 0.10.0", +] + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "anstream" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +dependencies = [ + "windows-sys 0.60.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.60.2", +] + +[[package]] +name = "any-uart" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ce5f140efb4e707ea8f8e894d5f710500e373be1c4435d56b28d1fd1f843341" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "embedded-hal-nb", + "fdt-parser", + "x86_64", +] + +[[package]] +name = "anyhow" +version = "1.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" + +[[package]] +name = "arm-gic-driver" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f251a1a74133f802b55eaf5e340107b0024457aa9b2ac3c72074501bfa8509a5" +dependencies = [ + "aarch64-cpu", + "bitflags 2.9.4", + "enum_dispatch", + "log", + "paste", + "rdif-intc", + "tock-registers 0.9.0", +] + +[[package]] +name = "as-any" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0f477b951e452a0b6b4a10b53ccd569042d1d01729b519e02074a9c0958a063" + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "axbsp-phytium-pi" +version = "0.1.0" +source = "git+https://github.com/drivercraft/axbsp.git#5dce480c619b6435135808c764aff818c4e891a1" +dependencies = [ + "axklib", + "axplat-aarch64-dyn", + "log", + "phytium-mci", + "rdif-block", + "rdrive", + "serde", + "spin 0.10.0", + "toml 0.8.23", +] + +[[package]] +name = "axconfig-gen" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf14099a96dbb925e39a44c4f25555f1e24516194452a84a943aa7eda62383d" +dependencies = [ + "clap", + "toml_edit", +] + +[[package]] +name = "axconfig-macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86a6711b80fbd1dc4c1d8e2fb77a5de6fc8e2eb2b96bbd0420ca8af370eb74c" +dependencies = [ + "axconfig-gen", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "axcpu" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e09bc1235e3da45e942b50f47812f8397ad84cb490264bf914c65ac44e6f8b1d" +dependencies = [ + "aarch64-cpu", + "cfg-if", + "lazyinit", + "linkme", + "log", + "loongArch64", + "memory_addr", + "page_table_entry", + "page_table_multiarch", + "percpu", + "riscv", + "static_assertions", + "tock-registers 0.9.0", + "x86", + "x86_64", +] + +[[package]] +name = "axerrno" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66ccd41dd4ef364e2385901a5c2a3adea974a41eccb2529c1f24e4c8bc93d834" +dependencies = [ + "log", +] + +[[package]] +name = "axklib" +version = "0.2.0" +source = "git+https://github.com/arceos-hypervisor/arceos?branch=hypervisor#96049da415c9b8f54caea54fdd98f4d69ca01670" +dependencies = [ + "axerrno", + "memory_addr", + "trait-ffi", +] + +[[package]] +name = "axplat" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4de04c54b63bf2ca1ff202733d2516da49d7779649cdb2f9c4ecf22909e6810" +dependencies = [ + "axplat-macros", + "bitflags 2.9.4", + "const-str", + "crate_interface", + "handler_table", + "kspin", + "memory_addr", +] + +[[package]] +name = "axplat-aarch64-dyn" +version = "0.2.0" +source = "git+https://github.com/arceos-hypervisor/axplat-aarch64-dyn?tag=v0.2.0#bdde9eec2a91f8c64926a991cbf6a4b048446165" +dependencies = [ + "aarch64-cpu", + "aarch64-cpu-ext", + "any-uart", + "arm-gic-driver", + "axconfig-macros", + "axcpu", + "axplat", + "fdt-parser", + "heapless", + "lazyinit", + "log", + "memory_addr", + "page_table_entry", + "paste", + "percpu", + "rdif-intc", + "rdrive", + "serde", + "somehal", + "spin 0.10.0", + "toml 0.8.23", +] + +[[package]] +name = "axplat-aarch64-phytium-pi" +version = "0.1.0" +dependencies = [ + "axbsp-phytium-pi", + "serde", + "toml 0.8.23", +] + +[[package]] +name = "axplat-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90dfaee06a112fe4f810c60af1a86bc080af2172185b491cacc307b84dff748" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "backtrace" +version = "0.3.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "bare-test-macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e585a01076fee271c5aabcf36212acb349fb3e638561d842fffa8ca013f4fdd8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bindeps-simple" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759b427caeff86cb964340e5fee96d7b26a58853941d3a8e051f46be7b1fada3" +dependencies = [ + "anyhow", + "cargo_metadata", + "flate2", + "rand", + "reqwest 0.12.23", + "tar", +] + +[[package]] +name = "bit_field" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "bytemuck" +version = "1.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3995eaeebcdf32f91f980d360f78732ddc061097ab4e39991ae7a6ace9194677" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "camino" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1de8bc0aa9e9385ceb3bf0c152e3a9b9544f6c4a912c8ae504e80c1f0368603" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84982c6c0ae343635a3a4ee6dedef965513735c8b183caa7289fa6e27399ebd4" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-util-schemas" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e63d2780ac94487eb9f1fea7b0d56300abc9eb488800854ca217f102f5caccca" +dependencies = [ + "semver", + "serde", + "serde-untagged", + "serde-value", + "thiserror 1.0.69", + "toml 0.8.23", + "unicode-xid", + "url", +] + +[[package]] +name = "cargo_metadata" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f7835cfc6135093070e95eb2b53e5d9b5c403dc3a6be6040ee026270aa82502" +dependencies = [ + "camino", + "cargo-platform", + "cargo-util-schemas", + "semver", + "serde", + "serde_json", + "thiserror 2.0.16", +] + +[[package]] +name = "cc" +version = "1.2.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "clap" +version = "4.5.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2134bb3ea021b78629caa971416385309e0131b351b25e01dc16fb54e1b5fae" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ba64afa3c0a6df7fa517765e31314e983f51dda798ffba27b988194fb65dc9" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "const-default" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" + +[[package]] +name = "const-str" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "451d0640545a0553814b4c646eb549343561618838e9b42495f466131fe3ad49" + +[[package]] +name = "convert_case" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "crate_interface" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70272a03a2cef15589bac05d3d15c023752f5f8f2da8be977d983a9d9e6250fb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.106", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "dma-api" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624f4a84cc1031cfceb56780b82570a785f6cfdcee4f34c06c4e8f1fba25c970" + +[[package]] +name = "dma-api" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2303b0bbacb23e7e1990fb31bed5cb46bc67aa4f307c03117b81bdee4d9f" +dependencies = [ + "aarch64-cpu-ext", + "cfg-if", + "spin 0.10.0", + "thiserror 2.0.16", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-nb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" +dependencies = [ + "embedded-hal", + "nb", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum_dispatch" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" +dependencies = [ + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "259d404d09818dec19332e31d94558aeb442fea04c817006456c24b5460bbd4b" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.1", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fdt-parser" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16ca123a5721e4a28ef60d6e1600cd0a33a9ab376c4b88de04c99bce757e458b" + +[[package]] +name = "filetime" +version = "0.2.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.60.2", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.7+wasi-0.2.4", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.3.1", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "handler_table" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702cb690200d6303c1e1992bc648f3f3bf9c1d6a27fcf50551c513d61f339c99" + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.3.1", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2 0.4.12", + "http 1.3.1", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http 1.3.1", + "hyper 1.7.0", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.32", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.7.0", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "hyper 1.7.0", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.6.0", + "system-configuration 0.6.1", + "tokio", + "tower-service", + "tracing", + "windows-registry", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "io-uring" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "libc", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "kasm-aarch64" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791dc7a2b079d81b8e3615521fccbd75c0c9f068b53f7d891a2e300222c7cada" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "kdef-pgtable" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7166660a78a4488f5f3269206242d3b76cd6b42d870f004898487ce16dba3f69" +dependencies = [ + "bitflags 2.9.4", + "prettyplease", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "kernel_guard" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "307e6be468f3d6b6d895e191f63c11602e4e76575ecca68325d8c8dbebe2870e" +dependencies = [ + "cfg-if", + "crate_interface", +] + +[[package]] +name = "kspin" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d841fd3aeaa9a55871068f5c3ce48497a6dbcf14e20ca7784a9f68bfdb4c825" +dependencies = [ + "cfg-if", + "kernel_guard", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin 0.9.8", +] + +[[package]] +name = "lazyinit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f03abfebdaaf0fad16790237a0348baf84886d3ade460db13bae59e614a180" + +[[package]] +name = "lenient_semver" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de8de3f4f3754c280ce1c8c42ed8dd26a9c8385c2e5ad4ec5a77e774cea9c1ec" +dependencies = [ + "lenient_semver_parser", + "semver", +] + +[[package]] +name = "lenient_semver_parser" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f650c1d024ddc26b4bb79c3076b30030f2cf2b18292af698c81f7337a64d7d6" +dependencies = [ + "lenient_semver_version_builder", + "semver", +] + +[[package]] +name = "lenient_semver_version_builder" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9049f8ff49f75b946f95557148e70230499c8a642bf2d6528246afc7d0282d17" +dependencies = [ + "semver", +] + +[[package]] +name = "libc" +version = "0.2.176" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" + +[[package]] +name = "libredox" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +dependencies = [ + "bitflags 2.9.4", + "libc", + "redox_syscall", +] + +[[package]] +name = "linkme" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b1703c00b2a6a70738920544aa51652532cacddfec2e162d2e29eae01e665c" +dependencies = [ + "linkme-impl", +] + +[[package]] +name = "linkme-impl" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04d55ca5d5a14363da83bf3c33874b8feaa34653e760d5216d7ef9829c88001a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "loongArch64" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c9f0d275c70310e2a9d2fc23250c5ac826a73fa828a5f256401f85c5c554283" +dependencies = [ + "bit_field", + "bitflags 2.9.4", +] + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "memory_addr" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4054cba279515fa87761b101d857333ce06391dbe8f18a11347204a7111416" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "num-align" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4b86e8ef968de2261141fc760ee57cae8fabb3a0e756b3390a4c4871b16c3d1" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "openssl" +version = "0.10.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +dependencies = [ + "bitflags 2.9.4", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-sys" +version = "0.9.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "page-table-generic" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a302d085e35d9edfa3ec531475ed95eae8a92e7e47ce7a15bd4e9c5e74f7526" +dependencies = [ + "bitflags 2.9.4", + "log", + "num-align", + "thiserror 2.0.16", +] + +[[package]] +name = "page_table_entry" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba811ef8ca8fb33d776e128624cb4fe25c9804cab96f83b822d4322431e6dd5a" +dependencies = [ + "aarch64-cpu", + "bitflags 2.9.4", + "memory_addr", + "x86_64", +] + +[[package]] +name = "page_table_multiarch" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cb76e21ce462270afd83b331599d5b83f876c2a98c0a70382b20d73e1da6be" +dependencies = [ + "log", + "memory_addr", + "page_table_entry", + "riscv", + "x86", +] + +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pci_types" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4325c6aa3cca3373503b1527e75756f9fbfe5fd76be4b4c8a143ee47430b8e0" +dependencies = [ + "bit_field", + "bitflags 2.9.4", +] + +[[package]] +name = "pcie" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225c81c0f672afbdd95e55abebe56541870e64e350eba9f7eabfb392112229ab" +dependencies = [ + "bare-test-macros", + "bit_field", + "bitflags 2.9.4", + "log", + "pci_types", + "rdif-pcie", + "thiserror 2.0.16", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "percpu" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01e56c0c558952222967b592899f98765b48590e7bd7403bfd7075f73afc6ed6" +dependencies = [ + "cfg-if", + "percpu_macros", + "spin 0.9.8", + "x86", +] + +[[package]] +name = "percpu_macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9f4cc54a2e471ff72f1499461ba381ad4eae9cbd60d29c258545b995e406e0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "phytium-mci" +version = "0.1.0" +source = "git+https://github.com/YanQD/phytium-mci.git?rev=99c9ee5#99c9ee5f66490fbf41370be3b3d7a42cf4406b0c" +dependencies = [ + "bare-test-macros", + "bitflags 2.9.4", + "bytemuck", + "dma-api 0.2.2", + "lazy_static", + "log", + "nb", + "rlsf", + "spin 0.10.0", + "tock-registers 0.9.0", +] + +[[package]] +name = "pie-boot-if" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d979b0d1208dd8a57c5adb7d3c4e07bf15cbea3840123e864f6bfcb655c5e05" +dependencies = [ + "heapless", +] + +[[package]] +name = "pie-boot-loader-aarch64" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de8836eb8759cd65e70c73dc0f519345d8a734284e8e4cfc5889a6e445af9f09" +dependencies = [ + "aarch64-cpu", + "aarch64-cpu-ext", + "any-uart", + "bitflags 2.9.4", + "fdt-parser", + "kasm-aarch64", + "kdef-pgtable", + "log", + "num-align", + "page-table-generic", + "pie-boot-if", + "prettyplease", + "quote", + "spin 0.10.0", + "syn 2.0.106", + "thiserror 2.0.16", +] + +[[package]] +name = "pie-boot-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513f5ca7603771d7524bfb7e6ba8dded83d2e8ac02d46f15815e0c1144bca566" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "potential_utf" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.106", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + +[[package]] +name = "raw-cpuid" +version = "10.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "rdif-base" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f8c32d8cbc18633a412130719b07d31135215d1715ac48fc3888ca835a811ba" +dependencies = [ + "as-any", + "async-trait", + "paste", + "rdif-def", + "thiserror 2.0.16", +] + +[[package]] +name = "rdif-block" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81ae1ba6c121eef2653dd2e0c88a209bb1d4d21e75e15cca71f19770ef327f81" +dependencies = [ + "cfg-if", + "dma-api 0.5.1", + "futures", + "rdif-base", + "spin_on", + "thiserror 2.0.16", +] + +[[package]] +name = "rdif-def" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c238eb44d86fabc99028adc973f896ce2202aeb6184cc8b89863f2d157d7ca06" +dependencies = [ + "thiserror 2.0.16", +] + +[[package]] +name = "rdif-intc" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170ec813e6cf4d1e5fa53fa8fed0fadc7aaab96683d4f1d44c602a6109931eb4" +dependencies = [ + "cfg-if", + "rdif-base", + "thiserror 2.0.16", +] + +[[package]] +name = "rdif-pcie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0abf057b17ca5ead0ee41c485bf3c2781fd9bbf88cc678539fa361aa5db3ed8d" +dependencies = [ + "pci_types", + "rdif-base", + "thiserror 2.0.16", +] + +[[package]] +name = "rdrive" +version = "0.18.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27096bc91e156403ba3be9c7fef8d4379ea12d96d9d1725bdb197104a4fe1010" +dependencies = [ + "fdt-parser", + "log", + "paste", + "pcie", + "rdif-base", + "rdif-pcie", + "rdrive-macros", + "spin 0.10.0", + "thiserror 2.0.16", +] + +[[package]] +name = "rdrive-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab3105c9af32e901a2adc7d920b39ff8b6ee0f6f0b7dfdeaf18f306ec12606f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "redox_syscall" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +dependencies = [ + "bitflags 2.9.4", +] + +[[package]] +name = "release-dep" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d2060fec225361f815b40c6857b5722835318abdea0e20ee86b81cf1ac5c9a" +dependencies = [ + "anyhow", + "futures", + "reqwest 0.11.27", + "semver", + "serde", + "serde_json", + "tokio", + "tokio-util", +] + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-tls 0.5.0", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration 0.5.1", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "reqwest" +version = "0.12.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.4.12", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.7.0", + "hyper-rustls", + "hyper-tls 0.6.0", + "hyper-util", + "js-sys", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "tokio", + "tokio-native-tls", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "riscv" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1671c79a01a149fe000af2429ce9ccc8e58cdecda72672355d50e5536b363c" +dependencies = [ + "critical-section", + "embedded-hal", + "paste", + "riscv-macros", + "riscv-pac", +] + +[[package]] +name = "riscv-macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c4aa1ea1af6dcc83a61be12e8189f9b293c3ba5a487778a4cd89fb060fdbbc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "riscv-pac" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436" + +[[package]] +name = "rlsf" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222fb240c3286247ecdee6fa5341e7cdad0ffdf8e7e401d9937f2d58482a20bf" +dependencies = [ + "cfg-if", + "const-default", + "libc", + "svgbobdoc", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags 2.9.4", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.1", +] + +[[package]] +name = "rustls" +version = "0.23.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.1", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.4", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.227" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80ece43fc6fbed4eb5392ab50c07334d3e577cbf40997ee896fe7af40bba4245" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-untagged" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" +dependencies = [ + "erased-serde", + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde_core" +version = "1.0.227" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a576275b607a2c86ea29e410193df32bc680303c82f31e275bbfcafe8b33be5" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.227" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e694923b8824cf0e9b382adf0f60d4e05f348f357b38833a3fa5ed7c2ede04" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "smccc" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c73e0ca8c566478040487791c9f488f86c5aec846ca1ab18484be8a1d8c55cd" +dependencies = [ + "thiserror 2.0.16", +] + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "somehal" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9b180e1abae1127bd99ecee566c3906d8c0f854cb1c442b945afe911e6eb71" +dependencies = [ + "aarch64-cpu", + "aarch64-cpu-ext", + "any-uart", + "bindeps-simple", + "fdt-parser", + "futures", + "heapless", + "kasm-aarch64", + "kdef-pgtable", + "log", + "num-align", + "page-table-generic", + "pie-boot-if", + "pie-boot-loader-aarch64", + "pie-boot-macros", + "release-dep", + "serde", + "smccc", + "spin 0.10.0", + "toml 0.9.7", + "url", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spin_on" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "076e103ed41b9864aa838287efe5f4e3a7a0362dd00671ae62a212e5e4612da2" +dependencies = [ + "pin-utils", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "svgbobdoc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c04b93fc15d79b39c63218f15e3fdffaa4c227830686e3b7c5f41244eb3e50" +dependencies = [ + "base64 0.13.1", + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-width", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys 0.5.0", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.9.4", + "core-foundation", + "system-configuration-sys 0.6.0", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tar" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix", + "windows-sys 0.61.1", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +dependencies = [ + "thiserror-impl 2.0.16", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "tinystr" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tock-registers" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b9e2fdb3a1e862c0661768b7ed25390811df1947a8acbfbefe09b47078d93c4" + +[[package]] +name = "tock-registers" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293f99756f16ff352cc78c99673766a305bdb5ed7652e78df649e9967c885a" + +[[package]] +name = "tokio" +version = "1.47.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +dependencies = [ + "backtrace", + "bytes", + "io-uring", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "slab", + "socket2 0.6.0", + "tokio-macros", + "windows-sys 0.59.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f63835928ca123f1bef57abbcd23bb2ba0ac9ae1235f1e65bda0d06e7786bd" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_edit", +] + +[[package]] +name = "toml" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned 1.0.2", + "toml_datetime 0.7.2", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.11", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "toml_writer" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d163a63c116ce562a22cda521fcc4d79152e7aba014456fb5eb442f6d6a10109" + +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +dependencies = [ + "bitflags 2.9.4", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +dependencies = [ + "once_cell", +] + +[[package]] +name = "trait-ffi" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87d49469ee333631b3130bec28965c47dcf0d4f3a792f8ed425dd036cf84be7" +dependencies = [ + "convert_case", + "lenient_semver", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "volatile" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442887c63f2c839b346c192d047a7c87e73d0689c9157b00b53dcc27dd5ea793" + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.106", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-registry" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" +dependencies = [ + "windows-link 0.1.3", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.4", +] + +[[package]] +name = "windows-sys" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" +dependencies = [ + "windows-link 0.2.0", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] +name = "winnow" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "writeable" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" + +[[package]] +name = "x86" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385" +dependencies = [ + "bit_field", + "bitflags 1.3.2", + "raw-cpuid", +] + +[[package]] +name = "x86_64" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f042214de98141e9c8706e8192b73f56494087cc55ebec28ce10f26c5c364ae" +dependencies = [ + "bit_field", + "bitflags 2.9.4", + "rustversion", + "volatile", +] + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "yoke" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] diff --git a/src/vmm/images/mod.rs b/src/vmm/images/mod.rs index 8611aa7e..2635ff3a 100644 --- a/src/vmm/images/mod.rs +++ b/src/vmm/images/mod.rs @@ -94,7 +94,7 @@ impl ImageLoader { /// Load VM images from memory /// into the guest VM's memory space based on the VM configuration. fn load_vm_images_from_memory(&self) -> AxResult { - trace!("Loading VM[{}] images from memory", self.config.base.id); + info!("Loading VM[{}] images from memory", self.config.base.id); let vm_imags = config::get_memory_images() .iter() From 2964833210005054a3a7e794ff059776f5bc81b4 Mon Sep 17 00:00:00 2001 From: szy Date: Fri, 26 Sep 2025 10:06:27 +0800 Subject: [PATCH 21/30] update --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index d07a6723..199f307f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1070,6 +1070,7 @@ dependencies = [ [[package]] name = "axvm" version = "0.1.0" +source = "git+https://github.com/arceos-hypervisor/axvm.git?branch=next#d0b1e63004d6a6b3caf47abe0f3b7020ffbacb72" dependencies = [ "arm_vcpu", "arm_vgic 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", From 1986658e030c1b1a16bcf4bc319fb133ec0ebbda Mon Sep 17 00:00:00 2001 From: szy Date: Fri, 26 Sep 2025 10:52:37 +0800 Subject: [PATCH 22/30] fix warn --- src/vmm/fdt/create.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index dc3678ad..13d2251e 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -12,10 +12,10 @@ use vm_fdt::{FdtWriter, FdtWriterNode}; use crate::vmm::{ VMRef, - fdt::test::{print_fdt, print_guest_fdt}, images::load_vm_image_from_memory, }; +// use crate::vmm::fdt::test::{print_fdt, print_guest_fdt}; /// Generate guest FDT and return DTB data /// /// # Parameters From 63a1c4f58795887423c119eed41d14542abd7166 Mon Sep 17 00:00:00 2001 From: szy Date: Fri, 26 Sep 2025 10:55:01 +0800 Subject: [PATCH 23/30] fmt --- src/vmm/fdt/create.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index 13d2251e..42924d2d 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -10,10 +10,7 @@ use axvm::{VMMemoryRegion, config::AxVMCrateConfig}; use fdt_parser::{Fdt, Node}; use vm_fdt::{FdtWriter, FdtWriterNode}; -use crate::vmm::{ - VMRef, - images::load_vm_image_from_memory, -}; +use crate::vmm::{VMRef, images::load_vm_image_from_memory}; // use crate::vmm::fdt::test::{print_fdt, print_guest_fdt}; /// Generate guest FDT and return DTB data From 007180b2be1856b96e2f6e32306a7bde383864fd Mon Sep 17 00:00:00 2001 From: szy Date: Fri, 26 Sep 2025 11:19:17 +0800 Subject: [PATCH 24/30] add cfg --- doc/FDT_Configuration_Guide.md | 4 +- src/vmm/config.rs | 69 ++++++++++++++++++++-------------- src/vmm/images/mod.rs | 3 ++ 3 files changed, 46 insertions(+), 30 deletions(-) diff --git a/doc/FDT_Configuration_Guide.md b/doc/FDT_Configuration_Guide.md index 84f53379..741a9f4e 100644 --- a/doc/FDT_Configuration_Guide.md +++ b/doc/FDT_Configuration_Guide.md @@ -2,12 +2,14 @@ 本文档详细说明了在 AxVisor 中如何配置和使用设备树(FDT)来生成客户机 VM 的设备树。 +本文档所述功能只在aarch64 架构下支持。 + ## 1. 概述 AxVisor 支持两种方式生成客户机 VM 的设备树: 1. **使用预定义的设备树文件**:通过 [kernel] 部分的 `dtb_path` 指定设备树文件路径 -2. **动态生成设备树**:当 `dtb_path` 为空时,根据配置文件中的参数动态生成设备树 +2. **动态生成设备树**:当 `dtb_path` 字段未使用时,根据配置文件中的参数动态生成设备树 无论采用哪种方式,CPU 节点和内存节点都会根据配置进行更新。 diff --git a/src/vmm/config.rs b/src/vmm/config.rs index 8ac4d5de..71a70f2b 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -7,7 +7,10 @@ use core::alloc::Layout; use fdt_parser::Fdt; use memory_addr::MemoryAddr; -use crate::vmm::{VM, fdt::*, images::ImageLoader, vm_list::push_vm}; +use crate::vmm::{VM, images::ImageLoader, vm_list::push_vm}; + +#[cfg(target_arch = "aarch64")] +use crate::vmm::fdt::*; use alloc::collections::BTreeMap; use alloc::sync::Arc; @@ -125,6 +128,39 @@ pub fn get_vm_dtb_arc(vm_cfg: &AxVMConfig) -> Option> { None } +/// Handle all FDT-related operations for aarch64 architecture +#[cfg(target_arch = "aarch64")] +fn handle_fdt_operations(vm_config: &mut AxVMConfig, vm_create_config: &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); + } + + // Overlay VM config with the given DTB. + if let Some(dtb_arc) = get_vm_dtb_arc(vm_config) { + let dtb = dtb_arc.as_ref(); + parse_passthrough_devices_address(vm_config, dtb); + parse_vm_interrupt(vm_config, dtb); + } else { + error!( + "VM[{}] DTB not found in memory, skipping...", + vm_config.id() + ); + } +} + pub fn init_guest_vms() { GENERATED_DTB_CACHE.init_once(Mutex::new(BTreeMap::new())); @@ -151,34 +187,9 @@ pub fn init_guest_vms() { let mut vm_config = AxVMConfig::from(vm_create_config.clone()); - 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(&mut 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, &mut vm_config, &vm_create_config); - } - - // Overlay VM config with the given DTB. - if let Some(dtb_arc) = get_vm_dtb_arc(&vm_config) { - let dtb = dtb_arc.as_ref(); - parse_passthrough_devices_address(&mut vm_config, dtb); - parse_vm_interrupt(&mut vm_config, dtb); - } else { - error!( - "VM[{}] DTB not found in memory, skipping...", - vm_config.id() - ); - } + // Handle FDT-related operations for aarch64 + #[cfg(target_arch = "aarch64")] + handle_fdt_operations(&mut vm_config, &vm_create_config); // info!("after parse_vm_interrupt, crate VM[{}] with config: {:#?}", vm_config.id(), vm_config); info!("Creating VM[{}] {:?}", vm_config.id(), vm_config.name()); diff --git a/src/vmm/images/mod.rs b/src/vmm/images/mod.rs index 2635ff3a..47f5574f 100644 --- a/src/vmm/images/mod.rs +++ b/src/vmm/images/mod.rs @@ -11,6 +11,7 @@ use crate::hal::CacheOp; use crate::vmm::VMRef; use crate::vmm::config::{config, get_vm_dtb_arc}; +#[cfg(target_arch = "aarch64")] use crate::vmm::fdt::update_fdt; mod linux; @@ -113,6 +114,7 @@ impl ImageLoader { Byte::from(dtb_slice.len()) ); + #[cfg(target_arch = "aarch64")] update_fdt( self.dtb_load_gpa.unwrap(), NonNull::new(dtb_slice.as_ptr() as *mut u8).unwrap(), @@ -259,6 +261,7 @@ mod fs { Byte::from(dtb_slice.len()) ); + #[cfg(target_arch = "aarch64")] update_fdt( loader.dtb_load_gpa.unwrap(), NonNull::new(dtb_slice.as_ptr() as *mut u8).unwrap(), From 767c398b6b302734d0bde8896cbd8e639ec4b1db Mon Sep 17 00:00:00 2001 From: szy Date: Fri, 26 Sep 2025 14:43:59 +0800 Subject: [PATCH 25/30] update --- src/vmm/fdt/create.rs | 2 +- src/vmm/fdt/mod.rs | 4 ++-- src/vmm/fdt/{test.rs => print.rs} | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename src/vmm/fdt/{test.rs => print.rs} (100%) diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index 42924d2d..81b04713 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -12,7 +12,7 @@ use vm_fdt::{FdtWriter, FdtWriterNode}; use crate::vmm::{VMRef, images::load_vm_image_from_memory}; -// use crate::vmm::fdt::test::{print_fdt, print_guest_fdt}; +// use crate::vmm::fdt::print::{print_fdt, print_guest_fdt}; /// Generate guest FDT and return DTB data /// /// # Parameters diff --git a/src/vmm/fdt/mod.rs b/src/vmm/fdt/mod.rs index 14016f7f..5fbfa3f2 100644 --- a/src/vmm/fdt/mod.rs +++ b/src/vmm/fdt/mod.rs @@ -6,10 +6,10 @@ mod create; mod device; mod parser; -mod test; +mod print; // Re-export public functions pub use parser::*; -// pub use test::print_fdt; +// pub use print::print_fdt; pub use create::*; pub use device::build_node_path; diff --git a/src/vmm/fdt/test.rs b/src/vmm/fdt/print.rs similarity index 100% rename from src/vmm/fdt/test.rs rename to src/vmm/fdt/print.rs From 2d076ff7ab6beda9dc3746f9bcebdf38fff78123 Mon Sep 17 00:00:00 2001 From: szy Date: Fri, 26 Sep 2025 18:25:57 +0800 Subject: [PATCH 26/30] fix clippy --- src/vmm/config.rs | 33 +++++++++------- src/vmm/fdt/create.rs | 87 ++++++++++++++++++++----------------------- src/vmm/fdt/device.rs | 35 ++++++++--------- src/vmm/fdt/parser.rs | 44 +++++++++------------- src/vmm/fdt/print.rs | 6 +-- src/vmm/images/mod.rs | 9 +++-- 6 files changed, 101 insertions(+), 113 deletions(-) diff --git a/src/vmm/config.rs b/src/vmm/config.rs index 71a70f2b..bb6e0df3 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -4,7 +4,6 @@ use axvm::{ config::{AxVMConfig, AxVMCrateConfig, VmMemMappingType}, }; use core::alloc::Layout; -use fdt_parser::Fdt; use memory_addr::MemoryAddr; use crate::vmm::{VM, images::ImageLoader, vm_list::push_vm}; @@ -12,9 +11,14 @@ use crate::vmm::{VM, images::ImageLoader, vm_list::push_vm}; #[cfg(target_arch = "aarch64")] use crate::vmm::fdt::*; +#[cfg(target_arch = "aarch64")] +use fdt_parser::Fdt; + +#[cfg(target_arch = "aarch64")] +use alloc::vec::Vec; + use alloc::collections::BTreeMap; use alloc::sync::Arc; -use alloc::vec::Vec; use lazyinit::LazyInit; use spin::Mutex; @@ -48,16 +52,12 @@ pub mod config { let mut configs = Vec::new(); if let Ok(entries) = fs::read_dir(config_dir) { - for entry in entries { - if let Ok(entry) = entry { - let path = entry.path(); - // Check if the file has a .toml extension - let path_str = path.as_str(); - if path_str.ends_with(".toml") { - if let Ok(content) = fs::read_to_string(path_str) { - configs.push(content); - } - } + for entry in entries.flatten() { + let path = entry.path(); + // Check if the file has a .toml extension + let path_str = path.as_str(); + if path_str.ends_with(".toml") && let Ok(content) = fs::read_to_string(path_str) { + configs.push(content); } } } @@ -74,6 +74,7 @@ pub mod config { include!(concat!(env!("OUT_DIR"), "/vm_configs.rs")); } +#[cfg(target_arch = "aarch64")] pub fn get_developer_provided_dtb( vm_cfg: &AxVMConfig, crate_config: &AxVMCrateConfig, @@ -94,7 +95,7 @@ pub fn get_developer_provided_dtb( use axerrno::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::open_image_file(&dtb_path).unwrap(); + let (dtb_file, dtb_size) = crate::vmm::images::open_image_file(dtb_path).unwrap(); info!("DTB file in fs, size: 0x{:x}", dtb_size); let mut file = BufReader::new(dtb_file); @@ -133,7 +134,7 @@ pub fn get_vm_dtb_arc(vm_cfg: &AxVMConfig) -> Option> { fn handle_fdt_operations(vm_config: &mut AxVMConfig, vm_create_config: &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)) + .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); @@ -185,8 +186,12 @@ pub fn init_guest_vms() { ); } + #[cfg(target_arch = "aarch64")] let mut vm_config = AxVMConfig::from(vm_create_config.clone()); + #[cfg(not(target_arch = "aarch64"))] + let vm_config = AxVMConfig::from(vm_create_config.clone()); + // Handle FDT-related operations for aarch64 #[cfg(target_arch = "aarch64")] handle_fdt_operations(&mut vm_config, &vm_create_config); diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index 81b04713..4b58929d 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -24,7 +24,7 @@ use crate::vmm::{VMRef, images::load_vm_image_from_memory}; /// Returns the generated DTB data pub fn crate_guest_fdt( fdt: &Fdt, - passthrough_device_names: &Vec, + passthrough_device_names: &[String], crate_config: &AxVMCrateConfig, ) -> Vec { let mut fdt_writer = FdtWriter::new().unwrap(); @@ -96,9 +96,7 @@ pub fn crate_guest_fdt( } assert_eq!(previous_node_level, 0); - let guest_fdt_bytes = fdt_writer.finish().unwrap(); - - guest_fdt_bytes + fdt_writer.finish().unwrap() } /// Generate guest FDT cache the result @@ -133,29 +131,29 @@ enum NodeAction { fn determine_node_action( node: &Node, node_path: &str, - passthrough_device_names: &Vec, + passthrough_device_names: &[String], ) -> NodeAction { if node.name() == "/" { // Special handling for root node - return NodeAction::RootNode; + NodeAction::RootNode } else if node.name().starts_with("memory") { // Skip memory nodes, will add them later - return NodeAction::Skip; + NodeAction::Skip } else if node_path.starts_with("/cpus") { - return NodeAction::CpuNode; + NodeAction::CpuNode } else if passthrough_device_names.contains(&node_path.to_string()) { // Fully matched passthrough device node - return NodeAction::IncludeAsPassthroughDevice; + NodeAction::IncludeAsPassthroughDevice } // Check if the node is a descendant of a passthrough device (by path inclusion and level validation) else if is_descendant_of_passthrough_device(node_path, node.level, passthrough_device_names) { - return NodeAction::IncludeAsChildNode; + NodeAction::IncludeAsChildNode } // Check if the node is an ancestor of a passthrough device (by path inclusion and level validation) else if is_ancestor_of_passthrough_device(node_path, passthrough_device_names) { - return NodeAction::IncludeAsAncestorNode; + NodeAction::IncludeAsAncestorNode } else { - return NodeAction::Skip; + NodeAction::Skip } } @@ -165,7 +163,7 @@ fn determine_node_action( fn is_descendant_of_passthrough_device( node_path: &str, node_level: usize, - passthrough_device_names: &Vec, + passthrough_device_names: &[String], ) -> bool { for passthrough_path in passthrough_device_names { // Check if the current node is a descendant of a passthrough device @@ -180,9 +178,9 @@ fn is_descendant_of_passthrough_device( // If passthrough_path is the root node "/", then its child node level should be 2 // Otherwise, the child node level should be higher than the parent node level - if passthrough_path == "/" && current_node_level >= 2 { - return true; - } else if passthrough_path != "/" && current_node_level > expected_parent_level { + if (passthrough_path == "/" && current_node_level >= 2) + || (passthrough_path != "/" && current_node_level > expected_parent_level) + { return true; } } @@ -210,11 +208,11 @@ fn handle_node_level_change( /// Determine if node is an ancestor of passthrough device fn is_ancestor_of_passthrough_device( node_path: &str, - passthrough_device_names: &Vec, + passthrough_device_names: &[String], ) -> bool { for passthrough_path in passthrough_device_names { // Check if the current node is an ancestor of a passthrough device - if passthrough_path.starts_with(&node_path) && passthrough_path.len() > node_path.len() { + if passthrough_path.starts_with(node_path) && passthrough_path.len() > node_path.len() { // Ensure it is a true ancestor path (separated by /) let next_char = passthrough_path.chars().nth(node_path.len()).unwrap_or(' '); if next_char == '/' || node_path == "/" { @@ -226,36 +224,33 @@ fn is_ancestor_of_passthrough_device( } /// Determine if CPU node is needed -fn need_cpu_node(phys_cpu_ids: &Vec, node: &Node, node_path: &str) -> bool { +fn need_cpu_node(phys_cpu_ids: &[usize], node: &Node, node_path: &str) -> bool { let mut should_include_node = false; if !node_path.starts_with("/cpus/cpu@") { should_include_node = true; - } else { - if let Some(mut cpu_reg) = node.reg() { - if let Some(reg_entry) = cpu_reg.next() { - let cpu_address = reg_entry.address as usize; - debug!( - "Checking CPU node {} with address 0x{:x}", - node.name(), - cpu_address - ); - // Check if this CPU address is in the configured phys_cpu_ids - if phys_cpu_ids.contains(&cpu_address) { - should_include_node = true; - debug!( - "CPU node {} with address 0x{:x} is in phys_cpu_ids, including in guest FDT", - node.name(), - cpu_address - ); - } else { - debug!( - "CPU node {} with address 0x{:x} is NOT in phys_cpu_ids, skipping", - node.name(), - cpu_address - ); - } - } + } else if let Some(mut cpu_reg) = node.reg() + && let Some(reg_entry) = cpu_reg.next() { + let cpu_address = reg_entry.address as usize; + debug!( + "Checking CPU node {} with address 0x{:x}", + node.name(), + cpu_address + ); + // Check if this CPU address is in the configured phys_cpu_ids + if phys_cpu_ids.contains(&cpu_address) { + should_include_node = true; + debug!( + "CPU node {} with address 0x{:x} is in phys_cpu_ids, including in guest FDT", + node.name(), + cpu_address + ); + } else { + debug!( + "CPU node {} with address 0x{:x} is NOT in phys_cpu_ids, skipping", + node.name(), + cpu_address + ); } } should_include_node @@ -415,7 +410,5 @@ pub fn update_cpu_node(fdt: &Fdt, host_fdt: &Fdt, crate_config: &AxVMCrateConfig } assert_eq!(previous_node_level, 0); - let guest_fdt_bytes = new_fdt.finish().unwrap(); - - guest_fdt_bytes + new_fdt.finish().unwrap() } diff --git a/src/vmm/fdt/device.rs b/src/vmm/fdt/device.rs index fb369d90..e870389c 100644 --- a/src/vmm/fdt/device.rs +++ b/src/vmm/fdt/device.rs @@ -178,11 +178,10 @@ pub fn find_all_passthrough_devices(vm_cfg: &mut AxVMConfig, fdt: &Fdt) -> Vec, target_index: usize) -> String { +pub fn build_node_path(all_nodes: &[Node], target_index: usize) -> String { let mut path_stack: Vec = Vec::new(); - for i in 0..=target_index { - let node = &all_nodes[i]; + for node in all_nodes.iter().take(target_index + 1) { let level = node.level; if level == 1 { @@ -215,16 +214,15 @@ pub fn build_optimized_node_cache<'a>(fdt: &'a Fdt) -> BTreeMap(fdt: &'a Fdt) -> BTreeMap "#power-domain-cells", "phys" => "#phy-cells", "interrupts" | "interrupts-extended" => "#interrupt-cells", - "gpios" | _ if prop_name.ends_with("-gpios") || prop_name.ends_with("-gpio") => { - "#gpio-cells" - } + "gpios" => "#gpio-cells", + _ if prop_name.ends_with("-gpios") || prop_name.ends_with("-gpio") => "#gpio-cells", "dmas" => "#dma-cells", "thermal-sensors" => "#thermal-sensor-cells", "sound-dai" => "#sound-dai-cells", @@ -405,7 +402,7 @@ fn parse_phandle_property( for (phandle, specifiers) in phandle_refs { if let Some((device_path, _cells_info)) = phandle_map.get(&phandle) { let spec_info = if !specifiers.is_empty() { - format!(" (specifiers: {:?})", specifiers) + format!(" (specifiers: {specifiers:?})") } else { String::new() }; @@ -504,7 +501,7 @@ fn get_descendant_nodes_by_path<'a>( }; // Traverse node_cache, find all nodes with parent path as prefix - for (path, _nodes) in node_cache { + for path in node_cache.keys() { // Check if path has parent path as prefix (and is not the parent path itself) if path.starts_with(&search_prefix) && path.len() > search_prefix.len() { // This is a descendant node path, add to results diff --git a/src/vmm/fdt/parser.rs b/src/vmm/fdt/parser.rs index c1333520..a535292f 100644 --- a/src/vmm/fdt/parser.rs +++ b/src/vmm/fdt/parser.rs @@ -13,7 +13,7 @@ pub fn get_host_fdt() -> &'static [u8] { core::slice::from_raw_parts(bootarg as *const u8, core::mem::size_of::()) }; let fdt_header = FdtHeader::from_bytes(header) - .map_err(|e| format!("Failed to parse FDT header: {:#?}", e)) + .map_err(|e| format!("Failed to parse FDT header: {e:#?}")) .unwrap(); if fdt_header.magic.get() != FDT_VALID_MAGIC { @@ -24,10 +24,7 @@ pub fn get_host_fdt() -> &'static [u8] { ); } - let fdt_bytes = - unsafe { core::slice::from_raw_parts(bootarg as *const u8, fdt_header.total_size()) }; - - fdt_bytes + unsafe { core::slice::from_raw_parts(bootarg as *const u8, fdt_header.total_size()) } } pub fn setup_guest_fdt_from_vmm( @@ -36,7 +33,7 @@ pub fn setup_guest_fdt_from_vmm( crate_config: &AxVMCrateConfig, ) { let fdt = Fdt::from_bytes(fdt_bytes) - .map_err(|e| format!("Failed to parse FDT: {:#?}", e)) + .map_err(|e| format!("Failed to parse FDT: {e:#?}")) .expect("Failed to parse FDT"); // Call the modified function and get the returned device name list @@ -158,13 +155,13 @@ fn add_device_address_config( // Create a device configuration for each address segment let device_name = if index == 0 { match prefix { - Some(p) => format!("{}-{}", node_name, p), + Some(p) => format!("{node_name}-{p}"), None => node_name.to_string(), } } else { match prefix { - Some(p) => format!("{}-{}-region{}", node_name, p, index), - None => format!("{}-region{}", node_name, index), + Some(p) => format!("{node_name}-{p}-region{index}"), + None => format!("{node_name}-region{index}"), } }; @@ -198,9 +195,9 @@ fn add_pci_ranges_config(vm_cfg: &mut AxVMConfig, node_name: &str, range: &PciRa }; let device_name = if index == 0 { - format!("{}-{}", node_name, prefix) + format!("{node_name}-{prefix}") } else { - format!("{}-{}-region{}", node_name, prefix, index) + format!("{node_name}-{prefix}-region{index}") }; // Add new device configuration @@ -238,20 +235,18 @@ pub fn parse_passthrough_devices_address(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { // Check if it's a PCIe device node if node_name.starts_with("pcie@") || node_name.contains("pci") { // Process PCIe device's ranges property - if let Some(pci) = node.clone().into_pci() { - if let Ok(ranges) = pci.ranges() { - for (index, range) in ranges.enumerate() { - add_pci_ranges_config(vm_cfg, &node_name, &range, index); - } + if let Some(pci) = node.clone().into_pci() + && let Ok(ranges) = pci.ranges() { + for (index, range) in ranges.enumerate() { + add_pci_ranges_config(vm_cfg, &node_name, &range, index); } } // Process PCIe device's reg property (ECAM space) - if let Some(mut reg_iter) = node.reg() { - let mut index = 0; - while let Some(reg) = reg_iter.next() { + if let Some(reg_iter) = node.reg() { + for (index, reg) in reg_iter.enumerate() { let base_address = reg.address as usize; - let size = reg.size.unwrap_or(0) as usize; + let size = reg.size.unwrap_or(0); add_device_address_config( vm_cfg, @@ -261,21 +256,18 @@ pub fn parse_passthrough_devices_address(vm_cfg: &mut AxVMConfig, dtb: &[u8]) { index, Some("ecam"), ); - index += 1; } } } else { // Get device's reg property (process regular devices) - if let Some(mut reg_iter) = node.reg() { + if let Some(reg_iter) = node.reg() { // Process all address segments of the device - let mut index = 0; - while let Some(reg) = reg_iter.next() { + for (index, reg) in reg_iter.enumerate() { // Get device's address and size information let base_address = reg.address as usize; - let size = reg.size.unwrap_or(0) as usize; + let size = reg.size.unwrap_or(0); add_device_address_config(vm_cfg, &node_name, base_address, size, index, None); - index += 1; } } } diff --git a/src/vmm/fdt/print.rs b/src/vmm/fdt/print.rs index dd96c026..e9f10d68 100644 --- a/src/vmm/fdt/print.rs +++ b/src/vmm/fdt/print.rs @@ -9,7 +9,7 @@ pub fn print_fdt(fdt_addr: usize) { core::slice::from_raw_parts(fdt_addr as *const u8, core::mem::size_of::()) }; let fdt_header = FdtHeader::from_bytes(header) - .map_err(|e| format!("Failed to parse FDT header: {:#?}", e)) + .map_err(|e| format!("Failed to parse FDT header: {e:#?}")) .unwrap(); if fdt_header.magic.get() != FDT_VALID_MAGIC { @@ -25,7 +25,7 @@ pub fn print_fdt(fdt_addr: usize) { unsafe { core::slice::from_raw_parts(fdt_addr as *const u8, fdt_header.total_size()) }; let fdt = Fdt::from_bytes(fdt_bytes) - .map_err(|e| format!("Failed to parse FDT: {:#?}", e)) + .map_err(|e| format!("Failed to parse FDT: {e:#?}")) .expect("Failed to parse FDT"); // Statistics of node count and level distribution @@ -82,7 +82,7 @@ pub fn print_fdt(fdt_addr: usize) { #[allow(dead_code)] pub fn print_guest_fdt(fdt_bytes: &[u8]) { let fdt = Fdt::from_bytes(fdt_bytes) - .map_err(|e| format!("Failed to parse FDT: {:#?}", e)) + .map_err(|e| format!("Failed to parse FDT: {e:#?}")) .expect("Failed to parse FDT"); // Statistics of node count and level distribution let mut node_count = 0; diff --git a/src/vmm/images/mod.rs b/src/vmm/images/mod.rs index 47f5574f..9c6ccc43 100644 --- a/src/vmm/images/mod.rs +++ b/src/vmm/images/mod.rs @@ -1,5 +1,3 @@ -use core::ptr::NonNull; - use axaddrspace::GuestPhysAddr; use axerrno::AxResult; @@ -14,6 +12,9 @@ use crate::vmm::config::{config, get_vm_dtb_arc}; #[cfg(target_arch = "aarch64")] use crate::vmm::fdt::update_fdt; +#[cfg(target_arch = "aarch64")] +use core::ptr::NonNull; + mod linux; pub fn get_image_header(config: &AxVMCrateConfig) -> Option { @@ -107,7 +108,7 @@ impl ImageLoader { // Load DTB image let vm_config = axvm::config::AxVMConfig::from(self.config.clone()); if let Some(dtb_arc) = get_vm_dtb_arc(&vm_config) { - let dtb_slice: &[u8] = &*dtb_arc; + let dtb_slice: &[u8] = &dtb_arc; debug!( "DTB buffer addr: {:x}, size: {:#}", self.dtb_load_gpa.unwrap(), @@ -254,7 +255,7 @@ mod fs { // Load DTB image if needed. let vm_config = axvm::config::AxVMConfig::from(loader.config.clone()); if let Some(dtb_arc) = get_vm_dtb_arc(&vm_config) { - let dtb_slice: &[u8] = &*dtb_arc; + let dtb_slice: &[u8] = &dtb_arc; debug!( "DTB buffer addr: {:x}, size: {:#}", loader.dtb_load_gpa.unwrap(), From 5ad6e1ee9a32990efd6afb977c2b5cfc01f6b898 Mon Sep 17 00:00:00 2001 From: szy Date: Fri, 26 Sep 2025 18:27:28 +0800 Subject: [PATCH 27/30] fix fmt --- src/vmm/config.rs | 4 +++- src/vmm/fdt/create.rs | 8 +++----- src/vmm/fdt/device.rs | 8 +++----- src/vmm/fdt/parser.rs | 3 ++- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/vmm/config.rs b/src/vmm/config.rs index bb6e0df3..aa1c1576 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -56,7 +56,9 @@ pub mod config { let path = entry.path(); // Check if the file has a .toml extension let path_str = path.as_str(); - if path_str.ends_with(".toml") && let Ok(content) = fs::read_to_string(path_str) { + if path_str.ends_with(".toml") + && let Ok(content) = fs::read_to_string(path_str) + { configs.push(content); } } diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index 4b58929d..0c058c99 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -206,10 +206,7 @@ fn handle_node_level_change( } /// Determine if node is an ancestor of passthrough device -fn is_ancestor_of_passthrough_device( - node_path: &str, - passthrough_device_names: &[String], -) -> bool { +fn is_ancestor_of_passthrough_device(node_path: &str, passthrough_device_names: &[String]) -> bool { for passthrough_path in passthrough_device_names { // Check if the current node is an ancestor of a passthrough device if passthrough_path.starts_with(node_path) && passthrough_path.len() > node_path.len() { @@ -230,7 +227,8 @@ fn need_cpu_node(phys_cpu_ids: &[usize], node: &Node, node_path: &str) -> bool { if !node_path.starts_with("/cpus/cpu@") { should_include_node = true; } else if let Some(mut cpu_reg) = node.reg() - && let Some(reg_entry) = cpu_reg.next() { + && let Some(reg_entry) = cpu_reg.next() + { let cpu_address = reg_entry.address as usize; debug!( "Checking CPU node {} with address 0x{:x}", diff --git a/src/vmm/fdt/device.rs b/src/vmm/fdt/device.rs index e870389c..cf9eaafd 100644 --- a/src/vmm/fdt/device.rs +++ b/src/vmm/fdt/device.rs @@ -215,7 +215,8 @@ pub fn build_optimized_node_cache<'a>(fdt: &'a Fdt) -> BTreeMap(fdt: &'a Fdt) -> BTreeMap Date: Sun, 28 Sep 2025 10:43:35 +0800 Subject: [PATCH 28/30] move some code to fdt --- src/vmm/config.rs | 23 ++++++++++++----------- src/vmm/fdt/create.rs | 13 +------------ src/vmm/fdt/mod.rs | 28 ++++++++++++++++++++++++++++ src/vmm/fdt/parser.rs | 6 ++++-- 4 files changed, 45 insertions(+), 25 deletions(-) diff --git a/src/vmm/config.rs b/src/vmm/config.rs index aa1c1576..3f18447a 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -17,12 +17,7 @@ use fdt_parser::Fdt; #[cfg(target_arch = "aarch64")] use alloc::vec::Vec; -use alloc::collections::BTreeMap; use alloc::sync::Arc; -use lazyinit::LazyInit; -use spin::Mutex; - -pub static GENERATED_DTB_CACHE: LazyInit>>> = LazyInit::new(); #[allow(clippy::module_inception)] pub mod config { @@ -121,11 +116,13 @@ pub fn get_developer_provided_dtb( None } -pub fn get_vm_dtb_arc(vm_cfg: &AxVMConfig) -> Option> { - if let Some(cache) = GENERATED_DTB_CACHE.get() { - let cache_lock = cache.lock(); - if let Some(dtb) = cache_lock.get(&vm_cfg.id()) { - return Some(dtb.clone()); +pub fn get_vm_dtb_arc(_vm_cfg: &AxVMConfig) -> Option> { + #[cfg(target_arch = "aarch64")] + { + let cache_lock = dtb_cache().lock(); + if let Some(dtb) = cache_lock.get(&_vm_cfg.id()) { + // Convert Vec to Arc<[u8]> + return Some(Arc::from(dtb.as_slice())); } } None @@ -165,7 +162,11 @@ fn handle_fdt_operations(vm_config: &mut AxVMConfig, vm_create_config: &AxVMCrat } pub fn init_guest_vms() { - GENERATED_DTB_CACHE.init_once(Mutex::new(BTreeMap::new())); + // Initialize the DTB cache in the fdt module + #[cfg(target_arch = "aarch64")] + { + init_dtb_cache(); + } // First try to get configs from filesystem if fs feature is enabled let mut gvm_raw_configs = config::filesystem_vm_configs(); diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index 0c058c99..c97c34d3 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -1,6 +1,5 @@ use alloc::{ string::{String, ToString}, - sync::Arc, vec::Vec, }; use core::ptr::NonNull; @@ -99,17 +98,7 @@ pub fn crate_guest_fdt( fdt_writer.finish().unwrap() } -/// Generate guest FDT cache the result -/// # Return Value -/// Returns the generated DTB data and stores it in the global cache -pub fn crate_guest_fdt_with_cache(dtb_data: Vec, crate_config: &AxVMCrateConfig) { - // Store data in global cache - if let Some(cache) = crate::vmm::config::GENERATED_DTB_CACHE.get() { - let mut cache_lock = cache.lock(); - let dtb_arc: Arc<[u8]> = Arc::from(dtb_data); - cache_lock.insert(crate_config.base.id, dtb_arc); - } -} +// 移除了 crate_guest_fdt_with_cache 函数,因为它现在在 mod.rs 中实现 /// Node processing action enumeration enum NodeAction { diff --git a/src/vmm/fdt/mod.rs b/src/vmm/fdt/mod.rs index 5fbfa3f2..df88f4d8 100644 --- a/src/vmm/fdt/mod.rs +++ b/src/vmm/fdt/mod.rs @@ -8,8 +8,36 @@ mod device; mod parser; mod print; +use alloc::collections::BTreeMap; +use alloc::vec::Vec; +use axvm::config::AxVMCrateConfig; +use lazyinit::LazyInit; +use spin::Mutex; + // Re-export public functions pub use parser::*; // pub use print::print_fdt; pub use create::*; pub use device::build_node_path; + +// DTB cache for generated device trees +static GENERATED_DTB_CACHE: LazyInit>>> = LazyInit::new(); + +/// Initialize the DTB cache +pub fn init_dtb_cache() { + GENERATED_DTB_CACHE.init_once(Mutex::new(BTreeMap::new())); +} + +/// Get reference to the DTB cache +pub fn dtb_cache() -> &'static Mutex>> { + GENERATED_DTB_CACHE.get().unwrap() +} + +/// Generate guest FDT cache the result +/// # Return Value +/// Returns the generated DTB data and stores it in the global cache +pub fn crate_guest_fdt_with_cache(dtb_data: Vec, crate_config: &AxVMCrateConfig) { + // Store data in global cache + let mut cache_lock = dtb_cache().lock(); + cache_lock.insert(crate_config.base.id, dtb_data); +} diff --git a/src/vmm/fdt/parser.rs b/src/vmm/fdt/parser.rs index ffde888d..eddd7044 100644 --- a/src/vmm/fdt/parser.rs +++ b/src/vmm/fdt/parser.rs @@ -4,6 +4,7 @@ use alloc::{string::ToString, vec::Vec}; use axvm::config::{AxVMConfig, AxVMCrateConfig, PassThroughDeviceConfig}; use fdt_parser::{Fdt, FdtHeader, PciRange, PciSpace}; +use crate::vmm::fdt::crate_guest_fdt_with_cache; use crate::vmm::fdt::create::update_cpu_node; pub fn get_host_fdt() -> &'static [u8] { @@ -40,7 +41,8 @@ pub fn setup_guest_fdt_from_vmm( let passthrough_device_names = super::device::find_all_passthrough_devices(vm_cfg, &fdt); let dtb_data = super::create::crate_guest_fdt(&fdt, &passthrough_device_names, crate_config); - super::create::crate_guest_fdt_with_cache(dtb_data, crate_config); + // 调用新的 crate_guest_fdt_with_cache 函数 + crate_guest_fdt_with_cache(dtb_data, crate_config); } pub fn set_phys_cpu_sets(vm_cfg: &mut AxVMConfig, fdt: &Fdt, crate_config: &AxVMCrateConfig) { @@ -375,5 +377,5 @@ pub fn update_provided_fdt(provided_dtb: &[u8], host_dtb: &[u8], crate_config: & let host_fdt = Fdt::from_bytes(host_dtb) .expect("Failed to parse DTB image, perhaps the DTB is invalid or corrupted"); let provided_dtb_data = update_cpu_node(&provided_fdt, &host_fdt, crate_config); - super::create::crate_guest_fdt_with_cache(provided_dtb_data, crate_config); + crate_guest_fdt_with_cache(provided_dtb_data, crate_config); } From 1a8df5d38d543093599c673ad078f26e46929fa1 Mon Sep 17 00:00:00 2001 From: szy Date: Sun, 28 Sep 2025 11:03:50 +0800 Subject: [PATCH 29/30] update log --- src/vmm/config.rs | 1 - src/vmm/fdt/create.rs | 2 -- src/vmm/fdt/parser.rs | 1 - 3 files changed, 4 deletions(-) diff --git a/src/vmm/config.rs b/src/vmm/config.rs index 3f18447a..15346347 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -121,7 +121,6 @@ pub fn get_vm_dtb_arc(_vm_cfg: &AxVMConfig) -> Option> { { let cache_lock = dtb_cache().lock(); if let Some(dtb) = cache_lock.get(&_vm_cfg.id()) { - // Convert Vec to Arc<[u8]> return Some(Arc::from(dtb.as_slice())); } } diff --git a/src/vmm/fdt/create.rs b/src/vmm/fdt/create.rs index c97c34d3..b2f9432d 100644 --- a/src/vmm/fdt/create.rs +++ b/src/vmm/fdt/create.rs @@ -98,8 +98,6 @@ pub fn crate_guest_fdt( fdt_writer.finish().unwrap() } -// 移除了 crate_guest_fdt_with_cache 函数,因为它现在在 mod.rs 中实现 - /// Node processing action enumeration enum NodeAction { /// Skip node, not included in guest FDT diff --git a/src/vmm/fdt/parser.rs b/src/vmm/fdt/parser.rs index eddd7044..859b8102 100644 --- a/src/vmm/fdt/parser.rs +++ b/src/vmm/fdt/parser.rs @@ -41,7 +41,6 @@ pub fn setup_guest_fdt_from_vmm( let passthrough_device_names = super::device::find_all_passthrough_devices(vm_cfg, &fdt); let dtb_data = super::create::crate_guest_fdt(&fdt, &passthrough_device_names, crate_config); - // 调用新的 crate_guest_fdt_with_cache 函数 crate_guest_fdt_with_cache(dtb_data, crate_config); } From 2484df53704031a28544de19c7a494f2222d179c Mon Sep 17 00:00:00 2001 From: szy Date: Sun, 28 Sep 2025 13:23:04 +0800 Subject: [PATCH 30/30] update --- src/vmm/config.rs | 84 ---------------------------------------------- src/vmm/fdt/mod.rs | 82 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 86 deletions(-) diff --git a/src/vmm/config.rs b/src/vmm/config.rs index 15346347..fa14b3c0 100644 --- a/src/vmm/config.rs +++ b/src/vmm/config.rs @@ -11,12 +11,6 @@ use crate::vmm::{VM, images::ImageLoader, vm_list::push_vm}; #[cfg(target_arch = "aarch64")] use crate::vmm::fdt::*; -#[cfg(target_arch = "aarch64")] -use fdt_parser::Fdt; - -#[cfg(target_arch = "aarch64")] -use alloc::vec::Vec; - use alloc::sync::Arc; #[allow(clippy::module_inception)] @@ -71,51 +65,6 @@ pub mod config { include!(concat!(env!("OUT_DIR"), "/vm_configs.rs")); } -#[cfg(target_arch = "aarch64")] -pub fn get_developer_provided_dtb( - vm_cfg: &AxVMConfig, - crate_config: &AxVMCrateConfig, -) -> Option> { - 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 axerrno::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::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 -} - pub fn get_vm_dtb_arc(_vm_cfg: &AxVMConfig) -> Option> { #[cfg(target_arch = "aarch64")] { @@ -127,39 +76,6 @@ pub fn get_vm_dtb_arc(_vm_cfg: &AxVMConfig) -> Option> { None } -/// Handle all FDT-related operations for aarch64 architecture -#[cfg(target_arch = "aarch64")] -fn handle_fdt_operations(vm_config: &mut AxVMConfig, vm_create_config: &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); - } - - // Overlay VM config with the given DTB. - if let Some(dtb_arc) = get_vm_dtb_arc(vm_config) { - let dtb = dtb_arc.as_ref(); - parse_passthrough_devices_address(vm_config, dtb); - parse_vm_interrupt(vm_config, dtb); - } else { - error!( - "VM[{}] DTB not found in memory, skipping...", - vm_config.id() - ); - } -} - pub fn init_guest_vms() { // Initialize the DTB cache in the fdt module #[cfg(target_arch = "aarch64")] diff --git a/src/vmm/fdt/mod.rs b/src/vmm/fdt/mod.rs index df88f4d8..ad294cf9 100644 --- a/src/vmm/fdt/mod.rs +++ b/src/vmm/fdt/mod.rs @@ -10,16 +10,18 @@ mod print; use alloc::collections::BTreeMap; use alloc::vec::Vec; -use axvm::config::AxVMCrateConfig; +use axvm::config::{AxVMConfig, AxVMCrateConfig}; +use fdt_parser::Fdt; use lazyinit::LazyInit; use spin::Mutex; -// Re-export public functions pub use parser::*; // pub use print::print_fdt; pub use create::*; pub use device::build_node_path; +use crate::vmm::config::{config, get_vm_dtb_arc}; + // DTB cache for generated device trees static GENERATED_DTB_CACHE: LazyInit>>> = LazyInit::new(); @@ -41,3 +43,79 @@ pub fn crate_guest_fdt_with_cache(dtb_data: Vec, crate_config: &AxVMCrateCon let mut cache_lock = dtb_cache().lock(); cache_lock.insert(crate_config.base.id, dtb_data); } + +/// Handle all FDT-related operations for aarch64 architecture +pub fn handle_fdt_operations(vm_config: &mut AxVMConfig, vm_create_config: &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); + } + + // Overlay VM config with the given DTB. + if let Some(dtb_arc) = get_vm_dtb_arc(vm_config) { + let dtb = dtb_arc.as_ref(); + parse_passthrough_devices_address(vm_config, dtb); + 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> { + 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 axerrno::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::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 +}