From af0af3c2e6f7867799e834074ce184f576729cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=AF=E5=AE=87?= <2537738252@qq.com> Date: Mon, 8 Sep 2025 11:11:07 +0800 Subject: [PATCH 001/109] riscv64: support timestamp --- Cargo.toml | 1 + platform/riscv64/hifive-premier-p550/board.rs | 100 ++- platform/riscv64/hifive-premier-p550/boot.scr | Bin 285 -> 459 bytes .../image/dts/eic7700-hifive-premier-p550.dts | 791 +++++++++--------- .../hifive-premier-p550/image/dts/minimal.dts | 196 +---- .../image/dts/zone0-npu.dts | 201 +---- .../hifive-premier-p550/scripts/README.md | 51 ++ .../hifive-premier-p550/scripts/init.sh | 17 + platform/riscv64/qemu-plic/board.rs | 2 + src/arch/riscv64/mod.rs | 1 + src/arch/riscv64/sbi.rs | 26 +- src/arch/riscv64/time.rs | 68 ++ src/consts.rs | 5 + src/logging.rs | 32 +- src/main.rs | 2 + 15 files changed, 676 insertions(+), 817 deletions(-) create mode 100644 platform/riscv64/hifive-premier-p550/scripts/init.sh create mode 100644 src/arch/riscv64/time.rs diff --git a/Cargo.toml b/Cargo.toml index 2a35c865..519000fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,7 @@ raw-cpuid = "10.7.0" ############# general ############## iommu = [] # supported by: aarch64 pci = [] # supported by: aarch64, loongarch64 +print_timestamp = [] # print timestamp when logging ############# aarch64 ############## # irqchip driver diff --git a/platform/riscv64/hifive-premier-p550/board.rs b/platform/riscv64/hifive-premier-p550/board.rs index 05cb782a..bcec7845 100644 --- a/platform/riscv64/hifive-premier-p550/board.rs +++ b/platform/riscv64/hifive-premier-p550/board.rs @@ -19,6 +19,8 @@ use crate::{arch::zone::HvArchZoneConfig, config::*}; pub const BOARD_NAME: &str = "hifive-premier-p550"; pub const BOARD_NCPUS: usize = 4; +pub const TIMEBASE_FREQ: u64 = 0xf4240; // 1MHz + pub const PLIC_BASE: usize = 0xc000000; pub const BOARD_PLIC_INTERRUPTS_NUM: usize = 1023; // except irq 0 pub const SIFIVE_CCACHE_BASE: usize = 0x2010000; // SiFive composable cache controller @@ -31,18 +33,24 @@ pub const ROOT_ZONE_CPUS: u64 = 0x1; pub const ROOT_ZONE_NAME: &str = "root-linux"; -pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 7] = [ +pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 4] = [ HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0x80000000, - virtual_start: 0x80000000, - size: 0x8000_0000, + physical_start: 0x8000_0000, + virtual_start: 0x8000_0000, + size: 0x4_0000_0000, }, // ram HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, - physical_start: 0x50900000, - virtual_start: 0x50900000, - size: 0x10000, + physical_start: 0x0000, + virtual_start: 0x0000, + size: 0xc00_0000, + }, // serial0 + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x1000_0000, + virtual_start: 0x1000_0000, + size: 0x7000_0000, }, // serial0 // HvConfigMemoryRegion { // mem_type: MEM_TYPE_IO, @@ -74,37 +82,37 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 7] = [ // virtual_start: 0x50920000, // size: 0x10000, // }, // serial2 - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0x50460000, - virtual_start: 0x50460000, - size: 0x10000, - }, // mmc - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0x50440000, - virtual_start: 0x50440000, - size: 0x2000, - }, // hsp_sp_top_csr - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0x51828000, - virtual_start: 0x51828000, - size: 0x80000, - }, // sys-crg (clock-controller, reset-controller) (SD card needs) - // Cache controller is needed, otherwise terminal will report "VFS: cannot open root device..." - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0x2010000, - virtual_start: 0x2010000, - size: 0x4000, - }, // L3 cache-controller, now hvisor has virtual sifive ccache. // HvConfigMemoryRegion { // mem_type: MEM_TYPE_IO, - // physical_start: 0x8000000, - // virtual_start: 0x8000000, - // size: 0x400000, - // }, // L3 Loosely-Integrated Memory (L3 LIM) + // physical_start: 0x50460000, + // virtual_start: 0x50460000, + // size: 0x10000, + // }, // mmc + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_IO, + // physical_start: 0x50440000, + // virtual_start: 0x50440000, + // size: 0x2000, + // }, // hsp_sp_top_csr + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_IO, + // physical_start: 0x51828000, + // virtual_start: 0x51828000, + // size: 0x80000, + // }, // sys-crg (clock-controller, reset-controller) (SD card needs) + // // Cache controller is needed, otherwise terminal will report "VFS: cannot open root device..." + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_IO, + // physical_start: 0x2010000, + // virtual_start: 0x2010000, + // size: 0x4000, + // }, // L3 cache-controller, now hvisor has virtual sifive ccache. + // // HvConfigMemoryRegion { + // // mem_type: MEM_TYPE_IO, + // // physical_start: 0x8000000, + // // virtual_start: 0x8000000, + // // size: 0x400000, + // // }, // L3 Loosely-Integrated Memory (L3 LIM) HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0xc0_0000_0000, @@ -140,16 +148,28 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 7] = [ // Note: all here's irqs are hardware irqs, // only these irq can be transferred to the physical PLIC. -pub const HW_IRQS: [u32; 3] = [ +pub const HW_IRQS: [u32; 21] = [ + 0x1, 0x2, 0x3, 0x4, // cache controller 0x4f, // emmc 0x51, // sd-card - 0x64 // uart0 + 0x64, // uart0 + 0x164, 0x168, 0x165, 0x166, // iommu + 0x183, // npu + 0x75, 0x77, 0x79, 0x7b, 0x7d, 0x7f, 0x81, 0x83, // mailbox + 0x123, // i2c + // 0x01, 0x03, 0x04, 0x02, // cache controller ]; // irqs belong to the root zone. -pub const ROOT_ZONE_IRQS: [u32; 2] = [ +pub const ROOT_ZONE_IRQS: [u32; 20] = [ + 0x1, 0x2, 0x3, 0x4, // cache controller 0x51, // sd-card - 0x64 // uart0 + 0x64, // uart0 + 0x164, 0x168, 0x165, 0x166, // iommu + 0x183, // npu + 0x75, 0x77, 0x79, 0x7b, 0x7d, 0x7f, 0x81, 0x83, // mailbox + 0x123, // i2c + // 0x01, 0x03, 0x04, 0x02, // cache controller ]; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { diff --git a/platform/riscv64/hifive-premier-p550/boot.scr b/platform/riscv64/hifive-premier-p550/boot.scr index b6aff6ab23c7826706f3beae73268fde4f6553e1..798ac7890253a65d8a2e06fdb99cdcd06c15fb73 100644 GIT binary patch literal 459 zcmY#ql?=Pk=b(_W{hbv917kM>6y%(}xSUmrjln5DzeFK8xhS)s1SW+>Gd6<+ic?Ec z^U4&8Q;W({fr=FjEsgXH%`Ef`jm`B84Xk;&pb9bz5>rx&P^AqK(s`*RxrxQu3Pz@; zdN7QnJEJVKIKL#du#HXc{z?GzdRbVK|PA$qy&4H=1geU^3 zDoHCTNCNp;r5eeyS|AtZwOT8PgkDl+9;yaZ+fns^<@8cYlCWt(at*33&)mfHRG)d9@a(2mmz{jQ0Ql literal 285 zcmY#ql?>~#@7$Wvut%1Gf#EI?gMpPr92ct;8-r7Reu+YGa#3bM2}}x|z6ug3PAy5z zD^n;=Eh0*-#Pn2aE|96Y NKx5(Rbdl_^1_0^%MZy38 diff --git a/platform/riscv64/hifive-premier-p550/image/dts/eic7700-hifive-premier-p550.dts b/platform/riscv64/hifive-premier-p550/image/dts/eic7700-hifive-premier-p550.dts index fd290b8a..aa6cc1c8 100644 --- a/platform/riscv64/hifive-premier-p550/image/dts/eic7700-hifive-premier-p550.dts +++ b/platform/riscv64/hifive-premier-p550/image/dts/eic7700-hifive-premier-p550.dts @@ -6,7 +6,7 @@ compatible = "sifive,hifive-premier-p550\0eswin,eic7700"; model = "SiFive HiFive Premier P550"; - opp-table@cpu { + opp-table-d0@cpu { compatible = "operating-points-v2"; opp-shared; phandle = <0x04>; @@ -114,9 +114,92 @@ }; }; + opp-table-d1@cpu { + compatible = "operating-points-v2"; + opp-shared; + + opp-24000000 { + opp-hz = <0x00 0x16e3600>; + opp-microvolt = "\0\f5"; + clock-latency-ns = <0x11170>; + }; + + opp-100000000 { + opp-hz = <0x00 0x5f5e100>; + opp-microvolt = "\0\f5"; + clock-latency-ns = <0x11170>; + }; + + opp-200000000 { + opp-hz = <0x00 0xbebc200>; + opp-microvolt = "\0\f5"; + clock-latency-ns = <0x11170>; + }; + + opp-400000000 { + opp-hz = <0x00 0x17d78400>; + opp-microvolt = "\0\f5"; + clock-latency-ns = <0x11170>; + }; + + opp-500000000 { + opp-hz = <0x00 0x1dcd6500>; + opp-microvolt = "\0\f5"; + clock-latency-ns = <0x11170>; + }; + + opp-600000000 { + opp-hz = <0x00 0x23c34600>; + opp-microvolt = "\0\f5"; + clock-latency-ns = <0x11170>; + }; + + opp-700000000 { + opp-hz = <0x00 0x29b92700>; + opp-microvolt = "\0\f5"; + clock-latency-ns = <0x11170>; + }; + + opp-800000000 { + opp-hz = <0x00 0x2faf0800>; + opp-microvolt = "\0\f5"; + clock-latency-ns = <0x11170>; + }; + + opp-900000000 { + opp-hz = <0x00 0x35a4e900>; + opp-microvolt = "\0\f5"; + clock-latency-ns = <0x11170>; + }; + + opp-1000000000 { + opp-hz = <0x00 0x3b9aca00>; + opp-microvolt = "\0\f5"; + clock-latency-ns = <0x11170>; + }; + + opp-1200000000 { + opp-hz = <0x00 0x47868c00>; + opp-microvolt = "\0\f5"; + clock-latency-ns = <0x11170>; + }; + + opp-1300000000 { + opp-hz = <0x00 0x4d7c6d00>; + opp-microvolt = "\0\f5"; + clock-latency-ns = <0x11170>; + }; + + opp-1400000000 { + opp-hz = <0x00 0x53724e00>; + opp-microvolt = "\0\f5"; + clock-latency-ns = <0x11170>; + }; + }; + opp-table@dsp { compatible = "operating-points-v2"; - phandle = <0x25>; + phandle = <0x22>; opp@520000000 { opp-hz = <0x00 0x1efe9200>; @@ -131,7 +214,7 @@ opp-table@npu { compatible = "operating-points-v2"; - phandle = <0x22>; + phandle = <0x1f>; opp@1040000000 { opp-hz = <0x00 0x3dfd2400>; @@ -146,7 +229,7 @@ opp-table@g2d { compatible = "operating-points-v2"; - phandle = <0x2b>; + phandle = <0x28>; opp@260000000 { opp-hz = <0x00 0xf7f4900>; @@ -171,7 +254,7 @@ opp-table@vi { compatible = "operating-points-v2"; - phandle = <0x6c>; + phandle = <0x63>; opp@800000000 { opp-hz = <0x00 0x2faf0800>; @@ -191,7 +274,7 @@ opp-table@venc { compatible = "operating-points-v2"; - phandle = <0x32>; + phandle = <0x2f>; opp@800000000 { opp-hz = <0x00 0x2faf0800>; @@ -211,7 +294,7 @@ opp-table@vdec { compatible = "operating-points-v2"; - phandle = <0x31>; + phandle = <0x2e>; opp@800000000 { opp-hz = <0x00 0x2faf0800>; @@ -544,6 +627,8 @@ }; cache-controller@2010000 { + #address-cells = <0x02>; + #size-cells = <0x02>; cache-block-size = <0x40>; cache-level = <0x03>; cache-sets = <0x1000>; @@ -552,7 +637,6 @@ compatible = "sifive,ccache1\0cache\0sifive,fu740-c000-ccache"; interrupt-parent = <0x10>; interrupts = <0x01 0x03 0x04 0x02>; - next-level-cache = <0x11 0x12 0x13>; reg = <0x00 0x2010000 0x00 0x4000 0x00 0x8000000 0x00 0x400000>; reg-names = "control\0sideband"; sifive,a-mshr-count = <0x3c>; @@ -561,7 +645,13 @@ sifive,max-master-id = <0x0d>; sifive,perfmon-counters = <0x06>; numa-node-id = <0x00>; - phandle = <0x14>; + ranges; + phandle = <0x11>; + + zero-device@1a000000 { + compatible = "l3,zero-device"; + reg = <0x00 0x1a000000 0x00 0x400000>; + }; }; debug-controller@0 { @@ -579,7 +669,6 @@ error-device@10003000 { compatible = "sifive,error0"; reg = <0x00 0x10003000 0x00 0x1000>; - phandle = <0x11>; }; interrupt-controller@c000000 { @@ -610,7 +699,7 @@ cache-size = <0x40000>; cache-unified; compatible = "sifive,pL2Cache0\0cache"; - next-level-cache = <0x14>; + next-level-cache = <0x11>; reg = <0x00 0x104000 0x00 0x4000>; reg-names = "control"; sifive,ecc-granularity = <0x10>; @@ -626,7 +715,7 @@ cache-size = <0x40000>; cache-unified; compatible = "sifive,pL2Cache0\0cache"; - next-level-cache = <0x14>; + next-level-cache = <0x11>; reg = <0x00 0x108000 0x00 0x4000>; reg-names = "control"; sifive,ecc-granularity = <0x10>; @@ -642,7 +731,7 @@ cache-size = <0x40000>; cache-unified; compatible = "sifive,pL2Cache0\0cache"; - next-level-cache = <0x14>; + next-level-cache = <0x11>; reg = <0x00 0x10c000 0x00 0x4000>; reg-names = "control"; sifive,ecc-granularity = <0x10>; @@ -658,7 +747,7 @@ cache-size = <0x40000>; cache-unified; compatible = "sifive,pL2Cache0\0cache"; - next-level-cache = <0x14>; + next-level-cache = <0x11>; reg = <0x00 0x110000 0x00 0x4000>; reg-names = "control"; sifive,ecc-granularity = <0x10>; @@ -670,13 +759,11 @@ rom@1a000000 { compatible = "ucbbar,cacheable-zero0"; reg = <0x00 0x1a000000 0x00 0x400000>; - phandle = <0x12>; }; rom@3a000000 { compatible = "ucbbar,cacheable-zero0"; reg = <0x00 0x3a000000 0x00 0x400000>; - phandle = <0x13>; }; subsystem_pbus_clock { @@ -748,7 +835,7 @@ reg-io-width = <0x04>; numa-node-id = <0x00>; status = "okay"; - phandle = <0x2a>; + phandle = <0x27>; }; serial@0x50910000 { @@ -805,13 +892,13 @@ #size-cells = <0x02>; reg = <0x00 0x51810000 0x00 0x8000>; numa-node-id = <0x00>; - phandle = <0x17>; + phandle = <0x14>; noc@51810324 { compatible = "eswin,win2030-noc-wdt"; interrupt-parent = <0x10>; interrupts = <0x188 0x189 0x18a 0x18b 0x18c 0x18d 0x18e 0x18f 0x190 0x191 0x192 0x193 0x194 0x195 0x196 0x197 0x198 0x199 0x19a 0x19b 0x19c 0x19d 0x19e 0x19f 0x1a0 0x1a1 0x1a2 0x1a3 0x1a4 0x1a5 0x1a6 0x1a7 0x1a8 0x1a9 0x1aa>; - eswin,syscrg_csr = <0x15 0x100 0xffff>; + eswin,syscrg_csr = <0x12 0x100 0xffff>; status = "okay"; }; }; @@ -820,14 +907,14 @@ compatible = "eswin,win2030-sys-crg\0syscon\0simple-mfd"; reg = <0x00 0x51828000 0x00 0x80000>; numa-node-id = <0x00>; - phandle = <0x15>; + phandle = <0x12>; reset-controller { compatible = "eswin,win2030-reset"; #reset-cells = <0x02>; numa-node-id = <0x00>; status = "okay"; - phandle = <0x18>; + phandle = <0x15>; }; clock-controller { @@ -835,7 +922,7 @@ #clock-cells = <0x01>; numa-node-id = <0x00>; status = "okay"; - cpu-voltage-gpios = <0x16 0x1e 0x00>; + cpu-voltage-gpios = <0x13 0x1e 0x00>; phandle = <0x03>; }; }; @@ -853,29 +940,29 @@ numa-node-id = <0x00>; #size-cells = <0x02>; reg = <0x00 0x50440000 0x00 0x2000>; - phandle = <0x1a>; + phandle = <0x17>; }; iommu@50c00000 { compatible = "arm,smmu-v3"; reg = <0x00 0x50c00000 0x00 0x100000>; - eswin,syscfg = <0x17 0x3fc>; + eswin,syscfg = <0x14 0x3fc>; interrupt-parent = <0x10>; interrupts = <0x164 0x168 0x165 0x166>; interrupt-names = "eventq\0gerror\0priq\0cmdq-sync"; #iommu-cells = <0x01>; - resets = <0x18 0x05 0x01 0x18 0x05 0x02 0x18 0x05 0x10 0x18 0x05 0x20 0x18 0x05 0x40 0x18 0x05 0x80 0x18 0x05 0x100 0x18 0x05 0x200 0x18 0x05 0x400 0x18 0x05 0x800>; + resets = <0x15 0x05 0x01 0x15 0x05 0x02 0x15 0x05 0x10 0x15 0x05 0x20 0x15 0x05 0x40 0x15 0x05 0x80 0x15 0x05 0x100 0x15 0x05 0x200 0x15 0x05 0x400 0x15 0x05 0x800>; reset-names = "axi_rst\0cfg_rst\0tbu0_rst\0tbu1_rst\0tbu2_rst\0tbu3_rst\0tbu4_rst\0tbu5_rst\0tbu6_rst\0tbu7_rst"; status = "okay"; numa-node-id = <0x00>; dma-noncoherent; - phandle = <0x19>; + phandle = <0x16>; }; pmu@50c02000 { compatible = "arm,smmu-v3-pmcg"; reg = <0x00 0x50c02000 0x00 0x1000 0x00 0x50c22000 0x00 0x1000>; - eswin,syscfg = <0x17 0x3fc>; + eswin,syscfg = <0x14 0x3fc>; interrupt-parent = <0x10>; interrupts = <0x16b>; status = "disabled"; @@ -887,7 +974,7 @@ compatible = "riscv,dev-foo-a"; #size-cells = <0x02>; dma-ranges = <0x00 0x20000000 0x00 0xc0000000 0x00 0x40000000>; - iommus = <0x19 0x1c>; + iommus = <0x16 0x1c>; tbus = <0xf00>; status = "okay"; numa-node-id = <0x00>; @@ -994,41 +1081,15 @@ }; }; - dma-controller-hsp@0x50430000 { - compatible = "eswin,eic770x-axi-dma"; - reg = <0x00 0x50430000 0x00 0x10000>; - interrupt-parent = <0x10>; - interrupts = <0x39>; - #dma-cells = <0x02>; - clocks = <0x03 0x2b2 0x03 0x2b3>; - clock-names = "core-clk\0cfgr-clk"; - resets = <0x18 0x07 0x4000 0x18 0x07 0x100000>; - reset-names = "arst\0prst"; - dma-channels = <0x0c>; - snps,dma-masters = <0x01>; - snps,priority = <0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b>; - snps,data-width = <0x02>; - snps,block-size = <0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000>; - snps,axi-max-burst-len = <0x10>; - snps,max-msize = <0x40>; - iommus = <0x19 0x01>; - tbus = <0x02>; - eswin,hsp_sp_csr = <0x1a 0x104c>; - eswin,syscfg = <0x17 0x3004 0x370>; - numa-node-id = <0x00>; - dma-noncoherent; - status = "okay"; - }; - dma-controller-aon@0x518c0000 { compatible = "eswin,eic770x-axi-dma"; reg = <0x00 0x518c0000 0x00 0x10000>; interrupt-parent = <0x10>; interrupts = <0x121>; - #dma-cells = <0x02>; + #dma-cells = <0x03>; clocks = <0x03 0x266 0x03 0x264>; clock-names = "core-clk\0cfgr-clk"; - resets = <0x18 0x27 0x01 0x18 0x27 0x02>; + resets = <0x15 0x27 0x01 0x15 0x27 0x02>; reset-names = "arst\0prst"; dma-channels = <0x10>; snps,dma-masters = <0x02>; @@ -1036,16 +1097,43 @@ snps,data-width = <0x03>; snps,block-size = <0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000>; snps,axi-max-burst-len = <0x20>; + snps,max-msize = <0x40>; #size-cells = <0x02>; #address-cells = <0x02>; dma-ranges = <0x00 0x80000000 0x00 0x80000000 0x100 0x00>; - iommus = <0x19 0x1a>; + iommus = <0x16 0x1a>; tbus = <0x04>; - eswin,syscfg = <0x17 0x3004 0x370>; + eswin,syscfg = <0x14 0x3004 0x370>; + numa-node-id = <0x00>; + dma-noncoherent; + status = "okay"; + phandle = <0x39>; + }; + + dma-controller-hsp@0x50430000 { + compatible = "eswin,eic770x-axi-dma"; + reg = <0x00 0x50430000 0x00 0x10000>; + interrupt-parent = <0x10>; + interrupts = <0x39>; + #dma-cells = <0x03>; + clocks = <0x03 0x2b2 0x03 0x2b3>; + clock-names = "core-clk\0cfgr-clk"; + resets = <0x15 0x07 0x4000 0x15 0x07 0x100000>; + reset-names = "arst\0prst"; + dma-channels = <0x0c>; + snps,dma-masters = <0x01>; + snps,priority = <0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b>; + snps,data-width = <0x02>; + snps,block-size = <0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000 0x80000>; + snps,axi-max-burst-len = <0x10>; + snps,max-msize = <0x40>; + iommus = <0x16 0x01>; + tbus = <0x02>; + eswin,hsp_sp_csr = <0x17 0x104c>; + eswin,syscfg = <0x14 0x3004 0x370>; numa-node-id = <0x00>; dma-noncoherent; status = "okay"; - phandle = <0x3c>; }; ethernet@50400000 { @@ -1060,18 +1148,18 @@ status = "okay"; clocks = <0x03 0x226 0x03 0x227 0x03 0x228>; clock-names = "app\0stmmaceth\0tx"; - resets = <0x18 0x07 0x4000000>; + resets = <0x15 0x07 0x4000000>; reset-names = "ethrst"; tbus = <0x02>; dma-noncoherent; - eswin,hsp_sp_csr = <0x1a 0x1030 0x100 0x108>; - eswin,syscrg_csr = <0x15 0x148 0x14c>; + eswin,hsp_sp_csr = <0x17 0x1030 0x100 0x108>; + eswin,syscrg_csr = <0x12 0x148 0x14c>; eswin,dly_hsp_reg = <0x114 0x118 0x11c>; - snps,axi-config = <0x1b>; + snps,axi-config = <0x18>; pinctrl-names = "default"; - pinctrl-0 = <0x1c>; - rst-gpios = <0x1d 0x0a 0x01>; - eswin,rgmiisel = <0x1e 0x290 0x03>; + pinctrl-0 = <0x19>; + rst-gpios = <0x1a 0x0a 0x01>; + eswin,rgmiisel = <0x1b 0x290 0x03>; eswin,led-cfgs = <0x6100 0xa40 0x420>; dly-param-1000m = <0x23232323 0x800c8023 0xc0c0c0c>; dly-param-100m = <0x50505050 0x803f8050 0x3f3f3f3f>; @@ -1082,7 +1170,7 @@ snps,rd_osr_lmt = <0x02>; snps,wr_osr_lmt = <0x02>; snps,lpi_en = <0x00>; - phandle = <0x1b>; + phandle = <0x18>; }; }; @@ -1098,18 +1186,18 @@ status = "okay"; clocks = <0x03 0x226 0x03 0x227 0x03 0x229>; clock-names = "app\0stmmaceth\0tx"; - resets = <0x18 0x07 0x2000000>; + resets = <0x15 0x07 0x2000000>; reset-names = "ethrst"; tbus = <0x02>; dma-noncoherent; - eswin,hsp_sp_csr = <0x1a 0x1034 0x200 0x208>; - eswin,syscrg_csr = <0x15 0x148 0x14c>; + eswin,hsp_sp_csr = <0x17 0x1034 0x200 0x208>; + eswin,syscrg_csr = <0x12 0x148 0x14c>; eswin,dly_hsp_reg = <0x214 0x218 0x21c>; - snps,axi-config = <0x1f>; + snps,axi-config = <0x1c>; pinctrl-names = "default"; - pinctrl-0 = <0x20>; - rst-gpios = <0x1d 0x0f 0x01>; - eswin,rgmiisel = <0x1e 0x294 0x03>; + pinctrl-0 = <0x1d>; + rst-gpios = <0x1a 0x0f 0x01>; + eswin,rgmiisel = <0x1b 0x294 0x03>; eswin,led-cfgs = <0x6100 0xa40 0x420>; dly-param-1000m = <0x25252525 0x80268025 0x26262626>; dly-param-100m = <0x48484848 0x80588048 0x58585858>; @@ -1120,7 +1208,7 @@ snps,rd_osr_lmt = <0x02>; snps,wr_osr_lmt = <0x02>; snps,lpi_en = <0x00>; - phandle = <0x1f>; + phandle = <0x1c>; }; }; @@ -2119,37 +2207,37 @@ interrupts = <0x183 0x10>; #size-cells = <0x02>; dma-ranges = <0x01 0x00 0x00 0xc0000000 0x1ff 0x00>; - iommus = <0x19 0x04>; + iommus = <0x16 0x04>; tbus = <0x05>; dsp-avail-num = <0x01>; spram-size = <0x400000>; - npu_mbox = <0x21>; - clocks = <0x03 0x236 0x03 0x237 0x03 0x23c 0x03 0x23d 0x03 0x26 0x03 0x0b 0x03 0x07>; - clock-names = "aclk\0cfg_clk\0core_clk\0e31_core_clk\0mux_u_npu_core_3mux1_gfree\0fixed_rate_clk_spll2_fout2\0fixed_rate_clk_spll1_fout1"; - resets = <0x18 0x06 0x08>; + npu_mbox = <0x1e>; + clocks = <0x03 0x236 0x03 0x237 0x03 0x23c 0x03 0x23a 0x03 0x23d 0x03 0x26 0x03 0x25 0x03 0x0b 0x03 0x07 0x03 0x238 0x03 0x0d>; + clock-names = "aclk\0cfg_clk\0core_clk\0clk_npu_llc_aclk\0e31_core_clk\0mux_u_npu_core_3mux1_gfree\0mux_u_npu_llclk_3mux1_gfree\0fixed_rate_clk_spll2_fout2\0fixed_rate_clk_spll1_fout1\0clk_clk_npu_llc_src0\0fixed_rate_clk_vpll_fout1"; + resets = <0x15 0x06 0x08>; reset-names = "e31_core"; - operating-points-v2 = <0x22>; + operating-points-v2 = <0x1f>; numa-node-id = <0x00>; firmware-name = "eic7700_die0_e31_fw"; dma-noncoherent; #cooling-cells = <0x02>; dynamic-power-coefficient = <0x00>; status = "okay"; - npu-supply = <0x23>; + npu-supply = <0x20>; }; llc@51c00000 { compatible = "eswin,llc"; reg = <0x00 0x51c00000 0x00 0x400000>; - eswin,syscfg = <0x17 0x324>; - eswin,syscrg_csr = <0x15>; + eswin,syscfg = <0x14 0x324>; + eswin,syscrg_csr = <0x12>; clocks = <0x03 0x236 0x03 0x237 0x03 0x23a 0x03 0x23c 0x03 0x26 0x03 0x0b 0x03 0x07>; clock-names = "aclk\0cfg_clk\0llc_clk\0core_clk\0mux_u_npu_core_3mux1_gfree\0fixed_rate_clk_spll2_fout2\0fixed_rate_clk_spll1_fout1"; - resets = <0x18 0x06 0x01 0x18 0x06 0x02 0x18 0x06 0x04 0x18 0x06 0x40>; + resets = <0x15 0x06 0x01 0x15 0x06 0x02 0x15 0x06 0x04 0x15 0x06 0x40>; reset-names = "axi\0cfg\0core\0llc"; numa-node-id = <0x00>; - spram-region = <0x24>; - npu-supply = <0x23>; + spram-region = <0x21>; + npu-supply = <0x20>; status = "okay"; }; @@ -2163,7 +2251,7 @@ compatible = "es-dsp-subsys\0simple-bus"; clocks = <0x03 0x210 0x03 0x20f>; clock-names = "cfg_clk\0aclk"; - resets = <0x18 0x02 0x01 0x18 0x02 0x02 0x18 0x02 0x04 0x18 0x02 0x10 0x18 0x02 0x20 0x18 0x02 0x40 0x18 0x02 0x80>; + resets = <0x15 0x02 0x01 0x15 0x02 0x02 0x15 0x02 0x04 0x15 0x02 0x10 0x15 0x02 0x20 0x15 0x02 0x40 0x15 0x02 0x80>; reset-names = "axi\0cfg\0div4\0div_0\0div_1\0div_2\0div_3"; status = "okay"; @@ -2174,15 +2262,15 @@ ranges = <0x28000000 0x00 0x5b000000 0x8000 0x28100000 0x00 0x5b100000 0x20000 0x28120000 0x00 0x5b120000 0x20000>; clocks = <0x03 0x2a8>; clock-names = "aclk"; - operating-points-v2 = <0x25>; - dsp_mbox = <0x26>; + operating-points-v2 = <0x22>; + dsp_mbox = <0x23>; device-irq = <0x0b 0x50a90000 0x20 0x50a80000 0x01 0x50a40000>; device-uart = <0x50900000>; device-irq-mode = <0x01>; host-irq-mode = <0x01>; firmware-name = "eic7700_dsp_fw"; process-id = <0x00>; - iommus = <0x19 0x12>; + iommus = <0x16 0x12>; tbus = <0x70>; dma-noncoherent; numa-node-id = <0x00>; @@ -2200,15 +2288,15 @@ ranges = <0x28000000 0x00 0x5b008000 0x8000 0x28100000 0x00 0x5b140000 0x20000 0x28120000 0x00 0x5b160000 0x20000>; clocks = <0x03 0x2a9>; clock-names = "aclk"; - operating-points-v2 = <0x25>; - dsp_mbox = <0x27>; + operating-points-v2 = <0x22>; + dsp_mbox = <0x24>; device-irq = <0x0d 0x50ab0000 0x40 0x50aa0000 0x01 0x50a40000>; device-uart = <0x50900000>; device-irq-mode = <0x01>; host-irq-mode = <0x01>; firmware-name = "eic7700_dsp_fw"; process-id = <0x01>; - iommus = <0x19 0x13>; + iommus = <0x16 0x13>; tbus = <0x71>; dma-noncoherent; numa-node-id = <0x00>; @@ -2226,15 +2314,15 @@ ranges = <0x28000000 0x00 0x5b010000 0x8000 0x28100000 0x00 0x5b180000 0x20000 0x28120000 0x00 0x5b1a0000 0x20000>; clocks = <0x03 0x2aa>; clock-names = "aclk"; - operating-points-v2 = <0x25>; - dsp_mbox = <0x28>; + operating-points-v2 = <0x22>; + dsp_mbox = <0x25>; device-irq = <0x0f 0x50ad0000 0x80 0x50ac0000 0x01 0x50a40000>; device-uart = <0x50900000>; device-irq-mode = <0x01>; host-irq-mode = <0x01>; firmware-name = "eic7700_dsp_fw"; process-id = <0x02>; - iommus = <0x19 0x14>; + iommus = <0x16 0x14>; tbus = <0x72>; dma-noncoherent; numa-node-id = <0x00>; @@ -2252,15 +2340,15 @@ ranges = <0x28000000 0x00 0x5b018000 0x8000 0x28100000 0x00 0x5b1c0000 0x20000 0x28120000 0x00 0x5b1e0000 0x20000>; clocks = <0x03 0x2ab>; clock-names = "aclk"; - operating-points-v2 = <0x25>; - dsp_mbox = <0x29>; + operating-points-v2 = <0x22>; + dsp_mbox = <0x26>; device-irq = <0x11 0x50af0000 0x100 0x50ae0000 0x01 0x50a40000>; device-uart = <0x50900000>; device-irq-mode = <0x01>; host-irq-mode = <0x01>; firmware-name = "eic7700_dsp_fw"; process-id = <0x03>; - iommus = <0x19 0x15>; + iommus = <0x16 0x15>; tbus = <0x73>; dma-noncoherent; numa-node-id = <0x00>; @@ -2278,16 +2366,16 @@ compatible = "eswin,sof-dsp"; reg = <0x00 0x5b018000 0x00 0x8000 0x00 0x5b1c0000 0x00 0x40000>; mbox-names = "dsp-mbox"; - mboxes = <0x29 0x00>; + mboxes = <0x26 0x00>; clocks = <0x03 0x2ab>; clock-names = "aclk"; process-id = <0x03>; - iommus = <0x19 0x15>; + iommus = <0x16 0x15>; tbus = <0x73>; dma-noncoherent; mailbox-dsp-to-u84-addr = <0x50af0000>; mailbox-u84-to-dsp-addr = <0x50ae0000>; - dsp-uart = <0x2a>; + dsp-uart = <0x27>; device-uart-mutex = <0x51820000>; numa-node-id = <0x00>; }; @@ -2297,7 +2385,7 @@ compatible = "eswin,galcore_d0"; clocks = <0x03 0x254 0x03 0x255 0x03 0x25a 0x03 0x25b 0x03 0x25c 0x03 0x25d 0x03 0x2b1>; clock-names = "vc_aclk\0vc_cfg\0g2d_cfg\0g2d_st2\0g2d_clk\0g2d_aclk\0mon_pclk"; - resets = <0x18 0x16 0x02 0x18 0x16 0x01 0x18 0x16 0x04 0x18 0x1b 0x01 0x18 0x1b 0x02 0x18 0x1b 0x04>; + resets = <0x15 0x16 0x02 0x15 0x16 0x01 0x15 0x16 0x04 0x15 0x1b 0x01 0x15 0x1b 0x02 0x15 0x1b 0x04>; reset-names = "axi\0cfg\0moncfg\0g2d_core\0g2d_cfg\0g2d_axi"; reg = <0x00 0x50140000 0x00 0x40000 0x00 0x50180000 0x00 0x40000>; reg-names = "core_2d\0core_2d1"; @@ -2309,7 +2397,7 @@ contiguous-size = <0xa00000>; recovery = <0x00>; dma-noncoherent; - operating-points-v2 = <0x2b>; + operating-points-v2 = <0x28>; numa-node-id = <0x00>; status = "okay"; }; @@ -2321,7 +2409,7 @@ reg = <0x00 0x51400000 0x00 0xfffff>; clocks = <0x03 0x20b 0x03 0x20c 0x03 0x20d>; clock-names = "aclk\0gray_clk\0cfg_clk"; - resets = <0x18 0x01 0x01 0x18 0x01 0x02 0x18 0x01 0x04 0x18 0x01 0x08 0x18 0x01 0x10>; + resets = <0x15 0x01 0x01 0x15 0x01 0x02 0x15 0x01 0x04 0x15 0x01 0x08 0x15 0x01 0x10>; reset-names = "axi\0cfg\0gray\0jones\0spu"; interrupt-parent = <0x10>; interrupts = <0x0f>; @@ -2339,19 +2427,19 @@ interrupt-names = "intrq\0msi\0pme"; interrupts = <0x3a 0x3b 0x3c>; ports-implemented = <0x01>; - resets = <0x18 0x07 0x8000000>; + resets = <0x15 0x07 0x8000000>; reset-names = "apb"; #size-cells = <0x02>; - iommus = <0x19 0x0e>; + iommus = <0x16 0x0e>; tbus = <0x02>; dma-ranges = <0x00 0x00 0x00 0xc0000000 0x200 0x00>; - eswin,hsp_sp_csr = <0x1a 0x1050>; - eswin,syscrg_csr = <0x15 0x41c>; + eswin,hsp_sp_csr = <0x17 0x1050>; + eswin,syscrg_csr = <0x12 0x41c>; numa-node-id = <0x00>; dma-noncoherent; status = "okay"; pinctrl-names = "default"; - pinctrl-0 = <0x2c>; + pinctrl-0 = <0x29>; }; pcie@0x54000000 { @@ -2359,7 +2447,7 @@ clocks = <0x03 0x232 0x03 0x233 0x03 0x234 0x03 0x235>; clock-names = "pcie_aclk\0pcie_cfg_clk\0pcie_cr_clk\0pcie_aux_clk"; reset-names = "pcie_cfg\0pcie_powerup\0pcie_pwren"; - resets = <0x18 0x08 0x01 0x18 0x08 0x02 0x18 0x08 0x04>; + resets = <0x15 0x08 0x01 0x15 0x08 0x02 0x15 0x08 0x04>; #address-cells = <0x03>; #size-cells = <0x02>; #interrupt-cells = <0x01>; @@ -2374,8 +2462,8 @@ interrupt-parent = <0x10>; interrupt-map-mask = <0x00 0x00 0x00 0x07>; interrupt-map = <0x00 0x00 0x00 0x01 0x10 0xb3 0x00 0x00 0x00 0x02 0x10 0xb4 0x00 0x00 0x00 0x03 0x10 0xb5 0x00 0x00 0x00 0x04 0x10 0xb6>; - iommus = <0x19 0xfe0000>; - iommu-map = <0x00 0x19 0xff0000 0xffffff>; + iommus = <0x16 0xfe0000>; + iommu-map = <0x00 0x16 0xff0000 0xffffff>; tbus = <0x03>; status = "okay"; numa-node-id = <0x00>; @@ -2392,7 +2480,7 @@ clock-names = "clk"; interrupt-parent = <0x10>; interrupts = <0x5b>; - resets = <0x18 0x10 0x01>; + resets = <0x15 0x10 0x01>; reset-names = "spi"; numa-node-id = <0x00>; status = "disabled"; @@ -2409,7 +2497,7 @@ clock-names = "clk"; interrupt-parent = <0x10>; interrupts = <0x5c>; - resets = <0x18 0x10 0x02>; + resets = <0x15 0x10 0x02>; reset-names = "spi"; numa-node-id = <0x00>; status = "disabled"; @@ -2423,15 +2511,15 @@ #size-cells = <0x00>; clocks = <0x03 0x205 0x03 0x204>; clock-names = "cfg_clk\0clk"; - resets = <0x18 0x24 0x02>; + resets = <0x15 0x24 0x02>; reset-names = "rst"; spi-max-frequency = "\0I>"; reg-io-width = <0x04>; numa-node-id = <0x00>; status = "okay"; num-cs = <0x01>; - cs-gpios = <0x1d 0x00 0x01>; - wp-gpios = <0x1d 0x04 0x01>; + cs-gpios = <0x1a 0x00 0x01>; + wp-gpios = <0x1a 0x04 0x01>; spi-flash@0 { compatible = "winbond,w25q128jw\0jedec,spi-nor"; @@ -2454,7 +2542,7 @@ clock-names = "clk_xin\0clk_ahb"; clock-output-names = "emmc_cardclock"; #clock-cells = <0x00>; - resets = <0x18 0x07 0x40 0x18 0x07 0x08 0x18 0x07 0x80000 0x18 0x07 0x800000>; + resets = <0x15 0x07 0x40 0x15 0x07 0x08 0x15 0x07 0x80000 0x15 0x07 0x800000>; reset-names = "txrx_rst\0phy_rst\0prstn\0arstn"; core-clk-reg = <0x51828160>; disable-cqe-dcmd; @@ -2463,11 +2551,11 @@ mmc-hs400-1_8v; max-frequency = <0xbebc200>; #size-cells = <0x02>; - iommus = <0x19 0x0f>; + iommus = <0x16 0x0f>; tbus = <0x02>; dma-ranges = <0x00 0x00 0x00 0xc0000000 0x01 0x00>; - eswin,hsp_sp_csr = <0x1a 0x1038 0x508 0x50c>; - eswin,syscrg_csr = <0x15 0x160 0x148 0x14c>; + eswin,hsp_sp_csr = <0x17 0x1038 0x508 0x50c>; + eswin,syscrg_csr = <0x12 0x160 0x148 0x14c>; status = "okay"; numa-node-id = <0x00>; dma-noncoherent; @@ -2476,7 +2564,7 @@ enable-cmd-pullup; enable-data-pullup; pinctrl-names = "default"; - pinctrl-0 = <0x2d>; + pinctrl-0 = <0x2a>; no-sdio; no-sd; }; @@ -2490,17 +2578,17 @@ clock-names = "clk_xin\0clk_ahb\0clk_spll2_fout3\0clk_mux1_1"; clock-output-names = "sdio0_cardclock"; #clock-cells = <0x00>; - resets = <0x18 0x07 0x80 0x18 0x07 0x10 0x18 0x07 0x40000 0x18 0x07 0x400000>; + resets = <0x15 0x07 0x80 0x15 0x07 0x10 0x15 0x07 0x40000 0x15 0x07 0x400000>; reset-names = "txrx_rst\0phy_rst\0prstn\0arstn"; clock-frequency = <0xc65d400>; max-frequency = <0xc65d400>; #address-cells = <0x01>; #size-cells = <0x00>; dma-ranges = <0x00 0x20000000 0x00 0xc0000000 0x00 0x40000000>; - iommus = <0x19 0x10>; + iommus = <0x16 0x10>; tbus = <0x02>; - eswin,hsp_sp_csr = <0x1a 0x103c 0x608 0x60c>; - eswin,syscrg_csr = <0x15 0x164 0x148 0x14c>; + eswin,hsp_sp_csr = <0x17 0x103c 0x608 0x60c>; + eswin,syscrg_csr = <0x12 0x164 0x148 0x14c>; bus-width = <0x04>; sdio-id = <0x00>; numa-node-id = <0x00>; @@ -2523,17 +2611,17 @@ clock-names = "clk_xin\0clk_ahb\0clk_spll2_fout3\0clk_mux1_1"; clock-output-names = "sdio1_cardclock"; #clock-cells = <0x00>; - resets = <0x18 0x07 0x100 0x18 0x07 0x20 0x18 0x07 0x20000 0x18 0x07 0x200000>; + resets = <0x15 0x07 0x100 0x15 0x07 0x20 0x15 0x07 0x20000 0x15 0x07 0x200000>; reset-names = "txrx_rst\0phy_rst\0prstn\0arstn"; clock-frequency = <0xc65d400>; max-frequency = <0xc65d400>; #address-cells = <0x01>; #size-cells = <0x00>; dma-ranges = <0x00 0x20000000 0x00 0xc0000000 0x00 0x40000000>; - iommus = <0x19 0x11>; + iommus = <0x16 0x11>; tbus = <0x02>; - eswin,hsp_sp_csr = <0x1a 0x1040 0x708 0x70c>; - eswin,syscrg_csr = <0x15 0x168 0x148 0x14c>; + eswin,hsp_sp_csr = <0x17 0x1040 0x708 0x70c>; + eswin,syscrg_csr = <0x12 0x168 0x148 0x14c>; bus-width = <0x04>; sdio-id = <0x01>; numa-node-id = <0x00>; @@ -2551,13 +2639,13 @@ wifi_aw3155@0 { compatible = "aml_w1_sdio"; reg = <0x00>; - interrupt-parent = <0x2e>; + interrupt-parent = <0x2b>; interrupts = <0x0f 0x08>; pinctrl-names = "default\0default"; - pinctrl-0 = <0x2f>; - pinctrl-1 = <0x30>; - irq-gpios = <0x2e 0x0f 0x00>; - rst-gpios = <0x16 0x0f 0x00>; + pinctrl-0 = <0x2c>; + pinctrl-1 = <0x2d>; + irq-gpios = <0x2b 0x0f 0x00>; + rst-gpios = <0x13 0x0f 0x00>; }; }; @@ -2565,17 +2653,17 @@ compatible = "eswin,video-decoder0"; clocks = <0x03 0x254 0x03 0x255 0x03 0x257 0x03 0x259 0x03 0x2e 0x03 0x04 0x03 0x0a 0x03 0x2ae 0x03 0x2b0 0x03 0x2b1>; clock-names = "aclk\0cfg_clk\0jd_clk\0vd_clk\0vc_mux\0spll0_fout1\0spll2_fout1\0jd_pclk\0vd_pclk\0mon_pclk"; - resets = <0x18 0x16 0x02 0x18 0x16 0x01 0x18 0x16 0x04 0x18 0x17 0x01 0x18 0x17 0x02 0x18 0x19 0x01 0x18 0x19 0x02>; + resets = <0x15 0x16 0x02 0x15 0x16 0x01 0x15 0x16 0x04 0x15 0x17 0x01 0x15 0x17 0x02 0x15 0x19 0x01 0x15 0x19 0x02>; reset-names = "axi\0cfg\0moncfg\0jd_cfg\0jd_axi\0vd_cfg\0vd_axi"; - eswin,syscfg = <0x17 0x00 0x04>; - operating-points-v2 = <0x31>; + eswin,syscfg = <0x14 0x00 0x04>; + operating-points-v2 = <0x2e>; vcmd-core = <0x00 0x6c>; axife-core = <0x200 0x100>; vdec-core = <0x800 0xc00>; interrupt-parent = <0x10>; #size-cells = <0x02>; dma-ranges = <0x00 0x00 0x00 0x80000000 0x200 0x00>; - iommus = <0x19 0x02>; + iommus = <0x16 0x02>; vccsr-reg = <0x00 0x501c0000 0x00 0x1000>; numa-node-id = <0x00>; tbus = <0x10 0x13>; @@ -2599,17 +2687,17 @@ compatible = "eswin,video-encoder0"; clocks = <0x03 0x254 0x03 0x255 0x03 0x256 0x03 0x258 0x03 0x2e 0x03 0x04 0x03 0x0a 0x03 0x2ad 0x03 0x2af 0x03 0x2b1>; clock-names = "aclk\0cfg_clk\0je_clk\0ve_clk\0vc_mux\0spll0_fout1\0spll2_fout1\0je_pclk\0ve_pclk\0mon_pclk"; - resets = <0x18 0x16 0x02 0x18 0x16 0x01 0x18 0x16 0x04 0x18 0x18 0x01 0x18 0x18 0x02 0x18 0x1a 0x02 0x18 0x1a 0x01>; + resets = <0x15 0x16 0x02 0x15 0x16 0x01 0x15 0x16 0x04 0x15 0x18 0x01 0x15 0x18 0x02 0x15 0x1a 0x02 0x15 0x1a 0x01>; reset-names = "axi\0cfg\0moncfg\0je_cfg\0je_axi\0ve_cfg\0ve_axi"; - eswin,syscfg = <0x17 0x00 0x04>; - operating-points-v2 = <0x32>; + eswin,syscfg = <0x14 0x00 0x04>; + operating-points-v2 = <0x2f>; vcmd-core = <0x00 0x6c>; axife-core = <0x2000 0x7d0>; venc-core = <0x1000 0x87c>; interrupt-parent = <0x10>; #size-cells = <0x02>; dma-ranges = <0x00 0x00 0x00 0x80000000 0x200 0x00>; - iommus = <0x19 0x03>; + iommus = <0x16 0x03>; vccsr-reg = <0x00 0x501c0000 0x00 0x1000>; numa-node-id = <0x00>; dma-noncoherent; @@ -2638,14 +2726,14 @@ #mbox-cells = <0x01>; clocks = <0x03 0x27e 0x03 0x27f>; clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x18 0x0c 0x01 0x18 0x0c 0x02>; + resets = <0x15 0x0c 0x01 0x15 0x0c 0x02>; reset-names = "rst\0rst_device"; lock-bit = <0x01>; irq-bit = <0x02>; numa-node-id = <0x00>; dma-noncoherent; status = "okay"; - phandle = <0x33>; + phandle = <0x30>; }; mbox@50a20000 { @@ -2656,14 +2744,14 @@ #mbox-cells = <0x01>; clocks = <0x03 0x280 0x03 0x281>; clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x18 0x0c 0x04 0x18 0x0c 0x08>; + resets = <0x15 0x0c 0x04 0x15 0x0c 0x08>; reset-names = "rst\0rst_device"; lock-bit = <0x01>; irq-bit = <0x04>; numa-node-id = <0x00>; dma-noncoherent; status = "okay"; - phandle = <0x34>; + phandle = <0x31>; }; mbox@50a40000 { @@ -2674,14 +2762,14 @@ #mbox-cells = <0x01>; clocks = <0x03 0x282 0x03 0x283>; clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x18 0x0c 0x10 0x18 0x0c 0x20>; + resets = <0x15 0x0c 0x10 0x15 0x0c 0x20>; reset-names = "rst\0rst_device"; lock-bit = <0x01>; irq-bit = <0x08>; numa-node-id = <0x00>; dma-noncoherent; status = "okay"; - phandle = <0x21>; + phandle = <0x1e>; }; mbox@50a60000 { @@ -2692,7 +2780,7 @@ #mbox-cells = <0x01>; clocks = <0x03 0x284 0x03 0x285>; clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x18 0x0c 0x40 0x18 0x0c 0x80>; + resets = <0x15 0x0c 0x40 0x15 0x0c 0x80>; reset-names = "rst\0rst_device"; lock-bit = <0x01>; irq-bit = <0x10>; @@ -2709,14 +2797,14 @@ #mbox-cells = <0x01>; clocks = <0x03 0x286 0x03 0x287>; clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x18 0x0c 0x100 0x18 0x0c 0x200>; + resets = <0x15 0x0c 0x100 0x15 0x0c 0x200>; reset-names = "rst\0rst_device"; lock-bit = <0x01>; irq-bit = <0x20>; numa-node-id = <0x00>; dma-noncoherent; status = "okay"; - phandle = <0x26>; + phandle = <0x23>; }; mbox@50aa0000 { @@ -2727,14 +2815,14 @@ #mbox-cells = <0x01>; clocks = <0x03 0x288 0x03 0x289>; clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x18 0x0c 0x400 0x18 0x0c 0x800>; + resets = <0x15 0x0c 0x400 0x15 0x0c 0x800>; reset-names = "rst\0rst_device"; lock-bit = <0x01>; irq-bit = <0x40>; numa-node-id = <0x00>; dma-noncoherent; status = "okay"; - phandle = <0x27>; + phandle = <0x24>; }; mbox@50ac0000 { @@ -2745,14 +2833,14 @@ #mbox-cells = <0x01>; clocks = <0x03 0x28a 0x03 0x28b>; clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x18 0x0c 0x1000 0x18 0x0c 0x2000>; + resets = <0x15 0x0c 0x1000 0x15 0x0c 0x2000>; reset-names = "rst\0rst_device"; lock-bit = <0x01>; irq-bit = <0x80>; numa-node-id = <0x00>; dma-noncoherent; status = "okay"; - phandle = <0x28>; + phandle = <0x25>; }; mbox@50ae0000 { @@ -2763,24 +2851,24 @@ #mbox-cells = <0x01>; clocks = <0x03 0x28c 0x03 0x28d>; clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x18 0x0c 0x4000 0x18 0x0c 0x8000>; + resets = <0x15 0x0c 0x4000 0x15 0x0c 0x8000>; reset-names = "rst\0rst_device"; lock-bit = <0x01>; irq-bit = <0x100>; numa-node-id = <0x00>; dma-noncoherent; status = "okay"; - phandle = <0x29>; + phandle = <0x26>; }; ipc@0 { compatible = "eswin,win2030-ipc"; #size-cells = <0x02>; dma-ranges = <0x00 0x80000000 0x00 0xc0000000 0x00 0x80000000>; - iommus = <0x19 0x18 0x19 0x18>; + iommus = <0x16 0x18 0x16 0x18>; tbus = <0x04>; - eswin,syscfg = <0x17 0x1004 0x00 0x17 0x4004 0x00>; - mboxes = <0x33 0x00>; + eswin,syscfg = <0x14 0x1004 0x00 0x14 0x4004 0x00>; + mboxes = <0x30 0x00>; mbox-names = "u84_scpu"; numa-node-id = <0x00>; dma-noncoherent; @@ -2792,13 +2880,13 @@ clocks = <0x03 0x209 0x03 0x20a>; clock-names = "core_clk\0bus_clk"; reset-names = "core_rst\0bus_rst\0dbg_rst"; - resets = <0x18 0x15 0x01 0x18 0x15 0x02 0x18 0x15 0x04>; + resets = <0x15 0x15 0x01 0x15 0x15 0x02 0x15 0x15 0x04>; #size-cells = <0x02>; dma-ranges = <0x00 0xb0000000 0x00 0xc0000000 0x00 0x50000000>; - iommus = <0x19 0x19>; - eswin,syscfg = <0x17 0x2004 0x00>; + iommus = <0x16 0x19>; + eswin,syscfg = <0x14 0x2004 0x00>; tbus = <0x04>; - mboxes = <0x34 0x00>; + mboxes = <0x31 0x00>; mbox-names = "u84_lpcpu"; numa-node-id = <0x00>; status = "okay"; @@ -2809,7 +2897,7 @@ compatible = "eswin,eswin-pvt-cpu"; clocks = <0x03 0x25f>; clock-names = "pvt_clk"; - resets = <0x18 0x0b 0x01>; + resets = <0x15 0x0b 0x01>; reset-names = "pvt_rst"; #address-cells = <0x01>; #size-cells = <0x00>; @@ -2820,14 +2908,14 @@ status = "okay"; label = "pvt0"; numa-node-id = <0x00>; - phandle = <0x71>; + phandle = <0x68>; }; pvt@0x52360000 { compatible = "eswin,eswin-pvt-ddr"; clocks = <0x03 0x260>; clock-names = "pvt_clk"; - resets = <0x18 0x0b 0x02>; + resets = <0x15 0x0b 0x02>; reset-names = "pvt_rst"; #address-cells = <0x01>; #size-cells = <0x00>; @@ -2844,16 +2932,16 @@ reg = <0x00 0x50b50000 0x00 0x10000>; clocks = <0x03 0x2a7>; clock-names = "pclk"; - resets = <0x18 0x0a 0x01>; + resets = <0x15 0x0a 0x01>; reset-names = "fan_rst"; interrupt-parent = <0x10>; interrupt-names = "fanirq"; interrupts = <0x162>; pulses-per-revolution = <0x02>; pwm-minimum-period = <0x3e8>; - pwms = <0x35 0x00 0x186a0>; + pwms = <0x32 0x00 0x186a0>; pinctrl-names = "default"; - pinctrl-0 = <0x36 0x37>; + pinctrl-0 = <0x33 0x34>; status = "okay"; label = "fan_control"; numa-node-id = <0x00>; @@ -2865,7 +2953,7 @@ clock-frequency = <0x186a0>; clocks = <0x03 0x28e>; clock-names = "pclk"; - resets = <0x18 0x09 0x01>; + resets = <0x15 0x09 0x01>; reset-names = "rst"; #address-cells = <0x01>; #size-cells = <0x00>; @@ -2881,16 +2969,16 @@ #sound-dai-cells = <0x00>; eswin-plat = <0x02>; pinctrl-names = "default"; - pinctrl-0 = <0x38 0x39>; - front-jack-gpios = <0x2e 0x00 0x00>; - back-jack-gpios = <0x2e 0x1c 0x00>; + pinctrl-0 = <0x35 0x36>; + front-jack-gpios = <0x2b 0x00 0x00>; + back-jack-gpios = <0x2b 0x1c 0x00>; port { endpoint { system-clock-frequency = <0xbb8000>; - remote-endpoint = <0x3a>; - phandle = <0x5a>; + remote-endpoint = <0x37>; + phandle = <0x57>; }; }; }; @@ -2901,7 +2989,7 @@ clock-frequency = <0x186a0>; clocks = <0x03 0x28f>; clock-names = "pclk"; - resets = <0x18 0x09 0x02>; + resets = <0x15 0x09 0x02>; reset-names = "rst"; #address-cells = <0x01>; #size-cells = <0x00>; @@ -2917,7 +3005,7 @@ clock-frequency = <0x186a0>; clocks = <0x03 0x290>; clock-names = "pclk"; - resets = <0x18 0x09 0x04>; + resets = <0x15 0x09 0x04>; reset-names = "rst"; #address-cells = <0x01>; #size-cells = <0x00>; @@ -2933,7 +3021,7 @@ clock-frequency = <0x186a0>; clocks = <0x03 0x291>; clock-names = "pclk"; - resets = <0x18 0x09 0x08>; + resets = <0x15 0x09 0x08>; reset-names = "rst"; #address-cells = <0x01>; #size-cells = <0x00>; @@ -2947,10 +3035,10 @@ compatible = "fcs,fusb303b"; status = "okay"; reg = <0x21>; - eswin,syscfg = <0x17 0x3c0 0x0c>; + eswin,syscfg = <0x14 0x3c0 0x0c>; pinctrl-names = "default"; - pinctrl-0 = <0x3b>; - int-gpios = <0x2e 0x05 0x00>; + pinctrl-0 = <0x38>; + int-gpios = <0x2b 0x05 0x00>; connector { compatible = "usb-c-connector"; @@ -2965,7 +3053,7 @@ clock-frequency = <0x186a0>; clocks = <0x03 0x292>; clock-names = "pclk"; - resets = <0x18 0x09 0x10>; + resets = <0x15 0x09 0x10>; reset-names = "rst"; #address-cells = <0x01>; #size-cells = <0x00>; @@ -2981,7 +3069,7 @@ clock-frequency = <0x186a0>; clocks = <0x03 0x293>; clock-names = "pclk"; - resets = <0x18 0x09 0x20>; + resets = <0x15 0x09 0x20>; reset-names = "rst"; #address-cells = <0x01>; #size-cells = <0x00>; @@ -2997,7 +3085,7 @@ clock-frequency = <0x186a0>; clocks = <0x03 0x294>; clock-names = "pclk"; - resets = <0x18 0x09 0x40>; + resets = <0x15 0x09 0x40>; reset-names = "rst"; #address-cells = <0x01>; #size-cells = <0x00>; @@ -3013,7 +3101,7 @@ clock-frequency = <0x186a0>; clocks = <0x03 0x295>; clock-names = "pclk"; - resets = <0x18 0x09 0x80>; + resets = <0x15 0x09 0x80>; reset-names = "rst"; #address-cells = <0x01>; #size-cells = <0x00>; @@ -3029,7 +3117,7 @@ clock-frequency = <0x186a0>; clocks = <0x03 0x296>; clock-names = "pclk"; - resets = <0x18 0x09 0x100>; + resets = <0x15 0x09 0x100>; reset-names = "rst"; #address-cells = <0x01>; #size-cells = <0x00>; @@ -3045,7 +3133,7 @@ clock-frequency = <0x186a0>; clocks = <0x03 0x297>; clock-names = "pclk"; - resets = <0x18 0x09 0x200>; + resets = <0x15 0x09 0x200>; reset-names = "rst"; #address-cells = <0x01>; #size-cells = <0x00>; @@ -3061,19 +3149,19 @@ clock-frequency = <0x186a0>; clocks = <0x03 0x29f>; clock-names = "pclk"; - resets = <0x18 0x26 0x01>; + resets = <0x15 0x26 0x01>; reset-names = "rst"; #address-cells = <0x01>; #size-cells = <0x00>; reg = <0x00 0x51830000 0x00 0x8000>; interrupts = <0x122>; interrupt-parent = <0x10>; - eswin,i2c_dma = <0x3c>; + eswin,i2c_dma = <0x39>; dma-names = "rx\0tx"; - dmas = <0x3c 0x29 0xff 0x3c 0x2a 0xff>; + dmas = <0x39 0x0a 0x29 0xff 0x39 0x0b 0x2a 0xff>; numa-node-id = <0x00>; status = "okay"; - eswin,syscfg = <0x17 0x3c0 0x10>; + eswin,syscfg = <0x14 0x3c0 0x10>; aon_eeprom@50 { compatible = "atmel,24c02"; @@ -3086,7 +3174,7 @@ clock-frequency = <0x186a0>; clocks = <0x03 0x2a0>; clock-names = "pclk"; - resets = <0x18 0x25 0x01>; + resets = <0x15 0x25 0x01>; reset-names = "rst"; #address-cells = <0x01>; #size-cells = <0x00>; @@ -3095,7 +3183,7 @@ interrupt-parent = <0x10>; numa-node-id = <0x00>; status = "okay"; - eswin,syscfg = <0x17 0x3c0 0x0f>; + eswin,syscfg = <0x14 0x3c0 0x0f>; i2c-sda-hold-time-ns = <0x40>; pmic@10 { @@ -3132,7 +3220,7 @@ regulator-min-microamp = <0x1312d00>; regulator-max-microamp = <0x2625a00>; regulator-ov-protection-microvolt = <0x10c8e0>; - phandle = <0x23>; + phandle = <0x20>; }; }; }; @@ -3144,11 +3232,11 @@ numa-node-id = <0x00>; status = "okay"; pinctrl-names = "default"; - pinctrl-0 = <0x3d 0x3e 0x3f 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x4b 0x4c 0x4d 0x4e 0x4f 0x50 0x51 0x52 0x53 0x54 0x55 0x56 0x57 0x58>; - phandle = <0x1e>; + pinctrl-0 = <0x3a 0x3b 0x3c 0x3d 0x3e 0x3f 0x40 0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0x49 0x4a 0x4b 0x4c 0x4d 0x4e 0x4f 0x50 0x51 0x52 0x53 0x54 0x55>; + phandle = <0x1b>; pwm0-default { - phandle = <0x37>; + phandle = <0x34>; mux { groups = "pwm0_group"; @@ -3157,7 +3245,7 @@ }; fan_tach-default { - phandle = <0x36>; + phandle = <0x33>; mux { groups = "fan_tach_group"; @@ -3538,7 +3626,7 @@ }; sata_act_led-default { - phandle = <0x2c>; + phandle = <0x29>; mux { groups = "sata_act_led_group"; @@ -3553,7 +3641,7 @@ }; emmc_led_control-default { - phandle = <0x2d>; + phandle = <0x2a>; mux { groups = "emmc_led_control_group"; @@ -3648,7 +3736,7 @@ }; gpio0-default { - phandle = <0x38>; + phandle = <0x35>; mux { groups = "gpio0_group"; @@ -3695,7 +3783,7 @@ }; gpio5-default { - phandle = <0x3b>; + phandle = <0x38>; mux { groups = "gpio5_group"; @@ -3710,7 +3798,7 @@ }; gpio6-default { - phandle = <0x3d>; + phandle = <0x3a>; mux { groups = "gpio6_group"; @@ -3725,7 +3813,7 @@ }; gpio7-default { - phandle = <0x3e>; + phandle = <0x3b>; mux { groups = "gpio7_group"; @@ -3740,7 +3828,7 @@ }; gpio8-default { - phandle = <0x3f>; + phandle = <0x3c>; mux { groups = "gpio8_group"; @@ -3755,7 +3843,7 @@ }; gpio9-default { - phandle = <0x40>; + phandle = <0x3d>; mux { groups = "gpio9_group"; @@ -3770,7 +3858,7 @@ }; gpio10-default { - phandle = <0x41>; + phandle = <0x3e>; mux { groups = "gpio10_group"; @@ -3823,7 +3911,7 @@ }; gpio15-default { - phandle = <0x2f>; + phandle = <0x2c>; mux { groups = "gpio15_group"; @@ -3846,7 +3934,7 @@ }; gpio17-default { - phandle = <0x42>; + phandle = <0x3f>; mux { groups = "gpio17_group"; @@ -3930,6 +4018,12 @@ groups = "gpio23_group"; function = "gpio23_func"; }; + + conf { + groups = "gpio23_group"; + input-enable = <0x01>; + bias-pull-down = <0x01>; + }; }; gpio24-default { @@ -3965,7 +4059,7 @@ }; gpio28-default { - phandle = <0x39>; + phandle = <0x36>; mux { groups = "gpio28_group"; @@ -4028,7 +4122,7 @@ }; gpio35-default { - phandle = <0x43>; + phandle = <0x40>; mux { groups = "gpio35_group"; @@ -4043,7 +4137,7 @@ }; gpio36-default { - phandle = <0x44>; + phandle = <0x41>; mux { groups = "gpio36_group"; @@ -4058,7 +4152,7 @@ }; gpio37-default { - phandle = <0x45>; + phandle = <0x42>; mux { groups = "gpio37_group"; @@ -4073,7 +4167,7 @@ }; gpio38-default { - phandle = <0x46>; + phandle = <0x43>; mux { groups = "gpio38_group"; @@ -4088,7 +4182,7 @@ }; gpio39-default { - phandle = <0x47>; + phandle = <0x44>; mux { groups = "gpio39_group"; @@ -4103,7 +4197,7 @@ }; gpio40-default { - phandle = <0x48>; + phandle = <0x45>; mux { groups = "gpio40_group"; @@ -4118,7 +4212,7 @@ }; gpio41-default { - phandle = <0x49>; + phandle = <0x46>; mux { groups = "gpio41_group"; @@ -4141,7 +4235,7 @@ }; gpio43-default { - phandle = <0x69>; + phandle = <0x60>; mux { groups = "gpio43_group"; @@ -4166,7 +4260,7 @@ }; gpio46-default { - phandle = <0x4a>; + phandle = <0x47>; mux { groups = "gpio46_group"; @@ -4227,7 +4321,7 @@ }; gpio52-default { - phandle = <0x4b>; + phandle = <0x48>; mux { groups = "gpio52_group"; @@ -4242,7 +4336,7 @@ }; gpio53-default { - phandle = <0x4c>; + phandle = <0x49>; mux { groups = "gpio53_group"; @@ -4337,7 +4431,7 @@ }; gpio64-default { - phandle = <0x4d>; + phandle = <0x4a>; mux { groups = "gpio64_group"; @@ -4352,7 +4446,7 @@ }; gpio65-default { - phandle = <0x4e>; + phandle = <0x4b>; mux { groups = "gpio65_group"; @@ -4367,7 +4461,7 @@ }; gpio66-default { - phandle = <0x4f>; + phandle = <0x4c>; mux { groups = "gpio66_group"; @@ -4382,7 +4476,7 @@ }; gpio67-default { - phandle = <0x50>; + phandle = <0x4d>; mux { groups = "gpio67_group"; @@ -4413,7 +4507,7 @@ }; gpio70-default { - phandle = <0x51>; + phandle = <0x4e>; mux { groups = "gpio70_group"; @@ -4438,7 +4532,7 @@ }; gpio73-default { - phandle = <0x52>; + phandle = <0x4f>; mux { groups = "gpio73_group"; @@ -4487,7 +4581,7 @@ }; gpio79-default { - phandle = <0x30>; + phandle = <0x2d>; mux { groups = "gpio79_group"; @@ -4512,7 +4606,6 @@ }; gpio82-default { - phandle = <0x64>; mux { groups = "gpio82_group"; @@ -4521,7 +4614,7 @@ }; gpio83-default { - phandle = <0x53>; + phandle = <0x50>; mux { groups = "gpio83_group"; @@ -4538,7 +4631,6 @@ }; gpio85-default { - phandle = <0x65>; mux { groups = "gpio85_group"; @@ -4547,7 +4639,7 @@ }; gpio86-default { - phandle = <0x54>; + phandle = <0x51>; mux { groups = "gpio86_group"; @@ -4556,7 +4648,7 @@ }; gpio87-default { - phandle = <0x55>; + phandle = <0x52>; mux { groups = "gpio87_group"; @@ -4597,7 +4689,7 @@ }; gpio92-default { - phandle = <0x56>; + phandle = <0x53>; mux { groups = "gpio92_group"; @@ -4612,7 +4704,7 @@ }; gpio93-default { - phandle = <0x57>; + phandle = <0x54>; mux { groups = "gpio93_group"; @@ -4627,7 +4719,7 @@ }; gpio94-default { - phandle = <0x58>; + phandle = <0x55>; mux { groups = "gpio94_group"; @@ -4730,7 +4822,7 @@ }; gpio106-default { - phandle = <0x1c>; + phandle = <0x19>; mux { groups = "gpio106_group"; @@ -4801,7 +4893,7 @@ }; gpio111-default { - phandle = <0x20>; + phandle = <0x1d>; mux { groups = "gpio111_group"; @@ -4922,7 +5014,7 @@ interrupt-controller; #interrupt-cells = <0x02>; interrupts = <0x12f 0x130 0x131 0x132 0x133 0x134 0x135 0x136 0x137 0x138 0x139 0x13a 0x13b 0x13c 0x13d 0x13e 0x13f 0x140 0x141 0x142 0x143 0x144 0x145 0x146 0x147 0x148 0x149 0x14a 0x14b 0x14c 0x14d 0x14e>; - phandle = <0x2e>; + phandle = <0x2b>; }; gpio-port@1 { @@ -4931,7 +5023,7 @@ #gpio-cells = <0x02>; ngpios = <0x20>; reg = <0x01>; - phandle = <0x6a>; + phandle = <0x61>; }; gpio-port@2 { @@ -4940,7 +5032,7 @@ #gpio-cells = <0x02>; ngpios = <0x20>; reg = <0x02>; - phandle = <0x16>; + phandle = <0x13>; }; gpio-port@3 { @@ -4949,7 +5041,7 @@ #gpio-cells = <0x02>; ngpios = <0x10>; reg = <0x03>; - phandle = <0x1d>; + phandle = <0x1a>; }; }; @@ -4960,11 +5052,11 @@ clock-names = "pclk"; clocks = <0x03 0x2a6>; clock-frequency = <0xbebc200>; - resets = <0x18 0x0f 0x01>; + resets = <0x15 0x0f 0x01>; reset-names = "rst"; status = "okay"; numa-node-id = <0x00>; - phandle = <0x35>; + phandle = <0x32>; }; watchdog@0x50800000 { @@ -4972,7 +5064,7 @@ reg = <0x00 0x50800000 0x00 0x4000>; clocks = <0x03 0x298>; clock-names = "pclk"; - resets = <0x18 0x11 0x01>; + resets = <0x15 0x11 0x01>; reset-names = "rst"; interrupts = <0x57>; interrupt-parent = <0x10>; @@ -4985,7 +5077,7 @@ reg = <0x00 0x50804000 0x00 0x4000>; clocks = <0x03 0x299>; clock-names = "pclk"; - resets = <0x18 0x11 0x02>; + resets = <0x15 0x11 0x02>; reset-names = "rst"; interrupts = <0x58>; interrupt-parent = <0x10>; @@ -4998,7 +5090,7 @@ reg = <0x00 0x50808000 0x00 0x4000>; clocks = <0x03 0x29a>; clock-names = "pclk"; - resets = <0x18 0x11 0x04>; + resets = <0x15 0x11 0x04>; reset-names = "rst"; interrupts = <0x59>; interrupt-parent = <0x10>; @@ -5011,7 +5103,7 @@ reg = <0x00 0x5080c000 0x00 0x4000>; clocks = <0x03 0x29b>; clock-names = "pclk"; - resets = <0x18 0x11 0x08>; + resets = <0x15 0x11 0x08>; reset-names = "rst"; interrupts = <0x5a>; interrupt-parent = <0x10>; @@ -5030,7 +5122,7 @@ interrupts = <0x159>; clock-names = "pclk\0timer_aclk"; clocks = <0x03 0x26c 0x03 0x268>; - resets = <0x18 0x30 0x01 0x18 0x30 0x02 0x18 0x30 0x04 0x18 0x30 0x08 0x18 0x30 0x10 0x18 0x30 0x20 0x18 0x30 0x40 0x18 0x30 0x80 0x18 0x30 0x100>; + resets = <0x15 0x30 0x01 0x15 0x30 0x02 0x15 0x30 0x04 0x15 0x30 0x08 0x15 0x30 0x10 0x15 0x30 0x20 0x15 0x30 0x40 0x15 0x30 0x80 0x15 0x30 0x100>; reset-names = "trst0\0trst1\0trst2\0trst3\0trst4\0trst5\0trst6\0trst7\0prst"; status = "okay"; }; @@ -5045,7 +5137,7 @@ interrupts = <0x15a>; clock-names = "pclk\0timer_aclk"; clocks = <0x03 0x26d 0x03 0x269>; - resets = <0x18 0x31 0x01 0x18 0x31 0x02 0x18 0x31 0x04 0x18 0x31 0x08 0x18 0x31 0x10 0x18 0x31 0x20 0x18 0x31 0x40 0x18 0x31 0x80 0x18 0x31 0x100>; + resets = <0x15 0x31 0x01 0x15 0x31 0x02 0x15 0x31 0x04 0x15 0x31 0x08 0x15 0x31 0x10 0x15 0x31 0x20 0x15 0x31 0x40 0x15 0x31 0x80 0x15 0x31 0x100>; reset-names = "trst0\0trst1\0trst2\0trst3\0trst4\0trst5\0trst6\0trst7\0prst"; status = "okay"; }; @@ -5060,7 +5152,7 @@ interrupts = <0x15b>; clock-names = "pclk\0timer_aclk"; clocks = <0x03 0x26e 0x03 0x26a>; - resets = <0x18 0x32 0x01 0x18 0x32 0x02 0x18 0x32 0x04 0x18 0x32 0x08 0x18 0x32 0x10 0x18 0x32 0x20 0x18 0x32 0x40 0x18 0x32 0x80 0x18 0x32 0x100>; + resets = <0x15 0x32 0x01 0x15 0x32 0x02 0x15 0x32 0x04 0x15 0x32 0x08 0x15 0x32 0x10 0x15 0x32 0x20 0x15 0x32 0x40 0x15 0x32 0x80 0x15 0x32 0x100>; reset-names = "trst0\0trst1\0trst2\0trst3\0trst4\0trst5\0trst6\0trst7\0prst"; status = "okay"; }; @@ -5075,7 +5167,7 @@ interrupts = <0x15c>; clock-names = "pclk\0timer_aclk\0timer3_clk8"; clocks = <0x03 0x26f 0x03 0x26b 0x03 0x270>; - resets = <0x18 0x33 0x01 0x18 0x33 0x02 0x18 0x33 0x04 0x18 0x33 0x08 0x18 0x33 0x10 0x18 0x33 0x20 0x18 0x33 0x40 0x18 0x33 0x80 0x18 0x33 0x100>; + resets = <0x15 0x33 0x01 0x15 0x33 0x02 0x15 0x33 0x04 0x15 0x33 0x08 0x15 0x33 0x10 0x15 0x33 0x20 0x15 0x33 0x40 0x15 0x33 0x80 0x15 0x33 0x100>; reset-names = "trst0\0trst1\0trst2\0trst3\0trst4\0trst5\0trst6\0trst7\0prst"; status = "okay"; }; @@ -5083,13 +5175,13 @@ rtc@51818000 { compatible = "eswin,win2030-rtc"; reg = <0x00 0x51818000 0x00 0x400>; - eswin,syscfg = <0x17 0x3c0>; + eswin,syscfg = <0x14 0x3c0>; interrupt-parent = <0x10>; interrupts = <0x124>; clocks = <0x03 0x272>; clock-names = "rtcclk"; clock-frequency = <0x3d09>; - resets = <0x18 0x34 0x01>; + resets = <0x15 0x34 0x01>; reset-names = "rtcrst"; status = "okay"; numa-node-id = <0x00>; @@ -5104,21 +5196,21 @@ #sound-dai-cells = <0x00>; reg = <0x00 0x50200000 0x00 0x10000>; dma-names = "rx\0tx"; - dmas = <0x3c 0x04 0x00 0x3c 0x05 0x00>; - vo_mclk_sel,syscrg = <0x15 0x1bc>; - resets = <0x18 0x22 0x01 0x18 0x22 0x02 0x18 0x21 0x02>; + dmas = <0x39 0x04 0x04 0x00 0x39 0x05 0x05 0x00>; + vo_mclk_sel,syscrg = <0x12 0x1bc>; + resets = <0x15 0x22 0x01 0x15 0x22 0x02 0x15 0x21 0x02>; reset-names = "i2srst\0i2sprst\0voprst"; dma-noncoherent; numa-node-id = <0x00>; status = "okay"; port { - phandle = <0x5c>; + phandle = <0x59>; endpoint { - remote-endpoint = <0x59>; + remote-endpoint = <0x56>; dai-format = "i2s"; - phandle = <0x68>; + phandle = <0x5f>; }; }; }; @@ -5132,21 +5224,21 @@ #sound-dai-cells = <0x00>; reg = <0x00 0x50210000 0x00 0x10000>; dma-names = "rx\0tx"; - dmas = <0x3c 0x02 0x01 0x3c 0x03 0x01>; - vo_mclk_sel,syscrg = <0x15 0x1bc>; - resets = <0x18 0x22 0x01 0x18 0x22 0x02 0x18 0x21 0x02>; + dmas = <0x39 0x06 0x02 0x01 0x39 0x07 0x03 0x01>; + vo_mclk_sel,syscrg = <0x12 0x1bc>; + resets = <0x15 0x22 0x01 0x15 0x22 0x02 0x15 0x21 0x02>; reset-names = "i2srst\0i2sprst\0voprst"; dma-noncoherent; numa-node-id = <0x00>; status = "okay"; port { - phandle = <0x5b>; + phandle = <0x58>; endpoint { - remote-endpoint = <0x5a>; + remote-endpoint = <0x57>; dai-format = "i2s"; - phandle = <0x3a>; + phandle = <0x37>; }; }; }; @@ -5160,9 +5252,9 @@ #sound-dai-cells = <0x00>; reg = <0x00 0x50220000 0x00 0x10000>; dma-names = "rx\0tx"; - dmas = <0x3c 0x00 0x02 0x3c 0x01 0x02>; - vo_mclk_sel,syscrg = <0x15 0x1bc>; - resets = <0x18 0x22 0x01 0x18 0x22 0x02 0x18 0x21 0x02>; + dmas = <0x39 0x08 0x00 0x02 0x39 0x09 0x01 0x02>; + vo_mclk_sel,syscrg = <0x12 0x1bc>; + resets = <0x15 0x22 0x01 0x15 0x22 0x02 0x15 0x21 0x02>; reset-names = "i2srst\0i2sprst\0voprst"; dma-noncoherent; numa-node-id = <0x00>; @@ -5180,7 +5272,7 @@ numa-node-id = <0x00>; status = "okay"; label = "Analog Audio"; - dais = <0x5b>; + dais = <0x58>; }; graphcard1 { @@ -5188,7 +5280,7 @@ numa-node-id = <0x00>; status = "okay"; label = "HDMI Audio"; - dais = <0x5c>; + dais = <0x59>; }; graphcard2 { @@ -5199,8 +5291,8 @@ display-subsystem@0 { compatible = "eswin,display-subsystem"; - ports = <0x5d>; numa-node-id = <0x00>; + ports = <0x5a>; dma-noncoherent; status = "okay"; }; @@ -5218,7 +5310,7 @@ interrupts = <0xee>; clocks = <0x03 0x24d 0x03 0x24f 0x03 0x24c 0x03 0x04 0x03 0x2a 0x03 0x2b 0x03 0x0b 0x03 0x0d>; clock-names = "cfg_clk\0pix_clk\0axi_clk\0spll0_fout1\0vo_mux\0pix_mux\0spll2_fout2\0vpll_fout1"; - resets = <0x18 0x23 0x01 0x18 0x23 0x02 0x18 0x23 0x04 0x18 0x23 0x08>; + resets = <0x15 0x23 0x01 0x15 0x23 0x02 0x15 0x23 0x04 0x15 0x23 0x08>; reset-names = "vo_arst\0vo_prst\0dc_arst\0dc_prst"; dma-noncoherent; numa-node-id = <0x00>; @@ -5227,24 +5319,18 @@ port { #address-cells = <0x01>; #size-cells = <0x00>; - phandle = <0x5d>; - - endpoint@0 { - reg = <0x00>; - remote-endpoint = <0x5e>; - phandle = <0x62>; - }; + phandle = <0x5a>; endpoint@1 { reg = <0x01>; - remote-endpoint = <0x5f>; - phandle = <0x61>; + remote-endpoint = <0x5b>; + phandle = <0x5d>; }; endpoint@2 { reg = <0x02>; - remote-endpoint = <0x60>; - phandle = <0x67>; + remote-endpoint = <0x5c>; + phandle = <0x5e>; }; }; }; @@ -5258,8 +5344,8 @@ port { endpoint { - remote-endpoint = <0x61>; - phandle = <0x5f>; + remote-endpoint = <0x5d>; + phandle = <0x5b>; }; }; }; @@ -5277,57 +5363,10 @@ reg = <0x00 0x50270000 0x00 0x10000>; clocks = <0x03 0x201>; clock-names = "pclk"; - resets = <0x18 0x21 0x01>; + resets = <0x15 0x21 0x01>; reset-names = "phyrstn"; numa-node-id = <0x00>; status = "okay"; - - ports { - #address-cells = <0x01>; - #size-cells = <0x00>; - - port@0 { - #address-cells = <0x01>; - #size-cells = <0x00>; - reg = <0x00>; - - endpoint { - remote-endpoint = <0x62>; - phandle = <0x5e>; - }; - }; - - port@1 { - #address-cells = <0x01>; - #size-cells = <0x00>; - reg = <0x01>; - - endpoint { - remote-endpoint = <0x63>; - phandle = <0x66>; - }; - }; - }; - - dsi_panel@0 { - compatible = "eswin,generic-panel"; - reg = <0x00>; - dsi,format = <0x00>; - dsi,lanes = <0x04>; - status = "okay"; - pinctrl-names = "default"; - pinctrl-0 = <0x64 0x65>; - backlight0-gpios = <0x16 0x12 0x00>; - rst-gpios = <0x16 0x15 0x00>; - - port { - - endpoint { - remote-endpoint = <0x66>; - phandle = <0x63>; - }; - }; - }; }; dctest@502c0000 { @@ -5351,7 +5390,7 @@ ddc-i2c-scl-high-time-ns = <0x1264>; ddc-i2c-scl-low-time-ns = <0x1334>; #sound-dai-cells = <0x00>; - resets = <0x18 0x21 0x08 0x18 0x21 0x10 0x18 0x21 0x20>; + resets = <0x15 0x21 0x08 0x15 0x21 0x10 0x15 0x21 0x20>; reset-names = "prstn\0phyrstn\0rstn"; numa-node-id = <0x00>; status = "okay"; @@ -5364,8 +5403,8 @@ reg = <0x00>; endpoint@0 { - remote-endpoint = <0x67>; - phandle = <0x60>; + remote-endpoint = <0x5e>; + phandle = <0x5c>; }; }; @@ -5374,8 +5413,8 @@ endpoint@1 { system-clock-frequency = <0xbb8000>; - remote-endpoint = <0x68>; - phandle = <0x59>; + remote-endpoint = <0x5f>; + phandle = <0x56>; }; }; }; @@ -5399,8 +5438,8 @@ #size-cells = <0x02>; clocks = <0x03 0x10e 0x03 0x221 0x03 0x222>; clock-names = "suspend\0aclk\0cfg_clk"; - eswin,hsp_sp_csr = <0x1a 0x800 0x808 0x83c 0x840>; - resets = <0x18 0x07 0x8000>; + eswin,hsp_sp_csr = <0x17 0x800 0x808 0x83c 0x840>; + resets = <0x15 0x07 0x8000>; reset-names = "vaux"; ranges; numa-node-id = <0x00>; @@ -5417,8 +5456,8 @@ dr_mode = "host"; phy_type = "utmi"; maximum-speed = "super-speed"; - iommus = <0x19 0x0a>; - eswin,hsp_sp_csr = <0x1a 0x1044>; + iommus = <0x16 0x0a>; + eswin,hsp_sp_csr = <0x17 0x1044>; dma-ranges = <0x00 0x00 0x00 0xc0000000 0x200 0x00>; snps,dis_enblslpm_quirk; snps,dis-u2-freeclk-exists-quirk; @@ -5438,8 +5477,8 @@ #size-cells = <0x02>; clocks = <0x03 0x10f 0x03 0x221 0x03 0x222>; clock-names = "suspend\0aclk\0cfg_clk"; - eswin,hsp_sp_csr = <0x1a 0x900 0x908 0x93c 0x940>; - resets = <0x18 0x07 0x10000>; + eswin,hsp_sp_csr = <0x17 0x900 0x908 0x93c 0x940>; + resets = <0x15 0x07 0x10000>; reset-names = "vaux"; ranges; numa-node-id = <0x00>; @@ -5456,8 +5495,8 @@ dr_mode = "host"; phy_type = "utmi"; maximum-speed = "super-speed"; - iommus = <0x19 0x0b>; - eswin,hsp_sp_csr = <0x1a 0x1048>; + iommus = <0x16 0x0b>; + eswin,hsp_sp_csr = <0x17 0x1048>; dma-ranges = <0x00 0x00 0x00 0xc0000000 0x200 0x00>; snps,dis_enblslpm_quirk; snps,dis-u2-freeclk-exists-quirk; @@ -5472,8 +5511,8 @@ usb-hub { gpio-hog; pinctrl-names = "default"; - pinctrl-0 = <0x69>; - gpios = <0x6a 0x0b 0x00>; + pinctrl-0 = <0x60>; + gpios = <0x61 0x0b 0x00>; output-low; line-name = "usb-hub-reset"; }; @@ -5484,7 +5523,7 @@ compatible = "esw,vi-common-csr\0syscon"; clocks = <0x03 0x23f 0x03 0x241 0x03 0x243 0x03 0x240 0x03 0x24b 0x03 0x24a 0x03 0x244 0x03 0x245 0x03 0x246 0x03 0x247 0x03 0x248 0x03 0x249 0x03 0x27 0x03 0x28 0x03 0x29 0x03 0x04 0x03 0x0d>; clock-names = "aclk\0cfg_clk\0isp_aclk\0dvp_clk\0phy_cfg\0phy_escclk\0sht0\0sht1\0sht2\0sht3\0sht4\0sht5\0aclk_mux\0dvp_mux\0isp_mux\0spll0_fout1\0vpll_fout1"; - resets = <0x18 0x1c 0x01 0x18 0x1c 0x02 0x18 0x1e 0x01 0x18 0x1f 0x01 0x18 0x1d 0x01 0x18 0x20 0x01 0x18 0x20 0x02 0x18 0x20 0x04 0x18 0x20 0x08 0x18 0x20 0x10 0x18 0x20 0x20>; + resets = <0x15 0x1c 0x01 0x15 0x1c 0x02 0x15 0x1e 0x01 0x15 0x1f 0x01 0x15 0x1d 0x01 0x15 0x20 0x01 0x15 0x20 0x02 0x15 0x20 0x04 0x15 0x20 0x08 0x15 0x20 0x10 0x15 0x20 0x20>; reset-names = "axi\0cfg\0isp0\0isp1\0dvp\0sht0\0sht1\0sht2\0sht3\0sht4\0sht5"; interrupt-parent = <0x10>; interrupts = <0x170 0x171 0x172 0x173 0x174 0x175 0x176 0x177>; @@ -5492,7 +5531,8 @@ #size-cells = <0x02>; reg = <0x00 0x51030000 0x00 0x10000>; numa-node-id = <0x00>; - phandle = <0x6b>; + tbus = <0x00>; + phandle = <0x62>; }; isp@0x51000000 { @@ -5503,9 +5543,9 @@ id = <0x00>; #size-cells = <0x02>; dma-ranges = <0x00 0x20000000 0x00 0x80000000 0x00 0x40000000>; - iommus = <0x19 0x06>; + iommus = <0x16 0x06>; tbus = <0x00>; - eswin,vi_top_csr = <0x6b 0x1000>; + eswin,vi_top_csr = <0x62 0x1000>; numa-node-id = <0x00>; dma-noncoherent; status = "disabled"; @@ -5519,9 +5559,9 @@ id = <0x01>; #size-cells = <0x02>; dma-ranges = <0x00 0x20000000 0x00 0x80000000 0x00 0x40000000>; - iommus = <0x19 0x06>; + iommus = <0x16 0x06>; tbus = <0x00>; - eswin,vi_top_csr = <0x6b 0x1004>; + eswin,vi_top_csr = <0x62 0x1004>; numa-node-id = <0x00>; dma-noncoherent; status = "disabled"; @@ -5531,16 +5571,16 @@ compatible = "eswin,dewarp"; clocks = <0x03 0x23f 0x03 0x241 0x03 0x242 0x03 0x27 0x03 0x54 0x03 0x04 0x03 0x0d>; clock-names = "aclk\0cfg_clk\0dw_aclk\0aclk_mux\0dw_mux\0spll0_fout1\0vpll_fout1"; - resets = <0x18 0x1c 0x01 0x18 0x1c 0x02 0x18 0x1c 0x04>; + resets = <0x15 0x1c 0x01 0x15 0x1c 0x02 0x15 0x1c 0x04>; reset-names = "axi\0cfg\0dwe"; - operating-points-v2 = <0x6c>; + operating-points-v2 = <0x63>; interrupt-parent = <0x10>; interrupts = <0x1a 0x19>; #size-cells = <0x02>; dma-ranges = <0x00 0x20000000 0x00 0x80000000 0x00 0x40000000>; - iommus = <0x19 0x08>; + iommus = <0x16 0x08>; tbus = <0x00>; - eswin,vi_top_csr = <0x6b 0x1008>; + eswin,vi_top_csr = <0x62 0x1008>; reg = <0x00 0x51020000 0x00 0xc00 0x00 0x51020c00 0x00 0x120>; numa-node-id = <0x00>; dma-noncoherent; @@ -5573,8 +5613,8 @@ endpoint@0 { reg = <0x00>; bus-type = <0x04>; - remote-endpoint = <0x6d>; - phandle = <0x6f>; + remote-endpoint = <0x64>; + phandle = <0x66>; }; }; }; @@ -5594,8 +5634,8 @@ endpoint@0 { reg = <0x00>; bus-type = <0x04>; - remote-endpoint = <0x6e>; - phandle = <0x70>; + remote-endpoint = <0x65>; + phandle = <0x67>; }; }; }; @@ -5624,8 +5664,8 @@ bus-type = <0x04>; clock-lanes = <0x00>; data-lanes = <0x01 0x02>; - remote-endpoint = <0x6f>; - phandle = <0x6d>; + remote-endpoint = <0x66>; + phandle = <0x64>; }; }; }; @@ -5652,8 +5692,8 @@ endpoint { bus-type = <0x04>; - remote-endpoint = <0x70>; - phandle = <0x6e>; + remote-endpoint = <0x67>; + phandle = <0x65>; }; }; }; @@ -5664,7 +5704,7 @@ #size-cells = <0x02>; ranges; dma-ranges = <0x00 0x80000000 0x00 0xc0000000 0x00 0x80000000>; - iommus = <0x19 0x18>; + iommus = <0x16 0x18>; tbus = <0xf00>; numa-node-id = <0x00>; status = "disabled"; @@ -5710,12 +5750,12 @@ polling-delay-passive = <0x1f4>; polling-delay = <0x1388>; sustainable-power = <0x4b0>; - thermal-sensors = <0x71>; + thermal-sensors = <0x68>; trips { trip-point2 { - temperature = <0x1adb0>; + temperature = <0x19a28>; hysteresis = <0x00>; type = "critical"; }; @@ -5733,6 +5773,7 @@ }; chosen { + bootargs = "root=PARTUUID=b0f77ad6-36cd-4a99-a8c0-31d73649aa09 console=ttyS0,115200 root=PARTUUID=b0f77ad6-36cd-4a99-a8c0-31d73649aa09 rootfstype=ext4 rootwait rw earlycon selinux=0 LANG=en_US.UTF-8 init=/bin/bash"; stdout-path = "serial0:115200n8"; domain-config { @@ -5770,7 +5811,7 @@ sprammemory@59000000 { no-map; reg = <0x00 0x59000000 0x00 0x400000>; - phandle = <0x24>; + phandle = <0x21>; }; g2d_4GB_boundary_reserved_4k { diff --git a/platform/riscv64/hifive-premier-p550/image/dts/minimal.dts b/platform/riscv64/hifive-premier-p550/image/dts/minimal.dts index 8d31e015..71bf9dba 100644 --- a/platform/riscv64/hifive-premier-p550/image/dts/minimal.dts +++ b/platform/riscv64/hifive-premier-p550/image/dts/minimal.dts @@ -447,105 +447,6 @@ dsp@0 { }; }; - - es_dsp@1 { - #address-cells = <0x01>; - #size-cells = <0x01>; - compatible = "eswin-dsp\0cdns,xrp-hw-eswin"; - ranges = <0x28000000 0x00 0x5b008000 0x8000 0x28100000 0x00 0x5b140000 0x20000 0x28120000 0x00 0x5b160000 0x20000>; - clocks = <0x03 0x2a9>; - clock-names = "aclk"; - operating-points-v2 = <0x22>; - dsp_mbox = <0x24>; - device-irq = <0x0d 0x50ab0000 0x40 0x50aa0000 0x01 0x50a40000>; - device-uart = <0x50900000>; - device-irq-mode = <0x01>; - host-irq-mode = <0x01>; - firmware-name = "eic7700_dsp_fw"; - process-id = <0x01>; - iommus = <0x16 0x13>; - tbus = <0x71>; - dma-noncoherent; - numa-node-id = <0x00>; - aux-e31-dtim = <0x5a110000>; - status = "okay"; - - dsp@0 { - }; - }; - - es_dsp@2 { - #address-cells = <0x01>; - #size-cells = <0x01>; - compatible = "eswin-dsp\0cdns,xrp-hw-eswin"; - ranges = <0x28000000 0x00 0x5b010000 0x8000 0x28100000 0x00 0x5b180000 0x20000 0x28120000 0x00 0x5b1a0000 0x20000>; - clocks = <0x03 0x2aa>; - clock-names = "aclk"; - operating-points-v2 = <0x22>; - dsp_mbox = <0x25>; - device-irq = <0x0f 0x50ad0000 0x80 0x50ac0000 0x01 0x50a40000>; - device-uart = <0x50900000>; - device-irq-mode = <0x01>; - host-irq-mode = <0x01>; - firmware-name = "eic7700_dsp_fw"; - process-id = <0x02>; - iommus = <0x16 0x14>; - tbus = <0x72>; - dma-noncoherent; - numa-node-id = <0x00>; - aux-e31-dtim = <0x5a110000>; - status = "okay"; - - dsp@0 { - }; - }; - - es_dsp@3 { - #address-cells = <0x01>; - #size-cells = <0x01>; - compatible = "eswin-dsp\0cdns,xrp-hw-eswin"; - ranges = <0x28000000 0x00 0x5b018000 0x8000 0x28100000 0x00 0x5b1c0000 0x20000 0x28120000 0x00 0x5b1e0000 0x20000>; - clocks = <0x03 0x2ab>; - clock-names = "aclk"; - operating-points-v2 = <0x22>; - dsp_mbox = <0x26>; - device-irq = <0x11 0x50af0000 0x100 0x50ae0000 0x01 0x50a40000>; - device-uart = <0x50900000>; - device-irq-mode = <0x01>; - host-irq-mode = <0x01>; - firmware-name = "eic7700_dsp_fw"; - process-id = <0x03>; - iommus = <0x16 0x15>; - tbus = <0x73>; - dma-noncoherent; - numa-node-id = <0x00>; - aux-e31-dtim = <0x5a110000>; - status = "okay"; - - dsp@0 { - }; - }; - - sofdsp@4 { - #sound-dai-cells = <0x01>; - #address-cells = <0x02>; - #size-cells = <0x02>; - compatible = "eswin,sof-dsp"; - reg = <0x00 0x5b018000 0x00 0x8000 0x00 0x5b1c0000 0x00 0x40000>; - mbox-names = "dsp-mbox"; - mboxes = <0x26 0x00>; - clocks = <0x03 0x2ab>; - clock-names = "aclk"; - process-id = <0x03>; - iommus = <0x16 0x15>; - tbus = <0x73>; - dma-noncoherent; - mailbox-dsp-to-u84-addr = <0x50af0000>; - mailbox-u84-to-dsp-addr = <0x50ae0000>; - dsp-uart = <0x27>; - device-uart-mutex = <0x51820000>; - numa-node-id = <0x00>; - }; }; mmc@0x50460000 { @@ -581,42 +482,6 @@ no-mmc; }; - mbox@50a00000 { - compatible = "eswin,win2030-mailbox"; - reg = <0x00 0x50a00000 0x00 0x10000 0x00 0x50a10000 0x00 0x10000>; - interrupt-parent = <0x10>; - interrupts = <0x75>; - #mbox-cells = <0x01>; - clocks = <0x03 0x27e 0x03 0x27f>; - clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x15 0x0c 0x01 0x15 0x0c 0x02>; - reset-names = "rst\0rst_device"; - lock-bit = <0x01>; - irq-bit = <0x02>; - numa-node-id = <0x00>; - dma-noncoherent; - status = "okay"; - phandle = <0x30>; - }; - - mbox@50a20000 { - compatible = "eswin,win2030-mailbox"; - reg = <0x00 0x50a20000 0x00 0x10000 0x00 0x50a30000 0x00 0x10000>; - interrupt-parent = <0x10>; - interrupts = <0x77>; - #mbox-cells = <0x01>; - clocks = <0x03 0x280 0x03 0x281>; - clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x15 0x0c 0x04 0x15 0x0c 0x08>; - reset-names = "rst\0rst_device"; - lock-bit = <0x01>; - irq-bit = <0x04>; - numa-node-id = <0x00>; - dma-noncoherent; - status = "okay"; - phandle = <0x31>; - }; - mbox@50a40000 { compatible = "eswin,npu0-mailbox"; reg = <0x00 0x50a40000 0x00 0x10000 0x00 0x50a50000 0x00 0x10000>; @@ -670,60 +535,6 @@ phandle = <0x23>; }; - mbox@50aa0000 { - compatible = "eswin,dsp1-mailbox"; - reg = <0x00 0x50aa0000 0x00 0x10000 0x00 0x50ab0000 0x00 0x10000>; - interrupt-parent = <0x10>; - interrupts = <0x7f>; - #mbox-cells = <0x01>; - clocks = <0x03 0x288 0x03 0x289>; - clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x15 0x0c 0x400 0x15 0x0c 0x800>; - reset-names = "rst\0rst_device"; - lock-bit = <0x01>; - irq-bit = <0x40>; - numa-node-id = <0x00>; - dma-noncoherent; - status = "okay"; - phandle = <0x24>; - }; - - mbox@50ac0000 { - compatible = "eswin,dsp2-mailbox"; - reg = <0x00 0x50ac0000 0x00 0x10000 0x00 0x50ad0000 0x00 0x10000>; - interrupt-parent = <0x10>; - interrupts = <0x81>; - #mbox-cells = <0x01>; - clocks = <0x03 0x28a 0x03 0x28b>; - clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x15 0x0c 0x1000 0x15 0x0c 0x2000>; - reset-names = "rst\0rst_device"; - lock-bit = <0x01>; - irq-bit = <0x80>; - numa-node-id = <0x00>; - dma-noncoherent; - status = "okay"; - phandle = <0x25>; - }; - - mbox@50ae0000 { - compatible = "eswin,dsp3-mailbox"; - reg = <0x00 0x50ae0000 0x00 0x10000 0x00 0x50af0000 0x00 0x10000>; - interrupt-parent = <0x10>; - interrupts = <0x83>; - #mbox-cells = <0x01>; - clocks = <0x03 0x28c 0x03 0x28d>; - clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x15 0x0c 0x4000 0x15 0x0c 0x8000>; - reset-names = "rst\0rst_device"; - lock-bit = <0x01>; - irq-bit = <0x100>; - numa-node-id = <0x00>; - dma-noncoherent; - status = "okay"; - phandle = <0x26>; - }; - i2c@51838000 { compatible = "snps,designware-i2c"; clock-frequency = <0x186a0>; @@ -769,13 +580,8 @@ }; chosen { - bootargs = "root=PARTUUID=b0f77ad6-36cd-4a99-a8c0-31d73649aa09 console=ttyS0,115200 root=PARTUUID=b0f77ad6-36cd-4a99-a8c0-31d73649aa09 rootfstype=ext4 rootwait rw earlycon selinux=0 LANG=en_US.UTF-8"; + bootargs = "root=PARTUUID=b0f77ad6-36cd-4a99-a8c0-31d73649aa09 console=ttyS0,115200 root=PARTUUID=b0f77ad6-36cd-4a99-a8c0-31d73649aa09 rootfstype=ext4 rootwait rw earlycon selinux=0 LANG=en_US.UTF-8 init=/bin/bash"; stdout-path = "serial0:115200n8"; - - domain-config { - compatible = "opensbi,domain,config"; - system-suspend-test; - }; }; memory@80000000 { diff --git a/platform/riscv64/hifive-premier-p550/image/dts/zone0-npu.dts b/platform/riscv64/hifive-premier-p550/image/dts/zone0-npu.dts index 8c5b65fa..22822015 100644 --- a/platform/riscv64/hifive-premier-p550/image/dts/zone0-npu.dts +++ b/platform/riscv64/hifive-premier-p550/image/dts/zone0-npu.dts @@ -300,105 +300,6 @@ dsp@0 { }; }; - - es_dsp@1 { - #address-cells = <0x01>; - #size-cells = <0x01>; - compatible = "eswin-dsp\0cdns,xrp-hw-eswin"; - ranges = <0x28000000 0x00 0x5b008000 0x8000 0x28100000 0x00 0x5b140000 0x20000 0x28120000 0x00 0x5b160000 0x20000>; - clocks = <0x03 0x2a9>; - clock-names = "aclk"; - operating-points-v2 = <0x22>; - dsp_mbox = <0x24>; - device-irq = <0x0d 0x50ab0000 0x40 0x50aa0000 0x01 0x50a40000>; - device-uart = <0x50900000>; - device-irq-mode = <0x01>; - host-irq-mode = <0x01>; - firmware-name = "eic7700_dsp_fw"; - process-id = <0x01>; - iommus = <0x16 0x13>; - tbus = <0x71>; - dma-noncoherent; - numa-node-id = <0x00>; - aux-e31-dtim = <0x5a110000>; - status = "okay"; - - dsp@0 { - }; - }; - - es_dsp@2 { - #address-cells = <0x01>; - #size-cells = <0x01>; - compatible = "eswin-dsp\0cdns,xrp-hw-eswin"; - ranges = <0x28000000 0x00 0x5b010000 0x8000 0x28100000 0x00 0x5b180000 0x20000 0x28120000 0x00 0x5b1a0000 0x20000>; - clocks = <0x03 0x2aa>; - clock-names = "aclk"; - operating-points-v2 = <0x22>; - dsp_mbox = <0x25>; - device-irq = <0x0f 0x50ad0000 0x80 0x50ac0000 0x01 0x50a40000>; - device-uart = <0x50900000>; - device-irq-mode = <0x01>; - host-irq-mode = <0x01>; - firmware-name = "eic7700_dsp_fw"; - process-id = <0x02>; - iommus = <0x16 0x14>; - tbus = <0x72>; - dma-noncoherent; - numa-node-id = <0x00>; - aux-e31-dtim = <0x5a110000>; - status = "okay"; - - dsp@0 { - }; - }; - - es_dsp@3 { - #address-cells = <0x01>; - #size-cells = <0x01>; - compatible = "eswin-dsp\0cdns,xrp-hw-eswin"; - ranges = <0x28000000 0x00 0x5b018000 0x8000 0x28100000 0x00 0x5b1c0000 0x20000 0x28120000 0x00 0x5b1e0000 0x20000>; - clocks = <0x03 0x2ab>; - clock-names = "aclk"; - operating-points-v2 = <0x22>; - dsp_mbox = <0x26>; - device-irq = <0x11 0x50af0000 0x100 0x50ae0000 0x01 0x50a40000>; - device-uart = <0x50900000>; - device-irq-mode = <0x01>; - host-irq-mode = <0x01>; - firmware-name = "eic7700_dsp_fw"; - process-id = <0x03>; - iommus = <0x16 0x15>; - tbus = <0x73>; - dma-noncoherent; - numa-node-id = <0x00>; - aux-e31-dtim = <0x5a110000>; - status = "okay"; - - dsp@0 { - }; - }; - - sofdsp@4 { - #sound-dai-cells = <0x01>; - #address-cells = <0x02>; - #size-cells = <0x02>; - compatible = "eswin,sof-dsp"; - reg = <0x00 0x5b018000 0x00 0x8000 0x00 0x5b1c0000 0x00 0x40000>; - mbox-names = "dsp-mbox"; - mboxes = <0x26 0x00>; - clocks = <0x03 0x2ab>; - clock-names = "aclk"; - process-id = <0x03>; - iommus = <0x16 0x15>; - tbus = <0x73>; - dma-noncoherent; - mailbox-dsp-to-u84-addr = <0x50af0000>; - mailbox-u84-to-dsp-addr = <0x50ae0000>; - dsp-uart = <0x27>; - device-uart-mutex = <0x51820000>; - numa-node-id = <0x00>; - }; }; mmc@0x50460000 { @@ -434,24 +335,6 @@ no-mmc; }; - mbox@50a00000 { - compatible = "eswin,win2030-mailbox"; - reg = <0x00 0x50a00000 0x00 0x10000 0x00 0x50a10000 0x00 0x10000>; - interrupt-parent = <0x10>; - interrupts = <0x75>; - #mbox-cells = <0x01>; - clocks = <0x03 0x27e 0x03 0x27f>; - clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x15 0x0c 0x01 0x15 0x0c 0x02>; - reset-names = "rst\0rst_device"; - lock-bit = <0x01>; - irq-bit = <0x02>; - numa-node-id = <0x00>; - dma-noncoherent; - status = "okay"; - phandle = <0x30>; - }; - mbox@50a20000 { compatible = "eswin,win2030-mailbox"; reg = <0x00 0x50a20000 0x00 0x10000 0x00 0x50a30000 0x00 0x10000>; @@ -488,23 +371,6 @@ phandle = <0x1e>; }; - mbox@50a60000 { - compatible = "eswin,win2030-mailbox"; - reg = <0x00 0x50a60000 0x00 0x10000 0x00 0x50a70000 0x00 0x10000>; - interrupt-parent = <0x10>; - interrupts = <0x7b>; - #mbox-cells = <0x01>; - clocks = <0x03 0x284 0x03 0x285>; - clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x15 0x0c 0x40 0x15 0x0c 0x80>; - reset-names = "rst\0rst_device"; - lock-bit = <0x01>; - irq-bit = <0x10>; - numa-node-id = <0x00>; - dma-noncoherent; - status = "okay"; - }; - mbox@50a80000 { compatible = "eswin,dsp0-mailbox"; reg = <0x00 0x50a80000 0x00 0x10000 0x00 0x50a90000 0x00 0x10000>; @@ -523,60 +389,6 @@ phandle = <0x23>; }; - mbox@50aa0000 { - compatible = "eswin,dsp1-mailbox"; - reg = <0x00 0x50aa0000 0x00 0x10000 0x00 0x50ab0000 0x00 0x10000>; - interrupt-parent = <0x10>; - interrupts = <0x7f>; - #mbox-cells = <0x01>; - clocks = <0x03 0x288 0x03 0x289>; - clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x15 0x0c 0x400 0x15 0x0c 0x800>; - reset-names = "rst\0rst_device"; - lock-bit = <0x01>; - irq-bit = <0x40>; - numa-node-id = <0x00>; - dma-noncoherent; - status = "okay"; - phandle = <0x24>; - }; - - mbox@50ac0000 { - compatible = "eswin,dsp2-mailbox"; - reg = <0x00 0x50ac0000 0x00 0x10000 0x00 0x50ad0000 0x00 0x10000>; - interrupt-parent = <0x10>; - interrupts = <0x81>; - #mbox-cells = <0x01>; - clocks = <0x03 0x28a 0x03 0x28b>; - clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x15 0x0c 0x1000 0x15 0x0c 0x2000>; - reset-names = "rst\0rst_device"; - lock-bit = <0x01>; - irq-bit = <0x80>; - numa-node-id = <0x00>; - dma-noncoherent; - status = "okay"; - phandle = <0x25>; - }; - - mbox@50ae0000 { - compatible = "eswin,dsp3-mailbox"; - reg = <0x00 0x50ae0000 0x00 0x10000 0x00 0x50af0000 0x00 0x10000>; - interrupt-parent = <0x10>; - interrupts = <0x83>; - #mbox-cells = <0x01>; - clocks = <0x03 0x28c 0x03 0x28d>; - clock-names = "pclk_mailbox_host\0pclk_mailbox_device"; - resets = <0x15 0x0c 0x4000 0x15 0x0c 0x8000>; - reset-names = "rst\0rst_device"; - lock-bit = <0x01>; - irq-bit = <0x100>; - numa-node-id = <0x00>; - dma-noncoherent; - status = "okay"; - phandle = <0x26>; - }; - i2c@51838000 { compatible = "snps,designware-i2c"; clock-frequency = <0x186a0>; @@ -622,7 +434,7 @@ }; chosen { - bootargs = "root=PARTUUID=b0f77ad6-36cd-4a99-a8c0-31d73649aa09 console=ttyS0,115200 root=PARTUUID=b0f77ad6-36cd-4a99-a8c0-31d73649aa09 rootfstype=ext4 rootwait rw earlycon selinux=0 LANG=en_US.UTF-8 init=/bin/bash"; + bootargs = "console=ttyS0,115200 root=/dev/mmcblk0p3 rootfstype=ext4 rootwait rw earlycon selinux=0 LANG=en_US.UTF-8 init=/init.sh"; stdout-path = "serial0:115200n8"; domain-config { @@ -643,6 +455,12 @@ numa-node-id = <0x00>; }; + hvisor_virtio_device { + compatible = "hvisor"; + interrupt-parent = <0x10>; + interrupts = <0x20>; + }; + reserved-memory { #address-cells = <0x02>; #size-cells = <0x02>; @@ -658,6 +476,11 @@ reg = <0x00 0x80200000 0x00 0x02E00000>; }; + nonroot@83000000 { + no-map; + reg = <0x00 0x83000000 0x00 0x0D000000>; + }; + sprammemory@59000000 { no-map; reg = <0x00 0x59000000 0x00 0x400000>; diff --git a/platform/riscv64/hifive-premier-p550/scripts/README.md b/platform/riscv64/hifive-premier-p550/scripts/README.md index 8a129c43..13622052 100644 --- a/platform/riscv64/hifive-premier-p550/scripts/README.md +++ b/platform/riscv64/hifive-premier-p550/scripts/README.md @@ -25,4 +25,55 @@ screen -S zone1 /dev/pts/0 # reattach to virtio-console screen -r zone1 +``` +
+ +--- + +
+ +If you want to test npu, you can use these cmds. + +```bash +# in hvisor +insmod /lib/modules/6.6.77-win2030/kernel/drivers/soc/eswin/ai_driver/dsp/eic7700_dsp.ko +insmod /lib/modules/6.6.77-win2030/kernel/drivers/soc/eswin/ai_driver/npu/eic7700_npu.ko +# these two modules are needed +cd /home/debian/qwen +/opt/eswin/sample-code/npu_sample/qwen_sample/bin/es_qwen2 ./config.json + + +# in phys linux +cd qwen +sudo /opt/eswin/sample-code/npu_sample/qwen_sample/bin/es_qwen2 ./config.json +``` + +Other, if you see: +```bash +bash: cannot set terminal process group (-1): Inappropriate ioctl for device +bash: no job control in this shell +``` + +You can execute cmds: +```bash +mount -t proc proc /proc +mount -t sysfs sys /sys +mkdir -p /dev/pts +mount -t devpts devpts /dev/pts -o gid=5,mode=620,ptmxmode=0666 + +# Set one temp hostname, maybe rockos-eswin +hostname $(cat /etc/hostname) + +# insmod related ko +insmod eic7700_dsp.ko +insmod eic7700_npu.ko + +# execute getty +/sbin/getty -L ttyS0 115200 vt100 +# enter user & passwd + +# execute qwen example +cd qwen +sudo /opt/eswin/sample-code/npu_sample/qwen_sample/bin/es_qwen2 ./config.json +# enter passwd: debian ``` \ No newline at end of file diff --git a/platform/riscv64/hifive-premier-p550/scripts/init.sh b/platform/riscv64/hifive-premier-p550/scripts/init.sh new file mode 100644 index 00000000..c3bfe333 --- /dev/null +++ b/platform/riscv64/hifive-premier-p550/scripts/init.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +mount -t proc proc /proc +mount -t sysfs sys /sys +mkdir -p /dev/pts +mount -t devpts devpts /dev/pts -o gid=5,mode=620,ptmxmode=0666 + +# Set one temp hostname, maybe rockos-eswin +hostname $(cat /etc/hostname) + +# insmod related ko +insmod /home/debian/module-6.77/eic7700_dsp.ko +insmod /home/debian/module-6.77/eic7700_npu.ko + +while true; do + /sbin/getty -L ttyS0 115200 vt100 +done \ No newline at end of file diff --git a/platform/riscv64/qemu-plic/board.rs b/platform/riscv64/qemu-plic/board.rs index f38945b8..094ef417 100644 --- a/platform/riscv64/qemu-plic/board.rs +++ b/platform/riscv64/qemu-plic/board.rs @@ -20,6 +20,8 @@ pub const BOARD_NAME: &str = "qem-plic"; pub const BOARD_NCPUS: usize = 4; +pub const TIMEBASE_FREQ: u64 = 10_000_000; // 10MHz + pub const ACLINT_SSWI_BASE: usize = 0x2F00000; pub const PLIC_BASE: usize = 0xc000000; diff --git a/src/arch/riscv64/mod.rs b/src/arch/riscv64/mod.rs index a4143b61..84ab2379 100644 --- a/src/arch/riscv64/mod.rs +++ b/src/arch/riscv64/mod.rs @@ -27,6 +27,7 @@ pub mod s2pt; pub mod sbi; pub mod trap; pub mod zone; +pub mod time; pub use s1pt::Stage1PageTable; pub use s2pt::stage2_mode_detect; diff --git a/src/arch/riscv64/sbi.rs b/src/arch/riscv64/sbi.rs index 4086f49d..eabe97c7 100644 --- a/src/arch/riscv64/sbi.rs +++ b/src/arch/riscv64/sbi.rs @@ -93,16 +93,16 @@ pub fn sbi_vs_handler(current_cpu: &mut ArchCpu) { } // Legacy::Console putchar (usually used), temporily don't support other legacy extensions. legacy::LEGACY_CONSOLE_PUTCHAR => { - sbi_ret = SbiRet { - error: sbi_rt::legacy::console_putchar(current_cpu.x[10] as _), - value: 0, - }; + sbi_ret = SbiRet { + error: sbi_rt::legacy::console_putchar(current_cpu.x[10] as _), + value: 0, + }; } legacy::LEGACY_CONSOLE_GETCHAR => { - sbi_ret = SbiRet { - error: sbi_rt::legacy::console_getchar(), - value: 0, - }; + sbi_ret = SbiRet { + error: sbi_rt::legacy::console_getchar(), + value: 0, + }; } _ => { // Pass through SBI call @@ -148,11 +148,17 @@ pub fn sbi_base_handler(fid: usize, current_cpu: &mut ArchCpu) -> SbiRet { sbi_ret.value = ext_id; } } - base::GET_MVENDORID | base::GET_MARCHID | base::GET_MIMPID => { + base::GET_MVENDORID => { // Return a value that is legal for the mvendorid CSR and 0 is always a legal value for this CSR. + sbi_ret.value = sbi_rt::get_mvendorid(); + } + base::GET_MARCHID => { // Return a value that is legal for the marchid CSR and 0 is always a legal value for this CSR. + sbi_ret.value = sbi_rt::get_marchid(); + } + base::GET_MIMPID => { // Return a value that is legal for the mimpid CSR and 0 is always a legal value for this CSR. - sbi_ret.value = 0; + sbi_ret.value = sbi_rt::get_mimpid(); } _ => { sbi_ret.error = RET_ERR_NOT_SUPPORTED; diff --git a/src/arch/riscv64/time.rs b/src/arch/riscv64/time.rs new file mode 100644 index 00000000..22401323 --- /dev/null +++ b/src/arch/riscv64/time.rs @@ -0,0 +1,68 @@ +// 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: Jingyu Liu +// + +use crate::platform::__board::TIMEBASE_FREQ; +use riscv::register::time; + +static mut TIMEBASE: u64 = 0; + +/// Note: You should call this function once during initialization. +pub fn init_timebase() { + unsafe { + TIMEBASE = time::read() as u64; + } +} + +pub fn get_timebase() -> u64 { + unsafe { TIMEBASE } +} + +pub fn get_timefreq() -> u64 { + TIMEBASE_FREQ +} + +pub fn read_time() -> u64 { + // Now only support 64-bit system. + time::read() as u64 +} + +/// Return time in nanoseconds since some arbitrary point in the past. +pub fn get_time_ns() -> u64 { + unsafe { + (read_time() - TIMEBASE) * 1_000_000_000 / TIMEBASE_FREQ + } +} + +/// Return time in seconds since some arbitrary point in the past. +pub fn get_time_us() -> u64 { + unsafe { + (read_time() - TIMEBASE) * 1_000_000 / TIMEBASE_FREQ + } +} + +/// Return time in seconds since some arbitrary point in the past. +pub fn get_time_ms() -> u64 { + unsafe { + (read_time() - TIMEBASE) * 1_000 / TIMEBASE_FREQ + } +} + +/// Return time in seconds since some arbitrary point in the past. +pub fn get_time_s() -> u64 { + unsafe { + (read_time() - TIMEBASE) / TIMEBASE_FREQ + } +} diff --git a/src/consts.rs b/src/consts.rs index c78adbe8..0b51783d 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -34,6 +34,10 @@ pub const MAX_ZONE_NUM: usize = 4; pub const MAX_WAIT_TIMES: usize = 10000000; +pub fn hv_start() -> VirtAddr { + skernel as _ +} + pub fn core_end() -> VirtAddr { __core_end as _ } @@ -52,5 +56,6 @@ pub const IPI_EVENT_UPDATE_HART_LINE: usize = 5; pub const IPI_EVENT_SEND_IPI: usize = 6; extern "C" { + fn skernel(); fn __core_end(); } diff --git a/src/logging.rs b/src/logging.rs index f153ffcc..f469d7b2 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -137,14 +137,30 @@ impl Log for SimpleLogger { Level::Debug => ColorCode::Cyan, Level::Trace => ColorCode::BrightBlack, }; - print(with_color!( - ColorCode::White, - "[{} {}] {} {}\n", - with_color!(level_color, "{:<5}", level), - with_color!(ColorCode::White, "{}", cpu_id), - with_color!(ColorCode::White, "({}:{})", target, line), - with_color!(args_color, "{}", record.args()), - )); + if cfg!(feature = "print_timestamp") + { + let time_us: u64 = crate::arch::time::get_time_us(); + let sec = time_us / 1_000_000; + let us = time_us % 1_000_000; + print(with_color!( + ColorCode::White, + "[{}] {} {} hvisor: {} {}\n", + with_color!(ColorCode::BrightWhite, "{:>5}.{:06}", sec, us), + with_color!(level_color, "{:<5}", level), + with_color!(ColorCode::BrightGreen, "CPU{}", cpu_id), + with_color!(ColorCode::White, "({}:{})", target, line), + with_color!(args_color, "{}", record.args()), + )); + } else { + print(with_color!( + ColorCode::White, + "[{} {}] {} {}\n", + with_color!(level_color, "{:<5}", level), + with_color!(ColorCode::White, "{}", cpu_id), + with_color!(ColorCode::White, "({}:{})", target, line), + with_color!(args_color, "{}", record.args()), + )); + } } fn flush(&self) {} diff --git a/src/main.rs b/src/main.rs index 3b82f2aa..f7b4264d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -179,6 +179,8 @@ fn rust_main(cpuid: usize, host_dtb: usize) { is_primary = true; memory::heap::init(); memory::heap::test(); + #[cfg(feature = "print_timestamp")] + arch::time::init_timebase(); } let cpu = PerCpu::new(cpuid); From 202e79f8988b63934addf7e5bb63df1357040290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=AF=E5=AE=87?= <2537738252@qq.com> Date: Mon, 8 Sep 2025 11:49:02 +0800 Subject: [PATCH 002/109] riscv64: fix sbi legacy extension bug --- src/arch/riscv64/sbi.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/arch/riscv64/sbi.rs b/src/arch/riscv64/sbi.rs index eabe97c7..414cb820 100644 --- a/src/arch/riscv64/sbi.rs +++ b/src/arch/riscv64/sbi.rs @@ -91,6 +91,8 @@ pub fn sbi_vs_handler(current_cpu: &mut ArchCpu) { EID_HVISOR => { sbi_ret = sbi_hvisor_handler(current_cpu); } + // Note: hvisor don't suggest to use Legacy Extension. + // But for compatibility, we still support some legacy SBI calls. // Legacy::Console putchar (usually used), temporily don't support other legacy extensions. legacy::LEGACY_CONSOLE_PUTCHAR => { sbi_ret = SbiRet { @@ -104,6 +106,9 @@ pub fn sbi_vs_handler(current_cpu: &mut ArchCpu) { value: 0, }; } + legacy::LEGACY_SET_TIMER => { + sbi_ret = sbi_time_handler(time::SET_TIMER, current_cpu); + } _ => { // Pass through SBI call warn!("Unsupported SBI extension {:#x} function {:#x}", eid, fid); @@ -114,8 +119,15 @@ pub fn sbi_vs_handler(current_cpu: &mut ArchCpu) { } } // Write the return value back to the current_cpu - current_cpu.x[10] = sbi_ret.error as usize; - current_cpu.x[11] = sbi_ret.value as usize; + // Note: for legacy SBI extensions, nothing is returned in a1 register. + // For other SBI extensions, a0 is error code, a1 is return value. + if eid > 0xF { // Legacy extensions are 0x0 ~ 0xF + current_cpu.x[10] = sbi_ret.error as usize; + current_cpu.x[11] = sbi_ret.value as usize; + } else { + // This SBI call returns 0 upon success or an implementation specific negative error code. + current_cpu.x[10] = sbi_ret.error as usize; + } } /// Handle SBI Base Extension calls. From 370819a6b0741830174b628fd1eedf2e206c901f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=AF=E5=AE=87?= <2537738252@qq.com> Date: Mon, 8 Sep 2025 11:52:43 +0800 Subject: [PATCH 003/109] make fmt --- src/arch/riscv64/mod.rs | 2 +- src/arch/riscv64/sbi.rs | 19 ++++++++++--------- src/arch/riscv64/time.rs | 16 ++++------------ src/logging.rs | 20 ++++++++++---------- 4 files changed, 25 insertions(+), 32 deletions(-) diff --git a/src/arch/riscv64/mod.rs b/src/arch/riscv64/mod.rs index 84ab2379..3c31bf95 100644 --- a/src/arch/riscv64/mod.rs +++ b/src/arch/riscv64/mod.rs @@ -25,9 +25,9 @@ pub mod paging; pub mod s1pt; pub mod s2pt; pub mod sbi; +pub mod time; pub mod trap; pub mod zone; -pub mod time; pub use s1pt::Stage1PageTable; pub use s2pt::stage2_mode_detect; diff --git a/src/arch/riscv64/sbi.rs b/src/arch/riscv64/sbi.rs index 414cb820..f4e3f221 100644 --- a/src/arch/riscv64/sbi.rs +++ b/src/arch/riscv64/sbi.rs @@ -95,16 +95,16 @@ pub fn sbi_vs_handler(current_cpu: &mut ArchCpu) { // But for compatibility, we still support some legacy SBI calls. // Legacy::Console putchar (usually used), temporily don't support other legacy extensions. legacy::LEGACY_CONSOLE_PUTCHAR => { - sbi_ret = SbiRet { - error: sbi_rt::legacy::console_putchar(current_cpu.x[10] as _), - value: 0, - }; + sbi_ret = SbiRet { + error: sbi_rt::legacy::console_putchar(current_cpu.x[10] as _), + value: 0, + }; } legacy::LEGACY_CONSOLE_GETCHAR => { - sbi_ret = SbiRet { - error: sbi_rt::legacy::console_getchar(), - value: 0, - }; + sbi_ret = SbiRet { + error: sbi_rt::legacy::console_getchar(), + value: 0, + }; } legacy::LEGACY_SET_TIMER => { sbi_ret = sbi_time_handler(time::SET_TIMER, current_cpu); @@ -121,7 +121,8 @@ pub fn sbi_vs_handler(current_cpu: &mut ArchCpu) { // Write the return value back to the current_cpu // Note: for legacy SBI extensions, nothing is returned in a1 register. // For other SBI extensions, a0 is error code, a1 is return value. - if eid > 0xF { // Legacy extensions are 0x0 ~ 0xF + if eid > 0xF { + // Legacy extensions are 0x0 ~ 0xF current_cpu.x[10] = sbi_ret.error as usize; current_cpu.x[11] = sbi_ret.value as usize; } else { diff --git a/src/arch/riscv64/time.rs b/src/arch/riscv64/time.rs index 22401323..58f62f94 100644 --- a/src/arch/riscv64/time.rs +++ b/src/arch/riscv64/time.rs @@ -41,28 +41,20 @@ pub fn read_time() -> u64 { /// Return time in nanoseconds since some arbitrary point in the past. pub fn get_time_ns() -> u64 { - unsafe { - (read_time() - TIMEBASE) * 1_000_000_000 / TIMEBASE_FREQ - } + unsafe { (read_time() - TIMEBASE) * 1_000_000_000 / TIMEBASE_FREQ } } /// Return time in seconds since some arbitrary point in the past. pub fn get_time_us() -> u64 { - unsafe { - (read_time() - TIMEBASE) * 1_000_000 / TIMEBASE_FREQ - } + unsafe { (read_time() - TIMEBASE) * 1_000_000 / TIMEBASE_FREQ } } /// Return time in seconds since some arbitrary point in the past. pub fn get_time_ms() -> u64 { - unsafe { - (read_time() - TIMEBASE) * 1_000 / TIMEBASE_FREQ - } + unsafe { (read_time() - TIMEBASE) * 1_000 / TIMEBASE_FREQ } } /// Return time in seconds since some arbitrary point in the past. pub fn get_time_s() -> u64 { - unsafe { - (read_time() - TIMEBASE) / TIMEBASE_FREQ - } + unsafe { (read_time() - TIMEBASE) / TIMEBASE_FREQ } } diff --git a/src/logging.rs b/src/logging.rs index f469d7b2..af0408c8 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -137,7 +137,7 @@ impl Log for SimpleLogger { Level::Debug => ColorCode::Cyan, Level::Trace => ColorCode::BrightBlack, }; - if cfg!(feature = "print_timestamp") + #[cfg(feature = "print_timestamp")] { let time_us: u64 = crate::arch::time::get_time_us(); let sec = time_us / 1_000_000; @@ -151,16 +151,16 @@ impl Log for SimpleLogger { with_color!(ColorCode::White, "({}:{})", target, line), with_color!(args_color, "{}", record.args()), )); - } else { - print(with_color!( - ColorCode::White, - "[{} {}] {} {}\n", - with_color!(level_color, "{:<5}", level), - with_color!(ColorCode::White, "{}", cpu_id), - with_color!(ColorCode::White, "({}:{})", target, line), - with_color!(args_color, "{}", record.args()), - )); } + #[cfg(not(feature = "print_timestamp"))] + print(with_color!( + ColorCode::White, + "[{} {}] {} {}\n", + with_color!(level_color, "{:<5}", level), + with_color!(ColorCode::White, "{}", cpu_id), + with_color!(ColorCode::White, "({}:{})", target, line), + with_color!(args_color, "{}", record.args()), + )); } fn flush(&self) {} From beff8334c0e643e0bc9ad8e06f31a89a33e9a182 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=AF=E5=AE=87?= <2537738252@qq.com> Date: Mon, 8 Sep 2025 13:00:21 +0800 Subject: [PATCH 004/109] riscv64: update qemu-aia's board.rs --- platform/riscv64/qemu-aia/board.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/platform/riscv64/qemu-aia/board.rs b/platform/riscv64/qemu-aia/board.rs index 61dcce29..059b4d46 100644 --- a/platform/riscv64/qemu-aia/board.rs +++ b/platform/riscv64/qemu-aia/board.rs @@ -19,6 +19,8 @@ pub const BOARD_NAME: &str = "qemu-aia"; pub const BOARD_NCPUS: usize = 4; +pub const TIMEBASE_FREQ: u64 = 10_000_000; // 10MHz + pub const ACLINT_SSWI_BASE: usize = 0x2F00000; // This device is used for qemu-quit. From 780399a8be9500374bc2cb5cae0201e5587cc9c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=AF=E5=AE=87?= <2537738252@qq.com> Date: Mon, 8 Sep 2025 13:22:10 +0800 Subject: [PATCH 005/109] update hifive-premier-p550 board.rs --- platform/riscv64/hifive-premier-p550/board.rs | 78 +++++++++---------- 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/platform/riscv64/hifive-premier-p550/board.rs b/platform/riscv64/hifive-premier-p550/board.rs index bcec7845..e7a3d179 100644 --- a/platform/riscv64/hifive-premier-p550/board.rs +++ b/platform/riscv64/hifive-premier-p550/board.rs @@ -33,24 +33,18 @@ pub const ROOT_ZONE_CPUS: u64 = 0x1; pub const ROOT_ZONE_NAME: &str = "root-linux"; -pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 4] = [ +pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 7] = [ HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0x8000_0000, - virtual_start: 0x8000_0000, - size: 0x4_0000_0000, + physical_start: 0x80000000, + virtual_start: 0x80000000, + size: 0x8000_0000, }, // ram HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, - physical_start: 0x0000, - virtual_start: 0x0000, - size: 0xc00_0000, - }, // serial0 - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0x1000_0000, - virtual_start: 0x1000_0000, - size: 0x7000_0000, + physical_start: 0x50900000, + virtual_start: 0x50900000, + size: 0x10000, }, // serial0 // HvConfigMemoryRegion { // mem_type: MEM_TYPE_IO, @@ -82,37 +76,37 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 4] = [ // virtual_start: 0x50920000, // size: 0x10000, // }, // serial2 + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x50460000, + virtual_start: 0x50460000, + size: 0x10000, + }, // mmc + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x50440000, + virtual_start: 0x50440000, + size: 0x2000, + }, // hsp_sp_top_csr + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x51828000, + virtual_start: 0x51828000, + size: 0x80000, + }, // sys-crg (clock-controller, reset-controller) (SD card needs) + // Cache controller is needed, otherwise terminal will report "VFS: cannot open root device..." + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x2010000, + virtual_start: 0x2010000, + size: 0x4000, + }, // L3 cache-controller, now hvisor has virtual sifive ccache. // HvConfigMemoryRegion { // mem_type: MEM_TYPE_IO, - // physical_start: 0x50460000, - // virtual_start: 0x50460000, - // size: 0x10000, - // }, // mmc - // HvConfigMemoryRegion { - // mem_type: MEM_TYPE_IO, - // physical_start: 0x50440000, - // virtual_start: 0x50440000, - // size: 0x2000, - // }, // hsp_sp_top_csr - // HvConfigMemoryRegion { - // mem_type: MEM_TYPE_IO, - // physical_start: 0x51828000, - // virtual_start: 0x51828000, - // size: 0x80000, - // }, // sys-crg (clock-controller, reset-controller) (SD card needs) - // // Cache controller is needed, otherwise terminal will report "VFS: cannot open root device..." - // HvConfigMemoryRegion { - // mem_type: MEM_TYPE_IO, - // physical_start: 0x2010000, - // virtual_start: 0x2010000, - // size: 0x4000, - // }, // L3 cache-controller, now hvisor has virtual sifive ccache. - // // HvConfigMemoryRegion { - // // mem_type: MEM_TYPE_IO, - // // physical_start: 0x8000000, - // // virtual_start: 0x8000000, - // // size: 0x400000, - // // }, // L3 Loosely-Integrated Memory (L3 LIM) + // physical_start: 0x8000000, + // virtual_start: 0x8000000, + // size: 0x400000, + // }, // L3 Loosely-Integrated Memory (L3 LIM) HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0xc0_0000_0000, From 91f9f0542654dc678e5dc7d70b355da534b1c387 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 10 Sep 2025 23:41:28 +0800 Subject: [PATCH 006/109] [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 007/109] [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 008/109] [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 009/109] [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 010/109] [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 011/109] [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 012/109] [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 013/109] [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 014/109] [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 015/109] [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 016/109] [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 b9c77c9ebdfbe0f99c6c0ada997eeec870ef71f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=AF=E5=AE=87?= <2537738252@qq.com> Date: Tue, 21 Oct 2025 16:10:45 +0800 Subject: [PATCH 017/109] remove cfg from main.rs --- src/arch/aarch64/mod.rs | 1 + src/arch/aarch64/time.rs | 21 +++++++++++++++++++++ src/arch/loongarch64/mod.rs | 1 + src/arch/loongarch64/time.rs | 20 ++++++++++++++++++++ src/main.rs | 1 - 5 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/arch/aarch64/time.rs create mode 100644 src/arch/loongarch64/time.rs diff --git a/src/arch/aarch64/mod.rs b/src/arch/aarch64/mod.rs index 85bd3d21..f1c74e2a 100644 --- a/src/arch/aarch64/mod.rs +++ b/src/arch/aarch64/mod.rs @@ -25,6 +25,7 @@ pub mod mmu; pub mod paging; pub mod s2pt; pub mod sysreg; +pub mod time; pub mod trap; pub mod zone; diff --git a/src/arch/aarch64/time.rs b/src/arch/aarch64/time.rs new file mode 100644 index 00000000..25ae0f3a --- /dev/null +++ b/src/arch/aarch64/time.rs @@ -0,0 +1,21 @@ +// 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: +// Jingyu Liu +// + +/// Note: You should call this function once during initialization. +pub fn init_timebase() { + info!("Initializing aarch64 timebase not implemented yet."); +} diff --git a/src/arch/loongarch64/mod.rs b/src/arch/loongarch64/mod.rs index e0ef90aa..f85dcf53 100644 --- a/src/arch/loongarch64/mod.rs +++ b/src/arch/loongarch64/mod.rs @@ -28,6 +28,7 @@ pub mod paging; pub mod register; pub mod s1pt; pub mod s2pt; +pub mod time; pub mod trap; pub mod zone; diff --git a/src/arch/loongarch64/time.rs b/src/arch/loongarch64/time.rs new file mode 100644 index 00000000..786cef20 --- /dev/null +++ b/src/arch/loongarch64/time.rs @@ -0,0 +1,20 @@ +// 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: +// Jingyu Liu + +/// Note: You should call this function once during initialization. +pub fn init_timebase() { + info!("Initializing loongArch64 timebase not implemented yet."); +} diff --git a/src/main.rs b/src/main.rs index f7b4264d..f17aeaee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -179,7 +179,6 @@ fn rust_main(cpuid: usize, host_dtb: usize) { is_primary = true; memory::heap::init(); memory::heap::test(); - #[cfg(feature = "print_timestamp")] arch::time::init_timebase(); } From 20a14fb59415044f0dbcc0738fed6f5cbc745fa6 Mon Sep 17 00:00:00 2001 From: dallas Date: Tue, 28 Oct 2025 16:54:47 +0800 Subject: [PATCH 018/109] 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)] From 00311d0e2144ee114bada8aea70cfd3e5dc8539c Mon Sep 17 00:00:00 2001 From: ZhongkaiXu <3605832858@qq.com> Date: Thu, 30 Oct 2025 12:14:17 +0800 Subject: [PATCH 019/109] =?UTF-8?q?=F0=9F=90=9E=20fix(pcibar):=20fix=20bar?= =?UTF-8?q?=20write?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix phantom-bar write --- src/pci/pcibar.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pci/pcibar.rs b/src/pci/pcibar.rs index 67530982..4657fb75 100644 --- a/src/pci/pcibar.rs +++ b/src/pci/pcibar.rs @@ -142,6 +142,6 @@ impl VirtPciBar { } pub fn write(&mut self, new_val: u32) { - self.val = new_val & self.mask; + self.val = (new_val & self.mask) | (self.val & !self.mask); } } From 4423b75e357d1e50507a976e768fcba80209ebeb Mon Sep 17 00:00:00 2001 From: Solicey Date: Wed, 12 Nov 2025 20:57:59 +0800 Subject: [PATCH 020/109] merge new_pcie into dev-x86_64 --- .../aarch64/imx8mp/configs/zone1-ruxos.json | 2 +- platform/aarch64/qemu-gicv2/board.rs | 36 +- .../aarch64/qemu-gicv2/image/dts/zone0.dts | 18 + platform/aarch64/qemu-gicv3/board.rs | 14 +- .../qemu-gicv3/configs/zone1-linux.json | 36 +- 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 +- platform/loongarch64/ls3a5000/board.rs | 88 +- .../ls3a5000/configs/zone1-linux.json | 9 +- .../ls3a5000/configs/zone2-linux.json | 9 +- .../ls3a5000/configs/zone3-linux.json | 9 +- platform/loongarch64/ls3a6000/board.rs | 87 +- .../ls3a6000/configs/zone1-linux.json | 9 +- .../ls3a6000/configs/zone2-linux.json | 9 +- .../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 +- platform/x86_64/nuc14mnk/board.rs | 28 +- platform/x86_64/qemu/board.rs | 19 +- src/arch/aarch64/iommu.rs | 1 + src/arch/aarch64/zone.rs | 17 - src/arch/loongarch64/zone.rs | 27 +- src/arch/riscv64/zone.rs | 17 - src/arch/x86_64/acpi.rs | 29 +- src/arch/x86_64/boot.rs | 4 +- src/arch/x86_64/cpu.rs | 1 + src/arch/x86_64/iommu.rs | 10 + src/arch/x86_64/pci.rs | 64 - src/arch/x86_64/zone.rs | 9 +- src/config.rs | 40 +- src/main.rs | 7 +- src/memory/mm.rs | 10 + src/pci/bridge.rs | 71 - src/pci/endpoint.rs | 155 --- src/pci/mem_alloc.rs | 85 ++ src/pci/mod.rs | 99 +- src/pci/pci.rs | 450 ------- src/pci/pci_access.rs | 1169 +++++++++++++++++ src/pci/pci_config.rs | 137 ++ src/pci/pci_mem.rs | 70 + src/pci/pci_struct.rs | 1062 +++++++++++++++ src/pci/pci_test.rs | 120 ++ src/pci/pcibar.rs | 147 --- src/pci/phantom_cfg.rs | 365 ----- src/platform/mod.rs | 19 +- src/zone.rs | 24 +- 50 files changed, 3153 insertions(+), 1686 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/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 98cae2b2..9a739804 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,26 @@ 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; 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] = []; -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-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/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index 124b9dca..107e9995 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; @@ -88,7 +91,7 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { }), }; -pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { +pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { ecam_base: 0x4010000000, ecam_size: 0x10000000, io_base: 0x3eff0000, @@ -100,8 +103,13 @@ pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { mem64_base: 0x8000000000, mem64_size: 0x8000000000, pci_mem64_base: 0x8000000000, -}; +}]; 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), + // 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/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 diff --git a/platform/loongarch64/ls3a5000/board.rs b/platform/loongarch64/ls3a5000/board.rs index 184dc110..0be34690 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,21 @@ 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; 1] = [ + 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, + } +]; /* 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 +180,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/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 184dc110..37b555f5 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,21 @@ 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; 1] = [ + 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, + } +]; /* 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 +180,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/platform/loongarch64/ls3a6000/configs/zone1-linux.json b/platform/loongarch64/ls3a6000/configs/zone1-linux.json index e56d3424..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,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/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 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/platform/x86_64/nuc14mnk/board.rs b/platform/x86_64/nuc14mnk/board.rs index d5f001e9..fc85c2fe 100644 --- a/platform/x86_64/nuc14mnk/board.rs +++ b/platform/x86_64/nuc14mnk/board.rs @@ -13,6 +13,7 @@ // // Authors: // +use crate::pci_dev; use crate::{arch::zone::HvArchZoneConfig, config::*, memory::GuestPhysAddr}; pub const MEM_TYPE_RESERVED: u32 = 5; @@ -144,7 +145,7 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { screen_base: ROOT_ZONE_SCREEN_BASE_ADDR, }; -pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { +pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { ecam_base: 0xc0000000, ecam_size: 0x300000, io_base: 0x0, @@ -156,11 +157,28 @@ pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { mem64_base: 0x0, mem64_size: 0x0, pci_mem64_base: 0x0, -}; +}]; -pub const ROOT_PCI_DEVS: [u64; 19] = [ - 0x0, 0x10, 0x20, 0x40, 0x50, 0x68, 0x90, 0xa0, 0xa2, 0xa3, 0xb0, 0xe0, 0xe8, 0xf8, 0xfb, 0xfc, - 0xfd, 0x100, 0x200, +pub const ROOT_PCI_DEVS: [HvPciDevConfig; 18] = [ + pci_dev!(0x0, 0x0, 0x0), // host bridge + pci_dev!(0x0, 0x2, 0x0), // VGA controller + pci_dev!(0x0, 0x4, 0x0), + pci_dev!(0x0, 0x8, 0x0), + pci_dev!(0x0, 0xa, 0x0), + // pci_dev!(0x0, 0xd, 0x0), // USB controller + pci_dev!(0x0, 0x12, 0x0), // serial controller + pci_dev!(0x0, 0x14, 0x0), // USB controller + pci_dev!(0x0, 0x14, 0x2), // RAM memory + pci_dev!(0x0, 0x14, 0x3), // network controller + pci_dev!(0x0, 0x16, 0x0), // communication controller + pci_dev!(0x0, 0x1c, 0x0), // PCI bridge + pci_dev!(0x0, 0x1d, 0x0), // PCI bridge + pci_dev!(0x0, 0x1f, 0x0), // ISA bridge + pci_dev!(0x0, 0x1f, 0x3), // audio controller + pci_dev!(0x0, 0x1f, 0x4), // SMBus + pci_dev!(0x0, 0x1f, 0x5), // serial bus controller + pci_dev!(0x1, 0x0, 0x0), // ethernet controller + pci_dev!(0x2, 0x0, 0x0), // memory controller ]; #[cfg(all(feature = "graphics"))] diff --git a/platform/x86_64/qemu/board.rs b/platform/x86_64/qemu/board.rs index 342bac03..2452894b 100644 --- a/platform/x86_64/qemu/board.rs +++ b/platform/x86_64/qemu/board.rs @@ -13,6 +13,7 @@ // // Authors: // +use crate::pci_dev; use crate::{arch::zone::HvArchZoneConfig, config::*, memory::GuestPhysAddr}; pub const MEM_TYPE_RESERVED: u32 = 5; @@ -90,7 +91,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 8] = [ const ROOT_ZONE_CMDLINE_ADDR: GuestPhysAddr = 0x9000; const ROOT_ZONE_SETUP_ADDR: GuestPhysAddr = 0xa000; const ROOT_ZONE_VMLINUX_ENTRY_ADDR: GuestPhysAddr = 0x10_0000; -const ROOT_ZONE_SCREEN_BASE_ADDR: GuestPhysAddr = 0x7000_0000; +const ROOT_ZONE_SCREEN_BASE_ADDR: GuestPhysAddr = 0; pub const ROOT_ZONE_IRQS: [u32; 32] = [0; 32]; pub const ROOT_ZONE_IOAPIC_BASE: usize = 0xfec0_0000; @@ -108,8 +109,7 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { screen_base: ROOT_ZONE_SCREEN_BASE_ADDR, }; -// only need to fill in ecam_base and ecam_size in x86_64 -pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { +pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { ecam_base: 0xe0000000, ecam_size: 0x200000, io_base: 0x0, @@ -121,9 +121,18 @@ pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { mem64_base: 0x0, mem64_size: 0x0, pci_mem64_base: 0x0, -}; +}]; -pub const ROOT_PCI_DEVS: [u64; 8] = [0x0, 0x8, 0x10, 0x18, 0xf8, 0xfa, 0xfb, 0x100]; +pub const ROOT_PCI_DEVS: [HvPciDevConfig; 8] = [ + pci_dev!(0x0, 0x0, 0x0), // host bridge + pci_dev!(0x0, 0x1, 0x0), // VGA controller + pci_dev!(0x0, 0x2, 0x0), // Ethernet controller + pci_dev!(0x0, 0x3, 0x0), // PCI bridge + pci_dev!(0x0, 0x1f, 0x0), // ISA bridge + pci_dev!(0x0, 0x1f, 0x2), // SATA controller + pci_dev!(0x0, 0x1f, 0x3), // SMBus + pci_dev!(0x1, 0x0, 0x0), // SCSI controller +]; #[cfg(all(feature = "graphics"))] pub const GRAPHICS_FONT: &[u8] = diff --git a/src/arch/aarch64/iommu.rs b/src/arch/aarch64/iommu.rs index 1b7110d5..acf06fd8 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/arch/aarch64/zone.rs b/src/arch/aarch64/zone.rs index b57fecae..207710fc 100644 --- a/src/arch/aarch64/zone.rs +++ b/src/arch/aarch64/zone.rs @@ -21,7 +21,6 @@ use crate::{ device::virtio_trampoline::mmio_virtio_handler, error::HvResult, memory::{GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet}, - pci::pcibar::BarRegion, zone::Zone, }; @@ -162,19 +161,3 @@ pub struct Gicv3Config { pub gits_base: usize, pub gits_size: usize, } - -impl BarRegion { - pub fn arch_set_bar_region_start(&mut self, cpu_base: usize, pci_base: usize) { - self.start = crate::memory::addr::align_down(cpu_base + self.start - pci_base); - } - - pub fn arch_insert_bar_region(&self, gpm: &mut MemorySet, zone_id: usize) { - gpm.insert(MemoryRegion::new_with_offset_mapper( - self.start as GuestPhysAddr, - self.start, - self.size, - MemFlags::READ | MemFlags::WRITE | MemFlags::IO, - )) - .ok(); - } -} diff --git a/src/arch/loongarch64/zone.rs b/src/arch/loongarch64/zone.rs index 96ac8883..3bc460f9 100644 --- a/src/arch/loongarch64/zone.rs +++ b/src/arch/loongarch64/zone.rs @@ -26,7 +26,6 @@ use crate::{ mmio_generic_handler, mmio_perform_access, GuestPhysAddr, HostPhysAddr, MMIOAccess, MemFlags, MemoryRegion, MemorySet, }, - pci::pcibar::BarRegion, zone::Zone, PHY_TO_DMW_UNCACHED, }; @@ -685,34 +684,10 @@ impl Zone { } pub fn arch_zone_pre_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(()) } pub fn arch_zone_post_configuration(&mut self, config: &HvZoneConfig) -> HvResult { Ok(()) } } - -impl BarRegion { - pub fn arch_set_bar_region_start(&mut self, cpu_base: usize, pci_base: usize) { - self.start = crate::memory::addr::align_down(cpu_base + self.start - pci_base); - } - - pub fn arch_insert_bar_region(&self, gpm: &mut MemorySet, zone_id: usize) { - gpm.insert(MemoryRegion::new_with_offset_mapper( - self.start as GuestPhysAddr, - self.start, - self.size, - MemFlags::READ | MemFlags::WRITE | MemFlags::IO, - )) - .ok(); - } -} diff --git a/src/arch/riscv64/zone.rs b/src/arch/riscv64/zone.rs index fd67b580..81a02c5b 100644 --- a/src/arch/riscv64/zone.rs +++ b/src/arch/riscv64/zone.rs @@ -19,7 +19,6 @@ use crate::{ device::virtio_trampoline::{mmio_virtio_handler, VIRTIO_BRIDGE}, error::HvResult, memory::{addr::align_up, GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet}, - pci::pcibar::BarRegion, percpu::get_cpu_data, zone::Zone, }; @@ -77,19 +76,3 @@ pub struct HvArchZoneConfig { pub aplic_base: usize, pub aplic_size: usize, } - -impl BarRegion { - pub fn arch_set_bar_region_start(&mut self, cpu_base: usize, pci_base: usize) { - self.start = crate::memory::addr::align_down(cpu_base + self.start - pci_base); - } - - pub fn arch_insert_bar_region(&self, gpm: &mut MemorySet, zone_id: usize) { - gpm.insert(MemoryRegion::new_with_offset_mapper( - self.start as GuestPhysAddr, - self.start, - self.size, - MemFlags::READ | MemFlags::WRITE | MemFlags::IO, - )) - .ok(); - } -} diff --git a/src/arch/x86_64/acpi.rs b/src/arch/x86_64/acpi.rs index b3c6636d..357c4ff1 100644 --- a/src/arch/x86_64/acpi.rs +++ b/src/arch/x86_64/acpi.rs @@ -273,13 +273,8 @@ pub struct RootAcpi { tables: BTreeMap, ssdts: BTreeMap, pointers: Vec, - devices: Vec, config_space_base: usize, config_space_size: usize, - /// key: data reg hpa, value: bdf - msi_data_reg_map: BTreeMap, - /// key: msi-x table bar, value: bdf - msix_bar_map: BTreeMap, /// key: apic id, value: cpu id (continuous) apic_id_to_cpu_id: BTreeMap, /// key: cpu id (continuous), value: apic id @@ -537,8 +532,7 @@ impl RootAcpi { println!("{:x?}", entry); // we don't have such many buses, probe devices to get the max_bus we have - let (mut devices, mut msi_data_reg_map, mut msix_bar_map, _, max_bus) = - probe_root_pci_devices(entry.base_address as _); + let (_, _, _, _, max_bus) = probe_root_pci_devices(entry.base_address as _); // update bus_number_end root_acpi @@ -547,14 +541,9 @@ impl RootAcpi { .set_u8(max_bus, offset); offset += size_of::(); - root_acpi.devices.append(&mut devices); - root_acpi.config_space_base = entry.base_address as _; root_acpi.config_space_size = (((max_bus as u64 - entry.bus_number_start as u64) + 1) << 20) as usize; - - root_acpi.msi_data_reg_map.append(&mut msi_data_reg_map); - root_acpi.msix_bar_map.append(&mut msix_bar_map); } root_acpi.add_pointer(Signature::RSDT, rsdt_offset, Signature::MCFG, RSDT_PTR_SIZE); @@ -709,22 +698,6 @@ pub fn root_get_config_space_info() -> Option<(usize, usize)> { Some((acpi.config_space_base, acpi.config_space_size)) } -pub fn is_msi_data_reg(hpa: usize) -> Option { - if let Some(&bdf) = ROOT_ACPI.get().unwrap().msi_data_reg_map.get(&hpa) { - Some(bdf) - } else { - None - } -} - -pub fn is_msix_bar(hpa: usize) -> Option { - if let Some(&bdf) = ROOT_ACPI.get().unwrap().msix_bar_map.get(&hpa) { - Some(bdf) - } else { - None - } -} - fn contains_apic_id(apic_id: usize) -> bool { ROOT_ACPI .get() diff --git a/src/arch/x86_64/boot.rs b/src/arch/x86_64/boot.rs index 334990f2..14d92a08 100644 --- a/src/arch/x86_64/boot.rs +++ b/src/arch/x86_64/boot.rs @@ -245,8 +245,8 @@ impl BootParams { } self.e820_table[index] = BootE820Entry { - addr: config.pci_config.ecam_base as _, - size: config.pci_config.ecam_size as _, + addr: config.pci_config[0].ecam_base as _, + size: config.pci_config[0].ecam_size as _, _type: E820Type::E820_RESERVED, }; index += 1; diff --git a/src/arch/x86_64/cpu.rs b/src/arch/x86_64/cpu.rs index 07190eb2..57905690 100644 --- a/src/arch/x86_64/cpu.rs +++ b/src/arch/x86_64/cpu.rs @@ -254,6 +254,7 @@ impl ArchCpu { unsafe { PARKING_MEMORY_SET.get().unwrap().activate(); + info!("before vmx launch"); self.vmx_launch(); } } diff --git a/src/arch/x86_64/iommu.rs b/src/arch/x86_64/iommu.rs index 80eff95f..ede523e8 100644 --- a/src/arch/x86_64/iommu.rs +++ b/src/arch/x86_64/iommu.rs @@ -297,6 +297,12 @@ impl Vtd { self.invalid_iotlb(zone_id as _); } + fn flush(&mut self, zone_id: usize, bus: u8, dev_func: u8) { + let bdf: u16 = (bus as u16) << 8 | (dev_func as u16); + self.invalidate_context_cache(zone_id as _, bdf as _, 0); + self.invalid_iotlb(zone_id as _); + } + fn init(&mut self) { self.check_capability(); self.set_interrupt(); @@ -518,6 +524,10 @@ pub fn activate() { VTD.get().unwrap().lock().activate(); } +pub fn flush(zone_id: usize, bus: u8, dev_func: u8) { + VTD.get().unwrap().lock().flush(zone_id, bus, dev_func); +} + fn flush_cache_range(hpa: usize, size: usize) { let mut i = 0usize; while i < size { diff --git a/src/arch/x86_64/pci.rs b/src/arch/x86_64/pci.rs index 8383fccd..257c7301 100644 --- a/src/arch/x86_64/pci.rs +++ b/src/arch/x86_64/pci.rs @@ -20,7 +20,6 @@ use crate::{ memory::{ mmio_generic_handler, mmio_handle_access, mmio_perform_access, GuestPhysAddr, MMIOAccess, }, - pci::pcibar::BarRegion, percpu::this_zone, zone::{this_zone_id, Zone}, }; @@ -112,69 +111,6 @@ pub fn probe_root_pci_devices( let secondary_bus = unsafe { *((bdf_config_hpa + 0x19) as *const u8) }; buses.push_back(secondary_bus); } - - // probe msi/msi-x capability registers - let mut cap_pointer = unsafe { *((bdf_config_hpa + 0x34) as *const u8) } as usize; - while cap_pointer != 0 { - let cap_hpa = bdf_config_hpa + cap_pointer; - let cap_id = unsafe { *(cap_hpa as *const u8) }; - - if cap_id == 0x5 { - // msi capablility - let msg_ctrl_reg = unsafe { *((cap_hpa + 0x2) as *const u16) }; - let is_64b = msg_ctrl_reg.get_bit(7); - let per_vector_masking = msg_ctrl_reg.get_bit(8); - - let data_reg_hpa = match is_64b { - true => cap_hpa + 0xc, - false => cap_hpa + 0x8, - }; - msi_data_reg_map.insert(data_reg_hpa, bdf as _); - // println!("msi data reg hpa: {:x?}", data_reg_hpa); - println!("msi per vector masking: {:#x?}", per_vector_masking); - } else if cap_id == 0x11 { - // msi-x capability - let msg_ctrl_reg = unsafe { *((cap_hpa + 0x2) as *const u16) }; - let table_size = msg_ctrl_reg.get_bits(0..=10) as usize; - let table_bir = - unsafe { *((cap_hpa + 0x4) as *const u16) }.get_bits(0..=2) as usize; - - // find msi-x table bar - let bar_hpa = bdf_config_hpa + 0x10 + (table_bir) * size_of::(); - let mut bar = unsafe { *(bar_hpa as *const u32) } as usize; - assert!(!bar.get_bit(0)); // memory request - match bar.get_bits(1..=2) { - 0b00 => { - // 32-bit decoding - bar &= !(0xfff); - } - 0b10 => { - // 64-bit decoding - let bar_high = - unsafe { *((bar_hpa + size_of::()) as *const u32) } as usize; - bar = (bar_high << 6) + bar.get_bits(26..=31); - } - _ => { - panic!("MSI-X table BAR type error!"); - } - } - - /*println!( - "table size: {:x}, table bir: {:x}, bar: {:x}", - table_size, table_bir, bar - );*/ - msix_bar_map.insert(bar, bdf as _); - - for i in 0..=table_size { - let data_reg_hpa = bar + i * size_of::() + 2 * size_of::(); - msi_data_reg_map.insert(data_reg_hpa, bdf as _); - // println!("msi-x data reg hpa: {:x?}", data_reg_hpa); - } - } - - // println!("cap id: {:x}, hpa: {:x}", cap_id, cap_hpa); - cap_pointer = unsafe { *((cap_hpa + 1) as *const u8) } as usize; - } } if !bus_empty && bus > max_bus { diff --git a/src/arch/x86_64/zone.rs b/src/arch/x86_64/zone.rs index 75e7c43d..f4ccba7b 100644 --- a/src/arch/x86_64/zone.rs +++ b/src/arch/x86_64/zone.rs @@ -20,7 +20,6 @@ use crate::{ device::virtio_trampoline::mmio_virtio_handler, error::HvResult, memory::{GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet}, - pci::pcibar::{BarRegion, BarType}, percpu::get_cpu_data, platform::MEM_TYPE_RESERVED, zone::Zone, @@ -118,7 +117,7 @@ impl Zone { } pub fn arch_zone_post_configuration(&mut self, config: &HvZoneConfig) -> HvResult { - let mut msix_bar_regions: Vec = Vec::new(); + /*let mut msix_bar_regions: Vec = Vec::new(); for region in self.pciroot.bar_regions.iter_mut() { // check whether this bar is msi-x table // if true, use msi-x table handler instead @@ -142,7 +141,7 @@ impl Zone { if self.id == 0 { self.pci_bars_register(&config.pci_config); - } + }*/ boot::BootParams::fill(&config, &mut self.gpm); acpi::copy_to_guest_memory_region(&config, &self.cpu_set); @@ -151,7 +150,7 @@ impl Zone { } } -impl BarRegion { +/*impl BarRegion { pub fn arch_set_bar_region_start(&mut self, cpu_base: usize, pci_base: usize) { self.start = cpu_base + self.start - pci_base; if self.bar_type != BarType::IO { @@ -175,4 +174,4 @@ impl BarRegion { ); } } -} +}*/ diff --git a/src/config.rs b/src/config.rs index 7d72f45d..49dc9303 100644 --- a/src/config.rs +++ b/src/config.rs @@ -14,6 +14,7 @@ // Authors: // use alloc::vec::Vec; +use core::fmt::Debug; use spin::Once; use crate::{arch::zone::HvArchZoneConfig, platform}; @@ -22,11 +23,12 @@ 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_MAXNUM: usize = 4; pub const CONFIG_MAX_PCI_DEV: usize = 32; #[repr(C)] @@ -91,9 +93,10 @@ pub struct HvZoneConfig { pub dtb_size: u64, pub name: [u8; CONFIG_NAME_MAXLEN], pub arch_config: HvArchZoneConfig, - pub pci_config: HvPciConfig, + pub num_pci_bus: u64, + pub pci_config: [HvPciConfig; CONFIG_PCI_BUS_MAXNUM], 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 +116,10 @@ impl HvZoneConfig { dtb_size: u64, name: [u8; CONFIG_NAME_MAXLEN], arch: HvArchZoneConfig, - pci: HvPciConfig, + num_pci_bus: u64, + pci: [HvPciConfig; CONFIG_PCI_BUS_MAXNUM], num_pci_devs: u64, - alloc_pci_devs: [u64; CONFIG_MAX_PCI_DEV], + alloc_pci_devs: [HvPciDevConfig; CONFIG_MAX_PCI_DEV], ) -> Self { Self { zone_id, @@ -133,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, @@ -192,3 +197,28 @@ 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, +} + +#[macro_export] +macro_rules! pci_dev { + ($bus:expr, $dev:expr, $func:expr) => { + HvPciDevConfig { + bdf: ($bus << 8) | ($dev << 3) | ($func), + vbdf: ($bus << 8) | ($dev << 3) | ($func), + } + }; +} + +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); + let vbdf = crate::pci::pci_struct::Bdf::from_address(self.vbdf); + write!(f, "bdf {:#?} vbdf {:#?}", bdf, vbdf) + } +} diff --git a/src/main.rs b/src/main.rs index b11ac8c4..196b4212 100644 --- a/src/main.rs +++ b/src/main.rs @@ -72,6 +72,7 @@ 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}; +use pci::pci_config::hvisor_pci_init; use percpu::PerCpu; use zone::{add_zone, zone_create}; @@ -134,9 +135,13 @@ fn primary_init_early() { iommu_init(); + let root_config = root_zone_config(); + + let _ = hvisor_pci_init(&root_config.pci_config); + #[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/memory/mm.rs b/src/memory/mm.rs index 54a7c7a8..e1449599 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..7e4533fe --- /dev/null +++ b/src/pci/mem_alloc.rs @@ -0,0 +1,85 @@ +// 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; +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..02c3259e 100644 --- a/src/pci/mod.rs +++ b/src/pci/mod.rs @@ -13,96 +13,13 @@ // // 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 5ab53bbc..00000000 --- a/src/pci/pci.rs +++ /dev/null @@ -1,450 +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 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 core::ptr::{read_volatile, write_volatile}; -use core::{panic, ptr, usize}; - -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, -}; -use crate::arch::consts::{BDF_SHIFT, HV_ADDR_PREFIX, LOONG_HT_PREFIX}; -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, - pub 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 = read_volatile(reg_ptr); - write_volatile(reg_ptr, 0xffffffffu32); - let new_val = read_volatile(reg_ptr); - ep.bars_init(bar_id, origin_val, new_val); - write_volatile(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 = read_volatile(reg_ptr); - write_volatile(reg_ptr, 0xffffffffu32); - let new_val = read_volatile(reg_ptr); - bridge.bars_init(bar_id, origin_val, new_val); - write_volatile(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], - ) { - #[cfg(not(feature = "pci"))] - { - info!("PCIe feature is not enabled, skipping PCIe initialization."); - return; - } - - if num_pci_devs == 0 { - return; - } - info!("PCIe init!"); - - let hv_addr_prefix: u64 = HV_ADDR_PREFIX; - let loong_ht_prefix: u64 = LOONG_HT_PREFIX; - let bdf_shift: usize = BDF_SHIFT; - - 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(any( - all(feature = "iommu", target_arch = "aarch64"), - target_arch = "x86_64" - ))] - if alloc_pci_devs[idx] != 0 { - let iommu_pt_addr = if self.iommu_pt.is_some() { - self.iommu_pt.as_ref().unwrap().root_paddr() - } else { - 0 - }; - iommu_add_device(self.id, alloc_pci_devs[idx] as _, iommu_pt_addr); - } - } - - 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(); - } - - pub 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.arch_set_bar_region_start(cpu_base, pci_base); - - info!( - "pci bar region: type: {:?}, base: {:#x}, size: {:#x}", - region.bar_type, region.start, region.size - ); - - region.arch_insert_bar_region(&mut self.gpm, self.id); - } - } -} - -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 { - #[cfg(not(target_arch = "x86_64"))] - 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); - // in x86, linux will probe for pci devices automatically - #[cfg(target_arch = "x86_64")] - return Ok(()); - } - } 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..8264de43 --- /dev/null +++ b/src/pci/pci_access.rs @@ -0,0 +1,1169 @@ +// 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, + 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}, + pci::pci_struct::BIT_LENTH, + percpu::this_zone, + zone::{this_zone_id, Zone}, +}; + +use super::{ + pci_mem::{PciRegion, PciRegionMmio}, + pci_struct::Bdf, + PciConfigAddress, +}; + +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; + } + + pub fn set_virtual_value64(&mut self, value: u64) { + self.virtual_value = value; + } +} + +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]") + } + } +} + +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(0x0e).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, 0xffffffff); + let mut readback = self.read_bar(slot).unwrap(); + let _ = self.write_bar(slot, value 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, 0xffffffff); + let _ = self.write_bar(slot + 1, 0xffffffff); + let mut readback_low = self.read_bar(slot).unwrap(); + let readback_high = self.read_bar(slot + 1).unwrap(); + let _ = self.write_bar(slot, value as u32); + let _ = self.write_bar(slot + 1, value_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) + } + }; + let value64 = (value as u64) | ((value_high as u64) << 32); + + bararr[slot as usize] = + PciMem::new_bar(PciMemType::Mem64Low, value64 as u64, size, pre); + bararr[(slot + 1) as usize] = + PciMem::new_bar(PciMemType::Mem64High, value64 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 + * | | | + * +-----------------------------+------------------------------+ + * | Status | Command | 0x04 + * | | | + * +-----------------------------+---------------+--------------+ + * | Class Code | Revision | 0x08 + * | | ID | + * +--------------+--------------+---------------+--------------+ + * | BIST | Header | Latency | Cacheline | 0x0c + * | | type | timer | size | + * +--------------+--------------+---------------+--------------+ + */ +#[derive(Debug, Clone)] +pub struct PciConfigHeader(PciRegionMmio); + +impl PciRWBase for PciConfigHeader { + fn backend(&self) -> &dyn PciRegion { + &self.0 + } +} +impl PciRW for PciConfigHeader {} +impl PciHeaderRW for 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 | Capability | 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, + CapabilityPointer, + 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, 1) => EndpointField::CapabilityPointer, + (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 PciRWBase for EndpointHeader { + fn backend(&self) -> &dyn PciRegion { + &self.0 + } +} +impl PciRW for EndpointHeader {} +impl PciHeaderRW for EndpointHeader {} +impl PciBarRW for EndpointHeader { + fn bar_limit(&self) -> u8 { + 6 + } +} +impl PciRomRW for EndpointHeader { + fn rom_offset(&self) -> u64 { + 0x30 + } +} + +impl EndpointHeader { + pub fn new_with_region(region: PciRegionMmio) -> Self { + EndpointHeader(region) + } +} + +/* 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 | + * +-----------------------------+--------------+--------------+ + */ +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 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 { + 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_id = this_zone_id(); + 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 (offset as usize) >= BIT_LENTH { + if !mmio.is_write { + mmio.value = 0; + } + return Ok(()); + } + + 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. 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 + * the old BAR addresses, potentially causing the update to fail? + */ + 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() & !0xf; + info!( + "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 + * TODO: for loongarch64 need ibar 0 dbar 0 + */ + #[cfg(target_arch = "aarch64")] + unsafe { + core::arch::asm!("isb"); + core::arch::asm!("tlbi vmalls12e1is"); + core::arch::asm!("dsb nsh"); + } + /* after update gpm, need to flush iommu table + * in x86_64 + */ + #[cfg(target_arch = "x86_64")] + crate::arch::iommu::flush( + zone_id, + vbdf.bus, + (vbdf.device << 3) + vbdf.function, + ); + } + } + } 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, addr: {:#x?}", mmio.address); + 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..afa409bc --- /dev/null +++ b/src/pci/pci_config.rs @@ -0,0 +1,137 @@ +// 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}; + +use crate::{ + arch::iommu::iommu_add_device, + config::{HvPciConfig, HvPciDevConfig, CONFIG_MAX_PCI_DEV, CONFIG_PCI_BUS_MAXNUM}, + 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_MAXNUM]) -> 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, + ); + + // TODO: refactor + // in x86, we do not take the initiative to reallocate BAR space + #[cfg(target_arch = "x86_64")] + let allocator_opt: Option = None; + #[cfg(not(target_arch = "x86_64"))] + let allocator_opt: Option = Some(allocator); + + let mut rootcomplex = RootComplex::new(rootcomplex_config.ecam_base); + for mut node in rootcomplex.enumerate(None, allocator_opt) { + node.capability_enumerate(); + GLOBAL_PCIE_LIST.lock().insert(node.get_bdf(), node); + } + } + info!("hvisor pci init done \n{:#?}", GLOBAL_PCIE_LIST); + Ok(()) +} + +impl Zone { + pub fn guest_pci_init( + &mut self, + zone_id: usize, + 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 << 12); + let vbdf = Bdf::from_address(dev_config.vbdf << 12); + #[cfg(any( + all(feature = "iommu", target_arch = "aarch64"), + target_arch = "x86_64" + ))] + { + let iommu_pt_addr = if self.iommu_pt.is_some() { + self.iommu_pt.as_ref().unwrap().root_paddr() + } else { + 0 + }; + iommu_add_device(self.id, (bdf.to_address(0) >> 12) as _, iommu_pt_addr); + } + 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 { + 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 done\n {:#?}", self.vpci_bus); + Ok(()) + } + + 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 */ + 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..e2240d3f --- /dev/null +++ b/src/pci/pci_mem.rs @@ -0,0 +1,70 @@ +// 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; +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..8e587376 --- /dev/null +++ b/src/pci/pci_struct.rs @@ -0,0 +1,1062 @@ +// 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}; +use bit_field::BitField; +use bitvec::{array::BitArray, order::Lsb0, BitArr}; + +use crate::{ + error::{HvErrorNum, HvResult}, + pci::pci_access::{Bar, PciBarRW, PciHeaderRW, PciRomRW}, +}; + +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; +pub 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 + } + + pub fn is_host_bridge(&self) -> bool { + if (self.device, self.function) == (0, 0) { + true + } else { + false + } + } +} + +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 + */ +#[derive(Clone)] +pub struct VirtualPciConfigSpace { + bdf: Bdf, + vbdf: Bdf, + config_type: HeaderType, + + space: [u8; BIT_LENTH], + control: VirtualPciConfigControl, + access: VirtualPciAccessBits, + + backend: Arc, + + bararr: Bar, + rom: PciMem, + capabilities: PciCapabilityList, +} + +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: Arc, 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, + capabilities: PciCapabilityList::new(), + } + } + + pub fn bridge(bdf: Bdf, backend: Arc, 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(), + capabilities: PciCapabilityList::new(), + } + } + + pub fn unknown(bdf: Bdf, backend: Arc) -> 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(), + capabilities: PciCapabilityList::new(), + } + } + + pub fn host_bridge(bdf: Bdf, backend: Arc) -> 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(), + capabilities: PciCapabilityList::new(), + } + } + + 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; + } + + /* 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(); + info!( + "{:#x?} has multiple func: {:#x?}", + address, self.is_mulitple_function + ); + + match pci_header.header_type() { + HeaderType::Endpoint => { + let mut ep = EndpointHeader::new_with_region(region); + let rom = ep.parse_rom(); + + 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 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, bararr)) + } + _ => { + warn!("unknown type"); + let pci_header = Arc::new(pci_header); + let bdf = Bdf::from_address(address); + Some(VirtualPciConfigSpace::unknown(bdf, pci_header)) + } + } + } + + fn bar_mem_init( + bar_max: usize, + allocator: &mut Option, + dev: &mut D, + ) -> Bar { + let mut bararr = dev.parse_bar(); + + info!("{:#?}", bararr); + + 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; + } + } else { + // use default bar address as virt bar address + let mut i = 0; + while i < bar_max { + match bararr[i].get_type() { + PciMemType::Mem32 => { + let value = bararr[i].get_value64(); + bararr[i].set_virtual_value64(value as u64); + let _ = dev.write_bar(i as u8, value as u32); + } + PciMemType::Mem64Low => { + let value = bararr[i].get_value64(); + bararr[i].set_virtual_value64(value); + let _ = dev.write_bar(i as u8, value as u32); + i += 1; + bararr[i].set_virtual_value64(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 { + 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 + } + + 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)] +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/pci/pci_test.rs b/src/pci/pci_test.rs new file mode 100644 index 00000000..f0ec3c22 --- /dev/null +++ b/src/pci/pci_test.rs @@ -0,0 +1,120 @@ +// 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; + +use alloc::{collections::btree_map::BTreeMap, sync::Arc}; +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, Arc::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 67530982..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, PartialEq)] -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..95fc4a88 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_MAXNUM, }, consts::INVALID_ADDRESS, }; @@ -71,16 +72,23 @@ 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_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( @@ -99,6 +107,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 58bf6ec4..f4cb5df4 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -17,7 +17,7 @@ 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; +use crate::pci::pci_struct::VirtualRootComplex; use spin::RwLock; use crate::arch::mm::new_s2_memory_set; @@ -38,9 +38,9 @@ pub struct Zone { pub cpu_set: CpuSet, pub irq_bitmap: [u32; 1024 / 32], pub gpm: MemorySet, - pub pciroot: PciRoot, pub iommu_pt: Option>, pub is_err: bool, + pub vpci_bus: VirtualRootComplex, } impl Zone { @@ -53,13 +53,13 @@ impl Zone { cpu_set: CpuSet::new(MAX_CPU_NUM as usize, 0), mmio: Vec::new(), irq_bitmap: [0; 1024 / 32], - pciroot: PciRoot::new(), iommu_pt: if cfg!(feature = "iommu") { Some(new_s2_memory_set()) } else { None }, is_err: false, + vpci_bus: VirtualRootComplex::new(), } } @@ -210,6 +210,20 @@ pub fn zone_create(config: &HvZoneConfig) -> HvResult>> { zone.pt_init(config.memory_regions()).unwrap(); zone.mmio_init(&config.arch_config); + let _ = zone.virtual_pci_mmio_init(&config.pci_config, config.num_pci_bus); + let _ = zone.guest_pci_init(zone_id, &config.alloc_pci_devs, config.num_pci_devs); + + // #[cfg(target_arch = "aarch64")] + // zone.ivc_init(config.ivc_config()); + + /* loongarch page table emergency */ + /* 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[0].ecam_base as _, + // config.pci_config[0].ecam_size as _, + // )?; + let mut cpu_num = 0; for cpu_id in config.cpus().iter() { if let Some(zone) = get_cpu_data(*cpu_id as _).zone.clone() { @@ -245,11 +259,11 @@ pub fn zone_create(config: &HvZoneConfig) -> HvResult>> { // config.pci_config.ecam_size as _, // )?; - zone.pci_init( + /*zone.pci_init( &config.pci_config, config.num_pci_devs as _, &config.alloc_pci_devs, - ); + );*/ zone.arch_zone_post_configuration(config)?; From 8a8a8dd31da039bd7c63887e40c96347e9ed5b1d Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 13 Nov 2025 00:58:52 +0800 Subject: [PATCH 021/109] add frame of dwc and longarch --- Cargo.toml | 5 + platform/aarch64/qemu-gicv3/board.rs | 2 + platform/aarch64/rk3568/board.rs | 111 ++++++- platform/aarch64/rk3568/cargo/features | 2 + platform/aarch64/rk3568/image/dts/rk3568.dts | 252 +++++++-------- .../rk3568/image/dts/rk3568_limit_zone0.dts | 303 +++++++++++++++++- platform/loongarch64/ls3a5000/cargo/features | 3 +- platform/loongarch64/ls3a6000/cargo/features | 3 +- src/config.rs | 8 + src/main.rs | 7 +- src/pci/config_accessors/dwc.rs | 137 ++++++++ src/pci/config_accessors/dwc_atu.rs | 107 +++++++ .../{pci_mem.rs => config_accessors/ecam.rs} | 57 ++-- src/pci/config_accessors/loongarch64.rs | 69 ++++ src/pci/config_accessors/mod.rs | 156 +++++++++ src/pci/mod.rs | 2 +- src/pci/pci_access.rs | 45 ++- src/pci/pci_config.rs | 100 +++++- src/pci/pci_struct.rs | 183 ++++++++--- src/pci/pci_test.rs | 29 +- 20 files changed, 1332 insertions(+), 249 deletions(-) create mode 100644 src/pci/config_accessors/dwc.rs create mode 100644 src/pci/config_accessors/dwc_atu.rs rename src/pci/{pci_mem.rs => config_accessors/ecam.rs} (53%) create mode 100644 src/pci/config_accessors/loongarch64.rs create mode 100644 src/pci/config_accessors/mod.rs diff --git a/Cargo.toml b/Cargo.toml index f61cca26..1062655b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,11 @@ raw-cpuid = "10.7.0" iommu = [] # supported by: aarch64 pci = [] # supported by: aarch64, loongarch64 +############# PCIe access mechanism ############## +ecam_pcie = [] # Standard ECAM mechanism (default for most platforms) +dwc_pcie = [] # DesignWare PCIe Core mechanism (CFG0/CFG1, used by RK3568) +loongarch64_pcie = [] # LoongArch PCIe mechanism (used by LoongArch platforms) + ############# aarch64 ############## # irqchip driver gicv2 = [] diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index 107e9995..779d55d1 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -103,6 +103,8 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { mem64_base: 0x8000000000, mem64_size: 0x8000000000, pci_mem64_base: 0x8000000000, + bus_range_begin: 0, + bus_range_end: 0xff, }]; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; diff --git a/platform/aarch64/rk3568/board.rs b/platform/aarch64/rk3568/board.rs index c2f8c4e9..1438e1bf 100644 --- a/platform/aarch64/rk3568/board.rs +++ b/platform/aarch64/rk3568/board.rs @@ -21,6 +21,7 @@ use crate::{ }, config::*, }; +use crate::pci_dev; pub const BOARD_NAME: &str = "rk3568"; @@ -43,7 +44,8 @@ pub const BOARD_PHYSMEM_LIST: &[(u64, u64, MemoryType)] = &[ // ( start, end, type) ( 0x0, 0xf0000000, MemoryType::Normal), ( 0xf0000000, 0x100000000, MemoryType::Device), - ( 0x100000000, 0x3fc000000, MemoryType::Normal), + ( 0x100000000, 0x3c0000000, MemoryType::Normal), + ( 0x3c0000000, 0x3d0000000, MemoryType::Device) ]; pub const ROOT_ZONE_DTB_ADDR: u64 = 0xa0000000; @@ -53,19 +55,43 @@ pub const ROOT_ZONE_ENTRY: u64 = 0x00280000 ; 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; 20] = [ - // HvConfigMemoryRegion { - // mem_type: MEM_TYPE_IO, - // physical_start: 0xfd400000, - // virtual_start: 0xfd400000, - // size: 0x10000, - // }, // gic - // HvConfigMemoryRegion { - // mem_type: MEM_TYPE_IO, - // physical_start: 0xfd460000, - // virtual_start: 0xfd460000, - // size: 0xc0000, - // }, // gic +pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xfdcb8000, + virtual_start: 0xfdcb8000, + size: 0x10000, + }, //syscon pcie30_phy_grf + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xfdc90000, + virtual_start: 0xfdc90000, + size: 0x10000, + }, //syscon pipe_phy_grf2 + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xfdc50000, + virtual_start: 0xfdc50000, + size: 0x10000, + }, //syscon pipegrf + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xfe8c0000, + virtual_start: 0xfe8c0000, + size: 0x20000, + }, // pcie30phy + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xfdd90000, + virtual_start: 0xfdd90000, + size: 0x1000, + }, // power-management + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xfe840000, + virtual_start: 0xfe840000, + size: 0x1000, + }, // combphy2_psq HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, physical_start: 0x200000, @@ -210,11 +236,62 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { gicd_size: 0x10000, gicr_base: 0xfd460000, gicr_size: 0xc0000, - gits_base: 0, - gits_size: 0, + gits_base: 0xfd440000, + gits_size: 0x20000, }), }; +pub const ROOT_PCI_CONFIG: &[HvPciConfig] = &[ + // HvPciConfig { + // ecam_base: 0xfe260000, + // ecam_size: 0x400000, + // io_base: 0xf4100000, + // io_size: 0x100000, + // pci_io_base: 0xf4100000, + // mem32_base: 0xf4200000, + // mem32_size: 0x1e00000, + // pci_mem32_base: 0xf4200000, + // mem64_base: 0x300000000, + // mem64_size: 0x40000000, + // pci_mem64_base: 0x300000000, + // bus_range_begin: 0x0, + // bus_range_end: 0x10, + // }, + HvPciConfig { + ecam_base: 0x3c0400000, + ecam_size: 0x100000, + io_base: 0xf2100000, + io_size: 0x100000, + pci_io_base: 0xf2100000, + mem32_base: 0xf2200000, + mem32_size: 0x1e00000, + pci_mem32_base: 0xf2200000, + mem64_base: 0x340000000, + mem64_size: 0x40000000, + pci_mem64_base: 0x340000000, + bus_range_begin: 0x10, + bus_range_end: 0x1f, + }, + // HvPciConfig { + // ecam_base: 0xfe280000, + // ecam_size: 0x400000, + // io_base: 0xf0100000, + // io_size: 0x100000, + // pci_io_base: 0xf0100000, + // mem32_base: 0xf0200000, + // mem32_size: 0x1e00000, + // pci_mem32_base: 0xf0200000, + // mem64_base: 0x380000000, + // mem64_size: 0x40000000, + // pci_mem64_base: 0x380000000, + // bus_range_begin: 0x20, + // bus_range_end: 0x2f, + // } +]; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; -pub const ROOT_PCI_DEVS: [u64; 0] = []; +pub const ROOT_PCI_DEVS: [HvPciDevConfig; 3] = [ + pci_dev!( 0x1, 0x0, 0x0), + pci_dev!(0x11, 0x0, 0x0), + pci_dev!(0x21, 0x0, 0x0), +]; \ No newline at end of file diff --git a/platform/aarch64/rk3568/cargo/features b/platform/aarch64/rk3568/cargo/features index afa59489..df350a43 100644 --- a/platform/aarch64/rk3568/cargo/features +++ b/platform/aarch64/rk3568/cargo/features @@ -1,2 +1,4 @@ gicv3 uart_16550 +pci +dwc_pcie \ No newline at end of file diff --git a/platform/aarch64/rk3568/image/dts/rk3568.dts b/platform/aarch64/rk3568/image/dts/rk3568.dts index 7cee4b82..8f4e912f 100644 --- a/platform/aarch64/rk3568/image/dts/rk3568.dts +++ b/platform/aarch64/rk3568/image/dts/rk3568.dts @@ -1648,48 +1648,48 @@ phandle = <0x155>; }; - // pcie@fe280000 { - // power-domains = <0x22 0x0f>; - // vpcie3v3-supply = <0xb0>; - // #address-cells = <0x03>; - // phy-names = "pcie-phy"; - // bus-range = <0x20 0x2f>; - // clock-names = "aclk_mst\0aclk_slv\0aclk_dbi\0pclk\0aux"; - // reg-names = "pcie-dbi\0pcie-apb"; - // num-ob-windows = <0x02>; - // resets = <0x20 0xc1>; - // interrupts = <0x00 0xa5 0x04 0x00 0xa4 0x04 0x00 0xa3 0x04 0x00 0xa2 0x04 0x00 0xa1 0x04>; - // clocks = <0x20 0x8f 0x20 0x90 0x20 0x91 0x20 0x92 0x20 0x93>; - // interrupt-map = <0x00 0x00 0x00 0x01 0xb1 0x00 0x00 0x00 0x00 0x02 0xb1 0x01 0x00 0x00 0x00 0x03 0xb1 0x02 0x00 0x00 0x00 0x04 0xb1 0x03>; - // #size-cells = <0x02>; - // max-link-speed = <0x03>; - // device_type = "pci"; - // interrupt-map-mask = <0x00 0x00 0x00 0x07>; - // reset-gpios = <0xb2 0x1e 0x00>; - // num-lanes = <0x02>; - // compatible = "rockchip,rk3568-pcie\0snps,dw-pcie"; - // ranges = <0x800 0x00 0xf0000000 0x00 0xf0000000 0x00 0x100000 0x81000000 0x00 0xf0100000 0x00 0xf0100000 0x00 0x100000 0x82000000 0x00 0xf0200000 0x00 0xf0200000 0x00 0x1e00000 0xc3000000 0x03 0x80000000 0x03 0x80000000 0x00 0x40000000>; - // msi-map = <0x2000 0xad 0x2000 0x1000>; - // #interrupt-cells = <0x01>; - // status = "okay"; - // interrupt-names = "sys\0pmc\0msg\0legacy\0err"; - // phys = <0xaf>; - // num-viewport = <0x08>; - // reg = <0x03 0xc0800000 0x00 0x400000 0x00 0xfe280000 0x00 0x10000>; - // linux,pci-domain = <0x02>; - // phandle = <0x19f>; - // reset-names = "pipe"; - // num-ib-windows = <0x06>; - - // legacy-interrupt-controller { - // #address-cells = <0x00>; - // interrupts = <0x00 0xa2 0x01>; - // interrupt-parent = <0x01>; - // #interrupt-cells = <0x01>; - // phandle = <0xb1>; - // interrupt-controller; - // }; - // }; + pcie@fe280000 { + power-domains = <0x22 0x0f>; + vpcie3v3-supply = <0xb0>; + #address-cells = <0x03>; + phy-names = "pcie-phy"; + bus-range = <0x20 0x2f>; + clock-names = "aclk_mst\0aclk_slv\0aclk_dbi\0pclk\0aux"; + reg-names = "pcie-dbi\0pcie-apb"; + num-ob-windows = <0x02>; + resets = <0x20 0xc1>; + interrupts = <0x00 0xa5 0x04 0x00 0xa4 0x04 0x00 0xa3 0x04 0x00 0xa2 0x04 0x00 0xa1 0x04>; + clocks = <0x20 0x8f 0x20 0x90 0x20 0x91 0x20 0x92 0x20 0x93>; + interrupt-map = <0x00 0x00 0x00 0x01 0xb1 0x00 0x00 0x00 0x00 0x02 0xb1 0x01 0x00 0x00 0x00 0x03 0xb1 0x02 0x00 0x00 0x00 0x04 0xb1 0x03>; + #size-cells = <0x02>; + max-link-speed = <0x03>; + device_type = "pci"; + interrupt-map-mask = <0x00 0x00 0x00 0x07>; + reset-gpios = <0xb2 0x1e 0x00>; + num-lanes = <0x02>; + compatible = "rockchip,rk3568-pcie\0snps,dw-pcie"; + ranges = <0x800 0x00 0xf0000000 0x00 0xf0000000 0x00 0x100000 0x81000000 0x00 0xf0100000 0x00 0xf0100000 0x00 0x100000 0x82000000 0x00 0xf0200000 0x00 0xf0200000 0x00 0x1e00000 0xc3000000 0x03 0x80000000 0x03 0x80000000 0x00 0x40000000>; + msi-map = <0x2000 0xad 0x2000 0x1000>; + #interrupt-cells = <0x01>; + status = "okay"; + interrupt-names = "sys\0pmc\0msg\0legacy\0err"; + phys = <0xaf>; + num-viewport = <0x08>; + reg = <0x03 0xc0800000 0x00 0x400000 0x00 0xfe280000 0x00 0x10000>; + linux,pci-domain = <0x02>; + phandle = <0x19f>; + reset-names = "pipe"; + num-ib-windows = <0x06>; + + legacy-interrupt-controller { + #address-cells = <0x00>; + interrupts = <0x00 0xa2 0x01>; + interrupt-parent = <0x01>; + #interrupt-cells = <0x01>; + phandle = <0xb1>; + interrupt-controller; + }; + }; vcc2v5-ddr { regulator-max-microvolt = <0x2625a0>; @@ -3942,47 +3942,47 @@ reset-names = "can\0can-apb"; }; - // pcie@fe260000 { - // power-domains = <0x22 0x0f>; - // #address-cells = <0x03>; - // phy-names = "pcie-phy"; - // bus-range = <0x00 0x0f>; - // clock-names = "aclk_mst\0aclk_slv\0aclk_dbi\0pclk\0aux"; - // reg-names = "pcie-dbi\0pcie-apb"; - // num-ob-windows = <0x02>; - // resets = <0x20 0xa1>; - // interrupts = <0x00 0x4b 0x04 0x00 0x4a 0x04 0x00 0x49 0x04 0x00 0x48 0x04 0x00 0x47 0x04>; - // clocks = <0x20 0x81 0x20 0x82 0x20 0x83 0x20 0x84 0x20 0x85>; - // interrupt-map = <0x00 0x00 0x00 0x01 0xac 0x00 0x00 0x00 0x00 0x02 0xac 0x01 0x00 0x00 0x00 0x03 0xac 0x02 0x00 0x00 0x00 0x04 0xac 0x03>; - // #size-cells = <0x02>; - // max-link-speed = <0x02>; - // device_type = "pci"; - // interrupt-map-mask = <0x00 0x00 0x00 0x07>; - // reset-gpios = <0x83 0x11 0x00>; - // num-lanes = <0x01>; - // compatible = "rockchip,rk3568-pcie\0snps,dw-pcie"; - // ranges = <0x800 0x00 0xf4000000 0x00 0xf4000000 0x00 0x100000 0x81000000 0x00 0xf4100000 0x00 0xf4100000 0x00 0x100000 0x82000000 0x00 0xf4200000 0x00 0xf4200000 0x00 0x1e00000 0xc3000000 0x03 0x00 0x03 0x00 0x00 0x40000000>; - // msi-map = <0x00 0xad 0x00 0x1000>; - // #interrupt-cells = <0x01>; - // status = "okay"; - // interrupt-names = "sys\0pmc\0msg\0legacy\0err"; - // phys = <0x24 0x02>; - // num-viewport = <0x08>; - // reg = <0x03 0xc0000000 0x00 0x400000 0x00 0xfe260000 0x00 0x10000>; - // linux,pci-domain = <0x00>; - // phandle = <0x19d>; - // reset-names = "pipe"; - // num-ib-windows = <0x06>; - - // legacy-interrupt-controller { - // #address-cells = <0x00>; - // interrupts = <0x00 0x48 0x01>; - // interrupt-parent = <0x01>; - // #interrupt-cells = <0x01>; - // phandle = <0xac>; - // interrupt-controller; - // }; - // }; + pcie@fe260000 { + power-domains = <0x22 0x0f>; + #address-cells = <0x03>; + phy-names = "pcie-phy"; + bus-range = <0x00 0x0f>; + clock-names = "aclk_mst\0aclk_slv\0aclk_dbi\0pclk\0aux"; + reg-names = "pcie-dbi\0pcie-apb"; + num-ob-windows = <0x02>; + resets = <0x20 0xa1>; + interrupts = <0x00 0x4b 0x04 0x00 0x4a 0x04 0x00 0x49 0x04 0x00 0x48 0x04 0x00 0x47 0x04>; + clocks = <0x20 0x81 0x20 0x82 0x20 0x83 0x20 0x84 0x20 0x85>; + interrupt-map = <0x00 0x00 0x00 0x01 0xac 0x00 0x00 0x00 0x00 0x02 0xac 0x01 0x00 0x00 0x00 0x03 0xac 0x02 0x00 0x00 0x00 0x04 0xac 0x03>; + #size-cells = <0x02>; + max-link-speed = <0x02>; + device_type = "pci"; + interrupt-map-mask = <0x00 0x00 0x00 0x07>; + reset-gpios = <0x83 0x11 0x00>; + num-lanes = <0x01>; + compatible = "rockchip,rk3568-pcie\0snps,dw-pcie"; + ranges = <0x800 0x00 0xf4000000 0x00 0xf4000000 0x00 0x100000 0x81000000 0x00 0xf4100000 0x00 0xf4100000 0x00 0x100000 0x82000000 0x00 0xf4200000 0x00 0xf4200000 0x00 0x1e00000 0xc3000000 0x03 0x00 0x03 0x00 0x00 0x40000000>; + msi-map = <0x00 0xad 0x00 0x1000>; + #interrupt-cells = <0x01>; + status = "okay"; + interrupt-names = "sys\0pmc\0msg\0legacy\0err"; + phys = <0x24 0x02>; + num-viewport = <0x08>; + reg = <0x03 0xc0000000 0x00 0x400000 0x00 0xfe260000 0x00 0x10000>; + linux,pci-domain = <0x00>; + phandle = <0x19d>; + reset-names = "pipe"; + num-ib-windows = <0x06>; + + legacy-interrupt-controller { + #address-cells = <0x00>; + interrupts = <0x00 0x48 0x01>; + interrupt-parent = <0x01>; + #interrupt-cells = <0x01>; + phandle = <0xac>; + interrupt-controller; + }; + }; i2c@fdd40000 { pinctrl-names = "default"; @@ -6104,49 +6104,49 @@ reset-names = "can\0can-apb"; }; - // pcie@fe270000 { - // power-domains = <0x22 0x0f>; - // vpcie3v3-supply = <0xb0>; - // #address-cells = <0x03>; - // phy-names = "pcie-phy"; - // bus-range = <0x10 0x1f>; - // clock-names = "aclk_mst\0aclk_slv\0aclk_dbi\0pclk\0aux"; - // reg-names = "pcie-dbi\0pcie-apb"; - // num-ob-windows = <0x02>; - // resets = <0x20 0xb1>; - // interrupts = <0x00 0xa0 0x04 0x00 0x9f 0x04 0x00 0x9e 0x04 0x00 0x9d 0x04 0x00 0x9c 0x04>; - // clocks = <0x20 0x88 0x20 0x89 0x20 0x8a 0x20 0x8b 0x20 0x8c>; - // interrupt-map = <0x00 0x00 0x00 0x01 0xae 0x00 0x00 0x00 0x00 0x02 0xae 0x01 0x00 0x00 0x00 0x03 0xae 0x02 0x00 0x00 0x00 0x04 0xae 0x03>; - // #size-cells = <0x02>; - // max-link-speed = <0x03>; - // device_type = "pci"; - // interrupt-map-mask = <0x00 0x00 0x00 0x07>; - // reset-gpios = <0x83 0x01 0x00>; - // num-lanes = <0x01>; - // compatible = "rockchip,rk3568-pcie\0snps,dw-pcie"; - // ranges = <0x800 0x00 0xf2000000 0x00 0xf2000000 0x00 0x100000 0x81000000 0x00 0xf2100000 0x00 0xf2100000 0x00 0x100000 0x82000000 0x00 0xf2200000 0x00 0xf2200000 0x00 0x1e00000 0xc3000000 0x03 0x40000000 0x03 0x40000000 0x00 0x40000000>; - // msi-map = <0x1000 0xad 0x1000 0x1000>; - // #interrupt-cells = <0x01>; - // status = "okay"; - // rockchip,bifurcation; - // interrupt-names = "sys\0pmc\0msg\0legacy\0err"; - // phys = <0xaf>; - // num-viewport = <0x08>; - // reg = <0x03 0xc0400000 0x00 0x400000 0x00 0xfe270000 0x00 0x10000>; - // linux,pci-domain = <0x01>; - // phandle = <0x19e>; - // reset-names = "pipe"; - // num-ib-windows = <0x06>; - - // legacy-interrupt-controller { - // #address-cells = <0x00>; - // interrupts = <0x00 0x9d 0x01>; - // interrupt-parent = <0x01>; - // #interrupt-cells = <0x01>; - // phandle = <0xae>; - // interrupt-controller; - // }; - // }; + pcie@fe270000 { + power-domains = <0x22 0x0f>; + vpcie3v3-supply = <0xb0>; + #address-cells = <0x03>; + phy-names = "pcie-phy"; + bus-range = <0x10 0x1f>; + clock-names = "aclk_mst\0aclk_slv\0aclk_dbi\0pclk\0aux"; + reg-names = "pcie-dbi\0pcie-apb"; + num-ob-windows = <0x02>; + resets = <0x20 0xb1>; + interrupts = <0x00 0xa0 0x04 0x00 0x9f 0x04 0x00 0x9e 0x04 0x00 0x9d 0x04 0x00 0x9c 0x04>; + clocks = <0x20 0x88 0x20 0x89 0x20 0x8a 0x20 0x8b 0x20 0x8c>; + interrupt-map = <0x00 0x00 0x00 0x01 0xae 0x00 0x00 0x00 0x00 0x02 0xae 0x01 0x00 0x00 0x00 0x03 0xae 0x02 0x00 0x00 0x00 0x04 0xae 0x03>; + #size-cells = <0x02>; + max-link-speed = <0x03>; + device_type = "pci"; + interrupt-map-mask = <0x00 0x00 0x00 0x07>; + reset-gpios = <0x83 0x01 0x00>; + num-lanes = <0x01>; + compatible = "rockchip,rk3568-pcie\0snps,dw-pcie"; + ranges = <0x800 0x00 0xf2000000 0x00 0xf2000000 0x00 0x100000 0x81000000 0x00 0xf2100000 0x00 0xf2100000 0x00 0x100000 0x82000000 0x00 0xf2200000 0x00 0xf2200000 0x00 0x1e00000 0xc3000000 0x03 0x40000000 0x03 0x40000000 0x00 0x40000000>; + msi-map = <0x1000 0xad 0x1000 0x1000>; + #interrupt-cells = <0x01>; + status = "okay"; + rockchip,bifurcation; + interrupt-names = "sys\0pmc\0msg\0legacy\0err"; + phys = <0xaf>; + num-viewport = <0x08>; + reg = <0x03 0xc0400000 0x00 0x400000 0x00 0xfe270000 0x00 0x10000>; + linux,pci-domain = <0x01>; + phandle = <0x19e>; + reset-names = "pipe"; + num-ib-windows = <0x06>; + + legacy-interrupt-controller { + #address-cells = <0x00>; + interrupts = <0x00 0x9d 0x01>; + interrupt-parent = <0x01>; + #interrupt-cells = <0x01>; + phandle = <0xae>; + interrupt-controller; + }; + }; hvisor_virtio_device { compatible = "hvisor"; diff --git a/platform/aarch64/rk3568/image/dts/rk3568_limit_zone0.dts b/platform/aarch64/rk3568/image/dts/rk3568_limit_zone0.dts index 5b188f0c..5687c1cc 100644 --- a/platform/aarch64/rk3568/image/dts/rk3568_limit_zone0.dts +++ b/platform/aarch64/rk3568/image/dts/rk3568_limit_zone0.dts @@ -18,6 +18,290 @@ mmc3 = "/dwmmc@fe000000"; }; + syscon@fdc50000 { + compatible = "rockchip,rk3568-pipegrf\0syscon"; + reg = <0x00 0xfdc50000 0x00 0x1000>; + phandle = <0x10d>; + }; + + syscon@fdc90000 { + compatible = "rockchip,pipe-phy-grf\0syscon"; + reg = <0x00 0xfdc90000 0x00 0x1000>; + phandle = <0x110>; + }; + + phy@fe840000 { + rockchip,pipe-grf = <0x10d>; + clock-names = "refclk\0apbclk\0pipe_clk"; + assigned-clocks = <0x33 0x25>; + assigned-clock-rates = <0x5f5e100>; + resets = <0x20 0x1c8 0x20 0x1c9>; + clocks = <0x33 0x25 0x20 0x17e 0x20 0x7f>; + #phy-cells = <0x01>; + compatible = "rockchip,rk3568-naneng-combphy"; + status = "okay"; + rockchip,pipe-phy-grf = <0x110>; + reg = <0x00 0xfe840000 0x00 0x100>; + phandle = <0x24>; + reset-names = "combphy-apb\0combphy"; + }; + + power-management@fdd90000 { + compatible = "rockchip,rk3568-pmu\0syscon\0simple-mfd"; + reg = <0x00 0xfdd90000 0x00 0x1000>; + phandle = <0x177>; + + power-controller { + #address-cells = <0x01>; + #size-cells = <0x00>; + #power-domain-cells = <0x01>; + compatible = "rockchip,rk3568-power-controller"; + status = "okay"; + phandle = <0x22>; + + pd_pipe@15 { + clocks = <0x20 0x7f>; + reg = <0x0f>; + pm_qos = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f 0x60 0x61>; + }; + + pd_vi@8 { + clocks = <0x20 0xcc 0x20 0xcd>; + reg = <0x08>; + pm_qos = <0x49 0x4a 0x4b>; + }; + + pd_rkvenc@14 { + clocks = <0x20 0x102>; + reg = <0x0e>; + pm_qos = <0x57 0x58 0x59>; + }; + + pd_rga@10 { + clocks = <0x20 0xf1 0x20 0xf2>; + reg = <0x0a>; + pm_qos = <0x4f 0x50 0x51 0x52 0x53 0x54>; + }; + + pd_vpu@11 { + clocks = <0x20 0xed>; + reg = <0x0b>; + pm_qos = <0x55>; + }; + + pd_gpu@7 { + clocks = <0x20 0x19 0x20 0x1a>; + reg = <0x07>; + pm_qos = <0x48>; + }; + + pd_rkvdec@13 { + clocks = <0x20 0x107>; + reg = <0x0d>; + pm_qos = <0x56>; + }; + + pd_vo@9 { + clocks = <0x20 0xda 0x20 0xdb 0x20 0xdc>; + reg = <0x09>; + pm_qos = <0x4c 0x4d 0x4e>; + }; + + pd_npu@6 { + clocks = <0x20 0x27 0x20 0x25 0x20 0x26>; + reg = <0x06>; + pm_qos = <0x47>; + }; + }; + }; + + dc-12v { + regulator-max-microvolt = <0xb71b00>; + regulator-boot-on; + regulator-always-on; + regulator-min-microvolt = <0xb71b00>; + regulator-name = "dc_12v"; + compatible = "regulator-fixed"; + phandle = <0x131>; + }; + + vcc3v3_pcie2-regulator { + regulator-max-microvolt = <0x325aa0>; + regulator-boot-on; + gpio = <0x38 0x17 0x00>; + regulator-always-on; + enable-active-high; + regulator-min-microvolt = <0x325aa0>; + regulator-name = "vcc3v3_pcie2"; + startup-delay-us = <0x1388>; + compatible = "regulator-fixed"; + phandle = <0x1ea>; + vin-supply = <0x131>; + }; + + + // pcie@fe260000 { + // power-domains = <0x22 0x0f>; + // #address-cells = <0x03>; + // phy-names = "pcie-phy"; + // bus-range = <0x00 0x0f>; + // clock-names = "aclk_mst\0aclk_slv\0aclk_dbi\0pclk\0aux"; + // reg-names = "pcie-dbi\0pcie-apb"; + // num-ob-windows = <0x02>; + // resets = <0x20 0xa1>; + // interrupts = <0x00 0x4b 0x04 0x00 0x4a 0x04 0x00 0x49 0x04 0x00 0x48 0x04 0x00 0x47 0x04>; + // clocks = <0x20 0x81 0x20 0x82 0x20 0x83 0x20 0x84 0x20 0x85>; + // interrupt-map = <0x00 0x00 0x00 0x01 0xac 0x00 0x00 0x00 0x00 0x02 0xac 0x01 0x00 0x00 0x00 0x03 0xac 0x02 0x00 0x00 0x00 0x04 0xac 0x03>; + // #size-cells = <0x02>; + // max-link-speed = <0x02>; + // device_type = "pci"; + // interrupt-map-mask = <0x00 0x00 0x00 0x07>; + // reset-gpios = <0x83 0x11 0x00>; + // num-lanes = <0x01>; + // compatible = "rockchip,rk3568-pcie\0snps,dw-pcie"; + // ranges = <0x800 0x00 0xf4000000 0x00 0xf4000000 0x00 0x100000 0x81000000 0x00 0xf4100000 0x00 0xf4100000 0x00 0x100000 0x82000000 0x00 0xf4200000 0x00 0xf4200000 0x00 0x1e00000 0xc3000000 0x03 0x00 0x03 0x00 0x00 0x40000000>; + // msi-map = <0x00 0xad 0x00 0x1000>; + // #interrupt-cells = <0x01>; + // status = "okay"; + // interrupt-names = "sys\0pmc\0msg\0legacy\0err"; + // phys = <0x24 0x02>; + // num-viewport = <0x08>; + // reg = <0x03 0xc0000000 0x00 0x400000 0x00 0xfe260000 0x00 0x10000>; + // linux,pci-domain = <0x00>; + // phandle = <0x19d>; + // reset-names = "pipe"; + // num-ib-windows = <0x06>; + + // legacy-interrupt-controller { + // #address-cells = <0x00>; + // interrupts = <0x00 0x48 0x01>; + // interrupt-parent = <0x01>; + // #interrupt-cells = <0x01>; + // phandle = <0xac>; + // interrupt-controller; + // }; + // }; + + syscon@fdcb8000 { + compatible = "rockchip,pcie30-phy-grf\0syscon"; + reg = <0x00 0xfdcb8000 0x00 0x10000>; + phandle = <0x116>; + }; + + phy@fe8c0000 { + clock-names = "refclk_m\0refclk_n\0pclk"; + resets = <0x20 0x1be>; + clocks = <0x33 0x26 0x33 0x27 0x20 0x177>; + #phy-cells = <0x00>; + compatible = "rockchip,rk3568-pcie3-phy"; + status = "okay"; + reg = <0x00 0xfe8c0000 0x00 0x20000>; + phandle = <0xaf>; + reset-names = "phy"; + rockchip,phy-grf = <0x116>; + }; + + vcc3v3_pcie-regulator { + regulator-max-microvolt = <0x325aa0>; + regulator-boot-on; + gpio = <0x38 0x1c 0x00>; + regulator-always-on; + enable-active-high; + regulator-min-microvolt = <0x325aa0>; + regulator-name = "vcc3v3_pcie"; + startup-delay-us = <0x3e8>; + compatible = "regulator-fixed"; + phandle = <0xb0>; + vin-supply = <0x131>; + }; + + pcie@fe270000 { + power-domains = <0x22 0x0f>; + vpcie3v3-supply = <0xb0>; + #address-cells = <0x03>; + phy-names = "pcie-phy"; + bus-range = <0x10 0x1f>; + clock-names = "aclk_mst\0aclk_slv\0aclk_dbi\0pclk\0aux"; + reg-names = "pcie-dbi\0pcie-apb"; + num-ob-windows = <0x02>; + resets = <0x20 0xb1>; + interrupts = <0x00 0xa0 0x04 0x00 0x9f 0x04 0x00 0x9e 0x04 0x00 0x9d 0x04 0x00 0x9c 0x04>; + clocks = <0x20 0x88 0x20 0x89 0x20 0x8a 0x20 0x8b 0x20 0x8c>; + interrupt-map = <0x00 0x00 0x00 0x01 0xae 0x00 0x00 0x00 0x00 0x02 0xae 0x01 0x00 0x00 0x00 0x03 0xae 0x02 0x00 0x00 0x00 0x04 0xae 0x03>; + #size-cells = <0x02>; + max-link-speed = <0x03>; + device_type = "pci"; + interrupt-map-mask = <0x00 0x00 0x00 0x07>; + reset-gpios = <0x83 0x01 0x00>; + num-lanes = <0x01>; + compatible = "rockchip,rk3568-pcie\0snps,dw-pcie"; + ranges = <0x800 0x00 0xf2000000 0x00 0xf2000000 0x00 0x100000 0x81000000 0x00 0xf2100000 0x00 0xf2100000 0x00 0x100000 0x82000000 0x00 0xf2200000 0x00 0xf2200000 0x00 0x1e00000 0xc3000000 0x03 0x40000000 0x03 0x40000000 0x00 0x40000000>; + msi-map = <0x1000 0xad 0x1000 0x1000>; + #interrupt-cells = <0x01>; + status = "okay"; + rockchip,bifurcation; + interrupt-names = "sys\0pmc\0msg\0legacy\0err"; + phys = <0xaf>; + num-viewport = <0x08>; + reg = <0x03 0xc0400000 0x00 0x400000 0x00 0xfe270000 0x00 0x10000>; + linux,pci-domain = <0x01>; + phandle = <0x19e>; + reset-names = "pipe"; + num-ib-windows = <0x06>; + + legacy-interrupt-controller { + #address-cells = <0x00>; + interrupts = <0x00 0x9d 0x01>; + interrupt-parent = <0x01>; + #interrupt-cells = <0x01>; + phandle = <0xae>; + interrupt-controller; + }; + }; + + // pcie@fe280000 { + // power-domains = <0x22 0x0f>; + // vpcie3v3-supply = <0xb0>; + // #address-cells = <0x03>; + // phy-names = "pcie-phy"; + // bus-range = <0x20 0x2f>; + // clock-names = "aclk_mst\0aclk_slv\0aclk_dbi\0pclk\0aux"; + // reg-names = "pcie-dbi\0pcie-apb"; + // num-ob-windows = <0x02>; + // resets = <0x20 0xc1>; + // interrupts = <0x00 0xa5 0x04 0x00 0xa4 0x04 0x00 0xa3 0x04 0x00 0xa2 0x04 0x00 0xa1 0x04>; + // clocks = <0x20 0x8f 0x20 0x90 0x20 0x91 0x20 0x92 0x20 0x93>; + // interrupt-map = <0x00 0x00 0x00 0x01 0xb1 0x00 0x00 0x00 0x00 0x02 0xb1 0x01 0x00 0x00 0x00 0x03 0xb1 0x02 0x00 0x00 0x00 0x04 0xb1 0x03>; + // #size-cells = <0x02>; + // max-link-speed = <0x03>; + // device_type = "pci"; + // interrupt-map-mask = <0x00 0x00 0x00 0x07>; + // reset-gpios = <0xb2 0x1e 0x00>; + // num-lanes = <0x02>; + // compatible = "rockchip,rk3568-pcie\0snps,dw-pcie"; + // ranges = <0x800 0x00 0xf0000000 0x00 0xf0000000 0x00 0x100000 0x81000000 0x00 0xf0100000 0x00 0xf0100000 0x00 0x100000 0x82000000 0x00 0xf0200000 0x00 0xf0200000 0x00 0x1e00000 0xc3000000 0x03 0x80000000 0x03 0x80000000 0x00 0x40000000>; + // msi-map = <0x2000 0xad 0x2000 0x1000>; + // #interrupt-cells = <0x01>; + // status = "okay"; + // interrupt-names = "sys\0pmc\0msg\0legacy\0err"; + // phys = <0xaf>; + // num-viewport = <0x08>; + // reg = <0x03 0xc0800000 0x00 0x400000 0x00 0xfe280000 0x00 0x10000>; + // linux,pci-domain = <0x02>; + // phandle = <0x19f>; + // reset-names = "pipe"; + // num-ib-windows = <0x06>; + + // legacy-interrupt-controller { + // #address-cells = <0x00>; + // interrupts = <0x00 0xa2 0x01>; + // interrupt-parent = <0x01>; + // #interrupt-cells = <0x01>; + // phandle = <0xb1>; + // interrupt-controller; + // }; + // }; + sdhci@fe310000 { clock-names = "core\0bus\0axi\0block\0timer"; assigned-clocks = <0x20 0x7b 0x20 0x7d 0x20 0x7c>; @@ -123,9 +407,9 @@ ftrace-size = <0x00>; }; - hvisor@280000 { + hvisor@60080000 { no-map; - reg = <0x00 0x280000 0x00 0x400000>; + reg = <0x00 0x60080000 0x00 0x400000>; }; nonroot { @@ -357,13 +641,13 @@ phandle = <0x01>; interrupt-controller; - // interrupt-controller@fd440000 { - // msi-controller; - // compatible = "arm,gic-v3-its"; - // reg = <0x00 0xfd440000 0x00 0x20000>; - // phandle = <0xad>; - // #msi-cells = <0x01>; - // }; + interrupt-controller@fd440000 { + msi-controller; + compatible = "arm,gic-v3-its"; + reg = <0x00 0xfd440000 0x00 0x20000>; + phandle = <0xad>; + #msi-cells = <0x01>; + }; }; @@ -1347,6 +1631,7 @@ chosen { // 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 systemd.mask=NetworkManager.service"; bootargs = "storagemedia=emmc rw rootwait earlycon=uart8250,mmio32,0xfe660000 console=ttyFIQ0 root=/dev/mmcblk0p5"; phandle = <0x1eb>; }; diff --git a/platform/loongarch64/ls3a5000/cargo/features b/platform/loongarch64/ls3a5000/cargo/features index a4727de5..2e4766e6 100644 --- a/platform/loongarch64/ls3a5000/cargo/features +++ b/platform/loongarch64/ls3a5000/cargo/features @@ -1,4 +1,5 @@ loongson_3a5000 loongson_7a2000 loongson_uart -pci \ No newline at end of file + +loongarch64_pcie \ No newline at end of file diff --git a/platform/loongarch64/ls3a6000/cargo/features b/platform/loongarch64/ls3a6000/cargo/features index e2e853ee..f047773e 100644 --- a/platform/loongarch64/ls3a6000/cargo/features +++ b/platform/loongarch64/ls3a6000/cargo/features @@ -1,4 +1,5 @@ loongson_3a6000 loongson_7a2000 loongson_uart -pci \ No newline at end of file + +loongarch64_pcie \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index 49dc9303..d8b892c1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -55,6 +55,8 @@ pub struct HvPciConfig { pub mem64_base: u64, pub mem64_size: u64, pub pci_mem64_base: u64, + pub bus_range_begin: u32, + pub bus_range_end: u32, } impl HvPciConfig { @@ -71,6 +73,8 @@ impl HvPciConfig { mem64_base: 0, mem64_size: 0, pci_mem64_base: 0, + bus_range_begin: 0, + bus_range_end: 0, } } } @@ -166,6 +170,10 @@ impl HvZoneConfig { pub fn ivc_config(&self) -> &[HvIvcConfig] { &self.ivc_configs[..self.num_ivc_configs as usize] } + + pub fn pci_config(&self) -> &[HvPciConfig] { + &self.pci_config[..self.num_pci_bus as usize] + } } pub static mut HV_ROOT_ZONE_CONFIG: Once = Once::new(); diff --git a/src/main.rs b/src/main.rs index 36bb145a..8622775c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -71,6 +71,7 @@ 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}; @@ -136,7 +137,11 @@ fn primary_init_early() { let root_config = root_zone_config(); - let _ = hvisor_pci_init(&root_config.pci_config); + #[cfg(feature = "pci")] + if root_config.num_pci_bus > 0 { + let num_pci_bus = root_config.num_pci_bus as usize; + let _ = hvisor_pci_init(&root_config.pci_config[..num_pci_bus]); + } #[cfg(not(test))] { diff --git a/src/pci/config_accessors/dwc.rs b/src/pci/config_accessors/dwc.rs new file mode 100644 index 00000000..38f4f647 --- /dev/null +++ b/src/pci/config_accessors/dwc.rs @@ -0,0 +1,137 @@ +// 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 crate::error::{HvResult, HvErrorNum::*}; +use crate::pci::{pci_access::{PciRW, PciRWBase}, pci_struct::Bdf, PciConfigAddress}; +use alloc::sync::Arc; +use spin::Mutex; +use super::{PciConfigAccessor, PciRegion, PciConfigMmio, PciRegionMmio}; +use super::dwc_atu::{AtuUnroll, AtuConfig, ATU_TYPE_CFG0, ATU_TYPE_CFG1}; + +#[cfg(feature = "dwc_pcie")] +impl PciRegion for PciConfigMmio { + fn read_u8(&self, _offset: PciConfigAddress) -> HvResult { + unimplemented!() + } + fn write_u8(&self, _offset: PciConfigAddress, _value: u8) -> HvResult { + unimplemented!() + } + fn read_u16(&self, _offset: PciConfigAddress) -> HvResult { + unimplemented!() + } + fn write_u16(&self, _offset: PciConfigAddress, _value: u16) -> HvResult { + unimplemented!() + } + fn read_u32(&self, _offset: PciConfigAddress) -> HvResult { + unimplemented!() + } + fn write_u32(&self, _offset: PciConfigAddress, _value: u32) -> HvResult { + unimplemented!() + } +} + +// DWC PCIe region types +#[repr(u32)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum DwcRegionType { + Dbi = 0, + Apb = 1, + Cfg0 = 2, + Cfg1 = 3, +} + +impl DwcRegionType { + pub fn as_usize(self) -> usize { + self as usize + } +} + +// DWC PCIe configuration region structure +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct DwcConfigRegion { + pub region_type: DwcRegionType, + pub physical_start: u64, + pub size: u64, +} + +pub struct DwcConfigRegionBackend(PciRegionMmio); + +impl PciRWBase for DwcConfigRegionBackend { + fn backend(&self) -> &dyn PciRegion { + &self.0 + } +} +impl PciRW for DwcConfigRegionBackend {} + +#[derive(Debug)] +pub struct DwcConfigAccessor { + dbi_backend: Arc, + cfg0_backend: Arc, + cfg1_backend: Arc, + apb_backend: Option>, +} + +impl DwcConfigAccessor { + pub fn new(regions: [DwcConfigRegion; 4]) -> Self { + let mut dbi_backend = None; + let mut cfg0_backend = None; + let mut cfg1_backend = None; + let mut apb_backend = None; + + for region in regions.iter() { + let mmio = PciRegionMmio::new(region.physical_start as PciConfigAddress, region.size); + let backend = Arc::new(DwcConfigRegionBackend(mmio)) as Arc; + + match region.region_type { + DwcRegionType::Dbi => { + dbi_backend = Some(backend); + } + DwcRegionType::Cfg0 => { + cfg0_backend = Some(backend); + } + DwcRegionType::Cfg1 => { + cfg1_backend = Some(backend); + } + DwcRegionType::Apb => { + apb_backend = Some(backend); + } + } + } + + Self { + dbi_backend: dbi_backend.expect("DBI backend is required"), + cfg0_backend: cfg0_backend.expect("CFG0 backend is required"), + cfg1_backend: cfg1_backend.expect("CFG1 backend is required"), + apb_backend, + } + } +} + +impl PciConfigAccessor for DwcConfigAccessor { + fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress) -> HvResult { + + } + + fn prepare_access(&self, bdf: Bdf) -> HvResult { + + } + + fn get_base_address(&self) -> PciConfigAddress { + + } +} + diff --git a/src/pci/config_accessors/dwc_atu.rs b/src/pci/config_accessors/dwc_atu.rs new file mode 100644 index 00000000..f1114fe5 --- /dev/null +++ b/src/pci/config_accessors/dwc_atu.rs @@ -0,0 +1,107 @@ +// 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 crate::error::{HvResult, HvErrorNum::*}; +use crate::pci::{pci_access::PciRW, PciConfigAddress}; + +// DWC PCIe ATU (Address Translation Unit) register offsets +// Unroll registers are used for unrolled ATU regions +pub const ATU_BASE: usize = 0x300000; +pub const ATU_REGION_SIZE: usize = 0x200; +pub const PCIE_ATU_UNR_REGION_CTRL1: usize = 0x00; // Type of the region +pub const PCIE_ATU_UNR_REGION_CTRL2: usize = 0x04; // Write 0x80000000 to enable +pub const PCIE_ATU_UNR_LOWER_BASE: usize = 0x08; // CPU lower address (32bit) +pub const PCIE_ATU_UNR_UPPER_BASE: usize = 0x0C; // CPU upper address (32bit) +pub const PCIE_ATU_UNR_LIMIT: usize = 0x10; // Region limit (lower 32 bit of (cpu_addr + size - 1)) +pub const PCIE_ATU_UNR_LOWER_TARGET: usize = 0x14; // PCI lower address +pub const PCIE_ATU_UNR_UPPER_TARGET: usize = 0x18; // PCI upper address + +// ATU region type constants +pub const ATU_TYPE_CFG0: u32 = 0x4; // CFG0 Type +pub const ATU_TYPE_CFG1: u32 = 0x5; // CFG1 Type +pub const ATU_TYPE_MEM: u32 = 0x0; // Memory Type +pub const ATU_TYPE_IO: u32 = 0x2; // IO Type + +// ATU enable bit +pub const ATU_ENABLE_BIT: u32 = 0x80000000; + +// ATU configuration parameters +#[derive(Debug, Clone, Copy)] +pub struct AtuConfig { + pub index: usize, + pub atu_type: u32, + pub cpu_base: PciConfigAddress, + pub cpu_limit: PciConfigAddress, + pub pci_target: PciConfigAddress, +} + +impl AtuConfig { + pub fn new( + index: usize, + atu_type: u32, + cpu_base: PciConfigAddress, + cpu_size: PciConfigAddress, + pci_target: PciConfigAddress, + ) -> Self { + let cpu_limit = cpu_base + cpu_size - 1; + Self { + index, + atu_type, + cpu_base, + cpu_limit, + pci_target, + } + } +} + +// ATU unroll configuration functions +pub struct AtuUnroll; + +impl AtuUnroll { + // Configure ATU region using unroll registers + // Follows the same order as Linux kernel dw_pcie_prog_outbound_atu_unroll + pub fn configure_region( + dbi_backend: &dyn PciRW, + config: &AtuConfig, + ) -> HvResult { + let atu_base = (ATU_BASE + config.index * ATU_REGION_SIZE) as PciConfigAddress; + + dbi_backend.write(atu_base + PCIE_ATU_UNR_LOWER_BASE as PciConfigAddress, 4, (config.cpu_base & 0xffffffff) as usize)?; + dbi_backend.write(atu_base + PCIE_ATU_UNR_UPPER_BASE as PciConfigAddress, 4, (config.cpu_base >> 32) as usize)?; + dbi_backend.write(atu_base + PCIE_ATU_UNR_LIMIT as PciConfigAddress, 4, (config.cpu_limit & 0xffffffff) as usize)?; + dbi_backend.write(atu_base + PCIE_ATU_UNR_LOWER_TARGET as PciConfigAddress, 4, (config.pci_target & 0xffffffff) as usize)?; + dbi_backend.write(atu_base + PCIE_ATU_UNR_UPPER_TARGET as PciConfigAddress, 4, (config.pci_target >> 32) as usize)?; + dbi_backend.write(atu_base + PCIE_ATU_UNR_REGION_CTRL1 as PciConfigAddress, 4, config.atu_type as usize)?; + dbi_backend.write(atu_base + PCIE_ATU_UNR_REGION_CTRL2 as PciConfigAddress, 4, ATU_ENABLE_BIT as usize)?; + + // Verify that ATU enable takes effect before any subsequent config and I/O accesses + const MAX_RETRIES: usize = 5; + const RETRY_DELAY_ITERATIONS: usize = 10; + + for _ in 0..MAX_RETRIES { + let val = dbi_backend.read(atu_base + PCIE_ATU_UNR_REGION_CTRL2 as PciConfigAddress, 4)?; + if (val as u32) & ATU_ENABLE_BIT != 0 { + return Ok(()); + } + for _ in 0..RETRY_DELAY_ITERATIONS { + core::hint::spin_loop(); + } + } + + hv_result_err!(EBUSY, "Outbound iATU is not being enabled") + } +} + diff --git a/src/pci/pci_mem.rs b/src/pci/config_accessors/ecam.rs similarity index 53% rename from src/pci/pci_mem.rs rename to src/pci/config_accessors/ecam.rs index e2240d3f..882ecea5 100644 --- a/src/pci/pci_mem.rs +++ b/src/pci/config_accessors/ecam.rs @@ -13,39 +13,51 @@ // // Authors: // -use core::{any::Any, fmt::Debug}; use crate::error::HvResult; -use crate::pci::PciConfigAddress; +use crate::pci::{pci_struct::Bdf, PciConfigAddress}; +use super::{PciConfigAccessor, PciRegion, PciConfigMmio}; -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; +// ECAM (Enhanced Configuration Access Mechanism) accessor implementation +// Standard ECAM mechanism used by most PCIe platforms +#[derive(Debug)] +pub struct EcamConfigAccessor { + ecam_base: PciConfigAddress, } -/* 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 EcamConfigAccessor { + pub fn new(ecam_base: PciConfigAddress) -> Self { + Self { ecam_base } + } } -impl PciRegionMmio { - pub fn new(base: PciConfigAddress, length: u64) -> Self { - Self { base, length } +impl PciConfigAccessor for EcamConfigAccessor { + fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress) -> HvResult { + let bus = bdf.bus() as PciConfigAddress; + let device = bdf.device() as PciConfigAddress; + let function = bdf.function() as PciConfigAddress; + + // ECAM standard address calculation: + // base + (bus << 20) + (device << 15) + (function << 12) + offset + let address = self.ecam_base + + (bus << 20) + + (device << 15) + + (function << 12) + + offset; + Ok(address) + } + + fn prepare_access(&self, _bdf: Bdf) -> HvResult { + Ok(()) // ECAM doesn't need special preparation } - /* TODO: may here need check whether length exceeds*/ - fn access(&self, offset: PciConfigAddress) -> *mut T { - (self.base + offset) as *mut T + + fn get_base_address(&self) -> PciConfigAddress { + self.ecam_base } } -impl PciRegion for PciRegionMmio { +#[cfg(any(feature = "ecam_pcie", all(not(feature = "dwc_pcie"), not(feature = "loongarch64_pcie"))))] +impl PciRegion for PciConfigMmio { fn read_u8(&self, offset: PciConfigAddress) -> HvResult { unsafe { Ok(self.access::(offset).read_volatile() as u8) } } @@ -68,3 +80,4 @@ impl PciRegion for PciRegionMmio { Ok(()) } } + diff --git a/src/pci/config_accessors/loongarch64.rs b/src/pci/config_accessors/loongarch64.rs new file mode 100644 index 00000000..f1601a3c --- /dev/null +++ b/src/pci/config_accessors/loongarch64.rs @@ -0,0 +1,69 @@ +// 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 crate::error::HvResult; +use crate::pci::{pci_struct::Bdf, PciConfigAddress}; +use super::{PciConfigAccessor, PciRegion, PciConfigMmio}; + +#[cfg(feature = "loongarch64_pcie")] +impl PciRegion for PciConfigMmio { + fn read_u8(&self, _offset: PciConfigAddress) -> HvResult { + unimplemented!() + } + fn write_u8(&self, _offset: PciConfigAddress, _value: u8) -> HvResult { + unimplemented!() + } + fn read_u16(&self, _offset: PciConfigAddress) -> HvResult { + unimplemented!() + } + fn write_u16(&self, _offset: PciConfigAddress, _value: u16) -> HvResult { + unimplemented!() + } + fn read_u32(&self, _offset: PciConfigAddress) -> HvResult { + unimplemented!() + } + fn write_u32(&self, _offset: PciConfigAddress, _value: u32) -> HvResult { + unimplemented!() + } +} + +// LoongArch PCIe accessor implementation +// Similar to ECAM, uses standard address calculation +#[derive(Debug)] +pub struct LoongArchConfigAccessor { + cfg_base: PciConfigAddress, +} + +impl LoongArchConfigAccessor { + pub fn new(cfg_base: PciConfigAddress) -> Self { + Self { cfg_base } + } +} + +impl PciConfigAccessor for LoongArchConfigAccessor { + fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress) -> HvResult { + + } + + fn prepare_access(&self, _bdf: Bdf) -> HvResult { + + } + + fn get_base_address(&self) -> PciConfigAddress { + + } +} + diff --git a/src/pci/config_accessors/mod.rs b/src/pci/config_accessors/mod.rs new file mode 100644 index 00000000..e99fadfb --- /dev/null +++ b/src/pci/config_accessors/mod.rs @@ -0,0 +1,156 @@ +// 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; +use crate::pci::{pci_struct::Bdf, PciConfigAddress}; +use alloc::sync::Arc; + +// PCIe region trait for memory-mapped I/O access +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 PciConfigMmio { + base: PciConfigAddress, + #[allow(dead_code)] + length: u64, +} + +impl PciConfigMmio { + pub fn new(base: PciConfigAddress, length: u64) -> Self { + Self { base, length } + } + /* TODO: may here need check whether length exceeds*/ + pub(crate) fn access(&self, offset: PciConfigAddress) -> *mut T { + (self.base + offset) as *mut T + } +} + +/* PCIe region MMIO for general memory-mapped I/O regions */ +#[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*/ + pub(crate) 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(()) + } +} + +// PCIe config space accessor trait +// Unified interface for different PCIe mechanisms (ECAM, DWC, LoongArch) +pub trait PciConfigAccessor: Send + Sync + core::fmt::Debug { + // Get physical address from BDF and offset + fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress) -> HvResult; + + // Prepare access before reading/writing (e.g., configure ATU) + fn prepare_access(&self, bdf: Bdf) -> HvResult; + + // Get base address of config space + fn get_base_address(&self) -> PciConfigAddress; +} + +// Accessor type enum +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum PciAccessorType { + Ecam, + Dwc, + LoongArch, +} + +// Factory function to create accessor based on feature flag +pub fn create_accessor( + accessor_type: PciAccessorType, + ecam_base: PciConfigAddress, +) -> Arc { + match accessor_type { + PciAccessorType::Ecam => Arc::new(ecam::EcamConfigAccessor::new(ecam_base)), + PciAccessorType::Dwc => Arc::new(ecam::EcamConfigAccessor::new(ecam_base)), + PciAccessorType::LoongArch => Arc::new(ecam::EcamConfigAccessor::new(ecam_base)), + } +} + +// Get default accessor type based on current features +pub fn get_default_accessor_type() -> PciAccessorType { + #[cfg(feature = "dwc_pcie")] + return PciAccessorType::Dwc; + + #[cfg(feature = "loongarch64_pcie")] + return PciAccessorType::LoongArch; + + #[cfg(feature = "ecam_pcie")] + return PciAccessorType::Ecam; + + #[cfg(all(not(feature = "ecam_pcie"), not(feature = "dwc_pcie"), not(feature = "loongarch64_pcie")))] + return PciAccessorType::Ecam; // Default to ECAM +} + +// Export accessor implementations +#[cfg(feature = "ecam_pcie")] +pub mod ecam; + +#[cfg(feature = "dwc_pcie")] +pub mod dwc; +#[cfg(feature = "dwc_pcie")] +pub mod dwc_atu; + +#[cfg(feature = "loongarch64_pcie")] +pub mod loongarch64; + +// Default ECAM implementation when no feature is specified +#[cfg(all(not(feature = "ecam_pcie"), not(feature = "dwc_pcie"), not(feature = "loongarch64_pcie")))] +pub mod ecam; + diff --git a/src/pci/mod.rs b/src/pci/mod.rs index 02c3259e..2bc0e902 100644 --- a/src/pci/mod.rs +++ b/src/pci/mod.rs @@ -16,8 +16,8 @@ pub mod mem_alloc; pub mod pci_access; pub mod pci_config; -pub mod pci_mem; pub mod pci_struct; +pub mod config_accessors; // pub mod vpci_dtb; pub mod pci_test; diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index d80bf10e..859c48ab 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -32,7 +32,7 @@ use crate::{ }; use super::{ - pci_mem::{PciRegion, PciRegionMmio}, + config_accessors::{PciRegion, PciConfigMmio}, pci_struct::Bdf, PciConfigAddress, }; @@ -146,12 +146,12 @@ impl PciMem { } } - pub fn new_io(value: u64) -> Self { + pub fn new_io(value: u64, size: u64) -> Self { Self { bar_type: PciMemType::Io, virtual_value: 0, value, - size: 0, + size, prefetchable: false, size_read: false, } @@ -499,7 +499,7 @@ pub trait PciHeaderRW: PciRWBase { } fn has_multiple_functions(&self) -> bool { - self.backend().read_u8(0x0c).unwrap().get_bit(7) + self.backend().read_u8(0x0e).unwrap().get_bit(7) } fn revision_and_class(&self) -> (DeviceRevision, BaseClass, SubClass, Interface) { @@ -598,7 +598,20 @@ pub trait PciBarRW: PciRWBase { } } } else { - bararr[slot as usize] = PciMem::new_io(value as u64); + let size = { + let _ = self.write_bar(slot, 0xffffffff); + let mut readback = self.read_bar(slot).unwrap(); + let _ = self.write_bar(slot, readback as u32); + + readback.set_bit(0, false); + if readback == 0x0 { + slot += 1; + continue; + } + + 1 << readback.trailing_zeros() + }; + bararr[slot as usize] = PciMem::new_io(value as u64, size as u64); } slot += 1; } @@ -655,7 +668,7 @@ pub trait PciRomRW: PciRWBase { * +--------------+--------------+---------------+--------------+ */ #[derive(Debug, Clone)] -pub struct PciConfigHeader(PciRegionMmio); +pub struct PciConfigHeader(PciConfigMmio); impl PciRWBase for PciConfigHeader { fn backend(&self) -> &dyn PciRegion { @@ -666,7 +679,7 @@ impl PciRW for PciConfigHeader {} impl PciHeaderRW for PciConfigHeader {} impl PciConfigHeader { - pub fn new_with_region(region: PciRegionMmio) -> Self { + pub fn new_with_region(region: PciConfigMmio) -> Self { PciConfigHeader(region) } } @@ -766,7 +779,7 @@ impl EndpointField { } #[derive(Debug, Clone)] -pub struct EndpointHeader(PciRegionMmio); +pub struct EndpointHeader(PciConfigMmio); impl PciRWBase for EndpointHeader { fn backend(&self) -> &dyn PciRegion { @@ -787,7 +800,7 @@ impl PciRomRW for EndpointHeader { } impl EndpointHeader { - pub fn new_with_region(region: PciRegionMmio) -> Self { + pub fn new_with_region(region: PciConfigMmio) -> Self { EndpointHeader(region) } } @@ -907,7 +920,7 @@ impl BridgeField { } #[derive(Debug, Clone)] -pub struct PciBridgeHeader(PciRegionMmio); +pub struct PciBridgeHeader(PciConfigMmio); impl PciRWBase for PciBridgeHeader { fn backend(&self) -> &dyn PciRegion { @@ -928,7 +941,7 @@ impl PciRomRW for PciBridgeHeader { } impl PciBridgeHeader { - pub fn new_with_region(region: PciRegionMmio) -> Self { + pub fn new_with_region(region: PciConfigMmio) -> Self { PciBridgeHeader(region) } } @@ -951,7 +964,7 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { let mut dev = None; for node in vbus.devs().iter_mut() { if node.1.get_vbdf() == vbdf { - debug!("vbdf find {:#?}", vbdf); + info!("vbdf find {:#?}", vbdf); dev = Some(node.1); break; } @@ -960,7 +973,7 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { if let Some(dev) = dev { match dev.access(offset, size) { false => { - debug!( + info!( "hw vbdf {:#?} reg 0x{:x} try {} {}", vbdf, offset, @@ -978,7 +991,7 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { } } true => { - debug!( + info!( "emu vbdf {:#?} reg 0x{:x} try {} {}", vbdf, offset, @@ -1118,7 +1131,7 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { } } } else { - debug!("not found dev"); + info!("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) { @@ -1133,7 +1146,7 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { } } - debug!( + info!( "vbdf {:#?} reg 0x{:x} {} 0x{:x}", vbdf, offset, diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 8838a770..91370486 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -17,14 +17,11 @@ use alloc::collections::btree_map::BTreeMap; use spin::{Lazy, Mutex}; use crate::{ - config::{HvPciConfig, HvPciDevConfig, CONFIG_MAX_PCI_DEV, CONFIG_PCI_BUS_MAXNUM}, - error::HvResult, - pci::{ + config::{HvPciConfig, HvPciDevConfig, CONFIG_MAX_PCI_DEV, CONFIG_PCI_BUS_MAXNUM}, error::HvResult, memory::{mmio_perform_access, MMIOAccess}, pci::{ mem_alloc::BaseAllocator, pci_access::mmio_vpci_handler, pci_struct::{Bdf, VirtualPciConfigSpace}, - }, - zone::Zone, + }, zone::Zone }; use super::pci_struct::RootComplex; @@ -35,12 +32,15 @@ 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_MAXNUM]) -> HvResult { - for rootcomplex_config in pci_rootcomplex_config { +pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { + warn!("begin {:#?}", pci_config); + for rootcomplex_config in pci_config { /* empty config */ if rootcomplex_config.ecam_base == 0 { + warn!("empty pcie config"); continue; } + let mut allocator = BaseAllocator::default(); allocator.set_mem32( rootcomplex_config.pci_mem32_base as u32, @@ -51,9 +51,37 @@ pub fn hvisor_pci_init(pci_rootcomplex_config: &[HvPciConfig; CONFIG_PCI_BUS_MAX rootcomplex_config.mem64_size, ); - let mut rootcomplex = RootComplex::new(rootcomplex_config.ecam_base); - for mut node in rootcomplex.enumerate(None, Some(allocator)) { - node.capability_enumerate(); + let mut rootcomplex = { + #[cfg(feature = "dwc_pcie")] + { + warn!("dwc pcie"); + // DWC PCIe: need dbi_base, cfg_base, etc. + // Get DWC related parameters from config + // Use ecam_base as dbi_base for now, should read from config + let dbi_base = 0x3c0400000; // TODO: should read from config + let cfg_base = rootcomplex_config.ecam_base; // TODO: should read from config + let cfg_size = rootcomplex_config.ecam_size; // TODO: should read from config + let first_busno = rootcomplex_config.bus_range_begin as u8; + + RootComplex::new_dwc(dbi_base, cfg_base, cfg_size, first_busno, None) + } + + #[cfg(feature = "loongarch64_pcie")] + { + RootComplex::new_loongarch(rootcomplex_config.ecam_base) + } + + #[cfg(all(not(feature = "dwc_pcie"), not(feature = "loongarch64_pcie")))] + { + // default use ECAM + RootComplex::new(rootcomplex_config.ecam_base) + } + }; + + let e = rootcomplex.enumerate(None, Some(allocator)); + info!("begin enumerate {:#?}", e); + for node in e{ + // Capabilities are already enumerated in get_node() during device discovery GLOBAL_PCIE_LIST.lock().insert(node.get_bdf(), node); } } @@ -111,6 +139,58 @@ impl Zone { mmio_vpci_handler, 0, ); + // self.mmio_region_register( + // 0xfe270000 as usize, + // 0x10000 as usize, + // mmio_vpci_handler_apb, + // 0xfe270000, + // ); + // self.mmio_region_register( + // 0x3c0400000 as usize, + // 0x400000 as usize, + // mmio_vpci_handler_dbi, + // 0x3c0400000, + // ); + // self.mmio_region_register( + // 0xf2000000 as usize, + // 0x2000000 as usize, + // mmio_vpci_handler_conf, + // 0xf2000000, + // ); } } } + +pub fn mmio_vpci_handler_apb(mmio: &mut MMIOAccess, _base: usize) -> HvResult { + mmio_perform_access(_base, mmio); + warn!( + "apb 0x{:x}+0x{:x} {} 0x{:x}", + _base, + mmio.address, + if mmio.is_write { "write" } else { "read" }, + mmio.value + ); + Ok(()) +} +pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { + mmio_perform_access(_base, mmio); + warn!( + "dbi 0x{:x}+0x{:x} {} 0x{:x}", + _base, + mmio.address, + if mmio.is_write { "write" } else { "read" }, + mmio.value + ); + Ok(()) +} +pub fn mmio_vpci_handler_conf(mmio: &mut MMIOAccess, _base: usize) -> HvResult { + mmio_perform_access(_base, mmio); + warn!( + "conf 0x{:x}+0x{:x} {} 0x{:x}", + _base, + mmio.address, + if mmio.is_write { "write" } else { "read" }, + mmio.value + ); + Ok(()) +} diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 9f8be11d..dc44e563 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -30,7 +30,7 @@ use super::{ EndpointField, EndpointHeader, HeaderType, PciBridgeHeader, PciCommand, PciConfigHeader, PciMem, PciMemType, PciRW, }, - pci_mem::{PciRegion, PciRegionMmio}, + config_accessors::{PciRegion, PciConfigMmio, PciConfigAccessor, get_default_accessor_type, create_accessor, PciAccessorType}, PciConfigAddress, }; @@ -41,6 +41,12 @@ const MAX_FUNCTION: u8 = 7; pub const CONFIG_LENTH: u64 = 256; const BIT_LENTH: usize = 256 * 2; +// PCIe Device/Port Type values +const PCI_EXP_TYPE_ROOT_PORT: u16 = 4; +const PCI_EXP_TYPE_UPSTREAM: u16 = 5; +const PCI_EXP_TYPE_DOWNSTREAM: u16 = 6; +const PCI_EXP_TYPE_PCIE_BRIDGE: u16 = 8; + #[derive(Clone, Copy, Eq, PartialEq, Default)] pub struct Bdf { pub bus: u8, @@ -58,12 +64,16 @@ impl Bdf { } } - #[allow(dead_code)] - pub fn is_zero(&self) -> bool { - if self.bus == 0 && self.device == 0 && self.function == 0 { - return true; - } - false + pub fn bus(&self) -> u8 { + self.bus + } + + pub fn device(&self) -> u8 { + self.device + } + + pub fn function(&self) -> u8 { + self.function } pub fn from_address(address: PciConfigAddress) -> Self { @@ -87,7 +97,7 @@ impl Bdf { } pub fn is_host_bridge(&self) -> bool { - if (self.device, self.function) == (0, 0) { + if (self.bus, self.device, self.function) == (0, 0, 0) { true } else { false @@ -466,14 +476,16 @@ impl VirtualPciConfigSpace { } } +#[derive(Debug)] pub struct PciIterator { allocator: Option, stack: Vec, segment: PciConfigAddress, - bus_max: u8, + bus_range: Range, function: u8, is_mulitple_function: bool, is_finish: bool, + accessor: Arc, } impl PciIterator { @@ -481,22 +493,40 @@ impl PciIterator { 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 + let function = self.function; + + let bdf = Bdf::new(bus, device, function); + let offset = 0; + + match self.accessor.get_physical_address(bdf, offset) { + Ok(addr) => addr, + Err(_) => { + 0x0 + } + } } fn get_node(&mut self) -> Option { + let mut parent = self.stack.last_mut().unwrap(); + let bus = parent.secondary_bus; + let device = parent.device; + let function = self.function; + let bdf = Bdf::new(bus, device, function); + + if let Err(e) = self.accessor.prepare_access(bdf) { + // Only warn if it's not a device that should be skipped + warn!("prepare access failed: {:?}", e); + return None; + } + let address = self.address(); + info!("get node {:x}", address); - let region = PciRegionMmio::new(address, CONFIG_LENTH); + let region = PciConfigMmio::new(address, CONFIG_LENTH); let pci_header = PciConfigHeader::new_with_region(region); let (vender_id, _device_id) = pci_header.id(); if vender_id == 0xffff { + warn!("get none"); return None; } @@ -510,9 +540,15 @@ impl PciIterator { let bararr = Self::bar_mem_init(ep.bar_limit().into(), &mut self.allocator, &mut ep); + info!("get node bar mem init end {:#?}", bararr); + let ep = Arc::new(ep); let bdf = Bdf::from_address(address); - Some(VirtualPciConfigSpace::endpoint(bdf, ep, bararr, rom)) + let mut node = VirtualPciConfigSpace::endpoint(bdf, ep, bararr, rom); + + let _ = node.capability_enumerate(); + + Some(node) } HeaderType::PciBridge => { warn!("bridge"); @@ -523,7 +559,11 @@ impl PciIterator { let bridge = Arc::new(bridge); let bdf = Bdf::from_address(address); - Some(VirtualPciConfigSpace::bridge(bdf, bridge, bararr)) + let mut node = VirtualPciConfigSpace::bridge(bdf, bridge, bararr); + + let _ = node.capability_enumerate(); + + Some(node) } _ => { warn!("unknown type"); @@ -604,9 +644,14 @@ impl PciIterator { fn next_device_not_ok(&mut self) -> bool { if let Some(parent) = self.stack.last_mut() { + // only one child and skip this bus + if parent.has_secondary_link { + parent.device = MAX_DEVICE; + } + if parent.device == MAX_DEVICE { if let Some(mut parent) = self.stack.pop() { - self.is_finish = parent.subordinate_bus == self.bus_max; + self.is_finish = parent.subordinate_bus as usize == self.bus_range.end; parent.update_bridge_bus(); self.function = 0; @@ -638,7 +683,6 @@ impl PciIterator { if self.is_next_function_max() { while self.next_device_not_ok() { - spin_loop(); } } } @@ -648,11 +692,12 @@ impl Iterator for PciIterator { type Item = VirtualPciConfigSpace; fn next(&mut self) -> Option { + info!("pci dev next"); 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())), + HeaderType::PciBridge => Some(self.get_bridge().next_bridge(self.address(), node.has_secondary_link())), _ => None, }); return Some(node); @@ -670,28 +715,32 @@ pub struct Bridge { subordinate_bus: u8, secondary_bus: u8, primary_bus: u8, - mmio: PciRegionMmio, + mmio: PciConfigMmio, + has_secondary_link: bool, } impl Bridge { - pub fn host_bridge(address: PciConfigAddress) -> Self { + pub fn host_bridge(address: PciConfigAddress, bus_begin: u8) -> Self { Self { device: 0, - subordinate_bus: 0, - secondary_bus: 0, - primary_bus: 0, - mmio: PciRegionMmio::new(address, CONFIG_LENTH), + subordinate_bus: bus_begin, + secondary_bus: bus_begin, + primary_bus: bus_begin, + mmio: PciConfigMmio::new(address, CONFIG_LENTH), + has_secondary_link: false, } } - pub fn next_bridge(&self, address: PciConfigAddress) -> Self { - let mmio = PciRegionMmio::new(address, CONFIG_LENTH); + pub fn next_bridge(&self, address: PciConfigAddress, has_secondary_link: bool) -> Self { + let mmio = PciConfigMmio::new(address, CONFIG_LENTH); + warn!("bridge has_secondary_link: {}", has_secondary_link); Self { device: 0, subordinate_bus: self.subordinate_bus + 1, secondary_bus: self.subordinate_bus + 1, primary_bus: self.secondary_bus, mmio, + has_secondary_link, } } @@ -702,16 +751,31 @@ impl Bridge { value.set_bits(0..8, self.primary_bus.into()); let _ = self.mmio.write_u32(0x18, value); } + + pub fn set_has_secondary_link(&mut self, value: bool) { + self.has_secondary_link = 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, + pub accessor: Arc, // Unified accessor } impl RootComplex { + // Create RootComplex, automatically select accessor type based on feature pub fn new(mmio_base: PciConfigAddress) -> Self { - Self { mmio_base } + let accessor_type = get_default_accessor_type(); + let accessor = create_accessor( + accessor_type, + mmio_base + ); + + Self { + mmio_base, + accessor, + } } fn __enumerate( @@ -723,12 +787,13 @@ impl RootComplex { let range = range.unwrap_or_else(|| 0..0x100); PciIterator { allocator: bar_alloc, - stack: vec![Bridge::host_bridge(mmio_base)], + stack: vec![Bridge::host_bridge(mmio_base, range.start as u8)], segment: mmio_base, - bus_max: (range.end - 1) as _, + bus_range: range, function: 0, is_mulitple_function: false, is_finish: false, + accessor: self.accessor.clone(), // Pass accessor to iterator } } @@ -737,6 +802,8 @@ impl RootComplex { range: Option>, bar_alloc: Option, ) -> PciIterator { + // DBI initialization is handled by the accessor in prepare_access + // No need to call dbi_init here self.__enumerate(range, bar_alloc) } } @@ -786,7 +853,8 @@ impl CapabilityIterator { } pub fn get_next_cap(&mut self) -> HvResult { - let address = self.backend.read(self.offset, 2).unwrap().get_bits(8..16) as PciConfigAddress; + let address = + self.backend.read(self.offset, 2).unwrap().get_bits(8..16) as PciConfigAddress; self.offset = address; Ok(()) } @@ -805,7 +873,8 @@ impl Iterator for CapabilityIterator { fn next(&mut self) -> Option { while self.get_offset() != 0 { - let cap = PciCapability::from_address(self.get_offset(), self.get_id(), self.get_extension()); + 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 { @@ -855,7 +924,11 @@ pub enum PciCapability { } impl PciCapability { - fn from_address(offset: PciConfigAddress, id: PciConfigAddress, extension: u16) -> Option { + fn from_address( + offset: PciConfigAddress, + id: PciConfigAddress, + extension: u16, + ) -> Option { match id { 0x00 => None, 0x01 => Some(PciCapability::PowerManagement(PciCapabilityRegion::new( @@ -1001,10 +1074,7 @@ pub struct PciCapabilityRegion { impl PciCapabilityRegion { pub fn new(offset: PciConfigAddress, extension: u16) -> Self { - Self { - offset, - extension, - } + Self { offset, extension } } } @@ -1013,8 +1083,8 @@ pub type PciCapabilityList = BTreeMap; impl VirtualPciConfigSpace { fn _capability_enumerate(&self, backend: Arc) -> CapabilityIterator { CapabilityIterator { - backend, - offset: 0x34 + backend, + offset: 0x34, } } @@ -1024,6 +1094,8 @@ impl VirtualPciConfigSpace { match capability { PciCapability::Msi(_) => {} PciCapability::MsiX(_) => {} + PciCapability::PciExpress(_) => {} + _ => {} } capabilities.insert(capability.get_offset(), capability); @@ -1031,4 +1103,31 @@ impl VirtualPciConfigSpace { info!("capability {:#?}", capabilities); self.capabilities = capabilities; } + + pub fn has_secondary_link(&self) -> bool { + match self.config_type { + HeaderType::PciBridge => { + // Find PciExpress capability + for (_, capability) in &self.capabilities { + if let PciCapability::PciExpress(PciCapabilityRegion { offset, .. }) = capability { + // Read PCIe Capability Register at offset + 0x00 + // Bits 4:0 contain the Device/Port Type + if let Ok(cap_reg) = self.backend.read(*offset, 2) { + let type_val = (cap_reg as u16).get_bits(0..5); + if type_val == PCI_EXP_TYPE_ROOT_PORT || type_val == PCI_EXP_TYPE_PCIE_BRIDGE { + return true; + } else if type_val == PCI_EXP_TYPE_UPSTREAM || type_val == PCI_EXP_TYPE_DOWNSTREAM { + // Parent check is not implemented, set to false for now + return false; + } + } + break; + } + } + false + } + _ => false, + } + } + } diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs index f0ec3c22..494896bd 100644 --- a/src/pci/pci_test.rs +++ b/src/pci/pci_test.rs @@ -20,8 +20,8 @@ use alloc::{collections::btree_map::BTreeMap, sync::Arc}; use spin::{lazy::Lazy, mutex::Mutex}; use crate::{ - memory::MMIOAccess, - pci::{pci_access::EndpointHeader, pci_mem::PciRegionMmio}, + memory::{MMIOAccess, mmio_perform_access}, + pci::{pci_access::EndpointHeader, config_accessors::PciConfigMmio}, percpu::this_zone, }; @@ -59,7 +59,7 @@ pub fn pcie_guest_init() { 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( + let backend = EndpointHeader::new_with_region(PciConfigMmio::new( bdf.to_address(0) + 0x4010000000, CONFIG_LENTH, )); @@ -118,3 +118,26 @@ pub fn pcie_guest_test() { info!("pcie guest test passed"); } + +pub fn pcie_dwc_test() { + info!("pcie dwc test begin"); + let mut mmio = MMIOAccess { + address: 0x3c0400000, + size: 4, + is_write: false, + value: 0x0, + }; + let ret = mmio_perform_access(0, &mut mmio); + info!("{:#?}", ret); + info!( + "mmio offset {:x}, is_wirte {}, size {}, value 0x{:x}", + mmio.address, mmio.is_write, mmio.size, mmio.value + ); + use core::ptr::{read_volatile, write_volatile}; + unsafe { + let a = read_volatile(0x3c0000900 as *const u32); + info!("{a}"); + }; + + info!("pcie dwc test passed"); +} \ No newline at end of file From 523739e852952385fedae16a4d7d2389dac7c227 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 19 Nov 2025 22:06:07 +0800 Subject: [PATCH 022/109] add dwc_and loongarch for pcie --- Cargo.toml | 1 + platform/aarch64/qemu-gicv3/cargo/features | 1 + platform/aarch64/rk3568/board.rs | 58 +++ platform/aarch64/rk3568/cargo/features | 2 - platform/x86_64/nuc14mnk/cargo/features | 2 + platform/x86_64/qemu/cargo/features | 2 + src/config.rs | 57 +++ src/main.rs | 1 + src/pci/config_accessors/dwc.rs | 214 +++++++---- src/pci/config_accessors/dwc_atu.rs | 17 +- src/pci/config_accessors/ecam.rs | 41 +- src/pci/config_accessors/loongarch64.rs | 51 ++- src/pci/config_accessors/mod.rs | 97 ++--- src/pci/pci_access.rs | 420 ++++++++++++--------- src/pci/pci_config.rs | 155 ++++---- src/pci/pci_struct.rs | 323 ++++++++++------ src/pci/pci_test.rs | 26 +- src/zone.rs | 8 +- 18 files changed, 969 insertions(+), 507 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 581a7046..b63b3df4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,7 @@ pci = [] # supported by: aarch64, loongarch64 ecam_pcie = [] # Standard ECAM mechanism (default for most platforms) dwc_pcie = [] # DesignWare PCIe Core mechanism (CFG0/CFG1, used by RK3568) loongarch64_pcie = [] # LoongArch PCIe mechanism (used by LoongArch platforms) +no_pcie_bar_realloc = [] ############# aarch64 ############## # irqchip driver diff --git a/platform/aarch64/qemu-gicv3/cargo/features b/platform/aarch64/qemu-gicv3/cargo/features index eb18579e..2092d180 100644 --- a/platform/aarch64/qemu-gicv3/cargo/features +++ b/platform/aarch64/qemu-gicv3/cargo/features @@ -2,3 +2,4 @@ gicv3 pl011 iommu pci +ecam_pcie \ No newline at end of file diff --git a/platform/aarch64/rk3568/board.rs b/platform/aarch64/rk3568/board.rs index 1438e1bf..86e10fa7 100644 --- a/platform/aarch64/rk3568/board.rs +++ b/platform/aarch64/rk3568/board.rs @@ -56,6 +56,42 @@ 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] = &[ + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x3c0400000, + virtual_start: 0x3c0400000, + size: 0x400000, + }, //pcie + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xfe270000, + virtual_start: 0xfe270000, + size: 0x10000, + }, //pcie + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xf2000000, + virtual_start: 0xf2000000, + size: 0x100000, + }, //pcie + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xf2100000, + virtual_start: 0xf2100000, + size: 0x100000, + }, //pcie + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xf2200000, + virtual_start: 0xf2200000, + size: 0x1e00000, + }, //pcie + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x340000000, + virtual_start: 0x340000000, + size: 0x40000000, + }, //pcie HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0xfdcb8000, @@ -290,6 +326,28 @@ pub const ROOT_PCI_CONFIG: &[HvPciConfig] = &[ pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; +pub const ROOT_DWC_ATU_CONFIG: &[HvDwcAtuConfig] = &[ + HvDwcAtuConfig { + ecam_base: 0x3c0400000, + dbi_base: 0x3c0400000, + dbi_size: 0x10000, + apb_base: 0, + apb_size: 0, + cfg_base: 0xf2000000, + cfg_size: 0x80000*2, + cfg0_atu_index: 0, + cfg0_atu_type: 4, + cfg1_atu_index: 0, + cfg1_atu_type: 4, + mem32_atu_index: 1, + mem32_atu_type: 0, + mem64_atu_index: 2, + mem64_atu_type: 0, + io_atu_index: 3, + io_atu_type: 2, + }, +]; + pub const ROOT_PCI_DEVS: [HvPciDevConfig; 3] = [ pci_dev!( 0x1, 0x0, 0x0), pci_dev!(0x11, 0x0, 0x0), diff --git a/platform/aarch64/rk3568/cargo/features b/platform/aarch64/rk3568/cargo/features index df350a43..afa59489 100644 --- a/platform/aarch64/rk3568/cargo/features +++ b/platform/aarch64/rk3568/cargo/features @@ -1,4 +1,2 @@ gicv3 uart_16550 -pci -dwc_pcie \ No newline at end of file diff --git a/platform/x86_64/nuc14mnk/cargo/features b/platform/x86_64/nuc14mnk/cargo/features index ac3b7f71..f8ee525a 100644 --- a/platform/x86_64/nuc14mnk/cargo/features +++ b/platform/x86_64/nuc14mnk/cargo/features @@ -1,2 +1,4 @@ pci +ecam_pcie +no_pcie_bar_realloc uart16550a \ No newline at end of file diff --git a/platform/x86_64/qemu/cargo/features b/platform/x86_64/qemu/cargo/features index ac3b7f71..f8ee525a 100644 --- a/platform/x86_64/qemu/cargo/features +++ b/platform/x86_64/qemu/cargo/features @@ -1,2 +1,4 @@ pci +ecam_pcie +no_pcie_bar_realloc uart16550a \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index d8b892c1..a05aa13c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -230,3 +230,60 @@ impl Debug for HvPciDevConfig { write!(f, "bdf {:#?} vbdf {:#?}", bdf, vbdf) } } + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct HvDwcAtuConfig { + /// ECAM (Enhanced Configuration Access Mechanism) base address + /// This is used to match with HvPciConfig::ecam_base + pub ecam_base: u64, + pub dbi_base: u64, + pub dbi_size: u64, + pub apb_base: u64, + pub apb_size: u64, + pub cfg_base: u64, + pub cfg_size: u64, + pub cfg0_atu_index: usize, + pub cfg0_atu_type: u32, + pub cfg1_atu_index: usize, + pub cfg1_atu_type: u32, + pub mem32_atu_index: usize, + pub mem32_atu_type: u32, + pub mem64_atu_index: usize, + pub mem64_atu_type: u32, + pub io_atu_index: usize, + pub io_atu_type: u32, +} + +impl HvDwcAtuConfig { + pub const fn new_empty() -> Self { + // Use ATU_UNUSED for ATU indices that are not used by default + // ATU_UNUSED is u32::MAX, cast to usize for consistency + // Default ATU types: CFG0=4, CFG1=5, MEM=0, IO=2 + Self { + ecam_base: 0, + dbi_base: 0, + dbi_size: 0, + apb_base: 0, + apb_size: 0, + cfg_base: 0, + cfg_size: 0, + cfg0_atu_index: u32::MAX as usize, + cfg0_atu_type: 4, // ATU_TYPE_CFG0 + cfg1_atu_index: u32::MAX as usize, + cfg1_atu_type: 5, // ATU_TYPE_CFG1 + mem32_atu_index: u32::MAX as usize, + mem32_atu_type: 0, // ATU_TYPE_MEM + mem64_atu_index: u32::MAX as usize, + mem64_atu_type: 0, // ATU_TYPE_MEM + io_atu_index: u32::MAX as usize, + io_atu_type: 2, // ATU_TYPE_IO + } + } +} + +impl Default for HvDwcAtuConfig { + fn default() -> Self { + Self::new_empty() + } +} diff --git a/src/main.rs b/src/main.rs index 16cd953e..96a3b0cc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -134,6 +134,7 @@ fn primary_init_early() { device::irqchip::primary_init_early(); + #[cfg(feature = "iommu")] iommu_init(); let root_config = root_zone_config(); diff --git a/src/pci/config_accessors/dwc.rs b/src/pci/config_accessors/dwc.rs index 38f4f647..b7a24f26 100644 --- a/src/pci/config_accessors/dwc.rs +++ b/src/pci/config_accessors/dwc.rs @@ -15,59 +15,63 @@ // use crate::error::{HvResult, HvErrorNum::*}; -use crate::pci::{pci_access::{PciRW, PciRWBase}, pci_struct::Bdf, PciConfigAddress}; +use crate::pci::{pci_access::{PciRW, PciRWBase}, pci_struct::{Bdf, RootComplex}, PciConfigAddress}; +use crate::config::HvDwcAtuConfig; use alloc::sync::Arc; -use spin::Mutex; -use super::{PciConfigAccessor, PciRegion, PciConfigMmio, PciRegionMmio}; -use super::dwc_atu::{AtuUnroll, AtuConfig, ATU_TYPE_CFG0, ATU_TYPE_CFG1}; +use super::{PciConfigAccessor, PciRegion, PciConfigMmio, PciRegionMmio, BdfAddressConversion}; +use super::dwc_atu::{AtuUnroll, AtuConfig, ATU_UNUSED}; +use bit_field::BitField; + +impl RootComplex { + pub fn new_dwc( + ecam_base: u64, + atu_config: &HvDwcAtuConfig, + root_bus: u8 + ) -> Self { + let accessor = Arc::new(DwcConfigAccessor::new(atu_config, root_bus)); + + Self { + mmio_base: ecam_base, + accessor, + } + } +} -#[cfg(feature = "dwc_pcie")] impl PciRegion for PciConfigMmio { - fn read_u8(&self, _offset: PciConfigAddress) -> HvResult { - unimplemented!() + 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 { - unimplemented!() + fn write_u8(&self, offset: PciConfigAddress, value: u8) -> HvResult { + unsafe { self.access::(offset).write_volatile(value) } + Ok(()) } - fn read_u16(&self, _offset: PciConfigAddress) -> HvResult { - unimplemented!() + 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 { - unimplemented!() + fn write_u16(&self, offset: PciConfigAddress, value: u16) -> HvResult { + unsafe { self.access::(offset).write_volatile(value) } + Ok(()) } - fn read_u32(&self, _offset: PciConfigAddress) -> HvResult { - unimplemented!() + 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 { - unimplemented!() + fn write_u32(&self, offset: PciConfigAddress, value: u32) -> HvResult { + unsafe { self.access::(offset).write_volatile(value) } + Ok(()) } } -// DWC PCIe region types -#[repr(u32)] -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum DwcRegionType { - Dbi = 0, - Apb = 1, - Cfg0 = 2, - Cfg1 = 3, -} -impl DwcRegionType { - pub fn as_usize(self) -> usize { - self as usize - } -} - -// DWC PCIe configuration region structure #[repr(C)] #[derive(Debug, Clone, Copy)] pub struct DwcConfigRegion { - pub region_type: DwcRegionType, - pub physical_start: u64, + pub atu_index: usize, + pub atu_type: u32, + pub base: PciConfigAddress, pub size: u64, } +#[derive(Debug)] pub struct DwcConfigRegionBackend(PciRegionMmio); impl PciRWBase for DwcConfigRegionBackend { @@ -79,59 +83,125 @@ impl PciRW for DwcConfigRegionBackend {} #[derive(Debug)] pub struct DwcConfigAccessor { - dbi_backend: Arc, - cfg0_backend: Arc, - cfg1_backend: Arc, - apb_backend: Option>, + dbi_backend: Arc, + dbi: DwcConfigRegion, + cfg0: DwcConfigRegion, + cfg1: DwcConfigRegion, + root_bus: u8, } impl DwcConfigAccessor { - pub fn new(regions: [DwcConfigRegion; 4]) -> Self { - let mut dbi_backend = None; - let mut cfg0_backend = None; - let mut cfg1_backend = None; - let mut apb_backend = None; + pub fn new( + atu_config: &HvDwcAtuConfig, + root_bus: u8 + ) -> Self { + let cfg_size_half = atu_config.cfg_size / 2; + let cfg0_base = atu_config.cfg_base; + let cfg1_base = atu_config.cfg_base + cfg_size_half; - for region in regions.iter() { - let mmio = PciRegionMmio::new(region.physical_start as PciConfigAddress, region.size); - let backend = Arc::new(DwcConfigRegionBackend(mmio)) as Arc; - - match region.region_type { - DwcRegionType::Dbi => { - dbi_backend = Some(backend); - } - DwcRegionType::Cfg0 => { - cfg0_backend = Some(backend); - } - DwcRegionType::Cfg1 => { - cfg1_backend = Some(backend); - } - DwcRegionType::Apb => { - apb_backend = Some(backend); - } - } - } + // Create DBI backend for ATU configuration + let dbi_base = atu_config.dbi_base as PciConfigAddress; + let dbi_size = atu_config.dbi_size; + let dbi_region = PciRegionMmio::new(dbi_base, dbi_size); + let dbi_backend = Arc::new(DwcConfigRegionBackend(dbi_region)); + + let dbi = DwcConfigRegion { + atu_index: ATU_UNUSED as usize, + atu_type: 0, + base: dbi_base, + size: dbi_size, + }; + let cfg0 = DwcConfigRegion { + atu_index: atu_config.cfg0_atu_index, + atu_type: atu_config.cfg0_atu_type, + base: cfg0_base, + size: cfg_size_half, + }; + let cfg1 = DwcConfigRegion { + atu_index: atu_config.cfg1_atu_index, + atu_type: atu_config.cfg1_atu_type, + base: cfg1_base, + size: cfg_size_half, + }; Self { - dbi_backend: dbi_backend.expect("DBI backend is required"), - cfg0_backend: cfg0_backend.expect("CFG0 backend is required"), - cfg1_backend: cfg1_backend.expect("CFG1 backend is required"), - apb_backend, + dbi_backend, + dbi, + cfg0, + cfg1, + root_bus, } } } impl PciConfigAccessor for DwcConfigAccessor { - fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress) -> HvResult { + fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress, parent_bus: u8) -> HvResult { + let bus = bdf.bus(); + let device = bdf.device() as PciConfigAddress; + let function = bdf.function() as PciConfigAddress; + warn!("parent_bus {} self.root_bus {}", parent_bus, self.root_bus); + + // Calculate address without bus field (bus is handled by different config regions) + // Address format: (device << 15) + (function << 12) + offset + let offset_without_bus = (device << 15) + (function << 12) + offset; + + let address = if bus == self.root_bus { + warn!("1"); + // Root bus: use DBI directly, no ATU configuration needed + self.dbi.base + offset_without_bus + } else if parent_bus == self.root_bus { + // Check if cfg0 ATU is configured (not ATU_UNUSED) + warn!("2"); + if self.cfg0.atu_index == ATU_UNUSED as usize { + return hv_result_err!(EINVAL, "CFG0 ATU is not configured"); + } + let atu_config = AtuConfig::new_with_dwc_config_region( + &self.cfg0, + ); + AtuUnroll::dw_pcie_prog_outbound_atu_unroll(self.dbi_backend.as_ref(), &atu_config)?; + + self.cfg0.base + offset_without_bus + } else { + // Check if cfg1 ATU is configured (not ATU_UNUSED) + warn!("3"); + if self.cfg1.atu_index == ATU_UNUSED as usize { + return hv_result_err!(EINVAL, "CFG1 ATU is not configured"); + } + let atu_config = AtuConfig::new_with_dwc_config_region( + &self.cfg1, + ); + AtuUnroll::dw_pcie_prog_outbound_atu_unroll(self.dbi_backend.as_ref(), &atu_config)?; + + self.cfg1.base + offset_without_bus + }; + + Ok(address) } - - fn prepare_access(&self, bdf: Bdf) -> HvResult { + fn skip_device(&self, bdf: Bdf) -> bool { + // On root bus, only device 0 (slot 0) is valid, devices with dev > 0 should be skipped + // This matches Linux kernel's dw_pcie_valid_device() behavior + if bdf.bus() == self.root_bus && bdf.device() > 0 { + warn!("skip_device {:#?}", bdf); + return true; + } + false } - - fn get_base_address(&self) -> PciConfigAddress { +} +#[cfg(feature = "dwc_pcie")] +impl BdfAddressConversion for Bdf { + fn from_address(address: PciConfigAddress) -> Bdf { + let bdf = address >> 12; + let function = (bdf & 0b111) as u8; + let device = ((bdf >> 3) & 0b11111) as u8; + let bus = (bdf >> 8) as u8; + Bdf { + bus, + device, + function, + } } } diff --git a/src/pci/config_accessors/dwc_atu.rs b/src/pci/config_accessors/dwc_atu.rs index f1114fe5..a1aa0e8c 100644 --- a/src/pci/config_accessors/dwc_atu.rs +++ b/src/pci/config_accessors/dwc_atu.rs @@ -16,6 +16,7 @@ use crate::error::{HvResult, HvErrorNum::*}; use crate::pci::{pci_access::PciRW, PciConfigAddress}; +use super::dwc::DwcConfigRegion; // DWC PCIe ATU (Address Translation Unit) register offsets // Unroll registers are used for unrolled ATU regions @@ -38,6 +39,8 @@ pub const ATU_TYPE_IO: u32 = 0x2; // IO Type // ATU enable bit pub const ATU_ENABLE_BIT: u32 = 0x80000000; +pub const ATU_UNUSED: u32 = u32::MAX; + // ATU configuration parameters #[derive(Debug, Clone, Copy)] pub struct AtuConfig { @@ -65,6 +68,18 @@ impl AtuConfig { pci_target, } } + + pub fn new_with_dwc_config_region( + config_region: &DwcConfigRegion, + ) -> Self { + Self::new( + config_region.atu_index, + config_region.atu_type, + config_region.base, + config_region.size, + config_region.base, + ) + } } // ATU unroll configuration functions @@ -73,7 +88,7 @@ pub struct AtuUnroll; impl AtuUnroll { // Configure ATU region using unroll registers // Follows the same order as Linux kernel dw_pcie_prog_outbound_atu_unroll - pub fn configure_region( + pub fn dw_pcie_prog_outbound_atu_unroll( dbi_backend: &dyn PciRW, config: &AtuConfig, ) -> HvResult { diff --git a/src/pci/config_accessors/ecam.rs b/src/pci/config_accessors/ecam.rs index 882ecea5..13bdac8f 100644 --- a/src/pci/config_accessors/ecam.rs +++ b/src/pci/config_accessors/ecam.rs @@ -14,12 +14,24 @@ // Authors: // +use alloc::sync::Arc; use crate::error::HvResult; +use crate::pci::pci_struct::RootComplex; use crate::pci::{pci_struct::Bdf, PciConfigAddress}; -use super::{PciConfigAccessor, PciRegion, PciConfigMmio}; +use super::{PciConfigAccessor, PciRegion, PciConfigMmio, BdfAddressConversion}; +use bit_field::BitField; + +impl RootComplex { + pub fn new_ecam(mmio_base: PciConfigAddress) -> Self { + let accessor = Arc::new(EcamConfigAccessor::new(mmio_base)); + + Self { + mmio_base, + accessor, + } + } +} -// ECAM (Enhanced Configuration Access Mechanism) accessor implementation -// Standard ECAM mechanism used by most PCIe platforms #[derive(Debug)] pub struct EcamConfigAccessor { ecam_base: PciConfigAddress, @@ -32,7 +44,7 @@ impl EcamConfigAccessor { } impl PciConfigAccessor for EcamConfigAccessor { - fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress) -> HvResult { + fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress, _parent_bus: u8) -> HvResult { let bus = bdf.bus() as PciConfigAddress; let device = bdf.device() as PciConfigAddress; let function = bdf.function() as PciConfigAddress; @@ -46,17 +58,22 @@ impl PciConfigAccessor for EcamConfigAccessor { + offset; Ok(address) } - - fn prepare_access(&self, _bdf: Bdf) -> HvResult { - Ok(()) // ECAM doesn't need special preparation - } - - fn get_base_address(&self) -> PciConfigAddress { - self.ecam_base +} + +impl BdfAddressConversion for Bdf { + fn from_address(address: PciConfigAddress) -> Bdf { + let bdf = address >> 12; + let function = (bdf & 0b111) as u8; + let device = ((bdf >> 3) & 0b11111) as u8; + let bus = (bdf >> 8) as u8; + Bdf { + bus, + device, + function, + } } } -#[cfg(any(feature = "ecam_pcie", all(not(feature = "dwc_pcie"), not(feature = "loongarch64_pcie"))))] impl PciRegion for PciConfigMmio { fn read_u8(&self, offset: PciConfigAddress) -> HvResult { unsafe { Ok(self.access::(offset).read_volatile() as u8) } diff --git a/src/pci/config_accessors/loongarch64.rs b/src/pci/config_accessors/loongarch64.rs index f1601a3c..984ed56f 100644 --- a/src/pci/config_accessors/loongarch64.rs +++ b/src/pci/config_accessors/loongarch64.rs @@ -15,8 +15,21 @@ // use crate::error::HvResult; -use crate::pci::{pci_struct::Bdf, PciConfigAddress}; -use super::{PciConfigAccessor, PciRegion, PciConfigMmio}; +use crate::pci::{pci_struct::{Bdf, RootComplex}, PciConfigAddress}; +use super::{PciConfigAccessor, PciRegion, PciConfigMmio, BdfAddressConversion}; +use alloc::sync::Arc; +use bit_field::BitField; + +impl RootComplex { + pub fn new_loongarch(mmio_base: PciConfigAddress) -> Self { + let accessor = Arc::new(LoongArchConfigAccessor::new(mmio_base)); + + Self { + mmio_base, + accessor, + } + } +} #[cfg(feature = "loongarch64_pcie")] impl PciRegion for PciConfigMmio { @@ -54,16 +67,38 @@ impl LoongArchConfigAccessor { } impl PciConfigAccessor for LoongArchConfigAccessor { - fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress) -> HvResult { - + fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress, _parent_bus: u8) -> HvResult { + let bus = bdf.bus() as PciConfigAddress; + let device = bdf.device() as PciConfigAddress; + let function = bdf.function() as PciConfigAddress; + + // LoongArch PCIe uses similar address calculation to ECAM + // base + (bus << 20) + (device << 15) + (function << 12) + offset + let address = self.cfg_base + + (bus << 20) + + (device << 15) + + (function << 12) + + offset; + Ok(address) } - - fn prepare_access(&self, _bdf: Bdf) -> HvResult { + fn skip_device(&self, _bdf: Bdf) -> bool { + false } - - fn get_base_address(&self) -> PciConfigAddress { +} +#[cfg(feature = "loongarch64_pcie")] +impl BdfAddressConversion for Bdf { + fn from_address(address: PciConfigAddress) -> Bdf { + let bdf = address >> 12; + let function = (bdf & 0b111) as u8; + let device = ((bdf >> 3) & 0b11111) as u8; + let bus = (bdf >> 8) as u8; + Bdf { + bus, + device, + function, + } } } diff --git a/src/pci/config_accessors/mod.rs b/src/pci/config_accessors/mod.rs index e99fadfb..62c3747e 100644 --- a/src/pci/config_accessors/mod.rs +++ b/src/pci/config_accessors/mod.rs @@ -18,7 +18,10 @@ use core::{any::Any, fmt::Debug}; use crate::error::HvResult; use crate::pci::{pci_struct::Bdf, PciConfigAddress}; -use alloc::sync::Arc; + +pub trait BdfAddressConversion { + fn from_address(address: PciConfigAddress) -> Bdf; +} // PCIe region trait for memory-mapped I/O access pub trait PciRegion: Debug + Sync + Send + Any { @@ -46,6 +49,10 @@ impl PciConfigMmio { pub(crate) fn access(&self, offset: PciConfigAddress) -> *mut T { (self.base + offset) as *mut T } + /// Check if this is a placeholder (dummy) mmio with base address 0 + pub fn is_placeholder(&self) -> bool { + self.base == 0 && self.length == 0 + } } /* PCIe region MMIO for general memory-mapped I/O regions */ @@ -90,20 +97,57 @@ impl PciRegion for PciRegionMmio { } } -// PCIe config space accessor trait -// Unified interface for different PCIe mechanisms (ECAM, DWC, LoongArch) +// Default implementation of PciRegion for PciConfigMmio +#[cfg(not(any(feature = "ecam_pcie", feature = "dwc_pcie", feature = "loongarch64_pcie")))] +impl PciRegion for PciConfigMmio { + 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(()) + } +} + +// Default implementation of BdfAddressConversion for Bdf +#[cfg(not(any(feature = "ecam_pcie", feature = "dwc_pcie", feature = "loongarch64_pcie")))] +impl BdfAddressConversion for Bdf { + fn from_address(address: PciConfigAddress) -> Bdf { + let bdf = address >> 12; + let function = (bdf & 0b111) as u8; + let device = ((bdf >> 3) & 0b11111) as u8; + let bus = (bdf >> 8) as u8; + Bdf { + bus, + device, + function, + } + } +} + pub trait PciConfigAccessor: Send + Sync + core::fmt::Debug { // Get physical address from BDF and offset - fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress) -> HvResult; - - // Prepare access before reading/writing (e.g., configure ATU) - fn prepare_access(&self, bdf: Bdf) -> HvResult; - - // Get base address of config space - fn get_base_address(&self) -> PciConfigAddress; + fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress, _parent_bus: u8) -> HvResult; + + fn skip_device(&self, _bdf: Bdf) -> bool { + false + } } -// Accessor type enum #[derive(Debug, Clone, Copy, PartialEq)] pub enum PciAccessorType { Ecam, @@ -111,33 +155,6 @@ pub enum PciAccessorType { LoongArch, } -// Factory function to create accessor based on feature flag -pub fn create_accessor( - accessor_type: PciAccessorType, - ecam_base: PciConfigAddress, -) -> Arc { - match accessor_type { - PciAccessorType::Ecam => Arc::new(ecam::EcamConfigAccessor::new(ecam_base)), - PciAccessorType::Dwc => Arc::new(ecam::EcamConfigAccessor::new(ecam_base)), - PciAccessorType::LoongArch => Arc::new(ecam::EcamConfigAccessor::new(ecam_base)), - } -} - -// Get default accessor type based on current features -pub fn get_default_accessor_type() -> PciAccessorType { - #[cfg(feature = "dwc_pcie")] - return PciAccessorType::Dwc; - - #[cfg(feature = "loongarch64_pcie")] - return PciAccessorType::LoongArch; - - #[cfg(feature = "ecam_pcie")] - return PciAccessorType::Ecam; - - #[cfg(all(not(feature = "ecam_pcie"), not(feature = "dwc_pcie"), not(feature = "loongarch64_pcie")))] - return PciAccessorType::Ecam; // Default to ECAM -} - // Export accessor implementations #[cfg(feature = "ecam_pcie")] pub mod ecam; @@ -150,7 +167,3 @@ pub mod dwc_atu; #[cfg(feature = "loongarch64_pcie")] pub mod loongarch64; -// Default ECAM implementation when no feature is specified -#[cfg(all(not(feature = "ecam_pcie"), not(feature = "dwc_pcie"), not(feature = "loongarch64_pcie")))] -pub mod ecam; - diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index cfb50bac..e1504ec1 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -26,18 +26,19 @@ use core::slice; use crate::{ error::HvResult, - memory::{GuestPhysAddr, HostPhysAddr, MMIOAccess, MemFlags, MemoryRegion}, + memory::{GuestPhysAddr, HostPhysAddr, MMIOAccess, MemFlags, MemoryRegion, MemorySet, mmio_perform_access}, pci::pci_struct::BIT_LENTH, percpu::this_zone, - zone::{this_zone_id, Zone}, + zone::{Zone, this_zone_id}, }; use super::{ config_accessors::{PciRegion, PciConfigMmio}, - pci_struct::Bdf, + pci_struct::VirtualPciConfigSpace, PciConfigAddress, }; + pub type VendorId = u16; pub type DeviceId = u16; pub type DeviceRevision = u8; @@ -361,6 +362,12 @@ impl Debug for PciMem { vaddr + size ) } + PciMemType::Rom => { + 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, vaddr, vaddr + size) + } _ => { write!(f, "[{:#?}]", self.bar_type) } @@ -462,6 +469,7 @@ 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 { @@ -546,6 +554,7 @@ pub trait PciBarRW: PciRWBase { let mut slot = 0u8; while slot < self.bar_limit() { + warn!("parse bar slot {}", slot); let value = self.read_bar(slot).unwrap(); if !value.get_bit(0) { @@ -595,9 +604,9 @@ pub trait PciBarRW: PciRWBase { let value64 = (value as u64) | ((value_high as u64) << 32); bararr[slot as usize] = - PciMem::new_bar(PciMemType::Mem64Low, value64 as u64, size, pre); + PciMem::new_bar(PciMemType::Mem64Low, value as u64, size, pre); bararr[(slot + 1) as usize] = - PciMem::new_bar(PciMemType::Mem64High, value64 as u64, size, pre); + PciMem::new_bar(PciMemType::Mem64High, value_high as u64, size, pre); slot += 1; // need extra add 1 } _ => { @@ -955,216 +964,191 @@ impl PciBridgeHeader { 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); +/// Handle PCI configuration space access +fn handle_config_space_access( + dev: &mut VirtualPciConfigSpace, + mmio: &mut MMIOAccess, + offset: PciConfigAddress, + gpm: &mut MemorySet, + zone_id: usize, +) -> HvResult { let size = mmio.size; let value = mmio.value; - - let zone_id = this_zone_id(); - 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 { - info!("vbdf find {:#?}", vbdf); - dev = Some(node.1); - break; - } - } + let is_write = mmio.is_write; + let vbdf = dev.get_vbdf(); if (offset as usize) >= BIT_LENTH { - if !mmio.is_write { + warn!("invalid pci offset {:#x}", offset); + if !is_write { mmio.value = 0; } return Ok(()); } - if let Some(dev) = dev { - match dev.access(offset, size) { - false => { - info!( - "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)?; + match dev.access(offset, size) { + false => { + info!( + "hw vbdf {:#?} reg 0x{:x} try {} {}", + vbdf, + offset, + if is_write { "write" } else { "read" }, + if is_write { + format!(" 0x{:x}", mmio.value) } else { - mmio.value = dev.read_hw(offset, size).unwrap(); + String::new() } + ); + if is_write { + dev.write_hw(offset, size, value)?; + } else { + mmio.value = dev.read_hw(offset, size).unwrap(); } - true => { - info!( - "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 + } + true => { + info!( + "emu vbdf {:#?} reg 0x{:x} try {} {}", + vbdf, + offset, + if is_write { "write" } else { "read" }, + if 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 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. 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 + * the old BAR addresses, potentially causing the update to fail? */ - if (bar_type == PciMemType::Mem32) - | (bar_type == PciMemType::Mem64High) + if !gpm + .try_delete(old_vaddr.try_into().unwrap()) + .is_ok() { - 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. 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 - * the old BAR addresses, potentially causing the update to fail? + /* The first delete from the guest will fail + * because the region has not yet been inserted */ - 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 + 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 - * TODO: for loongarch64 need ibar 0 dbar 0 - */ - #[cfg(target_arch = "aarch64")] - unsafe { - core::arch::asm!("isb"); - core::arch::asm!("tlbi vmalls12e1is"); - core::arch::asm!("dsb nsh"); - } - /* after update gpm, need to flush iommu table - * in x86_64 - */ - #[cfg(target_arch = "x86_64")] - crate::arch::iommu::flush( - zone_id, - vbdf.bus, - (vbdf.device << 3) + vbdf.function, - ); + 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 + * TODO: for loongarch64 need ibar 0 dbar 0 + */ + #[cfg(target_arch = "aarch64")] + unsafe { + core::arch::asm!("isb"); + core::arch::asm!("tlbi vmalls12e1is"); + core::arch::asm!("dsb nsh"); } + /* after update gpm, need to flush iommu table + * in x86_64 + */ + #[cfg(target_arch = "x86_64")] + crate::arch::iommu::flush( + zone_id, + vbdf.bus, + (vbdf.device << 3) + vbdf.function, + ); } - } 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; + 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 - } + } + EndpointField::ExpansionRomBar => { + let mut rom = dev.get_rom(); + if is_write { + if (mmio.value & 0xfffff800) == 0xfffff800 { + rom.set_size_read(); } else { - mmio.value = if rom.get_size_read() { - dev.read_emu(offset, size).unwrap() - } else { - rom.get_size_with_flag().try_into().unwrap() - }; + // 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 { - info!("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; + HeaderType::PciBridge => { + // TODO: add emu for bridge, actually it is same with endpoint } _ => { - // warn!("unhandled pci mmio read, addr: {:#x?}", mmio.address); - mmio.value = 0; + warn!("unhanled pci type {:#?}", dev.get_config_type()); } } } @@ -1174,9 +1158,75 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { "vbdf {:#?} reg 0x{:x} {} 0x{:x}", vbdf, offset, - if mmio.is_write { "write" } else { "read" }, + if is_write { "write" } else { "read" }, mmio.value ); Ok(()) } + +fn handle_device_not_found(mmio: &mut MMIOAccess, offset: PciConfigAddress) { + info!("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, mmio.size) { + EndpointField::ID => { + mmio.value = 0xFFFF_FFFF; + } + _ => { + // warn!("unhandled pci mmio read, addr: {:#x?}", mmio.address); + mmio.value = 0; + } + } + } +} + +pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { + info!("mmio_vpci_handler {:#x}", mmio.address); + let zone_id = this_zone_id(); + let zone = this_zone(); + let mut guard = zone.write(); + let (vbus, gpm) = { + let Zone { gpm, vpci_bus, .. } = &mut *guard; + (vpci_bus, gpm) + }; + + let offset = (mmio.address & 0xfff) as PciConfigAddress; + let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; + + if let Some(dev) = vbus.get_device_by_base(base) { + handle_config_space_access(dev, mmio, offset, gpm, zone_id)?; + } else { + handle_device_not_found(mmio, offset); + } + + Ok(()) +} + +pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { + info!("mmio_vpci_handler_dbi {:#x}", mmio.address); + let zone_id = this_zone_id(); + let zone = this_zone(); + let mut guard = zone.write(); + let (vbus, gpm) = { + let Zone { gpm, vpci_bus, .. } = &mut *guard; + (vpci_bus, gpm) + }; + + let offset = (mmio.address & 0xfff) as PciConfigAddress; + let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; + + if let Some(dev) = vbus.get_device_by_base(base) { + handle_config_space_access(dev, mmio, offset, gpm, zone_id)?; + } else { + if (offset as usize) >= BIT_LENTH { + // dbi read + mmio_perform_access(_base, mmio); + } else { + handle_device_not_found(mmio, offset); + } + + } + + Ok(()) +} \ No newline at end of file diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 02f0aa34..3e87d0a6 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -18,17 +18,16 @@ use spin::{Lazy, Mutex}; use crate::{ arch::iommu::iommu_add_device, - config::{HvPciConfig, HvPciDevConfig, CONFIG_MAX_PCI_DEV, CONFIG_PCI_BUS_MAXNUM}, + config::{CONFIG_MAX_PCI_DEV, CONFIG_PCI_BUS_MAXNUM, HvPciConfig, HvPciDevConfig}, error::HvResult, - memory::{mmio_perform_access, MMIOAccess}, + memory::mmio_generic_handler, pci::{ - mem_alloc::BaseAllocator, - pci_access::mmio_vpci_handler, - pci_struct::{Bdf, VirtualPciConfigSpace}, + config_accessors::BdfAddressConversion, mem_alloc::BaseAllocator, pci_access::{mmio_vpci_handler, mmio_vpci_handler_dbi}, pci_struct::{Bdf, VirtualPciConfigSpace} }, zone::Zone, }; +use crate::platform; use super::pci_struct::RootComplex; pub static GLOBAL_PCIE_LIST: Lazy>> = Lazy::new(|| { @@ -39,7 +38,8 @@ pub static GLOBAL_PCIE_LIST: Lazy>> = /* add all dev to GLOBAL_PCIE_LIST */ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { warn!("begin {:#?}", pci_config); - for rootcomplex_config in pci_config { + #[cfg(any(feature = "ecam_pcie", feature = "dwc_pcie", feature = "loongarch64_pcie"))] + for (index, rootcomplex_config) in pci_config.iter().enumerate() { /* empty config */ if rootcomplex_config.ecam_base == 0 { warn!("empty pcie config"); @@ -58,24 +58,31 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { // TODO: refactor // in x86, we do not take the initiative to reallocate BAR space - #[cfg(target_arch = "x86_64")] + #[cfg(target_arch = "no_pcie_bar_realloc")] let allocator_opt: Option = None; - #[cfg(not(target_arch = "x86_64"))] + #[cfg(not(target_arch = "no_pcie_bar_realloc"))] let allocator_opt: Option = Some(allocator); let mut rootcomplex = { #[cfg(feature = "dwc_pcie")] { warn!("dwc pcie"); - // DWC PCIe: need dbi_base, cfg_base, etc. - // Get DWC related parameters from config - // Use ecam_base as dbi_base for now, should read from config - let dbi_base = 0x3c0400000; // TODO: should read from config - let cfg_base = rootcomplex_config.ecam_base; // TODO: should read from config - let cfg_size = rootcomplex_config.ecam_size; // TODO: should read from config - let first_busno = rootcomplex_config.bus_range_begin as u8; + let ecam_base = rootcomplex_config.ecam_base; + let atu_config = platform::ROOT_DWC_ATU_CONFIG + .iter() + .find(|atu_cfg| atu_cfg.ecam_base == ecam_base); - RootComplex::new_dwc(dbi_base, cfg_base, cfg_size, first_busno, None) + let atu_config = match atu_config { + Some(cfg) => cfg, + None => { + warn!("No ATU config found for ecam_base 0x{:x}", ecam_base); + return hv_result_err!(EINVAL, "No ATU config found for ecam_base"); + } + }; + + let root_bus = rootcomplex_config.bus_range_begin as u8; + + RootComplex::new_dwc(rootcomplex_config.ecam_base, atu_config, root_bus) } #[cfg(feature = "loongarch64_pcie")] @@ -83,19 +90,17 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { RootComplex::new_loongarch(rootcomplex_config.ecam_base) } - #[cfg(all(not(feature = "dwc_pcie"), not(feature = "loongarch64_pcie")))] + #[cfg(feature = "ecam_pcie")] { - // default use ECAM - RootComplex::new(rootcomplex_config.ecam_base) + RootComplex::new_ecam(rootcomplex_config.ecam_base) } + }; - - let e = rootcomplex.enumerate(None, allocator_opt); + let range = rootcomplex_config.bus_range_begin as usize..rootcomplex_config.bus_range_end as usize; + let e = rootcomplex.enumerate(Some(range), allocator_opt); info!("begin enumerate {:#?}", e); - for mut node in e { - // Capabilities are already enumerated in get_node() during device discovery - // But we call capability_enumerate() explicitly to ensure they are processed - node.capability_enumerate(); + for node in e { + info!("node {:#?}", node); GLOBAL_PCIE_LIST.lock().insert(node.get_bdf(), node); } } @@ -114,8 +119,8 @@ 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 << 12); - let vbdf = Bdf::from_address(dev_config.vbdf << 12); + let bdf = ::from_address(dev_config.bdf << 12); + let vbdf = ::from_address(dev_config.vbdf << 12); #[cfg(any( all(feature = "iommu", target_arch = "aarch64"), target_arch = "x86_64" @@ -126,7 +131,7 @@ impl Zone { } else { 0 }; - iommu_add_device(zone_id, (bdf.to_address(0) >> 12) as _, iommu_pt_addr); + iommu_add_device(zone_id, dev_config.bdf as _, iommu_pt_addr); } if bdf.is_host_bridge() { if let Some(vdev) = guard.get(&bdf) { @@ -153,53 +158,71 @@ impl Zone { pub fn virtual_pci_mmio_init( &mut self, pci_rootcomplex_config: &[HvPciConfig; CONFIG_PCI_BUS_MAXNUM], - _num_pci_bus: u64, + _num_pci_config: usize, ) { for rootcomplex_config in pci_rootcomplex_config { /* empty config */ if rootcomplex_config.ecam_base == 0 { continue; } - self.mmio_region_register( + #[cfg(feature = "ecam_pcie")] + { + self.mmio_region_register( rootcomplex_config.ecam_base as usize, rootcomplex_config.ecam_size as usize, mmio_vpci_handler, - 0, + rootcomplex_config.ecam_base as usize, ); + } + // #[cfg(feature = "dwc_pcie")] + { + self.mmio_region_register( + rootcomplex_config.ecam_base as usize, + rootcomplex_config.ecam_size as usize, + mmio_vpci_handler_dbi, + rootcomplex_config.ecam_base as usize, + ); + #[cfg(feature = "dwc_pcie")] + { + let extend_config = platform::ROOT_DWC_ATU_CONFIG + .iter() + .find(|extend_cfg| extend_cfg.ecam_base == rootcomplex_config.ecam_base); + + if let Some(extend_config) = extend_config { + if extend_config.apb_base != 0 && extend_config.apb_size != 0 { + self.mmio_region_register( + extend_config.apb_base as usize, + extend_config.apb_size as usize, + mmio_generic_handler, + extend_config.apb_base as usize, + ); + } + + let cfg_size_half = extend_config.cfg_size / 2; + let cfg0_base = extend_config.cfg_base; + if cfg0_base != 0 && cfg_size_half != 0 { + self.mmio_region_register( + cfg0_base as usize, + cfg_size_half as usize, + mmio_vpci_handler, + cfg0_base as usize, + ); + } + + let cfg1_base = extend_config.cfg_base + cfg_size_half; + if cfg1_base != 0 && cfg_size_half != 0 { + self.mmio_region_register( + cfg1_base as usize, + cfg_size_half as usize, + mmio_vpci_handler, + cfg1_base as usize, + ); + } + } else { + warn!("No extend config found for base 0x{:x}", rootcomplex_config.ecam_base); + } + } + } } } -} - -pub fn mmio_vpci_handler_apb(mmio: &mut MMIOAccess, _base: usize) -> HvResult { - mmio_perform_access(_base, mmio); - warn!( - "apb 0x{:x}+0x{:x} {} 0x{:x}", - _base, - mmio.address, - if mmio.is_write { "write" } else { "read" }, - mmio.value - ); - Ok(()) -} -pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { - mmio_perform_access(_base, mmio); - warn!( - "dbi 0x{:x}+0x{:x} {} 0x{:x}", - _base, - mmio.address, - if mmio.is_write { "write" } else { "read" }, - mmio.value - ); - Ok(()) -} -pub fn mmio_vpci_handler_conf(mmio: &mut MMIOAccess, _base: usize) -> HvResult { - mmio_perform_access(_base, mmio); - warn!( - "conf 0x{:x}+0x{:x} {} 0x{:x}", - _base, - mmio.address, - if mmio.is_write { "write" } else { "read" }, - mmio.value - ); - Ok(()) -} +} \ No newline at end of file diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 5e868190..b1d31dd1 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -30,7 +30,7 @@ use super::{ EndpointField, EndpointHeader, HeaderType, PciBridgeHeader, PciCommand, PciConfigHeader, PciMem, PciMemType, PciRW, }, - config_accessors::{PciRegion, PciConfigMmio, PciConfigAccessor, get_default_accessor_type, create_accessor, PciAccessorType}, + config_accessors::{PciConfigMmio, PciConfigAccessor, BdfAddressConversion}, PciConfigAddress, }; @@ -77,23 +77,7 @@ impl Bdf { } 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 + ::from_address(address) } pub fn is_host_bridge(&self) -> bool { @@ -107,7 +91,10 @@ impl Bdf { impl Ord for Bdf { fn cmp(&self, other: &Self) -> Ordering { - self.to_address(0).cmp(&other.to_address(0)) + self.bus + .cmp(&other.bus) + .then_with(|| self.device.cmp(&other.device)) + .then_with(|| self.function.cmp(&other.function)) } } @@ -227,10 +214,14 @@ impl VirtualPciAccessBits { */ #[derive(Clone)] pub struct VirtualPciConfigSpace { + host_bdf: Bdf, + parent_bdf: Bdf, bdf: Bdf, vbdf: Bdf, config_type: HeaderType, + base: PciConfigAddress, + space: [u8; BIT_LENTH], control: VirtualPciConfigControl, access: VirtualPciAccessBits, @@ -303,21 +294,24 @@ 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 + "\n bdf {:#?}\n vbdf {:#?}\n type {:#?}\n {:#?} {:#?}", + self.bdf, self.vbdf, self.config_type, self.bararr, self.rom ) } } impl VirtualPciConfigSpace { - pub fn endpoint(bdf: Bdf, backend: Arc, bararr: Bar, rom: PciMem) -> Self { + pub fn endpoint(bdf: Bdf, base: PciConfigAddress, backend: Arc, bararr: Bar, rom: PciMem) -> Self { Self { + host_bdf: Bdf::default(), + parent_bdf: Bdf::default(), bdf, vbdf: Bdf::default(), + config_type: HeaderType::Endpoint, + base, space: [0u8; BIT_LENTH], control: VirtualPciConfigControl::endpoint(), access: VirtualPciAccessBits::endpoint(), - config_type: HeaderType::Endpoint, backend, bararr, rom, @@ -325,29 +319,35 @@ impl VirtualPciConfigSpace { } } - pub fn bridge(bdf: Bdf, backend: Arc, bararr: Bar) -> Self { + pub fn bridge(bdf: Bdf, base: PciConfigAddress, backend: Arc, bararr: Bar, rom: PciMem) -> Self { Self { + host_bdf: Bdf::default(), + parent_bdf: Bdf::default(), bdf, vbdf: Bdf::default(), + config_type: HeaderType::PciBridge, + base, space: [0u8; BIT_LENTH], control: VirtualPciConfigControl::bridge(), access: VirtualPciAccessBits::bridge(), - config_type: HeaderType::PciBridge, backend, bararr, - rom: PciMem::default(), + rom, capabilities: PciCapabilityList::new(), } } - pub fn unknown(bdf: Bdf, backend: Arc) -> Self { + pub fn unknown(bdf: Bdf, base: PciConfigAddress, backend: Arc) -> Self { Self { + host_bdf: Bdf::default(), + parent_bdf: Bdf::default(), bdf, vbdf: Bdf::default(), + config_type: HeaderType::Endpoint, + base, space: [0u8; BIT_LENTH], control: VirtualPciConfigControl::endpoint(), access: VirtualPciAccessBits::endpoint(), - config_type: HeaderType::Endpoint, backend, bararr: Bar::default(), rom: PciMem::default(), @@ -355,14 +355,17 @@ impl VirtualPciConfigSpace { } } - pub fn host_bridge(bdf: Bdf, backend: Arc) -> Self { + pub fn host_bridge(bdf: Bdf, base: PciConfigAddress, backend: Arc) -> Self { Self { + host_bdf: bdf, + parent_bdf: bdf, bdf: bdf, vbdf: bdf, + config_type: HeaderType::Endpoint, + base, space: [0u8; BIT_LENTH], control: VirtualPciConfigControl::host_bridge(), access: VirtualPciAccessBits::host_bridge(), - config_type: HeaderType::Endpoint, backend, bararr: Bar::default(), rom: PciMem::default(), @@ -370,6 +373,14 @@ impl VirtualPciConfigSpace { } } + pub fn set_host_bdf(&mut self, host_bdf: Bdf) { + self.host_bdf = host_bdf; + } + + pub fn set_parent_bdf(&mut self, parent_bdf: Bdf) { + self.parent_bdf = parent_bdf; + } + pub fn get_bdf(&self) -> Bdf { self.bdf } @@ -386,6 +397,10 @@ impl VirtualPciConfigSpace { self.vbdf = vbdf; } + pub fn get_base(&self) -> PciConfigAddress { + self.base + } + /* now the space_init just with bar */ pub fn space_init(&mut self) { @@ -489,16 +504,10 @@ pub struct PciIterator { } impl PciIterator { - fn address(&self) -> PciConfigAddress { - let parent = self.stack.last().unwrap(); - let bus = parent.secondary_bus; - let device = parent.device; - let function = self.function; - - let bdf = Bdf::new(bus, device, function); + fn address(&self, parent_bus: u8, bdf: Bdf) -> PciConfigAddress { let offset = 0; - match self.accessor.get_physical_address(bdf, offset) { + match self.accessor.get_physical_address(bdf, offset, parent_bus) { Ok(addr) => addr, Err(_) => { 0x0 @@ -507,26 +516,44 @@ impl PciIterator { } fn get_node(&mut self) -> Option { - let mut parent = self.stack.last_mut().unwrap(); - let bus = parent.secondary_bus; - let device = parent.device; - let function = self.function; - let bdf = Bdf::new(bus, device, function); - - if let Err(e) = self.accessor.prepare_access(bdf) { - // Only warn if it's not a device that should be skipped - warn!("prepare access failed: {:?}", e); - return None; + // Handle placeholder: pop it first, use bus_range.start for initial scan + let was_placeholder = self.stack.last().map(|b| b.mmio.is_placeholder()).unwrap_or(false); + if was_placeholder { + self.stack.pop(); // Remove placeholder } - let address = self.address(); - info!("get node {:x}", address); + let (bus, device, function, parent_bus) = if let Some(parent) = self.stack.last() { + // device is already added in next() + (parent.bus, parent.device, self.function, parent.primary_bus) + } else { + // host bridge, so device is 0 + let bus_begin = self.bus_range.start as u8; + (bus_begin, 0, self.function, bus_begin) + }; + + let bdf = Bdf::new(bus, device, function); + + let address = self.address(parent_bus, bdf); + info!("get node {:x} {:#?}", address, bdf); let region = PciConfigMmio::new(address, CONFIG_LENTH); let pci_header = PciConfigHeader::new_with_region(region); let (vender_id, _device_id) = pci_header.id(); - if vender_id == 0xffff { - warn!("get none"); + + warn!("vender_id {:#x}", vender_id); + + // Check if device exists + if vender_id == 0xffff || self.accessor.skip_device(bdf) { + if function == 0 { + // Function 0 doesn't exist, so device doesn't exist at all + // Skip all functions and move to next device + warn!("get none - device not present (vendor_id=0xffff) at {:#?}", bdf); + self.function = 0; + self.is_mulitple_function = false; + } else { + // Function > 0 doesn't exist, but device might have other functions + warn!("get none - function not present (vendor_id=0xffff) at {:#?}", bdf); + } return None; } @@ -534,8 +561,16 @@ impl PciIterator { match pci_header.header_type() { HeaderType::Endpoint => { + // For endpoint: push host_bridge if we popped placeholder + if was_placeholder { + let bus_begin = self.bus_range.start as u8; + let host_bridge = Bridge::host_bridge(self.segment, bus_begin); + self.stack.push(host_bridge); + } + let mut ep = EndpointHeader::new_with_region(region); - let rom = ep.parse_rom(); + let rom = Self::rom_init(&mut ep); + let bararr = Self::bar_mem_init(ep.bar_limit().into(), &mut self.allocator, &mut ep); @@ -543,23 +578,23 @@ impl PciIterator { info!("get node bar mem init end {:#?}", bararr); let ep = Arc::new(ep); - let bdf = Bdf::from_address(address); - let mut node = VirtualPciConfigSpace::endpoint(bdf, ep, bararr, rom); + let mut node = VirtualPciConfigSpace::endpoint(bdf, address, ep, bararr, rom); let _ = node.capability_enumerate(); Some(node) } HeaderType::PciBridge => { + // For bridge: don't push host_bridge, it will be handled in Iterator::next() warn!("bridge"); let mut bridge = PciBridgeHeader::new_with_region(region); + let rom = Self::rom_init(&mut bridge); 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); - let mut node = VirtualPciConfigSpace::bridge(bdf, bridge, bararr); + let mut node = VirtualPciConfigSpace::bridge(bdf, address, bridge, bararr, rom); let _ = node.capability_enumerate(); @@ -568,12 +603,19 @@ impl PciIterator { _ => { warn!("unknown type"); let pci_header = Arc::new(pci_header); - let bdf = Bdf::from_address(address); - Some(VirtualPciConfigSpace::unknown(bdf, pci_header)) + Some(VirtualPciConfigSpace::unknown(bdf, address, pci_header)) } } } + fn rom_init( + dev: &mut D, + ) -> PciMem { + let mut rom = dev.parse_rom(); + rom.set_virtual_value(rom.get_value() as u64); + rom + } + fn bar_mem_init( bar_max: usize, allocator: &mut Option, @@ -643,7 +685,7 @@ impl PciIterator { match a { Some(bridge) => bridge.clone(), None => { - unreachable!("get null stack") + unreachable!("get bridge none"); } } } @@ -702,9 +744,18 @@ impl PciIterator { return; } - if self.is_next_function_max() { - while self.next_device_not_ok() { - } + // Try next function first if device supports multiple functions + if self.is_mulitple_function && self.function < MAX_FUNCTION { + // Device supports multiple functions and we haven't checked all functions yet + self.function += 1; + return; + } + + // All functions of this device have been checked (or device doesn't support multiple functions) + // Move to next device + self.function = 0; + while self.next_device_not_ok() { + // Keep moving to next device until we find a valid one or finish } } } @@ -717,8 +768,23 @@ impl Iterator for PciIterator { while !self.is_finish { if let Some(mut node) = self.get_node() { node.space_init(); + let bus_begin = self.bus_range.start as u8; + // Ensure stack has a parent (host bridge if empty) + if self.stack.is_empty() { + let host_bridge = Bridge::host_bridge(self.segment, bus_begin); + self.stack.push(host_bridge); + } + let parent = self.stack.last().unwrap(); // Safe because we just ensured it exists + let host_bdf = Bdf::new(bus_begin, 0, 0); + let parent_bdf = Bdf::new(parent.bus, parent.device, 0); + let parent_bus = parent.primary_bus; + node.set_host_bdf(host_bdf); + node.set_parent_bdf(parent_bdf); self.next(match node.config_type { - HeaderType::PciBridge => Some(self.get_bridge().next_bridge(self.address(), node.has_secondary_link())), + HeaderType::PciBridge => { + let bdf = Bdf::new(parent.bus, parent.device, parent.subordinate_bus); + Some(self.get_bridge().next_bridge(self.address(parent_bus, bdf), node.has_secondary_link())) + }, _ => None, }); return Some(node); @@ -732,6 +798,7 @@ impl Iterator for PciIterator { #[derive(Debug, Clone)] pub struct Bridge { + bus: u8, device: u8, subordinate_bus: u8, secondary_bus: u8, @@ -741,8 +808,23 @@ pub struct Bridge { } impl Bridge { + /// Create a placeholder bridge for initializing the stack. + /// This is not a real host bridge, just a placeholder to track bus hierarchy. + pub fn placeholder() -> Self { + Self { + bus: 0, + device: 0, + subordinate_bus: 0, + secondary_bus: 0, + primary_bus: 0, + mmio: PciConfigMmio::new(0, 0), // Dummy mmio for placeholder + has_secondary_link: false, + } + } + pub fn host_bridge(address: PciConfigAddress, bus_begin: u8) -> Self { Self { + bus: bus_begin, device: 0, subordinate_bus: bus_begin, secondary_bus: bus_begin, @@ -754,23 +836,39 @@ impl Bridge { pub fn next_bridge(&self, address: PciConfigAddress, has_secondary_link: bool) -> Self { let mmio = PciConfigMmio::new(address, CONFIG_LENTH); - warn!("bridge has_secondary_link: {}", has_secondary_link); + warn!("next_bridge \n + bus {}\n + device {}\n + subordinate_bus {}\n + secondary_bus {}\n + primary_bus {}\n + has_secondary_link {}", + self.subordinate_bus + 1, 0, self.subordinate_bus, self.secondary_bus, self.primary_bus, has_secondary_link); Self { + bus: self.subordinate_bus + 1, device: 0, subordinate_bus: self.subordinate_bus + 1, secondary_bus: self.subordinate_bus + 1, - primary_bus: self.secondary_bus, + primary_bus: self.bus, mmio, has_secondary_link, } } 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); + // Skip update for placeholder bridges (they don't have real mmio) + if self.mmio.is_placeholder() { + return; + } + // Direct memory access using the access method + unsafe { + let ptr = self.mmio.access::(0x18); + let mut value = ptr.read_volatile(); + 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()); + ptr.write_volatile(value); + } } pub fn set_has_secondary_link(&mut self, value: bool) { @@ -785,20 +883,6 @@ pub struct RootComplex { } impl RootComplex { - // Create RootComplex, automatically select accessor type based on feature - pub fn new(mmio_base: PciConfigAddress) -> Self { - let accessor_type = get_default_accessor_type(); - let accessor = create_accessor( - accessor_type, - mmio_base - ); - - Self { - mmio_base, - accessor, - } - } - fn __enumerate( &mut self, range: Option>, @@ -808,7 +892,7 @@ impl RootComplex { let range = range.unwrap_or_else(|| 0..0x100); PciIterator { allocator: bar_alloc, - stack: vec![Bridge::host_bridge(mmio_base, range.start as u8)], + stack: vec![Bridge::placeholder()], segment: mmio_base, bus_range: range, function: 0, @@ -823,8 +907,6 @@ impl RootComplex { range: Option>, bar_alloc: Option, ) -> PciIterator { - // DBI initialization is handled by the accessor in prepare_access - // No need to call dbi_init here self.__enumerate(range, bar_alloc) } } @@ -832,12 +914,14 @@ impl RootComplex { #[derive(Debug)] pub struct VirtualRootComplex { devs: BTreeMap, + base_to_bdf: BTreeMap, } impl VirtualRootComplex { pub fn new() -> Self { Self { devs: BTreeMap::new(), + base_to_bdf: BTreeMap::new(), } } @@ -846,6 +930,8 @@ impl VirtualRootComplex { bdf: Bdf, dev: VirtualPciConfigSpace, ) -> Option { + let base = dev.get_base(); + self.base_to_bdf.insert(base, bdf); self.devs.insert(bdf, dev) } @@ -860,6 +946,11 @@ impl VirtualRootComplex { pub fn get_mut(&mut self, bdf: &Bdf) -> Option<&mut VirtualPciConfigSpace> { self.devs.get_mut(bdf) } + + pub fn get_device_by_base(&mut self, base: PciConfigAddress) -> Option<&mut VirtualPciConfigSpace> { + let bdf = self.base_to_bdf.get(&base).copied()?; + self.devs.get_mut(&bdf) + } } #[derive(Debug)] @@ -885,7 +976,7 @@ impl CapabilityIterator { } pub fn get_extension(&self) -> u16 { - self.backend.read(self.offset, 2).unwrap().get_bits(16..32) as u16 + self.backend.read(self.offset, 4).unwrap().get_bits(16..32) as u16 } } @@ -893,10 +984,21 @@ impl Iterator for CapabilityIterator { type Item = PciCapability; fn next(&mut self) -> Option { + if self.offset == 0x34 { + let first_cap_offset = self.backend.read(0x34, 1).unwrap() as PciConfigAddress; + if first_cap_offset == 0 { + return None; + } + self.offset = first_cap_offset; + } + while self.get_offset() != 0 { + warn!("get cap {:#x}", self.get_offset()); + // Get current capability before moving to next 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()); + warn!("cap value {:x}", self.backend.read(self.offset, 4).unwrap()); + // Move to next capability let _ = self.get_next_cap(); if let Some(cap) = cap { return Some(cap); @@ -1116,7 +1218,6 @@ impl VirtualPciConfigSpace { PciCapability::Msi(_) => {} PciCapability::MsiX(_) => {} PciCapability::PciExpress(_) => {} - _ => {} } capabilities.insert(capability.get_offset(), capability); @@ -1128,24 +1229,28 @@ impl VirtualPciConfigSpace { pub fn has_secondary_link(&self) -> bool { match self.config_type { HeaderType::PciBridge => { - // Find PciExpress capability - for (_, capability) in &self.capabilities { - if let PciCapability::PciExpress(PciCapabilityRegion { offset, .. }) = capability { - // Read PCIe Capability Register at offset + 0x00 - // Bits 4:0 contain the Device/Port Type - if let Ok(cap_reg) = self.backend.read(*offset, 2) { - let type_val = (cap_reg as u16).get_bits(0..5); - if type_val == PCI_EXP_TYPE_ROOT_PORT || type_val == PCI_EXP_TYPE_PCIE_BRIDGE { - return true; - } else if type_val == PCI_EXP_TYPE_UPSTREAM || type_val == PCI_EXP_TYPE_DOWNSTREAM { - // Parent check is not implemented, set to false for now - return false; - } - } - break; - } - } - false + // // Find PciExpress capability + // for (_, capability) in &self.capabilities { + // if let PciCapability::PciExpress(PciCapabilityRegion { offset, .. }) = capability { + // // Read PCIe Capability Register at offset + 0x00 + // // Bits 4:0 contain the Device/Port Type + // if let Ok(cap_reg) = self.backend.read(*offset, 2) { + // let type_val = (cap_reg as u16).get_bits(0..5); + // if type_val == PCI_EXP_TYPE_ROOT_PORT || type_val == PCI_EXP_TYPE_PCIE_BRIDGE { + // return true; + // } else if type_val == PCI_EXP_TYPE_UPSTREAM || type_val == PCI_EXP_TYPE_DOWNSTREAM { + // // Parent check is not implemented, set to false for now + // return false; + // } + // } + // break; + // } + // } + // false + #[cfg(feature = "dwc_pcie")] + return true; + #[cfg(not(feature = "dwc_pcie"))] + return false; } _ => false, } diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs index 494896bd..6fef8ca1 100644 --- a/src/pci/pci_test.rs +++ b/src/pci/pci_test.rs @@ -44,10 +44,10 @@ pub fn pcie_test() { 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); - } + // 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() { @@ -58,12 +58,12 @@ pub fn pcie_guest_init() { 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 base = 0x4010000000; // Base address for test let backend = EndpointHeader::new_with_region(PciConfigMmio::new( - bdf.to_address(0) + 0x4010000000, + base, CONFIG_LENTH, )); - let dev = VirtualPciConfigSpace::host_bridge(bdf, Arc::new(backend)); + let dev = VirtualPciConfigSpace::host_bridge(bdf, base, Arc::new(backend)); vbus.insert(vbdf, dev); let vbdf = Bdf::from_str("0000:00:01.0").unwrap(); @@ -103,8 +103,18 @@ pub fn pcie_guest_init() { } pub fn pcie_guest_test() { + let zone = this_zone(); + let vbus = &zone.read().vpci_bus; + let bdf = Bdf::from_str("0000:00:01.0").unwrap(); + // Get base from VirtualPciConfigSpace and add offset + let address = if let Some(vdev) = vbus.get(&bdf) { + vdev.get_base() + 0x24 + } else { + warn!("can not find dev {:#?} for test", bdf); + 0 + }; let mut mmio = MMIOAccess { - address: Bdf::from_str("0000:00:01.0").unwrap().to_address(0x24) as _, + address: address as _, size: 4, is_write: false, value: 0x0, diff --git a/src/zone.rs b/src/zone.rs index f4cb5df4..c3925aaf 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -210,8 +210,12 @@ pub fn zone_create(config: &HvZoneConfig) -> HvResult>> { zone.pt_init(config.memory_regions()).unwrap(); zone.mmio_init(&config.arch_config); - let _ = zone.virtual_pci_mmio_init(&config.pci_config, config.num_pci_bus); - let _ = zone.guest_pci_init(zone_id, &config.alloc_pci_devs, config.num_pci_devs); + #[cfg(feature = "pci")] + { + let _ = zone.virtual_pci_mmio_init(&config.pci_config, config.num_pci_bus as usize); + let _ = zone.guest_pci_init(zone_id, &config.alloc_pci_devs, config.num_pci_devs); + } + // #[cfg(target_arch = "aarch64")] // zone.ivc_init(config.ivc_config()); From 54c8e441278929e49ba7c94000405650461f544e Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 20 Nov 2025 02:32:14 +0800 Subject: [PATCH 023/109] fix rk3568 config --- platform/aarch64/rk3568/board.rs | 71 ++++++++------- platform/aarch64/rk3568/cargo/features | 3 + .../rk3568/image/dts/rk3568_limit_zone0.dts | 33 ++++--- src/pci/pci_access.rs | 67 ++++++++------ src/pci/pci_config.rs | 89 +++++++++---------- src/pci/pci_struct.rs | 35 +++++--- 6 files changed, 163 insertions(+), 135 deletions(-) diff --git a/platform/aarch64/rk3568/board.rs b/platform/aarch64/rk3568/board.rs index 86e10fa7..5c8676b0 100644 --- a/platform/aarch64/rk3568/board.rs +++ b/platform/aarch64/rk3568/board.rs @@ -56,36 +56,36 @@ 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] = &[ - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0x3c0400000, - virtual_start: 0x3c0400000, - size: 0x400000, - }, //pcie - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0xfe270000, - virtual_start: 0xfe270000, - size: 0x10000, - }, //pcie - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0xf2000000, - virtual_start: 0xf2000000, - size: 0x100000, - }, //pcie - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0xf2100000, - virtual_start: 0xf2100000, - size: 0x100000, - }, //pcie - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0xf2200000, - virtual_start: 0xf2200000, - size: 0x1e00000, - }, //pcie + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_IO, + // physical_start: 0x3c0400000, + // virtual_start: 0x3c0400000, + // size: 0x400000, + // }, //pcie + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_IO, + // physical_start: 0xfe270000, + // virtual_start: 0xfe270000, + // size: 0x10000, + // }, //pcie + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_IO, + // physical_start: 0xf2000000, + // virtual_start: 0xf2000000, + // size: 0x100000, + // }, //pcie + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_IO, + // physical_start: 0xf2100000, + // virtual_start: 0xf2100000, + // size: 0x100000, + // }, //pcie + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_IO, + // physical_start: 0xf2200000, + // virtual_start: 0xf2200000, + // size: 0x1e00000, + // }, //pcie HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x340000000, @@ -294,7 +294,7 @@ pub const ROOT_PCI_CONFIG: &[HvPciConfig] = &[ // }, HvPciConfig { ecam_base: 0x3c0400000, - ecam_size: 0x100000, + ecam_size: 0x400000, io_base: 0xf2100000, io_size: 0x100000, pci_io_base: 0xf2100000, @@ -331,8 +331,8 @@ pub const ROOT_DWC_ATU_CONFIG: &[HvDwcAtuConfig] = &[ ecam_base: 0x3c0400000, dbi_base: 0x3c0400000, dbi_size: 0x10000, - apb_base: 0, - apb_size: 0, + apb_base: 0xfe270000, + apb_size: 0x10000, cfg_base: 0xf2000000, cfg_size: 0x80000*2, cfg0_atu_index: 0, @@ -348,8 +348,7 @@ pub const ROOT_DWC_ATU_CONFIG: &[HvDwcAtuConfig] = &[ }, ]; -pub const ROOT_PCI_DEVS: [HvPciDevConfig; 3] = [ - pci_dev!( 0x1, 0x0, 0x0), +pub const ROOT_PCI_DEVS: [HvPciDevConfig; 2] = [ + pci_dev!(0x10, 0x0, 0x0), pci_dev!(0x11, 0x0, 0x0), - pci_dev!(0x21, 0x0, 0x0), ]; \ No newline at end of file diff --git a/platform/aarch64/rk3568/cargo/features b/platform/aarch64/rk3568/cargo/features index afa59489..0b11e0fa 100644 --- a/platform/aarch64/rk3568/cargo/features +++ b/platform/aarch64/rk3568/cargo/features @@ -1,2 +1,5 @@ gicv3 uart_16550 +pci +dwc_pcie +no_pcie_bar_realloc \ No newline at end of file diff --git a/platform/aarch64/rk3568/image/dts/rk3568_limit_zone0.dts b/platform/aarch64/rk3568/image/dts/rk3568_limit_zone0.dts index 5687c1cc..420426e8 100644 --- a/platform/aarch64/rk3568/image/dts/rk3568_limit_zone0.dts +++ b/platform/aarch64/rk3568/image/dts/rk3568_limit_zone0.dts @@ -318,6 +318,17 @@ supports-emmc; }; + sdio-pwrseq { + pinctrl-names = "default"; + pinctrl-0 = <0x136>; + clock-names = "ext_clock"; + clocks = <0x135 0x01>; + reset-gpios = <0x83 0x1d 0x01>; + compatible = "mmc-pwrseq-simple"; + post-power-on-delay-ms = <0xc8>; + phandle = <0x9f>; + }; + dwmmc@fe000000 { fifo-depth = <0x100>; pinctrl-names = "default"; @@ -407,10 +418,10 @@ ftrace-size = <0x00>; }; - hvisor@60080000 { - no-map; - reg = <0x00 0x60080000 0x00 0x400000>; - }; + // hvisor@0x2000000 { + // no-map; + // reg = <0x00 0x2000000 0x00 0x1000000>; + // }; nonroot { no-map; @@ -641,13 +652,13 @@ phandle = <0x01>; interrupt-controller; - interrupt-controller@fd440000 { - msi-controller; - compatible = "arm,gic-v3-its"; - reg = <0x00 0xfd440000 0x00 0x20000>; - phandle = <0xad>; - #msi-cells = <0x01>; - }; + // interrupt-controller@fd440000 { + // msi-controller; + // compatible = "arm,gic-v3-its"; + // reg = <0x00 0xfd440000 0x00 0x20000>; + // phandle = <0xad>; + // #msi-cells = <0x01>; + // }; }; diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index e1504ec1..3ee9f960 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -187,7 +187,7 @@ impl PciMem { pub fn get_size_with_flag(&mut self) -> u64 { match self.bar_type { - PciMemType::Mem32 | PciMemType::Rom => !(self.size - 1u64), + PciMemType::Mem32 | PciMemType::Rom | PciMemType::Io => !(self.size - 1u64), PciMemType::Mem64Low => { let bar_size = !(self.size - 1); bar_size.get_bits(0..32) @@ -322,9 +322,9 @@ impl PciMem { self.virtual_value = val; } - pub fn set_virtual_value64(&mut self, value: u64) { - self.virtual_value = value; - } + // pub fn set_virtual_value(&mut self, value: u64) { + // self.virtual_value = value; + // } } impl Debug for PciMem { @@ -562,6 +562,7 @@ pub trait PciBarRW: PciRWBase { match value.get_bits(1..3) { 0b00 => { + // 32-bit memory space let size = { let _ = self.write_bar(slot, 0xffffffff); let mut readback = self.read_bar(slot).unwrap(); @@ -579,6 +580,7 @@ pub trait PciBarRW: PciRWBase { PciMem::new_bar(PciMemType::Mem32, value as u64, size as u64, pre); } 0b10 => { + // 64-bit memory space if slot == 5 { warn!("read bar64 in last bar"); break; @@ -601,7 +603,7 @@ pub trait PciBarRW: PciRWBase { 1u64 << ((readback_high.trailing_zeros() + 32) as u64) } }; - let value64 = (value as u64) | ((value_high as u64) << 32); + // let value64 = (value as u64) | ((value_high as u64) << 32); bararr[slot as usize] = PciMem::new_bar(PciMemType::Mem64Low, value as u64, size, pre); @@ -614,6 +616,7 @@ pub trait PciBarRW: PciRWBase { } } } else { + // IO space let size = { let _ = self.write_bar(slot, 0xffffffff); let mut readback = self.read_bar(slot).unwrap(); @@ -987,7 +990,7 @@ fn handle_config_space_access( match dev.access(offset, size) { false => { - info!( + debug!( "hw vbdf {:#?} reg 0x{:x} try {} {}", vbdf, offset, @@ -1005,7 +1008,7 @@ fn handle_config_space_access( } } true => { - info!( + debug!( "emu vbdf {:#?} reg 0x{:x} try {} {}", vbdf, offset, @@ -1037,6 +1040,7 @@ fn handle_config_space_access( */ if (bar_type == PciMemType::Mem32) | (bar_type == PciMemType::Mem64High) + | (bar_type == PciMemType::Io) { let old_vaddr = bar.get_virtual_value64() & !0xf; let new_vaddr = { @@ -1084,10 +1088,16 @@ fn handle_config_space_access( dev.set_bar_virtual_value(slot - 1, new_vaddr); } + let bar_size = if crate::memory::addr::is_aligned(bar.get_size() as usize) { + bar.get_size() + } else { + crate::memory::PAGE_SIZE as u64 + }; + gpm.insert(MemoryRegion::new_with_offset_mapper( new_vaddr as GuestPhysAddr, paddr as HostPhysAddr, - bar.get_size() as _, + bar_size as _, MemFlags::READ | MemFlags::WRITE, ))?; /* after update gpm, mem barrier is needed @@ -1146,6 +1156,7 @@ fn handle_config_space_access( } HeaderType::PciBridge => { // TODO: add emu for bridge, actually it is same with endpoint + warn!("bridge emu rw"); } _ => { warn!("unhanled pci type {:#?}", dev.get_config_type()); @@ -1154,7 +1165,7 @@ fn handle_config_space_access( } } - info!( + debug!( "vbdf {:#?} reg 0x{:x} {} 0x{:x}", vbdf, offset, @@ -1182,7 +1193,7 @@ fn handle_device_not_found(mmio: &mut MMIOAccess, offset: PciConfigAddress) { } pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { - info!("mmio_vpci_handler {:#x}", mmio.address); + // info!("mmio_vpci_handler {:#x}", mmio.address); let zone_id = this_zone_id(); let zone = this_zone(); let mut guard = zone.write(); @@ -1204,28 +1215,30 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { } pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { - info!("mmio_vpci_handler_dbi {:#x}", mmio.address); - let zone_id = this_zone_id(); - let zone = this_zone(); - let mut guard = zone.write(); - let (vbus, gpm) = { - let Zone { gpm, vpci_bus, .. } = &mut *guard; - (vpci_bus, gpm) - }; + // info!("mmio_vpci_handler_dbi {:#x}", mmio.address); - let offset = (mmio.address & 0xfff) as PciConfigAddress; - let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; - - if let Some(dev) = vbus.get_device_by_base(base) { - handle_config_space_access(dev, mmio, offset, gpm, zone_id)?; + if mmio.address >= 0x300000 /* ATU base */ { + mmio_perform_access(_base, mmio); + } else if mmio.address >= BIT_LENTH { + // dbi read + mmio_perform_access(_base, mmio); } else { - if (offset as usize) >= BIT_LENTH { - // dbi read - mmio_perform_access(_base, mmio); + let offset = (mmio.address & 0xfff) as PciConfigAddress; + let zone_id = this_zone_id(); + let zone = this_zone(); + let mut guard = zone.write(); + let (vbus, gpm) = { + let Zone { gpm, vpci_bus, .. } = &mut *guard; + (vpci_bus, gpm) + }; + + let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; + + if let Some(dev) = vbus.get_device_by_base(base) { + handle_config_space_access(dev, mmio, offset, gpm, zone_id)?; } else { handle_device_not_found(mmio, offset); } - } Ok(()) diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 3e87d0a6..ba72ccba 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -133,21 +133,18 @@ impl Zone { }; iommu_add_device(zone_id, dev_config.bdf as _, iommu_pt_addr); } - if bdf.is_host_bridge() { - if let Some(vdev) = guard.get(&bdf) { - let mut vdev = vdev.clone(); + if let Some(dev) = guard.get(&bdf){ + if bdf.is_host_bridge(dev.get_host_bdf().bus()) { + let mut vdev = dev.clone(); vdev.set_vbdf(vbdf); self.vpci_bus.insert(vbdf, vdev); } else { - warn!("can not find host bridge {:#?}", bdf); - } - } else { - if let Some(mut vdev) = guard.remove(&bdf) { + let mut vdev = guard.remove(&bdf).unwrap(); vdev.set_vbdf(vbdf); self.vpci_bus.insert(vbdf, vdev); - } else { - warn!("can not find dev {:#?}", bdf); } + } else { + warn!("can not find dev {:#?}", bdf); } i += 1; } @@ -174,7 +171,7 @@ impl Zone { rootcomplex_config.ecam_base as usize, ); } - // #[cfg(feature = "dwc_pcie")] + #[cfg(feature = "dwc_pcie")] { self.mmio_region_register( rootcomplex_config.ecam_base as usize, @@ -182,45 +179,43 @@ impl Zone { mmio_vpci_handler_dbi, rootcomplex_config.ecam_base as usize, ); - #[cfg(feature = "dwc_pcie")] - { - let extend_config = platform::ROOT_DWC_ATU_CONFIG - .iter() - .find(|extend_cfg| extend_cfg.ecam_base == rootcomplex_config.ecam_base); + + let extend_config = platform::ROOT_DWC_ATU_CONFIG + .iter() + .find(|extend_cfg| extend_cfg.ecam_base == rootcomplex_config.ecam_base); + + if let Some(extend_config) = extend_config { + if extend_config.apb_base != 0 && extend_config.apb_size != 0 { + self.mmio_region_register( + extend_config.apb_base as usize, + extend_config.apb_size as usize, + mmio_generic_handler, + extend_config.apb_base as usize, + ); + } - if let Some(extend_config) = extend_config { - if extend_config.apb_base != 0 && extend_config.apb_size != 0 { - self.mmio_region_register( - extend_config.apb_base as usize, - extend_config.apb_size as usize, - mmio_generic_handler, - extend_config.apb_base as usize, - ); - } - - let cfg_size_half = extend_config.cfg_size / 2; - let cfg0_base = extend_config.cfg_base; - if cfg0_base != 0 && cfg_size_half != 0 { - self.mmio_region_register( - cfg0_base as usize, - cfg_size_half as usize, - mmio_vpci_handler, - cfg0_base as usize, - ); - } - - let cfg1_base = extend_config.cfg_base + cfg_size_half; - if cfg1_base != 0 && cfg_size_half != 0 { - self.mmio_region_register( - cfg1_base as usize, - cfg_size_half as usize, - mmio_vpci_handler, - cfg1_base as usize, - ); - } - } else { - warn!("No extend config found for base 0x{:x}", rootcomplex_config.ecam_base); + let cfg_size_half = extend_config.cfg_size / 2; + let cfg0_base = extend_config.cfg_base; + if cfg0_base != 0 && cfg_size_half != 0 { + self.mmio_region_register( + cfg0_base as usize, + cfg_size_half as usize, + mmio_vpci_handler, + cfg0_base as usize, + ); } + + let cfg1_base = extend_config.cfg_base + cfg_size_half; + if cfg1_base != 0 && cfg_size_half != 0 { + self.mmio_region_register( + cfg1_base as usize, + cfg_size_half as usize, + mmio_vpci_handler, + cfg1_base as usize, + ); + } + } else { + warn!("No extend config found for base 0x{:x}", rootcomplex_config.ecam_base); } } } diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index b1d31dd1..2385da92 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -39,7 +39,7 @@ 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; -pub const BIT_LENTH: usize = 256 * 2; +pub const BIT_LENTH: usize = 128 * 5; // PCIe Device/Port Type values const PCI_EXP_TYPE_ROOT_PORT: u16 = 4; @@ -80,8 +80,8 @@ impl Bdf { ::from_address(address) } - pub fn is_host_bridge(&self) -> bool { - if (self.bus, self.device, self.function) == (0, 0, 0) { + pub fn is_host_bridge(&self, bus_begin: u8) -> bool { + if (self.bus, self.device, self.function) == (bus_begin, 0, 0) { true } else { false @@ -377,6 +377,10 @@ impl VirtualPciConfigSpace { self.host_bdf = host_bdf; } + pub fn get_host_bdf(&self) -> Bdf { + self.host_bdf + } + pub fn set_parent_bdf(&mut self, parent_bdf: Bdf) { self.parent_bdf = parent_bdf; } @@ -650,6 +654,12 @@ impl PciIterator { bararr[i].set_virtual_value(value); let _ = dev.write_bar(i as u8, (value >> 32) as u32); } + PciMemType::Io => { + //TODO: alloc io in hvisor, just set virt value for now + let value = bararr[i].get_value64(); + bararr[i].set_virtual_value(value); + let _ = dev.write_bar(i as u8, value as u32); + } _ => {} } i += 1; @@ -661,17 +671,22 @@ impl PciIterator { match bararr[i].get_type() { PciMemType::Mem32 => { let value = bararr[i].get_value64(); - bararr[i].set_virtual_value64(value as u64); + bararr[i].set_virtual_value(value as u64); let _ = dev.write_bar(i as u8, value as u32); } PciMemType::Mem64Low => { let value = bararr[i].get_value64(); - bararr[i].set_virtual_value64(value); + bararr[i].set_virtual_value(value); let _ = dev.write_bar(i as u8, value as u32); i += 1; - bararr[i].set_virtual_value64(value); + bararr[i].set_virtual_value(value); let _ = dev.write_bar(i as u8, (value >> 32) as u32); } + PciMemType::Io => { + let value = bararr[i].get_value64(); + bararr[i].set_virtual_value(value); + let _ = dev.write_bar(i as u8, value as u32); + } _ => {} } i += 1; @@ -836,14 +851,6 @@ impl Bridge { pub fn next_bridge(&self, address: PciConfigAddress, has_secondary_link: bool) -> Self { let mmio = PciConfigMmio::new(address, CONFIG_LENTH); - warn!("next_bridge \n - bus {}\n - device {}\n - subordinate_bus {}\n - secondary_bus {}\n - primary_bus {}\n - has_secondary_link {}", - self.subordinate_bus + 1, 0, self.subordinate_bus, self.secondary_bus, self.primary_bus, has_secondary_link); Self { bus: self.subordinate_bus + 1, device: 0, From f9251e8cb43725c3e9f7134f4c3fce6b41e5f56a Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 20 Nov 2025 04:12:48 +0800 Subject: [PATCH 024/109] add loongarch64 pcie config --- platform/loongarch64/ls3a5000/cargo/features | 4 +- platform/loongarch64/ls3a6000/board.rs | 2 + src/pci/config_accessors/dwc.rs | 21 ++---- src/pci/config_accessors/ecam.rs | 41 ++--------- src/pci/config_accessors/loongarch64.rs | 72 +++++++------------- src/pci/config_accessors/mod.rs | 27 +------- src/pci/pci_config.rs | 12 ++-- src/pci/pci_struct.rs | 16 +++-- 8 files changed, 60 insertions(+), 135 deletions(-) diff --git a/platform/loongarch64/ls3a5000/cargo/features b/platform/loongarch64/ls3a5000/cargo/features index 2e4766e6..442505f4 100644 --- a/platform/loongarch64/ls3a5000/cargo/features +++ b/platform/loongarch64/ls3a5000/cargo/features @@ -2,4 +2,6 @@ loongson_3a5000 loongson_7a2000 loongson_uart -loongarch64_pcie \ No newline at end of file +pci +loongarch64_pcie +no_pcie_bar_realloc \ No newline at end of file diff --git a/platform/loongarch64/ls3a6000/board.rs b/platform/loongarch64/ls3a6000/board.rs index 37b555f5..56911387 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -157,6 +157,8 @@ pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ HvPciConfig { + bus_range_begin: 0x0, + bus_range_end: 0x1f, ecam_base: 0xfe00000000, ecam_size: 0x20000000, io_base: 0x18408000, diff --git a/src/pci/config_accessors/dwc.rs b/src/pci/config_accessors/dwc.rs index b7a24f26..d9908b22 100644 --- a/src/pci/config_accessors/dwc.rs +++ b/src/pci/config_accessors/dwc.rs @@ -18,7 +18,7 @@ use crate::error::{HvResult, HvErrorNum::*}; use crate::pci::{pci_access::{PciRW, PciRWBase}, pci_struct::{Bdf, RootComplex}, PciConfigAddress}; use crate::config::HvDwcAtuConfig; use alloc::sync::Arc; -use super::{PciConfigAccessor, PciRegion, PciConfigMmio, PciRegionMmio, BdfAddressConversion}; +use super::{PciConfigAccessor, PciRegion, PciConfigMmio, PciRegionMmio}; use super::dwc_atu::{AtuUnroll, AtuConfig, ATU_UNUSED}; use bit_field::BitField; @@ -190,18 +190,9 @@ impl PciConfigAccessor for DwcConfigAccessor { } } -#[cfg(feature = "dwc_pcie")] -impl BdfAddressConversion for Bdf { - fn from_address(address: PciConfigAddress) -> Bdf { - let bdf = address >> 12; - let function = (bdf & 0b111) as u8; - let device = ((bdf >> 3) & 0b11111) as u8; - let bus = (bdf >> 8) as u8; - Bdf { - bus, - device, - function, - } +impl PciConfigMmio { + /* TODO: may here need check whether length exceeds*/ + pub(crate) fn access(&self, offset: PciConfigAddress) -> *mut T { + (self.base + offset) as *mut T } -} - +} \ No newline at end of file diff --git a/src/pci/config_accessors/ecam.rs b/src/pci/config_accessors/ecam.rs index 13bdac8f..ec28c2f4 100644 --- a/src/pci/config_accessors/ecam.rs +++ b/src/pci/config_accessors/ecam.rs @@ -18,7 +18,7 @@ use alloc::sync::Arc; use crate::error::HvResult; use crate::pci::pci_struct::RootComplex; use crate::pci::{pci_struct::Bdf, PciConfigAddress}; -use super::{PciConfigAccessor, PciRegion, PciConfigMmio, BdfAddressConversion}; +use super::{PciConfigAccessor, PciRegion, PciConfigMmio}; use bit_field::BitField; impl RootComplex { @@ -60,41 +60,10 @@ impl PciConfigAccessor for EcamConfigAccessor { } } -impl BdfAddressConversion for Bdf { - fn from_address(address: PciConfigAddress) -> Bdf { - let bdf = address >> 12; - let function = (bdf & 0b111) as u8; - let device = ((bdf >> 3) & 0b11111) as u8; - let bus = (bdf >> 8) as u8; - Bdf { - bus, - device, - function, - } - } -} - -impl PciRegion for PciConfigMmio { - 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(()) +impl PciConfigMmio { + /* TODO: may here need check whether length exceeds*/ + pub(crate) fn access(&self, offset: PciConfigAddress) -> *mut T { + (self.base + offset) as *mut T } } diff --git a/src/pci/config_accessors/loongarch64.rs b/src/pci/config_accessors/loongarch64.rs index 984ed56f..069113e1 100644 --- a/src/pci/config_accessors/loongarch64.rs +++ b/src/pci/config_accessors/loongarch64.rs @@ -16,13 +16,14 @@ use crate::error::HvResult; use crate::pci::{pci_struct::{Bdf, RootComplex}, PciConfigAddress}; -use super::{PciConfigAccessor, PciRegion, PciConfigMmio, BdfAddressConversion}; +use super::{PciConfigAccessor, PciRegion, PciConfigMmio}; use alloc::sync::Arc; use bit_field::BitField; +use crate::arch::loongarch64::mm::LOONGARCH64_UNCACHED_DMW_PREFIX; impl RootComplex { - pub fn new_loongarch(mmio_base: PciConfigAddress) -> Self { - let accessor = Arc::new(LoongArchConfigAccessor::new(mmio_base)); + pub fn new_loongarch(mmio_base: PciConfigAddress, cfg_size: u64, root_bus: u8) -> Self { + let accessor = Arc::new(LoongArchConfigAccessor::new(mmio_base, cfg_size, root_bus)); Self { mmio_base, @@ -31,38 +32,21 @@ impl RootComplex { } } -#[cfg(feature = "loongarch64_pcie")] -impl PciRegion for PciConfigMmio { - fn read_u8(&self, _offset: PciConfigAddress) -> HvResult { - unimplemented!() - } - fn write_u8(&self, _offset: PciConfigAddress, _value: u8) -> HvResult { - unimplemented!() - } - fn read_u16(&self, _offset: PciConfigAddress) -> HvResult { - unimplemented!() - } - fn write_u16(&self, _offset: PciConfigAddress, _value: u16) -> HvResult { - unimplemented!() - } - fn read_u32(&self, _offset: PciConfigAddress) -> HvResult { - unimplemented!() - } - fn write_u32(&self, _offset: PciConfigAddress, _value: u32) -> HvResult { - unimplemented!() - } -} - // LoongArch PCIe accessor implementation // Similar to ECAM, uses standard address calculation #[derive(Debug)] pub struct LoongArchConfigAccessor { - cfg_base: PciConfigAddress, + cfg0: PciConfigAddress, + cfg1: PciConfigAddress, + root_bus: u8, } impl LoongArchConfigAccessor { - pub fn new(cfg_base: PciConfigAddress) -> Self { - Self { cfg_base } + pub fn new(cfg_base: PciConfigAddress, cfg_size: u64, root_bus: u8) -> Self { + let cfg_size_half = cfg_size / 2; + let cfg0 = cfg_base; + let cfg1 = cfg_base + cfg_size_half; + Self { cfg0, cfg1, root_bus } } } @@ -72,13 +56,12 @@ impl PciConfigAccessor for LoongArchConfigAccessor { let device = bdf.device() as PciConfigAddress; let function = bdf.function() as PciConfigAddress; - // LoongArch PCIe uses similar address calculation to ECAM - // base + (bus << 20) + (device << 15) + (function << 12) + offset - let address = self.cfg_base - + (bus << 20) - + (device << 15) - + (function << 12) - + offset; + let address = if bus == self.root_bus as PciConfigAddress{ + self.cfg0 + (offset >> 8) << 23 + device << 10 + function << 7 + (offset & 0xff) + } else { + self.cfg1 + (offset >> 8) << 23 + bus << 15 + device << 10 + function << 7 + (offset & 0xff) + }; + Ok(address) } @@ -87,18 +70,9 @@ impl PciConfigAccessor for LoongArchConfigAccessor { } } -#[cfg(feature = "loongarch64_pcie")] -impl BdfAddressConversion for Bdf { - fn from_address(address: PciConfigAddress) -> Bdf { - let bdf = address >> 12; - let function = (bdf & 0b111) as u8; - let device = ((bdf >> 3) & 0b11111) as u8; - let bus = (bdf >> 8) as u8; - Bdf { - bus, - device, - function, - } +impl PciConfigMmio { + /* TODO: may here need check whether length exceeds*/ + pub(crate) fn access(&self, offset: PciConfigAddress) -> *mut T { + (self.base + offset | LOONGARCH64_UNCACHED_DMW_PREFIX) as *mut T } -} - +} \ No newline at end of file diff --git a/src/pci/config_accessors/mod.rs b/src/pci/config_accessors/mod.rs index 62c3747e..1c0e5124 100644 --- a/src/pci/config_accessors/mod.rs +++ b/src/pci/config_accessors/mod.rs @@ -19,10 +19,6 @@ use core::{any::Any, fmt::Debug}; use crate::error::HvResult; use crate::pci::{pci_struct::Bdf, PciConfigAddress}; -pub trait BdfAddressConversion { - fn from_address(address: PciConfigAddress) -> Bdf; -} - // PCIe region trait for memory-mapped I/O access pub trait PciRegion: Debug + Sync + Send + Any { fn read_u8(&self, offset: PciConfigAddress) -> HvResult; @@ -45,10 +41,7 @@ impl PciConfigMmio { pub fn new(base: PciConfigAddress, length: u64) -> Self { Self { base, length } } - /* TODO: may here need check whether length exceeds*/ - pub(crate) fn access(&self, offset: PciConfigAddress) -> *mut T { - (self.base + offset) as *mut T - } + /// Check if this is a placeholder (dummy) mmio with base address 0 pub fn is_placeholder(&self) -> bool { self.base == 0 && self.length == 0 @@ -97,8 +90,6 @@ impl PciRegion for PciRegionMmio { } } -// Default implementation of PciRegion for PciConfigMmio -#[cfg(not(any(feature = "ecam_pcie", feature = "dwc_pcie", feature = "loongarch64_pcie")))] impl PciRegion for PciConfigMmio { fn read_u8(&self, offset: PciConfigAddress) -> HvResult { unsafe { Ok(self.access::(offset).read_volatile() as u8) } @@ -123,22 +114,6 @@ impl PciRegion for PciConfigMmio { } } -// Default implementation of BdfAddressConversion for Bdf -#[cfg(not(any(feature = "ecam_pcie", feature = "dwc_pcie", feature = "loongarch64_pcie")))] -impl BdfAddressConversion for Bdf { - fn from_address(address: PciConfigAddress) -> Bdf { - let bdf = address >> 12; - let function = (bdf & 0b111) as u8; - let device = ((bdf >> 3) & 0b11111) as u8; - let bus = (bdf >> 8) as u8; - Bdf { - bus, - device, - function, - } - } -} - pub trait PciConfigAccessor: Send + Sync + core::fmt::Debug { // Get physical address from BDF and offset fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress, _parent_bus: u8) -> HvResult; diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index ba72ccba..1ad445a6 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -22,13 +22,16 @@ use crate::{ error::HvResult, memory::mmio_generic_handler, pci::{ - config_accessors::BdfAddressConversion, mem_alloc::BaseAllocator, pci_access::{mmio_vpci_handler, mmio_vpci_handler_dbi}, pci_struct::{Bdf, VirtualPciConfigSpace} + pci_access::{mmio_vpci_handler, mmio_vpci_handler_dbi}, + pci_struct::{Bdf, VirtualPciConfigSpace}, + config_accessors::PciConfigMmio }, zone::Zone, }; use crate::platform; use super::pci_struct::RootComplex; +use crate::pci::mem_alloc::BaseAllocator; pub static GLOBAL_PCIE_LIST: Lazy>> = Lazy::new(|| { let m = BTreeMap::new(); @@ -87,7 +90,8 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { #[cfg(feature = "loongarch64_pcie")] { - RootComplex::new_loongarch(rootcomplex_config.ecam_base) + let root_bus = rootcomplex_config.bus_range_begin as u8; + RootComplex::new_loongarch(rootcomplex_config.ecam_base, rootcomplex_config.ecam_size, root_bus) } #[cfg(feature = "ecam_pcie")] @@ -119,8 +123,8 @@ impl Zone { let mut i = 0; while i < num_pci_devs { let dev_config = alloc_pci_devs[i as usize]; - let bdf = ::from_address(dev_config.bdf << 12); - let vbdf = ::from_address(dev_config.vbdf << 12); + let bdf = Bdf::from_address(dev_config.bdf << 12); + let vbdf = Bdf::from_address(dev_config.vbdf << 12); #[cfg(any( all(feature = "iommu", target_arch = "aarch64"), target_arch = "x86_64" diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 2385da92..69865031 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -30,7 +30,7 @@ use super::{ EndpointField, EndpointHeader, HeaderType, PciBridgeHeader, PciCommand, PciConfigHeader, PciMem, PciMemType, PciRW, }, - config_accessors::{PciConfigMmio, PciConfigAccessor, BdfAddressConversion}, + config_accessors::{PciConfigMmio, PciConfigAccessor}, PciConfigAddress, }; @@ -76,10 +76,18 @@ impl Bdf { self.function } - pub fn from_address(address: PciConfigAddress) -> Self { - ::from_address(address) + pub fn from_address(address: PciConfigAddress) -> Bdf { + let bdf = address >> 12; + let function = (bdf & 0b111) as u8; + let device = ((bdf >> 3) & 0b11111) as u8; + let bus = (bdf >> 8) as u8; + Bdf { + bus, + device, + function, + } } - + pub fn is_host_bridge(&self, bus_begin: u8) -> bool { if (self.bus, self.device, self.function) == (bus_begin, 0, 0) { true From ca7938666ea020cd64431590117414c05b218292 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 20 Nov 2025 04:54:52 +0800 Subject: [PATCH 025/109] fmt --- platform/aarch64/rk3588/board.rs | 2 + platform/x86_64/qemu/board.rs | 2 + src/config.rs | 7 +- src/pci/config_accessors/dwc.rs | 100 ++++++++------------- src/pci/config_accessors/dwc_atu.rs | 88 +++++++++++------- src/pci/config_accessors/ecam.rs | 35 ++++---- src/pci/config_accessors/loongarch64.rs | 46 +++++++--- src/pci/config_accessors/mod.rs | 27 ++++-- src/pci/mod.rs | 4 +- src/pci/pci_access.rs | 61 +++++++------ src/pci/pci_config.rs | 75 +++++++++------- src/pci/pci_struct.rs | 113 ++++++++++++++---------- src/pci/pci_test.rs | 28 +++--- src/zone.rs | 1 - 14 files changed, 335 insertions(+), 254 deletions(-) diff --git a/platform/aarch64/rk3588/board.rs b/platform/aarch64/rk3588/board.rs index b12c6ec1..eb44da23 100644 --- a/platform/aarch64/rk3588/board.rs +++ b/platform/aarch64/rk3588/board.rs @@ -188,6 +188,8 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { }; pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { + bus_range_begin: 0x0, + bus_range_end: 0x1f, ecam_base: 0x4010000000, ecam_size: 0x10000000, io_base: 0x3eff0000, diff --git a/platform/x86_64/qemu/board.rs b/platform/x86_64/qemu/board.rs index 7acc526b..6f4c5c7c 100644 --- a/platform/x86_64/qemu/board.rs +++ b/platform/x86_64/qemu/board.rs @@ -110,6 +110,8 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { }; pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { + bus_range_begin: 0x0, + bus_range_end: 0x1f, ecam_base: 0xe0000000, ecam_size: 0x200000, io_base: 0x0, diff --git a/src/config.rs b/src/config.rs index a05aa13c..4a09b211 100644 --- a/src/config.rs +++ b/src/config.rs @@ -171,6 +171,7 @@ impl HvZoneConfig { &self.ivc_configs[..self.num_ivc_configs as usize] } + #[allow(unused)] pub fn pci_config(&self) -> &[HvPciConfig] { &self.pci_config[..self.num_pci_bus as usize] } @@ -269,15 +270,15 @@ impl HvDwcAtuConfig { cfg_base: 0, cfg_size: 0, cfg0_atu_index: u32::MAX as usize, - cfg0_atu_type: 4, // ATU_TYPE_CFG0 + cfg0_atu_type: 4, // ATU_TYPE_CFG0 cfg1_atu_index: u32::MAX as usize, - cfg1_atu_type: 5, // ATU_TYPE_CFG1 + cfg1_atu_type: 5, // ATU_TYPE_CFG1 mem32_atu_index: u32::MAX as usize, mem32_atu_type: 0, // ATU_TYPE_MEM mem64_atu_index: u32::MAX as usize, mem64_atu_type: 0, // ATU_TYPE_MEM io_atu_index: u32::MAX as usize, - io_atu_type: 2, // ATU_TYPE_IO + io_atu_type: 2, // ATU_TYPE_IO } } } diff --git a/src/pci/config_accessors/dwc.rs b/src/pci/config_accessors/dwc.rs index d9908b22..3681bd91 100644 --- a/src/pci/config_accessors/dwc.rs +++ b/src/pci/config_accessors/dwc.rs @@ -14,54 +14,35 @@ // Authors: // -use crate::error::{HvResult, HvErrorNum::*}; -use crate::pci::{pci_access::{PciRW, PciRWBase}, pci_struct::{Bdf, RootComplex}, PciConfigAddress}; -use crate::config::HvDwcAtuConfig; use alloc::sync::Arc; -use super::{PciConfigAccessor, PciRegion, PciConfigMmio, PciRegionMmio}; -use super::dwc_atu::{AtuUnroll, AtuConfig, ATU_UNUSED}; use bit_field::BitField; +use super::{ + dwc_atu::{AtuConfig, AtuUnroll, ATU_UNUSED}, + PciConfigAccessor, PciConfigMmio, PciRegion, PciRegionMmio, +}; + +use crate::{ + config::HvDwcAtuConfig, + error::{HvErrorNum::*, HvResult}, + pci::{ + pci_access::{PciRW, PciRWBase}, + pci_struct::{Bdf, RootComplex}, + PciConfigAddress, + }, +}; + impl RootComplex { - pub fn new_dwc( - ecam_base: u64, - atu_config: &HvDwcAtuConfig, - root_bus: u8 - ) -> Self { + pub fn new_dwc(ecam_base: u64, atu_config: &HvDwcAtuConfig, root_bus: u8) -> Self { let accessor = Arc::new(DwcConfigAccessor::new(atu_config, root_bus)); - - Self { + + Self { mmio_base: ecam_base, accessor, } } } -impl PciRegion for PciConfigMmio { - 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(()) - } -} - - #[repr(C)] #[derive(Debug, Clone, Copy)] pub struct DwcConfigRegion { @@ -91,20 +72,17 @@ pub struct DwcConfigAccessor { } impl DwcConfigAccessor { - pub fn new( - atu_config: &HvDwcAtuConfig, - root_bus: u8 - ) -> Self { + pub fn new(atu_config: &HvDwcAtuConfig, root_bus: u8) -> Self { let cfg_size_half = atu_config.cfg_size / 2; let cfg0_base = atu_config.cfg_base; let cfg1_base = atu_config.cfg_base + cfg_size_half; - + // Create DBI backend for ATU configuration let dbi_base = atu_config.dbi_base as PciConfigAddress; let dbi_size = atu_config.dbi_size; let dbi_region = PciRegionMmio::new(dbi_base, dbi_size); let dbi_backend = Arc::new(DwcConfigRegionBackend(dbi_region)); - + let dbi = DwcConfigRegion { atu_index: ATU_UNUSED as usize, atu_type: 0, @@ -123,7 +101,7 @@ impl DwcConfigAccessor { base: cfg1_base, size: cfg_size_half, }; - + Self { dbi_backend, dbi, @@ -135,47 +113,44 @@ impl DwcConfigAccessor { } impl PciConfigAccessor for DwcConfigAccessor { - fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress, parent_bus: u8) -> HvResult { + fn get_physical_address( + &self, + bdf: Bdf, + offset: PciConfigAddress, + parent_bus: u8, + ) -> HvResult { let bus = bdf.bus(); let device = bdf.device() as PciConfigAddress; let function = bdf.function() as PciConfigAddress; warn!("parent_bus {} self.root_bus {}", parent_bus, self.root_bus); - + // Calculate address without bus field (bus is handled by different config regions) // Address format: (device << 15) + (function << 12) + offset let offset_without_bus = (device << 15) + (function << 12) + offset; - + let address = if bus == self.root_bus { - warn!("1"); // Root bus: use DBI directly, no ATU configuration needed self.dbi.base + offset_without_bus } else if parent_bus == self.root_bus { - // Check if cfg0 ATU is configured (not ATU_UNUSED) - warn!("2"); if self.cfg0.atu_index == ATU_UNUSED as usize { return hv_result_err!(EINVAL, "CFG0 ATU is not configured"); } - let atu_config = AtuConfig::new_with_dwc_config_region( - &self.cfg0, - ); + let atu_config = AtuConfig::new_with_dwc_config_region(&self.cfg0); AtuUnroll::dw_pcie_prog_outbound_atu_unroll(self.dbi_backend.as_ref(), &atu_config)?; - + self.cfg0.base + offset_without_bus } else { - // Check if cfg1 ATU is configured (not ATU_UNUSED) - warn!("3"); + //TODO: cfg1 not implemented yet because it's not used in the current board if self.cfg1.atu_index == ATU_UNUSED as usize { return hv_result_err!(EINVAL, "CFG1 ATU is not configured"); } - let atu_config = AtuConfig::new_with_dwc_config_region( - &self.cfg1, - ); + let atu_config = AtuConfig::new_with_dwc_config_region(&self.cfg1); AtuUnroll::dw_pcie_prog_outbound_atu_unroll(self.dbi_backend.as_ref(), &atu_config)?; - + self.cfg1.base + offset_without_bus }; - + Ok(address) } @@ -191,8 +166,7 @@ impl PciConfigAccessor for DwcConfigAccessor { } impl PciConfigMmio { - /* TODO: may here need check whether length exceeds*/ pub(crate) fn access(&self, offset: PciConfigAddress) -> *mut T { (self.base + offset) as *mut T } -} \ No newline at end of file +} diff --git a/src/pci/config_accessors/dwc_atu.rs b/src/pci/config_accessors/dwc_atu.rs index a1aa0e8c..b3951b25 100644 --- a/src/pci/config_accessors/dwc_atu.rs +++ b/src/pci/config_accessors/dwc_atu.rs @@ -14,34 +14,36 @@ // Authors: // -use crate::error::{HvResult, HvErrorNum::*}; -use crate::pci::{pci_access::PciRW, PciConfigAddress}; use super::dwc::DwcConfigRegion; +use crate::{ + error::{HvErrorNum::*, HvResult}, + pci::{pci_access::PciRW, PciConfigAddress}, +}; + // DWC PCIe ATU (Address Translation Unit) register offsets -// Unroll registers are used for unrolled ATU regions pub const ATU_BASE: usize = 0x300000; pub const ATU_REGION_SIZE: usize = 0x200; -pub const PCIE_ATU_UNR_REGION_CTRL1: usize = 0x00; // Type of the region -pub const PCIE_ATU_UNR_REGION_CTRL2: usize = 0x04; // Write 0x80000000 to enable -pub const PCIE_ATU_UNR_LOWER_BASE: usize = 0x08; // CPU lower address (32bit) -pub const PCIE_ATU_UNR_UPPER_BASE: usize = 0x0C; // CPU upper address (32bit) -pub const PCIE_ATU_UNR_LIMIT: usize = 0x10; // Region limit (lower 32 bit of (cpu_addr + size - 1)) -pub const PCIE_ATU_UNR_LOWER_TARGET: usize = 0x14; // PCI lower address -pub const PCIE_ATU_UNR_UPPER_TARGET: usize = 0x18; // PCI upper address +pub const PCIE_ATU_UNR_REGION_CTRL1: usize = 0x00; +pub const PCIE_ATU_UNR_REGION_CTRL2: usize = 0x04; +pub const PCIE_ATU_UNR_LOWER_BASE: usize = 0x08; +pub const PCIE_ATU_UNR_UPPER_BASE: usize = 0x0C; +pub const PCIE_ATU_UNR_LIMIT: usize = 0x10; +pub const PCIE_ATU_UNR_LOWER_TARGET: usize = 0x14; +pub const PCIE_ATU_UNR_UPPER_TARGET: usize = 0x18; // ATU region type constants pub const ATU_TYPE_CFG0: u32 = 0x4; // CFG0 Type pub const ATU_TYPE_CFG1: u32 = 0x5; // CFG1 Type -pub const ATU_TYPE_MEM: u32 = 0x0; // Memory Type -pub const ATU_TYPE_IO: u32 = 0x2; // IO Type +pub const ATU_TYPE_MEM: u32 = 0x0; // Memory Type +pub const ATU_TYPE_IO: u32 = 0x2; // IO Type // ATU enable bit pub const ATU_ENABLE_BIT: u32 = 0x80000000; +// the flag is for dbi just pub const ATU_UNUSED: u32 = u32::MAX; -// ATU configuration parameters #[derive(Debug, Clone, Copy)] pub struct AtuConfig { pub index: usize, @@ -69,9 +71,7 @@ impl AtuConfig { } } - pub fn new_with_dwc_config_region( - config_region: &DwcConfigRegion, - ) -> Self { + pub fn new_with_dwc_config_region(config_region: &DwcConfigRegion) -> Self { Self::new( config_region.atu_index, config_region.atu_type, @@ -86,28 +86,57 @@ impl AtuConfig { pub struct AtuUnroll; impl AtuUnroll { - // Configure ATU region using unroll registers + // Configure ATU region with unroll registers // Follows the same order as Linux kernel dw_pcie_prog_outbound_atu_unroll pub fn dw_pcie_prog_outbound_atu_unroll( dbi_backend: &dyn PciRW, config: &AtuConfig, ) -> HvResult { let atu_base = (ATU_BASE + config.index * ATU_REGION_SIZE) as PciConfigAddress; - - dbi_backend.write(atu_base + PCIE_ATU_UNR_LOWER_BASE as PciConfigAddress, 4, (config.cpu_base & 0xffffffff) as usize)?; - dbi_backend.write(atu_base + PCIE_ATU_UNR_UPPER_BASE as PciConfigAddress, 4, (config.cpu_base >> 32) as usize)?; - dbi_backend.write(atu_base + PCIE_ATU_UNR_LIMIT as PciConfigAddress, 4, (config.cpu_limit & 0xffffffff) as usize)?; - dbi_backend.write(atu_base + PCIE_ATU_UNR_LOWER_TARGET as PciConfigAddress, 4, (config.pci_target & 0xffffffff) as usize)?; - dbi_backend.write(atu_base + PCIE_ATU_UNR_UPPER_TARGET as PciConfigAddress, 4, (config.pci_target >> 32) as usize)?; - dbi_backend.write(atu_base + PCIE_ATU_UNR_REGION_CTRL1 as PciConfigAddress, 4, config.atu_type as usize)?; - dbi_backend.write(atu_base + PCIE_ATU_UNR_REGION_CTRL2 as PciConfigAddress, 4, ATU_ENABLE_BIT as usize)?; - + + dbi_backend.write( + atu_base + PCIE_ATU_UNR_LOWER_BASE as PciConfigAddress, + 4, + (config.cpu_base & 0xffffffff) as usize, + )?; + dbi_backend.write( + atu_base + PCIE_ATU_UNR_UPPER_BASE as PciConfigAddress, + 4, + (config.cpu_base >> 32) as usize, + )?; + dbi_backend.write( + atu_base + PCIE_ATU_UNR_LIMIT as PciConfigAddress, + 4, + (config.cpu_limit & 0xffffffff) as usize, + )?; + dbi_backend.write( + atu_base + PCIE_ATU_UNR_LOWER_TARGET as PciConfigAddress, + 4, + (config.pci_target & 0xffffffff) as usize, + )?; + dbi_backend.write( + atu_base + PCIE_ATU_UNR_UPPER_TARGET as PciConfigAddress, + 4, + (config.pci_target >> 32) as usize, + )?; + dbi_backend.write( + atu_base + PCIE_ATU_UNR_REGION_CTRL1 as PciConfigAddress, + 4, + config.atu_type as usize, + )?; + dbi_backend.write( + atu_base + PCIE_ATU_UNR_REGION_CTRL2 as PciConfigAddress, + 4, + ATU_ENABLE_BIT as usize, + )?; + // Verify that ATU enable takes effect before any subsequent config and I/O accesses const MAX_RETRIES: usize = 5; const RETRY_DELAY_ITERATIONS: usize = 10; - + for _ in 0..MAX_RETRIES { - let val = dbi_backend.read(atu_base + PCIE_ATU_UNR_REGION_CTRL2 as PciConfigAddress, 4)?; + let val = + dbi_backend.read(atu_base + PCIE_ATU_UNR_REGION_CTRL2 as PciConfigAddress, 4)?; if (val as u32) & ATU_ENABLE_BIT != 0 { return Ok(()); } @@ -115,8 +144,7 @@ impl AtuUnroll { core::hint::spin_loop(); } } - + hv_result_err!(EBUSY, "Outbound iATU is not being enabled") } } - diff --git a/src/pci/config_accessors/ecam.rs b/src/pci/config_accessors/ecam.rs index ec28c2f4..76794958 100644 --- a/src/pci/config_accessors/ecam.rs +++ b/src/pci/config_accessors/ecam.rs @@ -15,17 +15,23 @@ // use alloc::sync::Arc; -use crate::error::HvResult; -use crate::pci::pci_struct::RootComplex; -use crate::pci::{pci_struct::Bdf, PciConfigAddress}; -use super::{PciConfigAccessor, PciRegion, PciConfigMmio}; use bit_field::BitField; +use super::{PciConfigAccessor, PciConfigMmio, PciRegion}; + +use crate::{ + error::HvResult, + pci::{ + pci_struct::{Bdf, RootComplex}, + PciConfigAddress, + }, +}; + impl RootComplex { pub fn new_ecam(mmio_base: PciConfigAddress) -> Self { let accessor = Arc::new(EcamConfigAccessor::new(mmio_base)); - - Self { + + Self { mmio_base, accessor, } @@ -44,26 +50,25 @@ impl EcamConfigAccessor { } impl PciConfigAccessor for EcamConfigAccessor { - fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress, _parent_bus: u8) -> HvResult { + fn get_physical_address( + &self, + bdf: Bdf, + offset: PciConfigAddress, + _parent_bus: u8, + ) -> HvResult { let bus = bdf.bus() as PciConfigAddress; let device = bdf.device() as PciConfigAddress; let function = bdf.function() as PciConfigAddress; - + // ECAM standard address calculation: // base + (bus << 20) + (device << 15) + (function << 12) + offset - let address = self.ecam_base - + (bus << 20) - + (device << 15) - + (function << 12) - + offset; + let address = self.ecam_base + (bus << 20) + (device << 15) + (function << 12) + offset; Ok(address) } } impl PciConfigMmio { - /* TODO: may here need check whether length exceeds*/ pub(crate) fn access(&self, offset: PciConfigAddress) -> *mut T { (self.base + offset) as *mut T } } - diff --git a/src/pci/config_accessors/loongarch64.rs b/src/pci/config_accessors/loongarch64.rs index 069113e1..7a9a03ea 100644 --- a/src/pci/config_accessors/loongarch64.rs +++ b/src/pci/config_accessors/loongarch64.rs @@ -14,18 +14,25 @@ // Authors: // -use crate::error::HvResult; -use crate::pci::{pci_struct::{Bdf, RootComplex}, PciConfigAddress}; -use super::{PciConfigAccessor, PciRegion, PciConfigMmio}; use alloc::sync::Arc; use bit_field::BitField; -use crate::arch::loongarch64::mm::LOONGARCH64_UNCACHED_DMW_PREFIX; + +use super::{PciConfigAccessor, PciConfigMmio, PciRegion}; + +use crate::{ + arch::loongarch64::mm::LOONGARCH64_UNCACHED_DMW_PREFIX, + error::HvResult, + pci::{ + pci_struct::{Bdf, RootComplex}, + PciConfigAddress, + }, +}; impl RootComplex { pub fn new_loongarch(mmio_base: PciConfigAddress, cfg_size: u64, root_bus: u8) -> Self { let accessor = Arc::new(LoongArchConfigAccessor::new(mmio_base, cfg_size, root_bus)); - - Self { + + Self { mmio_base, accessor, } @@ -33,7 +40,6 @@ impl RootComplex { } // LoongArch PCIe accessor implementation -// Similar to ECAM, uses standard address calculation #[derive(Debug)] pub struct LoongArchConfigAccessor { cfg0: PciConfigAddress, @@ -46,20 +52,33 @@ impl LoongArchConfigAccessor { let cfg_size_half = cfg_size / 2; let cfg0 = cfg_base; let cfg1 = cfg_base + cfg_size_half; - Self { cfg0, cfg1, root_bus } + Self { + cfg0, + cfg1, + root_bus, + } } } impl PciConfigAccessor for LoongArchConfigAccessor { - fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress, _parent_bus: u8) -> HvResult { + fn get_physical_address( + &self, + bdf: Bdf, + offset: PciConfigAddress, + _parent_bus: u8, + ) -> HvResult { let bus = bdf.bus() as PciConfigAddress; let device = bdf.device() as PciConfigAddress; let function = bdf.function() as PciConfigAddress; - - let address = if bus == self.root_bus as PciConfigAddress{ + + let address = if bus == self.root_bus as PciConfigAddress { self.cfg0 + (offset >> 8) << 23 + device << 10 + function << 7 + (offset & 0xff) } else { - self.cfg1 + (offset >> 8) << 23 + bus << 15 + device << 10 + function << 7 + (offset & 0xff) + self.cfg1 + (offset >> 8) + << 23 + bus + << 15 + device + << 10 + function + << 7 + (offset & 0xff) }; Ok(address) @@ -71,8 +90,7 @@ impl PciConfigAccessor for LoongArchConfigAccessor { } impl PciConfigMmio { - /* TODO: may here need check whether length exceeds*/ pub(crate) fn access(&self, offset: PciConfigAddress) -> *mut T { (self.base + offset | LOONGARCH64_UNCACHED_DMW_PREFIX) as *mut T } -} \ No newline at end of file +} diff --git a/src/pci/config_accessors/mod.rs b/src/pci/config_accessors/mod.rs index 1c0e5124..5b3ee5ef 100644 --- a/src/pci/config_accessors/mod.rs +++ b/src/pci/config_accessors/mod.rs @@ -29,7 +29,6 @@ pub trait PciRegion: Debug + Sync + Send + Any { 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 PciConfigMmio { base: PciConfigAddress, @@ -42,13 +41,13 @@ impl PciConfigMmio { Self { base, length } } - /// Check if this is a placeholder (dummy) mmio with base address 0 + // placeholder is used only once in the beginning when hvisor init the pci bus + // defined that placeholder is a dummy mmio with base address 0 and length 0 pub fn is_placeholder(&self) -> bool { self.base == 0 && self.length == 0 } } -/* PCIe region MMIO for general memory-mapped I/O regions */ #[derive(Debug, Clone, Copy)] pub struct PciRegionMmio { base: PciConfigAddress, @@ -60,12 +59,23 @@ impl PciRegionMmio { pub fn new(base: PciConfigAddress, length: u64) -> Self { Self { base, length } } - /* TODO: may here need check whether length exceeds*/ + pub(crate) fn access(&self, offset: PciConfigAddress) -> *mut T { (self.base + offset) as *mut T } } +#[cfg(all( + not(feature = "ecam_pcie"), + not(feature = "dwc_pcie"), + not(feature = "loongarch64_pcie") +))] +impl PciConfigMmio { + pub 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) } @@ -115,8 +125,12 @@ impl PciRegion for PciConfigMmio { } pub trait PciConfigAccessor: Send + Sync + core::fmt::Debug { - // Get physical address from BDF and offset - fn get_physical_address(&self, bdf: Bdf, offset: PciConfigAddress, _parent_bus: u8) -> HvResult; + fn get_physical_address( + &self, + bdf: Bdf, + offset: PciConfigAddress, + _parent_bus: u8, + ) -> HvResult; fn skip_device(&self, _bdf: Bdf) -> bool { false @@ -141,4 +155,3 @@ pub mod dwc_atu; #[cfg(feature = "loongarch64_pcie")] pub mod loongarch64; - diff --git a/src/pci/mod.rs b/src/pci/mod.rs index 2bc0e902..0ef2bfac 100644 --- a/src/pci/mod.rs +++ b/src/pci/mod.rs @@ -13,12 +13,12 @@ // // Authors: // +#![allow(dead_code)] +pub mod config_accessors; pub mod mem_alloc; pub mod pci_access; pub mod pci_config; pub mod pci_struct; -pub mod config_accessors; -// pub mod vpci_dtb; pub mod pci_test; diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 3ee9f960..7c245d5b 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -14,31 +14,32 @@ // Authors: // // #![allow(dead_code)] +use alloc::string::String; +use bit_field::BitField; +use bitflags::bitflags; use core::{ fmt::Debug, ops::{Index, IndexMut}, + slice, }; -use alloc::string::String; -use bit_field::BitField; -use bitflags::bitflags; -use core::slice; +use super::{ + config_accessors::{PciConfigMmio, PciRegion}, + pci_struct::VirtualPciConfigSpace, + PciConfigAddress, +}; use crate::{ error::HvResult, - memory::{GuestPhysAddr, HostPhysAddr, MMIOAccess, MemFlags, MemoryRegion, MemorySet, mmio_perform_access}, + memory::{ + mmio_perform_access, GuestPhysAddr, HostPhysAddr, MMIOAccess, MemFlags, MemoryRegion, + MemorySet, + }, pci::pci_struct::BIT_LENTH, percpu::this_zone, - zone::{Zone, this_zone_id}, -}; - -use super::{ - config_accessors::{PciRegion, PciConfigMmio}, - pci_struct::VirtualPciConfigSpace, - PciConfigAddress, + zone::{this_zone_id, Zone}, }; - pub type VendorId = u16; pub type DeviceId = u16; pub type DeviceRevision = u8; @@ -321,10 +322,6 @@ impl PciMem { self.virtual_value = val; } - - // pub fn set_virtual_value(&mut self, value: u64) { - // self.virtual_value = value; - // } } impl Debug for PciMem { @@ -366,7 +363,15 @@ impl Debug for PciMem { 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, vaddr, vaddr + size) + write!( + f, + "{:#?} [0x{:x}-0x{:x}] => [0x{:x}-0x{:x}]", + self.bar_type, + paddr, + paddr + size, + vaddr, + vaddr + size + ) } _ => { write!(f, "[{:#?}]", self.bar_type) @@ -554,7 +559,7 @@ pub trait PciBarRW: PciRWBase { let mut slot = 0u8; while slot < self.bar_limit() { - warn!("parse bar slot {}", slot); + warn!("parse bar slot {}", slot); let value = self.read_bar(slot).unwrap(); if !value.get_bit(0) { @@ -967,7 +972,6 @@ impl PciBridgeHeader { impl PciBridgeHeader {} -/// Handle PCI configuration space access fn handle_config_space_access( dev: &mut VirtualPciConfigSpace, mmio: &mut MMIOAccess, @@ -1088,7 +1092,9 @@ fn handle_config_space_access( dev.set_bar_virtual_value(slot - 1, new_vaddr); } - let bar_size = if crate::memory::addr::is_aligned(bar.get_size() as usize) { + let bar_size = if crate::memory::addr::is_aligned( + bar.get_size() as usize, + ) { bar.get_size() } else { crate::memory::PAGE_SIZE as u64 @@ -1101,7 +1107,6 @@ fn handle_config_space_access( MemFlags::READ | MemFlags::WRITE, ))?; /* after update gpm, mem barrier is needed - * TODO: for loongarch64 need ibar 0 dbar 0 */ #[cfg(target_arch = "aarch64")] unsafe { @@ -1204,7 +1209,7 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { let offset = (mmio.address & 0xfff) as PciConfigAddress; let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; - + if let Some(dev) = vbus.get_device_by_base(base) { handle_config_space_access(dev, mmio, offset, gpm, zone_id)?; } else { @@ -1217,7 +1222,9 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { // info!("mmio_vpci_handler_dbi {:#x}", mmio.address); - if mmio.address >= 0x300000 /* ATU base */ { + if mmio.address >= 0x300000 + /* ATU base */ + { mmio_perform_access(_base, mmio); } else if mmio.address >= BIT_LENTH { // dbi read @@ -1231,9 +1238,9 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { let Zone { gpm, vpci_bus, .. } = &mut *guard; (vpci_bus, gpm) }; - + let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; - + if let Some(dev) = vbus.get_device_by_base(base) { handle_config_space_access(dev, mmio, offset, gpm, zone_id)?; } else { @@ -1242,4 +1249,4 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { } Ok(()) -} \ No newline at end of file +} diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 1ad445a6..6571054c 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -18,20 +18,24 @@ use spin::{Lazy, Mutex}; use crate::{ arch::iommu::iommu_add_device, - config::{CONFIG_MAX_PCI_DEV, CONFIG_PCI_BUS_MAXNUM, HvPciConfig, HvPciDevConfig}, + config::{HvPciConfig, HvPciDevConfig, CONFIG_MAX_PCI_DEV, CONFIG_PCI_BUS_MAXNUM}, error::HvResult, - memory::mmio_generic_handler, - pci::{ - pci_access::{mmio_vpci_handler, mmio_vpci_handler_dbi}, - pci_struct::{Bdf, VirtualPciConfigSpace}, - config_accessors::PciConfigMmio - }, + pci::pci_struct::{Bdf, VirtualPciConfigSpace}, zone::Zone, }; -use crate::platform; -use super::pci_struct::RootComplex; -use crate::pci::mem_alloc::BaseAllocator; +#[cfg(any( + feature = "ecam_pcie", + feature = "dwc_pcie", + feature = "loongarch64_pcie" +))] +use crate::pci::{mem_alloc::BaseAllocator, pci_struct::RootComplex}; + +#[cfg(any(feature = "ecam_pcie", feature = "dwc_pcie"))] +use crate::pci::pci_access::mmio_vpci_handler; + +#[cfg(feature = "dwc_pcie")] +use crate::{memory::mmio_generic_handler, pci::pci_access::mmio_vpci_handler_dbi, platform}; pub static GLOBAL_PCIE_LIST: Lazy>> = Lazy::new(|| { let m = BTreeMap::new(); @@ -41,7 +45,11 @@ pub static GLOBAL_PCIE_LIST: Lazy>> = /* add all dev to GLOBAL_PCIE_LIST */ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { warn!("begin {:#?}", pci_config); - #[cfg(any(feature = "ecam_pcie", feature = "dwc_pcie", feature = "loongarch64_pcie"))] + #[cfg(any( + feature = "ecam_pcie", + feature = "dwc_pcie", + feature = "loongarch64_pcie" + ))] for (index, rootcomplex_config) in pci_config.iter().enumerate() { /* empty config */ if rootcomplex_config.ecam_base == 0 { @@ -74,7 +82,7 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { let atu_config = platform::ROOT_DWC_ATU_CONFIG .iter() .find(|atu_cfg| atu_cfg.ecam_base == ecam_base); - + let atu_config = match atu_config { Some(cfg) => cfg, None => { @@ -82,25 +90,29 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { return hv_result_err!(EINVAL, "No ATU config found for ecam_base"); } }; - + let root_bus = rootcomplex_config.bus_range_begin as u8; - + RootComplex::new_dwc(rootcomplex_config.ecam_base, atu_config, root_bus) } - + #[cfg(feature = "loongarch64_pcie")] { let root_bus = rootcomplex_config.bus_range_begin as u8; - RootComplex::new_loongarch(rootcomplex_config.ecam_base, rootcomplex_config.ecam_size, root_bus) + RootComplex::new_loongarch( + rootcomplex_config.ecam_base, + rootcomplex_config.ecam_size, + root_bus, + ) } - + #[cfg(feature = "ecam_pcie")] { RootComplex::new_ecam(rootcomplex_config.ecam_base) } - }; - let range = rootcomplex_config.bus_range_begin as usize..rootcomplex_config.bus_range_end as usize; + let range = + rootcomplex_config.bus_range_begin as usize..rootcomplex_config.bus_range_end as usize; let e = rootcomplex.enumerate(Some(range), allocator_opt); info!("begin enumerate {:#?}", e); for node in e { @@ -137,7 +149,7 @@ impl Zone { }; iommu_add_device(zone_id, dev_config.bdf as _, iommu_pt_addr); } - if let Some(dev) = guard.get(&bdf){ + if let Some(dev) = guard.get(&bdf) { if bdf.is_host_bridge(dev.get_host_bdf().bus()) { let mut vdev = dev.clone(); vdev.set_vbdf(vbdf); @@ -169,11 +181,11 @@ impl Zone { #[cfg(feature = "ecam_pcie")] { self.mmio_region_register( - rootcomplex_config.ecam_base as usize, - rootcomplex_config.ecam_size as usize, - mmio_vpci_handler, - rootcomplex_config.ecam_base as usize, - ); + rootcomplex_config.ecam_base as usize, + rootcomplex_config.ecam_size as usize, + mmio_vpci_handler, + rootcomplex_config.ecam_base as usize, + ); } #[cfg(feature = "dwc_pcie")] { @@ -187,7 +199,7 @@ impl Zone { let extend_config = platform::ROOT_DWC_ATU_CONFIG .iter() .find(|extend_cfg| extend_cfg.ecam_base == rootcomplex_config.ecam_base); - + if let Some(extend_config) = extend_config { if extend_config.apb_base != 0 && extend_config.apb_size != 0 { self.mmio_region_register( @@ -197,7 +209,7 @@ impl Zone { extend_config.apb_base as usize, ); } - + let cfg_size_half = extend_config.cfg_size / 2; let cfg0_base = extend_config.cfg_base; if cfg0_base != 0 && cfg_size_half != 0 { @@ -208,7 +220,7 @@ impl Zone { cfg0_base as usize, ); } - + let cfg1_base = extend_config.cfg_base + cfg_size_half; if cfg1_base != 0 && cfg_size_half != 0 { self.mmio_region_register( @@ -219,9 +231,12 @@ impl Zone { ); } } else { - warn!("No extend config found for base 0x{:x}", rootcomplex_config.ecam_base); + warn!( + "No extend config found for base 0x{:x}", + rootcomplex_config.ecam_base + ); } } } } -} \ No newline at end of file +} diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 69865031..142f6b1d 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -13,33 +13,29 @@ // // Authors: // -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; use bitvec::{array::BitArray, order::Lsb0, BitArr}; - -use crate::{ - error::{HvErrorNum, HvResult}, - pci::pci_access::{Bar, PciBarRW, PciHeaderRW, PciRomRW}, -}; +use core::{cmp::Ordering, fmt::Debug, ops::Range, str::FromStr}; use super::{ + config_accessors::{PciConfigAccessor, PciConfigMmio}, mem_alloc::BarAllocator, pci_access::{ - EndpointField, EndpointHeader, HeaderType, PciBridgeHeader, PciCommand, PciConfigHeader, - PciMem, PciMemType, PciRW, + Bar, EndpointField, EndpointHeader, HeaderType, PciBarRW, PciBridgeHeader, PciCommand, + PciConfigHeader, PciHeaderRW, PciMem, PciMemType, PciRW, PciRomRW, }, - config_accessors::{PciConfigMmio, PciConfigAccessor}, PciConfigAddress, }; +use crate::error::{HvErrorNum, HvResult}; + 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; -pub const BIT_LENTH: usize = 128 * 5; +pub const BIT_LENTH: usize = 128 * 5; // PCIe Device/Port Type values const PCI_EXP_TYPE_ROOT_PORT: u16 = 4; @@ -87,7 +83,7 @@ impl Bdf { function, } } - + pub fn is_host_bridge(&self, bus_begin: u8) -> bool { if (self.bus, self.device, self.function) == (bus_begin, 0, 0) { true @@ -309,7 +305,13 @@ impl Debug for VirtualPciConfigSpace { } impl VirtualPciConfigSpace { - pub fn endpoint(bdf: Bdf, base: PciConfigAddress, backend: Arc, bararr: Bar, rom: PciMem) -> Self { + pub fn endpoint( + bdf: Bdf, + base: PciConfigAddress, + backend: Arc, + bararr: Bar, + rom: PciMem, + ) -> Self { Self { host_bdf: Bdf::default(), parent_bdf: Bdf::default(), @@ -327,7 +329,13 @@ impl VirtualPciConfigSpace { } } - pub fn bridge(bdf: Bdf, base: PciConfigAddress, backend: Arc, bararr: Bar, rom: PciMem) -> Self { + pub fn bridge( + bdf: Bdf, + base: PciConfigAddress, + backend: Arc, + bararr: Bar, + rom: PciMem, + ) -> Self { Self { host_bdf: Bdf::default(), parent_bdf: Bdf::default(), @@ -518,22 +526,24 @@ pub struct PciIterator { impl PciIterator { fn address(&self, parent_bus: u8, bdf: Bdf) -> PciConfigAddress { let offset = 0; - + match self.accessor.get_physical_address(bdf, offset, parent_bus) { Ok(addr) => addr, - Err(_) => { - 0x0 - } + Err(_) => 0x0, } } fn get_node(&mut self) -> Option { // Handle placeholder: pop it first, use bus_range.start for initial scan - let was_placeholder = self.stack.last().map(|b| b.mmio.is_placeholder()).unwrap_or(false); + let was_placeholder = self + .stack + .last() + .map(|b| b.mmio.is_placeholder()) + .unwrap_or(false); if was_placeholder { self.stack.pop(); // Remove placeholder } - + let (bus, device, function, parent_bus) = if let Some(parent) = self.stack.last() { // device is already added in next() (parent.bus, parent.device, self.function, parent.primary_bus) @@ -542,9 +552,9 @@ impl PciIterator { let bus_begin = self.bus_range.start as u8; (bus_begin, 0, self.function, bus_begin) }; - + let bdf = Bdf::new(bus, device, function); - + let address = self.address(parent_bus, bdf); info!("get node {:x} {:#?}", address, bdf); @@ -553,18 +563,24 @@ impl PciIterator { let (vender_id, _device_id) = pci_header.id(); warn!("vender_id {:#x}", vender_id); - + // Check if device exists if vender_id == 0xffff || self.accessor.skip_device(bdf) { if function == 0 { // Function 0 doesn't exist, so device doesn't exist at all // Skip all functions and move to next device - warn!("get none - device not present (vendor_id=0xffff) at {:#?}", bdf); + warn!( + "get none - device not present (vendor_id=0xffff) at {:#?}", + bdf + ); self.function = 0; self.is_mulitple_function = false; } else { // Function > 0 doesn't exist, but device might have other functions - warn!("get none - function not present (vendor_id=0xffff) at {:#?}", bdf); + warn!( + "get none - function not present (vendor_id=0xffff) at {:#?}", + bdf + ); } return None; } @@ -579,10 +595,9 @@ impl PciIterator { let host_bridge = Bridge::host_bridge(self.segment, bus_begin); self.stack.push(host_bridge); } - + let mut ep = EndpointHeader::new_with_region(region); let rom = Self::rom_init(&mut ep); - let bararr = Self::bar_mem_init(ep.bar_limit().into(), &mut self.allocator, &mut ep); @@ -591,9 +606,9 @@ impl PciIterator { let ep = Arc::new(ep); let mut node = VirtualPciConfigSpace::endpoint(bdf, address, ep, bararr, rom); - + let _ = node.capability_enumerate(); - + Some(node) } HeaderType::PciBridge => { @@ -607,9 +622,9 @@ impl PciIterator { let bridge = Arc::new(bridge); let mut node = VirtualPciConfigSpace::bridge(bdf, address, bridge, bararr, rom); - + let _ = node.capability_enumerate(); - + Some(node) } _ => { @@ -620,9 +635,7 @@ impl PciIterator { } } - fn rom_init( - dev: &mut D, - ) -> PciMem { + fn rom_init(dev: &mut D) -> PciMem { let mut rom = dev.parse_rom(); rom.set_virtual_value(rom.get_value() as u64); rom @@ -806,8 +819,13 @@ impl Iterator for PciIterator { self.next(match node.config_type { HeaderType::PciBridge => { let bdf = Bdf::new(parent.bus, parent.device, parent.subordinate_bus); - Some(self.get_bridge().next_bridge(self.address(parent_bus, bdf), node.has_secondary_link())) - }, + Some( + self.get_bridge().next_bridge( + self.address(parent_bus, bdf), + node.has_secondary_link(), + ), + ) + } _ => None, }); return Some(node); @@ -831,8 +849,8 @@ pub struct Bridge { } impl Bridge { - /// Create a placeholder bridge for initializing the stack. - /// This is not a real host bridge, just a placeholder to track bus hierarchy. + // Create a placeholder bridge for initializing the stack. + // This is not a real host bridge, just a placeholder to track bus hierarchy. pub fn placeholder() -> Self { Self { bus: 0, @@ -875,7 +893,7 @@ impl Bridge { if self.mmio.is_placeholder() { return; } - // Direct memory access using the access method + // we need to update the bridge bus number if we want linux not to update bus number unsafe { let ptr = self.mmio.access::(0x18); let mut value = ptr.read_volatile(); @@ -913,7 +931,7 @@ impl RootComplex { function: 0, is_mulitple_function: false, is_finish: false, - accessor: self.accessor.clone(), // Pass accessor to iterator + accessor: self.accessor.clone(), // accessor to iterator } } @@ -962,7 +980,11 @@ impl VirtualRootComplex { self.devs.get_mut(bdf) } - pub fn get_device_by_base(&mut self, base: PciConfigAddress) -> Option<&mut VirtualPciConfigSpace> { + /* because the base of device may discontinuous,get device by base is simpler */ + pub fn get_device_by_base( + &mut self, + base: PciConfigAddress, + ) -> Option<&mut VirtualPciConfigSpace> { let bdf = self.base_to_bdf.get(&base).copied()?; self.devs.get_mut(&bdf) } @@ -1008,11 +1030,10 @@ impl Iterator for CapabilityIterator { } while self.get_offset() != 0 { - warn!("get cap {:#x}", self.get_offset()); + debug!("get cap {:#x}", self.get_offset()); // Get current capability before moving to next 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()); // Move to next capability let _ = self.get_next_cap(); if let Some(cap) = cap { @@ -1241,10 +1262,11 @@ impl VirtualPciConfigSpace { self.capabilities = capabilities; } + //TODO: check secondary link by read cap pub fn has_secondary_link(&self) -> bool { match self.config_type { HeaderType::PciBridge => { - // // Find PciExpress capability + // Find PciExpress capability // for (_, capability) in &self.capabilities { // if let PciCapability::PciExpress(PciCapabilityRegion { offset, .. }) = capability { // // Read PCIe Capability Register at offset + 0x00 @@ -1265,10 +1287,9 @@ impl VirtualPciConfigSpace { #[cfg(feature = "dwc_pcie")] return true; #[cfg(not(feature = "dwc_pcie"))] - return false; + return false; } _ => false, } } - } diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs index 6fef8ca1..e8c299d0 100644 --- a/src/pci/pci_test.rs +++ b/src/pci/pci_test.rs @@ -19,17 +19,16 @@ use core::str::FromStr; use alloc::{collections::btree_map::BTreeMap, sync::Arc}; use spin::{lazy::Lazy, mutex::Mutex}; -use crate::{ - memory::{MMIOAccess, mmio_perform_access}, - pci::{pci_access::EndpointHeader, config_accessors::PciConfigMmio}, - percpu::this_zone, -}; - -use super::pci_struct::CONFIG_LENTH; use super::{ mem_alloc::BaseAllocator, pci_access::mmio_vpci_handler, - pci_struct::{Bdf, RootComplex, VirtualPciConfigSpace}, + pci_struct::{Bdf, VirtualPciConfigSpace, CONFIG_LENTH}, +}; + +use crate::{ + memory::{mmio_perform_access, MMIOAccess}, + pci::{config_accessors::PciConfigMmio, pci_access::EndpointHeader}, + percpu::this_zone, }; pub static GLOBAL_PCIE_LIST_TEST: Lazy>> = @@ -59,10 +58,7 @@ pub fn pcie_guest_init() { let vbdf = Bdf::from_str("0000:00:00.0").unwrap(); let bdf = Bdf::from_str("0000:00:00.0").unwrap(); let base = 0x4010000000; // Base address for test - let backend = EndpointHeader::new_with_region(PciConfigMmio::new( - base, - CONFIG_LENTH, - )); + let backend = EndpointHeader::new_with_region(PciConfigMmio::new(base, CONFIG_LENTH)); let dev = VirtualPciConfigSpace::host_bridge(bdf, base, Arc::new(backend)); vbus.insert(vbdf, dev); @@ -102,7 +98,7 @@ pub fn pcie_guest_init() { info!("pcie guest init done"); } -pub fn pcie_guest_test() { +pub fn ecam_pcie_guest_test() { let zone = this_zone(); let vbus = &zone.read().vpci_bus; let bdf = Bdf::from_str("0000:00:01.0").unwrap(); @@ -129,7 +125,7 @@ pub fn pcie_guest_test() { info!("pcie guest test passed"); } -pub fn pcie_dwc_test() { +pub fn dwc_pcie_guest_test() { info!("pcie dwc test begin"); let mut mmio = MMIOAccess { address: 0x3c0400000, @@ -143,11 +139,11 @@ pub fn pcie_dwc_test() { "mmio offset {:x}, is_wirte {}, size {}, value 0x{:x}", mmio.address, mmio.is_write, mmio.size, mmio.value ); - use core::ptr::{read_volatile, write_volatile}; + use core::ptr::read_volatile; unsafe { let a = read_volatile(0x3c0000900 as *const u32); info!("{a}"); }; info!("pcie dwc test passed"); -} \ No newline at end of file +} diff --git a/src/zone.rs b/src/zone.rs index c3925aaf..ed55a4be 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -216,7 +216,6 @@ pub fn zone_create(config: &HvZoneConfig) -> HvResult>> { let _ = zone.guest_pci_init(zone_id, &config.alloc_pci_devs, config.num_pci_devs); } - // #[cfg(target_arch = "aarch64")] // zone.ivc_init(config.ivc_config()); From 93f35abb5cbba091417ca4ecc5a7837d95c1135d Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 20 Nov 2025 04:55:08 +0800 Subject: [PATCH 026/109] for x86, add time.rs --- src/arch/x86_64/mod.rs | 1 + src/arch/x86_64/time.rs | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/arch/x86_64/time.rs diff --git a/src/arch/x86_64/mod.rs b/src/arch/x86_64/mod.rs index d75140ed..023abdc3 100644 --- a/src/arch/x86_64/mod.rs +++ b/src/arch/x86_64/mod.rs @@ -35,6 +35,7 @@ pub mod pci; pub mod pio; pub mod s1pt; pub mod s2pt; +pub mod time; pub mod trap; pub mod vmcs; pub mod vmx; diff --git a/src/arch/x86_64/time.rs b/src/arch/x86_64/time.rs new file mode 100644 index 00000000..f8bf3b11 --- /dev/null +++ b/src/arch/x86_64/time.rs @@ -0,0 +1,21 @@ +// 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: +// Jingyu Liu +// + +/// Note: You should call this function once during initialization. +pub fn init_timebase() { + info!("Initializing x86_64 timebase not implemented yet."); +} From cffc361389b77a9a0f4281ae07369a8ac051ceb5 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 20 Nov 2025 12:19:55 +0800 Subject: [PATCH 027/109] fix wrong base cal for loongarch in get_physical_address --- platform/loongarch64/ls3a6000/cargo/features | 4 ++- src/pci/config_accessors/loongarch64.rs | 27 +++++++++++++++----- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/platform/loongarch64/ls3a6000/cargo/features b/platform/loongarch64/ls3a6000/cargo/features index f047773e..86cd7a5c 100644 --- a/platform/loongarch64/ls3a6000/cargo/features +++ b/platform/loongarch64/ls3a6000/cargo/features @@ -2,4 +2,6 @@ loongson_3a6000 loongson_7a2000 loongson_uart -loongarch64_pcie \ No newline at end of file +pci +loongarch64_pcie +no_pcie_bar_realloc \ No newline at end of file diff --git a/src/pci/config_accessors/loongarch64.rs b/src/pci/config_accessors/loongarch64.rs index 7a9a03ea..dd412248 100644 --- a/src/pci/config_accessors/loongarch64.rs +++ b/src/pci/config_accessors/loongarch64.rs @@ -71,14 +71,29 @@ impl PciConfigAccessor for LoongArchConfigAccessor { let device = bdf.device() as PciConfigAddress; let function = bdf.function() as PciConfigAddress; + // Extract Offset[11:8] (bits 11-8 of offset) for bits 31-28 + let offset_high = (offset >> 8) & 0xf; + // Extract Offset[7:0] (bits 7-0 of offset) for bits 7-0 + let offset_low = offset & 0xff; + let address = if bus == self.root_bus as PciConfigAddress { - self.cfg0 + (offset >> 8) << 23 + device << 10 + function << 7 + (offset & 0xff) + // Type 0 format (Root Bus): + // Bits 31-28: Offset[11:8] + // Bits 27-16: Reserved (0) + // Bits 15-11: Device Number + // Bits 10-8: Function Number + // Bits 7-0: Offset[7:0] + self.cfg0 + + ((offset_high << 24) | (device << 11) | (function << 8) | offset_low) } else { - self.cfg1 + (offset >> 8) - << 23 + bus - << 15 + device - << 10 + function - << 7 + (offset & 0xff) + // Type 1 format (Other Bus): + // Bits 31-28: Offset[11:8] + // Bits 27-16: Bus Number + // Bits 15-11: Device Number + // Bits 10-8: Function Number + // Bits 7-0: Offset[7:0] + self.cfg1 + + ((offset_high << 24) | (bus << 16) | (device << 11) | (function << 8) | offset_low) }; Ok(address) From ad7a00a08c5f6f99ba12655f39193a6602e46be2 Mon Sep 17 00:00:00 2001 From: agicy Date: Thu, 20 Nov 2025 23:19:45 +0800 Subject: [PATCH 028/109] fix(aarch64/rk3588): correct dts directory structure Move the Makefile and DTS files into the 'dts' subdirectory. This restructuring is required to ensure that the 'make dtb' command executes correctly for the aarch64/rk3588 platform. --- platform/aarch64/rk3588/image/{ => dts}/Makefile | 0 platform/aarch64/rk3588/image/{ => dts}/zone0.dts | 0 platform/aarch64/rk3588/image/{ => dts}/zone1-linux.dts | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename platform/aarch64/rk3588/image/{ => dts}/Makefile (100%) rename platform/aarch64/rk3588/image/{ => dts}/zone0.dts (100%) rename platform/aarch64/rk3588/image/{ => dts}/zone1-linux.dts (100%) diff --git a/platform/aarch64/rk3588/image/Makefile b/platform/aarch64/rk3588/image/dts/Makefile similarity index 100% rename from platform/aarch64/rk3588/image/Makefile rename to platform/aarch64/rk3588/image/dts/Makefile diff --git a/platform/aarch64/rk3588/image/zone0.dts b/platform/aarch64/rk3588/image/dts/zone0.dts similarity index 100% rename from platform/aarch64/rk3588/image/zone0.dts rename to platform/aarch64/rk3588/image/dts/zone0.dts diff --git a/platform/aarch64/rk3588/image/zone1-linux.dts b/platform/aarch64/rk3588/image/dts/zone1-linux.dts similarity index 100% rename from platform/aarch64/rk3588/image/zone1-linux.dts rename to platform/aarch64/rk3588/image/dts/zone1-linux.dts From c3a744138091c498357e51bc2430534b9dbde9db Mon Sep 17 00:00:00 2001 From: agicy Date: Fri, 14 Nov 2025 20:34:17 +0800 Subject: [PATCH 029/109] feat(irq): raise interrupt limit to 1024 for modern SoC support The hardcoded `CONFIG_MAX_INTERRUPTS` limit of 32 was a significant limitation, preventing the system from booting on complex SoCs with a large number of interrupt sources. To address this, this commit introduces two key changes: 1. The `CONFIG_MAX_INTERRUPTS` limit is increased to 1024. This value is a power of two that accommodates a wide range of current and future hardware. 2. The underlying data structure for tracking interrupt status has been refactored to use a `u32` bitmap. This ensures that managing the larger interrupt space remains memory-efficient and performant. This enhancement improves the overall hardware compatibility of hvisor. Closes: #213 --- platform/aarch64/imx8mp/board.rs | 4 +- platform/aarch64/ok6254-c/board.rs | 5 +- platform/aarch64/phytium-pi/board.rs | 4 +- platform/aarch64/qemu-gicv2/board.rs | 8 +-- platform/aarch64/qemu-gicv3/board.rs | 3 +- platform/aarch64/rk3568/board.rs | 12 +++-- platform/aarch64/rk3588/board.rs | 6 +-- platform/aarch64/zcu102/board.rs | 8 ++- platform/loongarch64/ls3a5000/board.rs | 2 +- platform/loongarch64/ls3a6000/board.rs | 2 +- platform/riscv64/hifive-premier-p550/board.rs | 9 ++-- platform/riscv64/megrez/board.rs | 4 +- platform/riscv64/qemu-aia/board.rs | 2 +- platform/riscv64/qemu-plic/board.rs | 2 +- platform/x86_64/nuc14mnk/board.rs | 2 +- platform/x86_64/qemu/board.rs | 2 +- src/arch/loongarch64/zone.rs | 2 +- src/arch/x86_64/zone.rs | 2 +- src/config.rs | 51 +++++++++++++++---- src/device/irqchip/aia/mod.rs | 25 +++++---- src/device/irqchip/gicv2/vgic.rs | 16 ++++-- src/device/irqchip/gicv3/vgic.rs | 26 +++++++--- src/device/irqchip/plic/mod.rs | 26 +++++++--- src/platform/mod.rs | 17 +++---- src/zone.rs | 2 +- 25 files changed, 156 insertions(+), 86 deletions(-) diff --git a/platform/aarch64/imx8mp/board.rs b/platform/aarch64/imx8mp/board.rs index 63a29473..5b9ea976 100644 --- a/platform/aarch64/imx8mp/board.rs +++ b/platform/aarch64/imx8mp/board.rs @@ -109,10 +109,10 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 8] = [ // }, // serial ]; -pub const ROOT_ZONE_IRQS: [u32; 28] = [ +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[ 35, 36, 37, 38, 45, 52, 55, 56, 57, 59, 64, 67, 75, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 135, 150, 151, 152, 162, -]; +]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { is_aarch32: 0, diff --git a/platform/aarch64/ok6254-c/board.rs b/platform/aarch64/ok6254-c/board.rs index a3b76054..85a49631 100644 --- a/platform/aarch64/ok6254-c/board.rs +++ b/platform/aarch64/ok6254-c/board.rs @@ -26,7 +26,6 @@ pub const BOARD_NAME: &str = "ok6254"; pub const BOARD_NCPUS: usize = 4; pub const BOARD_UART_BASE: u64 = 0x2800000; - #[rustfmt::skip] pub static BOARD_MPIDR_MAPPINGS: [u64; BOARD_NCPUS] = [ 0x0, // cpu0 @@ -127,9 +126,9 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 12] = [ }, // 0x10000000 ~ 0x80000000 ]; -pub const ROOT_ZONE_IRQS: [u32; 13] = [ +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[ 64, 66, 114, 115, 118, 165, 194, 195, 210, 211, 228, 258, 266, -]; +]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { is_aarch32: 0, diff --git a/platform/aarch64/phytium-pi/board.rs b/platform/aarch64/phytium-pi/board.rs index aa102509..ce969f87 100644 --- a/platform/aarch64/phytium-pi/board.rs +++ b/platform/aarch64/phytium-pi/board.rs @@ -131,8 +131,8 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 11] = [ }, ]; //46-usb2,54-mailbox 64-usb2,87-net,104、105-mmc,116-uart,133、138-i2c,191-spi -pub const ROOT_ZONE_IRQS: [u32; 14] = - [46, 54, 64, 65, 75, 76, 78, 87, 104, 105, 116, 133, 138, 191]; +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = + &get_irqs_bitmap(&[46, 54, 64, 65, 75, 76, 78, 87, 104, 105, 116, 133, 138, 191]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { is_aarch32: 0, diff --git a/platform/aarch64/qemu-gicv2/board.rs b/platform/aarch64/qemu-gicv2/board.rs index 98cae2b2..c8e09dca 100644 --- a/platform/aarch64/qemu-gicv2/board.rs +++ b/platform/aarch64/qemu-gicv2/board.rs @@ -14,7 +14,10 @@ // Authors: // use crate::{ - arch::{mmu::MemoryType, zone::{HvArchZoneConfig,GicConfig,Gicv2Config}}, + arch::{ + mmu::MemoryType, + zone::{GicConfig, Gicv2Config, HvArchZoneConfig}, + }, config::*, }; @@ -72,7 +75,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 3] = [ // 35 36 37 38 -> pcie intx# // 65 -> ivc -pub const ROOT_ZONE_IRQS: [u32; 9] = [33, 64, 77, 79, 35, 36, 37, 38, 65]; +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[33, 64, 77, 79, 35, 36, 37, 38, 65]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { is_aarch32: 0, @@ -89,7 +92,6 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { }), }; - pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { ecam_base: 0x4010000000, ecam_size: 0x10000000, diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index 124b9dca..d60b4a8a 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -74,7 +74,8 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 3] = [ // 35 36 37 38 -> pcie intx# // 65 -> ivc -pub const ROOT_ZONE_IRQS: [u32; 9] = [33, 64, 77, 79, 35, 36, 37, 38, 65]; +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = + &get_irqs_bitmap(&[33, 64, 77, 79, 35, 36, 37, 38, 65]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { is_aarch32: 0, diff --git a/platform/aarch64/rk3568/board.rs b/platform/aarch64/rk3568/board.rs index 84f07a71..e590c189 100644 --- a/platform/aarch64/rk3568/board.rs +++ b/platform/aarch64/rk3568/board.rs @@ -46,10 +46,10 @@ pub const BOARD_PHYSMEM_LIST: &[(u64, u64, MemoryType)] = &[ ]; 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 = 0x60080000; +pub const ROOT_ZONE_ENTRY: u64 = 0x60080000; //pub const ROOT_ZONE_CPUS: u64 = (1 << 0) ; -pub const ROOT_ZONE_CPUS: u64 = (1 << 0)|(1 << 1); +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] = [ @@ -187,8 +187,10 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 19] = [ }, //sdhci ]; -pub const ROOT_ZONE_IRQS: [u32; 20] = [ - 0x84, 0x98, 0x40, 0x104, 0x105, 0x106, 0x107, 0x2d, 0x2e, 0x2b, 0x2a, 0x29, 0x33, 0x96, 0x11c, 0x44, 0x43, 0x42, 0x41, 0x8d]; +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[ + 0x84, 0x98, 0x40, 0x104, 0x105, 0x106, 0x107, 0x2d, 0x2e, 0x2b, 0x2a, 0x29, 0x33, 0x96, 0x11c, + 0x44, 0x43, 0x42, 0x41, 0x8d, +]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { is_aarch32: 0, diff --git a/platform/aarch64/rk3588/board.rs b/platform/aarch64/rk3588/board.rs index b12c6ec1..8ac239c3 100644 --- a/platform/aarch64/rk3588/board.rs +++ b/platform/aarch64/rk3588/board.rs @@ -169,11 +169,11 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 9] = [ // } ]; -// pub const ROOT_ZONE_IRQS: [u32; 10] = [39, 64, 235, 237, 309, 312, 360, 365, 429, 455]; -pub const ROOT_ZONE_IRQS: [u32; 29] = [ +// pub const ROOT_ZONE_IRQS_BITMAP: [u32; 10] = [39, 64, 235, 237, 309, 312, 360, 365, 429, 455]; +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[ 39, 41, 42, 43, 45, 46, 64, 120, 121, 235, 237, 247, 248, 250, 251, 252, 265, 266, 309, 312, 313, 355, 360, 365, 423, 424, 425, 429, 455, -]; +]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { is_aarch32: 0, diff --git a/platform/aarch64/zcu102/board.rs b/platform/aarch64/zcu102/board.rs index b3527283..1ca5fe5b 100644 --- a/platform/aarch64/zcu102/board.rs +++ b/platform/aarch64/zcu102/board.rs @@ -15,7 +15,10 @@ // ForeverYolo <2572131118@qq.com> use crate::config::HvConfigMemoryRegion; use crate::{ - arch::{mmu::MemoryType, zone::{GicConfig, Gicv2Config, HvArchZoneConfig},}, + arch::{ + mmu::MemoryType, + zone::{GicConfig, Gicv2Config, HvArchZoneConfig}, + }, config::*, }; @@ -112,7 +115,8 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 9] = [ }, // gpio ]; -pub const ROOT_ZONE_IRQS: [u32; 11] = [53, 81, 175, 176, 177, 178, 64, 50, 48, 49, 95]; +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = + &get_irqs_bitmap(&[53, 81, 175, 176, 177, 178, 64, 50, 48, 49, 95]); // serial-mmc-pmu-pmu-pmu-pmu-(hvisor_virtio_device)-gpio-i2c(ff030000)-i2c(ff020000)-ethernet pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { diff --git a/platform/loongarch64/ls3a5000/board.rs b/platform/loongarch64/ls3a5000/board.rs index 184dc110..0ac53198 100644 --- a/platform/loongarch64/ls3a5000/board.rs +++ b/platform/loongarch64/ls3a5000/board.rs @@ -150,7 +150,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ }, // SHARD_MEM ]; -pub const ROOT_ZONE_IRQS: [u32; 0] = []; +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { dummy: 0 }; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; diff --git a/platform/loongarch64/ls3a6000/board.rs b/platform/loongarch64/ls3a6000/board.rs index 184dc110..0ac53198 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -150,7 +150,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ }, // SHARD_MEM ]; -pub const ROOT_ZONE_IRQS: [u32; 0] = []; +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { dummy: 0 }; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; diff --git a/platform/riscv64/hifive-premier-p550/board.rs b/platform/riscv64/hifive-premier-p550/board.rs index e7a3d179..9cf06504 100644 --- a/platform/riscv64/hifive-premier-p550/board.rs +++ b/platform/riscv64/hifive-premier-p550/board.rs @@ -146,7 +146,7 @@ pub const HW_IRQS: [u32; 21] = [ 0x1, 0x2, 0x3, 0x4, // cache controller 0x4f, // emmc 0x51, // sd-card - 0x64, // uart0 + 0x64, // uart0 0x164, 0x168, 0x165, 0x166, // iommu 0x183, // npu 0x75, 0x77, 0x79, 0x7b, 0x7d, 0x7f, 0x81, 0x83, // mailbox @@ -155,16 +155,15 @@ pub const HW_IRQS: [u32; 21] = [ ]; // irqs belong to the root zone. -pub const ROOT_ZONE_IRQS: [u32; 20] = [ +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[ 0x1, 0x2, 0x3, 0x4, // cache controller 0x51, // sd-card - 0x64, // uart0 + 0x64, // uart0 0x164, 0x168, 0x165, 0x166, // iommu 0x183, // npu 0x75, 0x77, 0x79, 0x7b, 0x7d, 0x7f, 0x81, 0x83, // mailbox 0x123, // i2c - // 0x01, 0x03, 0x04, 0x02, // cache controller -]; +]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { plic_base: 0xc000000, diff --git a/platform/riscv64/megrez/board.rs b/platform/riscv64/megrez/board.rs index bfe9abe6..e77374b0 100644 --- a/platform/riscv64/megrez/board.rs +++ b/platform/riscv64/megrez/board.rs @@ -198,11 +198,11 @@ pub const HW_IRQS: [u32; 8] = [ ]; // irqs belong to the root zone. -pub const ROOT_ZONE_IRQS: [u32; 3] = [ +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[ 0x51, // mmc@0x50460000 0x64, // serial@0x50900000 0x3d, // ethernet@50400000 -]; +]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { plic_base: 0xc000000, diff --git a/platform/riscv64/qemu-aia/board.rs b/platform/riscv64/qemu-aia/board.rs index 059b4d46..a23eae5b 100644 --- a/platform/riscv64/qemu-aia/board.rs +++ b/platform/riscv64/qemu-aia/board.rs @@ -98,7 +98,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 9] = [ ]; pub const HW_IRQS: [u32; 11] = [1, 2, 3, 4, 5, 8, 10, 33, 34, 35, 36]; -pub const ROOT_ZONE_IRQS: [u32; 11] = [1, 2, 3, 4, 5, 8, 10, 33, 34, 35, 36]; // ARCH= riscv .It doesn't matter temporarily. +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[1, 2, 3, 4, 5, 8, 10, 33, 34, 35, 36]); // ARCH= riscv .It doesn't matter temporarily. pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { plic_base: 0xc000000, diff --git a/platform/riscv64/qemu-plic/board.rs b/platform/riscv64/qemu-plic/board.rs index 094ef417..569cb327 100644 --- a/platform/riscv64/qemu-plic/board.rs +++ b/platform/riscv64/qemu-plic/board.rs @@ -100,7 +100,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 9] = [ pub const HW_IRQS: [u32; 11] = [1, 2, 3, 4, 5, 8, 10, 33, 34, 35, 36]; // irqs belong to the root zone. -pub const ROOT_ZONE_IRQS: [u32; 11] = [1, 2, 3, 4, 5, 8, 10, 33, 34, 35, 36]; +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[1, 2, 3, 4, 5, 8, 10, 33, 34, 35, 36]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { plic_base: 0xc000000, diff --git a/platform/x86_64/nuc14mnk/board.rs b/platform/x86_64/nuc14mnk/board.rs index d5f001e9..cad0456c 100644 --- a/platform/x86_64/nuc14mnk/board.rs +++ b/platform/x86_64/nuc14mnk/board.rs @@ -128,7 +128,7 @@ const ROOT_ZONE_SETUP_ADDR: GuestPhysAddr = 0xa000; const ROOT_ZONE_VMLINUX_ENTRY_ADDR: GuestPhysAddr = 0x10_0000; const ROOT_ZONE_SCREEN_BASE_ADDR: GuestPhysAddr = 0x8000_0000; -pub const ROOT_ZONE_IRQS: [u32; 32] = [0; 32]; +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[0; 32]); pub const ROOT_ZONE_IOAPIC_BASE: usize = 0xfec0_0000; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { ioapic_base: ROOT_ZONE_IOAPIC_BASE, diff --git a/platform/x86_64/qemu/board.rs b/platform/x86_64/qemu/board.rs index 342bac03..666ad306 100644 --- a/platform/x86_64/qemu/board.rs +++ b/platform/x86_64/qemu/board.rs @@ -92,7 +92,7 @@ const ROOT_ZONE_SETUP_ADDR: GuestPhysAddr = 0xa000; const ROOT_ZONE_VMLINUX_ENTRY_ADDR: GuestPhysAddr = 0x10_0000; const ROOT_ZONE_SCREEN_BASE_ADDR: GuestPhysAddr = 0x7000_0000; -pub const ROOT_ZONE_IRQS: [u32; 32] = [0; 32]; +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[0; 32]); pub const ROOT_ZONE_IOAPIC_BASE: usize = 0xfec0_0000; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { ioapic_base: ROOT_ZONE_IOAPIC_BASE, diff --git a/src/arch/loongarch64/zone.rs b/src/arch/loongarch64/zone.rs index 96ac8883..b9dd8b70 100644 --- a/src/arch/loongarch64/zone.rs +++ b/src/arch/loongarch64/zone.rs @@ -117,7 +117,7 @@ impl Zone { } Ok(()) } - pub fn irq_bitmap_init(&mut self, irqs: &[u32]) {} + pub fn irq_bitmap_init(&mut self, irqs_bitmap: &[u32]) {} } pub fn disable_hwi_through() { diff --git a/src/arch/x86_64/zone.rs b/src/arch/x86_64/zone.rs index 75e7c43d..e4a55f82 100644 --- a/src/arch/x86_64/zone.rs +++ b/src/arch/x86_64/zone.rs @@ -96,7 +96,7 @@ impl Zone { Ok(()) } - pub fn irq_bitmap_init(&mut self, irqs: &[u32]) {} + pub fn irq_bitmap_init(&mut self, irqs_bitmap: &[u32]) {} /// called after cpu_set is initialized pub fn arch_zone_pre_configuration(&mut self, config: &HvZoneConfig) -> HvResult { diff --git a/src/config.rs b/src/config.rs index 7d72f45d..e09876a3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -22,9 +22,13 @@ 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 type BitmapWord = u32; +pub const CONFIG_MAX_INTERRUPTS: usize = 1024; +pub const CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD: usize = 32; + pub const CONFIG_NAME_MAXLEN: usize = 32; pub const CONFIG_MAX_IVC_CONFIGS: usize = 2; pub const CONFIG_MAX_PCI_DEV: usize = 32; @@ -80,8 +84,7 @@ pub struct HvZoneConfig { cpus: u64, num_memory_regions: u32, memory_regions: [HvConfigMemoryRegion; CONFIG_MAX_MEMORY_REGIONS], - num_interrupts: u32, - interrupts: [u32; CONFIG_MAX_INTERRUPTS], + interrupts_bitmap: [BitmapWord; CONFIG_MAX_INTERRUPTS / CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD], num_ivc_configs: u32, ivc_configs: [HvIvcConfig; CONFIG_MAX_IVC_CONFIGS], pub entry_point: u64, @@ -102,8 +105,8 @@ impl HvZoneConfig { cpus: u64, num_memory_regions: u32, memory_regions: [HvConfigMemoryRegion; CONFIG_MAX_MEMORY_REGIONS], - num_interrupts: u32, - interrupts: [u32; CONFIG_MAX_INTERRUPTS], + interrupts_bitmap: [BitmapWord; + CONFIG_MAX_INTERRUPTS / CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD], num_ivc_configs: u32, ivc_configs: [HvIvcConfig; CONFIG_MAX_IVC_CONFIGS], entry_point: u64, @@ -122,8 +125,7 @@ impl HvZoneConfig { cpus, num_memory_regions, memory_regions, - num_interrupts, - interrupts, + interrupts_bitmap, num_ivc_configs, ivc_configs, entry_point, @@ -144,8 +146,8 @@ impl HvZoneConfig { &self.memory_regions[..self.num_memory_regions as usize] } - pub fn interrupts(&self) -> &[u32] { - &self.interrupts[..self.num_interrupts as usize] + pub fn interrupts_bitmap(&self) -> &[BitmapWord] { + &self.interrupts_bitmap } pub fn cpus(&self) -> Vec { @@ -192,3 +194,32 @@ pub struct HvIvcConfig { pub interrupt_num: u32, pub max_peers: u32, } + +pub const fn get_irqs_bitmap( + numbers: &[u32; N], +) -> [BitmapWord; CONFIG_MAX_INTERRUPTS / CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD] { + assert!( + CONFIG_MAX_INTERRUPTS % CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD == 0, + "Configuration error: CONFIG_MAX_INTERRUPTS must be a multiple of 32 for a [u32] bitmap without rounding.", + ); + + let mut bitmap = [0; CONFIG_MAX_INTERRUPTS / CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD]; + + let mut i = 0; + while i < N { + let num = numbers[i]; + + assert!( + (num as usize) < CONFIG_MAX_INTERRUPTS, + "Input IRQ number is out of bounds. It must be less than CONFIG_MAX_INTERRUPTS.", + ); + + let word_index = num as usize / CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD; + let bit_index = num as usize & (CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD - 1); + + bitmap[word_index] |= (1 as BitmapWord) << bit_index; + i += 1; + } + + bitmap +} diff --git a/src/device/irqchip/aia/mod.rs b/src/device/irqchip/aia/mod.rs index fd1b89a4..9043dc85 100644 --- a/src/device/irqchip/aia/mod.rs +++ b/src/device/irqchip/aia/mod.rs @@ -22,7 +22,7 @@ pub mod vaplic; pub mod vimsic; use crate::arch::cpu::this_cpu_id; use crate::arch::zone::HvArchZoneConfig; -use crate::config::HvZoneConfig; +use crate::config::{BitmapWord, HvZoneConfig, CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD}; use crate::consts::{MAX_CPU_NUM, MAX_ZONE_NUM}; use crate::error::HvResult; use crate::memory::GuestPhysAddr; @@ -219,16 +219,23 @@ impl Zone { } /// irq_bitmap_init, and set these irqs' hw bit in vplic to true. - pub fn irq_bitmap_init(&mut self, irqs: &[u32]) { + pub fn irq_bitmap_init(&mut self, irqs_bitmap: &[BitmapWord]) { // insert to zone.irq_bitmap - for irq in irqs { - let irq_id = *irq; - // They are hardware interrupts. - if HW_IRQS.iter().any(|&x| x == irq_id) { - self.get_vaplic().vaplic_set_hw(irq_id as usize, true); - info!("Set irq {} to hardware interrupt", irq_id); + for i in 0..irqs_bitmap.len() { + let word = irqs_bitmap[i]; + + for j in 0..CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD { + if ((word >> j) & 1) == 1 { + let irq_id = (i * CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD + j) as u32; + + // They are hardware interrupts. + if HW_IRQS.iter().any(|&x| x == irq_id) { + self.get_vaplic().vaplic_set_hw(irq_id as usize, true); + info!("Set irq {} to hardware interrupt", irq_id); + } + self.insert_irq_to_bitmap(irq_id); + } } - self.insert_irq_to_bitmap(irq_id); } // print irq_bitmap for (index, &word) in self.irq_bitmap.iter().enumerate() { diff --git a/src/device/irqchip/gicv2/vgic.rs b/src/device/irqchip/gicv2/vgic.rs index a3af2309..4490ef10 100644 --- a/src/device/irqchip/gicv2/vgic.rs +++ b/src/device/irqchip/gicv2/vgic.rs @@ -14,6 +14,7 @@ // Authors: // Hangqi Ren <2572131118@qq.com> use crate::arch::zone::{GicConfig, Gicv2Config, HvArchZoneConfig}; +use crate::config::{BitmapWord, CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD}; use crate::device::irqchip::gicv2::gicd::{ get_max_int_num, GICD, GICD_CTRL_REG_OFFSET, GICD_ICACTIVER_REG_OFFSET, GICD_ICENABLER_REG_OFFSET, GICD_ICFGR_REG_OFFSET, GICD_ICPENDR_REG_OFFSET, @@ -93,12 +94,21 @@ impl Zone { } // store the interrupt number in the irq_bitmap. - pub fn irq_bitmap_init(&mut self, irqs: &[u32]) { + pub fn irq_bitmap_init(&mut self, irqs_bitmap: &[BitmapWord]) { // Enable each cpu's sgi and ppi access permission self.irq_bitmap[0] = 0xffff_ffff; - for irq in irqs { - self.insert_irq_to_bitmap(*irq); + + for i in 0..irqs_bitmap.len() { + let word = irqs_bitmap[i]; + + for j in 0..CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD { + if ((word >> j) & 1) == 1 { + let irq_id = (i * CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD + j) as u32; + self.insert_irq_to_bitmap(irq_id); + } + } } + for (index, &word) in self.irq_bitmap.iter().enumerate() { for bit_position in 0..32 { if word & (1 << bit_position) != 0 { diff --git a/src/device/irqchip/gicv3/vgic.rs b/src/device/irqchip/gicv3/vgic.rs index 7c52c26e..bd16002b 100644 --- a/src/device/irqchip/gicv3/vgic.rs +++ b/src/device/irqchip/gicv3/vgic.rs @@ -19,6 +19,7 @@ use super::{gicd::GICD_LOCK, is_spi}; use crate::platform::BOARD_MPIDR_MAPPINGS; use crate::{ arch::zone::{GicConfig, Gicv2Config, Gicv3Config, HvArchZoneConfig}, + config::{BitmapWord, CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD, CONFIG_MAX_INTERRUPTS}, consts::MAX_CPU_NUM, device::irqchip::gicv3::{ gicd::*, gicr::*, gits::*, host_gicd_base, host_gicr_base, host_gits_base, @@ -72,14 +73,23 @@ impl Zone { } } - pub fn irq_bitmap_init(&mut self, irqs: &[u32]) { - for irq in irqs { - self.insert_irq_to_bitmap(*irq); + pub fn irq_bitmap_init(&mut self, irqs_bitmap: &[BitmapWord]) { + for i in 0..irqs_bitmap.len() { + let word = irqs_bitmap[i]; + + for j in 0..CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD { + if ((word >> j) & 1) == 1 { + let irq_id = (i * CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD + j) as u32; + self.insert_irq_to_bitmap(irq_id); + } + } } + for (index, &word) in self.irq_bitmap.iter().enumerate() { - for bit_position in 0..32 { + for bit_position in 0..CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD { if word & (1 << bit_position) != 0 { - let interrupt_number = index * 32 + bit_position; + let interrupt_number = + index * CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD + bit_position; info!( "Found interrupt in Zone {} irq_bitmap: {}", self.id, interrupt_number @@ -90,9 +100,9 @@ impl Zone { } fn insert_irq_to_bitmap(&mut self, irq: u32) { - assert!(irq < 1024); // 1024 is the maximum number of interrupts supported by GICv3 (GICD_TYPER.ITLinesNumber) - let irq_index = irq / 32; - let irq_bit = irq % 32; + assert!(irq < (CONFIG_MAX_INTERRUPTS as u32)); // CONFIG_MAX_INTERRUPTS is the maximum number of interrupts supported by GICv3 (GICD_TYPER.ITLinesNumber) + let irq_index = irq / (CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD as u32); + let irq_bit = irq % (CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD as u32); self.irq_bitmap[irq_index as usize] |= 1 << irq_bit; } } diff --git a/src/device/irqchip/plic/mod.rs b/src/device/irqchip/plic/mod.rs index 64a9163c..243580c8 100644 --- a/src/device/irqchip/plic/mod.rs +++ b/src/device/irqchip/plic/mod.rs @@ -22,6 +22,7 @@ use self::vplic::*; use crate::arch::zone::HvArchZoneConfig; use crate::config::root_zone_config; use crate::config::HvZoneConfig; +use crate::config::{BitmapWord, CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD}; use crate::consts::{MAX_CPU_NUM, MAX_ZONE_NUM}; use crate::error::HvResult; use crate::memory::mmio::MMIOAccess; @@ -256,17 +257,26 @@ impl Zone { } /// irq_bitmap_init, and set these irqs' hw bit in vplic to true. - pub fn irq_bitmap_init(&mut self, irqs: &[u32]) { + pub fn irq_bitmap_init(&mut self, irqs_bitmap: &[BitmapWord]) { // insert to zone.irq_bitmap - for irq in irqs { - let irq_id = *irq; - // They are hardware interrupts. - if HW_IRQS.iter().any(|&x| x == irq_id) { - self.get_vplic().vplic_set_hw(irq_id as usize, true); - info!("Set irq {} to hardware interrupt", irq_id); + for i in 0..irqs_bitmap.len() { + let word = irqs_bitmap[i]; + + for j in 0..CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD { + if ((word >> j) & 1) == 1 { + let irq_id = (i * CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD + j) as u32; + + // They are hardware interrupts. + if HW_IRQS.iter().any(|&x| x == irq_id) { + self.get_vplic().vplic_set_hw(irq_id as usize, true); + info!("Set irq {} to hardware interrupt", irq_id); + } + + self.insert_irq_to_bitmap(irq_id); + } } - self.insert_irq_to_bitmap(irq_id); } + // print irq_bitmap for (index, &word) in self.irq_bitmap.iter().enumerate() { for bit_position in 0..32 { diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 8dc1c493..d5241d9b 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, HvZoneConfig, + CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD, CONFIG_MAX_INTERRUPTS, CONFIG_MAX_IVC_CONFIGS, + CONFIG_MAX_MEMORY_REGIONS, CONFIG_MAX_PCI_DEV, CONFIG_NAME_MAXLEN, }, consts::INVALID_ADDRESS, }; @@ -59,13 +60,8 @@ pub fn platform_root_zone_config() -> HvZoneConfig { ivc_configs[.._num_ivc_configs].copy_from_slice(&ROOT_ZONE_IVC_CONFIG); } - let mut interrupts = [0; CONFIG_MAX_INTERRUPTS]; - check!( - ROOT_ZONE_IRQS.len(), - CONFIG_MAX_INTERRUPTS, - "ROOT_ZONE_IRQS" - ); - interrupts[..ROOT_ZONE_IRQS.len()].copy_from_slice(&ROOT_ZONE_IRQS); + let mut interrupts_bitmap = [0; CONFIG_MAX_INTERRUPTS / CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD]; + interrupts_bitmap[..ROOT_ZONE_IRQS_BITMAP.len()].copy_from_slice(&ROOT_ZONE_IRQS_BITMAP); let mut name = [0; CONFIG_NAME_MAXLEN]; check!(ROOT_ZONE_NAME.len(), CONFIG_NAME_MAXLEN, "ROOT_ZONE_NAME"); @@ -88,8 +84,7 @@ pub fn platform_root_zone_config() -> HvZoneConfig { ROOT_ZONE_CPUS, ROOT_ZONE_MEMORY_REGIONS.len() as u32, memory_regions, - ROOT_ZONE_IRQS.len() as u32, - interrupts, + interrupts_bitmap, _num_ivc_configs as _, ivc_configs, ROOT_ZONE_ENTRY, diff --git a/src/zone.rs b/src/zone.rs index 58bf6ec4..28c99a4a 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -256,7 +256,7 @@ pub fn zone_create(config: &HvZoneConfig) -> HvResult>> { // Initialize the virtual interrupt controller, it needs zone.cpu_num zone.virqc_init(config); - zone.irq_bitmap_init(config.interrupts()); + zone.irq_bitmap_init(config.interrupts_bitmap()); let mut dtb_ipa = INVALID_ADDRESS as u64; for region in config.memory_regions() { From e93d1a34b33bf1015ced03636d5f01631fa34692 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 26 Nov 2025 18:45:13 +0800 Subject: [PATCH 030/109] 1.no_pcie_bar_realloc is now working correctly 2.for loongarch, pCI can now access HT with the correct address header 3.correctly traverse the next bridge, which is a device with the next function 4.only function0 is checked to determine if it is a multifunction device --- src/config.rs | 5 +-- src/pci/config_accessors/loongarch64.rs | 6 ++- src/pci/pci_config.rs | 6 +-- src/pci/pci_struct.rs | 54 +++++++++++++++---------- src/pci/pci_test.rs | 2 +- 5 files changed, 41 insertions(+), 32 deletions(-) diff --git a/src/config.rs b/src/config.rs index 4a09b211..13db0681 100644 --- a/src/config.rs +++ b/src/config.rs @@ -211,7 +211,6 @@ pub struct HvIvcConfig { #[derive(Copy, Clone, Default)] pub struct HvPciDevConfig { pub bdf: u64, - pub vbdf: u64, } #[macro_export] @@ -219,7 +218,6 @@ macro_rules! pci_dev { ($bus:expr, $dev:expr, $func:expr) => { HvPciDevConfig { bdf: ($bus << 8) | ($dev << 3) | ($func), - vbdf: ($bus << 8) | ($dev << 3) | ($func), } }; } @@ -227,8 +225,7 @@ macro_rules! pci_dev { 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); - let vbdf = crate::pci::pci_struct::Bdf::from_address(self.vbdf); - write!(f, "bdf {:#?} vbdf {:#?}", bdf, vbdf) + write!(f, "bdf {:#?}", bdf) } } diff --git a/src/pci/config_accessors/loongarch64.rs b/src/pci/config_accessors/loongarch64.rs index dd412248..7516d7f6 100644 --- a/src/pci/config_accessors/loongarch64.rs +++ b/src/pci/config_accessors/loongarch64.rs @@ -20,7 +20,6 @@ use bit_field::BitField; use super::{PciConfigAccessor, PciConfigMmio, PciRegion}; use crate::{ - arch::loongarch64::mm::LOONGARCH64_UNCACHED_DMW_PREFIX, error::HvResult, pci::{ pci_struct::{Bdf, RootComplex}, @@ -104,8 +103,11 @@ impl PciConfigAccessor for LoongArchConfigAccessor { } } +pub const HV_ADDR_PREFIX: u64 = 0x8000_0000_0000_0000; +pub const LOONG_HT_PREFIX: u64 = 0xe00_0000_0000; + impl PciConfigMmio { pub(crate) fn access(&self, offset: PciConfigAddress) -> *mut T { - (self.base + offset | LOONGARCH64_UNCACHED_DMW_PREFIX) as *mut T + (self.base + offset | HV_ADDR_PREFIX | LOONG_HT_PREFIX) as *mut T } } diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 6571054c..61de492e 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -69,9 +69,9 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { // TODO: refactor // in x86, we do not take the initiative to reallocate BAR space - #[cfg(target_arch = "no_pcie_bar_realloc")] + #[cfg(feature = "no_pcie_bar_realloc")] let allocator_opt: Option = None; - #[cfg(not(target_arch = "no_pcie_bar_realloc"))] + #[cfg(not(feature = "no_pcie_bar_realloc"))] let allocator_opt: Option = Some(allocator); let mut rootcomplex = { @@ -136,7 +136,7 @@ impl Zone { while i < num_pci_devs { let dev_config = alloc_pci_devs[i as usize]; let bdf = Bdf::from_address(dev_config.bdf << 12); - let vbdf = Bdf::from_address(dev_config.vbdf << 12); + let vbdf = bdf.clone(); #[cfg(any( all(feature = "iommu", target_arch = "aarch64"), target_arch = "x86_64" diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 142f6b1d..f6205ed1 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -26,6 +26,7 @@ use super::{ PciConfigHeader, PciHeaderRW, PciMem, PciMemType, PciRW, PciRomRW, }, PciConfigAddress, + pci_access::{BaseClass, SubClass, Interface}, }; use crate::error::{HvErrorNum, HvResult}; @@ -223,6 +224,7 @@ pub struct VirtualPciConfigSpace { bdf: Bdf, vbdf: Bdf, config_type: HeaderType, + class: (BaseClass, SubClass, Interface), base: PciConfigAddress, @@ -311,6 +313,7 @@ impl VirtualPciConfigSpace { backend: Arc, bararr: Bar, rom: PciMem, + class: (BaseClass, SubClass, Interface), ) -> Self { Self { host_bdf: Bdf::default(), @@ -318,6 +321,7 @@ impl VirtualPciConfigSpace { bdf, vbdf: Bdf::default(), config_type: HeaderType::Endpoint, + class, base, space: [0u8; BIT_LENTH], control: VirtualPciConfigControl::endpoint(), @@ -335,6 +339,7 @@ impl VirtualPciConfigSpace { backend: Arc, bararr: Bar, rom: PciMem, + class: (BaseClass, SubClass, Interface), ) -> Self { Self { host_bdf: Bdf::default(), @@ -342,6 +347,7 @@ impl VirtualPciConfigSpace { bdf, vbdf: Bdf::default(), config_type: HeaderType::PciBridge, + class, base, space: [0u8; BIT_LENTH], control: VirtualPciConfigControl::bridge(), @@ -360,6 +366,7 @@ impl VirtualPciConfigSpace { bdf, vbdf: Bdf::default(), config_type: HeaderType::Endpoint, + class: (0u8,0u8,0u8), base, space: [0u8; BIT_LENTH], control: VirtualPciConfigControl::endpoint(), @@ -371,13 +378,14 @@ impl VirtualPciConfigSpace { } } - pub fn host_bridge(bdf: Bdf, base: PciConfigAddress, backend: Arc) -> Self { + pub fn host_bridge(bdf: Bdf, base: PciConfigAddress, backend: Arc, class: (BaseClass, SubClass, Interface)) -> Self { Self { host_bdf: bdf, parent_bdf: bdf, bdf: bdf, vbdf: bdf, config_type: HeaderType::Endpoint, + class, base, space: [0u8; BIT_LENTH], control: VirtualPciConfigControl::host_bridge(), @@ -585,7 +593,13 @@ impl PciIterator { return None; } - self.is_mulitple_function = pci_header.has_multiple_functions(); + // only check is_mulitple_function for function 0 + if self.function == 0 { + self.is_mulitple_function = pci_header.has_multiple_functions(); + } + + let (_, base_class, sub_class, interface) = pci_header.revision_and_class(); + let class = (base_class, sub_class, interface); match pci_header.header_type() { HeaderType::Endpoint => { @@ -605,7 +619,7 @@ impl PciIterator { info!("get node bar mem init end {:#?}", bararr); let ep = Arc::new(ep); - let mut node = VirtualPciConfigSpace::endpoint(bdf, address, ep, bararr, rom); + let mut node = VirtualPciConfigSpace::endpoint(bdf, address, ep, bararr, rom, class); let _ = node.capability_enumerate(); @@ -621,7 +635,7 @@ impl PciIterator { Self::bar_mem_init(bridge.bar_limit().into(), &mut self.allocator, &mut bridge); let bridge = Arc::new(bridge); - let mut node = VirtualPciConfigSpace::bridge(bdf, address, bridge, bararr, rom); + let mut node = VirtualPciConfigSpace::bridge(bdf, address, bridge, bararr, rom, class); let _ = node.capability_enumerate(); @@ -726,21 +740,6 @@ impl PciIterator { } } - 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() { // only one child and skip this bus @@ -776,6 +775,12 @@ impl PciIterator { self.stack.push(bridge.clone()); + if self.is_mulitple_function && self.function < MAX_FUNCTION { + // Device supports multiple functions and we haven't checked all functions yet + self.function += 1; + return; + } + self.function = 0; return; } @@ -805,7 +810,11 @@ impl Iterator for PciIterator { if let Some(mut node) = self.get_node() { node.space_init(); let bus_begin = self.bus_range.start as u8; - // Ensure stack has a parent (host bridge if empty) + /* + * when first time to enumerate, placeholder is pop in get_node + * the message of host bridge must be got after get_node() + * so we push host bridge to stack here + */ if self.stack.is_empty() { let host_bridge = Bridge::host_bridge(self.segment, bus_begin); self.stack.push(host_bridge); @@ -816,8 +825,9 @@ impl Iterator for PciIterator { let parent_bus = parent.primary_bus; node.set_host_bdf(host_bdf); node.set_parent_bdf(parent_bdf); - self.next(match node.config_type { - HeaderType::PciBridge => { + //todo check bridge with + self.next(match node.class.0 { + 0x6 => { let bdf = Bdf::new(parent.bus, parent.device, parent.subordinate_bus); Some( self.get_bridge().next_bridge( diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs index e8c299d0..a61bb521 100644 --- a/src/pci/pci_test.rs +++ b/src/pci/pci_test.rs @@ -59,7 +59,7 @@ pub fn pcie_guest_init() { let bdf = Bdf::from_str("0000:00:00.0").unwrap(); let base = 0x4010000000; // Base address for test let backend = EndpointHeader::new_with_region(PciConfigMmio::new(base, CONFIG_LENTH)); - let dev = VirtualPciConfigSpace::host_bridge(bdf, base, Arc::new(backend)); + let dev = VirtualPciConfigSpace::host_bridge(bdf, base, Arc::new(backend), (0x6u8,0x0u8,0u8)); vbus.insert(vbdf, dev); let vbdf = Bdf::from_str("0000:00:01.0").unwrap(); From 223ffa07fb6cf058f422ee5443e3b3fe4c76cff8 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 26 Nov 2025 19:24:06 +0800 Subject: [PATCH 031/109] add function and is_mulitple_function to stack --- src/pci/pci_struct.rs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index f6205ed1..1e6f50c4 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -606,7 +606,7 @@ impl PciIterator { // For endpoint: push host_bridge if we popped placeholder if was_placeholder { let bus_begin = self.bus_range.start as u8; - let host_bridge = Bridge::host_bridge(self.segment, bus_begin); + let host_bridge = Bridge::host_bridge(self.segment, bus_begin, self.is_mulitple_function, self.function); self.stack.push(host_bridge); } @@ -752,7 +752,8 @@ impl PciIterator { self.is_finish = parent.subordinate_bus as usize == self.bus_range.end; parent.update_bridge_bus(); - self.function = 0; + self.function = parent.function; + self.is_mulitple_function = parent.is_mulitple_function; return true; } else { self.is_finish = true; @@ -780,7 +781,7 @@ impl PciIterator { self.function += 1; return; } - + self.function = 0; return; } @@ -816,7 +817,7 @@ impl Iterator for PciIterator { * so we push host bridge to stack here */ if self.stack.is_empty() { - let host_bridge = Bridge::host_bridge(self.segment, bus_begin); + let host_bridge = Bridge::host_bridge(self.segment, bus_begin, self.is_mulitple_function, self.function); self.stack.push(host_bridge); } let parent = self.stack.last().unwrap(); // Safe because we just ensured it exists @@ -825,14 +826,15 @@ impl Iterator for PciIterator { let parent_bus = parent.primary_bus; node.set_host_bdf(host_bdf); node.set_parent_bdf(parent_bdf); - //todo check bridge with self.next(match node.class.0 { - 0x6 => { - let bdf = Bdf::new(parent.bus, parent.device, parent.subordinate_bus); + 0x6 if node.class.1 != 0x0 => { + let bdf = Bdf::new(parent.subordinate_bus + 1, 0, 0); Some( self.get_bridge().next_bridge( self.address(parent_bus, bdf), node.has_secondary_link(), + self.is_mulitple_function, + self.function ), ) } @@ -851,11 +853,13 @@ impl Iterator for PciIterator { pub struct Bridge { bus: u8, device: u8, + function: u8, subordinate_bus: u8, secondary_bus: u8, primary_bus: u8, mmio: PciConfigMmio, has_secondary_link: bool, + is_mulitple_function: bool, } impl Bridge { @@ -865,36 +869,42 @@ impl Bridge { Self { bus: 0, device: 0, + function: 0, subordinate_bus: 0, secondary_bus: 0, primary_bus: 0, mmio: PciConfigMmio::new(0, 0), // Dummy mmio for placeholder has_secondary_link: false, + is_mulitple_function: false, } } - pub fn host_bridge(address: PciConfigAddress, bus_begin: u8) -> Self { + pub fn host_bridge(address: PciConfigAddress, bus_begin: u8, is_mulitple_function: bool, function: u8) -> Self { Self { bus: bus_begin, device: 0, + function, subordinate_bus: bus_begin, secondary_bus: bus_begin, primary_bus: bus_begin, mmio: PciConfigMmio::new(address, CONFIG_LENTH), has_secondary_link: false, + is_mulitple_function, } } - pub fn next_bridge(&self, address: PciConfigAddress, has_secondary_link: bool) -> Self { + pub fn next_bridge(&self, address: PciConfigAddress, has_secondary_link: bool, is_mulitple_function: bool, function: u8) -> Self { let mmio = PciConfigMmio::new(address, CONFIG_LENTH); Self { bus: self.subordinate_bus + 1, device: 0, + function, subordinate_bus: self.subordinate_bus + 1, secondary_bus: self.subordinate_bus + 1, primary_bus: self.bus, mmio, has_secondary_link, + is_mulitple_function, } } From 03aa2c0169b3af3dc18f9b31b7dea1c4ddc22eef Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 27 Nov 2025 12:22:32 +0800 Subject: [PATCH 032/109] [feature] add support for virt pci dev --- platform/loongarch64/ls3a6000/board.rs | 1 + src/config.rs | 6 +- src/pci/mod.rs | 1 + src/pci/pci_access.rs | 400 +++++++++++++++++-------- src/pci/pci_config.rs | 21 +- src/pci/pci_struct.rs | 134 ++++++++- src/pci/vpci_dev/mod.rs | 148 +++++++++ src/pci/vpci_dev/standard.rs | 66 ++++ src/zone.rs | 2 +- 9 files changed, 630 insertions(+), 149 deletions(-) create mode 100644 src/pci/vpci_dev/mod.rs create mode 100644 src/pci/vpci_dev/standard.rs diff --git a/platform/loongarch64/ls3a6000/board.rs b/platform/loongarch64/ls3a6000/board.rs index 56911387..252c6c3e 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -16,6 +16,7 @@ // use crate::{arch::zone::HvArchZoneConfig, config::*}; use crate::pci_dev; +use crate::pci::vpci_dev::VpciDevType; pub const BOARD_NAME: &str = "ls3a5000"; diff --git a/src/config.rs b/src/config.rs index 13db0681..a2b253a6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -17,7 +17,7 @@ use alloc::vec::Vec; use core::fmt::Debug; use spin::Once; -use crate::{arch::zone::HvArchZoneConfig, platform}; +use crate::{arch::zone::HvArchZoneConfig, pci::vpci_dev::VpciDevType, platform}; pub const MEM_TYPE_RAM: u32 = 0; pub const MEM_TYPE_IO: u32 = 1; @@ -211,13 +211,15 @@ pub struct HvIvcConfig { #[derive(Copy, Clone, Default)] pub struct HvPciDevConfig { pub bdf: u64, + pub dev_type: VpciDevType, } #[macro_export] macro_rules! pci_dev { - ($bus:expr, $dev:expr, $func:expr) => { + ($bus:expr, $dev:expr, $func:expr, $dev_type:expr) => { HvPciDevConfig { bdf: ($bus << 8) | ($dev << 3) | ($func), + dev_type: $dev_type, } }; } diff --git a/src/pci/mod.rs b/src/pci/mod.rs index 0ef2bfac..f4f53512 100644 --- a/src/pci/mod.rs +++ b/src/pci/mod.rs @@ -19,6 +19,7 @@ pub mod mem_alloc; pub mod pci_access; pub mod pci_config; pub mod pci_struct; +pub mod vpci_dev; pub mod pci_test; diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 7c245d5b..2791058d 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -752,6 +752,11 @@ impl PciConfigHeader { * | | | pin | line | * +--------------+--------------+--------------+--------------+ */ +pub trait PciField { + fn to_offset(&self) -> usize; + fn size(&self) -> usize; +} + pub enum EndpointField { ID, Command, @@ -774,6 +779,56 @@ pub enum EndpointField { Unknown(usize), } +impl PciField for EndpointField { + fn to_offset(&self) -> usize { + match self { + EndpointField::ID => 0x00, + EndpointField::Command => 0x04, + EndpointField::Status => 0x06, + EndpointField::RevisionIDAndClassCode => 0x08, + EndpointField::CacheLineSize => 0x0c, + EndpointField::LatencyTime => 0x0d, + EndpointField::HeaderType => 0x0e, + EndpointField::Bist => 0x0f, + EndpointField::Bar => 0x10, + EndpointField::CardCisPointer => 0x28, + EndpointField::SubsystemVendorId => 0x2c, + EndpointField::SubsystemId => 0x2e, + EndpointField::ExpansionRomBar => 0x30, + EndpointField::CapabilityPointer => 0x34, + EndpointField::InterruptLine => 0x3c, + EndpointField::InterruptPin => 0x3d, + EndpointField::MinGnt => 0x3e, + EndpointField::MaxLat => 0x3f, + EndpointField::Unknown(offset) => *offset, + } + } + + fn size(&self) -> usize { + match self { + EndpointField::ID => 4, + EndpointField::Command => 2, + EndpointField::Status => 2, + EndpointField::RevisionIDAndClassCode => 4, + EndpointField::CacheLineSize => 1, + EndpointField::LatencyTime => 1, + EndpointField::HeaderType => 1, + EndpointField::Bist => 1, + EndpointField::Bar => 4, + EndpointField::CardCisPointer => 4, + EndpointField::SubsystemVendorId => 2, + EndpointField::SubsystemId => 2, + EndpointField::ExpansionRomBar => 4, + EndpointField::CapabilityPointer => 1, + EndpointField::InterruptLine => 1, + EndpointField::InterruptPin => 1, + EndpointField::MinGnt => 1, + EndpointField::MaxLat => 1, + EndpointField::Unknown(_) => 4, // Default to 4 bytes for unknown fields + } + } +} + impl EndpointField { pub fn from(offset: usize, size: usize) -> Self { match (offset, size) { @@ -800,6 +855,7 @@ impl EndpointField { (x, _) => EndpointField::Unknown(x), } } + } #[derive(Debug, Clone)] @@ -906,6 +962,78 @@ pub enum BridgeField { Unknown(usize), } +impl PciField for BridgeField { + fn to_offset(&self) -> usize { + match self { + BridgeField::ID => 0x00, + BridgeField::Command => 0x04, + BridgeField::Status => 0x06, + BridgeField::RevisionIDAndClassCode => 0x08, + BridgeField::CacheLineSize => 0x0c, + BridgeField::LatencyTime => 0x0d, + BridgeField::HeaderType => 0x0e, + BridgeField::Bist => 0x0f, + BridgeField::Bar => 0x10, + BridgeField::PrimaryBusNumber => 0x18, + BridgeField::SecondaryBusNumber => 0x19, + BridgeField::SubordinateBusNumber => 0x1a, + BridgeField::SecondaryLatencyTimer => 0x1b, + BridgeField::IOBase => 0x1c, + BridgeField::IOLimit => 0x1d, + BridgeField::SecondaryStatus => 0x1e, + BridgeField::MemoryBase => 0x20, + BridgeField::MemoryLimit => 0x22, + BridgeField::PrefetchableMemoryBase => 0x24, + BridgeField::PrefetchableMemoryLimit => 0x26, + BridgeField::PrefetchableBaseUpper32Bits => 0x28, + BridgeField::PrefetchableLimitUpper32Bits => 0x2c, + BridgeField::UIBaseUpper16Bits => 0x30, + BridgeField::IOLimitUpper16Bits => 0x32, + BridgeField::CapabilityPointer => 0x34, + BridgeField::ExpansionRomBar => 0x38, + BridgeField::InterruptLine => 0x3c, + BridgeField::InterruptPin => 0x3d, + BridgeField::BridgeControl => 0x3e, + BridgeField::Unknown(offset) => *offset, + } + } + + fn size(&self) -> usize { + match self { + BridgeField::ID => 4, + BridgeField::Command => 2, + BridgeField::Status => 2, + BridgeField::RevisionIDAndClassCode => 4, + BridgeField::CacheLineSize => 1, + BridgeField::LatencyTime => 1, + BridgeField::HeaderType => 1, + BridgeField::Bist => 1, + BridgeField::Bar => 4, + BridgeField::PrimaryBusNumber => 1, + BridgeField::SecondaryBusNumber => 1, + BridgeField::SubordinateBusNumber => 1, + BridgeField::SecondaryLatencyTimer => 1, + BridgeField::IOBase => 1, + BridgeField::IOLimit => 1, + BridgeField::SecondaryStatus => 2, + BridgeField::MemoryBase => 2, + BridgeField::MemoryLimit => 2, + BridgeField::PrefetchableMemoryBase => 2, + BridgeField::PrefetchableMemoryLimit => 2, + BridgeField::PrefetchableBaseUpper32Bits => 4, + BridgeField::PrefetchableLimitUpper32Bits => 4, + BridgeField::UIBaseUpper16Bits => 2, + BridgeField::IOLimitUpper16Bits => 2, + BridgeField::CapabilityPointer => 1, + BridgeField::ExpansionRomBar => 4, + BridgeField::InterruptLine => 1, + BridgeField::InterruptPin => 1, + BridgeField::BridgeControl => 2, + BridgeField::Unknown(_) => 4, // Default to 4 bytes for unknown fields + } + } +} + impl BridgeField { pub fn from(offset: usize, size: usize) -> Self { match (offset, size) { @@ -984,6 +1112,10 @@ fn handle_config_space_access( let is_write = mmio.is_write; let vbdf = dev.get_vbdf(); + if vbdf.bus == 0 && vbdf.device == 5 && vbdf.function == 0 { + info!("virt pci standard access, vbdf {:#?}, offset {:#x}, size {:#x}, is_write {:#?}", vbdf, offset, size, is_write); + } + if (offset as usize) >= BIT_LENTH { warn!("invalid pci offset {:#x}", offset); if !is_write { @@ -1012,7 +1144,7 @@ fn handle_config_space_access( } } true => { - debug!( + info!( "emu vbdf {:#?} reg 0x{:x} try {} {}", vbdf, offset, @@ -1023,148 +1155,159 @@ fn handle_config_space_access( 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 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) - | (bar_type == PciMemType::Io) - { - 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 + match dev.get_dev_type() { + super::vpci_dev::VpciDevType::Physical => { + 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 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) + | (bar_type == PciMemType::Io) + { + 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. 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 + * the old BAR addresses, potentially causing the update to fail? + */ + 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); + } + + let bar_size = if crate::memory::addr::is_aligned( + bar.get_size() as usize, + ) { + bar.get_size() + } else { + crate::memory::PAGE_SIZE as u64 + }; + + gpm.insert(MemoryRegion::new_with_offset_mapper( + new_vaddr as GuestPhysAddr, + paddr as HostPhysAddr, + bar_size as _, + MemFlags::READ | MemFlags::WRITE, + ))?; + /* after update gpm, mem barrier is needed + */ + #[cfg(target_arch = "aarch64")] + unsafe { + core::arch::asm!("isb"); + core::arch::asm!("tlbi vmalls12e1is"); + core::arch::asm!("dsb nsh"); + } + /* after update gpm, need to flush iommu table + * in x86_64 */ - dev.read_emu64(offset - 0x4).unwrap() & !0xf - } else { - (value as u64) & !0xf + #[cfg(target_arch = "x86_64")] + crate::arch::iommu::flush( + zone_id, + vbdf.bus, + (vbdf.device << 3) + vbdf.function, + ); } - }; - /* 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 - * 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 - * the old BAR addresses, potentially causing the update to fail? - */ - 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); } - - let bar_size = if crate::memory::addr::is_aligned( - bar.get_size() as usize, - ) { - bar.get_size() + } 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 { - crate::memory::PAGE_SIZE as u64 + bar.get_virtual_value().try_into().unwrap() }; - - gpm.insert(MemoryRegion::new_with_offset_mapper( - new_vaddr as GuestPhysAddr, - paddr as HostPhysAddr, - bar_size as _, - MemFlags::READ | MemFlags::WRITE, - ))?; - /* after update gpm, mem barrier is needed - */ - #[cfg(target_arch = "aarch64")] - unsafe { - core::arch::asm!("isb"); - core::arch::asm!("tlbi vmalls12e1is"); - core::arch::asm!("dsb nsh"); - } - /* after update gpm, need to flush iommu table - * in x86_64 - */ - #[cfg(target_arch = "x86_64")] - crate::arch::iommu::flush( - zone_id, - vbdf.bus, - (vbdf.device << 3) + vbdf.function, - ); } + } else { + mmio.value = 0; } - } 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 + } + EndpointField::ExpansionRomBar => { + let mut rom = dev.get_rom(); + if 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 { - bar.get_virtual_value().try_into().unwrap() - }; + mmio.value = if rom.get_size_read() { + dev.read_emu(offset, size).unwrap() + } else { + rom.get_size_with_flag().try_into().unwrap() + }; + } } - } else { - mmio.value = 0; + _ => {} } } - EndpointField::ExpansionRomBar => { - let mut rom = dev.get_rom(); - if 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!("bridge emu rw"); + } + _ => { + warn!("unhanled pci type {:#?}", dev.get_config_type()); } - _ => {} } } - HeaderType::PciBridge => { - // TODO: add emu for bridge, actually it is same with endpoint - warn!("bridge emu rw"); - } _ => { - warn!("unhanled pci type {:#?}", dev.get_config_type()); + if mmio.is_write { + super::vpci_dev::vpci_dev_write_cfg(dev.get_dev_type(), dev, offset, size, value).unwrap(); + } else { + mmio.value = super::vpci_dev::vpci_dev_read_cfg(dev.get_dev_type(), dev, offset, size).unwrap() as usize; + } } } } @@ -1182,7 +1325,6 @@ fn handle_config_space_access( } fn handle_device_not_found(mmio: &mut MMIOAccess, offset: PciConfigAddress) { - info!("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, mmio.size) { diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 61de492e..4ce65da9 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -20,7 +20,7 @@ use crate::{ arch::iommu::iommu_add_device, config::{HvPciConfig, HvPciDevConfig, CONFIG_MAX_PCI_DEV, CONFIG_PCI_BUS_MAXNUM}, error::HvResult, - pci::pci_struct::{Bdf, VirtualPciConfigSpace}, + pci::{pci_struct::{Bdf, VirtualPciConfigSpace}, vpci_dev::VpciDevType}, zone::Zone, }; @@ -130,6 +130,8 @@ impl Zone { zone_id: usize, alloc_pci_devs: &[HvPciDevConfig; CONFIG_MAX_PCI_DEV], num_pci_devs: u64, + //TODO: set vpci dev base in other way + _ecam_base: u64, ) -> HvResult { let mut guard = GLOBAL_PCIE_LIST.lock(); let mut i = 0; @@ -137,6 +139,7 @@ impl Zone { let dev_config = alloc_pci_devs[i as usize]; let bdf = Bdf::from_address(dev_config.bdf << 12); let vbdf = bdf.clone(); + let dev_type = dev_config.dev_type; #[cfg(any( all(feature = "iommu", target_arch = "aarch64"), target_arch = "x86_64" @@ -160,7 +163,21 @@ impl Zone { self.vpci_bus.insert(vbdf, vdev); } } else { - warn!("can not find dev {:#?}", bdf); + // warn!("can not find dev {:#?}", bdf); + #[cfg(feature = "ecam_pcie")] + match dev_type { + VpciDevType::StandardVdev => { + let base = _ecam_base + + ((bdf.bus() as u64) << 20) + + ((bdf.device() as u64) << 15) + + ((bdf.function() as u64) << 12); + let dev = VirtualPciConfigSpace::virt_dev(bdf, base); + self.vpci_bus.insert(vbdf, dev); + } + _ => { + warn!("can not find dev {:#?}", bdf); + } + } } i += 1; } diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 1e6f50c4..18c13c42 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -23,13 +23,13 @@ use super::{ mem_alloc::BarAllocator, pci_access::{ Bar, EndpointField, EndpointHeader, HeaderType, PciBarRW, PciBridgeHeader, PciCommand, - PciConfigHeader, PciHeaderRW, PciMem, PciMemType, PciRW, PciRomRW, + PciConfigHeader, PciField, PciHeaderRW, PciMem, PciMemType, PciRW, PciRomRW, }, PciConfigAddress, pci_access::{BaseClass, SubClass, Interface}, }; -use crate::error::{HvErrorNum, HvResult}; +use crate::{error::{HvErrorNum, HvResult}, pci::vpci_dev::VpciDevType}; type VirtualPciConfigBits = BitArr!(for BIT_LENTH, in u8, Lsb0); @@ -179,6 +179,12 @@ impl VirtualPciConfigControl { bits: !BitArray::ZERO, } } + + pub fn virt_dev() -> Self { + Self { + bits: !BitArray::ZERO, + } + } } /* 0: read hw @@ -207,6 +213,72 @@ impl VirtualPciAccessBits { bits: BitArray::ZERO, } } + + pub fn virt_dev() -> Self { + Self { + bits: !BitArray::ZERO, + } + } +} + +#[derive(Clone, Debug)] +pub struct PciConfigSpace { + data: [u8; BIT_LENTH], +} + +impl PciConfigSpace { + pub fn new() -> Self { + Self { + data: [0u8; BIT_LENTH], + } + } + + pub fn as_slice(&self) -> &[u8] { + &self.data + } + + pub fn as_mut_slice(&mut self) -> &mut [u8] { + &mut self.data + } + + pub fn get_range(&self, offset: usize, size: usize) -> &[u8] { + &self.data[offset..offset + size] + } + + pub fn get_range_mut(&mut self, offset: usize, size: usize) -> &mut [u8] { + &mut self.data[offset..offset + size] + } + + pub fn set(&mut self, field: F, value: u32) { + let offset = field.to_offset(); + let size = field.size(); + match size { + 1 => { + self.get_range_mut(offset, 1)[0] = value as u8; + } + 2 => { + self.get_range_mut(offset, 2).copy_from_slice(&(value as u16).to_le_bytes()); + } + 4 => { + self.get_range_mut(offset, 4).copy_from_slice(&value.to_le_bytes()); + } + _ => { + // For other sizes, write as many bytes as needed + let bytes = value.to_le_bytes(); + self.get_range_mut(offset, size.min(bytes.len())).copy_from_slice(&bytes[..size.min(bytes.len())]); + } + } + } + + pub fn init_with_type(dev_type: VpciDevType) -> Self { + crate::pci::vpci_dev::init_config_space_with_type(dev_type) + } +} + +impl Default for PciConfigSpace { + fn default() -> Self { + Self::new() + } } /* VirtualPciConfigSpace @@ -228,7 +300,7 @@ pub struct VirtualPciConfigSpace { base: PciConfigAddress, - space: [u8; BIT_LENTH], + pub space: PciConfigSpace, control: VirtualPciConfigControl, access: VirtualPciAccessBits, @@ -237,6 +309,8 @@ pub struct VirtualPciConfigSpace { bararr: Bar, rom: PciMem, capabilities: PciCapabilityList, + + dev_type: VpciDevType, } impl VirtualPciConfigSpace { @@ -274,6 +348,10 @@ impl VirtualPciConfigSpace { self.rom } + pub fn get_dev_type(&self) -> VpciDevType { + self.dev_type + } + // 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() { @@ -300,13 +378,35 @@ 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, self.rom + "\n bdf {:#?}\n base {:#x}\n type {:#?}\n {:#?} {:#?}", + self.bdf, self.base, self.config_type, self.bararr, self.rom ) } } impl VirtualPciConfigSpace { + pub fn virt_dev( + bdf: Bdf, + base: PciConfigAddress, + ) -> Self { + Self { + host_bdf: Bdf::default(), + parent_bdf: Bdf::default(), + bdf, + vbdf: Bdf::default(), + config_type: HeaderType::Endpoint, + class: (0u8,0u8,0u8), + base, + space: PciConfigSpace::init_with_type(VpciDevType::StandardVdev), + control: VirtualPciConfigControl::virt_dev(), + access: VirtualPciAccessBits::virt_dev(), + backend: Arc::new(EndpointHeader::new_with_region(PciConfigMmio::new(base, CONFIG_LENTH))), + bararr: Bar::default(), + rom: PciMem::default(), + capabilities: PciCapabilityList::new(), + dev_type: VpciDevType::StandardVdev, + } + } pub fn endpoint( bdf: Bdf, base: PciConfigAddress, @@ -323,13 +423,14 @@ impl VirtualPciConfigSpace { config_type: HeaderType::Endpoint, class, base, - space: [0u8; BIT_LENTH], + space: PciConfigSpace::new(), control: VirtualPciConfigControl::endpoint(), access: VirtualPciAccessBits::endpoint(), backend, bararr, rom, capabilities: PciCapabilityList::new(), + dev_type: VpciDevType::Physical, } } @@ -349,13 +450,14 @@ impl VirtualPciConfigSpace { config_type: HeaderType::PciBridge, class, base, - space: [0u8; BIT_LENTH], + space: PciConfigSpace::new(), control: VirtualPciConfigControl::bridge(), access: VirtualPciAccessBits::bridge(), backend, bararr, rom, capabilities: PciCapabilityList::new(), + dev_type: VpciDevType::Physical, } } @@ -368,13 +470,14 @@ impl VirtualPciConfigSpace { config_type: HeaderType::Endpoint, class: (0u8,0u8,0u8), base, - space: [0u8; BIT_LENTH], + space: PciConfigSpace::new(), control: VirtualPciConfigControl::endpoint(), access: VirtualPciAccessBits::endpoint(), backend, bararr: Bar::default(), rom: PciMem::default(), capabilities: PciCapabilityList::new(), + dev_type: VpciDevType::Physical, } } @@ -387,13 +490,14 @@ impl VirtualPciConfigSpace { config_type: HeaderType::Endpoint, class, base, - space: [0u8; BIT_LENTH], + space: PciConfigSpace::new(), control: VirtualPciConfigControl::host_bridge(), access: VirtualPciAccessBits::host_bridge(), backend, bararr: Bar::default(), rom: PciMem::default(), capabilities: PciCapabilityList::new(), + dev_type: VpciDevType::Physical, } } @@ -435,16 +539,16 @@ impl VirtualPciConfigSpace { 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); + self.space.get_range_mut(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); + self.space.get_range_mut(0x30, 4).copy_from_slice(&bytes); } HeaderType::PciBridge => { let bytes = self.rom.get_value().to_le_bytes(); - self.space[0x38..0x3c].copy_from_slice(&bytes); + self.space.get_range_mut(0x38, 4).copy_from_slice(&bytes); } _ => {} } @@ -475,7 +579,7 @@ impl VirtualPciConfigSpace { 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 slice = self.space.get_range(offset as usize, size); let value = match size { 1 => slice[0] as usize, 2 => u16::from_le_bytes(slice.try_into().unwrap()) as usize, @@ -491,7 +595,7 @@ impl VirtualPciConfigSpace { } pub fn read_emu64(&mut self, offset: PciConfigAddress) -> HvResult { - let slice = &self.space[offset as usize..offset as usize + 8]; + let slice = self.space.get_range(offset as usize, 8); let value = u64::from_le_bytes(slice.try_into().unwrap()) as u64; Ok(value) } @@ -500,7 +604,7 @@ impl VirtualPciConfigSpace { if self.writable(offset, size) { match size { 1 | 2 | 4 => { - let slice = &mut self.space[offset as usize..offset as usize + size]; + let slice = self.space.get_range_mut(offset as usize, size); match size { 1 => slice[0] = value as u8, 2 => slice.copy_from_slice(&u16::to_le_bytes(value as u16)), diff --git a/src/pci/vpci_dev/mod.rs b/src/pci/vpci_dev/mod.rs new file mode 100644 index 00000000..b21b0f19 --- /dev/null +++ b/src/pci/vpci_dev/mod.rs @@ -0,0 +1,148 @@ +use crate::pci::pci_struct::{PciConfigSpace, VirtualPciConfigSpace}; +use crate::pci::PciConfigAddress; +use crate::error::HvResult; + +pub mod standard; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum PciConfigAccessStatus { + Done, + Perform, + Reject, +} + +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum VpciDevType { + #[default] + Physical=0, + StandardVdev=1, + // Add new device types here +} + +pub trait VpciDeviceHandler: Sync + Send { + fn read_cfg(&self) -> HvResult; + fn write_cfg(&self) -> HvResult; + fn init_config_space(&self) -> PciConfigSpace; +} + +/* + * Static handler instances for each device type (except Physical). + * To add a new device type: + * 1. Add the variant to VpciDevType enum above + * 2. Add the handler registration here: (&module::HANDLER, VpciDevType::YourType) + */ +static HANDLERS: &[(&dyn VpciDeviceHandler, VpciDevType)] = &[ + (&standard::HANDLER, VpciDevType::StandardVdev), +]; + +fn get_handler(dev_type: VpciDevType) -> Option<&'static dyn VpciDeviceHandler> { + HANDLERS.iter() + .find(|(_, ty)| *ty == dev_type) + .map(|(handler, _)| *handler) +} + +pub(super) fn vpci_dev_read_cfg( + dev_type: VpciDevType, + node: &mut VirtualPciConfigSpace, + offset: PciConfigAddress, + size: usize +) -> HvResult { + match dev_type { + VpciDevType::Physical => { + warn!("vpci_dev_read_cfg: physical device is not supported"); + Ok(0xFFFF_FFFF) + } + _ => { + if let Some(handler) = get_handler(dev_type) { + match handler.read_cfg() { + Ok(status) => { + match status { + PciConfigAccessStatus::Done => { + Ok(status as usize) + } + PciConfigAccessStatus::Perform => { + warn!("vpci_dev_read_cfg: perform, offset {:#x}, size {:#x}", offset, size); + // warn!("vpci_dev_read_cfg: node {:#?}", node.space); + let r = node.read_emu(offset, size).unwrap(); + warn!("vpci_dev_read_cfg: perform result {:#x}", r); + Ok(r) + } + PciConfigAccessStatus::Reject => { + warn!("vpci_dev_read_cfg: operation rejected"); + Ok(0xFFFF_FFFF) + } + } + } + Err(e) => { + warn!("vpci_dev_read_cfg error: {:?}", e); + Ok(0xFFFF_FFFF) + } + } + } else { + warn!("vpci_dev_read_cfg: unknown device type"); + Ok(0xFFFF_FFFF) + } + } + } +} + +pub(super) fn vpci_dev_write_cfg( + dev_type: VpciDevType, + node: &mut VirtualPciConfigSpace, + offset: PciConfigAddress, + size: usize, + value: usize +) -> HvResult { + match dev_type { + VpciDevType::Physical => { + warn!("vpci_dev_write_cfg: physical device is not supported"); + Ok(()) + } + _ => { + if let Some(handler) = get_handler(dev_type) { + match handler.write_cfg() { + Ok(status) => { + match status { + PciConfigAccessStatus::Done => { + Ok(()) + } + PciConfigAccessStatus::Perform => { + warn!("vpci_dev_write_cfg: perform"); + node.write_emu(offset, size, value) + } + PciConfigAccessStatus::Reject => { + warn!("vpci_dev_write_cfg: operation rejected"); + Ok(()) + } + } + } + Err(e) => { + warn!("vpci_dev_write_cfg error: {:?}", e); + Err(e) + } + } + } else { + warn!("vpci_dev_write_cfg: unknown device type"); + Ok(()) + } + } + } +} + +pub(super) fn init_config_space_with_type(dev_type: VpciDevType) -> PciConfigSpace { + match dev_type { + VpciDevType::Physical => { + // Physical devices use default (all zeros) space + PciConfigSpace::new() + } + _ => { + if let Some(handler) = get_handler(dev_type) { + handler.init_config_space() + } else { + warn!("init_config_space_with_type: unknown device type"); + PciConfigSpace::new() + } + } + } +} \ No newline at end of file diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs new file mode 100644 index 00000000..2636245f --- /dev/null +++ b/src/pci/vpci_dev/standard.rs @@ -0,0 +1,66 @@ +use crate::error::HvResult; +use crate::pci::pci_struct::PciConfigSpace; +use crate::pci::pci_access::EndpointField; +use super::{PciConfigAccessStatus, VpciDeviceHandler}; + +const STANDARD_VENDOR_ID: u16 = 0x110a; +const STANDARD_DEVICE_ID: u16 = 0x4106; +const PCI_STS_CAPS: u16 = 0x10; // bit 4 +const PCI_DEV_CLASS_OTHER: u8 = 0xff; +const PCI_CFG_CAPS: usize = 0x34; +const PCI_CAP_ID_VNDR: u8 = 0x09; +const PCI_CAP_ID_MSIX: u8 = 0x11; +const STANDARD_CFG_VNDR_CAP: u8 = 0x40; +const STANDARD_CFG_VNDR_LEN: u8 = 0x20; +const STANDARD_CFG_MSIX_CAP: usize = 0x60; // VNDR_CAP + VNDR_LEN +const STANDARD_MSIX_VECTORS: u16 = 16; +const STANDARD_CFG_SIZE: usize = 0x80; + +pub(crate) const DEFAULT_CSPACE_U32: [u32; STANDARD_CFG_SIZE / 4] = { + let mut arr = [0u32; STANDARD_CFG_SIZE / 4]; + arr[0x00 / 4] = (STANDARD_DEVICE_ID as u32) << 16 | STANDARD_VENDOR_ID as u32; + arr[0x04 / 4] = (PCI_STS_CAPS as u32) << 16; + arr[0x08 / 4] = (PCI_DEV_CLASS_OTHER as u32) << 24; + arr[0x2c / 4] = (STANDARD_DEVICE_ID as u32) << 16 | STANDARD_VENDOR_ID as u32; + arr[PCI_CFG_CAPS / 4] = STANDARD_CFG_VNDR_CAP as u32; + arr[STANDARD_CFG_VNDR_CAP as usize / 4] = (STANDARD_CFG_VNDR_LEN as u32) << 16 + | (STANDARD_CFG_MSIX_CAP as u32) << 8 + | PCI_CAP_ID_VNDR as u32; + arr[STANDARD_CFG_MSIX_CAP / 4] = (0x00u32) << 8 | PCI_CAP_ID_MSIX as u32; + arr[(STANDARD_CFG_MSIX_CAP + 0x4) / 4] = 1; + arr[(STANDARD_CFG_MSIX_CAP + 0x8) / 4] = ((0x10 * STANDARD_MSIX_VECTORS) as u32) | 1; + arr +}; + +/// Handler for standard virtual PCI devices +pub struct StandardHandler; + +impl VpciDeviceHandler for StandardHandler { + fn read_cfg(&self) -> HvResult { + info!("virt pci standard read_cfg"); + Ok(PciConfigAccessStatus::Perform) + } + + fn write_cfg(&self) -> HvResult { + info!("virt pci standard write_cfg"); + Ok(PciConfigAccessStatus::Perform) + } + + fn init_config_space(&self) -> PciConfigSpace { + let mut space = PciConfigSpace::new(); + let default_cspace = DEFAULT_CSPACE_U32; + let mut offset = 0; + for &value in &default_cspace { + space.get_range_mut(offset, 4).copy_from_slice(&value.to_le_bytes()); + offset += 4; + } + + // Example: update vendor ID + space.set(EndpointField::ID, 0x12345678); + + space + } +} + +/// Static handler instance for standard virtual PCI devices +pub const HANDLER: StandardHandler = StandardHandler; \ No newline at end of file diff --git a/src/zone.rs b/src/zone.rs index ed55a4be..39089846 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -213,7 +213,7 @@ pub fn zone_create(config: &HvZoneConfig) -> HvResult>> { #[cfg(feature = "pci")] { let _ = zone.virtual_pci_mmio_init(&config.pci_config, config.num_pci_bus as usize); - let _ = zone.guest_pci_init(zone_id, &config.alloc_pci_devs, config.num_pci_devs); + let _ = zone.guest_pci_init(zone_id, &config.alloc_pci_devs, config.num_pci_devs, config.pci_config[0].ecam_base as u64); } // #[cfg(target_arch = "aarch64")] From 21833c7b795c40f7114dff00944e8c6ae86c366e Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 27 Nov 2025 12:27:01 +0800 Subject: [PATCH 033/109] update config for virt pci --- platform/aarch64/qemu-gicv2/board.rs | 7 +-- platform/aarch64/qemu-gicv3/board.rs | 11 ++-- .../qemu-gicv3/configs/zone1-linux.json | 4 +- platform/aarch64/rk3568/board.rs | 11 +++- platform/loongarch64/ls3a5000/board.rs | 54 +++++++++---------- platform/loongarch64/ls3a6000/board.rs | 54 +++++++++---------- platform/x86_64/nuc14mnk/board.rs | 38 ++++++------- platform/x86_64/qemu/board.rs | 18 +++---- 8 files changed, 103 insertions(+), 94 deletions(-) diff --git a/platform/aarch64/qemu-gicv2/board.rs b/platform/aarch64/qemu-gicv2/board.rs index 9a739804..772b5085 100644 --- a/platform/aarch64/qemu-gicv2/board.rs +++ b/platform/aarch64/qemu-gicv2/board.rs @@ -16,6 +16,7 @@ use crate::{ arch::{mmu::MemoryType, zone::{HvArchZoneConfig,GicConfig,Gicv2Config}}, config::*, + pci::vpci_dev::VpciDevType, }; use crate::pci_dev; @@ -111,7 +112,7 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; 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, 0x0, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x1, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x2, 0x0, VpciDevType::Physical), ]; diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index 779d55d1..c24cf0fc 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -19,6 +19,7 @@ use crate::{ zone::{GicConfig, Gicv3Config, HvArchZoneConfig}, }, config::*, + pci::vpci_dev::VpciDevType, }; use crate::pci_dev; @@ -109,9 +110,9 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; -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), +pub const ROOT_PCI_DEVS: &[HvPciDevConfig] = &[ + pci_dev!(0x0, 0x0, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x1, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x2, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x5, 0x0, VpciDevType::StandardVdev), ]; diff --git a/platform/aarch64/qemu-gicv3/configs/zone1-linux.json b/platform/aarch64/qemu-gicv3/configs/zone1-linux.json index a4fa325d..9bef1db5 100644 --- a/platform/aarch64/qemu-gicv3/configs/zone1-linux.json +++ b/platform/aarch64/qemu-gicv3/configs/zone1-linux.json @@ -50,11 +50,11 @@ "alloc_pci_devs": [ { "bdf": "0x0", - "vbdf": "0x0" + "dev_type": "0" }, { "bdf": "0x18", - "vbdf": "0x18" + "dev_type": "0" } ] } \ No newline at end of file diff --git a/platform/aarch64/rk3568/board.rs b/platform/aarch64/rk3568/board.rs index 5c8676b0..a1682d3c 100644 --- a/platform/aarch64/rk3568/board.rs +++ b/platform/aarch64/rk3568/board.rs @@ -20,6 +20,7 @@ use crate::{ zone::{GicConfig, Gicv3Config, HvArchZoneConfig}, }, config::*, + pci::vpci_dev::VpciDevType, }; use crate::pci_dev; @@ -158,6 +159,12 @@ pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ // virtual_start: 0x10f000, // size: 0x1000, // }, //scmi-shmem + HvConfigMemoryRegion { + mem_type: MEM_TYPE_RAM, + physical_start: 0xfd440000, + virtual_start: 0xfd440000, + size: 0x20000, + }, // its HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, physical_start: 0x1f0000000, @@ -349,6 +356,6 @@ pub const ROOT_DWC_ATU_CONFIG: &[HvDwcAtuConfig] = &[ ]; pub const ROOT_PCI_DEVS: [HvPciDevConfig; 2] = [ - pci_dev!(0x10, 0x0, 0x0), - pci_dev!(0x11, 0x0, 0x0), + pci_dev!(0x10, 0x0, 0x0, VpciDevType::Physical), + pci_dev!(0x11, 0x0, 0x0, VpciDevType::Physical), ]; \ No newline at end of file diff --git a/platform/loongarch64/ls3a5000/board.rs b/platform/loongarch64/ls3a5000/board.rs index 0be34690..f91d83eb 100644 --- a/platform/loongarch64/ls3a5000/board.rs +++ b/platform/loongarch64/ls3a5000/board.rs @@ -14,7 +14,7 @@ // Authors: // Yulong Han // -use crate::{arch::zone::HvArchZoneConfig, config::*}; +use crate::{arch::zone::HvArchZoneConfig, config::*, pci::vpci_dev::VpciDevType}; use crate::pci_dev; pub const BOARD_NAME: &str = "ls3a5000"; @@ -181,32 +181,32 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ /* BUS 6 on X4 slot */ /* 06:00.0, 06:00.1, 06:00.2, 06:00.3 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 + pci_dev!(0x0, 0x0, 0x0, VpciDevType::Physical), // 00:00.0 + pci_dev!(0x0, 0x0, 0x1, VpciDevType::Physical), // 00:00.1 + pci_dev!(0x0, 0x0, 0x2, VpciDevType::Physical), // 00:00.2 + pci_dev!(0x0, 0x0, 0x3, VpciDevType::Physical), // 00:00.3 + pci_dev!(0x0, 0x4, 0x0, VpciDevType::Physical), // 00:04.0 + pci_dev!(0x0, 0x4, 0x1, VpciDevType::Physical), // 00:04.1 + pci_dev!(0x0, 0x5, 0x0, VpciDevType::Physical), // 00:05.0 + pci_dev!(0x0, 0x5, 0x1, VpciDevType::Physical), // 00:05.1 + pci_dev!(0x0, 0x6, 0x0, VpciDevType::Physical), // 00:06.0 + pci_dev!(0x0, 0x6, 0x1, VpciDevType::Physical), // 00:06.1 + pci_dev!(0x0, 0x6, 0x2, VpciDevType::Physical), // 00:06.2 + pci_dev!(0x0, 0x7, 0x0, VpciDevType::Physical), // 00:07.0 + pci_dev!(0x0, 0x8, 0x0, VpciDevType::Physical), // 00:08.0 + pci_dev!(0x0, 0x9, 0x0, VpciDevType::Physical), // 00:09.0 + pci_dev!(0x0, 0xa, 0x0, VpciDevType::Physical), // 00:0a.0 + pci_dev!(0x0, 0xb, 0x0, VpciDevType::Physical), // 00:0b.0 + pci_dev!(0x0, 0xc, 0x0, VpciDevType::Physical), // 00:0c.0 + pci_dev!(0x0, 0xd, 0x0, VpciDevType::Physical), // 00:0d.0 + pci_dev!(0x0, 0xf, 0x0, VpciDevType::Physical), // 00:0f.0 + pci_dev!(0x0, 0x10, 0x0, VpciDevType::Physical), // 00:10.0 + pci_dev!(0x0, 0x13, 0x0, VpciDevType::Physical), // 00:13.0 + pci_dev!(0x0, 0x16, 0x0, VpciDevType::Physical), // 00:16.0 + pci_dev!(0x0, 0x19, 0x0, VpciDevType::Physical), // 00:19.0 + pci_dev!(0x2, 0x0, 0x0, VpciDevType::Physical), // 02:00.0 + pci_dev!(0x5, 0x0, 0x0, VpciDevType::Physical), // 05:00.0 + pci_dev!(0x6, 0x0, 0x0, VpciDevType::Physical), // 06:00.0 ]; diff --git a/platform/loongarch64/ls3a6000/board.rs b/platform/loongarch64/ls3a6000/board.rs index 252c6c3e..8c51e758 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -14,7 +14,7 @@ // Authors: // Yulong Han // -use crate::{arch::zone::HvArchZoneConfig, config::*}; +use crate::{arch::zone::HvArchZoneConfig, config::*, pci::vpci_dev::VpciDevType}; use crate::pci_dev; use crate::pci::vpci_dev::VpciDevType; @@ -184,32 +184,32 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ /* BUS 6 on X4 slot */ /* 06:00.0, 06:00.1, 06:00.2, 06:00.3 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 + pci_dev!(0x0, 0x0, 0x0, VpciDevType::Physical), // 00:00.0 + pci_dev!(0x0, 0x0, 0x1, VpciDevType::Physical), // 00:00.1 + pci_dev!(0x0, 0x0, 0x2, VpciDevType::Physical), // 00:00.2 + pci_dev!(0x0, 0x0, 0x3, VpciDevType::Physical), // 00:00.3 + pci_dev!(0x0, 0x4, 0x0, VpciDevType::Physical), // 00:04.0 + pci_dev!(0x0, 0x4, 0x1, VpciDevType::Physical), // 00:04.1 + pci_dev!(0x0, 0x5, 0x0, VpciDevType::Physical), // 00:05.0 + pci_dev!(0x0, 0x5, 0x1, VpciDevType::Physical), // 00:05.1 + pci_dev!(0x0, 0x6, 0x0, VpciDevType::Physical), // 00:06.0 + pci_dev!(0x0, 0x6, 0x1, VpciDevType::Physical), // 00:06.1 + pci_dev!(0x0, 0x6, 0x2, VpciDevType::Physical), // 00:06.2 + pci_dev!(0x0, 0x7, 0x0, VpciDevType::Physical), // 00:07.0 + pci_dev!(0x0, 0x8, 0x0, VpciDevType::Physical), // 00:08.0 + pci_dev!(0x0, 0x9, 0x0, VpciDevType::Physical), // 00:09.0 + pci_dev!(0x0, 0xa, 0x0, VpciDevType::Physical), // 00:0a.0 + pci_dev!(0x0, 0xb, 0x0, VpciDevType::Physical), // 00:0b.0 + pci_dev!(0x0, 0xc, 0x0, VpciDevType::Physical), // 00:0c.0 + pci_dev!(0x0, 0xd, 0x0, VpciDevType::Physical), // 00:0d.0 + pci_dev!(0x0, 0xf, 0x0, VpciDevType::Physical), // 00:0f.0 + pci_dev!(0x0, 0x10, 0x0, VpciDevType::Physical), // 00:10.0 + pci_dev!(0x0, 0x13, 0x0, VpciDevType::Physical), // 00:13.0 + pci_dev!(0x0, 0x16, 0x0, VpciDevType::Physical), // 00:16.0 + pci_dev!(0x0, 0x19, 0x0, VpciDevType::Physical), // 00:19.0 + pci_dev!(0x2, 0x0, 0x0, VpciDevType::Physical), // 02:00.0 + pci_dev!(0x5, 0x0, 0x0, VpciDevType::Physical), // 05:00.0 + pci_dev!(0x6, 0x0, 0x0, VpciDevType::Physical), // 06:00.0 ]; diff --git a/platform/x86_64/nuc14mnk/board.rs b/platform/x86_64/nuc14mnk/board.rs index 1bae3f9c..4054dd49 100644 --- a/platform/x86_64/nuc14mnk/board.rs +++ b/platform/x86_64/nuc14mnk/board.rs @@ -14,7 +14,7 @@ // Authors: // use crate::pci_dev; -use crate::{arch::zone::HvArchZoneConfig, config::*, memory::GuestPhysAddr}; +use crate::{arch::zone::HvArchZoneConfig, config::*, memory::GuestPhysAddr, pci::vpci_dev::VpciDevType}; pub const MEM_TYPE_RESERVED: u32 = 5; @@ -161,25 +161,25 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { pub const ROOT_PCI_MAX_BUS: usize = 2; pub const ROOT_PCI_DEVS: [HvPciDevConfig; 18] = [ - pci_dev!(0x0, 0x0, 0x0), // host bridge - pci_dev!(0x0, 0x2, 0x0), // VGA controller - pci_dev!(0x0, 0x4, 0x0), - pci_dev!(0x0, 0x8, 0x0), - pci_dev!(0x0, 0xa, 0x0), + pci_dev!(0x0, 0x0, 0x0, VpciDevType::Physical), // host bridge + pci_dev!(0x0, 0x2, 0x0, VpciDevType::Physical), // VGA controller + pci_dev!(0x0, 0x4, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x8, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0xa, 0x0, VpciDevType::Physical), // pci_dev!(0x0, 0xd, 0x0), // USB controller - pci_dev!(0x0, 0x12, 0x0), // serial controller - pci_dev!(0x0, 0x14, 0x0), // USB controller - pci_dev!(0x0, 0x14, 0x2), // RAM memory - pci_dev!(0x0, 0x14, 0x3), // network controller - pci_dev!(0x0, 0x16, 0x0), // communication controller - pci_dev!(0x0, 0x1c, 0x0), // PCI bridge - pci_dev!(0x0, 0x1d, 0x0), // PCI bridge - pci_dev!(0x0, 0x1f, 0x0), // ISA bridge - pci_dev!(0x0, 0x1f, 0x3), // audio controller - pci_dev!(0x0, 0x1f, 0x4), // SMBus - pci_dev!(0x0, 0x1f, 0x5), // serial bus controller - pci_dev!(0x1, 0x0, 0x0), // ethernet controller - pci_dev!(0x2, 0x0, 0x0), // memory controller + pci_dev!(0x0, 0x12, 0x0, VpciDevType::Physical), // serial controller + pci_dev!(0x0, 0x14, 0x0, VpciDevType::Physical), // USB controller + pci_dev!(0x0, 0x14, 0x2, VpciDevType::Physical), // RAM memory + pci_dev!(0x0, 0x14, 0x3, VpciDevType::Physical), // network controller + pci_dev!(0x0, 0x16, 0x0, VpciDevType::Physical), // communication controller + pci_dev!(0x0, 0x1c, 0x0, VpciDevType::Physical), // PCI bridge + pci_dev!(0x0, 0x1d, 0x0, VpciDevType::Physical), // PCI bridge + pci_dev!(0x0, 0x1f, 0x0, VpciDevType::Physical), // ISA bridge + pci_dev!(0x0, 0x1f, 0x3, VpciDevType::Physical), // audio controller + pci_dev!(0x0, 0x1f, 0x4, VpciDevType::Physical), // SMBus + pci_dev!(0x0, 0x1f, 0x5, VpciDevType::Physical), // serial bus controller + pci_dev!(0x1, 0x0, 0x0, VpciDevType::Physical), // ethernet controller + pci_dev!(0x2, 0x0, 0x0, VpciDevType::Physical), // memory controller ]; #[cfg(all(feature = "graphics"))] diff --git a/platform/x86_64/qemu/board.rs b/platform/x86_64/qemu/board.rs index 6f4c5c7c..1150cfd4 100644 --- a/platform/x86_64/qemu/board.rs +++ b/platform/x86_64/qemu/board.rs @@ -14,7 +14,7 @@ // Authors: // use crate::pci_dev; -use crate::{arch::zone::HvArchZoneConfig, config::*, memory::GuestPhysAddr}; +use crate::{arch::zone::HvArchZoneConfig, config::*, memory::GuestPhysAddr, pci::vpci_dev::VpciDevType}; pub const MEM_TYPE_RESERVED: u32 = 5; @@ -127,14 +127,14 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { pub const ROOT_PCI_MAX_BUS: usize = 1; pub const ROOT_PCI_DEVS: [HvPciDevConfig; 8] = [ - pci_dev!(0x0, 0x0, 0x0), // host bridge - pci_dev!(0x0, 0x1, 0x0), // VGA controller - pci_dev!(0x0, 0x2, 0x0), // Ethernet controller - pci_dev!(0x0, 0x3, 0x0), // PCI bridge - pci_dev!(0x0, 0x1f, 0x0), // ISA bridge - pci_dev!(0x0, 0x1f, 0x2), // SATA controller - pci_dev!(0x0, 0x1f, 0x3), // SMBus - pci_dev!(0x1, 0x0, 0x0), // SCSI controller + pci_dev!(0x0, 0x0, 0x0, VpciDevType::Physical), // host bridge + pci_dev!(0x0, 0x1, 0x0, VpciDevType::Physical), // VGA controller + pci_dev!(0x0, 0x2, 0x0, VpciDevType::Physical), // Ethernet controller + pci_dev!(0x0, 0x3, 0x0, VpciDevType::Physical), // PCI bridge + pci_dev!(0x0, 0x1f, 0x0, VpciDevType::Physical), // ISA bridge + pci_dev!(0x0, 0x1f, 0x2, VpciDevType::Physical), // SATA controller + pci_dev!(0x0, 0x1f, 0x3, VpciDevType::Physical), // SMBus + pci_dev!(0x1, 0x0, 0x0, VpciDevType::Physical), // SCSI controller ]; #[cfg(all(feature = "graphics"))] From 25f973c1f7f81e0c6295fc6bcdc2bb07803e5c7a Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 27 Nov 2025 12:36:33 +0800 Subject: [PATCH 034/109] use get_handler for vpci dev in config --- src/pci/pci_config.rs | 31 ++++++++++++++++++++----------- src/pci/vpci_dev/mod.rs | 2 +- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 4ce65da9..8c422015 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -20,10 +20,13 @@ use crate::{ arch::iommu::iommu_add_device, config::{HvPciConfig, HvPciDevConfig, CONFIG_MAX_PCI_DEV, CONFIG_PCI_BUS_MAXNUM}, error::HvResult, - pci::{pci_struct::{Bdf, VirtualPciConfigSpace}, vpci_dev::VpciDevType}, + pci::pci_struct::{Bdf, VirtualPciConfigSpace}, zone::Zone, }; +#[cfg(feature = "ecam_pcie")] +use crate::pci::vpci_dev::{VpciDevType, get_handler}; + #[cfg(any( feature = "ecam_pcie", feature = "dwc_pcie", @@ -139,7 +142,6 @@ impl Zone { let dev_config = alloc_pci_devs[i as usize]; let bdf = Bdf::from_address(dev_config.bdf << 12); let vbdf = bdf.clone(); - let dev_type = dev_config.dev_type; #[cfg(any( all(feature = "iommu", target_arch = "aarch64"), target_arch = "x86_64" @@ -165,19 +167,26 @@ impl Zone { } else { // warn!("can not find dev {:#?}", bdf); #[cfg(feature = "ecam_pcie")] - match dev_type { - VpciDevType::StandardVdev => { - let base = _ecam_base - + ((bdf.bus() as u64) << 20) - + ((bdf.device() as u64) << 15) - + ((bdf.function() as u64) << 12); - let dev = VirtualPciConfigSpace::virt_dev(bdf, base); - self.vpci_bus.insert(vbdf, dev); + { + let dev_type = dev_config.dev_type; + match dev_type { + VpciDevType::Physical => { + warn!("can not find dev {:#?}", bdf); } _ => { - warn!("can not find dev {:#?}", bdf); + if let Some(_handler) = get_handler(dev_type) { + let base = _ecam_base + + ((bdf.bus() as u64) << 20) + + ((bdf.device() as u64) << 15) + + ((bdf.function() as u64) << 12); + let dev = VirtualPciConfigSpace::virt_dev(bdf, base); + self.vpci_bus.insert(vbdf, dev); + } else { + warn!("can not find dev {:#?}, unknown device type", bdf); + } } } + } } i += 1; } diff --git a/src/pci/vpci_dev/mod.rs b/src/pci/vpci_dev/mod.rs index b21b0f19..afc79bc3 100644 --- a/src/pci/vpci_dev/mod.rs +++ b/src/pci/vpci_dev/mod.rs @@ -36,7 +36,7 @@ static HANDLERS: &[(&dyn VpciDeviceHandler, VpciDevType)] = &[ (&standard::HANDLER, VpciDevType::StandardVdev), ]; -fn get_handler(dev_type: VpciDevType) -> Option<&'static dyn VpciDeviceHandler> { +pub(crate) fn get_handler(dev_type: VpciDevType) -> Option<&'static dyn VpciDeviceHandler> { HANDLERS.iter() .find(|(_, ty)| *ty == dev_type) .map(|(handler, _)| *handler) From c851f32b02ba2c50cc5580efdb167ad670e30747 Mon Sep 17 00:00:00 2001 From: agicy Date: Fri, 14 Nov 2025 21:24:11 +0800 Subject: [PATCH 035/109] fix(arch/aarch64/iommu): make IOMMU initialization conditional on a feature flag This commit resolves the issue #212 by wrapping the SMMUv3 initialization logic in a `#[cfg(feature = "iommu")]` attribute. A corresponding empty `iommu_init` function is provided under `#[cfg(not(feature = "iommu"))]`. This change allows the hypervisor to be compiled without IOMMU support, enabling it to boot successfully on affected hardware by disabling the default feature. Fixes: #212 --- src/arch/aarch64/iommu.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/arch/aarch64/iommu.rs b/src/arch/aarch64/iommu.rs index 1b7110d5..a33d3f17 100644 --- a/src/arch/aarch64/iommu.rs +++ b/src/arch/aarch64/iommu.rs @@ -530,7 +530,14 @@ impl Smmuv3 { static SMMUV3: spin::Once> = spin::Once::new(); -/// smmuv3 init +/// iommu feature is disabled. +#[cfg(not(feature = "iommu"))] +pub fn iommu_init() { + info!("aarch64: iommu_init: do nothing now"); +} + +/// smmuv3 init (enabled) +#[cfg(feature = "iommu")] pub fn iommu_init() { info!("Smmuv3 init..."); SMMUV3.call_once(|| Mutex::new(Smmuv3::new())); From dd6a72ce43ceaf938e1a33b67955055ae6f4cd09 Mon Sep 17 00:00:00 2001 From: dallas Date: Tue, 2 Dec 2025 19:00:39 +0800 Subject: [PATCH 036/109] 1. for loongarch, fix the wrong mmio handler register 2. for virt pci dev, improve the rw handler and add example --- src/pci/pci_access.rs | 69 +++++++++++++++++++++++++++++++++++- src/pci/pci_config.rs | 23 ++++++++---- src/pci/pci_struct.rs | 30 +++++++++++++++- src/pci/vpci_dev/mod.rs | 16 ++++----- src/pci/vpci_dev/standard.rs | 32 +++++++++++++---- 5 files changed, 148 insertions(+), 22 deletions(-) diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 2791058d..b135226d 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -752,7 +752,7 @@ impl PciConfigHeader { * | | | pin | line | * +--------------+--------------+--------------+--------------+ */ -pub trait PciField { +pub trait PciField: Debug { fn to_offset(&self) -> usize; fn size(&self) -> usize; } @@ -779,6 +779,34 @@ pub enum EndpointField { Unknown(usize), } +impl Debug for EndpointField { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "EndpointField {{")?; + match self { + EndpointField::ID => write!(f, "ID"), + EndpointField::Command => write!(f, "Command"), + EndpointField::Status => write!(f, "Status"), + EndpointField::RevisionIDAndClassCode => write!(f, "RevisionIDAndClassCode"), + EndpointField::CacheLineSize => write!(f, "CacheLineSize"), + EndpointField::LatencyTime => write!(f, "LatencyTime"), + EndpointField::HeaderType => write!(f, "HeaderType"), + EndpointField::Bist => write!(f, "Bist"), + EndpointField::Bar => write!(f, "Bar"), + EndpointField::CardCisPointer => write!(f, "CardCisPointer"), + EndpointField::SubsystemVendorId => write!(f, "SubsystemVendorId"), + EndpointField::SubsystemId => write!(f, "SubsystemId"), + EndpointField::ExpansionRomBar => write!(f, "ExpansionRomBar"), + EndpointField::CapabilityPointer => write!(f, "CapabilityPointer"), + EndpointField::InterruptLine => write!(f, "InterruptLine"), + EndpointField::InterruptPin => write!(f, "InterruptPin"), + EndpointField::MinGnt => write!(f, "MinGnt"), + EndpointField::MaxLat => write!(f, "MaxLat"), + EndpointField::Unknown(offset) => write!(f, "Unknown({})", offset), + }; + write!(f, "}}") + } +} + impl PciField for EndpointField { fn to_offset(&self) -> usize { match self { @@ -962,6 +990,45 @@ pub enum BridgeField { Unknown(usize), } +impl Debug for BridgeField { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "BridgeField {{")?; + match self { + BridgeField::ID => write!(f, "ID"), + BridgeField::Command => write!(f, "Command"), + BridgeField::Status => write!(f, "Status"), + BridgeField::RevisionIDAndClassCode => write!(f, "RevisionIDAndClassCode"), + BridgeField::CacheLineSize => write!(f, "CacheLineSize"), + BridgeField::LatencyTime => write!(f, "LatencyTime"), + BridgeField::HeaderType => write!(f, "HeaderType"), + BridgeField::Bist => write!(f, "Bist"), + BridgeField::Bar => write!(f, "Bar"), + BridgeField::PrimaryBusNumber => write!(f, "PrimaryBusNumber"), + BridgeField::SecondaryBusNumber => write!(f, "SecondaryBusNumber"), + BridgeField::SubordinateBusNumber => write!(f, "SubordinateBusNumber"), + BridgeField::SecondaryLatencyTimer => write!(f, "SecondaryLatencyTimer"), + BridgeField::IOBase => write!(f, "IOBase"), + BridgeField::IOLimit => write!(f, "IOLimit"), + BridgeField::SecondaryStatus => write!(f, "SecondaryStatus"), + BridgeField::MemoryBase => write!(f, "MemoryBase"), + BridgeField::MemoryLimit => write!(f, "MemoryLimit"), + BridgeField::PrefetchableMemoryBase => write!(f, "PrefetchableMemoryBase"), + BridgeField::PrefetchableMemoryLimit => write!(f, "PrefetchableMemoryLimit"), + BridgeField::PrefetchableBaseUpper32Bits => write!(f, "PrefetchableBaseUpper32Bits"), + BridgeField::PrefetchableLimitUpper32Bits => write!(f, "PrefetchableLimitUpper32Bits"), + BridgeField::UIBaseUpper16Bits => write!(f, "UIBaseUpper16Bits"), + BridgeField::IOLimitUpper16Bits => write!(f, "IOLimitUpper16Bits"), + BridgeField::CapabilityPointer => write!(f, "CapabilityPointer"), + BridgeField::ExpansionRomBar => write!(f, "ExpansionRomBar"), + BridgeField::InterruptLine => write!(f, "InterruptLine"), + BridgeField::InterruptPin => write!(f, "InterruptPin"), + BridgeField::BridgeControl => write!(f, "BridgeControl"), + BridgeField::Unknown(offset) => write!(f, "Unknown({})", offset), + }; + write!(f, "}}") + } +} + impl PciField for BridgeField { fn to_offset(&self) -> usize { match self { diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 8c422015..2a34bfe9 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -256,12 +256,23 @@ impl Zone { cfg1_base as usize, ); } - } else { - warn!( - "No extend config found for base 0x{:x}", - rootcomplex_config.ecam_base - ); - } + } + } + #[cfg(feature = "loongarch64_pcie")] + { + self.mmio_region_register( + rootcomplex_config.ecam_base as usize, + rootcomplex_config.ecam_size as usize, + mmio_vpci_handler, + rootcomplex_config.ecam_base as usize, + ); + } + #[cfg(not(any(feature = "ecam_pcie", feature = "dwc_pcie", feature = "loongarch64_pcie")))] + { + warn!( + "No extend config found for base 0x{:x}", + rootcomplex_config.ecam_base + ); } } } diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 18c13c42..15fdc595 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -270,6 +270,26 @@ impl PciConfigSpace { } } + pub fn get(&self, field: F) -> u32 { + let offset = field.to_offset(); + let size = field.size(); + match size { + 1 => { + self.get_range(offset, 1)[0] as u32 + } + 2 => { + u16::from_le_bytes(self.get_range(offset, 2).try_into().unwrap()) as u32 + } + 4 => { + u32::from_le_bytes(self.get_range(offset, 4).try_into().unwrap()) + } + _ => { + warn!("vpci dev {:#?} get size {:#?} not supported", field, size); + 0xFFFF_FFFF + } + } + } + pub fn init_with_type(dev_type: VpciDevType) -> Self { crate::pci::vpci_dev::init_config_space_with_type(dev_type) } @@ -300,7 +320,7 @@ pub struct VirtualPciConfigSpace { base: PciConfigAddress, - pub space: PciConfigSpace, + space: PciConfigSpace, control: VirtualPciConfigControl, access: VirtualPciAccessBits, @@ -352,6 +372,14 @@ impl VirtualPciConfigSpace { self.dev_type } + pub fn get_space_mut(&mut self) -> &mut PciConfigSpace { + &mut self.space + } + + pub fn get_space(&self) -> &PciConfigSpace { + &self.space + } + // 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() { diff --git a/src/pci/vpci_dev/mod.rs b/src/pci/vpci_dev/mod.rs index afc79bc3..6bf7f01f 100644 --- a/src/pci/vpci_dev/mod.rs +++ b/src/pci/vpci_dev/mod.rs @@ -6,7 +6,7 @@ pub mod standard; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum PciConfigAccessStatus { - Done, + Done(usize), Perform, Reject, } @@ -21,8 +21,8 @@ pub enum VpciDevType { } pub trait VpciDeviceHandler: Sync + Send { - fn read_cfg(&self) -> HvResult; - fn write_cfg(&self) -> HvResult; + fn read_cfg(&self, space: &mut PciConfigSpace, offset: PciConfigAddress, size: usize) -> HvResult; + fn write_cfg(&self, space: &mut PciConfigSpace, offset: PciConfigAddress, size: usize, value: usize) -> HvResult; fn init_config_space(&self) -> PciConfigSpace; } @@ -55,11 +55,11 @@ pub(super) fn vpci_dev_read_cfg( } _ => { if let Some(handler) = get_handler(dev_type) { - match handler.read_cfg() { + match handler.read_cfg(node.get_space_mut(), offset, size) { Ok(status) => { match status { - PciConfigAccessStatus::Done => { - Ok(status as usize) + PciConfigAccessStatus::Done(value) => { + Ok(value) } PciConfigAccessStatus::Perform => { warn!("vpci_dev_read_cfg: perform, offset {:#x}, size {:#x}", offset, size); @@ -101,10 +101,10 @@ pub(super) fn vpci_dev_write_cfg( } _ => { if let Some(handler) = get_handler(dev_type) { - match handler.write_cfg() { + match handler.write_cfg(node.get_space_mut(), offset, size, value) { Ok(status) => { match status { - PciConfigAccessStatus::Done => { + PciConfigAccessStatus::Done(_) => { Ok(()) } PciConfigAccessStatus::Perform => { diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index 2636245f..b5c28d31 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -1,6 +1,7 @@ use crate::error::HvResult; use crate::pci::pci_struct::PciConfigSpace; use crate::pci::pci_access::EndpointField; +use crate::pci::PciConfigAddress; use super::{PciConfigAccessStatus, VpciDeviceHandler}; const STANDARD_VENDOR_ID: u16 = 0x110a; @@ -36,14 +37,33 @@ pub(crate) const DEFAULT_CSPACE_U32: [u32; STANDARD_CFG_SIZE / 4] = { pub struct StandardHandler; impl VpciDeviceHandler for StandardHandler { - fn read_cfg(&self) -> HvResult { - info!("virt pci standard read_cfg"); - Ok(PciConfigAccessStatus::Perform) + fn read_cfg(&self, _space: &mut PciConfigSpace, offset: PciConfigAddress, size: usize) -> HvResult { + info!("virt pci standard read_cfg, offset {:#x}, size {:#x}", offset, size); + match EndpointField::from(offset as usize, size) { + EndpointField::ID => { + + Ok(PciConfigAccessStatus::Done(_space.get(EndpointField::ID) as usize)) + } + _ => { + Ok(PciConfigAccessStatus::Perform) + } + } } - fn write_cfg(&self) -> HvResult { - info!("virt pci standard write_cfg"); - Ok(PciConfigAccessStatus::Perform) + fn write_cfg(&self, space: &mut PciConfigSpace, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { + info!("virt pci standard write_cfg, offset {:#x}, size {:#x}, value {:#x}", offset, size, value); + match EndpointField::from(offset as usize, size) { + EndpointField::ID => { + Ok(PciConfigAccessStatus::Reject) + } + EndpointField::Command => { + space.set(EndpointField::Command, value as u32); + Ok(PciConfigAccessStatus::Done(value)) + } + _ => { + Ok(PciConfigAccessStatus::Reject) + } + } } fn init_config_space(&self) -> PciConfigSpace { From 5478a19ac9a1cb9ad6879769a4cfc3a9ebc2408b Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 3 Dec 2025 17:52:03 +0800 Subject: [PATCH 037/109] for loongarch, bar page aligned before insert --- src/memory/mm.rs | 13 +++++++++++++ src/pci/pci_access.rs | 8 +++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/memory/mm.rs b/src/memory/mm.rs index e1449599..8fb67dbf 100644 --- a/src/memory/mm.rs +++ b/src/memory/mm.rs @@ -127,6 +127,19 @@ where Ok(()) } + pub fn try_insert(&mut self, region: MemoryRegion) -> HvResult { + if !self.test_free_area(®ion) { + warn!( + "MemoryRegion overlapped in MemorySet: {:#x?}\n{:#x?}", + region, self + ); + return Ok(()); + } + + self.insert(region)?; + Ok(()) + } + /// Find and remove memory region which starts from `start`. pub fn delete(&mut self, start: PT::VA) -> HvResult { if let Entry::Occupied(e) = self.regions.entry(start) { diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index b135226d..8612c257 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -1300,8 +1300,14 @@ fn handle_config_space_access( } else { crate::memory::PAGE_SIZE as u64 }; + + let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) { + crate::memory::addr::align_up(new_vaddr as usize) as u64 + } else { + new_vaddr + }; - gpm.insert(MemoryRegion::new_with_offset_mapper( + gpm.try_insert(MemoryRegion::new_with_offset_mapper( new_vaddr as GuestPhysAddr, paddr as HostPhysAddr, bar_size as _, From 08a227c14b285fd3f5ecab585576a13261abd2a4 Mon Sep 17 00:00:00 2001 From: wheatfox Date: Thu, 4 Dec 2025 09:48:34 +0800 Subject: [PATCH 038/109] fix: fixed loongarch 3a5000 new_pcie compilation error and pagetable bugs(using emergency function) Signed-off-by: wheatfox --- platform/loongarch64/ls3a5000/board.rs | 2 ++ src/arch/loongarch64/zone.rs | 4 ++-- src/memory/mm.rs | 2 +- src/pci/pci_config.rs | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/platform/loongarch64/ls3a5000/board.rs b/platform/loongarch64/ls3a5000/board.rs index 5de319aa..7c32f624 100644 --- a/platform/loongarch64/ls3a5000/board.rs +++ b/platform/loongarch64/ls3a5000/board.rs @@ -157,6 +157,8 @@ pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ HvPciConfig { + bus_range_begin: 0x0, + bus_range_end: 0x1f, ecam_base: 0xfe00000000, ecam_size: 0x20000000, io_base: 0x18408000, diff --git a/src/arch/loongarch64/zone.rs b/src/arch/loongarch64/zone.rs index 457f32d6..618d6dfd 100644 --- a/src/arch/loongarch64/zone.rs +++ b/src/arch/loongarch64/zone.rs @@ -564,8 +564,8 @@ fn handle_extioi_mapping_mmio(mmio: &mut MMIOAccess, base_addr: usize, size: usi new_data |= (1 << target_cpu_id); let target_write_phyaddr = base_addr + target_ioi_number as usize; let target_write_value = new_data as u8; - info!( - "[[interrupt virtualization]] extioi[{}], node_selection={:#x}, irq_target={:#x}, changed irq routing to cpu {}, value={:#x}", + trace!( + "extioi[{}], node_selection={:#x}, irq_target={:#x}, changed irq routing to cpu {}, value={:#x}", target_ioi_number, target_ioi_node_selection, target_ioi_irq_target, target_cpu_id, target_write_value ); unsafe { diff --git a/src/memory/mm.rs b/src/memory/mm.rs index 8fb67dbf..b9088477 100644 --- a/src/memory/mm.rs +++ b/src/memory/mm.rs @@ -109,7 +109,7 @@ where /// Add a memory region to this set. pub fn insert(&mut self, region: MemoryRegion) -> HvResult { - info!("region.start: {:#X}", region.start.into()); + info!("region.start: {:#X}, size: {:#X}, flags: {:#X}", region.start.into(), region.size, region.flags); assert!(is_aligned(region.start.into())); assert!(is_aligned(region.size)); if region.size == 0 { diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 2a34bfe9..046a15bd 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -34,7 +34,7 @@ use crate::pci::vpci_dev::{VpciDevType, get_handler}; ))] use crate::pci::{mem_alloc::BaseAllocator, pci_struct::RootComplex}; -#[cfg(any(feature = "ecam_pcie", feature = "dwc_pcie"))] +#[cfg(any(feature = "ecam_pcie", feature = "dwc_pcie", feature = "loongarch64_pcie"))] use crate::pci::pci_access::mmio_vpci_handler; #[cfg(feature = "dwc_pcie")] @@ -266,6 +266,7 @@ impl Zone { mmio_vpci_handler, rootcomplex_config.ecam_base as usize, ); + self.page_table_emergency(rootcomplex_config.ecam_base as usize, rootcomplex_config.ecam_size as usize); } #[cfg(not(any(feature = "ecam_pcie", feature = "dwc_pcie", feature = "loongarch64_pcie")))] { From 9b584830b9ebe7c86bc37b737a1691b316921052 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 4 Dec 2025 15:50:51 +0800 Subject: [PATCH 039/109] 1. for loongarch, add allocator for bar 2.for virt dev, add bar init 3.update bar read handler for vpci_handler --- .../qemu-gicv3/configs/zone1-linux.json | 4 +- platform/loongarch64/ls3a5000/board.rs | 2 + src/pci/mem_alloc.rs | 80 +++++++++++++++++-- src/pci/pci_access.rs | 30 +++++-- src/pci/pci_config.rs | 34 ++++++-- src/pci/pci_struct.rs | 14 ++-- src/pci/vpci_dev/mod.rs | 21 ++++- src/pci/vpci_dev/standard.rs | 15 +++- 8 files changed, 170 insertions(+), 30 deletions(-) diff --git a/platform/aarch64/qemu-gicv3/configs/zone1-linux.json b/platform/aarch64/qemu-gicv3/configs/zone1-linux.json index 9bef1db5..7de1d7c4 100644 --- a/platform/aarch64/qemu-gicv3/configs/zone1-linux.json +++ b/platform/aarch64/qemu-gicv3/configs/zone1-linux.json @@ -44,7 +44,9 @@ "pci_mem32_base": "0x10000000", "mem64_base": "0x8000000000", "mem64_size": "0x8000000000", - "pci_mem64_base": "0x8000000000" + "pci_mem64_base": "0x8000000000", + "bus_range_begin": "0x0", + "bus_range_end": "0x1f" }], "num_pci_devs": 2, "alloc_pci_devs": [ diff --git a/platform/loongarch64/ls3a5000/board.rs b/platform/loongarch64/ls3a5000/board.rs index 5de319aa..cdcbc1ef 100644 --- a/platform/loongarch64/ls3a5000/board.rs +++ b/platform/loongarch64/ls3a5000/board.rs @@ -168,6 +168,8 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ mem64_base: 0x60000000, mem64_size: 0x20000000, pci_mem64_base: 0x60000000, + bus_range_begin: 0, + bus_range_end: 0xff, } ]; diff --git a/src/pci/mem_alloc.rs b/src/pci/mem_alloc.rs index 7e4533fe..6c871440 100644 --- a/src/pci/mem_alloc.rs +++ b/src/pci/mem_alloc.rs @@ -15,7 +15,7 @@ // use core::{fmt::Debug, ops::Range}; -pub type Mem32Address = u32; +pub type Mem32Address = u64; pub type Mem64Address = u64; trait Algin { @@ -28,15 +28,16 @@ impl Algin for Mem32Address { } } -impl Algin for Mem64Address { - 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; + fn alloc_io(&mut self, size: Mem64Address) -> Option; } #[derive(Default, Debug)] @@ -45,6 +46,8 @@ pub struct BaseAllocator { mem32_used: Mem32Address, mem64: Range, mem64_used: Mem64Address, + io: Range, + io_used: Mem64Address, } impl BaseAllocator { @@ -57,6 +60,11 @@ impl BaseAllocator { self.mem64 = start..start + size; self.mem64_used = start; } + + pub fn set_io(&mut self, start: Mem64Address, size: Mem64Address) { + self.io = start..start + size; + self.io_used = start; + } } impl BarAllocator for BaseAllocator { @@ -82,4 +90,64 @@ impl BarAllocator for BaseAllocator { None } } + + fn alloc_io(&mut self, _size: Mem64Address) -> Option { + warn!("alloc io not supported"); + None + } } + +#[derive(Default, Debug)] +pub struct LoongArchAllocator { + mem: Range, + mem_used: Mem64Address, + io: Range, + io_used: Mem64Address, +} + + +impl LoongArchAllocator { + pub fn set_mem(&mut self, start: Mem64Address, size: Mem64Address) { + self.mem = start..start + size; + self.mem_used = start; + } + + pub fn set_io(&mut self, start: Mem64Address, size: Mem64Address) { + self.io = start..start + size; + self.io_used = start; + } +} + +impl BarAllocator for LoongArchAllocator { + fn alloc_memory32(&mut self, size: Mem32Address) -> Option { + let ptr = self.mem_used.align_up(size); + if self.mem.contains(&ptr) && ptr + size <= self.mem.end { + self.mem_used = ptr + size; + // debug!("alloc mem64 {:x} {}", ptr, size); + Some(ptr) + } else { + None + } + } + + fn alloc_memory64(&mut self, size: Mem64Address) -> Option { + let ptr = self.mem_used.align_up(size); + if self.mem.contains(&ptr) && ptr + size <= self.mem.end { + self.mem_used = ptr + size; + // debug!("alloc mem64 {:x} {}", ptr, size); + Some(ptr) + } else { + None + } + } + + fn alloc_io(&mut self, size: Mem64Address) -> Option { + let ptr = self.io_used.align_up(size); + if self.io.contains(&ptr) && ptr + size <= self.io.end { + self.io_used = ptr + size; + Some(ptr) + } else { + None + } + } +} \ No newline at end of file diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 8612c257..cc088bcc 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -40,6 +40,8 @@ use crate::{ zone::{this_zone_id, Zone}, }; +use crate::pci::vpci_dev::VpciDevType; + pub type VendorId = u16; pub type DeviceId = u16; pub type DeviceRevision = u8; @@ -182,6 +184,10 @@ impl PciMem { } } + pub fn set_size(&mut self, size: u64){ + self.size = size; + } + pub fn get_size(&self) -> u64 { self.size } @@ -656,6 +662,12 @@ pub trait PciBarRW: PciRWBase { } } +impl Bar { + pub fn virt_bar_init(dev_type: VpciDevType) -> Self { + crate::pci::vpci_dev::virt_bar_init(dev_type) + } +} + pub trait PciRomRW: PciRWBase { fn rom_offset(&self) -> u64; fn parse_rom(&self) -> PciMem { @@ -1179,9 +1191,9 @@ fn handle_config_space_access( let is_write = mmio.is_write; let vbdf = dev.get_vbdf(); - if vbdf.bus == 0 && vbdf.device == 5 && vbdf.function == 0 { - info!("virt pci standard access, vbdf {:#?}, offset {:#x}, size {:#x}, is_write {:#?}", vbdf, offset, size, is_write); - } + // if vbdf.bus == 0 && vbdf.device == 5 && vbdf.function == 0 { + // info!("virt pci standard access, vbdf {:#?}, offset {:#x}, size {:#x}, is_write {:#?}", vbdf, offset, size, is_write); + // } if (offset as usize) >= BIT_LENTH { warn!("invalid pci offset {:#x}", offset); @@ -1193,7 +1205,7 @@ fn handle_config_space_access( match dev.access(offset, size) { false => { - debug!( + info!( "hw vbdf {:#?} reg 0x{:x} try {} {}", vbdf, offset, @@ -1283,7 +1295,7 @@ fn handle_config_space_access( ); } let paddr = bar.get_value64(); - debug!( + info!( "old_vaddr {:x} new_vaddr {:x} paddr {:x}", old_vaddr, new_vaddr, paddr ); @@ -1338,7 +1350,11 @@ fn handle_config_space_access( dev.clear_bar_size_read(slot); r } else { - bar.get_virtual_value().try_into().unwrap() + // bar.get_virtual_value().try_into().unwrap() + let emu_value = dev.read_emu(offset, size).unwrap() as usize; + let virtual_value = bar.get_virtual_value() as usize; + info!("emu value {:#x} virtual_value {:#x}", emu_value, virtual_value); + emu_value }; } } else { @@ -1386,7 +1402,7 @@ fn handle_config_space_access( } } - debug!( + info!( "vbdf {:#?} reg 0x{:x} {} 0x{:x}", vbdf, offset, diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 2a34bfe9..2e1cedc4 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -32,14 +32,14 @@ use crate::pci::vpci_dev::{VpciDevType, get_handler}; feature = "dwc_pcie", feature = "loongarch64_pcie" ))] -use crate::pci::{mem_alloc::BaseAllocator, pci_struct::RootComplex}; - -#[cfg(any(feature = "ecam_pcie", feature = "dwc_pcie"))] -use crate::pci::pci_access::mmio_vpci_handler; +use crate::pci::{mem_alloc::BaseAllocator, pci_struct::RootComplex, pci_access::mmio_vpci_handler}; #[cfg(feature = "dwc_pcie")] use crate::{memory::mmio_generic_handler, pci::pci_access::mmio_vpci_handler_dbi, platform}; +#[cfg(feature = "loongarch64_pcie")] +use crate::pci::mem_alloc::LoongArchAllocator; + pub static GLOBAL_PCIE_LIST: Lazy>> = Lazy::new(|| { let m = BTreeMap::new(); Mutex::new(m) @@ -62,13 +62,17 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { let mut allocator = BaseAllocator::default(); allocator.set_mem32( - rootcomplex_config.pci_mem32_base as u32, - rootcomplex_config.mem32_size as u32, + rootcomplex_config.mem32_base, + rootcomplex_config.mem32_size, ); allocator.set_mem64( - rootcomplex_config.pci_mem64_base, + rootcomplex_config.mem64_base, rootcomplex_config.mem64_size, ); + allocator.set_io( + rootcomplex_config.io_base as u64, + rootcomplex_config.io_size, + ); // TODO: refactor // in x86, we do not take the initiative to reallocate BAR space @@ -77,6 +81,20 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { #[cfg(not(feature = "no_pcie_bar_realloc"))] let allocator_opt: Option = Some(allocator); + #[cfg(feature = "loongarch64_pcie")] + let allocator_opt: Option = { + let mut allocator = LoongArchAllocator::default(); + allocator.set_mem( + rootcomplex_config.mem64_base, + rootcomplex_config.mem64_size, + ); + allocator.set_io( + rootcomplex_config.io_base, + rootcomplex_config.io_size, + ); + Some(allocator) + }; + let mut rootcomplex = { #[cfg(feature = "dwc_pcie")] { @@ -179,7 +197,7 @@ impl Zone { + ((bdf.bus() as u64) << 20) + ((bdf.device() as u64) << 15) + ((bdf.function() as u64) << 12); - let dev = VirtualPciConfigSpace::virt_dev(bdf, base); + let dev = VirtualPciConfigSpace::virt_dev(bdf, base, dev_type); self.vpci_bus.insert(vbdf, dev); } else { warn!("can not find dev {:#?}, unknown device type", bdf); diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 15fdc595..110b0bb4 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -416,6 +416,7 @@ impl VirtualPciConfigSpace { pub fn virt_dev( bdf: Bdf, base: PciConfigAddress, + dev_type: VpciDevType, ) -> Self { Self { host_bdf: Bdf::default(), @@ -425,14 +426,14 @@ impl VirtualPciConfigSpace { config_type: HeaderType::Endpoint, class: (0u8,0u8,0u8), base, - space: PciConfigSpace::init_with_type(VpciDevType::StandardVdev), + space: PciConfigSpace::init_with_type(dev_type), control: VirtualPciConfigControl::virt_dev(), access: VirtualPciAccessBits::virt_dev(), backend: Arc::new(EndpointHeader::new_with_region(PciConfigMmio::new(base, CONFIG_LENTH))), - bararr: Bar::default(), + bararr: Bar::virt_bar_init(dev_type), rom: PciMem::default(), capabilities: PciCapabilityList::new(), - dev_type: VpciDevType::StandardVdev, + dev_type, } } pub fn endpoint( @@ -629,7 +630,7 @@ impl VirtualPciConfigSpace { } pub fn write_emu(&mut self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { - if self.writable(offset, size) { + if true { match size { 1 | 2 | 4 => { let slice = self.space.get_range_mut(offset as usize, size); @@ -806,10 +807,10 @@ impl PciIterator { while i < bar_max { match bararr[i].get_type() { PciMemType::Mem32 => { - let value = a.alloc_memory32(bararr[i].get_size() as u32).unwrap(); + let value = a.alloc_memory32(bararr[i].get_size() as u64).unwrap(); bararr[i].set_value(value as u64); bararr[i].set_virtual_value(value as u64); - let _ = dev.write_bar(i as u8, value); + let _ = dev.write_bar(i as u8, value as u32); } PciMemType::Mem64Low => { let value = a.alloc_memory64(bararr[i].get_size()).unwrap(); @@ -1116,6 +1117,7 @@ impl VirtualRootComplex { dev: VirtualPciConfigSpace, ) -> Option { let base = dev.get_base(); + info!("pci insert base {:#x} to bdf {:#?}", base, bdf); self.base_to_bdf.insert(base, bdf); self.devs.insert(bdf, dev) } diff --git a/src/pci/vpci_dev/mod.rs b/src/pci/vpci_dev/mod.rs index 6bf7f01f..a16fbb94 100644 --- a/src/pci/vpci_dev/mod.rs +++ b/src/pci/vpci_dev/mod.rs @@ -1,6 +1,7 @@ use crate::pci::pci_struct::{PciConfigSpace, VirtualPciConfigSpace}; use crate::pci::PciConfigAddress; use crate::error::HvResult; +use crate::pci::pci_access::Bar; pub mod standard; @@ -12,7 +13,7 @@ pub(crate) enum PciConfigAccessStatus { } #[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] -#[repr(u32)] +#[repr(C, align(4))] pub enum VpciDevType { #[default] Physical=0, @@ -24,6 +25,7 @@ pub trait VpciDeviceHandler: Sync + Send { fn read_cfg(&self, space: &mut PciConfigSpace, offset: PciConfigAddress, size: usize) -> HvResult; fn write_cfg(&self, space: &mut PciConfigSpace, offset: PciConfigAddress, size: usize, value: usize) -> HvResult; fn init_config_space(&self) -> PciConfigSpace; + fn init_bar(&self) -> Bar; } /* @@ -145,4 +147,21 @@ pub(super) fn init_config_space_with_type(dev_type: VpciDevType) -> PciConfigSpa } } } +} + +pub(super) fn virt_bar_init(dev_type: VpciDevType) -> Bar { + match dev_type { + VpciDevType::Physical => { + // Physical devices use default (all zeros) space + unreachable!("virt_bar_init: physical device is not supported"); + } + _ => { + if let Some(handler) = get_handler(dev_type) { + handler.init_bar() + } else { + warn!("init_config_space_with_type: unknown device type"); + Bar::default() + } + } + } } \ No newline at end of file diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index b5c28d31..7a9337cf 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -1,8 +1,9 @@ use crate::error::HvResult; use crate::pci::pci_struct::PciConfigSpace; -use crate::pci::pci_access::EndpointField; +use crate::pci::pci_access::{EndpointField, Bar}; use crate::pci::PciConfigAddress; use super::{PciConfigAccessStatus, VpciDeviceHandler}; +use crate::memory::frame::Frame; const STANDARD_VENDOR_ID: u16 = 0x110a; const STANDARD_DEVICE_ID: u16 = 0x4106; @@ -80,6 +81,18 @@ impl VpciDeviceHandler for StandardHandler { space } + + fn init_bar(&self) -> Bar { + let mut bar = Bar::default(); + // value is the paddr of the mem you allocate + let frame = Frame::new().unwrap(); + let start = frame.start_paddr(); + let size = frame.size(); + bar[0].set_value(start as u64); + bar[0].set_virtual_value(start as u64); + bar[0].set_size(size as u64); + bar + } } /// Static handler instance for standard virtual PCI devices From ad624bc161edd778556adb465bdd720c53cb51de Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 4 Dec 2025 17:06:32 +0800 Subject: [PATCH 040/109] for virt dev, update bar and example for mmio register --- src/pci/pci_access.rs | 25 +++++++++++++++--------- src/pci/pci_struct.rs | 2 +- src/pci/vpci_dev/mod.rs | 8 ++++---- src/pci/vpci_dev/standard.rs | 37 +++++++++++++++++++++++++++--------- 4 files changed, 49 insertions(+), 23 deletions(-) diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index cc088bcc..3cc8ba42 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -778,7 +778,7 @@ pub enum EndpointField { LatencyTime, HeaderType, Bist, - Bar, + Bar(usize), CardCisPointer, SubsystemVendorId, SubsystemId, @@ -803,7 +803,7 @@ impl Debug for EndpointField { EndpointField::LatencyTime => write!(f, "LatencyTime"), EndpointField::HeaderType => write!(f, "HeaderType"), EndpointField::Bist => write!(f, "Bist"), - EndpointField::Bar => write!(f, "Bar"), + EndpointField::Bar(slot) => write!(f, "Bar({})", slot), EndpointField::CardCisPointer => write!(f, "CardCisPointer"), EndpointField::SubsystemVendorId => write!(f, "SubsystemVendorId"), EndpointField::SubsystemId => write!(f, "SubsystemId"), @@ -830,7 +830,7 @@ impl PciField for EndpointField { EndpointField::LatencyTime => 0x0d, EndpointField::HeaderType => 0x0e, EndpointField::Bist => 0x0f, - EndpointField::Bar => 0x10, + EndpointField::Bar(slot) => (0x10 + slot * 4) as usize, EndpointField::CardCisPointer => 0x28, EndpointField::SubsystemVendorId => 0x2c, EndpointField::SubsystemId => 0x2e, @@ -854,7 +854,7 @@ impl PciField for EndpointField { EndpointField::LatencyTime => 1, EndpointField::HeaderType => 1, EndpointField::Bist => 1, - EndpointField::Bar => 4, + EndpointField::Bar(_) => 4, EndpointField::CardCisPointer => 4, EndpointField::SubsystemVendorId => 2, EndpointField::SubsystemId => 2, @@ -880,9 +880,15 @@ impl EndpointField { (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 - } + // (0x10, 4) | (0x14, 4) | (0x18, 4) | (0x1c, 4) | (0x20, 4) | (0x24, 4) => { + // EndpointField::Bar + // } + (0x10, 4) => EndpointField::Bar(0), + (0x14, 4) => EndpointField::Bar(1), + (0x18, 4) => EndpointField::Bar(2), + (0x1c, 4) => EndpointField::Bar(3), + (0x20, 4) => EndpointField::Bar(4), + (0x24, 4) => EndpointField::Bar(5), (0x28, 4) => EndpointField::CardCisPointer, (0x2c, 2) => EndpointField::SubsystemVendorId, (0x2e, 2) => EndpointField::SubsystemId, @@ -1239,8 +1245,9 @@ fn handle_config_space_access( match dev.get_config_type() { HeaderType::Endpoint => { match EndpointField::from(offset as usize, size) { - EndpointField::Bar => { - let slot = ((offset - 0x10) / 4) as usize; + EndpointField::Bar(slot) => { + // let slot = ((offset - 0x10) / 4) as usize; + let slot = slot as usize; /* the write of bar needs to start from dev, * where the bar variable here is just a copy */ diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 110b0bb4..74017b9c 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -385,7 +385,7 @@ impl VirtualPciConfigSpace { match self.get_config_type() { HeaderType::Endpoint => { match EndpointField::from(offset as usize, size) { - EndpointField::Bar => { + 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); diff --git a/src/pci/vpci_dev/mod.rs b/src/pci/vpci_dev/mod.rs index a16fbb94..eaff6737 100644 --- a/src/pci/vpci_dev/mod.rs +++ b/src/pci/vpci_dev/mod.rs @@ -22,8 +22,8 @@ pub enum VpciDevType { } pub trait VpciDeviceHandler: Sync + Send { - fn read_cfg(&self, space: &mut PciConfigSpace, offset: PciConfigAddress, size: usize) -> HvResult; - fn write_cfg(&self, space: &mut PciConfigSpace, offset: PciConfigAddress, size: usize, value: usize) -> HvResult; + fn read_cfg(&self, dev: &mut VirtualPciConfigSpace, offset: PciConfigAddress, size: usize) -> HvResult; + fn write_cfg(&self, dev: &mut VirtualPciConfigSpace, offset: PciConfigAddress, size: usize, value: usize) -> HvResult; fn init_config_space(&self) -> PciConfigSpace; fn init_bar(&self) -> Bar; } @@ -57,7 +57,7 @@ pub(super) fn vpci_dev_read_cfg( } _ => { if let Some(handler) = get_handler(dev_type) { - match handler.read_cfg(node.get_space_mut(), offset, size) { + match handler.read_cfg(node, offset, size) { Ok(status) => { match status { PciConfigAccessStatus::Done(value) => { @@ -103,7 +103,7 @@ pub(super) fn vpci_dev_write_cfg( } _ => { if let Some(handler) = get_handler(dev_type) { - match handler.write_cfg(node.get_space_mut(), offset, size, value) { + match handler.write_cfg(node, offset, size, value) { Ok(status) => { match status { PciConfigAccessStatus::Done(_) => { diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index 7a9337cf..3641f4cf 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -4,6 +4,9 @@ use crate::pci::pci_access::{EndpointField, Bar}; use crate::pci::PciConfigAddress; use super::{PciConfigAccessStatus, VpciDeviceHandler}; use crate::memory::frame::Frame; +use crate::pci::pci_struct::VirtualPciConfigSpace; +use crate::percpu::this_zone; +use crate::memory::MMIOAccess; const STANDARD_VENDOR_ID: u16 = 0x110a; const STANDARD_DEVICE_ID: u16 = 0x4106; @@ -38,12 +41,13 @@ pub(crate) const DEFAULT_CSPACE_U32: [u32; STANDARD_CFG_SIZE / 4] = { pub struct StandardHandler; impl VpciDeviceHandler for StandardHandler { - fn read_cfg(&self, _space: &mut PciConfigSpace, offset: PciConfigAddress, size: usize) -> HvResult { + fn read_cfg(&self, dev: &mut VirtualPciConfigSpace, offset: PciConfigAddress, size: usize) -> HvResult { info!("virt pci standard read_cfg, offset {:#x}, size {:#x}", offset, size); + let space = dev.get_space_mut(); match EndpointField::from(offset as usize, size) { EndpointField::ID => { - Ok(PciConfigAccessStatus::Done(_space.get(EndpointField::ID) as usize)) + Ok(PciConfigAccessStatus::Done(space.get(EndpointField::ID) as usize)) } _ => { Ok(PciConfigAccessStatus::Perform) @@ -51,8 +55,9 @@ impl VpciDeviceHandler for StandardHandler { } } - fn write_cfg(&self, space: &mut PciConfigSpace, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { + fn write_cfg(&self, dev: &mut VirtualPciConfigSpace, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { info!("virt pci standard write_cfg, offset {:#x}, size {:#x}, value {:#x}", offset, size, value); + let mut space = dev.get_space_mut(); match EndpointField::from(offset as usize, size) { EndpointField::ID => { Ok(PciConfigAccessStatus::Reject) @@ -61,6 +66,19 @@ impl VpciDeviceHandler for StandardHandler { space.set(EndpointField::Command, value as u32); Ok(PciConfigAccessStatus::Done(value)) } + EndpointField::Bar(slot) => { + // let slot = 0; + if value == 0xFFFF_FFFF { + dev.set_bar_size_read(slot); + } else { + let zone = this_zone(); + let mut guard = zone.write(); + let size = dev.get_bararr()[slot].get_size(); + guard.mmio_region_register(value as usize, size as usize, mmio_vdev_standard_handler, value); + } + + Ok(PciConfigAccessStatus::Done(value)) + } _ => { Ok(PciConfigAccessStatus::Reject) } @@ -85,15 +103,16 @@ impl VpciDeviceHandler for StandardHandler { fn init_bar(&self) -> Bar { let mut bar = Bar::default(); // value is the paddr of the mem you allocate - let frame = Frame::new().unwrap(); - let start = frame.start_paddr(); - let size = frame.size(); - bar[0].set_value(start as u64); - bar[0].set_virtual_value(start as u64); + let size = 0x1000; bar[0].set_size(size as u64); bar } } /// Static handler instance for standard virtual PCI devices -pub const HANDLER: StandardHandler = StandardHandler; \ No newline at end of file +pub const HANDLER: StandardHandler = StandardHandler; + +pub fn mmio_vdev_standard_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { + info!("mmio_vdev_standard_handler {:#x}", mmio.address); + Ok(()) +} \ No newline at end of file From 655e58ab541feed2c58d055677564cc999ef4ee4 Mon Sep 17 00:00:00 2001 From: Zhongkai Xu <135129044+ZhongkaiXu@users.noreply.github.com> Date: Mon, 8 Dec 2025 22:43:11 +0800 Subject: [PATCH 041/109] fix(gits): fix MOVI cmd (#216) change vicid to icid when handling MOVI command in ITS --- src/device/irqchip/gicv3/gits.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/device/irqchip/gicv3/gits.rs b/src/device/irqchip/gicv3/gits.rs index e3ad3b75..eb8719f6 100644 --- a/src/device/irqchip/gicv3/gits.rs +++ b/src/device/irqchip/gicv3/gits.rs @@ -321,6 +321,19 @@ impl Cmdq { 0x0d => { debug!("INVALL cmd"); } + 0x01 => { + let vicid = value[2] & 0xffff; + let icid = vicid_to_icid(vicid, cpuset_bitmap) + .expect("vicid to icid failed, maybe logical_id out of range"); + new_cmd[2] &= !0xffffu64; + new_cmd[2] |= icid & 0xffff; + debug!( + "MOVI, for Device {:#x}, new vicid({}) -> icid({})", + value[0] >> 32, + vicid, + icid + ); + } _ => { debug!("other cmd, code: 0x{:x}", code); } From 14fb040d4b0a297bb26161ad23c65bcab31eef68 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 11 Dec 2025 00:52:57 +0800 Subject: [PATCH 042/109] 1. update bar init for virt dev 2. now bar allocate in root for loongarch64 --- src/pci/mem_alloc.rs | 96 ++++++------ src/pci/pci_access.rs | 277 ++++++++++++++++++++++++++++++++++- src/pci/pci_config.rs | 34 +++-- src/pci/pci_struct.rs | 38 +++-- src/pci/vpci_dev/mod.rs | 10 +- src/pci/vpci_dev/standard.rs | 27 +++- 6 files changed, 385 insertions(+), 97 deletions(-) diff --git a/src/pci/mem_alloc.rs b/src/pci/mem_alloc.rs index 6c871440..00df0d25 100644 --- a/src/pci/mem_alloc.rs +++ b/src/pci/mem_alloc.rs @@ -97,57 +97,57 @@ impl BarAllocator for BaseAllocator { } } -#[derive(Default, Debug)] -pub struct LoongArchAllocator { - mem: Range, - mem_used: Mem64Address, - io: Range, - io_used: Mem64Address, -} +// #[derive(Default, Debug)] +// pub struct LoongArchAllocator { +// mem: Range, +// mem_used: Mem64Address, +// io: Range, +// io_used: Mem64Address, +// } -impl LoongArchAllocator { - pub fn set_mem(&mut self, start: Mem64Address, size: Mem64Address) { - self.mem = start..start + size; - self.mem_used = start; - } +// impl LoongArchAllocator { +// pub fn set_mem(&mut self, start: Mem64Address, size: Mem64Address) { +// self.mem = start..start + size; +// self.mem_used = start; +// } - pub fn set_io(&mut self, start: Mem64Address, size: Mem64Address) { - self.io = start..start + size; - self.io_used = start; - } -} +// pub fn set_io(&mut self, start: Mem64Address, size: Mem64Address) { +// self.io = start..start + size; +// self.io_used = start; +// } +// } -impl BarAllocator for LoongArchAllocator { - fn alloc_memory32(&mut self, size: Mem32Address) -> Option { - let ptr = self.mem_used.align_up(size); - if self.mem.contains(&ptr) && ptr + size <= self.mem.end { - self.mem_used = ptr + size; - // debug!("alloc mem64 {:x} {}", ptr, size); - Some(ptr) - } else { - None - } - } +// impl BarAllocator for LoongArchAllocator { +// fn alloc_memory32(&mut self, size: Mem32Address) -> Option { +// let ptr = self.mem_used.align_up(size); +// if self.mem.contains(&ptr) && ptr + size <= self.mem.end { +// self.mem_used = ptr + size; +// // debug!("alloc mem64 {:x} {}", ptr, size); +// Some(ptr) +// } else { +// None +// } +// } - fn alloc_memory64(&mut self, size: Mem64Address) -> Option { - let ptr = self.mem_used.align_up(size); - if self.mem.contains(&ptr) && ptr + size <= self.mem.end { - self.mem_used = ptr + size; - // debug!("alloc mem64 {:x} {}", ptr, size); - Some(ptr) - } else { - None - } - } +// fn alloc_memory64(&mut self, size: Mem64Address) -> Option { +// let ptr = self.mem_used.align_up(size); +// if self.mem.contains(&ptr) && ptr + size <= self.mem.end { +// self.mem_used = ptr + size; +// // debug!("alloc mem64 {:x} {}", ptr, size); +// Some(ptr) +// } else { +// None +// } +// } - fn alloc_io(&mut self, size: Mem64Address) -> Option { - let ptr = self.io_used.align_up(size); - if self.io.contains(&ptr) && ptr + size <= self.io.end { - self.io_used = ptr + size; - Some(ptr) - } else { - None - } - } -} \ No newline at end of file +// fn alloc_io(&mut self, size: Mem64Address) -> Option { +// let ptr = self.io_used.align_up(size); +// if self.io.contains(&ptr) && ptr + size <= self.io.end { +// self.io_used = ptr + size; +// Some(ptr) +// } else { +// None +// } +// } +// } \ No newline at end of file diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 3cc8ba42..765858af 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -32,12 +32,11 @@ use super::{ use crate::{ error::HvResult, memory::{ - mmio_perform_access, GuestPhysAddr, HostPhysAddr, MMIOAccess, MemFlags, MemoryRegion, - MemorySet, + GuestPhysAddr, HostPhysAddr, MMIOAccess, MemFlags, MemoryRegion, MemorySet, mmio_perform_access }, - pci::pci_struct::BIT_LENTH, + pci::{pci_config::GLOBAL_PCIE_LIST, pci_struct::BIT_LENTH}, percpu::this_zone, - zone::{this_zone_id, Zone}, + zone::{Zone, is_this_root_zone, this_zone_id}, }; use crate::pci::vpci_dev::VpciDevType; @@ -192,7 +191,7 @@ impl PciMem { self.size } - pub fn get_size_with_flag(&mut self) -> u64 { + pub fn get_size_with_flag(&self) -> u64 { match self.bar_type { PciMemType::Mem32 | PciMemType::Rom | PciMemType::Io => !(self.size - 1u64), PciMemType::Mem64Low => { @@ -215,6 +214,10 @@ impl PciMem { } } + pub fn set_type(&mut self, bar_type: PciMemType) { + self.bar_type = bar_type; + } + pub fn is_enabled(&self) -> bool { if self.bar_type == PciMemType::default() { false @@ -1195,7 +1198,8 @@ fn handle_config_space_access( let size = mmio.size; let value = mmio.value; let is_write = mmio.is_write; - let vbdf = dev.get_vbdf(); + // now the vbdf is same with bdf + let vbdf = dev.get_bdf(); // if vbdf.bus == 0 && vbdf.device == 5 && vbdf.function == 0 { // info!("virt pci standard access, vbdf {:#?}, offset {:#x}, size {:#x}, is_write {:#?}", vbdf, offset, size, is_write); @@ -1386,6 +1390,11 @@ fn handle_config_space_access( }; } } + EndpointField::ID => { + if !is_write { + mmio.value = dev.read_emu(offset, size).unwrap() as usize; + } + } _ => {} } } @@ -1488,3 +1497,259 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { Ok(()) } + +fn handle_config_space_access_direct( + dev: &mut VirtualPciConfigSpace, + mmio: &mut MMIOAccess, + offset: PciConfigAddress, + gpm: &mut MemorySet, + zone_id: usize, + is_root: bool, + is_dev_belong_to_zone: bool, +) -> HvResult { + let size = mmio.size; + let value = mmio.value; + let is_write = mmio.is_write; + let vbdf = dev.get_bdf(); + + if (offset as usize) >= BIT_LENTH { + warn!("invalid pci offset {:#x}", offset); + if !is_write { + mmio.value = 0; + } + return Ok(()); + } + + if is_dev_belong_to_zone || is_root { + match dev.access(offset, size) { + false => { + info!( + "hw vbdf {:#?} reg 0x{:x} try {} {}", + vbdf, + offset, + if is_write { "write" } else { "read" }, + if is_write { + format!(" 0x{:x}", mmio.value) + } else { + String::new() + } + ); + if is_write { + dev.write_hw(offset, size, value)?; + } else { + mmio.value = dev.read_hw(offset, size).unwrap(); + } + } + true => { + info!( + "emu vbdf {:#?} reg 0x{:x} try {} {}", + vbdf, + offset, + if is_write { "write" } else { "read" }, + if 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::ID => { + if !is_write { + if is_dev_belong_to_zone { + mmio.value = dev.read_emu(offset, size).unwrap(); + } else { + if is_root { + /* just a id no one used now + * here let root allocate resources but not drive the device + */ + mmio.value = 0xFFFD_4106; + } + } + } + } + EndpointField::Bar(slot) => { + let bar = &mut dev.get_bararr()[slot]; + let bar_type = bar.get_type(); + if bar_type != PciMemType::default() { + if is_write { + if (value & 0xfffffff0) == 0xfffffff0 { + dev.set_bar_size_read(slot); + } else { + let _ = dev.write_emu(offset, size, value); + if (bar_type == PciMemType::Mem32) + | (bar_type == PciMemType::Mem64High) + | (bar_type == PciMemType::Io) { + 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 + } + }; + if !gpm.try_delete(old_vaddr.try_into().unwrap()).is_ok() { + warn!( + "delete bar {}: can not found 0x{:x}", + slot, old_vaddr + ); + } + + dev.set_bar_virtual_value(slot, new_vaddr); + if bar_type == PciMemType::Mem64High { + dev.set_bar_virtual_value(slot - 1, new_vaddr); + } + + let paddr = if is_root { + dev.set_bar_value(slot, new_vaddr); + if bar_type == PciMemType::Mem64High { + dev.set_bar_value(slot - 1, new_vaddr); + } + new_vaddr as HostPhysAddr + } else { + bar.get_value64() as HostPhysAddr + }; + + let bar_size = if crate::memory::addr::is_aligned( + bar.get_size() as usize, + ) { + bar.get_size() + } else { + crate::memory::PAGE_SIZE as u64 + }; + let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) { + crate::memory::addr::align_up(new_vaddr as usize) as u64 + } else { + new_vaddr as u64 + }; + gpm.try_insert(MemoryRegion::new_with_offset_mapper( + new_vaddr as GuestPhysAddr, + paddr as HostPhysAddr, + bar_size as _, + MemFlags::READ | MemFlags::WRITE, + ))?; + /* after update gpm, mem barrier is needed + */ + #[cfg(target_arch = "aarch64")] + unsafe { + core::arch::asm!("isb"); + core::arch::asm!("tlbi vmalls12e1is"); + core::arch::asm!("dsb nsh"); + } + /* after update gpm, need to flush iommu table + * in x86_64 + */ + #[cfg(target_arch = "x86_64")] + crate::arch::iommu::flush( + zone_id, + vbdf.bus, + (vbdf.device << 3) + vbdf.function, + ); + } + } + } else { + mmio.value = if bar.get_size_read() { + let r = bar.get_size_with_flag().try_into().unwrap(); + r + } else { + bar.get_virtual_value() as usize + } + } + } else { + mmio.value = 0; + } + } + EndpointField::ExpansionRomBar => { + let mut rom = dev.get_rom(); + if 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() + }; + } + } + _ => { + mmio.value = 0; + } + } + } + HeaderType::PciBridge => { + // TODO: add emu for bridge, actually it is same with endpoint + warn!("bridge emu rw"); + } + _ => { + warn!("unhanled pci type {:#?}", dev.get_config_type()); + } + } + } + _ => { + if mmio.is_write { + super::vpci_dev::vpci_dev_write_cfg(dev.get_dev_type(), dev, offset, size, value).unwrap(); + } else { + mmio.value = super::vpci_dev::vpci_dev_read_cfg(dev.get_dev_type(), dev, offset, size).unwrap() as usize; + } + } + } + } + info!( + "vbdf {:#?} reg 0x{:x} {} 0x{:x}", + vbdf, + offset, + if is_write { "write" } else { "read" }, + mmio.value + ); + + Ok(()) +} + +pub fn mmio_vpci_direct_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { + let zone_id = this_zone_id(); + let zone = this_zone(); + let mut guard = zone.write(); + let (vbus, gpm) = { + let Zone { gpm, vpci_bus, .. } = &mut *guard; + (vpci_bus, gpm) + }; + + let offset = (mmio.address & 0xfff) as PciConfigAddress; + let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; + let mut is_dev_belong_to_zone = false; + + let mut global_pcie_list = GLOBAL_PCIE_LIST.lock(); + let dev = match vbus.get_device_by_base(base) { + Some(dev) => { + is_dev_belong_to_zone = true; + Some(dev) + } + None => global_pcie_list + .values_mut() + .find(|dev| dev.get_base() == base) + }; + + let mut dev = match dev { + Some(dev) => dev, + None => { + handle_device_not_found(mmio, offset); + return Ok(()); + } + }; + + let is_root = is_this_root_zone(); + + handle_config_space_access_direct(&mut dev, mmio, offset, gpm, zone_id, is_root, is_dev_belong_to_zone); + + Ok(()) +} \ No newline at end of file diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 29ae5b16..1fd03804 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -38,7 +38,7 @@ use crate::pci::{mem_alloc::BaseAllocator, pci_struct::RootComplex, pci_access:: use crate::{memory::mmio_generic_handler, pci::pci_access::mmio_vpci_handler_dbi, platform}; #[cfg(feature = "loongarch64_pcie")] -use crate::pci::mem_alloc::LoongArchAllocator; +use crate::pci::pci_access::mmio_vpci_direct_handler; pub static GLOBAL_PCIE_LIST: Lazy>> = Lazy::new(|| { let m = BTreeMap::new(); @@ -81,19 +81,19 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { #[cfg(not(feature = "no_pcie_bar_realloc"))] let allocator_opt: Option = Some(allocator); - #[cfg(feature = "loongarch64_pcie")] - let allocator_opt: Option = { - let mut allocator = LoongArchAllocator::default(); - allocator.set_mem( - rootcomplex_config.mem64_base, - rootcomplex_config.mem64_size, - ); - allocator.set_io( - rootcomplex_config.io_base, - rootcomplex_config.io_size, - ); - Some(allocator) - }; + // #[cfg(feature = "loongarch64_pcie")] + // let allocator_opt: Option = { + // let mut allocator = LoongArchAllocator::default(); + // allocator.set_mem( + // rootcomplex_config.mem64_base, + // rootcomplex_config.mem64_size, + // ); + // allocator.set_io( + // rootcomplex_config.io_base, + // rootcomplex_config.io_size, + // ); + // Some(allocator) + // }; let mut rootcomplex = { #[cfg(feature = "dwc_pcie")] @@ -224,10 +224,12 @@ impl Zone { } #[cfg(feature = "ecam_pcie")] { + use crate::pci::pci_access::mmio_vpci_direct_handler; self.mmio_region_register( rootcomplex_config.ecam_base as usize, rootcomplex_config.ecam_size as usize, - mmio_vpci_handler, + // mmio_vpci_handler, + mmio_vpci_direct_handler, rootcomplex_config.ecam_base as usize, ); } @@ -281,7 +283,7 @@ impl Zone { self.mmio_region_register( rootcomplex_config.ecam_base as usize, rootcomplex_config.ecam_size as usize, - mmio_vpci_handler, + mmio_vpci_direct_handler, rootcomplex_config.ecam_base as usize, ); self.page_table_emergency(rootcomplex_config.ecam_base as usize, rootcomplex_config.ecam_size as usize); diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 74017b9c..8b94d7fe 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -26,7 +26,7 @@ use super::{ PciConfigHeader, PciField, PciHeaderRW, PciMem, PciMemType, PciRW, PciRomRW, }, PciConfigAddress, - pci_access::{BaseClass, SubClass, Interface}, + pci_access::{BaseClass, SubClass, Interface, DeviceId, VendorId}, }; use crate::{error::{HvErrorNum, HvResult}, pci::vpci_dev::VpciDevType}; @@ -198,6 +198,7 @@ pub struct VirtualPciAccessBits { impl VirtualPciAccessBits { pub fn endpoint() -> Self { let mut bits = BitArray::ZERO; + bits[0x0..0x4].fill(true); // ID bits[0x10..0x34].fill(true); //bar and rom Self { bits } } @@ -227,9 +228,12 @@ pub struct PciConfigSpace { } impl PciConfigSpace { - pub fn new() -> Self { + pub fn new(id: (DeviceId, VendorId)) -> Self { + let mut data = [0u8; BIT_LENTH]; + data[0x0..0x2].copy_from_slice(&id.0.to_le_bytes()); + data[0x2..0x4].copy_from_slice(&id.1.to_le_bytes()); Self { - data: [0u8; BIT_LENTH], + data, } } @@ -297,7 +301,7 @@ impl PciConfigSpace { impl Default for PciConfigSpace { fn default() -> Self { - Self::new() + Self::new((0xFFFFu16, 0xFFFFu16)) } } @@ -360,6 +364,10 @@ impl VirtualPciConfigSpace { self.bararr[slot].set_virtual_value(value); } + pub fn set_bar_value(&mut self, slot: usize, value: u64) { + self.bararr[slot].set_value(value); + } + pub fn clear_bar_size_read(&mut self, slot: usize) { self.bararr[slot].clear_size_read(); } @@ -422,7 +430,7 @@ impl VirtualPciConfigSpace { host_bdf: Bdf::default(), parent_bdf: Bdf::default(), bdf, - vbdf: Bdf::default(), + vbdf: bdf, config_type: HeaderType::Endpoint, class: (0u8,0u8,0u8), base, @@ -443,6 +451,7 @@ impl VirtualPciConfigSpace { bararr: Bar, rom: PciMem, class: (BaseClass, SubClass, Interface), + id: (DeviceId, VendorId), ) -> Self { Self { host_bdf: Bdf::default(), @@ -452,7 +461,7 @@ impl VirtualPciConfigSpace { config_type: HeaderType::Endpoint, class, base, - space: PciConfigSpace::new(), + space: PciConfigSpace::new(id), control: VirtualPciConfigControl::endpoint(), access: VirtualPciAccessBits::endpoint(), backend, @@ -470,6 +479,7 @@ impl VirtualPciConfigSpace { bararr: Bar, rom: PciMem, class: (BaseClass, SubClass, Interface), + id: (DeviceId, VendorId), ) -> Self { Self { host_bdf: Bdf::default(), @@ -479,7 +489,7 @@ impl VirtualPciConfigSpace { config_type: HeaderType::PciBridge, class, base, - space: PciConfigSpace::new(), + space: PciConfigSpace::new(id), control: VirtualPciConfigControl::bridge(), access: VirtualPciAccessBits::bridge(), backend, @@ -490,7 +500,7 @@ impl VirtualPciConfigSpace { } } - pub fn unknown(bdf: Bdf, base: PciConfigAddress, backend: Arc) -> Self { + pub fn unknown(bdf: Bdf, base: PciConfigAddress, backend: Arc, id: (DeviceId, VendorId)) -> Self { Self { host_bdf: Bdf::default(), parent_bdf: Bdf::default(), @@ -499,7 +509,7 @@ impl VirtualPciConfigSpace { config_type: HeaderType::Endpoint, class: (0u8,0u8,0u8), base, - space: PciConfigSpace::new(), + space: PciConfigSpace::new(id), control: VirtualPciConfigControl::endpoint(), access: VirtualPciAccessBits::endpoint(), backend, @@ -519,7 +529,7 @@ impl VirtualPciConfigSpace { config_type: HeaderType::Endpoint, class, base, - space: PciConfigSpace::new(), + space: PciConfigSpace::default(), control: VirtualPciConfigControl::host_bridge(), access: VirtualPciAccessBits::host_bridge(), backend, @@ -701,7 +711,7 @@ impl PciIterator { let region = PciConfigMmio::new(address, CONFIG_LENTH); let pci_header = PciConfigHeader::new_with_region(region); - let (vender_id, _device_id) = pci_header.id(); + let (vender_id, device_id) = pci_header.id(); warn!("vender_id {:#x}", vender_id); @@ -752,7 +762,7 @@ impl PciIterator { info!("get node bar mem init end {:#?}", bararr); let ep = Arc::new(ep); - let mut node = VirtualPciConfigSpace::endpoint(bdf, address, ep, bararr, rom, class); + let mut node = VirtualPciConfigSpace::endpoint(bdf, address, ep, bararr, rom, class, (device_id, vender_id)); let _ = node.capability_enumerate(); @@ -768,7 +778,7 @@ impl PciIterator { Self::bar_mem_init(bridge.bar_limit().into(), &mut self.allocator, &mut bridge); let bridge = Arc::new(bridge); - let mut node = VirtualPciConfigSpace::bridge(bdf, address, bridge, bararr, rom, class); + let mut node = VirtualPciConfigSpace::bridge(bdf, address, bridge, bararr, rom, class, (device_id, vender_id)); let _ = node.capability_enumerate(); @@ -777,7 +787,7 @@ impl PciIterator { _ => { warn!("unknown type"); let pci_header = Arc::new(pci_header); - Some(VirtualPciConfigSpace::unknown(bdf, address, pci_header)) + Some(VirtualPciConfigSpace::unknown(bdf, address, pci_header, (device_id, vender_id))) } } } diff --git a/src/pci/vpci_dev/mod.rs b/src/pci/vpci_dev/mod.rs index eaff6737..f4606d8c 100644 --- a/src/pci/vpci_dev/mod.rs +++ b/src/pci/vpci_dev/mod.rs @@ -64,14 +64,14 @@ pub(super) fn vpci_dev_read_cfg( Ok(value) } PciConfigAccessStatus::Perform => { - warn!("vpci_dev_read_cfg: perform, offset {:#x}, size {:#x}", offset, size); + // warn!("vpci_dev_read_cfg: perform, offset {:#x}, size {:#x}", offset, size); // warn!("vpci_dev_read_cfg: node {:#?}", node.space); let r = node.read_emu(offset, size).unwrap(); - warn!("vpci_dev_read_cfg: perform result {:#x}", r); + // warn!("vpci_dev_read_cfg: perform result {:#x}", r); Ok(r) } PciConfigAccessStatus::Reject => { - warn!("vpci_dev_read_cfg: operation rejected"); + // warn!("vpci_dev_read_cfg: operation rejected"); Ok(0xFFFF_FFFF) } } @@ -136,14 +136,14 @@ pub(super) fn init_config_space_with_type(dev_type: VpciDevType) -> PciConfigSpa match dev_type { VpciDevType::Physical => { // Physical devices use default (all zeros) space - PciConfigSpace::new() + PciConfigSpace::default() } _ => { if let Some(handler) = get_handler(dev_type) { handler.init_config_space() } else { warn!("init_config_space_with_type: unknown device type"); - PciConfigSpace::new() + PciConfigSpace::default() } } } diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index 3641f4cf..96c59caf 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -3,10 +3,11 @@ use crate::pci::pci_struct::PciConfigSpace; use crate::pci::pci_access::{EndpointField, Bar}; use crate::pci::PciConfigAddress; use super::{PciConfigAccessStatus, VpciDeviceHandler}; -use crate::memory::frame::Frame; +// use crate::memory::frame::Frame; use crate::pci::pci_struct::VirtualPciConfigSpace; use crate::percpu::this_zone; use crate::memory::MMIOAccess; +use crate::pci::pci_access::PciMemType; const STANDARD_VENDOR_ID: u16 = 0x110a; const STANDARD_DEVICE_ID: u16 = 0x4106; @@ -46,9 +47,18 @@ impl VpciDeviceHandler for StandardHandler { let space = dev.get_space_mut(); match EndpointField::from(offset as usize, size) { EndpointField::ID => { - Ok(PciConfigAccessStatus::Done(space.get(EndpointField::ID) as usize)) } + EndpointField::Bar(0) => { + let bar = dev.get_bararr()[0]; + if bar.get_size_read() { + let value = bar.get_size_with_flag(); + Ok(PciConfigAccessStatus::Done(value as usize)) + } else { + let value = bar.get_virtual_value(); + Ok(PciConfigAccessStatus::Done(value as usize)) + } + } _ => { Ok(PciConfigAccessStatus::Perform) } @@ -66,15 +76,15 @@ impl VpciDeviceHandler for StandardHandler { space.set(EndpointField::Command, value as u32); Ok(PciConfigAccessStatus::Done(value)) } - EndpointField::Bar(slot) => { - // let slot = 0; + EndpointField::Bar(0) => { + let slot = 0; if value == 0xFFFF_FFFF { dev.set_bar_size_read(slot); } else { - let zone = this_zone(); - let mut guard = zone.write(); let size = dev.get_bararr()[slot].get_size(); - guard.mmio_region_register(value as usize, size as usize, mmio_vdev_standard_handler, value); + let zone = this_zone(); + // let mut guard = zone.write(); + // guard.mmio_region_register(value as usize, size as usize, mmio_vdev_standard_handler, value); } Ok(PciConfigAccessStatus::Done(value)) @@ -86,7 +96,7 @@ impl VpciDeviceHandler for StandardHandler { } fn init_config_space(&self) -> PciConfigSpace { - let mut space = PciConfigSpace::new(); + let mut space = PciConfigSpace::default(); let default_cspace = DEFAULT_CSPACE_U32; let mut offset = 0; for &value in &default_cspace { @@ -102,6 +112,7 @@ impl VpciDeviceHandler for StandardHandler { fn init_bar(&self) -> Bar { let mut bar = Bar::default(); + bar[0].set_type(PciMemType::Mem32); // value is the paddr of the mem you allocate let size = 0x1000; bar[0].set_size(size as u64); From 9c46e3bea267743b74543e6cf9f782ac547ba5c2 Mon Sep 17 00:00:00 2001 From: wheatfox Date: Thu, 11 Dec 2025 13:07:55 +0800 Subject: [PATCH 043/109] Update memory size configuration and comment out unused PCI device entries in board.rs for loongarch64 ls3a5000 --- platform/loongarch64/ls3a5000/board.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/loongarch64/ls3a5000/board.rs b/platform/loongarch64/ls3a5000/board.rs index cdcbc1ef..25135209 100644 --- a/platform/loongarch64/ls3a5000/board.rs +++ b/platform/loongarch64/ls3a5000/board.rs @@ -166,7 +166,7 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ mem32_size: 0x0, pci_mem32_base: 0x0, mem64_base: 0x60000000, - mem64_size: 0x20000000, + mem64_size: 0x30000000, pci_mem64_base: 0x60000000, bus_range_begin: 0, bus_range_end: 0xff, @@ -191,9 +191,9 @@ pub const ROOT_PCI_DEVS: [HvPciDevConfig; 26] = [ pci_dev!(0x0, 0x4, 0x1, VpciDevType::Physical), // 00:04.1 pci_dev!(0x0, 0x5, 0x0, VpciDevType::Physical), // 00:05.0 pci_dev!(0x0, 0x5, 0x1, VpciDevType::Physical), // 00:05.1 - pci_dev!(0x0, 0x6, 0x0, VpciDevType::Physical), // 00:06.0 - pci_dev!(0x0, 0x6, 0x1, VpciDevType::Physical), // 00:06.1 - pci_dev!(0x0, 0x6, 0x2, VpciDevType::Physical), // 00:06.2 + // pci_dev!(0x0, 0x6, 0x0, VpciDevType::Physical), // 00:06.0 + // pci_dev!(0x0, 0x6, 0x1, VpciDevType::Physical), // 00:06.1 + // pci_dev!(0x0, 0x6, 0x2, VpciDevType::Physical), // 00:06.2 pci_dev!(0x0, 0x7, 0x0, VpciDevType::Physical), // 00:07.0 pci_dev!(0x0, 0x8, 0x0, VpciDevType::Physical), // 00:08.0 pci_dev!(0x0, 0x9, 0x0, VpciDevType::Physical), // 00:09.0 From c6e8828c4745b984fc369fda757a0b28f6675418 Mon Sep 17 00:00:00 2001 From: agicy <2359800311@qq.com> Date: Thu, 11 Dec 2025 02:01:15 +0000 Subject: [PATCH 044/109] feat: add hv_end address output and clarify hvisor memory layout This commit enhances the memory management of hvisor by adding hv_end address calculation and output, providing a clear definition of the hvisor memory layout and reserved memory regions. Key changes: - Enhanced documentation with comments on all memory boundary functions - Introduced `HV_EXTENDED_SIZE` constant representing the total additional memory required beyond the core static area - Exposed `HV_EXTENDED_SIZE` as a global symbol for linker accessibility - Added compilation output of (START_ADDR END_ADDR) to clearly indicate the reserved memory region for hvisor This implementation provides a clear and comprehensive view of the hvisor's memory requirements, making it easier to configure memory reservations for hvisor in different deployment scenarios. --- Makefile | 6 ++ platform/aarch64/imx8mp/linker.ld | 6 +- platform/aarch64/ok6254-c/linker.ld | 6 +- platform/aarch64/phytium-pi/linker.ld | 6 +- platform/aarch64/qemu-gicv2/linker.ld | 6 +- platform/aarch64/qemu-gicv3/linker.ld | 6 +- platform/aarch64/rk3568/linker.ld | 6 +- platform/aarch64/rk3588/linker.ld | 8 ++- platform/aarch64/zcu102/linker.ld | 6 +- platform/loongarch64/ls3a5000/linker.ld | 6 +- platform/loongarch64/ls3a6000/linker.ld | 6 +- .../riscv64/hifive-premier-p550/linker.ld | 6 +- platform/riscv64/megrez/linker.ld | 6 +- platform/riscv64/qemu-aia/linker.ld | 6 +- platform/riscv64/qemu-plic/linker.ld | 6 +- platform/x86_64/nuc14mnk/linker.ld | 6 +- platform/x86_64/qemu/linker.ld | 6 +- src/consts.rs | 70 +++++++++++++++++-- 18 files changed, 136 insertions(+), 38 deletions(-) diff --git a/Makefile b/Makefile index 6f2f21a2..47aeae91 100644 --- a/Makefile +++ b/Makefile @@ -89,6 +89,12 @@ all: clean_check gen_cargo_config $(hvisor_bin) @printf "%-10s %s\n" "RUSTC_TARGET =" "$(COLOR_BOLD)$(RUSTC_TARGET)$(COLOR_RESET)" @printf "%-10s %s\n" "BUILD_PATH =" "$(COLOR_BOLD)$(build_path)$(COLOR_RESET)" @printf "%-10s %s\n" "HVISON_BIN_SIZE =" "$(COLOR_BOLD)$(shell du -h $(hvisor_bin) | cut -f1)$(COLOR_RESET)" + @start_addr=$$(rust-nm $(hvisor_elf) | grep skernel | awk '{print $$1}'); \ + end_addr=$$(rust-nm $(hvisor_elf) | grep __hv_end | awk '{print $$1}'); \ + size=$$(printf '%016x\n' $$((0x$$end_addr - 0x$$start_addr))); \ + printf "%-10s %s\n" "START_ADDR =" "$(COLOR_BOLD)0x$$start_addr$(COLOR_RESET)"; \ + printf "%-10s %s\n" "MEM_SIZE =" "$(COLOR_BOLD)0x$$size$(COLOR_RESET)"; \ + printf "%-10s %s\n" "END_ADDR =" "$(COLOR_BOLD)0x$$end_addr$(COLOR_RESET)" @printf "%-10s %s\n" "BUILD TIME =" "$(COLOR_BOLD)$(shell date)$(COLOR_RESET)" @printf "\n" @printf "$(COLOR_GREEN)$(COLOR_BOLD)hvisor build success!$(COLOR_RESET)\n" diff --git a/platform/aarch64/imx8mp/linker.ld b/platform/aarch64/imx8mp/linker.ld index 4cd76ea3..0f5e41f3 100644 --- a/platform/aarch64/imx8mp/linker.ld +++ b/platform/aarch64/imx8mp/linker.ld @@ -45,5 +45,7 @@ SECTIONS *(.eh_frame) } . = ALIGN(4K); - __core_end = .; -} \ No newline at end of file + __core_end = .; +} + +__hv_end = __core_end + HV_EXTENDED_SIZE; diff --git a/platform/aarch64/ok6254-c/linker.ld b/platform/aarch64/ok6254-c/linker.ld index 34a79397..c3c0b34a 100644 --- a/platform/aarch64/ok6254-c/linker.ld +++ b/platform/aarch64/ok6254-c/linker.ld @@ -45,5 +45,7 @@ SECTIONS *(.eh_frame) } . = ALIGN(4K); - __core_end = .; -} \ No newline at end of file + __core_end = .; +} + +__hv_end = __core_end + HV_EXTENDED_SIZE; diff --git a/platform/aarch64/phytium-pi/linker.ld b/platform/aarch64/phytium-pi/linker.ld index 80e9014e..bc718226 100644 --- a/platform/aarch64/phytium-pi/linker.ld +++ b/platform/aarch64/phytium-pi/linker.ld @@ -45,5 +45,7 @@ SECTIONS *(.eh_frame) } . = ALIGN(4K); - __core_end = .; -} \ No newline at end of file + __core_end = .; +} + +__hv_end = __core_end + HV_EXTENDED_SIZE; diff --git a/platform/aarch64/qemu-gicv2/linker.ld b/platform/aarch64/qemu-gicv2/linker.ld index 4cd76ea3..0f5e41f3 100644 --- a/platform/aarch64/qemu-gicv2/linker.ld +++ b/platform/aarch64/qemu-gicv2/linker.ld @@ -45,5 +45,7 @@ SECTIONS *(.eh_frame) } . = ALIGN(4K); - __core_end = .; -} \ No newline at end of file + __core_end = .; +} + +__hv_end = __core_end + HV_EXTENDED_SIZE; diff --git a/platform/aarch64/qemu-gicv3/linker.ld b/platform/aarch64/qemu-gicv3/linker.ld index 4cd76ea3..0f5e41f3 100644 --- a/platform/aarch64/qemu-gicv3/linker.ld +++ b/platform/aarch64/qemu-gicv3/linker.ld @@ -45,5 +45,7 @@ SECTIONS *(.eh_frame) } . = ALIGN(4K); - __core_end = .; -} \ No newline at end of file + __core_end = .; +} + +__hv_end = __core_end + HV_EXTENDED_SIZE; diff --git a/platform/aarch64/rk3568/linker.ld b/platform/aarch64/rk3568/linker.ld index 947cb35c..db030e7d 100644 --- a/platform/aarch64/rk3568/linker.ld +++ b/platform/aarch64/rk3568/linker.ld @@ -5,7 +5,7 @@ SECTIONS { . = BASE_ADDRESS; skernel = .; - + .boot : { *(.text.boot) *(.data.boot) @@ -50,5 +50,7 @@ SECTIONS *(.eh_frame) } . = ALIGN(4K); - __core_end = .; + __core_end = .; } + +__hv_end = __core_end + HV_EXTENDED_SIZE; diff --git a/platform/aarch64/rk3588/linker.ld b/platform/aarch64/rk3588/linker.ld index 3f780a61..40a2ee2a 100644 --- a/platform/aarch64/rk3588/linker.ld +++ b/platform/aarch64/rk3588/linker.ld @@ -5,7 +5,7 @@ SECTIONS { . = BASE_ADDRESS; skernel = .; - + .boot : { *(.text.boot) *(.data.boot) @@ -50,5 +50,7 @@ SECTIONS *(.eh_frame) } . = ALIGN(4K); - __core_end = .; -} \ No newline at end of file + __core_end = .; +} + +__hv_end = __core_end + HV_EXTENDED_SIZE; diff --git a/platform/aarch64/zcu102/linker.ld b/platform/aarch64/zcu102/linker.ld index 4cd76ea3..0f5e41f3 100644 --- a/platform/aarch64/zcu102/linker.ld +++ b/platform/aarch64/zcu102/linker.ld @@ -45,5 +45,7 @@ SECTIONS *(.eh_frame) } . = ALIGN(4K); - __core_end = .; -} \ No newline at end of file + __core_end = .; +} + +__hv_end = __core_end + HV_EXTENDED_SIZE; diff --git a/platform/loongarch64/ls3a5000/linker.ld b/platform/loongarch64/ls3a5000/linker.ld index 2c1cf5a7..6ca259e4 100644 --- a/platform/loongarch64/ls3a5000/linker.ld +++ b/platform/loongarch64/ls3a5000/linker.ld @@ -55,5 +55,7 @@ SECTIONS *(.eh_frame) } . = ALIGN(4K); - __core_end = .; -} \ No newline at end of file + __core_end = .; +} + +__hv_end = __core_end + HV_EXTENDED_SIZE; diff --git a/platform/loongarch64/ls3a6000/linker.ld b/platform/loongarch64/ls3a6000/linker.ld index 2c1cf5a7..6ca259e4 100644 --- a/platform/loongarch64/ls3a6000/linker.ld +++ b/platform/loongarch64/ls3a6000/linker.ld @@ -55,5 +55,7 @@ SECTIONS *(.eh_frame) } . = ALIGN(4K); - __core_end = .; -} \ No newline at end of file + __core_end = .; +} + +__hv_end = __core_end + HV_EXTENDED_SIZE; diff --git a/platform/riscv64/hifive-premier-p550/linker.ld b/platform/riscv64/hifive-premier-p550/linker.ld index eb62b0fe..b1ec2354 100644 --- a/platform/riscv64/hifive-premier-p550/linker.ld +++ b/platform/riscv64/hifive-premier-p550/linker.ld @@ -46,5 +46,7 @@ SECTIONS *(.eh_frame) } . = ALIGN(4K); - __core_end = .; -} \ No newline at end of file + __core_end = .; +} + +__hv_end = __core_end + HV_EXTENDED_SIZE; diff --git a/platform/riscv64/megrez/linker.ld b/platform/riscv64/megrez/linker.ld index eb62b0fe..b1ec2354 100644 --- a/platform/riscv64/megrez/linker.ld +++ b/platform/riscv64/megrez/linker.ld @@ -46,5 +46,7 @@ SECTIONS *(.eh_frame) } . = ALIGN(4K); - __core_end = .; -} \ No newline at end of file + __core_end = .; +} + +__hv_end = __core_end + HV_EXTENDED_SIZE; diff --git a/platform/riscv64/qemu-aia/linker.ld b/platform/riscv64/qemu-aia/linker.ld index eb62b0fe..b1ec2354 100644 --- a/platform/riscv64/qemu-aia/linker.ld +++ b/platform/riscv64/qemu-aia/linker.ld @@ -46,5 +46,7 @@ SECTIONS *(.eh_frame) } . = ALIGN(4K); - __core_end = .; -} \ No newline at end of file + __core_end = .; +} + +__hv_end = __core_end + HV_EXTENDED_SIZE; diff --git a/platform/riscv64/qemu-plic/linker.ld b/platform/riscv64/qemu-plic/linker.ld index eb62b0fe..b1ec2354 100644 --- a/platform/riscv64/qemu-plic/linker.ld +++ b/platform/riscv64/qemu-plic/linker.ld @@ -46,5 +46,7 @@ SECTIONS *(.eh_frame) } . = ALIGN(4K); - __core_end = .; -} \ No newline at end of file + __core_end = .; +} + +__hv_end = __core_end + HV_EXTENDED_SIZE; diff --git a/platform/x86_64/nuc14mnk/linker.ld b/platform/x86_64/nuc14mnk/linker.ld index a0096daa..11ae57fd 100644 --- a/platform/x86_64/nuc14mnk/linker.ld +++ b/platform/x86_64/nuc14mnk/linker.ld @@ -49,5 +49,7 @@ SECTIONS *(.eh_frame) } . = ALIGN(4K); - __core_end = .; -} \ No newline at end of file + __core_end = .; +} + +__hv_end = __core_end + HV_EXTENDED_SIZE; diff --git a/platform/x86_64/qemu/linker.ld b/platform/x86_64/qemu/linker.ld index a0096daa..11ae57fd 100644 --- a/platform/x86_64/qemu/linker.ld +++ b/platform/x86_64/qemu/linker.ld @@ -49,5 +49,7 @@ SECTIONS *(.eh_frame) } . = ALIGN(4K); - __core_end = .; -} \ No newline at end of file + __core_end = .; +} + +__hv_end = __core_end + HV_EXTENDED_SIZE; diff --git a/src/consts.rs b/src/consts.rs index 4e5e4c29..62f93785 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -13,39 +13,73 @@ // // Authors: // + +//! This module defines core constants and memory layout for the hypervisor. +//! +//! It contains definitions for: +//! - Memory pool sizes and offsets +//! - Per-CPU data configuration +//! - Architecture-specific event codes +//! - Memory boundary access functions +//! - External assembly symbols for linker interaction + pub use crate::memory::PAGE_SIZE; use crate::{memory::addr::VirtAddr, platform::BOARD_NCPUS}; +use core::arch::global_asm; /// Size of the hypervisor heap. -pub const HV_HEAP_SIZE: usize = 1024 * 1024; // 1 MB -pub const HV_MEM_POOL_SIZE: usize = 64 * 1024 * 1024; // 64 MB +pub const HV_HEAP_SIZE: usize = 1024 * 1024; // 1 MiB + +/// Size of the hypervisor memory pool used for dynamic allocation. +pub const HV_MEM_POOL_SIZE: usize = 64 * 1024 * 1024; // 64 MiB -/// Size of the per-CPU data (stack and other CPU-local data). -pub const PER_CPU_SIZE: usize = 512 * 1024; // 512KB //may get bigger when dev +/// Size of the per-CPU data area, including stack and CPU-local data. +/// +/// This area is allocated for each CPU core and may increase in size during +/// development. +pub const PER_CPU_SIZE: usize = 512 * 1024; // 512 KiB -/// Pointer of the per-CPU data array. +/// Pointer to the beginning of the per-CPU data array. +/// +/// This array starts immediately after the core memory area ends. pub const PER_CPU_ARRAY_PTR: *mut VirtAddr = __core_end as _; +/// Represents an invalid memory address. pub const INVALID_ADDRESS: usize = usize::MAX; +/// Maximum number of supported CPU cores. +/// +/// This is determined by the board-specific configuration. pub const MAX_CPU_NUM: usize = BOARD_NCPUS; +/// Maximum number of memory zones supported. pub const MAX_ZONE_NUM: usize = 4; +/// Maximum number of spin-wait iterations before timing out. pub const MAX_WAIT_TIMES: usize = 100000000; +/// Returns the address of the hypervisor entry point. +#[allow(dead_code)] pub fn hv_start() -> VirtAddr { skernel as _ } +/// Returns the address marking the end of the core memory area. +/// +/// This is the boundary between statically linked code/data +/// and the memory allocated for per-CPU data and memory pool. pub fn core_end() -> VirtAddr { __core_end as _ } +/// Returns the address of the memory pool start. +/// +/// The memory pool follows immediately after all per-CPU data areas. pub fn mem_pool_start() -> VirtAddr { core_end() + MAX_CPU_NUM * PER_CPU_SIZE } +/// Returns the address marking the end of the entire hypervisor memory. pub fn hv_end() -> VirtAddr { mem_pool_start() + HV_MEM_POOL_SIZE } @@ -56,6 +90,32 @@ pub const IPI_EVENT_UPDATE_HART_LINE: usize = 5; pub const IPI_EVENT_SEND_IPI: usize = 6; extern "C" { + /// Entry point of the hypervisor written in assembly. + /// + /// This is the first function executed when the hypervisor boots. + #[allow(dead_code)] fn skernel(); + + /// Symbol marking the end of the core memory area. + /// + /// This is defined by the linker script and represents the boundary + /// between statically linked code/data and dynamic memory areas. + #[allow(dead_code)] fn __core_end(); } + +/// Total size of the extended memory area from the core end to the end of +/// the hypervisor memory. +/// +/// This is calculated as (MAX_CPU_NUM * PER_CPU_SIZE) + HV_MEM_POOL_SIZE and +/// represents the total additional memory required beyond the core static area. +#[allow(dead_code)] +pub const HV_EXTENDED_SIZE: usize = MAX_CPU_NUM * PER_CPU_SIZE + HV_MEM_POOL_SIZE; + +// Expose HV_EXTENDED_SIZE as a global assembly symbol for linker accessibility. +// This makes it easier for the linker script to directly reference this constant value. +global_asm!( + ".global HV_EXTENDED_SIZE", + ".equ HV_EXTENDED_SIZE, {hv_extended_size}", + hv_extended_size = const HV_EXTENDED_SIZE +); From 767820a9049dcab7e1de6a43d7e3589be91976ab Mon Sep 17 00:00:00 2001 From: wheatfox Date: Thu, 11 Dec 2025 18:41:56 +0800 Subject: [PATCH 045/109] Refactor ROOT_PCI_DEVS to use a slice reference in board.rs and clear BAR size read in pci_access.rs --- platform/loongarch64/ls3a5000/board.rs | 2 +- src/pci/pci_access.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/loongarch64/ls3a5000/board.rs b/platform/loongarch64/ls3a5000/board.rs index 25135209..a45655df 100644 --- a/platform/loongarch64/ls3a5000/board.rs +++ b/platform/loongarch64/ls3a5000/board.rs @@ -182,7 +182,7 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ /* 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: [HvPciDevConfig; 26] = [ +pub const ROOT_PCI_DEVS: &[HvPciDevConfig] = &[ pci_dev!(0x0, 0x0, 0x0, VpciDevType::Physical), // 00:00.0 pci_dev!(0x0, 0x0, 0x1, VpciDevType::Physical), // 00:00.1 pci_dev!(0x0, 0x0, 0x2, VpciDevType::Physical), // 00:00.2 diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 765858af..a22564f9 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -1654,6 +1654,7 @@ fn handle_config_space_access_direct( } 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() as usize From b35d9dcd8cb9f02f2ca9fc1836aa5e8e9053df86 Mon Sep 17 00:00:00 2001 From: dallas Date: Fri, 12 Dec 2025 16:19:59 +0800 Subject: [PATCH 046/109] update vdev bar init method --- src/pci/pci_access.rs | 22 +++++++++++++++++++--- src/pci/vpci_dev/mod.rs | 6 ++++++ src/pci/vpci_dev/standard.rs | 11 ++++++----- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 765858af..4367be75 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -214,10 +214,21 @@ impl PciMem { } } - pub fn set_type(&mut self, bar_type: PciMemType) { + pub fn set_bar_type(&mut self, bar_type: PciMemType){ self.bar_type = bar_type; } + pub fn set_prefetchable(&mut self, prefetchable: bool){ + self.prefetchable = prefetchable; + } + + pub fn config_init(&mut self, bar_type: PciMemType, prefetchable: bool, size: u64, value: u64) { + self.set_bar_type(bar_type); + self.set_prefetchable(prefetchable); + self.set_size(size); + self.set_value(value); + } + pub fn is_enabled(&self) -> bool { if self.bar_type == PciMemType::default() { false @@ -266,7 +277,9 @@ impl PciMem { val |= 0x8; } } - _ => {} + _ => { + warn!("please init bar first"); + } } self.value = val; @@ -326,7 +339,9 @@ impl PciMem { val |= 0x8; } } - _ => {} + _ => { + warn!("unkown bar type: {:#?}", self.bar_type); + } } self.virtual_value = val; @@ -1654,6 +1669,7 @@ fn handle_config_space_access_direct( } else { mmio.value = if bar.get_size_read() { let r = bar.get_size_with_flag().try_into().unwrap(); + r } else { bar.get_virtual_value() as usize diff --git a/src/pci/vpci_dev/mod.rs b/src/pci/vpci_dev/mod.rs index f4606d8c..6eed7694 100644 --- a/src/pci/vpci_dev/mod.rs +++ b/src/pci/vpci_dev/mod.rs @@ -5,6 +5,12 @@ use crate::pci::pci_access::Bar; pub mod standard; +/* + * PciConfigAccessStatus is used to return the result of the config space access + * Done(usize): the value is returned in usize + * Perform: use read_emu to read the value from the space + * Reject: the access is rejected + */ #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum PciConfigAccessStatus { Done(usize), diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index 96c59caf..46e657ae 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -47,12 +47,14 @@ impl VpciDeviceHandler for StandardHandler { let space = dev.get_space_mut(); match EndpointField::from(offset as usize, size) { EndpointField::ID => { - Ok(PciConfigAccessStatus::Done(space.get(EndpointField::ID) as usize)) + Ok(PciConfigAccessStatus::Perform) } EndpointField::Bar(0) => { - let bar = dev.get_bararr()[0]; + let slot = 0; + let bar = dev.get_bararr()[slot]; if bar.get_size_read() { let value = bar.get_size_with_flag(); + dev.clear_bar_size_read(slot); Ok(PciConfigAccessStatus::Done(value as usize)) } else { let value = bar.get_virtual_value(); @@ -111,11 +113,10 @@ impl VpciDeviceHandler for StandardHandler { } fn init_bar(&self) -> Bar { + let your_addr = 0x0; let mut bar = Bar::default(); - bar[0].set_type(PciMemType::Mem32); - // value is the paddr of the mem you allocate let size = 0x1000; - bar[0].set_size(size as u64); + bar[0].config_init(PciMemType::Mem32, false, size as u64, your_addr); bar } } From 477014b17a149daa03c05daf6997d09562a526df Mon Sep 17 00:00:00 2001 From: li041 Date: Thu, 11 Dec 2025 16:35:11 +0800 Subject: [PATCH 047/109] fix(aarch64): cpuid retrieved by `boot_cpuid_get` is corrupted in non-debug builds --- src/arch/aarch64/entry.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/arch/aarch64/entry.rs b/src/arch/aarch64/entry.rs index 45c443e4..f979c1da 100644 --- a/src/arch/aarch64/entry.rs +++ b/src/arch/aarch64/entry.rs @@ -40,7 +40,7 @@ pub unsafe extern "C" fn arch_entry() -> ! { adrp x2, __core_end // x2 = &__core_end mov x3, {per_cpu_size} // x3 = per_cpu_size - madd x4, x17, x3, x3 // x4 = cpuid * per_cpu_size + madd x4, x19, x3, x3 // x4 = cpuid * per_cpu_size add x5, x2, x4 mov sp, x5 // sp = &__core_end + (cpuid + 1) * per_cpu_size @@ -55,7 +55,7 @@ pub unsafe extern "C" fn arch_entry() -> ! { ic iallu - cmp x17, 0 + cmp x19, 0 b.ne 1f // if (cpu_id == 0) cache_invalidate(2): clear l2$ @@ -70,9 +70,9 @@ pub unsafe extern "C" fn arch_entry() -> ! { bl {mmu_enable} mov x1, x18 - mov x0, x17 + mov x0, x19 mov x18, #0 - mov x17, #0 + mov x19, #0 bl {rust_main} // x0 = cpuid, x1 = dtbaddr ", options(noreturn), @@ -94,15 +94,15 @@ pub unsafe extern "C" fn boot_cpuid_get() { core::arch::asm!( " - mrs x17, mpidr_el1 + mrs x19, mpidr_el1 ldr x2, ={mpidr_mask} - and x17, x17, x2 + and x19, x19, x2 adr x2, {mpidr_mappings} mov x4, #0 1: // search for the mpidr_el1 mapping in BOARD_MPIDR_MAPPINGS. ldr x3, [x2] - cmp x17, x3 + cmp x19, x3 b.eq 3f add x2, x2, #8 add x4, x4, #1 @@ -110,12 +110,12 @@ pub unsafe extern "C" fn boot_cpuid_get() { b.ne 1b 2: // failed to get cpuid, return an invalid id, and spin in an infinite loop. - mov x17, {inv_id} + mov x19, {inv_id} wfi b 2b 3: // found cpuid, return it. - mov x17, x4 + mov x19, x4 ret ", mpidr_mask = const cpu::MPIDR_MASK, From 0ec1dcb41d58ecf4965e21a251aa99501a3b22a2 Mon Sep 17 00:00:00 2001 From: dallas Date: Tue, 16 Dec 2025 19:56:28 +0800 Subject: [PATCH 048/109] 1.Replace VirtualPciConfigSpace with ArcRwLockVirtualPciConfigSpace and adjust the corresponding interface definition 2.The scope of locking in the PCI handler was reduced, thus resolving the deadlock issue in Vdev --- src/pci/pci_access.rs | 161 +++++++++++++++++++---------------- src/pci/pci_config.rs | 21 ++--- src/pci/pci_struct.rs | 124 +++++++++++++++++++++++++-- src/pci/pci_test.rs | 2 +- src/pci/vpci_dev/mod.rs | 18 ++-- src/pci/vpci_dev/standard.rs | 25 +++--- 6 files changed, 241 insertions(+), 110 deletions(-) diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 4367be75..3b4b3e29 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -25,7 +25,7 @@ use core::{ use super::{ config_accessors::{PciConfigMmio, PciRegion}, - pci_struct::VirtualPciConfigSpace, + pci_struct::ArcRwLockVirtualPciConfigSpace, PciConfigAddress, }; @@ -36,7 +36,7 @@ use crate::{ }, pci::{pci_config::GLOBAL_PCIE_LIST, pci_struct::BIT_LENTH}, percpu::this_zone, - zone::{Zone, is_this_root_zone, this_zone_id}, + zone::{is_this_root_zone, this_zone_id}, }; use crate::pci::vpci_dev::VpciDevType; @@ -1204,21 +1204,17 @@ impl PciBridgeHeader { impl PciBridgeHeader {} fn handle_config_space_access( - dev: &mut VirtualPciConfigSpace, + dev: ArcRwLockVirtualPciConfigSpace, mmio: &mut MMIOAccess, offset: PciConfigAddress, - gpm: &mut MemorySet, zone_id: usize, ) -> HvResult { let size = mmio.size; let value = mmio.value; let is_write = mmio.is_write; - // now the vbdf is same with bdf + let vbdf = dev.get_bdf(); - - // if vbdf.bus == 0 && vbdf.device == 5 && vbdf.function == 0 { - // info!("virt pci standard access, vbdf {:#?}, offset {:#x}, size {:#x}, is_write {:#?}", vbdf, offset, size, is_write); - // } + let dev_type = dev.get_dev_type(); if (offset as usize) >= BIT_LENTH { warn!("invalid pci offset {:#x}", offset); @@ -1230,6 +1226,7 @@ fn handle_config_space_access( match dev.access(offset, size) { false => { + // Hardware access path info!( "hw vbdf {:#?} reg 0x{:x} try {} {}", vbdf, @@ -1248,6 +1245,7 @@ fn handle_config_space_access( } } true => { + // Emulation access path info!( "emu vbdf {:#?} reg 0x{:x} try {} {}", vbdf, @@ -1259,9 +1257,10 @@ fn handle_config_space_access( String::new() } ); - match dev.get_dev_type() { + match dev_type { super::vpci_dev::VpciDevType::Physical => { - match dev.get_config_type() { + let config_type = dev.get_config_type(); + match config_type { HeaderType::Endpoint => { match EndpointField::from(offset as usize, size) { EndpointField::Bar(slot) => { @@ -1270,7 +1269,7 @@ fn handle_config_space_access( /* 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 = dev.get_bararr()[slot]; let bar_type = bar.get_type(); if bar_type != PciMemType::default() { if is_write { @@ -1308,18 +1307,6 @@ fn handle_config_space_access( * the PCIe bus, will the newly written BAR address overlap with * the old BAR addresses, potentially causing the update to fail? */ - 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(); info!( "old_vaddr {:x} new_vaddr {:x} paddr {:x}", @@ -1345,12 +1332,30 @@ fn handle_config_space_access( new_vaddr }; + let zone = this_zone(); + let mut guard = zone.write(); + let gpm = &mut guard.gpm; + + 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 + ); + } + gpm.try_insert(MemoryRegion::new_with_offset_mapper( new_vaddr as GuestPhysAddr, paddr as HostPhysAddr, bar_size as _, MemFlags::READ | MemFlags::WRITE, ))?; + /* after update gpm, mem barrier is needed */ #[cfg(target_arch = "aarch64")] @@ -1388,17 +1393,21 @@ fn handle_config_space_access( } } EndpointField::ExpansionRomBar => { - let mut rom = dev.get_rom(); + let rom = dev.get_rom(); + let rom_size_read = rom.get_size_read(); if is_write { if (mmio.value & 0xfffff800) == 0xfffff800 { - rom.set_size_read(); + // Note: get_rom() returns a copy, so we need to get it again after setting + // For now, we'll just set the flag through the dev guard + // TODO: Add a method to set rom size_read flag + warn!("ExpansionRomBar size_read not yet implemented"); } 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() { + mmio.value = if rom_size_read { dev.read_emu(offset, size).unwrap() } else { rom.get_size_with_flag().try_into().unwrap() @@ -1418,15 +1427,15 @@ fn handle_config_space_access( warn!("bridge emu rw"); } _ => { - warn!("unhanled pci type {:#?}", dev.get_config_type()); + warn!("unhanled pci type {:#?}", config_type); } } } _ => { if mmio.is_write { - super::vpci_dev::vpci_dev_write_cfg(dev.get_dev_type(), dev, offset, size, value).unwrap(); + super::vpci_dev::vpci_dev_write_cfg(dev_type, dev.clone(), offset, size, value).unwrap(); } else { - mmio.value = super::vpci_dev::vpci_dev_read_cfg(dev.get_dev_type(), dev, offset, size).unwrap() as usize; + mmio.value = super::vpci_dev::vpci_dev_read_cfg(dev_type, dev.clone(), offset, size).unwrap() as usize; } } } @@ -1463,17 +1472,18 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { // info!("mmio_vpci_handler {:#x}", mmio.address); let zone_id = this_zone_id(); let zone = this_zone(); - let mut guard = zone.write(); - let (vbus, gpm) = { - let Zone { gpm, vpci_bus, .. } = &mut *guard; - (vpci_bus, gpm) - }; - let offset = (mmio.address & 0xfff) as PciConfigAddress; let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; - if let Some(dev) = vbus.get_device_by_base(base) { - handle_config_space_access(dev, mmio, offset, gpm, zone_id)?; + let dev: Option = { + let mut guard = zone.write(); + let vbus = &mut guard.vpci_bus; + vbus.get_device_by_base(base) + }; + + + if let Some(dev) = dev { + handle_config_space_access(dev, mmio, offset, zone_id)?; } else { handle_device_not_found(mmio, offset); } @@ -1496,15 +1506,16 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { let zone_id = this_zone_id(); let zone = this_zone(); let mut guard = zone.write(); - let (vbus, gpm) = { - let Zone { gpm, vpci_bus, .. } = &mut *guard; - (vpci_bus, gpm) - }; let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; - if let Some(dev) = vbus.get_device_by_base(base) { - handle_config_space_access(dev, mmio, offset, gpm, zone_id)?; + let dev: Option = { + let vbus = &mut guard.vpci_bus; + vbus.get_device_by_base(base) + }; + + if let Some(dev) = dev { + handle_config_space_access(dev, mmio, offset, zone_id)?; } else { handle_device_not_found(mmio, offset); } @@ -1514,10 +1525,9 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { } fn handle_config_space_access_direct( - dev: &mut VirtualPciConfigSpace, + dev: ArcRwLockVirtualPciConfigSpace, mmio: &mut MMIOAccess, offset: PciConfigAddress, - gpm: &mut MemorySet, zone_id: usize, is_root: bool, is_dev_belong_to_zone: bool, @@ -1585,7 +1595,7 @@ fn handle_config_space_access_direct( } } EndpointField::Bar(slot) => { - let bar = &mut dev.get_bararr()[slot]; + let bar = dev.get_bararr()[slot]; let bar_type = bar.get_type(); if bar_type != PciMemType::default() { if is_write { @@ -1607,12 +1617,6 @@ fn handle_config_space_access_direct( (value as u64) & !0xf } }; - if !gpm.try_delete(old_vaddr.try_into().unwrap()).is_ok() { - warn!( - "delete bar {}: can not found 0x{:x}", - slot, old_vaddr - ); - } dev.set_bar_virtual_value(slot, new_vaddr); if bar_type == PciMemType::Mem64High { @@ -1641,6 +1645,17 @@ fn handle_config_space_access_direct( } else { new_vaddr as u64 }; + + let zone = this_zone(); + let mut guard = zone.write(); + let gpm = &mut guard.gpm; + + if !gpm.try_delete(old_vaddr.try_into().unwrap()).is_ok() { + warn!( + "delete bar {}: can not found 0x{:x}", + slot, old_vaddr + ); + } gpm.try_insert(MemoryRegion::new_with_offset_mapper( new_vaddr as GuestPhysAddr, paddr as HostPhysAddr, @@ -1680,17 +1695,19 @@ fn handle_config_space_access_direct( } } EndpointField::ExpansionRomBar => { - let mut rom = dev.get_rom(); + let rom = dev.get_rom(); + let rom_size_read = rom.get_size_read(); if is_write { if (mmio.value & 0xfffff800) == 0xfffff800 { - rom.set_size_read(); + // TODO: Add method to set rom size_read flag + warn!("ExpansionRomBar size_read not yet implemented for direct handler"); } 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() { + mmio.value = if rom_size_read { dev.read_emu(offset, size).unwrap() } else { rom.get_size_with_flag().try_into().unwrap() @@ -1713,9 +1730,9 @@ fn handle_config_space_access_direct( } _ => { if mmio.is_write { - super::vpci_dev::vpci_dev_write_cfg(dev.get_dev_type(), dev, offset, size, value).unwrap(); + super::vpci_dev::vpci_dev_write_cfg(dev.get_dev_type(), dev.clone(), offset, size, value).unwrap(); } else { - mmio.value = super::vpci_dev::vpci_dev_read_cfg(dev.get_dev_type(), dev, offset, size).unwrap() as usize; + mmio.value = super::vpci_dev::vpci_dev_read_cfg(dev.get_dev_type(), dev.clone(), offset, size).unwrap() as usize; } } } @@ -1734,28 +1751,28 @@ fn handle_config_space_access_direct( pub fn mmio_vpci_direct_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { let zone_id = this_zone_id(); let zone = this_zone(); - let mut guard = zone.write(); - let (vbus, gpm) = { - let Zone { gpm, vpci_bus, .. } = &mut *guard; - (vpci_bus, gpm) - }; - let offset = (mmio.address & 0xfff) as PciConfigAddress; let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; let mut is_dev_belong_to_zone = false; - let mut global_pcie_list = GLOBAL_PCIE_LIST.lock(); - let dev = match vbus.get_device_by_base(base) { - Some(dev) => { + + let dev: Option = { + let mut guard = zone.write(); + let vbus = &mut guard.vpci_bus; + if let Some(dev) = vbus.get_device_by_base(base) { is_dev_belong_to_zone = true; Some(dev) + } else { + drop(guard); + let global_pcie_list = GLOBAL_PCIE_LIST.lock(); + global_pcie_list + .values() + .find(|dev| dev.read().get_base() == base) + .cloned() } - None => global_pcie_list - .values_mut() - .find(|dev| dev.get_base() == base) }; - let mut dev = match dev { + let dev = match dev { Some(dev) => dev, None => { handle_device_not_found(mmio, offset); @@ -1765,7 +1782,7 @@ pub fn mmio_vpci_direct_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult let is_root = is_this_root_zone(); - handle_config_space_access_direct(&mut dev, mmio, offset, gpm, zone_id, is_root, is_dev_belong_to_zone); + handle_config_space_access_direct(dev, mmio, offset, zone_id, is_root, is_dev_belong_to_zone); Ok(()) } \ No newline at end of file diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 1fd03804..64ecc1fc 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -20,7 +20,7 @@ use crate::{ arch::iommu::iommu_add_device, config::{HvPciConfig, HvPciDevConfig, CONFIG_MAX_PCI_DEV, CONFIG_PCI_BUS_MAXNUM}, error::HvResult, - pci::pci_struct::{Bdf, VirtualPciConfigSpace}, + pci::pci_struct::{Bdf, ArcRwLockVirtualPciConfigSpace}, zone::Zone, }; @@ -40,7 +40,7 @@ use crate::{memory::mmio_generic_handler, pci::pci_access::mmio_vpci_handler_dbi #[cfg(feature = "loongarch64_pcie")] use crate::pci::pci_access::mmio_vpci_direct_handler; -pub static GLOBAL_PCIE_LIST: Lazy>> = Lazy::new(|| { +pub static GLOBAL_PCIE_LIST: Lazy>> = Lazy::new(|| { let m = BTreeMap::new(); Mutex::new(m) }); @@ -138,7 +138,7 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { info!("begin enumerate {:#?}", e); for node in e { info!("node {:#?}", node); - GLOBAL_PCIE_LIST.lock().insert(node.get_bdf(), node); + GLOBAL_PCIE_LIST.lock().insert(node.get_bdf(), ArcRwLockVirtualPciConfigSpace::new(node)); } } info!("hvisor pci init done \n{:#?}", GLOBAL_PCIE_LIST); @@ -173,14 +173,15 @@ impl Zone { iommu_add_device(zone_id, dev_config.bdf as _, iommu_pt_addr); } if let Some(dev) = guard.get(&bdf) { - if bdf.is_host_bridge(dev.get_host_bdf().bus()) { - let mut vdev = dev.clone(); + if bdf.is_host_bridge(dev.read().get_host_bdf().bus()) { + let mut vdev = dev.read().clone(); vdev.set_vbdf(vbdf); self.vpci_bus.insert(vbdf, vdev); } else { - let mut vdev = guard.remove(&bdf).unwrap(); - vdev.set_vbdf(vbdf); - self.vpci_bus.insert(vbdf, vdev); + let vdev = guard.remove(&bdf).unwrap(); + let mut vdev_inner = vdev.read().clone(); + vdev_inner.set_vbdf(vbdf); + self.vpci_bus.insert(vbdf, vdev_inner); } } else { // warn!("can not find dev {:#?}", bdf); @@ -228,8 +229,8 @@ impl Zone { self.mmio_region_register( rootcomplex_config.ecam_base as usize, rootcomplex_config.ecam_size as usize, - // mmio_vpci_handler, - mmio_vpci_direct_handler, + mmio_vpci_handler, + // mmio_vpci_direct_handler, rootcomplex_config.ecam_base as usize, ); } diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 8b94d7fe..0800e730 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -17,6 +17,7 @@ use alloc::{collections::btree_map::BTreeMap, sync::Arc, vec::Vec}; use bit_field::BitField; use bitvec::{array::BitArray, order::Lsb0, BitArr}; use core::{cmp::Ordering, fmt::Debug, ops::Range, str::FromStr}; +use spin::RwLock; use super::{ config_accessors::{PciConfigAccessor, PciConfigMmio}, @@ -337,6 +338,113 @@ pub struct VirtualPciConfigSpace { dev_type: VpciDevType, } +#[derive(Clone)] +pub struct ArcRwLockVirtualPciConfigSpace(Arc>); + +impl ArcRwLockVirtualPciConfigSpace { + pub fn new(dev: VirtualPciConfigSpace) -> Self { + Self(Arc::new(RwLock::new(dev))) + } + + pub fn inner(&self) -> &Arc> { + &self.0 + } + + pub fn access(&self, offset: PciConfigAddress, size: usize) -> bool { + self.0.read().access(offset, size) + } + + pub fn get_bdf(&self) -> Bdf { + self.0.read().get_bdf() + } + + pub fn get_dev_type(&self) -> VpciDevType { + self.0.read().get_dev_type() + } + + pub fn get_config_type(&self) -> HeaderType { + self.0.read().get_config_type() + } + + pub fn get_bararr(&self) -> Bar { + self.0.read().get_bararr() + } + + pub fn get_rom(&self) -> PciMem { + self.0.read().get_rom() + } + + pub fn read_emu(&self, offset: PciConfigAddress, size: usize) -> HvResult { + self.0.write().read_emu(offset, size) + } + + pub fn read_emu64(&self, offset: PciConfigAddress) -> HvResult { + self.0.write().read_emu64(offset) + } + + pub fn write_emu(&self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { + self.0.write().write_emu(offset, size, value) + } + + pub fn read_hw(&self, offset: PciConfigAddress, size: usize) -> HvResult { + self.0.write().read_hw(offset, size) + } + + pub fn write_hw(&self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { + self.0.write().write_hw(offset, size, value) + } + + pub fn set_bar_size_read(&self, slot: usize) { + self.0.write().set_bar_size_read(slot); + } + + pub fn clear_bar_size_read(&self, slot: usize) { + self.0.write().clear_bar_size_read(slot); + } + + pub fn set_bar_virtual_value(&self, slot: usize, value: u64) { + self.0.write().set_bar_virtual_value(slot, value); + } + + pub fn set_bar_value(&self, slot: usize, value: u64) { + self.0.write().set_bar_value(slot, value); + } + + pub fn read(&self) -> spin::RwLockReadGuard<'_, VirtualPciConfigSpace> { + self.0.read() + } + + pub fn write(&self) -> spin::RwLockWriteGuard<'_, VirtualPciConfigSpace> { + self.0.write() + } +} + +impl Debug for ArcRwLockVirtualPciConfigSpace { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.0.read().fmt(f) + } +} + +// impl core::ops::Deref for ArcRwLockVirtualPciConfigSpace { +// type Target = Arc>; + +// fn deref(&self) -> &Self::Target { +// &self.0 +// } +// } + +// impl From for ArcRwLockVirtualPciConfigSpace { +// fn from(dev: VirtualPciConfigSpace) -> Self { +// Self::new(dev) +// } +// } + +// impl From>> for ArcRwLockVirtualPciConfigSpace { +// fn from(arc: Arc>) -> Self { +// Self(arc) +// } +// } + impl VirtualPciConfigSpace { /* false: some bits ro */ pub fn writable(&self, offset: PciConfigAddress, size: usize) -> bool { @@ -1109,7 +1217,7 @@ impl RootComplex { #[derive(Debug)] pub struct VirtualRootComplex { - devs: BTreeMap, + devs: BTreeMap, base_to_bdf: BTreeMap, } @@ -1125,22 +1233,22 @@ impl VirtualRootComplex { &mut self, bdf: Bdf, dev: VirtualPciConfigSpace, - ) -> Option { + ) -> Option { let base = dev.get_base(); info!("pci insert base {:#x} to bdf {:#?}", base, bdf); self.base_to_bdf.insert(base, bdf); - self.devs.insert(bdf, dev) + self.devs.insert(bdf, ArcRwLockVirtualPciConfigSpace::new(dev)) } - pub fn devs(&mut self) -> &mut BTreeMap { + pub fn devs(&mut self) -> &mut BTreeMap { &mut self.devs } - pub fn get(&self, bdf: &Bdf) -> Option<&VirtualPciConfigSpace> { + pub fn get(&self, bdf: &Bdf) -> Option<&ArcRwLockVirtualPciConfigSpace> { self.devs.get(bdf) } - pub fn get_mut(&mut self, bdf: &Bdf) -> Option<&mut VirtualPciConfigSpace> { + pub fn get_mut(&mut self, bdf: &Bdf) -> Option<&mut ArcRwLockVirtualPciConfigSpace> { self.devs.get_mut(bdf) } @@ -1148,9 +1256,9 @@ impl VirtualRootComplex { pub fn get_device_by_base( &mut self, base: PciConfigAddress, - ) -> Option<&mut VirtualPciConfigSpace> { + ) -> Option { let bdf = self.base_to_bdf.get(&base).copied()?; - self.devs.get_mut(&bdf) + self.devs.get(&bdf).cloned() } } diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs index a61bb521..45545a5f 100644 --- a/src/pci/pci_test.rs +++ b/src/pci/pci_test.rs @@ -104,7 +104,7 @@ pub fn ecam_pcie_guest_test() { let bdf = Bdf::from_str("0000:00:01.0").unwrap(); // Get base from VirtualPciConfigSpace and add offset let address = if let Some(vdev) = vbus.get(&bdf) { - vdev.get_base() + 0x24 + vdev.read().get_base() + 0x24 } else { warn!("can not find dev {:#?} for test", bdf); 0 diff --git a/src/pci/vpci_dev/mod.rs b/src/pci/vpci_dev/mod.rs index 6eed7694..abfc500c 100644 --- a/src/pci/vpci_dev/mod.rs +++ b/src/pci/vpci_dev/mod.rs @@ -1,4 +1,4 @@ -use crate::pci::pci_struct::{PciConfigSpace, VirtualPciConfigSpace}; +use crate::pci::pci_struct::{PciConfigSpace, ArcRwLockVirtualPciConfigSpace}; use crate::pci::PciConfigAddress; use crate::error::HvResult; use crate::pci::pci_access::Bar; @@ -28,8 +28,8 @@ pub enum VpciDevType { } pub trait VpciDeviceHandler: Sync + Send { - fn read_cfg(&self, dev: &mut VirtualPciConfigSpace, offset: PciConfigAddress, size: usize) -> HvResult; - fn write_cfg(&self, dev: &mut VirtualPciConfigSpace, offset: PciConfigAddress, size: usize, value: usize) -> HvResult; + fn read_cfg(&self, dev: ArcRwLockVirtualPciConfigSpace, offset: PciConfigAddress, size: usize) -> HvResult; + fn write_cfg(&self, dev: ArcRwLockVirtualPciConfigSpace, offset: PciConfigAddress, size: usize, value: usize) -> HvResult; fn init_config_space(&self) -> PciConfigSpace; fn init_bar(&self) -> Bar; } @@ -52,7 +52,7 @@ pub(crate) fn get_handler(dev_type: VpciDevType) -> Option<&'static dyn VpciDevi pub(super) fn vpci_dev_read_cfg( dev_type: VpciDevType, - node: &mut VirtualPciConfigSpace, + node: ArcRwLockVirtualPciConfigSpace, offset: PciConfigAddress, size: usize ) -> HvResult { @@ -63,7 +63,7 @@ pub(super) fn vpci_dev_read_cfg( } _ => { if let Some(handler) = get_handler(dev_type) { - match handler.read_cfg(node, offset, size) { + match handler.read_cfg(node.clone(), offset, size) { Ok(status) => { match status { PciConfigAccessStatus::Done(value) => { @@ -72,7 +72,7 @@ pub(super) fn vpci_dev_read_cfg( PciConfigAccessStatus::Perform => { // warn!("vpci_dev_read_cfg: perform, offset {:#x}, size {:#x}", offset, size); // warn!("vpci_dev_read_cfg: node {:#?}", node.space); - let r = node.read_emu(offset, size).unwrap(); + let r = node.write().read_emu(offset, size).unwrap(); // warn!("vpci_dev_read_cfg: perform result {:#x}", r); Ok(r) } @@ -97,7 +97,7 @@ pub(super) fn vpci_dev_read_cfg( pub(super) fn vpci_dev_write_cfg( dev_type: VpciDevType, - node: &mut VirtualPciConfigSpace, + node: ArcRwLockVirtualPciConfigSpace, offset: PciConfigAddress, size: usize, value: usize @@ -109,7 +109,7 @@ pub(super) fn vpci_dev_write_cfg( } _ => { if let Some(handler) = get_handler(dev_type) { - match handler.write_cfg(node, offset, size, value) { + match handler.write_cfg(node.clone(), offset, size, value) { Ok(status) => { match status { PciConfigAccessStatus::Done(_) => { @@ -117,7 +117,7 @@ pub(super) fn vpci_dev_write_cfg( } PciConfigAccessStatus::Perform => { warn!("vpci_dev_write_cfg: perform"); - node.write_emu(offset, size, value) + node.write().write_emu(offset, size, value) } PciConfigAccessStatus::Reject => { warn!("vpci_dev_write_cfg: operation rejected"); diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index 46e657ae..ac9811c8 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -4,7 +4,7 @@ use crate::pci::pci_access::{EndpointField, Bar}; use crate::pci::PciConfigAddress; use super::{PciConfigAccessStatus, VpciDeviceHandler}; // use crate::memory::frame::Frame; -use crate::pci::pci_struct::VirtualPciConfigSpace; +use crate::pci::pci_struct::ArcRwLockVirtualPciConfigSpace; use crate::percpu::this_zone; use crate::memory::MMIOAccess; use crate::pci::pci_access::PciMemType; @@ -42,19 +42,21 @@ pub(crate) const DEFAULT_CSPACE_U32: [u32; STANDARD_CFG_SIZE / 4] = { pub struct StandardHandler; impl VpciDeviceHandler for StandardHandler { - fn read_cfg(&self, dev: &mut VirtualPciConfigSpace, offset: PciConfigAddress, size: usize) -> HvResult { + fn read_cfg(&self, dev: ArcRwLockVirtualPciConfigSpace, offset: PciConfigAddress, size: usize) -> HvResult { info!("virt pci standard read_cfg, offset {:#x}, size {:#x}", offset, size); - let space = dev.get_space_mut(); + let dev_guard = dev.read(); match EndpointField::from(offset as usize, size) { EndpointField::ID => { + warn!("virt pci standard read_cfg, id {:#x}", offset); Ok(PciConfigAccessStatus::Perform) } EndpointField::Bar(0) => { let slot = 0; - let bar = dev.get_bararr()[slot]; + let bar = dev_guard.get_bararr()[slot]; if bar.get_size_read() { let value = bar.get_size_with_flag(); - dev.clear_bar_size_read(slot); + drop(dev_guard); + dev.write().clear_bar_size_read(slot); Ok(PciConfigAccessStatus::Done(value as usize)) } else { let value = bar.get_virtual_value(); @@ -67,26 +69,29 @@ impl VpciDeviceHandler for StandardHandler { } } - fn write_cfg(&self, dev: &mut VirtualPciConfigSpace, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { + fn write_cfg(&self, dev: ArcRwLockVirtualPciConfigSpace, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { info!("virt pci standard write_cfg, offset {:#x}, size {:#x}, value {:#x}", offset, size, value); - let mut space = dev.get_space_mut(); match EndpointField::from(offset as usize, size) { EndpointField::ID => { Ok(PciConfigAccessStatus::Reject) } EndpointField::Command => { + let mut dev_guard = dev.write(); + let space = dev_guard.get_space_mut(); space.set(EndpointField::Command, value as u32); Ok(PciConfigAccessStatus::Done(value)) } EndpointField::Bar(0) => { let slot = 0; + let bar_size = dev.get_bararr()[slot].get_size(); + if value == 0xFFFF_FFFF { dev.set_bar_size_read(slot); } else { - let size = dev.get_bararr()[slot].get_size(); let zone = this_zone(); - // let mut guard = zone.write(); - // guard.mmio_region_register(value as usize, size as usize, mmio_vdev_standard_handler, value); + let mut guard = zone.write(); + warn!("virtual pci standard write_cfg, register mmio region {:#x}, size {:#x}", value, bar_size); + guard.mmio_region_register(value as usize, bar_size as usize, mmio_vdev_standard_handler, value); } Ok(PciConfigAccessStatus::Done(value)) From 81728297e1453fb98518656bb506fff568be0b59 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 17 Dec 2025 01:35:26 +0800 Subject: [PATCH 049/109] Fixes the issue of multiple device access in DWC PCIe --- platform/aarch64/rk3568/board.rs | 12 +- src/config.rs | 30 ++--- src/pci/config_accessors/dwc.rs | 78 ++++++++--- src/pci/config_accessors/dwc_atu.rs | 48 +++++-- src/pci/config_accessors/mod.rs | 8 ++ src/pci/pci_access.rs | 195 +++++++++++++++++++++++++++- src/pci/pci_config.rs | 36 ++++- src/pci/pci_struct.rs | 27 +++- src/zone.rs | 81 ++++++++++++ 9 files changed, 436 insertions(+), 79 deletions(-) diff --git a/platform/aarch64/rk3568/board.rs b/platform/aarch64/rk3568/board.rs index e343d632..cfabf7b2 100644 --- a/platform/aarch64/rk3568/board.rs +++ b/platform/aarch64/rk3568/board.rs @@ -344,16 +344,8 @@ pub const ROOT_DWC_ATU_CONFIG: &[HvDwcAtuConfig] = &[ apb_size: 0x10000, cfg_base: 0xf2000000, cfg_size: 0x80000*2, - cfg0_atu_index: 0, - cfg0_atu_type: 4, - cfg1_atu_index: 0, - cfg1_atu_type: 4, - mem32_atu_index: 1, - mem32_atu_type: 0, - mem64_atu_index: 2, - mem64_atu_type: 0, - io_atu_index: 3, - io_atu_type: 2, + io_cfg_atu_shared: 0, + pci_addr_base: 0xf2000000, }, ]; diff --git a/src/config.rs b/src/config.rs index bbb68d51..d19fae53 100644 --- a/src/config.rs +++ b/src/config.rs @@ -236,8 +236,8 @@ impl Debug for HvPciDevConfig { #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct HvDwcAtuConfig { - /// ECAM (Enhanced Configuration Access Mechanism) base address - /// This is used to match with HvPciConfig::ecam_base + // ECAM (Enhanced Configuration Access Mechanism) base address + // This is used to match with HvPciConfig::ecam_base pub ecam_base: u64, pub dbi_base: u64, pub dbi_size: u64, @@ -245,16 +245,10 @@ pub struct HvDwcAtuConfig { pub apb_size: u64, pub cfg_base: u64, pub cfg_size: u64, - pub cfg0_atu_index: usize, - pub cfg0_atu_type: u32, - pub cfg1_atu_index: usize, - pub cfg1_atu_type: u32, - pub mem32_atu_index: usize, - pub mem32_atu_type: u32, - pub mem64_atu_index: usize, - pub mem64_atu_type: u32, - pub io_atu_index: usize, - pub io_atu_type: u32, + // set 1 if io base use atu0, when hvisor need set mmio for io + // normally, when num-viewport less than 4, io_cfg_atu_shared is 1, otherwise is 0 + pub io_cfg_atu_shared: u64, + pub pci_addr_base: u64, } impl HvDwcAtuConfig { @@ -270,16 +264,8 @@ impl HvDwcAtuConfig { apb_size: 0, cfg_base: 0, cfg_size: 0, - cfg0_atu_index: u32::MAX as usize, - cfg0_atu_type: 4, // ATU_TYPE_CFG0 - cfg1_atu_index: u32::MAX as usize, - cfg1_atu_type: 5, // ATU_TYPE_CFG1 - mem32_atu_index: u32::MAX as usize, - mem32_atu_type: 0, // ATU_TYPE_MEM - mem64_atu_index: u32::MAX as usize, - mem64_atu_type: 0, // ATU_TYPE_MEM - io_atu_index: u32::MAX as usize, - io_atu_type: 2, // ATU_TYPE_IO + io_cfg_atu_shared: 0, + pci_addr_base: 0, } } } diff --git a/src/pci/config_accessors/dwc.rs b/src/pci/config_accessors/dwc.rs index 3681bd91..d0dfe357 100644 --- a/src/pci/config_accessors/dwc.rs +++ b/src/pci/config_accessors/dwc.rs @@ -18,7 +18,7 @@ use alloc::sync::Arc; use bit_field::BitField; use super::{ - dwc_atu::{AtuConfig, AtuUnroll, ATU_UNUSED}, + dwc_atu::{AtuConfig, AtuType, AtuUnroll, ATU_UNUSED}, PciConfigAccessor, PciConfigMmio, PciRegion, PciRegionMmio, }; @@ -47,7 +47,7 @@ impl RootComplex { #[derive(Debug, Clone, Copy)] pub struct DwcConfigRegion { pub atu_index: usize, - pub atu_type: u32, + pub atu_type: AtuType, pub base: PciConfigAddress, pub size: u64, } @@ -55,6 +55,12 @@ pub struct DwcConfigRegion { #[derive(Debug)] pub struct DwcConfigRegionBackend(PciRegionMmio); +impl DwcConfigRegionBackend { + pub fn new(region: PciRegionMmio) -> Self { + Self(region) + } +} + impl PciRWBase for DwcConfigRegionBackend { fn backend(&self) -> &dyn PciRegion { &self.0 @@ -85,19 +91,21 @@ impl DwcConfigAccessor { let dbi = DwcConfigRegion { atu_index: ATU_UNUSED as usize, - atu_type: 0, + atu_type: AtuType::Unused, base: dbi_base, size: dbi_size, }; + + /* actually we only use atu0 to init dwc pcie */ let cfg0 = DwcConfigRegion { - atu_index: atu_config.cfg0_atu_index, - atu_type: atu_config.cfg0_atu_type, + atu_index: 0, + atu_type: AtuType::Cfg0, base: cfg0_base, size: cfg_size_half, }; let cfg1 = DwcConfigRegion { - atu_index: atu_config.cfg1_atu_index, - atu_type: atu_config.cfg1_atu_type, + atu_index: 0, + atu_type: AtuType::Cfg1, base: cfg1_base, size: cfg_size_half, }; @@ -113,42 +121,74 @@ impl DwcConfigAccessor { } impl PciConfigAccessor for DwcConfigAccessor { + fn get_pci_addr_base( + &self, + bdf: Bdf, + parent_bus: u8, + pci_addr_base: Option, + ) -> HvResult { + let bus = bdf.bus() as PciConfigAddress; + let device = bdf.device() as PciConfigAddress; + let function = bdf.function() as PciConfigAddress; + + let pci_addr_base = if let Some(pci_addr_base) = pci_addr_base { + // pci_addr_base + 0 + } else { + return hv_result_err!(EINVAL, "PCI address base is not set"); + }; + + let pci_addr = pci_addr_base + (bus << 24) + (device << 19) + (function << 16); + info!("pci_addr {:#x}", pci_addr); + let address = if bus == self.root_bus.into() { + // Root bus: use DBI directly, no ATU configuration needed + self.dbi.base + } else { + pci_addr + }; + + Ok(address) + } + fn get_physical_address( &self, bdf: Bdf, offset: PciConfigAddress, parent_bus: u8, + pci_addr_base: Option, ) -> HvResult { - let bus = bdf.bus(); + let bus = bdf.bus() as PciConfigAddress; let device = bdf.device() as PciConfigAddress; let function = bdf.function() as PciConfigAddress; warn!("parent_bus {} self.root_bus {}", parent_bus, self.root_bus); + let pci_addr_base = if let Some(pci_addr_base) = pci_addr_base { + pci_addr_base + } else { + return hv_result_err!(EINVAL, "PCI address base is not set"); + }; - // Calculate address without bus field (bus is handled by different config regions) - // Address format: (device << 15) + (function << 12) + offset - let offset_without_bus = (device << 15) + (function << 12) + offset; + let pci_addr = pci_addr_base + (bus << 24) + (device << 19) + (function << 16); - let address = if bus == self.root_bus { + let address = if bus == self.root_bus.into() { // Root bus: use DBI directly, no ATU configuration needed - self.dbi.base + offset_without_bus - } else if parent_bus == self.root_bus { + self.dbi.base + } else if parent_bus == self.root_bus.into() { if self.cfg0.atu_index == ATU_UNUSED as usize { return hv_result_err!(EINVAL, "CFG0 ATU is not configured"); } - let atu_config = AtuConfig::new_with_dwc_config_region(&self.cfg0); + let atu_config = AtuConfig::new_with_dwc_config_region(&self.cfg0, AtuType::Cfg0, pci_addr); AtuUnroll::dw_pcie_prog_outbound_atu_unroll(self.dbi_backend.as_ref(), &atu_config)?; - self.cfg0.base + offset_without_bus + self.cfg0.base } else { - //TODO: cfg1 not implemented yet because it's not used in the current board if self.cfg1.atu_index == ATU_UNUSED as usize { return hv_result_err!(EINVAL, "CFG1 ATU is not configured"); } - let atu_config = AtuConfig::new_with_dwc_config_region(&self.cfg1); + let atu_config = AtuConfig::new_with_dwc_config_region(&self.cfg1, AtuType::Cfg1, pci_addr); AtuUnroll::dw_pcie_prog_outbound_atu_unroll(self.dbi_backend.as_ref(), &atu_config)?; - self.cfg1.base + offset_without_bus + self.cfg1.base }; Ok(address) diff --git a/src/pci/config_accessors/dwc_atu.rs b/src/pci/config_accessors/dwc_atu.rs index b3951b25..a478adeb 100644 --- a/src/pci/config_accessors/dwc_atu.rs +++ b/src/pci/config_accessors/dwc_atu.rs @@ -15,6 +15,7 @@ // use super::dwc::DwcConfigRegion; +use core::{fmt, fmt::Debug}; use crate::{ error::{HvErrorNum::*, HvResult}, @@ -32,31 +33,54 @@ pub const PCIE_ATU_UNR_LIMIT: usize = 0x10; pub const PCIE_ATU_UNR_LOWER_TARGET: usize = 0x14; pub const PCIE_ATU_UNR_UPPER_TARGET: usize = 0x18; -// ATU region type constants -pub const ATU_TYPE_CFG0: u32 = 0x4; // CFG0 Type -pub const ATU_TYPE_CFG1: u32 = 0x5; // CFG1 Type -pub const ATU_TYPE_MEM: u32 = 0x0; // Memory Type -pub const ATU_TYPE_IO: u32 = 0x2; // IO Type - // ATU enable bit pub const ATU_ENABLE_BIT: u32 = 0x80000000; // the flag is for dbi just pub const ATU_UNUSED: u32 = u32::MAX; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Default)] +pub enum AtuType { + #[default] + Unused = 0xFF, + Cfg0 = 0x4, + Cfg1 = 0x5, + Mem = 0x0, + Io = 0x2, +} + +impl AtuType { + pub fn from_u8(value: u8) -> Self { + match value { + 0x0 => AtuType::Mem, + 0x2 => AtuType::Io, + 0x4 => AtuType::Cfg0, + 0x5 => AtuType::Cfg1, + 0xFF => AtuType::Unused, + _ => AtuType::Unused, + } + } +} + +#[derive(Clone, Copy, Default)] pub struct AtuConfig { pub index: usize, - pub atu_type: u32, + pub atu_type: AtuType, pub cpu_base: PciConfigAddress, pub cpu_limit: PciConfigAddress, pub pci_target: PciConfigAddress, } +impl Debug for AtuConfig { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "AtuConfig {{ index: {},\n atu_type: {:?},\n cpu_base: {:#x},\n cpu_limit: {:#x},\n pci_target: {:#x} }}", self.index, self.atu_type, self.cpu_base, self.cpu_limit, self.pci_target) + } +} + impl AtuConfig { pub fn new( index: usize, - atu_type: u32, + atu_type: AtuType, cpu_base: PciConfigAddress, cpu_size: PciConfigAddress, pci_target: PciConfigAddress, @@ -71,13 +95,13 @@ impl AtuConfig { } } - pub fn new_with_dwc_config_region(config_region: &DwcConfigRegion) -> Self { + pub fn new_with_dwc_config_region(config_region: &DwcConfigRegion, atu_type: AtuType, pci_addr: PciConfigAddress) -> Self { Self::new( config_region.atu_index, - config_region.atu_type, + atu_type, config_region.base, config_region.size, - config_region.base, + pci_addr, ) } } diff --git a/src/pci/config_accessors/mod.rs b/src/pci/config_accessors/mod.rs index 5b3ee5ef..4eea9b69 100644 --- a/src/pci/config_accessors/mod.rs +++ b/src/pci/config_accessors/mod.rs @@ -125,11 +125,19 @@ impl PciRegion for PciConfigMmio { } pub trait PciConfigAccessor: Send + Sync + core::fmt::Debug { + fn get_pci_addr_base( + &self, + bdf: Bdf, + parent_bus: u8, + pci_addr_base: Option, + ) -> HvResult; + fn get_physical_address( &self, bdf: Bdf, offset: PciConfigAddress, _parent_bus: u8, + pci_addr_base: Option, ) -> HvResult; fn skip_device(&self, _bdf: Bdf) -> bool { diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 7627f7ce..553882d4 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -39,6 +39,20 @@ use crate::{ zone::{is_this_root_zone, this_zone_id}, }; +#[cfg(feature = "dwc_pcie")] +use crate::pci::config_accessors::{ + dwc_atu::{ + AtuConfig, AtuType, ATU_BASE, ATU_REGION_SIZE, + PCIE_ATU_UNR_REGION_CTRL1, PCIE_ATU_UNR_REGION_CTRL2, + PCIE_ATU_UNR_LOWER_BASE, PCIE_ATU_UNR_UPPER_BASE, + PCIE_ATU_UNR_LIMIT, PCIE_ATU_UNR_LOWER_TARGET, PCIE_ATU_UNR_UPPER_TARGET, + ATU_ENABLE_BIT, + AtuUnroll, + }, + dwc::DwcConfigRegionBackend, + PciRegionMmio, +}; + use crate::pci::vpci_dev::VpciDevType; pub type VendorId = u16; @@ -1490,18 +1504,193 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { Ok(()) } +#[cfg(feature = "dwc_pcie")] +pub fn mmio_dwc_io_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { + { + let zone = this_zone(); + let guard = zone.read(); + + let atu_config = guard.atu_configs.get_atu_by_io_base(_base as PciConfigAddress) + .and_then(|atu| { + guard.atu_configs.get_ecam_by_io_base(_base as PciConfigAddress) + .map(|ecam| (*atu, ecam)) + }); + + drop(guard); + + if let Some((atu, ecam_base)) = atu_config { + use crate::platform; + if let Some(extend_config) = platform::ROOT_DWC_ATU_CONFIG + .iter() + .find(|cfg| cfg.ecam_base == ecam_base as u64) + { + // Create DBI backend + let dbi_base = extend_config.dbi_base as PciConfigAddress; + let dbi_size = extend_config.dbi_size; + let dbi_region = PciRegionMmio::new(dbi_base, dbi_size); + let dbi_backend = DwcConfigRegionBackend::new(dbi_region); + + // Call AtuUnroll to program the ATU + AtuUnroll::dw_pcie_prog_outbound_atu_unroll(&dbi_backend, &atu)?; + } + mmio_perform_access(atu.pci_target as usize, mmio); + } else { + warn!("No ATU config yet, do nothing"); + } + } + Ok(()) +} +#[cfg(feature = "dwc_pcie")] +pub fn mmio_dwc_cfg_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { + info!("mmio_dwc_cfg_handler {:#x}", mmio.address + _base); + let zone = this_zone(); + let guard = zone.read(); + + let atu_config = guard.atu_configs.get_atu_by_cfg_base(_base as PciConfigAddress) + .and_then(|atu| { + guard.atu_configs.get_ecam_by_cfg_base(_base as PciConfigAddress) + .map(|ecam| (*atu, ecam)) + }); + + drop(guard); + + if let Some((atu, ecam_base)) = atu_config { + // Get dbi_base from platform config (usually dbi_base == ecam_base) + use crate::platform; + if let Some(extend_config) = platform::ROOT_DWC_ATU_CONFIG + .iter() + .find(|cfg| cfg.ecam_base == ecam_base as u64) + { + // Create DBI backend + let dbi_base = extend_config.dbi_base as PciConfigAddress; + let dbi_size = extend_config.dbi_size; + let dbi_region = PciRegionMmio::new(dbi_base, dbi_size); + let dbi_backend = DwcConfigRegionBackend::new(dbi_region); + + warn!("atu config {:#?}", atu); + + // Call AtuUnroll to program the ATU + AtuUnroll::dw_pcie_prog_outbound_atu_unroll(&dbi_backend, &atu)?; + } + + let offset = (mmio.address & 0xfff) as PciConfigAddress; + let zone_id = this_zone_id(); + + let base = mmio.address as PciConfigAddress - offset + atu.pci_target; + + let dev: Option = { + let zone = this_zone(); + let mut guard = zone.write(); + let vbus = &mut guard.vpci_bus; + vbus.get_device_by_base(base) + }; + + if let Some(dev) = dev { + handle_config_space_access(dev, mmio, offset, zone_id)?; + } else { + handle_device_not_found(mmio, offset); + } + } else { + warn!("No ATU config yet, do nothing"); + } + Ok(()) +} + +#[cfg(feature = "dwc_pcie")] pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { - // info!("mmio_vpci_handler_dbi {:#x}", mmio.address); + info!("mmio_vpci_handler_dbi {:#x}", mmio.address); - if mmio.address >= 0x300000 - /* ATU base */ + if mmio.address >= ATU_BASE && mmio.address < ATU_BASE + ATU_REGION_SIZE { + // ATU0 registers (0x300000 - 0x300200) + let zone = this_zone(); + let mut guard = zone.write(); + let ecam_base = _base; + let atu_offset = mmio.address - ATU_BASE; + + warn!("set atu0 register {:#X} value {:#X}", atu_offset, mmio.value); + + let mut atu = guard.atu_configs.get_atu_by_ecam_mut(ecam_base).unwrap(); + + info!("atu config write {:#?}", atu); + + if mmio.is_write { + if mmio.size == 4 { + match atu_offset { + PCIE_ATU_UNR_REGION_CTRL1 => { + info!("set atu0 region ctrl1 value {:#X}", mmio.value); + atu.atu_type = AtuType::from_u8((mmio.value & 0xff) as u8); + } + PCIE_ATU_UNR_REGION_CTRL2 => { + // Enable bit is written here, but we just track it + // The actual enable is handled by the driver + } + PCIE_ATU_UNR_LOWER_BASE => { + info!("set atu0 lower base value {:#X}", mmio.value); + atu.cpu_base = (atu.cpu_base & !0xffffffff) | (mmio.value as PciConfigAddress); + } + PCIE_ATU_UNR_UPPER_BASE => { + info!("set atu0 upper base value {:#X}", mmio.value); + atu.cpu_base = (atu.cpu_base & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32); + } + PCIE_ATU_UNR_LIMIT => { + info!("set atu0 limit value {:#X}", mmio.value); + atu.cpu_limit = (atu.cpu_limit & !0xffffffff) | (mmio.value as PciConfigAddress); + } + PCIE_ATU_UNR_LOWER_TARGET => { + info!("set atu0 lower target value {:#X}", mmio.value); + atu.pci_target = (atu.pci_target & !0xffffffff) | (mmio.value as PciConfigAddress); + } + PCIE_ATU_UNR_UPPER_TARGET => { + info!("set atu0 upper target value {:#X}", mmio.value); + atu.pci_target = (atu.pci_target & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32); + } + _ => { + warn!("invalid atu0 write size {:#x}", mmio.size); + } + } + } else { + warn!("invalid atu0 read size {:#x}", mmio.size); + } + } else { + // Read from virtual ATU + warn!("read atu0 {:#x}", atu_offset); + match atu_offset { + PCIE_ATU_UNR_REGION_CTRL1 => { + mmio.value = atu.atu_type as usize; + } + PCIE_ATU_UNR_REGION_CTRL2 => { + mmio.value = ATU_ENABLE_BIT as usize; + } + PCIE_ATU_UNR_LOWER_BASE => { + mmio.value = (atu.cpu_base & 0xffffffff) as usize; + } + PCIE_ATU_UNR_UPPER_BASE => { + mmio.value = ((atu.cpu_base >> 32) & 0xffffffff) as usize; + } + PCIE_ATU_UNR_LIMIT => { + mmio.value = (atu.cpu_limit & 0xffffffff) as usize; + } + PCIE_ATU_UNR_LOWER_TARGET => { + mmio.value = (atu.pci_target & 0xffffffff) as usize; + } + PCIE_ATU_UNR_UPPER_TARGET => { + mmio.value = ((atu.pci_target >> 32) & 0xffffffff) as usize; + } + _ => { + mmio_perform_access(_base, mmio); + } + } + } + } else if mmio.address > ATU_BASE + ATU_REGION_SIZE { + // other atu mmio_perform_access(_base, mmio); } else if mmio.address >= BIT_LENTH { // dbi read mmio_perform_access(_base, mmio); } else { + warn!("mmio_vpci_handler_dbi read {:#x}", mmio.address); let offset = (mmio.address & 0xfff) as PciConfigAddress; let zone_id = this_zone_id(); let zone = this_zone(); diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 64ecc1fc..898ddba6 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -32,10 +32,9 @@ use crate::pci::vpci_dev::{VpciDevType, get_handler}; feature = "dwc_pcie", feature = "loongarch64_pcie" ))] -use crate::pci::{mem_alloc::BaseAllocator, pci_struct::RootComplex, pci_access::mmio_vpci_handler}; - +use crate::pci::{mem_alloc::BaseAllocator, pci_struct::RootComplex, pci_access::mmio_vpci_handler, PciConfigAddress}; #[cfg(feature = "dwc_pcie")] -use crate::{memory::mmio_generic_handler, pci::pci_access::mmio_vpci_handler_dbi, platform}; +use crate::{platform, memory::mmio_generic_handler, pci::{config_accessors::dwc_atu::{AtuConfig, AtuType}, pci_access::{mmio_vpci_handler_dbi, mmio_dwc_io_handler, mmio_dwc_cfg_handler}}}; #[cfg(feature = "loongarch64_pcie")] use crate::pci::pci_access::mmio_vpci_direct_handler; @@ -134,7 +133,19 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { }; let range = rootcomplex_config.bus_range_begin as usize..rootcomplex_config.bus_range_end as usize; - let e = rootcomplex.enumerate(Some(range), allocator_opt); + + #[cfg(feature = "dwc_pcie")] + let pci_addr_base: Option = { + let ecam_base = rootcomplex_config.ecam_base; + platform::ROOT_DWC_ATU_CONFIG + .iter() + .find(|atu_cfg| atu_cfg.ecam_base == ecam_base) + .map(|atu_cfg| atu_cfg.pci_addr_base as PciConfigAddress) + }; + + #[cfg(not(feature = "dwc_pcie"))] + let pci_addr_base: Option = None; + let e = rootcomplex.enumerate(Some(range), allocator_opt, pci_addr_base); info!("begin enumerate {:#?}", e); for node in e { info!("node {:#?}", node); @@ -263,7 +274,7 @@ impl Zone { self.mmio_region_register( cfg0_base as usize, cfg_size_half as usize, - mmio_vpci_handler, + mmio_dwc_cfg_handler, cfg0_base as usize, ); } @@ -273,10 +284,23 @@ impl Zone { self.mmio_region_register( cfg1_base as usize, cfg_size_half as usize, - mmio_vpci_handler, + mmio_dwc_cfg_handler, cfg1_base as usize, ); } + + if extend_config.pci_addr_base != 0 { + self.mmio_region_register( + rootcomplex_config.io_base as usize, + rootcomplex_config.io_size as usize, + mmio_dwc_io_handler, + rootcomplex_config.io_base as usize, + ); + } + + self.atu_configs.insert_atu(rootcomplex_config.ecam_base as usize, AtuConfig::default()); + self.atu_configs.insert_cfg_base_mapping(extend_config.cfg_base as PciConfigAddress, rootcomplex_config.ecam_base as usize); + self.atu_configs.insert_io_base_mapping(rootcomplex_config.io_base as PciConfigAddress, rootcomplex_config.ecam_base as usize); } } #[cfg(feature = "loongarch64_pcie")] diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 0800e730..27df4e47 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -780,13 +780,21 @@ pub struct PciIterator { is_mulitple_function: bool, is_finish: bool, accessor: Arc, + pci_addr_base: Option, } impl PciIterator { + fn get_pci_addr_base(&self, parent_bus: u8, bdf: Bdf) -> PciConfigAddress { + match self.accessor.get_pci_addr_base(bdf, parent_bus, self.pci_addr_base) { + Ok(addr) => addr, + Err(_) => 0x0, + } + } + fn address(&self, parent_bus: u8, bdf: Bdf) -> PciConfigAddress { let offset = 0; - match self.accessor.get_physical_address(bdf, offset, parent_bus) { + match self.accessor.get_physical_address(bdf, offset, parent_bus, self.pci_addr_base) { Ok(addr) => addr, Err(_) => 0x0, } @@ -815,7 +823,9 @@ impl PciIterator { let bdf = Bdf::new(bus, device, function); let address = self.address(parent_bus, bdf); - info!("get node {:x} {:#?}", address, bdf); + let pci_addr_base = self.get_pci_addr_base(parent_bus, bdf); + // let pci_addr_base = address; + info!("get node {:x}->{:x} {:#?}", pci_addr_base, address, bdf); let region = PciConfigMmio::new(address, CONFIG_LENTH); let pci_header = PciConfigHeader::new_with_region(region); @@ -870,7 +880,7 @@ impl PciIterator { info!("get node bar mem init end {:#?}", bararr); let ep = Arc::new(ep); - let mut node = VirtualPciConfigSpace::endpoint(bdf, address, ep, bararr, rom, class, (device_id, vender_id)); + let mut node = VirtualPciConfigSpace::endpoint(bdf, pci_addr_base, ep, bararr, rom, class, (device_id, vender_id)); let _ = node.capability_enumerate(); @@ -886,7 +896,7 @@ impl PciIterator { Self::bar_mem_init(bridge.bar_limit().into(), &mut self.allocator, &mut bridge); let bridge = Arc::new(bridge); - let mut node = VirtualPciConfigSpace::bridge(bdf, address, bridge, bararr, rom, class, (device_id, vender_id)); + let mut node = VirtualPciConfigSpace::bridge(bdf, pci_addr_base, bridge, bararr, rom, class, (device_id, vender_id)); let _ = node.capability_enumerate(); @@ -895,7 +905,7 @@ impl PciIterator { _ => { warn!("unknown type"); let pci_header = Arc::new(pci_header); - Some(VirtualPciConfigSpace::unknown(bdf, address, pci_header, (device_id, vender_id))) + Some(VirtualPciConfigSpace::unknown(bdf, pci_addr_base, pci_header, (device_id, vender_id))) } } } @@ -1191,6 +1201,7 @@ impl RootComplex { &mut self, range: Option>, bar_alloc: Option, + pci_addr_base: Option, ) -> PciIterator { let mmio_base = self.mmio_base; let range = range.unwrap_or_else(|| 0..0x100); @@ -1203,6 +1214,7 @@ impl RootComplex { is_mulitple_function: false, is_finish: false, accessor: self.accessor.clone(), // accessor to iterator + pci_addr_base, } } @@ -1210,8 +1222,9 @@ impl RootComplex { &mut self, range: Option>, bar_alloc: Option, + pci_addr_base: Option, ) -> PciIterator { - self.__enumerate(range, bar_alloc) + self.__enumerate(range, bar_alloc, pci_addr_base) } } @@ -1538,7 +1551,7 @@ impl VirtualPciConfigSpace { pub fn has_secondary_link(&self) -> bool { match self.config_type { HeaderType::PciBridge => { - // Find PciExpress capability + // // Find PciExpress capability // for (_, capability) in &self.capabilities { // if let PciCapability::PciExpress(PciCapabilityRegion { offset, .. }) = capability { // // Read PCIe Capability Register at offset + 0x00 diff --git a/src/zone.rs b/src/zone.rs index 9d6a5f03..1c9ec13f 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -20,6 +20,11 @@ use crate::consts::{INVALID_ADDRESS, MAX_CPU_NUM}; use crate::pci::pci_struct::VirtualRootComplex; use spin::RwLock; +#[cfg(feature = "dwc_pcie")] +use alloc::collections::btree_map::BTreeMap; +#[cfg(feature = "dwc_pcie")] +use crate::pci::{config_accessors::dwc_atu::AtuConfig, PciConfigAddress}; + use crate::arch::mm::new_s2_memory_set; use crate::arch::s2pt::Stage2PageTable; use crate::config::{HvZoneConfig, CONFIG_NAME_MAXLEN}; @@ -30,6 +35,78 @@ use crate::memory::{MMIOConfig, MMIOHandler, MMIORegion, MemorySet}; use crate::percpu::{get_cpu_data, this_zone, CpuSet}; use core::panic; +#[cfg(feature = "dwc_pcie")] +#[derive(Debug)] +pub struct VirtualAtuConfigs { + ecam_to_atu: BTreeMap, + io_base_to_ecam: BTreeMap, + cfg_base_to_ecam: BTreeMap, +} + +#[cfg(feature = "dwc_pcie")] +impl VirtualAtuConfigs { + pub fn new() -> Self { + Self { + ecam_to_atu: BTreeMap::new(), + io_base_to_ecam: BTreeMap::new(), + cfg_base_to_ecam: BTreeMap::new(), + } + } + + pub fn get_atu_by_ecam(&self, ecam_base: usize) -> Option<&AtuConfig> { + self.ecam_to_atu.get(&ecam_base) + } + + pub fn get_atu_by_ecam_mut(&mut self, ecam_base: usize) -> Option<&mut AtuConfig> { + self.ecam_to_atu.get_mut(&ecam_base) + } + + pub fn insert_atu(&mut self, ecam_base: usize, atu: AtuConfig) -> Option { + self.ecam_to_atu.insert(ecam_base, atu) + } + + pub fn get_or_insert_atu(&mut self, ecam_base: usize, f: F) -> &mut AtuConfig + where + F: FnOnce() -> AtuConfig, + { + self.ecam_to_atu.entry(ecam_base).or_insert_with(f) + } + + pub fn get_atu_by_io_base(&self, io_base: PciConfigAddress) -> Option<&AtuConfig> { + let ecam = self.io_base_to_ecam.get(&io_base); + if let Some(ecam) = ecam { + self.get_atu_by_ecam(*ecam) + } else { + None + } + } + + pub fn get_ecam_by_io_base(&self, io_base: PciConfigAddress) -> Option { + self.io_base_to_ecam.get(&io_base).copied() + } + + pub fn insert_io_base_mapping(&mut self, io_base: PciConfigAddress, ecam_base: usize) { + self.io_base_to_ecam.insert(io_base, ecam_base); + } + + pub fn get_atu_by_cfg_base(&self, cfg_base: PciConfigAddress) -> Option<&AtuConfig> { + let ecam = self.cfg_base_to_ecam.get(&cfg_base); + if let Some(ecam) = ecam { + self.get_atu_by_ecam(*ecam) + } else { + None + } + } + + pub fn get_ecam_by_cfg_base(&self, cfg_base: PciConfigAddress) -> Option { + self.cfg_base_to_ecam.get(&cfg_base).copied() + } + + pub fn insert_cfg_base_mapping(&mut self, cfg_base: PciConfigAddress, ecam_base: usize) { + self.cfg_base_to_ecam.insert(cfg_base, ecam_base); + } +} + pub struct Zone { pub name: [u8; CONFIG_NAME_MAXLEN], pub id: usize, @@ -41,6 +118,8 @@ pub struct Zone { pub iommu_pt: Option>, pub is_err: bool, pub vpci_bus: VirtualRootComplex, + #[cfg(feature = "dwc_pcie")] + pub atu_configs: VirtualAtuConfigs, } impl Zone { @@ -60,6 +139,8 @@ impl Zone { }, is_err: false, vpci_bus: VirtualRootComplex::new(), + #[cfg(feature = "dwc_pcie")] + atu_configs: VirtualAtuConfigs::new(), } } From cba14d0c450f0c73eaaf118df7f993c4ede2a8a5 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 17 Dec 2025 09:40:49 +0800 Subject: [PATCH 050/109] remove pci_addr_base --- platform/aarch64/rk3568/board.rs | 1 - src/config.rs | 2 -- src/pci/config_accessors/dwc.rs | 18 ++----------- src/pci/config_accessors/ecam.rs | 9 +++++++ src/pci/config_accessors/loongarch64.rs | 34 +++++++++++++++++++++++++ src/pci/config_accessors/mod.rs | 2 -- src/pci/pci_config.rs | 17 +++---------- src/pci/pci_struct.rs | 22 +++++++--------- 8 files changed, 57 insertions(+), 48 deletions(-) diff --git a/platform/aarch64/rk3568/board.rs b/platform/aarch64/rk3568/board.rs index cfabf7b2..d50da8dc 100644 --- a/platform/aarch64/rk3568/board.rs +++ b/platform/aarch64/rk3568/board.rs @@ -345,7 +345,6 @@ pub const ROOT_DWC_ATU_CONFIG: &[HvDwcAtuConfig] = &[ cfg_base: 0xf2000000, cfg_size: 0x80000*2, io_cfg_atu_shared: 0, - pci_addr_base: 0xf2000000, }, ]; diff --git a/src/config.rs b/src/config.rs index d19fae53..851c4cdd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -248,7 +248,6 @@ pub struct HvDwcAtuConfig { // set 1 if io base use atu0, when hvisor need set mmio for io // normally, when num-viewport less than 4, io_cfg_atu_shared is 1, otherwise is 0 pub io_cfg_atu_shared: u64, - pub pci_addr_base: u64, } impl HvDwcAtuConfig { @@ -265,7 +264,6 @@ impl HvDwcAtuConfig { cfg_base: 0, cfg_size: 0, io_cfg_atu_shared: 0, - pci_addr_base: 0, } } } diff --git a/src/pci/config_accessors/dwc.rs b/src/pci/config_accessors/dwc.rs index d0dfe357..d61345ec 100644 --- a/src/pci/config_accessors/dwc.rs +++ b/src/pci/config_accessors/dwc.rs @@ -125,20 +125,12 @@ impl PciConfigAccessor for DwcConfigAccessor { &self, bdf: Bdf, parent_bus: u8, - pci_addr_base: Option, ) -> HvResult { let bus = bdf.bus() as PciConfigAddress; let device = bdf.device() as PciConfigAddress; let function = bdf.function() as PciConfigAddress; - let pci_addr_base = if let Some(pci_addr_base) = pci_addr_base { - // pci_addr_base - 0 - } else { - return hv_result_err!(EINVAL, "PCI address base is not set"); - }; - - let pci_addr = pci_addr_base + (bus << 24) + (device << 19) + (function << 16); + let pci_addr = (bus << 24) + (device << 19) + (function << 16); info!("pci_addr {:#x}", pci_addr); let address = if bus == self.root_bus.into() { // Root bus: use DBI directly, no ATU configuration needed @@ -155,20 +147,14 @@ impl PciConfigAccessor for DwcConfigAccessor { bdf: Bdf, offset: PciConfigAddress, parent_bus: u8, - pci_addr_base: Option, ) -> HvResult { let bus = bdf.bus() as PciConfigAddress; let device = bdf.device() as PciConfigAddress; let function = bdf.function() as PciConfigAddress; warn!("parent_bus {} self.root_bus {}", parent_bus, self.root_bus); - let pci_addr_base = if let Some(pci_addr_base) = pci_addr_base { - pci_addr_base - } else { - return hv_result_err!(EINVAL, "PCI address base is not set"); - }; - let pci_addr = pci_addr_base + (bus << 24) + (device << 19) + (function << 16); + let pci_addr = (bus << 24) + (device << 19) + (function << 16); let address = if bus == self.root_bus.into() { // Root bus: use DBI directly, no ATU configuration needed diff --git a/src/pci/config_accessors/ecam.rs b/src/pci/config_accessors/ecam.rs index 76794958..2545bc0e 100644 --- a/src/pci/config_accessors/ecam.rs +++ b/src/pci/config_accessors/ecam.rs @@ -50,6 +50,15 @@ impl EcamConfigAccessor { } impl PciConfigAccessor for EcamConfigAccessor { + fn get_pci_addr_base(&self, bdf: Bdf, parent_bus: u8) -> HvResult { + let bus = bdf.bus() as PciConfigAddress; + let device = bdf.device() as PciConfigAddress; + let function = bdf.function() as PciConfigAddress; + + let address = self.ecam_base + (bus << 20) + (device << 15) + (function << 12); + Ok(address) + } + fn get_physical_address( &self, bdf: Bdf, diff --git a/src/pci/config_accessors/loongarch64.rs b/src/pci/config_accessors/loongarch64.rs index 7516d7f6..284d2f8b 100644 --- a/src/pci/config_accessors/loongarch64.rs +++ b/src/pci/config_accessors/loongarch64.rs @@ -60,6 +60,40 @@ impl LoongArchConfigAccessor { } impl PciConfigAccessor for LoongArchConfigAccessor { + fn get_pci_addr_base(&self, bdf: Bdf, parent_bus: u8) -> HvResult { + let bus = bdf.bus() as PciConfigAddress; + let device = bdf.device() as PciConfigAddress; + let function = bdf.function() as PciConfigAddress; + let offset = 0; + + // Extract Offset[11:8] (bits 11-8 of offset) for bits 31-28 + let offset_high = (offset >> 8) & 0xf; + // Extract Offset[7:0] (bits 7-0 of offset) for bits 7-0 + let offset_low = offset & 0xff; + + let address = if bus == self.root_bus as PciConfigAddress { + // Type 0 format (Root Bus): + // Bits 31-28: Offset[11:8] + // Bits 27-16: Reserved (0) + // Bits 15-11: Device Number + // Bits 10-8: Function Number + // Bits 7-0: Offset[7:0] + self.cfg0 + + ((offset_high << 24) | (device << 11) | (function << 8) | offset_low) + } else { + // Type 1 format (Other Bus): + // Bits 31-28: Offset[11:8] + // Bits 27-16: Bus Number + // Bits 15-11: Device Number + // Bits 10-8: Function Number + // Bits 7-0: Offset[7:0] + self.cfg1 + + ((offset_high << 24) | (bus << 16) | (device << 11) | (function << 8) | offset_low) + }; + + Ok(address) + } + fn get_physical_address( &self, bdf: Bdf, diff --git a/src/pci/config_accessors/mod.rs b/src/pci/config_accessors/mod.rs index 4eea9b69..47488cf7 100644 --- a/src/pci/config_accessors/mod.rs +++ b/src/pci/config_accessors/mod.rs @@ -129,7 +129,6 @@ pub trait PciConfigAccessor: Send + Sync + core::fmt::Debug { &self, bdf: Bdf, parent_bus: u8, - pci_addr_base: Option, ) -> HvResult; fn get_physical_address( @@ -137,7 +136,6 @@ pub trait PciConfigAccessor: Send + Sync + core::fmt::Debug { bdf: Bdf, offset: PciConfigAddress, _parent_bus: u8, - pci_addr_base: Option, ) -> HvResult; fn skip_device(&self, _bdf: Bdf) -> bool { diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 898ddba6..14ccc3b6 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -25,7 +25,7 @@ use crate::{ }; #[cfg(feature = "ecam_pcie")] -use crate::pci::vpci_dev::{VpciDevType, get_handler}; +use crate::pci::{vpci_dev::{VpciDevType, get_handler}, pci_struct::VirtualPciConfigSpace}; #[cfg(any( feature = "ecam_pcie", @@ -134,18 +134,7 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { let range = rootcomplex_config.bus_range_begin as usize..rootcomplex_config.bus_range_end as usize; - #[cfg(feature = "dwc_pcie")] - let pci_addr_base: Option = { - let ecam_base = rootcomplex_config.ecam_base; - platform::ROOT_DWC_ATU_CONFIG - .iter() - .find(|atu_cfg| atu_cfg.ecam_base == ecam_base) - .map(|atu_cfg| atu_cfg.pci_addr_base as PciConfigAddress) - }; - - #[cfg(not(feature = "dwc_pcie"))] - let pci_addr_base: Option = None; - let e = rootcomplex.enumerate(Some(range), allocator_opt, pci_addr_base); + let e = rootcomplex.enumerate(Some(range), allocator_opt); info!("begin enumerate {:#?}", e); for node in e { info!("node {:#?}", node); @@ -289,7 +278,7 @@ impl Zone { ); } - if extend_config.pci_addr_base != 0 { + if extend_config.io_cfg_atu_shared != 0 { self.mmio_region_register( rootcomplex_config.io_base as usize, rootcomplex_config.io_size as usize, diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 27df4e47..77968b75 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -780,12 +780,11 @@ pub struct PciIterator { is_mulitple_function: bool, is_finish: bool, accessor: Arc, - pci_addr_base: Option, } impl PciIterator { fn get_pci_addr_base(&self, parent_bus: u8, bdf: Bdf) -> PciConfigAddress { - match self.accessor.get_pci_addr_base(bdf, parent_bus, self.pci_addr_base) { + match self.accessor.get_pci_addr_base(bdf, parent_bus) { Ok(addr) => addr, Err(_) => 0x0, } @@ -794,7 +793,7 @@ impl PciIterator { fn address(&self, parent_bus: u8, bdf: Bdf) -> PciConfigAddress { let offset = 0; - match self.accessor.get_physical_address(bdf, offset, parent_bus, self.pci_addr_base) { + match self.accessor.get_physical_address(bdf, offset, parent_bus) { Ok(addr) => addr, Err(_) => 0x0, } @@ -824,8 +823,7 @@ impl PciIterator { let address = self.address(parent_bus, bdf); let pci_addr_base = self.get_pci_addr_base(parent_bus, bdf); - // let pci_addr_base = address; - info!("get node {:x}->{:x} {:#?}", pci_addr_base, address, bdf); + info!("get node {:x} {:#?}", address, bdf); let region = PciConfigMmio::new(address, CONFIG_LENTH); let pci_header = PciConfigHeader::new_with_region(region); @@ -1201,7 +1199,6 @@ impl RootComplex { &mut self, range: Option>, bar_alloc: Option, - pci_addr_base: Option, ) -> PciIterator { let mmio_base = self.mmio_base; let range = range.unwrap_or_else(|| 0..0x100); @@ -1214,7 +1211,6 @@ impl RootComplex { is_mulitple_function: false, is_finish: false, accessor: self.accessor.clone(), // accessor to iterator - pci_addr_base, } } @@ -1222,9 +1218,8 @@ impl RootComplex { &mut self, range: Option>, bar_alloc: Option, - pci_addr_base: Option, ) -> PciIterator { - self.__enumerate(range, bar_alloc, pci_addr_base) + self.__enumerate(range, bar_alloc) } } @@ -1551,7 +1546,8 @@ impl VirtualPciConfigSpace { pub fn has_secondary_link(&self) -> bool { match self.config_type { HeaderType::PciBridge => { - // // Find PciExpress capability + // Find PciExpress capability + // warn!("has_secondary_link {:#?}", self.capabilities); // for (_, capability) in &self.capabilities { // if let PciCapability::PciExpress(PciCapabilityRegion { offset, .. }) = capability { // // Read PCIe Capability Register at offset + 0x00 @@ -1569,9 +1565,9 @@ impl VirtualPciConfigSpace { // } // } // false - #[cfg(feature = "dwc_pcie")] - return true; - #[cfg(not(feature = "dwc_pcie"))] + // #[cfg(feature = "dwc_pcie")] + // return true; + // #[cfg(not(feature = "dwc_pcie"))] return false; } _ => false, From 3d1bb0f436e37c32b523af3e2bd8fd3df0552c96 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 18 Dec 2025 01:56:05 +0800 Subject: [PATCH 051/109] 1.check size when delete bar region in gpm,no more accidental deletion of other regions 2.direct_handler not change gpm for root 3.try fix error updating for bar --- platform/aarch64/rk3568/board.rs | 36 ++--- platform/loongarch64/ls3a5000/board.rs | 24 +-- src/arch/loongarch64/zone.rs | 2 +- src/main.rs | 5 + src/memory/mm.rs | 32 +++- src/pci/pci_access.rs | 207 +++++++++++++++++-------- src/pci/pci_struct.rs | 4 +- src/pci/pci_test.rs | 121 +++++++++++++-- 8 files changed, 311 insertions(+), 120 deletions(-) diff --git a/platform/aarch64/rk3568/board.rs b/platform/aarch64/rk3568/board.rs index d50da8dc..6128c453 100644 --- a/platform/aarch64/rk3568/board.rs +++ b/platform/aarch64/rk3568/board.rs @@ -69,24 +69,24 @@ pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ // virtual_start: 0xfe270000, // size: 0x10000, // }, //pcie - // HvConfigMemoryRegion { - // mem_type: MEM_TYPE_IO, - // physical_start: 0xf2000000, - // virtual_start: 0xf2000000, - // size: 0x100000, - // }, //pcie - // HvConfigMemoryRegion { - // mem_type: MEM_TYPE_IO, - // physical_start: 0xf2100000, - // virtual_start: 0xf2100000, - // size: 0x100000, - // }, //pcie - // HvConfigMemoryRegion { - // mem_type: MEM_TYPE_IO, - // physical_start: 0xf2200000, - // virtual_start: 0xf2200000, - // size: 0x1e00000, - // }, //pcie + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xf2000000, + virtual_start: 0xf2000000, + size: 0x100000, + }, //pcie + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xf2100000, + virtual_start: 0xf2100000, + size: 0x100000, + }, //pcie + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xf2200000, + virtual_start: 0xf2200000, + size: 0x1e00000, + }, //pcie HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x340000000, diff --git a/platform/loongarch64/ls3a5000/board.rs b/platform/loongarch64/ls3a5000/board.rs index a45655df..1c17d74a 100644 --- a/platform/loongarch64/ls3a5000/board.rs +++ b/platform/loongarch64/ls3a5000/board.rs @@ -110,18 +110,18 @@ pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ // virtual_start: 0xfe_0000_0000, // size: 0x20000000, // }, // pci config space (HT) - // HvConfigMemoryRegion { - // mem_type: MEM_TYPE_IO, - // physical_start: 0x18408000, - // virtual_start: 0x18408000, - // size: 0x00008000, - // }, // pci io resource - // HvConfigMemoryRegion { - // mem_type: MEM_TYPE_IO, - // physical_start: 0x60000000, - // virtual_start: 0x60000000, - // size: 0x20000000, - // }, // pci mem resource + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x18408000, + virtual_start: 0x18408000, + size: 0x00008000, + }, // pci io resource + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x60000000, + virtual_start: 0x60000000, + size: 0x20000000, + }, // pci mem resource HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x1001_0000, diff --git a/src/arch/loongarch64/zone.rs b/src/arch/loongarch64/zone.rs index 618d6dfd..86dfafbc 100644 --- a/src/arch/loongarch64/zone.rs +++ b/src/arch/loongarch64/zone.rs @@ -680,7 +680,7 @@ impl Zone { size as _, MemFlags::READ | MemFlags::WRITE | MemFlags::IO, ))?; - self.gpm.delete(vaddr as GuestPhysAddr) + self.gpm.delete(vaddr as GuestPhysAddr, size) } pub fn arch_zone_pre_configuration(&mut self, config: &HvZoneConfig) -> HvResult { diff --git a/src/main.rs b/src/main.rs index 7e231c67..7565d5ce 100644 --- a/src/main.rs +++ b/src/main.rs @@ -150,6 +150,11 @@ fn primary_init_early() { let zone = zone_create(root_config).unwrap(); add_zone(zone); } + + // crate::pci::pci_test::pcie_test(); + // crate::pci::pci_test::pcie_guest_init(); + // crate::pci::pci_test::ecam_pcie_guest_test(); + INIT_EARLY_OK.store(1, Ordering::Release); } diff --git a/src/memory/mm.rs b/src/memory/mm.rs index b9088477..d25ff4c2 100644 --- a/src/memory/mm.rs +++ b/src/memory/mm.rs @@ -130,7 +130,7 @@ where pub fn try_insert(&mut self, region: MemoryRegion) -> HvResult { if !self.test_free_area(®ion) { warn!( - "MemoryRegion overlapped in MemorySet: {:#x?}\n{:#x?}", + "try insert MemoryRegion overlapped in MemorySet: {:#x?}\n{:#x?}", region, self ); return Ok(()); @@ -140,10 +140,22 @@ where Ok(()) } - /// Find and remove memory region which starts from `start`. - pub fn delete(&mut self, start: PT::VA) -> HvResult { + /// Find and remove memory region which starts from `start` and `size` + pub fn delete(&mut self, start: PT::VA, size: usize) -> HvResult { if let Entry::Occupied(e) = self.regions.entry(start) { - self.pt.unmap(e.get())?; + let region = e.get(); + if region.size != size { + return hv_result_err!( + EINVAL, + format!( + "MemorySet::delete(): size mismatch at {:#x?}, expected {:#x?}, got {:#x?}", + start.into(), + size, + region.size + ) + ); + } + self.pt.unmap(region)?; e.remove(); Ok(()) } else { @@ -157,11 +169,15 @@ where } } - pub fn try_delete(&mut self, start: PT::VA) -> HvResult { + pub fn try_delete(&mut self, start: PT::VA, size: usize) -> HvResult { if let Entry::Occupied(e) = self.regions.entry(start) { - self.pt.unmap(e.get())?; - e.remove(); - Ok(()) + let region = e.get(); + if region.size == size { + self.delete(start, size) + } else { + warn!("try delete MemoryRegion size mismatch at {:#x?}, expected {:#x?}, got {:#x?}", start.into(), size, region.size); + Err(hv_err!(ENOMEM)) + } } else { Err(hv_err!(ENOMEM)) } diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 553882d4..09f23caa 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -1331,6 +1331,18 @@ fn handle_config_space_access( if bar_type == PciMemType::Mem64High { dev.set_bar_virtual_value(slot - 1, new_vaddr); } + + // // Sync virtual_value back to space after processing (adding flags) + // let bar = dev.get_bararr()[slot]; + // let virtual_value = bar.get_virtual_value(); + // let bar_offset = (0x10 + slot * 4) as PciConfigAddress; + // let _ = dev.write_emu(bar_offset, 4, virtual_value as usize); + // if bar_type == PciMemType::Mem64High { + // let bar_low = dev.get_bararr()[slot - 1]; + // let virtual_value_low = bar_low.get_virtual_value(); + // let bar_offset_low = (0x10 + (slot - 1) * 4) as PciConfigAddress; + // let _ = dev.write_emu(bar_offset_low, 4, virtual_value_low as usize); + // } let bar_size = if crate::memory::addr::is_aligned( bar.get_size() as usize, @@ -1351,7 +1363,7 @@ fn handle_config_space_access( let gpm = &mut guard.gpm; if !gpm - .try_delete(old_vaddr.try_into().unwrap()) + .try_delete(old_vaddr.try_into().unwrap(), bar_size as usize) .is_ok() { /* The first delete from the guest will fail @@ -1568,7 +1580,7 @@ pub fn mmio_dwc_cfg_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { let dbi_region = PciRegionMmio::new(dbi_base, dbi_size); let dbi_backend = DwcConfigRegionBackend::new(dbi_region); - warn!("atu config {:#?}", atu); + // warn!("atu config {:#?}", atu); // Call AtuUnroll to program the ATU AtuUnroll::dw_pcie_prog_outbound_atu_unroll(&dbi_backend, &atu)?; @@ -1576,21 +1588,46 @@ pub fn mmio_dwc_cfg_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { let offset = (mmio.address & 0xfff) as PciConfigAddress; let zone_id = this_zone_id(); + let zone = this_zone(); + let mut is_dev_belong_to_zone = false; let base = mmio.address as PciConfigAddress - offset + atu.pci_target; let dev: Option = { - let zone = this_zone(); let mut guard = zone.write(); let vbus = &mut guard.vpci_bus; - vbus.get_device_by_base(base) + if let Some(dev) = vbus.get_device_by_base(base) { + is_dev_belong_to_zone = true; + Some(dev) + } else { + drop(guard); + // Clone Arc first while holding GLOBAL_PCIE_LIST lock, then release it + // This avoids holding multiple locks simultaneously + let dev_clone = { + let global_pcie_list = GLOBAL_PCIE_LIST.lock(); + global_pcie_list + .values() + .find(|dev| { + let dev_guard = dev.read(); + dev_guard.get_base() == base + }) + .cloned() + }; + dev_clone + } }; - if let Some(dev) = dev { - handle_config_space_access(dev, mmio, offset, zone_id)?; - } else { - handle_device_not_found(mmio, offset); - } + let dev = match dev { + Some(dev) => dev, + None => { + handle_device_not_found(mmio, offset); + return Ok(()); + } + }; + + let is_root = is_this_root_zone(); + + handle_config_space_access_direct(dev, mmio, offset, zone_id, is_root, is_dev_belong_to_zone); } else { warn!("No ATU config yet, do nothing"); } @@ -1599,27 +1636,30 @@ pub fn mmio_dwc_cfg_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { #[cfg(feature = "dwc_pcie")] pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { - info!("mmio_vpci_handler_dbi {:#x}", mmio.address); + // info!("mmio_vpci_handler_dbi {:#x}", mmio.address); - if mmio.address >= ATU_BASE && mmio.address < ATU_BASE + ATU_REGION_SIZE + /* 0x0-0x100 is outbound atu0 reg + * 0x100-0x200 is inbound atu0 reg just handle outbound right now + * so MAX is ATU_BASE + ATU_REGION_SIZE/2 + */ + if mmio.address >= ATU_BASE && mmio.address < ATU_BASE + ATU_REGION_SIZE/2 { - // ATU0 registers (0x300000 - 0x300200) let zone = this_zone(); let mut guard = zone.write(); let ecam_base = _base; let atu_offset = mmio.address - ATU_BASE; - warn!("set atu0 register {:#X} value {:#X}", atu_offset, mmio.value); + // warn!("set atu0 register {:#X} value {:#X}", atu_offset, mmio.value); let mut atu = guard.atu_configs.get_atu_by_ecam_mut(ecam_base).unwrap(); - info!("atu config write {:#?}", atu); + // info!("atu config write {:#?}", atu); if mmio.is_write { if mmio.size == 4 { match atu_offset { PCIE_ATU_UNR_REGION_CTRL1 => { - info!("set atu0 region ctrl1 value {:#X}", mmio.value); + // info!("set atu0 region ctrl1 value {:#X}", mmio.value); atu.atu_type = AtuType::from_u8((mmio.value & 0xff) as u8); } PCIE_ATU_UNR_REGION_CTRL2 => { @@ -1627,27 +1667,27 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { // The actual enable is handled by the driver } PCIE_ATU_UNR_LOWER_BASE => { - info!("set atu0 lower base value {:#X}", mmio.value); + // info!("set atu0 lower base value {:#X}", mmio.value); atu.cpu_base = (atu.cpu_base & !0xffffffff) | (mmio.value as PciConfigAddress); } PCIE_ATU_UNR_UPPER_BASE => { - info!("set atu0 upper base value {:#X}", mmio.value); + // info!("set atu0 upper base value {:#X}", mmio.value); atu.cpu_base = (atu.cpu_base & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32); } PCIE_ATU_UNR_LIMIT => { - info!("set atu0 limit value {:#X}", mmio.value); + // info!("set atu0 limit value {:#X}", mmio.value); atu.cpu_limit = (atu.cpu_limit & !0xffffffff) | (mmio.value as PciConfigAddress); } PCIE_ATU_UNR_LOWER_TARGET => { - info!("set atu0 lower target value {:#X}", mmio.value); + // info!("set atu0 lower target value {:#X}", mmio.value); atu.pci_target = (atu.pci_target & !0xffffffff) | (mmio.value as PciConfigAddress); } PCIE_ATU_UNR_UPPER_TARGET => { - info!("set atu0 upper target value {:#X}", mmio.value); + // info!("set atu0 upper target value {:#X}", mmio.value); atu.pci_target = (atu.pci_target & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32); } _ => { - warn!("invalid atu0 write size {:#x}", mmio.size); + warn!("invalid atu0 write {:#x} + {:#x}", atu_offset, mmio.size); } } } else { @@ -1655,7 +1695,7 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { } } else { // Read from virtual ATU - warn!("read atu0 {:#x}", atu_offset); + // warn!("read atu0 {:#x}", atu_offset); match atu_offset { PCIE_ATU_UNR_REGION_CTRL1 => { mmio.value = atu.atu_type as usize; @@ -1679,11 +1719,12 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { mmio.value = ((atu.pci_target >> 32) & 0xffffffff) as usize; } _ => { + warn!("invalid atu0 read {:#x}", atu_offset); mmio_perform_access(_base, mmio); } } } - } else if mmio.address > ATU_BASE + ATU_REGION_SIZE { + } else if mmio.address > ATU_BASE + ATU_REGION_SIZE/2 { // other atu mmio_perform_access(_base, mmio); } else if mmio.address >= BIT_LENTH { @@ -1694,20 +1735,45 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { let offset = (mmio.address & 0xfff) as PciConfigAddress; let zone_id = this_zone_id(); let zone = this_zone(); - let mut guard = zone.write(); + let mut is_dev_belong_to_zone = false; let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; let dev: Option = { + let mut guard = zone.write(); let vbus = &mut guard.vpci_bus; - vbus.get_device_by_base(base) + if let Some(dev) = vbus.get_device_by_base(base) { + is_dev_belong_to_zone = true; + Some(dev) + } else { + drop(guard); + // Clone Arc first while holding GLOBAL_PCIE_LIST lock, then release it + // This avoids holding multiple locks simultaneously + let dev_clone = { + let global_pcie_list = GLOBAL_PCIE_LIST.lock(); + global_pcie_list + .values() + .find(|dev| { + let dev_guard = dev.read(); + dev_guard.get_base() == base + }) + .cloned() + }; + dev_clone + } }; - if let Some(dev) = dev { - handle_config_space_access(dev, mmio, offset, zone_id)?; - } else { - handle_device_not_found(mmio, offset); - } + let dev = match dev { + Some(dev) => dev, + None => { + handle_device_not_found(mmio, offset); + return Ok(()); + } + }; + + let is_root = is_this_root_zone(); + + handle_config_space_access_direct(dev, mmio, offset, zone_id, is_root, is_dev_belong_to_zone); } Ok(()) @@ -1811,6 +1877,17 @@ fn handle_config_space_access_direct( if bar_type == PciMemType::Mem64High { dev.set_bar_virtual_value(slot - 1, new_vaddr); } + + // Sync virtual_value back to space after processing (adding flags) + // TODO: check whether need sync here + let virtual_value = dev.get_bararr()[slot].get_virtual_value(); + let bar_offset = (0x10 + slot * 4) as PciConfigAddress; + let _ = dev.write_emu(bar_offset, 4, virtual_value as usize); + if bar_type == PciMemType::Mem64High { + let virtual_value_low = dev.get_bararr()[slot - 1].get_virtual_value(); + let bar_offset_low = (0x10 + (slot - 1) * 4) as PciConfigAddress; + let _ = dev.write_emu(bar_offset_low, 4, virtual_value_low as usize); + } let paddr = if is_root { dev.set_bar_value(slot, new_vaddr); @@ -1835,39 +1912,41 @@ fn handle_config_space_access_direct( new_vaddr as u64 }; - let zone = this_zone(); - let mut guard = zone.write(); - let gpm = &mut guard.gpm; - - if !gpm.try_delete(old_vaddr.try_into().unwrap()).is_ok() { - warn!( - "delete bar {}: can not found 0x{:x}", - slot, old_vaddr + if !is_root { + let zone = this_zone(); + let mut guard = zone.write(); + let gpm = &mut guard.gpm; + + if !gpm.try_delete(old_vaddr.try_into().unwrap(), bar_size as usize).is_ok() { + warn!( + "delete bar {}: can not found 0x{:x}", + slot, old_vaddr + ); + } + gpm.try_insert(MemoryRegion::new_with_offset_mapper( + new_vaddr as GuestPhysAddr, + paddr as HostPhysAddr, + bar_size as _, + MemFlags::READ | MemFlags::WRITE, + ))?; + /* after update gpm, mem barrier is needed + */ + #[cfg(target_arch = "aarch64")] + unsafe { + core::arch::asm!("isb"); + core::arch::asm!("tlbi vmalls12e1is"); + core::arch::asm!("dsb nsh"); + } + /* after update gpm, need to flush iommu table + * in x86_64 + */ + #[cfg(target_arch = "x86_64")] + crate::arch::iommu::flush( + zone_id, + vbdf.bus, + (vbdf.device << 3) + vbdf.function, ); } - gpm.try_insert(MemoryRegion::new_with_offset_mapper( - new_vaddr as GuestPhysAddr, - paddr as HostPhysAddr, - bar_size as _, - MemFlags::READ | MemFlags::WRITE, - ))?; - /* after update gpm, mem barrier is needed - */ - #[cfg(target_arch = "aarch64")] - unsafe { - core::arch::asm!("isb"); - core::arch::asm!("tlbi vmalls12e1is"); - core::arch::asm!("dsb nsh"); - } - /* after update gpm, need to flush iommu table - * in x86_64 - */ - #[cfg(target_arch = "x86_64")] - crate::arch::iommu::flush( - zone_id, - vbdf.bus, - (vbdf.device << 3) + vbdf.function, - ); } } } else { @@ -1876,7 +1955,11 @@ fn handle_config_space_access_direct( dev.clear_bar_size_read(slot); r } else { - bar.get_virtual_value() as usize + // dev.read_emu(offset, size).unwrap() as usize + let emu_value = dev.read_emu(offset, size).unwrap() as usize; + let virtual_value = bar.get_virtual_value() as usize; + info!("emu value {:#x} virtual_value {:#x}", emu_value, virtual_value); + virtual_value } } } else { diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 77968b75..5039c3e7 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -231,8 +231,8 @@ pub struct PciConfigSpace { impl PciConfigSpace { pub fn new(id: (DeviceId, VendorId)) -> Self { let mut data = [0u8; BIT_LENTH]; - data[0x0..0x2].copy_from_slice(&id.0.to_le_bytes()); - data[0x2..0x4].copy_from_slice(&id.1.to_le_bytes()); + data[0x0..0x2].copy_from_slice(&id.1.to_le_bytes()); // VendorId + data[0x2..0x4].copy_from_slice(&id.0.to_le_bytes()); // DeviceId Self { data, } diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs index 45545a5f..43b9a9b3 100644 --- a/src/pci/pci_test.rs +++ b/src/pci/pci_test.rs @@ -21,8 +21,8 @@ use spin::{lazy::Lazy, mutex::Mutex}; use super::{ mem_alloc::BaseAllocator, - pci_access::mmio_vpci_handler, - pci_struct::{Bdf, VirtualPciConfigSpace, CONFIG_LENTH}, + pci_access::{mmio_vpci_direct_handler, mmio_vpci_handler}, + pci_struct::{Bdf, VirtualPciConfigSpace, CONFIG_LENTH, RootComplex}, }; use crate::{ @@ -31,22 +31,28 @@ use crate::{ percpu::this_zone, }; +#[cfg(feature = "ecam_pcie")] +use crate::pci::config_accessors::ecam::EcamConfigAccessor; + pub static GLOBAL_PCIE_LIST_TEST: Lazy>> = Lazy::new(|| { let m = BTreeMap::new(); Mutex::new(m) }); +#[cfg(feature = "ecam_pcie")] pub fn pcie_test() { - info!("pcie test"); + warn!("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); - // } + let mut root = RootComplex::new_ecam(0x4010000000); + for node in root.enumerate(None, Some(allocator)) { + GLOBAL_PCIE_LIST_TEST.lock().insert(node.get_bdf(), node); + } + warn!("pcie guest init done"); + warn!("{:#?}", GLOBAL_PCIE_LIST_TEST); } pub fn pcie_guest_init() { @@ -100,29 +106,110 @@ pub fn pcie_guest_init() { pub fn ecam_pcie_guest_test() { let zone = this_zone(); - let vbus = &zone.read().vpci_bus; let bdf = Bdf::from_str("0000:00:01.0").unwrap(); // Get base from VirtualPciConfigSpace and add offset - let address = if let Some(vdev) = vbus.get(&bdf) { - vdev.read().get_base() + 0x24 - } else { - warn!("can not find dev {:#?} for test", bdf); - 0 + // Use a block scope to ensure the read lock is released before calling mmio_vpci_direct_handler + let address = { + let vbus = &zone.read().vpci_bus; + if let Some(vdev) = vbus.get(&bdf) { + vdev.read().get_base() + } else { + warn!("can not find dev {:#?} for test", bdf); + 0 + } }; + let value = 0; + let test_address = address + 0x14; + let mut mmio = MMIOAccess { - address: address as _, + address: test_address as _, size: 4, is_write: false, - value: 0x0, + value: value, }; - let ret = mmio_vpci_handler(&mut mmio, 0); - info!("{:#?}", ret); + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + info!( + "mmio offset {:x}, is_wirte {}, size {}, value 0x{:x}", + mmio.address, mmio.is_write, mmio.size, mmio.value + ); + + + let mut mmio = MMIOAccess { + address: test_address as _, + size: 4, + is_write: true, + value: 0xFFFF_FFFF, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + info!( + "mmio offset {:x}, is_wirte {}, size {}, value 0x{:x}", + mmio.address, mmio.is_write, mmio.size, mmio.value + ); + + + let mut mmio = MMIOAccess { + address: test_address as _, + size: 4, + is_write: false, + value: value, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + info!( + "mmio offset {:x}, is_wirte {}, size {}, value 0x{:x}", + mmio.address, mmio.is_write, mmio.size, mmio.value + ); + + let mut mmio = MMIOAccess { + address: test_address as _, + size: 4, + is_write: true, + value: 0x80000000, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + info!( + "mmio offset {:x}, is_wirte {}, size {}, value 0x{:x}", + mmio.address, mmio.is_write, mmio.size, mmio.value + ); + + let mut mmio = MMIOAccess { + address: test_address as _, + size: 4, + is_write: false, + value: value, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + info!( + "mmio offset {:x}, is_wirte {}, size {}, value 0x{:x}", + mmio.address, mmio.is_write, mmio.size, mmio.value + ); + + let mut mmio = MMIOAccess { + address: test_address as _, + size: 4, + is_write: true, + value: 0x70000000, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + info!( + "mmio offset {:x}, is_wirte {}, size {}, value 0x{:x}", + mmio.address, mmio.is_write, mmio.size, mmio.value + ); + + let mut mmio = MMIOAccess { + address: test_address as _, + size: 4, + is_write: false, + value: value, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); info!( "mmio offset {:x}, is_wirte {}, size {}, value 0x{:x}", mmio.address, mmio.is_write, mmio.size, mmio.value ); info!("pcie guest test passed"); + + loop {} } pub fn dwc_pcie_guest_test() { From 7181b3b0beb5a1799dd8364025aed3224fb4b955 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 18 Dec 2025 03:09:09 +0800 Subject: [PATCH 052/109] in direct, for root update hardware when write bar --- src/pci/pci_access.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 09f23caa..9f239172 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -1858,6 +1858,9 @@ fn handle_config_space_access_direct( dev.set_bar_size_read(slot); } else { let _ = dev.write_emu(offset, size, value); + if is_root { + let _ = dev.write_hw(offset, size, value); + } if (bar_type == PciMemType::Mem32) | (bar_type == PciMemType::Mem64High) | (bar_type == PciMemType::Io) { From 09bfbc1eac76a58c8c40e6730885a5f484cc9e0a Mon Sep 17 00:00:00 2001 From: dallas Date: Tue, 23 Dec 2025 10:34:31 +0800 Subject: [PATCH 053/109] remove clone from bar access and update interface --- src/pci/pci_access.rs | 90 ++++++++++++++++++------------------ src/pci/pci_struct.rs | 35 +++++++++----- src/pci/vpci_dev/standard.rs | 16 +++---- 3 files changed, 75 insertions(+), 66 deletions(-) diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 9f239172..ceb5ef1e 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -1280,15 +1280,11 @@ fn handle_config_space_access( EndpointField::Bar(slot) => { // let slot = ((offset - 0x10) / 4) as usize; let slot = slot as usize; - /* the write of bar needs to start from dev, - * where the bar variable here is just a copy - */ - let bar = dev.get_bararr()[slot]; - let bar_type = bar.get_type(); + let bar_type = dev.with_bar_ref(slot, |bar| bar.get_type()); if bar_type != PciMemType::default() { if is_write { if (value & 0xfffffff0) == 0xfffffff0 { - dev.set_bar_size_read(slot); + dev.with_bar_ref_mut(slot, |bar| bar.set_size_read()); } else { let _ = dev.write_emu(offset, size, value); /* for mem64, Mem64High always write after Mem64Low, @@ -1298,7 +1294,7 @@ fn handle_config_space_access( | (bar_type == PciMemType::Mem64High) | (bar_type == PciMemType::Io) { - let old_vaddr = bar.get_virtual_value64() & !0xf; + let old_vaddr = dev.with_bar_ref(slot, |bar| bar.get_virtual_value64()) & !0xf; let new_vaddr = { if bar_type == PciMemType::Mem64High { /* last 4bit is flag, not address and need ignore @@ -1321,35 +1317,34 @@ fn handle_config_space_access( * the PCIe bus, will the newly written BAR address overlap with * the old BAR addresses, potentially causing the update to fail? */ - let paddr = bar.get_value64(); + let paddr = dev.with_bar_ref(slot, |bar| bar.get_value64()); info!( "old_vaddr {:x} new_vaddr {:x} paddr {:x}", old_vaddr, new_vaddr, paddr ); - dev.set_bar_virtual_value(slot, new_vaddr); + dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); if bar_type == PciMemType::Mem64High { - dev.set_bar_virtual_value(slot - 1, new_vaddr); + dev.with_bar_ref_mut(slot - 1, |bar| bar.set_virtual_value(new_vaddr)); } // // Sync virtual_value back to space after processing (adding flags) - // let bar = dev.get_bararr()[slot]; - // let virtual_value = bar.get_virtual_value(); + // let virtual_value = dev.get_bar_virtual_value(slot); // let bar_offset = (0x10 + slot * 4) as PciConfigAddress; // let _ = dev.write_emu(bar_offset, 4, virtual_value as usize); // if bar_type == PciMemType::Mem64High { - // let bar_low = dev.get_bararr()[slot - 1]; - // let virtual_value_low = bar_low.get_virtual_value(); + // let virtual_value_low = dev.get_bar_virtual_value(slot - 1); // let bar_offset_low = (0x10 + (slot - 1) * 4) as PciConfigAddress; // let _ = dev.write_emu(bar_offset_low, 4, virtual_value_low as usize); // } - let bar_size = if crate::memory::addr::is_aligned( - bar.get_size() as usize, - ) { - bar.get_size() - } else { - crate::memory::PAGE_SIZE as u64 + let bar_size = { + let size = dev.with_bar_ref(slot, |bar| bar.get_size()); + if crate::memory::addr::is_aligned(size as usize) { + size + } else { + crate::memory::PAGE_SIZE as u64 + } }; let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) { @@ -1402,14 +1397,15 @@ fn handle_config_space_access( } } } else { - mmio.value = if bar.get_size_read() { - let r = bar.get_size_with_flag().try_into().unwrap(); - dev.clear_bar_size_read(slot); + let size_read = dev.with_bar_ref(slot, |bar| bar.get_size_read()); + mmio.value = if size_read { + let r = dev.with_bar_ref(slot, |bar| bar.get_size_with_flag()).try_into().unwrap(); + dev.with_bar_ref_mut(slot, |bar| bar.clear_size_read()); r } else { - // bar.get_virtual_value().try_into().unwrap() + // dev.with_bar_ref(slot, |bar| bar.get_virtual_value()).try_into().unwrap() let emu_value = dev.read_emu(offset, size).unwrap() as usize; - let virtual_value = bar.get_virtual_value() as usize; + let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()) as usize; info!("emu value {:#x} virtual_value {:#x}", emu_value, virtual_value); emu_value }; @@ -1850,12 +1846,11 @@ fn handle_config_space_access_direct( } } EndpointField::Bar(slot) => { - let bar = dev.get_bararr()[slot]; - let bar_type = bar.get_type(); + let bar_type = dev.with_bar_ref(slot, |bar| bar.get_type()); if bar_type != PciMemType::default() { if is_write { if (value & 0xfffffff0) == 0xfffffff0 { - dev.set_bar_size_read(slot); + dev.with_bar_ref_mut(slot, |bar| bar.set_size_read()); } else { let _ = dev.write_emu(offset, size, value); if is_root { @@ -1864,7 +1859,7 @@ fn handle_config_space_access_direct( if (bar_type == PciMemType::Mem32) | (bar_type == PciMemType::Mem64High) | (bar_type == PciMemType::Io) { - let old_vaddr = bar.get_virtual_value64() & !0xf; + let old_vaddr = dev.with_bar_ref(slot, |bar| bar.get_virtual_value64()) & !0xf; let new_vaddr = { if bar_type == PciMemType::Mem64High { /* last 4bit is flag, not address and need ignore @@ -1876,38 +1871,39 @@ fn handle_config_space_access_direct( } }; - dev.set_bar_virtual_value(slot, new_vaddr); + dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); if bar_type == PciMemType::Mem64High { - dev.set_bar_virtual_value(slot - 1, new_vaddr); + dev.with_bar_ref_mut(slot - 1, |bar| bar.set_virtual_value(new_vaddr)); } // Sync virtual_value back to space after processing (adding flags) // TODO: check whether need sync here - let virtual_value = dev.get_bararr()[slot].get_virtual_value(); + let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()); let bar_offset = (0x10 + slot * 4) as PciConfigAddress; let _ = dev.write_emu(bar_offset, 4, virtual_value as usize); if bar_type == PciMemType::Mem64High { - let virtual_value_low = dev.get_bararr()[slot - 1].get_virtual_value(); + let virtual_value_low = dev.with_bar_ref(slot - 1, |bar| bar.get_virtual_value()); let bar_offset_low = (0x10 + (slot - 1) * 4) as PciConfigAddress; let _ = dev.write_emu(bar_offset_low, 4, virtual_value_low as usize); } let paddr = if is_root { - dev.set_bar_value(slot, new_vaddr); + dev.with_bar_ref_mut(slot, |bar| bar.set_value(new_vaddr)); if bar_type == PciMemType::Mem64High { - dev.set_bar_value(slot - 1, new_vaddr); + dev.with_bar_ref_mut(slot - 1, |bar| bar.set_value(new_vaddr)); } new_vaddr as HostPhysAddr } else { - bar.get_value64() as HostPhysAddr + dev.with_bar_ref(slot, |bar| bar.get_value64()) as HostPhysAddr }; - let bar_size = if crate::memory::addr::is_aligned( - bar.get_size() as usize, - ) { - bar.get_size() - } else { - crate::memory::PAGE_SIZE as u64 + let bar_size = { + let size = dev.with_bar_ref(slot, |bar| bar.get_size()); + if crate::memory::addr::is_aligned(size as usize) { + size + } else { + crate::memory::PAGE_SIZE as u64 + } }; let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) { crate::memory::addr::align_up(new_vaddr as usize) as u64 @@ -1953,14 +1949,16 @@ fn handle_config_space_access_direct( } } } else { - mmio.value = if bar.get_size_read() { - let r = bar.get_size_with_flag().try_into().unwrap(); - dev.clear_bar_size_read(slot); + // Re-fetch bar to get the latest virtual_value after potential write updates + let size_read = dev.with_bar_ref(slot, |bar| bar.get_size_read()); + mmio.value = if size_read { + let r = dev.with_bar_ref(slot, |bar| bar.get_size_with_flag()).try_into().unwrap(); + dev.with_bar_ref_mut(slot, |bar| bar.clear_size_read()); r } else { // dev.read_emu(offset, size).unwrap() as usize let emu_value = dev.read_emu(offset, size).unwrap() as usize; - let virtual_value = bar.get_virtual_value() as usize; + let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()) as usize; info!("emu value {:#x} virtual_value {:#x}", emu_value, virtual_value); virtual_value } diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 5039c3e7..b8efa2bd 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -394,20 +394,25 @@ impl ArcRwLockVirtualPciConfigSpace { self.0.write().write_hw(offset, size, value) } - pub fn set_bar_size_read(&self, slot: usize) { - self.0.write().set_bar_size_read(slot); - } - - pub fn clear_bar_size_read(&self, slot: usize) { - self.0.write().clear_bar_size_read(slot); - } - pub fn set_bar_virtual_value(&self, slot: usize, value: u64) { - self.0.write().set_bar_virtual_value(slot, value); + /// Execute a closure with a reference to the bar at the given slot + pub fn with_bar_ref(&self, slot: usize, f: F) -> R + where + F: FnOnce(&PciMem) -> R, + { + let guard = self.0.read(); + let bar = guard.get_bar_ref(slot); + f(bar) } - pub fn set_bar_value(&self, slot: usize, value: u64) { - self.0.write().set_bar_value(slot, value); + /// Execute a closure with a mutable reference to the bar at the given slot + pub fn with_bar_ref_mut(&self, slot: usize, f: F) -> R + where + F: FnOnce(&mut PciMem) -> R, + { + let mut guard = self.0.write(); + let bar = guard.get_bar_ref_mut(slot); + f(bar) } pub fn read(&self) -> spin::RwLockReadGuard<'_, VirtualPciConfigSpace> { @@ -464,6 +469,14 @@ impl VirtualPciConfigSpace { self.bararr } + pub fn get_bar_ref(&self, slot: usize) -> &PciMem { + &self.bararr[slot] + } + + pub fn get_bar_ref_mut(&mut self, slot: usize) -> &mut PciMem { + &mut self.bararr[slot] + } + pub fn set_bar_size_read(&mut self, slot: usize) { self.bararr[slot].set_size_read(); } diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index ac9811c8..50bb0d92 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -44,7 +44,6 @@ pub struct StandardHandler; impl VpciDeviceHandler for StandardHandler { fn read_cfg(&self, dev: ArcRwLockVirtualPciConfigSpace, offset: PciConfigAddress, size: usize) -> HvResult { info!("virt pci standard read_cfg, offset {:#x}, size {:#x}", offset, size); - let dev_guard = dev.read(); match EndpointField::from(offset as usize, size) { EndpointField::ID => { warn!("virt pci standard read_cfg, id {:#x}", offset); @@ -52,14 +51,13 @@ impl VpciDeviceHandler for StandardHandler { } EndpointField::Bar(0) => { let slot = 0; - let bar = dev_guard.get_bararr()[slot]; - if bar.get_size_read() { - let value = bar.get_size_with_flag(); - drop(dev_guard); - dev.write().clear_bar_size_read(slot); + let size_read = dev.with_bar_ref(slot, |bar| bar.get_size_read()); + if size_read { + let value = dev.with_bar_ref(slot, |bar| bar.get_size_with_flag()); + dev.with_bar_ref_mut(slot, |bar| bar.clear_size_read()); Ok(PciConfigAccessStatus::Done(value as usize)) } else { - let value = bar.get_virtual_value(); + let value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()); Ok(PciConfigAccessStatus::Done(value as usize)) } } @@ -83,10 +81,10 @@ impl VpciDeviceHandler for StandardHandler { } EndpointField::Bar(0) => { let slot = 0; - let bar_size = dev.get_bararr()[slot].get_size(); + let bar_size = dev.with_bar_ref(slot, |bar| bar.get_size()); if value == 0xFFFF_FFFF { - dev.set_bar_size_read(slot); + dev.with_bar_ref_mut(slot, |bar| bar.set_size_read()); } else { let zone = this_zone(); let mut guard = zone.write(); From 2dd37606c05c0d4a59279dcfc8cae6af4d044937 Mon Sep 17 00:00:00 2001 From: dallas Date: Tue, 23 Dec 2025 16:55:17 +0800 Subject: [PATCH 054/109] 1.remove config sapce for vdev and use config value instead 2.update emu rw interface --- src/pci/pci_access.rs | 36 ++-- src/pci/pci_struct.rs | 353 ++++++++++++++++++----------------- src/pci/vpci_dev/mod.rs | 25 +-- src/pci/vpci_dev/standard.rs | 78 ++++---- 4 files changed, 253 insertions(+), 239 deletions(-) diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index ceb5ef1e..6f075740 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -1286,7 +1286,7 @@ fn handle_config_space_access( if (value & 0xfffffff0) == 0xfffffff0 { dev.with_bar_ref_mut(slot, |bar| bar.set_size_read()); } else { - let _ = dev.write_emu(offset, size, value); + let _ = dev.write_emu(EndpointField::Bar(slot), value); /* for mem64, Mem64High always write after Mem64Low, * so update bar when write Mem64High */ @@ -1299,8 +1299,11 @@ fn handle_config_space_access( 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 + * Read from config_value.bar_value cache instead of space */ - dev.read_emu64(offset - 0x4).unwrap() & !0xf + let low_value = dev.with_config_value(|cv| cv.get_bar_value(slot - 1)) as u64; + let high_value = (value as u32 as u64) << 32; + (low_value | high_value) & !0xf } else { (value as u64) & !0xf } @@ -1404,7 +1407,7 @@ fn handle_config_space_access( r } else { // dev.with_bar_ref(slot, |bar| bar.get_virtual_value()).try_into().unwrap() - let emu_value = dev.read_emu(offset, size).unwrap() as usize; + let emu_value = dev.read_emu(EndpointField::Bar(slot)).unwrap() as usize; let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()) as usize; info!("emu value {:#x} virtual_value {:#x}", emu_value, virtual_value); emu_value @@ -1425,12 +1428,12 @@ fn handle_config_space_access( warn!("ExpansionRomBar size_read not yet implemented"); } else { // let old_vaddr = dev.read_emu(offset, size).unwrap() as u64; - let _ = dev.write_emu(offset, size, value); + let _ = dev.write_emu(EndpointField::ExpansionRomBar, value); // TODO: add gpm change for rom } } else { mmio.value = if rom_size_read { - dev.read_emu(offset, size).unwrap() + dev.read_emu(EndpointField::ExpansionRomBar).unwrap() } else { rom.get_size_with_flag().try_into().unwrap() }; @@ -1438,7 +1441,7 @@ fn handle_config_space_access( } EndpointField::ID => { if !is_write { - mmio.value = dev.read_emu(offset, size).unwrap() as usize; + mmio.value = dev.read_emu(EndpointField::ID).unwrap() as usize; } } _ => {} @@ -1834,7 +1837,7 @@ fn handle_config_space_access_direct( EndpointField::ID => { if !is_write { if is_dev_belong_to_zone { - mmio.value = dev.read_emu(offset, size).unwrap(); + mmio.value = dev.read_emu(EndpointField::ID).unwrap(); } else { if is_root { /* just a id no one used now @@ -1852,7 +1855,7 @@ fn handle_config_space_access_direct( if (value & 0xfffffff0) == 0xfffffff0 { dev.with_bar_ref_mut(slot, |bar| bar.set_size_read()); } else { - let _ = dev.write_emu(offset, size, value); + let _ = dev.write_emu(EndpointField::Bar(slot), value); if is_root { let _ = dev.write_hw(offset, size, value); } @@ -1864,8 +1867,11 @@ fn handle_config_space_access_direct( 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 + * Read from config_value.bar_value cache instead of space */ - dev.read_emu64(offset - 0x4).unwrap() & !0xf + let low_value = dev.with_config_value(|cv| cv.get_bar_value(slot - 1)) as u64; + let high_value = (value as u32 as u64) << 32; + (low_value | high_value) & !0xf } else { (value as u64) & !0xf } @@ -1879,12 +1885,10 @@ fn handle_config_space_access_direct( // Sync virtual_value back to space after processing (adding flags) // TODO: check whether need sync here let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()); - let bar_offset = (0x10 + slot * 4) as PciConfigAddress; - let _ = dev.write_emu(bar_offset, 4, virtual_value as usize); + let _ = dev.write_emu(EndpointField::Bar(slot), virtual_value as usize); if bar_type == PciMemType::Mem64High { let virtual_value_low = dev.with_bar_ref(slot - 1, |bar| bar.get_virtual_value()); - let bar_offset_low = (0x10 + (slot - 1) * 4) as PciConfigAddress; - let _ = dev.write_emu(bar_offset_low, 4, virtual_value_low as usize); + let _ = dev.write_emu(EndpointField::Bar(slot - 1), virtual_value_low as usize); } let paddr = if is_root { @@ -1957,7 +1961,7 @@ fn handle_config_space_access_direct( r } else { // dev.read_emu(offset, size).unwrap() as usize - let emu_value = dev.read_emu(offset, size).unwrap() as usize; + let emu_value = dev.read_emu(EndpointField::Bar(slot)).unwrap() as usize; let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()) as usize; info!("emu value {:#x} virtual_value {:#x}", emu_value, virtual_value); virtual_value @@ -1976,12 +1980,12 @@ fn handle_config_space_access_direct( warn!("ExpansionRomBar size_read not yet implemented for direct handler"); } else { // let old_vaddr = dev.read_emu(offset, size).unwrap() as u64; - let _ = dev.write_emu(offset, size, value); + let _ = dev.write_emu(EndpointField::ExpansionRomBar, value); // TODO: add gpm change for rom } } else { mmio.value = if rom_size_read { - dev.read_emu(offset, size).unwrap() + dev.read_emu(EndpointField::ExpansionRomBar).unwrap() } else { rom.get_size_with_flag().try_into().unwrap() }; diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index b8efa2bd..ef0e9be8 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -34,6 +34,61 @@ use crate::{error::{HvErrorNum, HvResult}, pci::vpci_dev::VpciDevType}; type VirtualPciConfigBits = BitArr!(for BIT_LENTH, in u8, Lsb0); +#[derive(Clone, Debug)] +pub struct ConfigValue { + id: (DeviceId, VendorId), + class: (BaseClass, SubClass, Interface), + bar_value: [u32; 6], +} + +impl ConfigValue { + pub fn new(id: (DeviceId, VendorId), class: (BaseClass, SubClass, Interface)) -> Self { + Self { + id, + class, + bar_value: [0; 6], + } + } + + pub fn get_id(&self) -> (DeviceId, VendorId) { + self.id + } + + pub fn set_id(&mut self, id: (DeviceId, VendorId)) { + self.id = id; + } + + pub fn get_class(&self) -> (BaseClass, SubClass, Interface) { + self.class + } + + pub fn set_class(&mut self, class: (BaseClass, SubClass, Interface)) { + self.class = class; + } + + pub fn get_bar_value(&self, slot: usize) -> u32 { + if slot < 6 { + self.bar_value[slot] + } else { + 0 + } + } + + pub fn set_bar_value(&mut self, slot: usize, value: u32) { + if slot < 6 { + self.bar_value[slot] = value; + } + } + + pub fn get_bar_value_ref(&self, slot: usize) -> &u32 { + &self.bar_value[slot] + } + + pub fn get_bar_value_ref_mut(&mut self, slot: usize) -> &mut u32 { + &mut self.bar_value[slot] + } +} + const MAX_DEVICE: u8 = 31; const MAX_FUNCTION: u8 = 7; pub const CONFIG_LENTH: u64 = 256; @@ -223,95 +278,13 @@ impl VirtualPciAccessBits { } } -#[derive(Clone, Debug)] -pub struct PciConfigSpace { - data: [u8; BIT_LENTH], -} - -impl PciConfigSpace { - pub fn new(id: (DeviceId, VendorId)) -> Self { - let mut data = [0u8; BIT_LENTH]; - data[0x0..0x2].copy_from_slice(&id.1.to_le_bytes()); // VendorId - data[0x2..0x4].copy_from_slice(&id.0.to_le_bytes()); // DeviceId - Self { - data, - } - } - - pub fn as_slice(&self) -> &[u8] { - &self.data - } - - pub fn as_mut_slice(&mut self) -> &mut [u8] { - &mut self.data - } - - pub fn get_range(&self, offset: usize, size: usize) -> &[u8] { - &self.data[offset..offset + size] - } - - pub fn get_range_mut(&mut self, offset: usize, size: usize) -> &mut [u8] { - &mut self.data[offset..offset + size] - } - - pub fn set(&mut self, field: F, value: u32) { - let offset = field.to_offset(); - let size = field.size(); - match size { - 1 => { - self.get_range_mut(offset, 1)[0] = value as u8; - } - 2 => { - self.get_range_mut(offset, 2).copy_from_slice(&(value as u16).to_le_bytes()); - } - 4 => { - self.get_range_mut(offset, 4).copy_from_slice(&value.to_le_bytes()); - } - _ => { - // For other sizes, write as many bytes as needed - let bytes = value.to_le_bytes(); - self.get_range_mut(offset, size.min(bytes.len())).copy_from_slice(&bytes[..size.min(bytes.len())]); - } - } - } - - pub fn get(&self, field: F) -> u32 { - let offset = field.to_offset(); - let size = field.size(); - match size { - 1 => { - self.get_range(offset, 1)[0] as u32 - } - 2 => { - u16::from_le_bytes(self.get_range(offset, 2).try_into().unwrap()) as u32 - } - 4 => { - u32::from_le_bytes(self.get_range(offset, 4).try_into().unwrap()) - } - _ => { - warn!("vpci dev {:#?} get size {:#?} not supported", field, size); - 0xFFFF_FFFF - } - } - } - - pub fn init_with_type(dev_type: VpciDevType) -> Self { - crate::pci::vpci_dev::init_config_space_with_type(dev_type) - } -} - -impl Default for PciConfigSpace { - fn default() -> Self { - Self::new((0xFFFFu16, 0xFFFFu16)) - } -} /* 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 + * config_value: tmp value for config space * control: control the satus of rw every bit in config space - * access: Determines whether the variable is read from space or hw + * access: Determines whether the variable is read from config_value or hw * backend: the hw rw interface */ #[derive(Clone)] @@ -321,11 +294,10 @@ pub struct VirtualPciConfigSpace { bdf: Bdf, vbdf: Bdf, config_type: HeaderType, - class: (BaseClass, SubClass, Interface), base: PciConfigAddress, - space: PciConfigSpace, + config_value: ConfigValue, control: VirtualPciConfigControl, access: VirtualPciAccessBits, @@ -374,18 +346,23 @@ impl ArcRwLockVirtualPciConfigSpace { self.0.read().get_rom() } - pub fn read_emu(&self, offset: PciConfigAddress, size: usize) -> HvResult { - self.0.write().read_emu(offset, size) + pub fn read_emu(&self, field: EndpointField) -> HvResult { + self.0.write().read_emu(field) } - pub fn read_emu64(&self, offset: PciConfigAddress) -> HvResult { - self.0.write().read_emu64(offset) + pub fn read_emu64(&self, field: EndpointField) -> HvResult { + self.0.write().read_emu64(field) } - pub fn write_emu(&self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { - self.0.write().write_emu(offset, size, value) + pub fn write_emu(&self, field: EndpointField, value: usize) -> HvResult { + self.0.write().write_emu(field, value) } + // Legacy method for backward compatibility + // pub fn write_emu_legacy(&self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { + // self.0.write().write_emu_legacy(offset, size, value) + // } + pub fn read_hw(&self, offset: PciConfigAddress, size: usize) -> HvResult { self.0.write().read_hw(offset, size) } @@ -415,6 +392,24 @@ impl ArcRwLockVirtualPciConfigSpace { f(bar) } + /// Execute a closure with a reference to the config_value + pub fn with_config_value(&self, f: F) -> R + where + F: FnOnce(&ConfigValue) -> R, + { + let guard = self.0.read(); + f(&guard.config_value) + } + + /// Execute a closure with a mutable reference to the config_value + pub fn with_config_value_mut(&self, f: F) -> R + where + F: FnOnce(&mut ConfigValue) -> R, + { + let mut guard = self.0.write(); + f(&mut guard.config_value) + } + pub fn read(&self) -> spin::RwLockReadGuard<'_, VirtualPciConfigSpace> { self.0.read() } @@ -477,6 +472,7 @@ impl VirtualPciConfigSpace { &mut self.bararr[slot] } + pub fn set_bar_size_read(&mut self, slot: usize) { self.bararr[slot].set_size_read(); } @@ -485,7 +481,7 @@ impl VirtualPciConfigSpace { self.bararr[slot].set_virtual_value(value); } - pub fn set_bar_value(&mut self, slot: usize, value: u64) { + pub fn set_bar_physical_value(&mut self, slot: usize, value: u64) { self.bararr[slot].set_value(value); } @@ -501,31 +497,19 @@ impl VirtualPciConfigSpace { self.dev_type } - pub fn get_space_mut(&mut self) -> &mut PciConfigSpace { - &mut self.space - } - pub fn get_space(&self) -> &PciConfigSpace { - &self.space - } - - // 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) { + // TODO: check whether need update config + pub fn update_config(&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); + // Bar values are cached in config_value.bar_value, updated in write_emu } _ => {} } } _ => { - // warn!("TODO updating space"); } } } @@ -547,15 +531,15 @@ impl VirtualPciConfigSpace { base: PciConfigAddress, dev_type: VpciDevType, ) -> Self { + let config_value = crate::pci::vpci_dev::init_config_value_with_type(dev_type); Self { host_bdf: Bdf::default(), parent_bdf: Bdf::default(), bdf, vbdf: bdf, config_type: HeaderType::Endpoint, - class: (0u8,0u8,0u8), base, - space: PciConfigSpace::init_with_type(dev_type), + config_value, control: VirtualPciConfigControl::virt_dev(), access: VirtualPciAccessBits::virt_dev(), backend: Arc::new(EndpointHeader::new_with_region(PciConfigMmio::new(base, CONFIG_LENTH))), @@ -580,9 +564,8 @@ impl VirtualPciConfigSpace { bdf, vbdf: Bdf::default(), config_type: HeaderType::Endpoint, - class, base, - space: PciConfigSpace::new(id), + config_value: ConfigValue::new(id, class), control: VirtualPciConfigControl::endpoint(), access: VirtualPciAccessBits::endpoint(), backend, @@ -608,9 +591,8 @@ impl VirtualPciConfigSpace { bdf, vbdf: Bdf::default(), config_type: HeaderType::PciBridge, - class, base, - space: PciConfigSpace::new(id), + config_value: ConfigValue::new(id, class), control: VirtualPciConfigControl::bridge(), access: VirtualPciAccessBits::bridge(), backend, @@ -628,9 +610,8 @@ impl VirtualPciConfigSpace { bdf, vbdf: Bdf::default(), config_type: HeaderType::Endpoint, - class: (0u8,0u8,0u8), base, - space: PciConfigSpace::new(id), + config_value: ConfigValue::new(id, (0u8,0u8,0u8)), control: VirtualPciConfigControl::endpoint(), access: VirtualPciAccessBits::endpoint(), backend, @@ -648,9 +629,8 @@ impl VirtualPciConfigSpace { bdf: bdf, vbdf: bdf, config_type: HeaderType::Endpoint, - class, base, - space: PciConfigSpace::default(), + config_value: ConfigValue::new((0xFFFFu16, 0xFFFFu16), class), // Default ID for host bridge control: VirtualPciConfigControl::host_bridge(), access: VirtualPciAccessBits::host_bridge(), backend, @@ -694,23 +674,13 @@ impl VirtualPciConfigSpace { } /* now the space_init just with bar + * Note: space field removed, bar values are cached in config_value.bar_value */ - 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.get_range_mut(offset, 4).copy_from_slice(&bytes); - } - match self.config_type { - HeaderType::Endpoint => { - let bytes = self.rom.get_value().to_le_bytes(); - self.space.get_range_mut(0x30, 4).copy_from_slice(&bytes); - } - HeaderType::PciBridge => { - let bytes = self.rom.get_value().to_le_bytes(); - self.space.get_range_mut(0x38, 4).copy_from_slice(&bytes); - } - _ => {} + pub fn config_value_init(&mut self) { + // Initialize bar_value cache from bar values + for slot in 0..6 { + let bar_value = self.bararr[slot].get_value(); + self.config_value.set_bar_value(slot, bar_value as u32); } } } @@ -719,7 +689,7 @@ 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); + self.update_config(offset, size, value); } r } @@ -728,7 +698,7 @@ impl VirtualPciConfigSpace { if self.writable(offset, size) { let r = self.backend.write(offset, size, value); if r.is_ok() { - self.update_space(offset, size, value); + self.update_config(offset, size, value); } r } else { @@ -736,17 +706,32 @@ impl VirtualPciConfigSpace { } } - pub fn read_emu(&mut self, offset: PciConfigAddress, size: usize) -> HvResult { + pub fn read_emu(&mut self, field: EndpointField) -> HvResult { + let offset = field.to_offset() as PciConfigAddress; + let size = field.size(); + match size { 1 | 2 | 4 => { - let slice = self.space.get_range(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) + match field { + EndpointField::ID => { + // Read ID from cached config_value.id field + let id = self.config_value.get_id(); + let id_value = ((id.0 as u32) << 16) | (id.1 as u32); + Ok(id_value as usize) + } + EndpointField::Bar(slot) => { + // Read bar_value from cache + if slot < 6 { + Ok(self.config_value.get_bar_value(slot) as usize) + } else { + self.backend.read(offset, size) + } + } + _ => { + // For other fields, read from backend + self.backend.read(offset, size) + } + } } _ => { hv_result_err!(EFAULT, "pci: invalid virtual mmio read size: {size}") @@ -754,33 +739,65 @@ impl VirtualPciConfigSpace { } } - pub fn read_emu64(&mut self, offset: PciConfigAddress) -> HvResult { - let slice = self.space.get_range(offset as usize, 8); - let value = u64::from_le_bytes(slice.try_into().unwrap()) as u64; - Ok(value) + pub fn read_emu64(&mut self, field: EndpointField) -> HvResult { + // Read 64-bit value (used for bar64) + // For Bar(slot), read from slot and slot+1 + match field { + EndpointField::Bar(slot) if slot < 5 => { + // Read from bar_value cache + let low = self.config_value.get_bar_value(slot) as u64; + let high = self.config_value.get_bar_value(slot + 1) as u64; + Ok(low | (high << 32)) + } + _ => { + // Fallback to backend read + let offset = field.to_offset() as PciConfigAddress; + let low = self.backend.read(offset, 4)? as u64; + let high = self.backend.read(offset + 4, 4)? as u64; + Ok(low | (high << 32)) + } + } } - pub fn write_emu(&mut self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { - if true { - match size { - 1 | 2 | 4 => { - let slice = self.space.get_range_mut(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!(), + pub fn write_emu(&mut self, field: EndpointField, value: usize) -> HvResult { + let offset = field.to_offset() as PciConfigAddress; + let size = field.size(); + + match size { + 1 | 2 | 4 => { + match field { + EndpointField::ID => { + // Update ID cache when writing ID field + self.config_value.set_id(( + ((value >> 16) & 0xFFFF) as DeviceId, + (value & 0xFFFF) as VendorId, + )); + } + EndpointField::Bar(slot) => { + // Update bar_value cache when writing bar + if slot < 6 { + self.config_value.set_bar_value(slot, value as u32); + } + } + _ => { + // For other fields, write to backend } - Ok(()) - } - _ => { - hv_result_err!(EFAULT, "pci: invalid virtual mmio write size: {size}") } + + // Write to backend + self.backend.write(offset, size, value) + } + _ => { + hv_result_err!(EFAULT, "pci: invalid virtual mmio write size: {size}") } - } else { - hv_result_err!(EPERM, "pci: invalid write to hw") } } + + // Legacy method for backward compatibility - converts offset/size to EndpointField + // pub fn write_emu_legacy(&mut self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { + // let field = EndpointField::from(offset as usize, size); + // self.write_emu(field, value) + // } } #[derive(Debug)] @@ -1081,7 +1098,7 @@ impl Iterator for PciIterator { info!("pci dev next"); while !self.is_finish { if let Some(mut node) = self.get_node() { - node.space_init(); + node.config_value_init(); let bus_begin = self.bus_range.start as u8; /* * when first time to enumerate, placeholder is pop in get_node @@ -1098,8 +1115,8 @@ impl Iterator for PciIterator { let parent_bus = parent.primary_bus; node.set_host_bdf(host_bdf); node.set_parent_bdf(parent_bdf); - self.next(match node.class.0 { - 0x6 if node.class.1 != 0x0 => { + self.next(match node.config_value.get_class().0 { + 0x6 if node.config_value.get_class().1 != 0x0 => { let bdf = Bdf::new(parent.subordinate_bus + 1, 0, 0); Some( self.get_bridge().next_bridge( diff --git a/src/pci/vpci_dev/mod.rs b/src/pci/vpci_dev/mod.rs index abfc500c..a51d014f 100644 --- a/src/pci/vpci_dev/mod.rs +++ b/src/pci/vpci_dev/mod.rs @@ -1,7 +1,7 @@ -use crate::pci::pci_struct::{PciConfigSpace, ArcRwLockVirtualPciConfigSpace}; +use crate::pci::pci_struct::{ConfigValue, ArcRwLockVirtualPciConfigSpace}; use crate::pci::PciConfigAddress; use crate::error::HvResult; -use crate::pci::pci_access::Bar; +use crate::pci::pci_access::{Bar, EndpointField}; pub mod standard; @@ -30,7 +30,7 @@ pub enum VpciDevType { pub trait VpciDeviceHandler: Sync + Send { fn read_cfg(&self, dev: ArcRwLockVirtualPciConfigSpace, offset: PciConfigAddress, size: usize) -> HvResult; fn write_cfg(&self, dev: ArcRwLockVirtualPciConfigSpace, offset: PciConfigAddress, size: usize, value: usize) -> HvResult; - fn init_config_space(&self) -> PciConfigSpace; + fn init_config_space(&self) -> ConfigValue; fn init_bar(&self) -> Bar; } @@ -72,7 +72,8 @@ pub(super) fn vpci_dev_read_cfg( PciConfigAccessStatus::Perform => { // warn!("vpci_dev_read_cfg: perform, offset {:#x}, size {:#x}", offset, size); // warn!("vpci_dev_read_cfg: node {:#?}", node.space); - let r = node.write().read_emu(offset, size).unwrap(); + let field = EndpointField::from(offset as usize, size); + let r = node.write().read_emu(field).unwrap(); // warn!("vpci_dev_read_cfg: perform result {:#x}", r); Ok(r) } @@ -117,7 +118,8 @@ pub(super) fn vpci_dev_write_cfg( } PciConfigAccessStatus::Perform => { warn!("vpci_dev_write_cfg: perform"); - node.write().write_emu(offset, size, value) + let field = EndpointField::from(offset as usize, size); + node.write().write_emu(field, value) } PciConfigAccessStatus::Reject => { warn!("vpci_dev_write_cfg: operation rejected"); @@ -138,18 +140,19 @@ pub(super) fn vpci_dev_write_cfg( } } -pub(super) fn init_config_space_with_type(dev_type: VpciDevType) -> PciConfigSpace { +pub(super) fn init_config_value_with_type(dev_type: VpciDevType) -> ConfigValue { match dev_type { VpciDevType::Physical => { - // Physical devices use default (all zeros) space - PciConfigSpace::default() + // Physical devices use default values + warn!("init_config_value_with_type: physical device is not supported"); + return ConfigValue::new((0xFFFFu16, 0xFFFFu16), (0u8, 0u8, 0u8)); } _ => { if let Some(handler) = get_handler(dev_type) { handler.init_config_space() } else { - warn!("init_config_space_with_type: unknown device type"); - PciConfigSpace::default() + warn!("init_config_value_with_type: unknown device type"); + ConfigValue::new((0xFFFFu16, 0xFFFFu16), (0u8, 0u8, 0u8)) } } } @@ -165,7 +168,7 @@ pub(super) fn virt_bar_init(dev_type: VpciDevType) -> Bar { if let Some(handler) = get_handler(dev_type) { handler.init_bar() } else { - warn!("init_config_space_with_type: unknown device type"); + warn!("init_config_value_with_type: unknown device type"); Bar::default() } } diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index 50bb0d92..53899c8a 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -1,6 +1,6 @@ use crate::error::HvResult; -use crate::pci::pci_struct::PciConfigSpace; -use crate::pci::pci_access::{EndpointField, Bar}; +use crate::pci::pci_struct::ConfigValue; +use crate::pci::pci_access::{EndpointField, Bar, DeviceId, VendorId, BaseClass, SubClass, Interface}; use crate::pci::PciConfigAddress; use super::{PciConfigAccessStatus, VpciDeviceHandler}; // use crate::memory::frame::Frame; @@ -9,34 +9,34 @@ use crate::percpu::this_zone; use crate::memory::MMIOAccess; use crate::pci::pci_access::PciMemType; -const STANDARD_VENDOR_ID: u16 = 0x110a; -const STANDARD_DEVICE_ID: u16 = 0x4106; -const PCI_STS_CAPS: u16 = 0x10; // bit 4 -const PCI_DEV_CLASS_OTHER: u8 = 0xff; -const PCI_CFG_CAPS: usize = 0x34; -const PCI_CAP_ID_VNDR: u8 = 0x09; -const PCI_CAP_ID_MSIX: u8 = 0x11; -const STANDARD_CFG_VNDR_CAP: u8 = 0x40; -const STANDARD_CFG_VNDR_LEN: u8 = 0x20; -const STANDARD_CFG_MSIX_CAP: usize = 0x60; // VNDR_CAP + VNDR_LEN -const STANDARD_MSIX_VECTORS: u16 = 16; -const STANDARD_CFG_SIZE: usize = 0x80; +// const STANDARD_VENDOR_ID: u16 = 0x110a; +// const STANDARD_DEVICE_ID: u16 = 0x4106; +// const PCI_STS_CAPS: u16 = 0x10; // bit 4 +// const PCI_DEV_CLASS_OTHER: u8 = 0xff; +// const PCI_CFG_CAPS: usize = 0x34; +// const PCI_CAP_ID_VNDR: u8 = 0x09; +// const PCI_CAP_ID_MSIX: u8 = 0x11; +// const STANDARD_CFG_VNDR_CAP: u8 = 0x40; +// const STANDARD_CFG_VNDR_LEN: u8 = 0x20; +// const STANDARD_CFG_MSIX_CAP: usize = 0x60; // VNDR_CAP + VNDR_LEN +// const STANDARD_MSIX_VECTORS: u16 = 16; +// const STANDARD_CFG_SIZE: usize = 0x80; -pub(crate) const DEFAULT_CSPACE_U32: [u32; STANDARD_CFG_SIZE / 4] = { - let mut arr = [0u32; STANDARD_CFG_SIZE / 4]; - arr[0x00 / 4] = (STANDARD_DEVICE_ID as u32) << 16 | STANDARD_VENDOR_ID as u32; - arr[0x04 / 4] = (PCI_STS_CAPS as u32) << 16; - arr[0x08 / 4] = (PCI_DEV_CLASS_OTHER as u32) << 24; - arr[0x2c / 4] = (STANDARD_DEVICE_ID as u32) << 16 | STANDARD_VENDOR_ID as u32; - arr[PCI_CFG_CAPS / 4] = STANDARD_CFG_VNDR_CAP as u32; - arr[STANDARD_CFG_VNDR_CAP as usize / 4] = (STANDARD_CFG_VNDR_LEN as u32) << 16 - | (STANDARD_CFG_MSIX_CAP as u32) << 8 - | PCI_CAP_ID_VNDR as u32; - arr[STANDARD_CFG_MSIX_CAP / 4] = (0x00u32) << 8 | PCI_CAP_ID_MSIX as u32; - arr[(STANDARD_CFG_MSIX_CAP + 0x4) / 4] = 1; - arr[(STANDARD_CFG_MSIX_CAP + 0x8) / 4] = ((0x10 * STANDARD_MSIX_VECTORS) as u32) | 1; - arr -}; +// pub(crate) const DEFAULT_CSPACE_U32: [u32; STANDARD_CFG_SIZE / 4] = { +// let mut arr = [0u32; STANDARD_CFG_SIZE / 4]; +// arr[0x00 / 4] = (STANDARD_DEVICE_ID as u32) << 16 | STANDARD_VENDOR_ID as u32; +// arr[0x04 / 4] = (PCI_STS_CAPS as u32) << 16; +// arr[0x08 / 4] = (PCI_DEV_CLASS_OTHER as u32) << 24; +// arr[0x2c / 4] = (STANDARD_DEVICE_ID as u32) << 16 | STANDARD_VENDOR_ID as u32; +// arr[PCI_CFG_CAPS / 4] = STANDARD_CFG_VNDR_CAP as u32; +// arr[STANDARD_CFG_VNDR_CAP as usize / 4] = (STANDARD_CFG_VNDR_LEN as u32) << 16 +// | (STANDARD_CFG_MSIX_CAP as u32) << 8 +// | PCI_CAP_ID_VNDR as u32; +// arr[STANDARD_CFG_MSIX_CAP / 4] = (0x00u32) << 8 | PCI_CAP_ID_MSIX as u32; +// arr[(STANDARD_CFG_MSIX_CAP + 0x4) / 4] = 1; +// arr[(STANDARD_CFG_MSIX_CAP + 0x8) / 4] = ((0x10 * STANDARD_MSIX_VECTORS) as u32) | 1; +// arr +// }; /// Handler for standard virtual PCI devices pub struct StandardHandler; @@ -74,9 +74,7 @@ impl VpciDeviceHandler for StandardHandler { Ok(PciConfigAccessStatus::Reject) } EndpointField::Command => { - let mut dev_guard = dev.write(); - let space = dev_guard.get_space_mut(); - space.set(EndpointField::Command, value as u32); + // Command field is written directly to backend, no need for space cache Ok(PciConfigAccessStatus::Done(value)) } EndpointField::Bar(0) => { @@ -100,19 +98,11 @@ impl VpciDeviceHandler for StandardHandler { } } - fn init_config_space(&self) -> PciConfigSpace { - let mut space = PciConfigSpace::default(); - let default_cspace = DEFAULT_CSPACE_U32; - let mut offset = 0; - for &value in &default_cspace { - space.get_range_mut(offset, 4).copy_from_slice(&value.to_le_bytes()); - offset += 4; - } - - // Example: update vendor ID - space.set(EndpointField::ID, 0x12345678); + fn init_config_space(&self) -> ConfigValue { + let id :(DeviceId, VendorId) = (0x110a, 0x4106); + let class :(BaseClass, SubClass, Interface) = (0x0, 0x0, 0x0); - space + ConfigValue::new(id, class) } fn init_bar(&self) -> Bar { From c0ff6f687d287113c737f37c47717dbe57b21540 Mon Sep 17 00:00:00 2001 From: dallas Date: Tue, 23 Dec 2025 17:26:08 +0800 Subject: [PATCH 055/109] updating mem64low when only rw mem64low --- src/pci/pci_access.rs | 184 ++++++++++++++++++++++-------------------- 1 file changed, 96 insertions(+), 88 deletions(-) diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 6f075740..8d96dfd3 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -1855,102 +1855,110 @@ fn handle_config_space_access_direct( if (value & 0xfffffff0) == 0xfffffff0 { dev.with_bar_ref_mut(slot, |bar| bar.set_size_read()); } else { - let _ = dev.write_emu(EndpointField::Bar(slot), value); - if is_root { - let _ = dev.write_hw(offset, size, value); - } - if (bar_type == PciMemType::Mem32) - | (bar_type == PciMemType::Mem64High) - | (bar_type == PciMemType::Io) { - let old_vaddr = dev.with_bar_ref(slot, |bar| 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 - * Read from config_value.bar_value cache instead of space - */ - let low_value = dev.with_config_value(|cv| cv.get_bar_value(slot - 1)) as u64; - let high_value = (value as u32 as u64) << 32; - (low_value | high_value) & !0xf - } else { - (value as u64) & !0xf - } - }; - - dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); - if bar_type == PciMemType::Mem64High { - dev.with_bar_ref_mut(slot - 1, |bar| bar.set_virtual_value(new_vaddr)); - } - - // Sync virtual_value back to space after processing (adding flags) - // TODO: check whether need sync here - let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()); - let _ = dev.write_emu(EndpointField::Bar(slot), virtual_value as usize); + let _ = dev.write_emu(EndpointField::Bar(slot), value); + if is_root { + let _ = dev.write_hw(offset, size, value); + } + // For Mem64Low, update virtual_value but don't update GPM yet + // (GPM will be updated when Mem64High is written) + if bar_type == PciMemType::Mem64Low { + let new_vaddr = (value as u64) & !0xf; + dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); + // Sync virtual_value back to emu value + let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()); + let _ = dev.write_emu(EndpointField::Bar(slot), virtual_value as usize); + } else if (bar_type == PciMemType::Mem32) + | (bar_type == PciMemType::Mem64High) + | (bar_type == PciMemType::Io) { + let old_vaddr = dev.with_bar_ref(slot, |bar| bar.get_virtual_value64()) & !0xf; + let new_vaddr = { if bar_type == PciMemType::Mem64High { - let virtual_value_low = dev.with_bar_ref(slot - 1, |bar| bar.get_virtual_value()); - let _ = dev.write_emu(EndpointField::Bar(slot - 1), virtual_value_low as usize); + /* last 4bit is flag, not address and need ignore + * flag will auto add when set_value and set_virtual_value + * Read from config_value.bar_value cache instead of space + */ + let low_value = dev.with_config_value(|cv| cv.get_bar_value(slot - 1)) as u64; + let high_value = (value as u32 as u64) << 32; + (low_value | high_value) & !0xf + } else { + (value as u64) & !0xf } + }; - let paddr = if is_root { - dev.with_bar_ref_mut(slot, |bar| bar.set_value(new_vaddr)); - if bar_type == PciMemType::Mem64High { - dev.with_bar_ref_mut(slot - 1, |bar| bar.set_value(new_vaddr)); - } - new_vaddr as HostPhysAddr - } else { - dev.with_bar_ref(slot, |bar| bar.get_value64()) as HostPhysAddr - }; + dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); + if bar_type == PciMemType::Mem64High { + dev.with_bar_ref_mut(slot - 1, |bar| bar.set_virtual_value(new_vaddr)); + } + + // Sync virtual_value back to space after processing (adding flags) + // TODO: check whether need sync here + let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()); + let _ = dev.write_emu(EndpointField::Bar(slot), virtual_value as usize); + if bar_type == PciMemType::Mem64High { + let virtual_value_low = dev.with_bar_ref(slot - 1, |bar| bar.get_virtual_value()); + let _ = dev.write_emu(EndpointField::Bar(slot - 1), virtual_value_low as usize); + } - let bar_size = { - let size = dev.with_bar_ref(slot, |bar| bar.get_size()); - if crate::memory::addr::is_aligned(size as usize) { - size - } else { - crate::memory::PAGE_SIZE as u64 - } - }; - let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) { - crate::memory::addr::align_up(new_vaddr as usize) as u64 + let paddr = if is_root { + dev.with_bar_ref_mut(slot, |bar| bar.set_value(new_vaddr)); + if bar_type == PciMemType::Mem64High { + dev.with_bar_ref_mut(slot - 1, |bar| bar.set_value(new_vaddr)); + } + new_vaddr as HostPhysAddr + } else { + dev.with_bar_ref(slot, |bar| bar.get_value64()) as HostPhysAddr + }; + + let bar_size = { + let size = dev.with_bar_ref(slot, |bar| bar.get_size()); + if crate::memory::addr::is_aligned(size as usize) { + size } else { - new_vaddr as u64 - }; - - if !is_root { - let zone = this_zone(); - let mut guard = zone.write(); - let gpm = &mut guard.gpm; - - if !gpm.try_delete(old_vaddr.try_into().unwrap(), bar_size as usize).is_ok() { - warn!( - "delete bar {}: can not found 0x{:x}", - slot, old_vaddr - ); - } - gpm.try_insert(MemoryRegion::new_with_offset_mapper( - new_vaddr as GuestPhysAddr, - paddr as HostPhysAddr, - bar_size as _, - MemFlags::READ | MemFlags::WRITE, - ))?; - /* after update gpm, mem barrier is needed - */ - #[cfg(target_arch = "aarch64")] - unsafe { - core::arch::asm!("isb"); - core::arch::asm!("tlbi vmalls12e1is"); - core::arch::asm!("dsb nsh"); - } - /* after update gpm, need to flush iommu table - * in x86_64 - */ - #[cfg(target_arch = "x86_64")] - crate::arch::iommu::flush( - zone_id, - vbdf.bus, - (vbdf.device << 3) + vbdf.function, + crate::memory::PAGE_SIZE as u64 + } + }; + let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) { + crate::memory::addr::align_up(new_vaddr as usize) as u64 + } else { + new_vaddr as u64 + }; + + if !is_root { + let zone = this_zone(); + let mut guard = zone.write(); + let gpm = &mut guard.gpm; + + if !gpm.try_delete(old_vaddr.try_into().unwrap(), bar_size as usize).is_ok() { + warn!( + "delete bar {}: can not found 0x{:x}", + slot, old_vaddr ); } + gpm.try_insert(MemoryRegion::new_with_offset_mapper( + new_vaddr as GuestPhysAddr, + paddr as HostPhysAddr, + bar_size as _, + MemFlags::READ | MemFlags::WRITE, + ))?; + /* after update gpm, mem barrier is needed + */ + #[cfg(target_arch = "aarch64")] + unsafe { + core::arch::asm!("isb"); + core::arch::asm!("tlbi vmalls12e1is"); + core::arch::asm!("dsb nsh"); + } + /* after update gpm, need to flush iommu table + * in x86_64 + */ + #[cfg(target_arch = "x86_64")] + crate::arch::iommu::flush( + zone_id, + vbdf.bus, + (vbdf.device << 3) + vbdf.function, + ); } + } } } else { // Re-fetch bar to get the latest virtual_value after potential write updates From 61cdcdbc778ac3bf6555f1864afa6b7c30dc3631 Mon Sep 17 00:00:00 2001 From: dallas Date: Tue, 23 Dec 2025 19:39:22 +0800 Subject: [PATCH 056/109] emu class and revision id for pci dev, so that prevent root to use dev that doesn't belong to it when using dirct handler --- src/pci/pci_access.rs | 22 ++++- src/pci/pci_struct.rs | 84 +++++++++++++---- src/pci/pci_test.rs | 173 ++++++++++++++++++++++++++++++++++- src/pci/vpci_dev/mod.rs | 4 +- src/pci/vpci_dev/standard.rs | 18 +++- 5 files changed, 272 insertions(+), 29 deletions(-) diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 8d96dfd3..3b127581 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -558,13 +558,13 @@ pub trait PciHeaderRW: PciRWBase { self.backend().read_u8(0x0e).unwrap().get_bit(7) } - fn revision_and_class(&self) -> (DeviceRevision, BaseClass, SubClass, Interface) { + fn revision_and_class(&self) -> (BaseClass, SubClass, Interface, DeviceRevision) { 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, + value.get_bits(0..8) as DeviceRevision, ) } @@ -826,7 +826,7 @@ pub enum EndpointField { impl Debug for EndpointField { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "EndpointField {{")?; - match self { + let _ =match self { EndpointField::ID => write!(f, "ID"), EndpointField::Command => write!(f, "Command"), EndpointField::Status => write!(f, "Status"), @@ -1043,7 +1043,7 @@ pub enum BridgeField { impl Debug for BridgeField { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "BridgeField {{")?; - match self { + let _ = match self { BridgeField::ID => write!(f, "ID"), BridgeField::Command => write!(f, "Command"), BridgeField::Status => write!(f, "Status"), @@ -1848,6 +1848,18 @@ fn handle_config_space_access_direct( } } } + EndpointField::RevisionIDAndClassCode => { + if !is_write { + if is_dev_belong_to_zone { + mmio.value = dev + .read_emu(EndpointField::RevisionIDAndClassCode) + .unwrap(); + } else if is_root { + // Default: base class 0xff, subclass/progIF/revision set to 0 + mmio.value = 0xff00_0000; + } + } + } EndpointField::Bar(slot) => { let bar_type = dev.with_bar_ref(slot, |bar| bar.get_type()); if bar_type != PciMemType::default() { @@ -2067,7 +2079,7 @@ pub fn mmio_vpci_direct_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult let is_root = is_this_root_zone(); - handle_config_space_access_direct(dev, mmio, offset, zone_id, is_root, is_dev_belong_to_zone); + let _ = handle_config_space_access_direct(dev, mmio, offset, zone_id, is_root, is_dev_belong_to_zone); Ok(()) } \ No newline at end of file diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index ef0e9be8..dbdedf29 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -27,7 +27,7 @@ use super::{ PciConfigHeader, PciField, PciHeaderRW, PciMem, PciMemType, PciRW, PciRomRW, }, PciConfigAddress, - pci_access::{BaseClass, SubClass, Interface, DeviceId, VendorId}, + pci_access::{BaseClass, SubClass, Interface, DeviceId, VendorId, DeviceRevision}, }; use crate::{error::{HvErrorNum, HvResult}, pci::vpci_dev::VpciDevType}; @@ -37,15 +37,15 @@ type VirtualPciConfigBits = BitArr!(for BIT_LENTH, in u8, Lsb0); #[derive(Clone, Debug)] pub struct ConfigValue { id: (DeviceId, VendorId), - class: (BaseClass, SubClass, Interface), + class_and_revision_id: (BaseClass, SubClass, Interface, DeviceRevision), bar_value: [u32; 6], } impl ConfigValue { - pub fn new(id: (DeviceId, VendorId), class: (BaseClass, SubClass, Interface)) -> Self { + pub fn new(id: (DeviceId, VendorId), class_and_revision_id: (BaseClass, SubClass, Interface, DeviceRevision)) -> Self { Self { id, - class, + class_and_revision_id, bar_value: [0; 6], } } @@ -58,12 +58,26 @@ impl ConfigValue { self.id = id; } + pub fn get_class_and_revision_id(&self) -> (BaseClass, SubClass, Interface, DeviceRevision) { + self.class_and_revision_id + } + pub fn get_class(&self) -> (BaseClass, SubClass, Interface) { - self.class + let (base, sub, interface, _) = self.class_and_revision_id; + (base, sub, interface) + } + + pub fn get_revision(&self) -> DeviceRevision { + self.class_and_revision_id.3 + } + + pub fn set_class_and_revision_id(&mut self, class_and_revision_id: (BaseClass, SubClass, Interface, DeviceRevision)) { + self.class_and_revision_id = class_and_revision_id; } pub fn set_class(&mut self, class: (BaseClass, SubClass, Interface)) { - self.class = class; + let (_, _, _, revision) = self.class_and_revision_id; + self.class_and_revision_id = (class.0, class.1, class.2, revision); } pub fn get_bar_value(&self, slot: usize) -> u32 { @@ -255,6 +269,7 @@ impl VirtualPciAccessBits { pub fn endpoint() -> Self { let mut bits = BitArray::ZERO; bits[0x0..0x4].fill(true); // ID + bits[0x08..0x0c].fill(true); // CLASS bits[0x10..0x34].fill(true); //bar and rom Self { bits } } @@ -555,7 +570,7 @@ impl VirtualPciConfigSpace { backend: Arc, bararr: Bar, rom: PciMem, - class: (BaseClass, SubClass, Interface), + class_and_revision_id: (DeviceRevision, BaseClass, SubClass, Interface), id: (DeviceId, VendorId), ) -> Self { Self { @@ -565,7 +580,7 @@ impl VirtualPciConfigSpace { vbdf: Bdf::default(), config_type: HeaderType::Endpoint, base, - config_value: ConfigValue::new(id, class), + config_value: ConfigValue::new(id, class_and_revision_id), control: VirtualPciConfigControl::endpoint(), access: VirtualPciAccessBits::endpoint(), backend, @@ -582,7 +597,7 @@ impl VirtualPciConfigSpace { backend: Arc, bararr: Bar, rom: PciMem, - class: (BaseClass, SubClass, Interface), + class_and_revision_id: (DeviceRevision, BaseClass, SubClass, Interface), id: (DeviceId, VendorId), ) -> Self { Self { @@ -592,7 +607,7 @@ impl VirtualPciConfigSpace { vbdf: Bdf::default(), config_type: HeaderType::PciBridge, base, - config_value: ConfigValue::new(id, class), + config_value: ConfigValue::new(id, class_and_revision_id), control: VirtualPciConfigControl::bridge(), access: VirtualPciAccessBits::bridge(), backend, @@ -611,7 +626,8 @@ impl VirtualPciConfigSpace { vbdf: Bdf::default(), config_type: HeaderType::Endpoint, base, - config_value: ConfigValue::new(id, (0u8,0u8,0u8)), + // Default class: base=0xFF, others 0, revision 0 + config_value: ConfigValue::new(id, (0xFFu8,0u8,0u8,0u8)), control: VirtualPciConfigControl::endpoint(), access: VirtualPciAccessBits::endpoint(), backend, @@ -622,7 +638,7 @@ impl VirtualPciConfigSpace { } } - pub fn host_bridge(bdf: Bdf, base: PciConfigAddress, backend: Arc, class: (BaseClass, SubClass, Interface)) -> Self { + pub fn host_bridge(bdf: Bdf, base: PciConfigAddress, backend: Arc, class_and_revision_id: (DeviceRevision, BaseClass, SubClass, Interface)) -> Self { Self { host_bdf: bdf, parent_bdf: bdf, @@ -630,7 +646,7 @@ impl VirtualPciConfigSpace { vbdf: bdf, config_type: HeaderType::Endpoint, base, - config_value: ConfigValue::new((0xFFFFu16, 0xFFFFu16), class), // Default ID for host bridge + config_value: ConfigValue::new((0xFFFFu16, 0xFFFFu16), class_and_revision_id), // Default ID for host bridge control: VirtualPciConfigControl::host_bridge(), access: VirtualPciAccessBits::host_bridge(), backend, @@ -719,6 +735,14 @@ impl VirtualPciConfigSpace { let id_value = ((id.0 as u32) << 16) | (id.1 as u32); Ok(id_value as usize) } + EndpointField::RevisionIDAndClassCode => { + let (base, sub, interface, revision) = self.config_value.get_class_and_revision_id(); + let value = ((base as u32) << 24) + | ((sub as u32) << 16) + | ((interface as u32) << 8) + | (revision as u32); + Ok(value as usize) + } EndpointField::Bar(slot) => { // Read bar_value from cache if slot < 6 { @@ -729,6 +753,7 @@ impl VirtualPciConfigSpace { } _ => { // For other fields, read from backend + warn!("read emu {:#?} failed, try read from hw", field); self.backend.read(offset, size) } } @@ -773,6 +798,15 @@ impl VirtualPciConfigSpace { (value & 0xFFFF) as VendorId, )); } + EndpointField::RevisionIDAndClassCode => { + // Update cached revision/class code + let revision = (value & 0xff) as DeviceRevision; + let interface = ((value >> 8) & 0xff) as Interface; + let sub = ((value >> 16) & 0xff) as SubClass; + let base = ((value >> 24) & 0xff) as BaseClass; + self.config_value + .set_class_and_revision_id((base, sub, interface, revision)); + } EndpointField::Bar(slot) => { // Update bar_value cache when writing bar if slot < 6 { @@ -785,6 +819,7 @@ impl VirtualPciConfigSpace { } // Write to backend + warn!("write emu {:#?} failed, try write to hw", field); self.backend.write(offset, size, value) } _ => { @@ -887,8 +922,7 @@ impl PciIterator { self.is_mulitple_function = pci_header.has_multiple_functions(); } - let (_, base_class, sub_class, interface) = pci_header.revision_and_class(); - let class = (base_class, sub_class, interface); + let class_and_revision = pci_header.revision_and_class(); match pci_header.header_type() { HeaderType::Endpoint => { @@ -908,7 +942,15 @@ impl PciIterator { info!("get node bar mem init end {:#?}", bararr); let ep = Arc::new(ep); - let mut node = VirtualPciConfigSpace::endpoint(bdf, pci_addr_base, ep, bararr, rom, class, (device_id, vender_id)); + let mut node = VirtualPciConfigSpace::endpoint( + bdf, + pci_addr_base, + ep, + bararr, + rom, + class_and_revision, + (device_id, vender_id), + ); let _ = node.capability_enumerate(); @@ -924,7 +966,15 @@ impl PciIterator { Self::bar_mem_init(bridge.bar_limit().into(), &mut self.allocator, &mut bridge); let bridge = Arc::new(bridge); - let mut node = VirtualPciConfigSpace::bridge(bdf, pci_addr_base, bridge, bararr, rom, class, (device_id, vender_id)); + let mut node = VirtualPciConfigSpace::bridge( + bdf, + pci_addr_base, + bridge, + bararr, + rom, + class_and_revision, + (device_id, vender_id), + ); let _ = node.capability_enumerate(); diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs index 43b9a9b3..c4c19211 100644 --- a/src/pci/pci_test.rs +++ b/src/pci/pci_test.rs @@ -65,7 +65,7 @@ pub fn pcie_guest_init() { let bdf = Bdf::from_str("0000:00:00.0").unwrap(); let base = 0x4010000000; // Base address for test let backend = EndpointHeader::new_with_region(PciConfigMmio::new(base, CONFIG_LENTH)); - let dev = VirtualPciConfigSpace::host_bridge(bdf, base, Arc::new(backend), (0x6u8,0x0u8,0u8)); + let dev = VirtualPciConfigSpace::host_bridge(bdf, base, Arc::new(backend), (0x6u8,0u8,0u8,0x0)); vbus.insert(vbdf, dev); let vbdf = Bdf::from_str("0000:00:01.0").unwrap(); @@ -234,3 +234,174 @@ pub fn dwc_pcie_guest_test() { info!("pcie dwc test passed"); } + +pub fn ecam_pcie_guest_test64() { + let zone = this_zone(); + let bdf = Bdf::from_str("0000:00:02.0").unwrap(); + // Get base from VirtualPciConfigSpace and add offset + // Use a block scope to ensure the read lock is released before calling mmio_vpci_direct_handler + let address = { + let vbus = &zone.read().vpci_bus; + if let Some(vdev) = vbus.get(&bdf) { + vdev.read().get_base() + } else { + warn!("can not find dev {:#?} for test", bdf); + 0 + } + }; + + if address == 0 { + warn!("Failed to get device base address"); + return; + } + + // 64-bit BAR: slot 4 (Mem64Low) at offset 0x20, slot 5 (Mem64High) at offset 0x24 + let bar_low_offset = 0x20; // slot 4: 0x10 + 4 * 4 + let bar_high_offset = 0x24; // slot 5: 0x10 + 5 * 4 + + let test_address_low = address + bar_low_offset; + let test_address_high = address + bar_high_offset; + + info!("Testing 64-bit BAR for device {:#?}", bdf); + info!("Base address: 0x{:x}, BAR Low offset: 0x{:x}, BAR High offset: 0x{:x}", + address, bar_low_offset, bar_high_offset); + + let mut mmio = MMIOAccess { + address: test_address_low as _, + size: 4, + is_write: false, + value: 0, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + info!( + "Step 1 - Read Mem64Low (offset 0x{:x}): value 0x{:x}", + bar_low_offset, mmio.value + ); + + let mut mmio = MMIOAccess { + address: test_address_low as _, + size: 4, + is_write: true, + value: 0xFFFF_FFFF, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + info!( + "Step 2 - Write 0xFFFF_FFFF to Mem64Low (size probe)" + ); + + let mut mmio = MMIOAccess { + address: test_address_low as _, + size: 4, + is_write: false, + value: 0, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + info!( + "Step 3 - Read Mem64Low after size probe: value 0x{:x}", + mmio.value + ); + + let low_addr = 0x90000000; + let mut mmio = MMIOAccess { + address: test_address_low as _, + size: 4, + is_write: true, + value: low_addr, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + info!( + "Step 4 - Write low 32-bit address 0x{:x} to Mem64Low", + low_addr + ); + + let mut mmio = MMIOAccess { + address: test_address_low as _, + size: 4, + is_write: false, + value: 0, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + let read_low = mmio.value; + info!( + "Step 5 - Read Mem64Low: value 0x{:x}", + read_low + ); + + let high_addr = 0x00000001; // High 32 bits of 64-bit address + let mut mmio = MMIOAccess { + address: test_address_high as _, + size: 4, + is_write: true, + value: high_addr, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + info!( + "Step 6 - Write high 32-bit address 0x{:x} to Mem64High", + high_addr + ); + + let mut mmio = MMIOAccess { + address: test_address_low as _, + size: 4, + is_write: false, + value: 0, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + let final_low = mmio.value; + + let mut mmio = MMIOAccess { + address: test_address_high as _, + size: 4, + is_write: false, + value: 0, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + let final_high = mmio.value; + + let full_64bit_addr = (final_low as u64) | ((final_high as u64) << 32); + info!( + "Step 7 - Full 64-bit address: Mem64Low=0x{:x}, Mem64High=0x{:x}, Combined=0x{:x}", + final_low, final_high, full_64bit_addr + ); + + let new_low_addr = 0x70000000; + let mut mmio = MMIOAccess { + address: test_address_low as _, + size: 4, + is_write: true, + value: new_low_addr, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + info!( + "Step 8 - Write new low address 0x{:x} to Mem64Low", + new_low_addr + ); + + let mut mmio = MMIOAccess { + address: test_address_low as _, + size: 4, + is_write: false, + value: 0, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + info!( + "Step 9 - Read Mem64Low after update: value 0x{:x}", + mmio.value + ); + + let mut mmio = MMIOAccess { + address: test_address_high as _, + size: 4, + is_write: false, + value: 0, + }; + let _ = mmio_vpci_direct_handler(&mut mmio, 0); + info!( + "Step 10 - Read Mem64High: value 0x{:x}", + mmio.value + ); + + info!("pcie guest test64 passed"); + + loop {} +} diff --git a/src/pci/vpci_dev/mod.rs b/src/pci/vpci_dev/mod.rs index a51d014f..61bc1c05 100644 --- a/src/pci/vpci_dev/mod.rs +++ b/src/pci/vpci_dev/mod.rs @@ -145,14 +145,14 @@ pub(super) fn init_config_value_with_type(dev_type: VpciDevType) -> ConfigValue VpciDevType::Physical => { // Physical devices use default values warn!("init_config_value_with_type: physical device is not supported"); - return ConfigValue::new((0xFFFFu16, 0xFFFFu16), (0u8, 0u8, 0u8)); + return ConfigValue::new((0xFFFFu16, 0xFFFFu16), (0xFFu8, 0u8, 0u8, 0u8)); } _ => { if let Some(handler) = get_handler(dev_type) { handler.init_config_space() } else { warn!("init_config_value_with_type: unknown device type"); - ConfigValue::new((0xFFFFu16, 0xFFFFu16), (0u8, 0u8, 0u8)) + ConfigValue::new((0xFFFFu16, 0xFFFFu16), (0xFFu8, 0u8, 0u8, 0u8)) } } } diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index 53899c8a..6b0e842e 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -1,6 +1,6 @@ use crate::error::HvResult; use crate::pci::pci_struct::ConfigValue; -use crate::pci::pci_access::{EndpointField, Bar, DeviceId, VendorId, BaseClass, SubClass, Interface}; +use crate::pci::pci_access::{EndpointField, Bar, DeviceId, VendorId, BaseClass, SubClass, Interface, DeviceRevision}; use crate::pci::PciConfigAddress; use super::{PciConfigAccessStatus, VpciDeviceHandler}; // use crate::memory::frame::Frame; @@ -100,9 +100,19 @@ impl VpciDeviceHandler for StandardHandler { fn init_config_space(&self) -> ConfigValue { let id :(DeviceId, VendorId) = (0x110a, 0x4106); - let class :(BaseClass, SubClass, Interface) = (0x0, 0x0, 0x0); - - ConfigValue::new(id, class) + let revision: DeviceRevision = 0xFFu8; + let base_class: BaseClass = 0x0; + let sub_class: SubClass = 0x0; + let interface: Interface = 0x0; + ConfigValue::new( + id, + ( + base_class as BaseClass, + sub_class as SubClass, + interface as Interface, + revision as DeviceRevision, + ), + ) } fn init_bar(&self) -> Bar { From 4f470718178680a6a03fc4ea0a24234308153559 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 24 Dec 2025 15:57:30 +0800 Subject: [PATCH 057/109] change vdev handler interface and set default value for vdev --- src/pci/pci_access.rs | 13 +-- src/pci/pci_struct.rs | 157 ++++++++++++++++++----------------- src/pci/vpci_dev/mod.rs | 116 +++++++++++++++++--------- src/pci/vpci_dev/standard.rs | 72 +++++----------- 4 files changed, 189 insertions(+), 169 deletions(-) diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 3b127581..1935e835 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -694,11 +694,6 @@ pub trait PciBarRW: PciRWBase { } } -impl Bar { - pub fn virt_bar_init(dev_type: VpciDevType) -> Self { - crate::pci::vpci_dev::virt_bar_init(dev_type) - } -} pub trait PciRomRW: PciRWBase { fn rom_offset(&self) -> u64; @@ -1290,7 +1285,13 @@ fn handle_config_space_access( /* for mem64, Mem64High always write after Mem64Low, * so update bar when write Mem64High */ - if (bar_type == PciMemType::Mem32) + if bar_type == PciMemType::Mem64Low { + let new_vaddr = (value as u64) & !0xf; + dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); + // Sync virtual_value back to emu value + let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()); + let _ = dev.write_emu(EndpointField::Bar(slot), virtual_value as usize); + } else if (bar_type == PciMemType::Mem32) | (bar_type == PciMemType::Mem64High) | (bar_type == PciMemType::Io) { diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index dbdedf29..86aeb96d 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -41,6 +41,16 @@ pub struct ConfigValue { bar_value: [u32; 6], } +impl Default for ConfigValue { + fn default() -> Self { + Self { + id: (0xFFFFu16, 0xFFFFu16), + class_and_revision_id: (0xFFu8, 0u8, 0u8, 0u8), + bar_value: [0; 6], + } + } +} + impl ConfigValue { pub fn new(id: (DeviceId, VendorId), class_and_revision_id: (BaseClass, SubClass, Interface, DeviceRevision)) -> Self { Self { @@ -106,7 +116,7 @@ impl ConfigValue { const MAX_DEVICE: u8 = 31; const MAX_FUNCTION: u8 = 7; pub const CONFIG_LENTH: u64 = 256; -pub const BIT_LENTH: usize = 128 * 5; +pub const BIT_LENTH: usize = 4096; // PCIe Device/Port Type values const PCI_EXP_TYPE_ROOT_PORT: u16 = 4; @@ -512,6 +522,26 @@ impl VirtualPciConfigSpace { self.dev_type } + pub fn get_config_value(&self) -> &ConfigValue { + &self.config_value + } + + /// Execute a closure with a mutable reference to the config_value + pub fn with_config_value_mut(&mut self, f: F) -> R + where + F: FnOnce(&mut ConfigValue) -> R, + { + f(&mut self.config_value) + } + + /// Execute a closure with a mutable reference to the bararr + pub fn with_bararr_mut(&mut self, f: F) -> R + where + F: FnOnce(&mut Bar) -> R, + { + f(&mut self.bararr) + } + // TODO: check whether need update config pub fn update_config(&mut self, offset: PciConfigAddress, size: usize, _value: usize) { @@ -541,12 +571,13 @@ impl Debug for VirtualPciConfigSpace { } impl VirtualPciConfigSpace { - pub fn virt_dev( + pub(super) fn virt_dev_init_default( bdf: Bdf, base: PciConfigAddress, dev_type: VpciDevType, + config_value: ConfigValue, + bararr: Bar, ) -> Self { - let config_value = crate::pci::vpci_dev::init_config_value_with_type(dev_type); Self { host_bdf: Bdf::default(), parent_bdf: Bdf::default(), @@ -558,12 +589,20 @@ impl VirtualPciConfigSpace { control: VirtualPciConfigControl::virt_dev(), access: VirtualPciAccessBits::virt_dev(), backend: Arc::new(EndpointHeader::new_with_region(PciConfigMmio::new(base, CONFIG_LENTH))), - bararr: Bar::virt_bar_init(dev_type), + bararr, rom: PciMem::default(), capabilities: PciCapabilityList::new(), dev_type, } } + + pub fn virt_dev( + bdf: Bdf, + base: PciConfigAddress, + dev_type: VpciDevType, + ) -> Self { + crate::pci::vpci_dev::virt_dev_init(bdf, base, dev_type) + } pub fn endpoint( bdf: Bdf, base: PciConfigAddress, @@ -725,41 +764,34 @@ impl VirtualPciConfigSpace { pub fn read_emu(&mut self, field: EndpointField) -> HvResult { let offset = field.to_offset() as PciConfigAddress; let size = field.size(); - - match size { - 1 | 2 | 4 => { - match field { - EndpointField::ID => { - // Read ID from cached config_value.id field - let id = self.config_value.get_id(); - let id_value = ((id.0 as u32) << 16) | (id.1 as u32); - Ok(id_value as usize) - } - EndpointField::RevisionIDAndClassCode => { - let (base, sub, interface, revision) = self.config_value.get_class_and_revision_id(); - let value = ((base as u32) << 24) - | ((sub as u32) << 16) - | ((interface as u32) << 8) - | (revision as u32); - Ok(value as usize) - } - EndpointField::Bar(slot) => { - // Read bar_value from cache - if slot < 6 { - Ok(self.config_value.get_bar_value(slot) as usize) - } else { - self.backend.read(offset, size) - } - } - _ => { - // For other fields, read from backend - warn!("read emu {:#?} failed, try read from hw", field); - self.backend.read(offset, size) - } + + match field { + EndpointField::ID => { + // Read ID from cached config_value.id field + let id = self.config_value.get_id(); + let id_value = ((id.0 as u32) << 16) | (id.1 as u32); + Ok(id_value as usize) + } + EndpointField::RevisionIDAndClassCode => { + let (base, sub, interface, revision) = self.config_value.get_class_and_revision_id(); + let value = ((base as u32) << 24) + | ((sub as u32) << 16) + | ((interface as u32) << 8) + | (revision as u32); + Ok(value as usize) + } + EndpointField::Bar(slot) => { + // Read bar_value from cache + if slot < 6 { + Ok(self.config_value.get_bar_value(slot) as usize) + } else { + hv_result_err!(EFAULT, "pci: invalid bar slot: {slot}") } } _ => { - hv_result_err!(EFAULT, "pci: invalid virtual mmio read size: {size}") + // For other fields, read from backend + warn!("read emu {:#?} failed, try read from hw", field); + self.backend.read(offset, size) } } } @@ -776,64 +808,35 @@ impl VirtualPciConfigSpace { } _ => { // Fallback to backend read - let offset = field.to_offset() as PciConfigAddress; - let low = self.backend.read(offset, 4)? as u64; - let high = self.backend.read(offset + 4, 4)? as u64; - Ok(low | (high << 32)) + warn!("read emu64 {:#?} failed", field); + Ok(0) } } } pub fn write_emu(&mut self, field: EndpointField, value: usize) -> HvResult { - let offset = field.to_offset() as PciConfigAddress; - let size = field.size(); - - match size { - 1 | 2 | 4 => { - match field { - EndpointField::ID => { - // Update ID cache when writing ID field - self.config_value.set_id(( - ((value >> 16) & 0xFFFF) as DeviceId, - (value & 0xFFFF) as VendorId, - )); - } - EndpointField::RevisionIDAndClassCode => { - // Update cached revision/class code - let revision = (value & 0xff) as DeviceRevision; - let interface = ((value >> 8) & 0xff) as Interface; - let sub = ((value >> 16) & 0xff) as SubClass; - let base = ((value >> 24) & 0xff) as BaseClass; - self.config_value - .set_class_and_revision_id((base, sub, interface, revision)); - } - EndpointField::Bar(slot) => { - // Update bar_value cache when writing bar - if slot < 6 { - self.config_value.set_bar_value(slot, value as u32); - } - } - _ => { - // For other fields, write to backend - } + match field { + EndpointField::Bar(slot) => { + // Update bar_value cache when writing bar + if slot < 6 { + self.config_value.set_bar_value(slot, value as u32); } - - // Write to backend - warn!("write emu {:#?} failed, try write to hw", field); - self.backend.write(offset, size, value) } _ => { - hv_result_err!(EFAULT, "pci: invalid virtual mmio write size: {size}") + // For other fields, write to backend + warn!("write emu {:#?} denied", field); } } + Ok(()) } +} // Legacy method for backward compatibility - converts offset/size to EndpointField // pub fn write_emu_legacy(&mut self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { // let field = EndpointField::from(offset as usize, size); // self.write_emu(field, value) // } -} + #[derive(Debug)] pub struct PciIterator { diff --git a/src/pci/vpci_dev/mod.rs b/src/pci/vpci_dev/mod.rs index 61bc1c05..65113fad 100644 --- a/src/pci/vpci_dev/mod.rs +++ b/src/pci/vpci_dev/mod.rs @@ -1,20 +1,50 @@ -use crate::pci::pci_struct::{ConfigValue, ArcRwLockVirtualPciConfigSpace}; +use crate::pci::pci_struct::{ConfigValue, ArcRwLockVirtualPciConfigSpace, VirtualPciConfigSpace, Bdf}; use crate::pci::PciConfigAddress; use crate::error::HvResult; use crate::pci::pci_access::{Bar, EndpointField}; +// Standard virtual device configuration space defaults +pub(crate) const STANDARD_CFG_SIZE: usize = 0x80; +pub(crate) const DEFAULT_CSPACE_U32: [u32; STANDARD_CFG_SIZE / 4] = { + const STANDARD_VENDOR_ID: u16 = 0x110a; + const STANDARD_DEVICE_ID: u16 = 0x4106; + const PCI_STS_CAPS: u16 = 0x10; + const PCI_DEV_CLASS_OTHER: u8 = 0xff; + const PCI_CFG_CAPS: usize = 0x34; + const PCI_CAP_ID_VNDR: u8 = 0x09; + const PCI_CAP_ID_MSIX: u8 = 0x11; + const STANDARD_CFG_VNDR_CAP: u8 = 0x40; + const STANDARD_CFG_VNDR_LEN: u8 = 0x20; + const STANDARD_CFG_MSIX_CAP: usize = 0x60; + const STANDARD_MSIX_VECTORS: u16 = 16; + + let mut arr = [0u32; STANDARD_CFG_SIZE / 4]; + arr[0x00 / 4] = (STANDARD_DEVICE_ID as u32) << 16 | STANDARD_VENDOR_ID as u32; + arr[0x04 / 4] = (PCI_STS_CAPS as u32) << 16; + arr[0x08 / 4] = (PCI_DEV_CLASS_OTHER as u32) << 24; + arr[0x2c / 4] = (STANDARD_DEVICE_ID as u32) << 16 | STANDARD_VENDOR_ID as u32; + arr[PCI_CFG_CAPS / 4] = STANDARD_CFG_VNDR_CAP as u32; + arr[STANDARD_CFG_VNDR_CAP as usize / 4] = (STANDARD_CFG_VNDR_LEN as u32) << 16 + | (STANDARD_CFG_MSIX_CAP as u32) << 8 + | PCI_CAP_ID_VNDR as u32; + arr[STANDARD_CFG_MSIX_CAP / 4] = (0x00u32) << 8 | PCI_CAP_ID_MSIX as u32; + arr[(STANDARD_CFG_MSIX_CAP + 0x4) / 4] = 1; + arr[(STANDARD_CFG_MSIX_CAP + 0x8) / 4] = ((0x10 * STANDARD_MSIX_VECTORS) as u32) | 1; + arr +}; + pub mod standard; /* * PciConfigAccessStatus is used to return the result of the config space access * Done(usize): the value is returned in usize - * Perform: use read_emu to read the value from the space + * Default: use default config space value * Reject: the access is rejected */ #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) enum PciConfigAccessStatus { Done(usize), - Perform, + Default, Reject, } @@ -30,8 +60,7 @@ pub enum VpciDevType { pub trait VpciDeviceHandler: Sync + Send { fn read_cfg(&self, dev: ArcRwLockVirtualPciConfigSpace, offset: PciConfigAddress, size: usize) -> HvResult; fn write_cfg(&self, dev: ArcRwLockVirtualPciConfigSpace, offset: PciConfigAddress, size: usize, value: usize) -> HvResult; - fn init_config_space(&self) -> ConfigValue; - fn init_bar(&self) -> Bar; + fn vdev_init(&self, dev: VirtualPciConfigSpace) -> VirtualPciConfigSpace; } /* @@ -69,12 +98,29 @@ pub(super) fn vpci_dev_read_cfg( PciConfigAccessStatus::Done(value) => { Ok(value) } - PciConfigAccessStatus::Perform => { - // warn!("vpci_dev_read_cfg: perform, offset {:#x}, size {:#x}", offset, size); - // warn!("vpci_dev_read_cfg: node {:#?}", node.space); + PciConfigAccessStatus::Default => { + // If this is a standard virtual device, read from DEFAULT_CSPACE_U32 + if offset < STANDARD_CFG_SIZE as PciConfigAddress { + let u32_offset = (offset as usize) / 4; + let u32_value = DEFAULT_CSPACE_U32[u32_offset]; + + // Extract the appropriate bytes based on size and offset within the u32 + let byte_offset_in_u32 = (offset as usize) % 4; + let value = match size { + 1 => ((u32_value >> (byte_offset_in_u32 * 8)) & 0xFF) as usize, + 2 => ((u32_value >> (byte_offset_in_u32 * 8)) & 0xFFFF) as usize, + 4 => u32_value as usize, + _ => { + warn!("vpci_dev_read_cfg: invalid size {size}, try read from emu"); + let field = EndpointField::from(offset as usize, size); + return node.write().read_emu(field); + } + }; + return Ok(value); + } + // For other device types or out of range, use read_emu let field = EndpointField::from(offset as usize, size); - let r = node.write().read_emu(field).unwrap(); - // warn!("vpci_dev_read_cfg: perform result {:#x}", r); + let r = node.write().read_emu(field)?; Ok(r) } PciConfigAccessStatus::Reject => { @@ -116,10 +162,9 @@ pub(super) fn vpci_dev_write_cfg( PciConfigAccessStatus::Done(_) => { Ok(()) } - PciConfigAccessStatus::Perform => { - warn!("vpci_dev_write_cfg: perform"); - let field = EndpointField::from(offset as usize, size); - node.write().write_emu(field, value) + PciConfigAccessStatus::Default => { + warn!("vpci_dev_write_cfg: Default"); + Ok(()) } PciConfigAccessStatus::Reject => { warn!("vpci_dev_write_cfg: operation rejected"); @@ -140,36 +185,33 @@ pub(super) fn vpci_dev_write_cfg( } } -pub(super) fn init_config_value_with_type(dev_type: VpciDevType) -> ConfigValue { +pub(super) fn virt_dev_init( + bdf: Bdf, + base: PciConfigAddress, + dev_type: VpciDevType, +) -> VirtualPciConfigSpace { + // Create initial VirtualPciConfigSpace with default values + let initial_dev = VirtualPciConfigSpace::virt_dev_init_default( + bdf, + base, + dev_type, + ConfigValue::default(), + Bar::default() + ); + match dev_type { VpciDevType::Physical => { // Physical devices use default values - warn!("init_config_value_with_type: physical device is not supported"); - return ConfigValue::new((0xFFFFu16, 0xFFFFu16), (0xFFu8, 0u8, 0u8, 0u8)); - } - _ => { - if let Some(handler) = get_handler(dev_type) { - handler.init_config_space() - } else { - warn!("init_config_value_with_type: unknown device type"); - ConfigValue::new((0xFFFFu16, 0xFFFFu16), (0xFFu8, 0u8, 0u8, 0u8)) - } - } - } -} - -pub(super) fn virt_bar_init(dev_type: VpciDevType) -> Bar { - match dev_type { - VpciDevType::Physical => { - // Physical devices use default (all zeros) space - unreachable!("virt_bar_init: physical device is not supported"); + warn!("virt_dev_init: physical device is not supported"); + initial_dev } _ => { if let Some(handler) = get_handler(dev_type) { - handler.init_bar() + // Let handler modify and return the device + handler.vdev_init(initial_dev) } else { - warn!("init_config_value_with_type: unknown device type"); - Bar::default() + warn!("virt_dev_init: unknown device type"); + initial_dev } } } diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index 6b0e842e..00a19d2b 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -1,6 +1,6 @@ use crate::error::HvResult; -use crate::pci::pci_struct::ConfigValue; -use crate::pci::pci_access::{EndpointField, Bar, DeviceId, VendorId, BaseClass, SubClass, Interface, DeviceRevision}; +use crate::pci::pci_struct::VirtualPciConfigSpace; +use crate::pci::pci_access::{EndpointField, DeviceId, VendorId, BaseClass, SubClass, Interface, DeviceRevision}; use crate::pci::PciConfigAddress; use super::{PciConfigAccessStatus, VpciDeviceHandler}; // use crate::memory::frame::Frame; @@ -9,34 +9,6 @@ use crate::percpu::this_zone; use crate::memory::MMIOAccess; use crate::pci::pci_access::PciMemType; -// const STANDARD_VENDOR_ID: u16 = 0x110a; -// const STANDARD_DEVICE_ID: u16 = 0x4106; -// const PCI_STS_CAPS: u16 = 0x10; // bit 4 -// const PCI_DEV_CLASS_OTHER: u8 = 0xff; -// const PCI_CFG_CAPS: usize = 0x34; -// const PCI_CAP_ID_VNDR: u8 = 0x09; -// const PCI_CAP_ID_MSIX: u8 = 0x11; -// const STANDARD_CFG_VNDR_CAP: u8 = 0x40; -// const STANDARD_CFG_VNDR_LEN: u8 = 0x20; -// const STANDARD_CFG_MSIX_CAP: usize = 0x60; // VNDR_CAP + VNDR_LEN -// const STANDARD_MSIX_VECTORS: u16 = 16; -// const STANDARD_CFG_SIZE: usize = 0x80; - -// pub(crate) const DEFAULT_CSPACE_U32: [u32; STANDARD_CFG_SIZE / 4] = { -// let mut arr = [0u32; STANDARD_CFG_SIZE / 4]; -// arr[0x00 / 4] = (STANDARD_DEVICE_ID as u32) << 16 | STANDARD_VENDOR_ID as u32; -// arr[0x04 / 4] = (PCI_STS_CAPS as u32) << 16; -// arr[0x08 / 4] = (PCI_DEV_CLASS_OTHER as u32) << 24; -// arr[0x2c / 4] = (STANDARD_DEVICE_ID as u32) << 16 | STANDARD_VENDOR_ID as u32; -// arr[PCI_CFG_CAPS / 4] = STANDARD_CFG_VNDR_CAP as u32; -// arr[STANDARD_CFG_VNDR_CAP as usize / 4] = (STANDARD_CFG_VNDR_LEN as u32) << 16 -// | (STANDARD_CFG_MSIX_CAP as u32) << 8 -// | PCI_CAP_ID_VNDR as u32; -// arr[STANDARD_CFG_MSIX_CAP / 4] = (0x00u32) << 8 | PCI_CAP_ID_MSIX as u32; -// arr[(STANDARD_CFG_MSIX_CAP + 0x4) / 4] = 1; -// arr[(STANDARD_CFG_MSIX_CAP + 0x8) / 4] = ((0x10 * STANDARD_MSIX_VECTORS) as u32) | 1; -// arr -// }; /// Handler for standard virtual PCI devices pub struct StandardHandler; @@ -47,7 +19,7 @@ impl VpciDeviceHandler for StandardHandler { match EndpointField::from(offset as usize, size) { EndpointField::ID => { warn!("virt pci standard read_cfg, id {:#x}", offset); - Ok(PciConfigAccessStatus::Perform) + Ok(PciConfigAccessStatus::Default) } EndpointField::Bar(0) => { let slot = 0; @@ -62,7 +34,7 @@ impl VpciDeviceHandler for StandardHandler { } } _ => { - Ok(PciConfigAccessStatus::Perform) + Ok(PciConfigAccessStatus::Default) } } } @@ -86,7 +58,7 @@ impl VpciDeviceHandler for StandardHandler { } else { let zone = this_zone(); let mut guard = zone.write(); - warn!("virtual pci standard write_cfg, register mmio region {:#x}, size {:#x}", value, bar_size); + info!("virtual pci standard write_cfg, register mmio region {:#x}, size {:#x}", value, bar_size); guard.mmio_region_register(value as usize, bar_size as usize, mmio_vdev_standard_handler, value); } @@ -98,29 +70,31 @@ impl VpciDeviceHandler for StandardHandler { } } - fn init_config_space(&self) -> ConfigValue { + fn vdev_init(&self, mut dev: VirtualPciConfigSpace) -> VirtualPciConfigSpace { + // Set config_value let id :(DeviceId, VendorId) = (0x110a, 0x4106); let revision: DeviceRevision = 0xFFu8; let base_class: BaseClass = 0x0; let sub_class: SubClass = 0x0; let interface: Interface = 0x0; - ConfigValue::new( - id, - ( - base_class as BaseClass, - sub_class as SubClass, - interface as Interface, - revision as DeviceRevision, - ), - ) - } - - fn init_bar(&self) -> Bar { + dev.with_config_value_mut(|config_value| { + config_value.set_id(id); + config_value.set_class_and_revision_id(( + base_class, + sub_class, + interface, + revision, + )); + }); + + // Set bararr let your_addr = 0x0; - let mut bar = Bar::default(); let size = 0x1000; - bar[0].config_init(PciMemType::Mem32, false, size as u64, your_addr); - bar + dev.with_bararr_mut(|bararr| { + bararr[0].config_init(PciMemType::Mem32, false, size as u64, your_addr); + }); + + dev } } From 4f5242dbc1253991392b87323e41e82e2d7059d6 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 25 Dec 2025 01:59:02 +0800 Subject: [PATCH 058/109] add cap for vdev --- src/pci/pci_access.rs | 114 ++++++++- src/pci/pci_struct.rs | 433 ++++++++++++++++++++++------------- src/pci/vpci_dev/mod.rs | 144 +++++++++++- src/pci/vpci_dev/standard.rs | 47 +++- 4 files changed, 550 insertions(+), 188 deletions(-) diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 1935e835..44626f7a 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -920,7 +920,7 @@ impl EndpointField { (0x2c, 2) => EndpointField::SubsystemVendorId, (0x2e, 2) => EndpointField::SubsystemId, (0x30, 4) => EndpointField::ExpansionRomBar, - (0x34, 1) => EndpointField::CapabilityPointer, + (0x34, 4) => EndpointField::CapabilityPointer, (0x3c, 1) => EndpointField::InterruptLine, (0x3d, 1) => EndpointField::InterruptPin, (0x3e, 1) => EndpointField::MinGnt, @@ -1445,7 +1445,9 @@ fn handle_config_space_access( mmio.value = dev.read_emu(EndpointField::ID).unwrap() as usize; } } - _ => {} + _ => { + mmio.value = 0; + } } } HeaderType::PciBridge => { @@ -1458,10 +1460,56 @@ fn handle_config_space_access( } } _ => { - if mmio.is_write { - super::vpci_dev::vpci_dev_write_cfg(dev_type, dev.clone(), offset, size, value).unwrap(); - } else { - mmio.value = super::vpci_dev::vpci_dev_read_cfg(dev_type, dev.clone(), offset, size).unwrap() as usize; + // warn!("virt pci standard rw offset {:#x}, size {:#x}", offset, size); + let result = dev.with_cap(|capabilities| { + if let Some((cap_offset, cap)) = capabilities.range(..=offset).next_back() { + info!("find cap at offset {:#x}, cap {:#?}", cap_offset, cap.get_type()); + let end = *cap_offset + cap.get_size() as u64; + if offset >= end { + // hv_result_err!(ENOENT) + warn!("virt pci cap rw offset {:#x} out of range", offset); + } + let relative_offset = offset - *cap_offset; + + if is_write { + cap.with_region_mut(|region| { + match region.write(relative_offset, size, mmio.value as u32) { + Ok(()) => Ok(0), + Err(e) => { + warn!("Failed to write capability at offset 0x{:x}: {:?}", offset, e); + Err(e) + } + } + }) + } else { + cap.with_region(|region| { + match region.read(relative_offset, size) { + Ok(val) => Ok(val), + Err(e) => { + warn!("Failed to read capability at offset 0x{:x}: {:?}", offset, e); + Err(e) + } + } + }) + } + } else { + hv_result_err!(ENOENT) + } + }); + + match result { + Ok(val) => { + if !is_write { + mmio.value = val as usize; + } + } + Err(_) => { + if mmio.is_write { + super::vpci_dev::vpci_dev_write_cfg(dev_type, dev.clone(), offset, size, value).unwrap(); + } else { + mmio.value = super::vpci_dev::vpci_dev_read_cfg(dev_type, dev.clone(), offset, size).unwrap() as usize; + } + } } } } @@ -2027,10 +2075,56 @@ fn handle_config_space_access_direct( } } _ => { - if mmio.is_write { - super::vpci_dev::vpci_dev_write_cfg(dev.get_dev_type(), dev.clone(), offset, size, value).unwrap(); - } else { - mmio.value = super::vpci_dev::vpci_dev_read_cfg(dev.get_dev_type(), dev.clone(), offset, size).unwrap() as usize; + // warn!("virt pci standard rw offset {:#x}, size {:#x}", offset, size); + let result = dev.with_cap(|capabilities| { + if let Some((cap_offset, cap)) = capabilities.range(..=offset).next_back() { + info!("find cap at offset {:#x}, cap {:#?}", cap_offset, cap.get_type()); + let end = *cap_offset + cap.get_size() as u64; + if offset >= end { + // hv_result_err!(ENOENT) + warn!("virt pci cap rw offset {:#x} out of range", offset); + } + let relative_offset = offset - *cap_offset; + + if is_write { + cap.with_region_mut(|region| { + match region.write(relative_offset, size, mmio.value as u32) { + Ok(()) => Ok(0), + Err(e) => { + warn!("Failed to write capability at offset 0x{:x}: {:?}", offset, e); + Err(e) + } + } + }) + } else { + cap.with_region(|region| { + match region.read(relative_offset, size) { + Ok(val) => Ok(val), + Err(e) => { + warn!("Failed to read capability at offset 0x{:x}: {:?}", offset, e); + Err(e) + } + } + }) + } + } else { + hv_result_err!(ENOENT) + } + }); + + match result { + Ok(val) => { + if !is_write { + mmio.value = val as usize; + } + } + Err(_) => { + if mmio.is_write { + super::vpci_dev::vpci_dev_write_cfg(dev.get_dev_type(), dev.clone(), offset, size, value).unwrap(); + } else { + mmio.value = super::vpci_dev::vpci_dev_read_cfg(dev.get_dev_type(), dev.clone(), offset, size).unwrap() as usize; + } + } } } } diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 86aeb96d..6e2b3e56 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -16,7 +16,7 @@ use alloc::{collections::btree_map::BTreeMap, sync::Arc, vec::Vec}; use bit_field::BitField; use bitvec::{array::BitArray, order::Lsb0, BitArr}; -use core::{cmp::Ordering, fmt::Debug, ops::Range, str::FromStr}; +use core::{cmp::Ordering, fmt::Debug, ops::{Deref, DerefMut, Range}, str::FromStr}; use spin::RwLock; use super::{ @@ -301,6 +301,10 @@ impl VirtualPciAccessBits { bits: !BitArray::ZERO, } } + + pub fn set_bits(&mut self, range: Range) { + self.bits[range].fill(true); + } } @@ -435,6 +439,15 @@ impl ArcRwLockVirtualPciConfigSpace { f(&mut guard.config_value) } + /// Execute a closure with a reference to the capabilities list + pub fn with_cap(&self, f: F) -> R + where + F: FnOnce(&PciCapabilityList) -> R, + { + let guard = self.0.read(); + f(&guard.capabilities) + } + pub fn read(&self) -> spin::RwLockReadGuard<'_, VirtualPciConfigSpace> { self.0.read() } @@ -542,6 +555,19 @@ impl VirtualPciConfigSpace { f(&mut self.bararr) } + pub fn with_cap_mut(&mut self, f: F) -> R + where + F: FnOnce(&mut PciCapabilityList) -> R, + { + f(&mut self.capabilities) + } + + pub fn with_access_mut(&mut self, f: F) -> R + where + F: FnOnce(&mut VirtualPciAccessBits) -> R, + { + f(&mut self.access) + } // TODO: check whether need update config pub fn update_config(&mut self, offset: PciConfigAddress, size: usize, _value: usize) { @@ -1396,7 +1422,7 @@ impl Iterator for CapabilityIterator { debug!("get cap {:#x}", self.get_offset()); // Get current capability before moving to next let cap = - PciCapability::from_address(self.get_offset(), self.get_id(), self.get_extension()); + PciCapability::from_address(self.get_offset(), self.get_id(), self.backend.clone()); // Move to next capability let _ = self.get_next_cap(); if let Some(cap) = cap { @@ -1407,200 +1433,286 @@ impl Iterator for CapabilityIterator { } } -#[derive(Clone)] -pub enum PciCapability { +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum CapabilityType { // Power management capability, Cap ID = `0x01` - PowerManagement(PciCapabilityRegion), + PowerManagement, // Accelerated graphics port capability, Cap ID = `0x02` - AcceleratedGraphicsPort(PciCapabilityRegion), + AcceleratedGraphicsPort, // Vital product data capability, Cap ID = `0x3` - VitalProductData(PciCapabilityRegion), + VitalProductData, // Slot identification capability, Cap ID = `0x04` - SlotIdentification(PciCapabilityRegion), + SlotIdentification, // Message signalling interrupts capability, Cap ID = `0x05` - Msi(PciCapabilityRegion), + Msi, // CompactPCI HotSwap capability, Cap ID = `0x06` - CompactPCIHotswap(PciCapabilityRegion), + CompactPCIHotswap, // PCI-X capability, Cap ID = `0x07` - PciX(PciCapabilityRegion), + PciX, // HyperTransport capability, Cap ID = `0x08` - HyperTransport(PciCapabilityRegion), + HyperTransport, // Vendor-specific capability, Cap ID = `0x09` - Vendor(PciCapabilityRegion), + Vendor, // Debug port capability, Cap ID = `0x0A` - DebugPort(PciCapabilityRegion), + DebugPort, // CompactPCI Central Resource Control capability, Cap ID = `0x0B` - CompactPCICentralResourceControl(PciCapabilityRegion), + CompactPCICentralResourceControl, // PCI Standard Hot-Plug Controller capability, Cap ID = `0x0C` - PciHotPlugControl(PciCapabilityRegion), + PciHotPlugControl, // Bridge subsystem vendor/device ID capability, Cap ID = `0x0D` - BridgeSubsystemVendorId(PciCapabilityRegion), + BridgeSubsystemVendorId, // AGP Target PCI-PCI bridge capability, Cap ID = `0x0E` - AGP3(PciCapabilityRegion), + AGP3, // PCI Express capability, Cap ID = `0x10` - PciExpress(PciCapabilityRegion), + PciExpress, // MSI-X capability, Cap ID = `0x11` - MsiX(PciCapabilityRegion), + MsiX, // Unknown capability - Unknown(PciCapabilityRegion), + Unknown, +} + +impl Debug for CapabilityType { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + CapabilityType::PowerManagement => write!(f, "PowerManagement(0x01)"), + CapabilityType::AcceleratedGraphicsPort => write!(f, "AcceleratedGraphicsPort(0x02)"), + CapabilityType::VitalProductData => write!(f, "VitalProductData(0x03)"), + CapabilityType::SlotIdentification => write!(f, "SlotIdentification(0x04)"), + CapabilityType::Msi => write!(f, "Msi(0x05)"), + CapabilityType::CompactPCIHotswap => write!(f, "CompactPCIHotswap(0x06)"), + CapabilityType::PciX => write!(f, "PciX(0x07)"), + CapabilityType::HyperTransport => write!(f, "HyperTransport(0x08)"), + CapabilityType::Vendor => write!(f, "Vendor(0x09)"), + CapabilityType::DebugPort => write!(f, "DebugPort(0x0A)"), + CapabilityType::CompactPCICentralResourceControl => write!(f, "CompactPCICentralResourceControl(0x0B)"), + CapabilityType::PciHotPlugControl => write!(f, "PciHotPlugControl(0x0C)"), + CapabilityType::BridgeSubsystemVendorId => write!(f, "BridgeSubsystemVendorId(0x0D)"), + CapabilityType::AGP3 => write!(f, "AGP3(0x0E)"), + CapabilityType::PciExpress => write!(f, "PciExpress(0x10)"), + CapabilityType::MsiX => write!(f, "MsiX(0x11)"), + CapabilityType::Unknown => write!(f, "Unknown(0x00)"), + } + } +} + +impl CapabilityType { + fn from_id(id: PciConfigAddress) -> Self { + match id { + 0x01 => CapabilityType::PowerManagement, + 0x02 => CapabilityType::AcceleratedGraphicsPort, + 0x03 => CapabilityType::VitalProductData, + 0x04 => CapabilityType::SlotIdentification, + 0x05 => CapabilityType::Msi, + 0x06 => CapabilityType::CompactPCIHotswap, + 0x07 => CapabilityType::PciX, + 0x08 => CapabilityType::HyperTransport, + 0x09 => CapabilityType::Vendor, + 0x0A => CapabilityType::DebugPort, + 0x0B => CapabilityType::CompactPCICentralResourceControl, + 0x0C => CapabilityType::PciHotPlugControl, + 0x0D => CapabilityType::BridgeSubsystemVendorId, + 0x0E => CapabilityType::AGP3, + 0x10 => CapabilityType::PciExpress, + 0x11 => CapabilityType::MsiX, + _ => CapabilityType::Unknown, + } + } + + pub fn to_id(&self) -> PciConfigAddress { + match self { + CapabilityType::PowerManagement => 0x01, + CapabilityType::AcceleratedGraphicsPort => 0x02, + CapabilityType::VitalProductData => 0x03, + CapabilityType::SlotIdentification => 0x04, + CapabilityType::Msi => 0x05, + CapabilityType::CompactPCIHotswap => 0x06, + CapabilityType::PciX => 0x07, + CapabilityType::HyperTransport => 0x08, + CapabilityType::Vendor => 0x09, + CapabilityType::DebugPort => 0x0A, + CapabilityType::CompactPCICentralResourceControl => 0x0B, + CapabilityType::PciHotPlugControl => 0x0C, + CapabilityType::BridgeSubsystemVendorId => 0x0D, + CapabilityType::AGP3 => 0x0E, + CapabilityType::PciExpress => 0x10, + CapabilityType::MsiX => 0x11, + CapabilityType::Unknown => 0x00, + } + } +} + +#[derive(Clone)] +pub struct PciCapability { + cap_type: CapabilityType, + region: Arc>, } impl PciCapability { + pub fn get_type(&self) -> CapabilityType { + self.cap_type + } + + /// Execute a closure with a read lock on the capability region + pub fn with_region(&self, f: F) -> R + where + F: FnOnce(&dyn PciCapabilityRegion) -> R, + { + let guard = self.region.read(); + f(&*guard) + } + + /// Execute a closure with a write lock on the capability region + pub fn with_region_mut(&self, f: F) -> R + where + F: FnOnce(&mut dyn PciCapabilityRegion) -> R, + { + let mut guard = self.region.write(); + f(&mut *guard) + } + fn from_address( offset: PciConfigAddress, id: PciConfigAddress, - extension: u16, + backend: Arc, ) -> 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, - ))), + match CapabilityType::from_id(id) { + CapabilityType::Unknown => None, + CapabilityType::Msi => { + let region = Arc::new(RwLock::new(StandardPciCapabilityRegion::new(offset, 32, backend))); + return Some(PciCapability { + cap_type: CapabilityType::Msi, + region, + }); + } + _ => { + let region = Arc::new(RwLock::new(StandardPciCapabilityRegion::new(offset, 32, backend))); + Some(PciCapability { + cap_type: CapabilityType::from_id(id), + region, + }) + } } } - 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, + pub fn new_virt(cap_type: CapabilityType, region: Arc>) -> Self { + Self { + cap_type, + region, } } + + pub fn get_offset(&self) -> PciConfigAddress { + self.with_region(|region| region.get_offset()) + } + + pub fn get_size(&self) -> usize { + self.with_region(|region| region.get_size()) + } + + fn next_cap(&self) -> HvResult { + self.with_region(|region| region.next_cap()) + } } 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) - } - } + write!(f, "{:?}", self.cap_type) } } -#[derive(Clone)] -pub struct PciCapabilityRegion { +pub trait PciCapabilityRegion: Send + Sync { + /// Read from capability region at relative offset + /// offset: relative offset from capability start (0 = capability start) + fn read(&self, offset: PciConfigAddress, size: usize) -> HvResult; + + /// Write to capability region at relative offset + /// offset: relative offset from capability start (0 = capability start) + fn write(&mut self, offset: PciConfigAddress, size: usize, value: u32) -> HvResult; + + /// Get absolute offset of capability in config space + fn get_offset(&self) -> PciConfigAddress; + + /// Get size of capability + fn get_size(&self) -> usize; + + /// Get next capability offset by reading next pointer + /// Default implementation: read 2 bytes at offset 0 (capability start), extract bits(8..16) as next pointer + fn next_cap(&self) -> HvResult { + let value = self.read(0, 2)?; + let next_offset = (value as u16).get_bits(8..16) as PciConfigAddress; + Ok(next_offset) + } +} + +pub struct StandardPciCapabilityRegion { offset: PciConfigAddress, - extension: u16, + size: usize, + backend: Arc, +} + +impl StandardPciCapabilityRegion { + pub fn new(offset: PciConfigAddress, size: usize, backend: Arc) -> Self { + Self { offset, size, backend } + } +} + +impl PciCapabilityRegion for StandardPciCapabilityRegion { + fn read(&self, offset: PciConfigAddress, size: usize) -> HvResult { + self.backend.read(self.offset + offset, size).map(|v| v as u32) + } + + fn write(&mut self, offset: PciConfigAddress, size: usize, value: u32) -> HvResult { + self.backend.write(self.offset + offset, size, value as usize) + } + + fn get_offset(&self) -> PciConfigAddress { + self.offset + } + + fn get_size(&self) -> usize { + self.size + } +} + +#[derive(Clone)] +pub struct PciCapabilityList(BTreeMap); + +impl PciCapabilityList { + pub fn new() -> Self { + Self(BTreeMap::new()) + } +} + +// impl Default for PciCapabilityList { +// fn default() -> Self { +// Self::new() +// } +// } + +impl Deref for PciCapabilityList { + type Target = BTreeMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } } -impl PciCapabilityRegion { - pub fn new(offset: PciConfigAddress, extension: u16) -> Self { - Self { offset, extension } +impl DerefMut for PciCapabilityList { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 } } -pub type PciCapabilityList = BTreeMap; +impl Debug for PciCapabilityList { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "PciCapabilityList {{\n")?; + for (offset, capability) in &self.0 { + write!(f, "0x{:x} {:?}\n", offset, capability)?; + } + write!(f, "}}")?; + Ok(()) + } +} impl VirtualPciConfigSpace { fn _capability_enumerate(&self, backend: Arc) -> CapabilityIterator { @@ -1613,10 +1725,10 @@ impl VirtualPciConfigSpace { 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(_) => {} - PciCapability::PciExpress(_) => {} + match capability.get_type() { + CapabilityType::Msi => {} + CapabilityType::MsiX => {} + CapabilityType::PciExpress => {} _ => {} } capabilities.insert(capability.get_offset(), capability); @@ -1632,10 +1744,11 @@ impl VirtualPciConfigSpace { // Find PciExpress capability // warn!("has_secondary_link {:#?}", self.capabilities); // for (_, capability) in &self.capabilities { - // if let PciCapability::PciExpress(PciCapabilityRegion { offset, .. }) = capability { + // if capability.cap_type == CapabilityType::PciExpress { // // Read PCIe Capability Register at offset + 0x00 // // Bits 4:0 contain the Device/Port Type - // if let Ok(cap_reg) = self.backend.read(*offset, 2) { + // let offset = capability.get_offset(); + // if let Ok(cap_reg) = self.backend.read(offset, 2) { // let type_val = (cap_reg as u16).get_bits(0..5); // if type_val == PCI_EXP_TYPE_ROOT_PORT || type_val == PCI_EXP_TYPE_PCIE_BRIDGE { // return true; diff --git a/src/pci/vpci_dev/mod.rs b/src/pci/vpci_dev/mod.rs index 65113fad..341085c5 100644 --- a/src/pci/vpci_dev/mod.rs +++ b/src/pci/vpci_dev/mod.rs @@ -1,8 +1,11 @@ -use crate::pci::pci_struct::{ConfigValue, ArcRwLockVirtualPciConfigSpace, VirtualPciConfigSpace, Bdf}; +use crate::pci::pci_struct::{ArcRwLockVirtualPciConfigSpace, Bdf, CapabilityType, ConfigValue, PciCapabilityRegion, VirtualPciConfigSpace}; use crate::pci::PciConfigAddress; use crate::error::HvResult; use crate::pci::pci_access::{Bar, EndpointField}; +use bitvec::array::BitArray; +use bitvec::{order::Lsb0, BitArr}; + // Standard virtual device configuration space defaults pub(crate) const STANDARD_CFG_SIZE: usize = 0x80; pub(crate) const DEFAULT_CSPACE_U32: [u32; STANDARD_CFG_SIZE / 4] = { @@ -15,7 +18,7 @@ pub(crate) const DEFAULT_CSPACE_U32: [u32; STANDARD_CFG_SIZE / 4] = { const PCI_CAP_ID_MSIX: u8 = 0x11; const STANDARD_CFG_VNDR_CAP: u8 = 0x40; const STANDARD_CFG_VNDR_LEN: u8 = 0x20; - const STANDARD_CFG_MSIX_CAP: usize = 0x60; + const STANDARD_CFG_MSIX_CAP: usize = 0x98; const STANDARD_MSIX_VECTORS: u16 = 16; let mut arr = [0u32; STANDARD_CFG_SIZE / 4]; @@ -23,13 +26,13 @@ pub(crate) const DEFAULT_CSPACE_U32: [u32; STANDARD_CFG_SIZE / 4] = { arr[0x04 / 4] = (PCI_STS_CAPS as u32) << 16; arr[0x08 / 4] = (PCI_DEV_CLASS_OTHER as u32) << 24; arr[0x2c / 4] = (STANDARD_DEVICE_ID as u32) << 16 | STANDARD_VENDOR_ID as u32; - arr[PCI_CFG_CAPS / 4] = STANDARD_CFG_VNDR_CAP as u32; - arr[STANDARD_CFG_VNDR_CAP as usize / 4] = (STANDARD_CFG_VNDR_LEN as u32) << 16 - | (STANDARD_CFG_MSIX_CAP as u32) << 8 - | PCI_CAP_ID_VNDR as u32; - arr[STANDARD_CFG_MSIX_CAP / 4] = (0x00u32) << 8 | PCI_CAP_ID_MSIX as u32; - arr[(STANDARD_CFG_MSIX_CAP + 0x4) / 4] = 1; - arr[(STANDARD_CFG_MSIX_CAP + 0x8) / 4] = ((0x10 * STANDARD_MSIX_VECTORS) as u32) | 1; + // arr[PCI_CFG_CAPS / 4] = STANDARD_CFG_VNDR_CAP as u32; + // arr[STANDARD_CFG_VNDR_CAP as usize / 4] = (STANDARD_CFG_VNDR_LEN as u32) << 16 + // | (STANDARD_CFG_MSIX_CAP as u32) << 8 + // | PCI_CAP_ID_VNDR as u32; + // arr[STANDARD_CFG_MSIX_CAP / 4] = (0x00u32) << 8 | PCI_CAP_ID_MSIX as u32; + // arr[(STANDARD_CFG_MSIX_CAP + 0x4) / 4] = 1; + // arr[(STANDARD_CFG_MSIX_CAP + 0x8) / 4] = ((0x10 * STANDARD_MSIX_VECTORS) as u32) | 1; arr }; @@ -100,6 +103,7 @@ pub(super) fn vpci_dev_read_cfg( } PciConfigAccessStatus::Default => { // If this is a standard virtual device, read from DEFAULT_CSPACE_U32 + warn!("vpci_dev_read_cfg: default config space read, offset {:#x}, size {:#x}", offset, size); if offset < STANDARD_CFG_SIZE as PciConfigAddress { let u32_offset = (offset as usize) / 4; let u32_value = DEFAULT_CSPACE_U32[u32_offset]; @@ -215,4 +219,126 @@ pub(super) fn virt_dev_init( } } } +} + +pub struct VirtMsiCap { + offset: PciConfigAddress, + next_cap_pointer: u16, + control_bits: BitArr!(for 16, in u16, Lsb0), + message_address_lower: u32, + message_address_upper: u32, + message_data: u16, +} + +impl PciCapabilityRegion for VirtMsiCap { + fn read(&self, offset: PciConfigAddress, size: usize) -> HvResult { + match (offset, size) { + (0x0, 2) => Ok((CapabilityType::Msi.to_id() as u32) | (self.next_cap_pointer << 8) as u32), + (0x2, 2) => Ok(self.control_bits.as_raw_slice()[0] as u32), + (0x4, 4) => Ok(self.message_address_lower), + (0x8, 4) => Ok(self.message_address_upper), + (0xC, 2) => Ok(self.message_data as u32), + _ => { + warn!("VirtMsiCap invalid read offset 0x{:x} size {}", offset, size); + Ok(0) + } + } + } + fn write(&mut self, offset: PciConfigAddress, size: usize, value: u32) -> HvResult { + match (offset, size) { + (0x2, 2) => self.control_bits = BitArray::new([value as u16]), + (0x4, 4) => self.message_address_lower = value, + (0x8, 4) => self.message_address_upper = value, + (0xC, 2) => self.message_data = value as u16, + _ => { + warn!("VirtMsiCap invalid write offset 0x{:x} size {}", offset, size); + } + } + Ok(()) + } + fn get_offset(&self) -> PciConfigAddress { + self.offset + } + fn get_size(&self) -> usize { + 128 + } +} + +impl VirtMsiCap { + pub fn new(offset: PciConfigAddress) -> Self { + let mut bits = BitArray::ZERO; + bits.set(0, true); + Self { + offset, + next_cap_pointer: 0, + control_bits: bits, + message_address_lower: 0, + message_address_upper: 0, + message_data: 0, + } + } + + pub fn set_next_cap_pointer(&mut self, next_cap_pointer: u16) { + self.next_cap_pointer = next_cap_pointer; + } +} + +pub struct VirtMsiXCap { + offset: PciConfigAddress, + next_cap_pointer: u16, + control_bits: BitArr!(for 16, in u16, Lsb0), + table: u32, + pba: u32, +} + +impl PciCapabilityRegion for VirtMsiXCap { + fn read(&self, offset: PciConfigAddress, size: usize) -> HvResult { + match (offset, size) { + (0x0, 4) => Ok(((CapabilityType::MsiX.to_id() as u32) | (self.next_cap_pointer << 8) as u32) | (((self.control_bits.as_raw_slice()[0] as u32) << 16) as u32)), + (0x0, 2) => Ok((CapabilityType::MsiX.to_id() as u32) | (self.next_cap_pointer << 8) as u32), + (0x2, 2) => Ok(self.control_bits.as_raw_slice()[0] as u32), + (0x4, 4) => Ok(self.table), + (0x8, 4) => Ok(self.pba), + _ => { + warn!("VirtMsiXCap invalid read offset 0x{:x} size {}", offset, size); + Ok(0) + } + } + } + fn write(&mut self, offset: PciConfigAddress, size: usize, value: u32) -> HvResult { + match (offset, size) { + (0x2, 2) => self.control_bits = BitArray::new([value as u16]), + (0x4, 4) => self.table = value, + (0x8, 4) => self.pba = value, + _ => { + warn!("VirtMsiXCap invalid write offset 0x{:x} size {}", offset, size); + } + } + + Ok(()) + } + + fn get_offset(&self) -> PciConfigAddress { + self.offset + } + fn get_size(&self) -> usize { + 96 + } +} + +impl VirtMsiXCap { + pub fn new(offset: PciConfigAddress) -> Self { + let bits = BitArray::ZERO; + Self { + offset, + next_cap_pointer: 0, + control_bits: bits, + table: 1, + pba: ((0x10 * 16) as u32) | 1, + } + } + + pub fn set_next_cap_pointer(&mut self, next_cap_pointer: u16) { + self.next_cap_pointer = next_cap_pointer; + } } \ No newline at end of file diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index 00a19d2b..20f7ba0d 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -1,5 +1,5 @@ use crate::error::HvResult; -use crate::pci::pci_struct::VirtualPciConfigSpace; +use crate::pci::pci_struct::{CapabilityType, PciCapability, VirtualPciConfigSpace}; use crate::pci::pci_access::{EndpointField, DeviceId, VendorId, BaseClass, SubClass, Interface, DeviceRevision}; use crate::pci::PciConfigAddress; use super::{PciConfigAccessStatus, VpciDeviceHandler}; @@ -8,7 +8,10 @@ use crate::pci::pci_struct::ArcRwLockVirtualPciConfigSpace; use crate::percpu::this_zone; use crate::memory::MMIOAccess; use crate::pci::pci_access::PciMemType; - +use crate::pci::vpci_dev::VirtMsiXCap; +use spin::RwLock; +use alloc::sync::Arc; +use crate::pci::pci_struct::PciCapabilityRegion; /// Handler for standard virtual PCI devices pub struct StandardHandler; @@ -18,10 +21,10 @@ impl VpciDeviceHandler for StandardHandler { info!("virt pci standard read_cfg, offset {:#x}, size {:#x}", offset, size); match EndpointField::from(offset as usize, size) { EndpointField::ID => { - warn!("virt pci standard read_cfg, id {:#x}", offset); - Ok(PciConfigAccessStatus::Default) + let id = dev.with_config_value(|config_value| config_value.get_id()); + Ok(PciConfigAccessStatus::Done((((id.0 as u32) << 16) | (id.1 as u32)) as usize)) } - EndpointField::Bar(0) => { + EndpointField::Bar(0) => { let slot = 0; let size_read = dev.with_bar_ref(slot, |bar| bar.get_size_read()); if size_read { @@ -33,6 +36,9 @@ impl VpciDeviceHandler for StandardHandler { Ok(PciConfigAccessStatus::Done(value as usize)) } } + EndpointField::CapabilityPointer => { + Ok(PciConfigAccessStatus::Done(0x98)) + } _ => { Ok(PciConfigAccessStatus::Default) } @@ -42,9 +48,6 @@ impl VpciDeviceHandler for StandardHandler { fn write_cfg(&self, dev: ArcRwLockVirtualPciConfigSpace, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { info!("virt pci standard write_cfg, offset {:#x}, size {:#x}, value {:#x}", offset, size, value); match EndpointField::from(offset as usize, size) { - EndpointField::ID => { - Ok(PciConfigAccessStatus::Reject) - } EndpointField::Command => { // Command field is written directly to backend, no need for space cache Ok(PciConfigAccessStatus::Done(value)) @@ -64,7 +67,11 @@ impl VpciDeviceHandler for StandardHandler { Ok(PciConfigAccessStatus::Done(value)) } + EndpointField::Bar(_) => { + Ok(PciConfigAccessStatus::Done(value)) + } _ => { + warn!("virt pci standard write_cfg, invalid offset {:#x}, size {:#x}, value {:#x}", offset, size, value); Ok(PciConfigAccessStatus::Reject) } } @@ -93,7 +100,29 @@ impl VpciDeviceHandler for StandardHandler { dev.with_bararr_mut(|bararr| { bararr[0].config_init(PciMemType::Mem32, false, size as u64, your_addr); }); - + + // 0x98 is an arbitrary value, used here only for demonstration purposes + // please don't forget to set next cap pointer if next cap exists + let msi_cap_offset = 0x98; + let mut msi_cap = VirtMsiXCap::new(msi_cap_offset); + msi_cap.set_next_cap_pointer(0x00); + dev.with_access_mut(|access| { + access.set_bits((msi_cap_offset as usize)..(msi_cap_offset as usize + msi_cap.get_size()) as usize); + }); + + dev.with_cap_mut(|capabilities| { + capabilities.insert( + msi_cap_offset, + PciCapability::new_virt( + CapabilityType::MsiX, + Arc::new(RwLock::new(msi_cap)) + ) + ); + }); + + dev.with_access_mut(|access| { + access.set_bits(0x34..0x38); + }); dev } } From 6c9080bbbd92fb7d3301de4a7305352dc63ca700 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 25 Dec 2025 02:07:45 +0800 Subject: [PATCH 059/109] fixed the bug where some bridges were incorrectly removed --- src/pci/pci_config.rs | 3 ++- src/pci/pci_struct.rs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 14ccc3b6..f30d7cb6 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -173,7 +173,8 @@ impl Zone { iommu_add_device(zone_id, dev_config.bdf as _, iommu_pt_addr); } if let Some(dev) = guard.get(&bdf) { - if bdf.is_host_bridge(dev.read().get_host_bdf().bus()) { + if bdf.is_host_bridge(dev.read().get_host_bdf().bus()) + || dev.with_config_value(|config_value| -> bool {config_value.get_class().0 == 0x6}) { let mut vdev = dev.read().clone(); vdev.set_vbdf(vbdf); self.vpci_bus.insert(vbdf, vdev); diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 6e2b3e56..7f56b182 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -1195,6 +1195,7 @@ impl Iterator for PciIterator { node.set_host_bdf(host_bdf); node.set_parent_bdf(parent_bdf); self.next(match node.config_value.get_class().0 { + // class code 0x6 is bridge and class.1 0x0 is host bridge 0x6 if node.config_value.get_class().1 != 0x0 => { let bdf = Bdf::new(parent.subordinate_bus + 1, 0, 0); Some( From e71e5eaa433a6368317091e6f05899774c7e87d3 Mon Sep 17 00:00:00 2001 From: Yulong Han Date: Fri, 26 Dec 2025 17:06:47 +0800 Subject: [PATCH 060/109] refactor: update GitHub workflows and labeler configuration --- .github/labeler.yml | 4 - .github/workflows/issue-labeler.yml | 7 +- .github/workflows/labeler.yml | 121 +++++++++++++--------------- 3 files changed, 59 insertions(+), 73 deletions(-) diff --git a/.github/labeler.yml b/.github/labeler.yml index d7b6a02d..8ac3822c 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -13,7 +13,3 @@ riscv64: x86_64: - changed-files: - any-glob-to-any-file: src/arch/x86_64/**/* - - - - diff --git a/.github/workflows/issue-labeler.yml b/.github/workflows/issue-labeler.yml index 4f542926..11599e3f 100644 --- a/.github/workflows/issue-labeler.yml +++ b/.github/workflows/issue-labeler.yml @@ -39,11 +39,6 @@ jobs: labels.push('documentation'); } - // CI/CD - if (title.includes('ci') || body.includes('ci')) { - labels.push('ci'); - } - // Architecture specific if (title.includes('aarch64') || body.includes('aarch64')) { labels.push('aarch64'); @@ -107,4 +102,4 @@ jobs: issue_number, labels }); - } \ No newline at end of file + } diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 9d48a3d4..441b43b3 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -1,70 +1,65 @@ --- - name: Pull Request Labeler - - on: - pull_request_target: - - jobs: - triage: - name: Label triage - permissions: - contents: read - pull-requests: write - issues: write - runs-on: ubuntu-latest - steps: - - uses: actions/labeler@v5 - with: - sync-labels: true - - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const title = context.payload.pull_request.title.toLowerCase(); - const labels = []; - - if (title.includes('feat') || title.includes('feature')) { - labels.push('feature'); - } - - if (title.includes('fix') || title.includes('bug')) { - labels.push('bug'); - } - - if (title.includes('docs') || title.includes('documentation')) { - labels.push('documentation'); - } +name: Pull Request Labeler - if (title.includes('ci')) { - labels.push('ci'); - } +on: + pull_request_target: - if (title.includes('aarch64')) { - labels.push('aarch64'); - } +jobs: + triage: + name: Label triage + permissions: + contents: read + pull-requests: write + issues: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v5 + with: + sync-labels: true + - uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const title = context.payload.pull_request.title.toLowerCase(); + const labels = []; + + if (title.includes('feat') || title.includes('feature')) { + labels.push('feature'); + } + + if (title.includes('fix') || title.includes('bug')) { + labels.push('bug'); + } + + if (title.includes('docs') || title.includes('documentation')) { + labels.push('documentation'); + } - if (title.includes('loongarch64')) { - labels.push('loongarch64'); - } + if (title.includes('aarch64')) { + labels.push('aarch64'); + } - if (title.includes('riscv64')) { - labels.push('riscv64'); - } + if (title.includes('loongarch64')) { + labels.push('loongarch64'); + } - if (title.includes('x86_64')) { - labels.push('x86_64'); - } - - const pr_number = context.payload.pull_request?.number; - console.log(`PR number: ${pr_number}`); - console.log(`Computed labels: ${labels}`); + if (title.includes('riscv64')) { + labels.push('riscv64'); + } + + if (title.includes('x86_64')) { + labels.push('x86_64'); + } + + const pr_number = context.payload.pull_request?.number; + console.log(`PR number: ${pr_number}`); + console.log(`Computed labels: ${labels}`); - if (pr_number && labels.length > 0) { - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: pr_number, - labels: labels - }); - } - \ No newline at end of file + if (pr_number && labels.length > 0) { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr_number, + labels: labels + }); + } From eebe224d50e96ed8def8351d24331e6864857c9d Mon Sep 17 00:00:00 2001 From: dallas Date: Mon, 29 Dec 2025 18:26:01 +0800 Subject: [PATCH 061/109] cover non root atu0 mmio bug --- src/pci/config_accessors/dwc_atu.rs | 1 + src/pci/pci_access.rs | 111 ++++++++++++++++++++++++---- src/pci/pci_struct.rs | 2 +- 3 files changed, 100 insertions(+), 14 deletions(-) diff --git a/src/pci/config_accessors/dwc_atu.rs b/src/pci/config_accessors/dwc_atu.rs index a478adeb..1ae191a6 100644 --- a/src/pci/config_accessors/dwc_atu.rs +++ b/src/pci/config_accessors/dwc_atu.rs @@ -32,6 +32,7 @@ pub const PCIE_ATU_UNR_UPPER_BASE: usize = 0x0C; pub const PCIE_ATU_UNR_LIMIT: usize = 0x10; pub const PCIE_ATU_UNR_LOWER_TARGET: usize = 0x14; pub const PCIE_ATU_UNR_UPPER_TARGET: usize = 0x18; +pub const PCIE_ATU_UNR_UPPER_LIMIT: usize = 0x20; // ATU enable bit pub const ATU_ENABLE_BIT: u32 = 0x80000000; diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 44626f7a..c4598d4e 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -45,7 +45,8 @@ use crate::pci::config_accessors::{ AtuConfig, AtuType, ATU_BASE, ATU_REGION_SIZE, PCIE_ATU_UNR_REGION_CTRL1, PCIE_ATU_UNR_REGION_CTRL2, PCIE_ATU_UNR_LOWER_BASE, PCIE_ATU_UNR_UPPER_BASE, - PCIE_ATU_UNR_LIMIT, PCIE_ATU_UNR_LOWER_TARGET, PCIE_ATU_UNR_UPPER_TARGET, + PCIE_ATU_UNR_LIMIT, PCIE_ATU_UNR_UPPER_LIMIT, + PCIE_ATU_UNR_LOWER_TARGET, PCIE_ATU_UNR_UPPER_TARGET, ATU_ENABLE_BIT, AtuUnroll, }, @@ -1407,11 +1408,11 @@ fn handle_config_space_access( dev.with_bar_ref_mut(slot, |bar| bar.clear_size_read()); r } else { - // dev.with_bar_ref(slot, |bar| bar.get_virtual_value()).try_into().unwrap() - let emu_value = dev.read_emu(EndpointField::Bar(slot)).unwrap() as usize; - let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()) as usize; - info!("emu value {:#x} virtual_value {:#x}", emu_value, virtual_value); - emu_value + dev.with_bar_ref(slot, |bar| bar.get_virtual_value()) as usize + // let emu_value = dev.read_emu(EndpointField::Bar(slot)).unwrap() as usize; + // let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()) as usize; + // info!("emu value {:#x} virtual_value {:#x}", emu_value, virtual_value); + // virtual_value }; } } else { @@ -1726,6 +1727,10 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { // info!("set atu0 limit value {:#X}", mmio.value); atu.cpu_limit = (atu.cpu_limit & !0xffffffff) | (mmio.value as PciConfigAddress); } + PCIE_ATU_UNR_UPPER_LIMIT => { + // Update the upper 32 bits of cpu_limit + atu.cpu_limit = (atu.cpu_limit & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32); + } PCIE_ATU_UNR_LOWER_TARGET => { // info!("set atu0 lower target value {:#X}", mmio.value); atu.pci_target = (atu.pci_target & !0xffffffff) | (mmio.value as PciConfigAddress); @@ -1758,7 +1763,15 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { mmio.value = ((atu.cpu_base >> 32) & 0xffffffff) as usize; } PCIE_ATU_UNR_LIMIT => { - mmio.value = (atu.cpu_limit & 0xffffffff) as usize; + let limit_value = (atu.cpu_limit & 0xffffffff) as usize; + // If limit is 0, return 0x3ffffff instead + mmio.value = if limit_value == 0 { 0x3ffffff } else { limit_value }; + } + PCIE_ATU_UNR_UPPER_LIMIT => { + // Return the upper 32 bits of cpu_limit + // If it's 0xffffffff, return 0x40000000 instead + let upper_limit = ((atu.cpu_limit >> 32) & 0xffffffff) as usize; + mmio.value = if upper_limit == 0xffffffff { 0x40000000 } else { upper_limit }; } PCIE_ATU_UNR_LOWER_TARGET => { mmio.value = (atu.pci_target & 0xffffffff) as usize; @@ -1773,8 +1786,80 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { } } } else if mmio.address > ATU_BASE + ATU_REGION_SIZE/2 { - // other atu mmio_perform_access(_base, mmio); + // // other atu + // let is_root = is_this_root_zone(); + // let atu_offset = (mmio.address - ATU_BASE) % ATU_REGION_SIZE; + + // // 0x0-0x100 is inbound ATU (needs emulation) + // // 0x100-0x200 is outbound ATU (direct passthrough) + // if atu_offset >= 0x100 { + // // Outbound ATU: direct passthrough + // mmio_perform_access(_base, mmio); + // return Ok(()); + // } + + // // Inbound ATU: needs emulation (0x0-0x100 range) + // // For non-root zones, only allow access to LIMIT registers + // if !is_root { + // if mmio.is_write { + // // For non-root zones, only allow writes to LIMIT registers + // if atu_offset == PCIE_ATU_UNR_LIMIT || atu_offset == PCIE_ATU_UNR_UPPER_LIMIT { + // // Allow the write to proceed, but we'll handle read specially + // mmio_perform_access(_base, mmio); + // } else { + // // Reject access to other registers for non-root zones + // warn!("non-root zone attempted to access ATU register {:#x} at offset {:#x}", mmio.address, atu_offset); + // return Ok(()); + // } + // } else { + // // For reads, handle LIMIT registers specially + // if atu_offset == PCIE_ATU_UNR_LIMIT { + // // Read from hardware first + // mmio_perform_access(_base, mmio); + // // If value is 0, return 0x3ffffff instead + // if mmio.value == 0 { + // mmio.value = 0x3ffffff; + // } + // } else if atu_offset == PCIE_ATU_UNR_UPPER_LIMIT { + // // Read upper limit from hardware + // mmio_perform_access(_base, mmio); + // // If value is 0xffffffff, return 0x40000000 instead + // if mmio.value == 0xffffffff { + // mmio.value = 0x40000000; + // } + // } else { + // // Reject access to other registers for non-root zones + // warn!("non-root zone attempted to read ATU register {:#x} at offset {:#x}", mmio.address, atu_offset); + // return Ok(()); + // } + // } + // } else { + // // For root zones, handle LIMIT registers specially but allow all other accesses + // if !mmio.is_write { + // if atu_offset == PCIE_ATU_UNR_LIMIT { + // // Read from hardware first + // mmio_perform_access(_base, mmio); + // // If value is 0, return 0x3ffffff instead + // if mmio.value == 0 { + // mmio.value = 0x3ffffff; + // } + // } else if atu_offset == PCIE_ATU_UNR_UPPER_LIMIT { + // // Read upper limit from hardware + // mmio_perform_access(_base, mmio); + // // If value is 0xffffffff, return 0x40000000 instead + // if mmio.value == 0xffffffff { + // mmio.value = 0x40000000; + // } + // } else { + // // For other registers, perform normal access + // mmio_perform_access(_base, mmio); + // } + // } else { + // // For writes, perform normal access (including LIMIT registers) + // mmio_perform_access(_base, mmio); + // } + // } } else if mmio.address >= BIT_LENTH { // dbi read mmio_perform_access(_base, mmio); @@ -2029,11 +2114,11 @@ fn handle_config_space_access_direct( dev.with_bar_ref_mut(slot, |bar| bar.clear_size_read()); r } else { - // dev.read_emu(offset, size).unwrap() as usize - let emu_value = dev.read_emu(EndpointField::Bar(slot)).unwrap() as usize; - let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()) as usize; - info!("emu value {:#x} virtual_value {:#x}", emu_value, virtual_value); - virtual_value + dev.with_bar_ref(slot, |bar| bar.get_virtual_value()) as usize + // let emu_value = dev.read_emu(EndpointField::Bar(slot)).unwrap() as usize; + // let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()) as usize; + // info!("emu value {:#x} virtual_value {:#x}", emu_value, virtual_value); + // virtual_value } } } else { diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 7f56b182..cfc0f2cd 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -116,7 +116,7 @@ impl ConfigValue { const MAX_DEVICE: u8 = 31; const MAX_FUNCTION: u8 = 7; pub const CONFIG_LENTH: u64 = 256; -pub const BIT_LENTH: usize = 4096; +pub const BIT_LENTH: usize = 128*8; // PCIe Device/Port Type values const PCI_EXP_TYPE_ROOT_PORT: u16 = 4; From 627d1b1ddd8fb5b492468862d778d193aba665c3 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 31 Dec 2025 18:31:45 +0800 Subject: [PATCH 062/109] 1. add emu rom 2. the PCI handler function has been reorganized --- src/pci/mod.rs | 1 + src/pci/pci_access.rs | 1057 +--------------------------------------- src/pci/pci_config.rs | 8 +- src/pci/pci_handler.rs | 937 +++++++++++++++++++++++++++++++++++ src/pci/pci_struct.rs | 43 ++ src/pci/pci_test.rs | 2 +- 6 files changed, 994 insertions(+), 1054 deletions(-) create mode 100644 src/pci/pci_handler.rs diff --git a/src/pci/mod.rs b/src/pci/mod.rs index f4f53512..fe8d201a 100644 --- a/src/pci/mod.rs +++ b/src/pci/mod.rs @@ -20,6 +20,7 @@ pub mod pci_access; pub mod pci_config; pub mod pci_struct; pub mod vpci_dev; +pub mod pci_handler; pub mod pci_test; diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index c4598d4e..db480638 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -141,7 +141,9 @@ impl Debug for PciMemType { * 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 + * acutally size_read is not used now, we keep it just in case of possible special register handling in the future */ #[derive(Default, Clone, Copy)] pub struct PciMem { @@ -291,6 +293,9 @@ impl PciMem { if self.prefetchable { val |= 0x8; } + } + PciMemType::Rom => { + } _ => { warn!("please init bar first"); @@ -353,6 +358,9 @@ impl PciMem { if self.prefetchable { val |= 0x8; } + } + PciMemType::Rom => { + } _ => { warn!("unkown bar type: {:#?}", self.bar_type); @@ -1213,1053 +1221,4 @@ impl PciBridgeHeader { impl PciBridgeHeader {} -fn handle_config_space_access( - dev: ArcRwLockVirtualPciConfigSpace, - mmio: &mut MMIOAccess, - offset: PciConfigAddress, - zone_id: usize, -) -> HvResult { - let size = mmio.size; - let value = mmio.value; - let is_write = mmio.is_write; - - let vbdf = dev.get_bdf(); - let dev_type = dev.get_dev_type(); - - if (offset as usize) >= BIT_LENTH { - warn!("invalid pci offset {:#x}", offset); - if !is_write { - mmio.value = 0; - } - return Ok(()); - } - - match dev.access(offset, size) { - false => { - // Hardware access path - info!( - "hw vbdf {:#?} reg 0x{:x} try {} {}", - vbdf, - offset, - if is_write { "write" } else { "read" }, - if is_write { - format!(" 0x{:x}", mmio.value) - } else { - String::new() - } - ); - if is_write { - dev.write_hw(offset, size, value)?; - } else { - mmio.value = dev.read_hw(offset, size).unwrap(); - } - } - true => { - // Emulation access path - info!( - "emu vbdf {:#?} reg 0x{:x} try {} {}", - vbdf, - offset, - if is_write { "write" } else { "read" }, - if is_write { - format!(" 0x{:x}", mmio.value) - } else { - String::new() - } - ); - match dev_type { - super::vpci_dev::VpciDevType::Physical => { - let config_type = dev.get_config_type(); - match config_type { - HeaderType::Endpoint => { - match EndpointField::from(offset as usize, size) { - EndpointField::Bar(slot) => { - // let slot = ((offset - 0x10) / 4) as usize; - let slot = slot as usize; - let bar_type = dev.with_bar_ref(slot, |bar| bar.get_type()); - if bar_type != PciMemType::default() { - if is_write { - if (value & 0xfffffff0) == 0xfffffff0 { - dev.with_bar_ref_mut(slot, |bar| bar.set_size_read()); - } else { - let _ = dev.write_emu(EndpointField::Bar(slot), value); - /* for mem64, Mem64High always write after Mem64Low, - * so update bar when write Mem64High - */ - if bar_type == PciMemType::Mem64Low { - let new_vaddr = (value as u64) & !0xf; - dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); - // Sync virtual_value back to emu value - let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()); - let _ = dev.write_emu(EndpointField::Bar(slot), virtual_value as usize); - } else if (bar_type == PciMemType::Mem32) - | (bar_type == PciMemType::Mem64High) - | (bar_type == PciMemType::Io) - { - let old_vaddr = dev.with_bar_ref(slot, |bar| 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 - * Read from config_value.bar_value cache instead of space - */ - let low_value = dev.with_config_value(|cv| cv.get_bar_value(slot - 1)) as u64; - let high_value = (value as u32 as u64) << 32; - (low_value | high_value) & !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. 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 - * the old BAR addresses, potentially causing the update to fail? - */ - let paddr = dev.with_bar_ref(slot, |bar| bar.get_value64()); - info!( - "old_vaddr {:x} new_vaddr {:x} paddr {:x}", - old_vaddr, new_vaddr, paddr - ); - - dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); - if bar_type == PciMemType::Mem64High { - dev.with_bar_ref_mut(slot - 1, |bar| bar.set_virtual_value(new_vaddr)); - } - - // // Sync virtual_value back to space after processing (adding flags) - // let virtual_value = dev.get_bar_virtual_value(slot); - // let bar_offset = (0x10 + slot * 4) as PciConfigAddress; - // let _ = dev.write_emu(bar_offset, 4, virtual_value as usize); - // if bar_type == PciMemType::Mem64High { - // let virtual_value_low = dev.get_bar_virtual_value(slot - 1); - // let bar_offset_low = (0x10 + (slot - 1) * 4) as PciConfigAddress; - // let _ = dev.write_emu(bar_offset_low, 4, virtual_value_low as usize); - // } - - let bar_size = { - let size = dev.with_bar_ref(slot, |bar| bar.get_size()); - if crate::memory::addr::is_aligned(size as usize) { - size - } else { - crate::memory::PAGE_SIZE as u64 - } - }; - - let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) { - crate::memory::addr::align_up(new_vaddr as usize) as u64 - } else { - new_vaddr - }; - - let zone = this_zone(); - let mut guard = zone.write(); - let gpm = &mut guard.gpm; - - if !gpm - .try_delete(old_vaddr.try_into().unwrap(), bar_size as usize) - .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 - ); - } - - gpm.try_insert(MemoryRegion::new_with_offset_mapper( - new_vaddr as GuestPhysAddr, - paddr as HostPhysAddr, - bar_size as _, - MemFlags::READ | MemFlags::WRITE, - ))?; - - /* after update gpm, mem barrier is needed - */ - #[cfg(target_arch = "aarch64")] - unsafe { - core::arch::asm!("isb"); - core::arch::asm!("tlbi vmalls12e1is"); - core::arch::asm!("dsb nsh"); - } - /* after update gpm, need to flush iommu table - * in x86_64 - */ - #[cfg(target_arch = "x86_64")] - crate::arch::iommu::flush( - zone_id, - vbdf.bus, - (vbdf.device << 3) + vbdf.function, - ); - } - } - } else { - let size_read = dev.with_bar_ref(slot, |bar| bar.get_size_read()); - mmio.value = if size_read { - let r = dev.with_bar_ref(slot, |bar| bar.get_size_with_flag()).try_into().unwrap(); - dev.with_bar_ref_mut(slot, |bar| bar.clear_size_read()); - r - } else { - dev.with_bar_ref(slot, |bar| bar.get_virtual_value()) as usize - // let emu_value = dev.read_emu(EndpointField::Bar(slot)).unwrap() as usize; - // let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()) as usize; - // info!("emu value {:#x} virtual_value {:#x}", emu_value, virtual_value); - // virtual_value - }; - } - } else { - mmio.value = 0; - } - } - EndpointField::ExpansionRomBar => { - let rom = dev.get_rom(); - let rom_size_read = rom.get_size_read(); - if is_write { - if (mmio.value & 0xfffff800) == 0xfffff800 { - // Note: get_rom() returns a copy, so we need to get it again after setting - // For now, we'll just set the flag through the dev guard - // TODO: Add a method to set rom size_read flag - warn!("ExpansionRomBar size_read not yet implemented"); - } else { - // let old_vaddr = dev.read_emu(offset, size).unwrap() as u64; - let _ = dev.write_emu(EndpointField::ExpansionRomBar, value); - // TODO: add gpm change for rom - } - } else { - mmio.value = if rom_size_read { - dev.read_emu(EndpointField::ExpansionRomBar).unwrap() - } else { - rom.get_size_with_flag().try_into().unwrap() - }; - } - } - EndpointField::ID => { - if !is_write { - mmio.value = dev.read_emu(EndpointField::ID).unwrap() as usize; - } - } - _ => { - mmio.value = 0; - } - } - } - HeaderType::PciBridge => { - // TODO: add emu for bridge, actually it is same with endpoint - warn!("bridge emu rw"); - } - _ => { - warn!("unhanled pci type {:#?}", config_type); - } - } - } - _ => { - // warn!("virt pci standard rw offset {:#x}, size {:#x}", offset, size); - let result = dev.with_cap(|capabilities| { - if let Some((cap_offset, cap)) = capabilities.range(..=offset).next_back() { - info!("find cap at offset {:#x}, cap {:#?}", cap_offset, cap.get_type()); - let end = *cap_offset + cap.get_size() as u64; - if offset >= end { - // hv_result_err!(ENOENT) - warn!("virt pci cap rw offset {:#x} out of range", offset); - } - let relative_offset = offset - *cap_offset; - - if is_write { - cap.with_region_mut(|region| { - match region.write(relative_offset, size, mmio.value as u32) { - Ok(()) => Ok(0), - Err(e) => { - warn!("Failed to write capability at offset 0x{:x}: {:?}", offset, e); - Err(e) - } - } - }) - } else { - cap.with_region(|region| { - match region.read(relative_offset, size) { - Ok(val) => Ok(val), - Err(e) => { - warn!("Failed to read capability at offset 0x{:x}: {:?}", offset, e); - Err(e) - } - } - }) - } - } else { - hv_result_err!(ENOENT) - } - }); - - match result { - Ok(val) => { - if !is_write { - mmio.value = val as usize; - } - } - Err(_) => { - if mmio.is_write { - super::vpci_dev::vpci_dev_write_cfg(dev_type, dev.clone(), offset, size, value).unwrap(); - } else { - mmio.value = super::vpci_dev::vpci_dev_read_cfg(dev_type, dev.clone(), offset, size).unwrap() as usize; - } - } - } - } - } - } - } - - info!( - "vbdf {:#?} reg 0x{:x} {} 0x{:x}", - vbdf, - offset, - if is_write { "write" } else { "read" }, - mmio.value - ); - - Ok(()) -} - -fn handle_device_not_found(mmio: &mut MMIOAccess, offset: PciConfigAddress) { - /* if the dev is None, just return 0xFFFF_FFFF when read ID */ - if !mmio.is_write { - match EndpointField::from(offset as usize, mmio.size) { - EndpointField::ID => { - mmio.value = 0xFFFF_FFFF; - } - _ => { - // warn!("unhandled pci mmio read, addr: {:#x?}", mmio.address); - mmio.value = 0; - } - } - } -} - -pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { - // info!("mmio_vpci_handler {:#x}", mmio.address); - let zone_id = this_zone_id(); - let zone = this_zone(); - let offset = (mmio.address & 0xfff) as PciConfigAddress; - let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; - - let dev: Option = { - let mut guard = zone.write(); - let vbus = &mut guard.vpci_bus; - vbus.get_device_by_base(base) - }; - - - if let Some(dev) = dev { - handle_config_space_access(dev, mmio, offset, zone_id)?; - } else { - handle_device_not_found(mmio, offset); - } - - Ok(()) -} -#[cfg(feature = "dwc_pcie")] -pub fn mmio_dwc_io_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { - { - let zone = this_zone(); - let guard = zone.read(); - - let atu_config = guard.atu_configs.get_atu_by_io_base(_base as PciConfigAddress) - .and_then(|atu| { - guard.atu_configs.get_ecam_by_io_base(_base as PciConfigAddress) - .map(|ecam| (*atu, ecam)) - }); - - drop(guard); - - if let Some((atu, ecam_base)) = atu_config { - use crate::platform; - if let Some(extend_config) = platform::ROOT_DWC_ATU_CONFIG - .iter() - .find(|cfg| cfg.ecam_base == ecam_base as u64) - { - // Create DBI backend - let dbi_base = extend_config.dbi_base as PciConfigAddress; - let dbi_size = extend_config.dbi_size; - let dbi_region = PciRegionMmio::new(dbi_base, dbi_size); - let dbi_backend = DwcConfigRegionBackend::new(dbi_region); - - // Call AtuUnroll to program the ATU - AtuUnroll::dw_pcie_prog_outbound_atu_unroll(&dbi_backend, &atu)?; - } - mmio_perform_access(atu.pci_target as usize, mmio); - } else { - warn!("No ATU config yet, do nothing"); - } - } - Ok(()) -} - -#[cfg(feature = "dwc_pcie")] -pub fn mmio_dwc_cfg_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { - info!("mmio_dwc_cfg_handler {:#x}", mmio.address + _base); - let zone = this_zone(); - let guard = zone.read(); - - let atu_config = guard.atu_configs.get_atu_by_cfg_base(_base as PciConfigAddress) - .and_then(|atu| { - guard.atu_configs.get_ecam_by_cfg_base(_base as PciConfigAddress) - .map(|ecam| (*atu, ecam)) - }); - - drop(guard); - - if let Some((atu, ecam_base)) = atu_config { - // Get dbi_base from platform config (usually dbi_base == ecam_base) - use crate::platform; - if let Some(extend_config) = platform::ROOT_DWC_ATU_CONFIG - .iter() - .find(|cfg| cfg.ecam_base == ecam_base as u64) - { - // Create DBI backend - let dbi_base = extend_config.dbi_base as PciConfigAddress; - let dbi_size = extend_config.dbi_size; - let dbi_region = PciRegionMmio::new(dbi_base, dbi_size); - let dbi_backend = DwcConfigRegionBackend::new(dbi_region); - - // warn!("atu config {:#?}", atu); - - // Call AtuUnroll to program the ATU - AtuUnroll::dw_pcie_prog_outbound_atu_unroll(&dbi_backend, &atu)?; - } - - let offset = (mmio.address & 0xfff) as PciConfigAddress; - let zone_id = this_zone_id(); - let zone = this_zone(); - let mut is_dev_belong_to_zone = false; - - let base = mmio.address as PciConfigAddress - offset + atu.pci_target; - - let dev: Option = { - let mut guard = zone.write(); - let vbus = &mut guard.vpci_bus; - if let Some(dev) = vbus.get_device_by_base(base) { - is_dev_belong_to_zone = true; - Some(dev) - } else { - drop(guard); - // Clone Arc first while holding GLOBAL_PCIE_LIST lock, then release it - // This avoids holding multiple locks simultaneously - let dev_clone = { - let global_pcie_list = GLOBAL_PCIE_LIST.lock(); - global_pcie_list - .values() - .find(|dev| { - let dev_guard = dev.read(); - dev_guard.get_base() == base - }) - .cloned() - }; - dev_clone - } - }; - - let dev = match dev { - Some(dev) => dev, - None => { - handle_device_not_found(mmio, offset); - return Ok(()); - } - }; - - let is_root = is_this_root_zone(); - - handle_config_space_access_direct(dev, mmio, offset, zone_id, is_root, is_dev_belong_to_zone); - } else { - warn!("No ATU config yet, do nothing"); - } - Ok(()) -} - -#[cfg(feature = "dwc_pcie")] -pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { - // info!("mmio_vpci_handler_dbi {:#x}", mmio.address); - - /* 0x0-0x100 is outbound atu0 reg - * 0x100-0x200 is inbound atu0 reg just handle outbound right now - * so MAX is ATU_BASE + ATU_REGION_SIZE/2 - */ - if mmio.address >= ATU_BASE && mmio.address < ATU_BASE + ATU_REGION_SIZE/2 - { - let zone = this_zone(); - let mut guard = zone.write(); - let ecam_base = _base; - let atu_offset = mmio.address - ATU_BASE; - - // warn!("set atu0 register {:#X} value {:#X}", atu_offset, mmio.value); - - let mut atu = guard.atu_configs.get_atu_by_ecam_mut(ecam_base).unwrap(); - - // info!("atu config write {:#?}", atu); - - if mmio.is_write { - if mmio.size == 4 { - match atu_offset { - PCIE_ATU_UNR_REGION_CTRL1 => { - // info!("set atu0 region ctrl1 value {:#X}", mmio.value); - atu.atu_type = AtuType::from_u8((mmio.value & 0xff) as u8); - } - PCIE_ATU_UNR_REGION_CTRL2 => { - // Enable bit is written here, but we just track it - // The actual enable is handled by the driver - } - PCIE_ATU_UNR_LOWER_BASE => { - // info!("set atu0 lower base value {:#X}", mmio.value); - atu.cpu_base = (atu.cpu_base & !0xffffffff) | (mmio.value as PciConfigAddress); - } - PCIE_ATU_UNR_UPPER_BASE => { - // info!("set atu0 upper base value {:#X}", mmio.value); - atu.cpu_base = (atu.cpu_base & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32); - } - PCIE_ATU_UNR_LIMIT => { - // info!("set atu0 limit value {:#X}", mmio.value); - atu.cpu_limit = (atu.cpu_limit & !0xffffffff) | (mmio.value as PciConfigAddress); - } - PCIE_ATU_UNR_UPPER_LIMIT => { - // Update the upper 32 bits of cpu_limit - atu.cpu_limit = (atu.cpu_limit & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32); - } - PCIE_ATU_UNR_LOWER_TARGET => { - // info!("set atu0 lower target value {:#X}", mmio.value); - atu.pci_target = (atu.pci_target & !0xffffffff) | (mmio.value as PciConfigAddress); - } - PCIE_ATU_UNR_UPPER_TARGET => { - // info!("set atu0 upper target value {:#X}", mmio.value); - atu.pci_target = (atu.pci_target & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32); - } - _ => { - warn!("invalid atu0 write {:#x} + {:#x}", atu_offset, mmio.size); - } - } - } else { - warn!("invalid atu0 read size {:#x}", mmio.size); - } - } else { - // Read from virtual ATU - // warn!("read atu0 {:#x}", atu_offset); - match atu_offset { - PCIE_ATU_UNR_REGION_CTRL1 => { - mmio.value = atu.atu_type as usize; - } - PCIE_ATU_UNR_REGION_CTRL2 => { - mmio.value = ATU_ENABLE_BIT as usize; - } - PCIE_ATU_UNR_LOWER_BASE => { - mmio.value = (atu.cpu_base & 0xffffffff) as usize; - } - PCIE_ATU_UNR_UPPER_BASE => { - mmio.value = ((atu.cpu_base >> 32) & 0xffffffff) as usize; - } - PCIE_ATU_UNR_LIMIT => { - let limit_value = (atu.cpu_limit & 0xffffffff) as usize; - // If limit is 0, return 0x3ffffff instead - mmio.value = if limit_value == 0 { 0x3ffffff } else { limit_value }; - } - PCIE_ATU_UNR_UPPER_LIMIT => { - // Return the upper 32 bits of cpu_limit - // If it's 0xffffffff, return 0x40000000 instead - let upper_limit = ((atu.cpu_limit >> 32) & 0xffffffff) as usize; - mmio.value = if upper_limit == 0xffffffff { 0x40000000 } else { upper_limit }; - } - PCIE_ATU_UNR_LOWER_TARGET => { - mmio.value = (atu.pci_target & 0xffffffff) as usize; - } - PCIE_ATU_UNR_UPPER_TARGET => { - mmio.value = ((atu.pci_target >> 32) & 0xffffffff) as usize; - } - _ => { - warn!("invalid atu0 read {:#x}", atu_offset); - mmio_perform_access(_base, mmio); - } - } - } - } else if mmio.address > ATU_BASE + ATU_REGION_SIZE/2 { - mmio_perform_access(_base, mmio); - // // other atu - // let is_root = is_this_root_zone(); - // let atu_offset = (mmio.address - ATU_BASE) % ATU_REGION_SIZE; - - // // 0x0-0x100 is inbound ATU (needs emulation) - // // 0x100-0x200 is outbound ATU (direct passthrough) - // if atu_offset >= 0x100 { - // // Outbound ATU: direct passthrough - // mmio_perform_access(_base, mmio); - // return Ok(()); - // } - - // // Inbound ATU: needs emulation (0x0-0x100 range) - // // For non-root zones, only allow access to LIMIT registers - // if !is_root { - // if mmio.is_write { - // // For non-root zones, only allow writes to LIMIT registers - // if atu_offset == PCIE_ATU_UNR_LIMIT || atu_offset == PCIE_ATU_UNR_UPPER_LIMIT { - // // Allow the write to proceed, but we'll handle read specially - // mmio_perform_access(_base, mmio); - // } else { - // // Reject access to other registers for non-root zones - // warn!("non-root zone attempted to access ATU register {:#x} at offset {:#x}", mmio.address, atu_offset); - // return Ok(()); - // } - // } else { - // // For reads, handle LIMIT registers specially - // if atu_offset == PCIE_ATU_UNR_LIMIT { - // // Read from hardware first - // mmio_perform_access(_base, mmio); - // // If value is 0, return 0x3ffffff instead - // if mmio.value == 0 { - // mmio.value = 0x3ffffff; - // } - // } else if atu_offset == PCIE_ATU_UNR_UPPER_LIMIT { - // // Read upper limit from hardware - // mmio_perform_access(_base, mmio); - // // If value is 0xffffffff, return 0x40000000 instead - // if mmio.value == 0xffffffff { - // mmio.value = 0x40000000; - // } - // } else { - // // Reject access to other registers for non-root zones - // warn!("non-root zone attempted to read ATU register {:#x} at offset {:#x}", mmio.address, atu_offset); - // return Ok(()); - // } - // } - // } else { - // // For root zones, handle LIMIT registers specially but allow all other accesses - // if !mmio.is_write { - // if atu_offset == PCIE_ATU_UNR_LIMIT { - // // Read from hardware first - // mmio_perform_access(_base, mmio); - // // If value is 0, return 0x3ffffff instead - // if mmio.value == 0 { - // mmio.value = 0x3ffffff; - // } - // } else if atu_offset == PCIE_ATU_UNR_UPPER_LIMIT { - // // Read upper limit from hardware - // mmio_perform_access(_base, mmio); - // // If value is 0xffffffff, return 0x40000000 instead - // if mmio.value == 0xffffffff { - // mmio.value = 0x40000000; - // } - // } else { - // // For other registers, perform normal access - // mmio_perform_access(_base, mmio); - // } - // } else { - // // For writes, perform normal access (including LIMIT registers) - // mmio_perform_access(_base, mmio); - // } - // } - } else if mmio.address >= BIT_LENTH { - // dbi read - mmio_perform_access(_base, mmio); - } else { - warn!("mmio_vpci_handler_dbi read {:#x}", mmio.address); - let offset = (mmio.address & 0xfff) as PciConfigAddress; - let zone_id = this_zone_id(); - let zone = this_zone(); - let mut is_dev_belong_to_zone = false; - - let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; - - let dev: Option = { - let mut guard = zone.write(); - let vbus = &mut guard.vpci_bus; - if let Some(dev) = vbus.get_device_by_base(base) { - is_dev_belong_to_zone = true; - Some(dev) - } else { - drop(guard); - // Clone Arc first while holding GLOBAL_PCIE_LIST lock, then release it - // This avoids holding multiple locks simultaneously - let dev_clone = { - let global_pcie_list = GLOBAL_PCIE_LIST.lock(); - global_pcie_list - .values() - .find(|dev| { - let dev_guard = dev.read(); - dev_guard.get_base() == base - }) - .cloned() - }; - dev_clone - } - }; - - let dev = match dev { - Some(dev) => dev, - None => { - handle_device_not_found(mmio, offset); - return Ok(()); - } - }; - - let is_root = is_this_root_zone(); - - handle_config_space_access_direct(dev, mmio, offset, zone_id, is_root, is_dev_belong_to_zone); - } - - Ok(()) -} - -fn handle_config_space_access_direct( - dev: ArcRwLockVirtualPciConfigSpace, - mmio: &mut MMIOAccess, - offset: PciConfigAddress, - zone_id: usize, - is_root: bool, - is_dev_belong_to_zone: bool, -) -> HvResult { - let size = mmio.size; - let value = mmio.value; - let is_write = mmio.is_write; - let vbdf = dev.get_bdf(); - - if (offset as usize) >= BIT_LENTH { - warn!("invalid pci offset {:#x}", offset); - if !is_write { - mmio.value = 0; - } - return Ok(()); - } - - if is_dev_belong_to_zone || is_root { - match dev.access(offset, size) { - false => { - info!( - "hw vbdf {:#?} reg 0x{:x} try {} {}", - vbdf, - offset, - if is_write { "write" } else { "read" }, - if is_write { - format!(" 0x{:x}", mmio.value) - } else { - String::new() - } - ); - if is_write { - dev.write_hw(offset, size, value)?; - } else { - mmio.value = dev.read_hw(offset, size).unwrap(); - } - } - true => { - info!( - "emu vbdf {:#?} reg 0x{:x} try {} {}", - vbdf, - offset, - if is_write { "write" } else { "read" }, - if 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::ID => { - if !is_write { - if is_dev_belong_to_zone { - mmio.value = dev.read_emu(EndpointField::ID).unwrap(); - } else { - if is_root { - /* just a id no one used now - * here let root allocate resources but not drive the device - */ - mmio.value = 0xFFFD_4106; - } - } - } - } - EndpointField::RevisionIDAndClassCode => { - if !is_write { - if is_dev_belong_to_zone { - mmio.value = dev - .read_emu(EndpointField::RevisionIDAndClassCode) - .unwrap(); - } else if is_root { - // Default: base class 0xff, subclass/progIF/revision set to 0 - mmio.value = 0xff00_0000; - } - } - } - EndpointField::Bar(slot) => { - let bar_type = dev.with_bar_ref(slot, |bar| bar.get_type()); - if bar_type != PciMemType::default() { - if is_write { - if (value & 0xfffffff0) == 0xfffffff0 { - dev.with_bar_ref_mut(slot, |bar| bar.set_size_read()); - } else { - let _ = dev.write_emu(EndpointField::Bar(slot), value); - if is_root { - let _ = dev.write_hw(offset, size, value); - } - // For Mem64Low, update virtual_value but don't update GPM yet - // (GPM will be updated when Mem64High is written) - if bar_type == PciMemType::Mem64Low { - let new_vaddr = (value as u64) & !0xf; - dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); - // Sync virtual_value back to emu value - let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()); - let _ = dev.write_emu(EndpointField::Bar(slot), virtual_value as usize); - } else if (bar_type == PciMemType::Mem32) - | (bar_type == PciMemType::Mem64High) - | (bar_type == PciMemType::Io) { - let old_vaddr = dev.with_bar_ref(slot, |bar| 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 - * Read from config_value.bar_value cache instead of space - */ - let low_value = dev.with_config_value(|cv| cv.get_bar_value(slot - 1)) as u64; - let high_value = (value as u32 as u64) << 32; - (low_value | high_value) & !0xf - } else { - (value as u64) & !0xf - } - }; - - dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); - if bar_type == PciMemType::Mem64High { - dev.with_bar_ref_mut(slot - 1, |bar| bar.set_virtual_value(new_vaddr)); - } - - // Sync virtual_value back to space after processing (adding flags) - // TODO: check whether need sync here - let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()); - let _ = dev.write_emu(EndpointField::Bar(slot), virtual_value as usize); - if bar_type == PciMemType::Mem64High { - let virtual_value_low = dev.with_bar_ref(slot - 1, |bar| bar.get_virtual_value()); - let _ = dev.write_emu(EndpointField::Bar(slot - 1), virtual_value_low as usize); - } - - let paddr = if is_root { - dev.with_bar_ref_mut(slot, |bar| bar.set_value(new_vaddr)); - if bar_type == PciMemType::Mem64High { - dev.with_bar_ref_mut(slot - 1, |bar| bar.set_value(new_vaddr)); - } - new_vaddr as HostPhysAddr - } else { - dev.with_bar_ref(slot, |bar| bar.get_value64()) as HostPhysAddr - }; - - let bar_size = { - let size = dev.with_bar_ref(slot, |bar| bar.get_size()); - if crate::memory::addr::is_aligned(size as usize) { - size - } else { - crate::memory::PAGE_SIZE as u64 - } - }; - let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) { - crate::memory::addr::align_up(new_vaddr as usize) as u64 - } else { - new_vaddr as u64 - }; - - if !is_root { - let zone = this_zone(); - let mut guard = zone.write(); - let gpm = &mut guard.gpm; - - if !gpm.try_delete(old_vaddr.try_into().unwrap(), bar_size as usize).is_ok() { - warn!( - "delete bar {}: can not found 0x{:x}", - slot, old_vaddr - ); - } - gpm.try_insert(MemoryRegion::new_with_offset_mapper( - new_vaddr as GuestPhysAddr, - paddr as HostPhysAddr, - bar_size as _, - MemFlags::READ | MemFlags::WRITE, - ))?; - /* after update gpm, mem barrier is needed - */ - #[cfg(target_arch = "aarch64")] - unsafe { - core::arch::asm!("isb"); - core::arch::asm!("tlbi vmalls12e1is"); - core::arch::asm!("dsb nsh"); - } - /* after update gpm, need to flush iommu table - * in x86_64 - */ - #[cfg(target_arch = "x86_64")] - crate::arch::iommu::flush( - zone_id, - vbdf.bus, - (vbdf.device << 3) + vbdf.function, - ); - } - } - } - } else { - // Re-fetch bar to get the latest virtual_value after potential write updates - let size_read = dev.with_bar_ref(slot, |bar| bar.get_size_read()); - mmio.value = if size_read { - let r = dev.with_bar_ref(slot, |bar| bar.get_size_with_flag()).try_into().unwrap(); - dev.with_bar_ref_mut(slot, |bar| bar.clear_size_read()); - r - } else { - dev.with_bar_ref(slot, |bar| bar.get_virtual_value()) as usize - // let emu_value = dev.read_emu(EndpointField::Bar(slot)).unwrap() as usize; - // let virtual_value = dev.with_bar_ref(slot, |bar| bar.get_virtual_value()) as usize; - // info!("emu value {:#x} virtual_value {:#x}", emu_value, virtual_value); - // virtual_value - } - } - } else { - mmio.value = 0; - } - } - EndpointField::ExpansionRomBar => { - let rom = dev.get_rom(); - let rom_size_read = rom.get_size_read(); - if is_write { - if (mmio.value & 0xfffff800) == 0xfffff800 { - // TODO: Add method to set rom size_read flag - warn!("ExpansionRomBar size_read not yet implemented for direct handler"); - } else { - // let old_vaddr = dev.read_emu(offset, size).unwrap() as u64; - let _ = dev.write_emu(EndpointField::ExpansionRomBar, value); - // TODO: add gpm change for rom - } - } else { - mmio.value = if rom_size_read { - dev.read_emu(EndpointField::ExpansionRomBar).unwrap() - } else { - rom.get_size_with_flag().try_into().unwrap() - }; - } - } - _ => { - mmio.value = 0; - } - } - } - HeaderType::PciBridge => { - // TODO: add emu for bridge, actually it is same with endpoint - warn!("bridge emu rw"); - } - _ => { - warn!("unhanled pci type {:#?}", dev.get_config_type()); - } - } - } - _ => { - // warn!("virt pci standard rw offset {:#x}, size {:#x}", offset, size); - let result = dev.with_cap(|capabilities| { - if let Some((cap_offset, cap)) = capabilities.range(..=offset).next_back() { - info!("find cap at offset {:#x}, cap {:#?}", cap_offset, cap.get_type()); - let end = *cap_offset + cap.get_size() as u64; - if offset >= end { - // hv_result_err!(ENOENT) - warn!("virt pci cap rw offset {:#x} out of range", offset); - } - let relative_offset = offset - *cap_offset; - - if is_write { - cap.with_region_mut(|region| { - match region.write(relative_offset, size, mmio.value as u32) { - Ok(()) => Ok(0), - Err(e) => { - warn!("Failed to write capability at offset 0x{:x}: {:?}", offset, e); - Err(e) - } - } - }) - } else { - cap.with_region(|region| { - match region.read(relative_offset, size) { - Ok(val) => Ok(val), - Err(e) => { - warn!("Failed to read capability at offset 0x{:x}: {:?}", offset, e); - Err(e) - } - } - }) - } - } else { - hv_result_err!(ENOENT) - } - }); - - match result { - Ok(val) => { - if !is_write { - mmio.value = val as usize; - } - } - Err(_) => { - if mmio.is_write { - super::vpci_dev::vpci_dev_write_cfg(dev.get_dev_type(), dev.clone(), offset, size, value).unwrap(); - } else { - mmio.value = super::vpci_dev::vpci_dev_read_cfg(dev.get_dev_type(), dev.clone(), offset, size).unwrap() as usize; - } - } - } - } - } - } - info!( - "vbdf {:#?} reg 0x{:x} {} 0x{:x}", - vbdf, - offset, - if is_write { "write" } else { "read" }, - mmio.value - ); - - Ok(()) -} - -pub fn mmio_vpci_direct_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { - let zone_id = this_zone_id(); - let zone = this_zone(); - let offset = (mmio.address & 0xfff) as PciConfigAddress; - let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; - let mut is_dev_belong_to_zone = false; - - - let dev: Option = { - let mut guard = zone.write(); - let vbus = &mut guard.vpci_bus; - if let Some(dev) = vbus.get_device_by_base(base) { - is_dev_belong_to_zone = true; - Some(dev) - } else { - drop(guard); - let global_pcie_list = GLOBAL_PCIE_LIST.lock(); - global_pcie_list - .values() - .find(|dev| dev.read().get_base() == base) - .cloned() - } - }; - - let dev = match dev { - Some(dev) => dev, - None => { - handle_device_not_found(mmio, offset); - return Ok(()); - } - }; - - let is_root = is_this_root_zone(); - let _ = handle_config_space_access_direct(dev, mmio, offset, zone_id, is_root, is_dev_belong_to_zone); - - Ok(()) -} \ No newline at end of file diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index f30d7cb6..89a7c899 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -32,12 +32,12 @@ use crate::pci::{vpci_dev::{VpciDevType, get_handler}, pci_struct::VirtualPciCon feature = "dwc_pcie", feature = "loongarch64_pcie" ))] -use crate::pci::{mem_alloc::BaseAllocator, pci_struct::RootComplex, pci_access::mmio_vpci_handler, PciConfigAddress}; +use crate::pci::{mem_alloc::BaseAllocator, pci_struct::RootComplex, pci_handler::mmio_vpci_handler, PciConfigAddress}; #[cfg(feature = "dwc_pcie")] -use crate::{platform, memory::mmio_generic_handler, pci::{config_accessors::dwc_atu::{AtuConfig, AtuType}, pci_access::{mmio_vpci_handler_dbi, mmio_dwc_io_handler, mmio_dwc_cfg_handler}}}; +use crate::{platform, memory::mmio_generic_handler, pci::{config_accessors::dwc_atu::{AtuConfig, AtuType}, pci_handler::{mmio_vpci_handler_dbi, mmio_dwc_io_handler, mmio_dwc_cfg_handler}}}; #[cfg(feature = "loongarch64_pcie")] -use crate::pci::pci_access::mmio_vpci_direct_handler; +use crate::pci::pci_handler::mmio_vpci_direct_handler; pub static GLOBAL_PCIE_LIST: Lazy>> = Lazy::new(|| { let m = BTreeMap::new(); @@ -226,7 +226,7 @@ impl Zone { } #[cfg(feature = "ecam_pcie")] { - use crate::pci::pci_access::mmio_vpci_direct_handler; + // use crate::pci::pci_handler::mmio_vpci_direct_handler; self.mmio_region_register( rootcomplex_config.ecam_base as usize, rootcomplex_config.ecam_size as usize, diff --git a/src/pci/pci_handler.rs b/src/pci/pci_handler.rs new file mode 100644 index 00000000..1de32ce2 --- /dev/null +++ b/src/pci/pci_handler.rs @@ -0,0 +1,937 @@ +use alloc::string::String; + +use crate::error::HvResult; +use crate::memory::MMIOAccess; +use crate::memory::{GuestPhysAddr, HostPhysAddr, MemoryRegion, MemFlags, mmio_perform_access}; +use crate::percpu::this_zone; +use crate::zone::{is_this_root_zone, this_zone_id}; + +use super::pci_access::{BridgeField, EndpointField, HeaderType, PciField, PciMemType}; +use super::pci_struct::{ArcRwLockVirtualPciConfigSpace, BIT_LENTH}; +use super::pci_config::GLOBAL_PCIE_LIST; +use super::vpci_dev::VpciDevType; +use super::PciConfigAddress; + +#[cfg(feature = "dwc_pcie")] +use crate::pci::config_accessors::{ + dwc_atu::{ + AtuConfig, AtuType, ATU_BASE, ATU_REGION_SIZE, + PCIE_ATU_UNR_REGION_CTRL1, PCIE_ATU_UNR_REGION_CTRL2, + PCIE_ATU_UNR_LOWER_BASE, PCIE_ATU_UNR_UPPER_BASE, + PCIE_ATU_UNR_LIMIT, PCIE_ATU_UNR_UPPER_LIMIT, + PCIE_ATU_UNR_LOWER_TARGET, PCIE_ATU_UNR_UPPER_TARGET, + ATU_ENABLE_BIT, + AtuUnroll, + }, + dwc::DwcConfigRegionBackend, + PciRegionMmio, +}; + +macro_rules! pci_log { + ($($arg:tt)*) => { + info!($($arg)*); + // To switch to debug level, change the line above to: + // debug!($($arg)*); + }; +} + +fn handle_virt_pci_request( + dev: ArcRwLockVirtualPciConfigSpace, + offset: PciConfigAddress, + size: usize, + value: usize, + is_write: bool, + dev_type: VpciDevType, +) -> HvResult> { + pci_log!( + "virt pci standard rw offset {:#x}, size {:#x}", + offset, + size + ); + + /* + * The capability is located in the upper part of the configuration space, + * and there is no other message. So the max cap_offset which is less than + * offset is the correct cap we need. + */ + let result = dev.with_cap(|capabilities| { + if let Some((cap_offset, cap)) = capabilities.range(..=offset).next_back() { + pci_log!( + "find cap at offset {:#x}, cap {:#?}", + cap_offset, + cap.get_type() + ); + let end = *cap_offset + cap.get_size() as u64; + if offset >= end { + return hv_result_err!( + ERANGE, + format!( + "virt pci cap rw offset {:#x} out of range [{:#x}..{:#x})", + offset, *cap_offset, end + ) + ); + } + let relative_offset = offset - *cap_offset; + + if is_write { + cap.with_region_mut(|region| { + match region.write(relative_offset, size, value as u32) { + Ok(()) => Ok(0), + Err(e) => { + warn!( + "Failed to write capability at offset 0x{:x}: {:?}", + offset, e + ); + Err(e) + } + } + }) + } else { + cap.with_region(|region| match region.read(relative_offset, size) { + Ok(val) => Ok(val), + Err(e) => { + warn!( + "Failed to read capability at offset 0x{:x}: {:?}", + offset, e + ); + Err(e) + } + }) + } + } else { + hv_result_err!(ENOENT) + } + }); + + match result { + Ok(val) => { + if !is_write { + Ok(Some(val as usize)) + } else { + Ok(None) + } + } + Err(_) => { + if is_write { + super::vpci_dev::vpci_dev_write_cfg(dev_type, dev.clone(), offset, size, value)?; + Ok(None) + } else { + Ok(Some(super::vpci_dev::vpci_dev_read_cfg( + dev_type, + dev.clone(), + offset, + size, + )?)) + } + } + } +} + +fn handle_endpoint_access( + dev: ArcRwLockVirtualPciConfigSpace, + field: EndpointField, + value: usize, + is_write: bool, + is_direct: bool, + is_root: bool, + is_dev_belong_to_zone: bool, +) -> HvResult> { + match field { + EndpointField::ID => { + if !is_write && is_dev_belong_to_zone { + Ok(Some(dev.read_emu(EndpointField::ID)?)) + } else if !is_write && is_direct && is_root { + /* just an id no one used now + * here let root allocate resources but not drive the device + */ + const ROOT_UNUSED_DEVICE_ID: usize = 0xFFFD_4106; + Ok(Some(ROOT_UNUSED_DEVICE_ID)) + } else { + // id is readonly (when is_write is true) + warn!( + "vbdf {:#?}: unhandled {:#?} {}", + dev.get_vbdf(), + field, + if is_write { "write" } else { "read" } + ); + Ok(None) + } + } + EndpointField::RevisionIDAndClassCode => { + if !is_write && is_dev_belong_to_zone { + Ok(Some(dev.read_emu(EndpointField::RevisionIDAndClassCode)?)) + } else if !is_write && is_direct && is_root { + const ROOT_DEFAULT_CLASS_AND_REVISION: usize = 0xff00_0000; + Ok(Some(ROOT_DEFAULT_CLASS_AND_REVISION)) + } else { + warn!( + "vbdf {:#?}: unhandled {:#?} {}", + dev.get_vbdf(), + field, + if is_write { "write" } else { "read" } + ); + Ok(None) + } + } + EndpointField::Bar(slot) => { + /* + * hw: the physical reg + * value: same with physical reg, the paddr for pt + * virt_value: the vaddr for pt + * config_value: the virtual reg for zone, directly rw + * + * The virt_value cache of vaddr is required because mem64 bar updates are + * split between mem64high and mem64low registers. The Hvisor must wait + * for both updates to complete before using old_vaddr for page table maintenance + * + * In typical operation, tmp_value maintains parity with virt_value; the sole exception occurs + * when exclusively updating mem64low while leaving mem64high unmodified, + * as previously described + */ + let bar_type = dev.with_bar_ref(slot, |bar| bar.get_type()); + if bar_type != PciMemType::default() { + if is_write { + if is_direct && is_root { + // direct mode and root zone, update resources directly + dev.with_config_value_mut(|configvalue| { + configvalue.set_bar_value(slot, value as u32); + }); + dev.write_hw(field.to_offset() as PciConfigAddress, field.size(), value)?; + if (bar_type == PciMemType::Mem32) + | (bar_type == PciMemType::Mem64High) + | (bar_type == PciMemType::Io) { + 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 + * Read from config_value.bar_value cache instead of space + */ + let low_value = dev.with_config_value(|cv| cv.get_bar_value(slot - 1)) as u64; + let high_value = (value as u32 as u64) << 32; + (low_value | high_value) & !0xf + } else { + (value as u64) & !0xf + } + }; + + // set virt_value + dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); + if bar_type == PciMemType::Mem64High { + dev.with_bar_ref_mut(slot - 1, |bar| bar.set_virtual_value(new_vaddr)); + } + + // set value + dev.with_bar_ref_mut(slot, |bar| bar.set_value(new_vaddr)); + if bar_type == PciMemType::Mem64High { + dev.with_bar_ref_mut(slot - 1, |bar| bar.set_value(new_vaddr)); + } + } + + } else if is_dev_belong_to_zone { + // normal mod, update virt resources + dev.with_config_value_mut(|configvalue| { + configvalue.set_bar_value(slot, value as u32); + }); + + if (bar_type == PciMemType::Mem32) + | (bar_type == PciMemType::Mem64High) + | (bar_type == PciMemType::Io) { + let old_vaddr = dev.with_bar_ref(slot, |bar| 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 + * Read from config_value.bar_value cache instead of space + */ + let low_value = dev.with_config_value(|cv| cv.get_bar_value(slot - 1)) as u64; + let high_value = (value as u32 as u64) << 32; + (low_value | high_value) & !0xf + } else { + (value as u64) & !0xf + } + }; + + dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); + if bar_type == PciMemType::Mem64High { + dev.with_bar_ref_mut(slot - 1, |bar| bar.set_virtual_value(new_vaddr)); + } + + let paddr = if is_root { + dev.with_bar_ref_mut(slot, |bar| bar.set_value(new_vaddr)); + if bar_type == PciMemType::Mem64High { + dev.with_bar_ref_mut(slot - 1, |bar| bar.set_value(new_vaddr)); + } + new_vaddr as HostPhysAddr + } else { + dev.with_bar_ref(slot, |bar| bar.get_value64()) as HostPhysAddr + }; + let bar_size = { + let size = dev.with_bar_ref(slot, |bar| bar.get_size()); + if crate::memory::addr::is_aligned(size as usize) { + size + } else { + crate::memory::PAGE_SIZE as u64 + } + }; + let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) { + crate::memory::addr::align_up(new_vaddr as usize) as u64 + } else { + new_vaddr as u64 + }; + + let zone = this_zone(); + let mut guard = zone.write(); + let gpm = &mut guard.gpm; + + if !gpm.try_delete(old_vaddr.try_into().unwrap(), bar_size as usize).is_ok() { + warn!( + "delete bar {}: can not found 0x{:x}", + slot, old_vaddr + ); + } + gpm.try_insert(MemoryRegion::new_with_offset_mapper( + new_vaddr as GuestPhysAddr, + paddr as HostPhysAddr, + bar_size as _, + MemFlags::READ | MemFlags::WRITE, + ))?; + drop(guard); + /* after update gpm, mem barrier is needed + */ + #[cfg(target_arch = "aarch64")] + unsafe { + core::arch::asm!("isb"); + core::arch::asm!("tlbi vmalls12e1is"); + core::arch::asm!("dsb nsh"); + } + /* after update gpm, need to flush iommu table + * in x86_64 + */ + #[cfg(target_arch = "x86_64")] + { + let vbdf = dev.get_vbdf(); + crate::arch::iommu::flush( + this_zone_id(), + vbdf.bus, + (vbdf.device << 3) + vbdf.function, + ); + } + } + } + Ok(None) + } else { + // read bar + if (dev.with_config_value(|configvalue| configvalue.get_bar_value(slot)) & 0xfffffff0) == 0xfffffff0 + { + /* + * tmp_value being 0xFFFF_FFFF means that Linux is attempting to determine the BAR size. + * The value of tmp_value is used directly here because Linux will rewrite this register later, + * so the Hvisor does not need to preserve any additional state. + */ + Ok(Some( + dev.with_bar_ref(slot, |bar| bar.get_size_with_flag()) as usize + )) + } else { + Ok(Some( + dev.with_config_value(|configvalue| configvalue.get_bar_value(slot)) + as usize, + )) + } + } + } else { + Ok(None) + } + } + EndpointField::ExpansionRomBar => { + // rom is same with bar + let rom_type = dev.with_rom_ref(|rom| rom.get_type()); + if rom_type == PciMemType::Rom { + if is_write { + if is_direct && is_root { + dev.with_config_value_mut(|configvalue| { + configvalue.set_rom_value(value as u32); + }); + dev.write_hw(field.to_offset() as PciConfigAddress, field.size(), value)?; + + let new_vaddr = (value as u64) & !0xf; + + // set virt_value + dev.with_rom_ref_mut(|rom| rom.set_virtual_value(new_vaddr)); + + // set value + dev.with_rom_ref_mut(|rom| rom.set_value(new_vaddr)); + } else if is_dev_belong_to_zone { + // normal mode, update virt resources + dev.with_config_value_mut(|configvalue| { + configvalue.set_rom_value(value as u32); + }); + + let old_vaddr = dev.with_rom_ref(|rom| rom.get_virtual_value64()) & !0xf; + let new_vaddr = (value as u64) & !0xf; + + dev.with_rom_ref_mut(|rom| rom.set_virtual_value(new_vaddr)); + + let paddr = if is_root { + dev.with_rom_ref_mut(|rom| rom.set_value(new_vaddr)); + new_vaddr as HostPhysAddr + } else { + dev.with_rom_ref(|rom| rom.get_value64()) as HostPhysAddr + }; + + let rom_size = { + let size = dev.with_rom_ref(|rom| rom.get_size()); + if crate::memory::addr::is_aligned(size as usize) { + size + } else { + crate::memory::PAGE_SIZE as u64 + } + }; + let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) { + crate::memory::addr::align_up(new_vaddr as usize) as u64 + } else { + new_vaddr as u64 + }; + + let zone = this_zone(); + let mut guard = zone.write(); + let gpm = &mut guard.gpm; + + if !gpm.try_delete(old_vaddr.try_into().unwrap(), rom_size as usize).is_ok() { + warn!( + "delete rom bar: can not found 0x{:x}", + old_vaddr + ); + } + gpm.try_insert(MemoryRegion::new_with_offset_mapper( + new_vaddr as GuestPhysAddr, + paddr as HostPhysAddr, + rom_size as _, + MemFlags::READ | MemFlags::WRITE, + ))?; + drop(guard); + /* after update gpm, mem barrier is needed + */ + #[cfg(target_arch = "aarch64")] + unsafe { + core::arch::asm!("isb"); + core::arch::asm!("tlbi vmalls12e1is"); + core::arch::asm!("dsb nsh"); + } + /* after update gpm, need to flush iommu table + * in x86_64 + */ + #[cfg(target_arch = "x86_64")] + { + let vbdf = dev.get_vbdf(); + crate::arch::iommu::flush( + this_zone_id(), + vbdf.bus, + (vbdf.device << 3) + vbdf.function, + ); + } + } + Ok(None) + } else { + // read rom bar + if (dev.with_config_value(|configvalue| configvalue.get_rom_value())) & 0xfffff800 == 0xfffff800 + { + /* + * config_value being 0xFFFF_FFFF means that Linux is attempting to determine the ROM size. + * The value is used directly here because Linux will rewrite this register later, + * so the Hvisor does not need to preserve any additional state. + */ + Ok(Some( + dev.with_rom_ref(|rom| rom.get_size_with_flag()) as usize + )) + } else { + Ok(Some( + dev.with_config_value(|configvalue| configvalue.get_rom_value()) + as usize, + )) + } + } + } else { + + Ok(None) + } + } + _ => Ok(None), + } +} + +fn handle_pci_bridge_access( + _dev: ArcRwLockVirtualPciConfigSpace, + _field: BridgeField, + _is_write: bool, +) -> HvResult> { + Ok(None) +} + +/* + * is_direct: if true, root can allocate resource for device belonging + * to ohter zone but can't drive it + * is_root: if the access is from the root zone + * is_dev_belong_to_zone: if the access is from the device that belongs to the zone + */ +fn handle_config_space_access( + dev: ArcRwLockVirtualPciConfigSpace, + mmio: &mut MMIOAccess, + offset: PciConfigAddress, + is_direct: bool, + is_root: bool, + is_dev_belong_to_zone: bool, +) -> HvResult { + let is_write = mmio.is_write; + + // the lenth of access and control bits are limited by BIT_LENTH + if (offset as usize) >= BIT_LENTH { + warn!("invalid pci offset {:#x}", offset); + if !is_write { + mmio.value = 0; + } + return Ok(()); + } + + let size = mmio.size; + let value = mmio.value; + + let vbdf = dev.get_bdf(); + let dev_type = dev.get_dev_type(); + + if is_root || is_dev_belong_to_zone { + match dev.access(offset, size) { + false => { + // Hardware access path + pci_log!( + "hw vbdf {:#?} reg 0x{:x} try {} {}", + vbdf, + offset, + if is_write { "write" } else { "read" }, + if is_write { + format!("0x{:x}", mmio.value) + } else { + String::new() + } + ); + if is_write { + dev.write_hw(offset, size, value)?; + } else { + mmio.value = dev.read_hw(offset, size).unwrap(); + } + } + true => { + // Emulation access path + pci_log!( + "emu vbdf {:#?} reg 0x{:x} try {} {}", + vbdf, + offset, + if is_write { "write" } else { "read" }, + if is_write { + format!(" 0x{:x}", mmio.value) + } else { + String::new() + } + ); + match dev_type { + VpciDevType::Physical => { + let config_type = dev.get_config_type(); + match config_type { + HeaderType::Endpoint => { + if let Some(val) = handle_endpoint_access( + dev, + EndpointField::from(offset as usize, size), + value, + is_write, + is_direct, + is_root, + is_dev_belong_to_zone, + )? { + mmio.value = val; + } + } + HeaderType::PciBridge => { + if let Some(val) = handle_pci_bridge_access( + dev, + BridgeField::from(offset as usize, size), + is_write, + )? { + mmio.value = val; + } + } + _ => { + mmio.value = 0; + } + } + } + _ => { + // virt pci dev + if let Some(val) = + handle_virt_pci_request(dev, offset, size, value, is_write, dev_type)? + { + mmio.value = val; + } + } + } + } + } + } + + pci_log!( + "vbdf {:#?} reg 0x{:x} {} 0x{:x}", + vbdf, + offset, + if is_write { "write" } else { "read" }, + mmio.value + ); + Ok(()) +} + +fn handle_device_not_found(mmio: &mut MMIOAccess, offset: PciConfigAddress) { + /* if the dev is None, just return 0xFFFF_FFFF when read ID */ + if !mmio.is_write { + match EndpointField::from(offset as usize, mmio.size) { + EndpointField::ID => { + mmio.value = 0xFFFF_FFFF; + } + _ => { + // warn!("unhandled pci mmio read, addr: {:#x?}", mmio.address); + mmio.value = 0; + } + } + } +} + +pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { + // info!("mmio_vpci_handler {:#x}", mmio.address); + let zone = this_zone(); + let offset = (mmio.address & 0xfff) as PciConfigAddress; + let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; + + let dev: Option = { + let mut guard = zone.write(); + let vbus = &mut guard.vpci_bus; + vbus.get_device_by_base(base) + }; + + let is_root = is_this_root_zone(); + + if let Some(dev) = dev { + handle_config_space_access(dev, mmio, offset, false, is_root, true)?; + } else { + handle_device_not_found(mmio, offset); + } + + Ok(()) +} + +#[cfg(feature = "dwc_pcie")] +pub fn mmio_dwc_io_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { + { + let zone = this_zone(); + let guard = zone.read(); + + let atu_config = guard.atu_configs.get_atu_by_io_base(_base as PciConfigAddress) + .and_then(|atu| { + guard.atu_configs.get_ecam_by_io_base(_base as PciConfigAddress) + .map(|ecam| (*atu, ecam)) + }); + + drop(guard); + + if let Some((atu, ecam_base)) = atu_config { + use crate::platform; + if let Some(extend_config) = platform::ROOT_DWC_ATU_CONFIG + .iter() + .find(|cfg| cfg.ecam_base == ecam_base as u64) + { + // Create DBI backend + let dbi_base = extend_config.dbi_base as PciConfigAddress; + let dbi_size = extend_config.dbi_size; + let dbi_region = PciRegionMmio::new(dbi_base, dbi_size); + let dbi_backend = DwcConfigRegionBackend::new(dbi_region); + + // Call AtuUnroll to program the ATU + AtuUnroll::dw_pcie_prog_outbound_atu_unroll(&dbi_backend, &atu)?; + } + mmio_perform_access(atu.pci_target as usize, mmio); + } else { + warn!("No ATU config yet, do nothing"); + } + } + Ok(()) +} + +#[cfg(feature = "dwc_pcie")] +pub fn mmio_dwc_cfg_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { + info!("mmio_dwc_cfg_handler {:#x}", mmio.address + _base); + let zone = this_zone(); + let guard = zone.read(); + + let atu_config = guard.atu_configs.get_atu_by_cfg_base(_base as PciConfigAddress) + .and_then(|atu| { + guard.atu_configs.get_ecam_by_cfg_base(_base as PciConfigAddress) + .map(|ecam| (*atu, ecam)) + }); + + drop(guard); + + if let Some((atu, ecam_base)) = atu_config { + // Get dbi_base from platform config (usually dbi_base == ecam_base) + use crate::platform; + if let Some(extend_config) = platform::ROOT_DWC_ATU_CONFIG + .iter() + .find(|cfg| cfg.ecam_base == ecam_base as u64) + { + // Create DBI backend + let dbi_base = extend_config.dbi_base as PciConfigAddress; + let dbi_size = extend_config.dbi_size; + let dbi_region = PciRegionMmio::new(dbi_base, dbi_size); + let dbi_backend = DwcConfigRegionBackend::new(dbi_region); + + // warn!("atu config {:#?}", atu); + + // Call AtuUnroll to program the ATU + AtuUnroll::dw_pcie_prog_outbound_atu_unroll(&dbi_backend, &atu)?; + } + + let offset = (mmio.address & 0xfff) as PciConfigAddress; + let zone = this_zone(); + let mut is_dev_belong_to_zone = false; + + let base = mmio.address as PciConfigAddress - offset + atu.pci_target; + + let dev: Option = { + let mut guard = zone.write(); + let vbus = &mut guard.vpci_bus; + if let Some(dev) = vbus.get_device_by_base(base) { + is_dev_belong_to_zone = true; + Some(dev) + } else { + drop(guard); + // Clone Arc first while holding GLOBAL_PCIE_LIST lock, then release it + // This avoids holding multiple locks simultaneously + let dev_clone = { + let global_pcie_list = GLOBAL_PCIE_LIST.lock(); + global_pcie_list + .values() + .find(|dev| { + let dev_guard = dev.read(); + dev_guard.get_base() == base + }) + .cloned() + }; + dev_clone + } + }; + + let dev = match dev { + Some(dev) => dev, + None => { + handle_device_not_found(mmio, offset); + return Ok(()); + } + }; + + let is_root = is_this_root_zone(); + let is_direct = true; // dwc_cfg_handler uses direct mode + + handle_config_space_access(dev, mmio, offset, is_direct, is_root, is_dev_belong_to_zone)?; + } else { + warn!("No ATU config yet, do nothing"); + } + Ok(()) +} + +#[cfg(feature = "dwc_pcie")] +pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { + // info!("mmio_vpci_handler_dbi {:#x}", mmio.address); + + /* 0x0-0x100 is outbound atu0 reg + * 0x100-0x200 is inbound atu0 reg just handle outbound right now + * so MAX is ATU_BASE + ATU_REGION_SIZE/2 + */ + if mmio.address >= ATU_BASE && mmio.address < ATU_BASE + ATU_REGION_SIZE/2 + { + let zone = this_zone(); + let mut guard = zone.write(); + let ecam_base = _base; + let atu_offset = mmio.address - ATU_BASE; + + // warn!("set atu0 register {:#X} value {:#X}", atu_offset, mmio.value); + + let mut atu = guard.atu_configs.get_atu_by_ecam_mut(ecam_base).unwrap(); + + // info!("atu config write {:#?}", atu); + + if mmio.is_write { + if mmio.size == 4 { + match atu_offset { + PCIE_ATU_UNR_REGION_CTRL1 => { + // info!("set atu0 region ctrl1 value {:#X}", mmio.value); + atu.atu_type = AtuType::from_u8((mmio.value & 0xff) as u8); + } + PCIE_ATU_UNR_REGION_CTRL2 => { + // Enable bit is written here, but we just track it + // The actual enable is handled by the driver + } + PCIE_ATU_UNR_LOWER_BASE => { + // info!("set atu0 lower base value {:#X}", mmio.value); + atu.cpu_base = (atu.cpu_base & !0xffffffff) | (mmio.value as PciConfigAddress); + } + PCIE_ATU_UNR_UPPER_BASE => { + // info!("set atu0 upper base value {:#X}", mmio.value); + atu.cpu_base = (atu.cpu_base & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32); + } + PCIE_ATU_UNR_LIMIT => { + // info!("set atu0 limit value {:#X}", mmio.value); + atu.cpu_limit = (atu.cpu_limit & !0xffffffff) | (mmio.value as PciConfigAddress); + } + PCIE_ATU_UNR_UPPER_LIMIT => { + // Update the upper 32 bits of cpu_limit + atu.cpu_limit = (atu.cpu_limit & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32); + } + PCIE_ATU_UNR_LOWER_TARGET => { + // info!("set atu0 lower target value {:#X}", mmio.value); + atu.pci_target = (atu.pci_target & !0xffffffff) | (mmio.value as PciConfigAddress); + } + PCIE_ATU_UNR_UPPER_TARGET => { + // info!("set atu0 upper target value {:#X}", mmio.value); + atu.pci_target = (atu.pci_target & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32); + } + _ => { + warn!("invalid atu0 write {:#x} + {:#x}", atu_offset, mmio.size); + } + } + } else { + warn!("invalid atu0 read size {:#x}", mmio.size); + } + } else { + // Read from virtual ATU + // warn!("read atu0 {:#x}", atu_offset); + match atu_offset { + PCIE_ATU_UNR_REGION_CTRL1 => { + mmio.value = atu.atu_type as usize; + } + PCIE_ATU_UNR_REGION_CTRL2 => { + mmio.value = ATU_ENABLE_BIT as usize; + } + PCIE_ATU_UNR_LOWER_BASE => { + mmio.value = (atu.cpu_base & 0xffffffff) as usize; + } + PCIE_ATU_UNR_UPPER_BASE => { + mmio.value = ((atu.cpu_base >> 32) & 0xffffffff) as usize; + } + PCIE_ATU_UNR_LIMIT => { + let limit_value = (atu.cpu_limit & 0xffffffff) as usize; + // If limit is 0, return 0x3ffffff instead + mmio.value = if limit_value == 0 { 0x3ffffff } else { limit_value }; + } + PCIE_ATU_UNR_UPPER_LIMIT => { + // Return the upper 32 bits of cpu_limit + // If it's 0xffffffff, return 0x40000000 instead + let upper_limit = ((atu.cpu_limit >> 32) & 0xffffffff) as usize; + mmio.value = if upper_limit == 0xffffffff { 0x40000000 } else { upper_limit }; + } + PCIE_ATU_UNR_LOWER_TARGET => { + mmio.value = (atu.pci_target & 0xffffffff) as usize; + } + PCIE_ATU_UNR_UPPER_TARGET => { + mmio.value = ((atu.pci_target >> 32) & 0xffffffff) as usize; + } + _ => { + warn!("invalid atu0 read {:#x}", atu_offset); + mmio_perform_access(_base, mmio); + } + } + } + } else if mmio.address > ATU_BASE + ATU_REGION_SIZE/2 { + mmio_perform_access(_base, mmio); + } else if mmio.address >= BIT_LENTH { + // dbi read + mmio_perform_access(_base, mmio); + } else { + warn!("mmio_vpci_handler_dbi read {:#x}", mmio.address); + let offset = (mmio.address & 0xfff) as PciConfigAddress; + let zone = this_zone(); + let mut is_dev_belong_to_zone = false; + + let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; + + let dev: Option = { + let mut guard = zone.write(); + let vbus = &mut guard.vpci_bus; + if let Some(dev) = vbus.get_device_by_base(base) { + is_dev_belong_to_zone = true; + Some(dev) + } else { + drop(guard); + // Clone Arc first while holding GLOBAL_PCIE_LIST lock, then release it + // This avoids holding multiple locks simultaneously + let dev_clone = { + let global_pcie_list = GLOBAL_PCIE_LIST.lock(); + global_pcie_list + .values() + .find(|dev| { + let dev_guard = dev.read(); + dev_guard.get_base() == base + }) + .cloned() + }; + dev_clone + } + }; + + let dev = match dev { + Some(dev) => dev, + None => { + handle_device_not_found(mmio, offset); + return Ok(()); + } + }; + + let is_root = is_this_root_zone(); + let is_direct = true; // dbi handler uses direct mode + + handle_config_space_access(dev, mmio, offset, is_direct, is_root, is_dev_belong_to_zone)?; + } + + Ok(()) +} + +pub fn mmio_vpci_direct_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { + let zone = this_zone(); + let offset = (mmio.address & 0xfff) as PciConfigAddress; + let base = mmio.address as PciConfigAddress - offset + _base as PciConfigAddress; + let mut is_dev_belong_to_zone = false; + + let dev: Option = { + let mut guard = zone.write(); + let vbus = &mut guard.vpci_bus; + if let Some(dev) = vbus.get_device_by_base(base) { + is_dev_belong_to_zone = true; + Some(dev) + } else { + drop(guard); + let global_pcie_list = GLOBAL_PCIE_LIST.lock(); + global_pcie_list + .values() + .find(|dev| dev.read().get_base() == base) + .cloned() + } + }; + + let dev = match dev { + Some(dev) => dev, + None => { + handle_device_not_found(mmio, offset); + return Ok(()); + } + }; + + let is_root = is_this_root_zone(); + let is_direct = true; // direct handler uses direct mode + + handle_config_space_access(dev, mmio, offset, is_direct, is_root, is_dev_belong_to_zone)?; + + Ok(()) +} \ No newline at end of file diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index cfc0f2cd..27b9be68 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -39,6 +39,7 @@ pub struct ConfigValue { id: (DeviceId, VendorId), class_and_revision_id: (BaseClass, SubClass, Interface, DeviceRevision), bar_value: [u32; 6], + rom_value: u32, } impl Default for ConfigValue { @@ -47,6 +48,7 @@ impl Default for ConfigValue { id: (0xFFFFu16, 0xFFFFu16), class_and_revision_id: (0xFFu8, 0u8, 0u8, 0u8), bar_value: [0; 6], + rom_value: 0, } } } @@ -57,6 +59,7 @@ impl ConfigValue { id, class_and_revision_id, bar_value: [0; 6], + rom_value: 0, } } @@ -111,6 +114,14 @@ impl ConfigValue { pub fn get_bar_value_ref_mut(&mut self, slot: usize) -> &mut u32 { &mut self.bar_value[slot] } + + pub fn get_rom_value(&self) -> u32 { + self.rom_value + } + + pub fn set_rom_value(&mut self, value: u32) { + self.rom_value = value; + } } const MAX_DEVICE: u8 = 31; @@ -359,6 +370,10 @@ impl ArcRwLockVirtualPciConfigSpace { self.0.read().get_bdf() } + pub fn get_vbdf(&self) -> Bdf { + self.0.read().get_vbdf() + } + pub fn get_dev_type(&self) -> VpciDevType { self.0.read().get_dev_type() } @@ -439,6 +454,26 @@ impl ArcRwLockVirtualPciConfigSpace { f(&mut guard.config_value) } + /// Execute a closure with a reference to the rom + pub fn with_rom_ref(&self, f: F) -> R + where + F: FnOnce(&PciMem) -> R, + { + let guard = self.0.read(); + let rom = &guard.rom; + f(rom) + } + + /// Execute a closure with a mutable reference to the rom + pub fn with_rom_ref_mut(&self, f: F) -> R + where + F: FnOnce(&mut PciMem) -> R, + { + let mut guard = self.0.write(); + let rom = &mut guard.rom; + f(rom) + } + /// Execute a closure with a reference to the capabilities list pub fn with_cap(&self, f: F) -> R where @@ -814,6 +849,10 @@ impl VirtualPciConfigSpace { hv_result_err!(EFAULT, "pci: invalid bar slot: {slot}") } } + EndpointField::ExpansionRomBar => { + // Read rom_value from cache + Ok(self.config_value.get_rom_value() as usize) + } _ => { // For other fields, read from backend warn!("read emu {:#?} failed, try read from hw", field); @@ -848,6 +887,10 @@ impl VirtualPciConfigSpace { self.config_value.set_bar_value(slot, value as u32); } } + EndpointField::ExpansionRomBar => { + // Update rom_value cache when writing rom bar + self.config_value.set_rom_value(value as u32); + } _ => { // For other fields, write to backend warn!("write emu {:#?} denied", field); diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs index c4c19211..f02df700 100644 --- a/src/pci/pci_test.rs +++ b/src/pci/pci_test.rs @@ -21,7 +21,7 @@ use spin::{lazy::Lazy, mutex::Mutex}; use super::{ mem_alloc::BaseAllocator, - pci_access::{mmio_vpci_direct_handler, mmio_vpci_handler}, + pci_handler::{mmio_vpci_direct_handler, mmio_vpci_handler}, pci_struct::{Bdf, VirtualPciConfigSpace, CONFIG_LENTH, RootComplex}, }; From 3775dffb10dae8f1b13835068e6842be5e6423e0 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 31 Dec 2025 20:51:21 +0800 Subject: [PATCH 063/109] 1.Added hardware emulation for the atu0 limit register 2.remove pub in atuconfig --- src/pci/config_accessors/dwc_atu.rs | 100 ++++++++++++++++++++++++---- src/pci/pci_config.rs | 14 +++- src/pci/pci_handler.rs | 39 +++++------ 3 files changed, 117 insertions(+), 36 deletions(-) diff --git a/src/pci/config_accessors/dwc_atu.rs b/src/pci/config_accessors/dwc_atu.rs index 1ae191a6..f4928c67 100644 --- a/src/pci/config_accessors/dwc_atu.rs +++ b/src/pci/config_accessors/dwc_atu.rs @@ -65,16 +65,18 @@ impl AtuType { #[derive(Clone, Copy, Default)] pub struct AtuConfig { - pub index: usize, - pub atu_type: AtuType, - pub cpu_base: PciConfigAddress, - pub cpu_limit: PciConfigAddress, - pub pci_target: PciConfigAddress, + index: usize, + atu_type: AtuType, + cpu_base: PciConfigAddress, + cpu_limit: PciConfigAddress, + pci_target: PciConfigAddress, + limit_hw_value: u32, + upper_limit_hw_value: u32, } impl Debug for AtuConfig { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "AtuConfig {{ index: {},\n atu_type: {:?},\n cpu_base: {:#x},\n cpu_limit: {:#x},\n pci_target: {:#x} }}", self.index, self.atu_type, self.cpu_base, self.cpu_limit, self.pci_target) + write!(f, "AtuConfig {{ index: {},\n atu_type: {:?},\n cpu_base: {:#x},\n cpu_limit: {:#x},\n pci_target: {:#x} }}", self.index(), self.atu_type(), self.cpu_base(), self.cpu_limit(), self.pci_target()) } } @@ -93,6 +95,8 @@ impl AtuConfig { cpu_base, cpu_limit, pci_target, + limit_hw_value: 0, + upper_limit_hw_value: 0, } } @@ -105,6 +109,76 @@ impl AtuConfig { pci_addr, ) } + + pub fn index(&self) -> usize { + self.index + } + + pub fn atu_type(&self) -> AtuType { + self.atu_type + } + + pub fn cpu_base(&self) -> PciConfigAddress { + self.cpu_base + } + + pub fn cpu_limit(&self) -> PciConfigAddress { + self.cpu_limit + } + + pub fn pci_target(&self) -> PciConfigAddress { + self.pci_target + } + + pub fn set_atu_type(&mut self, atu_type: AtuType) { + self.atu_type = atu_type; + } + + pub fn set_cpu_base(&mut self, cpu_base: PciConfigAddress) { + self.cpu_base = cpu_base; + } + + pub fn set_cpu_limit(&mut self, cpu_limit: PciConfigAddress) { + self.cpu_limit = cpu_limit; + } + + pub fn set_pci_target(&mut self, pci_target: PciConfigAddress) { + self.pci_target = pci_target; + } + + pub fn limit_hw_value(&self) -> u32 { + self.limit_hw_value + } + + pub fn upper_limit_hw_value(&self) -> u32 { + self.upper_limit_hw_value + } + + pub fn init_limit_hw_value(&mut self, dbi_backend: &dyn PciRW) -> HvResult { + let atu_base = (ATU_BASE + self.index() * ATU_REGION_SIZE) as PciConfigAddress; + + dbi_backend.write( + atu_base + PCIE_ATU_UNR_LIMIT as PciConfigAddress, + 4, + 0, + )?; + self.limit_hw_value = dbi_backend.read( + atu_base + PCIE_ATU_UNR_LIMIT as PciConfigAddress, + 4, + )? as u32; + + dbi_backend.write( + atu_base + PCIE_ATU_UNR_UPPER_LIMIT as PciConfigAddress, + 4, + 0xffffffff, + )?; + self.upper_limit_hw_value = dbi_backend.read( + atu_base + PCIE_ATU_UNR_UPPER_LIMIT as PciConfigAddress, + 4, + )? as u32; + + Ok(()) + } } // ATU unroll configuration functions @@ -117,37 +191,37 @@ impl AtuUnroll { dbi_backend: &dyn PciRW, config: &AtuConfig, ) -> HvResult { - let atu_base = (ATU_BASE + config.index * ATU_REGION_SIZE) as PciConfigAddress; + let atu_base = (ATU_BASE + config.index() * ATU_REGION_SIZE) as PciConfigAddress; dbi_backend.write( atu_base + PCIE_ATU_UNR_LOWER_BASE as PciConfigAddress, 4, - (config.cpu_base & 0xffffffff) as usize, + (config.cpu_base() & 0xffffffff) as usize, )?; dbi_backend.write( atu_base + PCIE_ATU_UNR_UPPER_BASE as PciConfigAddress, 4, - (config.cpu_base >> 32) as usize, + (config.cpu_base() >> 32) as usize, )?; dbi_backend.write( atu_base + PCIE_ATU_UNR_LIMIT as PciConfigAddress, 4, - (config.cpu_limit & 0xffffffff) as usize, + (config.cpu_limit() & 0xffffffff) as usize, )?; dbi_backend.write( atu_base + PCIE_ATU_UNR_LOWER_TARGET as PciConfigAddress, 4, - (config.pci_target & 0xffffffff) as usize, + (config.pci_target() & 0xffffffff) as usize, )?; dbi_backend.write( atu_base + PCIE_ATU_UNR_UPPER_TARGET as PciConfigAddress, 4, - (config.pci_target >> 32) as usize, + (config.pci_target() >> 32) as usize, )?; dbi_backend.write( atu_base + PCIE_ATU_UNR_REGION_CTRL1 as PciConfigAddress, 4, - config.atu_type as usize, + config.atu_type() as usize, )?; dbi_backend.write( atu_base + PCIE_ATU_UNR_REGION_CTRL2 as PciConfigAddress, diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 89a7c899..f5d49c80 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -34,7 +34,7 @@ use crate::pci::{vpci_dev::{VpciDevType, get_handler}, pci_struct::VirtualPciCon ))] use crate::pci::{mem_alloc::BaseAllocator, pci_struct::RootComplex, pci_handler::mmio_vpci_handler, PciConfigAddress}; #[cfg(feature = "dwc_pcie")] -use crate::{platform, memory::mmio_generic_handler, pci::{config_accessors::dwc_atu::{AtuConfig, AtuType}, pci_handler::{mmio_vpci_handler_dbi, mmio_dwc_io_handler, mmio_dwc_cfg_handler}}}; +use crate::{platform, memory::mmio_generic_handler, pci::{config_accessors::{dwc_atu::{AtuConfig, AtuType}, dwc::DwcConfigRegionBackend}, pci_access::PciRegionMmio, pci_handler::{mmio_vpci_handler_dbi, mmio_dwc_io_handler, mmio_dwc_cfg_handler}}}; #[cfg(feature = "loongarch64_pcie")] use crate::pci::pci_handler::mmio_vpci_direct_handler; @@ -288,7 +288,17 @@ impl Zone { ); } - self.atu_configs.insert_atu(rootcomplex_config.ecam_base as usize, AtuConfig::default()); + let mut atu = AtuConfig::default(); + + let dbi_base = extend_config.dbi_base as PciConfigAddress; + let dbi_size = extend_config.dbi_size; + let dbi_region = PciRegionMmio::new(dbi_base, dbi_size); + let dbi_backend = DwcConfigRegionBackend::new(dbi_region); + if let Err(e) = atu.init_limit_hw_value(dbi_backend.as_ref()) { + warn!("Failed to initialize ATU0 limit defaults: {:?}", e); + } + + self.atu_configs.insert_atu(rootcomplex_config.ecam_base as usize, atu); self.atu_configs.insert_cfg_base_mapping(extend_config.cfg_base as PciConfigAddress, rootcomplex_config.ecam_base as usize); self.atu_configs.insert_io_base_mapping(rootcomplex_config.io_base as PciConfigAddress, rootcomplex_config.ecam_base as usize); } diff --git a/src/pci/pci_handler.rs b/src/pci/pci_handler.rs index 1de32ce2..a945e386 100644 --- a/src/pci/pci_handler.rs +++ b/src/pci/pci_handler.rs @@ -653,7 +653,7 @@ pub fn mmio_dwc_io_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { // Call AtuUnroll to program the ATU AtuUnroll::dw_pcie_prog_outbound_atu_unroll(&dbi_backend, &atu)?; } - mmio_perform_access(atu.pci_target as usize, mmio); + mmio_perform_access(atu.pci_target() as usize, mmio); } else { warn!("No ATU config yet, do nothing"); } @@ -698,7 +698,7 @@ pub fn mmio_dwc_cfg_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { let zone = this_zone(); let mut is_dev_belong_to_zone = false; - let base = mmio.address as PciConfigAddress - offset + atu.pci_target; + let base = mmio.address as PciConfigAddress - offset + atu.pci_target(); let dev: Option = { let mut guard = zone.write(); @@ -768,7 +768,7 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { match atu_offset { PCIE_ATU_UNR_REGION_CTRL1 => { // info!("set atu0 region ctrl1 value {:#X}", mmio.value); - atu.atu_type = AtuType::from_u8((mmio.value & 0xff) as u8); + atu.set_atu_type(AtuType::from_u8((mmio.value & 0xff) as u8)); } PCIE_ATU_UNR_REGION_CTRL2 => { // Enable bit is written here, but we just track it @@ -776,27 +776,27 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { } PCIE_ATU_UNR_LOWER_BASE => { // info!("set atu0 lower base value {:#X}", mmio.value); - atu.cpu_base = (atu.cpu_base & !0xffffffff) | (mmio.value as PciConfigAddress); + atu.set_cpu_base((atu.cpu_base() & !0xffffffff) | (mmio.value as PciConfigAddress)); } PCIE_ATU_UNR_UPPER_BASE => { // info!("set atu0 upper base value {:#X}", mmio.value); - atu.cpu_base = (atu.cpu_base & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32); + atu.set_cpu_base((atu.cpu_base() & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32)); } PCIE_ATU_UNR_LIMIT => { // info!("set atu0 limit value {:#X}", mmio.value); - atu.cpu_limit = (atu.cpu_limit & !0xffffffff) | (mmio.value as PciConfigAddress); + atu.set_cpu_limit((atu.cpu_limit() & !0xffffffff) | (mmio.value as PciConfigAddress)); } PCIE_ATU_UNR_UPPER_LIMIT => { // Update the upper 32 bits of cpu_limit - atu.cpu_limit = (atu.cpu_limit & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32); + atu.set_cpu_limit((atu.cpu_limit() & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32)); } PCIE_ATU_UNR_LOWER_TARGET => { // info!("set atu0 lower target value {:#X}", mmio.value); - atu.pci_target = (atu.pci_target & !0xffffffff) | (mmio.value as PciConfigAddress); + atu.set_pci_target((atu.pci_target() & !0xffffffff) | (mmio.value as PciConfigAddress)); } PCIE_ATU_UNR_UPPER_TARGET => { // info!("set atu0 upper target value {:#X}", mmio.value); - atu.pci_target = (atu.pci_target & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32); + atu.set_pci_target((atu.pci_target() & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32)); } _ => { warn!("invalid atu0 write {:#x} + {:#x}", atu_offset, mmio.size); @@ -810,33 +810,30 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { // warn!("read atu0 {:#x}", atu_offset); match atu_offset { PCIE_ATU_UNR_REGION_CTRL1 => { - mmio.value = atu.atu_type as usize; + mmio.value = atu.atu_type() as usize; } PCIE_ATU_UNR_REGION_CTRL2 => { mmio.value = ATU_ENABLE_BIT as usize; } PCIE_ATU_UNR_LOWER_BASE => { - mmio.value = (atu.cpu_base & 0xffffffff) as usize; + mmio.value = (atu.cpu_base() & 0xffffffff) as usize; } PCIE_ATU_UNR_UPPER_BASE => { - mmio.value = ((atu.cpu_base >> 32) & 0xffffffff) as usize; + mmio.value = ((atu.cpu_base() >> 32) & 0xffffffff) as usize; } PCIE_ATU_UNR_LIMIT => { - let limit_value = (atu.cpu_limit & 0xffffffff) as usize; - // If limit is 0, return 0x3ffffff instead - mmio.value = if limit_value == 0 { 0x3ffffff } else { limit_value }; + let limit_value = (atu.cpu_limit() & 0xffffffff) as usize; + mmio.value = if limit_value == 0 { atu.limit_hw_value() as usize } else { limit_value }; } PCIE_ATU_UNR_UPPER_LIMIT => { - // Return the upper 32 bits of cpu_limit - // If it's 0xffffffff, return 0x40000000 instead - let upper_limit = ((atu.cpu_limit >> 32) & 0xffffffff) as usize; - mmio.value = if upper_limit == 0xffffffff { 0x40000000 } else { upper_limit }; + let upper_limit = ((atu.cpu_limit() >> 32) & 0xffffffff) as usize; + mmio.value = if upper_limit == 0xffffffff { atu.upper_limit_hw_value() as usize } else { upper_limit }; } PCIE_ATU_UNR_LOWER_TARGET => { - mmio.value = (atu.pci_target & 0xffffffff) as usize; + mmio.value = (atu.pci_target() & 0xffffffff) as usize; } PCIE_ATU_UNR_UPPER_TARGET => { - mmio.value = ((atu.pci_target >> 32) & 0xffffffff) as usize; + mmio.value = ((atu.pci_target() >> 32) & 0xffffffff) as usize; } _ => { warn!("invalid atu0 read {:#x}", atu_offset); From 49f0aed97db5f98d4925a3fdfb6cfa8616e90c76 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 31 Dec 2025 20:52:54 +0800 Subject: [PATCH 064/109] fmt --- src/memory/mm.rs | 14 +- src/pci/config_accessors/dwc.rs | 14 +- src/pci/config_accessors/dwc_atu.rs | 24 +-- src/pci/config_accessors/loongarch64.rs | 18 +- src/pci/config_accessors/mod.rs | 6 +- src/pci/mem_alloc.rs | 3 +- src/pci/mod.rs | 2 +- src/pci/pci_access.rs | 38 ++-- src/pci/pci_config.rs | 115 +++++++---- src/pci/pci_handler.rs | 257 ++++++++++++++---------- src/pci/pci_struct.rs | 193 +++++++++++------- src/pci/pci_test.rs | 33 ++- src/pci/vpci_dev/mod.rs | 136 ++++++++----- src/pci/vpci_dev/standard.rs | 100 +++++---- src/zone.rs | 11 +- 15 files changed, 569 insertions(+), 395 deletions(-) diff --git a/src/memory/mm.rs b/src/memory/mm.rs index d25ff4c2..943a7714 100644 --- a/src/memory/mm.rs +++ b/src/memory/mm.rs @@ -109,7 +109,12 @@ where /// Add a memory region to this set. pub fn insert(&mut self, region: MemoryRegion) -> HvResult { - info!("region.start: {:#X}, size: {:#X}, flags: {:#X}", region.start.into(), region.size, region.flags); + info!( + "region.start: {:#X}, size: {:#X}, flags: {:#X}", + region.start.into(), + region.size, + region.flags + ); assert!(is_aligned(region.start.into())); assert!(is_aligned(region.size)); if region.size == 0 { @@ -175,7 +180,12 @@ where if region.size == size { self.delete(start, size) } else { - warn!("try delete MemoryRegion size mismatch at {:#x?}, expected {:#x?}, got {:#x?}", start.into(), size, region.size); + warn!( + "try delete MemoryRegion size mismatch at {:#x?}, expected {:#x?}, got {:#x?}", + start.into(), + size, + region.size + ); Err(hv_err!(ENOMEM)) } } else { diff --git a/src/pci/config_accessors/dwc.rs b/src/pci/config_accessors/dwc.rs index d61345ec..52771a2b 100644 --- a/src/pci/config_accessors/dwc.rs +++ b/src/pci/config_accessors/dwc.rs @@ -95,7 +95,7 @@ impl DwcConfigAccessor { base: dbi_base, size: dbi_size, }; - + /* actually we only use atu0 to init dwc pcie */ let cfg0 = DwcConfigRegion { atu_index: 0, @@ -121,11 +121,7 @@ impl DwcConfigAccessor { } impl PciConfigAccessor for DwcConfigAccessor { - fn get_pci_addr_base( - &self, - bdf: Bdf, - parent_bus: u8, - ) -> HvResult { + fn get_pci_addr_base(&self, bdf: Bdf, parent_bus: u8) -> HvResult { let bus = bdf.bus() as PciConfigAddress; let device = bdf.device() as PciConfigAddress; let function = bdf.function() as PciConfigAddress; @@ -163,7 +159,8 @@ impl PciConfigAccessor for DwcConfigAccessor { if self.cfg0.atu_index == ATU_UNUSED as usize { return hv_result_err!(EINVAL, "CFG0 ATU is not configured"); } - let atu_config = AtuConfig::new_with_dwc_config_region(&self.cfg0, AtuType::Cfg0, pci_addr); + let atu_config = + AtuConfig::new_with_dwc_config_region(&self.cfg0, AtuType::Cfg0, pci_addr); AtuUnroll::dw_pcie_prog_outbound_atu_unroll(self.dbi_backend.as_ref(), &atu_config)?; self.cfg0.base @@ -171,7 +168,8 @@ impl PciConfigAccessor for DwcConfigAccessor { if self.cfg1.atu_index == ATU_UNUSED as usize { return hv_result_err!(EINVAL, "CFG1 ATU is not configured"); } - let atu_config = AtuConfig::new_with_dwc_config_region(&self.cfg1, AtuType::Cfg1, pci_addr); + let atu_config = + AtuConfig::new_with_dwc_config_region(&self.cfg1, AtuType::Cfg1, pci_addr); AtuUnroll::dw_pcie_prog_outbound_atu_unroll(self.dbi_backend.as_ref(), &atu_config)?; self.cfg1.base diff --git a/src/pci/config_accessors/dwc_atu.rs b/src/pci/config_accessors/dwc_atu.rs index f4928c67..08b3847a 100644 --- a/src/pci/config_accessors/dwc_atu.rs +++ b/src/pci/config_accessors/dwc_atu.rs @@ -100,7 +100,11 @@ impl AtuConfig { } } - pub fn new_with_dwc_config_region(config_region: &DwcConfigRegion, atu_type: AtuType, pci_addr: PciConfigAddress) -> Self { + pub fn new_with_dwc_config_region( + config_region: &DwcConfigRegion, + atu_type: AtuType, + pci_addr: PciConfigAddress, + ) -> Self { Self::new( config_region.atu_index, atu_type, @@ -157,25 +161,17 @@ impl AtuConfig { pub fn init_limit_hw_value(&mut self, dbi_backend: &dyn PciRW) -> HvResult { let atu_base = (ATU_BASE + self.index() * ATU_REGION_SIZE) as PciConfigAddress; - dbi_backend.write( - atu_base + PCIE_ATU_UNR_LIMIT as PciConfigAddress, - 4, - 0, - )?; - self.limit_hw_value = dbi_backend.read( - atu_base + PCIE_ATU_UNR_LIMIT as PciConfigAddress, - 4, - )? as u32; + dbi_backend.write(atu_base + PCIE_ATU_UNR_LIMIT as PciConfigAddress, 4, 0)?; + self.limit_hw_value = + dbi_backend.read(atu_base + PCIE_ATU_UNR_LIMIT as PciConfigAddress, 4)? as u32; dbi_backend.write( atu_base + PCIE_ATU_UNR_UPPER_LIMIT as PciConfigAddress, 4, 0xffffffff, )?; - self.upper_limit_hw_value = dbi_backend.read( - atu_base + PCIE_ATU_UNR_UPPER_LIMIT as PciConfigAddress, - 4, - )? as u32; + self.upper_limit_hw_value = + dbi_backend.read(atu_base + PCIE_ATU_UNR_UPPER_LIMIT as PciConfigAddress, 4)? as u32; Ok(()) } diff --git a/src/pci/config_accessors/loongarch64.rs b/src/pci/config_accessors/loongarch64.rs index 284d2f8b..dea4d12e 100644 --- a/src/pci/config_accessors/loongarch64.rs +++ b/src/pci/config_accessors/loongarch64.rs @@ -78,8 +78,7 @@ impl PciConfigAccessor for LoongArchConfigAccessor { // Bits 15-11: Device Number // Bits 10-8: Function Number // Bits 7-0: Offset[7:0] - self.cfg0 - + ((offset_high << 24) | (device << 11) | (function << 8) | offset_low) + self.cfg0 + ((offset_high << 24) | (device << 11) | (function << 8) | offset_low) } else { // Type 1 format (Other Bus): // Bits 31-28: Offset[11:8] @@ -88,7 +87,11 @@ impl PciConfigAccessor for LoongArchConfigAccessor { // Bits 10-8: Function Number // Bits 7-0: Offset[7:0] self.cfg1 - + ((offset_high << 24) | (bus << 16) | (device << 11) | (function << 8) | offset_low) + + ((offset_high << 24) + | (bus << 16) + | (device << 11) + | (function << 8) + | offset_low) }; Ok(address) @@ -116,8 +119,7 @@ impl PciConfigAccessor for LoongArchConfigAccessor { // Bits 15-11: Device Number // Bits 10-8: Function Number // Bits 7-0: Offset[7:0] - self.cfg0 - + ((offset_high << 24) | (device << 11) | (function << 8) | offset_low) + self.cfg0 + ((offset_high << 24) | (device << 11) | (function << 8) | offset_low) } else { // Type 1 format (Other Bus): // Bits 31-28: Offset[11:8] @@ -126,7 +128,11 @@ impl PciConfigAccessor for LoongArchConfigAccessor { // Bits 10-8: Function Number // Bits 7-0: Offset[7:0] self.cfg1 - + ((offset_high << 24) | (bus << 16) | (device << 11) | (function << 8) | offset_low) + + ((offset_high << 24) + | (bus << 16) + | (device << 11) + | (function << 8) + | offset_low) }; Ok(address) diff --git a/src/pci/config_accessors/mod.rs b/src/pci/config_accessors/mod.rs index 47488cf7..e7eeeb55 100644 --- a/src/pci/config_accessors/mod.rs +++ b/src/pci/config_accessors/mod.rs @@ -125,11 +125,7 @@ impl PciRegion for PciConfigMmio { } pub trait PciConfigAccessor: Send + Sync + core::fmt::Debug { - fn get_pci_addr_base( - &self, - bdf: Bdf, - parent_bus: u8, - ) -> HvResult; + fn get_pci_addr_base(&self, bdf: Bdf, parent_bus: u8) -> HvResult; fn get_physical_address( &self, diff --git a/src/pci/mem_alloc.rs b/src/pci/mem_alloc.rs index 00df0d25..9ed793d2 100644 --- a/src/pci/mem_alloc.rs +++ b/src/pci/mem_alloc.rs @@ -105,7 +105,6 @@ impl BarAllocator for BaseAllocator { // io_used: Mem64Address, // } - // impl LoongArchAllocator { // pub fn set_mem(&mut self, start: Mem64Address, size: Mem64Address) { // self.mem = start..start + size; @@ -150,4 +149,4 @@ impl BarAllocator for BaseAllocator { // None // } // } -// } \ No newline at end of file +// } diff --git a/src/pci/mod.rs b/src/pci/mod.rs index fe8d201a..fcf0a4f9 100644 --- a/src/pci/mod.rs +++ b/src/pci/mod.rs @@ -18,9 +18,9 @@ pub mod config_accessors; pub mod mem_alloc; pub mod pci_access; pub mod pci_config; +pub mod pci_handler; pub mod pci_struct; pub mod vpci_dev; -pub mod pci_handler; pub mod pci_test; diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index db480638..54daff63 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -32,7 +32,8 @@ use super::{ use crate::{ error::HvResult, memory::{ - GuestPhysAddr, HostPhysAddr, MMIOAccess, MemFlags, MemoryRegion, MemorySet, mmio_perform_access + mmio_perform_access, GuestPhysAddr, HostPhysAddr, MMIOAccess, MemFlags, MemoryRegion, + MemorySet, }, pci::{pci_config::GLOBAL_PCIE_LIST, pci_struct::BIT_LENTH}, percpu::this_zone, @@ -41,16 +42,13 @@ use crate::{ #[cfg(feature = "dwc_pcie")] use crate::pci::config_accessors::{ + dwc::DwcConfigRegionBackend, dwc_atu::{ - AtuConfig, AtuType, ATU_BASE, ATU_REGION_SIZE, - PCIE_ATU_UNR_REGION_CTRL1, PCIE_ATU_UNR_REGION_CTRL2, - PCIE_ATU_UNR_LOWER_BASE, PCIE_ATU_UNR_UPPER_BASE, - PCIE_ATU_UNR_LIMIT, PCIE_ATU_UNR_UPPER_LIMIT, - PCIE_ATU_UNR_LOWER_TARGET, PCIE_ATU_UNR_UPPER_TARGET, - ATU_ENABLE_BIT, - AtuUnroll, + AtuConfig, AtuType, AtuUnroll, ATU_BASE, ATU_ENABLE_BIT, ATU_REGION_SIZE, + PCIE_ATU_UNR_LIMIT, PCIE_ATU_UNR_LOWER_BASE, PCIE_ATU_UNR_LOWER_TARGET, + PCIE_ATU_UNR_REGION_CTRL1, PCIE_ATU_UNR_REGION_CTRL2, PCIE_ATU_UNR_UPPER_BASE, + PCIE_ATU_UNR_UPPER_LIMIT, PCIE_ATU_UNR_UPPER_TARGET, }, - dwc::DwcConfigRegionBackend, PciRegionMmio, }; @@ -141,7 +139,7 @@ impl Debug for PciMemType { * 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 * acutally size_read is not used now, we keep it just in case of possible special register handling in the future */ @@ -200,7 +198,7 @@ impl PciMem { } } - pub fn set_size(&mut self, size: u64){ + pub fn set_size(&mut self, size: u64) { self.size = size; } @@ -231,11 +229,11 @@ impl PciMem { } } - pub fn set_bar_type(&mut self, bar_type: PciMemType){ + pub fn set_bar_type(&mut self, bar_type: PciMemType) { self.bar_type = bar_type; } - pub fn set_prefetchable(&mut self, prefetchable: bool){ + pub fn set_prefetchable(&mut self, prefetchable: bool) { self.prefetchable = prefetchable; } @@ -294,9 +292,7 @@ impl PciMem { val |= 0x8; } } - PciMemType::Rom => { - - } + PciMemType::Rom => {} _ => { warn!("please init bar first"); } @@ -359,9 +355,7 @@ impl PciMem { val |= 0x8; } } - PciMemType::Rom => { - - } + PciMemType::Rom => {} _ => { warn!("unkown bar type: {:#?}", self.bar_type); } @@ -703,7 +697,6 @@ pub trait PciBarRW: PciRWBase { } } - pub trait PciRomRW: PciRWBase { fn rom_offset(&self) -> u64; fn parse_rom(&self) -> PciMem { @@ -830,7 +823,7 @@ pub enum EndpointField { impl Debug for EndpointField { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "EndpointField {{")?; - let _ =match self { + let _ = match self { EndpointField::ID => write!(f, "ID"), EndpointField::Command => write!(f, "Command"), EndpointField::Status => write!(f, "Status"), @@ -937,7 +930,6 @@ impl EndpointField { (x, _) => EndpointField::Unknown(x), } } - } #[derive(Debug, Clone)] @@ -1220,5 +1212,3 @@ impl PciBridgeHeader { } impl PciBridgeHeader {} - - diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index f5d49c80..47a3d3de 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -20,29 +20,47 @@ use crate::{ arch::iommu::iommu_add_device, config::{HvPciConfig, HvPciDevConfig, CONFIG_MAX_PCI_DEV, CONFIG_PCI_BUS_MAXNUM}, error::HvResult, - pci::pci_struct::{Bdf, ArcRwLockVirtualPciConfigSpace}, + pci::pci_struct::{ArcRwLockVirtualPciConfigSpace, Bdf}, zone::Zone, }; #[cfg(feature = "ecam_pcie")] -use crate::pci::{vpci_dev::{VpciDevType, get_handler}, pci_struct::VirtualPciConfigSpace}; +use crate::pci::{ + pci_struct::VirtualPciConfigSpace, + vpci_dev::{get_handler, VpciDevType}, +}; #[cfg(any( feature = "ecam_pcie", feature = "dwc_pcie", feature = "loongarch64_pcie" ))] -use crate::pci::{mem_alloc::BaseAllocator, pci_struct::RootComplex, pci_handler::mmio_vpci_handler, PciConfigAddress}; +use crate::pci::{ + mem_alloc::BaseAllocator, pci_handler::mmio_vpci_handler, pci_struct::RootComplex, + PciConfigAddress, +}; #[cfg(feature = "dwc_pcie")] -use crate::{platform, memory::mmio_generic_handler, pci::{config_accessors::{dwc_atu::{AtuConfig, AtuType}, dwc::DwcConfigRegionBackend}, pci_access::PciRegionMmio, pci_handler::{mmio_vpci_handler_dbi, mmio_dwc_io_handler, mmio_dwc_cfg_handler}}}; +use crate::{ + memory::mmio_generic_handler, + pci::{ + config_accessors::{ + dwc::DwcConfigRegionBackend, + dwc_atu::{AtuConfig, AtuType}, + }, + pci_access::PciRegionMmio, + pci_handler::{mmio_dwc_cfg_handler, mmio_dwc_io_handler, mmio_vpci_handler_dbi}, + }, + platform, +}; #[cfg(feature = "loongarch64_pcie")] use crate::pci::pci_handler::mmio_vpci_direct_handler; -pub static GLOBAL_PCIE_LIST: Lazy>> = Lazy::new(|| { - let m = BTreeMap::new(); - Mutex::new(m) -}); +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_config: &[HvPciConfig]) -> HvResult { @@ -60,14 +78,8 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { } let mut allocator = BaseAllocator::default(); - allocator.set_mem32( - rootcomplex_config.mem32_base, - rootcomplex_config.mem32_size, - ); - allocator.set_mem64( - rootcomplex_config.mem64_base, - rootcomplex_config.mem64_size, - ); + allocator.set_mem32(rootcomplex_config.mem32_base, rootcomplex_config.mem32_size); + allocator.set_mem64(rootcomplex_config.mem64_base, rootcomplex_config.mem64_size); allocator.set_io( rootcomplex_config.io_base as u64, rootcomplex_config.io_size, @@ -133,12 +145,14 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { }; let range = rootcomplex_config.bus_range_begin as usize..rootcomplex_config.bus_range_end as usize; - + let e = rootcomplex.enumerate(Some(range), allocator_opt); info!("begin enumerate {:#?}", e); for node in e { info!("node {:#?}", node); - GLOBAL_PCIE_LIST.lock().insert(node.get_bdf(), ArcRwLockVirtualPciConfigSpace::new(node)); + GLOBAL_PCIE_LIST + .lock() + .insert(node.get_bdf(), ArcRwLockVirtualPciConfigSpace::new(node)); } } info!("hvisor pci init done \n{:#?}", GLOBAL_PCIE_LIST); @@ -173,8 +187,11 @@ impl Zone { iommu_add_device(zone_id, dev_config.bdf as _, iommu_pt_addr); } if let Some(dev) = guard.get(&bdf) { - if bdf.is_host_bridge(dev.read().get_host_bdf().bus()) - || dev.with_config_value(|config_value| -> bool {config_value.get_class().0 == 0x6}) { + if bdf.is_host_bridge(dev.read().get_host_bdf().bus()) + || dev.with_config_value(|config_value| -> bool { + config_value.get_class().0 == 0x6 + }) + { let mut vdev = dev.read().clone(); vdev.set_vbdf(vbdf); self.vpci_bus.insert(vbdf, vdev); @@ -190,23 +207,23 @@ impl Zone { { let dev_type = dev_config.dev_type; match dev_type { - VpciDevType::Physical => { - warn!("can not find dev {:#?}", bdf); - } - _ => { - if let Some(_handler) = get_handler(dev_type) { - let base = _ecam_base - + ((bdf.bus() as u64) << 20) - + ((bdf.device() as u64) << 15) - + ((bdf.function() as u64) << 12); - let dev = VirtualPciConfigSpace::virt_dev(bdf, base, dev_type); - self.vpci_bus.insert(vbdf, dev); - } else { - warn!("can not find dev {:#?}, unknown device type", bdf); + VpciDevType::Physical => { + warn!("can not find dev {:#?}", bdf); + } + _ => { + if let Some(_handler) = get_handler(dev_type) { + let base = _ecam_base + + ((bdf.bus() as u64) << 20) + + ((bdf.device() as u64) << 15) + + ((bdf.function() as u64) << 12); + let dev = VirtualPciConfigSpace::virt_dev(bdf, base, dev_type); + self.vpci_bus.insert(vbdf, dev); + } else { + warn!("can not find dev {:#?}, unknown device type", bdf); + } } } } - } } i += 1; } @@ -289,7 +306,7 @@ impl Zone { } let mut atu = AtuConfig::default(); - + let dbi_base = extend_config.dbi_base as PciConfigAddress; let dbi_size = extend_config.dbi_size; let dbi_region = PciRegionMmio::new(dbi_base, dbi_size); @@ -297,11 +314,18 @@ impl Zone { if let Err(e) = atu.init_limit_hw_value(dbi_backend.as_ref()) { warn!("Failed to initialize ATU0 limit defaults: {:?}", e); } - - self.atu_configs.insert_atu(rootcomplex_config.ecam_base as usize, atu); - self.atu_configs.insert_cfg_base_mapping(extend_config.cfg_base as PciConfigAddress, rootcomplex_config.ecam_base as usize); - self.atu_configs.insert_io_base_mapping(rootcomplex_config.io_base as PciConfigAddress, rootcomplex_config.ecam_base as usize); - } + + self.atu_configs + .insert_atu(rootcomplex_config.ecam_base as usize, atu); + self.atu_configs.insert_cfg_base_mapping( + extend_config.cfg_base as PciConfigAddress, + rootcomplex_config.ecam_base as usize, + ); + self.atu_configs.insert_io_base_mapping( + rootcomplex_config.io_base as PciConfigAddress, + rootcomplex_config.ecam_base as usize, + ); + } } #[cfg(feature = "loongarch64_pcie")] { @@ -311,9 +335,16 @@ impl Zone { mmio_vpci_direct_handler, rootcomplex_config.ecam_base as usize, ); - self.page_table_emergency(rootcomplex_config.ecam_base as usize, rootcomplex_config.ecam_size as usize); + self.page_table_emergency( + rootcomplex_config.ecam_base as usize, + rootcomplex_config.ecam_size as usize, + ); } - #[cfg(not(any(feature = "ecam_pcie", feature = "dwc_pcie", feature = "loongarch64_pcie")))] + #[cfg(not(any( + feature = "ecam_pcie", + feature = "dwc_pcie", + feature = "loongarch64_pcie" + )))] { warn!( "No extend config found for base 0x{:x}", diff --git a/src/pci/pci_handler.rs b/src/pci/pci_handler.rs index a945e386..5393cb04 100644 --- a/src/pci/pci_handler.rs +++ b/src/pci/pci_handler.rs @@ -2,28 +2,25 @@ use alloc::string::String; use crate::error::HvResult; use crate::memory::MMIOAccess; -use crate::memory::{GuestPhysAddr, HostPhysAddr, MemoryRegion, MemFlags, mmio_perform_access}; +use crate::memory::{mmio_perform_access, GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion}; use crate::percpu::this_zone; use crate::zone::{is_this_root_zone, this_zone_id}; use super::pci_access::{BridgeField, EndpointField, HeaderType, PciField, PciMemType}; -use super::pci_struct::{ArcRwLockVirtualPciConfigSpace, BIT_LENTH}; use super::pci_config::GLOBAL_PCIE_LIST; +use super::pci_struct::{ArcRwLockVirtualPciConfigSpace, BIT_LENTH}; use super::vpci_dev::VpciDevType; use super::PciConfigAddress; #[cfg(feature = "dwc_pcie")] use crate::pci::config_accessors::{ + dwc::DwcConfigRegionBackend, dwc_atu::{ - AtuConfig, AtuType, ATU_BASE, ATU_REGION_SIZE, - PCIE_ATU_UNR_REGION_CTRL1, PCIE_ATU_UNR_REGION_CTRL2, - PCIE_ATU_UNR_LOWER_BASE, PCIE_ATU_UNR_UPPER_BASE, - PCIE_ATU_UNR_LIMIT, PCIE_ATU_UNR_UPPER_LIMIT, - PCIE_ATU_UNR_LOWER_TARGET, PCIE_ATU_UNR_UPPER_TARGET, - ATU_ENABLE_BIT, - AtuUnroll, + AtuConfig, AtuType, AtuUnroll, ATU_BASE, ATU_ENABLE_BIT, ATU_REGION_SIZE, + PCIE_ATU_UNR_LIMIT, PCIE_ATU_UNR_LOWER_BASE, PCIE_ATU_UNR_LOWER_TARGET, + PCIE_ATU_UNR_REGION_CTRL1, PCIE_ATU_UNR_REGION_CTRL2, PCIE_ATU_UNR_UPPER_BASE, + PCIE_ATU_UNR_UPPER_LIMIT, PCIE_ATU_UNR_UPPER_TARGET, }, - dwc::DwcConfigRegionBackend, PciRegionMmio, }; @@ -179,13 +176,13 @@ fn handle_endpoint_access( * value: same with physical reg, the paddr for pt * virt_value: the vaddr for pt * config_value: the virtual reg for zone, directly rw - * - * The virt_value cache of vaddr is required because mem64 bar updates are - * split between mem64high and mem64low registers. The Hvisor must wait + * + * The virt_value cache of vaddr is required because mem64 bar updates are + * split between mem64high and mem64low registers. The Hvisor must wait * for both updates to complete before using old_vaddr for page table maintenance - * - * In typical operation, tmp_value maintains parity with virt_value; the sole exception occurs - * when exclusively updating mem64low while leaving mem64high unmodified, + * + * In typical operation, tmp_value maintains parity with virt_value; the sole exception occurs + * when exclusively updating mem64low while leaving mem64high unmodified, * as previously described */ let bar_type = dev.with_bar_ref(slot, |bar| bar.get_type()); @@ -198,15 +195,18 @@ fn handle_endpoint_access( }); dev.write_hw(field.to_offset() as PciConfigAddress, field.size(), value)?; if (bar_type == PciMemType::Mem32) - | (bar_type == PciMemType::Mem64High) - | (bar_type == PciMemType::Io) { + | (bar_type == PciMemType::Mem64High) + | (bar_type == PciMemType::Io) + { 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 - * Read from config_value.bar_value cache instead of space - */ - let low_value = dev.with_config_value(|cv| cv.get_bar_value(slot - 1)) as u64; + * flag will auto add when set_value and set_virtual_value + * Read from config_value.bar_value cache instead of space + */ + let low_value = dev + .with_config_value(|cv| cv.get_bar_value(slot - 1)) + as u64; let high_value = (value as u32 as u64) << 32; (low_value | high_value) & !0xf } else { @@ -217,7 +217,9 @@ fn handle_endpoint_access( // set virt_value dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); if bar_type == PciMemType::Mem64High { - dev.with_bar_ref_mut(slot - 1, |bar| bar.set_virtual_value(new_vaddr)); + dev.with_bar_ref_mut(slot - 1, |bar| { + bar.set_virtual_value(new_vaddr) + }); } // set value @@ -226,7 +228,6 @@ fn handle_endpoint_access( dev.with_bar_ref_mut(slot - 1, |bar| bar.set_value(new_vaddr)); } } - } else if is_dev_belong_to_zone { // normal mod, update virt resources dev.with_config_value_mut(|configvalue| { @@ -234,16 +235,20 @@ fn handle_endpoint_access( }); if (bar_type == PciMemType::Mem32) - | (bar_type == PciMemType::Mem64High) - | (bar_type == PciMemType::Io) { - let old_vaddr = dev.with_bar_ref(slot, |bar| bar.get_virtual_value64()) & !0xf; + | (bar_type == PciMemType::Mem64High) + | (bar_type == PciMemType::Io) + { + let old_vaddr = + dev.with_bar_ref(slot, |bar| 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 - * Read from config_value.bar_value cache instead of space - */ - let low_value = dev.with_config_value(|cv| cv.get_bar_value(slot - 1)) as u64; + * flag will auto add when set_value and set_virtual_value + * Read from config_value.bar_value cache instead of space + */ + let low_value = dev + .with_config_value(|cv| cv.get_bar_value(slot - 1)) + as u64; let high_value = (value as u32 as u64) << 32; (low_value | high_value) & !0xf } else { @@ -253,7 +258,9 @@ fn handle_endpoint_access( dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); if bar_type == PciMemType::Mem64High { - dev.with_bar_ref_mut(slot - 1, |bar| bar.set_virtual_value(new_vaddr)); + dev.with_bar_ref_mut(slot - 1, |bar| { + bar.set_virtual_value(new_vaddr) + }); } let paddr = if is_root { @@ -273,7 +280,8 @@ fn handle_endpoint_access( crate::memory::PAGE_SIZE as u64 } }; - let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) { + let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) + { crate::memory::addr::align_up(new_vaddr as usize) as u64 } else { new_vaddr as u64 @@ -282,12 +290,12 @@ fn handle_endpoint_access( let zone = this_zone(); let mut guard = zone.write(); let gpm = &mut guard.gpm; - - if !gpm.try_delete(old_vaddr.try_into().unwrap(), bar_size as usize).is_ok() { - warn!( - "delete bar {}: can not found 0x{:x}", - slot, old_vaddr - ); + + if !gpm + .try_delete(old_vaddr.try_into().unwrap(), bar_size as usize) + .is_ok() + { + warn!("delete bar {}: can not found 0x{:x}", slot, old_vaddr); } gpm.try_insert(MemoryRegion::new_with_offset_mapper( new_vaddr as GuestPhysAddr, @@ -297,7 +305,7 @@ fn handle_endpoint_access( ))?; drop(guard); /* after update gpm, mem barrier is needed - */ + */ #[cfg(target_arch = "aarch64")] unsafe { core::arch::asm!("isb"); @@ -305,27 +313,29 @@ fn handle_endpoint_access( core::arch::asm!("dsb nsh"); } /* after update gpm, need to flush iommu table - * in x86_64 - */ + * in x86_64 + */ #[cfg(target_arch = "x86_64")] { let vbdf = dev.get_vbdf(); crate::arch::iommu::flush( - this_zone_id(), - vbdf.bus, - (vbdf.device << 3) + vbdf.function, - ); - } + this_zone_id(), + vbdf.bus, + (vbdf.device << 3) + vbdf.function, + ); + } } } Ok(None) } else { // read bar - if (dev.with_config_value(|configvalue| configvalue.get_bar_value(slot)) & 0xfffffff0) == 0xfffffff0 + if (dev.with_config_value(|configvalue| configvalue.get_bar_value(slot)) + & 0xfffffff0) + == 0xfffffff0 { /* * tmp_value being 0xFFFF_FFFF means that Linux is attempting to determine the BAR size. - * The value of tmp_value is used directly here because Linux will rewrite this register later, + * The value of tmp_value is used directly here because Linux will rewrite this register later, * so the Hvisor does not need to preserve any additional state. */ Ok(Some( @@ -352,12 +362,12 @@ fn handle_endpoint_access( configvalue.set_rom_value(value as u32); }); dev.write_hw(field.to_offset() as PciConfigAddress, field.size(), value)?; - + let new_vaddr = (value as u64) & !0xf; - + // set virt_value dev.with_rom_ref_mut(|rom| rom.set_virtual_value(new_vaddr)); - + // set value dev.with_rom_ref_mut(|rom| rom.set_value(new_vaddr)); } else if is_dev_belong_to_zone { @@ -365,19 +375,19 @@ fn handle_endpoint_access( dev.with_config_value_mut(|configvalue| { configvalue.set_rom_value(value as u32); }); - + let old_vaddr = dev.with_rom_ref(|rom| rom.get_virtual_value64()) & !0xf; let new_vaddr = (value as u64) & !0xf; - + dev.with_rom_ref_mut(|rom| rom.set_virtual_value(new_vaddr)); - + let paddr = if is_root { dev.with_rom_ref_mut(|rom| rom.set_value(new_vaddr)); new_vaddr as HostPhysAddr } else { dev.with_rom_ref(|rom| rom.get_value64()) as HostPhysAddr }; - + let rom_size = { let size = dev.with_rom_ref(|rom| rom.get_size()); if crate::memory::addr::is_aligned(size as usize) { @@ -391,16 +401,16 @@ fn handle_endpoint_access( } else { new_vaddr as u64 }; - + let zone = this_zone(); let mut guard = zone.write(); let gpm = &mut guard.gpm; - - if !gpm.try_delete(old_vaddr.try_into().unwrap(), rom_size as usize).is_ok() { - warn!( - "delete rom bar: can not found 0x{:x}", - old_vaddr - ); + + if !gpm + .try_delete(old_vaddr.try_into().unwrap(), rom_size as usize) + .is_ok() + { + warn!("delete rom bar: can not found 0x{:x}", old_vaddr); } gpm.try_insert(MemoryRegion::new_with_offset_mapper( new_vaddr as GuestPhysAddr, @@ -410,7 +420,7 @@ fn handle_endpoint_access( ))?; drop(guard); /* after update gpm, mem barrier is needed - */ + */ #[cfg(target_arch = "aarch64")] unsafe { core::arch::asm!("isb"); @@ -418,8 +428,8 @@ fn handle_endpoint_access( core::arch::asm!("dsb nsh"); } /* after update gpm, need to flush iommu table - * in x86_64 - */ + * in x86_64 + */ #[cfg(target_arch = "x86_64")] { let vbdf = dev.get_vbdf(); @@ -433,11 +443,13 @@ fn handle_endpoint_access( Ok(None) } else { // read rom bar - if (dev.with_config_value(|configvalue| configvalue.get_rom_value())) & 0xfffff800 == 0xfffff800 + if (dev.with_config_value(|configvalue| configvalue.get_rom_value())) + & 0xfffff800 + == 0xfffff800 { /* * config_value being 0xFFFF_FFFF means that Linux is attempting to determine the ROM size. - * The value is used directly here because Linux will rewrite this register later, + * The value is used directly here because Linux will rewrite this register later, * so the Hvisor does not need to preserve any additional state. */ Ok(Some( @@ -451,7 +463,6 @@ fn handle_endpoint_access( } } } else { - Ok(None) } } @@ -575,7 +586,7 @@ fn handle_config_space_access( } } } - + pci_log!( "vbdf {:#?} reg 0x{:x} {} 0x{:x}", vbdf, @@ -617,7 +628,7 @@ pub fn mmio_vpci_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { if let Some(dev) = dev { handle_config_space_access(dev, mmio, offset, false, is_root, true)?; - } else { + } else { handle_device_not_found(mmio, offset); } @@ -629,15 +640,19 @@ pub fn mmio_dwc_io_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { { let zone = this_zone(); let guard = zone.read(); - - let atu_config = guard.atu_configs.get_atu_by_io_base(_base as PciConfigAddress) + + let atu_config = guard + .atu_configs + .get_atu_by_io_base(_base as PciConfigAddress) .and_then(|atu| { - guard.atu_configs.get_ecam_by_io_base(_base as PciConfigAddress) + guard + .atu_configs + .get_ecam_by_io_base(_base as PciConfigAddress) .map(|ecam| (*atu, ecam)) }); - + drop(guard); - + if let Some((atu, ecam_base)) = atu_config { use crate::platform; if let Some(extend_config) = platform::ROOT_DWC_ATU_CONFIG @@ -649,7 +664,7 @@ pub fn mmio_dwc_io_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { let dbi_size = extend_config.dbi_size; let dbi_region = PciRegionMmio::new(dbi_base, dbi_size); let dbi_backend = DwcConfigRegionBackend::new(dbi_region); - + // Call AtuUnroll to program the ATU AtuUnroll::dw_pcie_prog_outbound_atu_unroll(&dbi_backend, &atu)?; } @@ -663,18 +678,22 @@ pub fn mmio_dwc_io_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { #[cfg(feature = "dwc_pcie")] pub fn mmio_dwc_cfg_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { - info!("mmio_dwc_cfg_handler {:#x}", mmio.address + _base); + info!("mmio_dwc_cfg_handler {:#x}", mmio.address + _base); let zone = this_zone(); let guard = zone.read(); - let atu_config = guard.atu_configs.get_atu_by_cfg_base(_base as PciConfigAddress) + let atu_config = guard + .atu_configs + .get_atu_by_cfg_base(_base as PciConfigAddress) .and_then(|atu| { - guard.atu_configs.get_ecam_by_cfg_base(_base as PciConfigAddress) + guard + .atu_configs + .get_ecam_by_cfg_base(_base as PciConfigAddress) .map(|ecam| (*atu, ecam)) }); - + drop(guard); - + if let Some((atu, ecam_base)) = atu_config { // Get dbi_base from platform config (usually dbi_base == ecam_base) use crate::platform; @@ -689,17 +708,17 @@ pub fn mmio_dwc_cfg_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { let dbi_backend = DwcConfigRegionBackend::new(dbi_region); // warn!("atu config {:#?}", atu); - + // Call AtuUnroll to program the ATU AtuUnroll::dw_pcie_prog_outbound_atu_unroll(&dbi_backend, &atu)?; } - + let offset = (mmio.address & 0xfff) as PciConfigAddress; let zone = this_zone(); let mut is_dev_belong_to_zone = false; - + let base = mmio.address as PciConfigAddress - offset + atu.pci_target(); - + let dev: Option = { let mut guard = zone.write(); let vbus = &mut guard.vpci_bus; @@ -723,7 +742,7 @@ pub fn mmio_dwc_cfg_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { dev_clone } }; - + let dev = match dev { Some(dev) => dev, None => { @@ -731,10 +750,10 @@ pub fn mmio_dwc_cfg_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { return Ok(()); } }; - + let is_root = is_this_root_zone(); let is_direct = true; // dwc_cfg_handler uses direct mode - + handle_config_space_access(dev, mmio, offset, is_direct, is_root, is_dev_belong_to_zone)?; } else { warn!("No ATU config yet, do nothing"); @@ -750,19 +769,18 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { * 0x100-0x200 is inbound atu0 reg just handle outbound right now * so MAX is ATU_BASE + ATU_REGION_SIZE/2 */ - if mmio.address >= ATU_BASE && mmio.address < ATU_BASE + ATU_REGION_SIZE/2 - { + if mmio.address >= ATU_BASE && mmio.address < ATU_BASE + ATU_REGION_SIZE / 2 { let zone = this_zone(); let mut guard = zone.write(); let ecam_base = _base; let atu_offset = mmio.address - ATU_BASE; // warn!("set atu0 register {:#X} value {:#X}", atu_offset, mmio.value); - + let mut atu = guard.atu_configs.get_atu_by_ecam_mut(ecam_base).unwrap(); // info!("atu config write {:#?}", atu); - + if mmio.is_write { if mmio.size == 4 { match atu_offset { @@ -776,27 +794,42 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { } PCIE_ATU_UNR_LOWER_BASE => { // info!("set atu0 lower base value {:#X}", mmio.value); - atu.set_cpu_base((atu.cpu_base() & !0xffffffff) | (mmio.value as PciConfigAddress)); + atu.set_cpu_base( + (atu.cpu_base() & !0xffffffff) | (mmio.value as PciConfigAddress), + ); } PCIE_ATU_UNR_UPPER_BASE => { // info!("set atu0 upper base value {:#X}", mmio.value); - atu.set_cpu_base((atu.cpu_base() & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32)); + atu.set_cpu_base( + (atu.cpu_base() & 0xffffffff) + | ((mmio.value as PciConfigAddress) << 32), + ); } PCIE_ATU_UNR_LIMIT => { // info!("set atu0 limit value {:#X}", mmio.value); - atu.set_cpu_limit((atu.cpu_limit() & !0xffffffff) | (mmio.value as PciConfigAddress)); + atu.set_cpu_limit( + (atu.cpu_limit() & !0xffffffff) | (mmio.value as PciConfigAddress), + ); } PCIE_ATU_UNR_UPPER_LIMIT => { // Update the upper 32 bits of cpu_limit - atu.set_cpu_limit((atu.cpu_limit() & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32)); + atu.set_cpu_limit( + (atu.cpu_limit() & 0xffffffff) + | ((mmio.value as PciConfigAddress) << 32), + ); } PCIE_ATU_UNR_LOWER_TARGET => { // info!("set atu0 lower target value {:#X}", mmio.value); - atu.set_pci_target((atu.pci_target() & !0xffffffff) | (mmio.value as PciConfigAddress)); + atu.set_pci_target( + (atu.pci_target() & !0xffffffff) | (mmio.value as PciConfigAddress), + ); } PCIE_ATU_UNR_UPPER_TARGET => { // info!("set atu0 upper target value {:#X}", mmio.value); - atu.set_pci_target((atu.pci_target() & 0xffffffff) | ((mmio.value as PciConfigAddress) << 32)); + atu.set_pci_target( + (atu.pci_target() & 0xffffffff) + | ((mmio.value as PciConfigAddress) << 32), + ); } _ => { warn!("invalid atu0 write {:#x} + {:#x}", atu_offset, mmio.size); @@ -823,11 +856,19 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { } PCIE_ATU_UNR_LIMIT => { let limit_value = (atu.cpu_limit() & 0xffffffff) as usize; - mmio.value = if limit_value == 0 { atu.limit_hw_value() as usize } else { limit_value }; + mmio.value = if limit_value == 0 { + atu.limit_hw_value() as usize + } else { + limit_value + }; } PCIE_ATU_UNR_UPPER_LIMIT => { let upper_limit = ((atu.cpu_limit() >> 32) & 0xffffffff) as usize; - mmio.value = if upper_limit == 0xffffffff { atu.upper_limit_hw_value() as usize } else { upper_limit }; + mmio.value = if upper_limit == 0xffffffff { + atu.upper_limit_hw_value() as usize + } else { + upper_limit + }; } PCIE_ATU_UNR_LOWER_TARGET => { mmio.value = (atu.pci_target() & 0xffffffff) as usize; @@ -841,7 +882,7 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { } } } - } else if mmio.address > ATU_BASE + ATU_REGION_SIZE/2 { + } else if mmio.address > ATU_BASE + ATU_REGION_SIZE / 2 { mmio_perform_access(_base, mmio); } else if mmio.address >= BIT_LENTH { // dbi read @@ -877,7 +918,7 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { dev_clone } }; - + let dev = match dev { Some(dev) => dev, None => { @@ -885,10 +926,10 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { return Ok(()); } }; - + let is_root = is_this_root_zone(); let is_direct = true; // dbi handler uses direct mode - + handle_config_space_access(dev, mmio, offset, is_direct, is_root, is_dev_belong_to_zone)?; } @@ -927,8 +968,8 @@ pub fn mmio_vpci_direct_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult let is_root = is_this_root_zone(); let is_direct = true; // direct handler uses direct mode - + handle_config_space_access(dev, mmio, offset, is_direct, is_root, is_dev_belong_to_zone)?; - + Ok(()) -} \ No newline at end of file +} diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 27b9be68..b86d98d7 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -16,7 +16,12 @@ use alloc::{collections::btree_map::BTreeMap, sync::Arc, vec::Vec}; use bit_field::BitField; use bitvec::{array::BitArray, order::Lsb0, BitArr}; -use core::{cmp::Ordering, fmt::Debug, ops::{Deref, DerefMut, Range}, str::FromStr}; +use core::{ + cmp::Ordering, + fmt::Debug, + ops::{Deref, DerefMut, Range}, + str::FromStr, +}; use spin::RwLock; use super::{ @@ -26,11 +31,14 @@ use super::{ Bar, EndpointField, EndpointHeader, HeaderType, PciBarRW, PciBridgeHeader, PciCommand, PciConfigHeader, PciField, PciHeaderRW, PciMem, PciMemType, PciRW, PciRomRW, }, + pci_access::{BaseClass, DeviceId, DeviceRevision, Interface, SubClass, VendorId}, PciConfigAddress, - pci_access::{BaseClass, SubClass, Interface, DeviceId, VendorId, DeviceRevision}, }; -use crate::{error::{HvErrorNum, HvResult}, pci::vpci_dev::VpciDevType}; +use crate::{ + error::{HvErrorNum, HvResult}, + pci::vpci_dev::VpciDevType, +}; type VirtualPciConfigBits = BitArr!(for BIT_LENTH, in u8, Lsb0); @@ -54,7 +62,10 @@ impl Default for ConfigValue { } impl ConfigValue { - pub fn new(id: (DeviceId, VendorId), class_and_revision_id: (BaseClass, SubClass, Interface, DeviceRevision)) -> Self { + pub fn new( + id: (DeviceId, VendorId), + class_and_revision_id: (BaseClass, SubClass, Interface, DeviceRevision), + ) -> Self { Self { id, class_and_revision_id, @@ -84,7 +95,10 @@ impl ConfigValue { self.class_and_revision_id.3 } - pub fn set_class_and_revision_id(&mut self, class_and_revision_id: (BaseClass, SubClass, Interface, DeviceRevision)) { + pub fn set_class_and_revision_id( + &mut self, + class_and_revision_id: (BaseClass, SubClass, Interface, DeviceRevision), + ) { self.class_and_revision_id = class_and_revision_id; } @@ -127,7 +141,7 @@ impl ConfigValue { const MAX_DEVICE: u8 = 31; const MAX_FUNCTION: u8 = 7; pub const CONFIG_LENTH: u64 = 256; -pub const BIT_LENTH: usize = 128*8; +pub const BIT_LENTH: usize = 128 * 8; // PCIe Device/Port Type values const PCI_EXP_TYPE_ROOT_PORT: u16 = 4; @@ -289,7 +303,7 @@ pub struct VirtualPciAccessBits { impl VirtualPciAccessBits { pub fn endpoint() -> Self { let mut bits = BitArray::ZERO; - bits[0x0..0x4].fill(true); // ID + bits[0x0..0x4].fill(true); // ID bits[0x08..0x0c].fill(true); // CLASS bits[0x10..0x34].fill(true); //bar and rom Self { bits } @@ -318,7 +332,6 @@ impl VirtualPciAccessBits { } } - /* 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 @@ -357,7 +370,7 @@ impl ArcRwLockVirtualPciConfigSpace { pub fn new(dev: VirtualPciConfigSpace) -> Self { Self(Arc::new(RwLock::new(dev))) } - + pub fn inner(&self) -> &Arc> { &self.0 } @@ -415,7 +428,6 @@ impl ArcRwLockVirtualPciConfigSpace { self.0.write().write_hw(offset, size, value) } - /// Execute a closure with a reference to the bar at the given slot pub fn with_bar_ref(&self, slot: usize, f: F) -> R where @@ -545,7 +557,6 @@ impl VirtualPciConfigSpace { &mut self.bararr[slot] } - pub fn set_bar_size_read(&mut self, slot: usize) { self.bararr[slot].set_size_read(); } @@ -615,8 +626,7 @@ impl VirtualPciConfigSpace { _ => {} } } - _ => { - } + _ => {} } } } @@ -649,7 +659,10 @@ impl VirtualPciConfigSpace { config_value, control: VirtualPciConfigControl::virt_dev(), access: VirtualPciAccessBits::virt_dev(), - backend: Arc::new(EndpointHeader::new_with_region(PciConfigMmio::new(base, CONFIG_LENTH))), + backend: Arc::new(EndpointHeader::new_with_region(PciConfigMmio::new( + base, + CONFIG_LENTH, + ))), bararr, rom: PciMem::default(), capabilities: PciCapabilityList::new(), @@ -657,11 +670,7 @@ impl VirtualPciConfigSpace { } } - pub fn virt_dev( - bdf: Bdf, - base: PciConfigAddress, - dev_type: VpciDevType, - ) -> Self { + pub fn virt_dev(bdf: Bdf, base: PciConfigAddress, dev_type: VpciDevType) -> Self { crate::pci::vpci_dev::virt_dev_init(bdf, base, dev_type) } pub fn endpoint( @@ -718,7 +727,12 @@ impl VirtualPciConfigSpace { } } - pub fn unknown(bdf: Bdf, base: PciConfigAddress, backend: Arc, id: (DeviceId, VendorId)) -> Self { + pub fn unknown( + bdf: Bdf, + base: PciConfigAddress, + backend: Arc, + id: (DeviceId, VendorId), + ) -> Self { Self { host_bdf: Bdf::default(), parent_bdf: Bdf::default(), @@ -727,7 +741,7 @@ impl VirtualPciConfigSpace { config_type: HeaderType::Endpoint, base, // Default class: base=0xFF, others 0, revision 0 - config_value: ConfigValue::new(id, (0xFFu8,0u8,0u8,0u8)), + config_value: ConfigValue::new(id, (0xFFu8, 0u8, 0u8, 0u8)), control: VirtualPciConfigControl::endpoint(), access: VirtualPciAccessBits::endpoint(), backend, @@ -738,7 +752,12 @@ impl VirtualPciConfigSpace { } } - pub fn host_bridge(bdf: Bdf, base: PciConfigAddress, backend: Arc, class_and_revision_id: (DeviceRevision, BaseClass, SubClass, Interface)) -> Self { + pub fn host_bridge( + bdf: Bdf, + base: PciConfigAddress, + backend: Arc, + class_and_revision_id: (DeviceRevision, BaseClass, SubClass, Interface), + ) -> Self { Self { host_bdf: bdf, parent_bdf: bdf, @@ -825,7 +844,7 @@ impl VirtualPciConfigSpace { pub fn read_emu(&mut self, field: EndpointField) -> HvResult { let offset = field.to_offset() as PciConfigAddress; let size = field.size(); - + match field { EndpointField::ID => { // Read ID from cached config_value.id field @@ -834,7 +853,8 @@ impl VirtualPciConfigSpace { Ok(id_value as usize) } EndpointField::RevisionIDAndClassCode => { - let (base, sub, interface, revision) = self.config_value.get_class_and_revision_id(); + let (base, sub, interface, revision) = + self.config_value.get_class_and_revision_id(); let value = ((base as u32) << 24) | ((sub as u32) << 16) | ((interface as u32) << 8) @@ -900,12 +920,11 @@ impl VirtualPciConfigSpace { } } - // Legacy method for backward compatibility - converts offset/size to EndpointField - // pub fn write_emu_legacy(&mut self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { - // let field = EndpointField::from(offset as usize, size); - // self.write_emu(field, value) - // } - +// Legacy method for backward compatibility - converts offset/size to EndpointField +// pub fn write_emu_legacy(&mut self, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { +// let field = EndpointField::from(offset as usize, size); +// self.write_emu(field, value) +// } #[derive(Debug)] pub struct PciIterator { @@ -1001,7 +1020,12 @@ impl PciIterator { // For endpoint: push host_bridge if we popped placeholder if was_placeholder { let bus_begin = self.bus_range.start as u8; - let host_bridge = Bridge::host_bridge(self.segment, bus_begin, self.is_mulitple_function, self.function); + let host_bridge = Bridge::host_bridge( + self.segment, + bus_begin, + self.is_mulitple_function, + self.function, + ); self.stack.push(host_bridge); } @@ -1055,7 +1079,12 @@ impl PciIterator { _ => { warn!("unknown type"); let pci_header = Arc::new(pci_header); - Some(VirtualPciConfigSpace::unknown(bdf, pci_addr_base, pci_header, (device_id, vender_id))) + Some(VirtualPciConfigSpace::unknown( + bdf, + pci_addr_base, + pci_header, + (device_id, vender_id), + )) } } } @@ -1222,13 +1251,18 @@ impl Iterator for PciIterator { if let Some(mut node) = self.get_node() { node.config_value_init(); let bus_begin = self.bus_range.start as u8; - /* + /* * when first time to enumerate, placeholder is pop in get_node * the message of host bridge must be got after get_node() * so we push host bridge to stack here - */ + */ if self.stack.is_empty() { - let host_bridge = Bridge::host_bridge(self.segment, bus_begin, self.is_mulitple_function, self.function); + let host_bridge = Bridge::host_bridge( + self.segment, + bus_begin, + self.is_mulitple_function, + self.function, + ); self.stack.push(host_bridge); } let parent = self.stack.last().unwrap(); // Safe because we just ensured it exists @@ -1241,14 +1275,12 @@ impl Iterator for PciIterator { // class code 0x6 is bridge and class.1 0x0 is host bridge 0x6 if node.config_value.get_class().1 != 0x0 => { let bdf = Bdf::new(parent.subordinate_bus + 1, 0, 0); - Some( - self.get_bridge().next_bridge( - self.address(parent_bus, bdf), - node.has_secondary_link(), - self.is_mulitple_function, - self.function - ), - ) + Some(self.get_bridge().next_bridge( + self.address(parent_bus, bdf), + node.has_secondary_link(), + self.is_mulitple_function, + self.function, + )) } _ => None, }); @@ -1291,7 +1323,12 @@ impl Bridge { } } - pub fn host_bridge(address: PciConfigAddress, bus_begin: u8, is_mulitple_function: bool, function: u8) -> Self { + pub fn host_bridge( + address: PciConfigAddress, + bus_begin: u8, + is_mulitple_function: bool, + function: u8, + ) -> Self { Self { bus: bus_begin, device: 0, @@ -1305,7 +1342,13 @@ impl Bridge { } } - pub fn next_bridge(&self, address: PciConfigAddress, has_secondary_link: bool, is_mulitple_function: bool, function: u8) -> Self { + pub fn next_bridge( + &self, + address: PciConfigAddress, + has_secondary_link: bool, + is_mulitple_function: bool, + function: u8, + ) -> Self { let mmio = PciConfigMmio::new(address, CONFIG_LENTH); Self { bus: self.subordinate_bus + 1, @@ -1398,7 +1441,8 @@ impl VirtualRootComplex { let base = dev.get_base(); info!("pci insert base {:#x} to bdf {:#?}", base, bdf); self.base_to_bdf.insert(base, bdf); - self.devs.insert(bdf, ArcRwLockVirtualPciConfigSpace::new(dev)) + self.devs + .insert(bdf, ArcRwLockVirtualPciConfigSpace::new(dev)) } pub fn devs(&mut self) -> &mut BTreeMap { @@ -1528,7 +1572,9 @@ impl Debug for CapabilityType { CapabilityType::HyperTransport => write!(f, "HyperTransport(0x08)"), CapabilityType::Vendor => write!(f, "Vendor(0x09)"), CapabilityType::DebugPort => write!(f, "DebugPort(0x0A)"), - CapabilityType::CompactPCICentralResourceControl => write!(f, "CompactPCICentralResourceControl(0x0B)"), + CapabilityType::CompactPCICentralResourceControl => { + write!(f, "CompactPCICentralResourceControl(0x0B)") + } CapabilityType::PciHotPlugControl => write!(f, "PciHotPlugControl(0x0C)"), CapabilityType::BridgeSubsystemVendorId => write!(f, "BridgeSubsystemVendorId(0x0D)"), CapabilityType::AGP3 => write!(f, "AGP3(0x0E)"), @@ -1622,14 +1668,18 @@ impl PciCapability { match CapabilityType::from_id(id) { CapabilityType::Unknown => None, CapabilityType::Msi => { - let region = Arc::new(RwLock::new(StandardPciCapabilityRegion::new(offset, 32, backend))); + let region = Arc::new(RwLock::new(StandardPciCapabilityRegion::new( + offset, 32, backend, + ))); return Some(PciCapability { cap_type: CapabilityType::Msi, region, }); } - _ => { - let region = Arc::new(RwLock::new(StandardPciCapabilityRegion::new(offset, 32, backend))); + _ => { + let region = Arc::new(RwLock::new(StandardPciCapabilityRegion::new( + offset, 32, backend, + ))); Some(PciCapability { cap_type: CapabilityType::from_id(id), region, @@ -1638,21 +1688,21 @@ impl PciCapability { } } - pub fn new_virt(cap_type: CapabilityType, region: Arc>) -> Self { - Self { - cap_type, - region, - } + pub fn new_virt( + cap_type: CapabilityType, + region: Arc>, + ) -> Self { + Self { cap_type, region } } pub fn get_offset(&self) -> PciConfigAddress { self.with_region(|region| region.get_offset()) } - + pub fn get_size(&self) -> usize { self.with_region(|region| region.get_size()) } - + fn next_cap(&self) -> HvResult { self.with_region(|region| region.next_cap()) } @@ -1668,17 +1718,17 @@ pub trait PciCapabilityRegion: Send + Sync { /// Read from capability region at relative offset /// offset: relative offset from capability start (0 = capability start) fn read(&self, offset: PciConfigAddress, size: usize) -> HvResult; - + /// Write to capability region at relative offset /// offset: relative offset from capability start (0 = capability start) fn write(&mut self, offset: PciConfigAddress, size: usize, value: u32) -> HvResult; - + /// Get absolute offset of capability in config space fn get_offset(&self) -> PciConfigAddress; - + /// Get size of capability fn get_size(&self) -> usize; - + /// Get next capability offset by reading next pointer /// Default implementation: read 2 bytes at offset 0 (capability start), extract bits(8..16) as next pointer fn next_cap(&self) -> HvResult { @@ -1696,23 +1746,30 @@ pub struct StandardPciCapabilityRegion { impl StandardPciCapabilityRegion { pub fn new(offset: PciConfigAddress, size: usize, backend: Arc) -> Self { - Self { offset, size, backend } + Self { + offset, + size, + backend, + } } } impl PciCapabilityRegion for StandardPciCapabilityRegion { fn read(&self, offset: PciConfigAddress, size: usize) -> HvResult { - self.backend.read(self.offset + offset, size).map(|v| v as u32) + self.backend + .read(self.offset + offset, size) + .map(|v| v as u32) } - + fn write(&mut self, offset: PciConfigAddress, size: usize, value: u32) -> HvResult { - self.backend.write(self.offset + offset, size, value as usize) + self.backend + .write(self.offset + offset, size, value as usize) } - + fn get_offset(&self) -> PciConfigAddress { self.offset } - + fn get_size(&self) -> usize { self.size } @@ -1735,7 +1792,7 @@ impl PciCapabilityList { impl Deref for PciCapabilityList { type Target = BTreeMap; - + fn deref(&self) -> &Self::Target { &self.0 } diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs index f02df700..082ad7c7 100644 --- a/src/pci/pci_test.rs +++ b/src/pci/pci_test.rs @@ -22,7 +22,7 @@ use spin::{lazy::Lazy, mutex::Mutex}; use super::{ mem_alloc::BaseAllocator, pci_handler::{mmio_vpci_direct_handler, mmio_vpci_handler}, - pci_struct::{Bdf, VirtualPciConfigSpace, CONFIG_LENTH, RootComplex}, + pci_struct::{Bdf, RootComplex, VirtualPciConfigSpace, CONFIG_LENTH}, }; use crate::{ @@ -65,7 +65,8 @@ pub fn pcie_guest_init() { let bdf = Bdf::from_str("0000:00:00.0").unwrap(); let base = 0x4010000000; // Base address for test let backend = EndpointHeader::new_with_region(PciConfigMmio::new(base, CONFIG_LENTH)); - let dev = VirtualPciConfigSpace::host_bridge(bdf, base, Arc::new(backend), (0x6u8,0u8,0u8,0x0)); + let dev = + VirtualPciConfigSpace::host_bridge(bdf, base, Arc::new(backend), (0x6u8, 0u8, 0u8, 0x0)); vbus.insert(vbdf, dev); let vbdf = Bdf::from_str("0000:00:01.0").unwrap(); @@ -133,7 +134,6 @@ pub fn ecam_pcie_guest_test() { mmio.address, mmio.is_write, mmio.size, mmio.value ); - let mut mmio = MMIOAccess { address: test_address as _, size: 4, @@ -146,7 +146,6 @@ pub fn ecam_pcie_guest_test() { mmio.address, mmio.is_write, mmio.size, mmio.value ); - let mut mmio = MMIOAccess { address: test_address as _, size: 4, @@ -249,22 +248,24 @@ pub fn ecam_pcie_guest_test64() { 0 } }; - + if address == 0 { warn!("Failed to get device base address"); return; } // 64-bit BAR: slot 4 (Mem64Low) at offset 0x20, slot 5 (Mem64High) at offset 0x24 - let bar_low_offset = 0x20; // slot 4: 0x10 + 4 * 4 + let bar_low_offset = 0x20; // slot 4: 0x10 + 4 * 4 let bar_high_offset = 0x24; // slot 5: 0x10 + 5 * 4 - + let test_address_low = address + bar_low_offset; let test_address_high = address + bar_high_offset; info!("Testing 64-bit BAR for device {:#?}", bdf); - info!("Base address: 0x{:x}, BAR Low offset: 0x{:x}, BAR High offset: 0x{:x}", - address, bar_low_offset, bar_high_offset); + info!( + "Base address: 0x{:x}, BAR Low offset: 0x{:x}, BAR High offset: 0x{:x}", + address, bar_low_offset, bar_high_offset + ); let mut mmio = MMIOAccess { address: test_address_low as _, @@ -285,9 +286,7 @@ pub fn ecam_pcie_guest_test64() { value: 0xFFFF_FFFF, }; let _ = mmio_vpci_direct_handler(&mut mmio, 0); - info!( - "Step 2 - Write 0xFFFF_FFFF to Mem64Low (size probe)" - ); + info!("Step 2 - Write 0xFFFF_FFFF to Mem64Low (size probe)"); let mut mmio = MMIOAccess { address: test_address_low as _, @@ -322,10 +321,7 @@ pub fn ecam_pcie_guest_test64() { }; let _ = mmio_vpci_direct_handler(&mut mmio, 0); let read_low = mmio.value; - info!( - "Step 5 - Read Mem64Low: value 0x{:x}", - read_low - ); + info!("Step 5 - Read Mem64Low: value 0x{:x}", read_low); let high_addr = 0x00000001; // High 32 bits of 64-bit address let mut mmio = MMIOAccess { @@ -396,10 +392,7 @@ pub fn ecam_pcie_guest_test64() { value: 0, }; let _ = mmio_vpci_direct_handler(&mut mmio, 0); - info!( - "Step 10 - Read Mem64High: value 0x{:x}", - mmio.value - ); + info!("Step 10 - Read Mem64High: value 0x{:x}", mmio.value); info!("pcie guest test64 passed"); diff --git a/src/pci/vpci_dev/mod.rs b/src/pci/vpci_dev/mod.rs index 341085c5..f77fbddd 100644 --- a/src/pci/vpci_dev/mod.rs +++ b/src/pci/vpci_dev/mod.rs @@ -1,7 +1,10 @@ -use crate::pci::pci_struct::{ArcRwLockVirtualPciConfigSpace, Bdf, CapabilityType, ConfigValue, PciCapabilityRegion, VirtualPciConfigSpace}; -use crate::pci::PciConfigAddress; use crate::error::HvResult; use crate::pci::pci_access::{Bar, EndpointField}; +use crate::pci::pci_struct::{ + ArcRwLockVirtualPciConfigSpace, Bdf, CapabilityType, ConfigValue, PciCapabilityRegion, + VirtualPciConfigSpace, +}; +use crate::pci::PciConfigAddress; use bitvec::array::BitArray; use bitvec::{order::Lsb0, BitArr}; @@ -20,7 +23,7 @@ pub(crate) const DEFAULT_CSPACE_U32: [u32; STANDARD_CFG_SIZE / 4] = { const STANDARD_CFG_VNDR_LEN: u8 = 0x20; const STANDARD_CFG_MSIX_CAP: usize = 0x98; const STANDARD_MSIX_VECTORS: u16 = 16; - + let mut arr = [0u32; STANDARD_CFG_SIZE / 4]; arr[0x00 / 4] = (STANDARD_DEVICE_ID as u32) << 16 | STANDARD_VENDOR_ID as u32; arr[0x04 / 4] = (PCI_STS_CAPS as u32) << 16; @@ -55,38 +58,49 @@ pub(crate) enum PciConfigAccessStatus { #[repr(C, align(4))] pub enum VpciDevType { #[default] - Physical=0, - StandardVdev=1, + Physical = 0, + StandardVdev = 1, // Add new device types here } pub trait VpciDeviceHandler: Sync + Send { - fn read_cfg(&self, dev: ArcRwLockVirtualPciConfigSpace, offset: PciConfigAddress, size: usize) -> HvResult; - fn write_cfg(&self, dev: ArcRwLockVirtualPciConfigSpace, offset: PciConfigAddress, size: usize, value: usize) -> HvResult; + fn read_cfg( + &self, + dev: ArcRwLockVirtualPciConfigSpace, + offset: PciConfigAddress, + size: usize, + ) -> HvResult; + fn write_cfg( + &self, + dev: ArcRwLockVirtualPciConfigSpace, + offset: PciConfigAddress, + size: usize, + value: usize, + ) -> HvResult; fn vdev_init(&self, dev: VirtualPciConfigSpace) -> VirtualPciConfigSpace; } -/* +/* * Static handler instances for each device type (except Physical). * To add a new device type: * 1. Add the variant to VpciDevType enum above - * 2. Add the handler registration here: (&module::HANDLER, VpciDevType::YourType) + * 2. Add the handler registration here: (&module::HANDLER, VpciDevType::YourType) */ -static HANDLERS: &[(&dyn VpciDeviceHandler, VpciDevType)] = &[ - (&standard::HANDLER, VpciDevType::StandardVdev), -]; +static HANDLERS: &[(&dyn VpciDeviceHandler, VpciDevType)] = + &[(&standard::HANDLER, VpciDevType::StandardVdev)]; pub(crate) fn get_handler(dev_type: VpciDevType) -> Option<&'static dyn VpciDeviceHandler> { - HANDLERS.iter() + HANDLERS + .iter() .find(|(_, ty)| *ty == dev_type) .map(|(handler, _)| *handler) } pub(super) fn vpci_dev_read_cfg( - dev_type: VpciDevType, - node: ArcRwLockVirtualPciConfigSpace, - offset: PciConfigAddress, - size: usize + dev_type: VpciDevType, + node: ArcRwLockVirtualPciConfigSpace, + offset: PciConfigAddress, + size: usize, ) -> HvResult { match dev_type { VpciDevType::Physical => { @@ -98,21 +112,25 @@ pub(super) fn vpci_dev_read_cfg( match handler.read_cfg(node.clone(), offset, size) { Ok(status) => { match status { - PciConfigAccessStatus::Done(value) => { - Ok(value) - } + PciConfigAccessStatus::Done(value) => Ok(value), PciConfigAccessStatus::Default => { // If this is a standard virtual device, read from DEFAULT_CSPACE_U32 warn!("vpci_dev_read_cfg: default config space read, offset {:#x}, size {:#x}", offset, size); if offset < STANDARD_CFG_SIZE as PciConfigAddress { let u32_offset = (offset as usize) / 4; let u32_value = DEFAULT_CSPACE_U32[u32_offset]; - + // Extract the appropriate bytes based on size and offset within the u32 let byte_offset_in_u32 = (offset as usize) % 4; let value = match size { - 1 => ((u32_value >> (byte_offset_in_u32 * 8)) & 0xFF) as usize, - 2 => ((u32_value >> (byte_offset_in_u32 * 8)) & 0xFFFF) as usize, + 1 => { + ((u32_value >> (byte_offset_in_u32 * 8)) & 0xFF) + as usize + } + 2 => { + ((u32_value >> (byte_offset_in_u32 * 8)) & 0xFFFF) + as usize + } 4 => u32_value as usize, _ => { warn!("vpci_dev_read_cfg: invalid size {size}, try read from emu"); @@ -147,11 +165,11 @@ pub(super) fn vpci_dev_read_cfg( } pub(super) fn vpci_dev_write_cfg( - dev_type: VpciDevType, - node: ArcRwLockVirtualPciConfigSpace, - offset: PciConfigAddress, - size: usize, - value: usize + dev_type: VpciDevType, + node: ArcRwLockVirtualPciConfigSpace, + offset: PciConfigAddress, + size: usize, + value: usize, ) -> HvResult { match dev_type { VpciDevType::Physical => { @@ -161,21 +179,17 @@ pub(super) fn vpci_dev_write_cfg( _ => { if let Some(handler) = get_handler(dev_type) { match handler.write_cfg(node.clone(), offset, size, value) { - Ok(status) => { - match status { - PciConfigAccessStatus::Done(_) => { - Ok(()) - } - PciConfigAccessStatus::Default => { - warn!("vpci_dev_write_cfg: Default"); - Ok(()) - } - PciConfigAccessStatus::Reject => { - warn!("vpci_dev_write_cfg: operation rejected"); - Ok(()) - } + Ok(status) => match status { + PciConfigAccessStatus::Done(_) => Ok(()), + PciConfigAccessStatus::Default => { + warn!("vpci_dev_write_cfg: Default"); + Ok(()) } - } + PciConfigAccessStatus::Reject => { + warn!("vpci_dev_write_cfg: operation rejected"); + Ok(()) + } + }, Err(e) => { warn!("vpci_dev_write_cfg error: {:?}", e); Err(e) @@ -200,9 +214,9 @@ pub(super) fn virt_dev_init( base, dev_type, ConfigValue::default(), - Bar::default() + Bar::default(), ); - + match dev_type { VpciDevType::Physical => { // Physical devices use default values @@ -233,13 +247,18 @@ pub struct VirtMsiCap { impl PciCapabilityRegion for VirtMsiCap { fn read(&self, offset: PciConfigAddress, size: usize) -> HvResult { match (offset, size) { - (0x0, 2) => Ok((CapabilityType::Msi.to_id() as u32) | (self.next_cap_pointer << 8) as u32), + (0x0, 2) => { + Ok((CapabilityType::Msi.to_id() as u32) | (self.next_cap_pointer << 8) as u32) + } (0x2, 2) => Ok(self.control_bits.as_raw_slice()[0] as u32), (0x4, 4) => Ok(self.message_address_lower), (0x8, 4) => Ok(self.message_address_upper), (0xC, 2) => Ok(self.message_data as u32), _ => { - warn!("VirtMsiCap invalid read offset 0x{:x} size {}", offset, size); + warn!( + "VirtMsiCap invalid read offset 0x{:x} size {}", + offset, size + ); Ok(0) } } @@ -251,7 +270,10 @@ impl PciCapabilityRegion for VirtMsiCap { (0x8, 4) => self.message_address_upper = value, (0xC, 2) => self.message_data = value as u16, _ => { - warn!("VirtMsiCap invalid write offset 0x{:x} size {}", offset, size); + warn!( + "VirtMsiCap invalid write offset 0x{:x} size {}", + offset, size + ); } } Ok(()) @@ -294,13 +316,20 @@ pub struct VirtMsiXCap { impl PciCapabilityRegion for VirtMsiXCap { fn read(&self, offset: PciConfigAddress, size: usize) -> HvResult { match (offset, size) { - (0x0, 4) => Ok(((CapabilityType::MsiX.to_id() as u32) | (self.next_cap_pointer << 8) as u32) | (((self.control_bits.as_raw_slice()[0] as u32) << 16) as u32)), - (0x0, 2) => Ok((CapabilityType::MsiX.to_id() as u32) | (self.next_cap_pointer << 8) as u32), + (0x0, 4) => Ok(((CapabilityType::MsiX.to_id() as u32) + | (self.next_cap_pointer << 8) as u32) + | (((self.control_bits.as_raw_slice()[0] as u32) << 16) as u32)), + (0x0, 2) => { + Ok((CapabilityType::MsiX.to_id() as u32) | (self.next_cap_pointer << 8) as u32) + } (0x2, 2) => Ok(self.control_bits.as_raw_slice()[0] as u32), (0x4, 4) => Ok(self.table), (0x8, 4) => Ok(self.pba), _ => { - warn!("VirtMsiXCap invalid read offset 0x{:x} size {}", offset, size); + warn!( + "VirtMsiXCap invalid read offset 0x{:x} size {}", + offset, size + ); Ok(0) } } @@ -311,7 +340,10 @@ impl PciCapabilityRegion for VirtMsiXCap { (0x4, 4) => self.table = value, (0x8, 4) => self.pba = value, _ => { - warn!("VirtMsiXCap invalid write offset 0x{:x} size {}", offset, size); + warn!( + "VirtMsiXCap invalid write offset 0x{:x} size {}", + offset, size + ); } } @@ -341,4 +373,4 @@ impl VirtMsiXCap { pub fn set_next_cap_pointer(&mut self, next_cap_pointer: u16) { self.next_cap_pointer = next_cap_pointer; } -} \ No newline at end of file +} diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index 20f7ba0d..313ca257 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -1,30 +1,42 @@ +use super::{PciConfigAccessStatus, VpciDeviceHandler}; use crate::error::HvResult; +use crate::pci::pci_access::{ + BaseClass, DeviceId, DeviceRevision, EndpointField, Interface, SubClass, VendorId, +}; use crate::pci::pci_struct::{CapabilityType, PciCapability, VirtualPciConfigSpace}; -use crate::pci::pci_access::{EndpointField, DeviceId, VendorId, BaseClass, SubClass, Interface, DeviceRevision}; use crate::pci::PciConfigAddress; -use super::{PciConfigAccessStatus, VpciDeviceHandler}; // use crate::memory::frame::Frame; -use crate::pci::pci_struct::ArcRwLockVirtualPciConfigSpace; -use crate::percpu::this_zone; use crate::memory::MMIOAccess; use crate::pci::pci_access::PciMemType; +use crate::pci::pci_struct::ArcRwLockVirtualPciConfigSpace; +use crate::pci::pci_struct::PciCapabilityRegion; use crate::pci::vpci_dev::VirtMsiXCap; -use spin::RwLock; +use crate::percpu::this_zone; use alloc::sync::Arc; -use crate::pci::pci_struct::PciCapabilityRegion; +use spin::RwLock; /// Handler for standard virtual PCI devices pub struct StandardHandler; impl VpciDeviceHandler for StandardHandler { - fn read_cfg(&self, dev: ArcRwLockVirtualPciConfigSpace, offset: PciConfigAddress, size: usize) -> HvResult { - info!("virt pci standard read_cfg, offset {:#x}, size {:#x}", offset, size); + fn read_cfg( + &self, + dev: ArcRwLockVirtualPciConfigSpace, + offset: PciConfigAddress, + size: usize, + ) -> HvResult { + info!( + "virt pci standard read_cfg, offset {:#x}, size {:#x}", + offset, size + ); match EndpointField::from(offset as usize, size) { EndpointField::ID => { let id = dev.with_config_value(|config_value| config_value.get_id()); - Ok(PciConfigAccessStatus::Done((((id.0 as u32) << 16) | (id.1 as u32)) as usize)) + Ok(PciConfigAccessStatus::Done( + (((id.0 as u32) << 16) | (id.1 as u32)) as usize, + )) } - EndpointField::Bar(0) => { + EndpointField::Bar(0) => { let slot = 0; let size_read = dev.with_bar_ref(slot, |bar| bar.get_size_read()); if size_read { @@ -36,17 +48,22 @@ impl VpciDeviceHandler for StandardHandler { Ok(PciConfigAccessStatus::Done(value as usize)) } } - EndpointField::CapabilityPointer => { - Ok(PciConfigAccessStatus::Done(0x98)) - } - _ => { - Ok(PciConfigAccessStatus::Default) - } + EndpointField::CapabilityPointer => Ok(PciConfigAccessStatus::Done(0x98)), + _ => Ok(PciConfigAccessStatus::Default), } } - fn write_cfg(&self, dev: ArcRwLockVirtualPciConfigSpace, offset: PciConfigAddress, size: usize, value: usize) -> HvResult { - info!("virt pci standard write_cfg, offset {:#x}, size {:#x}, value {:#x}", offset, size, value); + fn write_cfg( + &self, + dev: ArcRwLockVirtualPciConfigSpace, + offset: PciConfigAddress, + size: usize, + value: usize, + ) -> HvResult { + info!( + "virt pci standard write_cfg, offset {:#x}, size {:#x}, value {:#x}", + offset, size, value + ); match EndpointField::from(offset as usize, size) { EndpointField::Command => { // Command field is written directly to backend, no need for space cache @@ -55,23 +72,32 @@ impl VpciDeviceHandler for StandardHandler { EndpointField::Bar(0) => { let slot = 0; let bar_size = dev.with_bar_ref(slot, |bar| bar.get_size()); - + if value == 0xFFFF_FFFF { dev.with_bar_ref_mut(slot, |bar| bar.set_size_read()); } else { let zone = this_zone(); let mut guard = zone.write(); - info!("virtual pci standard write_cfg, register mmio region {:#x}, size {:#x}", value, bar_size); - guard.mmio_region_register(value as usize, bar_size as usize, mmio_vdev_standard_handler, value); + info!( + "virtual pci standard write_cfg, register mmio region {:#x}, size {:#x}", + value, bar_size + ); + guard.mmio_region_register( + value as usize, + bar_size as usize, + mmio_vdev_standard_handler, + value, + ); } Ok(PciConfigAccessStatus::Done(value)) } - EndpointField::Bar(_) => { - Ok(PciConfigAccessStatus::Done(value)) - } + EndpointField::Bar(_) => Ok(PciConfigAccessStatus::Done(value)), _ => { - warn!("virt pci standard write_cfg, invalid offset {:#x}, size {:#x}, value {:#x}", offset, size, value); + warn!( + "virt pci standard write_cfg, invalid offset {:#x}, size {:#x}, value {:#x}", + offset, size, value + ); Ok(PciConfigAccessStatus::Reject) } } @@ -79,21 +105,16 @@ impl VpciDeviceHandler for StandardHandler { fn vdev_init(&self, mut dev: VirtualPciConfigSpace) -> VirtualPciConfigSpace { // Set config_value - let id :(DeviceId, VendorId) = (0x110a, 0x4106); + let id: (DeviceId, VendorId) = (0x110a, 0x4106); let revision: DeviceRevision = 0xFFu8; let base_class: BaseClass = 0x0; let sub_class: SubClass = 0x0; let interface: Interface = 0x0; dev.with_config_value_mut(|config_value| { config_value.set_id(id); - config_value.set_class_and_revision_id(( - base_class, - sub_class, - interface, - revision, - )); + config_value.set_class_and_revision_id((base_class, sub_class, interface, revision)); }); - + // Set bararr let your_addr = 0x0; let size = 0x1000; @@ -107,16 +128,15 @@ impl VpciDeviceHandler for StandardHandler { let mut msi_cap = VirtMsiXCap::new(msi_cap_offset); msi_cap.set_next_cap_pointer(0x00); dev.with_access_mut(|access| { - access.set_bits((msi_cap_offset as usize)..(msi_cap_offset as usize + msi_cap.get_size()) as usize); + access.set_bits( + (msi_cap_offset as usize)..(msi_cap_offset as usize + msi_cap.get_size()) as usize, + ); }); dev.with_cap_mut(|capabilities| { capabilities.insert( - msi_cap_offset, - PciCapability::new_virt( - CapabilityType::MsiX, - Arc::new(RwLock::new(msi_cap)) - ) + msi_cap_offset, + PciCapability::new_virt(CapabilityType::MsiX, Arc::new(RwLock::new(msi_cap))), ); }); @@ -133,4 +153,4 @@ pub const HANDLER: StandardHandler = StandardHandler; pub fn mmio_vdev_standard_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { info!("mmio_vdev_standard_handler {:#x}", mmio.address); Ok(()) -} \ No newline at end of file +} diff --git a/src/zone.rs b/src/zone.rs index 1c9ec13f..dedda504 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -20,10 +20,10 @@ use crate::consts::{INVALID_ADDRESS, MAX_CPU_NUM}; use crate::pci::pci_struct::VirtualRootComplex; use spin::RwLock; -#[cfg(feature = "dwc_pcie")] -use alloc::collections::btree_map::BTreeMap; #[cfg(feature = "dwc_pcie")] use crate::pci::{config_accessors::dwc_atu::AtuConfig, PciConfigAddress}; +#[cfg(feature = "dwc_pcie")] +use alloc::collections::btree_map::BTreeMap; use crate::arch::mm::new_s2_memory_set; use crate::arch::s2pt::Stage2PageTable; @@ -294,7 +294,12 @@ pub fn zone_create(config: &HvZoneConfig) -> HvResult>> { #[cfg(feature = "pci")] { let _ = zone.virtual_pci_mmio_init(&config.pci_config, config.num_pci_bus as usize); - let _ = zone.guest_pci_init(zone_id, &config.alloc_pci_devs, config.num_pci_devs, config.pci_config[0].ecam_base as u64); + let _ = zone.guest_pci_init( + zone_id, + &config.alloc_pci_devs, + config.num_pci_devs, + config.pci_config[0].ecam_base as u64, + ); } // #[cfg(target_arch = "aarch64")] From 3c81c21736636ae42360d656f7a9e0197ddb64b7 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 31 Dec 2025 21:48:34 +0800 Subject: [PATCH 065/109] add domain for pci config --- platform/aarch64/qemu-gicv3/board.rs | 11 ++++--- platform/aarch64/rk3568/board.rs | 7 +++-- src/config.rs | 16 +++++++--- src/pci/pci_config.rs | 12 +++++--- src/pci/pci_struct.rs | 46 ++++++++++++++++------------ 5 files changed, 57 insertions(+), 35 deletions(-) diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index f4a70887..dc804178 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -55,7 +55,7 @@ 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; 3] = [ +pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, physical_start: 0x50000000, @@ -107,13 +107,14 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { pci_mem64_base: 0x8000000000, bus_range_begin: 0, bus_range_end: 0xff, + domain: 0x0, }]; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; pub const ROOT_PCI_DEVS: &[HvPciDevConfig] = &[ - pci_dev!(0x0, 0x0, 0x0, VpciDevType::Physical), - pci_dev!(0x0, 0x1, 0x0, VpciDevType::Physical), - pci_dev!(0x0, 0x2, 0x0, VpciDevType::Physical), - pci_dev!(0x0, 0x5, 0x0, VpciDevType::StandardVdev), + pci_dev!(0x0, 0x0, 0x0, 0, VpciDevType::Physical), + pci_dev!(0x0, 0x1, 0x0, 0, VpciDevType::Physical), + pci_dev!(0x0, 0x2, 0x0, 0, VpciDevType::Physical), + pci_dev!(0x0, 0x5, 0x0, 0, VpciDevType::StandardVdev), ]; diff --git a/platform/aarch64/rk3568/board.rs b/platform/aarch64/rk3568/board.rs index 6128c453..d2238aef 100644 --- a/platform/aarch64/rk3568/board.rs +++ b/platform/aarch64/rk3568/board.rs @@ -300,6 +300,7 @@ pub const ROOT_PCI_CONFIG: &[HvPciConfig] = &[ // pci_mem64_base: 0x300000000, // bus_range_begin: 0x0, // bus_range_end: 0x10, + // domain: 0x0, // }, HvPciConfig { ecam_base: 0x3c0400000, @@ -315,6 +316,7 @@ pub const ROOT_PCI_CONFIG: &[HvPciConfig] = &[ pci_mem64_base: 0x340000000, bus_range_begin: 0x10, bus_range_end: 0x1f, + domain: 0x1, }, // HvPciConfig { // ecam_base: 0xfe280000, @@ -330,6 +332,7 @@ pub const ROOT_PCI_CONFIG: &[HvPciConfig] = &[ // pci_mem64_base: 0x380000000, // bus_range_begin: 0x20, // bus_range_end: 0x2f, + // domain: 0x2, // } ]; @@ -349,6 +352,6 @@ pub const ROOT_DWC_ATU_CONFIG: &[HvDwcAtuConfig] = &[ ]; pub const ROOT_PCI_DEVS: [HvPciDevConfig; 2] = [ - pci_dev!(0x10, 0x0, 0x0, VpciDevType::Physical), - pci_dev!(0x11, 0x0, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x10, 0x0, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x11, 0x0, 0x0, VpciDevType::Physical), ]; \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index 851c4cdd..ee88a16c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -61,6 +61,7 @@ pub struct HvPciConfig { pub pci_mem64_base: u64, pub bus_range_begin: u32, pub bus_range_end: u32, + pub domain: u8, } impl HvPciConfig { @@ -79,6 +80,7 @@ impl HvPciConfig { pci_mem64_base: 0, bus_range_begin: 0, bus_range_end: 0, + domain: 0, } } } @@ -212,15 +214,21 @@ pub struct HvIvcConfig { #[repr(C)] #[derive(Copy, Clone, Default)] pub struct HvPciDevConfig { - pub bdf: u64, + pub domain: u8, + pub bus: u8, + pub device: u8, + pub function: u8, pub dev_type: VpciDevType, } #[macro_export] macro_rules! pci_dev { - ($bus:expr, $dev:expr, $func:expr, $dev_type:expr) => { + ($domain:expr, $bus:expr, $dev:expr, $func:expr, $dev_type:expr) => { HvPciDevConfig { - bdf: ($bus << 8) | ($dev << 3) | ($func), + domain: $domain, + bus: $bus, + device: $dev, + function: $func, dev_type: $dev_type, } }; @@ -228,7 +236,7 @@ macro_rules! pci_dev { 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); + let bdf = crate::pci::pci_struct::Bdf::new(self.domain, self.bus, self.device, self.function); write!(f, "bdf {:#?}", bdf) } } diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 47a3d3de..795eee9c 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -46,8 +46,8 @@ use crate::{ config_accessors::{ dwc::DwcConfigRegionBackend, dwc_atu::{AtuConfig, AtuType}, + PciRegionMmio, }, - pci_access::PciRegionMmio, pci_handler::{mmio_dwc_cfg_handler, mmio_dwc_io_handler, mmio_vpci_handler_dbi}, }, platform, @@ -146,7 +146,8 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { let range = rootcomplex_config.bus_range_begin as usize..rootcomplex_config.bus_range_end as usize; - let e = rootcomplex.enumerate(Some(range), allocator_opt); + let domain = rootcomplex_config.domain; + let e = rootcomplex.enumerate(Some(range), domain, allocator_opt); info!("begin enumerate {:#?}", e); for node in e { info!("node {:#?}", node); @@ -172,7 +173,7 @@ 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 << 12); + let bdf = Bdf::new_from_config(dev_config); let vbdf = bdf.clone(); #[cfg(any( all(feature = "iommu", target_arch = "aarch64"), @@ -184,7 +185,8 @@ impl Zone { } else { 0 }; - iommu_add_device(zone_id, dev_config.bdf as _, iommu_pt_addr); + let device_id = (dev_config.bus as usize) << 8 | (dev_config.device as usize) << 3 | dev_config.function as usize; + iommu_add_device(zone_id, device_id as _, iommu_pt_addr); } if let Some(dev) = guard.get(&bdf) { if bdf.is_host_bridge(dev.read().get_host_bdf().bus()) @@ -311,7 +313,7 @@ impl Zone { let dbi_size = extend_config.dbi_size; let dbi_region = PciRegionMmio::new(dbi_base, dbi_size); let dbi_backend = DwcConfigRegionBackend::new(dbi_region); - if let Err(e) = atu.init_limit_hw_value(dbi_backend.as_ref()) { + if let Err(e) = atu.init_limit_hw_value(&dbi_backend) { warn!("Failed to initialize ATU0 limit defaults: {:?}", e); } diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index b86d98d7..94a22fda 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -37,6 +37,7 @@ use super::{ use crate::{ error::{HvErrorNum, HvResult}, + config::HvPciDevConfig, pci::vpci_dev::VpciDevType, }; @@ -151,21 +152,30 @@ const PCI_EXP_TYPE_PCIE_BRIDGE: u16 = 8; #[derive(Clone, Copy, Eq, PartialEq, Default)] pub struct Bdf { + pub domain: u8, pub bus: u8, pub device: u8, pub function: u8, } impl Bdf { - #[allow(dead_code)] - pub fn new(bus: u8, device: u8, function: u8) -> Self { + pub fn new(domain: u8, bus: u8, device: u8, function: u8) -> Self { Self { + domain, bus, device, function, } } + pub fn new_from_config(config: HvPciDevConfig) -> Self { + Self::new(config.domain, config.bus, config.device, config.function) + } + + pub fn domain(&self) -> u8 { + self.domain + } + pub fn bus(&self) -> u8 { self.bus } @@ -178,18 +188,6 @@ impl Bdf { self.function } - pub fn from_address(address: PciConfigAddress) -> Bdf { - let bdf = address >> 12; - let function = (bdf & 0b111) as u8; - let device = ((bdf >> 3) & 0b11111) as u8; - let bus = (bdf >> 8) as u8; - Bdf { - bus, - device, - function, - } - } - pub fn is_host_bridge(&self, bus_begin: u8) -> bool { if (self.bus, self.device, self.function) == (bus_begin, 0, 0) { true @@ -224,6 +222,10 @@ impl FromStr for Bdf { return Err(HvErrorNum::EINVAL); } + let domain = u8::from_str_radix(parts[0], 16) + .map_err(|_| HvErrorNum::EINVAL) + .unwrap(); + let bus = u8::from_str_radix(parts[1], 16) .map_err(|_| HvErrorNum::EINVAL) .unwrap(); @@ -240,6 +242,7 @@ impl FromStr for Bdf { .unwrap(); Ok(Bdf { + domain, bus, device, function, @@ -932,6 +935,7 @@ pub struct PciIterator { stack: Vec, segment: PciConfigAddress, bus_range: Range, + domain: u8, function: u8, is_mulitple_function: bool, is_finish: bool, @@ -975,7 +979,7 @@ impl PciIterator { (bus_begin, 0, self.function, bus_begin) }; - let bdf = Bdf::new(bus, device, function); + let bdf = Bdf::new(self.domain, bus, device, function); let address = self.address(parent_bus, bdf); let pci_addr_base = self.get_pci_addr_base(parent_bus, bdf); @@ -1251,6 +1255,7 @@ impl Iterator for PciIterator { if let Some(mut node) = self.get_node() { node.config_value_init(); let bus_begin = self.bus_range.start as u8; + let domain = self.domain; /* * when first time to enumerate, placeholder is pop in get_node * the message of host bridge must be got after get_node() @@ -1266,15 +1271,15 @@ impl Iterator for PciIterator { self.stack.push(host_bridge); } let parent = self.stack.last().unwrap(); // Safe because we just ensured it exists - let host_bdf = Bdf::new(bus_begin, 0, 0); - let parent_bdf = Bdf::new(parent.bus, parent.device, 0); + let host_bdf = Bdf::new(domain, bus_begin, 0, 0); + let parent_bdf = Bdf::new(domain, parent.bus, parent.device, 0); let parent_bus = parent.primary_bus; node.set_host_bdf(host_bdf); node.set_parent_bdf(parent_bdf); self.next(match node.config_value.get_class().0 { // class code 0x6 is bridge and class.1 0x0 is host bridge 0x6 if node.config_value.get_class().1 != 0x0 => { - let bdf = Bdf::new(parent.subordinate_bus + 1, 0, 0); + let bdf = Bdf::new(domain, parent.subordinate_bus + 1, 0, 0); Some(self.get_bridge().next_bridge( self.address(parent_bus, bdf), node.has_secondary_link(), @@ -1394,6 +1399,7 @@ impl RootComplex { fn __enumerate( &mut self, range: Option>, + domain: u8, bar_alloc: Option, ) -> PciIterator { let mmio_base = self.mmio_base; @@ -1403,6 +1409,7 @@ impl RootComplex { stack: vec![Bridge::placeholder()], segment: mmio_base, bus_range: range, + domain, function: 0, is_mulitple_function: false, is_finish: false, @@ -1413,9 +1420,10 @@ impl RootComplex { pub fn enumerate( &mut self, range: Option>, + domain: u8, bar_alloc: Option, ) -> PciIterator { - self.__enumerate(range, bar_alloc) + self.__enumerate(range, domain, bar_alloc) } } From 013d64ef3518922e0751441fef413d27691c33f4 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 31 Dec 2025 23:38:23 +0800 Subject: [PATCH 066/109] added Vbdf generation logic to support discontinuous PCIe devices --- src/config.rs | 3 +- src/pci/pci_config.rs | 181 ++++++++++++++++++++++++++++++------------ src/pci/pci_struct.rs | 4 +- src/pci/pci_test.rs | 2 +- src/zone.rs | 3 +- 5 files changed, 137 insertions(+), 56 deletions(-) diff --git a/src/config.rs b/src/config.rs index ee88a16c..6e571ef3 100644 --- a/src/config.rs +++ b/src/config.rs @@ -236,7 +236,8 @@ macro_rules! pci_dev { impl Debug for HvPciDevConfig { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let bdf = crate::pci::pci_struct::Bdf::new(self.domain, self.bus, self.device, self.function); + let bdf = + crate::pci::pci_struct::Bdf::new(self.domain, self.bus, self.device, self.function); write!(f, "bdf {:#?}", bdf) } } diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 795eee9c..0de9122e 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -166,68 +166,147 @@ impl Zone { zone_id: usize, alloc_pci_devs: &[HvPciDevConfig; CONFIG_MAX_PCI_DEV], num_pci_devs: u64, - //TODO: set vpci dev base in other way - _ecam_base: u64, + pci_config: &[HvPciConfig], + _num_pci_config: usize, ) -> 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::new_from_config(dev_config); - let vbdf = bdf.clone(); - #[cfg(any( - all(feature = "iommu", target_arch = "aarch64"), - target_arch = "x86_64" - ))] - { - let iommu_pt_addr = if self.iommu_pt.is_some() { - self.iommu_pt.as_ref().unwrap().root_paddr() - } else { + for target_pci_config in pci_config { + // Skip empty config + if target_pci_config.ecam_base == 0 { + continue; + } + + #[allow(unused_variables)] + let ecam_base = target_pci_config.ecam_base; + let target_domain = target_pci_config.domain; + let bus_range_begin = target_pci_config.bus_range_begin as u8; + + let mut filtered_devices: alloc::vec::Vec = alloc::vec::Vec::new(); + for i in 0..num_pci_devs { + let dev_config = alloc_pci_devs[i as usize]; + if dev_config.domain == target_domain { + filtered_devices.push(dev_config); + } + } + + // Skip if no devices for this domain + if filtered_devices.is_empty() { + continue; + } + + filtered_devices.sort_by(|a, b| { + a.bus + .cmp(&b.bus) + .then_with(|| a.device.cmp(&b.device)) + .then_with(|| a.function.cmp(&b.function)) + }); + + let mut vbus_pre = bus_range_begin; + let mut bus_pre = bus_range_begin; + let mut device_pre = 0u8; + + /* + * To allow Linux to successfully recognize the devices we add, hvisor needs + * to adjust the devices’ BDFs. Linux always assumes that the PCIe buses + * it discovers are contiguous, and that device function numbers always start from 0. + * + * 1. The bus number of a virtual BDF (vBDF) must start from range_begin and + * be contiguous. Once the physical bus number increases—regardless of + * how much it increases—the corresponding virtual bus number (vbus) + * can only increase by 1. + * + * 2. If the function number of a vBDF is not 0, and it is found that + * the device with function 0 of the same vBDF does not belong to the current zone, + * then the function number of the current vBDF should be set to 0. + */ + for dev_config in &filtered_devices { + let bdf = Bdf::new_from_config(*dev_config); + let bus = bdf.bus(); + let device = bdf.device(); + let function = bdf.function(); + + /* + * vfunction = if (bus != bus_pre || device != device_pre) && function != 0 + * In practice, remapping is performed only for new devices whose function is not 0; + * however, the check for function != 0 does not affect the final result. + */ + let vfunction = if bus != bus_pre || device != device_pre { 0 + } else { + function }; - let device_id = (dev_config.bus as usize) << 8 | (dev_config.device as usize) << 3 | dev_config.function as usize; - iommu_add_device(zone_id, device_id as _, iommu_pt_addr); - } - if let Some(dev) = guard.get(&bdf) { - if bdf.is_host_bridge(dev.read().get_host_bdf().bus()) - || dev.with_config_value(|config_value| -> bool { - config_value.get_class().0 == 0x6 - }) - { - let mut vdev = dev.read().clone(); - vdev.set_vbdf(vbdf); - self.vpci_bus.insert(vbdf, vdev); + + let vbus = if bus > bus_pre { + vbus_pre += 1; + vbus_pre } else { - let vdev = guard.remove(&bdf).unwrap(); - let mut vdev_inner = vdev.read().clone(); - vdev_inner.set_vbdf(vbdf); - self.vpci_bus.insert(vbdf, vdev_inner); - } - } else { - // warn!("can not find dev {:#?}", bdf); - #[cfg(feature = "ecam_pcie")] + vbus_pre + }; + + let vbdf = Bdf::new(bdf.domain(), vbus, device, vfunction); + + device_pre = device; + bus_pre = bus; + + info!("set bdf {:#?} to vbdf {:#?}", bdf, vbdf); + + #[cfg(any( + all(feature = "iommu", target_arch = "aarch64"), + target_arch = "x86_64" + ))] { - let dev_type = dev_config.dev_type; - match dev_type { - VpciDevType::Physical => { - warn!("can not find dev {:#?}", bdf); - } - _ => { - if let Some(_handler) = get_handler(dev_type) { - let base = _ecam_base - + ((bdf.bus() as u64) << 20) - + ((bdf.device() as u64) << 15) - + ((bdf.function() as u64) << 12); - let dev = VirtualPciConfigSpace::virt_dev(bdf, base, dev_type); - self.vpci_bus.insert(vbdf, dev); - } else { - warn!("can not find dev {:#?}, unknown device type", bdf); + let iommu_pt_addr = if self.iommu_pt.is_some() { + self.iommu_pt.as_ref().unwrap().root_paddr() + } else { + 0 + }; + let device_id = (dev_config.bus as usize) << 8 + | (dev_config.device as usize) << 3 + | dev_config.function as usize; + iommu_add_device(zone_id, device_id as _, iommu_pt_addr); + } + + // Insert device into vpci_bus with calculated vbdf + if let Some(dev) = guard.get(&bdf) { + if bdf.is_host_bridge(dev.read().get_host_bdf().bus()) + || dev.with_config_value(|config_value| -> bool { + config_value.get_class().0 == 0x6 + }) + { + let mut vdev = dev.read().clone(); + vdev.set_vbdf(vbdf); + self.vpci_bus.insert(vbdf, vdev); + } else { + let vdev = guard.remove(&bdf).unwrap(); + let mut vdev_inner = vdev.read().clone(); + vdev_inner.set_vbdf(vbdf); + self.vpci_bus.insert(vbdf, vdev_inner); + } + } else { + // warn!("can not find dev {:#?}", bdf); + #[cfg(feature = "ecam_pcie")] + { + let dev_type = dev_config.dev_type; + match dev_type { + VpciDevType::Physical => { + warn!("can not find dev {:#?}", bdf); + } + _ => { + if let Some(_handler) = get_handler(dev_type) { + let base = ecam_base + + ((bdf.bus() as u64) << 20) + + ((bdf.device() as u64) << 15) + + ((bdf.function() as u64) << 12); + let dev = VirtualPciConfigSpace::virt_dev(bdf, base, dev_type); + self.vpci_bus.insert(vbdf, dev); + } else { + warn!("can not find dev {:#?}, unknown device type", bdf); + } } } } } } - i += 1; } info!("vpci bus init done\n {:#?}", self.vpci_bus); Ok(()) diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 94a22fda..c5f826b6 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -36,8 +36,8 @@ use super::{ }; use crate::{ - error::{HvErrorNum, HvResult}, config::HvPciDevConfig, + error::{HvErrorNum, HvResult}, pci::vpci_dev::VpciDevType, }; @@ -1279,7 +1279,7 @@ impl Iterator for PciIterator { self.next(match node.config_value.get_class().0 { // class code 0x6 is bridge and class.1 0x0 is host bridge 0x6 if node.config_value.get_class().1 != 0x0 => { - let bdf = Bdf::new(domain, parent.subordinate_bus + 1, 0, 0); + let bdf = Bdf::new(domain, parent.subordinate_bus + 1, 0, 0); Some(self.get_bridge().next_bridge( self.address(parent_bus, bdf), node.has_secondary_link(), diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs index 082ad7c7..0db8f840 100644 --- a/src/pci/pci_test.rs +++ b/src/pci/pci_test.rs @@ -48,7 +48,7 @@ pub fn pcie_test() { allocator.set_mem64(0x8000000000, 0xffffffffff - 0x8000000000); let mut root = RootComplex::new_ecam(0x4010000000); - for node in root.enumerate(None, Some(allocator)) { + for node in root.enumerate(None, 0, Some(allocator)) { GLOBAL_PCIE_LIST_TEST.lock().insert(node.get_bdf(), node); } warn!("pcie guest init done"); diff --git a/src/zone.rs b/src/zone.rs index dedda504..9efb5232 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -298,7 +298,8 @@ pub fn zone_create(config: &HvZoneConfig) -> HvResult>> { zone_id, &config.alloc_pci_devs, config.num_pci_devs, - config.pci_config[0].ecam_base as u64, + &config.pci_config, + config.num_pci_bus as usize, ); } From 6d6b24da20daa73dbe3846805f7e65533369f293 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 31 Dec 2025 23:46:07 +0800 Subject: [PATCH 067/109] pcie config update --- platform/aarch64/qemu-gicv2/board.rs | 9 ++-- platform/aarch64/qemu-gicv3/board.rs | 8 +-- .../qemu-gicv3/configs/zone1-linux.json | 10 +++- platform/aarch64/rk3588/board.rs | 9 +++- platform/loongarch64/ls3a5000/board.rs | 53 +++++++++--------- .../ls3a5000/configs/zone1-linux.json | 7 ++- .../ls3a5000/configs/zone2-linux.json | 7 ++- .../ls3a5000/configs/zone3-linux.json | 7 ++- platform/loongarch64/ls3a6000/board.rs | 54 +++++++++---------- .../ls3a6000/configs/zone1-linux.json | 7 ++- .../ls3a6000/configs/zone2-linux.json | 7 ++- .../ls3a6000/configs/zone3-linux.json | 7 ++- platform/x86_64/qemu/board.rs | 17 +++--- 13 files changed, 119 insertions(+), 83 deletions(-) diff --git a/platform/aarch64/qemu-gicv2/board.rs b/platform/aarch64/qemu-gicv2/board.rs index 9c50715a..d7d58d5b 100644 --- a/platform/aarch64/qemu-gicv2/board.rs +++ b/platform/aarch64/qemu-gicv2/board.rs @@ -109,13 +109,16 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ mem64_base: 0x8000000000, mem64_size: 0x8000000000, pci_mem64_base: 0x8000000000, + bus_range_begin: 0x0, + bus_range_end: 0xff, + domain: 0x0, } ]; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; pub const ROOT_PCI_DEVS: [HvPciDevConfig; 3] = [ - pci_dev!(0x0, 0x0, 0x0, VpciDevType::Physical), - pci_dev!(0x0, 0x1, 0x0, VpciDevType::Physical), - pci_dev!(0x0, 0x2, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x0, 0x0, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x0, 0x1, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x0, 0x2, 0x0, VpciDevType::Physical), ]; diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index dc804178..02f04aab 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -113,8 +113,8 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; pub const ROOT_PCI_DEVS: &[HvPciDevConfig] = &[ - pci_dev!(0x0, 0x0, 0x0, 0, VpciDevType::Physical), - pci_dev!(0x0, 0x1, 0x0, 0, VpciDevType::Physical), - pci_dev!(0x0, 0x2, 0x0, 0, VpciDevType::Physical), - pci_dev!(0x0, 0x5, 0x0, 0, VpciDevType::StandardVdev), + pci_dev!(0x0, 0x0, 0x0, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x0, 0x1, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x0, 0x2, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x0, 0x5, 0x0, VpciDevType::StandardVdev), ]; diff --git a/platform/aarch64/qemu-gicv3/configs/zone1-linux.json b/platform/aarch64/qemu-gicv3/configs/zone1-linux.json index 7de1d7c4..e4aa8e37 100644 --- a/platform/aarch64/qemu-gicv3/configs/zone1-linux.json +++ b/platform/aarch64/qemu-gicv3/configs/zone1-linux.json @@ -51,11 +51,17 @@ "num_pci_devs": 2, "alloc_pci_devs": [ { - "bdf": "0x0", + "domain": "0x0", + "bus": "0x0", + "device": "0x0", + "function": "0x0", "dev_type": "0" }, { - "bdf": "0x18", + "domain": "0x0", + "bus": "0x0", + "device": "0x1", + "function": "0x0", "dev_type": "0" } ] diff --git a/platform/aarch64/rk3588/board.rs b/platform/aarch64/rk3588/board.rs index 2d74033e..afc6acff 100644 --- a/platform/aarch64/rk3588/board.rs +++ b/platform/aarch64/rk3588/board.rs @@ -19,8 +19,11 @@ use crate::{ zone::{GicConfig, Gicv3Config, HvArchZoneConfig}, }, config::*, + pci::vpci_dev::VpciDevType, }; +use crate::pci_dev; + // [ 17.796762] node 0: [mem 0x0000000000200000-0x000000000047ffff] // [ 17.797335] node 0: [mem 0x0000000000480000-0x000000000087ffff] // [ 17.797907] node 0: [mem 0x0000000000880000-0x00000000083fffff] @@ -201,8 +204,12 @@ pub const ROOT_PCI_CONFIG: HvPciConfig = HvPciConfig { mem64_base: 0x8000000000, mem64_size: 0x8000000000, pci_mem64_base: 0x8000000000, + domain: 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; 2] = [ + pci_dev!(0x0, 0x0, 0x0, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x0, 0x1, 0x0, VpciDevType::Physical), +]; diff --git a/platform/loongarch64/ls3a5000/board.rs b/platform/loongarch64/ls3a5000/board.rs index 1c17d74a..0d59ecae 100644 --- a/platform/loongarch64/ls3a5000/board.rs +++ b/platform/loongarch64/ls3a5000/board.rs @@ -170,6 +170,7 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ pci_mem64_base: 0x60000000, bus_range_begin: 0, bus_range_end: 0xff, + domain: 0x0, } ]; @@ -183,32 +184,32 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ /* BUS 6 on X4 slot */ /* 06:00.0, 06:00.1, 06:00.2, 06:00.3 net */ pub const ROOT_PCI_DEVS: &[HvPciDevConfig] = &[ - pci_dev!(0x0, 0x0, 0x0, VpciDevType::Physical), // 00:00.0 - pci_dev!(0x0, 0x0, 0x1, VpciDevType::Physical), // 00:00.1 - pci_dev!(0x0, 0x0, 0x2, VpciDevType::Physical), // 00:00.2 - pci_dev!(0x0, 0x0, 0x3, VpciDevType::Physical), // 00:00.3 - pci_dev!(0x0, 0x4, 0x0, VpciDevType::Physical), // 00:04.0 - pci_dev!(0x0, 0x4, 0x1, VpciDevType::Physical), // 00:04.1 - pci_dev!(0x0, 0x5, 0x0, VpciDevType::Physical), // 00:05.0 - pci_dev!(0x0, 0x5, 0x1, VpciDevType::Physical), // 00:05.1 - // pci_dev!(0x0, 0x6, 0x0, VpciDevType::Physical), // 00:06.0 - // pci_dev!(0x0, 0x6, 0x1, VpciDevType::Physical), // 00:06.1 - // pci_dev!(0x0, 0x6, 0x2, VpciDevType::Physical), // 00:06.2 - pci_dev!(0x0, 0x7, 0x0, VpciDevType::Physical), // 00:07.0 - pci_dev!(0x0, 0x8, 0x0, VpciDevType::Physical), // 00:08.0 - pci_dev!(0x0, 0x9, 0x0, VpciDevType::Physical), // 00:09.0 - pci_dev!(0x0, 0xa, 0x0, VpciDevType::Physical), // 00:0a.0 - pci_dev!(0x0, 0xb, 0x0, VpciDevType::Physical), // 00:0b.0 - pci_dev!(0x0, 0xc, 0x0, VpciDevType::Physical), // 00:0c.0 - pci_dev!(0x0, 0xd, 0x0, VpciDevType::Physical), // 00:0d.0 - pci_dev!(0x0, 0xf, 0x0, VpciDevType::Physical), // 00:0f.0 - pci_dev!(0x0, 0x10, 0x0, VpciDevType::Physical), // 00:10.0 - pci_dev!(0x0, 0x13, 0x0, VpciDevType::Physical), // 00:13.0 - pci_dev!(0x0, 0x16, 0x0, VpciDevType::Physical), // 00:16.0 - pci_dev!(0x0, 0x19, 0x0, VpciDevType::Physical), // 00:19.0 - pci_dev!(0x2, 0x0, 0x0, VpciDevType::Physical), // 02:00.0 - pci_dev!(0x5, 0x0, 0x0, VpciDevType::Physical), // 05:00.0 - pci_dev!(0x6, 0x0, 0x0, VpciDevType::Physical), // 06:00.0 + pci_dev!(0x0, 0x0, 0x0, 0x0, VpciDevType::Physical), // 00:00.0 + pci_dev!(0x0, 0x0, 0x0, 0x1, VpciDevType::Physical), // 00:00.1 + pci_dev!(0x0, 0x0, 0x0, 0x2, VpciDevType::Physical), // 00:00.2 + pci_dev!(0x0, 0x0, 0x0, 0x3, VpciDevType::Physical), // 00:00.3 + pci_dev!(0x0, 0x0, 0x4, 0x0, VpciDevType::Physical), // 00:04.0 + pci_dev!(0x0, 0x0, 0x4, 0x1, VpciDevType::Physical), // 00:04.1 + pci_dev!(0x0, 0x0, 0x5, 0x0, VpciDevType::Physical), // 00:05.0 + pci_dev!(0x0, 0x0, 0x5, 0x1, VpciDevType::Physical), // 00:05.1 + // pci_dev!(0x0, 0x0, 0x6, 0x0, VpciDevType::Physical), // 00:06.0 + // pci_dev!(0x0, 0x0, 0x6, 0x1, VpciDevType::Physical), // 00:06.1 + // pci_dev!(0x0, 0x0, 0x6, 0x2, VpciDevType::Physical), // 00:06.2 + pci_dev!(0x0, 0x0, 0x7, 0x0, VpciDevType::Physical), // 00:07.0 + pci_dev!(0x0, 0x0, 0x8, 0x0, VpciDevType::Physical), // 00:08.0 + pci_dev!(0x0, 0x0, 0x9, 0x0, VpciDevType::Physical), // 00:09.0 + pci_dev!(0x0, 0x0, 0xa, 0x0, VpciDevType::Physical), // 00:0a.0 + pci_dev!(0x0, 0x0, 0xb, 0x0, VpciDevType::Physical), // 00:0b.0 + pci_dev!(0x0, 0x0, 0xc, 0x0, VpciDevType::Physical), // 00:0c.0 + pci_dev!(0x0, 0x0, 0xd, 0x0, VpciDevType::Physical), // 00:0d.0 + pci_dev!(0x0, 0x0, 0xf, 0x0, VpciDevType::Physical), // 00:0f.0 + pci_dev!(0x0, 0x0, 0x10, 0x0, VpciDevType::Physical), // 00:10.0 + pci_dev!(0x0, 0x0, 0x13, 0x0, VpciDevType::Physical), // 00:13.0 + pci_dev!(0x0, 0x0, 0x16, 0x0, VpciDevType::Physical), // 00:16.0 + pci_dev!(0x0, 0x0, 0x19, 0x0, VpciDevType::Physical), // 00:19.0 + pci_dev!(0x0, 0x2, 0x0, 0x0, VpciDevType::Physical), // 02:00.0 + pci_dev!(0x0, 0x5, 0x0, 0x0, VpciDevType::Physical), // 05:00.0 + pci_dev!(0x0, 0x6, 0x0, 0x0, VpciDevType::Physical), // 06:00.0 ]; diff --git a/platform/loongarch64/ls3a5000/configs/zone1-linux.json b/platform/loongarch64/ls3a5000/configs/zone1-linux.json index 0b5fb081..995d42ab 100644 --- a/platform/loongarch64/ls3a5000/configs/zone1-linux.json +++ b/platform/loongarch64/ls3a5000/configs/zone1-linux.json @@ -126,7 +126,10 @@ }], "num_pci_devs": 1, "alloc_pci_devs": [{ - "bdf": "0x601", - "vbdf": "0x601" + "domain": "0x0", + "bus": "0x6", + "device": "0x1", + "function": "0x0", + "dev_type": "0" }] } \ 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 be533e7d..ef26e27e 100644 --- a/platform/loongarch64/ls3a5000/configs/zone2-linux.json +++ b/platform/loongarch64/ls3a5000/configs/zone2-linux.json @@ -114,7 +114,10 @@ }], "num_pci_devs": 1, "alloc_pci_devs": [{ - "bdf": "0x602", - "vbdf": "0x602" + "domain": "0x0", + "bus": "0x6", + "device": "0x2", + "function": "0x0", + "dev_type": "0" }] } \ 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 9d5d235f..a90f3b2e 100644 --- a/platform/loongarch64/ls3a5000/configs/zone3-linux.json +++ b/platform/loongarch64/ls3a5000/configs/zone3-linux.json @@ -114,7 +114,10 @@ }], "num_pci_devs": 1, "alloc_pci_devs": [{ - "bdf": "0x603", - "vbdf": "0x603" + "domain": "0x0", + "bus": "0x6", + "device": "0x3", + "function": "0x0", + "dev_type": "0" }] } \ No newline at end of file diff --git a/platform/loongarch64/ls3a6000/board.rs b/platform/loongarch64/ls3a6000/board.rs index 5cf739e8..f78cfd1b 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -16,7 +16,6 @@ // use crate::{arch::zone::HvArchZoneConfig, config::*, pci::vpci_dev::VpciDevType}; use crate::pci_dev; -use crate::pci::vpci_dev::VpciDevType; pub const BOARD_NAME: &str = "ls3a5000"; @@ -171,6 +170,7 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ mem64_base: 0x60000000, mem64_size: 0x20000000, pci_mem64_base: 0x60000000, + domain: 0x0, } ]; @@ -184,32 +184,32 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ /* BUS 6 on X4 slot */ /* 06:00.0, 06:00.1, 06:00.2, 06:00.3 net */ pub const ROOT_PCI_DEVS: [HvPciDevConfig; 26] = [ - pci_dev!(0x0, 0x0, 0x0, VpciDevType::Physical), // 00:00.0 - pci_dev!(0x0, 0x0, 0x1, VpciDevType::Physical), // 00:00.1 - pci_dev!(0x0, 0x0, 0x2, VpciDevType::Physical), // 00:00.2 - pci_dev!(0x0, 0x0, 0x3, VpciDevType::Physical), // 00:00.3 - pci_dev!(0x0, 0x4, 0x0, VpciDevType::Physical), // 00:04.0 - pci_dev!(0x0, 0x4, 0x1, VpciDevType::Physical), // 00:04.1 - pci_dev!(0x0, 0x5, 0x0, VpciDevType::Physical), // 00:05.0 - pci_dev!(0x0, 0x5, 0x1, VpciDevType::Physical), // 00:05.1 - pci_dev!(0x0, 0x6, 0x0, VpciDevType::Physical), // 00:06.0 - pci_dev!(0x0, 0x6, 0x1, VpciDevType::Physical), // 00:06.1 - pci_dev!(0x0, 0x6, 0x2, VpciDevType::Physical), // 00:06.2 - pci_dev!(0x0, 0x7, 0x0, VpciDevType::Physical), // 00:07.0 - pci_dev!(0x0, 0x8, 0x0, VpciDevType::Physical), // 00:08.0 - pci_dev!(0x0, 0x9, 0x0, VpciDevType::Physical), // 00:09.0 - pci_dev!(0x0, 0xa, 0x0, VpciDevType::Physical), // 00:0a.0 - pci_dev!(0x0, 0xb, 0x0, VpciDevType::Physical), // 00:0b.0 - pci_dev!(0x0, 0xc, 0x0, VpciDevType::Physical), // 00:0c.0 - pci_dev!(0x0, 0xd, 0x0, VpciDevType::Physical), // 00:0d.0 - pci_dev!(0x0, 0xf, 0x0, VpciDevType::Physical), // 00:0f.0 - pci_dev!(0x0, 0x10, 0x0, VpciDevType::Physical), // 00:10.0 - pci_dev!(0x0, 0x13, 0x0, VpciDevType::Physical), // 00:13.0 - pci_dev!(0x0, 0x16, 0x0, VpciDevType::Physical), // 00:16.0 - pci_dev!(0x0, 0x19, 0x0, VpciDevType::Physical), // 00:19.0 - pci_dev!(0x2, 0x0, 0x0, VpciDevType::Physical), // 02:00.0 - pci_dev!(0x5, 0x0, 0x0, VpciDevType::Physical), // 05:00.0 - pci_dev!(0x6, 0x0, 0x0, VpciDevType::Physical), // 06:00.0 + pci_dev!(0x0, 0x0, 0x0, 0x0, VpciDevType::Physical), // 00:00.0 + pci_dev!(0x0, 0x0, 0x0, 0x1, VpciDevType::Physical), // 00:00.1 + pci_dev!(0x0, 0x0, 0x0, 0x2, VpciDevType::Physical), // 00:00.2 + pci_dev!(0x0, 0x0, 0x0, 0x3, VpciDevType::Physical), // 00:00.3 + pci_dev!(0x0, 0x0, 0x4, 0x0, VpciDevType::Physical), // 00:04.0 + pci_dev!(0x0, 0x0, 0x4, 0x1, VpciDevType::Physical), // 00:04.1 + pci_dev!(0x0, 0x0, 0x5, 0x0, VpciDevType::Physical), // 00:05.0 + pci_dev!(0x0, 0x0, 0x5, 0x1, VpciDevType::Physical), // 00:05.1 + pci_dev!(0x0, 0x0, 0x6, 0x0, VpciDevType::Physical), // 00:06.0 + pci_dev!(0x0, 0x0, 0x6, 0x1, VpciDevType::Physical), // 00:06.1 + pci_dev!(0x0, 0x0, 0x6, 0x2, VpciDevType::Physical), // 00:06.2 + pci_dev!(0x0, 0x0, 0x7, 0x0, VpciDevType::Physical), // 00:07.0 + pci_dev!(0x0, 0x0, 0x8, 0x0, VpciDevType::Physical), // 00:08.0 + pci_dev!(0x0, 0x0, 0x9, 0x0, VpciDevType::Physical), // 00:09.0 + pci_dev!(0x0, 0x0, 0xa, 0x0, VpciDevType::Physical), // 00:0a.0 + pci_dev!(0x0, 0x0, 0xb, 0x0, VpciDevType::Physical), // 00:0b.0 + pci_dev!(0x0, 0x0, 0xc, 0x0, VpciDevType::Physical), // 00:0c.0 + pci_dev!(0x0, 0x0, 0xd, 0x0, VpciDevType::Physical), // 00:0d.0 + pci_dev!(0x0, 0x0, 0xf, 0x0, VpciDevType::Physical), // 00:0f.0 + pci_dev!(0x0, 0x0, 0x10, 0x0, VpciDevType::Physical), // 00:10.0 + pci_dev!(0x0, 0x0, 0x13, 0x0, VpciDevType::Physical), // 00:13.0 + pci_dev!(0x0, 0x0, 0x16, 0x0, VpciDevType::Physical), // 00:16.0 + pci_dev!(0x0, 0x0, 0x19, 0x0, VpciDevType::Physical), // 00:19.0 + pci_dev!(0x0, 0x2, 0x0, 0x0, VpciDevType::Physical), // 02:00.0 + pci_dev!(0x0, 0x5, 0x0, 0x0, VpciDevType::Physical), // 05:00.0 + pci_dev!(0x0, 0x6, 0x0, 0x0, VpciDevType::Physical), // 06:00.0 ]; diff --git a/platform/loongarch64/ls3a6000/configs/zone1-linux.json b/platform/loongarch64/ls3a6000/configs/zone1-linux.json index 0b5fb081..995d42ab 100644 --- a/platform/loongarch64/ls3a6000/configs/zone1-linux.json +++ b/platform/loongarch64/ls3a6000/configs/zone1-linux.json @@ -126,7 +126,10 @@ }], "num_pci_devs": 1, "alloc_pci_devs": [{ - "bdf": "0x601", - "vbdf": "0x601" + "domain": "0x0", + "bus": "0x6", + "device": "0x1", + "function": "0x0", + "dev_type": "0" }] } \ No newline at end of file diff --git a/platform/loongarch64/ls3a6000/configs/zone2-linux.json b/platform/loongarch64/ls3a6000/configs/zone2-linux.json index be533e7d..ef26e27e 100644 --- a/platform/loongarch64/ls3a6000/configs/zone2-linux.json +++ b/platform/loongarch64/ls3a6000/configs/zone2-linux.json @@ -114,7 +114,10 @@ }], "num_pci_devs": 1, "alloc_pci_devs": [{ - "bdf": "0x602", - "vbdf": "0x602" + "domain": "0x0", + "bus": "0x6", + "device": "0x2", + "function": "0x0", + "dev_type": "0" }] } \ 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 9d5d235f..a90f3b2e 100644 --- a/platform/loongarch64/ls3a6000/configs/zone3-linux.json +++ b/platform/loongarch64/ls3a6000/configs/zone3-linux.json @@ -114,7 +114,10 @@ }], "num_pci_devs": 1, "alloc_pci_devs": [{ - "bdf": "0x603", - "vbdf": "0x603" + "domain": "0x0", + "bus": "0x6", + "device": "0x3", + "function": "0x0", + "dev_type": "0" }] } \ No newline at end of file diff --git a/platform/x86_64/qemu/board.rs b/platform/x86_64/qemu/board.rs index d49a1781..ab42fc3a 100644 --- a/platform/x86_64/qemu/board.rs +++ b/platform/x86_64/qemu/board.rs @@ -123,18 +123,19 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { mem64_base: 0x0, mem64_size: 0x0, pci_mem64_base: 0x0, + domain: 0x0, }]; pub const ROOT_PCI_MAX_BUS: usize = 1; pub const ROOT_PCI_DEVS: [HvPciDevConfig; 8] = [ - pci_dev!(0x0, 0x0, 0x0, VpciDevType::Physical), // host bridge - pci_dev!(0x0, 0x1, 0x0, VpciDevType::Physical), // VGA controller - pci_dev!(0x0, 0x2, 0x0, VpciDevType::Physical), // Ethernet controller - pci_dev!(0x0, 0x3, 0x0, VpciDevType::Physical), // PCI bridge - pci_dev!(0x0, 0x1f, 0x0, VpciDevType::Physical), // ISA bridge - pci_dev!(0x0, 0x1f, 0x2, VpciDevType::Physical), // SATA controller - pci_dev!(0x0, 0x1f, 0x3, VpciDevType::Physical), // SMBus - pci_dev!(0x1, 0x0, 0x0, VpciDevType::Physical), // SCSI controller + pci_dev!(0x0, 0x0, 0x0, 0x0, VpciDevType::Physical), // host bridge + pci_dev!(0x0, 0x0, 0x1, 0x0, VpciDevType::Physical), // VGA controller + pci_dev!(0x0, 0x0, 0x2, 0x0, VpciDevType::Physical), // Ethernet controller + pci_dev!(0x0, 0x0, 0x3, 0x0, VpciDevType::Physical), // PCI bridge + pci_dev!(0x0, 0x0, 0x1f, 0x0, VpciDevType::Physical), // ISA bridge + pci_dev!(0x0, 0x0, 0x1f, 0x2, VpciDevType::Physical), // SATA controller + pci_dev!(0x0, 0x0, 0x1f, 0x3, VpciDevType::Physical), // SMBus + pci_dev!(0x0, 0x1, 0x0, 0x0, VpciDevType::Physical), // SCSI controller ]; #[cfg(all(feature = "graphics"))] From 33ba6145ae1b84cfbc7a516a514086f3620dd312 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 1 Jan 2026 00:21:54 +0800 Subject: [PATCH 068/109] adjust log level for pcie --- src/memory/mm.rs | 9 +++++++++ src/pci/pci_access.rs | 2 +- src/pci/pci_handler.rs | 12 ++++++------ src/pci/pci_struct.rs | 32 +++++++++++++++++--------------- src/pci/vpci_dev/mod.rs | 10 +++++++++- src/pci/vpci_dev/standard.rs | 16 ++++++++++------ 6 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/memory/mm.rs b/src/memory/mm.rs index 943a7714..1edcbcef 100644 --- a/src/memory/mm.rs +++ b/src/memory/mm.rs @@ -145,6 +145,15 @@ where Ok(()) } + pub fn try_insert_quiet(&mut self, region: MemoryRegion) -> HvResult { + if !self.test_free_area(®ion) { + return Ok(()); + } + + self.insert(region)?; + Ok(()) + } + /// Find and remove memory region which starts from `start` and `size` pub fn delete(&mut self, start: PT::VA, size: usize) -> HvResult { if let Entry::Occupied(e) = self.regions.entry(start) { diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 54daff63..1afea223 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -600,7 +600,7 @@ pub trait PciBarRW: PciRWBase { let mut slot = 0u8; while slot < self.bar_limit() { - warn!("parse bar slot {}", slot); + // info!("parse bar slot {}", slot); let value = self.read_bar(slot).unwrap(); if !value.get_bit(0) { diff --git a/src/pci/pci_handler.rs b/src/pci/pci_handler.rs index 5393cb04..5d0fd8af 100644 --- a/src/pci/pci_handler.rs +++ b/src/pci/pci_handler.rs @@ -26,9 +26,9 @@ use crate::pci::config_accessors::{ macro_rules! pci_log { ($($arg:tt)*) => { - info!($($arg)*); + // info!($($arg)*); // To switch to debug level, change the line above to: - // debug!($($arg)*); + debug!($($arg)*); }; } @@ -295,9 +295,9 @@ fn handle_endpoint_access( .try_delete(old_vaddr.try_into().unwrap(), bar_size as usize) .is_ok() { - warn!("delete bar {}: can not found 0x{:x}", slot, old_vaddr); + // warn!("delete bar {}: can not found 0x{:x}", slot, old_vaddr); } - gpm.try_insert(MemoryRegion::new_with_offset_mapper( + gpm.try_insert_quiet(MemoryRegion::new_with_offset_mapper( new_vaddr as GuestPhysAddr, paddr as HostPhysAddr, bar_size as _, @@ -410,9 +410,9 @@ fn handle_endpoint_access( .try_delete(old_vaddr.try_into().unwrap(), rom_size as usize) .is_ok() { - warn!("delete rom bar: can not found 0x{:x}", old_vaddr); + // warn!("delete rom bar: can not found 0x{:x}", old_vaddr); } - gpm.try_insert(MemoryRegion::new_with_offset_mapper( + gpm.try_insert_quiet(MemoryRegion::new_with_offset_mapper( new_vaddr as GuestPhysAddr, paddr as HostPhysAddr, rom_size as _, diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index c5f826b6..ef7610e2 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -638,8 +638,8 @@ impl Debug for VirtualPciConfigSpace { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, - "\n bdf {:#?}\n base {:#x}\n type {:#?}\n {:#?} {:#?}", - self.bdf, self.base, self.config_type, self.bararr, self.rom + "\n bdf {:#?}\n base {:#x}\n type {:#?}\n {:#?}\n {:#?}\n {:#?}", + self.bdf, self.base, self.config_type, self.bararr, self.rom, self.capabilities ) } } @@ -983,31 +983,31 @@ impl PciIterator { let address = self.address(parent_bus, bdf); let pci_addr_base = self.get_pci_addr_base(parent_bus, bdf); - info!("get node {:x} {:#?}", address, bdf); + // info!("get node {:x} {:#?}", address, bdf); let region = PciConfigMmio::new(address, CONFIG_LENTH); let pci_header = PciConfigHeader::new_with_region(region); let (vender_id, device_id) = pci_header.id(); - warn!("vender_id {:#x}", vender_id); + // warn!("vender_id {:#x}", vender_id); // Check if device exists if vender_id == 0xffff || self.accessor.skip_device(bdf) { if function == 0 { // Function 0 doesn't exist, so device doesn't exist at all // Skip all functions and move to next device - warn!( - "get none - device not present (vendor_id=0xffff) at {:#?}", - bdf - ); + // info!( + // "get none - device not present (vendor_id=0xffff) at {:#?}", + // bdf + // ); self.function = 0; self.is_mulitple_function = false; } else { // Function > 0 doesn't exist, but device might have other functions - warn!( - "get none - function not present (vendor_id=0xffff) at {:#?}", - bdf - ); + // warn!( + // "get none - function not present (vendor_id=0xffff) at {:#?}", + // bdf + // ); } return None; } @@ -1039,7 +1039,7 @@ impl PciIterator { let bararr = Self::bar_mem_init(ep.bar_limit().into(), &mut self.allocator, &mut ep); - info!("get node bar mem init end {:#?}", bararr); + // info!("get node bar mem init end {:#?}", bararr); let ep = Arc::new(ep); let mut node = VirtualPciConfigSpace::endpoint( @@ -1095,7 +1095,10 @@ impl PciIterator { fn rom_init(dev: &mut D) -> PciMem { let mut rom = dev.parse_rom(); - rom.set_virtual_value(rom.get_value() as u64); + if rom.get_type() == PciMemType::Rom { + rom.set_value(rom.get_value() as u64); + rom.set_virtual_value(rom.get_value() as u64); + } rom } @@ -1250,7 +1253,6 @@ impl Iterator for PciIterator { type Item = VirtualPciConfigSpace; fn next(&mut self) -> Option { - info!("pci dev next"); while !self.is_finish { if let Some(mut node) = self.get_node() { node.config_value_init(); diff --git a/src/pci/vpci_dev/mod.rs b/src/pci/vpci_dev/mod.rs index f77fbddd..58c959f0 100644 --- a/src/pci/vpci_dev/mod.rs +++ b/src/pci/vpci_dev/mod.rs @@ -9,6 +9,14 @@ use crate::pci::PciConfigAddress; use bitvec::array::BitArray; use bitvec::{order::Lsb0, BitArr}; +macro_rules! pci_virt_log { + ($($arg:tt)*) => { + // info!($($arg)*); + // To switch to debug level, change the line above to: + debug!($($arg)*); + }; +} + // Standard virtual device configuration space defaults pub(crate) const STANDARD_CFG_SIZE: usize = 0x80; pub(crate) const DEFAULT_CSPACE_U32: [u32; STANDARD_CFG_SIZE / 4] = { @@ -115,7 +123,7 @@ pub(super) fn vpci_dev_read_cfg( PciConfigAccessStatus::Done(value) => Ok(value), PciConfigAccessStatus::Default => { // If this is a standard virtual device, read from DEFAULT_CSPACE_U32 - warn!("vpci_dev_read_cfg: default config space read, offset {:#x}, size {:#x}", offset, size); + pci_virt_log!("vpci_dev_read_cfg: default config space read, offset {:#x}, size {:#x}", offset, size); if offset < STANDARD_CFG_SIZE as PciConfigAddress { let u32_offset = (offset as usize) / 4; let u32_value = DEFAULT_CSPACE_U32[u32_offset]; diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index 313ca257..b98ce418 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -25,9 +25,10 @@ impl VpciDeviceHandler for StandardHandler { offset: PciConfigAddress, size: usize, ) -> HvResult { - info!( + pci_virt_log!( "virt pci standard read_cfg, offset {:#x}, size {:#x}", - offset, size + offset, + size ); match EndpointField::from(offset as usize, size) { EndpointField::ID => { @@ -60,9 +61,11 @@ impl VpciDeviceHandler for StandardHandler { size: usize, value: usize, ) -> HvResult { - info!( + pci_virt_log!( "virt pci standard write_cfg, offset {:#x}, size {:#x}, value {:#x}", - offset, size, value + offset, + size, + value ); match EndpointField::from(offset as usize, size) { EndpointField::Command => { @@ -78,9 +81,10 @@ impl VpciDeviceHandler for StandardHandler { } else { let zone = this_zone(); let mut guard = zone.write(); - info!( + pci_virt_log!( "virtual pci standard write_cfg, register mmio region {:#x}, size {:#x}", - value, bar_size + value, + bar_size ); guard.mmio_region_register( value as usize, From ed8f9a8bcf5faa8ef807ce1112cbcf3a433619a7 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 1 Jan 2026 00:39:05 +0800 Subject: [PATCH 069/109] update magic version --- src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index 6e571ef3..7b4bad30 100644 --- a/src/config.rs +++ b/src/config.rs @@ -23,7 +23,7 @@ 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 = 0x4; +pub const CONFIG_MAGIC_VERSION: usize = 0x5; pub const CONFIG_MAX_MEMORY_REGIONS: usize = 64; pub type BitmapWord = u32; From e139d5546d67aa2f3352eb5b6ae256967d387949 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 1 Jan 2026 01:21:02 +0800 Subject: [PATCH 070/109] add license and fix warning --- src/arch/aarch64/consts.rs | 6 ++-- src/pci/config_accessors/dwc.rs | 13 ++++---- src/pci/config_accessors/dwc_atu.rs | 2 +- src/pci/config_accessors/ecam.rs | 5 ++- src/pci/config_accessors/loongarch64.rs | 5 ++- src/pci/config_accessors/mod.rs | 2 +- src/pci/mem_alloc.rs | 1 + src/pci/mod.rs | 2 ++ src/pci/pci_access.rs | 34 ++++--------------- src/pci/pci_config.rs | 25 +++++++++----- src/pci/pci_handler.rs | 44 ++++++++++++++++++------- src/pci/pci_struct.rs | 7 ++-- src/pci/pci_test.rs | 10 ++++-- 13 files changed, 86 insertions(+), 70 deletions(-) diff --git a/src/arch/aarch64/consts.rs b/src/arch/aarch64/consts.rs index 5bfd0825..68e853a8 100644 --- a/src/arch/aarch64/consts.rs +++ b/src/arch/aarch64/consts.rs @@ -15,6 +15,6 @@ // ForeverYolo <2572131118@qq.com> // PCI constants -pub const HV_ADDR_PREFIX: u64 = 0; -pub const LOONG_HT_PREFIX: u64 = 0; -pub const BDF_SHIFT: usize = 12; +// pub const HV_ADDR_PREFIX: u64 = 0; +// pub const LOONG_HT_PREFIX: u64 = 0; +// pub const BDF_SHIFT: usize = 12; diff --git a/src/pci/config_accessors/dwc.rs b/src/pci/config_accessors/dwc.rs index 52771a2b..8c609480 100644 --- a/src/pci/config_accessors/dwc.rs +++ b/src/pci/config_accessors/dwc.rs @@ -15,7 +15,6 @@ // use alloc::sync::Arc; -use bit_field::BitField; use super::{ dwc_atu::{AtuConfig, AtuType, AtuUnroll, ATU_UNUSED}, @@ -24,7 +23,7 @@ use super::{ use crate::{ config::HvDwcAtuConfig, - error::{HvErrorNum::*, HvResult}, + error::HvResult, pci::{ pci_access::{PciRW, PciRWBase}, pci_struct::{Bdf, RootComplex}, @@ -121,13 +120,13 @@ impl DwcConfigAccessor { } impl PciConfigAccessor for DwcConfigAccessor { - fn get_pci_addr_base(&self, bdf: Bdf, parent_bus: u8) -> HvResult { + fn get_pci_addr_base(&self, bdf: Bdf) -> HvResult { let bus = bdf.bus() as PciConfigAddress; let device = bdf.device() as PciConfigAddress; let function = bdf.function() as PciConfigAddress; let pci_addr = (bus << 24) + (device << 19) + (function << 16); - info!("pci_addr {:#x}", pci_addr); + // info!("pci_addr {:#x}", pci_addr); let address = if bus == self.root_bus.into() { // Root bus: use DBI directly, no ATU configuration needed self.dbi.base @@ -141,14 +140,14 @@ impl PciConfigAccessor for DwcConfigAccessor { fn get_physical_address( &self, bdf: Bdf, - offset: PciConfigAddress, + _offset: PciConfigAddress, parent_bus: u8, ) -> HvResult { let bus = bdf.bus() as PciConfigAddress; let device = bdf.device() as PciConfigAddress; let function = bdf.function() as PciConfigAddress; - warn!("parent_bus {} self.root_bus {}", parent_bus, self.root_bus); + // warn!("parent_bus {} self.root_bus {}", parent_bus, self.root_bus); let pci_addr = (bus << 24) + (device << 19) + (function << 16); @@ -182,7 +181,7 @@ impl PciConfigAccessor for DwcConfigAccessor { // On root bus, only device 0 (slot 0) is valid, devices with dev > 0 should be skipped // This matches Linux kernel's dw_pcie_valid_device() behavior if bdf.bus() == self.root_bus && bdf.device() > 0 { - warn!("skip_device {:#?}", bdf); + // warn!("skip_device {:#?}", bdf); return true; } false diff --git a/src/pci/config_accessors/dwc_atu.rs b/src/pci/config_accessors/dwc_atu.rs index 08b3847a..f0353f3a 100644 --- a/src/pci/config_accessors/dwc_atu.rs +++ b/src/pci/config_accessors/dwc_atu.rs @@ -18,7 +18,7 @@ use super::dwc::DwcConfigRegion; use core::{fmt, fmt::Debug}; use crate::{ - error::{HvErrorNum::*, HvResult}, + error::HvResult, pci::{pci_access::PciRW, PciConfigAddress}, }; diff --git a/src/pci/config_accessors/ecam.rs b/src/pci/config_accessors/ecam.rs index 2545bc0e..bbd7cb81 100644 --- a/src/pci/config_accessors/ecam.rs +++ b/src/pci/config_accessors/ecam.rs @@ -15,9 +15,8 @@ // use alloc::sync::Arc; -use bit_field::BitField; -use super::{PciConfigAccessor, PciConfigMmio, PciRegion}; +use super::{PciConfigAccessor, PciConfigMmio}; use crate::{ error::HvResult, @@ -50,7 +49,7 @@ impl EcamConfigAccessor { } impl PciConfigAccessor for EcamConfigAccessor { - fn get_pci_addr_base(&self, bdf: Bdf, parent_bus: u8) -> HvResult { + fn get_pci_addr_base(&self, bdf: Bdf) -> HvResult { let bus = bdf.bus() as PciConfigAddress; let device = bdf.device() as PciConfigAddress; let function = bdf.function() as PciConfigAddress; diff --git a/src/pci/config_accessors/loongarch64.rs b/src/pci/config_accessors/loongarch64.rs index dea4d12e..cf60e437 100644 --- a/src/pci/config_accessors/loongarch64.rs +++ b/src/pci/config_accessors/loongarch64.rs @@ -15,9 +15,8 @@ // use alloc::sync::Arc; -use bit_field::BitField; -use super::{PciConfigAccessor, PciConfigMmio, PciRegion}; +use super::{PciConfigAccessor, PciConfigMmio}; use crate::{ error::HvResult, @@ -60,7 +59,7 @@ impl LoongArchConfigAccessor { } impl PciConfigAccessor for LoongArchConfigAccessor { - fn get_pci_addr_base(&self, bdf: Bdf, parent_bus: u8) -> HvResult { + fn get_pci_addr_base(&self, bdf: Bdf) -> HvResult { let bus = bdf.bus() as PciConfigAddress; let device = bdf.device() as PciConfigAddress; let function = bdf.function() as PciConfigAddress; diff --git a/src/pci/config_accessors/mod.rs b/src/pci/config_accessors/mod.rs index e7eeeb55..544505a6 100644 --- a/src/pci/config_accessors/mod.rs +++ b/src/pci/config_accessors/mod.rs @@ -125,7 +125,7 @@ impl PciRegion for PciConfigMmio { } pub trait PciConfigAccessor: Send + Sync + core::fmt::Debug { - fn get_pci_addr_base(&self, bdf: Bdf, parent_bus: u8) -> HvResult; + fn get_pci_addr_base(&self, bdf: Bdf) -> HvResult; fn get_physical_address( &self, diff --git a/src/pci/mem_alloc.rs b/src/pci/mem_alloc.rs index 9ed793d2..c55fed80 100644 --- a/src/pci/mem_alloc.rs +++ b/src/pci/mem_alloc.rs @@ -13,6 +13,7 @@ // // Authors: // + use core::{fmt::Debug, ops::Range}; pub type Mem32Address = u64; diff --git a/src/pci/mod.rs b/src/pci/mod.rs index fcf0a4f9..7217cce5 100644 --- a/src/pci/mod.rs +++ b/src/pci/mod.rs @@ -13,6 +13,7 @@ // // Authors: // + #![allow(dead_code)] pub mod config_accessors; pub mod mem_alloc; @@ -22,6 +23,7 @@ pub mod pci_handler; pub mod pci_struct; pub mod vpci_dev; +#[cfg(test)] pub mod pci_test; pub type PciConfigAddress = u64; diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 1afea223..d2bff12c 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -13,8 +13,8 @@ // // Authors: // + // #![allow(dead_code)] -use alloc::string::String; use bit_field::BitField; use bitflags::bitflags; use core::{ @@ -25,35 +25,13 @@ use core::{ use super::{ config_accessors::{PciConfigMmio, PciRegion}, - pci_struct::ArcRwLockVirtualPciConfigSpace, PciConfigAddress, }; use crate::{ - error::HvResult, - memory::{ - mmio_perform_access, GuestPhysAddr, HostPhysAddr, MMIOAccess, MemFlags, MemoryRegion, - MemorySet, - }, - pci::{pci_config::GLOBAL_PCIE_LIST, pci_struct::BIT_LENTH}, - percpu::this_zone, - zone::{is_this_root_zone, this_zone_id}, -}; - -#[cfg(feature = "dwc_pcie")] -use crate::pci::config_accessors::{ - dwc::DwcConfigRegionBackend, - dwc_atu::{ - AtuConfig, AtuType, AtuUnroll, ATU_BASE, ATU_ENABLE_BIT, ATU_REGION_SIZE, - PCIE_ATU_UNR_LIMIT, PCIE_ATU_UNR_LOWER_BASE, PCIE_ATU_UNR_LOWER_TARGET, - PCIE_ATU_UNR_REGION_CTRL1, PCIE_ATU_UNR_REGION_CTRL2, PCIE_ATU_UNR_UPPER_BASE, - PCIE_ATU_UNR_UPPER_LIMIT, PCIE_ATU_UNR_UPPER_TARGET, - }, - PciRegionMmio, + error::HvResult }; -use crate::pci::vpci_dev::VpciDevType; - pub type VendorId = u16; pub type DeviceId = u16; pub type DeviceRevision = u8; @@ -222,10 +200,10 @@ impl PciMem { */ 0 } - _ => { - warn!("{:#?} not support size", self.bar_type); - 0 - } + // _ => { + // warn!("{:#?} not support size", self.bar_type); + // 0 + // } } } diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 0de9122e..7eea48d1 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -13,17 +13,23 @@ // // Authors: // + use alloc::collections::btree_map::BTreeMap; use spin::{Lazy, Mutex}; use crate::{ - arch::iommu::iommu_add_device, config::{HvPciConfig, HvPciDevConfig, CONFIG_MAX_PCI_DEV, CONFIG_PCI_BUS_MAXNUM}, error::HvResult, pci::pci_struct::{ArcRwLockVirtualPciConfigSpace, Bdf}, zone::Zone, }; +#[cfg(any( + all(feature = "iommu", target_arch = "aarch64"), + target_arch = "x86_64" +))] +use crate::arch::iommu::iommu_add_device; + #[cfg(feature = "ecam_pcie")] use crate::pci::{ pci_struct::VirtualPciConfigSpace, @@ -36,19 +42,22 @@ use crate::pci::{ feature = "loongarch64_pcie" ))] use crate::pci::{ - mem_alloc::BaseAllocator, pci_handler::mmio_vpci_handler, pci_struct::RootComplex, - PciConfigAddress, + mem_alloc::BaseAllocator, pci_struct::RootComplex, }; + +#[cfg(feature = "ecam_pcie")] +use crate::pci::pci_handler::mmio_vpci_handler; #[cfg(feature = "dwc_pcie")] use crate::{ memory::mmio_generic_handler, pci::{ config_accessors::{ dwc::DwcConfigRegionBackend, - dwc_atu::{AtuConfig, AtuType}, + dwc_atu::AtuConfig, PciRegionMmio, }, pci_handler::{mmio_dwc_cfg_handler, mmio_dwc_io_handler, mmio_vpci_handler_dbi}, + PciConfigAddress, }, platform, }; @@ -70,7 +79,7 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { feature = "dwc_pcie", feature = "loongarch64_pcie" ))] - for (index, rootcomplex_config) in pci_config.iter().enumerate() { + for (_index, rootcomplex_config) in pci_config.iter().enumerate() { /* empty config */ if rootcomplex_config.ecam_base == 0 { warn!("empty pcie config"); @@ -163,7 +172,7 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { impl Zone { pub fn guest_pci_init( &mut self, - zone_id: usize, + _zone_id: usize, alloc_pci_devs: &[HvPciDevConfig; CONFIG_MAX_PCI_DEV], num_pci_devs: u64, pci_config: &[HvPciConfig], @@ -263,7 +272,7 @@ impl Zone { let device_id = (dev_config.bus as usize) << 8 | (dev_config.device as usize) << 3 | dev_config.function as usize; - iommu_add_device(zone_id, device_id as _, iommu_pt_addr); + iommu_add_device(_zone_id, device_id as _, iommu_pt_addr); } // Insert device into vpci_bus with calculated vbdf @@ -416,7 +425,7 @@ impl Zone { mmio_vpci_direct_handler, rootcomplex_config.ecam_base as usize, ); - self.page_table_emergency( + let _ = self.page_table_emergency( rootcomplex_config.ecam_base as usize, rootcomplex_config.ecam_size as usize, ); diff --git a/src/pci/pci_handler.rs b/src/pci/pci_handler.rs index 5d0fd8af..960d15e1 100644 --- a/src/pci/pci_handler.rs +++ b/src/pci/pci_handler.rs @@ -1,10 +1,26 @@ +// 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::string::String; use crate::error::HvResult; use crate::memory::MMIOAccess; -use crate::memory::{mmio_perform_access, GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion}; +use crate::memory::{GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion}; use crate::percpu::this_zone; -use crate::zone::{is_this_root_zone, this_zone_id}; +use crate::zone::is_this_root_zone; use super::pci_access::{BridgeField, EndpointField, HeaderType, PciField, PciMemType}; use super::pci_config::GLOBAL_PCIE_LIST; @@ -12,16 +28,22 @@ use super::pci_struct::{ArcRwLockVirtualPciConfigSpace, BIT_LENTH}; use super::vpci_dev::VpciDevType; use super::PciConfigAddress; +#[cfg(target_arch = "x86_64")] +use crate::zone::this_zone_id; + #[cfg(feature = "dwc_pcie")] -use crate::pci::config_accessors::{ - dwc::DwcConfigRegionBackend, - dwc_atu::{ - AtuConfig, AtuType, AtuUnroll, ATU_BASE, ATU_ENABLE_BIT, ATU_REGION_SIZE, - PCIE_ATU_UNR_LIMIT, PCIE_ATU_UNR_LOWER_BASE, PCIE_ATU_UNR_LOWER_TARGET, - PCIE_ATU_UNR_REGION_CTRL1, PCIE_ATU_UNR_REGION_CTRL2, PCIE_ATU_UNR_UPPER_BASE, - PCIE_ATU_UNR_UPPER_LIMIT, PCIE_ATU_UNR_UPPER_TARGET, +use crate::{ + pci::config_accessors::{ + dwc::DwcConfigRegionBackend, + dwc_atu::{ + AtuType, AtuUnroll, ATU_BASE, ATU_ENABLE_BIT, ATU_REGION_SIZE, + PCIE_ATU_UNR_LIMIT, PCIE_ATU_UNR_LOWER_BASE, PCIE_ATU_UNR_LOWER_TARGET, + PCIE_ATU_UNR_REGION_CTRL1, PCIE_ATU_UNR_REGION_CTRL2, PCIE_ATU_UNR_UPPER_BASE, + PCIE_ATU_UNR_UPPER_LIMIT, PCIE_ATU_UNR_UPPER_TARGET, + }, + PciRegionMmio, }, - PciRegionMmio, + memory::mmio_perform_access, }; macro_rules! pci_log { @@ -777,7 +799,7 @@ pub fn mmio_vpci_handler_dbi(mmio: &mut MMIOAccess, _base: usize) -> HvResult { // warn!("set atu0 register {:#X} value {:#X}", atu_offset, mmio.value); - let mut atu = guard.atu_configs.get_atu_by_ecam_mut(ecam_base).unwrap(); + let atu = guard.atu_configs.get_atu_by_ecam_mut(ecam_base).unwrap(); // info!("atu config write {:#?}", atu); diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index ef7610e2..9597693c 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -13,6 +13,7 @@ // // Authors: // + use alloc::{collections::btree_map::BTreeMap, sync::Arc, vec::Vec}; use bit_field::BitField; use bitvec::{array::BitArray, order::Lsb0, BitArr}; @@ -943,8 +944,8 @@ pub struct PciIterator { } impl PciIterator { - fn get_pci_addr_base(&self, parent_bus: u8, bdf: Bdf) -> PciConfigAddress { - match self.accessor.get_pci_addr_base(bdf, parent_bus) { + fn get_pci_addr_base(&self, bdf: Bdf) -> PciConfigAddress { + match self.accessor.get_pci_addr_base(bdf) { Ok(addr) => addr, Err(_) => 0x0, } @@ -982,7 +983,7 @@ impl PciIterator { let bdf = Bdf::new(self.domain, bus, device, function); let address = self.address(parent_bus, bdf); - let pci_addr_base = self.get_pci_addr_base(parent_bus, bdf); + let pci_addr_base = self.get_pci_addr_base(bdf); // info!("get node {:x} {:#?}", address, bdf); let region = PciConfigMmio::new(address, CONFIG_LENTH); diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs index 0db8f840..775ff605 100644 --- a/src/pci/pci_test.rs +++ b/src/pci/pci_test.rs @@ -13,16 +13,22 @@ // // Authors: // + #![allow(dead_code)] use core::str::FromStr; use alloc::{collections::btree_map::BTreeMap, sync::Arc}; use spin::{lazy::Lazy, mutex::Mutex}; +use super::{ + pci_handler::mmio_vpci_direct_handler, + pci_struct::{Bdf, VirtualPciConfigSpace, CONFIG_LENTH}, +}; + +#[cfg(feature = "ecam_pcie")] use super::{ mem_alloc::BaseAllocator, - pci_handler::{mmio_vpci_direct_handler, mmio_vpci_handler}, - pci_struct::{Bdf, RootComplex, VirtualPciConfigSpace, CONFIG_LENTH}, + pci_struct::RootComplex, }; use crate::{ From 3c1deb136b391f9222d85ca75acc78a867d61659 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 1 Jan 2026 01:23:06 +0800 Subject: [PATCH 071/109] add license for virt dev --- src/pci/vpci_dev/mod.rs | 16 ++++++++++++++++ src/pci/vpci_dev/standard.rs | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/pci/vpci_dev/mod.rs b/src/pci/vpci_dev/mod.rs index 58c959f0..091a402f 100644 --- a/src/pci/vpci_dev/mod.rs +++ b/src/pci/vpci_dev/mod.rs @@ -1,3 +1,19 @@ +// 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 crate::error::HvResult; use crate::pci::pci_access::{Bar, EndpointField}; use crate::pci::pci_struct::{ diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index b98ce418..7446abc9 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -1,3 +1,19 @@ +// 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::{PciConfigAccessStatus, VpciDeviceHandler}; use crate::error::HvResult; use crate::pci::pci_access::{ From 8a80de73f060c3040f54ce56e847128daf73f50a Mon Sep 17 00:00:00 2001 From: li041 Date: Tue, 6 Jan 2026 15:18:14 +0800 Subject: [PATCH 072/109] add virtio net configuration for gicv3 --- .../qemu-gicv3/configs/zone1-linux-virtio.json | 16 ++++++++++++++++ .../aarch64/qemu-gicv3/configs/zone1-linux.json | 12 +++++++++++- .../aarch64/qemu-gicv3/image/dts/zone1-linux.dts | 14 +++++++------- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/platform/aarch64/qemu-gicv3/configs/zone1-linux-virtio.json b/platform/aarch64/qemu-gicv3/configs/zone1-linux-virtio.json index cdcc6de6..37e2933b 100644 --- a/platform/aarch64/qemu-gicv3/configs/zone1-linux-virtio.json +++ b/platform/aarch64/qemu-gicv3/configs/zone1-linux-virtio.json @@ -24,6 +24,22 @@ "len": "0x200", "irq": 76, "status": "enable" + }, + { + "type": "net", + "addr": "0xa003600", + "len": "0x200", + "irq": 75, + "tap": "tap0", + "mac": [ + "0x02", + "0x00", + "0x00", + "0x00", + "0x01", + "0x01" + ], + "status": "enable" } ] } diff --git a/platform/aarch64/qemu-gicv3/configs/zone1-linux.json b/platform/aarch64/qemu-gicv3/configs/zone1-linux.json index 17cb55f2..8e63d7e3 100644 --- a/platform/aarch64/qemu-gicv3/configs/zone1-linux.json +++ b/platform/aarch64/qemu-gicv3/configs/zone1-linux.json @@ -21,9 +21,19 @@ "physical_start": "0xa003c00", "virtual_start": "0xa003c00", "size": "0x200" + }, + { + "type": "virtio", + "physical_start": "0xa003600", + "virtual_start": "0xa003600", + "size": "0x200" } ], - "interrupts": [76, 78], + "interrupts": [ + 75, + 76, + 78 + ], "ivc_configs": [], "kernel_filepath": "Image", "kernel_args": "", diff --git a/platform/aarch64/qemu-gicv3/image/dts/zone1-linux.dts b/platform/aarch64/qemu-gicv3/image/dts/zone1-linux.dts index 9239584b..f286adb2 100644 --- a/platform/aarch64/qemu-gicv3/image/dts/zone1-linux.dts +++ b/platform/aarch64/qemu-gicv3/image/dts/zone1-linux.dts @@ -121,13 +121,13 @@ // compatible = "virtio,mmio"; // }; // virtio-net - // virtio_mmio@a003600 { - // dma-coherent; - // interrupt-parent = <0x01>; - // interrupts = <0x0 0x2b 0x1>; - // reg = <0x0 0xa003600 0x0 0x200>; - // compatible = "virtio,mmio"; - // }; + virtio_mmio@a003600 { + dma-coherent; + interrupt-parent = <0x01>; + interrupts = <0x0 0x2b 0x1>; + reg = <0x0 0xa003600 0x0 0x200>; + compatible = "virtio,mmio"; + }; // virtio serial virtio_mmio@a003800 { From ff2062073f59f276e3ecc9669f6791d71ee9a97d Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 8 Jan 2026 00:03:59 +0800 Subject: [PATCH 073/109] fmt and update zone1 config for pcie --- platform/aarch64/qemu-gicv3/board.rs | 2 +- .../aarch64/qemu-gicv3/configs/zone1-linux.json | 3 ++- platform/aarch64/rk3568/board.rs | 4 ++-- .../loongarch64/ls3a5000/configs/zone1-linux.json | 5 ++++- .../loongarch64/ls3a5000/configs/zone2-linux.json | 5 ++++- .../loongarch64/ls3a5000/configs/zone3-linux.json | 5 ++++- .../loongarch64/ls3a6000/configs/zone1-linux.json | 5 ++++- .../loongarch64/ls3a6000/configs/zone2-linux.json | 5 ++++- .../loongarch64/ls3a6000/configs/zone3-linux.json | 5 ++++- platform/riscv64/qemu-aia/configs/zone1-linux.json | 5 ++++- .../riscv64/qemu-plic/configs/zone1-linux-io.json | 5 ++++- platform/riscv64/qemu-plic/configs/zone1-linux.json | 5 ++++- src/pci/pci_access.rs | 13 +++++-------- src/pci/pci_config.rs | 10 ++-------- src/pci/pci_handler.rs | 10 +++++----- src/pci/pci_test.rs | 5 +---- 16 files changed, 54 insertions(+), 38 deletions(-) diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index 02f04aab..61c94e5b 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -114,7 +114,7 @@ pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; pub const ROOT_PCI_DEVS: &[HvPciDevConfig] = &[ pci_dev!(0x0, 0x0, 0x0, 0x0, VpciDevType::Physical), - pci_dev!(0x0, 0x0, 0x1, 0x0, VpciDevType::Physical), + // pci_dev!(0x0, 0x0, 0x1, 0x0, VpciDevType::Physical), pci_dev!(0x0, 0x0, 0x2, 0x0, VpciDevType::Physical), pci_dev!(0x0, 0x0, 0x5, 0x0, VpciDevType::StandardVdev), ]; diff --git a/platform/aarch64/qemu-gicv3/configs/zone1-linux.json b/platform/aarch64/qemu-gicv3/configs/zone1-linux.json index e4aa8e37..3b78c7ee 100644 --- a/platform/aarch64/qemu-gicv3/configs/zone1-linux.json +++ b/platform/aarch64/qemu-gicv3/configs/zone1-linux.json @@ -46,7 +46,8 @@ "mem64_size": "0x8000000000", "pci_mem64_base": "0x8000000000", "bus_range_begin": "0x0", - "bus_range_end": "0x1f" + "bus_range_end": "0x1f", + "domain": "0x0" }], "num_pci_devs": 2, "alloc_pci_devs": [ diff --git a/platform/aarch64/rk3568/board.rs b/platform/aarch64/rk3568/board.rs index d2238aef..708fb21d 100644 --- a/platform/aarch64/rk3568/board.rs +++ b/platform/aarch64/rk3568/board.rs @@ -352,6 +352,6 @@ pub const ROOT_DWC_ATU_CONFIG: &[HvDwcAtuConfig] = &[ ]; pub const ROOT_PCI_DEVS: [HvPciDevConfig; 2] = [ - pci_dev!(0x0, 0x10, 0x0, 0x0, VpciDevType::Physical), - pci_dev!(0x0, 0x11, 0x0, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x00, 0x0, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x01, 0x0, 0x0, VpciDevType::Physical), ]; \ No newline at end of file diff --git a/platform/loongarch64/ls3a5000/configs/zone1-linux.json b/platform/loongarch64/ls3a5000/configs/zone1-linux.json index 995d42ab..cbfbf972 100644 --- a/platform/loongarch64/ls3a5000/configs/zone1-linux.json +++ b/platform/loongarch64/ls3a5000/configs/zone1-linux.json @@ -122,7 +122,10 @@ "pci_mem32_base": "0x0", "mem64_base": "0x60000000", "mem64_size": "0x20000000", - "pci_mem64_base": "0x60000000" + "pci_mem64_base": "0x60000000", + "bus_range_begin": "0x0", + "bus_range_end": "0x1f", + "domain": "0x0" }], "num_pci_devs": 1, "alloc_pci_devs": [{ diff --git a/platform/loongarch64/ls3a5000/configs/zone2-linux.json b/platform/loongarch64/ls3a5000/configs/zone2-linux.json index ef26e27e..54ed3e2b 100644 --- a/platform/loongarch64/ls3a5000/configs/zone2-linux.json +++ b/platform/loongarch64/ls3a5000/configs/zone2-linux.json @@ -110,7 +110,10 @@ "pci_mem32_base": "0x0", "mem64_base": "0x60000000", "mem64_size": "0x20000000", - "pci_mem64_base": "0x60000000" + "pci_mem64_base": "0x60000000", + "bus_range_begin": "0x0", + "bus_range_end": "0x1f", + "domain": "0x0" }], "num_pci_devs": 1, "alloc_pci_devs": [{ diff --git a/platform/loongarch64/ls3a5000/configs/zone3-linux.json b/platform/loongarch64/ls3a5000/configs/zone3-linux.json index a90f3b2e..4f8e39b7 100644 --- a/platform/loongarch64/ls3a5000/configs/zone3-linux.json +++ b/platform/loongarch64/ls3a5000/configs/zone3-linux.json @@ -110,7 +110,10 @@ "pci_mem32_base": "0x0", "mem64_base": "0x60000000", "mem64_size": "0x20000000", - "pci_mem64_base": "0x60000000" + "pci_mem64_base": "0x60000000", + "bus_range_begin": "0x0", + "bus_range_end": "0x1f", + "domain": "0x0" }], "num_pci_devs": 1, "alloc_pci_devs": [{ diff --git a/platform/loongarch64/ls3a6000/configs/zone1-linux.json b/platform/loongarch64/ls3a6000/configs/zone1-linux.json index 995d42ab..cbfbf972 100644 --- a/platform/loongarch64/ls3a6000/configs/zone1-linux.json +++ b/platform/loongarch64/ls3a6000/configs/zone1-linux.json @@ -122,7 +122,10 @@ "pci_mem32_base": "0x0", "mem64_base": "0x60000000", "mem64_size": "0x20000000", - "pci_mem64_base": "0x60000000" + "pci_mem64_base": "0x60000000", + "bus_range_begin": "0x0", + "bus_range_end": "0x1f", + "domain": "0x0" }], "num_pci_devs": 1, "alloc_pci_devs": [{ diff --git a/platform/loongarch64/ls3a6000/configs/zone2-linux.json b/platform/loongarch64/ls3a6000/configs/zone2-linux.json index ef26e27e..54ed3e2b 100644 --- a/platform/loongarch64/ls3a6000/configs/zone2-linux.json +++ b/platform/loongarch64/ls3a6000/configs/zone2-linux.json @@ -110,7 +110,10 @@ "pci_mem32_base": "0x0", "mem64_base": "0x60000000", "mem64_size": "0x20000000", - "pci_mem64_base": "0x60000000" + "pci_mem64_base": "0x60000000", + "bus_range_begin": "0x0", + "bus_range_end": "0x1f", + "domain": "0x0" }], "num_pci_devs": 1, "alloc_pci_devs": [{ diff --git a/platform/loongarch64/ls3a6000/configs/zone3-linux.json b/platform/loongarch64/ls3a6000/configs/zone3-linux.json index a90f3b2e..4f8e39b7 100644 --- a/platform/loongarch64/ls3a6000/configs/zone3-linux.json +++ b/platform/loongarch64/ls3a6000/configs/zone3-linux.json @@ -110,7 +110,10 @@ "pci_mem32_base": "0x0", "mem64_base": "0x60000000", "mem64_size": "0x20000000", - "pci_mem64_base": "0x60000000" + "pci_mem64_base": "0x60000000", + "bus_range_begin": "0x0", + "bus_range_end": "0x1f", + "domain": "0x0" }], "num_pci_devs": 1, "alloc_pci_devs": [{ diff --git a/platform/riscv64/qemu-aia/configs/zone1-linux.json b/platform/riscv64/qemu-aia/configs/zone1-linux.json index c5d90065..41b557d8 100644 --- a/platform/riscv64/qemu-aia/configs/zone1-linux.json +++ b/platform/riscv64/qemu-aia/configs/zone1-linux.json @@ -47,7 +47,10 @@ "pci_mem32_base": "0x40000000", "mem64_base": "0x400000000", "mem64_size": "0x400000000", - "pci_mem64_base": "0x400000000" + "pci_mem64_base": "0x400000000", + "bus_range_begin": "0x0", + "bus_range_end": "0x1f", + "domain": "0x0" }], "num_pci_devs": 2, "alloc_pci_devs": [ diff --git a/platform/riscv64/qemu-plic/configs/zone1-linux-io.json b/platform/riscv64/qemu-plic/configs/zone1-linux-io.json index 710fec27..b1083ee6 100644 --- a/platform/riscv64/qemu-plic/configs/zone1-linux-io.json +++ b/platform/riscv64/qemu-plic/configs/zone1-linux-io.json @@ -47,7 +47,10 @@ "pci_mem32_base": "0x40000000", "mem64_base": "0x400000000", "mem64_size": "0x400000000", - "pci_mem64_base": "0x400000000" + "pci_mem64_base": "0x400000000", + "bus_range_begin": "0x0", + "bus_range_end": "0x1f", + "domain": "0x0" }], "num_pci_devs": 2, "alloc_pci_devs": [ diff --git a/platform/riscv64/qemu-plic/configs/zone1-linux.json b/platform/riscv64/qemu-plic/configs/zone1-linux.json index b3b77ac1..63eb58b7 100644 --- a/platform/riscv64/qemu-plic/configs/zone1-linux.json +++ b/platform/riscv64/qemu-plic/configs/zone1-linux.json @@ -47,7 +47,10 @@ "pci_mem32_base": "0x40000000", "mem64_base": "0x400000000", "mem64_size": "0x400000000", - "pci_mem64_base": "0x400000000" + "pci_mem64_base": "0x400000000", + "bus_range_begin": "0x0", + "bus_range_end": "0x1f", + "domain": "0x0" }], "num_pci_devs": 2, "alloc_pci_devs": [ diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index d2bff12c..d78a2344 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -28,9 +28,7 @@ use super::{ PciConfigAddress, }; -use crate::{ - error::HvResult -}; +use crate::error::HvResult; pub type VendorId = u16; pub type DeviceId = u16; @@ -199,11 +197,10 @@ impl PciMem { /* for unused bar, size is 0 */ 0 - } - // _ => { - // warn!("{:#?} not support size", self.bar_type); - // 0 - // } + } // _ => { + // warn!("{:#?} not support size", self.bar_type); + // 0 + // } } } diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 7eea48d1..c0704320 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -41,9 +41,7 @@ use crate::pci::{ feature = "dwc_pcie", feature = "loongarch64_pcie" ))] -use crate::pci::{ - mem_alloc::BaseAllocator, pci_struct::RootComplex, -}; +use crate::pci::{mem_alloc::BaseAllocator, pci_struct::RootComplex}; #[cfg(feature = "ecam_pcie")] use crate::pci::pci_handler::mmio_vpci_handler; @@ -51,11 +49,7 @@ use crate::pci::pci_handler::mmio_vpci_handler; use crate::{ memory::mmio_generic_handler, pci::{ - config_accessors::{ - dwc::DwcConfigRegionBackend, - dwc_atu::AtuConfig, - PciRegionMmio, - }, + config_accessors::{dwc::DwcConfigRegionBackend, dwc_atu::AtuConfig, PciRegionMmio}, pci_handler::{mmio_dwc_cfg_handler, mmio_dwc_io_handler, mmio_vpci_handler_dbi}, PciConfigAddress, }, diff --git a/src/pci/pci_handler.rs b/src/pci/pci_handler.rs index 960d15e1..98c9c87b 100644 --- a/src/pci/pci_handler.rs +++ b/src/pci/pci_handler.rs @@ -33,17 +33,17 @@ use crate::zone::this_zone_id; #[cfg(feature = "dwc_pcie")] use crate::{ + memory::mmio_perform_access, pci::config_accessors::{ dwc::DwcConfigRegionBackend, dwc_atu::{ - AtuType, AtuUnroll, ATU_BASE, ATU_ENABLE_BIT, ATU_REGION_SIZE, - PCIE_ATU_UNR_LIMIT, PCIE_ATU_UNR_LOWER_BASE, PCIE_ATU_UNR_LOWER_TARGET, - PCIE_ATU_UNR_REGION_CTRL1, PCIE_ATU_UNR_REGION_CTRL2, PCIE_ATU_UNR_UPPER_BASE, - PCIE_ATU_UNR_UPPER_LIMIT, PCIE_ATU_UNR_UPPER_TARGET, + AtuType, AtuUnroll, ATU_BASE, ATU_ENABLE_BIT, ATU_REGION_SIZE, PCIE_ATU_UNR_LIMIT, + PCIE_ATU_UNR_LOWER_BASE, PCIE_ATU_UNR_LOWER_TARGET, PCIE_ATU_UNR_REGION_CTRL1, + PCIE_ATU_UNR_REGION_CTRL2, PCIE_ATU_UNR_UPPER_BASE, PCIE_ATU_UNR_UPPER_LIMIT, + PCIE_ATU_UNR_UPPER_TARGET, }, PciRegionMmio, }, - memory::mmio_perform_access, }; macro_rules! pci_log { diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs index 775ff605..67278065 100644 --- a/src/pci/pci_test.rs +++ b/src/pci/pci_test.rs @@ -26,10 +26,7 @@ use super::{ }; #[cfg(feature = "ecam_pcie")] -use super::{ - mem_alloc::BaseAllocator, - pci_struct::RootComplex, -}; +use super::{mem_alloc::BaseAllocator, pci_struct::RootComplex}; use crate::{ memory::{mmio_perform_access, MMIOAccess}, From f1a0def15c30f0faf8a8d37b614545c0bb8946d7 Mon Sep 17 00:00:00 2001 From: li041 Date: Thu, 8 Jan 2026 10:14:40 +0800 Subject: [PATCH 074/109] reorder, format --- .../configs/zone1-linux-virtio.json | 30 +++++++++---------- .../qemu-gicv3/configs/zone1-linux.json | 12 ++++---- .../qemu-gicv3/image/dts/zone1-linux.dts | 12 ++++---- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/platform/aarch64/qemu-gicv3/configs/zone1-linux-virtio.json b/platform/aarch64/qemu-gicv3/configs/zone1-linux-virtio.json index 37e2933b..64dd4897 100644 --- a/platform/aarch64/qemu-gicv3/configs/zone1-linux-virtio.json +++ b/platform/aarch64/qemu-gicv3/configs/zone1-linux-virtio.json @@ -10,21 +10,6 @@ } ], "devices": [ - { - "type": "blk", - "addr": "0xa003c00", - "len": "0x200", - "irq": 78, - "img": "rootfs2.ext4", - "status": "enable" - }, - { - "type": "console", - "addr": "0xa003800", - "len": "0x200", - "irq": 76, - "status": "enable" - }, { "type": "net", "addr": "0xa003600", @@ -40,6 +25,21 @@ "0x01" ], "status": "enable" + }, + { + "type": "console", + "addr": "0xa003800", + "len": "0x200", + "irq": 76, + "status": "enable" + }, + { + "type": "blk", + "addr": "0xa003c00", + "len": "0x200", + "irq": 78, + "img": "rootfs2.ext4", + "status": "enable" } ] } diff --git a/platform/aarch64/qemu-gicv3/configs/zone1-linux.json b/platform/aarch64/qemu-gicv3/configs/zone1-linux.json index 8e63d7e3..a3c8d1d5 100644 --- a/platform/aarch64/qemu-gicv3/configs/zone1-linux.json +++ b/platform/aarch64/qemu-gicv3/configs/zone1-linux.json @@ -12,20 +12,20 @@ }, { "type": "virtio", - "physical_start": "0xa003800", - "virtual_start": "0xa003800", + "physical_start": "0xa003600", + "virtual_start": "0xa003600", "size": "0x200" }, { "type": "virtio", - "physical_start": "0xa003c00", - "virtual_start": "0xa003c00", + "physical_start": "0xa003800", + "virtual_start": "0xa003800", "size": "0x200" }, { "type": "virtio", - "physical_start": "0xa003600", - "virtual_start": "0xa003600", + "physical_start": "0xa003c00", + "virtual_start": "0xa003c00", "size": "0x200" } ], diff --git a/platform/aarch64/qemu-gicv3/image/dts/zone1-linux.dts b/platform/aarch64/qemu-gicv3/image/dts/zone1-linux.dts index f286adb2..1db70028 100644 --- a/platform/aarch64/qemu-gicv3/image/dts/zone1-linux.dts +++ b/platform/aarch64/qemu-gicv3/image/dts/zone1-linux.dts @@ -121,12 +121,12 @@ // compatible = "virtio,mmio"; // }; // virtio-net - virtio_mmio@a003600 { - dma-coherent; - interrupt-parent = <0x01>; - interrupts = <0x0 0x2b 0x1>; - reg = <0x0 0xa003600 0x0 0x200>; - compatible = "virtio,mmio"; + virtio_mmio@a003600 { + dma-coherent; + interrupt-parent = <0x01>; + interrupts = <0x0 0x2b 0x1>; + reg = <0x0 0xa003600 0x0 0x200>; + compatible = "virtio,mmio"; }; // virtio serial From 9421818d0055e5b00365d0de28420ea41d44c90f Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 8 Jan 2026 19:18:23 +0800 Subject: [PATCH 075/109] fix error updating for virt dev standard --- src/pci/vpci_dev/standard.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index 7446abc9..7c3f396e 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -95,6 +95,7 @@ impl VpciDeviceHandler for StandardHandler { if value == 0xFFFF_FFFF { dev.with_bar_ref_mut(slot, |bar| bar.set_size_read()); } else { + dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(value as u64)); let zone = this_zone(); let mut guard = zone.write(); pci_virt_log!( From 6c6f63b97f7a8670e34410e4ae5363deb0719f9e Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 8 Jan 2026 19:51:41 +0800 Subject: [PATCH 076/109] fix ci bug --- platform/aarch64/qemu-gicv3/board.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index 61c94e5b..a001d89a 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -115,6 +115,6 @@ pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; pub const ROOT_PCI_DEVS: &[HvPciDevConfig] = &[ pci_dev!(0x0, 0x0, 0x0, 0x0, VpciDevType::Physical), // pci_dev!(0x0, 0x0, 0x1, 0x0, VpciDevType::Physical), - pci_dev!(0x0, 0x0, 0x2, 0x0, VpciDevType::Physical), + // pci_dev!(0x0, 0x0, 0x3, 0x0, VpciDevType::Physical), pci_dev!(0x0, 0x0, 0x5, 0x0, VpciDevType::StandardVdev), ]; From 658c6993cd9797efa6126c7d82d30b56e4606cc4 Mon Sep 17 00:00:00 2001 From: dallas Date: Tue, 13 Jan 2026 15:18:03 +0800 Subject: [PATCH 077/109] fix ci bug --- platform/aarch64/qemu-gicv3/configs/zone1-linux.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/aarch64/qemu-gicv3/configs/zone1-linux.json b/platform/aarch64/qemu-gicv3/configs/zone1-linux.json index 3b78c7ee..59bc63a0 100644 --- a/platform/aarch64/qemu-gicv3/configs/zone1-linux.json +++ b/platform/aarch64/qemu-gicv3/configs/zone1-linux.json @@ -19,7 +19,7 @@ "interrupts": [76, 78], "ivc_configs": [], "kernel_filepath": "./Image", - "dtb_filepath": "./linux2.dtb", + "dtb_filepath": "./zone1-linux.dtb", "kernel_load_paddr": "0x50400000", "dtb_load_paddr": "0x50000000", "entry_point": "0x50400000", From b2a4ffd6df18fa9fa4f84bca9bca0f6fab2f8b21 Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 15 Jan 2026 14:32:39 +0800 Subject: [PATCH 078/109] fix error mem map when get bar size --- platform/aarch64/qemu-gicv3/board.rs | 2 +- src/pci/pci_handler.rs | 225 ++++++++++++++------------- 2 files changed, 116 insertions(+), 111 deletions(-) diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index a001d89a..c3fb1a0e 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -114,7 +114,7 @@ pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; pub const ROOT_PCI_DEVS: &[HvPciDevConfig] = &[ pci_dev!(0x0, 0x0, 0x0, 0x0, VpciDevType::Physical), - // pci_dev!(0x0, 0x0, 0x1, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x0, 0x1, 0x0, VpciDevType::Physical), // pci_dev!(0x0, 0x0, 0x3, 0x0, VpciDevType::Physical), pci_dev!(0x0, 0x0, 0x5, 0x0, VpciDevType::StandardVdev), ]; diff --git a/src/pci/pci_handler.rs b/src/pci/pci_handler.rs index 98c9c87b..b58116af 100644 --- a/src/pci/pci_handler.rs +++ b/src/pci/pci_handler.rs @@ -216,38 +216,40 @@ fn handle_endpoint_access( configvalue.set_bar_value(slot, value as u32); }); dev.write_hw(field.to_offset() as PciConfigAddress, field.size(), value)?; - if (bar_type == PciMemType::Mem32) + if (value & 0xfffffff0) != 0xfffffff0 { + if (bar_type == PciMemType::Mem32) | (bar_type == PciMemType::Mem64High) | (bar_type == PciMemType::Io) - { - let new_vaddr = { + { + 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 + * Read from config_value.bar_value cache instead of space + */ + let low_value = dev + .with_config_value(|cv| cv.get_bar_value(slot - 1)) + as u64; + let high_value = (value as u32 as u64) << 32; + (low_value | high_value) & !0xf + } else { + (value as u64) & !0xf + } + }; + + // set virt_value + dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(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 - * Read from config_value.bar_value cache instead of space - */ - let low_value = dev - .with_config_value(|cv| cv.get_bar_value(slot - 1)) - as u64; - let high_value = (value as u32 as u64) << 32; - (low_value | high_value) & !0xf - } else { - (value as u64) & !0xf + dev.with_bar_ref_mut(slot - 1, |bar| { + bar.set_virtual_value(new_vaddr) + }); } - }; - - // set virt_value - dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); - if bar_type == PciMemType::Mem64High { - dev.with_bar_ref_mut(slot - 1, |bar| { - bar.set_virtual_value(new_vaddr) - }); - } - // set value - dev.with_bar_ref_mut(slot, |bar| bar.set_value(new_vaddr)); - if bar_type == PciMemType::Mem64High { - dev.with_bar_ref_mut(slot - 1, |bar| bar.set_value(new_vaddr)); + // set value + dev.with_bar_ref_mut(slot, |bar| bar.set_value(new_vaddr)); + if bar_type == PciMemType::Mem64High { + dev.with_bar_ref_mut(slot - 1, |bar| bar.set_value(new_vaddr)); + } } } } else if is_dev_belong_to_zone { @@ -255,96 +257,99 @@ fn handle_endpoint_access( dev.with_config_value_mut(|configvalue| { configvalue.set_bar_value(slot, value as u32); }); - - if (bar_type == PciMemType::Mem32) + if (value & 0xfffffff0) != 0xfffffff0 { + if (bar_type == PciMemType::Mem32) | (bar_type == PciMemType::Mem64High) | (bar_type == PciMemType::Io) - { - let old_vaddr = - dev.with_bar_ref(slot, |bar| bar.get_virtual_value64()) & !0xf; - let new_vaddr = { + { + let old_vaddr = + dev.with_bar_ref(slot, |bar| 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 + * Read from config_value.bar_value cache instead of space + */ + let low_value = dev + .with_config_value(|cv| cv.get_bar_value(slot - 1)) + as u64; + let high_value = (value as u32 as u64) << 32; + (low_value | high_value) & !0xf + } else { + (value as u64) & !0xf + } + }; + + info!("new_vaddr: {:#x}", new_vaddr); + info!("old_vaddr: {:#x}", old_vaddr); + dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(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 - * Read from config_value.bar_value cache instead of space - */ - let low_value = dev - .with_config_value(|cv| cv.get_bar_value(slot - 1)) - as u64; - let high_value = (value as u32 as u64) << 32; - (low_value | high_value) & !0xf - } else { - (value as u64) & !0xf + dev.with_bar_ref_mut(slot - 1, |bar| { + bar.set_virtual_value(new_vaddr) + }); } - }; - dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); - if bar_type == PciMemType::Mem64High { - dev.with_bar_ref_mut(slot - 1, |bar| { - bar.set_virtual_value(new_vaddr) - }); - } - - let paddr = if is_root { - dev.with_bar_ref_mut(slot, |bar| bar.set_value(new_vaddr)); - if bar_type == PciMemType::Mem64High { - dev.with_bar_ref_mut(slot - 1, |bar| bar.set_value(new_vaddr)); - } - new_vaddr as HostPhysAddr - } else { - dev.with_bar_ref(slot, |bar| bar.get_value64()) as HostPhysAddr - }; - let bar_size = { - let size = dev.with_bar_ref(slot, |bar| bar.get_size()); - if crate::memory::addr::is_aligned(size as usize) { - size + let paddr = if is_root { + dev.with_bar_ref_mut(slot, |bar| bar.set_value(new_vaddr)); + if bar_type == PciMemType::Mem64High { + dev.with_bar_ref_mut(slot - 1, |bar| bar.set_value(new_vaddr)); + } + new_vaddr as HostPhysAddr } else { - crate::memory::PAGE_SIZE as u64 + dev.with_bar_ref(slot, |bar| bar.get_value64()) as HostPhysAddr + }; + let bar_size = { + let size = dev.with_bar_ref(slot, |bar| bar.get_size()); + if crate::memory::addr::is_aligned(size as usize) { + size + } else { + crate::memory::PAGE_SIZE as u64 + } + }; + let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) + { + crate::memory::addr::align_up(new_vaddr as usize) as u64 + } else { + new_vaddr as u64 + }; + + let zone = this_zone(); + let mut guard = zone.write(); + let gpm = &mut guard.gpm; + + if !gpm + .try_delete(old_vaddr.try_into().unwrap(), bar_size as usize) + .is_ok() + { + // warn!("delete bar {}: can not found 0x{:x}", slot, old_vaddr); + } + gpm.try_insert_quiet(MemoryRegion::new_with_offset_mapper( + new_vaddr as GuestPhysAddr, + paddr as HostPhysAddr, + bar_size as _, + MemFlags::READ | MemFlags::WRITE, + ))?; + drop(guard); + /* after update gpm, mem barrier is needed + */ + #[cfg(target_arch = "aarch64")] + unsafe { + core::arch::asm!("isb"); + core::arch::asm!("tlbi vmalls12e1is"); + core::arch::asm!("dsb nsh"); + } + /* after update gpm, need to flush iommu table + * in x86_64 + */ + #[cfg(target_arch = "x86_64")] + { + let vbdf = dev.get_vbdf(); + crate::arch::iommu::flush( + this_zone_id(), + vbdf.bus, + (vbdf.device << 3) + vbdf.function, + ); } - }; - let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) - { - crate::memory::addr::align_up(new_vaddr as usize) as u64 - } else { - new_vaddr as u64 - }; - - let zone = this_zone(); - let mut guard = zone.write(); - let gpm = &mut guard.gpm; - - if !gpm - .try_delete(old_vaddr.try_into().unwrap(), bar_size as usize) - .is_ok() - { - // warn!("delete bar {}: can not found 0x{:x}", slot, old_vaddr); - } - gpm.try_insert_quiet(MemoryRegion::new_with_offset_mapper( - new_vaddr as GuestPhysAddr, - paddr as HostPhysAddr, - bar_size as _, - MemFlags::READ | MemFlags::WRITE, - ))?; - drop(guard); - /* after update gpm, mem barrier is needed - */ - #[cfg(target_arch = "aarch64")] - unsafe { - core::arch::asm!("isb"); - core::arch::asm!("tlbi vmalls12e1is"); - core::arch::asm!("dsb nsh"); - } - /* after update gpm, need to flush iommu table - * in x86_64 - */ - #[cfg(target_arch = "x86_64")] - { - let vbdf = dev.get_vbdf(); - crate::arch::iommu::flush( - this_zone_id(), - vbdf.bus, - (vbdf.device << 3) + vbdf.function, - ); } } } From 4e2edf7c8c348d88c4e17b70ec108851d059eafc Mon Sep 17 00:00:00 2001 From: dallas Date: Thu, 15 Jan 2026 15:52:40 +0800 Subject: [PATCH 079/109] fix riscv zone1 config --- .../riscv64/qemu-aia/configs/zone1-linux.json | 14 ++++-- .../qemu-plic/configs/zone1-linux-io.json | 14 ++++-- .../qemu-plic/configs/zone1-linux.json | 14 ++++-- src/pci/pci_handler.rs | 46 ++++++++++--------- 4 files changed, 54 insertions(+), 34 deletions(-) diff --git a/platform/riscv64/qemu-aia/configs/zone1-linux.json b/platform/riscv64/qemu-aia/configs/zone1-linux.json index 41b557d8..218629ba 100644 --- a/platform/riscv64/qemu-aia/configs/zone1-linux.json +++ b/platform/riscv64/qemu-aia/configs/zone1-linux.json @@ -55,12 +55,18 @@ "num_pci_devs": 2, "alloc_pci_devs": [ { - "bdf": "0x0", - "vbdf": "0x0" + "domain": "0x0", + "bus": "0x0", + "device": "0x0", + "function": "0x0", + "dev_type": "0" }, { - "bdf": "0x10", - "vbdf": "0x10" + "domain": "0x0", + "bus": "0x0", + "device": "0x2", + "function": "0x0", + "dev_type": "0" } ] } \ 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 b1083ee6..fd17a8a9 100644 --- a/platform/riscv64/qemu-plic/configs/zone1-linux-io.json +++ b/platform/riscv64/qemu-plic/configs/zone1-linux-io.json @@ -55,12 +55,18 @@ "num_pci_devs": 2, "alloc_pci_devs": [ { - "bdf": "0x0", - "vbdf": "0x0" + "domain": "0x0", + "bus": "0x0", + "device": "0x0", + "function": "0x0", + "dev_type": "0" }, { - "bdf": "0x10", - "vbdf": "0x10" + "domain": "0x0", + "bus": "0x0", + "device": "0x2", + "function": "0x0", + "dev_type": "0" } ] } \ 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 63eb58b7..a57f6201 100644 --- a/platform/riscv64/qemu-plic/configs/zone1-linux.json +++ b/platform/riscv64/qemu-plic/configs/zone1-linux.json @@ -55,12 +55,18 @@ "num_pci_devs": 2, "alloc_pci_devs": [ { - "bdf": "0x0", - "vbdf": "0x0" + "domain": "0x0", + "bus": "0x0", + "device": "0x0", + "function": "0x0", + "dev_type": "0" }, { - "bdf": "0x10", - "vbdf": "0x10" + "domain": "0x0", + "bus": "0x0", + "device": "0x2", + "function": "0x0", + "dev_type": "0" } ] } \ No newline at end of file diff --git a/src/pci/pci_handler.rs b/src/pci/pci_handler.rs index b58116af..fcc6133f 100644 --- a/src/pci/pci_handler.rs +++ b/src/pci/pci_handler.rs @@ -218,15 +218,15 @@ fn handle_endpoint_access( dev.write_hw(field.to_offset() as PciConfigAddress, field.size(), value)?; if (value & 0xfffffff0) != 0xfffffff0 { if (bar_type == PciMemType::Mem32) - | (bar_type == PciMemType::Mem64High) - | (bar_type == PciMemType::Io) + | (bar_type == PciMemType::Mem64High) + | (bar_type == PciMemType::Io) { 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 - * Read from config_value.bar_value cache instead of space - */ + * flag will auto add when set_value and set_virtual_value + * Read from config_value.bar_value cache instead of space + */ let low_value = dev .with_config_value(|cv| cv.get_bar_value(slot - 1)) as u64; @@ -259,17 +259,17 @@ fn handle_endpoint_access( }); if (value & 0xfffffff0) != 0xfffffff0 { if (bar_type == PciMemType::Mem32) - | (bar_type == PciMemType::Mem64High) - | (bar_type == PciMemType::Io) + | (bar_type == PciMemType::Mem64High) + | (bar_type == PciMemType::Io) { let old_vaddr = dev.with_bar_ref(slot, |bar| 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 - * Read from config_value.bar_value cache instead of space - */ + * flag will auto add when set_value and set_virtual_value + * Read from config_value.bar_value cache instead of space + */ let low_value = dev .with_config_value(|cv| cv.get_bar_value(slot - 1)) as u64; @@ -280,8 +280,8 @@ fn handle_endpoint_access( } }; - info!("new_vaddr: {:#x}", new_vaddr); - info!("old_vaddr: {:#x}", old_vaddr); + info!("new_vaddr: {:#x}", new_vaddr); + info!("old_vaddr: {:#x}", old_vaddr); dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); if bar_type == PciMemType::Mem64High { dev.with_bar_ref_mut(slot - 1, |bar| { @@ -292,7 +292,9 @@ fn handle_endpoint_access( let paddr = if is_root { dev.with_bar_ref_mut(slot, |bar| bar.set_value(new_vaddr)); if bar_type == PciMemType::Mem64High { - dev.with_bar_ref_mut(slot - 1, |bar| bar.set_value(new_vaddr)); + dev.with_bar_ref_mut(slot - 1, |bar| { + bar.set_value(new_vaddr) + }); } new_vaddr as HostPhysAddr } else { @@ -306,12 +308,12 @@ fn handle_endpoint_access( crate::memory::PAGE_SIZE as u64 } }; - let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) - { - crate::memory::addr::align_up(new_vaddr as usize) as u64 - } else { - new_vaddr as u64 - }; + let new_vaddr = + if !crate::memory::addr::is_aligned(new_vaddr as usize) { + crate::memory::addr::align_up(new_vaddr as usize) as u64 + } else { + new_vaddr as u64 + }; let zone = this_zone(); let mut guard = zone.write(); @@ -331,7 +333,7 @@ fn handle_endpoint_access( ))?; drop(guard); /* after update gpm, mem barrier is needed - */ + */ #[cfg(target_arch = "aarch64")] unsafe { core::arch::asm!("isb"); @@ -339,8 +341,8 @@ fn handle_endpoint_access( core::arch::asm!("dsb nsh"); } /* after update gpm, need to flush iommu table - * in x86_64 - */ + * in x86_64 + */ #[cfg(target_arch = "x86_64")] { let vbdf = dev.get_vbdf(); From c6496d820c4b9ffd3a1dead2d37dad98a9a69a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=AF=E5=AE=87?= <2537738252@qq.com> Date: Fri, 16 Jan 2026 23:00:41 +0800 Subject: [PATCH 080/109] riscv64: fix ci and update pci config --- platform/riscv64/qemu-aia/board.rs | 7 +- platform/riscv64/qemu-plic/README.md | 70 ++++++++++++ platform/riscv64/qemu-plic/board.rs | 89 +++++++-------- platform/riscv64/qemu-plic/cargo/features | 4 +- .../qemu-plic/configs/virtio-backend.json | 23 ++++ ...x-io.json => zone1-linux-passthrough.json} | 20 ++-- .../qemu-plic/configs/zone1-linux-virtio.json | 87 ++++++++++----- .../qemu-plic/configs/zone1-linux.json | 72 ------------- .../riscv64/qemu-plic/image/dts/zone0.dts | 102 ++++++++---------- .../qemu-plic/image/dts/zone1-linux.dts | 47 ++++++-- platform/riscv64/qemu-plic/platform.mk | 12 ++- .../riscv64/qemu-plic/scripts/boot_zone1.sh | 11 ++ .../qemu-plic/test/systemtest/boot_zone1.sh | 4 +- .../test/systemtest/tdownload_all.sh | 37 +++++++ .../test/systemtest/trootfs_deploy.sh | 2 +- src/arch/riscv64/consts.rs | 6 +- src/arch/riscv64/cpu.rs | 15 +-- src/arch/riscv64/csr.rs | 2 + src/arch/riscv64/entry.rs | 1 - src/arch/riscv64/hypercall.rs | 9 +- src/arch/riscv64/iommu.rs | 2 + src/arch/riscv64/ipi.rs | 11 +- src/arch/riscv64/mm.rs | 10 +- src/arch/riscv64/mod.rs | 7 +- src/arch/riscv64/paging.rs | 5 +- src/arch/riscv64/sbi.rs | 4 +- src/arch/riscv64/time.rs | 8 ++ src/arch/riscv64/trap.rs | 32 +++--- src/arch/riscv64/zone.rs | 10 +- src/device/irqchip/aia/mod.rs | 3 +- src/device/irqchip/mod.rs | 2 +- src/device/irqchip/plic/mod.rs | 10 +- src/device/irqchip/plic/vplic.rs | 5 +- src/device/virtio_trampoline.rs | 1 - src/hypercall/mod.rs | 7 +- src/pci/pci_handler.rs | 5 + 36 files changed, 431 insertions(+), 311 deletions(-) create mode 100644 platform/riscv64/qemu-plic/README.md create mode 100644 platform/riscv64/qemu-plic/configs/virtio-backend.json rename platform/riscv64/qemu-plic/configs/{zone1-linux-io.json => zone1-linux-passthrough.json} (82%) delete mode 100644 platform/riscv64/qemu-plic/configs/zone1-linux.json create mode 100644 platform/riscv64/qemu-plic/scripts/boot_zone1.sh diff --git a/platform/riscv64/qemu-aia/board.rs b/platform/riscv64/qemu-aia/board.rs index a23eae5b..cfae9481 100644 --- a/platform/riscv64/qemu-aia/board.rs +++ b/platform/riscv64/qemu-aia/board.rs @@ -14,16 +14,13 @@ // Authors: // use crate::{arch::zone::HvArchZoneConfig, config::*}; - pub const BOARD_NAME: &str = "qemu-aia"; - pub const BOARD_NCPUS: usize = 4; - pub const TIMEBASE_FREQ: u64 = 10_000_000; // 10MHz - pub const ACLINT_SSWI_BASE: usize = 0x2F00000; // This device is used for qemu-quit. +#[allow(unused)] pub const SIFIVE_TEST_BASE: u64 = 0x100000; pub const APLIC_BASE: usize = 0xc000000; @@ -32,12 +29,10 @@ pub const IMSIC_S_BASE: usize = 0x2800_0000; pub const IMSIC_GUEST_NUM: usize = 1; // hvisor only supports 1 guest now. pub const IMSIC_GUEST_INDEX: usize = 1; pub const IMSIC_NUM_IDS: usize = 0xFF; - pub const ROOT_ZONE_DTB_ADDR: u64 = 0x8f000000; pub const ROOT_ZONE_KERNEL_ADDR: u64 = 0x90000000; pub const ROOT_ZONE_ENTRY: u64 = 0x90000000; pub const ROOT_ZONE_CPUS: u64 = (1 << 0) | (1 << 1) | (1 << 2); - pub const ROOT_ZONE_NAME: &str = "root-linux"; pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 9] = [ diff --git a/platform/riscv64/qemu-plic/README.md b/platform/riscv64/qemu-plic/README.md new file mode 100644 index 00000000..3e12c5b8 --- /dev/null +++ b/platform/riscv64/qemu-plic/README.md @@ -0,0 +1,70 @@ +# Platform Configuration for RISC-V QEMU + +This document describes the platform setup for running **hvisor** on the RISC-V QEMU virtual machine. + +## Configuration Files Overview + +- **`platform.mk`**: + Defines QEMU parameters for the current platform, including: + - Number of harts (CPU cores) + - Memory size + - Virtio peripherals + - PCI devices + +- **`board.rs`**: + Contains board-specific configuration for **hvisor**, including: + - Root zone settings + - General platform initialization parameters + +## Environment Setup + +> **Recommended QEMU version**: `7.2.0` (tested and verified) + +### Prerequisites + +- A compiled Linux kernel +- Two root filesystems (`rootfs`) + +### Generate Device Tree Blob (DTB) + +Run the following command to generate the device tree file: + +```bash +make BID=riscv64/qemu-plic dtb +``` + +### Prepare Root Filesystem + +Copy the following files into the root filesystem of your primary Linux instance: + +- configs/virtio-backend.json + +- configs/zone1-linux-virtio.json + +- zone1-linux.dtb + +- Compiled hvisor binary + +- hvisor.ko kernel module + +- Scripts from the scripts/ directory (optional) + +### Boot Instructions + +Boot into the root Linux shell. + +Execute the boot script: + +```bash +./boot_linux.sh +``` + +After the system starts, connect to the non-root zone’s virtual serial console using: + +```bash +screen /dev/xxx (Replace xxx with the actual number.) +``` + +### Notes +In the current configuration, the virtio-console backend runs inside root Linux, not in QEMU. +Both the root zone and zone1 are assigned one virtio-pci-blk device(using wired-interupt) each. \ No newline at end of file diff --git a/platform/riscv64/qemu-plic/board.rs b/platform/riscv64/qemu-plic/board.rs index 569cb327..969d6810 100644 --- a/platform/riscv64/qemu-plic/board.rs +++ b/platform/riscv64/qemu-plic/board.rs @@ -13,32 +13,27 @@ // // Authors: // -use crate::{arch::zone::HvArchZoneConfig, config::*}; +use crate::{arch::zone::HvArchZoneConfig, config::*, pci::vpci_dev::VpciDevType, pci_dev}; #[allow(unused)] pub const BOARD_NAME: &str = "qem-plic"; - pub const BOARD_NCPUS: usize = 4; - pub const TIMEBASE_FREQ: u64 = 10_000_000; // 10MHz - pub const ACLINT_SSWI_BASE: usize = 0x2F00000; - pub const PLIC_BASE: usize = 0xc000000; - +pub const PLIC_SIZE: usize = 0x4000000; pub const BOARD_PLIC_INTERRUPTS_NUM: usize = 1023; // except irq 0 // This device is used for qemu-quit. +#[allow(unused)] pub const SIFIVE_TEST_BASE: u64 = 0x100000; - pub const ROOT_ZONE_DTB_ADDR: u64 = 0x8f000000; pub const ROOT_ZONE_KERNEL_ADDR: u64 = 0x90000000; pub const ROOT_ZONE_ENTRY: u64 = 0x90000000; 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; 9] = [ +pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, physical_start: 0x83000000, @@ -51,42 +46,6 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 9] = [ virtual_start: 0x10000000, size: 0x1000, }, // serial - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0x30000000, - virtual_start: 0x30000000, - size: 0x10000000, - }, // pci - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0x10001000, - virtual_start: 0x10001000, - size: 0x1000, - }, // virtio - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0x10002000, - virtual_start: 0x10002000, - size: 0x1000, - }, // virtio - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0x10003000, - virtual_start: 0x10003000, - size: 0x1000, - }, // virtio - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0x10004000, - virtual_start: 0x10004000, - size: 0x1000, - }, // virtio - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0x10005000, - virtual_start: 0x10005000, - size: 0x1000, - }, // virtio HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x10008000, @@ -97,14 +56,42 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 9] = [ // Note: all here's irqs are hardware irqs, // only these irq can be transferred to the physical PLIC. -pub const HW_IRQS: [u32; 11] = [1, 2, 3, 4, 5, 8, 10, 33, 34, 35, 36]; +// For qemu-virt, 32 is pcie pinA, 33 is pcie pinB, 34 is pcie pinC, 35 is pcie pinD, now only use 33,34 +pub const HW_IRQS: &[u32] = &[10, 33, 34]; // irqs belong to the root zone. -pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[1, 2, 3, 4, 5, 8, 10, 33, 34, 35, 36]); +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[10, 33]); +// Interrupt-controller config for the root zone. pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { - plic_base: 0xc000000, - plic_size: 0x4000000, - aplic_base: 0xd000000, - aplic_size: 0x8000, + plic_base: PLIC_BASE, + plic_size: PLIC_SIZE, + aplic_base: 0x0, + aplic_size: 0x0, }; + +pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { + ecam_base: 0x30000000, + ecam_size: 0x10000000, + io_base: 0x3000000, + io_size: 0x10000, + pci_io_base: 0x0, + mem32_base: 0x40000000, + mem32_size: 0x40000000, + pci_mem32_base: 0x40000000, + mem64_base: 0x400000000, + mem64_size: 0x400000000, + pci_mem64_base: 0x400000000, + bus_range_begin: 0, + bus_range_end: 0xff, + domain: 0x0, +}]; + +pub const ROOT_ZONE_IVC_CONFIG: &[HvIvcConfig] = &[]; + +pub const ROOT_PCI_DEVS: &[HvPciDevConfig] = &[ + pci_dev!(0x0, 0x0, 0x0, 0x0, VpciDevType::Physical), + pci_dev!(0x0, 0x0, 0x1, 0x0, VpciDevType::Physical), + // pci_dev!(0x0, 0x0, 0x3, 0x0, VpciDevType::Physical), + // pci_dev!(0x0, 0x0, 0x5, 0x0, VpciDevType::StandardVdev), +]; diff --git a/platform/riscv64/qemu-plic/cargo/features b/platform/riscv64/qemu-plic/cargo/features index 647916d7..4fa220e3 100644 --- a/platform/riscv64/qemu-plic/cargo/features +++ b/platform/riscv64/qemu-plic/cargo/features @@ -1,3 +1,5 @@ aclint plic -sstc \ No newline at end of file +sstc +pci +ecam_pcie \ No newline at end of file diff --git a/platform/riscv64/qemu-plic/configs/virtio-backend.json b/platform/riscv64/qemu-plic/configs/virtio-backend.json new file mode 100644 index 00000000..7ab47816 --- /dev/null +++ b/platform/riscv64/qemu-plic/configs/virtio-backend.json @@ -0,0 +1,23 @@ +{ + "zones": [ + { + "id": 1, + "memory_region": [ + { + "zone0_ipa": "0x85000000", + "zonex_ipa": "0x85000000", + "size": "0x0a000000" + } + ], + "devices": [ + { + "type": "console", + "addr": "0x10007000", + "len": "0x1000", + "irq": 7, + "status": "enable" + } + ] + } + ] +} \ 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-passthrough.json similarity index 82% rename from platform/riscv64/qemu-plic/configs/zone1-linux-io.json rename to platform/riscv64/qemu-plic/configs/zone1-linux-passthrough.json index fd17a8a9..11930624 100644 --- a/platform/riscv64/qemu-plic/configs/zone1-linux-io.json +++ b/platform/riscv64/qemu-plic/configs/zone1-linux-passthrough.json @@ -6,9 +6,9 @@ "memory_regions": [ { "type": "ram", - "physical_start": "0x83000000", - "virtual_start": "0x83000000", - "size": "0x0C000000" + "physical_start": "0x85000000", + "virtual_start": "0x85000000", + "size": "0x0A000000" }, { "type": "io", @@ -23,18 +23,18 @@ "size": "0x1000" } ], - "interrupts": [6, 7], + "interrupts": [6, 7, 34], "ivc_configs": [], "kernel_filepath": "./Image", "dtb_filepath": "./zone1-linux.dtb", - "kernel_load_paddr": "0x84000000", - "dtb_load_paddr": "0x83000000", - "entry_point": "0x84000000", + "kernel_load_paddr": "0x86000000", + "dtb_load_paddr": "0x85000000", + "entry_point": "0x86000000", "arch_config": { "plic_base": "0xc000000", "plic_size": "0x4000000", - "aplic_base": "0xd000000", - "aplic_size": "0x8000" + "aplic_base": "0x0", + "aplic_size": "0x0" }, "pci_config": [{ "ecam_base": "0x30000000", @@ -54,7 +54,7 @@ }], "num_pci_devs": 2, "alloc_pci_devs": [ - { + { "domain": "0x0", "bus": "0x0", "device": "0x0", diff --git a/platform/riscv64/qemu-plic/configs/zone1-linux-virtio.json b/platform/riscv64/qemu-plic/configs/zone1-linux-virtio.json index 1310b332..08bad2a1 100644 --- a/platform/riscv64/qemu-plic/configs/zone1-linux-virtio.json +++ b/platform/riscv64/qemu-plic/configs/zone1-linux-virtio.json @@ -1,31 +1,66 @@ { - "zones": [ + "arch": "riscv", + "name": "linux2", + "zone_id": 1, + "cpus": [2, 3], + "memory_regions": [ { - "id": 1, - "memory_region": [ - { - "zone0_ipa": "0x83000000", - "zonex_ipa": "0x83000000", - "size": "0x0C000000" - } - ], - "devices": [ - { - "type": "blk", - "addr": "0x10006000", - "len": "0x1000", - "irq": 6, - "img": "riscv_rootfs2.img", - "status": "enable" - }, - { - "type": "console", - "addr": "0x10007000", - "len": "0x1000", - "irq": 7, - "status": "enable" - } - ] + "type": "ram", + "physical_start": "0x85000000", + "virtual_start": "0x85000000", + "size": "0x0a000000" + }, + { + "type": "virtio", + "physical_start": "0x10007000", + "virtual_start": "0x10007000", + "size": "0x1000" + } + ], + "interrupts": [7, 34], + "ivc_configs": [], + "kernel_filepath": "./Image", + "dtb_filepath": "./zone1-linux.dtb", + "kernel_load_paddr": "0x86000000", + "dtb_load_paddr": "0x85000000", + "entry_point": "0x86000000", + "arch_config": { + "plic_base": "0xc000000", + "plic_size": "0x4000000", + "aplic_base": "0xd000000", + "aplic_size": "0x8000" + }, + "pci_config": [{ + "ecam_base": "0x30000000", + "ecam_size": "0x10000000", + "io_base": "0x3000000", + "io_size": "0x10000", + "pci_io_base": "0x0", + "mem32_base": "0x40000000", + "mem32_size": "0x40000000", + "pci_mem32_base": "0x40000000", + "mem64_base": "0x400000000", + "mem64_size": "0x400000000", + "pci_mem64_base": "0x400000000", + "bus_range_begin": "0x0", + "bus_range_end": "0x1f", + "domain": "0x0" + }], + "num_pci_devs": 2, + "alloc_pci_devs": [ + { + "domain": "0x0", + "bus": "0x0", + "device": "0x0", + "function": "0x0", + "dev_type": "0" + }, + { + "domain": "0x0", + "bus": "0x0", + "device": "0x2", + "function": "0x0", + "dev_type": "0" } ] } \ 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 deleted file mode 100644 index a57f6201..00000000 --- a/platform/riscv64/qemu-plic/configs/zone1-linux.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "arch": "riscv", - "name": "linux2", - "zone_id": 1, - "cpus": [2, 3], - "memory_regions": [ - { - "type": "ram", - "physical_start": "0x83000000", - "virtual_start": "0x83000000", - "size": "0x0C000000" - }, - { - "type": "virtio", - "physical_start": "0x10007000", - "virtual_start": "0x10007000", - "size": "0x1000" - }, - { - "type": "virtio", - "physical_start": "0x10006000", - "virtual_start": "0x10006000", - "size": "0x1000" - } - ], - "interrupts": [6, 7], - "ivc_configs": [], - "kernel_filepath": "./Image", - "dtb_filepath": "./zone1-linux.dtb", - "kernel_load_paddr": "0x84000000", - "dtb_load_paddr": "0x83000000", - "entry_point": "0x84000000", - "arch_config": { - "plic_base": "0xc000000", - "plic_size": "0x4000000", - "aplic_base": "0xd000000", - "aplic_size": "0x8000" - }, - "pci_config": [{ - "ecam_base": "0x30000000", - "ecam_size": "0x10000000", - "io_base": "0x3000000", - "io_size": "0x10000", - "pci_io_base": "0x0", - "mem32_base": "0x40000000", - "mem32_size": "0x40000000", - "pci_mem32_base": "0x40000000", - "mem64_base": "0x400000000", - "mem64_size": "0x400000000", - "pci_mem64_base": "0x400000000", - "bus_range_begin": "0x0", - "bus_range_end": "0x1f", - "domain": "0x0" - }], - "num_pci_devs": 2, - "alloc_pci_devs": [ - { - "domain": "0x0", - "bus": "0x0", - "device": "0x0", - "function": "0x0", - "dev_type": "0" - }, - { - "domain": "0x0", - "bus": "0x0", - "device": "0x2", - "function": "0x0", - "dev_type": "0" - } - ] -} \ No newline at end of file diff --git a/platform/riscv64/qemu-plic/image/dts/zone0.dts b/platform/riscv64/qemu-plic/image/dts/zone0.dts index 70ec4e1e..a1e6cdb4 100644 --- a/platform/riscv64/qemu-plic/image/dts/zone0.dts +++ b/platform/riscv64/qemu-plic/image/dts/zone0.dts @@ -3,6 +3,8 @@ / { #address-cells = <0x2>; #size-cells = <0x2>; + model = "linux,dummy-virt"; + compatible = "linux,dummy-virt"; cpus { #address-cells = <0x1>; @@ -50,28 +52,23 @@ #size-cells = <0x02>; ranges; - opensbi@0x80000000 { + opensbi+hvisor@80000000 { // reserved for opensbi and hvisor no-map; - reg = <0x00 0x80000000 0x00 0x00200000>; + reg = <0x00 0x80000000 0x00 0x05000000>; }; - hvisor@0x80200000 { + nonroot@85000000 { no-map; - reg = <0x00 0x80200000 0x00 0x02E00000>; + reg = <0x00 0x85000000 0x00 0x0a000000>; }; - nonroot@0x83000000 { - no-map; - reg = <0x00 0x83000000 0x00 0x0C000000>; - }; - - dtbfile@0x8f000000 { + dtbfile@8f000000 { no-map; reg = <0x00 0x8f000000 0x00 0x01000000>; }; }; - soc{ + soc { #address-cells = <0x02>; #size-cells = <0x02>; compatible = "simple-bus"; @@ -81,15 +78,44 @@ phandle = <0x03>; riscv,ndev = <0x5f>; reg = <0x00 0xc000000 0x00 0x600000>; - interrupts-extended = < - &cpu0_intc 11 &cpu0_intc 9 - &cpu1_intc 11 &cpu1_intc 9 - >; + interrupts-extended = <&cpu0_intc 11 &cpu0_intc 9 &cpu1_intc 11 &cpu1_intc 9>; interrupt-controller; compatible = "riscv,plic0"; #interrupt-cells = <0x1>; }; + pci@30000000 { + interrupt-map-mask = <0x1800 0x00 0x00 0x07>; + interrupt-map = <0x00 0x00 0x00 0x01 &plic 0x20 + 0x00 0x00 0x00 0x02 &plic 0x21 + 0x00 0x00 0x00 0x03 &plic 0x22 + 0x00 0x00 0x00 0x04 &plic 0x23 + 0x800 0x00 0x00 0x01 &plic 0x21 + 0x800 0x00 0x00 0x02 &plic 0x22 + 0x800 0x00 0x00 0x03 &plic 0x23 + 0x800 0x00 0x00 0x04 &plic 0x20 + 0x1000 0x00 0x00 0x01 &plic 0x22 + 0x1000 0x00 0x00 0x02 &plic 0x23 + 0x1000 0x00 0x00 0x03 &plic 0x20 + 0x1000 0x00 0x00 0x04 &plic 0x21 + 0x1800 0x00 0x00 0x01 &plic 0x23 + 0x1800 0x00 0x00 0x02 &plic 0x20 + 0x1800 0x00 0x00 0x03 &plic 0x21 + 0x1800 0x00 0x00 0x04 &plic 0x22>; + ranges = <0x1000000 0x00 0x00 0x00 0x3000000 0x00 0x10000 + 0x2000000 0x00 0x40000000 0x00 0x40000000 0x00 0x40000000 + 0x3000000 0x04 0x00 0x04 0x00 0x04 0x00>; + reg = <0x00 0x30000000 0x00 0x10000000>; + dma-coherent; + bus-range = <0x00 0xff>; + linux,pci-domain = <0x00>; + device_type = "pci"; + compatible = "pci-host-ecam-generic"; + #size-cells = <0x02>; + #interrupt-cells = <0x01>; + #address-cells = <0x03>; + }; + uart@10000000 { interrupts = <0x0a>; interrupt-parent = <&plic>; @@ -97,54 +123,12 @@ reg = <0x00 0x10000000 0x00 0x100>; compatible = "ns16550a"; }; - - virtio_mmio@10008000 { - interrupts = <0x8>; - interrupt-parent = <&plic>; - reg = <0x0 0x10008000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - - virtio_mmio@10005000 { - interrupts = <0x5>; - interrupt-parent = <&plic>; - reg = <0x0 0x10005000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - - virtio_mmio@10004000 { - interrupts = <0x4>; - interrupt-parent = <&plic>; - reg = <0x0 0x10004000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - - virtio_mmio@10003000 { - interrupts = <0x3>; - interrupt-parent = <&plic>; - reg = <0x0 0x10003000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - - virtio_mmio@10002000 { - interrupts = <0x2>; - interrupt-parent = <&plic>; - reg = <0x0 0x10002000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - - virtio_mmio@10001000 { - interrupts = <0x1>; - interrupt-parent = <&plic>; - reg = <0x0 0x10001000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; }; hvisor_virtio_device { compatible = "hvisor"; - interrupt-parent = <&plic>; - interrupts = <0x20>; + interrupt-parent = <&plic>; + interrupts = <0x20>; }; chosen { diff --git a/platform/riscv64/qemu-plic/image/dts/zone1-linux.dts b/platform/riscv64/qemu-plic/image/dts/zone1-linux.dts index 2c860395..9583df74 100644 --- a/platform/riscv64/qemu-plic/image/dts/zone1-linux.dts +++ b/platform/riscv64/qemu-plic/image/dts/zone1-linux.dts @@ -1,6 +1,8 @@ /dts-v1/; / { + model = "linux,dummy-virt"; + compatible = "linux,dummy-virt"; #address-cells = <0x02>; #size-cells = <0x02>; @@ -42,9 +44,9 @@ }; }; - memory@83000000 { + memory@85000000 { device_type = "memory"; - reg = <0x00 0x83000000 0x00 0x0C000000>; + reg = <0x00 0x85000000 0x00 0x0a000000>; }; soc { @@ -53,7 +55,7 @@ compatible = "simple-bus"; ranges; - interrupt-controller@c000000 { + plic: interrupt-controller@c000000 { riscv,ndev = <0x3c>; reg = <0x00 0xc000000 0x00 0x4000000>; interrupts-extended = <0x01 0x0b 0x01 0x09 0x03 0x0b 0x03 0x09>; @@ -63,19 +65,44 @@ phandle = <0x02>; }; + pci@30000000 { + interrupt-map-mask = <0x1800 0x00 0x00 0x07>; + interrupt-map = <0x00 0x00 0x00 0x01 &plic 0x20 + 0x00 0x00 0x00 0x02 &plic 0x21 + 0x00 0x00 0x00 0x03 &plic 0x22 + 0x00 0x00 0x00 0x04 &plic 0x23 + 0x800 0x00 0x00 0x01 &plic 0x21 + 0x800 0x00 0x00 0x02 &plic 0x22 + 0x800 0x00 0x00 0x03 &plic 0x23 + 0x800 0x00 0x00 0x04 &plic 0x20 + 0x1000 0x00 0x00 0x01 &plic 0x22 + 0x1000 0x00 0x00 0x02 &plic 0x23 + 0x1000 0x00 0x00 0x03 &plic 0x20 + 0x1000 0x00 0x00 0x04 &plic 0x21 + 0x1800 0x00 0x00 0x01 &plic 0x23 + 0x1800 0x00 0x00 0x02 &plic 0x20 + 0x1800 0x00 0x00 0x03 &plic 0x21 + 0x1800 0x00 0x00 0x04 &plic 0x22>; + ranges = <0x1000000 0x00 0x00 0x00 0x3000000 0x00 0x10000 + 0x2000000 0x00 0x40000000 0x00 0x40000000 0x00 0x40000000 + 0x3000000 0x04 0x00 0x04 0x00 0x04 0x00>; + reg = <0x00 0x30000000 0x00 0x10000000>; + dma-coherent; + bus-range = <0x00 0xff>; + linux,pci-domain = <0x00>; + device_type = "pci"; + compatible = "pci-host-ecam-generic"; + #size-cells = <0x02>; + #interrupt-cells = <0x01>; + #address-cells = <0x03>; + }; + virtio_mmio@10007000 { interrupts = <0x07>; interrupt-parent = <0x02>; reg = <0x00 0x10007000 0x00 0x1000>; compatible = "virtio,mmio"; }; - - virtio_mmio@10006000 { - interrupts = <0x06>; - interrupt-parent = <0x02>; - reg = <0x00 0x10006000 0x00 0x1000>; - compatible = "virtio,mmio"; - }; }; chosen { diff --git a/platform/riscv64/qemu-plic/platform.mk b/platform/riscv64/qemu-plic/platform.mk index 839a7680..498e1c3c 100644 --- a/platform/riscv64/qemu-plic/platform.mk +++ b/platform/riscv64/qemu-plic/platform.mk @@ -2,7 +2,7 @@ QEMU := qemu-system-riscv64 FSIMG1 := $(image_dir)/virtdisk/rootfs1.ext4 -FSIMG2 := $(image_dir)/virtdisk/rootfs-busybox.qcow2 +FSIMG2 := $(image_dir)/virtdisk/rootfs2.ext4 # HVISOR ENTRY HVISOR_ENTRY_PA := 0x80200000 zone0_kernel := $(image_dir)/kernel/Image @@ -23,11 +23,13 @@ QEMU_ARGS += -device loader,file="$(zone0_dtb)",addr=0x8f000000,force-raw=on # QEMU_ARGS += -device loader,file="$(zone1_kernel)",addr=0x84000000,force-raw=on # QEMU_ARGS += -device loader,file="$(zone1_dtb)",addr=0x83000000,force-raw=on -QEMU_ARGS += -drive if=none,file=$(FSIMG1),id=X10008000,format=raw -QEMU_ARGS += -device virtio-blk-device,drive=X10008000,bus=virtio-mmio-bus.7 +QEMU_ARGS += -drive if=none,file=$(FSIMG1),id=hd0,format=raw +# QEMU_ARGS += -device virtio-blk-device,drive=hd0,bus=virtio-mmio-bus.7 +QEMU_ARGS += -device virtio-blk-pci,drive=hd0,disable-legacy=on,disable-modern=off,addr=01.0 QEMU_ARGS += -device virtio-serial-device,bus=virtio-mmio-bus.6 -chardev pty,id=X10007000 -device virtconsole,chardev=X10007000 -S -# QEMU_ARGS += -drive if=none,file=$(FSIMG2),id=X10006000,format=qcow2 -# QEMU_ARGS += -device virtio-blk-device,drive=X10006000,bus=virtio-mmio-bus.5 +QEMU_ARGS += -drive if=none,file=$(FSIMG2),id=hd1,format=raw +# QEMU_ARGS += -device virtio-blk-device,drive=hd1,bus=virtio-mmio-bus.5 +QEMU_ARGS += -device virtio-blk-pci,drive=hd1,disable-legacy=on,disable-modern=off,addr=02.0 # ------------------------------------------------------------------- # QEMU_ARGS := -machine virt diff --git a/platform/riscv64/qemu-plic/scripts/boot_zone1.sh b/platform/riscv64/qemu-plic/scripts/boot_zone1.sh new file mode 100644 index 00000000..889f5fa4 --- /dev/null +++ b/platform/riscv64/qemu-plic/scripts/boot_zone1.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +insmod hvisor.ko +mount -t proc proc /proc +mount -t sysfs sysfs /sys +rm nohup.out +mkdir -p /dev/pts +mount -t devpts devpts /dev/pts +nohup ./hvisor virtio start virtio-backend.json & +./hvisor zone start zone1-linux-virtio.json && \ +cat nohup.out | grep "char device" \ No newline at end of file diff --git a/platform/riscv64/qemu-plic/test/systemtest/boot_zone1.sh b/platform/riscv64/qemu-plic/test/systemtest/boot_zone1.sh index 5b834b23..37913619 100755 --- a/platform/riscv64/qemu-plic/test/systemtest/boot_zone1.sh +++ b/platform/riscv64/qemu-plic/test/systemtest/boot_zone1.sh @@ -2,7 +2,7 @@ rm nohup.out mkdir -p /dev/pts mount -t devpts devpts /dev/pts -nohup ./hvisor virtio start zone1-linux-virtio.json & -./hvisor zone start zone1-linux.json && \ +nohup ./hvisor virtio start virtio-backend.json & +./hvisor zone start zone1-linux-virtio.json && \ cat nohup.out | grep "char device" && \ script /dev/null diff --git a/platform/riscv64/qemu-plic/test/systemtest/tdownload_all.sh b/platform/riscv64/qemu-plic/test/systemtest/tdownload_all.sh index d0843653..3a147f2c 100755 --- a/platform/riscv64/qemu-plic/test/systemtest/tdownload_all.sh +++ b/platform/riscv64/qemu-plic/test/systemtest/tdownload_all.sh @@ -136,6 +136,43 @@ main() { } fi + # Mount rootfs1.ext4, extract /home/riscv64/riscv_rootfs2.img to rootfs2.ext4, then unmount + local ROOTFS_LOOP_MNT="/tmp/hvisor-rootfs1-mnt.$" + + mkdir -p "$ROOTFS_LOOP_MNT" || { + echo -e "${RED}Failed to create mount dir: $ROOTFS_LOOP_MNT${NC}" + exit 1 + } + + echo -e "${YELLOW}Mounting $ROOTFS_FILE to $ROOTFS_LOOP_MNT ...${NC}" + if ! sudo mount -o loop "$ROOTFS_FILE" "$ROOTFS_LOOP_MNT"; then + echo -e "${RED}Failed to mount $ROOTFS_FILE${NC}" + rmdir "$ROOTFS_LOOP_MNT" + exit 1 + fi + + if [ ! -f "$ROOTFS_LOOP_MNT/home/riscv64/riscv_rootfs2.img" ]; then + echo -e "${RED}File not found: $ROOTFS_LOOP_MNT/home/riscv64/riscv_rootfs2.img${NC}" + sudo umount "$ROOTFS_LOOP_MNT" + rmdir "$ROOTFS_LOOP_MNT" + exit 1 + fi + + echo -e "${YELLOW}Copying riscv_rootfs2.img to $UNZIP_DIR/rootfs2.ext4 ...${NC}" + cp "$ROOTFS_LOOP_MNT/home/riscv64/riscv_rootfs2.img" "$UNZIP_DIR/rootfs2.ext4" || { + echo -e "${RED}Failed to copy rootfs2 image${NC}" + sudo umount "$ROOTFS_LOOP_MNT" + rmdir "$ROOTFS_LOOP_MNT" + exit 1 + } + + sudo umount "$ROOTFS_LOOP_MNT" || { + echo -e "${RED}Failed to umount $ROOTFS_LOOP_MNT${NC}" + rmdir "$ROOTFS_LOOP_MNT" + exit 1 + } + rmdir "$ROOTFS_LOOP_MNT" + # Download independent image echo -e "${YELLOW}Downloading image file: $IMAGE_FILE ...${NC}" mkdir -p "$TARGET_DIR" || { diff --git a/platform/riscv64/qemu-plic/test/systemtest/trootfs_deploy.sh b/platform/riscv64/qemu-plic/test/systemtest/trootfs_deploy.sh index c235f292..daa7895d 100755 --- a/platform/riscv64/qemu-plic/test/systemtest/trootfs_deploy.sh +++ b/platform/riscv64/qemu-plic/test/systemtest/trootfs_deploy.sh @@ -52,7 +52,7 @@ deploy_artifacts() { sudo cp -v "${HVISOR_TOOL_DIR}/driver/hvisor.ko" "${dest_dir}/" # Device Tree & Configurations sudo cp -v "${DTS_DIR}/zone1-linux.dtb" "${dest_dir}/zone1-linux.dtb" - sudo cp -v "${CONFIG_DIR}/zone1-linux.json" "${dest_dir}/zone1-linux.json" + sudo cp -v "${CONFIG_DIR}/virtio-backend.json" "${dest_dir}/virtio-backend.json" sudo cp -v "${CONFIG_DIR}/zone1-linux-virtio.json" "${dest_dir}/zone1-linux-virtio.json" # Test artifacts sudo cp -v ${TEST_DIR}/testcase/* "${test_dest}/testcase/" diff --git a/src/arch/riscv64/consts.rs b/src/arch/riscv64/consts.rs index 5bfd0825..68e853a8 100644 --- a/src/arch/riscv64/consts.rs +++ b/src/arch/riscv64/consts.rs @@ -15,6 +15,6 @@ // ForeverYolo <2572131118@qq.com> // PCI constants -pub const HV_ADDR_PREFIX: u64 = 0; -pub const LOONG_HT_PREFIX: u64 = 0; -pub const BDF_SHIFT: usize = 12; +// pub const HV_ADDR_PREFIX: u64 = 0; +// pub const LOONG_HT_PREFIX: u64 = 0; +// pub const BDF_SHIFT: usize = 12; diff --git a/src/arch/riscv64/cpu.rs b/src/arch/riscv64/cpu.rs index 1f036a73..45e0c55a 100644 --- a/src/arch/riscv64/cpu.rs +++ b/src/arch/riscv64/cpu.rs @@ -14,18 +14,17 @@ // Authors: // use super::csr::*; -use crate::arch::Stage2PageTable; use crate::percpu::this_cpu_data; use crate::{ arch::mm::new_s2_memory_set, consts::{PAGE_SIZE, PER_CPU_ARRAY_PTR, PER_CPU_SIZE}, - memory::PhysAddr, memory::{ addr::PHYS_VIRT_OFFSET, mm::PARKING_MEMORY_SET, GuestPhysAddr, HostPhysAddr, MemFlags, - MemoryRegion, MemorySet, VirtAddr, PARKING_INST_PAGE, + MemoryRegion, VirtAddr, PARKING_INST_PAGE, }, zone::find_zone, }; +use core::ptr::addr_of; #[repr(C)] #[derive(Debug)] @@ -84,6 +83,8 @@ impl ArchCpu { self.x[10] = cpu_id; // cpu id self.x[11] = dtb; // dtb addr + // hvisor doesn't handle timer interrupt. + set_csr!(CSR_STIMECMP, usize::MAX); if self.sstc { set_csr!(CSR_HENVCFG, 1 << 63); set_csr!(CSR_VSTIMECMP, usize::MAX); @@ -166,7 +167,9 @@ impl ArchCpu { let mut gpm = new_s2_memory_set(); gpm.insert(MemoryRegion::new_with_offset_mapper( PARKING_INST_GPA as GuestPhysAddr, - unsafe { &PARKING_INST_PAGE as *const _ as HostPhysAddr - PHYS_VIRT_OFFSET }, + unsafe { + addr_of!(PARKING_INST_PAGE) as *const _ as HostPhysAddr - PHYS_VIRT_OFFSET + }, PAGE_SIZE, MemFlags::READ | MemFlags::WRITE | MemFlags::EXECUTE, )) @@ -225,13 +228,13 @@ pub fn cpu_start(cpuid: usize, start_addr: usize, opaque: usize) { } pub fn store_cpu_pointer_to_reg(pointer: usize) { - /// Store the pointer to the current CPU's ArchCpu structure in CSR_SSCRATCH + // Store the pointer to the current CPU's ArchCpu structure in CSR_SSCRATCH write_csr!(CSR_SSCRATCH, pointer); // println!("Stored CPU pointer to CSR_SSCRATCH: {:#x}", pointer); return; } -pub fn get_target_cpu(irq: usize, zone_id: usize) -> usize { +pub fn get_target_cpu(_irq: usize, zone_id: usize) -> usize { find_zone(zone_id) .unwrap() .read() diff --git a/src/arch/riscv64/csr.rs b/src/arch/riscv64/csr.rs index 556d7899..2c1917e4 100644 --- a/src/arch/riscv64/csr.rs +++ b/src/arch/riscv64/csr.rs @@ -89,6 +89,7 @@ macro_rules! write_csr { } pub(crate) use write_csr; +#[allow(unused)] macro_rules! clear_csr { ($csr_number:expr, $value: expr) => { unsafe{ @@ -100,6 +101,7 @@ macro_rules! clear_csr { options(nomem, nostack),)} }; } +#[allow(unused)] pub(crate) use clear_csr; macro_rules! set_csr { diff --git a/src/arch/riscv64/entry.rs b/src/arch/riscv64/entry.rs index 653ab9f0..936ce2ae 100644 --- a/src/arch/riscv64/entry.rs +++ b/src/arch/riscv64/entry.rs @@ -13,7 +13,6 @@ // // Authors: // -use crate::clear_bss; use crate::consts::PER_CPU_SIZE; #[no_mangle] #[link_section = ".data"] diff --git a/src/arch/riscv64/hypercall.rs b/src/arch/riscv64/hypercall.rs index ee37e015..ab8f4a19 100644 --- a/src/arch/riscv64/hypercall.rs +++ b/src/arch/riscv64/hypercall.rs @@ -15,18 +15,18 @@ // ForeverYolo <2572131118@qq.com> use crate::arch::cpu::this_cpu_id; -use crate::config::{HvZoneConfig, CONFIG_MAGIC_VERSION}; +use crate::config::CONFIG_MAGIC_VERSION; use crate::device::virtio_trampoline::MAX_DEVS; use crate::hypercall::HyperCall; use crate::hypercall::HyperCallResult; impl<'a> HyperCall<'a> { - pub fn hv_ivc_info(&mut self, ivc_info_ipa: u64) -> HyperCallResult { + pub fn hv_ivc_info(&mut self, _ivc_info_ipa: u64) -> HyperCallResult { warn!("hv_ivc_info is not implemented for Risc-V"); HyperCallResult::Ok(0) } - pub fn wait_for_interrupt(&mut self, irq_list: &mut [u64; MAX_DEVS + 1]) { + pub fn wait_for_interrupt(&mut self, _irq_list: &mut [u64; MAX_DEVS + 1]) { trace!("wait_for_interrupt is not need for RISC-V"); } @@ -46,6 +46,7 @@ impl<'a> HyperCall<'a> { return config_addr; } + #[allow(unused)] pub fn hv_get_real_list_pa(&mut self, list_addr: u64) -> u64 { // RISC-V does not have a specific prefix for cached memory, so we return the address as is. return list_addr; @@ -56,7 +57,7 @@ impl<'a> HyperCall<'a> { trace!("CPU ID: {} Start Zone", cpuid); } - pub fn hv_virtio_get_irq(&self, virtio_irq: *mut u32) -> HyperCallResult { + pub fn hv_virtio_get_irq(&self, _virtio_irq: *mut u32) -> HyperCallResult { trace!("hv_virtio_get_irq is not need for RISC-V"); HyperCallResult::Ok(0) } diff --git a/src/arch/riscv64/iommu.rs b/src/arch/riscv64/iommu.rs index fd0d60bd..5bc86493 100644 --- a/src/arch/riscv64/iommu.rs +++ b/src/arch/riscv64/iommu.rs @@ -14,10 +14,12 @@ // Authors: // ForeverYolo <2572131118@qq.com> +#[allow(unused)] pub fn iommu_init() { info!("riscv: iommu_init: do nothing now"); } +#[allow(unused)] pub fn iommu_add_device(vmid: usize, sid: usize) { info!( "riscv: iommu_add_device: do nothing now, vmid: {}, sid: {}", diff --git a/src/arch/riscv64/ipi.rs b/src/arch/riscv64/ipi.rs index 97a59791..d13c15f9 100644 --- a/src/arch/riscv64/ipi.rs +++ b/src/arch/riscv64/ipi.rs @@ -13,9 +13,9 @@ // // Authors: // -use crate::consts::{IPI_EVENT_SEND_IPI, IPI_EVENT_UPDATE_HART_LINE}; -use sbi_rt::HartMask; -use sbi_rt::SbiRet; +use crate::consts::IPI_EVENT_SEND_IPI; +#[cfg(feature = "plic")] +use crate::consts::IPI_EVENT_UPDATE_HART_LINE; // arch_send_event pub fn arch_send_event(cpu_id: u64, _sgi_num: u64) { @@ -24,7 +24,8 @@ pub fn arch_send_event(cpu_id: u64, _sgi_num: u64) { crate::device::irqchip::aclint::aclint_send_ipi(cpu_id as usize); #[cfg(not(feature = "aclint"))] { - let sbi_ret: SbiRet = sbi_rt::send_ipi(HartMask::from_mask_base(1 << cpu_id, 0)); + let sbi_ret: sbi_rt::SbiRet = + sbi_rt::send_ipi(sbi_rt::HartMask::from_mask_base(1 << cpu_id, 0)); if sbi_ret.is_err() { error!("arch_send_event: send_ipi failed: {:?}", sbi_ret); } @@ -55,6 +56,6 @@ pub fn arch_check_events(event: Option) { } } -pub fn arch_prepare_send_event(cpu_id: usize, ipi_int_id: usize, event_id: usize) { +pub fn arch_prepare_send_event(_cpu_id: usize, _ipi_int_id: usize, _event_id: usize) { debug!("risc-v arch_prepare_send_event: do nothing now.") } diff --git a/src/arch/riscv64/mm.rs b/src/arch/riscv64/mm.rs index fcdfaed0..2d9004e0 100644 --- a/src/arch/riscv64/mm.rs +++ b/src/arch/riscv64/mm.rs @@ -13,14 +13,10 @@ // // Authors: // -use spin::RwLock; -use crate::{ - arch::Stage2PageTable, - error::HvResult, - memory::{addr::align_up, GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet}, -}; +use crate::{arch::Stage2PageTable, error::HvResult, memory::MemorySet}; +#[allow(unused)] pub fn init_hv_page_table() -> HvResult { todo!(); // let mut hv_pt: MemorySet = MemorySet::new(); @@ -146,7 +142,7 @@ pub fn arch_setup_parange() { // So we do not need to do anything here. } -pub fn arch_post_heap_init(host_dtb: usize) { +pub fn arch_post_heap_init(_host_dtb: usize) { // RISC-V does not need to do some setup work after heap init like x86_64. // This function can be used to set up any architecture-specific parameters if needed. // Currently, it does nothing. diff --git a/src/arch/riscv64/mod.rs b/src/arch/riscv64/mod.rs index 3c31bf95..897c7e42 100644 --- a/src/arch/riscv64/mod.rs +++ b/src/arch/riscv64/mod.rs @@ -13,6 +13,11 @@ // // Authors: // +#![deny(unused_variables)] +#![deny(unused_imports)] +#![deny(unused_mut)] +#![deny(unused)] + pub mod consts; pub mod cpu; pub mod csr; @@ -29,6 +34,6 @@ pub mod time; pub mod trap; pub mod zone; -pub use s1pt::Stage1PageTable; +// pub use s1pt::Stage1PageTable; pub use s2pt::stage2_mode_detect; pub use s2pt::Stage2PageTable; diff --git a/src/arch/riscv64/paging.rs b/src/arch/riscv64/paging.rs index 99928f05..963b3eab 100644 --- a/src/arch/riscv64/paging.rs +++ b/src/arch/riscv64/paging.rs @@ -71,6 +71,7 @@ impl PageSize { addr & (self as usize - 1) } + #[allow(unused)] pub const fn is_huge(self) -> bool { !matches!(self, Self::Size4K) } @@ -127,6 +128,7 @@ pub trait GenericPageTable: GenericPageTableImmut { fn map(&mut self, region: &MemoryRegion) -> HvResult; fn unmap(&mut self, region: &MemoryRegion) -> HvResult; + #[allow(unused)] fn update( &mut self, vaddr: Self::VA, @@ -137,6 +139,7 @@ pub trait GenericPageTable: GenericPageTableImmut { fn clone(&self) -> Self; unsafe fn activate(&self); + #[allow(unused)] fn flush(&self, vaddr: Option); } @@ -335,7 +338,7 @@ where fn get_entry_mut_or_create( &mut self, page: Page, - flags: &mut MemFlags, + _flags: &mut MemFlags, ) -> PagingResult<&mut PTE> { let vaddr: usize = page.vaddr.into(); // Current hvisor don't support huge page which > 1G. diff --git a/src/arch/riscv64/sbi.rs b/src/arch/riscv64/sbi.rs index f4e3f221..bac0c49f 100644 --- a/src/arch/riscv64/sbi.rs +++ b/src/arch/riscv64/sbi.rs @@ -21,7 +21,7 @@ use crate::consts::IPI_EVENT_SEND_IPI; use crate::event::{send_event, IPI_EVENT_WAKEUP}; use crate::hypercall::HyperCall; use crate::percpu::{get_cpu_data, this_cpu_data}; -use core::sync::atomic::{self, Ordering}; +use core::sync::atomic; use riscv::register::sie; use riscv_h::register::hvip; use sbi_rt::{HartMask, SbiRet}; @@ -65,6 +65,7 @@ pub fn sbi_vs_handler(current_cpu: &mut ArchCpu) { // a6 encodes the SBI function ID (FID) let eid: usize = current_cpu.x[17]; let fid: usize = current_cpu.x[16]; + // info!("SBI call: EID={:#x}, FID={:#x}", eid, fid); let sbi_ret; match eid { // Base Extension (SBI Spec Chapter 4) @@ -211,6 +212,7 @@ pub fn sbi_time_handler(fid: usize, current_cpu: &mut ArchCpu) -> SbiRet { } #[allow(unused)] +#[allow(non_camel_case_types)] #[derive(Debug, PartialEq)] pub enum HSM_STATUS { STARTED, diff --git a/src/arch/riscv64/time.rs b/src/arch/riscv64/time.rs index 58f62f94..77b4f6be 100644 --- a/src/arch/riscv64/time.rs +++ b/src/arch/riscv64/time.rs @@ -20,41 +20,49 @@ use riscv::register::time; static mut TIMEBASE: u64 = 0; /// Note: You should call this function once during initialization. +#[allow(unused)] pub fn init_timebase() { unsafe { TIMEBASE = time::read() as u64; } } +#[allow(unused)] pub fn get_timebase() -> u64 { unsafe { TIMEBASE } } +#[allow(unused)] pub fn get_timefreq() -> u64 { TIMEBASE_FREQ } +#[allow(unused)] pub fn read_time() -> u64 { // Now only support 64-bit system. time::read() as u64 } /// Return time in nanoseconds since some arbitrary point in the past. +#[allow(unused)] pub fn get_time_ns() -> u64 { unsafe { (read_time() - TIMEBASE) * 1_000_000_000 / TIMEBASE_FREQ } } /// Return time in seconds since some arbitrary point in the past. +#[allow(unused)] pub fn get_time_us() -> u64 { unsafe { (read_time() - TIMEBASE) * 1_000_000 / TIMEBASE_FREQ } } /// Return time in seconds since some arbitrary point in the past. +#[allow(unused)] pub fn get_time_ms() -> u64 { unsafe { (read_time() - TIMEBASE) * 1_000 / TIMEBASE_FREQ } } /// Return time in seconds since some arbitrary point in the past. +#[allow(unused)] pub fn get_time_s() -> u64 { unsafe { (read_time() - TIMEBASE) / TIMEBASE_FREQ } } diff --git a/src/arch/riscv64/trap.rs b/src/arch/riscv64/trap.rs index f1563fdc..e1fc1bca 100644 --- a/src/arch/riscv64/trap.rs +++ b/src/arch/riscv64/trap.rs @@ -14,15 +14,10 @@ // Authors: // use super::cpu::ArchCpu; -use crate::arch::csr::read_csr; -use crate::arch::csr::*; use crate::arch::sbi::sbi_vs_handler; -use crate::consts::{IPI_EVENT_SEND_IPI, IPI_EVENT_UPDATE_HART_LINE}; use crate::event::check_events; +use crate::memory::GuestPhysAddr; use crate::memory::{mmio_handle_access, MMIOAccess}; -use crate::memory::{GuestPhysAddr, HostPhysAddr}; -use crate::percpu::this_cpu_data; -use crate::platform::__board::*; use core::arch::{asm, global_asm}; use riscv::register::stvec::TrapMode; use riscv::register::{sie, stvec}; @@ -37,7 +32,7 @@ global_asm!(include_str!("trap.S"), sync_exception_handler=sym sync_exception_handler, interrupts_arch_handle=sym interrupts_arch_handle); -#[allow(non_snake_case)] +#[allow(non_snake_case, unused)] pub mod ExceptionType { pub const ECALL_VU: usize = 8; pub const ECALL_VS: usize = 10; @@ -94,7 +89,7 @@ pub const INS_C_LW: usize = 0x4000; // [15:13] = 0b010, [1:0] = 0b00 pub const INS_C_SW: usize = 0xc000; // [15:13] = 0b110, [1:0] = 0b00 pub const INS_C_LD: usize = 0x6000; // [15:13] = 0b011, [1:0] = 0b00 pub const INS_C_SD: usize = 0xe000; // [15:13] = 0b111, [1:0] = 0b00 - +#[allow(unused)] pub const INS_RS1_MASK: usize = 0x000f8000; pub const INS_RS2_MASK: usize = 0x01f00000; pub const INS_RD_MASK: usize = 0x00000f80; @@ -197,7 +192,7 @@ pub fn ins_ldst_decode(ins: usize) -> (usize, bool, bool, usize) { ins ); } - let size = if (ins_is_cld || ins_is_csd) { 8 } else { 4 }; + let size = if ins_is_cld || ins_is_csd { 8 } else { 4 }; let is_write = ins_is_csw || ins_is_csd; // Decode register number. let reg = ((ins >> 2) & 0x7) + 8; @@ -244,7 +239,7 @@ pub fn guest_page_fault_handler(current_cpu: &mut ArchCpu) { // htinst: Hypervisor trap instruction (transformed). let mut trap_ins = htinst::read(); // Default instruction size is 4 bytes. - let mut ins_size = 4; + let ins_size; /* * According riscv spec, htinst is one of the following: * 1. zero; @@ -359,6 +354,7 @@ fn hlvxhu(addr: GuestPhysAddr) -> u64 { } /// Decode risc-v instruction, return (inst len, inst). +#[allow(unused)] fn decode_inst(inst: u32) -> (usize, Option) { let i1 = inst as u16; let len = riscv_decode::instruction_length(i1); @@ -372,8 +368,11 @@ fn decode_inst(inst: u32) -> (usize, Option) { /// Handle interrupts which hvisor receives. pub fn interrupts_arch_handle(current_cpu: &mut ArchCpu) { - trace!("interrupts_arch_handle @CPU{}", current_cpu.cpuid); - let trap_code = unsafe { riscv::register::scause::read().code() }; + let trap_code = riscv::register::scause::read().code(); + debug!( + "interrupts_arch_handle @CPU{}: {:?}", + current_cpu.cpuid, trap_code + ); match trap_code { InterruptType::STI => { // Inject timer interrupt to VS. @@ -398,7 +397,7 @@ pub fn interrupts_arch_handle(current_cpu: &mut ArchCpu) { } /// Handle supervisor timer interrupt. -pub fn handle_timer_interrupt(current_cpu: &mut ArchCpu) { +pub fn handle_timer_interrupt(_current_cpu: &mut ArchCpu) { unsafe { hvip::set_vstip(); sie::clear_stimer(); @@ -406,7 +405,7 @@ pub fn handle_timer_interrupt(current_cpu: &mut ArchCpu) { } /// Handle supervisor software interrupt. -pub fn handle_software_interrupt(current_cpu: &mut ArchCpu) { +pub fn handle_software_interrupt(_current_cpu: &mut ArchCpu) { while check_events() { // Get next event to handle, it is handled in check_events function. } @@ -416,12 +415,13 @@ pub fn handle_software_interrupt(current_cpu: &mut ArchCpu) { } /// Handle supervisor external interrupt. -pub fn handle_external_interrupt(current_cpu: &mut ArchCpu) { +pub fn handle_external_interrupt(_current_cpu: &mut ArchCpu) { #[cfg(feature = "plic")] { // Note: in hvisor, all external interrupts are assigned to VS. // 1. claim hw irq. - let context_id = 2 * this_cpu_data().id + 1; + use crate::arch::cpu::this_cpu_id; + let context_id = 2 * this_cpu_id() + 1; let irq_id = crate::device::irqchip::plic::host_plic().claim(context_id); // If this irq has been claimed, it will be 0. diff --git a/src/arch/riscv64/zone.rs b/src/arch/riscv64/zone.rs index 81a02c5b..1f53e97d 100644 --- a/src/arch/riscv64/zone.rs +++ b/src/arch/riscv64/zone.rs @@ -14,12 +14,10 @@ // Authors: // use crate::{ - arch::Stage2PageTable, config::*, - device::virtio_trampoline::{mmio_virtio_handler, VIRTIO_BRIDGE}, + device::virtio_trampoline::mmio_virtio_handler, error::HvResult, - memory::{addr::align_up, GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet}, - percpu::get_cpu_data, + memory::{GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion}, zone::Zone, }; impl Zone { @@ -57,13 +55,13 @@ impl Zone { Ok(()) } - pub fn arch_zone_pre_configuration(&mut self, config: &HvZoneConfig) -> HvResult { + pub fn arch_zone_pre_configuration(&mut self, _config: &HvZoneConfig) -> HvResult { // We do not have any specific architecture configuration for RISC-V. // If needed, this function can be extended in the future. Ok(()) } - pub fn arch_zone_post_configuration(&mut self, config: &HvZoneConfig) -> HvResult { + pub fn arch_zone_post_configuration(&mut self, _config: &HvZoneConfig) -> HvResult { Ok(()) } } diff --git a/src/device/irqchip/aia/mod.rs b/src/device/irqchip/aia/mod.rs index 9043dc85..93b4f5f5 100644 --- a/src/device/irqchip/aia/mod.rs +++ b/src/device/irqchip/aia/mod.rs @@ -23,9 +23,8 @@ pub mod vimsic; use crate::arch::cpu::this_cpu_id; use crate::arch::zone::HvArchZoneConfig; use crate::config::{BitmapWord, HvZoneConfig, CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD}; -use crate::consts::{MAX_CPU_NUM, MAX_ZONE_NUM}; +use crate::consts::MAX_ZONE_NUM; use crate::error::HvResult; -use crate::memory::GuestPhysAddr; use crate::memory::HostPhysAddr; use crate::memory::MMIOAccess; use crate::memory::MemFlags; diff --git a/src/device/irqchip/mod.rs b/src/device/irqchip/mod.rs index de616fd3..0d74c011 100644 --- a/src/device/irqchip/mod.rs +++ b/src/device/irqchip/mod.rs @@ -124,7 +124,7 @@ pub mod aclint; pub mod plic; #[cfg(all(feature = "plic", target_arch = "riscv64"))] -pub use plic::{host_plic, inject_irq, percpu_init, primary_init_late}; +pub use plic::{inject_irq, percpu_init, primary_init_late}; #[cfg(all(feature = "aia", target_arch = "riscv64"))] pub mod aia; diff --git a/src/device/irqchip/plic/mod.rs b/src/device/irqchip/plic/mod.rs index 243580c8..efb6c0a5 100644 --- a/src/device/irqchip/plic/mod.rs +++ b/src/device/irqchip/plic/mod.rs @@ -26,16 +26,12 @@ use crate::config::{BitmapWord, CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD}; use crate::consts::{MAX_CPU_NUM, MAX_ZONE_NUM}; use crate::error::HvResult; use crate::memory::mmio::MMIOAccess; -use crate::memory::GuestPhysAddr; -use crate::percpu::this_zone; +use crate::percpu::this_cpu_data; use crate::platform::__board::*; use crate::platform::BOARD_PLIC_INTERRUPTS_NUM; use crate::zone::Zone; -use crate::{arch::cpu::ArchCpu, percpu::this_cpu_data}; use alloc::vec::Vec; use heapless::FnvIndexMap; -use riscv_decode::Instruction; -use riscv_h::register::hvip; use spin::Once; /* @@ -105,7 +101,7 @@ pub fn vcontext_to_pcontext(vcontext_id: usize) -> usize { } /// Convert pcontext id to vcontext id. -pub fn pcontext_to_vcontext(pcontext_id: usize) -> usize { +pub fn pcontext_to_vcontext(_pcontext_id: usize) -> usize { // vcpu is the pcpus index of the pcpu_set let pcpu_set = this_cpu_data() .zone @@ -206,7 +202,7 @@ impl Zone { // We should make sure only one cpu to do this. // This func will only be called by one root zone's cpu. let host_plic = host_plic(); - let vplic = self.get_vplic(); + // let vplic = self.get_vplic(); for (index, &word) in self.irq_bitmap.iter().enumerate() { for bit_position in 0..32 { if word & (1 << bit_position) != 0 { diff --git a/src/device/irqchip/plic/vplic.rs b/src/device/irqchip/plic/vplic.rs index 91d057a7..bc05395f 100644 --- a/src/device/irqchip/plic/vplic.rs +++ b/src/device/irqchip/plic/vplic.rs @@ -78,6 +78,7 @@ impl VirtualPLIC { } /// Get one interrupt as hardware interrupt. + #[allow(unused)] pub fn vplic_get_hw(&self, intr_id: usize) -> bool { let inner = self.inner.lock(); inner.vplic_get_hw(intr_id) @@ -113,7 +114,7 @@ impl VirtualPLIC { } pub fn update_hart_line(&self, vcontext_id: usize) { - let mut inner = self.inner.lock(); + let inner = self.inner.lock(); inner.vplic_update_hart_line(vcontext_id); } @@ -197,7 +198,7 @@ impl VirtualPLIC { let irq_start = bits; let irq_end = bits + 31; let mut pending = 0; - let mut inner = self.inner.lock(); + let inner = self.inner.lock(); // irq_end isn't beyond max_interrupts. for irq in irq_start..=irq_end.min(self.max_interrupts) { pending |= (inner.vplic_get_pending(irq) as u32) << (irq - irq_start); diff --git a/src/device/virtio_trampoline.rs b/src/device/virtio_trampoline.rs index ebd851b7..c58b7fed 100644 --- a/src/device/virtio_trampoline.rs +++ b/src/device/virtio_trampoline.rs @@ -20,7 +20,6 @@ use crate::device::irqchip::inject_irq; use crate::event::send_event; use crate::event::IPI_EVENT_WAKEUP_VIRTIO_DEVICE; use crate::hypercall::SGI_IPI_ID; -use crate::zone::root_zone; use crate::zone::this_zone_id; use crate::{error::HvResult, memory::MMIOAccess}; use alloc::collections::BTreeMap; diff --git a/src/hypercall/mod.rs b/src/hypercall/mod.rs index 5065b324..b4eb67b0 100644 --- a/src/hypercall/mod.rs +++ b/src/hypercall/mod.rs @@ -17,14 +17,13 @@ #![allow(unreachable_patterns)] use crate::arch::cpu::get_target_cpu; -use crate::config::{HvZoneConfig, CONFIG_MAGIC_VERSION}; +use crate::config::HvZoneConfig; use crate::consts::{INVALID_ADDRESS, MAX_CPU_NUM, MAX_WAIT_TIMES, PAGE_SIZE}; use crate::device::virtio_trampoline::{MAX_DEVS, MAX_REQ, VIRTIO_BRIDGE, VIRTIO_IRQS}; use crate::error::HvResult; -use crate::percpu::{get_cpu_data, this_zone, PerCpu}; +use crate::percpu::{get_cpu_data, PerCpu}; use crate::zone::{ - add_zone, all_zones_info, find_zone, is_this_root_zone, remove_zone, this_zone_id, zone_create, - ZoneInfo, + add_zone, all_zones_info, find_zone, is_this_root_zone, remove_zone, zone_create, ZoneInfo, }; use crate::event::{send_event, IPI_EVENT_SHUTDOWN, IPI_EVENT_VIRTIO_INJECT_IRQ, IPI_EVENT_WAKEUP}; diff --git a/src/pci/pci_handler.rs b/src/pci/pci_handler.rs index fcc6133f..235214f6 100644 --- a/src/pci/pci_handler.rs +++ b/src/pci/pci_handler.rs @@ -468,6 +468,11 @@ fn handle_endpoint_access( (vbdf.device << 3) + vbdf.function, ); } + #[cfg(target_arch = "riscv64")] + unsafe { + // TOOD: add remote fence support (using sbi rfence spec?) + core::arch::asm!("hfence.gvma"); + } } Ok(None) } else { From 3abdf102440da09e2d10a92b3fae28943f324871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=AF=E5=AE=87?= <2537738252@qq.com> Date: Fri, 16 Jan 2026 23:07:01 +0800 Subject: [PATCH 081/109] optimize some pci log --- src/config.rs | 2 +- src/pci/pci_config.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/config.rs b/src/config.rs index 7b4bad30..aecc2759 100644 --- a/src/config.rs +++ b/src/config.rs @@ -238,7 +238,7 @@ impl Debug for HvPciDevConfig { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let bdf = crate::pci::pci_struct::Bdf::new(self.domain, self.bus, self.device, self.function); - write!(f, "bdf {:#?}", bdf) + write!(f, "bdf {:#x?}", bdf) } } diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index c0704320..89d1b7af 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -67,7 +67,7 @@ pub static GLOBAL_PCIE_LIST: Lazy HvResult { - warn!("begin {:#?}", pci_config); + warn!("begin {:#x?}", pci_config); #[cfg(any( feature = "ecam_pcie", feature = "dwc_pcie", @@ -151,7 +151,7 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { let domain = rootcomplex_config.domain; let e = rootcomplex.enumerate(Some(range), domain, allocator_opt); - info!("begin enumerate {:#?}", e); + info!("begin enumerate {:#x?}", e); for node in e { info!("node {:#?}", node); GLOBAL_PCIE_LIST @@ -311,7 +311,7 @@ impl Zone { } } } - info!("vpci bus init done\n {:#?}", self.vpci_bus); + info!("vpci bus init done\n {:#x?}", self.vpci_bus); Ok(()) } From 1c870f66bdb438d972f4b2c8b588af9e95f8f206 Mon Sep 17 00:00:00 2001 From: Jingyu Liu <86109975+liulog@users.noreply.github.com> Date: Tue, 20 Jan 2026 20:24:42 +0800 Subject: [PATCH 082/109] riscv64: disable timer interrupt handling in hvisor --- src/arch/riscv64/cpu.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arch/riscv64/cpu.rs b/src/arch/riscv64/cpu.rs index 45e0c55a..f38eba43 100644 --- a/src/arch/riscv64/cpu.rs +++ b/src/arch/riscv64/cpu.rs @@ -83,9 +83,9 @@ impl ArchCpu { self.x[10] = cpu_id; // cpu id self.x[11] = dtb; // dtb addr - // hvisor doesn't handle timer interrupt. - set_csr!(CSR_STIMECMP, usize::MAX); if self.sstc { + // hvisor doesn't handle timer interrupt. + set_csr!(CSR_STIMECMP, usize::MAX); set_csr!(CSR_HENVCFG, 1 << 63); set_csr!(CSR_VSTIMECMP, usize::MAX); } else { From 880ab15f51dfbb20ddf1c134d9ba3565aa9b7750 Mon Sep 17 00:00:00 2001 From: dallas Date: Tue, 20 Jan 2026 20:54:38 +0800 Subject: [PATCH 083/109] 1. pci log reorganized 2.fix rom read when get size --- src/pci/pci_config.rs | 2 +- src/pci/pci_handler.rs | 161 +++++++++++++++++++++-------------------- 2 files changed, 84 insertions(+), 79 deletions(-) diff --git a/src/pci/pci_config.rs b/src/pci/pci_config.rs index 89d1b7af..34f881fc 100644 --- a/src/pci/pci_config.rs +++ b/src/pci/pci_config.rs @@ -112,7 +112,7 @@ pub fn hvisor_pci_init(pci_config: &[HvPciConfig]) -> HvResult { let mut rootcomplex = { #[cfg(feature = "dwc_pcie")] { - warn!("dwc pcie"); + // warn!("dwc pcie"); let ecam_base = rootcomplex_config.ecam_base; let atu_config = platform::ROOT_DWC_ATU_CONFIG .iter() diff --git a/src/pci/pci_handler.rs b/src/pci/pci_handler.rs index 235214f6..dafc4650 100644 --- a/src/pci/pci_handler.rs +++ b/src/pci/pci_handler.rs @@ -167,12 +167,12 @@ fn handle_endpoint_access( Ok(Some(ROOT_UNUSED_DEVICE_ID)) } else { // id is readonly (when is_write is true) - warn!( - "vbdf {:#?}: unhandled {:#?} {}", - dev.get_vbdf(), - field, - if is_write { "write" } else { "read" } - ); + // warn!( + // "vbdf {:#?}: unhandled {:#?} {}", + // dev.get_vbdf(), + // field, + // if is_write { "write" } else { "read" } + // ); Ok(None) } } @@ -280,8 +280,8 @@ fn handle_endpoint_access( } }; - info!("new_vaddr: {:#x}", new_vaddr); - info!("old_vaddr: {:#x}", old_vaddr); + // info!("new_vaddr: {:#x}", new_vaddr); + // info!("old_vaddr: {:#x}", old_vaddr); dev.with_bar_ref_mut(slot, |bar| bar.set_virtual_value(new_vaddr)); if bar_type == PciMemType::Mem64High { dev.with_bar_ref_mut(slot - 1, |bar| { @@ -391,87 +391,92 @@ fn handle_endpoint_access( configvalue.set_rom_value(value as u32); }); dev.write_hw(field.to_offset() as PciConfigAddress, field.size(), value)?; + if value & 0xfffff800 != 0xfffff800 { + let new_vaddr = (value as u64) & !0xf; - let new_vaddr = (value as u64) & !0xf; + // set virt_value + dev.with_rom_ref_mut(|rom| rom.set_virtual_value(new_vaddr)); - // set virt_value - dev.with_rom_ref_mut(|rom| rom.set_virtual_value(new_vaddr)); - - // set value - dev.with_rom_ref_mut(|rom| rom.set_value(new_vaddr)); + // set value + dev.with_rom_ref_mut(|rom| rom.set_value(new_vaddr)); + } } else if is_dev_belong_to_zone { // normal mode, update virt resources dev.with_config_value_mut(|configvalue| { configvalue.set_rom_value(value as u32); }); - let old_vaddr = dev.with_rom_ref(|rom| rom.get_virtual_value64()) & !0xf; - let new_vaddr = (value as u64) & !0xf; + if value & 0xfffff800 != 0xfffff800 { + let old_vaddr = + dev.with_rom_ref(|rom| rom.get_virtual_value64()) & !0xf; + let new_vaddr = (value as u64) & !0xf; - dev.with_rom_ref_mut(|rom| rom.set_virtual_value(new_vaddr)); + dev.with_rom_ref_mut(|rom| rom.set_virtual_value(new_vaddr)); - let paddr = if is_root { - dev.with_rom_ref_mut(|rom| rom.set_value(new_vaddr)); - new_vaddr as HostPhysAddr - } else { - dev.with_rom_ref(|rom| rom.get_value64()) as HostPhysAddr - }; - - let rom_size = { - let size = dev.with_rom_ref(|rom| rom.get_size()); - if crate::memory::addr::is_aligned(size as usize) { - size + let paddr = if is_root { + dev.with_rom_ref_mut(|rom| rom.set_value(new_vaddr)); + new_vaddr as HostPhysAddr + } else { + dev.with_rom_ref(|rom| rom.get_value64()) as HostPhysAddr + }; + + let rom_size = { + let size = dev.with_rom_ref(|rom| rom.get_size()); + if crate::memory::addr::is_aligned(size as usize) { + size + } else { + crate::memory::PAGE_SIZE as u64 + } + }; + let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) + { + crate::memory::addr::align_up(new_vaddr as usize) as u64 } else { - crate::memory::PAGE_SIZE as u64 + new_vaddr as u64 + }; + + let zone = this_zone(); + let mut guard = zone.write(); + let gpm = &mut guard.gpm; + + if !gpm + .try_delete(old_vaddr.try_into().unwrap(), rom_size as usize) + .is_ok() + { + // warn!("delete rom bar: can not found 0x{:x}", old_vaddr); + } + gpm.try_insert_quiet(MemoryRegion::new_with_offset_mapper( + new_vaddr as GuestPhysAddr, + paddr as HostPhysAddr, + rom_size as _, + MemFlags::READ | MemFlags::WRITE, + ))?; + drop(guard); + /* after update gpm, mem barrier is needed + */ + #[cfg(target_arch = "aarch64")] + unsafe { + core::arch::asm!("isb"); + core::arch::asm!("tlbi vmalls12e1is"); + core::arch::asm!("dsb nsh"); + } + /* after update gpm, need to flush iommu table + * in x86_64 + */ + #[cfg(target_arch = "x86_64")] + { + let vbdf = dev.get_vbdf(); + crate::arch::iommu::flush( + this_zone_id(), + vbdf.bus, + (vbdf.device << 3) + vbdf.function, + ); + } + #[cfg(target_arch = "riscv64")] + unsafe { + // TOOD: add remote fence support (using sbi rfence spec?) + core::arch::asm!("hfence.gvma"); } - }; - let new_vaddr = if !crate::memory::addr::is_aligned(new_vaddr as usize) { - crate::memory::addr::align_up(new_vaddr as usize) as u64 - } else { - new_vaddr as u64 - }; - - let zone = this_zone(); - let mut guard = zone.write(); - let gpm = &mut guard.gpm; - - if !gpm - .try_delete(old_vaddr.try_into().unwrap(), rom_size as usize) - .is_ok() - { - // warn!("delete rom bar: can not found 0x{:x}", old_vaddr); - } - gpm.try_insert_quiet(MemoryRegion::new_with_offset_mapper( - new_vaddr as GuestPhysAddr, - paddr as HostPhysAddr, - rom_size as _, - MemFlags::READ | MemFlags::WRITE, - ))?; - drop(guard); - /* after update gpm, mem barrier is needed - */ - #[cfg(target_arch = "aarch64")] - unsafe { - core::arch::asm!("isb"); - core::arch::asm!("tlbi vmalls12e1is"); - core::arch::asm!("dsb nsh"); - } - /* after update gpm, need to flush iommu table - * in x86_64 - */ - #[cfg(target_arch = "x86_64")] - { - let vbdf = dev.get_vbdf(); - crate::arch::iommu::flush( - this_zone_id(), - vbdf.bus, - (vbdf.device << 3) + vbdf.function, - ); - } - #[cfg(target_arch = "riscv64")] - unsafe { - // TOOD: add remote fence support (using sbi rfence spec?) - core::arch::asm!("hfence.gvma"); } } Ok(None) @@ -712,7 +717,7 @@ pub fn mmio_dwc_io_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { #[cfg(feature = "dwc_pcie")] pub fn mmio_dwc_cfg_handler(mmio: &mut MMIOAccess, _base: usize) -> HvResult { - info!("mmio_dwc_cfg_handler {:#x}", mmio.address + _base); + // info!("mmio_dwc_cfg_handler {:#x}", mmio.address + _base); let zone = this_zone(); let guard = zone.read(); From 25fb9d5e64e1d542dfad6b6fba78cfd19d2ea5f0 Mon Sep 17 00:00:00 2001 From: dallas Date: Tue, 20 Jan 2026 21:51:12 +0800 Subject: [PATCH 084/109] 1.The logic for bar initialization has been adjusted for direct mode. 2.The method for inspecting bridges has been adjusted; now only PCI-PCI bridges are inspected. --- src/pci/pci_access.rs | 12 ++++++------ src/pci/pci_handler.rs | 5 +++-- src/pci/pci_struct.rs | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index d78a2344..dc891bd9 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -440,8 +440,8 @@ impl Debug for Bar { let mut is_null = true; while i < self.bararr.len() { let bar = &self.bararr[i]; - let address = bar.value & !0xf; - // let address = bar.value; + let address = bar.virtual_value & !0xf; + // let address = bar.virtual_value; match bar.bar_type { PciMemType::Mem32 => { is_null = false; @@ -473,7 +473,7 @@ impl Debug for Bar { i += 1; } PciMemType::Io => { - writeln!(f, " IO @ 0x{:x}", bar.value)?; + write!(f, "\n IO @ 0x{:x}", bar.value)?; } _ => {} } @@ -624,12 +624,12 @@ pub trait PciBarRW: PciRWBase { 1u64 << ((readback_high.trailing_zeros() + 32) as u64) } }; - // let value64 = (value as u64) | ((value_high as u64) << 32); + let value64 = (value as u64) | ((value_high as u64) << 32); bararr[slot as usize] = - PciMem::new_bar(PciMemType::Mem64Low, value as u64, size, pre); + PciMem::new_bar(PciMemType::Mem64Low, value64, size, pre); bararr[(slot + 1) as usize] = - PciMem::new_bar(PciMemType::Mem64High, value_high as u64, size, pre); + PciMem::new_bar(PciMemType::Mem64High, value64, size, pre); slot += 1; // need extra add 1 } _ => { diff --git a/src/pci/pci_handler.rs b/src/pci/pci_handler.rs index dafc4650..8ae4744f 100644 --- a/src/pci/pci_handler.rs +++ b/src/pci/pci_handler.rs @@ -215,8 +215,8 @@ fn handle_endpoint_access( dev.with_config_value_mut(|configvalue| { configvalue.set_bar_value(slot, value as u32); }); - dev.write_hw(field.to_offset() as PciConfigAddress, field.size(), value)?; if (value & 0xfffffff0) != 0xfffffff0 { + dev.write_hw(field.to_offset() as PciConfigAddress, field.size(), value)?; if (bar_type == PciMemType::Mem32) | (bar_type == PciMemType::Mem64High) | (bar_type == PciMemType::Io) @@ -390,8 +390,9 @@ fn handle_endpoint_access( dev.with_config_value_mut(|configvalue| { configvalue.set_rom_value(value as u32); }); - dev.write_hw(field.to_offset() as PciConfigAddress, field.size(), value)?; if value & 0xfffff800 != 0xfffff800 { + dev.write_hw(field.to_offset() as PciConfigAddress, field.size(), value)?; + let new_vaddr = (value as u64) & !0xf; // set virt_value diff --git a/src/pci/pci_struct.rs b/src/pci/pci_struct.rs index 9597693c..13140269 100644 --- a/src/pci/pci_struct.rs +++ b/src/pci/pci_struct.rs @@ -1160,10 +1160,10 @@ impl PciIterator { PciMemType::Mem64Low => { let value = bararr[i].get_value64(); bararr[i].set_virtual_value(value); - let _ = dev.write_bar(i as u8, value as u32); + // let _ = dev.write_bar(i as u8, value as u32); i += 1; bararr[i].set_virtual_value(value); - let _ = dev.write_bar(i as u8, (value >> 32) as u32); + // let _ = dev.write_bar(i as u8, (value >> 32) as u32); } PciMemType::Io => { let value = bararr[i].get_value64(); @@ -1281,7 +1281,7 @@ impl Iterator for PciIterator { node.set_parent_bdf(parent_bdf); self.next(match node.config_value.get_class().0 { // class code 0x6 is bridge and class.1 0x0 is host bridge - 0x6 if node.config_value.get_class().1 != 0x0 => { + 0x6 if node.config_value.get_class().1 == 0x4 => { let bdf = Bdf::new(domain, parent.subordinate_bus + 1, 0, 0); Some(self.get_bridge().next_bridge( self.address(parent_bus, bdf), From 417ee35dc9e7e90be0f279717d49b540e98ad0cf Mon Sep 17 00:00:00 2001 From: dallas Date: Tue, 20 Jan 2026 21:56:00 +0800 Subject: [PATCH 085/109] fmt --- src/pci/pci_handler.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/pci/pci_handler.rs b/src/pci/pci_handler.rs index 8ae4744f..0d310b8e 100644 --- a/src/pci/pci_handler.rs +++ b/src/pci/pci_handler.rs @@ -216,7 +216,11 @@ fn handle_endpoint_access( configvalue.set_bar_value(slot, value as u32); }); if (value & 0xfffffff0) != 0xfffffff0 { - dev.write_hw(field.to_offset() as PciConfigAddress, field.size(), value)?; + dev.write_hw( + field.to_offset() as PciConfigAddress, + field.size(), + value, + )?; if (bar_type == PciMemType::Mem32) | (bar_type == PciMemType::Mem64High) | (bar_type == PciMemType::Io) @@ -391,8 +395,12 @@ fn handle_endpoint_access( configvalue.set_rom_value(value as u32); }); if value & 0xfffff800 != 0xfffff800 { - dev.write_hw(field.to_offset() as PciConfigAddress, field.size(), value)?; - + dev.write_hw( + field.to_offset() as PciConfigAddress, + field.size(), + value, + )?; + let new_vaddr = (value as u64) & !0xf; // set virt_value From fbfb32dc72394e5a6e9f8371ad1d9538b701e594 Mon Sep 17 00:00:00 2001 From: wheatfox Date: Wed, 21 Jan 2026 10:53:03 +0800 Subject: [PATCH 086/109] fix(Makefile): fixed memory size calculation on loongarch64 Signed-off-by: wheatfox --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 47aeae91..103c2924 100644 --- a/Makefile +++ b/Makefile @@ -91,7 +91,7 @@ all: clean_check gen_cargo_config $(hvisor_bin) @printf "%-10s %s\n" "HVISON_BIN_SIZE =" "$(COLOR_BOLD)$(shell du -h $(hvisor_bin) | cut -f1)$(COLOR_RESET)" @start_addr=$$(rust-nm $(hvisor_elf) | grep skernel | awk '{print $$1}'); \ end_addr=$$(rust-nm $(hvisor_elf) | grep __hv_end | awk '{print $$1}'); \ - size=$$(printf '%016x\n' $$((0x$$end_addr - 0x$$start_addr))); \ + size=$$(echo "obase=16; ibase=16; $$(echo $$end_addr | tr 'a-z' 'A-Z') - $$(echo $$start_addr | tr 'a-z' 'A-Z')" | bc | tr 'A-Z' 'a-z'); \ printf "%-10s %s\n" "START_ADDR =" "$(COLOR_BOLD)0x$$start_addr$(COLOR_RESET)"; \ printf "%-10s %s\n" "MEM_SIZE =" "$(COLOR_BOLD)0x$$size$(COLOR_RESET)"; \ printf "%-10s %s\n" "END_ADDR =" "$(COLOR_BOLD)0x$$end_addr$(COLOR_RESET)" From ea2ef5d9a5130b7804fa4c53fc890a06f8039a31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=AF=E5=AE=87?= <2537738252@qq.com> Date: Fri, 23 Jan 2026 14:34:15 +0800 Subject: [PATCH 087/109] riscv64: add cpuid-hartid mapping --- platform/riscv64/README.md | 8 ++ platform/riscv64/hifive-premier-p550/board.rs | 18 ++- platform/riscv64/megrez/board.rs | 21 +++- platform/riscv64/qemu-aia/board.rs | 18 ++- platform/riscv64/qemu-plic/board.rs | 8 ++ src/arch/riscv64/cpu.rs | 15 ++- src/arch/riscv64/entry.rs | 118 +++++++++++------- src/arch/riscv64/ipi.rs | 9 +- src/arch/riscv64/sbi.rs | 12 +- src/main.rs | 6 + src/percpu.rs | 1 + 11 files changed, 168 insertions(+), 66 deletions(-) create mode 100644 platform/riscv64/README.md diff --git a/platform/riscv64/README.md b/platform/riscv64/README.md new file mode 100644 index 00000000..c282e1fe --- /dev/null +++ b/platform/riscv64/README.md @@ -0,0 +1,8 @@ + +## Note + +1. Assume all harts have the same number contexts. (e.g.M-mode/S-mode...) +2. Static partition, no enable lock for host PLIC. +3. HW_IRQS related configuration will be done at host PLIC. +4. ROOT_ZONE_IRQS means all irqs belong to root zone. (contain hw_irq & sw_irq) + diff --git a/platform/riscv64/hifive-premier-p550/board.rs b/platform/riscv64/hifive-premier-p550/board.rs index 9cf06504..f6a5535f 100644 --- a/platform/riscv64/hifive-premier-p550/board.rs +++ b/platform/riscv64/hifive-premier-p550/board.rs @@ -19,10 +19,20 @@ use crate::{arch::zone::HvArchZoneConfig, config::*}; pub const BOARD_NAME: &str = "hifive-premier-p550"; pub const BOARD_NCPUS: usize = 4; +#[rustfmt::skip] +pub static BOARD_HARTID_MAP: [usize; BOARD_NCPUS] = [ + 0x0, // core0 \ + 0x1, // core1 | -> cluster0 -> CPU + 0x2, // core2 | + 0x3, // core3 / +]; pub const TIMEBASE_FREQ: u64 = 0xf4240; // 1MHz pub const PLIC_BASE: usize = 0xc000000; +pub const PLIC_SIZE: usize = 0x4000000; pub const BOARD_PLIC_INTERRUPTS_NUM: usize = 1023; // except irq 0 +pub const NUM_CONTEXTS_PER_HART: usize = 2; // M-mode、S-mode + pub const SIFIVE_CCACHE_BASE: usize = 0x2010000; // SiFive composable cache controller pub const SIFIVE_CCACHE_SIZE: usize = 0x4000; // 16KB @@ -166,10 +176,10 @@ pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[ ]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { - plic_base: 0xc000000, - plic_size: 0x4000000, - aplic_base: 0xd000000, - aplic_size: 0x8000, + plic_base: PLIC_BASE, + plic_size: PLIC_SIZE, + aplic_base: 0x0, + aplic_size: 0x0, }; // Virtio zone1 cmd: diff --git a/platform/riscv64/megrez/board.rs b/platform/riscv64/megrez/board.rs index e77374b0..923de93f 100644 --- a/platform/riscv64/megrez/board.rs +++ b/platform/riscv64/megrez/board.rs @@ -19,8 +19,21 @@ use crate::{arch::zone::HvArchZoneConfig, config::*}; pub const BOARD_NAME: &str = "milkv-megrez"; pub const BOARD_NCPUS: usize = 4; +#[rustfmt::skip] +pub static BOARD_HARTID_MAP: [usize; BOARD_NCPUS] = [ + 0x0, // core0 \ + 0x1, // core1 | -> cluster0 -> CPU + 0x2, // core2 | + 0x3, // core3 / +]; + +pub const TIMEBASE_FREQ: u64 = 0xf4240; // 1MHz + pub const PLIC_BASE: usize = 0xc000000; +pub const PLIC_SIZE: usize = 0x4000000; pub const BOARD_PLIC_INTERRUPTS_NUM: usize = 1023; // except irq 0 +pub const NUM_CONTEXTS_PER_HART: usize = 2; // M-mode、S-mode + pub const SIFIVE_CCACHE_BASE: usize = 0x2010000; // SiFive composable cache controller pub const SIFIVE_CCACHE_SIZE: usize = 0x4000; // 16KB @@ -205,8 +218,8 @@ pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[ ]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { - plic_base: 0xc000000, - plic_size: 0x4000000, - aplic_base: 0xd000000, - aplic_size: 0x8000, + plic_base: PLIC_BASE, + plic_size: PLIC_SIZE, + aplic_base: 0x0, + aplic_size: 0x0, }; diff --git a/platform/riscv64/qemu-aia/board.rs b/platform/riscv64/qemu-aia/board.rs index cfae9481..f6ee20d7 100644 --- a/platform/riscv64/qemu-aia/board.rs +++ b/platform/riscv64/qemu-aia/board.rs @@ -16,6 +16,13 @@ use crate::{arch::zone::HvArchZoneConfig, config::*}; pub const BOARD_NAME: &str = "qemu-aia"; pub const BOARD_NCPUS: usize = 4; +#[rustfmt::skip] +pub static BOARD_HARTID_MAP: [usize; BOARD_NCPUS] = [ + 0x0, // core0 \ + 0x1, // core1 | -> cluster0 -> CPU + 0x2, // core2 | + 0x3, // core3 / +]; pub const TIMEBASE_FREQ: u64 = 10_000_000; // 10MHz pub const ACLINT_SSWI_BASE: usize = 0x2F00000; @@ -23,7 +30,8 @@ pub const ACLINT_SSWI_BASE: usize = 0x2F00000; #[allow(unused)] pub const SIFIVE_TEST_BASE: u64 = 0x100000; -pub const APLIC_BASE: usize = 0xc000000; +pub const APLIC_S_BASE: usize = 0xd000000; +pub const APLIC_S_SIZE: usize = 0x8000; // Related to BOARD_NCPUS. pub const BOARD_APLIC_INTERRUPTS_NUM: usize = 1023; pub const IMSIC_S_BASE: usize = 0x2800_0000; pub const IMSIC_GUEST_NUM: usize = 1; // hvisor only supports 1 guest now. @@ -96,8 +104,8 @@ pub const HW_IRQS: [u32; 11] = [1, 2, 3, 4, 5, 8, 10, 33, 34, 35, 36]; pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[1, 2, 3, 4, 5, 8, 10, 33, 34, 35, 36]); // ARCH= riscv .It doesn't matter temporarily. pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { - plic_base: 0xc000000, - plic_size: 0x4000000, - aplic_base: 0xd000000, - aplic_size: 0x8000, + plic_base: 0x0, + plic_size: 0x0, + aplic_base: APLIC_S_BASE, + aplic_size: APLIC_S_SIZE, }; diff --git a/platform/riscv64/qemu-plic/board.rs b/platform/riscv64/qemu-plic/board.rs index 969d6810..9a061b70 100644 --- a/platform/riscv64/qemu-plic/board.rs +++ b/platform/riscv64/qemu-plic/board.rs @@ -18,6 +18,14 @@ use crate::{arch::zone::HvArchZoneConfig, config::*, pci::vpci_dev::VpciDevType, #[allow(unused)] pub const BOARD_NAME: &str = "qem-plic"; pub const BOARD_NCPUS: usize = 4; +#[rustfmt::skip] +pub static BOARD_HARTID_MAP: [usize; BOARD_NCPUS] = [ + 0x0, // core0 \ + 0x1, // core1 | -> cluster0 -> CPU + 0x2, // core2 | + 0x3, // core3 / +]; + pub const TIMEBASE_FREQ: u64 = 10_000_000; // 10MHz pub const ACLINT_SSWI_BASE: usize = 0x2F00000; pub const PLIC_BASE: usize = 0xc000000; diff --git a/src/arch/riscv64/cpu.rs b/src/arch/riscv64/cpu.rs index f38eba43..71efcde4 100644 --- a/src/arch/riscv64/cpu.rs +++ b/src/arch/riscv64/cpu.rs @@ -15,6 +15,7 @@ // use super::csr::*; use crate::percpu::this_cpu_data; +use crate::platform::{BOARD_HARTID_MAP, BOARD_NCPUS}; use crate::{ arch::mm::new_s2_memory_set, consts::{PAGE_SIZE, PER_CPU_ARRAY_PTR, PER_CPU_SIZE}, @@ -139,7 +140,7 @@ impl ArchCpu { // reset all registers related self.reset_regs( this_cpu_data().cpu_on_entry, - this_cpu_data().id, + BOARD_HARTID_MAP[this_cpu_id()], // This should be hartid. this_cpu_data().dtb_ipa, ); this_cpu_data().activate_gpm(); @@ -181,7 +182,7 @@ impl ArchCpu { // Note: in park_inst_page self.reset_regs( PARKING_INST_GPA, // entry_addr - this_cpu_data().id, // a0 + this_cpu_id(), // a0 this_cpu_data().dtb_ipa, // a1 ); self.reset_interrupt(); @@ -217,12 +218,20 @@ fn this_cpu_arch() -> &'static mut ArchCpu { unsafe { &mut *(sscratch as *mut ArchCpu) } } +/// Get the logical cpu_id 0..BOARD_NCPUS. pub fn this_cpu_id() -> usize { this_cpu_arch().get_cpuid() } +pub fn hartid_to_cpuid(hartid: usize) -> usize { + (0..BOARD_NCPUS) + .find(|&i| BOARD_HARTID_MAP[i] == hartid) + .unwrap() +} + pub fn cpu_start(cpuid: usize, start_addr: usize, opaque: usize) { - if let Some(e) = sbi_rt::hart_start(cpuid, start_addr, opaque).err() { + // Convert cpuid to hartid + if let Some(e) = sbi_rt::hart_start(BOARD_HARTID_MAP[cpuid], start_addr, opaque).err() { panic!("cpu_start error: {:#x?}", e); } } diff --git a/src/arch/riscv64/entry.rs b/src/arch/riscv64/entry.rs index 936ce2ae..67d716b8 100644 --- a/src/arch/riscv64/entry.rs +++ b/src/arch/riscv64/entry.rs @@ -12,69 +12,103 @@ // https://www.syswonder.org // // Authors: +// Jingyu Liu // + use crate::consts::PER_CPU_SIZE; -#[no_mangle] +use crate::platform::BOARD_HARTID_MAP; +use crate::platform::BOARD_NCPUS; + +extern "C" { + fn __core_end(); + fn sbss(); + fn ebss(); +} + #[link_section = ".data"] -pub static mut CPU_BSS_LOCK: u32 = 1; +static mut CLEAR_BSS_DONE: usize = 0; -#[no_mangle] #[link_section = ".data"] -pub static mut ENTER_CPU: u32 = u32::MAX; // the first entered cpuid will be written. +static mut ENTER_CPU: usize = usize::MAX; // i.e., -1 #[naked] #[no_mangle] #[link_section = ".text.entry"] pub unsafe extern "C" fn arch_entry() -> i32 { - //a0=cpuid,a1=dtb addr + // a0=hart_id, a1=dtb_addr + // Note: hart_id may not be continuous, we should map it to continuous cpu_id. core::arch::asm!( " - la t0, __core_end // t0 = core_end - li t1, {per_cpu_size} // t1 = per_cpu_size - mul t2, a0, t1 // t2 = cpuid * per_cpu_size - add t2, t1, t2 // t2 = cpuid * per_cpu_size+per_cpu_size - add sp, t0, t2 // sp = core_end + cpuid * per_cpu_size + per_cpu_size + // ================================================ + // Step1: Map hart_id to cpu_id, store cpu_id in a0 + // ================================================ + la t0, {board_hartid_map} // t0 = &BOARD_HARTID_MAP + li t1, {num_cpus} // t1 = num_cpus + li t2, 0 // t2 = 0 + 0: + ld t3, 0(t0) // t3 = BOARD_HARTID_MAP[t2] + beq a0, t3, 1f // if hartid == BOARD_HARTID_MAP[t2], found + addi t2, t2, 1 // t2++ + addi t0, t0, 8 // t0 += sizeof(usize) + bltu t2, t1, 0b // if t2 < num_cpus, continue + j . // not found, hang + 1: + mv a0, t2 // store logical cpu_id in a0 - # The first entered CPU will be stored in ENTER_CPU. - # And the first CPU will clear the bss. + // =================================== + // Step2: Prepare stack used by hvisor + // =================================== + la t0, {__core_end} // t0 = core_end + li t1, {per_cpu_size} // t1 = per_cpu_size + mul t2, a0, t1 // t2 = cpu_id * per_cpu_size + add t2, t1, t2 // t2 = cpu_id * per_cpu_size + per_cpu_size + add sp, t0, t2 // sp = core_end + cpu_id * per_cpu_size + per_cpu_size - la t0, ENTER_CPU # t0 = &ENTER_CPU - la t3, CPU_BSS_LOCK - li t1, -1 # t1 = initial expected value (-1) - amoswap.w.aq t2, a0, (t0) # t2 = old value; swap a0(cpuid) into ENTER_CPU - bne t2, t1, 2f # if old != -1, someone else already wrote + // ================================================== + // Step3: Record the master CPU (first entered hart) + // ================================================== + la t0, {enter_cpu} // t0 = &ENTER_CPU + la t3, {clear_bss_done} // t3 = &CLEAR_BSS_DONE + li t1, -1 // t1 = -1 + amoswap.w t2, a0, (t0) // t2 = ENTER_CPU; ENTER_CPU = a0 (atomic) + bne t2, t1, 5f // only master cpu can get -1 - 0: - la a3, sbss // a3 = bss's start addr - la a4, ebss // a4 = bss's end addr - 1: - blt a4, a3, 2f // first entered cpu clear bss + // =================================== + // Step4: Master CPU clear bss section + // =================================== + 2: + la a3, {sbss} // a3 = bss's start addr + la a4, {ebss} // a4 = bss's end addr + 3: + bgeu a3, a4, 4f // master cpu clear bss segment sb zero, 0(a3) addi a3, a3, 1 - j 1b - 2: - fence w, w - sw zero, 0(t3) // clear bss done - j 4f - 3: - lw t4, 0(t3) // wait for ENTER_CPU to clear bss - bnez t4, 3b + j 3b + 4: + li t4, 1 + fence rw, w + sd t4, 0(t3) // Master cpu: clear bss done + j 6f + 5: + ld t6, 0(t3) // Secondary cpus: wait for master cpu to clear bss fence r, rw + beq t6, zero, 5b + 6: - 4: - # All CPUs could see the bss cleared. - call {rust_main} // a0, a1, sp are certain values + // ======================================================================================== + // Step5: Jump to rust, with a0=cpu_id, a1=dtb_addr, sp=stack_addr, and bss segment cleared + // ======================================================================================== + call {rust_main} ", rust_main = sym crate::rust_main, - per_cpu_size=const PER_CPU_SIZE, + __core_end = sym __core_end, + sbss = sym sbss, + ebss = sym ebss, + enter_cpu = sym ENTER_CPU, + clear_bss_done = sym CLEAR_BSS_DONE, + board_hartid_map = sym BOARD_HARTID_MAP, + per_cpu_size = const PER_CPU_SIZE, + num_cpus = const BOARD_NCPUS, options(noreturn), ); } - -// global_asm!(" -// .section \".rootcfg\", \"a\" -// .incbin \"imgs/config/qemu-riscv64.zone\" - -// // .section \".nrcfg1\", \"a\" -// // .incbin \"imgs/config/qemu-arm64-linux-demo.zone\" -// "); diff --git a/src/arch/riscv64/ipi.rs b/src/arch/riscv64/ipi.rs index d13c15f9..0d9cb3c3 100644 --- a/src/arch/riscv64/ipi.rs +++ b/src/arch/riscv64/ipi.rs @@ -12,20 +12,23 @@ // https://www.syswonder.org // // Authors: +// Jingyu Liu // +use crate::platform::BOARD_HARTID_MAP; use crate::consts::IPI_EVENT_SEND_IPI; #[cfg(feature = "plic")] use crate::consts::IPI_EVENT_UPDATE_HART_LINE; // arch_send_event pub fn arch_send_event(cpu_id: u64, _sgi_num: u64) { - debug!("arch_send_event: cpu_id: {}", cpu_id); + let hart_id = BOARD_HARTID_MAP[cpu_id as usize]; + debug!("arch_send_event: cpu_id: {}", hart_id); #[cfg(feature = "aclint")] - crate::device::irqchip::aclint::aclint_send_ipi(cpu_id as usize); + crate::device::irqchip::aclint::aclint_send_ipi(hart_id as usize); #[cfg(not(feature = "aclint"))] { let sbi_ret: sbi_rt::SbiRet = - sbi_rt::send_ipi(sbi_rt::HartMask::from_mask_base(1 << cpu_id, 0)); + sbi_rt::send_ipi(sbi_rt::HartMask::from_mask_base(1 << hart_id, 0)); if sbi_ret.is_err() { error!("arch_send_event: send_ipi failed: {:?}", sbi_ret); } diff --git a/src/arch/riscv64/sbi.rs b/src/arch/riscv64/sbi.rs index bac0c49f..04492318 100644 --- a/src/arch/riscv64/sbi.rs +++ b/src/arch/riscv64/sbi.rs @@ -16,6 +16,7 @@ //! SBI call wrappers use super::cpu::ArchCpu; +use crate::arch::cpu::hartid_to_cpuid; use crate::arch::csr::*; use crate::consts::IPI_EVENT_SEND_IPI; use crate::event::{send_event, IPI_EVENT_WAKEUP}; @@ -65,7 +66,6 @@ pub fn sbi_vs_handler(current_cpu: &mut ArchCpu) { // a6 encodes the SBI function ID (FID) let eid: usize = current_cpu.x[17]; let fid: usize = current_cpu.x[16]; - // info!("SBI call: EID={:#x}, FID={:#x}", eid, fid); let sbi_ret; match eid { // Base Extension (SBI Spec Chapter 4) @@ -97,12 +97,14 @@ pub fn sbi_vs_handler(current_cpu: &mut ArchCpu) { // Legacy::Console putchar (usually used), temporily don't support other legacy extensions. legacy::LEGACY_CONSOLE_PUTCHAR => { sbi_ret = SbiRet { + #[allow(deprecated)] error: sbi_rt::legacy::console_putchar(current_cpu.x[10] as _), value: 0, }; } legacy::LEGACY_CONSOLE_GETCHAR => { sbi_ret = SbiRet { + #[allow(deprecated)] error: sbi_rt::legacy::console_getchar(), value: 0, }; @@ -264,7 +266,7 @@ pub fn sbi_hsm_start_handler(current_cpu: &mut ArchCpu) -> SbiRet { error: RET_SUCCESS, value: 0, }; - let cpuid = current_cpu.x[10]; // In hvisor, it is physical cpu id. + let cpuid = hartid_to_cpuid(current_cpu.x[10]); // convert to hvisor's logical cpuid let start_addr = current_cpu.x[11]; let opaque = current_cpu.x[12]; if cpuid == current_cpu.cpuid { @@ -306,11 +308,11 @@ pub fn sbi_ipi_handler(fid: usize, current_cpu: &mut ArchCpu) -> SbiRet { let hart_mask = current_cpu.x[10]; let hart_mask_base = current_cpu.x[11]; let hart_mask_bits = HartMask::from_mask_base(hart_mask, hart_mask_base); - for cpu_id in 0..64 { + for hart_id in 0..64 { // hart_mask is 64 bits - if hart_mask_bits.has_bit(cpu_id) { + if hart_mask_bits.has_bit(hart_id) { // the second parameter is ignored is riscv64. - send_event(cpu_id, 0, IPI_EVENT_SEND_IPI); + send_event(hartid_to_cpuid(hart_id), 0, IPI_EVENT_SEND_IPI); } } SbiRet { diff --git a/src/main.rs b/src/main.rs index 7565d5ce..ebfdf43d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -180,6 +180,12 @@ fn wakeup_secondary_cpus(this_id: usize, host_dtb: usize) { } } +/// Rust main function for hvisor. +/// +/// # Arguments +/// +/// * `cpuid` - The logical cpu_id 0..BOARD_NCPUS. +/// * `host_dtb` - The device tree blob address. fn rust_main(cpuid: usize, host_dtb: usize) { arch::trap::install_trap_vector(); diff --git a/src/percpu.rs b/src/percpu.rs index e731a106..5c22d1bc 100644 --- a/src/percpu.rs +++ b/src/percpu.rs @@ -95,6 +95,7 @@ pub fn get_cpu_data<'a>(cpu_id: usize) -> &'a mut PerCpu { } pub fn this_cpu_data<'a>() -> &'a mut PerCpu { + // Note: this_cpu_id() should return logical cpu_id 0..BOARD_NCPUS get_cpu_data(this_cpu_id()) } From d12a4353efffda333b819097eb374e7fe2d5347c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=AF=E5=AE=87?= <2537738252@qq.com> Date: Fri, 23 Jan 2026 14:40:41 +0800 Subject: [PATCH 088/109] make fmt --- src/arch/riscv64/cpu.rs | 2 +- src/arch/riscv64/ipi.rs | 2 +- src/main.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/arch/riscv64/cpu.rs b/src/arch/riscv64/cpu.rs index 71efcde4..35f9a3a4 100644 --- a/src/arch/riscv64/cpu.rs +++ b/src/arch/riscv64/cpu.rs @@ -140,7 +140,7 @@ impl ArchCpu { // reset all registers related self.reset_regs( this_cpu_data().cpu_on_entry, - BOARD_HARTID_MAP[this_cpu_id()], // This should be hartid. + BOARD_HARTID_MAP[this_cpu_id()], // This should be hartid. this_cpu_data().dtb_ipa, ); this_cpu_data().activate_gpm(); diff --git a/src/arch/riscv64/ipi.rs b/src/arch/riscv64/ipi.rs index 0d9cb3c3..d4ad55d2 100644 --- a/src/arch/riscv64/ipi.rs +++ b/src/arch/riscv64/ipi.rs @@ -14,10 +14,10 @@ // Authors: // Jingyu Liu // -use crate::platform::BOARD_HARTID_MAP; use crate::consts::IPI_EVENT_SEND_IPI; #[cfg(feature = "plic")] use crate::consts::IPI_EVENT_UPDATE_HART_LINE; +use crate::platform::BOARD_HARTID_MAP; // arch_send_event pub fn arch_send_event(cpu_id: u64, _sgi_num: u64) { diff --git a/src/main.rs b/src/main.rs index ebfdf43d..b320606a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -181,9 +181,9 @@ fn wakeup_secondary_cpus(this_id: usize, host_dtb: usize) { } /// Rust main function for hvisor. -/// +/// /// # Arguments -/// +/// /// * `cpuid` - The logical cpu_id 0..BOARD_NCPUS. /// * `host_dtb` - The device tree blob address. fn rust_main(cpuid: usize, host_dtb: usize) { From c09166014d65eed3ed25d89909c1f7707a5dfc14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=AF=E5=AE=87?= <2537738252@qq.com> Date: Fri, 23 Jan 2026 17:30:38 +0800 Subject: [PATCH 089/109] riscv64: add ur-dp1000 support --- Cargo.toml | 1 + platform/riscv64/qemu-plic/board.rs | 1 + platform/riscv64/ur-dp1000/README.md | 76 +++ platform/riscv64/ur-dp1000/board.rs | 165 ++++++ .../ur-dp1000/cargo/config.template.toml | 6 + platform/riscv64/ur-dp1000/cargo/features | 2 + .../ur-dp1000/configs/zone1-linux-virtio.json | 23 + .../ur-dp1000/configs/zone1-linux.json | 95 ++++ platform/riscv64/ur-dp1000/image/dts/Makefile | 8 + .../riscv64/ur-dp1000/image/dts/ur-dp1000.dts | 505 ++++++++++++++++++ .../riscv64/ur-dp1000/image/dts/zone0.dts | 275 ++++++++++ .../ur-dp1000/image/dts/zone1-linux.dts | 277 ++++++++++ platform/riscv64/ur-dp1000/linker.ld | 50 ++ platform/riscv64/ur-dp1000/platform.mk | 6 + .../riscv64/ur-dp1000/scripts/boot_zone1.sh | 10 + platform/riscv64/ur-dp1000/scripts/init.sh | 13 + src/arch/riscv64/trap.rs | 17 +- src/device/irqchip/plic/mod.rs | 208 ++++---- src/device/irqchip/plic/plic.rs | 89 ++- src/device/irqchip/plic/vplic.rs | 23 +- 20 files changed, 1733 insertions(+), 117 deletions(-) create mode 100644 platform/riscv64/ur-dp1000/README.md create mode 100644 platform/riscv64/ur-dp1000/board.rs create mode 100644 platform/riscv64/ur-dp1000/cargo/config.template.toml create mode 100644 platform/riscv64/ur-dp1000/cargo/features create mode 100644 platform/riscv64/ur-dp1000/configs/zone1-linux-virtio.json create mode 100644 platform/riscv64/ur-dp1000/configs/zone1-linux.json create mode 100644 platform/riscv64/ur-dp1000/image/dts/Makefile create mode 100644 platform/riscv64/ur-dp1000/image/dts/ur-dp1000.dts create mode 100644 platform/riscv64/ur-dp1000/image/dts/zone0.dts create mode 100644 platform/riscv64/ur-dp1000/image/dts/zone1-linux.dts create mode 100644 platform/riscv64/ur-dp1000/linker.ld create mode 100644 platform/riscv64/ur-dp1000/platform.mk create mode 100644 platform/riscv64/ur-dp1000/scripts/boot_zone1.sh create mode 100644 platform/riscv64/ur-dp1000/scripts/init.sh diff --git a/Cargo.toml b/Cargo.toml index e4b1320a..20fc9ef3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -73,6 +73,7 @@ uart16550a = [] ############## riscv64 ############# # irqchip driver plic = [] +dp1000_plic = [] aia = [] aclint = [] # extensions diff --git a/platform/riscv64/qemu-plic/board.rs b/platform/riscv64/qemu-plic/board.rs index 9a061b70..f1327a2f 100644 --- a/platform/riscv64/qemu-plic/board.rs +++ b/platform/riscv64/qemu-plic/board.rs @@ -31,6 +31,7 @@ pub const ACLINT_SSWI_BASE: usize = 0x2F00000; pub const PLIC_BASE: usize = 0xc000000; pub const PLIC_SIZE: usize = 0x4000000; pub const BOARD_PLIC_INTERRUPTS_NUM: usize = 1023; // except irq 0 +pub const NUM_CONTEXTS_PER_HART: usize = 2; // M-mode、S-mode // This device is used for qemu-quit. #[allow(unused)] diff --git a/platform/riscv64/ur-dp1000/README.md b/platform/riscv64/ur-dp1000/README.md new file mode 100644 index 00000000..ec441685 --- /dev/null +++ b/platform/riscv64/ur-dp1000/README.md @@ -0,0 +1,76 @@ +## UR-DP1000 + +Physical PLIC has one hardware bug(claim register). +But Virtual PLIC can be treated as a standard PLIC, this can improve some performance. + +```c +// https://github.com/RVCK-Project/rvck/blob/rvck-6.6/drivers/irqchip/irq-sifive-plic.c + +static bool plic_check_enable_first_pending(u32 ie[]) +{ + struct plic_handler *handler = this_cpu_ptr(&plic_handlers); + void __iomem *enable = handler->enable_base; + void __iomem *pending = handler->priv->regs + PENDING_BASE; + int nr_irqs = handler->priv->nr_irqs; + int nr_irq_groups = (nr_irqs + 31) / 32; + bool is_pending = false; + int i, j; + raw_spin_lock(&handler->enable_lock); + // Read current interrupt enables + for (i = 0; i < nr_irq_groups; i++) + ie[i] = readl(enable + i * sizeof(u32)); + // Check for pending interrupts and enable only the first one found + for (i = 0; i < nr_irq_groups; i++) { + u32 pending_irqs = readl(pending + i * sizeof(u32)) & ie[i]; + if (pending_irqs) { + int nbit = __ffs(pending_irqs); + for (j = 0; j < nr_irq_groups; j++) + writel((i == j)?(1 << nbit):0, enable + j * sizeof(u32)); + is_pending = true; + break; + } + } + raw_spin_unlock(&handler->enable_lock); + return is_pending; +} + +static void plic_restore_enable_state(u32 ie[]) +{ + struct plic_handler *handler = this_cpu_ptr(&plic_handlers); + void __iomem *enable = handler->enable_base; + int nr_irqs = handler->priv->nr_irqs; + int nr_irq_groups = (nr_irqs + 31) / 32; + int i; + + raw_spin_lock(&handler->enable_lock); + + for (i = 0; i < nr_irq_groups; i++) // restore original enable bits + writel(ie[i], enable + i * sizeof(u32)); + + raw_spin_unlock(&handler->enable_lock); +} + + +static irq_hw_number_t plic_get_hwirq(void) +{ + struct plic_handler *handler = this_cpu_ptr(&plic_handlers); + struct plic_priv *priv = handler->priv; + void __iomem *claim = handler->hart_base + CONTEXT_CLAIM; + irq_hw_number_t hwirq; + u32 ie[32] = {0}; // 32x32 = 1024 + /* + * Due to the implementation of the claim register in the UltraRISC DP1000 + * platform PLIC not conforming to the specification, this is a hardware + * bug. Therefore, when an interrupt is pending, we need to disable the other + * interrupts before reading the claim register. After processing the interrupt, + * we should then restore the enable register. + */ + if (test_bit(PLIC_QUIRK_CLAIM_REGISTER, &priv->plic_quirks)) { + hwirq = plic_check_enable_first_pending(ie)?readl(claim):0; + plic_restore_enable_state(ie); + } else { + hwirq = readl(claim); + } + return hwirq; +} +``` \ No newline at end of file diff --git a/platform/riscv64/ur-dp1000/board.rs b/platform/riscv64/ur-dp1000/board.rs new file mode 100644 index 00000000..dde8c423 --- /dev/null +++ b/platform/riscv64/ur-dp1000/board.rs @@ -0,0 +1,165 @@ +// 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: +// Jingyu Liu +// + +use crate::pci::vpci_dev::VpciDevType; +use crate::{arch::zone::HvArchZoneConfig, config::*, pci_dev}; + +// ================================================== +// System Level Config +// ================================================== +#[allow(unused)] +pub const BOARD_NAME: &str = "ur-dp1000"; +// CPU Topology Information +pub const BOARD_NCPUS: usize = 8; +#[rustfmt::skip] +pub static BOARD_HARTID_MAP: [usize; BOARD_NCPUS] = [ + 0x0, // core0 \ + 0x1, // core1 | -> cluster0 \ + 0x2, // core2 | | + 0x3, // core3 / | -> CPU + 0x10, // core4 \ | + 0x11, // core5 | -> cluster1 / + 0x12, // core6 | + 0x13, // core7 / +]; +// Timebase frequency +pub const TIMEBASE_FREQ: u64 = 10_000_000; +// PLIC Configuration +pub const PLIC_BASE: usize = 0x9000000; +pub const PLIC_SIZE: usize = 0x4000000; +// Number of interrupts is defined in dts, its max value is 1023. +// riscv,ndev = <0xa0> +pub const BOARD_PLIC_INTERRUPTS_NUM: usize = 0xa0; // except irq 0, here range is [1, 160] +pub const NUM_CONTEXTS_PER_HART: usize = 3; // M-mode、S-mode and VS-mode(unused) + +// ================================================== +// Root Zone Config +// ================================================== +pub const ROOT_ZONE_NAME: &str = "root-linux"; +// ROOT_ZONE_DTB_ADDR is HPA (Host physical Address). +pub const ROOT_ZONE_DTB_ADDR: u64 = 0x8F000000; +// ROOT_ZONE_KERNEL_ADDR is HPA (Host Physical Address), but it isn't used now. +pub const ROOT_ZONE_KERNEL_ADDR: u64 = 0x90000000; +// ROOT_ZONE_ENTRY is GPA (Guest Physical Address). +pub const ROOT_ZONE_ENTRY: u64 = 0x90000000; +pub const ROOT_ZONE_CPUS: u64 = 0x3; // core0,1,2,3 +#[rustfmt::skip] +pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ + // Main memory (~32GB), reserved 0x500_0000 (80M) for high-level privilege softwares (opensbi & hvisor). + HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, physical_start: 0x8500_0000, virtual_start: 0x8500_0000, size: 0x8_0000_0000 - 0x500_0000 }, + // Serial0 + HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x2030_0000, virtual_start: 0x2030_0000, size: 0x1_0000 }, + // // Pcie_x16 + // HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x2100_0000, virtual_start: 0x2100_0000, size: 0x100_0000 }, // IP_register + // HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x4fff_0000, virtual_start: 0x4fff_0000, size: 0x1_0000 }, // Configuration Space + // HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x4fbf_0000, virtual_start: 0x4fbf_0000, size: 0x40_0000 }, // IO Space + // HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x4000_0000, virtual_start: 0x4000_0000, size: 0xfbf_0000 }, // Mem32 Space + // HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x40_0000_0000, virtual_start: 0x40_0000_0000, size: 0xd_0000_0000 }, // Mem64 Space + // // Pcie_x4a + // HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x2300_0000, virtual_start: 0x2300_0000, size: 0x100_0000 }, // IP register + // HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x6fff_0000, virtual_start: 0x6fff_0000, size: 0x1_0000 }, // Configuration Space + // HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x6fbf_0000, virtual_start: 0x6fbf_0000, size: 0x40_0000 }, // IO Space + // HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x6000_0000, virtual_start: 0x6000_0000, size: 0xfbf_0000 }, // Mem32 Space + // HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x80_0000_0000, virtual_start: 0x80_0000_0000, size: 0xd_0000_0000 }, // Mem64 Space + // // Pcie_x4b + // HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x2400_0000, virtual_start: 0x2400_0000, size: 0x100_0000 }, // IP register + // HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x7fff_0000, virtual_start: 0x7fff_0000, size: 0x1_0000 }, // Configuration Space + // HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x7fbf_0000, virtual_start: 0x7fbf_0000, size: 0x40_0000 }, // IO Space + // HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x7000_0000, virtual_start: 0x7000_0000, size: 0xfbf_0000 }, // Mem32 Space + // HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0xc0_0000_0000, virtual_start: 0xc0_0000_0000, size: 0xd_0000_0000 }, // Mem64 Space + // // Eth + // HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x3800_0000, virtual_start: 0x3800_0000, size: 0x100_0000 }, +]; +// No mapped io regions in root zone. +pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { + plic_base: PLIC_BASE, + plic_size: PLIC_SIZE, + aplic_base: 0x0, // UNUSED for PLIC + aplic_size: 0x0, // UNUSED for PLIC +}; + +// ================================================== +// Interrupt Config +// ================================================== +// Note: all here's irqs are hardware irqs, +// only these irq can be transferred to the physical PLIC. +#[rustfmt::skip] +pub const HW_IRQS: &[u32] = &[ + 17, 18, 25, 26, // uart0, uart1, uart2, uart3 + 19, 27, // spi0, spi1 + 20, 21, 28, 29, // i2c0, i2c1, i2c2, i2c3 + 33, // watchdog@20210000 + 34, // gpio@20200000 porta + 84, // ethernet1@38000000 + 152, //dma-controller@39000000 + 43, 44, 45, 46, 47, 48, // pcie_x16@21000000, msi, inta, intb, intc, intd, aer + 63, 64, 65, 66, 67, 68, // pcie_x4a@23000000, msi, inta, intb, intc, intd, aer + 73, 74, 75, 76, 77, 78, // pcie_x4b@24000000, msi, inta, intb, intc, intd, aer +]; +// irqs belong to the root zone. +#[rustfmt::skip] +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[ + 17, // uart0, + // 84, // ethernet1@38000000 + // 43, 44, 45, 46, 47, 48, // pcie_x16@21000000, msi, inta, intb, intc, intd, aer + // 63, 64, 65, 66, 67, 68, // pcie_x4a@23000000, msi, inta, intb, intc, intd, aer + // 73, 74, 75, 76, 77, 78, // pcie_x4b@24000000, msi, inta, intb, intc, intd, aer +]); + +// ===================================================== +// PCIe Config +// Note: here only config the pciex4b, the others, +// pciex16 and pciex4a are directly passed through +// ===================================================== +// pub const ROOT_PCI_CONFIG: &[HvPciConfig] = &[HvPciConfig { +// ecam_base: 0x24000000, // reg = <0x0 0x24000000 0x0 0x01000000>, /* IP registers */ +// ecam_size: 0x1000000, +// io_base: 0x7fbf0000, // IO Space <0x81000000 0x0 0x7fbf0000 0x0 0x7fbf0000 0x0 0x00400000> +// io_size: 0x400000, +// pci_io_base: 0x7fbf0000, +// mem32_base: 0x70000000, // Mem32 Space <0x82000000 0x0 0x70000000 0x0 0x70000000 0x0 0x0fbf0000> +// mem32_size: 0xfbf0000, +// pci_mem32_base: 0x70000000, +// mem64_base: 0xc000000000, // Mem64 Space <0xc3000000 0xc0 0x00000000 0xc0 0x00000000 0xd 0x00000000> +// mem64_size: 0xd00000000, +// pci_mem64_base: 0xc000000000, +// bus_range_begin: 0x0, // bus-range = <0x0 0xff> +// bus_range_end: 0xff, +// }]; +// pub const ROOT_DWC_ATU_CONFIG: &[HvDwcAtuConfig] = &[HvDwcAtuConfig { +// ecam_base: 0x24000000, // reg = <0x0 0x24000000 0x0 0x01000000>, /* IP registers */ +// dbi_base: 0x24000000, // reg = <0x0 0x24000000 0x0 0x01000000>, /* IP registers */ +// dbi_size: 0x1000000, +// apb_base: 0x0, // UNUSED +// apb_size: 0x0, // UNUSED +// cfg_base: 0x7fff0000, // <0x0 0x7fff0000 0x0 0x00010000>; /* Configuration space */ +// cfg_size: 0x10000, +// io_cfg_atu_shared: 0, // IO and Configuration space share the same ATU +// }]; +// pub const ROOT_PCI_DEVS: &[HvPciDevConfig] = &[ +// pci_dev!(0x0, 0x0, 0x0, VpciDevType::Physical), // 00:00.0 PCIe x16 Root Complex 0x0 +// pci_dev!(0x1, 0x0, 0x0, VpciDevType::Physical), // 01:00.0 ASM2812 6-port PCIe x4 Gen3 Packet Switch 0x100 +// // pci_dev!(0x2, 0x0, 0x0, VpciDevType::Physical), // 02:00.0 ASM2812 6-port PCIe x4 Gen3 Packet Switch 0x200 +// // pci_dev!(0x2, 0x2, 0x0, VpciDevType::Physical), // 02:02.0 ASM2812 6-port PCIe x4 Gen3 Packet Switch (04:00.0 USB controller is behind it) 0x210 +// // pci_dev!(0x2, 0x3, 0x0, VpciDevType::Physical), // 02:03.0 ASM2812 6-port PCIe x4 Gen3 Packet Switch 0x218 +// // pci_dev!(0x2, 0x8, 0x0, VpciDevType::Physical), // 02:08.0 ASM2812 6-port PCIe x4 Gen3 Packet Switch (06:00.0 SATA controller is behind it) 0x240 +// pci_dev!(0x2, 0xa, 0x0, VpciDevType::Physical), // 02:0a.0 ASM2812 6-port PCIe x4 Gen3 Packet Switch (07:00.0 USB controller is behind it) 0x250 +// // pci_dev!(0x2, 0xb, 0x0, VpciDevType::Physical), // 02:0b.0 ASM2812 6-port PCIe x4 Gen3 Packet Switch 0x258 +// // pci_dev!(0x4, 0x0, 0x0, VpciDevType::Physical), // 04:00.0 USB controller 0x400 +// // pci_dev!(0x6, 0x0, 0x0, VpciDevType::Physical), // 06:00.0 SATA controller 0x600 +// pci_dev!(0x7, 0x0, 0x0, VpciDevType::Physical), // 07:00.0 USB controller 0x700 +// ]; diff --git a/platform/riscv64/ur-dp1000/cargo/config.template.toml b/platform/riscv64/ur-dp1000/cargo/config.template.toml new file mode 100644 index 00000000..f5d5b55c --- /dev/null +++ b/platform/riscv64/ur-dp1000/cargo/config.template.toml @@ -0,0 +1,6 @@ +[target.riscv64gc-unknown-none-elf] +runner = "platform/__ARCH__/__BOARD__/test/runner.sh" +rustflags = [ + "-Clink-arg=-Tplatform/__ARCH__/__BOARD__/linker.ld", + "-Cforce-frame-pointers=yes", +] \ No newline at end of file diff --git a/platform/riscv64/ur-dp1000/cargo/features b/platform/riscv64/ur-dp1000/cargo/features new file mode 100644 index 00000000..cac3e049 --- /dev/null +++ b/platform/riscv64/ur-dp1000/cargo/features @@ -0,0 +1,2 @@ +plic +dp1000_plic diff --git a/platform/riscv64/ur-dp1000/configs/zone1-linux-virtio.json b/platform/riscv64/ur-dp1000/configs/zone1-linux-virtio.json new file mode 100644 index 00000000..ed047ae6 --- /dev/null +++ b/platform/riscv64/ur-dp1000/configs/zone1-linux-virtio.json @@ -0,0 +1,23 @@ +{ + "zones": [ + { + "id": 1, + "memory_region": [ + { + "zone0_ipa": "0xC0000000", + "zonex_ipa": "0xC0000000", + "size": "0x7C0000000" + } + ], + "devices": [ + { + "type": "console", + "addr": "0x10007000", + "len": "0x1000", + "irq": 7, + "status": "enable" + } + ] + } + ] +} \ No newline at end of file diff --git a/platform/riscv64/ur-dp1000/configs/zone1-linux.json b/platform/riscv64/ur-dp1000/configs/zone1-linux.json new file mode 100644 index 00000000..14943c33 --- /dev/null +++ b/platform/riscv64/ur-dp1000/configs/zone1-linux.json @@ -0,0 +1,95 @@ +{ + "arch": "riscv", + "name": "linux2", + "zone_id": 1, + "cpus": [2,3,4,5,6,7], + "memory_regions": [ + { + "type": "ram", + "physical_start": "0xC0000000", + "virtual_start": "0xC0000000", + "size": "0x7C0000000" + }, + { + "type": "virtio", + "physical_start": "0x10007000", + "virtual_start": "0x10007000", + "size": "0x1000" + }, + { + "type": "io", + "physical_start": "0x21000000", + "virtual_start": "0x21000000", + "size": "0x1000000" + }, + { + "type": "io", + "physical_start": "0x40000000", + "virtual_start": "0x40000000", + "size": "0x10000000" + }, + { + "type": "io", + "physical_start": "0x4000000000", + "virtual_start": "0x4000000000", + "size": "0xd00000000" + }, + { + "type": "io", + "physical_start": "0x23000000", + "virtual_start": "0x23000000", + "size": "0x1000000" + }, + { + "type": "io", + "physical_start": "0x60000000", + "virtual_start": "0x60000000", + "size": "0x10000000" + }, + { + "type": "io", + "physical_start": "0x8000000000", + "virtual_start": "0x8000000000", + "size": "0xd00000000" + }, + { + "type": "io", + "physical_start": "0x24000000", + "virtual_start": "0x24000000", + "size": "0x1000000" + }, + { + "type": "io", + "physical_start": "0x70000000", + "virtual_start": "0x70000000", + "size": "0x10000000" + }, + { + "type": "io", + "physical_start": "0xc000000000", + "virtual_start": "0xc000000000", + "size": "0xd00000000" + }, + { + "type": "io", + "physical_start": "0x38000000", + "virtual_start": "0x38000000", + "size": "0x1000000" + } + ], + "interrupts": [7, 84, 43, 44, 45, 46, 47, 48, 63, 64, 65, 66, 67, 68, 73, 74, 75, 76, 77, 78], + "ivc_configs": [], + "kernel_filepath": "./Image", + "dtb_filepath": "./zone1-linux.dtb", + "kernel_load_paddr": "0xC0000000", + "dtb_load_paddr": "0xD0000000", + "entry_point": "0xC0000000", + "arch_config": { + "plic_base": "0x9000000", + "plic_size": "0x4000000", + "aplic_base": "0x0", + "aplic_size": "0x0" + }, + "pci_config": [], + "alloc_pci_devs": [] +} \ No newline at end of file diff --git a/platform/riscv64/ur-dp1000/image/dts/Makefile b/platform/riscv64/ur-dp1000/image/dts/Makefile new file mode 100644 index 00000000..2f795e7f --- /dev/null +++ b/platform/riscv64/ur-dp1000/image/dts/Makefile @@ -0,0 +1,8 @@ +DTS_FILES := $(wildcard *.dts) +DTB_FILES := $(DTS_FILES:.dts=.dtb) + +all: $(DTB_FILES) +%.dtb: %.dts + dtc -I dts -O dtb $< -o $@ +clean: + rm -f $(DTB_FILES) \ No newline at end of file diff --git a/platform/riscv64/ur-dp1000/image/dts/ur-dp1000.dts b/platform/riscv64/ur-dp1000/image/dts/ur-dp1000.dts new file mode 100644 index 00000000..51025687 --- /dev/null +++ b/platform/riscv64/ur-dp1000/image/dts/ur-dp1000.dts @@ -0,0 +1,505 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2019-2022 UltraRISC Technology (Shanghai) Co., Ltd. + * + */ + +/dts-v1/; + +/ { + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "ultrarisc,dp1000"; + model = "ultrarisc,dp1000"; + + chosen { + bootargs = "earlycon=sbi console=ttyS1,115200"; + stdout-path = &uart1; + }; + + cpus { + #address-cells = <0x01>; + #size-cells = <0x00>; + timebase-frequency = <10000000>; + + cpu0: cpu@0 { + device_type = "cpu"; + reg = <0x00>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcbh"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + cpu0_intc:interrupt-controller { + #address-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + #interrupt-cells = <0x01>; + }; + }; + cpu1: cpu@1 { + device_type = "cpu"; + reg = <0x1>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcbh"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + cpu1_intc:interrupt-controller { + #address-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + #interrupt-cells = <0x01>; + }; + }; + cpu2: cpu@2 { + device_type = "cpu"; + reg = <0x2>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcbh"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + cpu2_intc:interrupt-controller { + #address-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + #interrupt-cells = <0x01>; + }; + }; + cpu3: cpu@3 { + device_type = "cpu"; + reg = <0x3>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcbh"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + cpu3_intc:interrupt-controller { + #address-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + #interrupt-cells = <0x01>; + }; + }; + cpu4: cpu@4 { + device_type = "cpu"; + reg = <0x10>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcbh"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + cpu4_intc:interrupt-controller { + #address-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + #interrupt-cells = <0x01>; + }; + }; + cpu5: cpu@5 { + device_type = "cpu"; + reg = <0x11>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcbh"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + cpu5_intc:interrupt-controller { + #address-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + #interrupt-cells = <0x01>; + }; + }; + cpu6: cpu@6 { + device_type = "cpu"; + reg = <0x12>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcbh"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + cpu6_intc:interrupt-controller { + #address-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + #interrupt-cells = <0x01>; + }; + }; + cpu7: cpu@7 { + device_type = "cpu"; + reg = <0x13>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcbh"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + cpu7_intc:interrupt-controller { + #address-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + #interrupt-cells = <0x01>; + }; + }; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x00 0x80000000 0x4 0x00000000>; + }; + + soc { + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "simple-bus"; + ranges; + + clocks { + compatible = "simple-bus"; + u-boot,dm-pre-reloc; + device_clk: device_clk { + compatible = "fixed-clock"; + clock-frequency = <62500000>; + #clock-cells = <0>; + }; + + csr_clk: csr_clk { + compatible = "fixed-clock"; + clock-frequency = <250000000>; + #clock-cells = <0>; + }; + }; + + clint: clint@8000000 { + compatible = "riscv,clint0"; + interrupts-extended = <&cpu0_intc 0x03>, <&cpu0_intc 0x07>, + <&cpu1_intc 0x03>, <&cpu1_intc 0x07>, + <&cpu2_intc 0x03>, <&cpu2_intc 0x07>, + <&cpu3_intc 0x03>, <&cpu3_intc 0x07>, + <&cpu4_intc 0x03>, <&cpu4_intc 0x07>, + <&cpu5_intc 0x03>, <&cpu5_intc 0x07>, + <&cpu6_intc 0x03>, <&cpu6_intc 0x07>, + <&cpu7_intc 0x03>, <&cpu7_intc 0x07>; + reg = <0x00 0x8000000 0x00 0x100000>; + }; + + plic: plic@9000000 { + #interrupt-cells = <1>; + #address-cells = <0>; + phandle = <0x01>; + compatible = "ultrarisc,dp1000-plic"; + interrupt-controller; + interrupts-extended = <&cpu0_intc 0xb>, <&cpu0_intc 0x9>, <&cpu0_intc 0xa>, + <&cpu1_intc 0xb>, <&cpu1_intc 0x9>, <&cpu1_intc 0xa>, + <&cpu2_intc 0xb>, <&cpu2_intc 0x9>, <&cpu2_intc 0xa>, + <&cpu3_intc 0xb>, <&cpu3_intc 0x9>, <&cpu3_intc 0xa>, + <&cpu4_intc 0xb>, <&cpu4_intc 0x9>, <&cpu4_intc 0xa>, + <&cpu5_intc 0xb>, <&cpu5_intc 0x9>, <&cpu5_intc 0xa>, + <&cpu6_intc 0xb>, <&cpu6_intc 0x9>, <&cpu6_intc 0xa>, + <&cpu7_intc 0xb>, <&cpu7_intc 0x9>, <&cpu7_intc 0xa>; + reg = <0x00 0x9000000 0x00 0x4000000>; + riscv,max-priority = <0x07>; + riscv,ndev = <160>; + }; + + uart0: serial@20300000 { + interrupt-parent = <0x01>; + interrupts = <17>; + clock-frequency = <62500000>; + current-speed = <115200>; + reg = <0x00 0x20300000 0x00 0x10000>; + compatible = "ultrarisc,dp1000-uart","ns16550"; + reg-offset = <0x0>; + reg-shift = <0x02>; + }; + + uart1: serial@20310000 { + interrupt-parent = <0x01>; + interrupts = <18>; + clock-frequency = <62500000>; + current-speed = <115200>; + reg = <0x00 0x20310000 0x00 0x10000>; + compatible = "ultrarisc,dp1000-uart","ns16550"; + reg-offset = <0x0>; + reg-shift = <0x02>; + }; + + uart2: serial@20400000 { + interrupt-parent = <0x01>; + interrupts = <25>; + clock-frequency = <62500000>; + current-speed = <115200>; + reg = <0x00 0x20400000 0x00 0x10000>; + compatible = "ultrarisc,dp1000-uart","ns16550"; + reg-offset = <0x0>; + reg-shift = <0x02>; + }; + + uart3: serial@20410000 { + interrupt-parent = <0x01>; + interrupts = <26>; + clock-frequency = <62500000>; + current-speed = <115200>; + reg = <0x00 0x20410000 0x00 0x10000>; + compatible = "ultrarisc,dp1000-uart","ns16550"; + reg-offset = <0x0>; + reg-shift = <0x02>; + }; + + spi0: spi@20320000 { + compatible = "baikal,bt1-ssi","snps,dw-apb-ssi"; + status = "okay"; + #address-cells = <0x01>; + #size-cells = <0x00>; + reg = <0x0 0x20320000 0x0 0x1000>; + interrupt-parent = <0x01>; + interrupts = <19>; + clocks = <&device_clk>; + clock-names = "device_clk"; + num-cs = <3>; + spi-max-frequency = <62500000>; + }; + + spi1: spi@20420000 { + compatible = "baikal,bt1-ssi","snps,dw-apb-ssi"; + status = "okay"; + #address-cells = <0x01>; + #size-cells = <0x00>; + reg = <0x0 0x20420000 0x0 0x1000>; + interrupt-parent = <0x01>; + interrupts = <27>; + clocks = <&device_clk>; + clock-names = "device_clk"; + num-cs = <3>; + spi-max-frequency = <62500000>; + }; + + i2c0: i2c@20330000{ + compatible = "snps,designware-i2c"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x20330000 0x0 0x100>; + clock-frequency = <400000>; + clocks = <&device_clk>; + interrupt-parent = <0x01>; + interrupts = <20>; + }; + + i2c1: i2c@20340000{ + compatible = "snps,designware-i2c"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x20340000 0x0 0x100>; + clock-frequency = <400000>; + clocks = <&device_clk>; + interrupt-parent = <0x01>; + interrupts = <21>; + }; + + i2c2: i2c@20430000{ + compatible = "snps,designware-i2c"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x20430000 0x0 0x100>; + clock-frequency = <400000>; + clocks = <&device_clk>; + interrupt-parent = <0x01>; + interrupts = <28>; + }; + + i2c3: i2c@20440000{ + compatible = "snps,designware-i2c"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x20440000 0x0 0x100>; + clock-frequency = <400000>; + clocks = <&device_clk>; + interrupt-parent = <0x01>; + interrupts = <29>; + }; + + wdt0: watchdog@20210000 { + compatible = "snps,dw-wdt"; + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x20210000 0x0 0x100>; + interrupt-parent = <0x01>; + interrupts = <33>; + clocks = <&device_clk>; + }; + + gpio: gpio@20200000 { + compatible = "snps,dw-apb-gpio"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x20200000 0x0 0x1000>; + clocks = <&csr_clk>, <&device_clk>; + clock-names = "bus", "db"; + status = "okay"; + + porta: gpio-port@0 { + compatible = "snps,dw-apb-gpio-port"; + reg = <0>; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <16>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <0x01>; + interrupts = <34>; + }; + + portb: gpio-port@1 { + compatible = "snps,dw-apb-gpio-port"; + reg = <1>; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + }; + + portc: gpio-port@2 { + compatible = "snps,dw-apb-gpio-port"; + reg = <2>; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + }; + + portd: gpio-port@3 { + compatible = "snps,dw-apb-gpio-port"; + reg = <3>; + gpio-controller; + #gpio-cells = <2>; + snps,nr-gpios = <8>; + }; + }; + + ethernet1@38000000 { + clocks = <&csr_clk>; + clock-names = "stmmaceth"; + compatible = "ultrarisc,dp1000-gmac", "snps,dwmac-5.10a"; + interrupt-parent = <0x01>; + interrupts = <84>; + interrupt-names = "macirq"; + reg = <0x00 0x38000000 0x00 0x1000000>; + local-mac-address = [ff ff ff ff ff ff]; + phy-mode = "rgmii"; + max-speed = <1000>; + snps,txpbl = <8>; + snps,rxpbl = <8>; + phy-handle = <&phy0>; + mdio { + #address-cells = <0x01>; + #size-cells = <0x00>; + compatible = "snps,dwmac-mdio"; + phy0: phy@0{ + phandle = <0x04>; + reg = <0x00>; + status = "okay"; + }; + }; + }; + + dmac: dma-controller@39000000 { + compatible = "snps,axi-dma-1.01a"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x0 0x39000000 0x0 0x400>; + clocks = <&device_clk>, <&device_clk>; + clock-names = "core-clk", "cfgr-clk"; + interrupt-parent = <0x01>; + interrupts = <152>; + #dma-cells = <1>; + dma-channels = <8>; + snps,dma-masters = <1>; + snps,data-width = <4>; + snps,block-size = <512 512 512 512 512 512 512 512>; + snps,priority = <0 1 2 3 4 5 6 7>; + snps,axi-max-burst-len = <256>; + }; + + pcie_x16: pcie@21000000 { + compatible = "ultrarisc,dw-pcie"; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + reg = <0x0 0x21000000 0x0 0x01000000>, /* IP registers */ + <0x0 0x4fff0000 0x0 0x00010000>; /* Configuration space */ + reg-names = "dbi", "config"; + device_type = "pci"; + dma-coherent; + bus-range = <0x0 0xff>; + num-lanes = <16>; + ranges = <0x81000000 0x0 0x4fbf0000 0x0 0x4fbf0000 0x0 0x00400000>, + <0x82000000 0x0 0x40000000 0x0 0x40000000 0x0 0x0fbf0000>, + <0xc3000000 0x40 0x00000000 0x40 0x00000000 0xd 0x00000000>; + max-link-speed = <4>; + interrupt-parent = <&plic>; + interrupts = <43>, <44>, <45>, <46>, <47>, <48>; + interrupt-names = "msi", "inta", "intb", "intc", "intd", "aer"; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &plic 44>, + <0x0 0x0 0x0 0x2 &plic 45>, + <0x0 0x0 0x0 0x3 &plic 46>, + <0x0 0x0 0x0 0x4 &plic 47>; + }; + + pcie_x4a: pcie@23000000 { + compatible = "ultrarisc,dw-pcie"; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + reg = <0x0 0x23000000 0x0 0x01000000>, /* IP registers */ + <0x0 0x6fff0000 0x0 0x00010000>; /* Configuration space */ + reg-names = "dbi", "config"; + device_type = "pci"; + dma-coherent; + bus-range = <0x0 0xff>; + num-lanes = <4>; + ranges = <0x81000000 0x0 0x6fbf0000 0x0 0x6fbf0000 0x0 0x00400000>, + <0x82000000 0x0 0x60000000 0x0 0x60000000 0x0 0x0fbf0000>, + <0xc3000000 0x80 0x00000000 0x80 0x00000000 0xd 0x00000000>; + max-link-speed = <4>; + interrupt-parent = <&plic>; + interrupts = <63>, <64>, <65>, <66>, <67>, <68>; + interrupt-names = "msi", "inta", "intb", "intc", "intd", "aer"; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &plic 64>, + <0x0 0x0 0x0 0x2 &plic 65>, + <0x0 0x0 0x0 0x3 &plic 66>, + <0x0 0x0 0x0 0x4 &plic 67>; + }; + + pcie_x4b: pcie@24000000 { + compatible = "ultrarisc,dw-pcie"; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + reg = <0x0 0x24000000 0x0 0x01000000>, /* IP registers */ + <0x0 0x7fff0000 0x0 0x00010000>; /* Configuration space */ + reg-names = "dbi", "config"; + device_type = "pci"; + dma-coherent; + bus-range = <0x0 0xff>; + num-lanes = <4>; + ranges = <0x81000000 0x0 0x7fbf0000 0x0 0x7fbf0000 0x0 0x00400000>, + <0x82000000 0x0 0x70000000 0x0 0x70000000 0x0 0x0fbf0000>, + <0xc3000000 0xc0 0x00000000 0xc0 0x00000000 0xd 0x00000000>; + max-link-speed = <4>; + interrupt-parent = <&plic>; + interrupts = <73>, <74>, <75>, <76>, <77>, <78>; + interrupt-names = "msi", "inta", "intb", "intc", "intd", "aer"; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &plic 74>, + <0x0 0x0 0x0 0x2 &plic 75>, + <0x0 0x0 0x0 0x3 &plic 76>, + <0x0 0x0 0x0 0x4 &plic 77>; + }; + }; +}; \ No newline at end of file diff --git a/platform/riscv64/ur-dp1000/image/dts/zone0.dts b/platform/riscv64/ur-dp1000/image/dts/zone0.dts new file mode 100644 index 00000000..26564c9e --- /dev/null +++ b/platform/riscv64/ur-dp1000/image/dts/zone0.dts @@ -0,0 +1,275 @@ +/dts-v1/; + +/ { + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "ultrarisc,dp1000"; + model = "ultrarisc,dp1000"; + + chosen { + bootargs = "earlycon=sbi console=tty0 console=ttyS0,115200n8"; + stdout-path = "/soc/serial@20300000"; + }; + + cpus { + #address-cells = <0x01>; + #size-cells = <0x00>; + timebase-frequency = <10000000>; + + cpu0: cpu@0 { + device_type = "cpu"; + reg = <0x00>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcb"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + cpu0_intc:interrupt-controller { + #address-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + #interrupt-cells = <0x01>; + }; + }; + cpu1: cpu@1 { + device_type = "cpu"; + reg = <0x1>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcb"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + cpu1_intc:interrupt-controller { + #address-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + #interrupt-cells = <0x01>; + }; + }; + //cpu2: cpu@2 { + // device_type = "cpu"; + // reg = <0x2>; + // status = "okay"; + // compatible = "riscv"; + // riscv,isa = "rv64imafdcb"; + // mmu-type = "riscv,sv48"; + // clock-frequency = <2000000000>; + // cpu2_intc:interrupt-controller { + // #address-cells = <0x01>; + // interrupt-controller; + // compatible = "riscv,cpu-intc"; + // #interrupt-cells = <0x01>; + // }; + //}; + //cpu3: cpu@3 { + // device_type = "cpu"; + // reg = <0x3>; + // status = "okay"; + // compatible = "riscv"; + // riscv,isa = "rv64imafdcb"; + // mmu-type = "riscv,sv48"; + // clock-frequency = <2000000000>; + // cpu3_intc:interrupt-controller { + // #address-cells = <0x01>; + // interrupt-controller; + // compatible = "riscv,cpu-intc"; + // #interrupt-cells = <0x01>; + // }; + //}; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x00 0x80000000 0x00 0x40000000>; + }; + + reserved-memory { + #address-cells = <0x02>; + #size-cells = <0x02>; + ranges; + + // 0x8000_0000 - 0x8500_0000 is reserverd for low-level software + opensbi@80000000 { + no-map; + reg = <0x00 0x80000000 0x00 0x00200000>; + }; + hvisor@80200000 { + no-map; + reg = <0x00 0x80200000 0x00 0x04E00000>; + }; + + // zone0's dtb is located here + dtbfile@8f000000 { + no-map; + reg = <0x00 0x8f000000 0x00 0x01000000>; + }; + + // reserved for zonex's pcie msi (needs DMA32 mem) + pcimsi@c0000000 { + no-map; + reg = <0x00 0xc0000000 0x00 0x40000000>; + }; + + // non-root area, top 30 GB + //nonroot@100000000 { + // no-map; + // reg = <0x01 0x00 0x07 0x80000000>; + //}; + }; + + soc { + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "simple-bus"; + ranges; + + //clocks { + // compatible = "simple-bus"; + // u-boot,dm-pre-reloc; + // device_clk: device_clk { + // compatible = "fixed-clock"; + // clock-frequency = <62500000>; + // #clock-cells = <0>; + // }; + // csr_clk: csr_clk { + // compatible = "fixed-clock"; + // clock-frequency = <250000000>; + // #clock-cells = <0>; + // }; + //}; + + plic: plic@9000000 { + #interrupt-cells = <1>; + #address-cells = <0>; + phandle = <0x01>; + compatible = "sifive,plic-1.0.0"; + interrupt-controller; + interrupts-extended = <&cpu0_intc 0xffffffff>, <&cpu0_intc 0x9>, <&cpu0_intc 0xffffffff>, + <&cpu1_intc 0xffffffff>, <&cpu1_intc 0x9>, <&cpu1_intc 0xffffffff>; + reg = <0x00 0x9000000 0x00 0x4000000>; + riscv,max-priority = <0x07>; + riscv,ndev = <160>; + }; + + uart0: serial@20300000 { + interrupt-parent = <0x01>; + interrupts = <17>; + clock-frequency = <62500000>; + current-speed = <115200>; + reg = <0x00 0x20300000 0x00 0x10000>; + compatible = "ultrarisc,dp1000-uart","ns16550"; + reg-offset = <0x0>; + reg-shift = <0x02>; + }; + + //ethernet1@38000000 { + // clocks = <&csr_clk>; + // clock-names = "stmmaceth"; + // compatible = "ultrarisc,dp1000-gmac", "snps,dwmac-5.10a"; + // interrupt-parent = <0x01>; + // interrupts = <84>; + // interrupt-names = "macirq"; + // reg = <0x00 0x38000000 0x00 0x1000000>; + // local-mac-address = [ff ff ff ff ff ff]; + // phy-mode = "rgmii"; + // max-speed = <1000>; + // snps,txpbl = <8>; + // snps,rxpbl = <8>; + // phy-handle = <&phy0>; + // mdio { + // #address-cells = <0x01>; + // #size-cells = <0x00>; + // compatible = "snps,dwmac-mdio"; + // phy0: phy@0{ + // phandle = <0x04>; + // reg = <0x00>; + // status = "okay"; + // }; + // }; + //}; + + //pcie_x16: pcie@21000000 { + // compatible = "ultrarisc,dw-pcie"; + // #address-cells = <3>; + // #size-cells = <2>; + // #interrupt-cells = <1>; + // reg = <0x0 0x21000000 0x0 0x01000000>, /* IP registers */ + // <0x0 0x4fff0000 0x0 0x00010000>; /* Configuration space */ + // reg-names = "dbi", "config"; + // device_type = "pci"; + // dma-coherent; + // bus-range = <0x0 0xff>; + // num-lanes = <16>; + // ranges = <0x81000000 0x0 0x4fbf0000 0x0 0x4fbf0000 0x0 0x00400000>, + // <0x82000000 0x0 0x40000000 0x0 0x40000000 0x0 0x0fbf0000>, + // <0xc3000000 0x40 0x00000000 0x40 0x00000000 0xd 0x00000000>; + // max-link-speed = <4>; + // interrupt-parent = <&plic>; + // interrupts = <43>, <44>, <45>, <46>, <47>, <48>; + // interrupt-names = "msi", "inta", "intb", "intc", "intd", "aer"; + // interrupt-map-mask = <0x0 0x0 0x0 0x7>; + // interrupt-map = <0x0 0x0 0x0 0x1 &plic 44>, + // <0x0 0x0 0x0 0x2 &plic 45>, + // <0x0 0x0 0x0 0x3 &plic 46>, + // <0x0 0x0 0x0 0x4 &plic 47>; + //}; + + //pcie_x4a: pcie@23000000 { + // compatible = "ultrarisc,dw-pcie"; + // #address-cells = <3>; + // #size-cells = <2>; + // #interrupt-cells = <1>; + // reg = <0x0 0x23000000 0x0 0x01000000>, /* IP registers */ + // <0x0 0x6fff0000 0x0 0x00010000>; /* Configuration space */ + // reg-names = "dbi", "config"; + // device_type = "pci"; + // dma-coherent; + // bus-range = <0x0 0xff>; + // num-lanes = <4>; + // ranges = <0x81000000 0x0 0x6fbf0000 0x0 0x6fbf0000 0x0 0x00400000>, + // <0x82000000 0x0 0x60000000 0x0 0x60000000 0x0 0x0fbf0000>, + // <0xc3000000 0x80 0x00000000 0x80 0x00000000 0xd 0x00000000>; + // max-link-speed = <4>; + // interrupt-parent = <&plic>; + // interrupts = <63>, <64>, <65>, <66>, <67>, <68>; + // interrupt-names = "msi", "inta", "intb", "intc", "intd", "aer"; + // interrupt-map-mask = <0x0 0x0 0x0 0x7>; + // interrupt-map = <0x0 0x0 0x0 0x1 &plic 64>, + // <0x0 0x0 0x0 0x2 &plic 65>, + // <0x0 0x0 0x0 0x3 &plic 66>, + // <0x0 0x0 0x0 0x4 &plic 67>; + //}; + + //pcie_x4b: pcie@24000000 { + // compatible = "ultrarisc,dw-pcie"; + // #address-cells = <3>; + // #size-cells = <2>; + // #interrupt-cells = <1>; + // reg = <0x0 0x24000000 0x0 0x01000000>, /* IP registers */ + // <0x0 0x7fff0000 0x0 0x00010000>; /* Configuration space */ + // reg-names = "dbi", "config"; + // device_type = "pci"; + // dma-coherent; + // bus-range = <0x0 0xff>; + // num-lanes = <4>; + // ranges = <0x81000000 0x0 0x7fbf0000 0x0 0x7fbf0000 0x0 0x00400000>, + // <0x82000000 0x0 0x70000000 0x0 0x70000000 0x0 0x0fbf0000>, + // <0xc3000000 0xc0 0x00000000 0xc0 0x00000000 0xd 0x00000000>; + // max-link-speed = <4>; + // interrupt-parent = <&plic>; + // interrupts = <73>, <74>, <75>, <76>, <77>, <78>; + // interrupt-names = "msi", "inta", "intb", "intc", "intd", "aer"; + // interrupt-map-mask = <0x0 0x0 0x0 0x7>; + // interrupt-map = <0x0 0x0 0x0 0x1 &plic 74>, + // <0x0 0x0 0x0 0x2 &plic 75>, + // <0x0 0x0 0x0 0x3 &plic 76>, + // <0x0 0x0 0x0 0x4 &plic 77>; + //}; + }; + + hvisor_virtio_device { + compatible = "hvisor"; + interrupt-parent = <&plic>; + interrupts = <0x20>; + }; +}; \ No newline at end of file diff --git a/platform/riscv64/ur-dp1000/image/dts/zone1-linux.dts b/platform/riscv64/ur-dp1000/image/dts/zone1-linux.dts new file mode 100644 index 00000000..f22a83cf --- /dev/null +++ b/platform/riscv64/ur-dp1000/image/dts/zone1-linux.dts @@ -0,0 +1,277 @@ +/dts-v1/; + +/ { + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "ultrarisc,dp1000"; + model = "ultrarisc,dp1000"; + + aliases { + virtio-console = "/soc/virtio_mmio@10007000"; + }; + + chosen { + bootargs = "earlycon console=hvc0 root=UUID=8910ab6a-efb3-4d32-9b75-b4478dc494e0 ro splash"; + stdout-path = "virtio-console"; + }; + + cpus { + #address-cells = <0x01>; + #size-cells = <0x00>; + timebase-frequency = <10000000>; + + cpu2: cpu@2 { + device_type = "cpu"; + reg = <0x2>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcb"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + cpu2_intc:interrupt-controller { + #address-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + #interrupt-cells = <0x01>; + }; + }; + cpu3: cpu@3 { + device_type = "cpu"; + reg = <0x3>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcb"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + cpu3_intc:interrupt-controller { + #address-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + #interrupt-cells = <0x01>; + }; + }; + cpu4: cpu@4 { + device_type = "cpu"; + reg = <0x10>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcb"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + cpu4_intc:interrupt-controller { + #address-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + #interrupt-cells = <0x01>; + }; + }; + cpu5: cpu@5 { + device_type = "cpu"; + reg = <0x11>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcb"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + cpu5_intc:interrupt-controller { + #address-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + #interrupt-cells = <0x01>; + }; + }; + cpu6: cpu@6 { + device_type = "cpu"; + reg = <0x12>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcb"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + cpu6_intc:interrupt-controller { + #address-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + #interrupt-cells = <0x01>; + }; + }; + cpu7: cpu@7 { + device_type = "cpu"; + reg = <0x13>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcb"; + mmu-type = "riscv,sv48"; + clock-frequency = <2000000000>; + cpu7_intc:interrupt-controller { + #address-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + #interrupt-cells = <0x01>; + }; + }; + }; + + memory@C0000000 { + device_type = "memory"; + reg = <0x00 0xC0000000 0x07 0xC0000000>; + }; + + soc { + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "simple-bus"; + ranges; + + clocks { + compatible = "simple-bus"; + u-boot,dm-pre-reloc; + device_clk: device_clk { + compatible = "fixed-clock"; + clock-frequency = <62500000>; + #clock-cells = <0>; + }; + + csr_clk: csr_clk { + compatible = "fixed-clock"; + clock-frequency = <250000000>; + #clock-cells = <0>; + }; + }; + + plic: plic@9000000 { + #interrupt-cells = <1>; + #address-cells = <0>; + phandle = <0x01>; + compatible = "sifive,plic-1.0.0"; + interrupt-controller; + interrupts-extended = <&cpu2_intc 0xffffffff>, <&cpu2_intc 0x9>, <&cpu2_intc 0xffffffff>, + <&cpu3_intc 0xffffffff>, <&cpu3_intc 0x9>, <&cpu3_intc 0xffffffff>, + <&cpu4_intc 0xffffffff>, <&cpu4_intc 0x9>, <&cpu4_intc 0xffffffff>, + <&cpu5_intc 0xffffffff>, <&cpu5_intc 0x9>, <&cpu5_intc 0xffffffff>, + <&cpu6_intc 0xffffffff>, <&cpu6_intc 0x9>, <&cpu6_intc 0xffffffff>, + <&cpu7_intc 0xffffffff>, <&cpu7_intc 0x9>, <&cpu7_intc 0xffffffff>; + reg = <0x00 0x9000000 0x00 0x4000000>; + riscv,max-priority = <0x07>; + riscv,ndev = <160>; + }; + + //virtio_mmio@10006000 { + // interrupts = <0x06>; + // interrupt-parent = <&plic>; + // reg = <0x00 0x10006000 0x00 0x1000>; + // compatible = "virtio,mmio"; + //}; + + virtio_mmio@10007000 { + interrupts = <0x07>; + interrupt-parent = <&plic>; + reg = <0x00 0x10007000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + + ethernet1@38000000 { + clocks = <&csr_clk>; + clock-names = "stmmaceth"; + compatible = "ultrarisc,dp1000-gmac", "snps,dwmac-5.10a"; + interrupt-parent = <0x01>; + interrupts = <84>; + interrupt-names = "macirq"; + reg = <0x00 0x38000000 0x00 0x1000000>; + local-mac-address = [ff ff ff ff ff ff]; + phy-mode = "rgmii"; + max-speed = <1000>; + snps,txpbl = <8>; + snps,rxpbl = <8>; + phy-handle = <&phy0>; + mdio { + #address-cells = <0x01>; + #size-cells = <0x00>; + compatible = "snps,dwmac-mdio"; + phy0: phy@0{ + phandle = <0x04>; + reg = <0x00>; + status = "okay"; + }; + }; + }; + + pcie_x16: pcie@21000000 { + compatible = "ultrarisc,dw-pcie"; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + reg = <0x0 0x21000000 0x0 0x01000000>, /* IP registers */ + <0x0 0x4fff0000 0x0 0x00010000>; /* Configuration space */ + reg-names = "dbi", "config"; + device_type = "pci"; + dma-coherent; + bus-range = <0x0 0xff>; + num-lanes = <16>; + ranges = <0x81000000 0x0 0x4fbf0000 0x0 0x4fbf0000 0x0 0x00400000>, + <0x82000000 0x0 0x40000000 0x0 0x40000000 0x0 0x0fbf0000>, + <0xc3000000 0x40 0x00000000 0x40 0x00000000 0xd 0x00000000>; + max-link-speed = <4>; + interrupt-parent = <&plic>; + interrupts = <43>, <44>, <45>, <46>, <47>, <48>; + interrupt-names = "msi", "inta", "intb", "intc", "intd", "aer"; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &plic 44>, + <0x0 0x0 0x0 0x2 &plic 45>, + <0x0 0x0 0x0 0x3 &plic 46>, + <0x0 0x0 0x0 0x4 &plic 47>; + }; + + pcie_x4a: pcie@23000000 { + compatible = "ultrarisc,dw-pcie"; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + reg = <0x0 0x23000000 0x0 0x01000000>, /* IP registers */ + <0x0 0x6fff0000 0x0 0x00010000>; /* Configuration space */ + reg-names = "dbi", "config"; + device_type = "pci"; + dma-coherent; + bus-range = <0x0 0xff>; + num-lanes = <4>; + ranges = <0x81000000 0x0 0x6fbf0000 0x0 0x6fbf0000 0x0 0x00400000>, + <0x82000000 0x0 0x60000000 0x0 0x60000000 0x0 0x0fbf0000>, + <0xc3000000 0x80 0x00000000 0x80 0x00000000 0xd 0x00000000>; + max-link-speed = <4>; + interrupt-parent = <&plic>; + interrupts = <63>, <64>, <65>, <66>, <67>, <68>; + interrupt-names = "msi", "inta", "intb", "intc", "intd", "aer"; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &plic 64>, + <0x0 0x0 0x0 0x2 &plic 65>, + <0x0 0x0 0x0 0x3 &plic 66>, + <0x0 0x0 0x0 0x4 &plic 67>; + }; + + pcie_x4b: pcie@24000000 { + compatible = "ultrarisc,dw-pcie"; + #address-cells = <3>; + #size-cells = <2>; + #interrupt-cells = <1>; + reg = <0x0 0x24000000 0x0 0x01000000>, /* IP registers */ + <0x0 0x7fff0000 0x0 0x00010000>; /* Configuration space */ + reg-names = "dbi", "config"; + device_type = "pci"; + dma-coherent; + bus-range = <0x0 0xff>; + num-lanes = <4>; + ranges = <0x81000000 0x0 0x7fbf0000 0x0 0x7fbf0000 0x0 0x00400000>, + <0x82000000 0x0 0x70000000 0x0 0x70000000 0x0 0x0fbf0000>, + <0xc3000000 0xc0 0x00000000 0xc0 0x00000000 0xd 0x00000000>; + max-link-speed = <4>; + interrupt-parent = <&plic>; + interrupts = <73>, <74>, <75>, <76>, <77>, <78>; + interrupt-names = "msi", "inta", "intb", "intc", "intd", "aer"; + interrupt-map-mask = <0x0 0x0 0x0 0x7>; + interrupt-map = <0x0 0x0 0x0 0x1 &plic 74>, + <0x0 0x0 0x0 0x2 &plic 75>, + <0x0 0x0 0x0 0x3 &plic 76>, + <0x0 0x0 0x0 0x4 &plic 77>; + }; + }; +}; \ No newline at end of file diff --git a/platform/riscv64/ur-dp1000/linker.ld b/platform/riscv64/ur-dp1000/linker.ld new file mode 100644 index 00000000..eb62b0fe --- /dev/null +++ b/platform/riscv64/ur-dp1000/linker.ld @@ -0,0 +1,50 @@ +ENTRY(arch_entry) +BASE_ADDRESS = 0x80200000; + + +SECTIONS +{ + . = BASE_ADDRESS; + skernel = .; + + stext = .; + .text : { + *(.text.entry) + *(.text .text.*) + } + + . = ALIGN(4K); + etext = .; + srodata = .; + .rodata : { + *(.rodata .rodata.*) + *(.srodata .srodata.*) + } + + . = ALIGN(4K); + erodata = .; + sdata = .; + .data : { + *(.data .data.*) + *(.sdata .sdata.*) + } + + . = ALIGN(4K); + edata = .; + .bss : { + *(.bss.stack) + sbss = .; + *(.bss .bss.*) + *(.sbss .sbss.*) + } + + . = ALIGN(4K); + ebss = .; + ekernel = .; + + /DISCARD/ : { + *(.eh_frame) + } + . = ALIGN(4K); + __core_end = .; +} \ No newline at end of file diff --git a/platform/riscv64/ur-dp1000/platform.mk b/platform/riscv64/ur-dp1000/platform.mk new file mode 100644 index 00000000..d21cb066 --- /dev/null +++ b/platform/riscv64/ur-dp1000/platform.mk @@ -0,0 +1,6 @@ + +# HVISOR ENTRY +HVISOR_ENTRY_PA := 0x80200000 + +$(hvisor_bin): elf + $(OBJCOPY) $(hvisor_elf) --strip-all -O binary $@ diff --git a/platform/riscv64/ur-dp1000/scripts/boot_zone1.sh b/platform/riscv64/ur-dp1000/scripts/boot_zone1.sh new file mode 100644 index 00000000..08759372 --- /dev/null +++ b/platform/riscv64/ur-dp1000/scripts/boot_zone1.sh @@ -0,0 +1,10 @@ +insmod hvisor.ko +mount -t proc proc /proc +mount -t sysfs sysfs /sys +rm nohup.out +mkdir -p /dev/pts +mount -t devpts devpts /dev/pts +nohup ./hvisor virtio start zone1-linux-virtio.json & +./hvisor zone start zone1-linux.json && \ +cat nohup.out | grep "char device" && \ +script /dev/null \ No newline at end of file diff --git a/platform/riscv64/ur-dp1000/scripts/init.sh b/platform/riscv64/ur-dp1000/scripts/init.sh new file mode 100644 index 00000000..338cdecf --- /dev/null +++ b/platform/riscv64/ur-dp1000/scripts/init.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +mount -t proc proc /proc +mount -t sysfs sys /sys +mkdir -p /dev/pts +mount -t devpts devpts /dev/pts -o gid=5,mode=620,ptmxmode=0666 + +# Set one temp hostname, maybe rockos-eswin +hostname $(cat /etc/hostname) + +while true; do + /sbin/getty -L ttyS0 115200 vt100 +done \ No newline at end of file diff --git a/src/arch/riscv64/trap.rs b/src/arch/riscv64/trap.rs index e1fc1bca..99277f72 100644 --- a/src/arch/riscv64/trap.rs +++ b/src/arch/riscv64/trap.rs @@ -15,6 +15,8 @@ // use super::cpu::ArchCpu; use crate::arch::sbi::sbi_vs_handler; +#[cfg(feature = "plic")] +use crate::device::irqchip::plic::{inject_irq, plic_get_hwirq}; use crate::event::check_events; use crate::memory::GuestPhysAddr; use crate::memory::{mmio_handle_access, MMIOAccess}; @@ -32,7 +34,8 @@ global_asm!(include_str!("trap.S"), sync_exception_handler=sym sync_exception_handler, interrupts_arch_handle=sym interrupts_arch_handle); -#[allow(non_snake_case, unused)] +#[allow(non_snake_case)] +#[allow(unused)] pub mod ExceptionType { pub const ECALL_VU: usize = 8; pub const ECALL_VS: usize = 10; @@ -89,6 +92,7 @@ pub const INS_C_LW: usize = 0x4000; // [15:13] = 0b010, [1:0] = 0b00 pub const INS_C_SW: usize = 0xc000; // [15:13] = 0b110, [1:0] = 0b00 pub const INS_C_LD: usize = 0x6000; // [15:13] = 0b011, [1:0] = 0b00 pub const INS_C_SD: usize = 0xe000; // [15:13] = 0b111, [1:0] = 0b00 + #[allow(unused)] pub const INS_RS1_MASK: usize = 0x000f8000; pub const INS_RS2_MASK: usize = 0x01f00000; @@ -368,11 +372,8 @@ fn decode_inst(inst: u32) -> (usize, Option) { /// Handle interrupts which hvisor receives. pub fn interrupts_arch_handle(current_cpu: &mut ArchCpu) { + trace!("interrupts_arch_handle @CPU{}", current_cpu.cpuid); let trap_code = riscv::register::scause::read().code(); - debug!( - "interrupts_arch_handle @CPU{}: {:?}", - current_cpu.cpuid, trap_code - ); match trap_code { InterruptType::STI => { // Inject timer interrupt to VS. @@ -420,9 +421,7 @@ pub fn handle_external_interrupt(_current_cpu: &mut ArchCpu) { { // Note: in hvisor, all external interrupts are assigned to VS. // 1. claim hw irq. - use crate::arch::cpu::this_cpu_id; - let context_id = 2 * this_cpu_id() + 1; - let irq_id = crate::device::irqchip::plic::host_plic().claim(context_id); + let irq_id = plic_get_hwirq(); // If this irq has been claimed, it will be 0. if irq_id == 0 { @@ -430,7 +429,7 @@ pub fn handle_external_interrupt(_current_cpu: &mut ArchCpu) { } // 2. inject hw irq to zone. - crate::device::irqchip::plic::inject_irq(irq_id as usize, true); + inject_irq(irq_id as usize, true); } #[cfg(feature = "aia")] { diff --git a/src/device/irqchip/plic/mod.rs b/src/device/irqchip/plic/mod.rs index efb6c0a5..1add8f67 100644 --- a/src/device/irqchip/plic/mod.rs +++ b/src/device/irqchip/plic/mod.rs @@ -11,40 +11,46 @@ // Syswonder Website: // https://www.syswonder.org // -// Authors: Jingyu Liu +// Authors: +// Jingyu Liu // -pub mod plic; -pub mod vplic; +#![deny(unused_variables)] +#![deny(unused_imports)] +#![deny(unused_mut)] +#![deny(unused)] -pub use self::plic::*; -use self::vplic::*; +mod plic; +mod vplic; + +use crate::arch::cpu::this_cpu_id; use crate::arch::zone::HvArchZoneConfig; -use crate::config::root_zone_config; use crate::config::HvZoneConfig; use crate::config::{BitmapWord, CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD}; -use crate::consts::{MAX_CPU_NUM, MAX_ZONE_NUM}; +use crate::consts::MAX_CPU_NUM; use crate::error::HvResult; use crate::memory::mmio::MMIOAccess; use crate::percpu::this_cpu_data; -use crate::platform::__board::*; -use crate::platform::BOARD_PLIC_INTERRUPTS_NUM; +use crate::platform::*; use crate::zone::Zone; +use alloc::collections::BTreeMap; +use alloc::sync::Arc; use alloc::vec::Vec; -use heapless::FnvIndexMap; -use spin::Once; +use plic::*; +use spin::{Mutex, Once}; +use vplic::*; /* - Due to hvisor is a static partitioning hypervisor. - The irq is assigned to a specific zone, a zone has its own harts. - So we assume different harts will don't access the same plic register. - For physical plic, we don't add lock for it. + Due to hvisor is a static partitioning hypervisor. + The irq is assigned to a specific zone, a zone has its own harts. + So we assume different harts will don't access the same plic register. + For physical plic, we don't add lock for it. */ // Physical PLIC -pub static PLIC: Once = Once::new(); -// The MAX_ZONE_NUM should be the power of 2. -static mut VPLIC_MAP: Option> = None; +static PLIC: Once = Once::new(); +// VPLIC_MAP, one VPLIC per VM +static VPLIC_MAP: Mutex>> = Mutex::new(BTreeMap::new()); pub fn init_plic(plic_base: usize) { PLIC.call_once(|| Plic::new(plic_base)); @@ -56,13 +62,11 @@ pub fn host_plic<'a>() -> &'a Plic { pub fn primary_init_early() { // Init the physical PLIC global part - let root_config = root_zone_config(); - init_plic(root_config.arch_config.plic_base as usize); - host_plic().init_global(BOARD_PLIC_INTERRUPTS_NUM, MAX_CPU_NUM * 2); - - unsafe { - VPLIC_MAP = Some(FnvIndexMap::new()); - } + init_plic(PLIC_BASE); + host_plic().init_global( + BOARD_PLIC_INTERRUPTS_NUM, + MAX_CPU_NUM * NUM_CONTEXTS_PER_HART, + ); } pub fn primary_init_late() { @@ -70,19 +74,30 @@ pub fn primary_init_late() { } pub fn percpu_init() { - host_plic().init_per_hart(this_cpu_data().id); + host_plic().init_per_hart(this_cpu_id()); +} + +pub fn plic_get_hwirq() -> u32 { + let context_id = this_cpu_id() * NUM_CONTEXTS_PER_HART + 1; + host_plic().plic_get_hwirq(context_id) } pub fn inject_irq(irq: usize, is_hardware: bool) { debug!("inject_irq: {} is_hardware: {}", irq, is_hardware); - let vcontext_id = pcontext_to_vcontext(this_cpu_data().id * 2 + 1); - this_cpu_data() - .zone - .as_ref() - .unwrap() - .read() - .get_vplic() - .inject_irq(vcontext_id, irq, is_hardware); + let vcontext_id = pcontext_to_vcontext(this_cpu_id() * NUM_CONTEXTS_PER_HART + 1); + // this_cpu_data() + // .zone + // .as_ref() + // .unwrap() + // .read() + // .get_vplic() + // .inject_irq(vcontext_id, irq, is_hardware); + let vplic = { + let zone = this_cpu_data().zone.as_ref().unwrap().read(); + zone.get_vplic() + }; + // Avoid holding the read lock when calling inject_irq + vplic.inject_irq(vcontext_id, irq, is_hardware); } /// Convert vcontext id to pcontext id. @@ -95,9 +110,9 @@ pub fn vcontext_to_pcontext(vcontext_id: usize) -> usize { .cpu_set .iter() .collect::>(); - let index = vcontext_id / 2; + let index = vcontext_id / NUM_CONTEXTS_PER_HART; // convert to physical hart S-mode - pcpu_set[index] * 2 + 1 + pcpu_set[index] * NUM_CONTEXTS_PER_HART + 1 } /// Convert pcontext id to vcontext id. @@ -111,7 +126,7 @@ pub fn pcontext_to_vcontext(_pcontext_id: usize) -> usize { .cpu_set .iter() .collect::>(); - let pcpu_id = this_cpu_data().id; + let pcpu_id = this_cpu_id(); let mut index = 0; for (i, &id) in pcpu_set.iter().enumerate() { if id == pcpu_id { @@ -120,18 +135,24 @@ pub fn pcontext_to_vcontext(_pcontext_id: usize) -> usize { } } // convert to virtual hart S-mode - index * 2 + 1 + index * NUM_CONTEXTS_PER_HART + 1 } /// handle Zone's plic mmio access. pub fn vplic_handler(mmio: &mut MMIOAccess, _arg: usize) -> HvResult { - let value = this_cpu_data() - .zone - .as_ref() - .unwrap() - .read() - .get_vplic() - .vplic_emul_access(mmio.address, mmio.size, mmio.value, mmio.is_write); + // let value = this_cpu_data() + // .zone + // .as_ref() + // .unwrap() + // .read() + // .get_vplic() + // .vplic_emul_access(mmio.address, mmio.size, mmio.value, mmio.is_write); + let vplic = { + let zone = this_cpu_data().zone.as_ref().unwrap().read(); + zone.get_vplic() + }; + // Avoid holding the read lock when calling vplic_emul_access + let value = vplic.vplic_emul_access(mmio.address, mmio.size, mmio.value, mmio.is_write); if !mmio.is_write { // read from vplic mmio.value = value as usize; @@ -141,26 +162,37 @@ pub fn vplic_handler(mmio: &mut MMIOAccess, _arg: usize) -> HvResult { /// Update hart line handler. pub fn update_hart_line() { - let pcontext_id = this_cpu_data().id * 2 + 1; + let pcontext_id = this_cpu_id() * NUM_CONTEXTS_PER_HART + 1; let vcontext_id = pcontext_to_vcontext(pcontext_id); - this_cpu_data() - .zone - .as_ref() - .unwrap() - .read() - .get_vplic() - .update_hart_line(vcontext_id); + // this_cpu_data() + // .zone + // .as_ref() + // .unwrap() + // .read() + // .get_vplic() + // .update_hart_line(vcontext_id); + let vplic = { + let zone = this_cpu_data().zone.as_ref().unwrap().read(); + zone.get_vplic() + }; + // Avoid holding the read lock when calling update_hart_line + vplic.update_hart_line(vcontext_id); } /// Print all keys in the VPLIC_MAP for debugging purposes. +/// This function acquires the lock internally and is safe to call from outside. +#[allow(unused)] fn print_keys() { + let map = VPLIC_MAP.lock(); + print_keys_from_map(&map); +} + +/// Helper: print keys from an already-locked map reference. +/// Useful to avoid nested locking when called from within a locked scope. +fn print_keys_from_map(map: &BTreeMap>) { info!("VPLIC_MAP keys:"); - unsafe { - if let Some(map) = &VPLIC_MAP { - for (&key, _) in map.iter() { - info!("Zone {} in VPLIC_MAP", key); - } - } + for (&key, _) in map.iter() { + info!(" Zone {}'s VPLIC is in VPLIC_MAP", key); } } @@ -168,41 +200,34 @@ impl Zone { /// Initial the virtual PLIC related to thiz Zone. pub fn vplic_init(&mut self, config: &HvZoneConfig) { // Create a new VirtualPLIC for this Zone. - unsafe { - if let Some(map) = &mut VPLIC_MAP { - if map.contains_key(&self.id) { - panic!("VirtualPLIC for Zone {} already exists!", self.id); - } - let vplic = vplic::VirtualPLIC::new( - config.arch_config.plic_base, - BOARD_PLIC_INTERRUPTS_NUM, - self.cpu_num * 2, - ); - // Insert into Map - let _ = map.insert(self.id, vplic); - } else { - panic!("VPLIC_MAP is not initialized!"); - } + let mut map = VPLIC_MAP.lock(); + if map.contains_key(&self.id) { + panic!("VirtualPLIC for Zone {} already exists!", self.id); } + let vplic = vplic::VirtualPLIC::new( + config.arch_config.plic_base, + BOARD_PLIC_INTERRUPTS_NUM, + self.cpu_num * NUM_CONTEXTS_PER_HART, + ); + // Insert into Map + map.insert(self.id, Arc::new(vplic)); info!("VirtualPLIC for Zone {} initialized successfully", self.id); - print_keys(); + print_keys_from_map(&map); } - pub fn get_vplic(&self) -> &VirtualPLIC { - unsafe { - VPLIC_MAP - .as_ref() - .expect("VPLIC_MAP is not initialized!") - .get(&self.id) - .expect("VirtualPLIC for this Zone does not exist!") - } + pub fn get_vplic(&self) -> Arc { + VPLIC_MAP + .lock() + .get(&self.id) + .expect("No vplic exists for current zone.") + .clone() } pub fn arch_irqchip_reset(&self) { // We should make sure only one cpu to do this. // This func will only be called by one root zone's cpu. let host_plic = host_plic(); - // let vplic = self.get_vplic(); + let _vplic = self.get_vplic(); for (index, &word) in self.irq_bitmap.iter().enumerate() { for bit_position in 0..32 { if word & (1 << bit_position) != 0 { @@ -216,7 +241,7 @@ impl Zone { host_plic.set_priority(irq_id, 0); // Reset enable self.cpu_set.iter().for_each(|cpuid| { - let pcontext_id = cpuid * 2 + 1; + let pcontext_id = cpuid * NUM_CONTEXTS_PER_HART + 1; info!( "Reset pcontext_id {} irq_id {} enable to false", pcontext_id, irq_id @@ -228,7 +253,7 @@ impl Zone { } self.cpu_set.iter().for_each(|cpuid| { // Reset threshold - let pcontext_id = cpuid * 2 + 1; + let pcontext_id = cpuid * NUM_CONTEXTS_PER_HART + 1; info!("Reset pcontext_id {} threshold to 0", pcontext_id); host_plic.set_threshold(pcontext_id, 0); // At the same time, clear the events related to this cpu. @@ -236,14 +261,9 @@ impl Zone { crate::event::clear_events(cpuid); }); - unsafe { - if let Some(map) = &mut VPLIC_MAP { - map.remove(&self.id); - } else { - panic!("VPLIC_MAP is not initialized!"); - } - } - print_keys(); + let mut map = VPLIC_MAP.lock(); + map.remove(&self.id); + print_keys_from_map(&map); } fn insert_irq_to_bitmap(&mut self, irq: u32) { diff --git a/src/device/irqchip/plic/plic.rs b/src/device/irqchip/plic/plic.rs index 821d678e..a7f069bc 100644 --- a/src/device/irqchip/plic/plic.rs +++ b/src/device/irqchip/plic/plic.rs @@ -70,6 +70,9 @@ pub const PLIC_COMPLETE_OFFSET: usize = 0x200004; pub const PLIC_MAX_IRQ: usize = 1023; // 1-1023, in PLIC, irq 0 does not exist. pub const PLIC_MAX_CONTEXT: usize = 15872; +use crate::platform::BOARD_PLIC_INTERRUPTS_NUM; +use crate::platform::NUM_CONTEXTS_PER_HART; + /// Plic struct pub struct Plic { base: usize, @@ -99,7 +102,7 @@ impl Plic { } // set enable to 0 for i in 0..num_contexts { - for j in 0..(num_interrupts + 31 / 32) { + for j in 0..((num_interrupts + 31) / 32) { self.set_enable(i, j * 4, 0); } } @@ -109,7 +112,7 @@ impl Plic { pub fn init_per_hart(&self, cpu_id: usize) { // set threshold to 0 info!("PLIC init per hart: cpu_id = {}", cpu_id); - let context = cpu_id * 2 + 1; + let context = cpu_id * NUM_CONTEXTS_PER_HART + 1; self.set_threshold(context, 0); } @@ -139,12 +142,30 @@ impl Plic { pub fn set_enable_num(&self, context: usize, irq_id: usize, enable: bool) { let addr = self.base + PLIC_ENABLE_OFFSET + context * 0x80 + irq_id / 32 * 4; let mut value = unsafe { core::ptr::read_volatile(addr as *const u32) }; - value = value | ((enable as u32) << (irq_id % 32)); + if enable { + value |= 1 << (irq_id % 32); + } else { + value &= !(1 << (irq_id % 32)); + } unsafe { core::ptr::write_volatile(addr as *mut u32, value); } } + /// Plic get enable + #[inline(always)] + pub fn get_enable(&self, context: usize, irq_base: usize) -> u32 { + let addr = self.base + PLIC_ENABLE_OFFSET + context * 0x80 + irq_base; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + + /// Plic get pending + #[inline(always)] + fn get_pending(&self, irq_base: usize) -> u32 { + let addr = self.base + PLIC_PENDING_OFFSET + irq_base; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + /// Plic set threshold pub fn set_threshold(&self, context: usize, value: u32) { let addr = self.base + PLIC_THRESHOLD_OFFSET + context * 0x1000; @@ -153,6 +174,12 @@ impl Plic { } } + /// Plic get threshold + pub fn get_threshold(&self, context: usize) -> u32 { + let addr = self.base + PLIC_THRESHOLD_OFFSET + context * 0x1000; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + /// Plic claim pub fn claim(&self, context: usize) -> u32 { let addr = self.base + PLIC_CLAIM_OFFSET + context * 0x1000; @@ -166,4 +193,60 @@ impl Plic { core::ptr::write_volatile(addr as *mut u32, irq_id as u32); } } + + fn plic_check_enable_first_pending(&self, context: usize, ie: &mut [u32; 32]) -> bool { + let nr_irq_groups = (BOARD_PLIC_INTERRUPTS_NUM + 1) / 32; + // Read Current interrupt enables + for i in 0..nr_irq_groups { + ie[i] = self.get_enable(context, i * 4); + } + // Check for pending interrupts and enable only the first one found + for i in 0..nr_irq_groups { + let pending_irqs = self.get_pending(i * 4) & ie[i]; + // Find first pending irq + if pending_irqs != 0 { + let nbits = pending_irqs.trailing_zeros(); + for j in 0..nr_irq_groups { + let value = if j == i { 1 << nbits } else { 0 }; + self.set_enable(context, j * 4, value); + } + return true; + } + } + false + } + + fn plic_restore_enable_state(&self, context: usize, ie: &[u32; 32]) { + let nr_irq_groups = (BOARD_PLIC_INTERRUPTS_NUM + 1) / 32; + for i in 0..nr_irq_groups { + self.set_enable(context, i * 4, ie[i]); + } + } + + /// Get hw irq from PLIC + pub fn plic_get_hwirq(&self, context: usize) -> u32 { + /* + * https://github.com/RVCK-Project/rvck/blob/rvck-6.6/drivers/irqchip/irq-sifive-plic.c: + * Due to the implementation of the claim register in the UltraRISC DP1000 + * platform PLIC not conforming to the specification, this is a hardware + * bug. Therefore, when an interrupt is pending, we need to disable the other + * interrupts before reading the claim register. After processing the interrupt, + * we should then restore the enable register. + */ + + let mut hwirq = 0; + if cfg!(feature = "dp1000_plic") { + let mut ie: [u32; 32] = [0; 32]; // max 1024 irqs + hwirq = if self.plic_check_enable_first_pending(context, &mut ie) { + self.claim(context) + } else { + 0 + }; + self.plic_restore_enable_state(context, &ie); + } else { + hwirq = self.claim(context); + } + + hwirq + } } diff --git a/src/device/irqchip/plic/vplic.rs b/src/device/irqchip/plic/vplic.rs index bc05395f..84621d22 100644 --- a/src/device/irqchip/plic/vplic.rs +++ b/src/device/irqchip/plic/vplic.rs @@ -12,10 +12,11 @@ // https://www.syswonder.org // // Authors: +// Jingyu Liu // -use crate::percpu::this_cpu_data; -use alloc::sync::Arc; +use crate::arch::cpu::this_cpu_id; +use crate::platform::NUM_CONTEXTS_PER_HART; use alloc::vec::Vec; use bitvec::prelude::*; use spin::Mutex; @@ -30,7 +31,7 @@ pub struct VirtualPLIC { /// Number of Hart contexts (contains S-mode and M-mode), only S-mode works num_contexts: usize, /// Inner state of the vPLIC (thread-safe) - inner: Arc>, + inner: Mutex, } /// Inner state of the vPLIC @@ -67,7 +68,7 @@ impl VirtualPLIC { base_addr, max_interrupts, num_contexts, - inner: Arc::new(Mutex::new(vplic)), + inner: Mutex::new(vplic), } } @@ -99,7 +100,7 @@ impl VirtualPLIC { inner.vplic_update_hart_line(vcontext_id); } else { for vcontext_id in 0..self.num_contexts { - if vcontext_id % 2 == 0 { + if vcontext_id % NUM_CONTEXTS_PER_HART != 1 { continue; } if inner.vplic_get_enable(intr_id, vcontext_id) @@ -172,7 +173,7 @@ impl VirtualPLIC { } else { // only support S-mode hart. for vcontext_id in 0..self.num_contexts { - if vcontext_id % 2 == 0 { + if vcontext_id % NUM_CONTEXTS_PER_HART != 1 { continue; } if inner.vplic_get_enable(intr_id, vcontext_id) { @@ -209,7 +210,7 @@ impl VirtualPLIC { // PLIC enable offset if offset >= 0x2000 && offset < (0x2000 + 0x80 * self.num_contexts) => { let vcontext_id = (offset - 0x2000) / 0x80; - if vcontext_id >= self.num_contexts || vcontext_id % 2 == 0 { + if vcontext_id >= self.num_contexts || vcontext_id % NUM_CONTEXTS_PER_HART != 1 { // context should be a S-mode hart context. error!("Invalid context ID {}", vcontext_id); return 0; @@ -256,7 +257,7 @@ impl VirtualPLIC { // PLIC threshold offset if offset >= 0x200000 && (offset - 0x200000) % 0x1000 == 0 => { let vcontext_id = (offset - 0x200000) / 0x1000; - if vcontext_id >= self.num_contexts || vcontext_id % 2 == 0 { + if vcontext_id >= self.num_contexts || vcontext_id % NUM_CONTEXTS_PER_HART != 1 { // context should be a S-mode hart context. error!("Invalid context ID {}", vcontext_id); return 0; @@ -281,7 +282,7 @@ impl VirtualPLIC { // PLIC claim/complete offset if offset >= 0x200004 && (offset - 0x200004) % 0x1000 == 0 => { let vcontext_id = (offset - 0x200004) / 0x1000; - if vcontext_id >= self.num_contexts || vcontext_id % 2 == 0 { + if vcontext_id >= self.num_contexts || vcontext_id % NUM_CONTEXTS_PER_HART != 1 { // context should be a S-mode hart context. error!("Invalid context ID {}", vcontext_id); return 0; @@ -408,7 +409,7 @@ impl VirtualPLICInner { "vPLIC update line to vcontext_id {}, pcontext_id {}", vcontext_id, pcontext_id ); - if pcontext_id / 2 == this_cpu_data().id { + if pcontext_id / NUM_CONTEXTS_PER_HART == this_cpu_id() { let irq_id = self.vplic_get_next_pending(vcontext_id); if irq_id != 0 { unsafe { @@ -422,7 +423,7 @@ impl VirtualPLICInner { } else { use crate::consts::IPI_EVENT_UPDATE_HART_LINE; use crate::event::send_event; - let cpu_id = pcontext_id / 2; + let cpu_id = pcontext_id / NUM_CONTEXTS_PER_HART; info!("vplic_update_hart_line to cpu {}", cpu_id); // the second arg don't need. send_event(cpu_id, 0, IPI_EVENT_UPDATE_HART_LINE); From 1db7b53c45de8bb5018f1c67ec971a4dd9ad6f90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=AF=E5=AE=87?= <2537738252@qq.com> Date: Mon, 26 Jan 2026 17:22:15 +0800 Subject: [PATCH 090/109] split virtio_bridge big lock to little locks --- src/device/virtio_trampoline.rs | 357 ++++++++++++++++++++------------ src/hypercall/mod.rs | 29 +-- 2 files changed, 235 insertions(+), 151 deletions(-) diff --git a/src/device/virtio_trampoline.rs b/src/device/virtio_trampoline.rs index c58b7fed..7085a734 100644 --- a/src/device/virtio_trampoline.rs +++ b/src/device/virtio_trampoline.rs @@ -12,33 +12,45 @@ // https://www.syswonder.org // // Authors: +// Guowei Li <2401213322@stu.pku.edu.cn> +// Jingyu Liu // -use crate::arch::cpu::{get_target_cpu, this_cpu_id}; -use crate::consts::MAX_CPU_NUM; -use crate::consts::MAX_WAIT_TIMES; -use crate::device::irqchip::inject_irq; -use crate::event::send_event; -use crate::event::IPI_EVENT_WAKEUP_VIRTIO_DEVICE; -use crate::hypercall::SGI_IPI_ID; -use crate::zone::this_zone_id; -use crate::{error::HvResult, memory::MMIOAccess}; +#![deny(unused_variables)] +#![deny(unused_imports)] +#![deny(unused_mut)] +#![deny(unused)] + +use crate::{ + arch::cpu::{get_target_cpu, this_cpu_id}, + consts::MAX_WAIT_TIMES, + device::irqchip::inject_irq, + error::HvResult, + event::{send_event, IPI_EVENT_WAKEUP_VIRTIO_DEVICE}, + hypercall::SGI_IPI_ID, + memory::MMIOAccess, + zone::this_zone_id, +}; use alloc::collections::BTreeMap; -use core::fmt::Debug; -use core::fmt::Formatter; -use core::fmt::Result; -use core::sync::atomic::fence; -use core::sync::atomic::Ordering; -use spin::Mutex; +use core::{ + fmt::{Debug, Formatter, Result}, + sync::atomic::{fence, AtomicBool, AtomicUsize, Ordering}, +}; +use spin::{Mutex, MutexGuard}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + registers::ReadWrite, +}; /// Save the irqs the virtio-device wants to inject. The format is >, and the first elem of List is the valid len of it. pub static VIRTIO_IRQS: Mutex> = Mutex::new(BTreeMap::new()); // Controller of the shared memory the root linux's virtio device and hvisor shares. -pub static VIRTIO_BRIDGE: Mutex = Mutex::new(VirtioBridgeRegion::default()); +pub static VIRTIO_BRIDGE: VirtioBridgeController = VirtioBridgeController::new(); const QUEUE_NOTIFY: usize = 0x50; pub const MAX_REQ: u32 = 32; pub const MAX_DEVS: usize = 8; // Attention: The max virtio-dev number for vm is 8 (loongarch64 needs 3 consoles and 3 disks for zgclab project). pub const MAX_CPUS: usize = 32; +pub const MAX_BACKOFF: usize = 1024; #[cfg(all(not(target_arch = "riscv64"), not(target_arch = "x86_64")))] pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 32 + 0x20; @@ -55,12 +67,19 @@ pub fn mmio_virtio_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { trace!("notify !!!, cpu id is {}", this_cpu_id()); } mmio.address += base; - let mut dev = VIRTIO_BRIDGE.lock(); - while dev.is_req_list_full() { + let mut backoff = 1; + let mut req_agent = VIRTIO_BRIDGE.req_agent(); + while req_agent.is_full() { // When root linux's cpu is in el2's finish req handler and is getting the dev lock, // if we don't release dev lock, it will cause a dead lock. - drop(dev); - dev = VIRTIO_BRIDGE.lock(); + drop(req_agent); + // Exponential Backoff Algorithm, here especially useful for big.LITTLE architecture. + for _ in 0..backoff { + core::hint::spin_loop(); + } + backoff <<= 1; + backoff = backoff.min(MAX_BACKOFF); + req_agent = VIRTIO_BRIDGE.req_agent(); } let hreq = HvisorDeviceReq::new( this_cpu_id() as _, @@ -72,40 +91,35 @@ pub fn mmio_virtio_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { need_interrupt, ); // debug!("non root sends req: {:#x?}", hreq); - let (cfg_flags, cfg_values) = unsafe { - ( - core::slice::from_raw_parts(dev.get_cfg_flags(), MAX_CPU_NUM), - core::slice::from_raw_parts(dev.get_cfg_values(), MAX_CPU_NUM), - ) - }; let cpu_id = this_cpu_id() as usize; - let old_cfg_flag = cfg_flags[cpu_id]; // debug!("old cfg flag: {:#x?}", old_cfg_flag); - dev.push_req(hreq); - // If req list is empty, send sgi to root linux to wake up virtio device. - #[cfg(not(target_arch = "loongarch64"))] - if dev.need_wakeup() { - debug!("need wakeup, sending ipi to wake up virtio device"); - send_event( - get_target_cpu(IRQ_WAKEUP_VIRTIO_DEVICE, 0), - SGI_IPI_ID as _, - IPI_EVENT_WAKEUP_VIRTIO_DEVICE, - ); - } - drop(dev); + req_agent.push_req(hreq); + drop(req_agent); + + // Due to cfg_flag and cfg_value are per-cpu, so there is no need to lock them. + let old_cfg_flag = VIRTIO_BRIDGE.cfg_flag(cpu_id); let mut count: usize = 0; // if it is cfg request, current cpu should be blocked until gets the result if need_interrupt == 0 { + let mut ipi_sent = false; // when virtio backend finish the req, it will add 1 to cfg_flag. - while unsafe { core::ptr::read_volatile(&cfg_flags[cpu_id]) } == old_cfg_flag { - // fence(Ordering::Acquire); + while !VIRTIO_BRIDGE.is_cfg_updated(cpu_id, old_cfg_flag) { + #[cfg(not(target_arch = "loongarch64"))] + if !ipi_sent && VIRTIO_BRIDGE.need_wakeup() { + debug!("need wakeup (recheck), sending ipi to wake up virtio device"); + send_event( + get_target_cpu(IRQ_WAKEUP_VIRTIO_DEVICE, 0), + SGI_IPI_ID as _, + IPI_EVENT_WAKEUP_VIRTIO_DEVICE, + ); + ipi_sent = true; + } count += 1; if count == MAX_WAIT_TIMES { warn!( "virtio backend is too slow, please check it! addr: {:x} is_write: {:x?}", mmio.address, mmio.is_write ); - fence(Ordering::Acquire); } if count == MAX_WAIT_TIMES * 10 { error!( @@ -117,7 +131,7 @@ pub fn mmio_virtio_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { } if !mmio.is_write { // ensure cfg value is right. - mmio.value = unsafe { core::ptr::read_volatile(&cfg_values[cpu_id]) as _ }; + mmio.value = VIRTIO_BRIDGE.cfg_value(cpu_id) as _; // debug!("non root receives value: {:#x?}", mmio.value); } } @@ -137,127 +151,196 @@ pub fn handle_virtio_irq() { irq_list[0] = 0; } -pub struct VirtioBridgeRegion { - base_address: usize, // el1 and el2 shared region addr, el2 virtual address - pub is_enable: bool, +/// Virtio bridge controller. +pub struct VirtioBridgeController { + base_address: AtomicUsize, + is_enable: AtomicBool, + req_lock: Mutex<()>, + res_lock: Mutex<()>, } -impl VirtioBridgeRegion { - // return a mut region - pub fn region(&self) -> &mut VirtioBridge { - if !self.is_enable { - panic!("hvisor device region is not enabled!"); +impl VirtioBridgeController { + pub const fn new() -> Self { + Self { + base_address: AtomicUsize::new(0), + is_enable: AtomicBool::new(false), + req_lock: Mutex::new(()), + res_lock: Mutex::new(()), } - unsafe { &mut *(self.base_address as *mut VirtioBridge) } } - // return a non mut region - pub fn immut_region(&self) -> &VirtioBridge { - if !self.is_enable { - panic!("hvisor device region is not enabled!"); + + pub fn set_base_addr(&self, base: usize) { + self.base_address.store(base, Ordering::Release); + self.is_enable.store(true, Ordering::Release); + } + + /// Get req list agent. + pub fn req_agent(&self) -> ReqAgent { + if !self.is_enable.load(Ordering::Acquire) { + panic!("VirtioBridge not enabled"); + } + let guard = self.req_lock.lock(); + ReqAgent { + base: self.base_address.load(Ordering::Relaxed), + _guard: guard, } - unsafe { &*(self.base_address as *const VirtioBridge) } } - pub const fn default() -> Self { - VirtioBridgeRegion { - base_address: 0, - is_enable: false, + /// Get res list agent. + pub fn res_agent(&self) -> ResAgent { + if !self.is_enable.load(Ordering::Acquire) { + panic!("VirtioBridge not enabled"); + } + let guard = self.res_lock.lock(); + ResAgent { + base: self.base_address.load(Ordering::Relaxed), + _guard: guard, } } - pub fn set_base_addr(&mut self, base_addr: usize) { - self.base_address = base_addr; - self.is_enable = true; + /// Get cfg flags (0..MAX_CPUS) + fn cfg_flags(&self) -> &[ReadWrite; MAX_CPUS] { + let base = self.base_address.load(Ordering::Relaxed); + unsafe { &(*(base as *const VirtioBridge)).cfg_flags } } - pub fn is_req_list_full(&self) -> bool { - let region = self.immut_region(); - if ((region.req_rear + 1) & (MAX_REQ - 1)) == region.req_front { - debug!("hvisor req queue full"); - true - } else { - false - } + /// Get cfg values (0..MAX_CPUS) + fn cfg_values(&self) -> &[ReadWrite; MAX_CPUS] { + let base = self.base_address.load(Ordering::Relaxed); + unsafe { &(*(base as *const VirtioBridge)).cfg_values } } - #[allow(dead_code)] - pub fn is_req_list_empty(&self) -> bool { - let region = self.immut_region(); + pub fn is_cfg_updated(&self, cpu_id: usize, old_val: u64) -> bool { + let val = self.cfg_flags()[cpu_id].get(); fence(Ordering::Acquire); - if region.req_rear == region.req_front { - true - } else { - false - } + val != old_val + } + + pub fn cfg_flag(&self, cpu_id: usize) -> u64 { + self.cfg_flags()[cpu_id].get() + } + + pub fn cfg_value(&self, cpu_id: usize) -> u64 { + self.cfg_values()[cpu_id].get() + } + + pub fn need_wakeup(&self) -> bool { + let base = self.base_address.load(Ordering::Relaxed); + let need_wakeup = unsafe { (&*(base as *const VirtioBridge)).need_wakeup.get() }; + fence(Ordering::Acquire); + need_wakeup == 1 + } +} + +struct ReqAgent<'a> { + base: usize, + _guard: MutexGuard<'a, ()>, +} + +impl<'a> ReqAgent<'a> { + fn region(&self) -> &mut VirtioBridge { + unsafe { &mut *(self.base as *mut VirtioBridge) } } - pub fn is_res_list_empty(&self) -> bool { + fn immut_region(&self) -> &VirtioBridge { + unsafe { &*(self.base as *const VirtioBridge) } + } + + pub fn is_full(&self) -> bool { let region = self.immut_region(); - if region.res_rear == region.res_front { - true - } else { - false - } + let req_front = region.req_front.get(); + let req_rear = (region.req_rear.get() + 1) & (MAX_REQ - 1); + // fence: ensure all following req_list reads are visible after req_rear & req_front read + fence(Ordering::Acquire); + req_rear == req_front } - // push a req to hvisor's req list + pub fn push_req(&mut self, req: HvisorDeviceReq) { let region = self.region(); - region.req_list[(region.req_rear % MAX_REQ) as usize] = req; + let slot = ®ion.req_list[(region.req_rear.get() % MAX_REQ) as usize]; + slot.src_cpu.set(req.src_cpu); + slot.address.set(req.address); + slot.size.set(req.size); + slot.value.set(req.value); + slot.src_zone.set(req.src_zone); + slot.is_write.set(req.is_write); + slot.need_interrupt.set(req.need_interrupt); // Write barrier so that virtio device sees changes to req_list before change to req_idx - fence(Ordering::SeqCst); - region.req_rear = (region.req_rear + 1) % MAX_REQ; - // Write barrier so that device can see change after this method returns - // fence(Ordering::SeqCst); + fence(Ordering::Release); + region.req_rear.set((region.req_rear.get() + 1) % MAX_REQ); } +} - pub fn get_cfg_flags(&self) -> *const u64 { - let region = self.immut_region(); - region.cfg_flags.as_ptr() +pub struct ResAgent<'a> { + base: usize, + _guard: MutexGuard<'a, ()>, +} + +impl<'a> ResAgent<'a> { + // Unsafe: Caller must ensure only Res fields are accessed + fn region(&self) -> &mut VirtioBridge { + unsafe { &mut *(self.base as *mut VirtioBridge) } } - pub fn get_cfg_values(&self) -> *const u64 { - let region = self.immut_region(); - region.cfg_values.as_ptr() + fn immut_region(&self) -> &VirtioBridge { + unsafe { &*(self.base as *const VirtioBridge) } } - pub fn need_wakeup(&self) -> bool { + pub fn is_empty(&self) -> bool { let region = self.immut_region(); + let res_rear = region.res_rear.get(); + let res_front = region.res_front.get(); + // fence: ensure all following res_list reads are visible after res_rear & res_front read fence(Ordering::Acquire); - if region.need_wakeup == 1 { - true - } else { - false - } + res_rear == res_front + } + + pub fn peek_front(&self) -> (u32, u64, u32) { + let region = self.immut_region(); + let res_front = region.res_front.get() as usize; + let res = ®ion.res_list[res_front]; + let irq_id = res.irq_id.get() as u64; + let target_zone = res.target_zone.get(); + (res_front as u32, irq_id, target_zone) + } + + pub fn advance_front(&mut self) { + let region = self.region(); + // fence: ensure all previous res_list updates are visible before advancing res_front + fence(Ordering::Release); + region + .res_front + .set((region.res_front.get() + 1) & (MAX_REQ - 1)); } } /// El1 and EL2 shared region for virtio requests and results. #[repr(C)] -pub struct VirtioBridge { +struct VirtioBridge { /// The first elem of req list, only virtio device updates - pub req_front: u32, + req_front: ReadWrite, /// The last elem's next place of req list, only hvisor updates - pub req_rear: u32, + req_rear: ReadWrite, /// The first elem of res list, only hvisor updates - pub res_front: u32, + res_front: ReadWrite, /// The last elem's next place of res list, only virtio device updates - pub res_rear: u32, - pub req_list: [HvisorDeviceReq; MAX_REQ as usize], - pub res_list: [HvisorDeviceRes; MAX_REQ as usize], // irqs - cfg_flags: [u64; MAX_CPUS], - cfg_values: [u64; MAX_CPUS], - pub mmio_addrs: [u64; MAX_DEVS], - pub mmio_avail: u8, - pub need_wakeup: u8, + res_rear: ReadWrite, + req_list: [HvisorDeviceReqVolatile; MAX_REQ as usize], + res_list: [HvisorDeviceResVolatile; MAX_REQ as usize], // irqs + cfg_flags: [ReadWrite; MAX_CPUS], + cfg_values: [ReadWrite; MAX_CPUS], + _mmio_addrs: [ReadWrite; MAX_DEVS], // remove later + _mmio_avail: ReadWrite, // remove later + need_wakeup: ReadWrite, } impl Debug for VirtioBridge { fn fmt(&self, f: &mut Formatter<'_>) -> Result { f.debug_struct("VirtioBridge") - .field("req_front", &self.req_front) - .field("req_rear", &self.req_rear) - .field("res_front", &self.res_front) - .field("res_rear", &self.res_rear) + .field("req_front", &self.req_front.get()) + .field("req_rear", &self.req_rear.get()) + .field("res_front", &self.res_front.get()) + .field("res_rear", &self.res_rear.get()) .finish() } } @@ -265,25 +348,19 @@ impl Debug for VirtioBridge { /// Hvisor device requests #[repr(C)] #[derive(Debug)] -pub struct HvisorDeviceReq { - pub src_cpu: u64, +struct HvisorDeviceReq { + src_cpu: u64, address: u64, size: u64, - pub value: u64, + value: u64, src_zone: u32, is_write: u8, - pub need_interrupt: u8, + need_interrupt: u8, _padding: u16, } -#[repr(C)] -pub struct HvisorDeviceRes { - pub target_zone: u32, - pub irq_id: u32, -} - impl HvisorDeviceReq { - pub fn new( + fn new( src_cpu: u64, address: u64, size: u64, @@ -305,3 +382,21 @@ impl HvisorDeviceReq { } } } + +#[repr(C)] +struct HvisorDeviceReqVolatile { + src_cpu: ReadWrite, + address: ReadWrite, + size: ReadWrite, + value: ReadWrite, + src_zone: ReadWrite, + is_write: ReadWrite, + need_interrupt: ReadWrite, + _padding: u16, +} + +#[repr(C)] +struct HvisorDeviceResVolatile { + target_zone: ReadWrite, + irq_id: ReadWrite, +} diff --git a/src/hypercall/mod.rs b/src/hypercall/mod.rs index b4eb67b0..ec3e3810 100644 --- a/src/hypercall/mod.rs +++ b/src/hypercall/mod.rs @@ -19,7 +19,7 @@ use crate::arch::cpu::get_target_cpu; use crate::config::HvZoneConfig; use crate::consts::{INVALID_ADDRESS, MAX_CPU_NUM, MAX_WAIT_TIMES, PAGE_SIZE}; -use crate::device::virtio_trampoline::{MAX_DEVS, MAX_REQ, VIRTIO_BRIDGE, VIRTIO_IRQS}; +use crate::device::virtio_trampoline::{MAX_DEVS, VIRTIO_BRIDGE, VIRTIO_IRQS}; use crate::error::HvResult; use crate::percpu::{get_cpu_data, PerCpu}; use crate::zone::{ @@ -28,7 +28,6 @@ use crate::zone::{ use crate::event::{send_event, IPI_EVENT_SHUTDOWN, IPI_EVENT_VIRTIO_INJECT_IRQ, IPI_EVENT_WAKEUP}; use core::convert::TryFrom; -use core::sync::atomic::{fence, Ordering}; use numeric_enum_macro::numeric_enum; numeric_enum! { @@ -125,9 +124,7 @@ impl<'a> HyperCall<'a> { // MemFlags::READ | MemFlags::WRITE, // ))?; // TODO: flush tlb - VIRTIO_BRIDGE - .lock() - .set_base_addr(shared_region_addr_pa as _); + VIRTIO_BRIDGE.set_base_addr(shared_region_addr_pa as _); info!("hvisor device region base is {:#x?}", shared_region_addr_pa); HyperCallResult::Ok(0) @@ -142,20 +139,14 @@ impl<'a> HyperCall<'a> { "Virtio send irq operation over non-root zones: unsupported!" ); } - let dev = VIRTIO_BRIDGE.lock(); + let mut res_agent = VIRTIO_BRIDGE.res_agent(); let mut map_irq = VIRTIO_IRQS.lock(); - let region = dev.region(); - - while !dev.is_res_list_empty() { - let res_front = region.res_front as usize; - let irq_id = region.res_list[res_front].irq_id as u64; - let target_zone = region.res_list[res_front].target_zone; + while !res_agent.is_empty() { + let (_res_front, irq_id, target_zone) = res_agent.peek_front(); let target_cpu = match find_zone(target_zone as _) { - Some(zone) => get_target_cpu(irq_id as _, target_zone as _), + Some(_zone) => get_target_cpu(irq_id as _, target_zone as _), _ => { - fence(Ordering::SeqCst); - region.res_front = (region.res_front + 1) & (MAX_REQ - 1); - fence(Ordering::SeqCst); + res_agent.advance_front(); continue; } }; @@ -175,11 +166,9 @@ impl<'a> HyperCall<'a> { ); } - fence(Ordering::SeqCst); - region.res_front = (region.res_front + 1) & (MAX_REQ - 1); - fence(Ordering::SeqCst); + res_agent.advance_front(); } - drop(dev); + drop(res_agent); HyperCallResult::Ok(0) } From 6e2f925568222d8696f7f9af4c245ee84ac3e14d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=AF=E5=AE=87?= <2537738252@qq.com> Date: Mon, 26 Jan 2026 18:45:42 +0800 Subject: [PATCH 091/109] move IRQ_WAKEUP_VIRTIO_DEVICE to board.rs --- platform/aarch64/imx8mp/board.rs | 1 + platform/aarch64/ok6254-c/board.rs | 1 + platform/aarch64/phytium-pi/board.rs | 2 ++ platform/aarch64/qemu-gicv2/board.rs | 1 + platform/aarch64/qemu-gicv3/board.rs | 1 + platform/aarch64/rk3568/board.rs | 1 + platform/aarch64/rk3588/board.rs | 1 + platform/aarch64/zcu102/board.rs | 1 + platform/loongarch64/ls3a5000/board.rs | 1 + platform/loongarch64/ls3a6000/board.rs | 1 + platform/riscv64/hifive-premier-p550/board.rs | 2 ++ platform/riscv64/megrez/board.rs | 2 ++ platform/riscv64/qemu-aia/board.rs | 1 + platform/riscv64/qemu-plic/board.rs | 3 ++ platform/riscv64/ur-dp1000/board.rs | 1 + platform/x86_64/nuc14mnk/board.rs | 1 + platform/x86_64/qemu/board.rs | 1 + src/device/virtio_trampoline.rs | 31 ++++++++++--------- src/event.rs | 6 ++-- 19 files changed, 41 insertions(+), 18 deletions(-) diff --git a/platform/aarch64/imx8mp/board.rs b/platform/aarch64/imx8mp/board.rs index 5b9ea976..c9b5ece0 100644 --- a/platform/aarch64/imx8mp/board.rs +++ b/platform/aarch64/imx8mp/board.rs @@ -109,6 +109,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 8] = [ // }, // serial ]; +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 32 + 0x20; pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[ 35, 36, 37, 38, 45, 52, 55, 56, 57, 59, 64, 67, 75, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 135, 150, 151, 152, 162, diff --git a/platform/aarch64/ok6254-c/board.rs b/platform/aarch64/ok6254-c/board.rs index 85a49631..95909885 100644 --- a/platform/aarch64/ok6254-c/board.rs +++ b/platform/aarch64/ok6254-c/board.rs @@ -126,6 +126,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 12] = [ }, // 0x10000000 ~ 0x80000000 ]; +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 32 + 0x20; pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[ 64, 66, 114, 115, 118, 165, 194, 195, 210, 211, 228, 258, 266, ]); diff --git a/platform/aarch64/phytium-pi/board.rs b/platform/aarch64/phytium-pi/board.rs index ce969f87..127b8ff6 100644 --- a/platform/aarch64/phytium-pi/board.rs +++ b/platform/aarch64/phytium-pi/board.rs @@ -130,6 +130,8 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 11] = [ size: 0x2000, }, ]; + +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 32 + 0x20; //46-usb2,54-mailbox 64-usb2,87-net,104、105-mmc,116-uart,133、138-i2c,191-spi pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[46, 54, 64, 65, 75, 76, 78, 87, 104, 105, 116, 133, 138, 191]); diff --git a/platform/aarch64/qemu-gicv2/board.rs b/platform/aarch64/qemu-gicv2/board.rs index d7d58d5b..26c0f715 100644 --- a/platform/aarch64/qemu-gicv2/board.rs +++ b/platform/aarch64/qemu-gicv2/board.rs @@ -76,6 +76,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 3] = [ }, // virtio ]; +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 32 + 0x20; // 35 36 37 38 -> pcie intx# // 65 -> ivc pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[33, 64, 77, 79, 35, 36, 37, 38, 65]); diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index c3fb1a0e..d583330b 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -76,6 +76,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ }, // virtio ]; +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 32 + 0x20; // 35 36 37 38 -> pcie intx# // 65 -> ivc pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = diff --git a/platform/aarch64/rk3568/board.rs b/platform/aarch64/rk3568/board.rs index 708fb21d..120370f3 100644 --- a/platform/aarch64/rk3568/board.rs +++ b/platform/aarch64/rk3568/board.rs @@ -269,6 +269,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ }, //sdhci ]; +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 32 + 0x20; pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[ 0x84, 0x98, 0x40, 0x104, 0x105, 0x106, 0x107, 0x2d, 0x2e, 0x2b, 0x2a, 0x29, 0x33, 0x96, 0x11c, 0x44, 0x43, 0x42, 0x41, 0x8d, diff --git a/platform/aarch64/rk3588/board.rs b/platform/aarch64/rk3588/board.rs index afc6acff..e2fc5e47 100644 --- a/platform/aarch64/rk3588/board.rs +++ b/platform/aarch64/rk3588/board.rs @@ -172,6 +172,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 9] = [ // } ]; +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 32 + 0x20; // pub const ROOT_ZONE_IRQS_BITMAP: [u32; 10] = [39, 64, 235, 237, 309, 312, 360, 365, 429, 455]; pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[ 39, 41, 42, 43, 45, 46, 64, 120, 121, 235, 237, 247, 248, 250, 251, 252, 265, 266, 309, 312, diff --git a/platform/aarch64/zcu102/board.rs b/platform/aarch64/zcu102/board.rs index 1ca5fe5b..a2662693 100644 --- a/platform/aarch64/zcu102/board.rs +++ b/platform/aarch64/zcu102/board.rs @@ -115,6 +115,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 9] = [ }, // gpio ]; +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 32 + 0x20; pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[53, 81, 175, 176, 177, 178, 64, 50, 48, 49, 95]); // serial-mmc-pmu-pmu-pmu-pmu-(hvisor_virtio_device)-gpio-i2c(ff030000)-i2c(ff020000)-ethernet diff --git a/platform/loongarch64/ls3a5000/board.rs b/platform/loongarch64/ls3a5000/board.rs index 0d59ecae..b373f9b7 100644 --- a/platform/loongarch64/ls3a5000/board.rs +++ b/platform/loongarch64/ls3a5000/board.rs @@ -151,6 +151,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ }, // SHARD_MEM ]; +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 32 + 0x20; pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { dummy: 0 }; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; diff --git a/platform/loongarch64/ls3a6000/board.rs b/platform/loongarch64/ls3a6000/board.rs index f78cfd1b..8e99e9fa 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -151,6 +151,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ }, // SHARD_MEM ]; +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 32 + 0x20; pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { dummy: 0 }; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; diff --git a/platform/riscv64/hifive-premier-p550/board.rs b/platform/riscv64/hifive-premier-p550/board.rs index f6a5535f..06e6d03c 100644 --- a/platform/riscv64/hifive-premier-p550/board.rs +++ b/platform/riscv64/hifive-premier-p550/board.rs @@ -150,6 +150,8 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 7] = [ // }, // pinctrl ]; +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 0x20; + // Note: all here's irqs are hardware irqs, // only these irq can be transferred to the physical PLIC. pub const HW_IRQS: [u32; 21] = [ diff --git a/platform/riscv64/megrez/board.rs b/platform/riscv64/megrez/board.rs index 923de93f..d7bb6f2a 100644 --- a/platform/riscv64/megrez/board.rs +++ b/platform/riscv64/megrez/board.rs @@ -199,6 +199,8 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 10] = [ // }, // mmc@50450000 ]; +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 0x20; + // Note: all here's irqs are hardware irqs, // only these irq can be transferred to the physical PLIC. pub const HW_IRQS: [u32; 8] = [ diff --git a/platform/riscv64/qemu-aia/board.rs b/platform/riscv64/qemu-aia/board.rs index f6ee20d7..61bab9d6 100644 --- a/platform/riscv64/qemu-aia/board.rs +++ b/platform/riscv64/qemu-aia/board.rs @@ -100,6 +100,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 9] = [ }, // virtio ]; +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 0x20; pub const HW_IRQS: [u32; 11] = [1, 2, 3, 4, 5, 8, 10, 33, 34, 35, 36]; pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[1, 2, 3, 4, 5, 8, 10, 33, 34, 35, 36]); // ARCH= riscv .It doesn't matter temporarily. diff --git a/platform/riscv64/qemu-plic/board.rs b/platform/riscv64/qemu-plic/board.rs index f1327a2f..bf414567 100644 --- a/platform/riscv64/qemu-plic/board.rs +++ b/platform/riscv64/qemu-plic/board.rs @@ -63,6 +63,9 @@ pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ }, // virtio ]; +// The irq number used by the hvisor_device for virtio device wakeup. +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 0x20; + // Note: all here's irqs are hardware irqs, // only these irq can be transferred to the physical PLIC. // For qemu-virt, 32 is pcie pinA, 33 is pcie pinB, 34 is pcie pinC, 35 is pcie pinD, now only use 33,34 diff --git a/platform/riscv64/ur-dp1000/board.rs b/platform/riscv64/ur-dp1000/board.rs index dde8c423..f7a47f52 100644 --- a/platform/riscv64/ur-dp1000/board.rs +++ b/platform/riscv64/ur-dp1000/board.rs @@ -95,6 +95,7 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { // ================================================== // Interrupt Config // ================================================== +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 0x20; // Note: all here's irqs are hardware irqs, // only these irq can be transferred to the physical PLIC. #[rustfmt::skip] diff --git a/platform/x86_64/nuc14mnk/board.rs b/platform/x86_64/nuc14mnk/board.rs index c865b506..8cf71387 100644 --- a/platform/x86_64/nuc14mnk/board.rs +++ b/platform/x86_64/nuc14mnk/board.rs @@ -129,6 +129,7 @@ const ROOT_ZONE_SETUP_ADDR: GuestPhysAddr = 0xa000; const ROOT_ZONE_VMLINUX_ENTRY_ADDR: GuestPhysAddr = 0x10_0000; const ROOT_ZONE_SCREEN_BASE_ADDR: GuestPhysAddr = 0x8000_0000; +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 0x6; pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[0; 32]); pub const ROOT_ZONE_IOAPIC_BASE: usize = 0xfec0_0000; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { diff --git a/platform/x86_64/qemu/board.rs b/platform/x86_64/qemu/board.rs index ab42fc3a..08e48eca 100644 --- a/platform/x86_64/qemu/board.rs +++ b/platform/x86_64/qemu/board.rs @@ -93,6 +93,7 @@ const ROOT_ZONE_SETUP_ADDR: GuestPhysAddr = 0xa000; const ROOT_ZONE_VMLINUX_ENTRY_ADDR: GuestPhysAddr = 0x10_0000; const ROOT_ZONE_SCREEN_BASE_ADDR: GuestPhysAddr = 0; +pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 0x6; pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[0; 32]); pub const ROOT_ZONE_IOAPIC_BASE: usize = 0xfec0_0000; pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { diff --git a/src/device/virtio_trampoline.rs b/src/device/virtio_trampoline.rs index 7085a734..d28bfe66 100644 --- a/src/device/virtio_trampoline.rs +++ b/src/device/virtio_trampoline.rs @@ -52,19 +52,21 @@ pub const MAX_DEVS: usize = 8; // Attention: The max virtio-dev number for vm is pub const MAX_CPUS: usize = 32; pub const MAX_BACKOFF: usize = 1024; -#[cfg(all(not(target_arch = "riscv64"), not(target_arch = "x86_64")))] -pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 32 + 0x20; -#[cfg(target_arch = "riscv64")] -pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 0x20; -#[cfg(target_arch = "x86_64")] -pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 0x6; +use crate::platform::IRQ_WAKEUP_VIRTIO_DEVICE; +// #[cfg(all(not(target_arch = "riscv64"), not(target_arch = "x86_64")))] +// pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 32 + 0x20; +// #[cfg(target_arch = "riscv64")] +// pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 0x20; +// #[cfg(target_arch = "x86_64")] +// pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 0x6; /// non root zone's virtio request handler pub fn mmio_virtio_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { // debug!("mmio virtio handler"); + let cpu_id = this_cpu_id() as usize; let need_interrupt = if mmio.address == QUEUE_NOTIFY { 1 } else { 0 }; if need_interrupt == 1 { - trace!("notify !!!, cpu id is {}", this_cpu_id()); + trace!("notify !!!, cpu id is {}", cpu_id); } mmio.address += base; let mut backoff = 1; @@ -82,7 +84,7 @@ pub fn mmio_virtio_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { req_agent = VIRTIO_BRIDGE.req_agent(); } let hreq = HvisorDeviceReq::new( - this_cpu_id() as _, + cpu_id as _, mmio.address as _, mmio.size as _, mmio.value as _, @@ -91,19 +93,17 @@ pub fn mmio_virtio_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { need_interrupt, ); // debug!("non root sends req: {:#x?}", hreq); - let cpu_id = this_cpu_id() as usize; - // debug!("old cfg flag: {:#x?}", old_cfg_flag); req_agent.push_req(hreq); drop(req_agent); // Due to cfg_flag and cfg_value are per-cpu, so there is no need to lock them. let old_cfg_flag = VIRTIO_BRIDGE.cfg_flag(cpu_id); let mut count: usize = 0; + let mut ipi_sent = false; // if it is cfg request, current cpu should be blocked until gets the result if need_interrupt == 0 { - let mut ipi_sent = false; - // when virtio backend finish the req, it will add 1 to cfg_flag. - while !VIRTIO_BRIDGE.is_cfg_updated(cpu_id, old_cfg_flag) { + loop { + // If backend is sleep, hvisor needs to send ipi to wake it up. #[cfg(not(target_arch = "loongarch64"))] if !ipi_sent && VIRTIO_BRIDGE.need_wakeup() { debug!("need wakeup (recheck), sending ipi to wake up virtio device"); @@ -114,6 +114,10 @@ pub fn mmio_virtio_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { ); ipi_sent = true; } + // when virtio backend finish the req, it will add 1 to cfg_flags[cpu_id]. + if VIRTIO_BRIDGE.is_cfg_updated(cpu_id, old_cfg_flag) { + break; + } count += 1; if count == MAX_WAIT_TIMES { warn!( @@ -277,7 +281,6 @@ pub struct ResAgent<'a> { } impl<'a> ResAgent<'a> { - // Unsafe: Caller must ensure only Res fields are accessed fn region(&self) -> &mut VirtioBridge { unsafe { &mut *(self.base as *mut VirtioBridge) } } diff --git a/src/event.rs b/src/event.rs index e084a219..7cec4dee 100644 --- a/src/event.rs +++ b/src/event.rs @@ -19,11 +19,9 @@ use crate::{ consts::{ IPI_EVENT_CLEAR_INJECT_IRQ, IPI_EVENT_SEND_IPI, IPI_EVENT_UPDATE_HART_LINE, MAX_CPU_NUM, }, - device::{ - irqchip::inject_irq, - virtio_trampoline::{handle_virtio_irq, IRQ_WAKEUP_VIRTIO_DEVICE}, - }, + device::{irqchip::inject_irq, virtio_trampoline::handle_virtio_irq}, percpu::this_cpu_data, + platform::IRQ_WAKEUP_VIRTIO_DEVICE, }; use alloc::{collections::VecDeque, vec::Vec}; use spin::{Mutex, Once}; From 65862e854a4ee27766688bbb5e5e50e0452c66ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=AF=E5=AE=87?= <2537738252@qq.com> Date: Mon, 26 Jan 2026 18:58:01 +0800 Subject: [PATCH 092/109] ci: add new boards build test --- .github/workflows/ci.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ae9eb622..a6639703 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -108,6 +108,9 @@ jobs: - arch: aarch64 board: "ok6254-c" rustc_target: aarch64-unknown-none + - arch: aarch64 + board: "phytium-pi" + rustc_target: aarch64-unknown-none # riscv64 - arch: riscv64 board: "qemu-aia" @@ -115,10 +118,29 @@ jobs: - arch: riscv64 board: "qemu-plic" rustc_target: riscv64gc-unknown-none-elf + - arch: riscv64 + board: "hifive-premier-p550" + rustc_target: riscv64gc-unknown-none-elf + - arch: riscv64 + board: "megrez" + rustc_target: riscv64gc-unknown-none-elf + - arch: riscv64 + board: "ur-dp1000" + rustc_target: riscv64gc-unknown-none-elf # loongarch64 - arch: loongarch64 board: "ls3a5000" rustc_target: loongarch64-unknown-none + - arch: loongarch64 + board: "ls3a6000" + rustc_target: loongarch64-unknown-none + # x86_64 + - arch: x86_64 + board: "qemu" + rustc_target: x86_64-unknown-none + - arch: x86_64 + board: "nuc14mnk" + rustc_target: x86_64-unknown-none steps: - name: Checkout Repository uses: actions/checkout@v4 From e1af8c690b8bad667fdb3ff4551371d1f556ab27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=AF=E5=AE=87?= <2537738252@qq.com> Date: Tue, 27 Jan 2026 11:15:49 +0800 Subject: [PATCH 093/109] fix virtio_trampoline --- .github/workflows/ci.yml | 14 ++++---- src/arch/x86_64/hypercall.rs | 2 +- src/device/virtio_trampoline.rs | 61 +++++++++++++++++++-------------- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a6639703..a04296c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -134,13 +134,13 @@ jobs: - arch: loongarch64 board: "ls3a6000" rustc_target: loongarch64-unknown-none - # x86_64 - - arch: x86_64 - board: "qemu" - rustc_target: x86_64-unknown-none - - arch: x86_64 - board: "nuc14mnk" - rustc_target: x86_64-unknown-none + # # x86_64 + # - arch: x86_64 + # board: "qemu" + # rustc_target: x86_64-unknown-none + # - arch: x86_64 + # board: "nuc14mnk" + # rustc_target: x86_64-unknown-none steps: - name: Checkout Repository uses: actions/checkout@v4 diff --git a/src/arch/x86_64/hypercall.rs b/src/arch/x86_64/hypercall.rs index 9a84d84d..cb5517f1 100644 --- a/src/arch/x86_64/hypercall.rs +++ b/src/arch/x86_64/hypercall.rs @@ -79,7 +79,7 @@ impl<'a> HyperCall<'a> { .0 as *mut u32 }; unsafe { - (*virtio_irq) = crate::device::virtio_trampoline::IRQ_WAKEUP_VIRTIO_DEVICE as _; + (*virtio_irq) = crate::platform::IRQ_WAKEUP_VIRTIO_DEVICE as _; }; HyperCallResult::Ok(0) } diff --git a/src/device/virtio_trampoline.rs b/src/device/virtio_trampoline.rs index d28bfe66..b7896f17 100644 --- a/src/device/virtio_trampoline.rs +++ b/src/device/virtio_trampoline.rs @@ -20,15 +20,15 @@ #![deny(unused_mut)] #![deny(unused)] +#[cfg(not(target_arch = "loongarch64"))] use crate::{ - arch::cpu::{get_target_cpu, this_cpu_id}, - consts::MAX_WAIT_TIMES, - device::irqchip::inject_irq, - error::HvResult, + arch::cpu::get_target_cpu, event::{send_event, IPI_EVENT_WAKEUP_VIRTIO_DEVICE}, hypercall::SGI_IPI_ID, - memory::MMIOAccess, - zone::this_zone_id, +}; +use crate::{ + arch::cpu::this_cpu_id, consts::MAX_WAIT_TIMES, device::irqchip::inject_irq, error::HvResult, + memory::MMIOAccess, zone::this_zone_id, }; use alloc::collections::BTreeMap; use core::{ @@ -52,6 +52,7 @@ pub const MAX_DEVS: usize = 8; // Attention: The max virtio-dev number for vm is pub const MAX_CPUS: usize = 32; pub const MAX_BACKOFF: usize = 1024; +#[cfg(not(target_arch = "loongarch64"))] use crate::platform::IRQ_WAKEUP_VIRTIO_DEVICE; // #[cfg(all(not(target_arch = "riscv64"), not(target_arch = "x86_64")))] // pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 32 + 0x20; @@ -69,6 +70,12 @@ pub fn mmio_virtio_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { trace!("notify !!!, cpu id is {}", cpu_id); } mmio.address += base; + // Ensure read old_cfg_flag before push_req + let old_cfg_flag = VIRTIO_BRIDGE.cfg_flag(cpu_id); + fence(Ordering::Acquire); + + // Try to push req to req_list (in VirtioBridge critical area) + // To avoid concurrent access to req_list, hvisor should lock VIRTIO_BRIDGE's req_list related part (here use req_agent) let mut backoff = 1; let mut req_agent = VIRTIO_BRIDGE.req_agent(); while req_agent.is_full() { @@ -96,28 +103,17 @@ pub fn mmio_virtio_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { req_agent.push_req(hreq); drop(req_agent); - // Due to cfg_flag and cfg_value are per-cpu, so there is no need to lock them. - let old_cfg_flag = VIRTIO_BRIDGE.cfg_flag(cpu_id); + #[cfg(not(target_arch = "loongarch64"))] + let mut is_ipi_sent = false; + // If backend is sleep, hvisor needs to send ipi to wake it up. + #[cfg(not(target_arch = "loongarch64"))] + check_need_wakeup_and_send_ipi(&mut is_ipi_sent); + let mut count: usize = 0; - let mut ipi_sent = false; // if it is cfg request, current cpu should be blocked until gets the result if need_interrupt == 0 { - loop { - // If backend is sleep, hvisor needs to send ipi to wake it up. - #[cfg(not(target_arch = "loongarch64"))] - if !ipi_sent && VIRTIO_BRIDGE.need_wakeup() { - debug!("need wakeup (recheck), sending ipi to wake up virtio device"); - send_event( - get_target_cpu(IRQ_WAKEUP_VIRTIO_DEVICE, 0), - SGI_IPI_ID as _, - IPI_EVENT_WAKEUP_VIRTIO_DEVICE, - ); - ipi_sent = true; - } - // when virtio backend finish the req, it will add 1 to cfg_flags[cpu_id]. - if VIRTIO_BRIDGE.is_cfg_updated(cpu_id, old_cfg_flag) { - break; - } + // when virtio backend finish the req, it will add 1 to cfg_flags[cpu_id]. + while !VIRTIO_BRIDGE.is_cfg_updated(cpu_id, old_cfg_flag) { count += 1; if count == MAX_WAIT_TIMES { warn!( @@ -132,6 +128,7 @@ pub fn mmio_virtio_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { ); count = 0; } + // check_need_wakeup_and_send_ipi(&mut is_ipi_sent); } if !mmio.is_write { // ensure cfg value is right. @@ -143,6 +140,19 @@ pub fn mmio_virtio_handler(mmio: &mut MMIOAccess, base: usize) -> HvResult { Ok(()) } +#[cfg(not(target_arch = "loongarch64"))] +pub fn check_need_wakeup_and_send_ipi(is_send_ipi: &mut bool) { + if !(*is_send_ipi) && VIRTIO_BRIDGE.need_wakeup() { + debug!("need wakeup (recheck), sending ipi to wake up virtio device"); + send_event( + get_target_cpu(IRQ_WAKEUP_VIRTIO_DEVICE, 0), + SGI_IPI_ID as _, + IPI_EVENT_WAKEUP_VIRTIO_DEVICE, + ); + *is_send_ipi = true; + } +} + /// When virtio req type is notify, root zone will send sgi to non root, \ /// and non root will call this function. pub fn handle_virtio_irq() { @@ -228,6 +238,7 @@ impl VirtioBridgeController { self.cfg_values()[cpu_id].get() } + #[allow(unused)] pub fn need_wakeup(&self) -> bool { let base = self.base_address.load(Ordering::Relaxed); let need_wakeup = unsafe { (&*(base as *const VirtioBridge)).need_wakeup.get() }; From c14250c9c739f91bc8d23f558c676bfd93e40d37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=99=AF=E5=AE=87?= <2537738252@qq.com> Date: Tue, 27 Jan 2026 12:05:57 +0800 Subject: [PATCH 094/109] auto generate vscode/settings.json --- Makefile | 9 ++++-- tools/gen_vscode_settings.sh | 62 ++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) create mode 100755 tools/gen_vscode_settings.sh diff --git a/Makefile b/Makefile index 103c2924..3593b906 100644 --- a/Makefile +++ b/Makefile @@ -77,8 +77,8 @@ COLOR_BOLD := $(shell tput bold) COLOR_RESET := $(shell tput sgr0) # Targets -.PHONY: all elf disa run gdb monitor clean tools rootfs -all: clean_check gen_cargo_config $(hvisor_bin) +.PHONY: all elf disa run gdb monitor clean tools rootfs vscode +all: clean_check gen_cargo_config vscode $(hvisor_bin) @printf "\n" @printf "$(COLOR_GREEN)$(COLOR_BOLD)hvisor build summary:$(COLOR_RESET)\n" @printf "%-10s %s\n" "ARCH =" "$(COLOR_BOLD)$(ARCH)$(COLOR_RESET)" @@ -116,6 +116,11 @@ gen_cargo_config: ./tools/gen_cargo_config.sh @printf "$(COLOR_GREEN)$(COLOR_BOLD)generating .cargo/config.toml success!$(COLOR_RESET)\n" +vscode: + @printf "$(COLOR_GREEN)$(COLOR_BOLD)generating .vscode/settings.json...$(COLOR_RESET)\n" + ./tools/gen_vscode_settings.sh + @printf "$(COLOR_GREEN)$(COLOR_BOLD)generating .vscode/settings.json success!$(COLOR_RESET)\n" + elf: cargo build $(build_args) diff --git a/tools/gen_vscode_settings.sh b/tools/gen_vscode_settings.sh new file mode 100755 index 00000000..2d911faa --- /dev/null +++ b/tools/gen_vscode_settings.sh @@ -0,0 +1,62 @@ +#!/bin/bash +set -e + +function find_hvisor_src { + ret=$(find . -name CHANGELOG.md -exec grep -l "hvisor" {} \;) + if [ -z "$ret" ]; then + ret=$(find .. -name CHANGELOG.md -exec grep -l "hvisor" {} \;) + fi + if [ -z "$ret" ]; then + echo "ERROR: Could not locate hvisor source root (CHANGELOG.md with 'hvisor')" >&2 + exit 1 + fi + echo "$(dirname "$ret")" +} + +HVISOR_SRC=$(realpath $(find_hvisor_src)) +cd "$HVISOR_SRC" + +if [ -n "$BID" ]; then + ARCH=$(echo "$BID" | cut -d'/' -f1) + BOARD=$(echo "$BID" | cut -d'/' -f2) +fi + +if [ -z "$ARCH" ] || [ -z "$BOARD" ]; then + echo "ERROR: ARCH/BOARD not set, please use BID=arch/board or ARCH=... BOARD=..." + exit 1 +fi + +if [ -z "$FEATURES" ]; then + FEATURES=$(./tools/read_features.sh "$ARCH" "$BOARD") +fi + +FEATURES=$(echo "$FEATURES" | tr '\n' ' ' | tr -s ' ' | sed 's/^ *//;s/ *$//') + +case "$ARCH" in + aarch64) TARGET="aarch64-unknown-none" ;; + riscv64) TARGET="riscv64gc-unknown-none-elf" ;; + loongarch64) TARGET="loongarch64-unknown-none" ;; + x86_64) TARGET="x86_64-unknown-none" ;; + *) + echo "ERROR: Unsupported ARCH value: $ARCH" + exit 1 + ;; +esac + +mkdir -p .vscode + +cat > .vscode/settings.json < Date: Tue, 27 Jan 2026 22:57:28 +0800 Subject: [PATCH 095/109] adapt log style from hvisor-tool for arch64_gicv3 --- .github/workflows/ci.yml | 2 +- platform/aarch64/qemu-gicv3/test/systemtest/boot_zone1.sh | 5 ++--- platform/aarch64/qemu-gicv3/test/systemtest/screen_zone1.sh | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a04296c4..da8b86a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -216,7 +216,7 @@ jobs: - name: Install Dependencies run: | sudo apt-get update - sudo apt-get install -y qemu-system-aarch64 qemu-system-riscv64 gdb-multiarch llvm-dev libclang-dev wget expect device-tree-compiler p7zip-full gcc-aarch64-linux-gnu gcc-riscv64-linux-gnu + sudo apt-get install -y qemu-system-aarch64 qemu-system-riscv64 gdb-multiarch llvm-dev libclang-dev wget expect device-tree-compiler p7zip-full gcc-aarch64-linux-gnu gcc-riscv64-linux-gnu rsyslog cargo install --version 0.3.0 --locked cargo-binutils cargo install cargo-xbuild diff --git a/platform/aarch64/qemu-gicv3/test/systemtest/boot_zone1.sh b/platform/aarch64/qemu-gicv3/test/systemtest/boot_zone1.sh index 5b834b23..e53b46cc 100755 --- a/platform/aarch64/qemu-gicv3/test/systemtest/boot_zone1.sh +++ b/platform/aarch64/qemu-gicv3/test/systemtest/boot_zone1.sh @@ -1,8 +1,7 @@ # insmod hvisor.ko -rm nohup.out mkdir -p /dev/pts mount -t devpts devpts /dev/pts -nohup ./hvisor virtio start zone1-linux-virtio.json & +./hvisor virtio start zone1-linux-virtio.json & ./hvisor zone start zone1-linux.json && \ -cat nohup.out | grep "char device" && \ +grep "char device" /var/log/syslog && \ script /dev/null diff --git a/platform/aarch64/qemu-gicv3/test/systemtest/screen_zone1.sh b/platform/aarch64/qemu-gicv3/test/systemtest/screen_zone1.sh index d24f677c..aca07c08 100755 --- a/platform/aarch64/qemu-gicv3/test/systemtest/screen_zone1.sh +++ b/platform/aarch64/qemu-gicv3/test/systemtest/screen_zone1.sh @@ -1,4 +1,4 @@ -screen_output=$(grep "char device" nohup.out) +screen_output=$(grep "char device" /var/log/syslog) echo "$screen_output" device=$(echo "$screen_output" | awk '{print $NF}') echo "$device" From 64257298a344b4fd4acdc15754f7c76c81b9e218 Mon Sep 17 00:00:00 2001 From: Jingyu Liu <86109975+liulog@users.noreply.github.com> Date: Tue, 27 Jan 2026 23:15:19 +0800 Subject: [PATCH 096/109] Add rsyslog service start to boot_zone1.sh Start rsyslog service before launching zone1. --- platform/aarch64/qemu-gicv3/test/systemtest/boot_zone1.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/aarch64/qemu-gicv3/test/systemtest/boot_zone1.sh b/platform/aarch64/qemu-gicv3/test/systemtest/boot_zone1.sh index e53b46cc..6257486d 100755 --- a/platform/aarch64/qemu-gicv3/test/systemtest/boot_zone1.sh +++ b/platform/aarch64/qemu-gicv3/test/systemtest/boot_zone1.sh @@ -1,6 +1,9 @@ # insmod hvisor.ko mkdir -p /dev/pts mount -t devpts devpts /dev/pts +# exec rsyslog +rsyslogd +# start zone1 ./hvisor virtio start zone1-linux-virtio.json & ./hvisor zone start zone1-linux.json && \ grep "char device" /var/log/syslog && \ From 0be28ca762e07afaeef1eeddaf311df4c683e272 Mon Sep 17 00:00:00 2001 From: Solicey Date: Wed, 26 Nov 2025 18:35:59 +0800 Subject: [PATCH 097/109] support x86 platform ecx-2300f-peg, fix pci enumerate bugs --- platform/x86_64/ecx-2300f-peg/board.rs | 167 ++++++++++++++++++ .../ecx-2300f-peg/cargo/config.template.toml | 10 ++ platform/x86_64/ecx-2300f-peg/cargo/features | 2 + .../ecx-2300f-peg/image/bootloader/boot.S | 41 +++++ .../ecx-2300f-peg/image/bootloader/boot.ld | 15 ++ .../ecx-2300f-peg/image/bootloader/boot.mk | 36 ++++ .../image/font/solarize-12x29.psf | Bin 0 -> 29728 bytes .../ecx-2300f-peg/image/font/spleen-6x12.psf | Bin 0 -> 7859 bytes .../image/iso/boot/grub/grub.cfg | 27 +++ platform/x86_64/ecx-2300f-peg/linker.ld | 53 ++++++ platform/x86_64/ecx-2300f-peg/platform.mk | 51 ++++++ platform/x86_64/ecx-2300f-peg/test/runner.sh | 0 12 files changed, 402 insertions(+) create mode 100644 platform/x86_64/ecx-2300f-peg/board.rs create mode 100644 platform/x86_64/ecx-2300f-peg/cargo/config.template.toml create mode 100644 platform/x86_64/ecx-2300f-peg/cargo/features create mode 100644 platform/x86_64/ecx-2300f-peg/image/bootloader/boot.S create mode 100644 platform/x86_64/ecx-2300f-peg/image/bootloader/boot.ld create mode 100644 platform/x86_64/ecx-2300f-peg/image/bootloader/boot.mk create mode 100644 platform/x86_64/ecx-2300f-peg/image/font/solarize-12x29.psf create mode 100644 platform/x86_64/ecx-2300f-peg/image/font/spleen-6x12.psf create mode 100644 platform/x86_64/ecx-2300f-peg/image/iso/boot/grub/grub.cfg create mode 100644 platform/x86_64/ecx-2300f-peg/linker.ld create mode 100644 platform/x86_64/ecx-2300f-peg/platform.mk create mode 100644 platform/x86_64/ecx-2300f-peg/test/runner.sh diff --git a/platform/x86_64/ecx-2300f-peg/board.rs b/platform/x86_64/ecx-2300f-peg/board.rs new file mode 100644 index 00000000..262e6eeb --- /dev/null +++ b/platform/x86_64/ecx-2300f-peg/board.rs @@ -0,0 +1,167 @@ +// 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 crate::pci_dev; +use crate::{arch::zone::HvArchZoneConfig, config::*, memory::GuestPhysAddr}; + +pub const MEM_TYPE_RESERVED: u32 = 5; + +pub const BOARD_NCPUS: usize = 16; + +pub const ROOT_ZONE_DTB_ADDR: u64 = 0x00000000; +pub const ROOT_ZONE_BOOT_STACK: GuestPhysAddr = 0x7000; +pub const ROOT_ZONE_ENTRY: u64 = 0x8000; +pub const ROOT_ZONE_KERNEL_ADDR: u64 = 0x500_0000; // hpa +pub const ROOT_ZONE_CPUS: u64 = + (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7); + +const ROOT_ZONE_RSDP_REGION: HvConfigMemoryRegion = HvConfigMemoryRegion { + mem_type: MEM_TYPE_RAM, + physical_start: 0x50e_0000, + virtual_start: 0xe_0000, + size: 0x2_0000, +}; + +const ROOT_ZONE_ACPI_REGION: HvConfigMemoryRegion = HvConfigMemoryRegion { + mem_type: MEM_TYPE_RAM, + physical_start: 0x3a30_0000, // hpa + virtual_start: 0x3530_0000, // gpa + size: 0x10_0000, // modify size accordingly +}; + +pub const ROOT_ZONE_NAME: &str = "root-linux"; +pub const ROOT_ZONE_CMDLINE: &str = "video=vesafb console=tty0 nointremap no_timer_check pci=pcie_scan_all root=/dev/sdb2 rw init=/init rootwait\0"; +// pub const ROOT_ZONE_CMDLINE: &str = "video=vesafb console=ttyS0 earlyprintk=serial nointremap no_timer_check pci=pcie_scan_all root=/dev/vda rw init=/init\0"; +//"console=ttyS0 earlyprintk=serial rdinit=/init nokaslr nointremap\0"; // noapic +// video=vesafb + +pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 10] = [ + HvConfigMemoryRegion { + mem_type: MEM_TYPE_RAM, + physical_start: 0x500_0000, + virtual_start: 0x0, + size: 0xe_0000, + }, // ram + ROOT_ZONE_RSDP_REGION, // rsdp + HvConfigMemoryRegion { + mem_type: MEM_TYPE_RAM, + physical_start: 0x510_0000, + virtual_start: 0x10_0000, + size: 0x14f0_0000, + }, // ram + HvConfigMemoryRegion { + mem_type: MEM_TYPE_RAM, + physical_start: 0x1a00_0000, + virtual_start: 0x1500_0000, + size: 0x30_0000, + }, // ram + HvConfigMemoryRegion { + mem_type: MEM_TYPE_RAM, + physical_start: 0x1a30_0000, + virtual_start: 0x1530_0000, + size: 0x2000_0000, + }, // ram + ROOT_ZONE_ACPI_REGION, // acpi + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xfed0_0000, + virtual_start: 0xfed0_0000, + size: 0x1000, + }, // hpet + // TODO: e820 mem space probe + HvConfigMemoryRegion { + mem_type: MEM_TYPE_RESERVED, + physical_start: 0x1_0000_0000, + virtual_start: 0x1_0000_0000, + size: 0x2000_0000, + }, // zone 1 + HvConfigMemoryRegion { + mem_type: MEM_TYPE_RESERVED, + physical_start: 0xfd00_0000, + virtual_start: 0xfd00_0000, + size: 0x100_0000, + }, // reserved + HvConfigMemoryRegion { + mem_type: MEM_TYPE_RESERVED, + physical_start: 0x9000_0000, + virtual_start: 0x9000_0000, + size: 0x1000_0000, + }, // reserved +]; + +const ROOT_ZONE_CMDLINE_ADDR: GuestPhysAddr = 0x9000; +const ROOT_ZONE_SETUP_ADDR: GuestPhysAddr = 0xa000; +const ROOT_ZONE_VMLINUX_ENTRY_ADDR: GuestPhysAddr = 0x10_0000; +const ROOT_ZONE_SCREEN_BASE_ADDR: GuestPhysAddr = 0x8000_0000; + +pub const ROOT_ZONE_IRQS: [u32; 32] = [0; 32]; +pub const ROOT_ZONE_IOAPIC_BASE: usize = 0xfec0_0000; +pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { + ioapic_base: ROOT_ZONE_IOAPIC_BASE, + ioapic_size: 0x1000, + kernel_entry_gpa: ROOT_ZONE_VMLINUX_ENTRY_ADDR, + cmdline_load_gpa: ROOT_ZONE_CMDLINE_ADDR, + setup_load_gpa: ROOT_ZONE_SETUP_ADDR, + initrd_load_gpa: 0, // 0x1500_0000, + initrd_size: 0, // 0x26_b000, + rsdp_memory_region_id: 0x1, + acpi_memory_region_id: 0x5, + // not longer than 32 bits + screen_base: ROOT_ZONE_SCREEN_BASE_ADDR, +}; + +pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { + ecam_base: 0xe0000000, + ecam_size: 0x400000, + 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_PCI_MAX_BUS: usize = 3; +pub const ROOT_PCI_DEVS: [HvPciDevConfig; 21] = [ + pci_dev!(0x0, 0x0, 0x0), // host bridge + pci_dev!(0x0, 0x1, 0x0), // PCI bridge + pci_dev!(0x0, 0x1, 0x1), // PCI bridge + // pci_dev!(0x0, 0x2, 0x0), // display controller + pci_dev!(0x0, 0x8, 0x0), // system peripheral + pci_dev!(0x0, 0x12, 0x0), // signal processing controller + pci_dev!(0x0, 0x14, 0x0), // USB controller + pci_dev!(0x0, 0x14, 0x2), // RAM memory + pci_dev!(0x0, 0x14, 0x5), // SD host controller + pci_dev!(0x0, 0x15, 0x0), // serial bus controller + pci_dev!(0x0, 0x16, 0x0), // communication controller + pci_dev!(0x0, 0x16, 0x3), // serial controller + pci_dev!(0x0, 0x17, 0x0), // SATA controller + pci_dev!(0x0, 0x1d, 0x0), // PCI bridge + pci_dev!(0x0, 0x1f, 0x0), // ISA bridge + pci_dev!(0x0, 0x1f, 0x3), // audio device + pci_dev!(0x0, 0x1f, 0x4), // SMBus + pci_dev!(0x0, 0x1f, 0x5), // serial bus controller + pci_dev!(0x0, 0x1f, 0x6), // ethernet controller + pci_dev!(0x2, 0x0, 0x0), // VGA controller + pci_dev!(0x2, 0x0, 0x1), // audio device + pci_dev!(0x3, 0x0, 0x0), // ethernet controller +]; + +#[cfg(all(feature = "graphics"))] +pub const GRAPHICS_FONT: &[u8] = + include_bytes!("../../platform/x86_64/qemu/image/font/spleen-6x12.psf"); diff --git a/platform/x86_64/ecx-2300f-peg/cargo/config.template.toml b/platform/x86_64/ecx-2300f-peg/cargo/config.template.toml new file mode 100644 index 00000000..a454e986 --- /dev/null +++ b/platform/x86_64/ecx-2300f-peg/cargo/config.template.toml @@ -0,0 +1,10 @@ +[target.x86_64-unknown-none] +linker = "rust-lld" +rustflags = [ + "-Clink-arg=-Tplatform/__ARCH__/__BOARD__/linker.ld", + "-Clink-arg=-no-pie", + "-Clinker-flavor=ld.lld", + "-Cforce-frame-pointers=yes", + "-Ctarget-feature=-mmx,-sse,+soft-float", + "-Cno-redzone=yes", +] \ No newline at end of file diff --git a/platform/x86_64/ecx-2300f-peg/cargo/features b/platform/x86_64/ecx-2300f-peg/cargo/features new file mode 100644 index 00000000..ac3b7f71 --- /dev/null +++ b/platform/x86_64/ecx-2300f-peg/cargo/features @@ -0,0 +1,2 @@ +pci +uart16550a \ No newline at end of file diff --git a/platform/x86_64/ecx-2300f-peg/image/bootloader/boot.S b/platform/x86_64/ecx-2300f-peg/image/bootloader/boot.S new file mode 100644 index 00000000..9b979b63 --- /dev/null +++ b/platform/x86_64/ecx-2300f-peg/image/bootloader/boot.S @@ -0,0 +1,41 @@ +.section .text +.code16 +.global entry16 +entry16: + cli + cld + + mov ecx, eax + xor ax, ax + mov ds, ax + mov es, ax + mov ss, ax + + lgdt [prot_gdt_desc] + mov eax, cr0 + or eax, 0x1 + mov cr0, eax + + ljmp 0x8, entry32 + +.code32 +.global entry32 +entry32: + mov ax, 0x10 + mov ds, ax + mov es, ax + mov ss, ax + mov fs, ax + mov gs, ax + + jmp ecx + +.balign 16 +prot_gdt: + .quad 0x0000000000000000 # 0x00: null + .quad 0x00cf9b000000ffff # 0x08: code segment (base=0, limit=0xfffff, type=32bit code exec/read, DPL=0, 4k) + .quad 0x00cf93000000ffff # 0x10: data segment (base=0, limit=0xfffff, type=32bit data read/write, DPL=0, 4k) + +prot_gdt_desc: + .short prot_gdt_desc - prot_gdt - 1 # limit + .long prot_gdt # base diff --git a/platform/x86_64/ecx-2300f-peg/image/bootloader/boot.ld b/platform/x86_64/ecx-2300f-peg/image/bootloader/boot.ld new file mode 100644 index 00000000..3f96b209 --- /dev/null +++ b/platform/x86_64/ecx-2300f-peg/image/bootloader/boot.ld @@ -0,0 +1,15 @@ +OUTPUT_ARCH(i386) +BASE_ADDRESS = 0x8000; + +ENTRY(entry16) +SECTIONS +{ + . = BASE_ADDRESS; + .text : { + *(.text .text.*) + } + + /DISCARD/ : { + *(.eh_frame) *(.eh_frame_hdr) + } +} diff --git a/platform/x86_64/ecx-2300f-peg/image/bootloader/boot.mk b/platform/x86_64/ecx-2300f-peg/image/bootloader/boot.mk new file mode 100644 index 00000000..e23e4540 --- /dev/null +++ b/platform/x86_64/ecx-2300f-peg/image/bootloader/boot.mk @@ -0,0 +1,36 @@ +boot_dir := $(image_dir)/bootloader +boot_out_dir := $(image_dir)/bootloader/out + +boot_src := $(boot_dir)/boot.S +boot_lds := $(boot_dir)/boot.ld + +boot_o := $(boot_out_dir)/boot.o +boot_elf := $(boot_out_dir)/boot.elf +boot_bin := $(boot_out_dir)/boot.bin +boot_disa := $(boot_out_dir)/boot.asm + +AS ?= as +LD ?= ld +OBJCOPY ?= objcopy +OBJDUMP ?= objdump + +boot: mkout $(boot_bin) + +disasm: + $(OBJDUMP) -d -m i8086 -M intel $(boot_elf) | less + +mkout: + rm -rf $(boot_out_dir) + mkdir -p $(boot_out_dir) + +$(boot_o): $(boot_src) + $(AS) --32 -msyntax=intel -mnaked-reg $< -o $@ + +$(boot_elf): $(boot_o) $(boot_lds) + $(LD) -T$(boot_lds) $< -o $@ + $(OBJDUMP) -d -m i8086 -M intel $@ > $(boot_disa) + +$(boot_bin): $(boot_elf) + $(OBJCOPY) $< --strip-all -O binary $@ + +.PHONY: all disasm \ No newline at end of file diff --git a/platform/x86_64/ecx-2300f-peg/image/font/solarize-12x29.psf b/platform/x86_64/ecx-2300f-peg/image/font/solarize-12x29.psf new file mode 100644 index 0000000000000000000000000000000000000000..071330e9e585e79ebcd2079e1daf51e0f8e572c7 GIT binary patch literal 29728 zcmcIt&yO6(b*|;CcPMGOGlXDeNUnB@q(EJJxCXh5C`}Vom?%~v`<9$kt5tTBfRKhU zAT1GvQ$T6a1 zHA?DXr>nc`t5-i>y?XVdYya#Ye)q2goa7&NXN34oT%O0@Cg0b(4bc-9bV5ocbV2vT z#!|?Ce6lL7i~m3Rbxqt$iLbb=LpGHHpRS(TUsork#nZZcp3YXK*W{{HpWHDOsXnCtW&^EpsBh3UIuvtCZ_rTl^Lp3Q z+ccnoV0r|yzJYi}PR%~mxd@TrL(4=CPIl*jXzuyu_w1x zS2rQw6pB(MOh-@6mYAA7F%i&4ruR6E?1RI1L_h88^U!tQNS{j2r&rRuMx>yiTSC&) zvM(jwfzs@l5HJzHBhHE>J*!_6*P}S*v7QxuXz5g(&Qe_ah_8)X7hB?+;syO`>bJM` zHc*6F6GDTfM9XH@8uzVSk=Lu~3;LT#M~JIZlXOoH^?8y;&7J?GnQgJ1}_hw+q27 z$tP}Qt~I-Bbxa98G!M-{4bV?ZT^*+GX(wUYP{Y}9wn>}l=P&3fO=&mNDs?D+&h39p zhvrZnidW$8(uO)z@2N4dZV0PU6i|WL?Psscvf82BRvuq z#kSZHFNy=X|5(w4ZmAtvkK9DqojIp=t;)u=rd|3rVJmGf^yN10HnaFTVog`^9W35= zkjIW*n^Oldx;O__z``@OxlpF&0(e}|@1d;Q=vy0wlb@+^zCzS3Z&oY0F|~}oGMMEV zwoTEAkRUGAygWCv`bnVsRb{;PVOR9@dEKX^Na)#yX#XL1Mrjwv80if;lnm$_pr=6RL6`Ly+^i&q zkUj9}XMNFFqdjIEGoH{dLmfhPZLYE!IMVOZWUlEajj0`)u~8{{AVPn{ZAGk!4suJ142`+77719%R3xAq}RZw{RC`*%O!aWs=18$$hJBFU*U5 zO|Gj4sg(ClUOV}I|4045kv~@7)@eUcJsn1J+|PiXf()RIqkobl(-iH+G>o%gm1;#y z`+CYg=jgP7C)$dVQgX9gkVMNKq)n+k75mI_*`@pXt8g~Ol#&#Lc9!U|PITr2Pu3@4 zXbloE9fyHpIiLG8rKC#Kps`kF2cTLjAqvbN87i{Q1g)ry^(VjsU1k=;dx;(C83cIgnhmz?%`F^^a-b`Pjmtf0V z3M1{@WQC<=wNG_>RxcGNOpS9jv0og;dB zKz-`aHd)K+7VVf&WD><^@TY`t^>$FZz_QnNC+;NdMT!(UGGCf8kJqFh)p)IIX zrV>6~2KSM!NhZ5D^(`unS{|Bmc>f7Y0y{hQ&08mr-Ln_9KUurLTjB{0ml5> z6=;`Mv^6u*y9jj~e>cT0YWFy(P0DG^)7z9<0;pLB2D zhf3U4Noz67+-q$@!d;8Wu5v5w>SDOMyN9MI@6bc4E^P6+?U~$+we8o6A?ofD*6s6H@EOb*J}Zajs=O+$io4=&|I?PW^0GNh?j;+^cy=g00sSob z3scR@JuQytzFf5IrV$-V38ivQ3)-Sx?gi(Bc}?A*`(#g@r^|HN9H@g#@7-7T)gEl> zJ^e1GQ(8D;4R#fH)|>a$2S5(d--MhU>0snZ^KpQ3BZ2S;KnhiBC%mf_-ZE87{2O{^ zT!9v@W=3pDK7$qzc4ZxZ3|vP)SJ{(sT+h#5?B5k1Taq7}k0tv*74P?7ZY@Lil21VY zGGhs9BSUsvrsjoV$II=;WiIz@Nu`F1lF`{3i+fdbotl(O0xfluEd$D`AsZt#NM9Bo z+wvVC`(i9E)4YPgo%;yLZw*how}AEgNZ-^WmZgkF`uz%ooloy%Z&-7*pXG7+VrU%l zjOe0G4k#W8ZH2MkRlN$5XZm@*KQ^@+nDu%JIgCeUkhw(|S3->BogwVvkr}KBneu!v zy5JcES`^DP))y*BL&97i_l^hG{1{Lehaf5T>cZxuY4%#*UNJ2EpC0q zt?P5DoX4N%VP*xmUv(Hg^)gnvOkRM!e+Nto<;gR zS6>(Okz=wwg8i-Pv;8#tNFQfs@|RP~Hhg9!A&R)QNM91-kiI0uAvvGUPKZak_8E_K zBiA^jKhBOrVvMXLhSbraY$c=;*gv}Ckb&#pC^})n@caY z6@NBhUYriXdV<@j@Rv~>voSoqES%@K9b#f!fx|v_UWLWyj)U;E@=NY#~=SzOO zT5(`i}l+PXDRDr(dRW z{_-blgc&j;@LO6@4DRJAv`-PUJEqV+qmYI68HMEhI(s2@FArmFYl%lXNr*=>S9VoM z{sL(oc6-_R8oLTvMz|*hiI;IZkGO2D#T2_|$!jZ7JPR#53hDC8*Xq>btGdb^R)zN2 zlIK~huiOv^8PiEN4;8yNi&2kOK>F>oorU2_#xL7Aq%T8pNapR@XFSri&v>M3pH;~E zR_02IuT@C@ebJ9ymwJOX6+i7lTQAe%IppuRp38C?=9$j`mv@bX zc3t|tU>wpf>MG>2B;?_J4OWHBLoWM#Z4$SS(a&cbve4VN8n5K3&TA!(C&%FQP(0G< zp;)9h100o4zii|7Yx;IV9Mb1GB<#dV+wS!A>oX3S*DFf6f@l2*z?b+cq#tv=zZ$tb zm+Ik3q}czhSKHBA+zUI#J`0d+vlq6AobRQbBkNM@&j81b(0xgWL;8{shvYJL?K2+f z+Gjk{*|%{>e}o=~^k;x$k+~dJBGbBkQoi*Tx3}5v9paF_48E|H&`(cQHy?)vXIY z$Kq+grT!oDfWDhH#ndx9=_?uSq+98k0ySat_xAi6t6lP^AzyxiPtjL}v1f1Ck(;fP z%28$&bn&bUY3s9{$)qo6mWsAD#F6CkYAyT2Ma*>`r)_PDd3CnWb3XVw&Yi7jI?hTS_SxgcSjqfvo-P< zno$2Ouc|ALugIo6mE&@(p=%a?%H#yn%0V6Kc{gSgpm0I+*Q3`tYTz-UjdX+QjmFlX;%} zUH^yu?>r9kJex_(HIzu~O1KmXozg#>ft-K!nGR`?&i!K0AJ=}#WRd?gTYTfC#@HK{ zQ~me6tmTw=Q#&bGzShsZS)P9_;?JhA$PXtnV(*8Q636ovDIC5)bHbNX=7Roy|5vkL z)s)b(-RI3VqMrC0{7!=yPPsfKYl3A8e@AES5?>NfN`dweZ zPqCIIugZgTA72H5=sInyV(7vhSu8&rYOD}Lc5y{}hmY!8Ht+p*Ek=m)JT-K;qXIj= z@sZ1|Y@@c7@z;z4pn0!2y9Y>ZuDwFvCT79CpU4sdlJ`PnlB;iu5&P7fXuN3a9)k++ zK;5PnXkFt3H|$WeQp9J$xV_$G$Pi~EO5I1U+0sSL%qiS|`tiioCnNiGo_esP*|O!+ zOD!b=r_*7!l&PbA4rPCwBru-sV0Y%**p@PW2bslCj=$sX>$sKtxsE#gYqC zeZ>jGDsdv646weKr>UtEvfgR6dn-VEHH86K%J^Hf=>~?i6y+O}u9(C|}`8S9y^yX8c zcrG_Pcb7Wcml(mPVWjn^S-4cJUMulP$8$XEt19{s2W+}9_1B^%$nWYA{AP6-Vsy@> z=;L?wj!USTPEkLgTIVAtgjt#et(jU-_Trbbd_-6DHH{(z$Qc@1ps9T&et_0!=^SmT z%>}`x4m!VmzN5aU_)H*6Uo}X=?M#2!S)ogq%gU_A?02k#EOENqzDPAn6g4om^`HdZ zp#$BthVeNasJG-{!t^NnW#3!!Kz&YOp1s*%ZYTCt&vZ;zZK-Xwr*MpFLq2(b-VO@? zNWVtzbn13zpg*T6y@MV&)blRKp3>*~>`uqbx-pHI=Q4q5K7DoBGU4 zv*>fNR$aFQ+X76OMWbuzZ|9WWNZof;P4i(qmtQ34TLo%#4!K9rmKm*?Mo<>um*$X) zG^Lf1EmQkQyq;-#r{}lSrItLM4Be;qvQ)oEKQ--A>vX--^V=9_w?htv;u4+f`IPn> zb-auB=X7Y^R&UD>(zVM+b}YHD!rHe_ zj)BqbTedqV;*bvLfqsXSVkOJeXh_Yo{+V#6*dD3_^#J40BNd22@~MP=%kurL?4eYk z$MsR{Z$i$pJaM{?#6#_R-FAKU1o1Q76t{FPLG@ORlYrI7pDu=F>y1aRWr_2jj7^`a z=)))b4btagDcM6$K59U^p2(JJZqsBl5wu3lCv&ft&xkl{%UzX$gIXcWvlVYFKWux&4jK#x^giL1!j1uzR&(&gWz?1 literal 0 HcmV?d00001 diff --git a/platform/x86_64/ecx-2300f-peg/image/font/spleen-6x12.psf b/platform/x86_64/ecx-2300f-peg/image/font/spleen-6x12.psf new file mode 100644 index 0000000000000000000000000000000000000000..892d085c647255d9d284c87fe956027e85f3970b GIT binary patch literal 7859 zcmeHJheH#|_m5`-+XWF7Yg82FP!Ku69>vp$1;h$A5F08Qv4M(2MF=36WOwOcKuQFp z2uP7;77^6TCD^dTob9Z5ipCRtzu8RyzyHJU!R~(M&6_vxedf(fdBN9v zIGkSi!#v%XHisjy7T|vjcv#xr9A~DhU7WRAAy41p3EQx5AeoX<5a`Qv_y!ha6=dnK zP;be6tOZ;HfwfM-%*Lt5*i2x}GLF&D!p_8F*NWrp?A+1iti??& zqu}|<Zm1kPOESOFhHoQuHPofPk5F!sZI7#Yapv%(w5;ka`RSmC;}T>|UY z_8@pXZO0hg%dCn{wED09!^2+#11=XE@I@lr5Q?J}wYuDO>!{-p>kSNqA`v?rV`~Eg zmLHBtB#}t8TrM8U(cUDv$Mi7`91r%-j>lMBTwKi741?S1jnga^<9{(58!jJ4e3`L~@+Unm zH=SNrVk{+0xfNp@)*gSE5@u>xUp~4@*Od~liqVV3l17Q%hMh_8Q{13cw2c+l)+!Xy z(K{7HGA>ze8NEW=z>XD*oq5i< z-DZ#ZXF1U_Wa`$}S65iDWHxS_F#Da$?bQpv+;xLF zf?O6DFnbnnTA>Ix+iIKHJWh8iu^nsl z6UJkI*1I!NGn`=i4$SSqc-r>8`SbbD<>@w_z8)IJZY!3v7@w1Jtz2HL^N9yz8ZpK> zwqqv#Ha(t~f$UmfeLKeXI*d8j4`u!6)%vw#PGz~=mxujZ3z$OGoqKpWh0I-o)qEc7 zhPCJZ5ANU)bKagi#_h3T+#U~J!e+LCeF}2*hXTeNYXf_MJx50ad#UL$KIZT~Wn*Ud zF&?bv3LlPaopSh9{J8=yZ*__Rce)<4_b)ymd8{!0IUF;AL?STLVGM8+V>XwzGl3&w zV`~;MvHg^nZl`s;n{`mmm$&E0*fV*tYs4`SGM5TdpY6FbHQ#n7;9cd+aM(64-h9l& z%}i|8_@=~nCA(h~3QRxV!Hm8c-y3abAlvQ;hdYE(;JFxS)nWGC`m>D=>-0JsR-?D! zh@+W3Rm;qaW79PlGxkKl!7*5izl<=L`L@N+U@S+vbTMet8!$FFbVgWCbWp+CG~&I2 ze*;+S{nX;VS_b3AYS-g@v3uQ_BT*<`VjBr#!^Fcp494deLmca$FPAeMvY25D-^cno zVKeZ>p4fbwbpzS=kakXRkeFy)7apshSC^%(-q;0euRXCuj&D4jJ?o#v?h*+;g==#e zz5ZMh>1=d2p&qy2(f@lUK=M3xZdfm?`tZGq{Zt9bG*9Q-#Nx zFyu4BG??FYtdf1{dfM8&Ho)olO^)MnZo5XT1^ANIW%66)z{f;g-ufpMK5m!hY^rG> zicIzm3EL!Xc|303oHx6#@l2Y#nR}QAH|}z9zB2eqfgSCY_D+bE_uiL!^W7xG)v(i^h1%WsT*7`x-!;{&rA?v{-> zR2v}OW4PR#>Yo)ky`trjap*=)QSYwGq<5#hHrXusJ$}Qu{eMmF<8AOsPJ9p6}5^ z%`M#acQePe`TLsxx~*yu7RUxon32Y@ z4@Cs@Text!iRq-lmbY)d3GvN8Uj6Mr=F|ICMg4DV*uSnOy3g>_>D-fd$8w(AS$)wI zMrPMcv)fQVE`IoKPT+xDgRP?Zux|awehJstXeaEd8z!EaP&2{*z4Kbr4Szpt9X#fJ zZKDG(Wc9}Nex>h@`h8mDQ}0pgdhTI{>aEKm>CS)q?{vy{6AvwWJL*HXEt3WrZrhVR z=P%RL;{oQ$gD0cbE)R!|l#X~5wrA&5xOrmh*rLP5_wV@qV`6c>`XBEHu9{%^!e{oOnP)m=S5a{%+h}^N=_ES@*ehVLeP1*6-`G@hmTL$#TX}y+zt&BbsFI$nY zxvZ;aLQHdAeSLzHrsqUzyij!fptD8QPFcgX;cv-3=ce>nKG5sD*hn+j>Dg$DyIp^r zj$AV0qbV=M({7VZOK9PWo1ry^%~$um;r;q-&NKHeWGr`o?XJwZYxK(th=3(hyCl7kk`ybde?^`>5^mOS_di`HzCI47&8Z^w}{luHEe|!FW zR|}h*CKH=WcQS7nmL0xXb$RCejaeDB%S!rNxrc{m`4H>0k&n9>R@$y{OM7D1dc)8I zd?UMjAJc2}kKYSRR~t`9L*mviTQ}HnQ}x@B;BG^AnNB>g5_!vr4QtK2{jeC88Ckm2 zZSR&P?#~83=sU|Qk(#_e?%l830uEeyT3~eIM4zfbj{iK`&@I0g_2IscRFxa%3o>UD+2E5;bj z-97jEx~?I{*CVIFwyUQe{8}&XvG2glyGzrPUZn=Uy?E+`pZjk|OtqeLBcE0wKixzihl^+Qt z{w`O(_j9Uk@jRU4VK6RkiXl;=z1I}ENA>TIUWH8=N8j0W-)~gg|8&LWA5&fDow@ha z_nu%w4Y8f*WV^{}_L&&ho*|}=vwmD}-RWzw`D%pe_woff+ji~fH}6KgvtZ`zN0;J^ zUe5Nl``|j)MEKO(%j(YWqJ`nwL8I!@g5Ozol3PcOk6rDZaOz>=p=o_u`i(g3KKjV8 z9X}inWeQ6sG%e{?FvvgXlGCM{)Ku5u5q|sZYyO~!Yi7YSj0La0SbwAh;Uj#12)&+E*Wmlro=G)#Kllx*l>V{$|?@7kB~9$voY zSF5kg3?C)$(JA1;lG022BCkKm>-YZFOYW;p*UBfF?;!hsS)W~VAh_l0^WvxhPsYuB z5^mB&UvA3rdA=xTp7(%$AI`Pd-d9|!p4#uqR->$@)(`Rreft|sGUU3=yf$aSiWQ5t zd!1iW-c^>Fd?#YA_NZkemG%7AAjg2-wF^1Qr&DgJ%xvkiHJuOpiw)rqlbnsco1$GZ zJo)A?6;-D%)E>H@+M?`hpYB*!UiCdGwPjoP^Xh}6)AM>f-?4n7nTg2Ad2hy#&wtjn zWSLs**qQg>YIpBxs=;-4N3WdM?H}2T&L=-=)?^1ynX~zs`>ceO;@@7Gf4NYw3 zku^k8NBp;Yye;TFi~c(OgZ(dpp!ZiM@4X?KYO1oeqaFx^L*BoXg;jfeypwEeGf7go zV53h!#DY%)R9$+=Z59quCZ03>?$zo&KwV)uYGSP8y~?{w$A1s#vw56Vw7(5!;U{Ok8UwbH6xqk6`E z=0#24zH|BaxCj0w$8w$u!|oK%h%=1r**L*%aLMz-Q>`?zI@+_3)5!5HPg=gs8ddUk zUd3fpp|z?Oegj47m-6p?<#*X|xpaQ2ruwgAypeSc2UPy zTr3XUGNjg3b?Vc#8&C4PHntv4-G%}?EqiC{^!V}17pwCgP6_=y-Mt}TKCkd~mD@Ah zVGbw8_j=(_Z@A#@hW}3f(zJe$_oFU;yCg2B=5zWOj-7hjc<}6FBS)J}U46Aw`hF|l zNY;6Fq*uO6_>*9hbrrKmS$*~D>zD7oASBFUXWXsnAy#{OE}gYLYW~D|9z%P~?$N91 zirB|f9M)Xrc53eA%X6;|Uu#oz`&{&&1D}q&v4i~4*~YFPH%VA{ak?=_DRrz}a=w1y ziM65G+(9LC=eb;clr^A_aVNC2m$9I6Wa21Oaop&Azdp7+pr(Ac1`Qheq;Ky%hcDWV z|7|++S_a%}vvsjjQuPICQs%xVYmuB1!X zD)I-7S!Aek*=YV|nSJVUE0II@(>B@NJw`k~KJWWtvWoM=YLScS7`I6aTWT9;m~ZHR z|Hj*kZv!3e29e|UHBNuJ0+A7B$5%dx-Vks3b?$&7`xo~fWk2`mMsf1O)^`$JZde;! z`MTvBFMcQT9_FpE8N7Pr)YJW6-i_Jb<)He%KPMQ~ zD?JWqf7B$bv;8!EyQ9W@@u7s|-bP2w9a?9KkJd-_UfZ+a%v|r7t&b;H&PaPlu9+t1eO~V(@p347{9G}K}QW(GK=@IK5xL@IR40`$}Kn2 zY;Jk??eVQK=d|L%YT?I4``<21MVGdH-_v@fF^2!Awx@6Oa0|~PVOn_xC+K`;&*91x zP^N)W0VpOFKWQjR{Jydrl;=R14a%JBA)w3$WdSIQL0JOI3ZO+m9|QV0&?kTv104!< znEDtfFM={1=u<$4104bMX>~Brl4=RiGN1{dNuVj9qkyNBBasM+jv>);Bszgafk<=` ziGq+Q7>UG46oN#dNR$I3U?hwJGZ+nHz#PWHIIuvWaqt@orN9!#BasY=2qcy%&m)lp ziKHkr5+4eZ3UE}5k*pFHs$*5LC@=#NB3OioW3X5quZl;+ zaaf{CK*R}fQYWg;AR-W))pAu5B2L0mLtH=>0C(_E=ORJ^8xbJ|Pt7qz z$Y2v92-vJHL<9+25JACKL`1?iL_~p?2K$JH?V4yr#J~l;Na60KIT884I zP<%AXE(br&2}CI15F*aOVK@T*a1`ihpm7zI0eueWWS~=kmIIv%G%mCZpffd6pcO#p zXrh45209DqK%h^ez)YY+fKCHC2~LK6hvksG6Rw45UD_9IwI2$nTn_+ zL?t8YEYP_?7Xn=jbUDx!ppF2w6x1ZBBS9U7$4d}NAX0`%DWWJuMItH+QQ5eIL}U~q zBN2(UcnicJDi%?>xT64(mk?Qs$Pz>rBeDpQ7ZHi$OGlIfQRlEl79#Tzc>$4mh|EP~ z4kEJ=c^*+Ih{BPjVT*V~o<(FbB9jm)N8}kqCL%HcQHh8;gD5$+5FzpyqACzohNx0R zT|`tdqVUv#h&+i%F(N|{bqZ0qP9@kH8(}^|5rws4L#48nnNF1FEQ3Rq$L}4EnL0tsuVo;ZW zx)jv7jLv|HP!pgo19ds5D?wSPDg(`NP^GC;Koba>AkYMZMhuz|(1d~}3^b=enFpG1 i&_sadG-z Date: Sun, 14 Dec 2025 19:08:32 +0800 Subject: [PATCH 098/109] support UEFI for zone0 linux --- Cargo.lock | 145 +++++++++++++++++++----------- Cargo.toml | 2 + platform/x86_64/nuc14mnk/board.rs | 26 ++++-- platform/x86_64/qemu/board.rs | 26 ++++-- src/arch/x86_64/boot.rs | 140 +++++++++++++++++++++++++++-- src/arch/x86_64/cpu.rs | 1 - src/arch/x86_64/zone.rs | 1 + 7 files changed, 267 insertions(+), 74 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4b904038..43a258fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,26 +17,20 @@ version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94476c7ef97af4c4d998b3f422c1b01d5211aad57c80ed200baf148d1f1efab6" dependencies = [ - "bit_field 0.10.2", - "bitflags 2.9.1", + "bit_field 0.10.3", + "bitflags 2.10.0", "log", ] [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - [[package]] name = "bare-metal" version = "0.2.5" @@ -60,9 +54,9 @@ checksum = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56" [[package]] name = "bit_field" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" [[package]] name = "bitflags" @@ -72,9 +66,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "bitmap-allocator" @@ -113,9 +107,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cortex-a" @@ -169,8 +163,8 @@ version = "0.1.0" dependencies = [ "aarch64-cpu", "acpi", - "bit_field 0.10.2", - "bitflags 2.9.1", + "bit_field 0.10.3", + "bitflags 2.10.0", "bitmap-allocator", "bitvec", "buddy_system_allocator", @@ -193,6 +187,8 @@ dependencies = [ "sbi-spec 0.0.8", "spin 0.10.0", "tock-registers", + "uefi-raw", + "uguid", "x2apic", "x86", "x86_64", @@ -209,19 +205,18 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "loongArch64" @@ -229,15 +224,15 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c9f0d275c70310e2a9d2fc23250c5ac826a73fa828a5f256401f85c5c554283" dependencies = [ - "bit_field 0.10.2", - "bitflags 2.9.1", + "bit_field 0.10.3", + "bitflags 2.10.0", ] [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "numeric-enum-macro" @@ -253,9 +248,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] @@ -266,6 +261,26 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b6fb7be1022539b1ea394ff4bcbad807a55c93841bb12c733f0be1048ea3e53" +[[package]] +name = "ptr_meta" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcada80daa06c42ed5f48c9a043865edea5dc44cbf9ac009fda3b89526e28607" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca9224df2e20e7c5548aeb5f110a0f3b77ef05f8585139b7148b59056168ed2" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "qemu-exit" version = "3.0.2" @@ -274,9 +289,9 @@ checksum = "8bb0fd6580eeed0103c054e3fba2c2618ff476943762f28a645b63b8692b21c9" [[package]] name = "quote" -version = "1.0.40" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -298,9 +313,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -310,9 +325,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -321,9 +336,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "riscv" @@ -331,7 +346,7 @@ version = "0.6.0" source = "git+https://github.com/rcore-os/riscv#11d43cf7cccb3b62a3caaf3e07a1db7449588f9a" dependencies = [ "bare-metal", - "bit_field 0.10.2", + "bit_field 0.10.3", "bitflags 1.3.2", "log", "riscv-target", @@ -352,9 +367,9 @@ dependencies = [ [[package]] name = "riscv-decode" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf8b4cfb0da0528321d22daee4299a23a8c5ac8848623d716e898d2a9eec0694" +checksum = "68b59d645e392e041ad18f5e529ed13242d8405c66bb192f59703ea2137017d0" [[package]] name = "riscv-macros" @@ -364,7 +379,7 @@ checksum = "e8c4aa1ea1af6dcc83a61be12e8189f9b293c3ba5a487778a4cd89fb060fdbbc" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.111", ] [[package]] @@ -405,9 +420,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "sbi-rt" @@ -474,15 +489,26 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "syn" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] [[package]] name = "syn" -version = "2.0.100" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -501,11 +527,28 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "696941a0aee7e276a165a978b37918fd5d22c55c3d6bda197813070ca9c0f21c" +[[package]] +name = "uefi-raw" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d465de2c918779dafb769a5a4fe8d6e4fb7cc4cc6cb1a735f2f6ec68beea4" +dependencies = [ + "bitflags 2.10.0", + "ptr_meta", + "uguid", +] + +[[package]] +name = "uguid" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab14ea9660d240e7865ce9d54ecdbd1cd9fa5802ae6f4512f093c7907e921533" + [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "volatile" @@ -541,7 +584,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385" dependencies = [ - "bit_field 0.10.2", + "bit_field 0.10.3", "bitflags 1.3.2", "raw-cpuid", ] @@ -552,7 +595,7 @@ version = "0.14.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "100555a863c0092238c2e0e814c1096c1e5cf066a309c696a87e907b5f8c5d69" dependencies = [ - "bit_field 0.10.2", + "bit_field 0.10.3", "bitflags 1.3.2", "rustversion", "volatile", diff --git a/Cargo.toml b/Cargo.toml index 20fc9ef3..83fe42e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,8 @@ x86_64 = "=0.14.10" x2apic = "=0.4.3" raw-cpuid = "=10.7.0" acpi = "=5.2.0" +uguid = "=2.2.0" +uefi-raw = "=0.9.0" [features] ############# general ############## diff --git a/platform/x86_64/nuc14mnk/board.rs b/platform/x86_64/nuc14mnk/board.rs index 8cf71387..8a30d21c 100644 --- a/platform/x86_64/nuc14mnk/board.rs +++ b/platform/x86_64/nuc14mnk/board.rs @@ -32,6 +32,7 @@ const ROOT_ZONE_RSDP_REGION: HvConfigMemoryRegion = HvConfigMemoryRegion { virtual_start: 0xe_0000, size: 0x2_0000, }; +const ROOT_ZONE_RSDP_REGION_ID: usize = 0x1; const ROOT_ZONE_ACPI_REGION: HvConfigMemoryRegion = HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, @@ -39,14 +40,23 @@ const ROOT_ZONE_ACPI_REGION: HvConfigMemoryRegion = HvConfigMemoryRegion { virtual_start: 0x3530_0000, // gpa size: 0x10_0000, // modify size accordingly }; +const ROOT_ZONE_ACPI_REGION_ID: usize = 0x6; + +const ROOT_ZONE_UEFI_REGION: HvConfigMemoryRegion = HvConfigMemoryRegion { + mem_type: MEM_TYPE_RAM, + physical_start: 0x1a00_0000, + virtual_start: 0x1500_0000, + size: 0x1_0000, +}; +const ROOT_ZONE_UEFI_REGION_ID: usize = 0x3; pub const ROOT_ZONE_NAME: &str = "root-linux"; -pub const ROOT_ZONE_CMDLINE: &str = "video=vesafb console=tty0 nointremap no_timer_check pci=pcie_scan_all root=/dev/sda2 rw init=/init rootwait\0"; +pub const ROOT_ZONE_CMDLINE: &str = "video=vesafb console=tty0 nointremap no_timer_check efi=noruntime pci=pcie_scan_all root=/dev/sda2 rw init=/init rootwait\0"; // pub const ROOT_ZONE_CMDLINE: &str = "video=vesafb console=ttyS0 earlyprintk=serial nointremap no_timer_check pci=pcie_scan_all root=/dev/vda rw init=/init\0"; //"console=ttyS0 earlyprintk=serial rdinit=/init nokaslr nointremap\0"; // noapic // video=vesafb -pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 14] = [ +pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 15] = [ HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, physical_start: 0x500_0000, @@ -60,11 +70,12 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 14] = [ virtual_start: 0x10_0000, size: 0x14f0_0000, }, // ram + ROOT_ZONE_UEFI_REGION, // uefi HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0x1a00_0000, - virtual_start: 0x1500_0000, - size: 0x30_0000, + physical_start: 0x1a01_0000, + virtual_start: 0x1501_0000, + size: 0x2f_0000, }, // ram HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, @@ -140,8 +151,9 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { setup_load_gpa: ROOT_ZONE_SETUP_ADDR, initrd_load_gpa: 0, // 0x1500_0000, initrd_size: 0, // 0x26_b000, - rsdp_memory_region_id: 0x1, - acpi_memory_region_id: 0x5, + rsdp_memory_region_id: ROOT_ZONE_RSDP_REGION_ID, + acpi_memory_region_id: ROOT_ZONE_ACPI_REGION_ID, + uefi_memory_region_id: ROOT_ZONE_UEFI_REGION_ID, // not longer than 32 bits screen_base: ROOT_ZONE_SCREEN_BASE_ADDR, }; diff --git a/platform/x86_64/qemu/board.rs b/platform/x86_64/qemu/board.rs index 08e48eca..74d9739a 100644 --- a/platform/x86_64/qemu/board.rs +++ b/platform/x86_64/qemu/board.rs @@ -32,6 +32,7 @@ const ROOT_ZONE_RSDP_REGION: HvConfigMemoryRegion = HvConfigMemoryRegion { virtual_start: 0xe_0000, size: 0x2_0000, }; +const ROOT_ZONE_RSDP_REGION_ID: usize = 0x1; const ROOT_ZONE_ACPI_REGION: HvConfigMemoryRegion = HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, @@ -39,14 +40,23 @@ const ROOT_ZONE_ACPI_REGION: HvConfigMemoryRegion = HvConfigMemoryRegion { virtual_start: 0x3530_0000, // gpa size: 0xf000, // modify size accordingly }; +const ROOT_ZONE_ACPI_REGION_ID: usize = 0x6; + +const ROOT_ZONE_UEFI_REGION: HvConfigMemoryRegion = HvConfigMemoryRegion { + mem_type: MEM_TYPE_RAM, + physical_start: 0x1a00_0000, + virtual_start: 0x1500_0000, + size: 0x1_0000, +}; +const ROOT_ZONE_UEFI_REGION_ID: usize = 0x3; pub const ROOT_ZONE_NAME: &str = "root-linux"; pub const ROOT_ZONE_CMDLINE: &str = - "console=ttyS0 earlyprintk=serial nointremap no_timer_check pci=pcie_scan_all,lastbus=1 root=/dev/vda rw init=/init\0"; + "console=ttyS0 earlyprintk=serial nointremap no_timer_check efi=noruntime pci=pcie_scan_all,lastbus=1 root=/dev/vda rw init=/init\0"; //"console=ttyS0 earlyprintk=serial rdinit=/init nokaslr nointremap\0"; // noapic // video=vesafb -pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 8] = [ +pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 9] = [ HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, physical_start: 0x500_0000, @@ -60,11 +70,12 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 8] = [ virtual_start: 0x10_0000, size: 0x14f0_0000, }, // ram + ROOT_ZONE_UEFI_REGION, // uefi HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0x1a00_0000, - virtual_start: 0x1500_0000, - size: 0x30_0000, + physical_start: 0x1a01_0000, + virtual_start: 0x1501_0000, + size: 0x2f_0000, }, // ram HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, @@ -104,8 +115,9 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { setup_load_gpa: ROOT_ZONE_SETUP_ADDR, initrd_load_gpa: 0, // 0x1500_0000, initrd_size: 0, //0x26_b000, - rsdp_memory_region_id: 0x1, - acpi_memory_region_id: 0x5, + rsdp_memory_region_id: ROOT_ZONE_RSDP_REGION_ID, + acpi_memory_region_id: ROOT_ZONE_ACPI_REGION_ID, + uefi_memory_region_id: ROOT_ZONE_UEFI_REGION_ID, // not longer than 32 bits screen_base: ROOT_ZONE_SCREEN_BASE_ADDR, }; diff --git a/src/arch/x86_64/boot.rs b/src/arch/x86_64/boot.rs index 14d92a08..35bbc397 100644 --- a/src/arch/x86_64/boot.rs +++ b/src/arch/x86_64/boot.rs @@ -16,13 +16,15 @@ use crate::{ arch::{zone::HvArchZoneConfig, Stage2PageTable}, - config::{root_zone_config, HvPciConfig, HvZoneConfig, MEM_TYPE_RAM}, + config::{root_zone_config, HvConfigMemoryRegion, HvPciConfig, HvZoneConfig, MEM_TYPE_RAM}, + consts::PAGE_SIZE, error::HvResult, memory::{GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet}, percpu::this_zone, platform::MEM_TYPE_RESERVED, }; use alloc::string::{String, ToString}; +use bit_field::BitField; use core::{ arch::{self, global_asm}, ffi::{c_char, CStr}, @@ -31,6 +33,15 @@ use core::{ }; use multiboot_tag::{Modules, MultibootTags}; use spin::{Mutex, Once}; +use uefi_raw::table::{ + boot::{MemoryAttribute, MemoryDescriptor, MemoryType}, + configuration::ConfigurationTable, + system::SystemTable, + Header, Revision, +}; +use uguid::{guid, Guid}; + +const ACPI_20_TABLE_GUID: Guid = guid!("8868E871-E4F1-11D3-BC22-0080C73C8881"); mod multiboot_tag { pub const END: u32 = 0; @@ -92,6 +103,8 @@ static MULTIBOOT_TAGS: Once = Once::new(); const E820_MAX_ENTRIES_ZEROPAGE: usize = 128; +const EFI64_LOADER_SIGNATURE: u32 = 0x34364c45; // EL64 + bitflags::bitflags! { #[derive(Clone, Copy, Debug)] /// https://www.kernel.org/doc/html/latest/arch/x86/boot.html @@ -123,7 +136,9 @@ pub enum E820Type { /// The so-called "zeropage" pub struct BootParams { screen_info: ScreenInfo, - pad0: [u8; 0x1a8], + pad9: [u8; 0x180], + efi_info: EfiInfo, + pad0: [u8; 0x8], e820_entries: u8, pad1: [u8; 0x8], setup_sects: u8, @@ -213,26 +228,27 @@ impl BootParams { boot_params.set_screen_info(config, gpm); } + // set efi_info + boot_params.set_uefi_info(config); + Ok(()) } fn set_e820_entries(&mut self, config: &HvZoneConfig) { let mut index = 0; for i in 0..config.memory_regions().len() { - let mem_region = config.memory_regions()[i]; + let mem_region = &config.memory_regions()[i]; let mut e820_type = E820Type::E820_DEFAULT; if i == config.arch_config.rsdp_memory_region_id || i == config.arch_config.acpi_memory_region_id { e820_type = E820Type::E820_ACPI; + } else if i == config.arch_config.uefi_memory_region_id { + e820_type = E820Type::E820_RESERVED; } else if mem_region.mem_type == MEM_TYPE_RAM { e820_type = E820Type::E820_RAM; - } /* - else if config.arch_config.initrd_load_gpa != 0 - && i == config.arch_config.initrd_memory_region_id - { - } */ + } if e820_type != E820Type::E820_DEFAULT { self.e820_table[index] = BootE820Entry { @@ -254,12 +270,120 @@ impl BootParams { self.e820_entries = index as _; } + fn set_efi_mem_map(&mut self, config: &HvZoneConfig, paddr: usize) -> usize { + let mut cnt = 0; + let mem_map_cnt = config.memory_regions().len(); + let mut mem_map = unsafe { paddr as *mut MemoryDescriptor }; + for i in 0..mem_map_cnt { + let mem_region = &config.memory_regions()[i]; + let mem_desc = unsafe { &mut *mem_map }; + + let mut mem_desc_type = MemoryType::RESERVED; + + if i == config.arch_config.rsdp_memory_region_id + || i == config.arch_config.acpi_memory_region_id + { + mem_desc_type = MemoryType::ACPI_RECLAIM; + } else if i == config.arch_config.uefi_memory_region_id { + mem_desc_type = MemoryType::RUNTIME_SERVICES_DATA; + } else if mem_region.mem_type == MEM_TYPE_RAM { + mem_desc_type = MemoryType::CONVENTIONAL; + } + + if mem_desc_type != MemoryType::RESERVED { + *mem_desc = MemoryDescriptor { + ty: mem_desc_type, + phys_start: mem_region.virtual_start, + virt_start: mem_region.virtual_start, + page_count: mem_region.size / (PAGE_SIZE as u64), + att: MemoryAttribute::WRITE_BACK, + }; + cnt += 1; + mem_map = mem_map.wrapping_add(1); + } + } + + let mem_desc = unsafe { &mut *mem_map }; + *mem_desc = MemoryDescriptor { + ty: MemoryType::MMIO, + phys_start: config.pci_config[0].ecam_base, + virt_start: config.pci_config[0].ecam_base, + page_count: config.pci_config[0].ecam_size / (PAGE_SIZE as u64), + att: MemoryAttribute::UNCACHEABLE, + }; + cnt += 1; + + cnt + } + fn set_initrd(&mut self, ramdisk_image: u32, ramdisk_size: u32) { self.ramdisk_image = ramdisk_image; self.ramdisk_size = ramdisk_size; info!("initrd size: {}", self.ramdisk_size); } + fn set_uefi_info(&mut self, config: &HvZoneConfig) { + self.efi_info.loader_signature = EFI64_LOADER_SIGNATURE; + + let uefi_region = &config.memory_regions()[config.arch_config.uefi_memory_region_id]; + let mut vaddr = uefi_region.virtual_start as usize; + let mut paddr = uefi_region.physical_start as usize; + + // set system table + self.efi_info.systab = vaddr.get_bits(0..32) as _; + self.efi_info.systab_hi = vaddr.get_bits(32..64) as _; + let system_table = unsafe { &mut *(paddr as usize as *mut SystemTable) }; + + let system_table_header = Header { + signature: SystemTable::SIGNATURE, + revision: Revision::EFI_2_90, + size: size_of::() as u32, + crc: 0, + reserved: 0, + }; + + // start of the efi memmap + vaddr += size_of::(); + paddr += size_of::(); + + let mem_desc_cnt = self.set_efi_mem_map(config, paddr); + let mem_map_tot_size = size_of::() * mem_desc_cnt; + self.efi_info.memmap = vaddr.get_bits(0..32) as _; + self.efi_info.memmap_hi = vaddr.get_bits(32..64) as _; + self.efi_info.memdesc_size = size_of::() as _; + self.efi_info.memmap_size = mem_map_tot_size as _; + self.efi_info.memdesc_version = MemoryDescriptor::VERSION; + + // start of the config table + vaddr += size_of::() * mem_desc_cnt; + paddr += size_of::() * mem_desc_cnt; + + const CONFIG_TABLE_ENTRIES: usize = 1; + let config_table = + unsafe { &mut *(paddr as *mut [ConfigurationTable; CONFIG_TABLE_ENTRIES]) }; + + // ACPI_20_TABLE_GUID + let rsdp_region = &config.memory_regions()[config.arch_config.rsdp_memory_region_id]; + config_table[0].vendor_guid = ACPI_20_TABLE_GUID; + config_table[0].vendor_table = unsafe { rsdp_region.virtual_start as _ }; + + *system_table = SystemTable { + header: system_table_header, + firmware_vendor: core::ptr::null_mut(), + firmware_revision: 0, + stdin_handle: core::ptr::null_mut(), + stdin: core::ptr::null_mut(), + stdout_handle: core::ptr::null_mut(), + stdout: core::ptr::null_mut(), + stderr_handle: core::ptr::null_mut(), + stderr: core::ptr::null_mut(), + runtime_services: core::ptr::null_mut(), + boot_services: core::ptr::null_mut(), + number_of_configuration_table_entries: CONFIG_TABLE_ENTRIES, + configuration_table: unsafe { vaddr as *mut ConfigurationTable }, + }; + } + fn set_screen_info(&mut self, config: &HvZoneConfig, gpm: &mut MemorySet) { let fb_info = &get_multiboot_tags().framebuffer; diff --git a/src/arch/x86_64/cpu.rs b/src/arch/x86_64/cpu.rs index 25f3653d..4610cc5f 100644 --- a/src/arch/x86_64/cpu.rs +++ b/src/arch/x86_64/cpu.rs @@ -254,7 +254,6 @@ impl ArchCpu { unsafe { PARKING_MEMORY_SET.get().unwrap().activate(); - info!("before vmx launch"); self.vmx_launch(); } } diff --git a/src/arch/x86_64/zone.rs b/src/arch/x86_64/zone.rs index f69f4eac..8c808718 100644 --- a/src/arch/x86_64/zone.rs +++ b/src/arch/x86_64/zone.rs @@ -54,6 +54,7 @@ pub struct HvArchZoneConfig { /// no restriction on start gpa and size, but its type should be MEM_TYPE_RAM as well. /// Usually, the DSDT table is large, so the size of this region should be large enough. pub acpi_memory_region_id: usize, + pub uefi_memory_region_id: usize, /// If you want to use a graphical console, set screen_base to a preferred gpa /// as the start of the framebuffer. Otherwise, leave it as zero. /// No need to add a memory region for the framebuffer, From 88b2272cf458c79648d8b3032a79a03f3430a705 Mon Sep 17 00:00:00 2001 From: Solicey Date: Wed, 14 Jan 2026 23:40:47 +0800 Subject: [PATCH 099/109] add ecx-2300f-peg --- Cargo.toml | 2 +- platform/x86_64/ecx-2300f-peg/board.rs | 42 +++++++++++++------- platform/x86_64/ecx-2300f-peg/cargo/features | 2 +- platform/x86_64/nuc14mnk/board.rs | 10 ++++- platform/x86_64/nuc14mnk/cargo/features | 4 +- platform/x86_64/qemu/board.rs | 9 ++++- src/arch/x86_64/boot.rs | 6 +++ src/arch/x86_64/graphics.rs | 13 ++++++ src/arch/x86_64/pio.rs | 8 ++-- 9 files changed, 71 insertions(+), 25 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 83fe42e6..949a646c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,7 +94,7 @@ loongson_3a6000 = [] ############# x86_64 ############### graphics = [] - +split_screen = [] [profile.dev] # panic = "abort" # avoid cargo test failure, this is a bug of cargo diff --git a/platform/x86_64/ecx-2300f-peg/board.rs b/platform/x86_64/ecx-2300f-peg/board.rs index 262e6eeb..59e338f7 100644 --- a/platform/x86_64/ecx-2300f-peg/board.rs +++ b/platform/x86_64/ecx-2300f-peg/board.rs @@ -33,6 +33,7 @@ const ROOT_ZONE_RSDP_REGION: HvConfigMemoryRegion = HvConfigMemoryRegion { virtual_start: 0xe_0000, size: 0x2_0000, }; +const ROOT_ZONE_RSDP_REGION_ID: usize = 0x1; const ROOT_ZONE_ACPI_REGION: HvConfigMemoryRegion = HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, @@ -40,14 +41,23 @@ const ROOT_ZONE_ACPI_REGION: HvConfigMemoryRegion = HvConfigMemoryRegion { virtual_start: 0x3530_0000, // gpa size: 0x10_0000, // modify size accordingly }; +const ROOT_ZONE_ACPI_REGION_ID: usize = 0x6; + +const ROOT_ZONE_UEFI_REGION: HvConfigMemoryRegion = HvConfigMemoryRegion { + mem_type: MEM_TYPE_RAM, + physical_start: 0x1a00_0000, + virtual_start: 0x1500_0000, + size: 0x1_0000, +}; +const ROOT_ZONE_UEFI_REGION_ID: usize = 0x3; pub const ROOT_ZONE_NAME: &str = "root-linux"; -pub const ROOT_ZONE_CMDLINE: &str = "video=vesafb console=tty0 nointremap no_timer_check pci=pcie_scan_all root=/dev/sdb2 rw init=/init rootwait\0"; +pub const ROOT_ZONE_CMDLINE: &str = "video=vesafb console=tty0 nointremap no_timer_check pci=pcie_scan_all efi=noruntime root=/dev/sda2 rw init=/init rootwait\0"; // pub const ROOT_ZONE_CMDLINE: &str = "video=vesafb console=ttyS0 earlyprintk=serial nointremap no_timer_check pci=pcie_scan_all root=/dev/vda rw init=/init\0"; //"console=ttyS0 earlyprintk=serial rdinit=/init nokaslr nointremap\0"; // noapic // video=vesafb -pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 10] = [ +pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 11] = [ HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, physical_start: 0x500_0000, @@ -61,12 +71,13 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 10] = [ virtual_start: 0x10_0000, size: 0x14f0_0000, }, // ram + ROOT_ZONE_UEFI_REGION, // uefi HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0x1a00_0000, - virtual_start: 0x1500_0000, - size: 0x30_0000, - }, // ram + physical_start: 0x1a01_0000, + virtual_start: 0x1501_0000, + size: 0x2f_0000, + }, HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, physical_start: 0x1a30_0000, @@ -85,7 +96,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 10] = [ mem_type: MEM_TYPE_RESERVED, physical_start: 0x1_0000_0000, virtual_start: 0x1_0000_0000, - size: 0x2000_0000, + size: 0x7_0000_0000, }, // zone 1 HvConfigMemoryRegion { mem_type: MEM_TYPE_RESERVED, @@ -116,8 +127,9 @@ pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { setup_load_gpa: ROOT_ZONE_SETUP_ADDR, initrd_load_gpa: 0, // 0x1500_0000, initrd_size: 0, // 0x26_b000, - rsdp_memory_region_id: 0x1, - acpi_memory_region_id: 0x5, + rsdp_memory_region_id: ROOT_ZONE_RSDP_REGION_ID, + acpi_memory_region_id: ROOT_ZONE_ACPI_REGION_ID, + uefi_memory_region_id: ROOT_ZONE_UEFI_REGION_ID, // not longer than 32 bits screen_base: ROOT_ZONE_SCREEN_BASE_ADDR, }; @@ -137,7 +149,7 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { }]; pub const ROOT_PCI_MAX_BUS: usize = 3; -pub const ROOT_PCI_DEVS: [HvPciDevConfig; 21] = [ +pub const ROOT_PCI_DEVS: [HvPciDevConfig; 19] = [ pci_dev!(0x0, 0x0, 0x0), // host bridge pci_dev!(0x0, 0x1, 0x0), // PCI bridge pci_dev!(0x0, 0x1, 0x1), // PCI bridge @@ -152,14 +164,14 @@ pub const ROOT_PCI_DEVS: [HvPciDevConfig; 21] = [ pci_dev!(0x0, 0x16, 0x3), // serial controller pci_dev!(0x0, 0x17, 0x0), // SATA controller pci_dev!(0x0, 0x1d, 0x0), // PCI bridge - pci_dev!(0x0, 0x1f, 0x0), // ISA bridge + // pci_dev!(0x0, 0x1f, 0x0), // ISA bridge pci_dev!(0x0, 0x1f, 0x3), // audio device pci_dev!(0x0, 0x1f, 0x4), // SMBus pci_dev!(0x0, 0x1f, 0x5), // serial bus controller - pci_dev!(0x0, 0x1f, 0x6), // ethernet controller - pci_dev!(0x2, 0x0, 0x0), // VGA controller - pci_dev!(0x2, 0x0, 0x1), // audio device - pci_dev!(0x3, 0x0, 0x0), // ethernet controller + // pci_dev!(0x0, 0x1f, 0x6), // ethernet controller + pci_dev!(0x2, 0x0, 0x0), // VGA controller + pci_dev!(0x2, 0x0, 0x1), // audio device + pci_dev!(0x3, 0x0, 0x0), // ethernet controller ]; #[cfg(all(feature = "graphics"))] diff --git a/platform/x86_64/ecx-2300f-peg/cargo/features b/platform/x86_64/ecx-2300f-peg/cargo/features index ac3b7f71..e4ad1c13 100644 --- a/platform/x86_64/ecx-2300f-peg/cargo/features +++ b/platform/x86_64/ecx-2300f-peg/cargo/features @@ -1,2 +1,2 @@ pci -uart16550a \ No newline at end of file +uart16550a diff --git a/platform/x86_64/nuc14mnk/board.rs b/platform/x86_64/nuc14mnk/board.rs index 8a30d21c..1f3f8319 100644 --- a/platform/x86_64/nuc14mnk/board.rs +++ b/platform/x86_64/nuc14mnk/board.rs @@ -51,7 +51,7 @@ const ROOT_ZONE_UEFI_REGION: HvConfigMemoryRegion = HvConfigMemoryRegion { const ROOT_ZONE_UEFI_REGION_ID: usize = 0x3; pub const ROOT_ZONE_NAME: &str = "root-linux"; -pub const ROOT_ZONE_CMDLINE: &str = "video=vesafb console=tty0 nointremap no_timer_check efi=noruntime pci=pcie_scan_all root=/dev/sda2 rw init=/init rootwait\0"; +pub const ROOT_ZONE_CMDLINE: &str = "video=vesafb console=tty0 nointremap no_timer_check efi=noruntime pci=pcie_scan_all root=/dev/nvme0n1p5 rw init=/init rootwait\0"; // pub const ROOT_ZONE_CMDLINE: &str = "video=vesafb console=ttyS0 earlyprintk=serial nointremap no_timer_check pci=pcie_scan_all root=/dev/vda rw init=/init\0"; //"console=ttyS0 earlyprintk=serial rdinit=/init nokaslr nointremap\0"; // noapic // video=vesafb @@ -95,7 +95,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 15] = [ mem_type: MEM_TYPE_RESERVED, physical_start: 0x1_0000_0000, virtual_start: 0x1_0000_0000, - size: 0x2000_0000, + size: 0x2_0000_0000, }, // zone 1 HvConfigMemoryRegion { mem_type: MEM_TYPE_RESERVED, @@ -173,6 +173,12 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { }]; pub const ROOT_PCI_MAX_BUS: usize = 2; +pub const ROOT_PCI_DEVS: [HvPciDevConfig; 17] = [ + pci_dev!(0x0, 0x0, 0x0), // host bridge + pci_dev!(0x0, 0x2, 0x0), // VGA controller + pci_dev!(0x0, 0x4, 0x0), + pci_dev!(0x0, 0x8, 0x0), + pci_dev!(0x0, 0xa, 0x0), pub const ROOT_PCI_DEVS: [HvPciDevConfig; 18] = [ pci_dev!(0x0, 0x0, 0x0, VpciDevType::Physical), // host bridge pci_dev!(0x0, 0x2, 0x0, VpciDevType::Physical), // VGA controller diff --git a/platform/x86_64/nuc14mnk/cargo/features b/platform/x86_64/nuc14mnk/cargo/features index f8ee525a..69fb95c9 100644 --- a/platform/x86_64/nuc14mnk/cargo/features +++ b/platform/x86_64/nuc14mnk/cargo/features @@ -1,4 +1,6 @@ pci ecam_pcie no_pcie_bar_realloc -uart16550a \ No newline at end of file +uart16550a +graphics +split_screen \ No newline at end of file diff --git a/platform/x86_64/qemu/board.rs b/platform/x86_64/qemu/board.rs index 74d9739a..81885502 100644 --- a/platform/x86_64/qemu/board.rs +++ b/platform/x86_64/qemu/board.rs @@ -55,8 +55,9 @@ pub const ROOT_ZONE_CMDLINE: &str = "console=ttyS0 earlyprintk=serial nointremap no_timer_check efi=noruntime pci=pcie_scan_all,lastbus=1 root=/dev/vda rw init=/init\0"; //"console=ttyS0 earlyprintk=serial rdinit=/init nokaslr nointremap\0"; // noapic // video=vesafb +// /lib/systemd/systemd -pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 9] = [ +pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 10] = [ HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, physical_start: 0x500_0000, @@ -97,6 +98,12 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 9] = [ virtual_start: 0x4030_0000, size: 0x2000_0000, }, // zone 1 + HvConfigMemoryRegion { + mem_type: MEM_TYPE_RESERVED, + physical_start: 0x1_0000_0000, + virtual_start: 0x1_0000_0000, + size: 0x7000_0000, + }, // zone 1 ]; const ROOT_ZONE_CMDLINE_ADDR: GuestPhysAddr = 0x9000; diff --git a/src/arch/x86_64/boot.rs b/src/arch/x86_64/boot.rs index 35bbc397..8e8c90b2 100644 --- a/src/arch/x86_64/boot.rs +++ b/src/arch/x86_64/boot.rs @@ -229,7 +229,9 @@ impl BootParams { } // set efi_info + // if (config.zone_id == 0) { boot_params.set_uefi_info(config); + // } Ok(()) } @@ -389,7 +391,11 @@ impl BootParams { let bytes_per_pixel = (fb_info.bpp as usize) / 8; let width = fb_info.width as usize; + + #[cfg(not(feature = "split_screen"))] let height = fb_info.height as usize; + #[cfg(all(feature = "split_screen"))] + let height = (fb_info.height / 2) as usize; self.screen_info.lfb_base = config.arch_config.screen_base as _; self.screen_info.lfb_width = width as _; diff --git a/src/arch/x86_64/graphics.rs b/src/arch/x86_64/graphics.rs index af5453d8..2097e401 100644 --- a/src/arch/x86_64/graphics.rs +++ b/src/arch/x86_64/graphics.rs @@ -85,15 +85,28 @@ pub fn font_init(psf: &'static [u8]) { }); let framebuffer = &get_multiboot_tags().framebuffer; + let mid_addr = framebuffer.addr + + (framebuffer.width as u64) + * ((framebuffer.height as u64) / 2) + * ((framebuffer.bpp as u64) / 8); FRAMEBUFFER_INFO.call_once(|| { Mutex::new(FramebufferInfo { cursor_x: 0, cursor_y: 0, max_char_nr_x: (framebuffer.width / font_width) as _, + #[cfg(not(feature = "split_screen"))] max_char_nr_y: (framebuffer.height / psf_header.height) as _, + #[cfg(all(feature = "split_screen"))] + max_char_nr_y: (framebuffer.height / 2 / psf_header.height) as _, + #[cfg(not(feature = "split_screen"))] addr: framebuffer.addr as _, + #[cfg(all(feature = "split_screen"))] + addr: mid_addr as _, width: framebuffer.width as _, + #[cfg(not(feature = "split_screen"))] height: framebuffer.height as _, + #[cfg(all(feature = "split_screen"))] + height: (framebuffer.height / 2) as _, }) }); diff --git a/src/arch/x86_64/pio.rs b/src/arch/x86_64/pio.rs index feee7537..f89a5564 100644 --- a/src/arch/x86_64/pio.rs +++ b/src/arch/x86_64/pio.rs @@ -88,10 +88,10 @@ impl PortIoBitmap { bitmap.set_range_intercept(PCI_CONFIG_ADDR_PORT, true); bitmap.set_range_intercept(PCI_CONFIG_DATA_PORT, true); - if zone_id == 0 { - #[cfg(feature = "graphics")] - bitmap.set_range_intercept(UART_COM1_PORT, true); - } + // if zone_id == 0 { + #[cfg(feature = "graphics")] + bitmap.set_range_intercept(UART_COM1_PORT, true); + // } // i8042, we won't use it, but intercept its ports might block linux init bitmap.set_range_intercept(0x60..0x65, false); From 3f8c1daf5f5d65c2346e32172c24fefeb0924c73 Mon Sep 17 00:00:00 2001 From: Solicey Date: Tue, 20 Jan 2026 23:07:45 +0800 Subject: [PATCH 100/109] Merge branch 'new_pcie' into dev-x86_64 --- platform/aarch64/rk3568/board.rs | 30 ++++--- platform/loongarch64/ls3a5000/board.rs | 76 +++++++++-------- platform/loongarch64/ls3a6000/board.rs | 81 +++++++++---------- platform/riscv64/hifive-premier-p550/board.rs | 8 +- platform/riscv64/qemu-aia/board.rs | 3 +- platform/x86_64/qemu/board.rs | 14 ++-- platform/x86_64/qemu/cargo/features | 3 +- src/pci/pci_access.rs | 2 +- 8 files changed, 106 insertions(+), 111 deletions(-) diff --git a/platform/aarch64/rk3568/board.rs b/platform/aarch64/rk3568/board.rs index 120370f3..32ed5d3c 100644 --- a/platform/aarch64/rk3568/board.rs +++ b/platform/aarch64/rk3568/board.rs @@ -14,6 +14,7 @@ // Authors: // +use crate::pci_dev; use crate::{ arch::{ mmu::MemoryType, @@ -22,7 +23,6 @@ use crate::{ config::*, pci::vpci_dev::VpciDevType, }; -use crate::pci_dev; pub const BOARD_NAME: &str = "rk3568"; @@ -50,8 +50,8 @@ pub const BOARD_PHYSMEM_LIST: &[(u64, u64, MemoryType)] = &[ ]; pub const ROOT_ZONE_DTB_ADDR: u64 = 0xa0000000; -pub const ROOT_ZONE_KERNEL_ADDR: u64 = 0x00280000 ; -pub const ROOT_ZONE_ENTRY: u64 = 0x00280000 ; +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); @@ -339,20 +339,18 @@ pub const ROOT_PCI_CONFIG: &[HvPciConfig] = &[ pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; -pub const ROOT_DWC_ATU_CONFIG: &[HvDwcAtuConfig] = &[ - HvDwcAtuConfig { - ecam_base: 0x3c0400000, - dbi_base: 0x3c0400000, - dbi_size: 0x10000, - apb_base: 0xfe270000, - apb_size: 0x10000, - cfg_base: 0xf2000000, - cfg_size: 0x80000*2, - io_cfg_atu_shared: 0, - }, -]; +pub const ROOT_DWC_ATU_CONFIG: &[HvDwcAtuConfig] = &[HvDwcAtuConfig { + ecam_base: 0x3c0400000, + dbi_base: 0x3c0400000, + dbi_size: 0x10000, + apb_base: 0xfe270000, + apb_size: 0x10000, + cfg_base: 0xf2000000, + cfg_size: 0x80000 * 2, + io_cfg_atu_shared: 0, +}]; pub const ROOT_PCI_DEVS: [HvPciDevConfig; 2] = [ pci_dev!(0x0, 0x00, 0x0, 0x0, VpciDevType::Physical), pci_dev!(0x0, 0x01, 0x0, 0x0, VpciDevType::Physical), -]; \ No newline at end of file +]; diff --git a/platform/loongarch64/ls3a5000/board.rs b/platform/loongarch64/ls3a5000/board.rs index b373f9b7..541d73a8 100644 --- a/platform/loongarch64/ls3a5000/board.rs +++ b/platform/loongarch64/ls3a5000/board.rs @@ -14,8 +14,8 @@ // Authors: // Yulong Han // -use crate::{arch::zone::HvArchZoneConfig, config::*, pci::vpci_dev::VpciDevType}; use crate::pci_dev; +use crate::{arch::zone::HvArchZoneConfig, config::*, pci::vpci_dev::VpciDevType}; pub const BOARD_NAME: &str = "ls3a5000"; @@ -156,24 +156,22 @@ pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { dummy: 0 }; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; -pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ - 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: 0x30000000, - pci_mem64_base: 0x60000000, - bus_range_begin: 0, - bus_range_end: 0xff, - domain: 0x0, - } -]; +pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [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: 0x30000000, + pci_mem64_base: 0x60000000, + bus_range_begin: 0, + bus_range_end: 0xff, + domain: 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 */ @@ -185,36 +183,34 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ /* BUS 6 on X4 slot */ /* 06:00.0, 06:00.1, 06:00.2, 06:00.3 net */ pub const ROOT_PCI_DEVS: &[HvPciDevConfig] = &[ - pci_dev!(0x0, 0x0, 0x0, 0x0, VpciDevType::Physical), // 00:00.0 - pci_dev!(0x0, 0x0, 0x0, 0x1, VpciDevType::Physical), // 00:00.1 - pci_dev!(0x0, 0x0, 0x0, 0x2, VpciDevType::Physical), // 00:00.2 - pci_dev!(0x0, 0x0, 0x0, 0x3, VpciDevType::Physical), // 00:00.3 - pci_dev!(0x0, 0x0, 0x4, 0x0, VpciDevType::Physical), // 00:04.0 - pci_dev!(0x0, 0x0, 0x4, 0x1, VpciDevType::Physical), // 00:04.1 - pci_dev!(0x0, 0x0, 0x5, 0x0, VpciDevType::Physical), // 00:05.0 - pci_dev!(0x0, 0x0, 0x5, 0x1, VpciDevType::Physical), // 00:05.1 + pci_dev!(0x0, 0x0, 0x0, 0x0, VpciDevType::Physical), // 00:00.0 + pci_dev!(0x0, 0x0, 0x0, 0x1, VpciDevType::Physical), // 00:00.1 + pci_dev!(0x0, 0x0, 0x0, 0x2, VpciDevType::Physical), // 00:00.2 + pci_dev!(0x0, 0x0, 0x0, 0x3, VpciDevType::Physical), // 00:00.3 + pci_dev!(0x0, 0x0, 0x4, 0x0, VpciDevType::Physical), // 00:04.0 + pci_dev!(0x0, 0x0, 0x4, 0x1, VpciDevType::Physical), // 00:04.1 + pci_dev!(0x0, 0x0, 0x5, 0x0, VpciDevType::Physical), // 00:05.0 + pci_dev!(0x0, 0x0, 0x5, 0x1, VpciDevType::Physical), // 00:05.1 // pci_dev!(0x0, 0x0, 0x6, 0x0, VpciDevType::Physical), // 00:06.0 // pci_dev!(0x0, 0x0, 0x6, 0x1, VpciDevType::Physical), // 00:06.1 // pci_dev!(0x0, 0x0, 0x6, 0x2, VpciDevType::Physical), // 00:06.2 - pci_dev!(0x0, 0x0, 0x7, 0x0, VpciDevType::Physical), // 00:07.0 - pci_dev!(0x0, 0x0, 0x8, 0x0, VpciDevType::Physical), // 00:08.0 - pci_dev!(0x0, 0x0, 0x9, 0x0, VpciDevType::Physical), // 00:09.0 - pci_dev!(0x0, 0x0, 0xa, 0x0, VpciDevType::Physical), // 00:0a.0 - pci_dev!(0x0, 0x0, 0xb, 0x0, VpciDevType::Physical), // 00:0b.0 - pci_dev!(0x0, 0x0, 0xc, 0x0, VpciDevType::Physical), // 00:0c.0 - pci_dev!(0x0, 0x0, 0xd, 0x0, VpciDevType::Physical), // 00:0d.0 - pci_dev!(0x0, 0x0, 0xf, 0x0, VpciDevType::Physical), // 00:0f.0 + pci_dev!(0x0, 0x0, 0x7, 0x0, VpciDevType::Physical), // 00:07.0 + pci_dev!(0x0, 0x0, 0x8, 0x0, VpciDevType::Physical), // 00:08.0 + pci_dev!(0x0, 0x0, 0x9, 0x0, VpciDevType::Physical), // 00:09.0 + pci_dev!(0x0, 0x0, 0xa, 0x0, VpciDevType::Physical), // 00:0a.0 + pci_dev!(0x0, 0x0, 0xb, 0x0, VpciDevType::Physical), // 00:0b.0 + pci_dev!(0x0, 0x0, 0xc, 0x0, VpciDevType::Physical), // 00:0c.0 + pci_dev!(0x0, 0x0, 0xd, 0x0, VpciDevType::Physical), // 00:0d.0 + pci_dev!(0x0, 0x0, 0xf, 0x0, VpciDevType::Physical), // 00:0f.0 pci_dev!(0x0, 0x0, 0x10, 0x0, VpciDevType::Physical), // 00:10.0 pci_dev!(0x0, 0x0, 0x13, 0x0, VpciDevType::Physical), // 00:13.0 pci_dev!(0x0, 0x0, 0x16, 0x0, VpciDevType::Physical), // 00:16.0 pci_dev!(0x0, 0x0, 0x19, 0x0, VpciDevType::Physical), // 00:19.0 - pci_dev!(0x0, 0x2, 0x0, 0x0, VpciDevType::Physical), // 02:00.0 - pci_dev!(0x0, 0x5, 0x0, 0x0, VpciDevType::Physical), // 05:00.0 - pci_dev!(0x0, 0x6, 0x0, 0x0, VpciDevType::Physical), // 06:00.0 + pci_dev!(0x0, 0x2, 0x0, 0x0, VpciDevType::Physical), // 02:00.0 + pci_dev!(0x0, 0x5, 0x0, 0x0, VpciDevType::Physical), // 05:00.0 + pci_dev!(0x0, 0x6, 0x0, 0x0, VpciDevType::Physical), // 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 8e99e9fa..6bd74afa 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -14,8 +14,8 @@ // Authors: // Yulong Han // -use crate::{arch::zone::HvArchZoneConfig, config::*, pci::vpci_dev::VpciDevType}; use crate::pci_dev; +use crate::{arch::zone::HvArchZoneConfig, config::*, pci::vpci_dev::VpciDevType}; pub const BOARD_NAME: &str = "ls3a5000"; @@ -156,24 +156,22 @@ pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[]); pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { dummy: 0 }; pub const ROOT_ZONE_IVC_CONFIG: [HvIvcConfig; 0] = []; -pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ - HvPciConfig { - bus_range_begin: 0x0, - bus_range_end: 0x1f, - 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, - domain: 0x0, - } -]; +pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { + bus_range_begin: 0x0, + bus_range_end: 0x1f, + 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, + domain: 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 */ @@ -185,35 +183,34 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [ /* BUS 6 on X4 slot */ /* 06:00.0, 06:00.1, 06:00.2, 06:00.3 net */ pub const ROOT_PCI_DEVS: [HvPciDevConfig; 26] = [ - pci_dev!(0x0, 0x0, 0x0, 0x0, VpciDevType::Physical), // 00:00.0 - pci_dev!(0x0, 0x0, 0x0, 0x1, VpciDevType::Physical), // 00:00.1 - pci_dev!(0x0, 0x0, 0x0, 0x2, VpciDevType::Physical), // 00:00.2 - pci_dev!(0x0, 0x0, 0x0, 0x3, VpciDevType::Physical), // 00:00.3 - pci_dev!(0x0, 0x0, 0x4, 0x0, VpciDevType::Physical), // 00:04.0 - pci_dev!(0x0, 0x0, 0x4, 0x1, VpciDevType::Physical), // 00:04.1 - pci_dev!(0x0, 0x0, 0x5, 0x0, VpciDevType::Physical), // 00:05.0 - pci_dev!(0x0, 0x0, 0x5, 0x1, VpciDevType::Physical), // 00:05.1 - pci_dev!(0x0, 0x0, 0x6, 0x0, VpciDevType::Physical), // 00:06.0 - pci_dev!(0x0, 0x0, 0x6, 0x1, VpciDevType::Physical), // 00:06.1 - pci_dev!(0x0, 0x0, 0x6, 0x2, VpciDevType::Physical), // 00:06.2 - pci_dev!(0x0, 0x0, 0x7, 0x0, VpciDevType::Physical), // 00:07.0 - pci_dev!(0x0, 0x0, 0x8, 0x0, VpciDevType::Physical), // 00:08.0 - pci_dev!(0x0, 0x0, 0x9, 0x0, VpciDevType::Physical), // 00:09.0 - pci_dev!(0x0, 0x0, 0xa, 0x0, VpciDevType::Physical), // 00:0a.0 - pci_dev!(0x0, 0x0, 0xb, 0x0, VpciDevType::Physical), // 00:0b.0 - pci_dev!(0x0, 0x0, 0xc, 0x0, VpciDevType::Physical), // 00:0c.0 - pci_dev!(0x0, 0x0, 0xd, 0x0, VpciDevType::Physical), // 00:0d.0 - pci_dev!(0x0, 0x0, 0xf, 0x0, VpciDevType::Physical), // 00:0f.0 + pci_dev!(0x0, 0x0, 0x0, 0x0, VpciDevType::Physical), // 00:00.0 + pci_dev!(0x0, 0x0, 0x0, 0x1, VpciDevType::Physical), // 00:00.1 + pci_dev!(0x0, 0x0, 0x0, 0x2, VpciDevType::Physical), // 00:00.2 + pci_dev!(0x0, 0x0, 0x0, 0x3, VpciDevType::Physical), // 00:00.3 + pci_dev!(0x0, 0x0, 0x4, 0x0, VpciDevType::Physical), // 00:04.0 + pci_dev!(0x0, 0x0, 0x4, 0x1, VpciDevType::Physical), // 00:04.1 + pci_dev!(0x0, 0x0, 0x5, 0x0, VpciDevType::Physical), // 00:05.0 + pci_dev!(0x0, 0x0, 0x5, 0x1, VpciDevType::Physical), // 00:05.1 + pci_dev!(0x0, 0x0, 0x6, 0x0, VpciDevType::Physical), // 00:06.0 + pci_dev!(0x0, 0x0, 0x6, 0x1, VpciDevType::Physical), // 00:06.1 + pci_dev!(0x0, 0x0, 0x6, 0x2, VpciDevType::Physical), // 00:06.2 + pci_dev!(0x0, 0x0, 0x7, 0x0, VpciDevType::Physical), // 00:07.0 + pci_dev!(0x0, 0x0, 0x8, 0x0, VpciDevType::Physical), // 00:08.0 + pci_dev!(0x0, 0x0, 0x9, 0x0, VpciDevType::Physical), // 00:09.0 + pci_dev!(0x0, 0x0, 0xa, 0x0, VpciDevType::Physical), // 00:0a.0 + pci_dev!(0x0, 0x0, 0xb, 0x0, VpciDevType::Physical), // 00:0b.0 + pci_dev!(0x0, 0x0, 0xc, 0x0, VpciDevType::Physical), // 00:0c.0 + pci_dev!(0x0, 0x0, 0xd, 0x0, VpciDevType::Physical), // 00:0d.0 + pci_dev!(0x0, 0x0, 0xf, 0x0, VpciDevType::Physical), // 00:0f.0 pci_dev!(0x0, 0x0, 0x10, 0x0, VpciDevType::Physical), // 00:10.0 pci_dev!(0x0, 0x0, 0x13, 0x0, VpciDevType::Physical), // 00:13.0 pci_dev!(0x0, 0x0, 0x16, 0x0, VpciDevType::Physical), // 00:16.0 pci_dev!(0x0, 0x0, 0x19, 0x0, VpciDevType::Physical), // 00:19.0 - pci_dev!(0x0, 0x2, 0x0, 0x0, VpciDevType::Physical), // 02:00.0 - pci_dev!(0x0, 0x5, 0x0, 0x0, VpciDevType::Physical), // 05:00.0 - pci_dev!(0x0, 0x6, 0x0, 0x0, VpciDevType::Physical), // 06:00.0 + pci_dev!(0x0, 0x2, 0x0, 0x0, VpciDevType::Physical), // 02:00.0 + pci_dev!(0x0, 0x5, 0x0, 0x0, VpciDevType::Physical), // 05:00.0 + pci_dev!(0x0, 0x6, 0x0, 0x0, VpciDevType::Physical), // 06:00.0 ]; - // bus << 8 | dev << 5 | func << 3 // pub const ROOT_PCI_DEVS: [u64; 0] = []; diff --git a/platform/riscv64/hifive-premier-p550/board.rs b/platform/riscv64/hifive-premier-p550/board.rs index 06e6d03c..4424db5d 100644 --- a/platform/riscv64/hifive-premier-p550/board.rs +++ b/platform/riscv64/hifive-premier-p550/board.rs @@ -155,7 +155,7 @@ pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 0x20; // Note: all here's irqs are hardware irqs, // only these irq can be transferred to the physical PLIC. pub const HW_IRQS: [u32; 21] = [ - 0x1, 0x2, 0x3, 0x4, // cache controller + 0x1, 0x2, 0x3, 0x4, // cache controller 0x4f, // emmc 0x51, // sd-card 0x64, // uart0 @@ -163,17 +163,17 @@ pub const HW_IRQS: [u32; 21] = [ 0x183, // npu 0x75, 0x77, 0x79, 0x7b, 0x7d, 0x7f, 0x81, 0x83, // mailbox 0x123, // i2c - // 0x01, 0x03, 0x04, 0x02, // cache controller + // 0x01, 0x03, 0x04, 0x02, // cache controller ]; // irqs belong to the root zone. pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[ - 0x1, 0x2, 0x3, 0x4, // cache controller + 0x1, 0x2, 0x3, 0x4, // cache controller 0x51, // sd-card 0x64, // uart0 0x164, 0x168, 0x165, 0x166, // iommu 0x183, // npu - 0x75, 0x77, 0x79, 0x7b, 0x7d, 0x7f, 0x81, 0x83, // mailbox + 0x75, 0x77, 0x79, 0x7b, 0x7d, 0x7f, 0x81, 0x83, // mailbox 0x123, // i2c ]); diff --git a/platform/riscv64/qemu-aia/board.rs b/platform/riscv64/qemu-aia/board.rs index 61bab9d6..951d93a6 100644 --- a/platform/riscv64/qemu-aia/board.rs +++ b/platform/riscv64/qemu-aia/board.rs @@ -102,7 +102,8 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 9] = [ pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 0x20; pub const HW_IRQS: [u32; 11] = [1, 2, 3, 4, 5, 8, 10, 33, 34, 35, 36]; -pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[1, 2, 3, 4, 5, 8, 10, 33, 34, 35, 36]); // ARCH= riscv .It doesn't matter temporarily. +pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = + &get_irqs_bitmap(&[1, 2, 3, 4, 5, 8, 10, 33, 34, 35, 36]); // ARCH= riscv .It doesn't matter temporarily. pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { plic_base: 0x0, diff --git a/platform/x86_64/qemu/board.rs b/platform/x86_64/qemu/board.rs index 81885502..8020834a 100644 --- a/platform/x86_64/qemu/board.rs +++ b/platform/x86_64/qemu/board.rs @@ -14,7 +14,9 @@ // Authors: // use crate::pci_dev; -use crate::{arch::zone::HvArchZoneConfig, config::*, memory::GuestPhysAddr, pci::vpci_dev::VpciDevType}; +use crate::{ + arch::zone::HvArchZoneConfig, config::*, memory::GuestPhysAddr, pci::vpci_dev::VpciDevType, +}; pub const MEM_TYPE_RESERVED: u32 = 5; @@ -148,14 +150,14 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [HvPciConfig { pub const ROOT_PCI_MAX_BUS: usize = 1; pub const ROOT_PCI_DEVS: [HvPciDevConfig; 8] = [ - pci_dev!(0x0, 0x0, 0x0, 0x0, VpciDevType::Physical), // host bridge - pci_dev!(0x0, 0x0, 0x1, 0x0, VpciDevType::Physical), // VGA controller - pci_dev!(0x0, 0x0, 0x2, 0x0, VpciDevType::Physical), // Ethernet controller - pci_dev!(0x0, 0x0, 0x3, 0x0, VpciDevType::Physical), // PCI bridge + pci_dev!(0x0, 0x0, 0x0, 0x0, VpciDevType::Physical), // host bridge + pci_dev!(0x0, 0x0, 0x1, 0x0, VpciDevType::Physical), // VGA controller + pci_dev!(0x0, 0x0, 0x2, 0x0, VpciDevType::Physical), // Ethernet controller + pci_dev!(0x0, 0x0, 0x3, 0x0, VpciDevType::Physical), // PCI bridge pci_dev!(0x0, 0x0, 0x1f, 0x0, VpciDevType::Physical), // ISA bridge pci_dev!(0x0, 0x0, 0x1f, 0x2, VpciDevType::Physical), // SATA controller pci_dev!(0x0, 0x0, 0x1f, 0x3, VpciDevType::Physical), // SMBus - pci_dev!(0x0, 0x1, 0x0, 0x0, VpciDevType::Physical), // SCSI controller + pci_dev!(0x0, 0x1, 0x0, 0x0, VpciDevType::Physical), // SCSI controller ]; #[cfg(all(feature = "graphics"))] diff --git a/platform/x86_64/qemu/cargo/features b/platform/x86_64/qemu/cargo/features index f8ee525a..1c961621 100644 --- a/platform/x86_64/qemu/cargo/features +++ b/platform/x86_64/qemu/cargo/features @@ -1,4 +1,5 @@ pci ecam_pcie no_pcie_bar_realloc -uart16550a \ No newline at end of file +uart16550a +iommu \ No newline at end of file diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index dc891bd9..2646d3c8 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -624,7 +624,7 @@ pub trait PciBarRW: PciRWBase { 1u64 << ((readback_high.trailing_zeros() + 32) as u64) } }; - let value64 = (value as u64) | ((value_high as u64) << 32); + // let value64 = (value as u64) | ((value_high as u64) << 32); bararr[slot as usize] = PciMem::new_bar(PciMemType::Mem64Low, value64, size, pre); From 7b161b76ab37744dc16d0abab99f00c3049d379e Mon Sep 17 00:00:00 2001 From: Solicey Date: Thu, 22 Jan 2026 00:36:12 +0800 Subject: [PATCH 101/109] Merge branch 'percpu-local' into dev-x86_64 --- Cargo.lock | 27 +++++ Cargo.toml | 1 + platform/aarch64/imx8mp/linker.ld | 12 ++ platform/aarch64/ok6254-c/linker.ld | 12 ++ platform/aarch64/phytium-pi/linker.ld | 12 ++ platform/aarch64/qemu-gicv2/linker.ld | 12 ++ platform/aarch64/qemu-gicv3/linker.ld | 12 ++ platform/aarch64/rk3568/linker.ld | 14 ++- platform/aarch64/rk3588/linker.ld | 12 ++ platform/aarch64/zcu102/linker.ld | 12 ++ platform/loongarch64/ls3a5000/linker.ld | 12 ++ platform/loongarch64/ls3a6000/linker.ld | 12 ++ .../riscv64/hifive-premier-p550/linker.ld | 12 ++ platform/riscv64/megrez/linker.ld | 12 ++ platform/riscv64/qemu-aia/linker.ld | 12 ++ platform/riscv64/qemu-plic/linker.ld | 12 ++ platform/x86_64/nuc14mnk/linker.ld | 12 ++ platform/x86_64/qemu/linker.ld | 12 ++ src/arch/aarch64/cpu.rs | 2 +- src/arch/aarch64/hypercall.rs | 2 +- src/arch/aarch64/trap.rs | 2 +- src/arch/loongarch64/cpu.rs | 2 +- src/arch/loongarch64/trap.rs | 2 +- src/arch/riscv64/sbi.rs | 4 +- src/arch/riscv64/trap.rs | 2 + src/arch/riscv64/zone.rs | 4 +- src/arch/x86_64/acpi.rs | 2 +- src/arch/x86_64/boot.rs | 2 +- src/arch/x86_64/cpu.rs | 4 +- src/arch/x86_64/hypercall.rs | 2 +- src/arch/x86_64/ipi.rs | 2 +- src/arch/x86_64/mmio.rs | 2 +- src/arch/x86_64/pci.rs | 2 +- src/arch/x86_64/s2pt.rs | 2 +- src/arch/x86_64/trap.rs | 2 +- src/arch/x86_64/zone.rs | 2 +- src/{percpu.rs => cpu_data.rs} | 0 src/device/irqchip/aia/aplic.rs | 2 +- src/device/irqchip/aia/mod.rs | 2 +- src/device/irqchip/aia/vaplic.rs | 2 +- src/device/irqchip/gicv2/vgic.rs | 2 +- src/device/irqchip/gicv3/gits.rs | 2 +- src/device/irqchip/gicv3/vgic.rs | 2 +- src/device/irqchip/pic/lapic.rs | 2 +- src/event.rs | 104 ++++++------------ src/hypercall/mod.rs | 1 - src/logging.rs | 2 +- src/main.rs | 7 +- src/memory/mmio.rs | 2 +- src/pci/pci_handler.rs | 2 +- src/pci/pci_test.rs | 2 +- src/pci/vpci_dev/standard.rs | 2 +- src/zone.rs | 2 +- 53 files changed, 295 insertions(+), 107 deletions(-) rename src/{percpu.rs => cpu_data.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index 43a258fc..98b19c05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -175,6 +175,7 @@ dependencies = [ "log", "loongArch64", "numeric-enum-macro", + "percpu", "psci", "qemu-exit", "raw-cpuid", @@ -246,6 +247,29 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "percpu" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01e56c0c558952222967b592899f98765b48590e7bd7403bfd7075f73afc6ed6" +dependencies = [ + "cfg-if", + "percpu_macros", + "spin 0.9.8", + "x86", +] + +[[package]] +name = "percpu_macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9f4cc54a2e471ff72f1499461ba381ad4eae9cbd60d29c258545b995e406e0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "proc-macro2" version = "1.0.103" @@ -477,6 +501,9 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] name = "spin" diff --git a/Cargo.toml b/Cargo.toml index 949a646c..978406c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ cortex-a = "8.1.1" cfg-if = "1.0" bitvec = { version="1.0.1", default-features = false, features = ["atomic", "alloc"] } heapless = { version = "0.8.0 "} +percpu = { package = "percpu", version="0.2", features=["arm-el2"]} [target.'cfg(target_arch = "aarch64")'.dependencies] aarch64-cpu = "9.4.0" diff --git a/platform/aarch64/imx8mp/linker.ld b/platform/aarch64/imx8mp/linker.ld index 0f5e41f3..f8c4a9eb 100644 --- a/platform/aarch64/imx8mp/linker.ld +++ b/platform/aarch64/imx8mp/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x40400000; +CPU_NUM = 4; SECTIONS { @@ -37,6 +38,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/ok6254-c/linker.ld b/platform/aarch64/ok6254-c/linker.ld index c3c0b34a..4da975bb 100644 --- a/platform/aarch64/ok6254-c/linker.ld +++ b/platform/aarch64/ok6254-c/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80400000; +CPU_NUM = 4; SECTIONS { @@ -37,6 +38,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/phytium-pi/linker.ld b/platform/aarch64/phytium-pi/linker.ld index bc718226..1438cfec 100644 --- a/platform/aarch64/phytium-pi/linker.ld +++ b/platform/aarch64/phytium-pi/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x90100000; +CPU_NUM = 4; SECTIONS { @@ -37,6 +38,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/qemu-gicv2/linker.ld b/platform/aarch64/qemu-gicv2/linker.ld index 0f5e41f3..f8c4a9eb 100644 --- a/platform/aarch64/qemu-gicv2/linker.ld +++ b/platform/aarch64/qemu-gicv2/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x40400000; +CPU_NUM = 4; SECTIONS { @@ -37,6 +38,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/qemu-gicv3/linker.ld b/platform/aarch64/qemu-gicv3/linker.ld index 0f5e41f3..f8c4a9eb 100644 --- a/platform/aarch64/qemu-gicv3/linker.ld +++ b/platform/aarch64/qemu-gicv3/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x40400000; +CPU_NUM = 4; SECTIONS { @@ -37,6 +38,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/rk3568/linker.ld b/platform/aarch64/rk3568/linker.ld index 26e135cd..0c741e0c 100644 --- a/platform/aarch64/rk3568/linker.ld +++ b/platform/aarch64/rk3568/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) -BASE_ADDRESS = 0x60080000; +BASE_ADDRESS = 0x00480000; +CPU_NUM = 4; SECTIONS { @@ -42,6 +43,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/rk3588/linker.ld b/platform/aarch64/rk3588/linker.ld index 40a2ee2a..b287362b 100644 --- a/platform/aarch64/rk3588/linker.ld +++ b/platform/aarch64/rk3588/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x500000; +CPU_NUM = 8; SECTIONS { @@ -41,6 +42,17 @@ SECTIONS *(.bss .bss.*) *(.sbss .sbss.*) } + + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; . = ALIGN(4K); ebss = .; diff --git a/platform/aarch64/zcu102/linker.ld b/platform/aarch64/zcu102/linker.ld index 0f5e41f3..f8c4a9eb 100644 --- a/platform/aarch64/zcu102/linker.ld +++ b/platform/aarch64/zcu102/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x40400000; +CPU_NUM = 4; SECTIONS { @@ -37,6 +38,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/loongarch64/ls3a5000/linker.ld b/platform/loongarch64/ls3a5000/linker.ld index 6ca259e4..a226494f 100644 --- a/platform/loongarch64/ls3a5000/linker.ld +++ b/platform/loongarch64/ls3a5000/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x90000001f0000000; +CPU_NUM = 4; SECTIONS @@ -46,6 +47,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; diff --git a/platform/loongarch64/ls3a6000/linker.ld b/platform/loongarch64/ls3a6000/linker.ld index 6ca259e4..a226494f 100644 --- a/platform/loongarch64/ls3a6000/linker.ld +++ b/platform/loongarch64/ls3a6000/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x90000001f0000000; +CPU_NUM = 4; SECTIONS @@ -46,6 +47,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; diff --git a/platform/riscv64/hifive-premier-p550/linker.ld b/platform/riscv64/hifive-premier-p550/linker.ld index b1ec2354..6f2d2083 100644 --- a/platform/riscv64/hifive-premier-p550/linker.ld +++ b/platform/riscv64/hifive-premier-p550/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80200000; +CPU_NUM = 4; SECTIONS @@ -38,6 +39,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/riscv64/megrez/linker.ld b/platform/riscv64/megrez/linker.ld index b1ec2354..6f2d2083 100644 --- a/platform/riscv64/megrez/linker.ld +++ b/platform/riscv64/megrez/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80200000; +CPU_NUM = 4; SECTIONS @@ -38,6 +39,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/riscv64/qemu-aia/linker.ld b/platform/riscv64/qemu-aia/linker.ld index b1ec2354..6f2d2083 100644 --- a/platform/riscv64/qemu-aia/linker.ld +++ b/platform/riscv64/qemu-aia/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80200000; +CPU_NUM = 4; SECTIONS @@ -38,6 +39,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/riscv64/qemu-plic/linker.ld b/platform/riscv64/qemu-plic/linker.ld index b1ec2354..6f2d2083 100644 --- a/platform/riscv64/qemu-plic/linker.ld +++ b/platform/riscv64/qemu-plic/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80200000; +CPU_NUM = 4; SECTIONS @@ -38,6 +39,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/x86_64/nuc14mnk/linker.ld b/platform/x86_64/nuc14mnk/linker.ld index 11ae57fd..3fc54b77 100644 --- a/platform/x86_64/nuc14mnk/linker.ld +++ b/platform/x86_64/nuc14mnk/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0xffffff8000200000; +CPU_NUM = 4; SECTIONS { @@ -41,6 +42,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/x86_64/qemu/linker.ld b/platform/x86_64/qemu/linker.ld index 11ae57fd..3fc54b77 100644 --- a/platform/x86_64/qemu/linker.ld +++ b/platform/x86_64/qemu/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0xffffff8000200000; +CPU_NUM = 4; SECTIONS { @@ -41,6 +42,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/src/arch/aarch64/cpu.rs b/src/arch/aarch64/cpu.rs index 3f7e3676..9dc5357b 100644 --- a/src/arch/aarch64/cpu.rs +++ b/src/arch/aarch64/cpu.rs @@ -20,7 +20,7 @@ use crate::{ addr::PHYS_VIRT_OFFSET, mm::PARKING_MEMORY_SET, GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, VirtAddr, PARKING_INST_PAGE, }, - percpu::this_cpu_data, + cpu_data::this_cpu_data, platform::BOARD_MPIDR_MAPPINGS, zone::find_zone, }; diff --git a/src/arch/aarch64/hypercall.rs b/src/arch/aarch64/hypercall.rs index 91e59485..99bdfcbc 100644 --- a/src/arch/aarch64/hypercall.rs +++ b/src/arch/aarch64/hypercall.rs @@ -20,7 +20,7 @@ use crate::config::{HvZoneConfig, CONFIG_MAGIC_VERSION}; use crate::device::virtio_trampoline::MAX_DEVS; use crate::hypercall::HyperCall; use crate::hypercall::HyperCallResult; -use crate::percpu::this_zone; +use crate::cpu_data::this_zone; use crate::zone::this_zone_id; impl<'a> HyperCall<'a> { diff --git a/src/arch/aarch64/trap.rs b/src/arch/aarch64/trap.rs index e49146e0..8d25527e 100644 --- a/src/arch/aarch64/trap.rs +++ b/src/arch/aarch64/trap.rs @@ -28,7 +28,7 @@ use crate::{ event::{send_event, IPI_EVENT_SHUTDOWN, IPI_EVENT_WAKEUP}, hypercall::{HyperCall, SGI_IPI_ID}, memory::{mmio_handle_access, MMIOAccess}, - percpu::{get_cpu_data, this_cpu_data, this_zone}, + cpu_data::{get_cpu_data, this_cpu_data, this_zone}, zone::{is_this_root_zone, remove_zone}, }; diff --git a/src/arch/loongarch64/cpu.rs b/src/arch/loongarch64/cpu.rs index 625e43c4..3e00ec1d 100644 --- a/src/arch/loongarch64/cpu.rs +++ b/src/arch/loongarch64/cpu.rs @@ -18,7 +18,7 @@ use super::ipi::*; use super::zone::ZoneContext; use crate::arch::zone::disable_hwi_through; use crate::device::common::MMIODerefWrapper; -use crate::percpu::this_cpu_data; +use crate::cpu_data::this_cpu_data; use crate::zone::find_zone; use core::arch::asm; use core::fmt::{self, Debug, Formatter}; diff --git a/src/arch/loongarch64/trap.rs b/src/arch/loongarch64/trap.rs index d16e1c81..a748c2e2 100644 --- a/src/arch/loongarch64/trap.rs +++ b/src/arch/loongarch64/trap.rs @@ -25,7 +25,7 @@ use crate::device::irqchip::ls7a2000::chip::*; use crate::event::{check_events, dump_cpu_events, dump_events}; use crate::hypercall::{SGI_IPI_ID, *}; use crate::memory::{addr, mmio_handle_access, MMIOAccess}; -use crate::percpu::this_cpu_data; +use crate::cpu_data::this_cpu_data; use crate::zone::Zone; use crate::PHY_TO_DMW_UNCACHED; use core::arch; diff --git a/src/arch/riscv64/sbi.rs b/src/arch/riscv64/sbi.rs index 04492318..9f00f93b 100644 --- a/src/arch/riscv64/sbi.rs +++ b/src/arch/riscv64/sbi.rs @@ -19,10 +19,10 @@ use super::cpu::ArchCpu; use crate::arch::cpu::hartid_to_cpuid; use crate::arch::csr::*; use crate::consts::IPI_EVENT_SEND_IPI; +use crate::cpu_data::{get_cpu_data, this_cpu_data}; use crate::event::{send_event, IPI_EVENT_WAKEUP}; use crate::hypercall::HyperCall; -use crate::percpu::{get_cpu_data, this_cpu_data}; -use core::sync::atomic; +use core::sync::atomic::{self, Ordering}; use riscv::register::sie; use riscv_h::register::hvip; use sbi_rt::{HartMask, SbiRet}; diff --git a/src/arch/riscv64/trap.rs b/src/arch/riscv64/trap.rs index 99277f72..96ea3e60 100644 --- a/src/arch/riscv64/trap.rs +++ b/src/arch/riscv64/trap.rs @@ -20,6 +20,8 @@ use crate::device::irqchip::plic::{inject_irq, plic_get_hwirq}; use crate::event::check_events; use crate::memory::GuestPhysAddr; use crate::memory::{mmio_handle_access, MMIOAccess}; +use crate::memory::{GuestPhysAddr, HostPhysAddr}; +use crate::platform::__board::*; use core::arch::{asm, global_asm}; use riscv::register::stvec::TrapMode; use riscv::register::{sie, stvec}; diff --git a/src/arch/riscv64/zone.rs b/src/arch/riscv64/zone.rs index 1f53e97d..55f9d99f 100644 --- a/src/arch/riscv64/zone.rs +++ b/src/arch/riscv64/zone.rs @@ -15,9 +15,11 @@ // use crate::{ config::*, + cpu_data::get_cpu_data, device::virtio_trampoline::mmio_virtio_handler, error::HvResult, - memory::{GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion}, + memory::{addr::align_up, GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet}, + pci::pcibar::BarRegion, zone::Zone, }; impl Zone { diff --git a/src/arch/x86_64/acpi.rs b/src/arch/x86_64/acpi.rs index 4bfdc530..701b5dff 100644 --- a/src/arch/x86_64/acpi.rs +++ b/src/arch/x86_64/acpi.rs @@ -17,8 +17,8 @@ use crate::{ arch::boot, config::{HvConfigMemoryRegion, HvZoneConfig}, + cpu_data::{this_zone, CpuSet}, error::HvResult, - percpu::{this_zone, CpuSet}, platform::ROOT_PCI_MAX_BUS, }; use acpi::{ diff --git a/src/arch/x86_64/boot.rs b/src/arch/x86_64/boot.rs index 8e8c90b2..631b7749 100644 --- a/src/arch/x86_64/boot.rs +++ b/src/arch/x86_64/boot.rs @@ -20,7 +20,7 @@ use crate::{ consts::PAGE_SIZE, error::HvResult, memory::{GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet}, - percpu::this_zone, + cpu_data::this_zone, platform::MEM_TYPE_RESERVED, }; use alloc::string::{String, ToString}; diff --git a/src/arch/x86_64/cpu.rs b/src/arch/x86_64/cpu.rs index 4610cc5f..57a6ffaa 100644 --- a/src/arch/x86_64/cpu.rs +++ b/src/arch/x86_64/cpu.rs @@ -30,6 +30,7 @@ use crate::{ vmx::*, }, consts::{self, core_end, PER_CPU_SIZE}, + cpu_data::{this_cpu_data, this_zone}, device::irqchip::pic::{check_pending_vectors, clear_vectors, ioapic, lapic::VirtLocalApic}, error::{HvError, HvResult}, memory::{ @@ -38,8 +39,7 @@ use crate::{ Frame, GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, PhysAddr, PAGE_SIZE, PARKING_INST_PAGE, }, - percpu::{this_cpu_data, this_zone}, - platform::ROOT_ZONE_BOOT_STACK, + platform::{ROOT_ZONE_BOOT_STACK, ROOT_ZONE_CMDLINE}, zone::{find_zone, this_zone_id}, }; use alloc::boxed::Box; diff --git a/src/arch/x86_64/hypercall.rs b/src/arch/x86_64/hypercall.rs index cb5517f1..598a8147 100644 --- a/src/arch/x86_64/hypercall.rs +++ b/src/arch/x86_64/hypercall.rs @@ -19,7 +19,7 @@ use crate::{ config::CONFIG_MAGIC_VERSION, device::virtio_trampoline::MAX_DEVS, hypercall::{HyperCall, HyperCallResult}, - percpu::this_zone, + cpu_data::this_zone, zone::{Zone, ZoneInfo}, }; use spin::RwLock; diff --git a/src/arch/x86_64/ipi.rs b/src/arch/x86_64/ipi.rs index b8c20de5..e8aba3e6 100644 --- a/src/arch/x86_64/ipi.rs +++ b/src/arch/x86_64/ipi.rs @@ -24,7 +24,7 @@ use crate::{ error::HvResult, event, hypercall::SGI_IPI_ID, - percpu::{this_cpu_data, this_zone, CpuSet}, + cpu_data::{this_cpu_data, this_zone, CpuSet}, }; use alloc::{collections::vec_deque::VecDeque, vec::Vec}; use bit_field::BitField; diff --git a/src/arch/x86_64/mmio.rs b/src/arch/x86_64/mmio.rs index 2b7681c4..abeb2ad1 100644 --- a/src/arch/x86_64/mmio.rs +++ b/src/arch/x86_64/mmio.rs @@ -24,7 +24,7 @@ use crate::{ addr::{GuestPhysAddr, GuestVirtAddr, HostPhysAddr}, MMIOAccess, MMIOHandler, }, - percpu::{this_cpu_data, this_zone}, + cpu_data::{this_cpu_data, this_zone}, }; use alloc::{sync::Arc, vec::Vec}; use bit_field::BitField; diff --git a/src/arch/x86_64/pci.rs b/src/arch/x86_64/pci.rs index cc05d533..ef173ce8 100644 --- a/src/arch/x86_64/pci.rs +++ b/src/arch/x86_64/pci.rs @@ -16,11 +16,11 @@ use crate::{ arch::{acpi, idt, mmio::MMIoDevice, pio::get_pio_bitmap, zone::HvArchZoneConfig}, + cpu_data::this_zone, error::HvResult, memory::{ mmio_generic_handler, mmio_handle_access, mmio_perform_access, GuestPhysAddr, MMIOAccess, }, - percpu::this_zone, zone::{this_zone_id, Zone}, }; use ::acpi::{mcfg::Mcfg, sdt::Signature}; diff --git a/src/arch/x86_64/s2pt.rs b/src/arch/x86_64/s2pt.rs index 9a4e8e49..2a0377e2 100644 --- a/src/arch/x86_64/s2pt.rs +++ b/src/arch/x86_64/s2pt.rs @@ -26,7 +26,7 @@ use crate::{ addr::{GuestPhysAddr, HostPhysAddr, PhysAddr}, MemFlags, }, - percpu::this_cpu_data, + cpu_data::this_cpu_data, zone::this_zone_id, }; use bit_field::BitField; diff --git a/src/arch/x86_64/trap.rs b/src/arch/x86_64/trap.rs index edfbeee9..88eaa3bc 100644 --- a/src/arch/x86_64/trap.rs +++ b/src/arch/x86_64/trap.rs @@ -36,7 +36,7 @@ use crate::{ error::HvResult, hypercall::HyperCall, memory::{mmio_handle_access, MMIOAccess, MemFlags}, - percpu::{this_cpu_data, this_zone}, + cpu_data::{this_cpu_data, this_zone}, zone::this_zone_id, }; use bit_field::BitField; diff --git a/src/arch/x86_64/zone.rs b/src/arch/x86_64/zone.rs index 8c808718..6a3b5f0c 100644 --- a/src/arch/x86_64/zone.rs +++ b/src/arch/x86_64/zone.rs @@ -17,10 +17,10 @@ use crate::{ arch::{acpi, boot, msr::set_msr_bitmap, pio, pio::set_pio_bitmap, Stage2PageTable}, config::*, + cpu_data::get_cpu_data, device::virtio_trampoline::mmio_virtio_handler, error::HvResult, memory::{GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet}, - percpu::get_cpu_data, platform::MEM_TYPE_RESERVED, zone::Zone, }; diff --git a/src/percpu.rs b/src/cpu_data.rs similarity index 100% rename from src/percpu.rs rename to src/cpu_data.rs diff --git a/src/device/irqchip/aia/aplic.rs b/src/device/irqchip/aia/aplic.rs index b92556a3..5c1c967b 100644 --- a/src/device/irqchip/aia/aplic.rs +++ b/src/device/irqchip/aia/aplic.rs @@ -17,7 +17,7 @@ use crate::config::root_zone_config; use crate::device::irqchip::aia::imsic::imsic_trigger; use crate::zone::Zone; -use crate::{arch::cpu::ArchCpu, memory::GuestPhysAddr, percpu::this_cpu_data}; +use crate::{arch::cpu::ArchCpu, memory::GuestPhysAddr, cpu_data::this_cpu_data}; use riscv_decode::Instruction; use spin::Once; use spin::RwLock; diff --git a/src/device/irqchip/aia/mod.rs b/src/device/irqchip/aia/mod.rs index 93b4f5f5..7c5a5337 100644 --- a/src/device/irqchip/aia/mod.rs +++ b/src/device/irqchip/aia/mod.rs @@ -29,7 +29,7 @@ use crate::memory::HostPhysAddr; use crate::memory::MMIOAccess; use crate::memory::MemFlags; use crate::memory::MemoryRegion; -use crate::percpu::this_cpu_data; +use crate::cpu_data::this_cpu_data; use crate::platform::HW_IRQS; use crate::platform::{ BOARD_APLIC_INTERRUPTS_NUM, IMSIC_GUEST_INDEX, IMSIC_GUEST_NUM, IMSIC_S_BASE, diff --git a/src/device/irqchip/aia/vaplic.rs b/src/device/irqchip/aia/vaplic.rs index fdd50405..795b72f1 100644 --- a/src/device/irqchip/aia/vaplic.rs +++ b/src/device/irqchip/aia/vaplic.rs @@ -15,7 +15,7 @@ // use super::*; -use crate::percpu::this_cpu_data; +use crate::cpu_data::this_cpu_data; use alloc::sync::Arc; use alloc::vec::Vec; use bitvec::prelude::*; diff --git a/src/device/irqchip/gicv2/vgic.rs b/src/device/irqchip/gicv2/vgic.rs index 4490ef10..adeead25 100644 --- a/src/device/irqchip/gicv2/vgic.rs +++ b/src/device/irqchip/gicv2/vgic.rs @@ -28,7 +28,7 @@ use crate::device::irqchip::gicv2::gicd::{ use crate::device::irqchip::gicv2::GICV2; use crate::error::HvResult; use crate::memory::{mmio_perform_access, MMIOAccess, MemFlags, MemoryRegion}; -use crate::percpu::this_zone; +use crate::cpu_data::this_zone; /// This file defines and implements the functional functions of virtual gicv2. /// author: ForeverYolo /// reference: diff --git a/src/device/irqchip/gicv3/gits.rs b/src/device/irqchip/gicv3/gits.rs index eb8719f6..4552e281 100644 --- a/src/device/irqchip/gicv3/gits.rs +++ b/src/device/irqchip/gicv3/gits.rs @@ -21,7 +21,7 @@ use spin::{mutex::Mutex, Once, RwLock}; use crate::{ consts::MAX_ZONE_NUM, device::irqchip::gicv3::gicr::enable_one_lpi, memory::Frame, - percpu::this_zone, zone::this_zone_id, + cpu_data::this_zone, zone::this_zone_id, }; use super::host_gits_base; diff --git a/src/device/irqchip/gicv3/vgic.rs b/src/device/irqchip/gicv3/vgic.rs index bd16002b..cfae391b 100644 --- a/src/device/irqchip/gicv3/vgic.rs +++ b/src/device/irqchip/gicv3/vgic.rs @@ -28,7 +28,7 @@ use crate::{ error::HvResult, hypercall::SGI_IPI_ID, memory::{mmio_perform_access, MMIOAccess}, - percpu::{get_cpu_data, this_zone}, + cpu_data::{get_cpu_data, this_zone}, zone::{this_zone_id, Zone}, }; pub fn reg_range(base: usize, n: usize, size: usize) -> core::ops::Range { diff --git a/src/device/irqchip/pic/lapic.rs b/src/device/irqchip/pic/lapic.rs index f5697c3b..97482ada 100644 --- a/src/device/irqchip/pic/lapic.rs +++ b/src/device/irqchip/pic/lapic.rs @@ -24,7 +24,7 @@ use crate::{ device::irqchip::pic::pop_vector, error::HvResult, memory::Frame, - percpu::this_cpu_data, + cpu_data::this_cpu_data, }; use bit_field::BitField; use core::{ops::Range, u32}; diff --git a/src/event.rs b/src/event.rs index 7cec4dee..c7f073d4 100644 --- a/src/event.rs +++ b/src/event.rs @@ -24,92 +24,63 @@ use crate::{ platform::IRQ_WAKEUP_VIRTIO_DEVICE, }; use alloc::{collections::VecDeque, vec::Vec}; -use spin::{Mutex, Once}; +use spin::Mutex; pub const IPI_EVENT_WAKEUP: usize = 0; pub const IPI_EVENT_SHUTDOWN: usize = 1; pub const IPI_EVENT_VIRTIO_INJECT_IRQ: usize = 2; pub const IPI_EVENT_WAKEUP_VIRTIO_DEVICE: usize = 3; -static EVENT_MANAGER: Once = Once::new(); +#[percpu::def_percpu] +static PERCPU_EVENTS: Mutex> = Mutex::new(VecDeque::new()); -struct EventManager { - pub inner: Vec>>, +// The caller ensures the cpu_id is valid +#[inline(always)] +fn get_percpu_events(cpu: usize) -> &'static Mutex> { + unsafe { PERCPU_EVENTS.remote_ref_raw(cpu) } } -impl EventManager { - fn new(max_cpus: usize) -> Self { - let mut vs = vec![]; - for _ in 0..max_cpus { - let v = Mutex::new(VecDeque::new()); - vs.push(v) - } - Self { inner: vs } - } - - fn add_event(&self, cpu: usize, event_id: usize) -> Option<()> { - match self.inner.get(cpu) { - Some(events) => { - let mut e = events.lock(); - if event_id == IPI_EVENT_SHUTDOWN { - e.clear(); - } - e.push_back(event_id); - Some(()) - } - None => None, - } - } - - fn fetch_event(&self, cpu: usize) -> Option { - match self.inner.get(cpu) { - Some(events) => { - let mut e = events.lock(); - e.pop_front() - } - None => None, - } - } - - fn dump(&self) { - for (cpu, events) in self.inner.iter().enumerate() { - let e = events.lock(); - debug!("event manager: cpu: {}, events: {:?}", cpu, e); - } +fn add_event(cpu: usize, event_id: usize) -> Option<()> { + if cpu >= MAX_CPU_NUM { + return None; } - - fn dump_cpu(&self, cpu: usize) -> Vec { - let mut res = Vec::new(); - let e = self.inner[cpu].lock(); - for i in e.iter() { - res.push(*i); - } - res + let mut e = get_percpu_events(cpu).lock(); + if event_id == IPI_EVENT_SHUTDOWN { + // If the event is shutdown, we need to clear all previous events, because shutdown will make cpu idle and won't process any events. + e.clear(); } -} - -fn add_event(cpu: usize, event_id: usize) -> Option<()> { - EVENT_MANAGER.get().unwrap().add_event(cpu, event_id) + e.push_back(event_id); + Some(()) } pub fn fetch_event(cpu: usize) -> Option { - EVENT_MANAGER.get().unwrap().fetch_event(cpu) -} - -pub fn init() { - EVENT_MANAGER.call_once(|| EventManager::new(MAX_CPU_NUM)); + if cpu >= MAX_CPU_NUM { + return None; + } + get_percpu_events(cpu).lock().pop_front() } pub fn dump_events() { - EVENT_MANAGER.get().unwrap().dump(); + for cpu in 0..MAX_CPU_NUM { + let events = get_percpu_events(cpu).lock(); + if !events.is_empty() { + debug!("cpu {} events: {:?}", cpu, *events); + } + } } pub fn dump_cpu_events(cpu: usize) -> Vec { - EVENT_MANAGER.get().unwrap().dump_cpu(cpu) + if cpu >= MAX_CPU_NUM { + return Vec::new(); + } + get_percpu_events(cpu).lock().iter().cloned().collect() } pub fn clear_events(cpu: usize) { - EVENT_MANAGER.get().unwrap().inner[cpu].lock().clear(); + if cpu >= MAX_CPU_NUM { + return; + } + get_percpu_events(cpu).lock().clear(); } pub fn check_events() -> bool { @@ -179,10 +150,3 @@ pub fn send_event(cpu_id: usize, ipi_int_id: usize, event_id: usize) { add_event(cpu_id, event_id); arch_send_event(cpu_id as _, ipi_int_id as _); } - -#[test_case] -fn test_simple_send_event() { - init(); - send_event(0, 0, IPI_EVENT_WAKEUP); - assert_eq!(fetch_event(0), Some(IPI_EVENT_WAKEUP)); -} diff --git a/src/hypercall/mod.rs b/src/hypercall/mod.rs index ec3e3810..d757b561 100644 --- a/src/hypercall/mod.rs +++ b/src/hypercall/mod.rs @@ -21,7 +21,6 @@ use crate::config::HvZoneConfig; use crate::consts::{INVALID_ADDRESS, MAX_CPU_NUM, MAX_WAIT_TIMES, PAGE_SIZE}; use crate::device::virtio_trampoline::{MAX_DEVS, VIRTIO_BRIDGE, VIRTIO_IRQS}; use crate::error::HvResult; -use crate::percpu::{get_cpu_data, PerCpu}; use crate::zone::{ add_zone, all_zones_info, find_zone, is_this_root_zone, remove_zone, zone_create, ZoneInfo, }; diff --git a/src/logging.rs b/src/logging.rs index 128aeffc..fb7f2faf 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -204,7 +204,7 @@ impl Log for SimpleLogger { let level = record.level(); let line = record.line().unwrap_or(0); let target = record.target(); - let cpu_id = crate::percpu::this_cpu_data().id; + let cpu_id = crate::cpu_data::this_cpu_data().id; let level_color = match level { Level::Error => ColorCode::BrightRed, Level::Warn => ColorCode::BrightYellow, diff --git a/src/main.rs b/src/main.rs index b320606a..e03533ae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,12 +52,12 @@ mod logging; mod arch; mod config; mod consts; +mod cpu_data; mod device; mod event; mod hypercall; mod memory; mod panic; -mod percpu; mod platform; mod zone; @@ -72,9 +72,9 @@ 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}; +use cpu_data::PerCpu; #[cfg(feature = "pci")] use pci::pci_config::hvisor_pci_init; -use percpu::PerCpu; use zone::{add_zone, zone_create}; static INITED_CPUS: AtomicU32 = AtomicU32::new(0); @@ -128,7 +128,6 @@ fn primary_init_early() { ); memory::frame::init(); memory::frame::test(); - event::init(); arch::stage2_mode_detect(); @@ -197,11 +196,13 @@ fn rust_main(cpuid: usize, host_dtb: usize) { if MASTER_CPU.load(Ordering::Acquire) == -1 { MASTER_CPU.store(cpuid as i32, Ordering::Release); is_primary = true; + percpu::init(); memory::heap::init(); memory::heap::test(); arch::time::init_timebase(); arch_post_heap_init(host_dtb); } + percpu::init_percpu_reg(cpuid); let cpu = PerCpu::new(cpuid); diff --git a/src/memory/mmio.rs b/src/memory/mmio.rs index 5c88ac31..54c7f3a6 100644 --- a/src/memory/mmio.rs +++ b/src/memory/mmio.rs @@ -15,7 +15,7 @@ // use core::{ptr, usize}; -use crate::{error::HvResult, percpu::this_zone, zone::zone_error}; +use crate::{error::HvResult, cpu_data::this_zone, zone::zone_error}; use super::GuestPhysAddr; diff --git a/src/pci/pci_handler.rs b/src/pci/pci_handler.rs index 0d310b8e..bc65d51d 100644 --- a/src/pci/pci_handler.rs +++ b/src/pci/pci_handler.rs @@ -16,10 +16,10 @@ use alloc::string::String; +use crate::cpu_data::this_zone; use crate::error::HvResult; use crate::memory::MMIOAccess; use crate::memory::{GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion}; -use crate::percpu::this_zone; use crate::zone::is_this_root_zone; use super::pci_access::{BridgeField, EndpointField, HeaderType, PciField, PciMemType}; diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs index 67278065..8cf4fc48 100644 --- a/src/pci/pci_test.rs +++ b/src/pci/pci_test.rs @@ -29,9 +29,9 @@ use super::{ use super::{mem_alloc::BaseAllocator, pci_struct::RootComplex}; use crate::{ + cpu_data::this_zone, memory::{mmio_perform_access, MMIOAccess}, pci::{config_accessors::PciConfigMmio, pci_access::EndpointHeader}, - percpu::this_zone, }; #[cfg(feature = "ecam_pcie")] diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index 7c3f396e..6a7e3bc8 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -22,12 +22,12 @@ use crate::pci::pci_access::{ use crate::pci::pci_struct::{CapabilityType, PciCapability, VirtualPciConfigSpace}; use crate::pci::PciConfigAddress; // use crate::memory::frame::Frame; +use crate::cpu_data::this_zone; use crate::memory::MMIOAccess; use crate::pci::pci_access::PciMemType; use crate::pci::pci_struct::ArcRwLockVirtualPciConfigSpace; use crate::pci::pci_struct::PciCapabilityRegion; use crate::pci::vpci_dev::VirtMsiXCap; -use crate::percpu::this_zone; use alloc::sync::Arc; use spin::RwLock; diff --git a/src/zone.rs b/src/zone.rs index 9efb5232..b02d079b 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -32,7 +32,7 @@ use crate::config::{HvZoneConfig, CONFIG_NAME_MAXLEN}; use crate::error::HvResult; use crate::memory::addr::GuestPhysAddr; use crate::memory::{MMIOConfig, MMIOHandler, MMIORegion, MemorySet}; -use crate::percpu::{get_cpu_data, this_zone, CpuSet}; +use crate::cpu_data::{get_cpu_data, this_zone, CpuSet}; use core::panic; #[cfg(feature = "dwc_pcie")] From 5212c17c021fe9f2d54ee02926c32ac90fc907b4 Mon Sep 17 00:00:00 2001 From: Solicey Date: Tue, 27 Jan 2026 23:23:04 +0800 Subject: [PATCH 102/109] change vesafb to efifb --- platform/x86_64/qemu/board.rs | 4 ++-- src/arch/x86_64/boot.rs | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/platform/x86_64/qemu/board.rs b/platform/x86_64/qemu/board.rs index 8020834a..bff9e8f8 100644 --- a/platform/x86_64/qemu/board.rs +++ b/platform/x86_64/qemu/board.rs @@ -54,7 +54,7 @@ const ROOT_ZONE_UEFI_REGION_ID: usize = 0x3; pub const ROOT_ZONE_NAME: &str = "root-linux"; pub const ROOT_ZONE_CMDLINE: &str = - "console=ttyS0 earlyprintk=serial nointremap no_timer_check efi=noruntime pci=pcie_scan_all,lastbus=1 root=/dev/vda rw init=/init\0"; + "console=tty0 console=ttyS0 earlycon=efifb earlyprintk=serial nointremap no_timer_check efi=noruntime pci=pcie_scan_all,lastbus=1 root=/dev/vda rw init=/sbin/init\0"; //"console=ttyS0 earlyprintk=serial rdinit=/init nokaslr nointremap\0"; // noapic // video=vesafb // /lib/systemd/systemd @@ -111,7 +111,7 @@ pub const ROOT_ZONE_MEMORY_REGIONS: [HvConfigMemoryRegion; 10] = [ const ROOT_ZONE_CMDLINE_ADDR: GuestPhysAddr = 0x9000; const ROOT_ZONE_SETUP_ADDR: GuestPhysAddr = 0xa000; const ROOT_ZONE_VMLINUX_ENTRY_ADDR: GuestPhysAddr = 0x10_0000; -const ROOT_ZONE_SCREEN_BASE_ADDR: GuestPhysAddr = 0; +const ROOT_ZONE_SCREEN_BASE_ADDR: GuestPhysAddr = 0x7000_0000; pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 0x6; pub const ROOT_ZONE_IRQS_BITMAP: &[BitmapWord] = &get_irqs_bitmap(&[0; 32]); diff --git a/src/arch/x86_64/boot.rs b/src/arch/x86_64/boot.rs index 631b7749..08bf6401 100644 --- a/src/arch/x86_64/boot.rs +++ b/src/arch/x86_64/boot.rs @@ -18,9 +18,9 @@ use crate::{ arch::{zone::HvArchZoneConfig, Stage2PageTable}, config::{root_zone_config, HvConfigMemoryRegion, HvPciConfig, HvZoneConfig, MEM_TYPE_RAM}, consts::PAGE_SIZE, + cpu_data::this_zone, error::HvResult, memory::{GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet}, - cpu_data::this_zone, platform::MEM_TYPE_RESERVED, }; use alloc::string::{String, ToString}; @@ -105,6 +105,9 @@ const E820_MAX_ENTRIES_ZEROPAGE: usize = 128; const EFI64_LOADER_SIGNATURE: u32 = 0x34364c45; // EL64 +const VIDEO_TYPE_VLFB: u8 = 0x23; +const VIDEO_TYPE_EFI: u8 = 0x70; + bitflags::bitflags! { #[derive(Clone, Copy, Debug)] /// https://www.kernel.org/doc/html/latest/arch/x86/boot.html @@ -413,7 +416,7 @@ impl BootParams { self.screen_info.red_pos = 16; self.screen_info.alpha_size = 8; self.screen_info.alpha_pos = 24; - self.screen_info.orig_video_is_vga = 0x23; // VESA + self.screen_info.orig_video_is_vga = VIDEO_TYPE_EFI; self.screen_info.capabilities = 0; self.vid_mode = 0xffff; From 253a67fbed9dd01029f838c931c49ef8b5d2c4b2 Mon Sep 17 00:00:00 2001 From: Solicey Date: Wed, 28 Jan 2026 00:25:40 +0800 Subject: [PATCH 103/109] fix headers --- src/event.rs | 3 ++- src/hypercall/mod.rs | 1 + src/pci/pci_access.rs | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/event.rs b/src/event.rs index c7f073d4..f31b1159 100644 --- a/src/event.rs +++ b/src/event.rs @@ -19,8 +19,8 @@ use crate::{ consts::{ IPI_EVENT_CLEAR_INJECT_IRQ, IPI_EVENT_SEND_IPI, IPI_EVENT_UPDATE_HART_LINE, MAX_CPU_NUM, }, + cpu_data::this_cpu_data, device::{irqchip::inject_irq, virtio_trampoline::handle_virtio_irq}, - percpu::this_cpu_data, platform::IRQ_WAKEUP_VIRTIO_DEVICE, }; use alloc::{collections::VecDeque, vec::Vec}; @@ -93,6 +93,7 @@ pub fn check_events() -> bool { } Some(IPI_EVENT_SHUTDOWN) => { cpu_data.arch_cpu.idle(); + false } Some(IPI_EVENT_VIRTIO_INJECT_IRQ) => { handle_virtio_irq(); diff --git a/src/hypercall/mod.rs b/src/hypercall/mod.rs index d757b561..55a3b8e1 100644 --- a/src/hypercall/mod.rs +++ b/src/hypercall/mod.rs @@ -19,6 +19,7 @@ use crate::arch::cpu::get_target_cpu; use crate::config::HvZoneConfig; use crate::consts::{INVALID_ADDRESS, MAX_CPU_NUM, MAX_WAIT_TIMES, PAGE_SIZE}; +use crate::cpu_data::{get_cpu_data, PerCpu}; use crate::device::virtio_trampoline::{MAX_DEVS, VIRTIO_BRIDGE, VIRTIO_IRQS}; use crate::error::HvResult; use crate::zone::{ diff --git a/src/pci/pci_access.rs b/src/pci/pci_access.rs index 2646d3c8..dc891bd9 100644 --- a/src/pci/pci_access.rs +++ b/src/pci/pci_access.rs @@ -624,7 +624,7 @@ pub trait PciBarRW: PciRWBase { 1u64 << ((readback_high.trailing_zeros() + 32) as u64) } }; - // let value64 = (value as u64) | ((value_high as u64) << 32); + let value64 = (value as u64) | ((value_high as u64) << 32); bararr[slot as usize] = PciMem::new_bar(PciMemType::Mem64Low, value64, size, pre); From e827145f42f2dd78064c4967061a8b1dac9d2d32 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 28 Jan 2026 12:18:30 +0800 Subject: [PATCH 104/109] Set the default serial port for screen to /dev/pts/0 --- .github/workflows/ci.yml | 2 +- .../aarch64/qemu-gicv3/test/systemtest/boot_zone1.sh | 6 +++--- .../qemu-gicv3/test/systemtest/screen_zone1.sh | 11 ++++++----- .../riscv64/qemu-plic/test/systemtest/boot_zone1.sh | 4 ++-- .../riscv64/qemu-plic/test/systemtest/screen_zone1.sh | 11 ++++++----- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da8b86a9..a04296c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -216,7 +216,7 @@ jobs: - name: Install Dependencies run: | sudo apt-get update - sudo apt-get install -y qemu-system-aarch64 qemu-system-riscv64 gdb-multiarch llvm-dev libclang-dev wget expect device-tree-compiler p7zip-full gcc-aarch64-linux-gnu gcc-riscv64-linux-gnu rsyslog + sudo apt-get install -y qemu-system-aarch64 qemu-system-riscv64 gdb-multiarch llvm-dev libclang-dev wget expect device-tree-compiler p7zip-full gcc-aarch64-linux-gnu gcc-riscv64-linux-gnu cargo install --version 0.3.0 --locked cargo-binutils cargo install cargo-xbuild diff --git a/platform/aarch64/qemu-gicv3/test/systemtest/boot_zone1.sh b/platform/aarch64/qemu-gicv3/test/systemtest/boot_zone1.sh index 6257486d..56f5e1c6 100755 --- a/platform/aarch64/qemu-gicv3/test/systemtest/boot_zone1.sh +++ b/platform/aarch64/qemu-gicv3/test/systemtest/boot_zone1.sh @@ -1,10 +1,10 @@ # insmod hvisor.ko mkdir -p /dev/pts mount -t devpts devpts /dev/pts -# exec rsyslog -rsyslogd +# # exec rsyslog +# rsyslogd # start zone1 ./hvisor virtio start zone1-linux-virtio.json & ./hvisor zone start zone1-linux.json && \ -grep "char device" /var/log/syslog && \ +# grep "char device" /var/log/syslog && \ script /dev/null diff --git a/platform/aarch64/qemu-gicv3/test/systemtest/screen_zone1.sh b/platform/aarch64/qemu-gicv3/test/systemtest/screen_zone1.sh index aca07c08..c62a7a16 100755 --- a/platform/aarch64/qemu-gicv3/test/systemtest/screen_zone1.sh +++ b/platform/aarch64/qemu-gicv3/test/systemtest/screen_zone1.sh @@ -1,5 +1,6 @@ -screen_output=$(grep "char device" /var/log/syslog) -echo "$screen_output" -device=$(echo "$screen_output" | awk '{print $NF}') -echo "$device" -screen -S screen_linux2 $device +# screen_output=$(grep "char device" /var/log/syslog) +# echo "$screen_output" +# device=$(echo "$screen_output" | awk '{print $NF}') +# echo "$device" +# screen -S screen_linux2 $device +screen -S screen_linux2 /dev/pts/0 diff --git a/platform/riscv64/qemu-plic/test/systemtest/boot_zone1.sh b/platform/riscv64/qemu-plic/test/systemtest/boot_zone1.sh index 37913619..e7391298 100755 --- a/platform/riscv64/qemu-plic/test/systemtest/boot_zone1.sh +++ b/platform/riscv64/qemu-plic/test/systemtest/boot_zone1.sh @@ -2,7 +2,7 @@ rm nohup.out mkdir -p /dev/pts mount -t devpts devpts /dev/pts -nohup ./hvisor virtio start virtio-backend.json & +./hvisor virtio start virtio-backend.json & ./hvisor zone start zone1-linux-virtio.json && \ -cat nohup.out | grep "char device" && \ +# cat /var/log/syslog | grep "char device" && \ script /dev/null diff --git a/platform/riscv64/qemu-plic/test/systemtest/screen_zone1.sh b/platform/riscv64/qemu-plic/test/systemtest/screen_zone1.sh index d24f677c..505b8df3 100755 --- a/platform/riscv64/qemu-plic/test/systemtest/screen_zone1.sh +++ b/platform/riscv64/qemu-plic/test/systemtest/screen_zone1.sh @@ -1,5 +1,6 @@ -screen_output=$(grep "char device" nohup.out) -echo "$screen_output" -device=$(echo "$screen_output" | awk '{print $NF}') -echo "$device" -screen -S screen_linux2 $device +# screen_output=$(grep "char device" nohup.out) +# echo "$screen_output" +# device=$(echo "$screen_output" | awk '{print $NF}') +# echo "$device" +# screen -S screen_linux2 $device +screen -S screen_linux2 /dev/pts/0 \ No newline at end of file From 2b1faac5fc468d1be2235e86eabab7481a3fe387 Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 28 Jan 2026 13:25:10 +0800 Subject: [PATCH 105/109] Enhance the strictness of shell startup checks for zone1 --- platform/aarch64/qemu-gicv3/test/systemtest/tstart.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/aarch64/qemu-gicv3/test/systemtest/tstart.sh b/platform/aarch64/qemu-gicv3/test/systemtest/tstart.sh index 9f2a197b..2be57c3c 100755 --- a/platform/aarch64/qemu-gicv3/test/systemtest/tstart.sh +++ b/platform/aarch64/qemu-gicv3/test/systemtest/tstart.sh @@ -124,9 +124,9 @@ expect { } } expect { - "# " { - send "bash\r" - } + -re {\r?\n# } { + send "bash\r" + } timeout { exit 1 } From 8ed017df78f1f133021446b1f6baf7921546ac7a Mon Sep 17 00:00:00 2001 From: dallas Date: Wed, 28 Jan 2026 13:35:25 +0800 Subject: [PATCH 106/109] sync ci change for riscv --- platform/riscv64/qemu-plic/test/systemtest/tstart.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/riscv64/qemu-plic/test/systemtest/tstart.sh b/platform/riscv64/qemu-plic/test/systemtest/tstart.sh index 468c771d..0a8e3e6f 100755 --- a/platform/riscv64/qemu-plic/test/systemtest/tstart.sh +++ b/platform/riscv64/qemu-plic/test/systemtest/tstart.sh @@ -135,9 +135,9 @@ expect { } expect { - "# " { - send "bash\r" - } + -re {\r?\n# } { + send "bash\r" + } timeout { exit 1 } From d761504920aee96d667155060eff90dc763ce328 Mon Sep 17 00:00:00 2001 From: lxh Date: Wed, 28 Jan 2026 14:56:55 +0800 Subject: [PATCH 107/109] refactor(percpu): add percpu support (#255) * add percpu support * Change core nums for Dp1000 board --------- Co-authored-by: XingyuChen <124949998+dallasxy@users.noreply.github.com> --- Cargo.lock | 27 +++++ Cargo.toml | 1 + platform/aarch64/imx8mp/linker.ld | 12 ++ platform/aarch64/ok6254-c/linker.ld | 12 ++ platform/aarch64/phytium-pi/linker.ld | 12 ++ platform/aarch64/qemu-gicv2/linker.ld | 12 ++ platform/aarch64/qemu-gicv3/board.rs | 1 + platform/aarch64/qemu-gicv3/linker.ld | 12 ++ platform/aarch64/rk3568/linker.ld | 12 ++ platform/aarch64/rk3588/linker.ld | 12 ++ platform/aarch64/zcu102/linker.ld | 12 ++ platform/loongarch64/ls3a5000/linker.ld | 12 ++ platform/loongarch64/ls3a6000/linker.ld | 12 ++ .../riscv64/hifive-premier-p550/linker.ld | 12 ++ platform/riscv64/megrez/linker.ld | 12 ++ platform/riscv64/qemu-aia/linker.ld | 12 ++ platform/riscv64/qemu-plic/linker.ld | 12 ++ platform/riscv64/ur-dp1000/linker.ld | 12 ++ platform/x86_64/nuc14mnk/linker.ld | 12 ++ platform/x86_64/qemu/linker.ld | 12 ++ src/arch/aarch64/cpu.rs | 6 +- src/arch/aarch64/hypercall.rs | 9 +- src/arch/aarch64/iommu.rs | 5 +- src/arch/aarch64/ipi.rs | 2 +- src/arch/aarch64/mm.rs | 2 +- src/arch/aarch64/trap.rs | 2 +- src/arch/aarch64/zone.rs | 6 +- src/arch/loongarch64/cpu.rs | 2 +- src/arch/loongarch64/trap.rs | 2 +- src/arch/riscv64/cpu.rs | 2 +- src/arch/riscv64/sbi.rs | 2 +- src/arch/x86_64/acpi.rs | 2 +- src/arch/x86_64/boot.rs | 2 +- src/arch/x86_64/cpu.rs | 2 +- src/arch/x86_64/hypercall.rs | 2 +- src/arch/x86_64/ipi.rs | 2 +- src/arch/x86_64/mmio.rs | 2 +- src/arch/x86_64/pci.rs | 2 +- src/arch/x86_64/s2pt.rs | 2 +- src/arch/x86_64/trap.rs | 2 +- src/arch/x86_64/zone.rs | 2 +- src/{percpu.rs => cpu_data.rs} | 0 src/device/irqchip/aia/aplic.rs | 2 +- src/device/irqchip/aia/mod.rs | 2 +- src/device/irqchip/aia/vaplic.rs | 2 +- src/device/irqchip/gicv2/vgic.rs | 2 +- src/device/irqchip/gicv3/gits.rs | 7 +- src/device/irqchip/gicv3/vgic.rs | 4 +- src/device/irqchip/mod.rs | 8 +- src/device/irqchip/pic/lapic.rs | 2 +- src/device/irqchip/plic/mod.rs | 2 +- src/device/virtio_trampoline.rs | 2 +- src/event.rs | 106 ++++++------------ src/hypercall/mod.rs | 2 +- src/logging.rs | 3 +- src/main.rs | 9 +- src/memory/mmio.rs | 2 +- src/pci/pci_handler.rs | 2 +- src/pci/pci_test.rs | 5 +- src/pci/vpci_dev/standard.rs | 2 +- src/tests.rs | 1 - src/zone.rs | 2 +- 62 files changed, 326 insertions(+), 134 deletions(-) rename src/{percpu.rs => cpu_data.rs} (100%) diff --git a/Cargo.lock b/Cargo.lock index 4b904038..3f218724 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -181,6 +181,7 @@ dependencies = [ "log", "loongArch64", "numeric-enum-macro", + "percpu", "psci", "qemu-exit", "raw-cpuid", @@ -251,6 +252,29 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "percpu" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01e56c0c558952222967b592899f98765b48590e7bd7403bfd7075f73afc6ed6" +dependencies = [ + "cfg-if", + "percpu_macros", + "spin 0.9.8", + "x86", +] + +[[package]] +name = "percpu_macros" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9f4cc54a2e471ff72f1499461ba381ad4eae9cbd60d29c258545b995e406e0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.94" @@ -462,6 +486,9 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] name = "spin" diff --git a/Cargo.toml b/Cargo.toml index 20fc9ef3..dc84847b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ cortex-a = "8.1.1" cfg-if = "1.0" bitvec = { version="1.0.1", default-features = false, features = ["atomic", "alloc"] } heapless = { version = "0.8.0 "} +percpu = { package = "percpu", version="0.2", features=["arm-el2"]} [target.'cfg(target_arch = "aarch64")'.dependencies] aarch64-cpu = "9.4.0" diff --git a/platform/aarch64/imx8mp/linker.ld b/platform/aarch64/imx8mp/linker.ld index 0f5e41f3..f8c4a9eb 100644 --- a/platform/aarch64/imx8mp/linker.ld +++ b/platform/aarch64/imx8mp/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x40400000; +CPU_NUM = 4; SECTIONS { @@ -37,6 +38,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/ok6254-c/linker.ld b/platform/aarch64/ok6254-c/linker.ld index c3c0b34a..4da975bb 100644 --- a/platform/aarch64/ok6254-c/linker.ld +++ b/platform/aarch64/ok6254-c/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80400000; +CPU_NUM = 4; SECTIONS { @@ -37,6 +38,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/phytium-pi/linker.ld b/platform/aarch64/phytium-pi/linker.ld index bc718226..1438cfec 100644 --- a/platform/aarch64/phytium-pi/linker.ld +++ b/platform/aarch64/phytium-pi/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x90100000; +CPU_NUM = 4; SECTIONS { @@ -37,6 +38,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/qemu-gicv2/linker.ld b/platform/aarch64/qemu-gicv2/linker.ld index 0f5e41f3..f8c4a9eb 100644 --- a/platform/aarch64/qemu-gicv2/linker.ld +++ b/platform/aarch64/qemu-gicv2/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x40400000; +CPU_NUM = 4; SECTIONS { @@ -37,6 +38,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/qemu-gicv3/board.rs b/platform/aarch64/qemu-gicv3/board.rs index d583330b..119c357c 100644 --- a/platform/aarch64/qemu-gicv3/board.rs +++ b/platform/aarch64/qemu-gicv3/board.rs @@ -24,6 +24,7 @@ use crate::{ use crate::pci_dev; +#[allow(unused)] pub const BOARD_NAME: &str = "qemu-gicv3"; pub const BOARD_NCPUS: usize = 4; diff --git a/platform/aarch64/qemu-gicv3/linker.ld b/platform/aarch64/qemu-gicv3/linker.ld index 0f5e41f3..f8c4a9eb 100644 --- a/platform/aarch64/qemu-gicv3/linker.ld +++ b/platform/aarch64/qemu-gicv3/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x40400000; +CPU_NUM = 4; SECTIONS { @@ -37,6 +38,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/rk3568/linker.ld b/platform/aarch64/rk3568/linker.ld index 26e135cd..0fe74fbe 100644 --- a/platform/aarch64/rk3568/linker.ld +++ b/platform/aarch64/rk3568/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x60080000; +CPU_NUM = 4; SECTIONS { @@ -42,6 +43,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/aarch64/rk3588/linker.ld b/platform/aarch64/rk3588/linker.ld index 40a2ee2a..b287362b 100644 --- a/platform/aarch64/rk3588/linker.ld +++ b/platform/aarch64/rk3588/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x500000; +CPU_NUM = 8; SECTIONS { @@ -41,6 +42,17 @@ SECTIONS *(.bss .bss.*) *(.sbss .sbss.*) } + + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; . = ALIGN(4K); ebss = .; diff --git a/platform/aarch64/zcu102/linker.ld b/platform/aarch64/zcu102/linker.ld index 0f5e41f3..f8c4a9eb 100644 --- a/platform/aarch64/zcu102/linker.ld +++ b/platform/aarch64/zcu102/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x40400000; +CPU_NUM = 4; SECTIONS { @@ -37,6 +38,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/loongarch64/ls3a5000/linker.ld b/platform/loongarch64/ls3a5000/linker.ld index 6ca259e4..a226494f 100644 --- a/platform/loongarch64/ls3a5000/linker.ld +++ b/platform/loongarch64/ls3a5000/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x90000001f0000000; +CPU_NUM = 4; SECTIONS @@ -46,6 +47,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; diff --git a/platform/loongarch64/ls3a6000/linker.ld b/platform/loongarch64/ls3a6000/linker.ld index 6ca259e4..a226494f 100644 --- a/platform/loongarch64/ls3a6000/linker.ld +++ b/platform/loongarch64/ls3a6000/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x90000001f0000000; +CPU_NUM = 4; SECTIONS @@ -46,6 +47,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; diff --git a/platform/riscv64/hifive-premier-p550/linker.ld b/platform/riscv64/hifive-premier-p550/linker.ld index b1ec2354..6f2d2083 100644 --- a/platform/riscv64/hifive-premier-p550/linker.ld +++ b/platform/riscv64/hifive-premier-p550/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80200000; +CPU_NUM = 4; SECTIONS @@ -38,6 +39,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/riscv64/megrez/linker.ld b/platform/riscv64/megrez/linker.ld index b1ec2354..6f2d2083 100644 --- a/platform/riscv64/megrez/linker.ld +++ b/platform/riscv64/megrez/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80200000; +CPU_NUM = 4; SECTIONS @@ -38,6 +39,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/riscv64/qemu-aia/linker.ld b/platform/riscv64/qemu-aia/linker.ld index b1ec2354..6f2d2083 100644 --- a/platform/riscv64/qemu-aia/linker.ld +++ b/platform/riscv64/qemu-aia/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80200000; +CPU_NUM = 4; SECTIONS @@ -38,6 +39,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/riscv64/qemu-plic/linker.ld b/platform/riscv64/qemu-plic/linker.ld index b1ec2354..6f2d2083 100644 --- a/platform/riscv64/qemu-plic/linker.ld +++ b/platform/riscv64/qemu-plic/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80200000; +CPU_NUM = 4; SECTIONS @@ -38,6 +39,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/riscv64/ur-dp1000/linker.ld b/platform/riscv64/ur-dp1000/linker.ld index eb62b0fe..cb2da6df 100644 --- a/platform/riscv64/ur-dp1000/linker.ld +++ b/platform/riscv64/ur-dp1000/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0x80200000; +CPU_NUM = 8; SECTIONS @@ -38,6 +39,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/x86_64/nuc14mnk/linker.ld b/platform/x86_64/nuc14mnk/linker.ld index 11ae57fd..3fc54b77 100644 --- a/platform/x86_64/nuc14mnk/linker.ld +++ b/platform/x86_64/nuc14mnk/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0xffffff8000200000; +CPU_NUM = 4; SECTIONS { @@ -41,6 +42,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/platform/x86_64/qemu/linker.ld b/platform/x86_64/qemu/linker.ld index 11ae57fd..3fc54b77 100644 --- a/platform/x86_64/qemu/linker.ld +++ b/platform/x86_64/qemu/linker.ld @@ -1,5 +1,6 @@ ENTRY(arch_entry) BASE_ADDRESS = 0xffffff8000200000; +CPU_NUM = 4; SECTIONS { @@ -41,6 +42,17 @@ SECTIONS *(.sbss .sbss.*) } + . = ALIGN(4K); + _percpu_start = .; + _percpu_end = _percpu_start + SIZEOF(.percpu); + .percpu 0x0 (NOLOAD) : AT(_percpu_start) { + _percpu_load_start = .; + *(.percpu .percpu.*) + _percpu_load_end = .; + . = _percpu_load_start + ALIGN(64) * CPU_NUM; + } + . = _percpu_end; + . = ALIGN(4K); ebss = .; ekernel = .; diff --git a/src/arch/aarch64/cpu.rs b/src/arch/aarch64/cpu.rs index 3f7e3676..442a2a29 100644 --- a/src/arch/aarch64/cpu.rs +++ b/src/arch/aarch64/cpu.rs @@ -16,11 +16,11 @@ use crate::{ arch::{mm::new_s2_memory_set, sysreg::write_sysreg}, consts::{MAX_CPU_NUM, PAGE_SIZE, PER_CPU_ARRAY_PTR, PER_CPU_SIZE}, + cpu_data::this_cpu_data, memory::{ addr::PHYS_VIRT_OFFSET, mm::PARKING_MEMORY_SET, GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, VirtAddr, PARKING_INST_PAGE, }, - percpu::this_cpu_data, platform::BOARD_MPIDR_MAPPINGS, zone::find_zone, }; @@ -265,12 +265,12 @@ pub fn this_cpu_id() -> usize { mpidr_to_cpuid(MPIDR_EL1.get()) as _ } -pub fn store_cpu_pointer_to_reg(pointer: usize) { +pub fn store_cpu_pointer_to_reg(_pointer: usize) { // println!("aarch64 doesn't support store cpu pointer to reg, pointer: {:#x}", pointer); return; } -pub fn get_target_cpu(irq: usize, zone_id: usize) -> usize { +pub fn get_target_cpu(_irq: usize, zone_id: usize) -> usize { find_zone(zone_id) .unwrap() .read() diff --git a/src/arch/aarch64/hypercall.rs b/src/arch/aarch64/hypercall.rs index 91e59485..5a1ec0da 100644 --- a/src/arch/aarch64/hypercall.rs +++ b/src/arch/aarch64/hypercall.rs @@ -16,11 +16,11 @@ use crate::arch::cpu::this_cpu_id; use crate::arch::ivc::{IvcInfo, IVC_INFOS}; -use crate::config::{HvZoneConfig, CONFIG_MAGIC_VERSION}; +use crate::config::CONFIG_MAGIC_VERSION; +use crate::cpu_data::this_zone; use crate::device::virtio_trampoline::MAX_DEVS; use crate::hypercall::HyperCall; use crate::hypercall::HyperCallResult; -use crate::percpu::this_zone; use crate::zone::this_zone_id; impl<'a> HyperCall<'a> { @@ -46,7 +46,7 @@ impl<'a> HyperCall<'a> { HyperCallResult::Ok(0) } - pub fn wait_for_interrupt(&mut self, irq_list: &mut [u64; MAX_DEVS + 1]) { + pub fn wait_for_interrupt(&mut self, _irq_list: &mut [u64; MAX_DEVS + 1]) { trace!("wait_for_interrupt is not need for AArch64"); } @@ -66,6 +66,7 @@ impl<'a> HyperCall<'a> { return config_addr; } + #[allow(unused)] pub fn hv_get_real_list_pa(&mut self, list_addr: u64) -> u64 { // RISC-V does not have a specific prefix for cached memory, so we return the address as is. return list_addr; @@ -76,7 +77,7 @@ impl<'a> HyperCall<'a> { trace!("CPU ID: {} Start Zone", cpuid); } - pub fn hv_virtio_get_irq(&self, virtio_irq: *mut u32) -> HyperCallResult { + pub fn hv_virtio_get_irq(&self, _virtio_irq: *mut u32) -> HyperCallResult { trace!("hv_virtio_get_irq is not need for AArch64"); HyperCallResult::Ok(0) } diff --git a/src/arch/aarch64/iommu.rs b/src/arch/aarch64/iommu.rs index 7e6336d4..58aa75eb 100644 --- a/src/arch/aarch64/iommu.rs +++ b/src/arch/aarch64/iommu.rs @@ -15,9 +15,8 @@ // #![allow(dead_code)] use crate::{ - arch::mm::new_s2_memory_set, consts::{MAX_ZONE_NUM, PAGE_SIZE}, - memory::{Frame, GuestPhysAddr, MemFlags, MemoryRegion, MemorySet, PhysAddr}, + memory::{Frame, PhysAddr}, }; use aarch64_cpu::registers::{Readable, Writeable}; use alloc::vec::Vec; @@ -27,8 +26,6 @@ use tock_registers::{ registers::{ReadOnly, ReadWrite}, }; -use super::Stage2PageTable; - #[allow(dead_code)] const SMMU_BASE_ADDR: PhysAddr = 0x09050000; #[allow(dead_code)] diff --git a/src/arch/aarch64/ipi.rs b/src/arch/aarch64/ipi.rs index a0aa0ab8..974a3013 100644 --- a/src/arch/aarch64/ipi.rs +++ b/src/arch/aarch64/ipi.rs @@ -30,6 +30,6 @@ pub fn arch_check_events(event: Option) { } } -pub fn arch_prepare_send_event(cpu_id: usize, ipi_int_id: usize, event_id: usize) { +pub fn arch_prepare_send_event(_cpu_id: usize, _ipi_int_id: usize, _event_id: usize) { debug!("aarch64 arch_prepare_send_event: do nothing now.") } diff --git a/src/arch/aarch64/mm.rs b/src/arch/aarch64/mm.rs index 36e8e687..23b0b9dd 100644 --- a/src/arch/aarch64/mm.rs +++ b/src/arch/aarch64/mm.rs @@ -53,7 +53,7 @@ pub fn new_s2_memory_set() -> MemorySet { MemorySet::new(if is_s2_pt_level3() { 3 } else { 4 }) } -pub fn arch_post_heap_init(host_dtb: usize) { +pub fn arch_post_heap_init(_host_dtb: usize) { // AArch64 does not need to do some setup work after heap init like x86_64. // This function can be used to set up any architecture-specific parameters if needed. // Currently, it does nothing. diff --git a/src/arch/aarch64/trap.rs b/src/arch/aarch64/trap.rs index e49146e0..acd09f06 100644 --- a/src/arch/aarch64/trap.rs +++ b/src/arch/aarch64/trap.rs @@ -24,11 +24,11 @@ use crate::{ cpu::mpidr_to_cpuid, sysreg::{read_sysreg, write_sysreg}, }, + cpu_data::{get_cpu_data, this_cpu_data, this_zone}, device::irqchip::gic_handle_irq, event::{send_event, IPI_EVENT_SHUTDOWN, IPI_EVENT_WAKEUP}, hypercall::{HyperCall, SGI_IPI_ID}, memory::{mmio_handle_access, MMIOAccess}, - percpu::{get_cpu_data, this_cpu_data, this_zone}, zone::{is_this_root_zone, remove_zone}, }; diff --git a/src/arch/aarch64/zone.rs b/src/arch/aarch64/zone.rs index 207710fc..c4691135 100644 --- a/src/arch/aarch64/zone.rs +++ b/src/arch/aarch64/zone.rs @@ -16,11 +16,10 @@ use core::panic; use crate::{ - arch::Stage2PageTable, config::*, device::virtio_trampoline::mmio_virtio_handler, error::HvResult, - memory::{GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet}, + memory::{GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion}, zone::Zone, }; @@ -118,7 +117,7 @@ impl Zone { Ok(()) } - pub fn arch_zone_post_configuration(&mut self, config: &HvZoneConfig) -> HvResult { + pub fn arch_zone_post_configuration(&mut self, _config: &HvZoneConfig) -> HvResult { Ok(()) } } @@ -132,6 +131,7 @@ pub struct HvArchZoneConfig { #[repr(C, usize)] #[derive(Debug, Clone)] +#[allow(unused)] pub enum GicConfig { Gicv2(Gicv2Config), Gicv3(Gicv3Config), diff --git a/src/arch/loongarch64/cpu.rs b/src/arch/loongarch64/cpu.rs index 625e43c4..5b524dd4 100644 --- a/src/arch/loongarch64/cpu.rs +++ b/src/arch/loongarch64/cpu.rs @@ -17,8 +17,8 @@ use super::ipi::*; use super::zone::ZoneContext; use crate::arch::zone::disable_hwi_through; +use crate::cpu_data::this_cpu_data; use crate::device::common::MMIODerefWrapper; -use crate::percpu::this_cpu_data; use crate::zone::find_zone; use core::arch::asm; use core::fmt::{self, Debug, Formatter}; diff --git a/src/arch/loongarch64/trap.rs b/src/arch/loongarch64/trap.rs index d16e1c81..29397185 100644 --- a/src/arch/loongarch64/trap.rs +++ b/src/arch/loongarch64/trap.rs @@ -20,12 +20,12 @@ use super::zone::ZoneContext; use crate::arch::cpu::this_cpu_id; use crate::arch::ipi::*; use crate::consts::{IPI_EVENT_CLEAR_INJECT_IRQ, MAX_CPU_NUM}; +use crate::cpu_data::this_cpu_data; use crate::device::irqchip::inject_irq; use crate::device::irqchip::ls7a2000::chip::*; use crate::event::{check_events, dump_cpu_events, dump_events}; use crate::hypercall::{SGI_IPI_ID, *}; use crate::memory::{addr, mmio_handle_access, MMIOAccess}; -use crate::percpu::this_cpu_data; use crate::zone::Zone; use crate::PHY_TO_DMW_UNCACHED; use core::arch; diff --git a/src/arch/riscv64/cpu.rs b/src/arch/riscv64/cpu.rs index 35f9a3a4..966ab9b6 100644 --- a/src/arch/riscv64/cpu.rs +++ b/src/arch/riscv64/cpu.rs @@ -14,7 +14,7 @@ // Authors: // use super::csr::*; -use crate::percpu::this_cpu_data; +use crate::cpu_data::this_cpu_data; use crate::platform::{BOARD_HARTID_MAP, BOARD_NCPUS}; use crate::{ arch::mm::new_s2_memory_set, diff --git a/src/arch/riscv64/sbi.rs b/src/arch/riscv64/sbi.rs index 04492318..d922f103 100644 --- a/src/arch/riscv64/sbi.rs +++ b/src/arch/riscv64/sbi.rs @@ -19,9 +19,9 @@ use super::cpu::ArchCpu; use crate::arch::cpu::hartid_to_cpuid; use crate::arch::csr::*; use crate::consts::IPI_EVENT_SEND_IPI; +use crate::cpu_data::{get_cpu_data, this_cpu_data}; use crate::event::{send_event, IPI_EVENT_WAKEUP}; use crate::hypercall::HyperCall; -use crate::percpu::{get_cpu_data, this_cpu_data}; use core::sync::atomic; use riscv::register::sie; use riscv_h::register::hvip; diff --git a/src/arch/x86_64/acpi.rs b/src/arch/x86_64/acpi.rs index 4bfdc530..701b5dff 100644 --- a/src/arch/x86_64/acpi.rs +++ b/src/arch/x86_64/acpi.rs @@ -17,8 +17,8 @@ use crate::{ arch::boot, config::{HvConfigMemoryRegion, HvZoneConfig}, + cpu_data::{this_zone, CpuSet}, error::HvResult, - percpu::{this_zone, CpuSet}, platform::ROOT_PCI_MAX_BUS, }; use acpi::{ diff --git a/src/arch/x86_64/boot.rs b/src/arch/x86_64/boot.rs index 14d92a08..319e62b7 100644 --- a/src/arch/x86_64/boot.rs +++ b/src/arch/x86_64/boot.rs @@ -17,9 +17,9 @@ use crate::{ arch::{zone::HvArchZoneConfig, Stage2PageTable}, config::{root_zone_config, HvPciConfig, HvZoneConfig, MEM_TYPE_RAM}, + cpu_data::this_zone, error::HvResult, memory::{GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet}, - percpu::this_zone, platform::MEM_TYPE_RESERVED, }; use alloc::string::{String, ToString}; diff --git a/src/arch/x86_64/cpu.rs b/src/arch/x86_64/cpu.rs index 25f3653d..5eeaee4f 100644 --- a/src/arch/x86_64/cpu.rs +++ b/src/arch/x86_64/cpu.rs @@ -30,6 +30,7 @@ use crate::{ vmx::*, }, consts::{self, core_end, PER_CPU_SIZE}, + cpu_data::{this_cpu_data, this_zone}, device::irqchip::pic::{check_pending_vectors, clear_vectors, ioapic, lapic::VirtLocalApic}, error::{HvError, HvResult}, memory::{ @@ -38,7 +39,6 @@ use crate::{ Frame, GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, PhysAddr, PAGE_SIZE, PARKING_INST_PAGE, }, - percpu::{this_cpu_data, this_zone}, platform::ROOT_ZONE_BOOT_STACK, zone::{find_zone, this_zone_id}, }; diff --git a/src/arch/x86_64/hypercall.rs b/src/arch/x86_64/hypercall.rs index cb5517f1..4a228af7 100644 --- a/src/arch/x86_64/hypercall.rs +++ b/src/arch/x86_64/hypercall.rs @@ -17,9 +17,9 @@ use crate::{ arch::cpu::this_cpu_id, config::CONFIG_MAGIC_VERSION, + cpu_data::this_zone, device::virtio_trampoline::MAX_DEVS, hypercall::{HyperCall, HyperCallResult}, - percpu::this_zone, zone::{Zone, ZoneInfo}, }; use spin::RwLock; diff --git a/src/arch/x86_64/ipi.rs b/src/arch/x86_64/ipi.rs index b8c20de5..4c3b6d46 100644 --- a/src/arch/x86_64/ipi.rs +++ b/src/arch/x86_64/ipi.rs @@ -20,11 +20,11 @@ use crate::{ cpu::this_cpu_id, idt::IdtVector, }, + cpu_data::{this_cpu_data, this_zone, CpuSet}, device::irqchip::inject_vector, error::HvResult, event, hypercall::SGI_IPI_ID, - percpu::{this_cpu_data, this_zone, CpuSet}, }; use alloc::{collections::vec_deque::VecDeque, vec::Vec}; use bit_field::BitField; diff --git a/src/arch/x86_64/mmio.rs b/src/arch/x86_64/mmio.rs index 2b7681c4..7e7443c5 100644 --- a/src/arch/x86_64/mmio.rs +++ b/src/arch/x86_64/mmio.rs @@ -19,12 +19,12 @@ use crate::{ s2pt::DescriptorAttr, vmcs::{VmcsGuest16, VmcsGuestNW}, }, + cpu_data::{this_cpu_data, this_zone}, error::HvResult, memory::{ addr::{GuestPhysAddr, GuestVirtAddr, HostPhysAddr}, MMIOAccess, MMIOHandler, }, - percpu::{this_cpu_data, this_zone}, }; use alloc::{sync::Arc, vec::Vec}; use bit_field::BitField; diff --git a/src/arch/x86_64/pci.rs b/src/arch/x86_64/pci.rs index cc05d533..ef173ce8 100644 --- a/src/arch/x86_64/pci.rs +++ b/src/arch/x86_64/pci.rs @@ -16,11 +16,11 @@ use crate::{ arch::{acpi, idt, mmio::MMIoDevice, pio::get_pio_bitmap, zone::HvArchZoneConfig}, + cpu_data::this_zone, error::HvResult, memory::{ mmio_generic_handler, mmio_handle_access, mmio_perform_access, GuestPhysAddr, MMIOAccess, }, - percpu::this_zone, zone::{this_zone_id, Zone}, }; use ::acpi::{mcfg::Mcfg, sdt::Signature}; diff --git a/src/arch/x86_64/s2pt.rs b/src/arch/x86_64/s2pt.rs index 9a4e8e49..43680f66 100644 --- a/src/arch/x86_64/s2pt.rs +++ b/src/arch/x86_64/s2pt.rs @@ -21,12 +21,12 @@ use crate::{ vmcs::*, }, consts::PAGE_SIZE, + cpu_data::this_cpu_data, error::HvResult, memory::{ addr::{GuestPhysAddr, HostPhysAddr, PhysAddr}, MemFlags, }, - percpu::this_cpu_data, zone::this_zone_id, }; use bit_field::BitField; diff --git a/src/arch/x86_64/trap.rs b/src/arch/x86_64/trap.rs index edfbeee9..9621852d 100644 --- a/src/arch/x86_64/trap.rs +++ b/src/arch/x86_64/trap.rs @@ -26,6 +26,7 @@ use crate::{ vmcs::*, vmx::{VmxCrAccessInfo, VmxExitInfo, VmxExitReason, VmxInterruptInfo, VmxIoExitInfo}, }, + cpu_data::{this_cpu_data, this_zone}, device::{ irqchip::{ inject_vector, @@ -36,7 +37,6 @@ use crate::{ error::HvResult, hypercall::HyperCall, memory::{mmio_handle_access, MMIOAccess, MemFlags}, - percpu::{this_cpu_data, this_zone}, zone::this_zone_id, }; use bit_field::BitField; diff --git a/src/arch/x86_64/zone.rs b/src/arch/x86_64/zone.rs index f69f4eac..e0c3a67d 100644 --- a/src/arch/x86_64/zone.rs +++ b/src/arch/x86_64/zone.rs @@ -17,10 +17,10 @@ use crate::{ arch::{acpi, boot, msr::set_msr_bitmap, pio, pio::set_pio_bitmap, Stage2PageTable}, config::*, + cpu_data::get_cpu_data, device::virtio_trampoline::mmio_virtio_handler, error::HvResult, memory::{GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet}, - percpu::get_cpu_data, platform::MEM_TYPE_RESERVED, zone::Zone, }; diff --git a/src/percpu.rs b/src/cpu_data.rs similarity index 100% rename from src/percpu.rs rename to src/cpu_data.rs diff --git a/src/device/irqchip/aia/aplic.rs b/src/device/irqchip/aia/aplic.rs index b92556a3..a42fdb80 100644 --- a/src/device/irqchip/aia/aplic.rs +++ b/src/device/irqchip/aia/aplic.rs @@ -17,7 +17,7 @@ use crate::config::root_zone_config; use crate::device::irqchip::aia::imsic::imsic_trigger; use crate::zone::Zone; -use crate::{arch::cpu::ArchCpu, memory::GuestPhysAddr, percpu::this_cpu_data}; +use crate::{arch::cpu::ArchCpu, cpu_data::this_cpu_data, memory::GuestPhysAddr}; use riscv_decode::Instruction; use spin::Once; use spin::RwLock; diff --git a/src/device/irqchip/aia/mod.rs b/src/device/irqchip/aia/mod.rs index 93b4f5f5..1579ee80 100644 --- a/src/device/irqchip/aia/mod.rs +++ b/src/device/irqchip/aia/mod.rs @@ -24,12 +24,12 @@ use crate::arch::cpu::this_cpu_id; use crate::arch::zone::HvArchZoneConfig; use crate::config::{BitmapWord, HvZoneConfig, CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD}; use crate::consts::MAX_ZONE_NUM; +use crate::cpu_data::this_cpu_data; use crate::error::HvResult; use crate::memory::HostPhysAddr; use crate::memory::MMIOAccess; use crate::memory::MemFlags; use crate::memory::MemoryRegion; -use crate::percpu::this_cpu_data; use crate::platform::HW_IRQS; use crate::platform::{ BOARD_APLIC_INTERRUPTS_NUM, IMSIC_GUEST_INDEX, IMSIC_GUEST_NUM, IMSIC_S_BASE, diff --git a/src/device/irqchip/aia/vaplic.rs b/src/device/irqchip/aia/vaplic.rs index fdd50405..795b72f1 100644 --- a/src/device/irqchip/aia/vaplic.rs +++ b/src/device/irqchip/aia/vaplic.rs @@ -15,7 +15,7 @@ // use super::*; -use crate::percpu::this_cpu_data; +use crate::cpu_data::this_cpu_data; use alloc::sync::Arc; use alloc::vec::Vec; use bitvec::prelude::*; diff --git a/src/device/irqchip/gicv2/vgic.rs b/src/device/irqchip/gicv2/vgic.rs index 4490ef10..19b18268 100644 --- a/src/device/irqchip/gicv2/vgic.rs +++ b/src/device/irqchip/gicv2/vgic.rs @@ -15,6 +15,7 @@ // Hangqi Ren <2572131118@qq.com> use crate::arch::zone::{GicConfig, Gicv2Config, HvArchZoneConfig}; use crate::config::{BitmapWord, CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD}; +use crate::cpu_data::this_zone; use crate::device::irqchip::gicv2::gicd::{ get_max_int_num, GICD, GICD_CTRL_REG_OFFSET, GICD_ICACTIVER_REG_OFFSET, GICD_ICENABLER_REG_OFFSET, GICD_ICFGR_REG_OFFSET, GICD_ICPENDR_REG_OFFSET, @@ -28,7 +29,6 @@ use crate::device::irqchip::gicv2::gicd::{ use crate::device::irqchip::gicv2::GICV2; use crate::error::HvResult; use crate::memory::{mmio_perform_access, MMIOAccess, MemFlags, MemoryRegion}; -use crate::percpu::this_zone; /// This file defines and implements the functional functions of virtual gicv2. /// author: ForeverYolo /// reference: diff --git a/src/device/irqchip/gicv3/gits.rs b/src/device/irqchip/gicv3/gits.rs index eb8719f6..65ddc30c 100644 --- a/src/device/irqchip/gicv3/gits.rs +++ b/src/device/irqchip/gicv3/gits.rs @@ -15,13 +15,12 @@ // use core::ptr; -use aarch64_cpu::registers::DAIF::A; use alloc::{sync::Arc, vec::Vec}; use spin::{mutex::Mutex, Once, RwLock}; use crate::{ - consts::MAX_ZONE_NUM, device::irqchip::gicv3::gicr::enable_one_lpi, memory::Frame, - percpu::this_zone, zone::this_zone_id, + consts::MAX_ZONE_NUM, cpu_data::this_zone, device::irqchip::gicv3::gicr::enable_one_lpi, + memory::Frame, }; use super::host_gits_base; @@ -177,7 +176,7 @@ impl Cmdq { self.cbaser_list[zone_id] = value; let gpa_base = value & 0xffffffffff000; unsafe { - let phy_base = match this_zone().read().gpm.page_table_query(gpa_base) { + let _phy_base = match this_zone().read().gpm.page_table_query(gpa_base) { Ok(p) => self.phy_base_list[zone_id] = p.0, _ => {} }; diff --git a/src/device/irqchip/gicv3/vgic.rs b/src/device/irqchip/gicv3/vgic.rs index bd16002b..8ac7dd87 100644 --- a/src/device/irqchip/gicv3/vgic.rs +++ b/src/device/irqchip/gicv3/vgic.rs @@ -18,9 +18,10 @@ use alloc::sync::Arc; use super::{gicd::GICD_LOCK, is_spi}; use crate::platform::BOARD_MPIDR_MAPPINGS; use crate::{ - arch::zone::{GicConfig, Gicv2Config, Gicv3Config, HvArchZoneConfig}, + arch::zone::{GicConfig, HvArchZoneConfig}, config::{BitmapWord, CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD, CONFIG_MAX_INTERRUPTS}, consts::MAX_CPU_NUM, + cpu_data::{get_cpu_data, this_zone}, device::irqchip::gicv3::{ gicd::*, gicr::*, gits::*, host_gicd_base, host_gicr_base, host_gits_base, MAINTENACE_INTERRUPT, PER_GICR_SIZE, @@ -28,7 +29,6 @@ use crate::{ error::HvResult, hypercall::SGI_IPI_ID, memory::{mmio_perform_access, MMIOAccess}, - percpu::{get_cpu_data, this_zone}, zone::{this_zone_id, Zone}, }; pub fn reg_range(base: usize, n: usize, size: usize) -> core::ops::Range { diff --git a/src/device/irqchip/mod.rs b/src/device/irqchip/mod.rs index 0d74c011..345c4d20 100644 --- a/src/device/irqchip/mod.rs +++ b/src/device/irqchip/mod.rs @@ -72,15 +72,15 @@ pub fn gic_send_event(cpu_id: u64, sgi_num: u64) { } impl Zone { - pub fn virqc_init(&mut self, config: &HvZoneConfig) { + pub fn virqc_init(&mut self, _config: &HvZoneConfig) { #[cfg(all(feature = "plic", target_arch = "riscv64"))] { - self.vplic_init(config); + self.vplic_init(_config); } #[cfg(all(feature = "aia", target_arch = "riscv64"))] { - self.vaplic_init(config); - self.vimsic_init(config); + self.vaplic_init(_config); + self.vimsic_init(_config); } } diff --git a/src/device/irqchip/pic/lapic.rs b/src/device/irqchip/pic/lapic.rs index f5697c3b..8ba43c18 100644 --- a/src/device/irqchip/pic/lapic.rs +++ b/src/device/irqchip/pic/lapic.rs @@ -21,10 +21,10 @@ use crate::{ ipi, msr::Msr::{self, *}, }, + cpu_data::this_cpu_data, device::irqchip::pic::pop_vector, error::HvResult, memory::Frame, - percpu::this_cpu_data, }; use bit_field::BitField; use core::{ops::Range, u32}; diff --git a/src/device/irqchip/plic/mod.rs b/src/device/irqchip/plic/mod.rs index 1add8f67..f2fb304d 100644 --- a/src/device/irqchip/plic/mod.rs +++ b/src/device/irqchip/plic/mod.rs @@ -28,9 +28,9 @@ use crate::arch::zone::HvArchZoneConfig; use crate::config::HvZoneConfig; use crate::config::{BitmapWord, CONFIG_INTERRUPTS_BITMAP_BITS_PER_WORD}; use crate::consts::MAX_CPU_NUM; +use crate::cpu_data::this_cpu_data; use crate::error::HvResult; use crate::memory::mmio::MMIOAccess; -use crate::percpu::this_cpu_data; use crate::platform::*; use crate::zone::Zone; use alloc::collections::BTreeMap; diff --git a/src/device/virtio_trampoline.rs b/src/device/virtio_trampoline.rs index b7896f17..4c8e00c6 100644 --- a/src/device/virtio_trampoline.rs +++ b/src/device/virtio_trampoline.rs @@ -189,7 +189,7 @@ impl VirtioBridgeController { } /// Get req list agent. - pub fn req_agent(&self) -> ReqAgent { + fn req_agent(&self) -> ReqAgent { if !self.is_enable.load(Ordering::Acquire) { panic!("VirtioBridge not enabled"); } diff --git a/src/event.rs b/src/event.rs index 7cec4dee..5bc2e0b7 100644 --- a/src/event.rs +++ b/src/event.rs @@ -19,97 +19,68 @@ use crate::{ consts::{ IPI_EVENT_CLEAR_INJECT_IRQ, IPI_EVENT_SEND_IPI, IPI_EVENT_UPDATE_HART_LINE, MAX_CPU_NUM, }, + cpu_data::this_cpu_data, device::{irqchip::inject_irq, virtio_trampoline::handle_virtio_irq}, - percpu::this_cpu_data, platform::IRQ_WAKEUP_VIRTIO_DEVICE, }; use alloc::{collections::VecDeque, vec::Vec}; -use spin::{Mutex, Once}; +use spin::Mutex; pub const IPI_EVENT_WAKEUP: usize = 0; pub const IPI_EVENT_SHUTDOWN: usize = 1; pub const IPI_EVENT_VIRTIO_INJECT_IRQ: usize = 2; pub const IPI_EVENT_WAKEUP_VIRTIO_DEVICE: usize = 3; -static EVENT_MANAGER: Once = Once::new(); +#[percpu::def_percpu] +static PERCPU_EVENTS: Mutex> = Mutex::new(VecDeque::new()); -struct EventManager { - pub inner: Vec>>, +// The caller ensures the cpu_id is valid +#[inline(always)] +fn get_percpu_events(cpu: usize) -> &'static Mutex> { + unsafe { PERCPU_EVENTS.remote_ref_raw(cpu) } } -impl EventManager { - fn new(max_cpus: usize) -> Self { - let mut vs = vec![]; - for _ in 0..max_cpus { - let v = Mutex::new(VecDeque::new()); - vs.push(v) - } - Self { inner: vs } - } - - fn add_event(&self, cpu: usize, event_id: usize) -> Option<()> { - match self.inner.get(cpu) { - Some(events) => { - let mut e = events.lock(); - if event_id == IPI_EVENT_SHUTDOWN { - e.clear(); - } - e.push_back(event_id); - Some(()) - } - None => None, - } - } - - fn fetch_event(&self, cpu: usize) -> Option { - match self.inner.get(cpu) { - Some(events) => { - let mut e = events.lock(); - e.pop_front() - } - None => None, - } - } - - fn dump(&self) { - for (cpu, events) in self.inner.iter().enumerate() { - let e = events.lock(); - debug!("event manager: cpu: {}, events: {:?}", cpu, e); - } +fn add_event(cpu: usize, event_id: usize) -> Option<()> { + if cpu >= MAX_CPU_NUM { + return None; } - - fn dump_cpu(&self, cpu: usize) -> Vec { - let mut res = Vec::new(); - let e = self.inner[cpu].lock(); - for i in e.iter() { - res.push(*i); - } - res + let mut e = get_percpu_events(cpu).lock(); + if event_id == IPI_EVENT_SHUTDOWN { + // If the event is shutdown, we need to clear all previous events, because shutdown will make cpu idle and won't process any events. + e.clear(); } -} - -fn add_event(cpu: usize, event_id: usize) -> Option<()> { - EVENT_MANAGER.get().unwrap().add_event(cpu, event_id) + e.push_back(event_id); + Some(()) } pub fn fetch_event(cpu: usize) -> Option { - EVENT_MANAGER.get().unwrap().fetch_event(cpu) -} - -pub fn init() { - EVENT_MANAGER.call_once(|| EventManager::new(MAX_CPU_NUM)); + if cpu >= MAX_CPU_NUM { + return None; + } + get_percpu_events(cpu).lock().pop_front() } pub fn dump_events() { - EVENT_MANAGER.get().unwrap().dump(); + for cpu in 0..MAX_CPU_NUM { + let events = get_percpu_events(cpu).lock(); + if !events.is_empty() { + debug!("cpu {} events: {:?}", cpu, *events); + } + } } pub fn dump_cpu_events(cpu: usize) -> Vec { - EVENT_MANAGER.get().unwrap().dump_cpu(cpu) + if cpu >= MAX_CPU_NUM { + return Vec::new(); + } + get_percpu_events(cpu).lock().iter().cloned().collect() } pub fn clear_events(cpu: usize) { - EVENT_MANAGER.get().unwrap().inner[cpu].lock().clear(); + if cpu >= MAX_CPU_NUM { + return; + } + get_percpu_events(cpu).lock().clear(); } pub fn check_events() -> bool { @@ -179,10 +150,3 @@ pub fn send_event(cpu_id: usize, ipi_int_id: usize, event_id: usize) { add_event(cpu_id, event_id); arch_send_event(cpu_id as _, ipi_int_id as _); } - -#[test_case] -fn test_simple_send_event() { - init(); - send_event(0, 0, IPI_EVENT_WAKEUP); - assert_eq!(fetch_event(0), Some(IPI_EVENT_WAKEUP)); -} diff --git a/src/hypercall/mod.rs b/src/hypercall/mod.rs index ec3e3810..55a3b8e1 100644 --- a/src/hypercall/mod.rs +++ b/src/hypercall/mod.rs @@ -19,9 +19,9 @@ use crate::arch::cpu::get_target_cpu; use crate::config::HvZoneConfig; use crate::consts::{INVALID_ADDRESS, MAX_CPU_NUM, MAX_WAIT_TIMES, PAGE_SIZE}; +use crate::cpu_data::{get_cpu_data, PerCpu}; use crate::device::virtio_trampoline::{MAX_DEVS, VIRTIO_BRIDGE, VIRTIO_IRQS}; use crate::error::HvResult; -use crate::percpu::{get_cpu_data, PerCpu}; use crate::zone::{ add_zone, all_zones_info, find_zone, is_this_root_zone, remove_zone, zone_create, ZoneInfo, }; diff --git a/src/logging.rs b/src/logging.rs index 128aeffc..6f8320c0 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -94,6 +94,7 @@ enum ColorCode { BrightWhite = 97, } +#[allow(unused)] fn color_code_to_bgra(code: &ColorCode) -> u32 { match code { ColorCode::Black => 0, @@ -204,7 +205,7 @@ impl Log for SimpleLogger { let level = record.level(); let line = record.line().unwrap_or(0); let target = record.target(); - let cpu_id = crate::percpu::this_cpu_data().id; + let cpu_id = crate::cpu_data::this_cpu_data().id; let level_color = match level { Level::Error => ColorCode::BrightRed, Level::Warn => ColorCode::BrightYellow, diff --git a/src/main.rs b/src/main.rs index b320606a..92e98022 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,12 +52,12 @@ mod logging; mod arch; mod config; mod consts; +mod cpu_data; mod device; mod event; mod hypercall; mod memory; mod panic; -mod percpu; mod platform; mod zone; @@ -72,10 +72,9 @@ 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}; +use cpu_data::PerCpu; #[cfg(feature = "pci")] use pci::pci_config::hvisor_pci_init; -use percpu::PerCpu; -use zone::{add_zone, zone_create}; static INITED_CPUS: AtomicU32 = AtomicU32::new(0); static ENTERED_CPUS: AtomicU32 = AtomicU32::new(0); @@ -128,7 +127,6 @@ fn primary_init_early() { ); memory::frame::init(); memory::frame::test(); - event::init(); arch::stage2_mode_detect(); @@ -147,6 +145,7 @@ fn primary_init_early() { #[cfg(not(test))] { + use zone::{add_zone, zone_create}; let zone = zone_create(root_config).unwrap(); add_zone(zone); } @@ -197,11 +196,13 @@ fn rust_main(cpuid: usize, host_dtb: usize) { if MASTER_CPU.load(Ordering::Acquire) == -1 { MASTER_CPU.store(cpuid as i32, Ordering::Release); is_primary = true; + percpu::init(); memory::heap::init(); memory::heap::test(); arch::time::init_timebase(); arch_post_heap_init(host_dtb); } + percpu::init_percpu_reg(cpuid); let cpu = PerCpu::new(cpuid); diff --git a/src/memory/mmio.rs b/src/memory/mmio.rs index 5c88ac31..e96641c1 100644 --- a/src/memory/mmio.rs +++ b/src/memory/mmio.rs @@ -15,7 +15,7 @@ // use core::{ptr, usize}; -use crate::{error::HvResult, percpu::this_zone, zone::zone_error}; +use crate::{cpu_data::this_zone, error::HvResult, zone::zone_error}; use super::GuestPhysAddr; diff --git a/src/pci/pci_handler.rs b/src/pci/pci_handler.rs index 0d310b8e..bc65d51d 100644 --- a/src/pci/pci_handler.rs +++ b/src/pci/pci_handler.rs @@ -16,10 +16,10 @@ use alloc::string::String; +use crate::cpu_data::this_zone; use crate::error::HvResult; use crate::memory::MMIOAccess; use crate::memory::{GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion}; -use crate::percpu::this_zone; use crate::zone::is_this_root_zone; use super::pci_access::{BridgeField, EndpointField, HeaderType, PciField, PciMemType}; diff --git a/src/pci/pci_test.rs b/src/pci/pci_test.rs index 67278065..021ccf3b 100644 --- a/src/pci/pci_test.rs +++ b/src/pci/pci_test.rs @@ -29,14 +29,11 @@ use super::{ use super::{mem_alloc::BaseAllocator, pci_struct::RootComplex}; use crate::{ + cpu_data::this_zone, memory::{mmio_perform_access, MMIOAccess}, pci::{config_accessors::PciConfigMmio, pci_access::EndpointHeader}, - percpu::this_zone, }; -#[cfg(feature = "ecam_pcie")] -use crate::pci::config_accessors::ecam::EcamConfigAccessor; - pub static GLOBAL_PCIE_LIST_TEST: Lazy>> = Lazy::new(|| { let m = BTreeMap::new(); diff --git a/src/pci/vpci_dev/standard.rs b/src/pci/vpci_dev/standard.rs index 7c3f396e..6a7e3bc8 100644 --- a/src/pci/vpci_dev/standard.rs +++ b/src/pci/vpci_dev/standard.rs @@ -22,12 +22,12 @@ use crate::pci::pci_access::{ use crate::pci::pci_struct::{CapabilityType, PciCapability, VirtualPciConfigSpace}; use crate::pci::PciConfigAddress; // use crate::memory::frame::Frame; +use crate::cpu_data::this_zone; use crate::memory::MMIOAccess; use crate::pci::pci_access::PciMemType; use crate::pci::pci_struct::ArcRwLockVirtualPciConfigSpace; use crate::pci::pci_struct::PciCapabilityRegion; use crate::pci::vpci_dev::VirtMsiXCap; -use crate::percpu::this_zone; use alloc::sync::Arc; use spin::RwLock; diff --git a/src/tests.rs b/src/tests.rs index 5d740709..98db70af 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -17,7 +17,6 @@ /// since this is a baremetal program /// all unittests are performed when running hvisor on qemu /// you will need to use `make test` to run the unittests -use core::ptr::write_volatile; use qemu_exit::QEMUExit; #[cfg(target_arch = "riscv64")] diff --git a/src/zone.rs b/src/zone.rs index 9efb5232..6297d1f6 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -29,10 +29,10 @@ use crate::arch::mm::new_s2_memory_set; use crate::arch::s2pt::Stage2PageTable; use crate::config::{HvZoneConfig, CONFIG_NAME_MAXLEN}; +use crate::cpu_data::{get_cpu_data, this_zone, CpuSet}; use crate::error::HvResult; use crate::memory::addr::GuestPhysAddr; use crate::memory::{MMIOConfig, MMIOHandler, MMIORegion, MemorySet}; -use crate::percpu::{get_cpu_data, this_zone, CpuSet}; use core::panic; #[cfg(feature = "dwc_pcie")] From df1f23d35e4efeb4bf60206fc0d6bc56e0006427 Mon Sep 17 00:00:00 2001 From: Solicey <58247189+Solicey@users.noreply.github.com> Date: Wed, 28 Jan 2026 15:48:36 +0800 Subject: [PATCH 108/109] Remove unused import in zone.rs Removed unused import of get_cpu_data from zone.rs. --- src/arch/riscv64/zone.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/arch/riscv64/zone.rs b/src/arch/riscv64/zone.rs index 55f9d99f..1f53e97d 100644 --- a/src/arch/riscv64/zone.rs +++ b/src/arch/riscv64/zone.rs @@ -15,11 +15,9 @@ // use crate::{ config::*, - cpu_data::get_cpu_data, device::virtio_trampoline::mmio_virtio_handler, error::HvResult, - memory::{addr::align_up, GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet}, - pci::pcibar::BarRegion, + memory::{GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion}, zone::Zone, }; impl Zone { From a0597d5df09a4bf10eaa5d07391abb54170f7f5d Mon Sep 17 00:00:00 2001 From: Solicey <58247189+Solicey@users.noreply.github.com> Date: Wed, 28 Jan 2026 15:49:36 +0800 Subject: [PATCH 109/109] Clean up imports in trap.rs Removed unused imports for HostPhysAddr and __board. --- src/arch/riscv64/trap.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/arch/riscv64/trap.rs b/src/arch/riscv64/trap.rs index 96ea3e60..99277f72 100644 --- a/src/arch/riscv64/trap.rs +++ b/src/arch/riscv64/trap.rs @@ -20,8 +20,6 @@ use crate::device::irqchip::plic::{inject_irq, plic_get_hwirq}; use crate::event::check_events; use crate::memory::GuestPhysAddr; use crate::memory::{mmio_handle_access, MMIOAccess}; -use crate::memory::{GuestPhysAddr, HostPhysAddr}; -use crate::platform::__board::*; use core::arch::{asm, global_asm}; use riscv::register::stvec::TrapMode; use riscv::register::{sie, stvec};