From 91f9f0542654dc678e5dc7d70b355da534b1c387 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 10 Sep 2025 23:41:28 +0800 Subject: [PATCH 01/12] [refactor] aarch64: Refactored PCI device passthrough --- platform/aarch64/qemu-gicv3/board.rs | 79 +- src/arch/aarch64/iommu.rs | 1 + src/config.rs | 28 +- src/main.rs | 10 +- src/memory/mm.rs | 10 + src/pci/bridge.rs | 71 -- src/pci/endpoint.rs | 155 ---- src/pci/mem_alloc.rs | 70 ++ src/pci/mod.rs | 114 +-- src/pci/pci.rs | 452 ----------- src/pci/pci_access.rs | 1034 ++++++++++++++++++++++++++ src/pci/pci_config.rs | 89 +++ src/pci/pci_mem.rs | 55 ++ src/pci/pci_struct.rs | 731 ++++++++++++++++++ src/pci/pci_test.rs | 105 +++ src/pci/pcibar.rs | 147 ---- src/pci/phantom_cfg.rs | 365 --------- src/platform/mod.rs | 9 +- src/zone.rs | 25 +- 19 files changed, 2218 insertions(+), 1332 deletions(-) delete mode 100644 src/pci/bridge.rs delete mode 100644 src/pci/endpoint.rs create mode 100644 src/pci/mem_alloc.rs delete mode 100644 src/pci/pci.rs create mode 100644 src/pci/pci_access.rs create mode 100644 src/pci/pci_config.rs create mode 100644 src/pci/pci_mem.rs create mode 100644 src/pci/pci_struct.rs create mode 100644 src/pci/pci_test.rs delete mode 100644 src/pci/pcibar.rs delete mode 100644 src/pci/phantom_cfg.rs diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index 9ff4be52..32ce6724 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -67,20 +67,71 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { gits_size: 0x20000, }; -pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { - ecam_base: 0x4010000000, - ecam_size: 0x10000000, - io_base: 0x3eff0000, - io_size: 0x10000, - pci_io_base: 0x0, - mem32_base: 0x10000000, - mem32_size: 0x2eff0000, - pci_mem32_base: 0x10000000, - mem64_base: 0x8000000000, - mem64_size: 0x8000000000, - pci_mem64_base: 0x8000000000, -}; +pub const ROOT_PCI_CONFIG: [HvPciConfig; 4] = [ + HvPciConfig { + ecam_base: 0x4010000000, + ecam_size: 0x10000000, + io_base: 0x3eff0000, + io_size: 0x10000, + pci_io_base: 0x0, + mem32_base: 0x10000000, + mem32_size: 0x2eff0000, + pci_mem32_base: 0x10000000, + mem64_base: 0x8000000000, + mem64_size: 0x8000000000, + pci_mem64_base: 0x8000000000, + }, + HvPciConfig { + ecam_base: 0x0, + ecam_size: 0x0, + io_base: 0x0, + io_size: 0x0, + pci_io_base: 0x0, + mem32_base: 0x0, + mem32_size: 0x0, + pci_mem32_base: 0x0, + mem64_base: 0x0, + mem64_size: 0x0, + pci_mem64_base: 0x0, + }, + HvPciConfig { + ecam_base: 0x0, + ecam_size: 0x0, + io_base: 0x0, + io_size: 0x0, + pci_io_base: 0x0, + mem32_base: 0x0, + mem32_size: 0x0, + pci_mem32_base: 0x0, + mem64_base: 0x0, + mem64_size: 0x0, + pci_mem64_base: 0x0, + }, + HvPciConfig { + ecam_base: 0x0, + ecam_size: 0x0, + io_base: 0x0, + io_size: 0x0, + pci_io_base: 0x0, + mem32_base: 0x0, + mem32_size: 0x0, + pci_mem32_base: 0x0, + mem64_base: 0x0, + mem64_size: 0x0, + pci_mem64_base: 0x0, + }, +]; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; -pub const ROOT_PCI_DEVS: [u64; 2] = [0, 1 << 3]; +pub const ROOT_PCI_DEVS: [HvPciDevConfig; 3] = [ + HvPciDevConfig { bdf: 0, vbdf: 0 }, + HvPciDevConfig { + bdf: (0 << 20 | 2 << 15 | 0 << 12), + vbdf: (0 << 20 | 2 << 15 | 0 << 12), + }, + HvPciDevConfig { + bdf: (0 << 20 | 3 << 15 | 0 << 12), + vbdf: (0 << 20 | 3 << 15 | 0 << 12), + }, +]; diff --git a/src/arch/aarch64/iommu.rs b/src/arch/aarch64/iommu.rs index 50b22e81..2e4cf361 100644 --- a/src/arch/aarch64/iommu.rs +++ b/src/arch/aarch64/iommu.rs @@ -13,6 +13,7 @@ // // Authors: // +#![allow(dead_code)] use crate::{ arch::mm::new_s2_memory_set, consts::{MAX_ZONE_NUM, PAGE_SIZE}, diff --git a/src/config.rs b/src/config.rs index ebb323f1..129e6c29 100644 --- a/src/config.rs +++ b/src/config.rs @@ -15,8 +15,9 @@ // use alloc::vec::Vec; use spin::Once; +use core::fmt::Debug; -use crate::{arch::zone::HvArchZoneConfig, platform}; +use crate::{arch::zone::HvArchZoneConfig, pci::pci_struct::Bdf, platform}; pub const MEM_TYPE_RAM: u32 = 0; pub const MEM_TYPE_IO: u32 = 1; @@ -27,6 +28,7 @@ pub const CONFIG_MAX_MEMORY_REGIONS: usize = 64; pub const CONFIG_MAX_INTERRUPTS: usize = 32; pub const CONFIG_NAME_MAXLEN: usize = 32; pub const CONFIG_MAX_IVC_CONFIGS: usize = 2; +pub const CONFIG_PCI_BUS_MAXLEN: usize = 4; pub const CONFIG_MAX_PCI_DEV: usize = 32; #[repr(C)] @@ -91,9 +93,9 @@ pub struct HvZoneConfig { pub dtb_size: u64, pub name: [u8; CONFIG_NAME_MAXLEN], pub arch_config: HvArchZoneConfig, - pub pci_config: HvPciConfig, + pub pci_config: [HvPciConfig; CONFIG_PCI_BUS_MAXLEN], pub num_pci_devs: u64, - pub alloc_pci_devs: [u64; CONFIG_MAX_PCI_DEV], + pub alloc_pci_devs: [HvPciDevConfig; CONFIG_MAX_PCI_DEV], } impl HvZoneConfig { @@ -113,9 +115,9 @@ impl HvZoneConfig { dtb_size: u64, name: [u8; CONFIG_NAME_MAXLEN], arch: HvArchZoneConfig, - pci: HvPciConfig, + pci: [HvPciConfig; CONFIG_PCI_BUS_MAXLEN], num_pci_devs: u64, - alloc_pci_devs: [u64; CONFIG_MAX_PCI_DEV], + alloc_pci_devs: [HvPciDevConfig; CONFIG_MAX_PCI_DEV], ) -> Self { Self { zone_id, @@ -192,3 +194,19 @@ pub struct HvIvcConfig { pub interrupt_num: u32, pub max_peers: u32, } + +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct HvPciDevConfig { + pub bdf: u64, + pub vbdf: u64, +} + +// #[cfg(feature = "pci")] +impl Debug for HvPciDevConfig { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let bdf = Bdf::from_address(self.bdf); + let vbdf = Bdf::from_address(self.vbdf); + write!(f, "bdf {:#?} vbdf {:#?}", bdf, vbdf) + } +} diff --git a/src/main.rs b/src/main.rs index fa6aec9c..6cc74b3f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,7 +64,7 @@ mod zone; #[cfg(target_arch = "aarch64")] mod ivc; - +#[cfg(feature = "pci")] mod pci; #[cfg(test)] @@ -76,6 +76,8 @@ use crate::consts::MAX_CPU_NUM; use arch::{cpu::cpu_start, entry::arch_entry}; use config::root_zone_config; use core::sync::atomic::{AtomicI32, AtomicU32, Ordering}; +#[cfg(feature = "pci")] +use pci::pci_config::hvisor_pci_init; use percpu::PerCpu; use zone::{add_zone, zone_create}; @@ -138,6 +140,12 @@ fn primary_init_early() { #[cfg(all(feature = "iommu", target_arch = "aarch64"))] iommu_init(); + #[cfg(feature = "pci")] + { + let config = unsafe { config::HV_ROOT_ZONE_CONFIG.get().unwrap().pci_config }; + let _ = hvisor_pci_init(&config); + } + #[cfg(not(test))] { let zone = zone_create(root_zone_config()).unwrap(); diff --git a/src/memory/mm.rs b/src/memory/mm.rs index 164a0d61..4683650b 100644 --- a/src/memory/mm.rs +++ b/src/memory/mm.rs @@ -144,6 +144,16 @@ where } } + pub fn try_delete(&mut self, start: PT::VA) -> HvResult { + if let Entry::Occupied(e) = self.regions.entry(start) { + self.pt.unmap(e.get())?; + e.remove(); + Ok(()) + } else { + Err(hv_err!(ENOMEM)) + } + } + pub fn clear(&mut self) { for region in self.regions.values() { self.pt.unmap(region).unwrap(); diff --git a/src/pci/bridge.rs b/src/pci/bridge.rs deleted file mode 100644 index 9bd67c2e..00000000 --- a/src/pci/bridge.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2025 Syswonder -// hvisor is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -// FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. -// -// Syswonder Website: -// https://www.syswonder.org -// -// Authors: -// -use alloc::vec::Vec; - -use super::{ - pcibar::{BarRegion, PciBar, VirtPciBar}, - phantom_cfg::{PhantomCfg, PhantomCfgType}, - NUM_BAR_REGS_TYPE1, NUM_MAX_BARS, -}; - -#[derive(Debug)] -pub struct BridgeConfig { - bars: [PciBar; NUM_BAR_REGS_TYPE1], - pub bdf: usize, -} - -impl BridgeConfig { - pub fn new(bdf: usize) -> Self { - Self { - bars: [PciBar::default(); NUM_BAR_REGS_TYPE1], - bdf: bdf, - } - } - - pub fn bars_init(&mut self, bar_id: usize, origin_val: u32, val: u32) { - self.bars[bar_id].init(origin_val, val); - } - - pub fn get_regions(&self) -> Vec { - let mut regions: Vec = Vec::new(); - let mut bar_id = 0; - while bar_id < NUM_BAR_REGS_TYPE1 { - if self.bars[bar_id].is_mutable() { - if !self.bars[bar_id].mem_type_64() { - regions.push(self.bars[bar_id].get_32b_region()); - bar_id += 1; - } else { - regions.push( - self.bars[bar_id + 1].get_64b_region(self.bars[bar_id].get_32b_region()), - ); - bar_id += 2; - } - } else { - bar_id += 1; - } - } - regions - } - - // after we get bar regions, we should generate a virtual device instance that mirrors this device for use by other VMs - pub fn generate_vbridge(&self) -> PhantomCfg { - let mut v_bars: [VirtPciBar; NUM_MAX_BARS] = [VirtPciBar::default(); NUM_MAX_BARS]; - for i in 0..NUM_BAR_REGS_TYPE1 { - v_bars[i] = self.bars[i].generate_vbar(); - } - PhantomCfg::new(self.bdf, v_bars, PhantomCfgType::BRIDGE) - } -} diff --git a/src/pci/endpoint.rs b/src/pci/endpoint.rs deleted file mode 100644 index d069afa6..00000000 --- a/src/pci/endpoint.rs +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (c) 2025 Syswonder -// hvisor is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -// FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. -// -// Syswonder Website: -// https://www.syswonder.org -// -// Authors: -// -use alloc::vec::Vec; -use core::ptr::read_volatile; - -use super::{ - cfg_base, cfg_reg_addr, - pcibar::{BarRegion, PciBar, VirtPciBar}, - phantom_cfg::{PhantomCfg, PhantomCfgType}, - CFG_CAP_PTR_OFF, CFG_EXT_CAP_ID, CFG_EXT_CAP_PTR_OFF, CFG_NEXT_EXT_CAP_OFF, CFG_SRIOV_CAP_ID, - NUM_BAR_REGS_TYPE0, NUM_MAX_BARS, -}; - -#[derive(Debug)] -pub struct EndpointConfig { - bars: [PciBar; NUM_BAR_REGS_TYPE0], - pub bdf: usize, - pub node_before_sriov: usize, - pub node_after_sriov: usize, -} - -impl EndpointConfig { - pub fn new(bdf: usize) -> Self { - let (bars, bdf) = { ([PciBar::default(); NUM_BAR_REGS_TYPE0], bdf) }; - let mut r = EndpointConfig { - bars, - bdf, - node_before_sriov: 0xfff, - node_after_sriov: 0xfff, - }; - if r.ext_cap_exists() { - r.find_sriov(); - } - r - } - - pub fn ext_cap_exists(&self) -> bool { - let cap_ptr_addr = cfg_reg_addr(self.bdf, CFG_CAP_PTR_OFF); - let mut cur_cap_ptr = unsafe { read_volatile(cap_ptr_addr as *const u8) } as usize; - - if cur_cap_ptr == 0 { - return false; - } - - while cur_cap_ptr != 0 { - let cap_addr = cfg_reg_addr(self.bdf, cur_cap_ptr); - let cap_val = unsafe { read_volatile(cap_addr as *const u16) }; - - let cap_id = (cap_val & 0xff) as u8; - let next_cap_ptr = ((cap_val >> 8) & 0xff) as usize; - - if (cap_id as usize) == CFG_EXT_CAP_ID { - info!( - "{:x}:{:x}.{:x} is a PCI Express device!", - self.bdf >> 8, - (self.bdf >> 3) & 0b11111, - self.bdf & 0b111 - ); - return true; - } - - cur_cap_ptr = next_cap_ptr; - } - - false - } - - pub fn find_sriov(&mut self) { - info!("finding sriov"); - - let mut prev_cap_ptr = 0; - let mut curr_cap_ptr = CFG_EXT_CAP_PTR_OFF; // start from 0x100 - - // init to invalid offset value, to check if we find sriov - self.node_before_sriov = 0xfff; - self.node_after_sriov = 0xfff; - - while curr_cap_ptr != 0 { - let cap_addr = cfg_reg_addr(self.bdf, curr_cap_ptr); - let cap_val = unsafe { read_volatile(cap_addr as *const u32) }; // each ext cap is 8 bytes - - let cap_id = (cap_val & 0xffff) as u16; - let next_cap_ptr = ((cap_val >> 20) & 0xfff) as usize; - - if (cap_id as usize) == CFG_SRIOV_CAP_ID { - self.node_before_sriov = prev_cap_ptr; - self.node_after_sriov = next_cap_ptr; - info!( - "{:x}:{:x}.{:x} SR-IOV off: {:#x}, prev_node_off: {:#x}, next_node_off: {:#x}", - self.bdf >> 8, - (self.bdf >> 3) & 0b11111, - self.bdf & 0b111, - curr_cap_ptr, - prev_cap_ptr, - next_cap_ptr - ); - break; - } - - prev_cap_ptr = curr_cap_ptr; - curr_cap_ptr = next_cap_ptr; - } - } - - pub fn skip_sriov(&self, cur_cap_hdr: usize) -> usize { - (cur_cap_hdr & 0x000fffff) | (self.node_after_sriov << CFG_NEXT_EXT_CAP_OFF) - } - - pub fn bars_init(&mut self, bar_id: usize, origin_val: u32, val: u32) { - self.bars[bar_id].init(origin_val, val); - } - - pub fn get_regions(&self) -> Vec { - let mut regions: Vec = Vec::new(); - let mut bar_id = 0; - while bar_id < NUM_BAR_REGS_TYPE0 { - if self.bars[bar_id].is_mutable() { - if !self.bars[bar_id].mem_type_64() { - regions.push(self.bars[bar_id].get_32b_region()); - bar_id += 1; - } else { - regions.push( - self.bars[bar_id + 1].get_64b_region(self.bars[bar_id].get_32b_region()), - ); - bar_id += 2; - } - } else { - bar_id += 1; - } - } - regions - } - - // after we get bar regions, we should generate a virtual device instance that mirrors this device for use by other VMs - pub fn generate_vep(&self) -> PhantomCfg { - let mut v_bars: [VirtPciBar; NUM_MAX_BARS] = [VirtPciBar::default(); NUM_MAX_BARS]; - for i in 0..NUM_BAR_REGS_TYPE0 { - v_bars[i] = self.bars[i].generate_vbar(); - } - PhantomCfg::new(self.bdf, v_bars, PhantomCfgType::ENDPOINT) - } -} diff --git a/src/pci/mem_alloc.rs b/src/pci/mem_alloc.rs new file mode 100644 index 00000000..73b8cf53 --- /dev/null +++ b/src/pci/mem_alloc.rs @@ -0,0 +1,70 @@ +use core::{fmt::Debug, ops::Range}; + +pub type Mem32Address = u32; +pub type Mem64Address = u64; + +trait Algin { + fn align_up(self, align: Self) -> Self; +} + +impl Algin for Mem32Address { + fn align_up(self, align: Self) -> Self { + (self + align - 1) & !(align - 1) + } +} + +impl Algin for Mem64Address { + fn align_up(self, align: Self) -> Self { + (self + align - 1) & !(align - 1) + } +} + +pub trait BarAllocator: Debug { + fn alloc_memory32(&mut self, size: Mem32Address) -> Option; + fn alloc_memory64(&mut self, size: Mem64Address) -> Option; +} + +#[derive(Default, Debug)] +pub struct BaseAllocator { + mem32: Range, + mem32_used: Mem32Address, + mem64: Range, + mem64_used: Mem64Address, +} + +impl BaseAllocator { + pub fn set_mem32(&mut self, start: Mem32Address, size: Mem32Address) { + self.mem32 = start..start + size; + self.mem32_used = start; + } + + pub fn set_mem64(&mut self, start: Mem64Address, size: Mem64Address) { + self.mem64 = start..start + size; + self.mem64_used = start; + } +} + +impl BarAllocator for BaseAllocator { + fn alloc_memory32(&mut self, size: Mem32Address) -> Option { + let ptr = self.mem32_used.align_up(size); + + if self.mem32.contains(&ptr) && ptr + size <= self.mem32.end { + self.mem32_used = ptr + size; + // debug!("alloc mem32 {:x} {}", ptr, size); + Some(ptr) + } else { + None + } + } + + fn alloc_memory64(&mut self, size: Mem64Address) -> Option { + let ptr = self.mem64_used.align_up(size); + if self.mem64.contains(&ptr) && ptr + size <= self.mem64.end { + self.mem64_used = ptr + size; + // debug!("alloc mem64 {:x} {}", ptr, size); + Some(ptr) + } else { + None + } + } +} diff --git a/src/pci/mod.rs b/src/pci/mod.rs index 203999af..8df8db9a 100644 --- a/src/pci/mod.rs +++ b/src/pci/mod.rs @@ -1,108 +1,10 @@ -// Copyright (c) 2025 Syswonder -// hvisor is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -// FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. -// -// Syswonder Website: -// https://www.syswonder.org -// -// Authors: -// -use spin::Once; +pub mod mem_alloc; +pub mod pci_access; +pub mod pci_config; +pub mod pci_mem; +pub mod pci_struct; +// pub mod vpci_dtb; -pub mod bridge; -pub mod endpoint; -pub mod pci; -pub mod pcibar; -pub mod phantom_cfg; +pub mod pci_test; -pub const CFG_CMD_OFF: usize = 0x4; //status -pub const CFG_CAP_PTR_OFF: usize = 0x34; // capabilities pointer -pub const CFG_EXT_CAP_PTR_OFF: usize = 0x100; // extended capabilities pointer -pub const CFG_NEXT_EXT_CAP_OFF: usize = 20; -pub const CFG_CLASS_CODE_OFF: usize = 0x8; // 4 bytes, include revision and class code -pub const CFG_SRIOV_CAP_ID: usize = 0x0010; -pub const CFG_EXT_CAP_ID: usize = 0x10; -pub const CFG_BAR0: usize = 0x10; -pub const CFG_BAR1: usize = 0x14; -pub const CFG_BAR2: usize = 0x18; -pub const CFG_BAR3: usize = 0x1c; -pub const CFG_BAR4: usize = 0x20; -pub const CFG_BAR5: usize = 0x24; -pub const CFG_PRIMARY_BUS: usize = 0x18; -pub const CFG_SECONDARY_BUS: usize = 0x19; -pub const CFG_IO_BASE: usize = 0x1c; -pub const CFG_IO_LIMIT: usize = 0x1d; -pub const CFG_MEM_BASE: usize = 0x20; -pub const CFG_MEM_LIMIT: usize = 0x22; -pub const CFG_PREF_MEM_BASE: usize = 0x24; -pub const CFG_PREF_MEM_LIMIT: usize = 0x26; -pub const CFG_PREF_BASE_UPPER32: usize = 0x28; -pub const CFG_PREF_LIMIT_UPPER32: usize = 0x2c; -pub const CFG_IO_BASE_UPPER16: usize = 0x30; -pub const CFG_IO_LIMIT_UPPER16: usize = 0x32; -pub const CFG_INT_LINE: usize = 0x3d; -pub const CFG_INT_PIN: usize = 0x3d; - -pub const NUM_BAR_REGS_TYPE0: usize = 6; -pub const NUM_BAR_REGS_TYPE1: usize = 2; -pub const NUM_MAX_BARS: usize = 6; -pub const PHANTOM_DEV_HEADER: u32 = 0x77777777u32; - -pub static ECAM_BASE: Once = Once::new(); - -pub static BDF_SHIFT: Once = Once::new(); - -pub fn init_ecam_base(ecam_base: usize) { - ECAM_BASE.call_once(|| ecam_base); -} - -pub fn get_ecam_base() -> usize { - *ECAM_BASE.get().unwrap() as _ -} - -pub fn init_bdf_shift(bdf_shift: usize) { - BDF_SHIFT.call_once(|| bdf_shift); -} - -pub fn get_bdf_shift() -> usize { - *BDF_SHIFT.get().unwrap() as _ -} - -pub fn cfg_base(bdf: usize) -> usize { - let shift = get_bdf_shift(); - if cfg!(all(target_arch = "loongarch64", feature = "pci")) && ((bdf >> 8) != 0) { - get_ecam_base() + (bdf << shift) + 0x1000_0000 - } else { - get_ecam_base() + (bdf << shift) - } -} - -// generate addr with reg addr, example off = 0x123, shift = 0x8 -pub fn cfg_reg_addr(bdf: usize, off: usize) -> usize { - let base = cfg_base(bdf); - let shift = get_bdf_shift(); - let upper_off = off >> shift; // 0x1 - let lower_off = off & ((1 << shift) - 1); // 0x23 - let addr = (upper_off << (shift + 16)) + base + lower_off; - addr -} - -/// Extracts the PCI config space register offset, compatible with architectures where the offset layout is split (e.g., LoongArch). -/// Low bits are taken from address[0..bdf_shift), high bits from address[(bdf_shift + 16)..). -fn extract_reg_addr(addr: usize) -> usize { - let bdf_shift = get_bdf_shift(); - let low_mask = (1usize << bdf_shift) - 1; - let low_bits = addr & low_mask; - - let high_shift = bdf_shift + 16; - let high_mask = (1usize << (12 - bdf_shift)) - 1; - let high_bits = ((addr >> high_shift) & high_mask) << bdf_shift; - - high_bits | low_bits -} +pub type PciConfigAddress = u64; diff --git a/src/pci/pci.rs b/src/pci/pci.rs deleted file mode 100644 index 52cc61d0..00000000 --- a/src/pci/pci.rs +++ /dev/null @@ -1,452 +0,0 @@ -// Copyright (c) 2025 Syswonder -// hvisor is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -// FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. -// -// Syswonder Website: -// https://www.syswonder.org -// -// Authors: -// -use core::{panic, ptr, usize}; - -use crate::config::{HvPciConfig, CONFIG_MAX_PCI_DEV}; -use crate::memory::addr::align_down; -use crate::memory::mmio_perform_access; -use crate::pci::pcibar::BarType; -use crate::pci::phantom_cfg::find_phantom_dev; -use crate::pci::{get_ecam_base, init_bdf_shift, init_ecam_base}; -use crate::percpu::this_zone; -use crate::{ - error::HvResult, - memory::MMIOAccess, - memory::{GuestPhysAddr, MemFlags, MemoryRegion}, - zone::Zone, -}; -use alloc::vec::Vec; - -use super::bridge::BridgeConfig; -use super::endpoint::EndpointConfig; -use super::pcibar::BarRegion; -use super::phantom_cfg::{add_phantom_devices, generate_vep_by_bdf, PhantomCfg}; -use super::{ - cfg_base, extract_reg_addr, get_bdf_shift, CFG_EXT_CAP_PTR_OFF, NUM_BAR_REGS_TYPE0, - NUM_BAR_REGS_TYPE1, -}; - -#[cfg(all(feature = "iommu", target_arch = "aarch64"))] -use crate::arch::iommu::iommu_add_device; - -#[derive(Debug)] -pub struct PciRoot { - endpoints: Vec, - bridges: Vec, - alloc_devs: Vec, // include host bridge - phantom_devs: Vec, - bar_regions: Vec, -} -impl PciRoot { - pub fn new() -> Self { - let r = Self { - endpoints: Vec::new(), - bridges: Vec::new(), - alloc_devs: Vec::new(), - phantom_devs: Vec::new(), - bar_regions: Vec::new(), - }; - r - } - - pub fn is_assigned_device(&self, bdf: usize) -> bool { - if self.alloc_devs.contains(&bdf) { - true - } else { - false - } - } - - pub fn is_bridge(&self, bdf: usize) -> bool { - match self.bridges.iter().find(|&b| b.bdf == bdf) { - Some(b) => true, - None => false, - } - } - - pub fn bars_register(&mut self) { - self.ep_bars_init(); - self.bridge_bars_init(); - self.get_bars_regions(); - } - - pub fn generate_vdevs(&self) { - for ep in self.endpoints.iter() { - add_phantom_devices(ep.generate_vep()); - } - for bridge in self.bridges.iter() { - add_phantom_devices(bridge.generate_vbridge()); - } - } - - fn get_bars_regions(&mut self) { - for ep in self.endpoints.iter() { - let regions = ep.get_regions(); - for mut region in regions { - if region.size < 0x1000 { - // unnecessary unless you use qemu pci-test-dev - region.size = 0x1000; - } - self.bar_regions.push(region); - } - } - for bridge in self.bridges.iter() { - let regions = bridge.get_regions(); - for mut region in regions { - if region.size < 0x1000 { - region.size = 0x1000; - } - self.bar_regions.push(region); - } - } - info!("PCI BAR regions init done"); - } - - fn ep_bars_init(&mut self) { - for ep in self.endpoints.iter_mut() { - let cfg_base = cfg_base(ep.bdf); - let offsets: [usize; NUM_BAR_REGS_TYPE0] = [0x10, 0x14, 0x18, 0x1c, 0x20, 0x24]; - for bar_id in 0..NUM_BAR_REGS_TYPE0 { - unsafe { - let reg_ptr = (cfg_base + offsets[bar_id]) as *mut u32; - let origin_val = *reg_ptr; - *reg_ptr = 0xffffffffu32; - let new_val = *reg_ptr; - ep.bars_init(bar_id, origin_val, new_val); - *reg_ptr = origin_val; - } - } - } - } - - fn bridge_bars_init(&mut self) { - for bridge in self.bridges.iter_mut() { - let cfg_base = cfg_base(bridge.bdf); - let offsets: [usize; NUM_BAR_REGS_TYPE1] = [0x10, 0x14]; - for bar_id in 0..NUM_BAR_REGS_TYPE1 { - unsafe { - let reg_ptr = (cfg_base + offsets[bar_id]) as *mut u32; - let origin_val = *reg_ptr; - *reg_ptr = 0xffffffffu32; - let new_val = *reg_ptr; - bridge.bars_init(bar_id, origin_val, new_val); - *reg_ptr = origin_val; - } - } - } - } -} - -impl Zone { - pub fn pci_init( - &mut self, - pci_config: &HvPciConfig, - num_pci_devs: usize, - alloc_pci_devs: &[u64; CONFIG_MAX_PCI_DEV], - ) { - if num_pci_devs == 0 { - return; - } - - info!("PCIe init!"); - - let mut hv_addr_prefix: u64 = 0; - let mut loong_ht_prefix: u64 = 0; - let mut bdf_shift: usize = 12; - - #[cfg(all(target_arch = "loongarch64"))] - { - info!("change bdf shift to 8 for loongson"); - bdf_shift = 8; - /* turn to virtual address and add 0xe prefix for HT accessing */ - hv_addr_prefix = 0x8000_0000_0000_0000; - loong_ht_prefix = 0xe00_0000_0000 - } - - init_bdf_shift(bdf_shift); - - init_ecam_base((pci_config.ecam_base + hv_addr_prefix + loong_ht_prefix) as _); - - info!("PCIe ECAM base: {:#x}", get_ecam_base()); - - for idx in 0..num_pci_devs { - info!( - "PCIe device assigned to zone {}: {:#x}:{:#x}.{:#x}", - self.id, - alloc_pci_devs[idx] >> 8, - (alloc_pci_devs[idx] >> 3) & 0b11111, - alloc_pci_devs[idx] & 0b111 - ); - self.pciroot.alloc_devs.push(alloc_pci_devs[idx] as _); - #[cfg(all(feature = "iommu", target_arch = "aarch64"))] - if alloc_pci_devs[idx] != 0 { - iommu_add_device(self.id, alloc_pci_devs[idx] as _); - } - } - - if self.id == 0 { - self.root_pci_init(pci_config, hv_addr_prefix, loong_ht_prefix); - } else { - self.virtual_pci_mmio_init(pci_config, hv_addr_prefix, loong_ht_prefix); - } - self.virtual_pci_device_init(pci_config); - } - - pub fn root_pci_init( - &mut self, - pci_config: &HvPciConfig, - hv_addr_prefix: u64, - loong_ht_prefix: u64, - ) { - // Virtual ECAM - - self.mmio_region_register( - pci_config.ecam_base as _, - pci_config.ecam_size as _, - mmio_pci_handler, - (pci_config.ecam_base + hv_addr_prefix + loong_ht_prefix) as _, - ); - - // self.gpm.insert(MemoryRegion::new_with_offset_mapper( - // pci_config.ecam_base as GuestPhysAddr, - // (pci_config.ecam_base + loong_ht_prefix) as _, - // pci_config.ecam_size as _, - // MemFlags::READ | MemFlags::WRITE | MemFlags::IO, - // )) - // .ok(); - - info!( - "pci handler args : {:#x}", - pci_config.ecam_base + hv_addr_prefix + loong_ht_prefix - ); - - if pci_config.io_size != 0 { - self.gpm - .insert(MemoryRegion::new_with_offset_mapper( - pci_config.io_base as GuestPhysAddr, - pci_config.io_base as _, - pci_config.io_size as _, - MemFlags::READ | MemFlags::WRITE | MemFlags::IO, - )) - .ok(); - } - - if pci_config.mem32_size != 0 { - self.gpm - .insert(MemoryRegion::new_with_offset_mapper( - pci_config.mem32_base as GuestPhysAddr, - pci_config.mem32_base as _, - pci_config.mem32_size as _, - MemFlags::READ | MemFlags::WRITE | MemFlags::IO, - )) - .ok(); - } - - if pci_config.mem64_size != 0 { - self.gpm - .insert(MemoryRegion::new_with_offset_mapper( - pci_config.mem64_base as GuestPhysAddr, - pci_config.mem64_base as _, - pci_config.mem64_size as _, - MemFlags::READ | MemFlags::WRITE | MemFlags::IO, - )) - .ok(); - } - } - - //probe pci mmio - pub fn virtual_pci_mmio_init( - &mut self, - pci_config: &HvPciConfig, - hv_addr_prefix: u64, - loong_ht_prefix: u64, - ) { - self.mmio_region_register( - pci_config.ecam_base as _, - pci_config.ecam_size as _, - mmio_pci_handler, - (pci_config.ecam_base + hv_addr_prefix + loong_ht_prefix) as _, - ); - - if pci_config.io_size != 0 { - self.mmio_region_register( - pci_config.io_base as _, - pci_config.io_size as _, - mmio_pci_bar_handler, - (pci_config.io_base + hv_addr_prefix) as _, - ); - } - - if pci_config.mem32_size != 0 { - self.mmio_region_register( - pci_config.mem32_base as _, - pci_config.mem32_size as _, - mmio_pci_bar_handler, - (pci_config.mem32_base + hv_addr_prefix) as _, - ); - } - - if pci_config.mem64_size != 0 { - self.mmio_region_register( - pci_config.mem64_base as _, - pci_config.mem64_size as _, - mmio_pci_bar_handler, - (pci_config.mem64_base + hv_addr_prefix) as _, - ); - } - - info!("PCIe MMIO init done!"); - } - - pub fn virtual_pci_device_init(&mut self, pci_config: &HvPciConfig) { - for bdf in self.pciroot.alloc_devs.clone() { - if bdf != 0 { - let base = cfg_base(bdf) + 0xe; - let header_val = unsafe { ptr::read_volatile(base as *mut u8) }; - match header_val & 0b1111111 { - 0b0 => self.pciroot.endpoints.push(EndpointConfig::new(bdf)), - 0b1 => self.pciroot.bridges.push(BridgeConfig::new(bdf)), - _ => error!( - "bdf {:#x} unsupported device type: {}!", - bdf, - header_val & 0b1111111 - ), - }; - } else { - // host bridge - self.pciroot.bridges.push(BridgeConfig::new(bdf)); - } - } - - trace!("pciroot = {:?}", self.pciroot); - self.pciroot.bars_register(); - if self.id != 0 { - self.pci_bars_register(pci_config); - } - self.pciroot.generate_vdevs(); - } - - fn pci_bars_register(&mut self, pci_config: &HvPciConfig) { - for region in self.pciroot.bar_regions.iter_mut() { - let (cpu_base, pci_base) = match region.bar_type { - BarType::IO => (pci_config.io_base as usize, pci_config.pci_io_base as usize), - BarType::Mem32 => ( - pci_config.mem32_base as usize, - pci_config.pci_mem32_base as usize, - ), - BarType::Mem64 => ( - pci_config.mem64_base as usize, - pci_config.pci_mem64_base as usize, - ), - _ => panic!("Unknown BAR type!"), - }; - - region.start = cpu_base + region.start - pci_base; - region.start = align_down(region.start); - - info!( - "pci bar region: type: {:?}, base: {:#x}, size:{:#x}", - region.bar_type, region.start, region.size - ); - - self.gpm - .insert(MemoryRegion::new_with_offset_mapper( - region.start as GuestPhysAddr, - region.start, - region.size, - MemFlags::READ | MemFlags::WRITE | MemFlags::IO, - )) - .ok(); - } - } -} - -pub fn mmio_pci_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { - // info!("mmio pci: {:#x}", mmio.address); - let zone = this_zone(); - let mut binding = zone.write(); - let zone_id = binding.id; - - let reg_addr = extract_reg_addr(mmio.address); - let bdf_shift = get_bdf_shift(); - let bdf = (mmio.address >> bdf_shift) & 0xffff; - let bus = (mmio.address >> 8) & 0xff; - let dev = (mmio.address >> 3) & 0x1f; - let func = mmio.address & 0x7; - - let is_assigned = binding.pciroot.is_assigned_device(bdf); - let is_bridge = binding.pciroot.is_bridge(bdf); - - match is_assigned { - true => { - mmio_perform_access(base, mmio); - if bus == 6 && reg_addr == 0x150 && !mmio.is_write { - // assume pcie network card is in bus 6(X4 slot in 3A6000 board), this will skip it's sriov - mmio.value = mmio.value & 0x00ffffff; - mmio.value += 0x1a000000; - } - // if (reg_addr >= CFG_EXT_CAP_PTR_OFF) && !is_bridge { - // mmio.value = match binding.pciroot.endpoints.iter().find(|&ep| ep.bdf == bdf) { - // Some(ep) => ep.skip_sriov(mmio.value), - // None => { - // error!("Endpoint {:x}:{:x}.{:x} doesn't exist!", bdf >> 8, (bdf >> 3) &0b11111, bdf & 0b111); - // mmio.value - // } - // } - // } - return Ok(()); - } - false => { - let header_addr = cfg_base(bdf); - let header_val = unsafe { ptr::read_volatile(header_addr as *mut u32) }; - if header_val == 0xffffffffu32 || header_val == 0 { - if reg_addr == 0 && mmio.is_write == false { - mmio.value = header_val as _; - return Ok(()); - } else { - panic!("invalid access to empty device {:x}:{:x}.{:x}, addr: {:#x}, reg_addr: {:#x}!", bdf >> 8, (bdf >> 3) & 0b11111, bdf & 0b111, mmio.address, reg_addr); - } - } else { - // device exists, so we try to get the phantom device - let pdev = match binding - .pciroot - .phantom_devs - .iter_mut() - .find(|dev| dev.bdf == bdf) - { - Some(dev) => dev, - None => { - let new_dev = find_phantom_dev(bdf); - binding.pciroot.phantom_devs.push(new_dev); - binding - .pciroot - .phantom_devs - .iter_mut() - .find(|dev| dev.bdf == bdf) - .unwrap() - } - }; - pdev.phantom_mmio_handler(mmio, base, zone_id) - } - } - } -} - -pub fn mmio_pci_bar_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { - panic!("mmio pci bar: {:#x}", mmio.address + base); - mmio_perform_access(base, mmio); - Ok(()) -} diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs new file mode 100644 index 00000000..4f4c96a4 --- /dev/null +++ b/src/pci/pci_access.rs @@ -0,0 +1,1034 @@ +#![allow(dead_code)] +use core::{ + fmt::Debug, + ops::{Index, IndexMut}, +}; + +use alloc::string::String; +use bit_field::BitField; +use bitflags::bitflags; +use core::slice; + +use crate::{ + error::HvResult, + memory::{GuestPhysAddr, HostPhysAddr, MMIOAccess, MemFlags, MemoryRegion}, + percpu::this_zone, + zone::Zone, +}; + +use super::{ + pci_mem::{PciRegion, PciRegionMmio}, + pci_struct::Bdf, + PciConfigAddress, +}; + +pub trait PciRW: Debug + Send + Sync { + fn read(&self, offset: PciConfigAddress, size: usize) -> HvResult; + fn write(&self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult; +} + +pub type VendorId = u16; +pub type DeviceId = u16; +pub type DeviceRevision = u8; +pub type BaseClass = u8; +pub type SubClass = u8; +pub type Interface = u8; +pub type SubsystemId = u16; +pub type SubsystemVendorId = u16; +pub type InterruptLine = u8; +pub type InterruptPin = u8; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum HeaderType { + Endpoint, + PciBridge, + CardBusBridge, + Unknown(u8), +} + +bitflags! { + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + pub struct PciStatus: u16 { + const DETECTED_PARITY_ERROR = 1 << 15; + const SIGNALED_SYSTEM_ERROR = 1 << 14; + const RECEIVED_MASTER_ABORT = 1 << 13; + const RECEIVED_TARGET_ABORT = 1 << 12; + const SIGNALED_TARGET_ABORT = 1 << 11; + const DEVSEL_MASK = 0b11 << 9; + const MASTER_PARITY_ERROR = 1 << 8; + const FAST_BACK_TO_BACK = 1 << 7; + // resersed bit 6 + const CAP_66MHZ = 1 << 5; + const CAPABILITIES_LIST = 1 << 4; + const INTERRUPT_STATUS = 1 << 3; + // resersed bit 0-2 + const _ = !0; + } +} + +bitflags::bitflags! { + #[derive(Debug, Clone, Copy, PartialEq, Eq)] + pub struct PciCommand: u16 { + const IO_ENABLE = 1 << 0; + const MEMORY_ENABLE = 1 << 1; + const BUS_MASTER_ENABLE = 1 << 2; + const SPECIAL_CYCLE_ENABLE = 1 << 3; + const MEMORY_WRITE_AND_INVALIDATE = 1 << 4; + const VGA_PALETTE_SNOOP = 1 << 5; + const PARITY_ERROR_RESPONSE = 1 << 6; + const IDSEL_STEP_WAIT_CYCLE_CONTROL = 1 << 7; + const SERR_ENABLE = 1 << 8; + const FAST_BACK_TO_BACK_ENABLE = 1 << 9; + const INTERRUPT_DISABLE = 1 << 10; + const _ = !0; + } +} + +#[derive(Default, Clone, Copy, PartialEq, Eq)] +pub enum PciMemType { + Mem32, + Mem64High, + Mem64Low, + Io, + Rom, + #[default] + Unused, +} + +impl Debug for PciMemType { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + PciMemType::Mem32 => write!(f, "Mem32"), + PciMemType::Mem64High => write!(f, "Mem64High"), + PciMemType::Mem64Low => write!(f, "Mem64Low"), + PciMemType::Io => write!(f, "IO"), + PciMemType::Unused => write!(f, "Unused"), + PciMemType::Rom => write!(f, "Rom"), + } + } +} + +/* PciMem + * virtaul_value: the vaddr guset zone can rw, same with as the corresponding value in virtualconfigspace.space + * value: the paddr which hvisor and hw can rw, init when hvisor init the pci bus + * size: the size of mem region, when size_read is true return !(size - 1) + * size_read: if software write 0xffff_ffff to bar, size_read will set so next time hvisor can rerturn !(size - 1) indicating size to the software + */ +#[derive(Default, Clone, Copy)] +pub struct PciMem { + bar_type: PciMemType, + virtual_value: u64, + value: u64, + size: u64, + prefetchable: bool, + size_read: bool, +} + +impl PciMem { + pub fn new_bar(bar_type: PciMemType, value: u64, size: u64, prefetchable: bool) -> Self { + Self { + bar_type, + virtual_value: 0, + value, + size, + prefetchable, + size_read: false, + } + } + + pub fn new_io(value: u64) -> Self { + Self { + bar_type: PciMemType::Io, + virtual_value: 0, + value, + size: 0, + prefetchable: false, + size_read: false, + } + } + + pub fn init(value: u64, size: u64) -> Self { + Self { + bar_type: PciMemType::Unused, + virtual_value: 0, + value, + size, + prefetchable: false, + size_read: false, + } + } + + pub fn new_rom(value: u64, size: u64) -> Self { + Self { + bar_type: PciMemType::Rom, + virtual_value: 0, + value, + size, + prefetchable: false, + size_read: false, + } + } + + pub fn get_size(&self) -> u64 { + self.size + } + + pub fn get_size_with_flag(&mut self) -> u64 { + match self.bar_type { + PciMemType::Mem32 | PciMemType::Rom => !(self.size - 1u64), + PciMemType::Mem64Low => { + let bar_size = !(self.size - 1); + bar_size.get_bits(0..32) + } + PciMemType::Mem64High => { + let bar_size = !(self.size - 1); + bar_size.get_bits(32..64) >> 32 + } + PciMemType::Unused => { + /* for unused bar, size is 0 + */ + 0 + } + _ => { + warn!("{:#?} not support size", self.bar_type); + 0 + } + } + } + + pub fn is_enabled(&self) -> bool { + if self.bar_type == PciMemType::default() { + false + } else { + true + } + } + + /* the longest of mmio read is 32 */ + pub fn get_value(&self) -> u32 { + match self.bar_type { + PciMemType::Mem64High => (self.value >> 32) as u32, + _ => self.value as u32, + } + } + + /* when update map of bar region, + * need to read u64 to get whole address + * the virtual_value is same with value + */ + pub fn get_value64(&self) -> u64 { + self.value as u64 + } + + /* Automatically add flags */ + pub fn set_value(&mut self, address: u64) { + let mut val = address; + + match self.bar_type { + PciMemType::Io => { + // bit0 = 1 + val |= 0x1; + } + PciMemType::Mem32 => { + // bit1..2 = 00 + val &= !0x6; + if self.prefetchable { + val |= 0x8; + } + } + PciMemType::Mem64Low | PciMemType::Mem64High => { + // bit1..=2 = 0b10 + val &= !0x6; + val |= 0x4; + if self.prefetchable { + val |= 0x8; + } + } + _ => {} + } + + self.value = val; + } + + pub fn get_type(&self) -> PciMemType { + self.bar_type + } + + pub fn get_prefetchable(&self) -> bool { + self.prefetchable + } + + pub fn set_size_read(&mut self) { + self.size_read = true; + } + + pub fn clear_size_read(&mut self) { + self.size_read = false; + } + + pub fn get_size_read(&self) -> bool { + self.size_read + } + + pub fn get_virtual_value(&self) -> u32 { + match self.bar_type { + PciMemType::Mem64High => (self.virtual_value >> 32) as u32, + _ => self.virtual_value as u32, + } + } + + pub fn get_virtual_value64(&self) -> u64 { + self.virtual_value + } + + pub fn set_virtual_value(&mut self, address: u64) { + let mut val = address; + + match self.bar_type { + PciMemType::Io => { + // bit0 = 1 + val |= 0x1; + } + PciMemType::Mem32 => { + // bit1..2 = 00 + val &= !0x6; + if self.prefetchable { + val |= 0x8; + } + } + PciMemType::Mem64Low | PciMemType::Mem64High => { + // bit1..=2 = 0b10 + val &= !0x6; + val |= 0x4; + if self.prefetchable { + val |= 0x8; + } + } + _ => {} + } + + self.virtual_value = val; + } +} + +impl Debug for PciMem { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self.bar_type { + PciMemType::Mem32 => { + let pre = if self.prefetchable { "pre" } else { "" }; + let paddr = self.value & !0xf; + let vaddr = self.virtual_value & !0xf; + let size = self.size; + write!( + f, + "[{:#?} 0x{:x}-0x{:x} {}] => [0x{:x}-0x{:x}]", + self.bar_type, + paddr, + paddr + size, + pre, + vaddr, + vaddr + size + ) + } + PciMemType::Mem64Low | PciMemType::Mem64High => { + let pre = if self.prefetchable { "pre" } else { "" }; + let paddr = self.value & !0xf; + let vaddr = self.virtual_value & !0xf; + let size = self.size; + write!( + f, + "[{:#?} 0x{:x} size 0x{:x} 64bit {}] => [0x{:x}-0x{:x}]", + self.bar_type, + paddr, + paddr + size, + pre, + vaddr, + vaddr + size + ) + } + _ => { + write!(f, "[{:#?}]", self.bar_type) + } + } + } +} + +#[derive(Clone, Copy, Default)] +pub struct Bar { + bararr: [PciMem; 6], +} + +impl Index for Bar { + type Output = PciMem; + + fn index(&self, index: usize) -> &Self::Output { + &self.bararr[index] + } +} + +impl IndexMut for Bar { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.bararr[index] + } +} + +impl<'a> IntoIterator for &'a Bar { + type Item = &'a PciMem; + type IntoIter = slice::Iter<'a, PciMem>; + + fn into_iter(self) -> Self::IntoIter { + self.bararr.iter() + } +} + +impl<'a> IntoIterator for &'a mut Bar { + type Item = &'a mut PciMem; + type IntoIter = slice::IterMut<'a, PciMem>; + + fn into_iter(self) -> Self::IntoIter { + self.bararr.iter_mut() + } +} + +impl Debug for Bar { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "BARs [")?; + let mut i = 0; + let mut is_null = true; + while i < self.bararr.len() { + let bar = &self.bararr[i]; + let address = bar.value & !0xf; + // let address = bar.value; + match bar.bar_type { + PciMemType::Mem32 => { + is_null = false; + write!( + f, + "\n slot {} [mem 0x{:x}-0x{:x}", + i, + address, + address + bar.size + )?; + if bar.prefetchable { + write!(f, " pre")?; + } + write!(f, "]")?; + } + PciMemType::Mem64Low => { + is_null = false; + write!( + f, + "\n slot {} [mem 0x{:x}-0x{:x} 64bit", + i, + address, + address + bar.size + )?; + if bar.prefetchable { + write!(f, " pre")?; + } + write!(f, "]")?; + i += 1; + } + PciMemType::Io => { + writeln!(f, " IO @ 0x{:x}", bar.value)?; + } + _ => {} + } + i += 1; + } + if is_null { + writeln!(f, "]") + } else { + write!(f, "\n]") + } + } +} + +/* 32 16 0 + * +-----------------------------+------------------------------+ + * | Device ID | Vendor ID | 0x00 + * | | | + * +-----------------------------+------------------------------+ + * | Status | Command | 0x04 + * | | | + * +-----------------------------+---------------+--------------+ + * | Class Code | Revision | 0x08 + * | | ID | + * +--------------+--------------+---------------+--------------+ + * | BIST | Header | Latency | Cacheline | 0x0c + * | | type | timer | size | + * +--------------+--------------+---------------+--------------+ + */ +#[derive(Debug, Clone)] +pub struct PciConfigHeader(PciRegionMmio); + +macro_rules! impl_pci_rw { + ($ty:ty) => { + impl PciRW for $ty { + fn read(&self, offset: PciConfigAddress, size: usize) -> HvResult { + match size { + 1 => self.0.read_u8(offset).map(|v| v as usize), + 2 => self.0.read_u16(offset).map(|v| v as usize), + 4 => self.0.read_u32(offset).map(|v| v as usize), + _ => { + hv_result_err!(EFAULT, "pci: invalid mmio read size: {size}") + } + } + } + fn write(&self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { + match size { + 1 => self.0.write_u8(offset, value as u8), + 2 => self.0.write_u16(offset, value as u16), + 4 => self.0.write_u32(offset, value as u32), + _ => { + hv_result_err!(EFAULT, "pci: invalid mmio write size: {size}") + } + } + } + } + }; +} + +macro_rules! impl_pci_header { + ($ty:ty) => { + impl $ty { + pub fn id(&self) -> (DeviceId, VendorId) { + let id = self.0.read_u32(0x00).unwrap(); + ( + id.get_bits(0..16) as VendorId, + id.get_bits(16..32) as DeviceId, + ) + } + + pub fn header_type(&self) -> HeaderType { + match self.0.read_u8(0x0e).unwrap().get_bits(0..7) { + 0x00 => HeaderType::Endpoint, + 0x01 => HeaderType::PciBridge, + 0x02 => HeaderType::CardBusBridge, + v => HeaderType::Unknown(v as u8), + } + } + + pub fn has_multiple_functions(&self) -> bool { + self.0.read_u8(0x0c).unwrap().get_bit(7) + } + + pub fn revision_and_class(&self) -> (DeviceRevision, BaseClass, SubClass, Interface) { + let value = self.0.read_u32(0x08).unwrap(); + ( + value.get_bits(0..8) as DeviceRevision, + value.get_bits(24..32) as BaseClass, + value.get_bits(16..24) as SubClass, + value.get_bits(8..16) as Interface, + ) + } + + pub fn status(&self) -> PciStatus { + let status = self.0.read_u16(0x06).unwrap(); + PciStatus::from_bits_truncate(status) + } + + pub fn command(&self) -> PciCommand { + let command = self.0.read_u16(0x04).unwrap(); + PciCommand::from_bits_truncate(command) + } + + pub fn update_command(&mut self, f: F) + where + F: FnOnce(PciCommand) -> PciCommand, + { + let mut data = self.0.read_u16(0x04).unwrap(); + let new_command = f(PciCommand::from_bits_retain(data.get_bits(0..16))); + data.set_bits(0..16, new_command.bits()); + let _ = self.0.write_u16(0x04, data); + } + } + }; +} + +impl_pci_rw!(PciConfigHeader); +impl_pci_header!(PciConfigHeader); + +impl PciConfigHeader { + pub fn new_with_region(region: PciRegionMmio) -> Self { + PciConfigHeader(region) + } +} + +/* 32 16 0 + * +-----------------------------------------------------------+ 0x00 + * | | + * | Predefined region of header | + * | | + * | | + * +-----------------------------------------------------------+ + * | Base Address Register 0 | 0x10 + * | | + * +-----------------------------------------------------------+ + * | Base Address Register 1 | 0x14 + * | | + * +-----------------------------------------------------------+ + * | Base Address Register 2 | 0x18 + * | | + * +-----------------------------------------------------------+ + * | Base Address Register 3 | 0x1c + * | | + * +-----------------------------------------------------------+ + * | Base Address Register 4 | 0x20 + * | | + * +-----------------------------------------------------------+ + * | Base Address Register 5 | 0x24 + * | | + * +-----------------------------------------------------------+ + * | CardBus CIS Pointer | 0x28 + * | | + * +----------------------------+------------------------------+ + * | Subsystem ID | Subsystem vendor ID | 0x2c + * | | | + * +----------------------------+------------------------------+ + * | Expansion ROM Base Address | 0x30 + * | | + * +--------------------------------------------+--------------+ + * | Reserved | Capabilities | 0x34 + * | | Pointer | + * +--------------------------------------------+--------------+ + * | Reserved | 0x38 + * | | + * +--------------+--------------+--------------+--------------+ + * | Max_Lat | Min_Gnt | Interrupt | Interrupt | 0x3c + * | | | pin | line | + * +--------------+--------------+--------------+--------------+ + */ +pub enum EndpointField { + ID, + Command, + Status, + RevisionIDAndClassCode, + CacheLineSize, + LatencyTime, + HeaderType, + Bist, + Bar, + CardCisPointer, + SubsystemVendorId, + SubsystemId, + ExpansionRomBar, + CapabilitiesPointer, + InterruptLine, + InterruptPin, + MinGnt, + MaxLat, + Unknown(usize), +} + +impl EndpointField { + pub fn from(offset: usize, size: usize) -> Self { + match (offset, size) { + (0x00, 4) => EndpointField::ID, + (0x04, 2) => EndpointField::Command, + (0x06, 2) => EndpointField::Status, + (0x08, 4) => EndpointField::RevisionIDAndClassCode, + (0x0c, 1) => EndpointField::CacheLineSize, + (0x0d, 1) => EndpointField::LatencyTime, + (0x0e, 1) => EndpointField::HeaderType, + (0x0f, 1) => EndpointField::Bist, + (0x10, 4) | (0x14, 4) | (0x18, 4) | (0x1c, 4) | (0x20, 4) | (0x24, 4) => { + EndpointField::Bar + } + (0x28, 4) => EndpointField::CardCisPointer, + (0x2c, 2) => EndpointField::SubsystemVendorId, + (0x2e, 2) => EndpointField::SubsystemId, + (0x30, 4) => EndpointField::ExpansionRomBar, + (0x34, 4) => EndpointField::CapabilitiesPointer, + (0x3c, 1) => EndpointField::InterruptLine, + (0x3d, 1) => EndpointField::InterruptPin, + (0x3e, 1) => EndpointField::MinGnt, + (0x3f, 1) => EndpointField::MaxLat, + (x, _) => EndpointField::Unknown(x), + } + } +} + +#[derive(Debug, Clone)] +pub struct EndpointHeader(PciRegionMmio); + +impl_pci_rw!(EndpointHeader); +impl_pci_header!(EndpointHeader); + +impl EndpointHeader { + pub fn new_with_region(region: PciRegionMmio) -> Self { + EndpointHeader(region) + } + + pub fn parse_bar(&self) -> Bar { + let mut bararr = Bar::default(); + + let mut slot = 0u8; + while slot < 6 { + let value = self.read_bar(slot).unwrap(); + + if !value.get_bit(0) { + let pre = value.get_bit(3); + + match value.get_bits(1..3) { + 0b00 => { + let size = { + let _ = self.write_bar(slot, 0xfffffff0); + let mut readback = self.read_bar(slot).unwrap(); + let _ = self.write_bar(slot, readback as u32); + + if readback == 0x0 { + // bar is null + slot += 1; + continue; + } + readback.set_bits(0..4, 0); + 1 << readback.trailing_zeros() + }; + bararr[slot as usize] = + PciMem::new_bar(PciMemType::Mem32, value as u64, size as u64, pre); + } + 0b10 => { + if slot == 5 { + warn!("read bar64 in last bar"); + break; + } + + let value_high = self.read_bar(slot + 1).unwrap(); + let size = { + let _ = self.write_bar(slot, 0xfffffff0); + let _ = self.write_bar(slot + 1, 0xfffffff0); + let mut readback_low = self.read_bar(slot).unwrap(); + let readback_high = self.read_bar(slot + 1).unwrap(); + let _ = self.write_bar(slot, readback_low as u32); + let _ = self.write_bar(slot + 1, readback_high as u32); + + readback_low.set_bits(0..4, 0); + + if readback_low != 0 { + (1 << readback_low.trailing_zeros()) as u64 + } else { + 1u64 << ((readback_high.trailing_zeros() + 32) as u64) + } + }; + bararr[slot as usize] = + PciMem::new_bar(PciMemType::Mem64Low, value as u64, size, pre); + bararr[(slot + 1) as usize] = + PciMem::new_bar(PciMemType::Mem64High, value_high as u64, size, pre); + slot += 1; // need extra add 1 + } + _ => { + warn!("unknown bar type"); + } + } + } else { + bararr[slot as usize] = PciMem::new_io(value as u64); + } + slot += 1; + } + bararr + } + + pub fn read_bar(&self, slot: u8) -> HvResult { + // println!("read bar slot {}", slot); + self.0 + .read_u32((0x10 + (slot as u16) * 4) as PciConfigAddress) + .map(|r| r as usize) + } + + pub fn write_bar(&self, slot: u8, value: u32) -> HvResult { + // println!("write bar slot {} {}", slot, value); + self.0 + .write_u32((0x10 + (slot as u16) * 4) as PciConfigAddress, value) + } + + pub fn parse_rom(&self) -> PciMem { + let offset = 0x30; + let value = self.0.read_u32(offset).unwrap(); + + let size = { + let _ = self.0.write_u32(offset, 0xfffff800); + let mut readback = self.0.read_u32(offset).unwrap(); + let _ = self.0.write_u32(offset, value); + if readback == 0x0 { + return PciMem::default(); + } + readback.set_bits(0..4, 0); + 1 << readback.trailing_zeros() + }; + PciMem::new_rom(value as u64, size) + } +} + +/* 32 16 0 + * +-----------------------------------------------------------+ 0x00 + * | | + * | Predefined region of header | + * | | + * | | + * +-----------------------------------------------------------+ + * | Base Address Register 0 | 0x10 + * | | + * +-----------------------------------------------------------+ + * | Base Address Register 1 | 0x14 + * | | + * +--------------+--------------+--------------+--------------+ + * | Secondary | Subordinate | Secondary | Primary Bus | 0x18 + * |Latency Timer | Bus Number | Bus Number | Number | + * +--------------+--------------+--------------+--------------+ + * | Secondary Status | I/O Limit | I/O Base | 0x1C + * | | | | + * +-----------------------------+--------------+--------------+ + * | Memory Limit | Memory Base | 0x20 + * | | | + * +-----------------------------+-----------------------------+ + * | Prefetchable Memory Limit | Prefetchable Memory Base | 0x24 + * | | | + * +-----------------------------+-----------------------------+ + * | Prefetchable Base Upper 32 Bits | 0x28 + * | | + * +-----------------------------------------------------------+ + * | Prefetchable Limit Upper 32 Bits | 0x2C + * | | + * +-----------------------------+-----------------------------+ + * | I/O Limit Upper 16 Bits | I/O Base Upper 16 Bits | 0x30 + * | | | + * +-----------------------------+--------------+--------------+ + * | Reserved | Capability | 0x34 + * | | Pointer | + * +--------------------------------------------+--------------+ + * | Expansion ROM base address | 0x38 + * | | + * +-----------------------------+--------------+--------------+ + * | Bridge Control | Interrupt | Interrupt | 0x3C + * | | PIN | Line | + * +-----------------------------+--------------+--------------+ + */ +#[derive(Debug, Clone)] +pub struct PciBridgeHeader(PciRegionMmio); + +impl_pci_rw!(PciBridgeHeader); +impl_pci_header!(PciBridgeHeader); + +impl PciBridgeHeader { + pub fn new_with_region(region: PciRegionMmio) -> Self { + PciBridgeHeader(region) + } +} + +impl PciBridgeHeader {} + +pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { + let offset = (mmio.address & 0xfff) as PciConfigAddress; + let vbdf = Bdf::from_address(mmio.address as u64); + let size = mmio.size; + let value = mmio.value; + + let zone = this_zone(); + let mut guard = zone.write(); + let (vbus, gpm) = { + let Zone { gpm, vpci_bus, .. } = &mut *guard; + (vpci_bus, gpm) + }; + + let mut dev = None; + for node in vbus.devs().iter_mut() { + if node.1.get_vbdf() == vbdf { + debug!("vbdf find {:#?}", vbdf); + dev = Some(node.1); + break; + } + } + + if let Some(dev) = dev { + match dev.access(offset, size) { + false => { + debug!( + "hw vbdf {:#?} reg 0x{:x} try {} {}", + vbdf, + offset, + if mmio.is_write { "write" } else { "read" }, + if mmio.is_write { + format!(" 0x{:x}", mmio.value) + } else { + String::new() + } + ); + if mmio.is_write { + dev.write_hw(offset, size, value)?; + } else { + mmio.value = dev.read_hw(offset, size).unwrap(); + } + } + true => { + debug!( + "emu vbdf {:#?} reg 0x{:x} try {} {}", + vbdf, + offset, + if mmio.is_write { "write" } else { "read" }, + if mmio.is_write { + format!(" 0x{:x}", mmio.value) + } else { + String::new() + } + ); + match dev.get_config_type() { + HeaderType::Endpoint => { + match EndpointField::from(offset as usize, size) { + EndpointField::Bar => { + let slot = ((offset - 0x10) / 4) as usize; + /* the write of bar needs to start from dev, + * where the bar variable here is just a copy + */ + let bar = &mut dev.get_bararr()[slot]; + let bar_type = bar.get_type(); + if bar_type != PciMemType::default() { + if mmio.is_write { + if (value & 0xfffffff0) == 0xfffffff0 { + dev.set_bar_size_read(slot); + } else { + let _ = dev.write_emu(offset, size, value); + /* for mem64, Mem64High always write after Mem64Low, + * so update bar when write Mem64High + */ + if (bar_type == PciMemType::Mem32) + | (bar_type == PciMemType::Mem64High) + { + let old_vaddr = bar.get_virtual_value64() & &!0xf; + let new_vaddr = { + if bar_type == PciMemType::Mem64High { + /* last 4bit is flag, not address and need ignore + * flag will auto add when set_value and set_virtual_value + */ + dev.read_emu64(offset - 0x4).unwrap() & !0xf + } else { + (value as u64) & !0xf + } + }; + /* Linux traverses the PCI bus twice. During the first traversal, + * it does not assign addresses to the BARs; it simply writes back the same + * values. In the second traversal, it reorders the BARs and assigns + * addresses to them. If address allocation is performed during the first + * traversal, then in the second traversal conflicts may occur between the + * current BAR addresses and other BAR addresses that have not yet been updated. + * When the new and old values are the same, it indicates the first traversal, + * and no address remapping is performed. Only when the addresses are actually + * modified will remapping take place. + * + * This issue also leads to the hypervisor not fully supporting PCIe bus hot-reload: + * if the number of devices changes before and after the reload, address conflicts + * may also occur. + */ + if old_vaddr != new_vaddr { + if !gpm + .try_delete(old_vaddr.try_into().unwrap()) + .is_ok() + { + /* The first delete from the guest will fail + * because the region has not yet been inserted + */ + warn!( + "delete bar {}: can not found 0x{:x}", + slot, old_vaddr + ); + } + let paddr = bar.get_value64(); + debug!( + "old_vaddr {:x} new_vaddr {:x} paddr {:x}", + old_vaddr, new_vaddr, paddr + ); + + dev.set_bar_virtual_value(slot, new_vaddr); + if bar_type == PciMemType::Mem64High { + dev.set_bar_virtual_value( + slot - 1, + new_vaddr, + ); + } + + gpm.insert( + MemoryRegion::new_with_offset_mapper( + new_vaddr as GuestPhysAddr, + paddr as HostPhysAddr, + bar.get_size() as _, + MemFlags::READ | MemFlags::WRITE, + ), + )?; + /* after update gpm, mem barrier is needed */ + unsafe { + core::arch::asm!("isb"); + core::arch::asm!("tlbi vmalls12e1is"); + core::arch::asm!("dsb nsh"); + } + } + } + } + } else { + mmio.value = if bar.get_size_read() { + let r = bar.get_size_with_flag().try_into().unwrap(); + dev.clear_bar_size_read(slot); + r + } else { + bar.get_virtual_value().try_into().unwrap() + }; + } + } else { + mmio.value = 0; + } + } + EndpointField::ExpansionRomBar => { + let mut rom = dev.get_rom(); + if mmio.is_write { + if (mmio.value & 0xfffff800) == 0xfffff800 { + rom.set_size_read(); + } else { + // let old_vaddr = dev.read_emu(offset, size).unwrap() as u64; + let _ = dev.write_emu(offset, size, value); + // TODO: add gpm change for rom + } + } else { + mmio.value = if rom.get_size_read() { + dev.read_emu(offset, size).unwrap() + } else { + rom.get_size_with_flag().try_into().unwrap() + }; + } + } + _ => {} + } + } + HeaderType::PciBridge => { + // TODO: add emu for bridge, actually it is same with endpoint + } + _ => { + warn!("unhanled pci type {:#?}", dev.get_config_type()); + } + } + } + } + } else { + debug!("not found dev"); + /* if the dev is None, just return 0xFFFF_FFFF when read ID */ + if !mmio.is_write { + match EndpointField::from(offset as usize, size) { + EndpointField::ID => { + mmio.value = 0xFFFF_FFFF; + } + _ => { + warn!("unhandled pci mmio read"); + mmio.value = 0; + } + } + } + } + + debug!( + "vbdf {:#?} reg 0x{:x} {} 0x{:x}", + vbdf, + offset, + if mmio.is_write { "write" } else { "read" }, + mmio.value + ); + + Ok(()) +} diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs new file mode 100644 index 00000000..b3a10d48 --- /dev/null +++ b/src/pci/pci_config.rs @@ -0,0 +1,89 @@ +use alloc::collections::btree_map::BTreeMap; +use spin::{Lazy, Mutex}; + +use crate::{ + config::{HvPciConfig, HvPciDevConfig, CONFIG_MAX_PCI_DEV, CONFIG_PCI_BUS_MAXLEN}, + error::HvResult, + pci::{ + mem_alloc::BaseAllocator, + pci_access::mmio_vpci_handler, + pci_struct::{Bdf, VirtualPciConfigSpace}, + }, + zone::Zone, +}; + +use super::pci_struct::RootComplex; + +pub static GLOBAL_PCIE_LIST: Lazy>> = Lazy::new(|| { + let m = BTreeMap::new(); + Mutex::new(m) +}); + +/* add all dev to GLOBAL_PCIE_LIST */ +pub fn hvisor_pci_init(pci_rootcomplex_config: &[HvPciConfig; CONFIG_PCI_BUS_MAXLEN]) -> HvResult { + for rootcomplex_config in pci_rootcomplex_config { + /* empty config */ + if rootcomplex_config.ecam_base == 0 { + continue; + } + let mut allocator = BaseAllocator::default(); + allocator.set_mem32( + rootcomplex_config.pci_mem32_base as u32, + rootcomplex_config.mem32_size as u32, + ); + allocator.set_mem64( + rootcomplex_config.pci_mem64_base, + rootcomplex_config.mem64_size, + ); + + let mut rootcomplex = RootComplex::new(rootcomplex_config.ecam_base); + for node in rootcomplex.enumerate(None, Some(allocator)) { + GLOBAL_PCIE_LIST.lock().insert(node.get_bdf(), node); + } + } + info!("hvisor pci init \n{:#?}", GLOBAL_PCIE_LIST); + Ok(()) +} + +impl Zone { + pub fn guest_pci_init( + &mut self, + alloc_pci_devs: &[HvPciDevConfig; CONFIG_MAX_PCI_DEV], + num_pci_devs: u64, + ) -> HvResult { + let mut guard = GLOBAL_PCIE_LIST.lock(); + let mut i = 0; + while i < num_pci_devs { + let dev_config = alloc_pci_devs[i as usize]; + let bdf = Bdf::from_address(dev_config.bdf); + let vbdf = Bdf::from_address(dev_config.vbdf); + if let Some(mut vdev) = guard.remove(&bdf) { + vdev.set_vbdf(vbdf); + self.vpci_bus.insert(vbdf, vdev); + } else { + warn!("can not find dev {:#?}", bdf); + } + i += 1; + } + info!("vpci bus init end\n {:#?}", self.vpci_bus); + Ok(()) + } + + pub fn virtual_pci_mmio_init( + &mut self, + pci_rootcomplex_config: &[HvPciConfig; CONFIG_PCI_BUS_MAXLEN], + ) { + for rootcomplex_config in pci_rootcomplex_config { + /* empty config */ + if rootcomplex_config.ecam_base == 0 { + continue; + } + self.mmio_region_register( + rootcomplex_config.ecam_base as usize, + rootcomplex_config.ecam_size as usize, + mmio_vpci_handler, + 0, + ); + } + } +} diff --git a/src/pci/pci_mem.rs b/src/pci/pci_mem.rs new file mode 100644 index 00000000..5b59272a --- /dev/null +++ b/src/pci/pci_mem.rs @@ -0,0 +1,55 @@ +use core::{any::Any, fmt::Debug}; + +use crate::error::HvResult; +use crate::pci::PciConfigAddress; + +pub trait PciRegion: Debug + Sync + Send + Any { + fn read_u8(&self, offset: PciConfigAddress) -> HvResult; + fn write_u8(&self, offset: PciConfigAddress, value: u8) -> HvResult; + fn read_u16(&self, offset: PciConfigAddress) -> HvResult; + fn write_u16(&self, offset: PciConfigAddress, value: u16) -> HvResult; + fn read_u32(&self, offset: PciConfigAddress) -> HvResult; + fn write_u32(&self, offset: PciConfigAddress, value: u32) -> HvResult; +} + +/* in aarch64, config space just like a normal mem space */ +#[derive(Debug, Clone, Copy)] +pub struct PciRegionMmio { + base: PciConfigAddress, + #[allow(dead_code)] + length: u64, +} + +impl PciRegionMmio { + pub fn new(base: PciConfigAddress, length: u64) -> Self { + Self { base, length } + } + /* TODO: may here need check whether length exceeds*/ + fn access(&self, offset: PciConfigAddress) -> *mut T { + (self.base + offset) as *mut T + } +} + +impl PciRegion for PciRegionMmio { + fn read_u8(&self, offset: PciConfigAddress) -> HvResult { + unsafe { Ok(self.access::(offset).read_volatile() as u8) } + } + fn write_u8(&self, offset: PciConfigAddress, value: u8) -> HvResult { + unsafe { self.access::(offset).write_volatile(value) } + Ok(()) + } + fn read_u16(&self, offset: PciConfigAddress) -> HvResult { + unsafe { Ok(self.access::(offset).read_volatile() as u16) } + } + fn write_u16(&self, offset: PciConfigAddress, value: u16) -> HvResult { + unsafe { self.access::(offset).write_volatile(value) } + Ok(()) + } + fn read_u32(&self, offset: PciConfigAddress) -> HvResult { + unsafe { Ok(self.access::(offset).read_volatile() as u32) } + } + fn write_u32(&self, offset: PciConfigAddress, value: u32) -> HvResult { + unsafe { self.access::(offset).write_volatile(value) } + Ok(()) + } +} diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs new file mode 100644 index 00000000..f12e3a00 --- /dev/null +++ b/src/pci/pci_struct.rs @@ -0,0 +1,731 @@ +use core::{ + cmp::Ordering, fmt::Debug, hint::spin_loop, ops::Range, str::FromStr, sync::atomic::AtomicBool, +}; + +use alloc::{boxed::Box, collections::btree_map::BTreeMap, vec::Vec}; +use bit_field::BitField; +use bitvec::{array::BitArray, order::Lsb0, BitArr}; + +use crate::{ + error::{HvErrorNum, HvResult}, + pci::pci_access::Bar, +}; + +use super::{ + mem_alloc::BarAllocator, + pci_access::{ + EndpointField, EndpointHeader, HeaderType, PciBridgeHeader, PciCommand, PciConfigHeader, + PciMem, PciMemType, PciRW, + }, + pci_mem::{PciRegion, PciRegionMmio}, + PciConfigAddress, +}; + +type VirtualPciConfigBits = BitArr!(for BIT_LENTH, in u8, Lsb0); + +const MAX_DEVICE: u8 = 31; +const MAX_FUNCTION: u8 = 7; +pub const CONFIG_LENTH: u64 = 256; +const BIT_LENTH: usize = 256 * 2; + +#[derive(Clone, Copy, Eq, PartialEq, Default)] +pub struct Bdf { + pub bus: u8, + pub device: u8, + pub function: u8, +} + +impl Bdf { + #[allow(dead_code)] + pub fn new(bus: u8, device: u8, function: u8) -> Self { + Self { + bus, + device, + function, + } + } + + #[allow(dead_code)] + pub fn is_zero(&self) -> bool { + if self.bus == 0 && self.device == 0 && self.function == 0 { + return true; + } + false + } + + pub fn from_address(address: PciConfigAddress) -> Self { + let bdf = address >> 12; + let function = (bdf & 0b111) as u8; + let device = ((bdf >> 3) & 0b11111) as u8; + let bus = (bdf >> 8) as u8; + Self { + bus, + device, + function, + } + } + + pub fn to_address(&self, offset: usize) -> PciConfigAddress { + let mut address = offset as PciConfigAddress; + address.set_bits(12..15, self.function as u64); + address.set_bits(15..20, self.device as u64); + address.set_bits(20..28, self.bus as u64); + address + } +} + +impl Ord for Bdf { + fn cmp(&self, other: &Self) -> Ordering { + self.to_address(0).cmp(&other.to_address(0)) + } +} + +impl PartialOrd for Bdf { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl FromStr for Bdf { + type Err = HvErrorNum; + + fn from_str(s: &str) -> Result { + // 0000:00:04.0 + let parts: Vec<&str> = s.split(':').collect(); + if parts.len() != 3 { + return Err(HvErrorNum::EINVAL); + } + + let bus = u8::from_str_radix(parts[1], 16) + .map_err(|_| HvErrorNum::EINVAL) + .unwrap(); + let device_function: Vec<&str> = parts[2].split('.').collect(); + if device_function.len() != 2 { + panic!("Invalid device.function format"); + } + + let device = u8::from_str_radix(device_function[0], 16) + .map_err(|_| HvErrorNum::EINVAL) + .unwrap(); + let function = u8::from_str_radix(device_function[1], 10) + .map_err(|_| HvErrorNum::EINVAL) + .unwrap(); + + Ok(Bdf { + bus, + device, + function, + }) + } +} + +impl Debug for Bdf { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "{:04x}:{:02x}:{:02x}.{}", + 0, self.bus, self.device, self.function + ) + } +} + +/* 0: ro; + * 1: rw + */ +#[derive(Debug, Clone)] +pub struct VirtualPciConfigControl { + bits: VirtualPciConfigBits, +} + +impl VirtualPciConfigControl { + /* 0x0F, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x08, */ + pub fn endpoint() -> Self { + Self { + bits: !BitArray::ZERO, + } + } + + pub fn bridge() -> Self { + Self { + bits: !BitArray::ZERO, + } + } + + pub fn host_bridge() -> Self { + Self { + bits: !BitArray::ZERO, + } + } +} + +/* 0: read hw + * 1: read emu + */ +#[derive(Debug, Clone)] +pub struct VirtualPciAccessBits { + bits: VirtualPciConfigBits, +} + +impl VirtualPciAccessBits { + pub fn endpoint() -> Self { + let mut bits = BitArray::ZERO; + bits[0x10..0x34].fill(true); //bar and rom + Self { bits } + } + + pub fn bridge() -> Self { + Self { + bits: BitArray::ZERO, + } + } + + pub fn host_bridge() -> Self { + Self { + bits: BitArray::ZERO, + } + } +} + +/* VirtualPciConfigSpace + * bdf: the bdf hvisor seeing(same with the bdf without hvisor) + * vbdf: the bdf zone seeing, it can set just you like without sr-iov + * space: the space where emulate the config space + * control: control the satus of rw every bit in config space + * access: Determines whether the variable is read from space or hw + * backend: the hw rw interface + * disabled: not used yet + */ +pub struct VirtualPciConfigSpace { + bdf: Bdf, + vbdf: Bdf, + config_type: HeaderType, + + space: [u8; BIT_LENTH], + control: VirtualPciConfigControl, + access: VirtualPciAccessBits, + + backend: Box, + + bararr: Bar, + rom: PciMem, + + disabled: AtomicBool, +} + +impl VirtualPciConfigSpace { + /* false: some bits ro */ + pub fn writable(&self, offset: PciConfigAddress, size: usize) -> bool { + self.control.bits[offset as usize..offset as usize + size] + .last_zero() + .is_none() + } + + /* false: some bits need read from hw */ + pub fn access(&self, offset: PciConfigAddress, size: usize) -> bool { + self.access.bits[offset as usize..offset as usize + size] + .last_zero() + .is_none() + } + + pub fn get_bararr(&self) -> Bar { + self.bararr + } + + pub fn set_bar_size_read(&mut self, slot: usize) { + self.bararr[slot].set_size_read(); + } + + pub fn set_bar_virtual_value(&mut self, slot: usize, value: u64) { + self.bararr[slot].set_virtual_value(value); + } + + pub fn clear_bar_size_read(&mut self, slot: usize) { + self.bararr[slot].clear_size_read(); + } + + pub fn get_rom(&self) -> PciMem { + self.rom + } + + // TODO: update sapce when first time read value from hw, and next read will more quick + pub fn update_space(&mut self, offset: PciConfigAddress, size: usize, _value: usize) { + match self.get_config_type() { + HeaderType::Endpoint => { + match EndpointField::from(offset as usize, size) { + EndpointField::Bar => { + // let updating_range = offset as usize..offset as usize+ size; + // let bytes = &value.to_le_bytes()[..size]; + // info!("[{:x}-{:x}] bytes {:#?} \n{:x}", updating_range.start, updating_range.end, bytes, value); + // self.space[updating_range.clone()].copy_from_slice(bytes); + // self.access.bits[updating_range].fill(true); + } + _ => {} + } + } + _ => { + warn!("TODO updating space"); + } + } + } +} + +impl Debug for VirtualPciConfigSpace { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "\n bdf {:#?}\n vbdf {:#?}\n type {:#?}\n {:#?}", + self.bdf, self.vbdf, self.config_type, self.bararr + ) + } +} + +impl VirtualPciConfigSpace { + pub fn endpoint(bdf: Bdf, backend: Box, bararr: Bar, rom: PciMem) -> Self { + Self { + bdf, + vbdf: Bdf::default(), + space: [0u8; BIT_LENTH], + control: VirtualPciConfigControl::endpoint(), + access: VirtualPciAccessBits::endpoint(), + config_type: HeaderType::Endpoint, + backend, + bararr, + rom, + disabled: AtomicBool::new(false), + } + } + + pub fn bridge(bdf: Bdf, backend: Box, bararr: Bar) -> Self { + Self { + bdf, + vbdf: Bdf::default(), + space: [0u8; BIT_LENTH], + control: VirtualPciConfigControl::bridge(), + access: VirtualPciAccessBits::bridge(), + config_type: HeaderType::PciBridge, + backend, + bararr, + rom: PciMem::default(), + disabled: AtomicBool::new(false), + } + } + + pub fn unknown(bdf: Bdf, backend: Box) -> Self { + Self { + bdf, + vbdf: Bdf::default(), + space: [0u8; BIT_LENTH], + control: VirtualPciConfigControl::endpoint(), + access: VirtualPciAccessBits::endpoint(), + config_type: HeaderType::Endpoint, + backend, + bararr: Bar::default(), + rom: PciMem::default(), + disabled: AtomicBool::new(false), + } + } + + pub fn host_bridge(bdf: Bdf, backend: Box) -> Self { + Self { + bdf: bdf, + vbdf: bdf, + space: [0u8; BIT_LENTH], + control: VirtualPciConfigControl::host_bridge(), + access: VirtualPciAccessBits::host_bridge(), + config_type: HeaderType::Endpoint, + backend, + bararr: Bar::default(), + rom: PciMem::default(), + disabled: AtomicBool::new(false), + } + } + + pub fn get_bdf(&self) -> Bdf { + self.bdf + } + + pub fn get_vbdf(&self) -> Bdf { + self.vbdf + } + + pub fn get_config_type(&self) -> HeaderType { + self.config_type + } + + pub fn set_vbdf(&mut self, vbdf: Bdf) { + self.vbdf = vbdf; + self.disabled + .store(true, core::sync::atomic::Ordering::SeqCst); + } + + /* now the space_init just with bar + */ + pub fn space_init(&mut self) { + for (slot, bar) in self.bararr.into_iter().enumerate() { + let offset = 0x10 + slot * 4; + let bytes = bar.get_value().to_le_bytes(); + self.space[offset..offset + 4].copy_from_slice(&bytes); + } + match self.config_type { + HeaderType::Endpoint => { + let bytes = self.rom.get_value().to_le_bytes(); + self.space[0x30..0x34].copy_from_slice(&bytes); + } + HeaderType::PciBridge => { + let bytes = self.rom.get_value().to_le_bytes(); + self.space[0x38..0x3c].copy_from_slice(&bytes); + } + _ => {} + } + } +} + +impl VirtualPciConfigSpace { + pub fn read_hw(&mut self, offset: PciConfigAddress, size: usize) -> HvResult { + let r = self.backend.read(offset, size); + if let Ok(value) = r { + self.update_space(offset, size, value); + } + r + } + + pub fn write_hw(&mut self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { + if self.writable(offset, size) { + let r = self.backend.write(offset, size, value); + if r.is_ok() { + self.update_space(offset, size, value); + } + r + } else { + hv_result_err!(EPERM, "pci: invalid write to hw") + } + } + + pub fn read_emu(&mut self, offset: PciConfigAddress, size: usize) -> HvResult { + match size { + 1 | 2 | 4 => { + let slice = &self.space[offset as usize..offset as usize + size]; + let value = match size { + 1 => slice[0] as usize, + 2 => u16::from_le_bytes(slice.try_into().unwrap()) as usize, + 4 => u32::from_le_bytes(slice.try_into().unwrap()) as usize, + _ => unreachable!(), + }; + Ok(value) + } + _ => { + hv_result_err!(EFAULT, "pci: invalid virtual mmio read size: {size}") + } + } + } + + pub fn read_emu64(&mut self, offset: PciConfigAddress) -> HvResult { + let slice = &self.space[offset as usize..offset as usize + 8]; + let value = u64::from_le_bytes(slice.try_into().unwrap()) as u64; + Ok(value) + } + + pub fn write_emu(&mut self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { + if self.writable(offset, size) { + match size { + 1 | 2 | 4 => { + let slice = &mut self.space[offset as usize..offset as usize + size]; + match size { + 1 => slice[0] = value as u8, + 2 => slice.copy_from_slice(&u16::to_le_bytes(value as u16)), + 4 => slice.copy_from_slice(&u32::to_le_bytes(value as u32)), + _ => unreachable!(), + } + Ok(()) + } + _ => { + hv_result_err!(EFAULT, "pci: invalid virtual mmio write size: {size}") + } + } + } else { + hv_result_err!(EPERM, "pci: invalid write to hw") + } + } +} + +pub struct PciIterator { + allocator: Option, + stack: Vec, + segment: PciConfigAddress, + bus_max: u8, + function: u8, + is_mulitple_function: bool, + is_finish: bool, +} + +impl PciIterator { + fn address(&self) -> PciConfigAddress { + let parent = self.stack.last().unwrap(); + let bus = parent.secondary_bus; + let device = parent.device; + + let mut address: PciConfigAddress = 0; + address.set_bits(12..15, self.function as PciConfigAddress); + address.set_bits(15..20, device as PciConfigAddress); + address.set_bits(20..28, bus as PciConfigAddress); + address += self.segment; + address + } + + fn get_node(&mut self) -> Option { + let address = self.address(); + + let region = PciRegionMmio::new(address, CONFIG_LENTH); + let pci_header = PciConfigHeader::new_with_region(region); + let (vender_id, _device_id) = pci_header.id(); + if vender_id == 0xffff { + return None; + } + + self.is_mulitple_function = pci_header.has_multiple_functions(); + + match pci_header.header_type() { + HeaderType::Endpoint => { + let mut ep = EndpointHeader::new_with_region(region); + + let mut bararr = ep.parse_bar(); + let rom = ep.parse_rom(); + if let Some(a) = &mut self.allocator { + ep.update_command(|mut cmd| { + cmd.remove(PciCommand::IO_ENABLE); + cmd.remove(PciCommand::MEMORY_ENABLE); + cmd + }); + + let mut i = 0; + while i < 6 { + match bararr[i].get_type() { + PciMemType::Mem32 => { + let value = a.alloc_memory32(bararr[i].get_size() as u32).unwrap(); + bararr[i].set_value(value as u64); + bararr[i].set_virtual_value(value as u64); + let _ = ep.write_bar(i as u8, value); + } + PciMemType::Mem64Low => { + let value = a.alloc_memory64(bararr[i].get_size()).unwrap(); + bararr[i].set_value(value); + bararr[i].set_virtual_value(value); + let _ = ep.write_bar(i as u8, value as u32); + i += 1; + bararr[i].set_value(value); + bararr[i].set_virtual_value(value); + let _ = ep.write_bar(i as u8, (value >> 32) as u32); + } + _ => {} + } + i += 1; + } + } + let ep = Box::new(ep); + let bdf = Bdf::from_address(address); + Some(VirtualPciConfigSpace::endpoint(bdf, ep, bararr, rom)) + } + HeaderType::PciBridge => { + warn!("bridge"); + let bridge = PciBridgeHeader::new_with_region(region); + let bridge = Box::new(bridge); + let bdf = Bdf::from_address(address); + Some(VirtualPciConfigSpace::bridge(bdf, bridge, Bar::default())) + } + _ => { + warn!("unknown type"); + let pci_header = Box::new(pci_header); + let bdf = Bdf::from_address(address); + Some(VirtualPciConfigSpace::unknown(bdf, pci_header)) + } + } + } + + fn get_bridge(&self) -> Bridge { + let a = self.stack.last(); + match a { + Some(bridge) => bridge.clone(), + None => { + unreachable!("get null stack") + } + } + } + + fn is_next_function_max(&mut self) -> bool { + if self.is_mulitple_function { + if self.function == MAX_FUNCTION { + self.function = 0; + true + } else { + self.function += 1; + false + } + } else { + self.function = 0; + true + } + } + + fn next_device_not_ok(&mut self) -> bool { + if let Some(parent) = self.stack.last_mut() { + if parent.device == MAX_DEVICE { + if let Some(mut parent) = self.stack.pop() { + self.is_finish = parent.subordinate_bus == self.bus_max; + + parent.update_bridge_bus(); + self.function = 0; + return true; + } else { + self.is_finish = true; + } + } else { + parent.device += 1; + } + } else { + self.is_finish = true; + } + + false + } + + fn next(&mut self, current_bridge: Option) { + if let Some(bridge) = current_bridge { + for parent in &mut self.stack { + parent.subordinate_bus += 1; + } + + self.stack.push(bridge.clone()); + + self.function = 0; + return; + } + + if self.is_next_function_max() { + while self.next_device_not_ok() { + spin_loop(); + } + } + } +} + +impl Iterator for PciIterator { + type Item = VirtualPciConfigSpace; + + fn next(&mut self) -> Option { + while !self.is_finish { + if let Some(mut node) = self.get_node() { + node.space_init(); + self.next(match node.config_type { + HeaderType::PciBridge => Some(self.get_bridge().next_bridge(self.address())), + _ => None, + }); + return Some(node); + } else { + self.next(None); + } + } + None + } +} + +#[derive(Debug, Clone)] +pub struct Bridge { + device: u8, + subordinate_bus: u8, + secondary_bus: u8, + primary_bus: u8, + mmio: PciRegionMmio, +} + +impl Bridge { + pub fn host_bridge(address: PciConfigAddress) -> Self { + Self { + device: 0, + subordinate_bus: 0, + secondary_bus: 0, + primary_bus: 0, + mmio: PciRegionMmio::new(address, CONFIG_LENTH), + } + } + + pub fn next_bridge(&self, address: PciConfigAddress) -> Self { + let mmio = PciRegionMmio::new(address, CONFIG_LENTH); + Self { + device: 0, + subordinate_bus: self.subordinate_bus + 1, + secondary_bus: self.subordinate_bus + 1, + primary_bus: self.secondary_bus, + mmio, + } + } + + pub fn update_bridge_bus(&mut self) { + let mut value = self.mmio.read_u32(0x18).unwrap(); + value.set_bits(16..24, self.subordinate_bus.into()); + value.set_bits(8..16, self.secondary_bus.into()); + value.set_bits(0..8, self.primary_bus.into()); + let _ = self.mmio.write_u32(0x18, value); + } +} + +/* In fact, the size will be managed by the pci_mmio_handler, so only base is needed here */ +pub struct RootComplex { + pub mmio_base: PciConfigAddress, +} + +impl RootComplex { + pub fn new(mmio_base: PciConfigAddress) -> Self { + Self { mmio_base } + } + + fn __enumerate( + &mut self, + range: Option>, + bar_alloc: Option, + ) -> PciIterator { + let mmio_base = self.mmio_base; + let range = range.unwrap_or_else(|| 0..0x100); + PciIterator { + allocator: bar_alloc, + stack: vec![Bridge::host_bridge(mmio_base)], + segment: mmio_base, + bus_max: (range.end - 1) as _, + function: 0, + is_mulitple_function: false, + is_finish: false, + } + } + + pub fn enumerate( + &mut self, + range: Option>, + bar_alloc: Option, + ) -> PciIterator { + self.__enumerate(range, bar_alloc) + } +} + +#[derive(Debug)] +pub struct VirtualRootComplex { + devs: BTreeMap, +} + +impl VirtualRootComplex { + pub fn new() -> Self { + Self { + devs: BTreeMap::new(), + } + } + + pub fn insert( + &mut self, + bdf: Bdf, + dev: VirtualPciConfigSpace, + ) -> Option { + self.devs.insert(bdf, dev) + } + + pub fn devs(&mut self) -> &mut BTreeMap { + &mut self.devs + } +} diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs new file mode 100644 index 00000000..4fa97841 --- /dev/null +++ b/src/pci/pci_test.rs @@ -0,0 +1,105 @@ +#![allow(dead_code)] +use core::str::FromStr; + +use alloc::{boxed::Box, collections::btree_map::BTreeMap}; +use spin::{lazy::Lazy, mutex::Mutex}; + +use crate::{ + memory::MMIOAccess, + pci::{pci_access::EndpointHeader, pci_mem::PciRegionMmio}, + percpu::this_zone, +}; + +use super::pci_struct::CONFIG_LENTH; +use super::{ + mem_alloc::BaseAllocator, + pci_access::mmio_vpci_handler, + pci_struct::{Bdf, RootComplex, VirtualPciConfigSpace}, +}; + +pub static GLOBAL_PCIE_LIST_TEST: Lazy>> = + Lazy::new(|| { + let m = BTreeMap::new(); + Mutex::new(m) + }); + +pub fn pcie_test() { + info!("pcie test"); + let mut allocator = BaseAllocator::default(); + allocator.set_mem32(0x10000000, 0x2efeffff); + allocator.set_mem64(0x8000000000, 0xffffffffff - 0x8000000000); + + let mut root = RootComplex::new(0x4010000000); + for node in root.enumerate(None, Some(allocator)) { + GLOBAL_PCIE_LIST_TEST.lock().insert(node.get_bdf(), node); + } +} + +pub fn pcie_guest_init() { + let zone = this_zone(); + let vbus = &mut zone.write().vpci_bus; + + let mut guard = GLOBAL_PCIE_LIST_TEST.lock(); + + let vbdf = Bdf::from_str("0000:00:00.0").unwrap(); + let bdf = Bdf::from_str("0000:00:00.0").unwrap(); + // warn!("address {}", bdf.to_address(0)); + let backend = EndpointHeader::new_with_region(PciRegionMmio::new( + bdf.to_address(0) + 0x4010000000, + CONFIG_LENTH, + )); + let dev = VirtualPciConfigSpace::host_bridge(bdf, Box::new(backend)); + vbus.insert(vbdf, dev); + + let vbdf = Bdf::from_str("0000:00:01.0").unwrap(); + let bdf = Bdf::from_str("0000:00:01.0").unwrap(); + if let Some(mut dev) = guard.remove(&bdf) { + // let _ = dev.write_hw(0x20, 4, 0xffffffff); + // let value1 = dev.read_hw(0x20, 4).unwrap(); + // let _ = dev.write_hw(0x24, 4, 0xffffffff); + // let value2 = dev.read_hw(0x24, 4).unwrap(); + // info!("{:#?} bar64 {:x}, {:x}", bdf, (value1 as u64), ((value2 as u64) << 32u64)); + dev.set_vbdf(vbdf); + vbus.insert(vbdf, dev); + } else { + warn!("can not find dev"); + } + + let vbdf = Bdf::from_str("0000:00:02.0").unwrap(); + let bdf = Bdf::from_str("0000:00:02.0").unwrap(); + if let Some(mut dev) = guard.remove(&bdf) { + dev.set_vbdf(vbdf); + vbus.insert(vbdf, dev); + } else { + warn!("can not find dev"); + } + + let vbdf = Bdf::from_str("0000:00:03.0").unwrap(); + let bdf = Bdf::from_str("0000:00:03.0").unwrap(); + if let Some(mut dev) = guard.remove(&bdf) { + dev.set_vbdf(vbdf); + vbus.insert(vbdf, dev); + } else { + warn!("can not find dev"); + } + + info!("{:#?}", vbus); + info!("pcie guest init done"); +} + +pub fn pcie_guest_test() { + let mut mmio = MMIOAccess { + address: Bdf::from_str("0000:00:01.0").unwrap().to_address(0x24) as _, + size: 4, + is_write: false, + value: 0x0, + }; + let ret = mmio_vpci_handler(&mut mmio, 0); + info!("{:#?}", ret); + info!( + "mmio offset {:x}, is_wirte {}, size {}, value 0x{:x}", + mmio.address, mmio.is_write, mmio.size, mmio.value + ); + + info!("pcie guest test passed"); +} diff --git a/src/pci/pcibar.rs b/src/pci/pcibar.rs deleted file mode 100644 index fd42bbc8..00000000 --- a/src/pci/pcibar.rs +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) 2025 Syswonder -// hvisor is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -// FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. -// -// Syswonder Website: -// https://www.syswonder.org -// -// Authors: -// -#[derive(Debug, Default, Clone, Copy)] -pub struct PciBar { - val: u32, - bar_type: BarType, - size: usize, -} - -#[derive(Debug, Copy, Clone)] -pub struct BarRegion { - pub start: usize, - pub size: usize, - pub bar_type: BarType, -} - -#[derive(Default, Debug, Copy, Clone)] -pub enum BarType { - Mem32, - Mem64, - IO, - #[default] - Unknown, -} - -impl PciBar { - // origin_val: the register value written by vm - // val: write !0u64 to the BAR to get the size this BAR need - pub fn init(&mut self, origin_val: u32, val: u32) { - self.val = origin_val; - - if let Some(fix_bit) = (0..32).rev().find(|&off| val & (1 << off) == 0) { - if fix_bit != 31 { - self.size = 1 << (fix_bit + 1); - } else { - // fix_bit == 31, indicates that all the bits are read-only - self.size = 0; - } - } else { - // all the bits are rw, indicates this BAR's value is the upper 32 bits of a region's address - // so the size depends on the next BAR, set self.size to 1, or the value will overflow - self.size = 1; - } - - self.bar_type = match self.val & 0b1 { - 0b1 => BarType::IO, - _ => match self.val & 0b110 { - 0b000 => BarType::Mem32, - 0b100 => BarType::Mem64, - _ => BarType::Unknown, - }, - }; - } - - pub fn is_mutable(&self) -> bool { - match self.size { - 0 => false, - _ => true, - } - } - - pub fn mem_type_64(&self) -> bool { - match self.bar_type { - BarType::Mem64 => true, - _ => false, - } - } - - pub fn get_32b_region(&self) -> BarRegion { - BarRegion { - start: (self.val & 0xfffffff0) as _, - size: self.size, - bar_type: self.bar_type, - } - } - - pub fn get_upper_mem64_32b(&self) -> BarRegion { - BarRegion { - start: self.val as _, // upper 32bits are all mutable - size: self.size, - bar_type: self.bar_type, - } - } - - pub fn get_64b_region(&self, lower_region: BarRegion) -> BarRegion { - let higher_region = self.get_upper_mem64_32b(); - // info!("mm64, high: {:#x}, low: {:#x}", higher_region.start, lower_region.start); - BarRegion { - start: (higher_region.start << 32) + lower_region.start, - size: higher_region.size * lower_region.size, - bar_type: BarType::Mem64, - } - } - - pub fn generate_vbar(&self) -> VirtPciBar { - match self.size { - 0 => VirtPciBar { - val: self.val, - mask: 0x0, - }, - 1 => VirtPciBar { - val: self.val, - mask: 0xffffffff, - }, - _ => VirtPciBar { - val: self.val, - mask: !((self.size - 1) as u64) as _, - }, - } - } -} - -#[derive(Default, Clone, Debug, Copy)] -pub struct VirtPciBar { - val: u32, - mask: u32, -} - -impl VirtPciBar { - pub fn new(val: u32, mask: u32) -> Self { - Self { - val: val, - mask: mask, - } - } - - pub fn read(&self) -> u32 { - self.val - } - - pub fn write(&mut self, new_val: u32) { - self.val = new_val & self.mask; - } -} diff --git a/src/pci/phantom_cfg.rs b/src/pci/phantom_cfg.rs deleted file mode 100644 index b4d9252e..00000000 --- a/src/pci/phantom_cfg.rs +++ /dev/null @@ -1,365 +0,0 @@ -// Copyright (c) 2025 Syswonder -// hvisor is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR -// FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. -// -// Syswonder Website: -// https://www.syswonder.org -// -// Authors: -// -use super::{ - cfg_base, endpoint::EndpointConfig, extract_reg_addr, pcibar::VirtPciBar, CFG_BAR0, CFG_BAR1, - CFG_BAR2, CFG_BAR3, CFG_BAR4, CFG_BAR5, CFG_CAP_PTR_OFF, CFG_CLASS_CODE_OFF, CFG_CMD_OFF, - CFG_EXT_CAP_PTR_OFF, CFG_INT_LINE, CFG_INT_PIN, CFG_IO_BASE, CFG_IO_BASE_UPPER16, CFG_IO_LIMIT, - CFG_IO_LIMIT_UPPER16, CFG_MEM_BASE, CFG_MEM_LIMIT, CFG_PREF_BASE_UPPER32, - CFG_PREF_LIMIT_UPPER32, CFG_PREF_MEM_BASE, CFG_PREF_MEM_LIMIT, CFG_PRIMARY_BUS, - CFG_SECONDARY_BUS, NUM_BAR_REGS_TYPE0, NUM_BAR_REGS_TYPE1, NUM_MAX_BARS, -}; -use crate::{ - error::HvResult, - memory::{mmio_perform_access, MMIOAccess}, - pci::PHANTOM_DEV_HEADER, - zone::this_zone_id, -}; -use alloc::collections::btree_map::BTreeMap; -use core::{ptr, usize}; - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum PhantomCfgType { - ENDPOINT, - BRIDGE, -} - -#[derive(Debug, Copy, Clone)] -pub struct PhantomCfg { - pub bdf: usize, - command: u16, - status: u16, - int_line: u8, - v_bars: [VirtPciBar; NUM_MAX_BARS], - bar_num: usize, - cfg_type: PhantomCfgType, -} - -impl PhantomCfg { - pub fn new(bdf: usize, v_bars: [VirtPciBar; NUM_MAX_BARS], cfg_type: PhantomCfgType) -> Self { - Self { - bdf, - command: 0, - status: 0, - int_line: 0, - v_bars: v_bars, - bar_num: if cfg_type == PhantomCfgType::ENDPOINT { - NUM_BAR_REGS_TYPE0 - } else { - NUM_BAR_REGS_TYPE1 - }, - cfg_type: cfg_type, - } - } - - pub fn read_bar(&self, bar_id: usize) -> u32 { - if bar_id >= self.bar_num { - panic!("bar {} doesn't exists!", bar_id); - } - self.v_bars[bar_id].read() - } - pub fn write_bar(&mut self, bar_id: usize, val: u32) { - if bar_id >= self.bar_num { - panic!("bar {} doesn't exists!", bar_id); - } - self.v_bars[bar_id].write(val as _); - } - pub fn read_cmd(&self) -> u16 { - self.command - } - pub fn write_cmd(&mut self, command: u16) { - self.command = command; - } - pub fn read_stats(&self) -> u16 { - self.status - } - pub fn write_stats(&mut self, val: u16) { - self.status = val; - } - pub fn read_int_line(&self) -> u8 { - self.int_line - } - pub fn write_int_line(&mut self, val: u8) { - self.int_line = val; - } - - pub fn phantom_mmio_handler( - &mut self, - mmio: &mut MMIOAccess, - base: usize, - zone_id: usize, - ) -> HvResult { - match self.cfg_type { - PhantomCfgType::ENDPOINT => self.phantom_ep_handler(mmio, base, zone_id), - PhantomCfgType::BRIDGE => self.phantom_bridge_handler(mmio, base, zone_id), - } - } - - fn phantom_ep_handler( - &mut self, - mmio: &mut MMIOAccess, - base: usize, - zone_id: usize, - ) -> HvResult { - let reg_addr = extract_reg_addr(mmio.address); - match reg_addr { - 0 => { - // phantom device - let header_addr = base + mmio.address; - let bdf = self.bdf; - let function = bdf & 0x7; - let device = (bdf >> 3) & 0b11111; - let bus = bdf >> 8; - let header_val = unsafe { ptr::read_volatile(header_addr as *mut u32) }; - debug!( - "{:x}:{:x}.{:x} exists but we don't show it to vm {:x}:{:x}", - bus, - device, - function, - header_val & 0xffff, - (header_val >> 16) & 0xffff - ); - mmio.value = PHANTOM_DEV_HEADER as _; - } - CFG_CMD_OFF => { - if mmio.is_write { - self.write_cmd(mmio.value as _); - } else { - mmio.value = self.read_cmd() as _; - } - } - CFG_CAP_PTR_OFF => { - // can't see any capabilities - mmio.value = 0x0; - } - CFG_EXT_CAP_PTR_OFF => { - mmio.value = 0x0; - } - CFG_CLASS_CODE_OFF => { - mmio.value = 0x1f0000; - } - CFG_BAR0 => { - if zone_id == 0 { - mmio_perform_access(base, mmio); - } - if mmio.is_write { - self.write_bar(0, mmio.value as _); - } else { - mmio.value = self.read_bar(0) as _; - } - } - CFG_BAR1 => { - if zone_id == 0 { - mmio_perform_access(base, mmio); - } - if mmio.is_write { - self.write_bar(1, mmio.value as _); - } else { - mmio.value = self.read_bar(1) as _; - } - } - CFG_BAR2 => { - if zone_id == 0 { - mmio_perform_access(base, mmio); - } - if mmio.is_write { - self.write_bar(2, mmio.value as _); - } else { - mmio.value = self.read_bar(2) as _; - } - } - CFG_BAR3 => { - if zone_id == 0 { - mmio_perform_access(base, mmio); - } - if mmio.is_write { - self.write_bar(3, mmio.value as _); - } else { - mmio.value = self.read_bar(3) as _; - } - } - CFG_BAR4 => { - if zone_id == 0 { - mmio_perform_access(base, mmio); - } - if mmio.is_write { - self.write_bar(4, mmio.value as _); - } else { - mmio.value = self.read_bar(4) as _; - } - } - CFG_BAR5 => { - if zone_id == 0 { - mmio_perform_access(base, mmio); - } - if mmio.is_write { - self.write_bar(5, mmio.value as _); - } else { - mmio.value = self.read_bar(5) as _; - } - } - CFG_INT_PIN => { - mmio.value = 0; - } - CFG_INT_LINE => { - if mmio.is_write { - self.write_int_line(mmio.value as _); - } else { - mmio.value = self.read_int_line() as _; - } - } - _ => { - mmio_perform_access(base, mmio); - // if self.bdf >> 8 == 8 { - // info!( - // "{:x}:{:x}.{:x} access {:#x} {:?} {} -> {:#x}", - // self.bdf >> 8, - // (self.bdf >> 3) & 0b11111, - // self.bdf & 0b111, - // reg_addr, - // if mmio.is_write {"W"} else {"R"}, - // mmio.size, - // mmio.value - // ); - // } - } - } - Ok(()) - } - - fn phantom_bridge_handler( - &mut self, - mmio: &mut MMIOAccess, - base: usize, - _zone_id: usize, - ) -> HvResult { - let reg_addr = extract_reg_addr(mmio.address); - match reg_addr { - 0 => { - // phantom device - let header_addr = base + mmio.address; - let header_val = unsafe { ptr::read_volatile(header_addr as *mut u32) }; - let bdf = self.bdf; - let function = bdf & 0x7; - let device = (bdf >> 3) & 0b11111; - let bus = bdf >> 8; - debug!( - "{:x}:{:x}.{:x} exists but we don't show it to vm {:x}:{:x}", - bdf >> 8, - device, - function, - header_val & 0xffff, - (header_val >> 16) & 0xffff - ); - mmio.value = PHANTOM_DEV_HEADER as _; - } - CFG_CMD_OFF => { - if mmio.is_write { - self.write_cmd(mmio.value as _); - } else { - mmio.value = self.read_cmd() as _; - } - } - CFG_CAP_PTR_OFF => { - // can't see any capabilities - mmio.value = 0x0; - } - CFG_EXT_CAP_PTR_OFF => { - mmio.value = 0x0; - } - CFG_BAR0 => { - if mmio.is_write { - self.write_bar(0, mmio.value as _); - } else { - mmio.value = self.read_bar(0) as _; - } - } - CFG_BAR1 => { - if mmio.is_write { - self.write_bar(1, mmio.value as _); - } else { - mmio.value = self.read_bar(1) as _; - } - } - CFG_INT_PIN => { - mmio.value = 0; - } - CFG_INT_LINE => { - if mmio.is_write { - self.write_int_line(mmio.value as _); - } else { - mmio.value = self.read_int_line() as _; - } - } - _ => { - // if !mmio.is_write { - mmio_perform_access(base, mmio); - // } - } - } - Ok(()) - } -} - -pub static mut PHANTOM_DEVS: BTreeMap = BTreeMap::new(); - -pub fn add_phantom_devices(phantom_dev: PhantomCfg) { - unsafe { - let bdf = phantom_dev.bdf; - if !PHANTOM_DEVS.contains_key(&bdf) { - info!( - "Add a new virt pci device: {:x}:{:x}.{:x}", - &phantom_dev.bdf >> 8, - (&phantom_dev.bdf >> 3) & 0b11111, - &phantom_dev.bdf & 0b111 - ); - PHANTOM_DEVS.insert(bdf, phantom_dev); - } else { - warn!( - "Phantom device with BDF {:#x} already exists, skipping", - bdf - ); - } - } -} - -pub fn find_phantom_dev(bdf: usize) -> PhantomCfg { - unsafe { - match PHANTOM_DEVS.get(&bdf) { - Some(device) => device.clone(), - None => generate_vep_by_bdf(bdf), // root will generate all virt bridges so we don't need to actively generate vbridges - } - } -} - -pub fn generate_vep_by_bdf(bdf: usize) -> PhantomCfg { - let mut tmp_ep = EndpointConfig::new(bdf); - let cfg_base = cfg_base(bdf); - let offsets: [usize; NUM_BAR_REGS_TYPE0] = [0x10, 0x14, 0x18, 0x1c, 0x20, 0x24]; - for bar_id in 0..NUM_BAR_REGS_TYPE0 { - unsafe { - let reg_ptr = (cfg_base + offsets[bar_id]) as *mut u32; - let origin_val = *reg_ptr; - *reg_ptr = 0xffffffffu32; - let new_val = *reg_ptr; - tmp_ep.bars_init(bar_id, origin_val, new_val); - *reg_ptr = origin_val; - } - } - let pdev = tmp_ep.generate_vep(); - add_phantom_devices(pdev); - // info!("generate a pdev: {:#x?}", &pdev); - pdev -} diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 8dc1c493..e4d879ea 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -15,8 +15,9 @@ // use crate::{ config::{ - HvConfigMemoryRegion, HvIvcConfig, HvPciConfig, HvZoneConfig, CONFIG_MAX_INTERRUPTS, - CONFIG_MAX_IVC_CONFIGS, CONFIG_MAX_MEMORY_REGIONS, CONFIG_MAX_PCI_DEV, CONFIG_NAME_MAXLEN, + HvConfigMemoryRegion, HvIvcConfig, HvPciConfig, HvPciDevConfig, HvZoneConfig, + CONFIG_MAX_INTERRUPTS, CONFIG_MAX_IVC_CONFIGS, CONFIG_MAX_MEMORY_REGIONS, + CONFIG_MAX_PCI_DEV, CONFIG_NAME_MAXLEN, CONFIG_PCI_BUS_MAXLEN, }, consts::INVALID_ADDRESS, }; @@ -71,8 +72,8 @@ pub fn platform_root_zone_config() -> HvZoneConfig { check!(ROOT_ZONE_NAME.len(), CONFIG_NAME_MAXLEN, "ROOT_ZONE_NAME"); name[..ROOT_ZONE_NAME.len()].copy_from_slice(ROOT_ZONE_NAME.as_bytes()); - let mut pci_devs = [0; CONFIG_MAX_PCI_DEV]; - let mut _root_pci_cfg = HvPciConfig::new_empty(); + let mut pci_devs = [HvPciDevConfig::default(); CONFIG_MAX_PCI_DEV]; + let mut _root_pci_cfg = [HvPciConfig::new_empty(); CONFIG_PCI_BUS_MAXLEN]; let mut _num_pci_devs: u64 = 0; #[cfg(feature = "pci")] diff --git a/src/zone.rs b/src/zone.rs index 0177b220..aaff5faa 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -17,7 +17,8 @@ use alloc::sync::Arc; use alloc::vec::Vec; // use psci::error::INVALID_ADDRESS; use crate::consts::{INVALID_ADDRESS, MAX_CPU_NUM}; -use crate::pci::pci::PciRoot; +#[cfg(feature = "pci")] +use crate::pci::pci_struct::VirtualRootComplex; use spin::RwLock; use crate::arch::mm::new_s2_memory_set; @@ -41,10 +42,11 @@ pub struct Zone { pub cpu_set: CpuSet, pub irq_bitmap: [u32; 1024 / 32], pub gpm: MemorySet, - pub pciroot: PciRoot, #[cfg(all(target_arch = "riscv64", feature = "plic"))] pub vplic: Option, pub is_err: bool, + #[cfg(feature = "pci")] + pub vpci_bus: VirtualRootComplex, } impl Zone { @@ -56,10 +58,11 @@ impl Zone { cpu_set: CpuSet::new(MAX_CPU_NUM as usize, 0), mmio: Vec::new(), irq_bitmap: [0; 1024 / 32], - pciroot: PciRoot::new(), is_err: false, #[cfg(all(target_arch = "riscv64", feature = "plic"))] vplic: None, + #[cfg(feature = "pci")] + vpci_bus: VirtualRootComplex::new(), } } @@ -209,6 +212,11 @@ pub fn zone_create(config: &HvZoneConfig) -> HvResult>> { let mut zone = Zone::new(zone_id, &config.name); zone.pt_init(config.memory_regions()).unwrap(); zone.mmio_init(&config.arch_config); + #[cfg(feature = "pci")] + { + let _ = zone.virtual_pci_mmio_init(&config.pci_config); + let _ = zone.guest_pci_init(&config.alloc_pci_devs, config.num_pci_devs); + } #[cfg(target_arch = "aarch64")] zone.ivc_init(config.ivc_config()); @@ -216,17 +224,10 @@ pub fn zone_create(config: &HvZoneConfig) -> HvResult>> { /* Kai: Maybe unnecessary but i can't boot vms on my 3A6000 PC without this function. */ #[cfg(target_arch = "loongarch64")] zone.page_table_emergency( - config.pci_config.ecam_base as _, - config.pci_config.ecam_size as _, + config.pci_config[0].ecam_base as _, + config.pci_config[0].ecam_size as _, )?; - #[cfg(all(feature = "pci"))] - zone.pci_init( - &config.pci_config, - config.num_pci_devs as _, - &config.alloc_pci_devs, - ); - let mut _cpu_num = 0; for cpu_id in config.cpus().iter() { From 760e56fe24f20977209b369915a748e79a5bbd64 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 11 Sep 2025 00:51:31 +0800 Subject: [PATCH 02/12] [fixed] Synchronize pci changes to configuration files --- platform/aarch64/qemu-gicv2/board.rs | 75 ++++++++++++--- platform/aarch64/qemu-gicv3/board.rs | 15 ++- platform/loongarch64/ls3a5000/board.rs | 127 ++++++++++++++++--------- platform/loongarch64/ls3a6000/board.rs | 126 +++++++++++++++--------- src/config.rs | 33 +++++-- src/pci/pci_config.rs | 6 +- src/platform/mod.rs | 4 +- 7 files changed, 264 insertions(+), 122 deletions(-) diff --git a/platform/aarch64/qemu-gicv2/board.rs b/platform/aarch64/qemu-gicv2/board.rs index 98cae2b2..fcf4c97f 100644 --- a/platform/aarch64/qemu-gicv2/board.rs +++ b/platform/aarch64/qemu-gicv2/board.rs @@ -18,6 +18,8 @@ use crate::{ config::*, }; +use crate::pci_dev; + pub const BOARD_NAME: &str = "qemu-gicv2"; pub const BOARD_NCPUS: usize = 4; @@ -90,20 +92,65 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { }; -pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { - ecam_base: 0x4010000000, - ecam_size: 0x10000000, - io_base: 0x3eff0000, - io_size: 0x10000, - pci_io_base: 0x0, - mem32_base: 0x10000000, - mem32_size: 0x2eff0000, - pci_mem32_base: 0x10000000, - mem64_base: 0x8000000000, - mem64_size: 0x8000000000, - pci_mem64_base: 0x8000000000, -}; +pub const ROOT_PCI_CONFIG: [HvPciConfig; 4] = [ + HvPciConfig { + ecam_base: 0x4010000000, + ecam_size: 0x10000000, + io_base: 0x3eff0000, + io_size: 0x10000, + pci_io_base: 0x0, + mem32_base: 0x10000000, + mem32_size: 0x2eff0000, + pci_mem32_base: 0x10000000, + mem64_base: 0x8000000000, + mem64_size: 0x8000000000, + pci_mem64_base: 0x8000000000, + }, + HvPciConfig { + ecam_base: 0x0, + ecam_size: 0x0, + io_base: 0x0, + io_size: 0x0, + pci_io_base: 0x0, + mem32_base: 0x0, + mem32_size: 0x0, + pci_mem32_base: 0x0, + mem64_base: 0x0, + mem64_size: 0x0, + pci_mem64_base: 0x0, + }, + HvPciConfig { + ecam_base: 0x0, + ecam_size: 0x0, + io_base: 0x0, + io_size: 0x0, + pci_io_base: 0x0, + mem32_base: 0x0, + mem32_size: 0x0, + pci_mem32_base: 0x0, + mem64_base: 0x0, + mem64_size: 0x0, + pci_mem64_base: 0x0, + }, + HvPciConfig { + ecam_base: 0x0, + ecam_size: 0x0, + io_base: 0x0, + io_size: 0x0, + pci_io_base: 0x0, + mem32_base: 0x0, + mem32_size: 0x0, + pci_mem32_base: 0x0, + mem64_base: 0x0, + mem64_size: 0x0, + pci_mem64_base: 0x0, + }, +]; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; -pub const ROOT_PCI_DEVS: [u64; 2] = [0, 1 << 3]; +pub const ROOT_PCI_DEVS: [HvPciDevConfig; 3] = [ + pci_dev!(0x0, 0x0, 0x0), + pci_dev!(0x0, 0x1, 0x0), + pci_dev!(0x0, 0x2, 0x0), +]; diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index cf2d4586..3bfab78c 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -20,6 +20,9 @@ use crate::{ }, config::*, }; + +use crate::pci_dev; + pub const BOARD_NAME: &str = "qemu-gicv3"; pub const BOARD_NCPUS: usize = 4; @@ -146,13 +149,7 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 4] = [ pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; pub const ROOT_PCI_DEVS: [HvPciDevConfig; 3] = [ - HvPciDevConfig { bdf: 0, vbdf: 0 }, - HvPciDevConfig { - bdf: (0 << 20 | 2 << 15 | 0 << 12), - vbdf: (0 << 20 | 2 << 15 | 0 << 12), - }, - HvPciDevConfig { - bdf: (0 << 20 | 3 << 15 | 0 << 12), - vbdf: (0 << 20 | 3 << 15 | 0 << 12), - }, + pci_dev!(0x0, 0x0, 0x0), + pci_dev!(0x0, 0x1, 0x0), + pci_dev!(0x0, 0x2, 0x0), ]; diff --git a/platform/loongarch64/ls3a5000/board.rs b/platform/loongarch64/ls3a5000/board.rs index 184dc110..ac2616ed 100644 --- a/platform/loongarch64/ls3a5000/board.rs +++ b/platform/loongarch64/ls3a5000/board.rs @@ -15,6 +15,7 @@ // Yulong Han // use crate::{arch::zone::HvArchZoneConfig, config::*}; +use crate::pci_dev; pub const BOARD_NAME: &str = "ls3a5000"; @@ -154,19 +155,60 @@ pub const ROOT_ZONE_IRQS: [u32; 0] = []; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { dummy: 0 }; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; -pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { - ecam_base: 0xfe00000000, - ecam_size: 0x20000000, - io_base: 0x18408000, - io_size: 0x8000, - pci_io_base: 0x00008000, - mem32_base: 0x0, - mem32_size: 0x0, - pci_mem32_base: 0x0, - mem64_base: 0x60000000, - mem64_size: 0x20000000, - pci_mem64_base: 0x60000000, -}; +pub const ROOT_PCI_CONFIG: [HvPciConfig; 4] = [ + HvPciConfig { + ecam_base: 0xfe00000000, + ecam_size: 0x20000000, + io_base: 0x18408000, + io_size: 0x8000, + pci_io_base: 0x00008000, + mem32_base: 0x0, + mem32_size: 0x0, + pci_mem32_base: 0x0, + mem64_base: 0x60000000, + mem64_size: 0x20000000, + pci_mem64_base: 0x60000000, + }, + HvPciConfig { + ecam_base: 0x0, + ecam_size: 0x0, + io_base: 0x0, + io_size: 0x0, + pci_io_base: 0x0, + mem32_base: 0x0, + mem32_size: 0x0, + pci_mem32_base: 0x0, + mem64_base: 0x0, + mem64_size: 0x0, + pci_mem64_base: 0x0, + }, + HvPciConfig { + ecam_base: 0x0, + ecam_size: 0x0, + io_base: 0x0, + io_size: 0x0, + pci_io_base: 0x0, + mem32_base: 0x0, + mem32_size: 0x0, + pci_mem32_base: 0x0, + mem64_base: 0x0, + mem64_size: 0x0, + pci_mem64_base: 0x0, + }, + HvPciConfig { + ecam_base: 0x0, + ecam_size: 0x0, + io_base: 0x0, + io_size: 0x0, + pci_io_base: 0x0, + mem32_base: 0x0, + mem32_size: 0x0, + pci_mem32_base: 0x0, + mem64_base: 0x0, + mem64_size: 0x0, + pci_mem64_base: 0x0, + }, +]; /* 00:00.0, 00:00.1, 00:00.2, 00:00.3, 00:04.0, 00:04.1*/ /* 00:05.0, 00:05.1, 00:06.0, 00:06.1, 00:06.2 */ @@ -177,38 +219,37 @@ pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { /* 08:00.0, 08:00.1, 08:00.2, 08:00.3 net */ /* BUS 6 on X4 slot */ /* 06:00.0, 06:00.1, 06:00.2, 06:00.3 net */ -pub const ROOT_PCI_DEVS: [u64; 26] = [ - 0, - 1, - 2, - 3, - 4 << 3, - (4 << 3) + 1, - 5 << 3, - (5 << 3) + 1, - // 00:06.xx is VGA and Graphics card - (6 << 3), - (6 << 3) + 1, - (6 << 3) + 2, - 7 << 3, - 8 << 3, // bus 0 device 8: AHCI - 9 << 3, - 0xa << 3, - 0xb << 3, - 0xc << 3, - 0xd << 3, - 0xf << 3, - 0x10 << 3, - 0x13 << 3, - 0x16 << 3, - 0x19 << 3, - 2 << 8, - 5 << 8, - // bus 6 (x4 slot) is PCIe network card - // (8 << 8), // bus 8 net - (6 << 8), // bus 6 net +pub const ROOT_PCI_DEVS: [HvPciDevConfig; 26] = [ + pci_dev!(0x0, 0x0, 0x0), // 00:00.0 + pci_dev!(0x0, 0x0, 0x1), // 00:00.1 + pci_dev!(0x0, 0x0, 0x2), // 00:00.2 + pci_dev!(0x0, 0x0, 0x3), // 00:00.3 + pci_dev!(0x0, 0x4, 0x0), // 00:04.0 + pci_dev!(0x0, 0x4, 0x1), // 00:04.1 + pci_dev!(0x0, 0x5, 0x0), // 00:05.0 + pci_dev!(0x0, 0x5, 0x1), // 00:05.1 + pci_dev!(0x0, 0x6, 0x0), // 00:06.0 + pci_dev!(0x0, 0x6, 0x1), // 00:06.1 + pci_dev!(0x0, 0x6, 0x2), // 00:06.2 + pci_dev!(0x0, 0x7, 0x0), // 00:07.0 + pci_dev!(0x0, 0x8, 0x0), // 00:08.0 + pci_dev!(0x0, 0x9, 0x0), // 00:09.0 + pci_dev!(0x0, 0xa, 0x0), // 00:0a.0 + pci_dev!(0x0, 0xb, 0x0), // 00:0b.0 + pci_dev!(0x0, 0xc, 0x0), // 00:0c.0 + pci_dev!(0x0, 0xd, 0x0), // 00:0d.0 + pci_dev!(0x0, 0xf, 0x0), // 00:0f.0 + pci_dev!(0x0, 0x10, 0x0), // 00:10.0 + pci_dev!(0x0, 0x13, 0x0), // 00:13.0 + pci_dev!(0x0, 0x16, 0x0), // 00:16.0 + pci_dev!(0x0, 0x19, 0x0), // 00:19.0 + pci_dev!(0x2, 0x0, 0x0), // 02:00.0 + pci_dev!(0x5, 0x0, 0x0), // 05:00.0 + pci_dev!(0x6, 0x0, 0x0), // 06:00.0 ]; + + // bus << 8 | dev << 5 | func << 3 // pub const ROOT_PCI_DEVS: [u64; 0] = []; diff --git a/platform/loongarch64/ls3a6000/board.rs b/platform/loongarch64/ls3a6000/board.rs index 184dc110..2a4acc27 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -15,6 +15,7 @@ // Yulong Han // use crate::{arch::zone::HvArchZoneConfig, config::*}; +use crate::pci_dev; pub const BOARD_NAME: &str = "ls3a5000"; @@ -154,19 +155,60 @@ pub const ROOT_ZONE_IRQS: [u32; 0] = []; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { dummy: 0 }; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; -pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { - ecam_base: 0xfe00000000, - ecam_size: 0x20000000, - io_base: 0x18408000, - io_size: 0x8000, - pci_io_base: 0x00008000, - mem32_base: 0x0, - mem32_size: 0x0, - pci_mem32_base: 0x0, - mem64_base: 0x60000000, - mem64_size: 0x20000000, - pci_mem64_base: 0x60000000, -}; +pub const ROOT_PCI_CONFIG: [HvPciConfig; 4] = [ + HvPciConfig { + ecam_base: 0xfe00000000, + ecam_size: 0x20000000, + io_base: 0x18408000, + io_size: 0x8000, + pci_io_base: 0x00008000, + mem32_base: 0x0, + mem32_size: 0x0, + pci_mem32_base: 0x0, + mem64_base: 0x60000000, + mem64_size: 0x20000000, + pci_mem64_base: 0x60000000, + }, + HvPciConfig { + ecam_base: 0x0, + ecam_size: 0x0, + io_base: 0x0, + io_size: 0x0, + pci_io_base: 0x0, + mem32_base: 0x0, + mem32_size: 0x0, + pci_mem32_base: 0x0, + mem64_base: 0x0, + mem64_size: 0x0, + pci_mem64_base: 0x0, + }, + HvPciConfig { + ecam_base: 0x0, + ecam_size: 0x0, + io_base: 0x0, + io_size: 0x0, + pci_io_base: 0x0, + mem32_base: 0x0, + mem32_size: 0x0, + pci_mem32_base: 0x0, + mem64_base: 0x0, + mem64_size: 0x0, + pci_mem64_base: 0x0, + }, + HvPciConfig { + ecam_base: 0x0, + ecam_size: 0x0, + io_base: 0x0, + io_size: 0x0, + pci_io_base: 0x0, + mem32_base: 0x0, + mem32_size: 0x0, + pci_mem32_base: 0x0, + mem64_base: 0x0, + mem64_size: 0x0, + pci_mem64_base: 0x0, + }, +]; /* 00:00.0, 00:00.1, 00:00.2, 00:00.3, 00:04.0, 00:04.1*/ /* 00:05.0, 00:05.1, 00:06.0, 00:06.1, 00:06.2 */ @@ -177,38 +219,36 @@ pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { /* 08:00.0, 08:00.1, 08:00.2, 08:00.3 net */ /* BUS 6 on X4 slot */ /* 06:00.0, 06:00.1, 06:00.2, 06:00.3 net */ -pub const ROOT_PCI_DEVS: [u64; 26] = [ - 0, - 1, - 2, - 3, - 4 << 3, - (4 << 3) + 1, - 5 << 3, - (5 << 3) + 1, - // 00:06.xx is VGA and Graphics card - (6 << 3), - (6 << 3) + 1, - (6 << 3) + 2, - 7 << 3, - 8 << 3, // bus 0 device 8: AHCI - 9 << 3, - 0xa << 3, - 0xb << 3, - 0xc << 3, - 0xd << 3, - 0xf << 3, - 0x10 << 3, - 0x13 << 3, - 0x16 << 3, - 0x19 << 3, - 2 << 8, - 5 << 8, - // bus 6 (x4 slot) is PCIe network card - // (8 << 8), // bus 8 net - (6 << 8), // bus 6 net +pub const ROOT_PCI_DEVS: [HvPciDevConfig; 26] = [ + pci_dev!(0x0, 0x0, 0x0), // 00:00.0 + pci_dev!(0x0, 0x0, 0x1), // 00:00.1 + pci_dev!(0x0, 0x0, 0x2), // 00:00.2 + pci_dev!(0x0, 0x0, 0x3), // 00:00.3 + pci_dev!(0x0, 0x4, 0x0), // 00:04.0 + pci_dev!(0x0, 0x4, 0x1), // 00:04.1 + pci_dev!(0x0, 0x5, 0x0), // 00:05.0 + pci_dev!(0x0, 0x5, 0x1), // 00:05.1 + pci_dev!(0x0, 0x6, 0x0), // 00:06.0 + pci_dev!(0x0, 0x6, 0x1), // 00:06.1 + pci_dev!(0x0, 0x6, 0x2), // 00:06.2 + pci_dev!(0x0, 0x7, 0x0), // 00:07.0 + pci_dev!(0x0, 0x8, 0x0), // 00:08.0 + pci_dev!(0x0, 0x9, 0x0), // 00:09.0 + pci_dev!(0x0, 0xa, 0x0), // 00:0a.0 + pci_dev!(0x0, 0xb, 0x0), // 00:0b.0 + pci_dev!(0x0, 0xc, 0x0), // 00:0c.0 + pci_dev!(0x0, 0xd, 0x0), // 00:0d.0 + pci_dev!(0x0, 0xf, 0x0), // 00:0f.0 + pci_dev!(0x0, 0x10, 0x0), // 00:10.0 + pci_dev!(0x0, 0x13, 0x0), // 00:13.0 + pci_dev!(0x0, 0x16, 0x0), // 00:16.0 + pci_dev!(0x0, 0x19, 0x0), // 00:19.0 + pci_dev!(0x2, 0x0, 0x0), // 02:00.0 + pci_dev!(0x5, 0x0, 0x0), // 05:00.0 + pci_dev!(0x6, 0x0, 0x0), // 06:00.0 ]; + // bus << 8 | dev << 5 | func << 3 // pub const ROOT_PCI_DEVS: [u64; 0] = []; diff --git a/src/config.rs b/src/config.rs index 82f29151..9301468f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -17,18 +17,18 @@ use alloc::vec::Vec; use spin::Once; use core::fmt::Debug; -use crate::{arch::zone::HvArchZoneConfig, pci::pci_struct::Bdf, platform}; +use crate::{arch::zone::HvArchZoneConfig, platform}; pub const MEM_TYPE_RAM: u32 = 0; pub const MEM_TYPE_IO: u32 = 1; pub const MEM_TYPE_VIRTIO: u32 = 2; -pub const CONFIG_MAGIC_VERSION: usize = 0x3; +pub const CONFIG_MAGIC_VERSION: usize = 0x4; pub const CONFIG_MAX_MEMORY_REGIONS: usize = 64; pub const CONFIG_MAX_INTERRUPTS: usize = 32; pub const CONFIG_NAME_MAXLEN: usize = 32; pub const CONFIG_MAX_IVC_CONFIGS: usize = 2; -pub const CONFIG_PCI_BUS_MAXLEN: usize = 4; +pub const CONFIG_PCI_BUS_MAXNUM: usize = 4; pub const CONFIG_MAX_PCI_DEV: usize = 32; #[repr(C)] @@ -93,7 +93,7 @@ pub struct HvZoneConfig { pub dtb_size: u64, pub name: [u8; CONFIG_NAME_MAXLEN], pub arch_config: HvArchZoneConfig, - pub pci_config: [HvPciConfig; CONFIG_PCI_BUS_MAXLEN], + pub pci_config: [HvPciConfig; CONFIG_PCI_BUS_MAXNUM], pub num_pci_devs: u64, pub alloc_pci_devs: [HvPciDevConfig; CONFIG_MAX_PCI_DEV], } @@ -115,7 +115,7 @@ impl HvZoneConfig { dtb_size: u64, name: [u8; CONFIG_NAME_MAXLEN], arch: HvArchZoneConfig, - pci: [HvPciConfig; CONFIG_PCI_BUS_MAXLEN], + pci: [HvPciConfig; CONFIG_PCI_BUS_MAXNUM], num_pci_devs: u64, alloc_pci_devs: [HvPciDevConfig; CONFIG_MAX_PCI_DEV], ) -> Self { @@ -202,11 +202,28 @@ pub struct HvPciDevConfig { pub vbdf: u64, } -// #[cfg(feature = "pci")] +#[macro_export] +macro_rules! pci_dev { + ($bus:expr, $dev:expr, $func:expr) => { + HvPciDevConfig { + bdf: ($bus << 20) | ($dev << 15) | ($func << 12), + vbdf: ($bus << 20) | ($dev << 15) | ($func << 12), + } + }; +} + +#[cfg(not(feature = "pci"))] +impl core::fmt::Debug for HvPciDevConfig { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Debug::fmt(&(self.bdf, self.vbdf), f) + } +} + +#[cfg(feature = "pci")] impl Debug for HvPciDevConfig { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let bdf = Bdf::from_address(self.bdf); - let vbdf = Bdf::from_address(self.vbdf); + let bdf = crate::pci::pci_struct::Bdf::from_address(self.bdf); + let vbdf = crate::pci::pci_struct::Bdf::from_address(self.vbdf); write!(f, "bdf {:#?} vbdf {:#?}", bdf, vbdf) } } diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index b3a10d48..eea5c55a 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -2,7 +2,7 @@ use alloc::collections::btree_map::BTreeMap; use spin::{Lazy, Mutex}; use crate::{ - config::{HvPciConfig, HvPciDevConfig, CONFIG_MAX_PCI_DEV, CONFIG_PCI_BUS_MAXLEN}, + config::{HvPciConfig, HvPciDevConfig, CONFIG_MAX_PCI_DEV, CONFIG_PCI_BUS_MAXNUM}, error::HvResult, pci::{ mem_alloc::BaseAllocator, @@ -20,7 +20,7 @@ pub static GLOBAL_PCIE_LIST: Lazy>> = }); /* add all dev to GLOBAL_PCIE_LIST */ -pub fn hvisor_pci_init(pci_rootcomplex_config: &[HvPciConfig; CONFIG_PCI_BUS_MAXLEN]) -> HvResult { +pub fn hvisor_pci_init(pci_rootcomplex_config: &[HvPciConfig; CONFIG_PCI_BUS_MAXNUM]) -> HvResult { for rootcomplex_config in pci_rootcomplex_config { /* empty config */ if rootcomplex_config.ecam_base == 0 { @@ -71,7 +71,7 @@ impl Zone { pub fn virtual_pci_mmio_init( &mut self, - pci_rootcomplex_config: &[HvPciConfig; CONFIG_PCI_BUS_MAXLEN], + pci_rootcomplex_config: &[HvPciConfig; CONFIG_PCI_BUS_MAXNUM], ) { for rootcomplex_config in pci_rootcomplex_config { /* empty config */ diff --git a/src/platform/mod.rs b/src/platform/mod.rs index e4d879ea..0925d21e 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -17,7 +17,7 @@ use crate::{ config::{ HvConfigMemoryRegion, HvIvcConfig, HvPciConfig, HvPciDevConfig, HvZoneConfig, CONFIG_MAX_INTERRUPTS, CONFIG_MAX_IVC_CONFIGS, CONFIG_MAX_MEMORY_REGIONS, - CONFIG_MAX_PCI_DEV, CONFIG_NAME_MAXLEN, CONFIG_PCI_BUS_MAXLEN, + CONFIG_MAX_PCI_DEV, CONFIG_NAME_MAXLEN, CONFIG_PCI_BUS_MAXNUM, }, consts::INVALID_ADDRESS, }; @@ -73,7 +73,7 @@ pub fn platform_root_zone_config() -> HvZoneConfig { name[..ROOT_ZONE_NAME.len()].copy_from_slice(ROOT_ZONE_NAME.as_bytes()); let mut pci_devs = [HvPciDevConfig::default(); CONFIG_MAX_PCI_DEV]; - let mut _root_pci_cfg = [HvPciConfig::new_empty(); CONFIG_PCI_BUS_MAXLEN]; + let mut _root_pci_cfg = [HvPciConfig::new_empty(); CONFIG_PCI_BUS_MAXNUM]; let mut _num_pci_devs: u64 = 0; #[cfg(feature = "pci")] From 9c7ac92767bf7a71e2dff6f7bb8fc1ac49cf8bcf Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 11 Sep 2025 00:59:12 +0800 Subject: [PATCH 03/12] [fixed] The bar remap is no longer mistakenly skipped --- src/pci/pci_access.rs | 92 +++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 48 deletions(-) diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 4f4c96a4..f4a152f3 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -908,58 +908,54 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { /* Linux traverses the PCI bus twice. During the first traversal, * it does not assign addresses to the BARs; it simply writes back the same * values. In the second traversal, it reorders the BARs and assigns - * addresses to them. If address allocation is performed during the first - * traversal, then in the second traversal conflicts may occur between the - * current BAR addresses and other BAR addresses that have not yet been updated. - * When the new and old values are the same, it indicates the first traversal, - * and no address remapping is performed. Only when the addresses are actually - * modified will remapping take place. + * addresses to them. Each time the guest writes to a BAR, + * it attempts to remove the previous mapping and add a new one. + * However, on the first access there is no prior mapping, so a single warning + * is normal. Subsequent warnings should be treated with caution. * - * This issue also leads to the hypervisor not fully supporting PCIe bus hot-reload: - * if the number of devices changes before and after the reload, address conflicts - * may also occur. + * TODO: When adding a new device or removing an old one, reloading + * the PCIe bus, will the newly written BAR address overlap with + * the old BAR addresses, potentially causing the update to fail? */ - if old_vaddr != new_vaddr { - if !gpm - .try_delete(old_vaddr.try_into().unwrap()) - .is_ok() - { - /* The first delete from the guest will fail - * because the region has not yet been inserted - */ - warn!( - "delete bar {}: can not found 0x{:x}", - slot, old_vaddr - ); - } - let paddr = bar.get_value64(); - debug!( - "old_vaddr {:x} new_vaddr {:x} paddr {:x}", - old_vaddr, new_vaddr, paddr + if !gpm + .try_delete(old_vaddr.try_into().unwrap()) + .is_ok() + { + /* The first delete from the guest will fail + * because the region has not yet been inserted + */ + warn!( + "delete bar {}: can not found 0x{:x}", + slot, old_vaddr ); + } + let paddr = bar.get_value64(); + debug!( + "old_vaddr {:x} new_vaddr {:x} paddr {:x}", + old_vaddr, new_vaddr, paddr + ); + + dev.set_bar_virtual_value(slot, new_vaddr); + if bar_type == PciMemType::Mem64High { + dev.set_bar_virtual_value( + slot - 1, + new_vaddr, + ); + } - dev.set_bar_virtual_value(slot, new_vaddr); - if bar_type == PciMemType::Mem64High { - dev.set_bar_virtual_value( - slot - 1, - new_vaddr, - ); - } - - gpm.insert( - MemoryRegion::new_with_offset_mapper( - new_vaddr as GuestPhysAddr, - paddr as HostPhysAddr, - bar.get_size() as _, - MemFlags::READ | MemFlags::WRITE, - ), - )?; - /* after update gpm, mem barrier is needed */ - unsafe { - core::arch::asm!("isb"); - core::arch::asm!("tlbi vmalls12e1is"); - core::arch::asm!("dsb nsh"); - } + gpm.insert( + MemoryRegion::new_with_offset_mapper( + new_vaddr as GuestPhysAddr, + paddr as HostPhysAddr, + bar.get_size() as _, + MemFlags::READ | MemFlags::WRITE, + ), + )?; + /* after update gpm, mem barrier is needed */ + unsafe { + core::arch::asm!("isb"); + core::arch::asm!("tlbi vmalls12e1is"); + core::arch::asm!("dsb nsh"); } } } From 74928420c5d04ddd89b31bfc74aaaa52d86d4656 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 11 Sep 2025 13:52:44 +0800 Subject: [PATCH 04/12] [fixed] Adapt PCI configuration changes for other zones --- .../aarch64/imx8mp/configs/zone1-ruxos.json | 2 +- platform/aarch64/qemu-gicv2/board.rs | 43 +----------------- platform/aarch64/qemu-gicv3/board.rs | 44 ++----------------- .../qemu-gicv3/configs/zone1-linux.json | 36 ++++++++------- platform/loongarch64/ls3a5000/board.rs | 43 +----------------- .../ls3a5000/configs/zone1-linux.json | 9 ++-- .../ls3a5000/configs/zone2-linux.json | 9 ++-- .../ls3a5000/configs/zone3-linux.json | 9 ++-- platform/loongarch64/ls3a6000/board.rs | 43 +----------------- .../ls3a6000/configs/zone1-linux.json | 5 ++- .../ls3a6000/configs/zone3-linux.json | 9 ++-- .../riscv64/qemu-aia/configs/zone1-linux.json | 15 +++++-- .../qemu-plic/configs/zone1-linux-io.json | 15 +++++-- .../qemu-plic/configs/zone1-linux.json | 15 +++++-- src/config.rs | 7 ++- src/pci/pci_config.rs | 23 +++++++--- src/pci/pci_struct.rs | 38 ++++++++-------- src/pci/pci_test.rs | 4 +- src/platform/mod.rs | 6 ++- src/zone.rs | 2 +- 20 files changed, 142 insertions(+), 235 deletions(-) diff --git a/platform/aarch64/imx8mp/configs/zone1-ruxos.json b/platform/aarch64/imx8mp/configs/zone1-ruxos.json index b882694a..82335457 100644 --- a/platform/aarch64/imx8mp/configs/zone1-ruxos.json +++ b/platform/aarch64/imx8mp/configs/zone1-ruxos.json @@ -74,5 +74,5 @@ }, "num_pci_devs": 0, "alloc_pci_devs": [], - "pci_config": {} + "pci_config": [] } diff --git a/platform/aarch64/qemu-gicv2/board.rs b/platform/aarch64/qemu-gicv2/board.rs index fcf4c97f..9a739804 100644 --- a/platform/aarch64/qemu-gicv2/board.rs +++ b/platform/aarch64/qemu-gicv2/board.rs @@ -92,7 +92,7 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { }; -pub const ROOT_PCI_CONFIG: [HvPciConfig; 4] = [ +pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ HvPciConfig { ecam_base: 0x4010000000, ecam_size: 0x10000000, @@ -105,46 +105,7 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 4] = [ mem64_base: 0x8000000000, mem64_size: 0x8000000000, pci_mem64_base: 0x8000000000, - }, - HvPciConfig { - ecam_base: 0x0, - ecam_size: 0x0, - io_base: 0x0, - io_size: 0x0, - pci_io_base: 0x0, - mem32_base: 0x0, - mem32_size: 0x0, - pci_mem32_base: 0x0, - mem64_base: 0x0, - mem64_size: 0x0, - pci_mem64_base: 0x0, - }, - HvPciConfig { - ecam_base: 0x0, - ecam_size: 0x0, - io_base: 0x0, - io_size: 0x0, - pci_io_base: 0x0, - mem32_base: 0x0, - mem32_size: 0x0, - pci_mem32_base: 0x0, - mem64_base: 0x0, - mem64_size: 0x0, - pci_mem64_base: 0x0, - }, - HvPciConfig { - ecam_base: 0x0, - ecam_size: 0x0, - io_base: 0x0, - io_size: 0x0, - pci_io_base: 0x0, - mem32_base: 0x0, - mem32_size: 0x0, - pci_mem32_base: 0x0, - mem64_base: 0x0, - mem64_size: 0x0, - pci_mem64_base: 0x0, - }, + } ]; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index 3bfab78c..ee5c92de 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -91,7 +91,7 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { }), }; -pub const ROOT_PCI_CONFIG: [HvPciConfig; 4] = [ +pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ HvPciConfig { ecam_base: 0x4010000000, ecam_size: 0x10000000, @@ -104,46 +104,7 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 4] = [ mem64_base: 0x8000000000, mem64_size: 0x8000000000, pci_mem64_base: 0x8000000000, - }, - HvPciConfig { - ecam_base: 0x0, - ecam_size: 0x0, - io_base: 0x0, - io_size: 0x0, - pci_io_base: 0x0, - mem32_base: 0x0, - mem32_size: 0x0, - pci_mem32_base: 0x0, - mem64_base: 0x0, - mem64_size: 0x0, - pci_mem64_base: 0x0, - }, - HvPciConfig { - ecam_base: 0x0, - ecam_size: 0x0, - io_base: 0x0, - io_size: 0x0, - pci_io_base: 0x0, - mem32_base: 0x0, - mem32_size: 0x0, - pci_mem32_base: 0x0, - mem64_base: 0x0, - mem64_size: 0x0, - pci_mem64_base: 0x0, - }, - HvPciConfig { - ecam_base: 0x0, - ecam_size: 0x0, - io_base: 0x0, - io_size: 0x0, - pci_io_base: 0x0, - mem32_base: 0x0, - mem32_size: 0x0, - pci_mem32_base: 0x0, - mem64_base: 0x0, - mem64_size: 0x0, - pci_mem64_base: 0x0, - }, + } ]; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; @@ -152,4 +113,5 @@ pub const ROOT_PCI_DEVS: [HvPciDevConfig; 3] = [ pci_dev!(0x0, 0x0, 0x0), pci_dev!(0x0, 0x1, 0x0), pci_dev!(0x0, 0x2, 0x0), + // pci_dev!(0x0, 0x3, 0x0), ]; diff --git a/platform/aarch64/qemu-gicv3/configs/zone1-linux.json b/platform/aarch64/qemu-gicv3/configs/zone1-linux.json index 17cb55f2..a4fa325d 100644 --- a/platform/aarch64/qemu-gicv3/configs/zone1-linux.json +++ b/platform/aarch64/qemu-gicv3/configs/zone1-linux.json @@ -1,5 +1,4 @@ { - "arch": "arm64", "name": "linux2", "zone_id": 1, "cpus": [2, 3], @@ -12,22 +11,15 @@ }, { "type": "virtio", - "physical_start": "0xa003800", - "virtual_start": "0xa003800", - "size": "0x200" - }, - { - "type": "virtio", - "physical_start": "0xa003c00", - "virtual_start": "0xa003c00", - "size": "0x200" + "physical_start": "0xa000000", + "virtual_start": "0xa000000", + "size": "0x4000" } ], "interrupts": [76, 78], "ivc_configs": [], - "kernel_filepath": "Image", - "kernel_args": "", - "dtb_filepath": "zone1-linux.dtb", + "kernel_filepath": "./Image", + "dtb_filepath": "./linux2.dtb", "kernel_load_paddr": "0x50400000", "dtb_load_paddr": "0x50000000", "entry_point": "0x50400000", @@ -38,9 +30,10 @@ "gicr_base": "0x80a0000", "gicr_size": "0xf60000", "gits_base": "0x8080000", - "gits_size": "0x20000" + "gits_size": "0x20000", + "is_aarch32": false }, - "pci_config": { + "pci_config": [{ "ecam_base": "0x4010000000", "ecam_size": "0x10000000", "io_base": "0x3eff0000", @@ -52,7 +45,16 @@ "mem64_base": "0x8000000000", "mem64_size": "0x8000000000", "pci_mem64_base": "0x8000000000" - }, + }], "num_pci_devs": 2, - "alloc_pci_devs": [0, 16] + "alloc_pci_devs": [ + { + "bdf": "0x0", + "vbdf": "0x0" + }, + { + "bdf": "0x18", + "vbdf": "0x18" + } + ] } \ No newline at end of file diff --git a/platform/loongarch64/ls3a5000/board.rs b/platform/loongarch64/ls3a5000/board.rs index ac2616ed..0be34690 100644 --- a/platform/loongarch64/ls3a5000/board.rs +++ b/platform/loongarch64/ls3a5000/board.rs @@ -155,7 +155,7 @@ pub const ROOT_ZONE_IRQS: [u32; 0] = []; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { dummy: 0 }; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; -pub const ROOT_PCI_CONFIG: [HvPciConfig; 4] = [ +pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ HvPciConfig { ecam_base: 0xfe00000000, ecam_size: 0x20000000, @@ -168,46 +168,7 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 4] = [ mem64_base: 0x60000000, mem64_size: 0x20000000, pci_mem64_base: 0x60000000, - }, - HvPciConfig { - ecam_base: 0x0, - ecam_size: 0x0, - io_base: 0x0, - io_size: 0x0, - pci_io_base: 0x0, - mem32_base: 0x0, - mem32_size: 0x0, - pci_mem32_base: 0x0, - mem64_base: 0x0, - mem64_size: 0x0, - pci_mem64_base: 0x0, - }, - HvPciConfig { - ecam_base: 0x0, - ecam_size: 0x0, - io_base: 0x0, - io_size: 0x0, - pci_io_base: 0x0, - mem32_base: 0x0, - mem32_size: 0x0, - pci_mem32_base: 0x0, - mem64_base: 0x0, - mem64_size: 0x0, - pci_mem64_base: 0x0, - }, - HvPciConfig { - ecam_base: 0x0, - ecam_size: 0x0, - io_base: 0x0, - io_size: 0x0, - pci_io_base: 0x0, - mem32_base: 0x0, - mem32_size: 0x0, - pci_mem32_base: 0x0, - mem64_base: 0x0, - mem64_size: 0x0, - pci_mem64_base: 0x0, - }, + } ]; /* 00:00.0, 00:00.1, 00:00.2, 00:00.3, 00:04.0, 00:04.1*/ diff --git a/platform/loongarch64/ls3a5000/configs/zone1-linux.json b/platform/loongarch64/ls3a5000/configs/zone1-linux.json index e56d3424..0b5fb081 100644 --- a/platform/loongarch64/ls3a5000/configs/zone1-linux.json +++ b/platform/loongarch64/ls3a5000/configs/zone1-linux.json @@ -111,7 +111,7 @@ "arch_config": { "dummy": "0x1234" }, - "pci_config": { + "pci_config": [{ "ecam_base": "0xfe00000000", "ecam_size": "0x20000000", "io_base": "0x18408000", @@ -123,7 +123,10 @@ "mem64_base": "0x60000000", "mem64_size": "0x20000000", "pci_mem64_base": "0x60000000" - }, + }], "num_pci_devs": 1, - "alloc_pci_devs": [1537] + "alloc_pci_devs": [{ + "bdf": "0x601", + "vbdf": "0x601" + }] } \ No newline at end of file diff --git a/platform/loongarch64/ls3a5000/configs/zone2-linux.json b/platform/loongarch64/ls3a5000/configs/zone2-linux.json index 8255f01e..be533e7d 100644 --- a/platform/loongarch64/ls3a5000/configs/zone2-linux.json +++ b/platform/loongarch64/ls3a5000/configs/zone2-linux.json @@ -99,7 +99,7 @@ "arch_config": { "dummy": "0x1234" }, - "pci_config": { + "pci_config": [{ "ecam_base": "0xfe00000000", "ecam_size": "0x20000000", "io_base": "0x18408000", @@ -111,7 +111,10 @@ "mem64_base": "0x60000000", "mem64_size": "0x20000000", "pci_mem64_base": "0x60000000" - }, + }], "num_pci_devs": 1, - "alloc_pci_devs": [1538] + "alloc_pci_devs": [{ + "bdf": "0x602", + "vbdf": "0x602" + }] } \ No newline at end of file diff --git a/platform/loongarch64/ls3a5000/configs/zone3-linux.json b/platform/loongarch64/ls3a5000/configs/zone3-linux.json index fcb03239..9d5d235f 100644 --- a/platform/loongarch64/ls3a5000/configs/zone3-linux.json +++ b/platform/loongarch64/ls3a5000/configs/zone3-linux.json @@ -99,7 +99,7 @@ "arch_config": { "dummy": "0x1234" }, - "pci_config": { + "pci_config": [{ "ecam_base": "0xfe00000000", "ecam_size": "0x20000000", "io_base": "0x18408000", @@ -111,7 +111,10 @@ "mem64_base": "0x60000000", "mem64_size": "0x20000000", "pci_mem64_base": "0x60000000" - }, + }], "num_pci_devs": 1, - "alloc_pci_devs": [1539] + "alloc_pci_devs": [{ + "bdf": "0x603", + "vbdf": "0x603" + }] } \ No newline at end of file diff --git a/platform/loongarch64/ls3a6000/board.rs b/platform/loongarch64/ls3a6000/board.rs index 2a4acc27..37b555f5 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -155,7 +155,7 @@ pub const ROOT_ZONE_IRQS: [u32; 0] = []; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { dummy: 0 }; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; -pub const ROOT_PCI_CONFIG: [HvPciConfig; 4] = [ +pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ HvPciConfig { ecam_base: 0xfe00000000, ecam_size: 0x20000000, @@ -168,46 +168,7 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 4] = [ mem64_base: 0x60000000, mem64_size: 0x20000000, pci_mem64_base: 0x60000000, - }, - HvPciConfig { - ecam_base: 0x0, - ecam_size: 0x0, - io_base: 0x0, - io_size: 0x0, - pci_io_base: 0x0, - mem32_base: 0x0, - mem32_size: 0x0, - pci_mem32_base: 0x0, - mem64_base: 0x0, - mem64_size: 0x0, - pci_mem64_base: 0x0, - }, - HvPciConfig { - ecam_base: 0x0, - ecam_size: 0x0, - io_base: 0x0, - io_size: 0x0, - pci_io_base: 0x0, - mem32_base: 0x0, - mem32_size: 0x0, - pci_mem32_base: 0x0, - mem64_base: 0x0, - mem64_size: 0x0, - pci_mem64_base: 0x0, - }, - HvPciConfig { - ecam_base: 0x0, - ecam_size: 0x0, - io_base: 0x0, - io_size: 0x0, - pci_io_base: 0x0, - mem32_base: 0x0, - mem32_size: 0x0, - pci_mem32_base: 0x0, - mem64_base: 0x0, - mem64_size: 0x0, - pci_mem64_base: 0x0, - }, + } ]; /* 00:00.0, 00:00.1, 00:00.2, 00:00.3, 00:04.0, 00:04.1*/ diff --git a/platform/loongarch64/ls3a6000/configs/zone1-linux.json b/platform/loongarch64/ls3a6000/configs/zone1-linux.json index e56d3424..af02a43d 100644 --- a/platform/loongarch64/ls3a6000/configs/zone1-linux.json +++ b/platform/loongarch64/ls3a6000/configs/zone1-linux.json @@ -125,5 +125,8 @@ "pci_mem64_base": "0x60000000" }, "num_pci_devs": 1, - "alloc_pci_devs": [1537] + "alloc_pci_devs": [{ + "bdf": "0x601", + "vbdf": "0x601" + }] } \ No newline at end of file diff --git a/platform/loongarch64/ls3a6000/configs/zone3-linux.json b/platform/loongarch64/ls3a6000/configs/zone3-linux.json index fcb03239..9d5d235f 100644 --- a/platform/loongarch64/ls3a6000/configs/zone3-linux.json +++ b/platform/loongarch64/ls3a6000/configs/zone3-linux.json @@ -99,7 +99,7 @@ "arch_config": { "dummy": "0x1234" }, - "pci_config": { + "pci_config": [{ "ecam_base": "0xfe00000000", "ecam_size": "0x20000000", "io_base": "0x18408000", @@ -111,7 +111,10 @@ "mem64_base": "0x60000000", "mem64_size": "0x20000000", "pci_mem64_base": "0x60000000" - }, + }], "num_pci_devs": 1, - "alloc_pci_devs": [1539] + "alloc_pci_devs": [{ + "bdf": "0x603", + "vbdf": "0x603" + }] } \ No newline at end of file diff --git a/platform/riscv64/qemu-aia/configs/zone1-linux.json b/platform/riscv64/qemu-aia/configs/zone1-linux.json index 7dd2e0b8..c5d90065 100644 --- a/platform/riscv64/qemu-aia/configs/zone1-linux.json +++ b/platform/riscv64/qemu-aia/configs/zone1-linux.json @@ -36,7 +36,7 @@ "aplic_base": "0xd000000", "aplic_size": "0x8000" }, - "pci_config": { + "pci_config": [{ "ecam_base": "0x30000000", "ecam_size": "0x10000000", "io_base": "0x3000000", @@ -48,7 +48,16 @@ "mem64_base": "0x400000000", "mem64_size": "0x400000000", "pci_mem64_base": "0x400000000" - }, + }], "num_pci_devs": 2, - "alloc_pci_devs": [0, 16] + "alloc_pci_devs": [ + { + "bdf": "0x0", + "vbdf": "0x0" + }, + { + "bdf": "0x10", + "vbdf": "0x10" + } + ] } \ No newline at end of file diff --git a/platform/riscv64/qemu-plic/configs/zone1-linux-io.json b/platform/riscv64/qemu-plic/configs/zone1-linux-io.json index 3ca63476..710fec27 100644 --- a/platform/riscv64/qemu-plic/configs/zone1-linux-io.json +++ b/platform/riscv64/qemu-plic/configs/zone1-linux-io.json @@ -36,7 +36,7 @@ "aplic_base": "0xd000000", "aplic_size": "0x8000" }, - "pci_config": { + "pci_config": [{ "ecam_base": "0x30000000", "ecam_size": "0x10000000", "io_base": "0x3000000", @@ -48,7 +48,16 @@ "mem64_base": "0x400000000", "mem64_size": "0x400000000", "pci_mem64_base": "0x400000000" - }, + }], "num_pci_devs": 2, - "alloc_pci_devs": [0, 16] + "alloc_pci_devs": [ + { + "bdf": "0x0", + "vbdf": "0x0" + }, + { + "bdf": "0x10", + "vbdf": "0x10" + } + ] } \ No newline at end of file diff --git a/platform/riscv64/qemu-plic/configs/zone1-linux.json b/platform/riscv64/qemu-plic/configs/zone1-linux.json index 798e7be2..b3b77ac1 100644 --- a/platform/riscv64/qemu-plic/configs/zone1-linux.json +++ b/platform/riscv64/qemu-plic/configs/zone1-linux.json @@ -36,7 +36,7 @@ "aplic_base": "0xd000000", "aplic_size": "0x8000" }, - "pci_config": { + "pci_config": [{ "ecam_base": "0x30000000", "ecam_size": "0x10000000", "io_base": "0x3000000", @@ -48,7 +48,16 @@ "mem64_base": "0x400000000", "mem64_size": "0x400000000", "pci_mem64_base": "0x400000000" - }, + }], "num_pci_devs": 2, - "alloc_pci_devs": [0, 16] + "alloc_pci_devs": [ + { + "bdf": "0x0", + "vbdf": "0x0" + }, + { + "bdf": "0x10", + "vbdf": "0x10" + } + ] } \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index 9301468f..c2fa1137 100644 --- a/src/config.rs +++ b/src/config.rs @@ -93,6 +93,7 @@ pub struct HvZoneConfig { pub dtb_size: u64, pub name: [u8; CONFIG_NAME_MAXLEN], pub arch_config: HvArchZoneConfig, + pub num_pci_bus: u64, pub pci_config: [HvPciConfig; CONFIG_PCI_BUS_MAXNUM], pub num_pci_devs: u64, pub alloc_pci_devs: [HvPciDevConfig; CONFIG_MAX_PCI_DEV], @@ -115,6 +116,7 @@ impl HvZoneConfig { dtb_size: u64, name: [u8; CONFIG_NAME_MAXLEN], arch: HvArchZoneConfig, + num_pci_bus: u64, pci: [HvPciConfig; CONFIG_PCI_BUS_MAXNUM], num_pci_devs: u64, alloc_pci_devs: [HvPciDevConfig; CONFIG_MAX_PCI_DEV], @@ -135,6 +137,7 @@ impl HvZoneConfig { dtb_size, name, arch_config: arch, + num_pci_bus, pci_config: pci, num_pci_devs: num_pci_devs, alloc_pci_devs: alloc_pci_devs, @@ -206,8 +209,8 @@ pub struct HvPciDevConfig { macro_rules! pci_dev { ($bus:expr, $dev:expr, $func:expr) => { HvPciDevConfig { - bdf: ($bus << 20) | ($dev << 15) | ($func << 12), - vbdf: ($bus << 20) | ($dev << 15) | ($func << 12), + bdf: ($bus << 8) | ($dev << 3) | ($func), + vbdf: ($bus << 8) | ($dev << 3) | ($func), } }; } diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index eea5c55a..1de93c88 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -55,13 +55,23 @@ impl Zone { let mut i = 0; while i < num_pci_devs { let dev_config = alloc_pci_devs[i as usize]; - let bdf = Bdf::from_address(dev_config.bdf); - let vbdf = Bdf::from_address(dev_config.vbdf); - if let Some(mut vdev) = guard.remove(&bdf) { - vdev.set_vbdf(vbdf); - self.vpci_bus.insert(vbdf, vdev); + let bdf = Bdf::from_address(dev_config.bdf << 12); + let vbdf = Bdf::from_address(dev_config.vbdf << 12); + if bdf.is_host_bridge() { + if let Some(mut vdev) = guard.get(&bdf) { + let mut vdev = vdev.clone(); + vdev.set_vbdf(vbdf); + self.vpci_bus.insert(vbdf, vdev); + } else { + warn!("can not find host bridge {:#?}", bdf); + } } else { - warn!("can not find dev {:#?}", bdf); + if let Some(mut vdev) = guard.remove(&bdf) { + vdev.set_vbdf(vbdf); + self.vpci_bus.insert(vbdf, vdev); + } else { + warn!("can not find dev {:#?}", bdf); + } } i += 1; } @@ -72,6 +82,7 @@ impl Zone { pub fn virtual_pci_mmio_init( &mut self, pci_rootcomplex_config: &[HvPciConfig; CONFIG_PCI_BUS_MAXNUM], + _num_pci_bus: u64 ) { for rootcomplex_config in pci_rootcomplex_config { /* empty config */ diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index f12e3a00..c716fcde 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -1,8 +1,8 @@ use core::{ - cmp::Ordering, fmt::Debug, hint::spin_loop, ops::Range, str::FromStr, sync::atomic::AtomicBool, + cmp::Ordering, fmt::Debug, hint::spin_loop, ops::Range, str::FromStr, }; -use alloc::{boxed::Box, collections::btree_map::BTreeMap, vec::Vec}; +use alloc::{collections::btree_map::BTreeMap, sync::Arc, vec::Vec}; use bit_field::BitField; use bitvec::{array::BitArray, order::Lsb0, BitArr}; @@ -72,6 +72,14 @@ impl Bdf { address.set_bits(20..28, self.bus as u64); address } + + pub fn is_host_bridge(&self) -> bool { + if (self.device, self.function) == (0, 0) { + true + } else { + false + } + } } impl Ord for Bdf { @@ -193,8 +201,8 @@ impl VirtualPciAccessBits { * control: control the satus of rw every bit in config space * access: Determines whether the variable is read from space or hw * backend: the hw rw interface - * disabled: not used yet */ +#[derive(Clone)] pub struct VirtualPciConfigSpace { bdf: Bdf, vbdf: Bdf, @@ -204,12 +212,10 @@ pub struct VirtualPciConfigSpace { control: VirtualPciConfigControl, access: VirtualPciAccessBits, - backend: Box, + backend: Arc, bararr: Bar, rom: PciMem, - - disabled: AtomicBool, } impl VirtualPciConfigSpace { @@ -280,7 +286,7 @@ impl Debug for VirtualPciConfigSpace { } impl VirtualPciConfigSpace { - pub fn endpoint(bdf: Bdf, backend: Box, bararr: Bar, rom: PciMem) -> Self { + pub fn endpoint(bdf: Bdf, backend: Arc, bararr: Bar, rom: PciMem) -> Self { Self { bdf, vbdf: Bdf::default(), @@ -291,11 +297,10 @@ impl VirtualPciConfigSpace { backend, bararr, rom, - disabled: AtomicBool::new(false), } } - pub fn bridge(bdf: Bdf, backend: Box, bararr: Bar) -> Self { + pub fn bridge(bdf: Bdf, backend: Arc, bararr: Bar) -> Self { Self { bdf, vbdf: Bdf::default(), @@ -306,11 +311,10 @@ impl VirtualPciConfigSpace { backend, bararr, rom: PciMem::default(), - disabled: AtomicBool::new(false), } } - pub fn unknown(bdf: Bdf, backend: Box) -> Self { + pub fn unknown(bdf: Bdf, backend: Arc) -> Self { Self { bdf, vbdf: Bdf::default(), @@ -321,11 +325,10 @@ impl VirtualPciConfigSpace { backend, bararr: Bar::default(), rom: PciMem::default(), - disabled: AtomicBool::new(false), } } - pub fn host_bridge(bdf: Bdf, backend: Box) -> Self { + pub fn host_bridge(bdf: Bdf, backend: Arc) -> Self { Self { bdf: bdf, vbdf: bdf, @@ -336,7 +339,6 @@ impl VirtualPciConfigSpace { backend, bararr: Bar::default(), rom: PciMem::default(), - disabled: AtomicBool::new(false), } } @@ -354,8 +356,6 @@ impl VirtualPciConfigSpace { pub fn set_vbdf(&mut self, vbdf: Bdf) { self.vbdf = vbdf; - self.disabled - .store(true, core::sync::atomic::Ordering::SeqCst); } /* now the space_init just with bar @@ -521,20 +521,20 @@ impl PciIterator { i += 1; } } - let ep = Box::new(ep); + let ep = Arc::new(ep); let bdf = Bdf::from_address(address); Some(VirtualPciConfigSpace::endpoint(bdf, ep, bararr, rom)) } HeaderType::PciBridge => { warn!("bridge"); let bridge = PciBridgeHeader::new_with_region(region); - let bridge = Box::new(bridge); + let bridge = Arc::new(bridge); let bdf = Bdf::from_address(address); Some(VirtualPciConfigSpace::bridge(bdf, bridge, Bar::default())) } _ => { warn!("unknown type"); - let pci_header = Box::new(pci_header); + let pci_header = Arc::new(pci_header); let bdf = Bdf::from_address(address); Some(VirtualPciConfigSpace::unknown(bdf, pci_header)) } diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs index 4fa97841..61d1fdc4 100644 --- a/src/pci/pci_test.rs +++ b/src/pci/pci_test.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] use core::str::FromStr; -use alloc::{boxed::Box, collections::btree_map::BTreeMap}; +use alloc::{collections::btree_map::BTreeMap, sync::Arc}; use spin::{lazy::Lazy, mutex::Mutex}; use crate::{ @@ -48,7 +48,7 @@ pub fn pcie_guest_init() { bdf.to_address(0) + 0x4010000000, CONFIG_LENTH, )); - let dev = VirtualPciConfigSpace::host_bridge(bdf, Box::new(backend)); + let dev = VirtualPciConfigSpace::host_bridge(bdf, Arc::new(backend)); vbus.insert(vbdf, dev); let vbdf = Bdf::from_str("0000:00:01.0").unwrap(); diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 0925d21e..10514ead 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -75,13 +75,16 @@ pub fn platform_root_zone_config() -> HvZoneConfig { let mut pci_devs = [HvPciDevConfig::default(); CONFIG_MAX_PCI_DEV]; let mut _root_pci_cfg = [HvPciConfig::new_empty(); CONFIG_PCI_BUS_MAXNUM]; let mut _num_pci_devs: u64 = 0; + let mut _num_pci_bus: u64 = 0; #[cfg(feature = "pci")] { check!(ROOT_PCI_DEVS.len(), CONFIG_MAX_PCI_DEV, "ROOT_PCI_DEVS"); pci_devs[..ROOT_PCI_DEVS.len()].copy_from_slice(&ROOT_PCI_DEVS); - _root_pci_cfg = ROOT_PCI_CONFIG; + check!(ROOT_PCI_CONFIG.len(), CONFIG_PCI_BUS_MAXNUM, "ROOT_PCI_CONFIG"); + _root_pci_cfg[..ROOT_PCI_CONFIG.len()].copy_from_slice(&ROOT_PCI_CONFIG); _num_pci_devs = ROOT_PCI_DEVS.len() as _; + _num_pci_bus = ROOT_PCI_CONFIG.len() as _; } HvZoneConfig::new( @@ -100,6 +103,7 @@ pub fn platform_root_zone_config() -> HvZoneConfig { INVALID_ADDRESS as _, name, ROOT_ARCH_ZONE_CONFIG, + _num_pci_bus, _root_pci_cfg, _num_pci_devs, pci_devs, diff --git a/src/zone.rs b/src/zone.rs index 73d90698..8db28181 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -210,7 +210,7 @@ pub fn zone_create(config: &HvZoneConfig) -> HvResult>> { zone.mmio_init(&config.arch_config); #[cfg(feature = "pci")] { - let _ = zone.virtual_pci_mmio_init(&config.pci_config); + let _ = zone.virtual_pci_mmio_init(&config.pci_config, config.num_pci_bus); let _ = zone.guest_pci_init(&config.alloc_pci_devs, config.num_pci_devs); } // #[cfg(target_arch = "aarch64")] From d395612ade9f93723a7306c932306edd3dbc86e6 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 11 Sep 2025 13:54:10 +0800 Subject: [PATCH 05/12] [fixed] fmt --- platform/aarch64/qemu-gicv3/board.rs | 28 +++++++++++------------ src/config.rs | 2 +- src/pci/pci_access.rs | 33 ++++++++++++---------------- src/pci/pci_config.rs | 2 +- src/pci/pci_struct.rs | 4 +--- src/platform/mod.rs | 6 ++++- 6 files changed, 35 insertions(+), 40 deletions(-) diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index ee5c92de..107e9995 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -91,21 +91,19 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { }), }; -pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ - HvPciConfig { - ecam_base: 0x4010000000, - ecam_size: 0x10000000, - io_base: 0x3eff0000, - io_size: 0x10000, - pci_io_base: 0x0, - mem32_base: 0x10000000, - mem32_size: 0x2eff0000, - pci_mem32_base: 0x10000000, - mem64_base: 0x8000000000, - mem64_size: 0x8000000000, - pci_mem64_base: 0x8000000000, - } -]; +pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { + ecam_base: 0x4010000000, + ecam_size: 0x10000000, + io_base: 0x3eff0000, + io_size: 0x10000, + pci_io_base: 0x0, + mem32_base: 0x10000000, + mem32_size: 0x2eff0000, + pci_mem32_base: 0x10000000, + mem64_base: 0x8000000000, + mem64_size: 0x8000000000, + pci_mem64_base: 0x8000000000, +}]; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; diff --git a/src/config.rs b/src/config.rs index c2fa1137..17a7a87c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -14,8 +14,8 @@ // Authors: // use alloc::vec::Vec; -use spin::Once; use core::fmt::Debug; +use spin::Once; use crate::{arch::zone::HvArchZoneConfig, platform}; diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index f4a152f3..66ba29f9 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -908,13 +908,13 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { /* Linux traverses the PCI bus twice. During the first traversal, * it does not assign addresses to the BARs; it simply writes back the same * values. In the second traversal, it reorders the BARs and assigns - * addresses to them. Each time the guest writes to a BAR, - * it attempts to remove the previous mapping and add a new one. - * However, on the first access there is no prior mapping, so a single warning + * addresses to them. Each time the guest writes to a BAR, + * it attempts to remove the previous mapping and add a new one. + * However, on the first access there is no prior mapping, so a single warning * is normal. Subsequent warnings should be treated with caution. * - * TODO: When adding a new device or removing an old one, reloading - * the PCIe bus, will the newly written BAR address overlap with + * TODO: When adding a new device or removing an old one, reloading + * the PCIe bus, will the newly written BAR address overlap with * the old BAR addresses, potentially causing the update to fail? */ if !gpm @@ -922,8 +922,8 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { .is_ok() { /* The first delete from the guest will fail - * because the region has not yet been inserted - */ + * because the region has not yet been inserted + */ warn!( "delete bar {}: can not found 0x{:x}", slot, old_vaddr @@ -937,20 +937,15 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { dev.set_bar_virtual_value(slot, new_vaddr); if bar_type == PciMemType::Mem64High { - dev.set_bar_virtual_value( - slot - 1, - new_vaddr, - ); + dev.set_bar_virtual_value(slot - 1, new_vaddr); } - gpm.insert( - MemoryRegion::new_with_offset_mapper( - new_vaddr as GuestPhysAddr, - paddr as HostPhysAddr, - bar.get_size() as _, - MemFlags::READ | MemFlags::WRITE, - ), - )?; + gpm.insert(MemoryRegion::new_with_offset_mapper( + new_vaddr as GuestPhysAddr, + paddr as HostPhysAddr, + bar.get_size() as _, + MemFlags::READ | MemFlags::WRITE, + ))?; /* after update gpm, mem barrier is needed */ unsafe { core::arch::asm!("isb"); diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 1de93c88..06c23636 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -82,7 +82,7 @@ impl Zone { pub fn virtual_pci_mmio_init( &mut self, pci_rootcomplex_config: &[HvPciConfig; CONFIG_PCI_BUS_MAXNUM], - _num_pci_bus: u64 + _num_pci_bus: u64, ) { for rootcomplex_config in pci_rootcomplex_config { /* empty config */ diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index c716fcde..cb6ad54b 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -1,6 +1,4 @@ -use core::{ - cmp::Ordering, fmt::Debug, hint::spin_loop, ops::Range, str::FromStr, -}; +use core::{cmp::Ordering, fmt::Debug, hint::spin_loop, ops::Range, str::FromStr}; use alloc::{collections::btree_map::BTreeMap, sync::Arc, vec::Vec}; use bit_field::BitField; diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 10514ead..95fc4a88 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -81,7 +81,11 @@ pub fn platform_root_zone_config() -> HvZoneConfig { { check!(ROOT_PCI_DEVS.len(), CONFIG_MAX_PCI_DEV, "ROOT_PCI_DEVS"); pci_devs[..ROOT_PCI_DEVS.len()].copy_from_slice(&ROOT_PCI_DEVS); - check!(ROOT_PCI_CONFIG.len(), CONFIG_PCI_BUS_MAXNUM, "ROOT_PCI_CONFIG"); + check!( + ROOT_PCI_CONFIG.len(), + CONFIG_PCI_BUS_MAXNUM, + "ROOT_PCI_CONFIG" + ); _root_pci_cfg[..ROOT_PCI_CONFIG.len()].copy_from_slice(&ROOT_PCI_CONFIG); _num_pci_devs = ROOT_PCI_DEVS.len() as _; _num_pci_bus = ROOT_PCI_CONFIG.len() as _; From 0f64e9430f497cd6d2ec0dd2d86720a7d5fc5923 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 11 Sep 2025 13:56:45 +0800 Subject: [PATCH 06/12] [fixed] fix loongarch64 config for pci changes --- platform/loongarch64/ls3a6000/configs/zone1-linux.json | 4 ++-- platform/loongarch64/ls3a6000/configs/zone2-linux.json | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/platform/loongarch64/ls3a6000/configs/zone1-linux.json b/platform/loongarch64/ls3a6000/configs/zone1-linux.json index af02a43d..0b5fb081 100644 --- a/platform/loongarch64/ls3a6000/configs/zone1-linux.json +++ b/platform/loongarch64/ls3a6000/configs/zone1-linux.json @@ -111,7 +111,7 @@ "arch_config": { "dummy": "0x1234" }, - "pci_config": { + "pci_config": [{ "ecam_base": "0xfe00000000", "ecam_size": "0x20000000", "io_base": "0x18408000", @@ -123,7 +123,7 @@ "mem64_base": "0x60000000", "mem64_size": "0x20000000", "pci_mem64_base": "0x60000000" - }, + }], "num_pci_devs": 1, "alloc_pci_devs": [{ "bdf": "0x601", diff --git a/platform/loongarch64/ls3a6000/configs/zone2-linux.json b/platform/loongarch64/ls3a6000/configs/zone2-linux.json index 8255f01e..be533e7d 100644 --- a/platform/loongarch64/ls3a6000/configs/zone2-linux.json +++ b/platform/loongarch64/ls3a6000/configs/zone2-linux.json @@ -99,7 +99,7 @@ "arch_config": { "dummy": "0x1234" }, - "pci_config": { + "pci_config": [{ "ecam_base": "0xfe00000000", "ecam_size": "0x20000000", "io_base": "0x18408000", @@ -111,7 +111,10 @@ "mem64_base": "0x60000000", "mem64_size": "0x20000000", "pci_mem64_base": "0x60000000" - }, + }], "num_pci_devs": 1, - "alloc_pci_devs": [1538] + "alloc_pci_devs": [{ + "bdf": "0x602", + "vbdf": "0x602" + }] } \ No newline at end of file From a5886e4b5bd8702b471d580d5b31b9540a3eab18 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 11 Sep 2025 15:27:25 +0800 Subject: [PATCH 07/12] [fixed] fix ci --- .gitignore | 4 ++-- .../aarch64/qemu-gicv2/image/dts/zone0.dts | 18 ++++++++++++++++++ src/arch/loongarch64/zone.rs | 10 +--------- src/main.rs | 9 ++++++--- src/pci/mem_alloc.rs | 15 +++++++++++++++ src/pci/mod.rs | 15 +++++++++++++++ src/pci/pci_access.rs | 15 +++++++++++++++ src/pci/pci_config.rs | 15 +++++++++++++++ src/pci/pci_mem.rs | 15 +++++++++++++++ src/pci/pci_struct.rs | 15 +++++++++++++++ src/pci/pci_test.rs | 15 +++++++++++++++ src/zone.rs | 2 -- 12 files changed, 132 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 4cb7754b..ee35f79a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,8 @@ /hvisor.S /hvisor-elf.txt /images/* -/platform/*/*/image/kernel/* -/platform/*/*/image/virtdisk/* +/platform/*/*/image/kernel +/platform/*/*/image/virtdisk /tools/hvisor /tmp *.mod.[co] diff --git a/platform/aarch64/qemu-gicv2/image/dts/zone0.dts b/platform/aarch64/qemu-gicv2/image/dts/zone0.dts index c17e8e7f..8cbcae70 100644 --- a/platform/aarch64/qemu-gicv2/image/dts/zone0.dts +++ b/platform/aarch64/qemu-gicv2/image/dts/zone0.dts @@ -85,6 +85,24 @@ compatible = "arm,armv8-timer\0arm,armv7-timer"; }; + pcie@10000000 { + interrupt-map-mask = <0x1800 0x00 0x00 0x07>; + interrupt-map = <0x00 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x03 0x04 0x00 0x00 0x00 0x02 0x01 0x00 0x00 0x00 0x04 0x04 0x00 0x00 0x00 0x03 0x01 0x00 0x00 0x00 0x05 0x04 0x00 0x00 0x00 0x04 0x01 0x00 0x00 0x00 0x06 0x04 0x800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x04 0x04 0x800 0x00 0x00 0x02 0x01 0x00 0x00 0x00 0x05 0x04 0x800 0x00 0x00 0x03 0x01 0x00 0x00 0x00 0x06 0x04 0x800 0x00 0x00 0x04 0x01 0x00 0x00 0x00 0x03 0x04 0x1000 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x05 0x04 0x1000 0x00 0x00 0x02 0x01 0x00 0x00 0x00 0x06 0x04 0x1000 0x00 0x00 0x03 0x01 0x00 0x00 0x00 0x03 0x04 0x1000 0x00 0x00 0x04 0x01 0x00 0x00 0x00 0x04 0x04 0x1800 0x00 0x00 0x01 0x01 0x00 0x00 0x00 0x06 0x04 0x1800 0x00 0x00 0x02 0x01 0x00 0x00 0x00 0x03 0x04 0x1800 0x00 0x00 0x03 0x01 0x00 0x00 0x00 0x04 0x04 0x1800 0x00 0x00 0x04 0x01 0x00 0x00 0x00 0x05 0x04>; + #interrupt-cells = <0x01>; + ranges = <0x1000000 0x00 0x00 0x00 0x3eff0000 0x00 0x10000 + 0x2000000 0x00 0x10000000 0x00 0x10000000 0x00 0x2eff0000 + 0x3000000 0x80 0x00 0x80 0x00 0x80 0x00>; + reg = <0x40 0x10000000 0x00 0x10000000>; + msi-map = <0x00 0x8006 0x00 0x10000>; + dma-coherent; + bus-range = <0x00 0xff>; + linux,pci-domain = <0x00>; + #size-cells = <0x02>; + #address-cells = <0x03>; + device_type = "pci"; + compatible = "pci-host-ecam-generic"; + }; + virtio_mmio@a003a00 { dma-coherent; interrupt-parent = <0x01>; diff --git a/src/arch/loongarch64/zone.rs b/src/arch/loongarch64/zone.rs index 419b29ef..c5a1cde3 100644 --- a/src/arch/loongarch64/zone.rs +++ b/src/arch/loongarch64/zone.rs @@ -684,14 +684,6 @@ impl Zone { } pub fn arch_zone_configuration(&mut self, config: &HvZoneConfig) -> HvResult { - let vaddr = config.pci_config.ecam_base; - let size = config.pci_config.ecam_size; - self.gpm.insert(MemoryRegion::new_with_offset_mapper( - vaddr as GuestPhysAddr, - vaddr as HostPhysAddr, - size as _, - MemFlags::READ | MemFlags::WRITE | MemFlags::IO, - ))?; - self.gpm.delete(vaddr as GuestPhysAddr) + Ok(()) } } diff --git a/src/main.rs b/src/main.rs index e710fd1e..67c24db2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -136,15 +136,18 @@ fn primary_init_early() { iommu_init(); + let root_config = root_zone_config(); + #[cfg(feature = "pci")] { - let config = unsafe { config::HV_ROOT_ZONE_CONFIG.get().unwrap().pci_config }; - let _ = hvisor_pci_init(&config); + info!("1"); + let _ = hvisor_pci_init(&root_config.pci_config); + info!("3"); } #[cfg(not(test))] { - let zone = zone_create(root_zone_config()).unwrap(); + let zone = zone_create(root_config).unwrap(); add_zone(zone); } INIT_EARLY_OK.store(1, Ordering::Release); diff --git a/src/pci/mem_alloc.rs b/src/pci/mem_alloc.rs index 73b8cf53..7e4533fe 100644 --- a/src/pci/mem_alloc.rs +++ b/src/pci/mem_alloc.rs @@ -1,3 +1,18 @@ +// Copyright (c) 2025 Syswonder +// hvisor is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +// FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. +// +// Syswonder Website: +// https://www.syswonder.org +// +// Authors: +// use core::{fmt::Debug, ops::Range}; pub type Mem32Address = u32; diff --git a/src/pci/mod.rs b/src/pci/mod.rs index 8df8db9a..02c3259e 100644 --- a/src/pci/mod.rs +++ b/src/pci/mod.rs @@ -1,3 +1,18 @@ +// Copyright (c) 2025 Syswonder +// hvisor is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +// FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. +// +// Syswonder Website: +// https://www.syswonder.org +// +// Authors: +// pub mod mem_alloc; pub mod pci_access; pub mod pci_config; diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 66ba29f9..16245dec 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -1,3 +1,18 @@ +// Copyright (c) 2025 Syswonder +// hvisor is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +// FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. +// +// Syswonder Website: +// https://www.syswonder.org +// +// Authors: +// #![allow(dead_code)] use core::{ fmt::Debug, diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 06c23636..10278b39 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -1,3 +1,18 @@ +// Copyright (c) 2025 Syswonder +// hvisor is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +// FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. +// +// Syswonder Website: +// https://www.syswonder.org +// +// Authors: +// use alloc::collections::btree_map::BTreeMap; use spin::{Lazy, Mutex}; diff --git a/src/pci/pci_mem.rs b/src/pci/pci_mem.rs index 5b59272a..e2240d3f 100644 --- a/src/pci/pci_mem.rs +++ b/src/pci/pci_mem.rs @@ -1,3 +1,18 @@ +// Copyright (c) 2025 Syswonder +// hvisor is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +// FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. +// +// Syswonder Website: +// https://www.syswonder.org +// +// Authors: +// use core::{any::Any, fmt::Debug}; use crate::error::HvResult; diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index cb6ad54b..c753ee87 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -1,3 +1,18 @@ +// Copyright (c) 2025 Syswonder +// hvisor is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +// FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. +// +// Syswonder Website: +// https://www.syswonder.org +// +// Authors: +// use core::{cmp::Ordering, fmt::Debug, hint::spin_loop, ops::Range, str::FromStr}; use alloc::{collections::btree_map::BTreeMap, sync::Arc, vec::Vec}; diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs index 61d1fdc4..f0ec3c22 100644 --- a/src/pci/pci_test.rs +++ b/src/pci/pci_test.rs @@ -1,3 +1,18 @@ +// Copyright (c) 2025 Syswonder +// hvisor is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR +// FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. +// +// Syswonder Website: +// https://www.syswonder.org +// +// Authors: +// #![allow(dead_code)] use core::str::FromStr; diff --git a/src/zone.rs b/src/zone.rs index 8db28181..70cc8e65 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -39,8 +39,6 @@ pub struct Zone { pub cpu_set: CpuSet, pub irq_bitmap: [u32; 1024 / 32], pub gpm: MemorySet, - #[cfg(all(target_arch = "riscv64", feature = "plic"))] - pub vplic: Option, pub is_err: bool, #[cfg(feature = "pci")] pub vpci_bus: VirtualRootComplex, From e369ee00935226ffb0ac62b5348ce4221a2b7e63 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 11 Sep 2025 22:07:38 +0800 Subject: [PATCH 08/12] [feature] pci:add parse of bridge --- src/pci/pci_access.rs | 501 +++++++++++++++++++++++++----------------- src/pci/pci_struct.rs | 88 +++++--- 2 files changed, 355 insertions(+), 234 deletions(-) diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 16245dec..d80bf10e 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -13,7 +13,7 @@ // // Authors: // -#![allow(dead_code)] +// #![allow(dead_code)] use core::{ fmt::Debug, ops::{Index, IndexMut}, @@ -37,11 +37,6 @@ use super::{ PciConfigAddress, }; -pub trait PciRW: Debug + Send + Sync { - fn read(&self, offset: PciConfigAddress, size: usize) -> HvResult; - fn write(&self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult; -} - pub type VendorId = u16; pub type DeviceId = u16; pub type DeviceRevision = u8; @@ -459,6 +454,191 @@ impl Debug for Bar { } } +pub trait PciRWBase: Debug + Send + Sync { + fn backend(&self) -> &dyn PciRegion; +} +pub trait PciRW: Debug + Send + Sync + PciRWBase { + fn read(&self, offset: PciConfigAddress, size: usize) -> HvResult { + match size { + 1 => self.backend().read_u8(offset).map(|v| v as usize), + 2 => self.backend().read_u16(offset).map(|v| v as usize), + 4 => self.backend().read_u32(offset).map(|v| v as usize), + _ => { + hv_result_err!(EFAULT, "pci: invalid mmio read size: {size}") + } + } + } + fn write(&self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { + match size { + 1 => self.backend().write_u8(offset, value as u8), + 2 => self.backend().write_u16(offset, value as u16), + 4 => self.backend().write_u32(offset, value as u32), + _ => { + hv_result_err!(EFAULT, "pci: invalid mmio write size: {size}") + } + } + } +} + +pub trait PciHeaderRW: PciRWBase { + fn id(&self) -> (DeviceId, VendorId) { + let id = self.backend().read_u32(0x00).unwrap(); + ( + id.get_bits(0..16) as VendorId, + id.get_bits(16..32) as DeviceId, + ) + } + + fn header_type(&self) -> HeaderType { + match self.backend().read_u8(0x0e).unwrap().get_bits(0..7) { + 0x00 => HeaderType::Endpoint, + 0x01 => HeaderType::PciBridge, + 0x02 => HeaderType::CardBusBridge, + v => HeaderType::Unknown(v as u8), + } + } + + fn has_multiple_functions(&self) -> bool { + self.backend().read_u8(0x0c).unwrap().get_bit(7) + } + + fn revision_and_class(&self) -> (DeviceRevision, BaseClass, SubClass, Interface) { + let value = self.backend().read_u32(0x08).unwrap(); + ( + value.get_bits(0..8) as DeviceRevision, + value.get_bits(24..32) as BaseClass, + value.get_bits(16..24) as SubClass, + value.get_bits(8..16) as Interface, + ) + } + + fn status(&self) -> PciStatus { + let status = self.backend().read_u16(0x06).unwrap(); + PciStatus::from_bits_truncate(status) + } + + fn command(&self) -> PciCommand { + let command = self.backend().read_u16(0x04).unwrap(); + PciCommand::from_bits_truncate(command) + } + + fn update_command(&mut self, f: F) + where + F: FnOnce(PciCommand) -> PciCommand, + { + let mut data = self.backend().read_u16(0x04).unwrap(); + let new_command = f(PciCommand::from_bits_retain(data.get_bits(0..16))); + data.set_bits(0..16, new_command.bits()); + let _ = self.backend().write_u16(0x04, data); + } +} + +pub trait PciBarRW: PciRWBase { + fn bar_limit(&self) -> u8; + + fn parse_bar(&self) -> Bar { + let mut bararr = Bar::default(); + + let mut slot = 0u8; + while slot < self.bar_limit() { + let value = self.read_bar(slot).unwrap(); + + if !value.get_bit(0) { + let pre = value.get_bit(3); + + match value.get_bits(1..3) { + 0b00 => { + let size = { + let _ = self.write_bar(slot, 0xfffffff0); + let mut readback = self.read_bar(slot).unwrap(); + let _ = self.write_bar(slot, readback as u32); + + if readback == 0x0 { + // bar is null + slot += 1; + continue; + } + readback.set_bits(0..4, 0); + 1 << readback.trailing_zeros() + }; + bararr[slot as usize] = + PciMem::new_bar(PciMemType::Mem32, value as u64, size as u64, pre); + } + 0b10 => { + if slot == 5 { + warn!("read bar64 in last bar"); + break; + } + + let value_high = self.read_bar(slot + 1).unwrap(); + let size = { + let _ = self.write_bar(slot, 0xfffffff0); + let _ = self.write_bar(slot + 1, 0xfffffff0); + let mut readback_low = self.read_bar(slot).unwrap(); + let readback_high = self.read_bar(slot + 1).unwrap(); + let _ = self.write_bar(slot, readback_low as u32); + let _ = self.write_bar(slot + 1, readback_high as u32); + + readback_low.set_bits(0..4, 0); + + if readback_low != 0 { + (1 << readback_low.trailing_zeros()) as u64 + } else { + 1u64 << ((readback_high.trailing_zeros() + 32) as u64) + } + }; + bararr[slot as usize] = + PciMem::new_bar(PciMemType::Mem64Low, value as u64, size, pre); + bararr[(slot + 1) as usize] = + PciMem::new_bar(PciMemType::Mem64High, value_high as u64, size, pre); + slot += 1; // need extra add 1 + } + _ => { + warn!("unknown bar type"); + } + } + } else { + bararr[slot as usize] = PciMem::new_io(value as u64); + } + slot += 1; + } + bararr + } + + fn read_bar(&self, slot: u8) -> HvResult { + // println!("read bar slot {}", slot); + self.backend() + .read_u32((0x10 + (slot as u16) * 4) as PciConfigAddress) + .map(|r| r as usize) + } + + fn write_bar(&self, slot: u8, value: u32) -> HvResult { + // println!("write bar slot {} {}", slot, value); + self.backend() + .write_u32((0x10 + (slot as u16) * 4) as PciConfigAddress, value) + } +} + +pub trait PciRomRW: PciRWBase { + fn rom_offset(&self) -> u64; + fn parse_rom(&self) -> PciMem { + let offset = self.rom_offset(); + let value = self.backend().read_u32(offset).unwrap(); + + let size = { + let _ = self.backend().write_u32(offset, 0xfffff800); + let mut readback = self.backend().read_u32(offset).unwrap(); + let _ = self.backend().write_u32(offset, value); + if readback == 0x0 { + return PciMem::default(); + } + readback.set_bits(0..4, 0); + 1 << readback.trailing_zeros() + }; + PciMem::new_rom(value as u64, size) + } +} + /* 32 16 0 * +-----------------------------+------------------------------+ * | Device ID | Vendor ID | 0x00 @@ -477,92 +657,13 @@ impl Debug for Bar { #[derive(Debug, Clone)] pub struct PciConfigHeader(PciRegionMmio); -macro_rules! impl_pci_rw { - ($ty:ty) => { - impl PciRW for $ty { - fn read(&self, offset: PciConfigAddress, size: usize) -> HvResult { - match size { - 1 => self.0.read_u8(offset).map(|v| v as usize), - 2 => self.0.read_u16(offset).map(|v| v as usize), - 4 => self.0.read_u32(offset).map(|v| v as usize), - _ => { - hv_result_err!(EFAULT, "pci: invalid mmio read size: {size}") - } - } - } - fn write(&self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { - match size { - 1 => self.0.write_u8(offset, value as u8), - 2 => self.0.write_u16(offset, value as u16), - 4 => self.0.write_u32(offset, value as u32), - _ => { - hv_result_err!(EFAULT, "pci: invalid mmio write size: {size}") - } - } - } - } - }; -} - -macro_rules! impl_pci_header { - ($ty:ty) => { - impl $ty { - pub fn id(&self) -> (DeviceId, VendorId) { - let id = self.0.read_u32(0x00).unwrap(); - ( - id.get_bits(0..16) as VendorId, - id.get_bits(16..32) as DeviceId, - ) - } - - pub fn header_type(&self) -> HeaderType { - match self.0.read_u8(0x0e).unwrap().get_bits(0..7) { - 0x00 => HeaderType::Endpoint, - 0x01 => HeaderType::PciBridge, - 0x02 => HeaderType::CardBusBridge, - v => HeaderType::Unknown(v as u8), - } - } - - pub fn has_multiple_functions(&self) -> bool { - self.0.read_u8(0x0c).unwrap().get_bit(7) - } - - pub fn revision_and_class(&self) -> (DeviceRevision, BaseClass, SubClass, Interface) { - let value = self.0.read_u32(0x08).unwrap(); - ( - value.get_bits(0..8) as DeviceRevision, - value.get_bits(24..32) as BaseClass, - value.get_bits(16..24) as SubClass, - value.get_bits(8..16) as Interface, - ) - } - - pub fn status(&self) -> PciStatus { - let status = self.0.read_u16(0x06).unwrap(); - PciStatus::from_bits_truncate(status) - } - - pub fn command(&self) -> PciCommand { - let command = self.0.read_u16(0x04).unwrap(); - PciCommand::from_bits_truncate(command) - } - - pub fn update_command(&mut self, f: F) - where - F: FnOnce(PciCommand) -> PciCommand, - { - let mut data = self.0.read_u16(0x04).unwrap(); - let new_command = f(PciCommand::from_bits_retain(data.get_bits(0..16))); - data.set_bits(0..16, new_command.bits()); - let _ = self.0.write_u16(0x04, data); - } - } - }; +impl PciRWBase for PciConfigHeader { + fn backend(&self) -> &dyn PciRegion { + &self.0 + } } - -impl_pci_rw!(PciConfigHeader); -impl_pci_header!(PciConfigHeader); +impl PciRW for PciConfigHeader {} +impl PciHeaderRW for PciConfigHeader {} impl PciConfigHeader { pub fn new_with_region(region: PciRegionMmio) -> Self { @@ -604,7 +705,7 @@ impl PciConfigHeader { * | Expansion ROM Base Address | 0x30 * | | * +--------------------------------------------+--------------+ - * | Reserved | Capabilities | 0x34 + * | Reserved | Capability | 0x34 * | | Pointer | * +--------------------------------------------+--------------+ * | Reserved | 0x38 @@ -628,7 +729,7 @@ pub enum EndpointField { SubsystemVendorId, SubsystemId, ExpansionRomBar, - CapabilitiesPointer, + CapabilityPointer, InterruptLine, InterruptPin, MinGnt, @@ -654,7 +755,7 @@ impl EndpointField { (0x2c, 2) => EndpointField::SubsystemVendorId, (0x2e, 2) => EndpointField::SubsystemId, (0x30, 4) => EndpointField::ExpansionRomBar, - (0x34, 4) => EndpointField::CapabilitiesPointer, + (0x34, 1) => EndpointField::CapabilityPointer, (0x3c, 1) => EndpointField::InterruptLine, (0x3d, 1) => EndpointField::InterruptPin, (0x3e, 1) => EndpointField::MinGnt, @@ -667,111 +768,27 @@ impl EndpointField { #[derive(Debug, Clone)] pub struct EndpointHeader(PciRegionMmio); -impl_pci_rw!(EndpointHeader); -impl_pci_header!(EndpointHeader); - -impl EndpointHeader { - pub fn new_with_region(region: PciRegionMmio) -> Self { - EndpointHeader(region) - } - - pub fn parse_bar(&self) -> Bar { - let mut bararr = Bar::default(); - - let mut slot = 0u8; - while slot < 6 { - let value = self.read_bar(slot).unwrap(); - - if !value.get_bit(0) { - let pre = value.get_bit(3); - - match value.get_bits(1..3) { - 0b00 => { - let size = { - let _ = self.write_bar(slot, 0xfffffff0); - let mut readback = self.read_bar(slot).unwrap(); - let _ = self.write_bar(slot, readback as u32); - - if readback == 0x0 { - // bar is null - slot += 1; - continue; - } - readback.set_bits(0..4, 0); - 1 << readback.trailing_zeros() - }; - bararr[slot as usize] = - PciMem::new_bar(PciMemType::Mem32, value as u64, size as u64, pre); - } - 0b10 => { - if slot == 5 { - warn!("read bar64 in last bar"); - break; - } - - let value_high = self.read_bar(slot + 1).unwrap(); - let size = { - let _ = self.write_bar(slot, 0xfffffff0); - let _ = self.write_bar(slot + 1, 0xfffffff0); - let mut readback_low = self.read_bar(slot).unwrap(); - let readback_high = self.read_bar(slot + 1).unwrap(); - let _ = self.write_bar(slot, readback_low as u32); - let _ = self.write_bar(slot + 1, readback_high as u32); - - readback_low.set_bits(0..4, 0); - - if readback_low != 0 { - (1 << readback_low.trailing_zeros()) as u64 - } else { - 1u64 << ((readback_high.trailing_zeros() + 32) as u64) - } - }; - bararr[slot as usize] = - PciMem::new_bar(PciMemType::Mem64Low, value as u64, size, pre); - bararr[(slot + 1) as usize] = - PciMem::new_bar(PciMemType::Mem64High, value_high as u64, size, pre); - slot += 1; // need extra add 1 - } - _ => { - warn!("unknown bar type"); - } - } - } else { - bararr[slot as usize] = PciMem::new_io(value as u64); - } - slot += 1; - } - bararr +impl PciRWBase for EndpointHeader { + fn backend(&self) -> &dyn PciRegion { + &self.0 } - - pub fn read_bar(&self, slot: u8) -> HvResult { - // println!("read bar slot {}", slot); - self.0 - .read_u32((0x10 + (slot as u16) * 4) as PciConfigAddress) - .map(|r| r as usize) +} +impl PciRW for EndpointHeader {} +impl PciHeaderRW for EndpointHeader {} +impl PciBarRW for EndpointHeader { + fn bar_limit(&self) -> u8 { + 6 } - - pub fn write_bar(&self, slot: u8, value: u32) -> HvResult { - // println!("write bar slot {} {}", slot, value); - self.0 - .write_u32((0x10 + (slot as u16) * 4) as PciConfigAddress, value) +} +impl PciRomRW for EndpointHeader { + fn rom_offset(&self) -> u64 { + 0x30 } +} - pub fn parse_rom(&self) -> PciMem { - let offset = 0x30; - let value = self.0.read_u32(offset).unwrap(); - - let size = { - let _ = self.0.write_u32(offset, 0xfffff800); - let mut readback = self.0.read_u32(offset).unwrap(); - let _ = self.0.write_u32(offset, value); - if readback == 0x0 { - return PciMem::default(); - } - readback.set_bits(0..4, 0); - 1 << readback.trailing_zeros() - }; - PciMem::new_rom(value as u64, size) +impl EndpointHeader { + pub fn new_with_region(region: PciRegionMmio) -> Self { + EndpointHeader(region) } } @@ -819,11 +836,96 @@ impl EndpointHeader { * | | PIN | Line | * +-----------------------------+--------------+--------------+ */ +pub enum BridgeField { + ID, + Command, + Status, + RevisionIDAndClassCode, + CacheLineSize, + LatencyTime, + HeaderType, + Bist, + Bar, + PrimaryBusNumber, + SecondaryBusNumber, + SubordinateBusNumber, + SecondaryLatencyTimer, + IOBase, + IOLimit, + SecondaryStatus, + MemoryBase, + MemoryLimit, + PrefetchableMemoryBase, + PrefetchableMemoryLimit, + PrefetchableBaseUpper32Bits, + PrefetchableLimitUpper32Bits, + UIBaseUpper16Bits, + IOLimitUpper16Bits, + CapabilityPointer, + ExpansionRomBar, + InterruptLine, + InterruptPin, + BridgeControl, + Unknown(usize), +} + +impl BridgeField { + pub fn from(offset: usize, size: usize) -> Self { + match (offset, size) { + (0x00, 4) => BridgeField::ID, + (0x04, 2) => BridgeField::Command, + (0x06, 2) => BridgeField::Status, + (0x08, 4) => BridgeField::RevisionIDAndClassCode, + (0x0c, 1) => BridgeField::CacheLineSize, + (0x0d, 1) => BridgeField::LatencyTime, + (0x0e, 1) => BridgeField::HeaderType, + (0x0f, 1) => BridgeField::Bist, + (0x10, 4) | (0x14, 4) => BridgeField::Bar, + (0x18, 1) => BridgeField::PrimaryBusNumber, + (0x19, 1) => BridgeField::SecondaryBusNumber, + (0x1a, 1) => BridgeField::SubordinateBusNumber, + (0x1b, 1) => BridgeField::SecondaryLatencyTimer, + (0x1c, 1) => BridgeField::IOBase, + (0x1d, 1) => BridgeField::IOLimit, + (0x1e, 2) => BridgeField::SecondaryStatus, + (0x20, 2) => BridgeField::MemoryBase, + (0x22, 2) => BridgeField::MemoryLimit, + (0x24, 2) => BridgeField::PrefetchableMemoryBase, + (0x26, 2) => BridgeField::PrefetchableMemoryLimit, + (0x28, 4) => BridgeField::PrefetchableBaseUpper32Bits, + (0x2c, 4) => BridgeField::PrefetchableLimitUpper32Bits, + (0x30, 2) => BridgeField::UIBaseUpper16Bits, + (0x32, 2) => BridgeField::IOLimitUpper16Bits, + (0x34, 1) => BridgeField::CapabilityPointer, + (0x38, 4) => BridgeField::ExpansionRomBar, + (0x3c, 1) => BridgeField::InterruptLine, + (0x3d, 1) => BridgeField::InterruptPin, + (0x3e, 2) => BridgeField::BridgeControl, + (x, _) => BridgeField::Unknown(x), + } + } +} + #[derive(Debug, Clone)] pub struct PciBridgeHeader(PciRegionMmio); -impl_pci_rw!(PciBridgeHeader); -impl_pci_header!(PciBridgeHeader); +impl PciRWBase for PciBridgeHeader { + fn backend(&self) -> &dyn PciRegion { + &self.0 + } +} +impl PciRW for PciBridgeHeader {} +impl PciHeaderRW for PciBridgeHeader {} +impl PciBarRW for PciBridgeHeader { + fn bar_limit(&self) -> u8 { + 2 + } +} +impl PciRomRW for PciBridgeHeader { + fn rom_offset(&self) -> u64 { + 0x38 + } +} impl PciBridgeHeader { pub fn new_with_region(region: PciRegionMmio) -> Self { @@ -961,7 +1063,10 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { bar.get_size() as _, MemFlags::READ | MemFlags::WRITE, ))?; - /* after update gpm, mem barrier is needed */ + /* after update gpm, mem barrier is needed + * TODO: for loongarch64 need ibar 0 dbar 0 + */ + #[cfg(target_arch = "aarch64")] unsafe { core::arch::asm!("isb"); core::arch::asm!("tlbi vmalls12e1is"); diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index c753ee87..1deeb19f 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -21,7 +21,7 @@ use bitvec::{array::BitArray, order::Lsb0, BitArr}; use crate::{ error::{HvErrorNum, HvResult}, - pci::pci_access::Bar, + pci::pci_access::{Bar, PciBarRW, PciHeaderRW, PciRomRW}, }; use super::{ @@ -500,50 +500,25 @@ impl PciIterator { match pci_header.header_type() { HeaderType::Endpoint => { let mut ep = EndpointHeader::new_with_region(region); - - let mut bararr = ep.parse_bar(); let rom = ep.parse_rom(); - if let Some(a) = &mut self.allocator { - ep.update_command(|mut cmd| { - cmd.remove(PciCommand::IO_ENABLE); - cmd.remove(PciCommand::MEMORY_ENABLE); - cmd - }); - - let mut i = 0; - while i < 6 { - match bararr[i].get_type() { - PciMemType::Mem32 => { - let value = a.alloc_memory32(bararr[i].get_size() as u32).unwrap(); - bararr[i].set_value(value as u64); - bararr[i].set_virtual_value(value as u64); - let _ = ep.write_bar(i as u8, value); - } - PciMemType::Mem64Low => { - let value = a.alloc_memory64(bararr[i].get_size()).unwrap(); - bararr[i].set_value(value); - bararr[i].set_virtual_value(value); - let _ = ep.write_bar(i as u8, value as u32); - i += 1; - bararr[i].set_value(value); - bararr[i].set_virtual_value(value); - let _ = ep.write_bar(i as u8, (value >> 32) as u32); - } - _ => {} - } - i += 1; - } - } + + let bararr = + Self::bar_mem_init(ep.bar_limit().into(), &mut self.allocator, &mut ep); + let ep = Arc::new(ep); let bdf = Bdf::from_address(address); Some(VirtualPciConfigSpace::endpoint(bdf, ep, bararr, rom)) } HeaderType::PciBridge => { warn!("bridge"); - let bridge = PciBridgeHeader::new_with_region(region); + let mut bridge = PciBridgeHeader::new_with_region(region); + + let bararr = + Self::bar_mem_init(bridge.bar_limit().into(), &mut self.allocator, &mut bridge); + let bridge = Arc::new(bridge); let bdf = Bdf::from_address(address); - Some(VirtualPciConfigSpace::bridge(bdf, bridge, Bar::default())) + Some(VirtualPciConfigSpace::bridge(bdf, bridge, bararr)) } _ => { warn!("unknown type"); @@ -554,6 +529,47 @@ impl PciIterator { } } + fn bar_mem_init( + bar_max: usize, + allocator: &mut Option, + dev: &mut D, + ) -> Bar { + let mut bararr = dev.parse_bar(); + + if let Some(a) = allocator { + dev.update_command(|mut cmd| { + cmd.remove(PciCommand::IO_ENABLE); + cmd.remove(PciCommand::MEMORY_ENABLE); + cmd + }); + + let mut i = 0; + while i < bar_max { + match bararr[i].get_type() { + PciMemType::Mem32 => { + let value = a.alloc_memory32(bararr[i].get_size() as u32).unwrap(); + bararr[i].set_value(value as u64); + bararr[i].set_virtual_value(value as u64); + let _ = dev.write_bar(i as u8, value); + } + PciMemType::Mem64Low => { + let value = a.alloc_memory64(bararr[i].get_size()).unwrap(); + bararr[i].set_value(value); + bararr[i].set_virtual_value(value); + let _ = dev.write_bar(i as u8, value as u32); + i += 1; + bararr[i].set_value(value); + bararr[i].set_virtual_value(value); + let _ = dev.write_bar(i as u8, (value >> 32) as u32); + } + _ => {} + } + i += 1; + } + } + bararr + } + fn get_bridge(&self) -> Bridge { let a = self.stack.last(); match a { From 6cfd3b291c946a88c2a3a7eb3efab25e270455f6 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 11 Sep 2025 22:14:09 +0800 Subject: [PATCH 09/12] [build] pci: adjust import method of mod pci --- src/config.rs | 8 -------- src/main.rs | 9 +-------- src/pci/pci_config.rs | 4 ++-- src/zone.rs | 12 ++++-------- 4 files changed, 7 insertions(+), 26 deletions(-) diff --git a/src/config.rs b/src/config.rs index 17a7a87c..49dc9303 100644 --- a/src/config.rs +++ b/src/config.rs @@ -215,14 +215,6 @@ macro_rules! pci_dev { }; } -#[cfg(not(feature = "pci"))] -impl core::fmt::Debug for HvPciDevConfig { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - core::fmt::Debug::fmt(&(self.bdf, self.vbdf), f) - } -} - -#[cfg(feature = "pci")] impl Debug for HvPciDevConfig { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let bdf = crate::pci::pci_struct::Bdf::from_address(self.bdf); diff --git a/src/main.rs b/src/main.rs index 67c24db2..36bb145a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -60,7 +60,6 @@ mod percpu; mod platform; mod zone; -#[cfg(feature = "pci")] mod pci; #[cfg(test)] @@ -72,7 +71,6 @@ use crate::consts::{hv_end, mem_pool_start, MAX_CPU_NUM}; use arch::{cpu::cpu_start, entry::arch_entry}; use config::root_zone_config; use core::sync::atomic::{AtomicI32, AtomicU32, Ordering}; -#[cfg(feature = "pci")] use pci::pci_config::hvisor_pci_init; use percpu::PerCpu; use zone::{add_zone, zone_create}; @@ -138,12 +136,7 @@ fn primary_init_early() { let root_config = root_zone_config(); - #[cfg(feature = "pci")] - { - info!("1"); - let _ = hvisor_pci_init(&root_config.pci_config); - info!("3"); - } + let _ = hvisor_pci_init(&root_config.pci_config); #[cfg(not(test))] { diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 10278b39..dc4700c5 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -56,7 +56,7 @@ pub fn hvisor_pci_init(pci_rootcomplex_config: &[HvPciConfig; CONFIG_PCI_BUS_MAX GLOBAL_PCIE_LIST.lock().insert(node.get_bdf(), node); } } - info!("hvisor pci init \n{:#?}", GLOBAL_PCIE_LIST); + info!("hvisor pci init done \n{:#?}", GLOBAL_PCIE_LIST); Ok(()) } @@ -90,7 +90,7 @@ impl Zone { } i += 1; } - info!("vpci bus init end\n {:#?}", self.vpci_bus); + info!("vpci bus init done\n {:#?}", self.vpci_bus); Ok(()) } diff --git a/src/zone.rs b/src/zone.rs index 70cc8e65..24a09364 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -17,7 +17,6 @@ use alloc::sync::Arc; use alloc::vec::Vec; // use psci::error::INVALID_ADDRESS; use crate::consts::{INVALID_ADDRESS, MAX_CPU_NUM}; -#[cfg(feature = "pci")] use crate::pci::pci_struct::VirtualRootComplex; use spin::RwLock; @@ -40,7 +39,6 @@ pub struct Zone { pub irq_bitmap: [u32; 1024 / 32], pub gpm: MemorySet, pub is_err: bool, - #[cfg(feature = "pci")] pub vpci_bus: VirtualRootComplex, } @@ -55,7 +53,6 @@ impl Zone { mmio: Vec::new(), irq_bitmap: [0; 1024 / 32], is_err: false, - #[cfg(feature = "pci")] vpci_bus: VirtualRootComplex::new(), } } @@ -206,11 +203,10 @@ pub fn zone_create(config: &HvZoneConfig) -> HvResult>> { let mut zone = Zone::new(zone_id, &config.name); zone.pt_init(config.memory_regions()).unwrap(); zone.mmio_init(&config.arch_config); - #[cfg(feature = "pci")] - { - let _ = zone.virtual_pci_mmio_init(&config.pci_config, config.num_pci_bus); - let _ = zone.guest_pci_init(&config.alloc_pci_devs, config.num_pci_devs); - } + + let _ = zone.virtual_pci_mmio_init(&config.pci_config, config.num_pci_bus); + let _ = zone.guest_pci_init(&config.alloc_pci_devs, config.num_pci_devs); + // #[cfg(target_arch = "aarch64")] // zone.ivc_init(config.ivc_config()); From 16867d646b7dbeb6a462d162c66f6781c7c50e41 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 17 Sep 2025 22:08:12 +0800 Subject: [PATCH 10/12] [feature] pci: add cap --- src/pci/pci_config.rs | 3 +- src/pci/pci_struct.rs | 266 ++++++++++++++++++++++++++++++++++++++++++ src/zone.rs | 2 +- 3 files changed, 269 insertions(+), 2 deletions(-) diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index dc4700c5..8838a770 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -52,7 +52,8 @@ pub fn hvisor_pci_init(pci_rootcomplex_config: &[HvPciConfig; CONFIG_PCI_BUS_MAX ); let mut rootcomplex = RootComplex::new(rootcomplex_config.ecam_base); - for node in rootcomplex.enumerate(None, Some(allocator)) { + for mut node in rootcomplex.enumerate(None, Some(allocator)) { + node.capability_enumerate(); GLOBAL_PCIE_LIST.lock().insert(node.get_bdf(), node); } } diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 1deeb19f..876871d0 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -229,6 +229,7 @@ pub struct VirtualPciConfigSpace { bararr: Bar, rom: PciMem, + capabilities: PciCapabilityList, } impl VirtualPciConfigSpace { @@ -310,6 +311,7 @@ impl VirtualPciConfigSpace { backend, bararr, rom, + capabilities: PciCapabilityList::new(), } } @@ -324,6 +326,7 @@ impl VirtualPciConfigSpace { backend, bararr, rom: PciMem::default(), + capabilities: PciCapabilityList::new(), } } @@ -338,6 +341,7 @@ impl VirtualPciConfigSpace { backend, bararr: Bar::default(), rom: PciMem::default(), + capabilities: PciCapabilityList::new(), } } @@ -352,6 +356,7 @@ impl VirtualPciConfigSpace { backend, bararr: Bar::default(), rom: PciMem::default(), + capabilities: PciCapabilityList::new(), } } @@ -536,6 +541,8 @@ impl PciIterator { ) -> Bar { let mut bararr = dev.parse_bar(); + info!("{:#?}", bararr); + if let Some(a) = allocator { dev.update_command(|mut cmd| { cmd.remove(PciCommand::IO_ENABLE); @@ -758,3 +765,262 @@ impl VirtualRootComplex { &mut self.devs } } + +#[derive(Debug)] +pub struct CapabilityIterator { + backend: Arc, + offset: PciConfigAddress, +} + +impl CapabilityIterator { + pub fn get_offset(&self) -> PciConfigAddress { + self.offset + } + + pub fn get_next_cap(&mut self) -> HvResult { + let address = self.backend.read(self.offset, 2).unwrap().get_bits(8..16) as PciConfigAddress; + self.offset = address; + Ok(()) + } + + pub fn get_id(&self) -> PciConfigAddress { + self.backend.read(self.offset, 2).unwrap().get_bits(0..8) as PciConfigAddress + } + + pub fn get_extension(&self) -> u16 { + self.backend.read(self.offset, 2).unwrap().get_bits(16..32) as u16 + } +} + +impl Iterator for CapabilityIterator { + type Item = PciCapability; + + fn next(&mut self) -> Option { + while self.get_offset() != 0 { + let cap = PciCapability::from_address(self.get_offset(), self.get_id(), self.get_extension()); + // warn!("cap value {:x}", self.backend.read(self.offset, 4).unwrap()); + let _ = self.get_next_cap(); + if let Some(cap) = cap { + return Some(cap); + } + } + None + } +} + +#[derive(Clone)] +pub enum PciCapability { + // Power management capability, Cap ID = `0x01` + PowerManagement(PciCapabilityRegion), + // Accelerated graphics port capability, Cap ID = `0x02` + AcceleratedGraphicsPort(PciCapabilityRegion), + // Vital product data capability, Cap ID = `0x3` + VitalProductData(PciCapabilityRegion), + // Slot identification capability, Cap ID = `0x04` + SlotIdentification(PciCapabilityRegion), + // Message signalling interrupts capability, Cap ID = `0x05` + Msi(PciCapabilityRegion), + // CompactPCI HotSwap capability, Cap ID = `0x06` + CompactPCIHotswap(PciCapabilityRegion), + // PCI-X capability, Cap ID = `0x07` + PciX(PciCapabilityRegion), + // HyperTransport capability, Cap ID = `0x08` + HyperTransport(PciCapabilityRegion), + // Vendor-specific capability, Cap ID = `0x09` + Vendor(PciCapabilityRegion), + // Debug port capability, Cap ID = `0x0A` + DebugPort(PciCapabilityRegion), + // CompactPCI Central Resource Control capability, Cap ID = `0x0B` + CompactPCICentralResourceControl(PciCapabilityRegion), + // PCI Standard Hot-Plug Controller capability, Cap ID = `0x0C` + PciHotPlugControl(PciCapabilityRegion), + // Bridge subsystem vendor/device ID capability, Cap ID = `0x0D` + BridgeSubsystemVendorId(PciCapabilityRegion), + // AGP Target PCI-PCI bridge capability, Cap ID = `0x0E` + AGP3(PciCapabilityRegion), + // PCI Express capability, Cap ID = `0x10` + PciExpress(PciCapabilityRegion), + // MSI-X capability, Cap ID = `0x11` + MsiX(PciCapabilityRegion), + // Unknown capability + Unknown(PciCapabilityRegion), +} + +impl PciCapability { + fn from_address(offset: PciConfigAddress, id: PciConfigAddress, extension: u16) -> Option { + match id { + 0x00 => None, + 0x01 => Some(PciCapability::PowerManagement(PciCapabilityRegion::new( + offset, extension, + ))), + 0x02 => Some(PciCapability::AcceleratedGraphicsPort( + PciCapabilityRegion::new(offset, extension), + )), + 0x03 => Some(PciCapability::VitalProductData(PciCapabilityRegion::new( + offset, extension, + ))), + 0x04 => Some(PciCapability::SlotIdentification(PciCapabilityRegion::new( + offset, extension, + ))), + 0x05 => Some(PciCapability::Msi(PciCapabilityRegion::new( + offset, extension, + ))), + 0x06 => Some(PciCapability::CompactPCIHotswap(PciCapabilityRegion::new( + offset, extension, + ))), + 0x07 => Some(PciCapability::PciX(PciCapabilityRegion::new( + offset, extension, + ))), + 0x08 => Some(PciCapability::HyperTransport(PciCapabilityRegion::new( + offset, extension, + ))), + 0x09 => Some(PciCapability::Vendor(PciCapabilityRegion::new( + offset, extension, + ))), + 0x0A => Some(PciCapability::DebugPort(PciCapabilityRegion::new( + offset, extension, + ))), + 0x0B => Some(PciCapability::CompactPCICentralResourceControl( + PciCapabilityRegion::new(offset, extension), + )), + 0x0C => Some(PciCapability::PciHotPlugControl(PciCapabilityRegion::new( + offset, extension, + ))), + 0x0D => Some(PciCapability::BridgeSubsystemVendorId( + PciCapabilityRegion::new(offset, extension), + )), + 0x0E => Some(PciCapability::AGP3(PciCapabilityRegion::new( + offset, extension, + ))), + 0x10 => Some(PciCapability::PciExpress(PciCapabilityRegion::new( + offset, extension, + ))), + 0x11 => Some(PciCapability::MsiX(PciCapabilityRegion::new( + offset, extension, + ))), + _ => Some(PciCapability::Unknown(PciCapabilityRegion::new( + offset, extension, + ))), + } + } + + fn get_offset(&self) -> PciConfigAddress { + match *self { + PciCapability::PowerManagement(PciCapabilityRegion { offset, .. }) => offset, + PciCapability::AcceleratedGraphicsPort(PciCapabilityRegion { offset, .. }) => offset, + PciCapability::VitalProductData(PciCapabilityRegion { offset, .. }) => offset, + PciCapability::SlotIdentification(PciCapabilityRegion { offset, .. }) => offset, + PciCapability::Msi(PciCapabilityRegion { offset, .. }) => offset, + PciCapability::CompactPCIHotswap(PciCapabilityRegion { offset, .. }) => offset, + PciCapability::PciX(PciCapabilityRegion { offset, .. }) => offset, + PciCapability::HyperTransport(PciCapabilityRegion { offset, .. }) => offset, + PciCapability::Vendor(PciCapabilityRegion { offset, .. }) => offset, + PciCapability::DebugPort(PciCapabilityRegion { offset, .. }) => offset, + PciCapability::CompactPCICentralResourceControl(PciCapabilityRegion { + offset, .. + }) => offset, + PciCapability::PciHotPlugControl(PciCapabilityRegion { offset, .. }) => offset, + PciCapability::BridgeSubsystemVendorId(PciCapabilityRegion { offset, .. }) => offset, + PciCapability::AGP3(PciCapabilityRegion { offset, .. }) => offset, + PciCapability::PciExpress(PciCapabilityRegion { offset, .. }) => offset, + PciCapability::MsiX(PciCapabilityRegion { offset, .. }) => offset, + PciCapability::Unknown(PciCapabilityRegion { offset, .. }) => offset, + } + } +} + +impl Debug for PciCapability { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match *self { + PciCapability::PowerManagement(PciCapabilityRegion { offset, .. }) => { + write!(f, "PowerManagement {:x}", offset) + } + PciCapability::AcceleratedGraphicsPort(PciCapabilityRegion { offset, .. }) => { + write!(f, "AcceleratedGraphicsPort {:x}", offset) + } + PciCapability::VitalProductData(PciCapabilityRegion { offset, .. }) => { + write!(f, "VitalProductData {:x}", offset) + } + PciCapability::SlotIdentification(PciCapabilityRegion { offset, .. }) => { + write!(f, "SlotIdentification {:x}", offset) + } + PciCapability::Msi(PciCapabilityRegion { offset, .. }) => write!(f, "Msi {:x}", offset), + PciCapability::CompactPCIHotswap(PciCapabilityRegion { offset, .. }) => { + write!(f, "CompactPCIHotswap {:x}", offset) + } + PciCapability::PciX(PciCapabilityRegion { offset, .. }) => { + write!(f, "PciX {:x}", offset) + } + PciCapability::HyperTransport(PciCapabilityRegion { offset, .. }) => { + write!(f, "HyperTransport {:x}", offset) + } + PciCapability::Vendor(PciCapabilityRegion { offset, .. }) => { + write!(f, "Vendor {:x}", offset) + } + PciCapability::DebugPort(PciCapabilityRegion { offset, .. }) => { + write!(f, "DebugPort {:x}", offset) + } + PciCapability::CompactPCICentralResourceControl(PciCapabilityRegion { + offset, .. + }) => write!(f, "CompactPCICentralResourceControl {:x}", offset), + PciCapability::PciHotPlugControl(PciCapabilityRegion { offset, .. }) => { + write!(f, "PciHotPlugControl {:x}", offset) + } + PciCapability::BridgeSubsystemVendorId(PciCapabilityRegion { offset, .. }) => { + write!(f, "BridgeSubsystemVendorId {:x}", offset) + } + PciCapability::AGP3(PciCapabilityRegion { offset, .. }) => { + write!(f, "AGP3 {:x}", offset) + } + PciCapability::PciExpress(PciCapabilityRegion { offset, .. }) => { + write!(f, "PciExpress {:x}", offset) + } + PciCapability::MsiX(PciCapabilityRegion { offset, .. }) => { + write!(f, "MsiX {:x}", offset) + } + PciCapability::Unknown(PciCapabilityRegion { offset, .. }) => { + write!(f, "Unknown {:x}", offset) + } + } + } +} + +#[derive(Clone)] +pub struct PciCapabilityRegion { + offset: PciConfigAddress, + extension: u16, +} + +impl PciCapabilityRegion { + pub fn new(offset: PciConfigAddress, extension: u16) -> Self { + Self { + offset, + extension, + } + } +} + +pub type PciCapabilityList = BTreeMap; + +impl VirtualPciConfigSpace { + fn _capability_enumerate(&self, backend: Arc) -> CapabilityIterator { + CapabilityIterator { + backend, + offset: 0x34 + } + } + + pub fn capability_enumerate(&mut self) { + let mut capabilities = PciCapabilityList::new(); + for capability in self._capability_enumerate(self.backend.clone()) { + match capability { + PciCapability::Msi(_) => {} + PciCapability::MsiX(_) => {} + _ => {} + } + capabilities.insert(capability.get_offset(), capability); + } + info!("capability {:#?}", capabilities); + self.capabilities = capabilities; + } +} diff --git a/src/zone.rs b/src/zone.rs index 24a09364..74246829 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -206,7 +206,7 @@ pub fn zone_create(config: &HvZoneConfig) -> HvResult>> { let _ = zone.virtual_pci_mmio_init(&config.pci_config, config.num_pci_bus); let _ = zone.guest_pci_init(&config.alloc_pci_devs, config.num_pci_devs); - + // #[cfg(target_arch = "aarch64")] // zone.ivc_init(config.ivc_config()); From 786357b69ef51a2f91cecf95540d4d0cd599908a Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 24 Sep 2025 21:58:00 +0800 Subject: [PATCH 11/12] [fixed] rk3568: Fixed a memory corruption caused by oversized binary files (hvisor.bin), and improved startup speed --- platform/aarch64/rk3568/board.rs | 63 +++++---- .../rk3568/image/dts/rk3568_limit_zone0.dts | 130 ++++++++++++------ .../rk3568/image/dts/rk3568_limit_zone1.dts | 4 +- platform/aarch64/rk3568/linker.ld | 2 +- platform/aarch64/rk3568/platform.mk | 4 +- 5 files changed, 129 insertions(+), 74 deletions(-) diff --git a/platform/aarch64/rk3568/board.rs b/platform/aarch64/rk3568/board.rs index 84f07a71..c2f8c4e9 100644 --- a/platform/aarch64/rk3568/board.rs +++ b/platform/aarch64/rk3568/board.rs @@ -43,16 +43,17 @@ pub const BOARD_PHYSMEM_LIST: &[(u64, u64, MemoryType)] = &[ // ( start, end, type) ( 0x0, 0xf0000000, MemoryType::Normal), ( 0xf0000000, 0x100000000, MemoryType::Device), + ( 0x100000000, 0x3fc000000, MemoryType::Normal), ]; pub const ROOT_ZONE_DTB_ADDR: u64 = 0xa0000000; -pub const ROOT_ZONE_KERNEL_ADDR: u64 = 0x60080000 ; -pub const ROOT_ZONE_ENTRY: u64 = 0x60080000 ; +pub const ROOT_ZONE_KERNEL_ADDR: u64 = 0x00280000 ; +pub const ROOT_ZONE_ENTRY: u64 = 0x00280000 ; //pub const ROOT_ZONE_CPUS: u64 = (1 << 0) ; pub const ROOT_ZONE_CPUS: u64 = (1 << 0)|(1 << 1); pub const ROOT_ZONE_NAME: &str = "root-linux"; -pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 19] = [ +pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 20] = [ // HvConfigMemoryRegion { // mem_type: MEM_TYPE_IO, // physical_start: 0xfd400000, @@ -65,12 +66,6 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 19] = [ // virtual_start: 0xfd460000, // size: 0xc0000, // }, // gic - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0xfe000000, - virtual_start: 0xfe000000, - size: 0x4000, - }, // dwmmc HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, physical_start: 0x200000, @@ -83,30 +78,48 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 19] = [ virtual_start: 0x9400000, size: 0xe6c00000, }, // memory - // HvConfigMemoryRegion { - // mem_type: MEM_TYPE_RAM, - // physical_start: 0x0, - // virtual_start: 0x0, - // size: 0x200000, - // }, // ram HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0x110000, - virtual_start: 0x110000, - size: 0xf0000, - }, // ramoops - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0x10f000, - virtual_start: 0x10f000, - size: 0x1000, - }, //scmi-shmem + physical_start: 0x0, + virtual_start: 0x0, + size: 0x200000, + }, // ram + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_RAM, + // physical_start: 0x110000, + // virtual_start: 0x110000, + // size: 0xf0000, + // }, // ramoops + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_IO, + // physical_start: 0x10f000, + // virtual_start: 0x10f000, + // size: 0x1000, + // }, //scmi-shmem HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, physical_start: 0x1f0000000, virtual_start: 0x1f0000000, size: 0x10000000, }, // memory + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xfe2b0000, + virtual_start: 0xfe2b0000, + size: 0x4000, + }, //dwmmc mmc1 + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xfe2c0000, + virtual_start: 0xfe2c0000, + size: 0x4000, + }, //dwmmc mmc2 + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xfe000000, + virtual_start: 0xfe000000, + size: 0x4000, + }, //dwmmc mmc3 HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0xFE660000, diff --git a/platform/aarch64/rk3568/image/dts/rk3568_limit_zone0.dts b/platform/aarch64/rk3568/image/dts/rk3568_limit_zone0.dts index d2d43a26..5b188f0c 100644 --- a/platform/aarch64/rk3568/image/dts/rk3568_limit_zone0.dts +++ b/platform/aarch64/rk3568/image/dts/rk3568_limit_zone0.dts @@ -13,6 +13,88 @@ serial2 = "/serial@fe660000"; sdmmc2 = "/dwmmc@fe000000"; serial4 = "/serial@fe680000"; + mmc1 = "/dwmmc@fe2b0000"; + mmc2 = "/dwmmc@fe2c0000"; + mmc3 = "/dwmmc@fe000000"; + }; + + sdhci@fe310000 { + clock-names = "core\0bus\0axi\0block\0timer"; + assigned-clocks = <0x20 0x7b 0x20 0x7d 0x20 0x7c>; + bus-width = <0x08>; + non-removable; + assigned-clock-rates = <0xbebc200 0x16e3600 0xbebc200>; + interrupts = <0x00 0x13 0x04>; + clocks = <0x20 0x7c 0x20 0x7a 0x20 0x79 0x20 0x7b 0x20 0x7d>; + compatible = "rockchip,dwcmshc-sdhci\0snps,dwcmshc-sdhci"; + status = "okay"; + reg = <0x00 0xfe310000 0x00 0x10000>; + phandle = <0x1a5>; + max-frequency = <0xbebc200>; + supports-emmc; + }; + + dwmmc@fe000000 { + fifo-depth = <0x100>; + pinctrl-names = "default"; + supports-sdio; + pinctrl-0 = <0xa0 0xa1 0xa2>; + clock-names = "biu\0ciu\0ciu-drive\0ciu-sample"; + cap-sd-highspeed; + bus-width = <0x04>; + non-removable; + resets = <0x20 0xeb>; + cap-sdio-irq; + interrupts = <0x00 0x64 0x04>; + clocks = <0x20 0xc1 0x20 0xc2 0x20 0x18e 0x20 0x18f>; + keep-power-in-suspend; + compatible = "rockchip,rk3568-dw-mshc\0rockchip,rk3288-dw-mshc"; + status = "okay"; + disable-wp; + mmc-pwrseq = <0x9f>; + reg = <0x00 0xfe000000 0x00 0x4000>; + phandle = <0x19a>; + sd-uhs-sdr104; + max-frequency = <0x8f0d180>; + reset-names = "reset"; + }; + + dwmmc@fe2b0000 { + supports-sd; + fifo-depth = <0x100>; + pinctrl-names = "default"; + pinctrl-0 = <0xbe 0xbf 0xc0 0xc1>; + clock-names = "biu\0ciu\0ciu-drive\0ciu-sample"; + cap-sd-highspeed; + vqmmc-supply = <0x2d>; + bus-width = <0x04>; + resets = <0x20 0xd4>; + interrupts = <0x00 0x62 0x04>; + clocks = <0x20 0xb0 0x20 0xb1 0x20 0x18a 0x20 0x18b>; + vmmc-supply = <0xbd>; + compatible = "rockchip,rk3568-dw-mshc\0rockchip,rk3288-dw-mshc"; + status = "okay"; + disable-wp; + reg = <0x00 0xfe2b0000 0x00 0x4000>; + phandle = <0x1a2>; + sd-uhs-sdr104; + max-frequency = <0x8f0d180>; + cap-mmc-highspeed; + reset-names = "reset"; + }; + + dwmmc@fe2c0000 { + fifo-depth = <0x100>; + clock-names = "biu\0ciu\0ciu-drive\0ciu-sample"; + resets = <0x20 0xd6>; + interrupts = <0x00 0x63 0x04>; + clocks = <0x20 0xb2 0x20 0xb3 0x20 0x18c 0x20 0x18d>; + compatible = "rockchip,rk3568-dw-mshc\0rockchip,rk3288-dw-mshc"; + status = "disabled"; + reg = <0x00 0xfe2c0000 0x00 0x4000>; + phandle = <0x1a3>; + max-frequency = <0x8f0d180>; + reset-names = "reset"; }; memory { @@ -41,9 +123,9 @@ ftrace-size = <0x00>; }; - hvisor@480000 { + hvisor@280000 { no-map; - reg = <0x00 0x480000 0x00 0x400000>; + reg = <0x00 0x280000 0x00 0x400000>; }; nonroot { @@ -1165,47 +1247,6 @@ phandle = <0x34>; }; - sdhci@fe310000 { - clock-names = "core\0bus\0axi\0block\0timer"; - assigned-clocks = <0x20 0x7b 0x20 0x7d 0x20 0x7c>; - bus-width = <0x08>; - non-removable; - assigned-clock-rates = <0xbebc200 0x16e3600 0xbebc200>; - interrupts = <0x00 0x13 0x04>; - clocks = <0x20 0x7c 0x20 0x7a 0x20 0x79 0x20 0x7b 0x20 0x7d>; - compatible = "rockchip,dwcmshc-sdhci\0snps,dwcmshc-sdhci"; - status = "okay"; - reg = <0x00 0xfe310000 0x00 0x10000>; - phandle = <0x1a5>; - max-frequency = <0xbebc200>; - supports-emmc; - }; - - dwmmc@fe000000 { - fifo-depth = <0x100>; - pinctrl-names = "default"; - supports-sdio; - pinctrl-0 = <0xa0 0xa1 0xa2>; - clock-names = "biu\0ciu\0ciu-drive\0ciu-sample"; - cap-sd-highspeed; - bus-width = <0x04>; - non-removable; - resets = <0x20 0xeb>; - cap-sdio-irq; - interrupts = <0x00 0x64 0x04>; - clocks = <0x20 0xc1 0x20 0xc2 0x20 0x18e 0x20 0x18f>; - keep-power-in-suspend; - compatible = "rockchip,rk3568-dw-mshc\0rockchip,rk3288-dw-mshc"; - status = "okay"; - disable-wp; - mmc-pwrseq = <0x9f>; - reg = <0x00 0xfe000000 0x00 0x4000>; - phandle = <0x19a>; - sd-uhs-sdr104; - max-frequency = <0x8f0d180>; - reset-names = "reset"; - }; - scmi-shmem@10f000 { compatible = "arm,scmi-shmem"; reg = <0x00 0x10f000 0x00 0x100>; @@ -1305,7 +1346,8 @@ }; chosen { - bootargs = "storagemedia=emmc rw rootwait earlycon=uart8250,mmio32,0xfe660000 console=ttyFIQ0 root=PARTUUID=614e0000-0000"; + // bootargs = "storagemedia=emmc rw rootwait earlycon=uart8250,mmio32,0xfe660000 console=ttyFIQ0 root=PARTUUID=root=PARTUUID=614e0000-0000-4b53-8000-1d28000054a9"; + bootargs = "storagemedia=emmc rw rootwait earlycon=uart8250,mmio32,0xfe660000 console=ttyFIQ0 root=/dev/mmcblk0p5"; phandle = <0x1eb>; }; diff --git a/platform/aarch64/rk3568/image/dts/rk3568_limit_zone1.dts b/platform/aarch64/rk3568/image/dts/rk3568_limit_zone1.dts index 8775c052..97e392ab 100644 --- a/platform/aarch64/rk3568/image/dts/rk3568_limit_zone1.dts +++ b/platform/aarch64/rk3568/image/dts/rk3568_limit_zone1.dts @@ -25,9 +25,9 @@ ranges; phandle = <0x142>; - hvisor@480000 { + hvisor@280000 { no-map; - reg = <0x00 0x480000 0x00 0x400000>; + reg = <0x00 0x280000 0x00 0x400000>; }; }; diff --git a/platform/aarch64/rk3568/linker.ld b/platform/aarch64/rk3568/linker.ld index 947cb35c..b561212a 100644 --- a/platform/aarch64/rk3568/linker.ld +++ b/platform/aarch64/rk3568/linker.ld @@ -1,5 +1,5 @@ ENTRY(arch_entry) -BASE_ADDRESS = 0x00480000; +BASE_ADDRESS = 0x60080000; SECTIONS { diff --git a/platform/aarch64/rk3568/platform.mk b/platform/aarch64/rk3568/platform.mk index 51824073..7bf0b004 100644 --- a/platform/aarch64/rk3568/platform.mk +++ b/platform/aarch64/rk3568/platform.mk @@ -3,6 +3,6 @@ $(hvisor_bin): elf sudo apt update && sudo apt install u-boot-tools; \ fi && \ $(OBJCOPY) $(hvisor_elf) --strip-all -O binary $(hvisor_bin).tmp && \ - mkimage -n hvisor_img -A arm64 -O linux -C none -T kernel -a 0x00480000 \ - -e 0x00480000 -d $(hvisor_bin).tmp $(hvisor_bin) && \ + mkimage -n hvisor_img -A arm64 -O linux -C none -T kernel -a 0x60080000 \ + -e 0x60080000 -d $(hvisor_bin).tmp $(hvisor_bin) && \ rm -rf $(hvisor_bin).tmp \ No newline at end of file From 20a14fb59415044f0dbcc0738fed6f5cbc745fa6 Mon Sep 17 00:00:00 2001 From: dallas Date: Tue, 28 Oct 2025 16:54:47 +0800 Subject: [PATCH 12/12] add get & get_mut for VirtualRootComplex --- src/pci/pci_struct.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 876871d0..9f8be11d 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -764,6 +764,14 @@ impl VirtualRootComplex { pub fn devs(&mut self) -> &mut BTreeMap { &mut self.devs } + + pub fn get(&self, bdf: &Bdf) -> Option<&VirtualPciConfigSpace> { + self.devs.get(bdf) + } + + pub fn get_mut(&mut self, bdf: &Bdf) -> Option<&mut VirtualPciConfigSpace> { + self.devs.get_mut(bdf) + } } #[derive(Debug)]