diff --git a/.gitignore b/.gitignore index d2f81579..717b0ff9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ /test-img /hvisor.S /hvisor-elf.txt +/hvisor.elf +/hvisor-trap-vector.txt +/Doc/compile.md /images/* /platform/*/*/image/kernel/* /platform/*/*/image/virtdisk/* diff --git a/build-la-nopci.sh b/build-la-nopci.sh new file mode 100755 index 00000000..0d5cceae --- /dev/null +++ b/build-la-nopci.sh @@ -0,0 +1,2 @@ +#!/bin/bash +make BID=loongarch64/ls3a6000 LOG=info FEATURES="loongson_3a6000 loongson_7a2000 loongson_uart" diff --git a/build.rs b/build.rs index 9fdedbbf..5ab25aa3 100644 --- a/build.rs +++ b/build.rs @@ -137,7 +137,8 @@ fn main() { } // soft link the board.rs to __board.rs - if target_path.exists() { + // Use symlink_metadata so we detect broken symlinks too (exists() follows the link) + if target_path.symlink_metadata().is_ok() { fs::remove_file(target_path).expect("Failed to remove existing __board.rs"); } std::os::unix::fs::symlink(source_path, target_path).expect("Failed to create symlink"); diff --git a/platform/loongarch64/ls3a5000/board.rs b/platform/loongarch64/ls3a5000/board.rs index 541d73a8..15113dc7 100644 --- a/platform/loongarch64/ls3a5000/board.rs +++ b/platform/loongarch64/ls3a5000/board.rs @@ -13,7 +13,7 @@ // // Authors: // Yulong Han -// +// Ming Shen use crate::pci_dev; use crate::{arch::zone::HvArchZoneConfig, config::*, pci::vpci_dev::VpciDevType}; @@ -21,134 +21,226 @@ pub const BOARD_NAME: &str = "ls3a5000"; pub const BOARD_NCPUS: usize = 4; +pub const CPU_BOOT_CONTEXT_ADDRESS: usize = 0x90000001e0000000; + pub const ROOT_ZONE_DTB_ADDR: u64 = 0x10000f000; pub const ROOT_ZONE_KERNEL_ADDR: u64 = 0x200000; -pub const ROOT_ZONE_ENTRY: u64 = 0x9000000000d8c000; -pub const ROOT_ZONE_CPUS: u64 = 1 << 0; +pub const ROOT_ZONE_ENTRY: u64 = 0xe71000; +pub const ROOT_ZONE_CPUS: u64 = (1 << 0) | (1 << 1); pub const ROOT_ZONE_NAME: &str = "root-linux-la64"; + pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ - /* memory regions */ HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0x00200000, - virtual_start: 0x00200000, - size: 0x0ee00000, - }, // ram + physical_start: 0x200000, + virtual_start: 0x200000, + size: 0xec00000, + }, // RAM + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x1fe00000, + virtual_start: 0x1fe00000, + size: 0x2000, + }, // IO important MMIO + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x10080000, + virtual_start: 0x10080000, + size: 0x1000, + }, // serial + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x10090000, + virtual_start: 0x10090000, + size: 0x1000, + }, // IO + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x18000000, + virtual_start: 0x18000000, + size: 0x1000, + }, // IO???? unknown + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x100a0000, + virtual_start: 0x100a0000, + size: 0x1000, + }, // IO + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x100d0000, + virtual_start: 0x100d0000, + size: 0x1000, + }, // IO + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x100e0000, + virtual_start: 0x100e0000, + size: 0x1000, + }, // IO + + // 46f000000-47f7fffff HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0x90000000, - virtual_start: 0x90000000, - size: 0x10000000, - }, // ram + physical_start: 0x46f000000, + virtual_start: 0x46f000000, + size: 0x10800000, + }, // Reserved RAM + + // 47f800000 - 47fffffff HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0xf000_0000, - virtual_start: 0xf000_0000, - size: 0x1000_0000, - }, // ram + physical_start: 0x47f800000, + virtual_start: 0x47f800000, + size: 0x800000, + }, // Reserved RAM + + // ====== for start_image ====== + // 0x90000000 - 0xf9ffffff 0x6a000000 + // 0xf7000000 - 0xf7ffffff 0x1000000 + //(0xf9000000 - 0xf9ffffff 0x1000000) + // 0xfa000000 - 0xfaffffff 0x1000000 + // 0xfb000000 - 0xfbffffff 0x1000000 + // 0xfc000000 - 0xfcffffff 0x1000000 + // 0xfd000000 - 0xfdffffff 0x1000000 + // 0xfe000000 - 0xfeffffff 0x1000000 HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0x1_6000_0000, - virtual_start: 0x1_6000_0000, - size: 0x1000_0000, - }, // linux0 + physical_start: 0x90000000, + virtual_start: 0x90000000, + size: 0x6a000000, + }, // RAM + HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0xc000_0000, - virtual_start: 0xc000_0000, - size: 0x3000_0000, - }, // linux1 + physical_start: 0xfa000000, + virtual_start: 0xfa000000, + size: 0x5000000, + }, // RAM + + // 0x800000000 ~ 0x87fffffff HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0xa000_0000, - virtual_start: 0xa000_0000, - size: 0x2000_0000, - }, // linux2 + physical_start: 0x800000000, + virtual_start: 0x800000000, + size: 0x80000000, + }, // RAM + HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0x1_0000_0000, - virtual_start: 0x1_0000_0000, - size: 0x2000_0000, - }, // linux3 - /* devices and controllers */ + physical_start: 0x7f0000000, + virtual_start: 0x7f0000000, + size: 0x10000000, + }, // RAM + + // ==== for start_image ==== + + // addition HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, - physical_start: 0x1fe00000, - virtual_start: 0x1fe00000, + // mem_type: MEM_TYPE_PCH_PCI, + physical_start: 0x10000000, + virtual_start: 0x10000000, size: 0x1000, - }, // uart0 + }, // IO!!!!????? PCH-PCI + HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, - physical_start: 0x10080000, - virtual_start: 0x10080000, + physical_start: 0x10002000, + virtual_start: 0x10002000, size: 0x1000, - }, // uart1, passthrough now + }, // IO!!!!????? + HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, - physical_start: 0x100d0000, - virtual_start: 0x100d0000, + physical_start: 0x10010000, + virtual_start: 0x10010000, size: 0x1000, - }, // rtc, passthrough now + }, // IO!!!!????? + + // ===========unknown region=============== + // addition HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0x10000000, - virtual_start: 0x10000000, - size: 0x1000, - }, // pch-pic irq controller - /* PCI related stuffs ... */ - // HvConfigMemoryRegion { - // mem_type: MEM_TYPE_IO, - // physical_start: 0x1a000000, - // virtual_start: 0x1a000000, - // size: 0x02000000, - // }, // pci + mem_type: MEM_TYPE_RAM, + physical_start: 0x100000000, + virtual_start: 0x100000000, + size: 0x200000000, + // size: 0xe0000000, + }, // RAM + // HvConfigMemoryRegion { - // mem_type: MEM_TYPE_IO, - // physical_start: 0xefe_0000_0000, - // virtual_start: 0xfe_0000_0000, - // size: 0x20000000, - // }, // pci config space (HT) + // mem_type: MEM_TYPE_RAM, + // physical_start: 0x200000000, + // virtual_start: 0x200000000, + // size: 0x100000000, + // // size: 0x10000, + // }, // RAM + // =========unknown region====== + HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, - physical_start: 0x18408000, - virtual_start: 0x18408000, - size: 0x00008000, - }, // pci io resource + physical_start: 0xe0030000000, + virtual_start: 0xe0030000000, + size: 0x50000000, + }, // PCI + HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, - physical_start: 0x60000000, - virtual_start: 0x60000000, + physical_start: 0xefe00000000, + virtual_start: 0xefe00000000, size: 0x20000000, - }, // pci mem resource + }, // PCI + HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, - physical_start: 0x1001_0000, - virtual_start: 0x1001_0000, - size: 0x0001_0000, - }, // ? - /* map special regions - 2024.4.12 */ - // linux's strscpy called gpa at 0x9000_0000_0000_0000 which is ldx x, 0x9000_0000_0000_0000(a1) + 0x0(a0) why ? - // __memcpy_fromio 0xf0000 why? - HvConfigMemoryRegion { - mem_type: MEM_TYPE_RAM, - physical_start: 0x1000, - virtual_start: 0x0, - size: 0x10000, - }, // 0x0 - HvConfigMemoryRegion { - mem_type: MEM_TYPE_RAM, - physical_start: 0xf0000, - virtual_start: 0xf0000, - size: 0x10000, - }, // 0xf0000 - HvConfigMemoryRegion { - mem_type: MEM_TYPE_RAM, - physical_start: 0x1_4000_0000, - virtual_start: 0x1_4000_0000, - size: 0x80_0000, // linux1-root - }, // SHARD_MEM + physical_start: 0xefdfe000000, + virtual_start: 0xefdfe000000, + size: 0x2000, + }, // PCI + + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_IO, + // physical_start: 0xe8000000000, + // virtual_start: 0xe8000000000, + // size: 0x10000000, + // }, // PCI + + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_IO, + // physical_start: 0xe8015150000, + // virtual_start: 0xe8015150000, + // size: 0x8000 + // }, // PCI + + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_IO, + // physical_start: 0xe8015000000, + // virtual_start: 0xe8015000000, + // size: 0x100000 + // }, // PCI + + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_IOMMU, + // physical_start: 0xe0030000000, + // virtual_start: 0xe0030000000, + // size: 0x50000000, + // }, // PCI-IOMMU + + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_IOMMU, + // physical_start: 0xefe00000000, + // virtual_start: 0xefe00000000, + // size: 0x20000000, + // }, // PCI-IOMMU ]; pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 32 + 0x20; diff --git a/platform/loongarch64/ls3a5000/linker.ld b/platform/loongarch64/ls3a5000/linker.ld index a226494f..935a526d 100644 --- a/platform/loongarch64/ls3a5000/linker.ld +++ b/platform/loongarch64/ls3a5000/linker.ld @@ -1,5 +1,5 @@ ENTRY(arch_entry) -BASE_ADDRESS = 0x90000001f0000000; +BASE_ADDRESS = 0x90000007f0000000; CPU_NUM = 4; @@ -14,10 +14,10 @@ SECTIONS *(.text .text.*) } - . = ALIGN(4K); + . = ALIGN(64K); .trap_entry : { *(.trap_entry) - . = ALIGN(4K); + . = ALIGN(64K); *(.tlbrefill_entry) } diff --git a/platform/loongarch64/ls3a5000/platform.mk b/platform/loongarch64/ls3a5000/platform.mk index e2abe865..b10d4d44 100644 --- a/platform/loongarch64/ls3a5000/platform.mk +++ b/platform/loongarch64/ls3a5000/platform.mk @@ -1,5 +1,6 @@ # hvisor for loongarch64 makefile # wheatfox(wheatfox17@icloud.com) 2024.6 +# boneinscri(boneinscri@163.com) 2026.4 # HVISOR ENTRY HVISOR_ENTRY_PA := 0x9000000080000000 @@ -22,4 +23,9 @@ HVISOR_ENTRY_PA := 0x9000000080000000 # QEMU_ARGS += -device loader,file="$(zone0_dtb)",addr=0x8f000000,force-raw=on $(hvisor_bin): elf - $(OBJCOPY) $(hvisor_elf) --strip-all -O binary $@ \ No newline at end of file + $(OBJCOPY) $(hvisor_elf) --strip-all -O binary $@ +# objdump + hvisor-trap-vector.txt + readelf -a $(hvisor_elf) > hvisor-elf.txt + loongarch64-linux-gnu-objdump --disassemble $(hvisor_elf) > hvisor.S + cp $(hvisor_elf) hvisor.elf + nm -n hvisor.elf | grep -w _hyp_trap_vector | awk '{print "0x"$$1""}' > hvisor-trap-vector.txt \ No newline at end of file diff --git a/platform/loongarch64/ls3a6000/board.rs b/platform/loongarch64/ls3a6000/board.rs index 6bd74afa..632ba62d 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -13,142 +13,225 @@ // // Authors: // Yulong Han -// +// Ming Shen use crate::pci_dev; use crate::{arch::zone::HvArchZoneConfig, config::*, pci::vpci_dev::VpciDevType}; -pub const BOARD_NAME: &str = "ls3a5000"; +pub const BOARD_NAME: &str = "ls3a6000"; + +pub const BOARD_NCPUS: usize = 8; -pub const BOARD_NCPUS: usize = 4; +pub const CPU_BOOT_CONTEXT_ADDRESS: usize = 0x90000001e0000000; pub const ROOT_ZONE_DTB_ADDR: u64 = 0x10000f000; pub const ROOT_ZONE_KERNEL_ADDR: u64 = 0x200000; -pub const ROOT_ZONE_ENTRY: u64 = 0x9000000000d8c000; -pub const ROOT_ZONE_CPUS: u64 = 1 << 0; +pub const ROOT_ZONE_ENTRY: u64 = 0xe71000; +// pub const ROOT_ZONE_CPUS: u64 = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7); +// pub const ROOT_ZONE_CPUS: u64 = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) ; +pub const ROOT_ZONE_CPUS: u64 = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6); pub const ROOT_ZONE_NAME: &str = "root-linux-la64"; pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ - /* memory regions */ - HvConfigMemoryRegion { + HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0x00200000, - virtual_start: 0x00200000, - size: 0x0ee00000, - }, // ram - HvConfigMemoryRegion { - mem_type: MEM_TYPE_RAM, - physical_start: 0x90000000, - virtual_start: 0x90000000, - size: 0x10000000, - }, // ram + physical_start: 0x0, + virtual_start: 0x0, + size: 0x200000, + }, // ???? + HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0xf000_0000, - virtual_start: 0xf000_0000, - size: 0x1000_0000, - }, // ram + physical_start: 0x200000, + virtual_start: 0x200000, + size: 0xec00000, + }, // RAM + HvConfigMemoryRegion { - mem_type: MEM_TYPE_RAM, - physical_start: 0x1_6000_0000, - virtual_start: 0x1_6000_0000, - size: 0x1000_0000, - }, // linux0 + mem_type: MEM_TYPE_IO, + physical_start: 0x1fe00000, + virtual_start: 0x1fe00000, + size: 0x2000, + }, // IO important MMIO + HvConfigMemoryRegion { - mem_type: MEM_TYPE_RAM, - physical_start: 0xc000_0000, - virtual_start: 0xc000_0000, - size: 0x3000_0000, - }, // linux1 + mem_type: MEM_TYPE_IO, + physical_start: 0x1fe10000, + virtual_start: 0x1fe10000, + size: 0x2000, + }, // IO important MMIO + HvConfigMemoryRegion { - mem_type: MEM_TYPE_RAM, - physical_start: 0xa000_0000, - virtual_start: 0xa000_0000, - size: 0x2000_0000, - }, // linux2 + mem_type: MEM_TYPE_IO, + physical_start: 0x10080000, + virtual_start: 0x10080000, + size: 0x1000, + }, // serial + HvConfigMemoryRegion { - mem_type: MEM_TYPE_RAM, - physical_start: 0x1_0000_0000, - virtual_start: 0x1_0000_0000, - size: 0x2000_0000, - }, // linux3 - /* devices and controllers */ + mem_type: MEM_TYPE_IO, + physical_start: 0x10090000, + virtual_start: 0x10090000, + size: 0x1000, + }, // IO + HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, - physical_start: 0x1fe00000, - virtual_start: 0x1fe00000, + physical_start: 0x18000000, + virtual_start: 0x18000000, size: 0x1000, - }, // uart0 + }, // IO???? unknown + HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, - physical_start: 0x10080000, - virtual_start: 0x10080000, + physical_start: 0x100a0000, + virtual_start: 0x100a0000, size: 0x1000, - }, // uart1, passthrough now + }, // IO + HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x100d0000, - virtual_start: 0x100d0000, + virtual_start: 0x100d0000, size: 0x1000, - }, // rtc, passthrough now + }, // IO + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x100e0000, + virtual_start: 0x100e0000, + size: 0x1000, + }, // IO + + // ====== for start_image ====== + HvConfigMemoryRegion { + mem_type: MEM_TYPE_RAM, + physical_start: 0x90000000, + virtual_start: 0x90000000, + size: 0x6a000000, + }, // RAM 0x90000000 ~ 0xf9ffffff + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_RAM, + physical_start: 0xfa000000, + virtual_start: 0xfa000000, + size: 0x5000000, + }, // RAM 0xfa000000 ~ 0xfeffffff + // ==== for start_image ==== + + // addition HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x10000000, - virtual_start: 0x10000000, + virtual_start: 0x10000000, + size: 0x1000, + }, // IO PCH-PCI + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x10002000, + virtual_start: 0x10002000, + size: 0x1000, + }, // IO + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0x10010000, + virtual_start: 0x10010000, size: 0x1000, - }, // pch-pic irq controller - /* PCI related stuffs ... */ + }, // IO + + // 0x100000000 ~ 0x87fffffff (30GB) + HvConfigMemoryRegion { + mem_type: MEM_TYPE_RAM, + physical_start: 0x100000000, + virtual_start: 0x100000000, + size: 0x780000000, + }, // RAM + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xe0030000000, + virtual_start: 0xe0030000000, + size: 0x50000000, + }, // PCI + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xefe00000000, + virtual_start: 0xefe00000000, + size: 0x20000000, + }, // PCI + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xefdfe000000, + virtual_start: 0xefdfe000000, + size: 0x2000, + }, // PCI + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xefdfc000000, + virtual_start: 0xefdfc000000, + size: 0x2000000, + }, // PCI (covers 0xefdfc0003ce) + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xe8000000000, + virtual_start: 0xe8000000000, + size: 0xc00000000, + }, // PCI + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xe8c15000000, + virtual_start: 0xe8c15000000, + size: 0x162000, + }, // PCI + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_IO, + physical_start: 0xe0000000000, + virtual_start: 0xe0000000000, + size: 0x30000000, + }, // PCI + // HvConfigMemoryRegion { // mem_type: MEM_TYPE_IO, - // physical_start: 0x1a000000, - // virtual_start: 0x1a000000, - // size: 0x02000000, - // }, // pci + // physical_start: 0xe8000000000, + // virtual_start: 0xe8000000000, + // size: 0x10000000, + // }, // PCI + // HvConfigMemoryRegion { // mem_type: MEM_TYPE_IO, - // physical_start: 0xefe_0000_0000, - // virtual_start: 0xfe_0000_0000, - // size: 0x20000000, - // }, // pci config space (HT) + // physical_start: 0xe8015150000, + // virtual_start: 0xe8015150000, + // size: 0x8000 + // }, // PCI + // HvConfigMemoryRegion { // mem_type: MEM_TYPE_IO, - // physical_start: 0x18408000, - // virtual_start: 0x18408000, - // size: 0x00008000, - // }, // pci io resource + // physical_start: 0xe8015000000, + // virtual_start: 0xe8015000000, + // size: 0x100000 + // }, // PCI + // HvConfigMemoryRegion { - // mem_type: MEM_TYPE_IO, - // physical_start: 0x60000000, - // virtual_start: 0x60000000, + // mem_type: MEM_TYPE_IOMMU, + // physical_start: 0xe0030000000, + // virtual_start: 0xe0030000000, + // size: 0x50000000, + // }, // PCI-IOMMU + + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_IOMMU, + // physical_start: 0xefe00000000, + // virtual_start: 0xefe00000000, // size: 0x20000000, - // }, // pci mem resource - HvConfigMemoryRegion { - mem_type: MEM_TYPE_IO, - physical_start: 0x1001_0000, - virtual_start: 0x1001_0000, - size: 0x0001_0000, - }, // ? - /* map special regions - 2024.4.12 */ - // linux's strscpy called gpa at 0x9000_0000_0000_0000 which is ldx x, 0x9000_0000_0000_0000(a1) + 0x0(a0) why ? - // __memcpy_fromio 0xf0000 why? - HvConfigMemoryRegion { - mem_type: MEM_TYPE_RAM, - physical_start: 0x1000, - virtual_start: 0x0, - size: 0x10000, - }, // 0x0 - HvConfigMemoryRegion { - mem_type: MEM_TYPE_RAM, - physical_start: 0xf0000, - virtual_start: 0xf0000, - size: 0x10000, - }, // 0xf0000 - HvConfigMemoryRegion { - mem_type: MEM_TYPE_RAM, - physical_start: 0x1_4000_0000, - virtual_start: 0x1_4000_0000, - size: 0x80_0000, // linux1-root - }, // SHARD_MEM + // }, // PCI-IOMMU ]; pub const IRQ_WAKEUP_VIRTIO_DEVICE: usize = 32 + 0x20; @@ -156,22 +239,23 @@ 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, +// }]; +pub const ROOT_PCI_CONFIG: [HvPciConfig; 0] = []; /* 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 */ @@ -182,34 +266,35 @@ pub const ROOT_PCI_CONFIG: [HvPciConfig; 1] = [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: [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, 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 -]; +// 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, 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 +// ]; +pub const ROOT_PCI_DEVS: [HvPciDevConfig; 0] = []; // bus << 8 | dev << 5 | func << 3 diff --git a/platform/loongarch64/ls3a6000/linker.ld b/platform/loongarch64/ls3a6000/linker.ld index a226494f..cd13590e 100644 --- a/platform/loongarch64/ls3a6000/linker.ld +++ b/platform/loongarch64/ls3a6000/linker.ld @@ -1,6 +1,6 @@ ENTRY(arch_entry) -BASE_ADDRESS = 0x90000001f0000000; -CPU_NUM = 4; +BASE_ADDRESS = 0x90000007f0000000; +CPU_NUM = 8; SECTIONS @@ -14,10 +14,10 @@ SECTIONS *(.text .text.*) } - . = ALIGN(4K); + . = ALIGN(64K); .trap_entry : { *(.trap_entry) - . = ALIGN(4K); + . = ALIGN(64K); *(.tlbrefill_entry) } diff --git a/platform/loongarch64/ls3a6000/platform.mk b/platform/loongarch64/ls3a6000/platform.mk index e2abe865..b10d4d44 100644 --- a/platform/loongarch64/ls3a6000/platform.mk +++ b/platform/loongarch64/ls3a6000/platform.mk @@ -1,5 +1,6 @@ # hvisor for loongarch64 makefile # wheatfox(wheatfox17@icloud.com) 2024.6 +# boneinscri(boneinscri@163.com) 2026.4 # HVISOR ENTRY HVISOR_ENTRY_PA := 0x9000000080000000 @@ -22,4 +23,9 @@ HVISOR_ENTRY_PA := 0x9000000080000000 # QEMU_ARGS += -device loader,file="$(zone0_dtb)",addr=0x8f000000,force-raw=on $(hvisor_bin): elf - $(OBJCOPY) $(hvisor_elf) --strip-all -O binary $@ \ No newline at end of file + $(OBJCOPY) $(hvisor_elf) --strip-all -O binary $@ +# objdump + hvisor-trap-vector.txt + readelf -a $(hvisor_elf) > hvisor-elf.txt + loongarch64-linux-gnu-objdump --disassemble $(hvisor_elf) > hvisor.S + cp $(hvisor_elf) hvisor.elf + nm -n hvisor.elf | grep -w _hyp_trap_vector | awk '{print "0x"$$1""}' > hvisor-trap-vector.txt \ No newline at end of file diff --git a/src/arch/loongarch64/cpu.rs b/src/arch/loongarch64/cpu.rs index c458efa7..64eba595 100644 --- a/src/arch/loongarch64/cpu.rs +++ b/src/arch/loongarch64/cpu.rs @@ -13,25 +13,387 @@ // // Authors: // Yulong Han -// +// Ming Shen +use super::eiointc::LoongArch64Eiointc; use super::ipi::*; +use super::register::*; use super::zone::ZoneContext; +use crate::arch::trap::enable_global_interrupt; use crate::arch::zone::disable_hwi_through; -use crate::cpu_data::{this_cpu_data, VcpuState}; +use crate::cpu_data::this_zone; +use crate::cpu_data::{get_vcpuid_from_pcpuid, this_cpu_data, VcpuState}; use crate::device::common::MMIODerefWrapper; -use crate::zone::find_zone; +use crate::zone::{find_zone, this_zone_id}; use core::arch::asm; use core::fmt::{self, Debug, Formatter}; use loongArch64::register::crmd::Crmd; use loongArch64::register::pgdl; use loongArch64::register::{cpuid, crmd}; +use spin::Mutex; use tock_registers::interfaces::Writeable; use crate::{ consts::{PER_CPU_ARRAY_PTR, PER_CPU_SIZE}, memory::VirtAddr, + platform::CPU_BOOT_CONTEXT_ADDRESS, }; +// CPU_BOOT_CONTEXT_ADDRESS is defined in board.rs (platform-specific) + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct BootContext { + pub ra: usize, // return address + pub sp: usize, // stack pointer + pub tp: usize, // threads pointer + pub s0: usize, + pub s1: usize, + pub s2: usize, + pub s3: usize, + pub s4: usize, + pub s5: usize, + pub s6: usize, + pub s7: usize, + pub s8: usize, + pub fp: usize, + pub start_image: usize, + pub image_handle: usize, + pub efi_system_table: usize, + pub cmd_line_ptr: usize, + // pub t0: usize, + // pub t1: usize, + pub t2: usize, + pub t3: usize, + pub t4: usize, + pub t5: usize, + pub t6: usize, + pub t7: usize, + pub t8: usize, + pub crmd: usize, + pub prmd: usize, + pub euen: usize, + pub misc: usize, + pub ecfg: usize, + pub estat: usize, + pub era: usize, + pub badv: usize, + pub badi: usize, + pub eentry: usize, + pub tlbidx: usize, + pub tlbehi: usize, + pub tlbelo0: usize, + pub tlbelo1: usize, + pub asid: usize, + pub pgdl: usize, + pub pgdh: usize, + pub pwcl: usize, + pub pwch: usize, + pub stlbps: usize, + pub rvacfg: usize, + pub cpuid: usize, + pub prcfg1: usize, + pub prcfg2: usize, + pub prcfg3: usize, + pub save0: usize, + pub save1: usize, + pub save2: usize, + pub save3: usize, + pub save4: usize, + pub save5: usize, + pub save6: usize, + pub save7: usize, + pub tid: usize, + pub tcfg: usize, + pub tval: usize, + pub cntc: usize, + pub ticlr: usize, + pub tlbrentry: usize, + pub tlbrbadv: usize, + pub tlbrera: usize, + pub tlbrsave: usize, + pub tlbrelo0: usize, + pub tlbrelo1: usize, + pub tlbrehi: usize, + pub tlbrprmd: usize, + pub dmw0: usize, + pub dmw1: usize, + pub dmw2: usize, + pub dmw3: usize, + + pub second_crmd: usize, + pub second_prmd: usize, + pub second_euen: usize, + pub second_misc: usize, + pub second_ecfg: usize, + pub second_estat: usize, + pub second_era: usize, + pub second_badv: usize, + pub second_badi: usize, + pub second_eentry: usize, + pub second_tlbidx: usize, + pub second_tlbehi: usize, + pub second_tlbelo0: usize, + pub second_tlbelo1: usize, + pub second_asid: usize, + pub second_pgdl: usize, + pub second_pgdh: usize, + pub second_pwcl: usize, + pub second_pwch: usize, + pub second_stlbps: usize, + pub second_rvacfg: usize, + pub second_cpuid: usize, + pub second_prcfg1: usize, + pub second_prcfg2: usize, + pub second_prcfg3: usize, + pub second_save0: usize, + pub second_save1: usize, + pub second_save2: usize, + pub second_save3: usize, + pub second_save4: usize, + pub second_save5: usize, + pub second_save6: usize, + pub second_save7: usize, + pub second_tid: usize, + pub second_tcfg: usize, + pub second_tval: usize, + pub second_cntc: usize, + pub second_ticlr: usize, + pub second_tlbrentry: usize, + pub second_tlbrbadv: usize, + pub second_tlbrera: usize, + pub second_tlbrsave: usize, + pub second_tlbrelo0: usize, + pub second_tlbrelo1: usize, + pub second_tlbrehi: usize, + pub second_tlbrprmd: usize, + pub second_dmw0: usize, + pub second_dmw1: usize, + pub second_dmw2: usize, + pub second_dmw3: usize, +} + +/// Flattened GCSR values extracted from BootContext (primary or secondary). +struct GcsrSnapshot { + crmd: usize, + prmd: usize, + euen: usize, + misc: usize, + ecfg: usize, + estat: usize, + era: usize, + badv: usize, + badi: usize, + eentry: usize, + tlbidx: usize, + tlbehi: usize, + tlbelo0: usize, + tlbelo1: usize, + asid: usize, + pgdl: usize, + pgdh: usize, + pwcl: usize, + pwch: usize, + stlbps: usize, + rvacfg: usize, + cpuid: usize, + prcfg1: usize, + prcfg2: usize, + prcfg3: usize, + save0: usize, + save1: usize, + save2: usize, + save3: usize, + save4: usize, + save5: usize, + save6: usize, + save7: usize, + tid: usize, + tcfg: usize, + tval: usize, + cntc: usize, + ticlr: usize, + tlbrentry: usize, + tlbrbadv: usize, + tlbrera: usize, + tlbrsave: usize, + tlbrelo0: usize, + tlbrelo1: usize, + tlbrehi: usize, + tlbrprmd: usize, + dmw0: usize, + dmw1: usize, + dmw2: usize, + dmw3: usize, +} + +impl GcsrSnapshot { + fn from_primary(b: &BootContext, vcpu_id: usize) -> Self { + Self { + crmd: b.crmd, + prmd: b.prmd, + euen: b.euen, + misc: b.misc, + ecfg: b.ecfg, + estat: b.estat, + era: b.era, + badv: b.badv, + badi: b.badi, + eentry: b.eentry, + tlbidx: b.tlbidx, + tlbehi: b.tlbehi, + tlbelo0: b.tlbelo0, + tlbelo1: b.tlbelo1, + asid: b.asid, + pgdl: b.pgdl, + pgdh: b.pgdh, + pwcl: b.pwcl, + pwch: b.pwch, + stlbps: b.stlbps, + rvacfg: b.rvacfg, + cpuid: vcpu_id, + prcfg1: b.prcfg1, + prcfg2: b.prcfg2, + prcfg3: b.prcfg3, + save0: b.save0, + save1: b.save1, + save2: b.save2, + save3: b.save3, + save4: b.save4, + save5: b.save5, + save6: b.save6, + save7: b.save7, + tid: vcpu_id, + tcfg: b.tcfg, + tval: b.tval, + cntc: b.cntc, + ticlr: b.ticlr, + tlbrentry: b.tlbrentry, + tlbrbadv: b.tlbrbadv, + tlbrera: b.tlbrera, + tlbrsave: b.tlbrsave, + tlbrelo0: b.tlbrelo0, + tlbrelo1: b.tlbrelo1, + tlbrehi: b.tlbrehi, + tlbrprmd: b.tlbrprmd, + dmw0: b.dmw0, + dmw1: b.dmw1, + dmw2: b.dmw2, + dmw3: b.dmw3, + } + } + + fn from_secondary(b: &BootContext, vcpu_id: usize) -> Self { + Self { + crmd: b.second_crmd, + prmd: b.second_prmd, + euen: b.second_euen, + misc: b.second_misc, + ecfg: b.second_ecfg, + estat: b.second_estat, + era: b.second_era, + badv: b.second_badv, + badi: b.second_badi, + eentry: b.second_eentry, + tlbidx: b.second_tlbidx, + tlbehi: b.second_tlbehi, + tlbelo0: b.second_tlbelo0, + tlbelo1: b.second_tlbelo1, + asid: b.second_asid, + pgdl: b.second_pgdl, + pgdh: b.second_pgdh, + pwcl: b.second_pwcl, + pwch: b.second_pwch, + stlbps: b.second_stlbps, + rvacfg: b.second_rvacfg, + cpuid: vcpu_id, + prcfg1: b.second_prcfg1, + prcfg2: b.second_prcfg2, + prcfg3: b.second_prcfg3, + save0: b.second_save0, + save1: b.second_save1, + save2: b.second_save2, + save3: b.second_save3, + save4: b.second_save4, + save5: b.second_save5, + save6: b.second_save6, + save7: b.second_save7, + tid: vcpu_id, + tcfg: b.second_tcfg, + tval: b.second_tval, + cntc: b.second_cntc, + ticlr: b.second_ticlr, + tlbrentry: b.second_tlbrentry, + tlbrbadv: b.second_tlbrbadv, + tlbrera: b.second_tlbrera, + tlbrsave: b.second_tlbrsave, + tlbrelo0: b.second_tlbrelo0, + tlbrelo1: b.second_tlbrelo1, + tlbrehi: b.second_tlbrehi, + tlbrprmd: b.second_tlbrprmd, + dmw0: b.second_dmw0, + dmw1: b.second_dmw1, + dmw2: b.second_dmw2, + dmw3: b.second_dmw3, + } + } + + fn write_all(&self) { + write_gcsr_crmd(self.crmd); + write_gcsr_prmd(self.prmd); + write_gcsr_pgdh(self.euen); + write_gcsr_pgdl(self.misc); + write_gcsr_tval(self.ecfg); + write_gcsr_estat(self.estat); + write_gcsr_era(self.era); + write_gcsr_badv(self.badv); + write_gcsr_badi(self.badi); + write_gcsr_eentry(self.eentry); + write_gcsr_tlbidx(self.tlbidx); + write_gcsr_tlbehi(self.tlbehi); + write_gcsr_tlbelo0(self.tlbelo0); + write_gcsr_tlbelo1(self.tlbelo1); + write_gcsr_asid(self.asid); + write_gcsr_pgdl(self.pgdl); + write_gcsr_pgdh(self.pgdh); + write_gcsr_pwcl(self.pwcl); + write_gcsr_pwch(self.pwch); + write_gcsr_stlbps(self.stlbps); + write_gcsr_rvacfg(self.rvacfg); + write_gcsr_cpuid(self.cpuid); + write_gcsr_prcfg1(self.prcfg1); + write_gcsr_prcfg2(self.prcfg2); + write_gcsr_prcfg3(self.prcfg3); + write_gcsr_save0(self.save0); + write_gcsr_save1(self.save1); + write_gcsr_save2(self.save2); + write_gcsr_save3(self.save3); + write_gcsr_save4(self.save4); + write_gcsr_save5(self.save5); + write_gcsr_save6(self.save6); + write_gcsr_save7(self.save7); + write_gcsr_tid(self.tid); + write_gcsr_tcfg(self.tcfg); + write_gcsr_tval(self.tval); + write_gcsr_cntc(self.cntc); + write_gcsr_ticlr(self.ticlr); + write_gcsr_tlbrentry(self.tlbrentry); + write_gcsr_tlbrbadv(self.tlbrbadv); + write_gcsr_tlbrera(self.tlbrera); + write_gcsr_tlbrsave(self.tlbrsave); + write_gcsr_tlbrelo0(self.tlbrelo0); + write_gcsr_tlbrelo1(self.tlbrelo1); + write_gcsr_tlbrehi(self.tlbrehi); + write_gcsr_tlbrprmd(self.tlbrprmd); + write_gcsr_dmw0(self.dmw0); + write_gcsr_dmw1(self.dmw1); + write_gcsr_dmw2(self.dmw2); + write_gcsr_dmw3(self.dmw3); + } +} + +pub type IpiState = LoongArch64IpiState; +pub type Eiointc = LoongArch64Eiointc; + #[repr(C)] #[derive(Debug)] pub struct ArchCpu { @@ -39,6 +401,15 @@ pub struct ArchCpu { pub stack_top: usize, pub cpuid: usize, pub init: bool, + + // boneinscri 2026.04 + // ipi/eiointc/timer according to kvm + pub irq_pending: usize, + pub irq_clear: usize, + pub ipi_state: Mutex, + pub eiointc: Mutex, + pub expire: isize, + pub csr: [usize; 0x513], } impl ArchCpu { @@ -48,9 +419,30 @@ impl ArchCpu { stack_top: 0, cpuid, init: false, + irq_pending: 0, + irq_clear: 0, + ipi_state: Mutex::new(LoongArch64IpiState::new()), + eiointc: Mutex::new(LoongArch64Eiointc::new()), + expire: 0, + csr: [0; 0x513], }; return ret; } + + // ================ + // boneinscri : 2026.04 (for smp) + pub fn add_irq(&mut self, irq: usize) { + let mask = 1 << irq; + self.irq_pending = self.irq_pending | mask; + self.irq_clear = self.irq_clear & (!mask); + } + pub fn remove_irq(&mut self, irq: usize) { + let mask = 1 << irq; + self.irq_pending = self.irq_pending & (!mask); + self.irq_clear = self.irq_clear | mask; + } + // ================ + pub fn get_cpuid(&self) -> usize { self.cpuid } @@ -61,45 +453,22 @@ impl ArchCpu { self.ctx.sepc = entry; self.stack_top = self.stack_top() as usize; } - pub fn run(&mut self) -> ! { - assert!(this_cpu_id() == self.get_cpuid()); - this_cpu_data().activate_gpm(); - this_cpu_data().vcpu_state.store(VcpuState::Running); - if !self.init { - self.init(this_cpu_data().cpu_on_entry, this_cpu_data().id, 0); - self.init = true; - } - // set x[] to all 0 - for i in 0..32 { - self.ctx.x[i] = 0; - } - // set all zone's GCSR.CPUID to 0 beacuse linux running on it will believe it's CPU0 - // - wheatfox 2025.5.20 - self.ctx.gcsr_cpuid = 0; - info!( - "[[CPU virtualization]] CPU{} run@{:#x}", - self.get_cpuid(), - self.ctx.sepc - ); - info!("loongarch64: @{:#x?}", self); - // step 1: enable guest mode - // step 2: set guest entry to era - // step 3: run ertn and enter guest mode + /// Common vcpu entry: write SAVE3/SAVE4, flush TLB, jump to guest. + fn vcpu_enter(&mut self) -> ! { let ctx_addr = &mut self.ctx as *mut ZoneContext; debug!( - "loongarch64: ArchCpu::run: percpu_s={:#x}", + "loongarch64: ArchCpu::vcpu_enter: percpu_s={:#x}", self.stack_top() - PER_CPU_SIZE ); debug!( - "loongarch64: ArchCpu::run: ctx_addr={:#x}, size={}", + "loongarch64: ArchCpu::vcpu_enter: ctx_addr={:#x}, size={}", ctx_addr as usize, core::mem::size_of::() ); debug!( - "loongarch64: ArchCpu::run: stack_tp={:#x}", + "loongarch64: ArchCpu::vcpu_enter: stack_tp={:#x}", self.stack_top() ); - unsafe { asm!( "csrwr {}, {LOONGARCH_CSR_SAVE3}", @@ -109,16 +478,123 @@ impl ArchCpu { LOONGARCH_CSR_SAVE3 = const 0x33, LOONGARCH_CSR_SAVE4 = const 0x34, ); + asm!("invtlb 0, $r0, $r0"); } + super::trap::_vcpu_return(ctx_addr as usize); + panic!("loongarch64: ArchCpu::vcpu_enter: unreachable"); + } - unsafe { - asm!("invtlb 0, $r0, $r0"); // flush TLBs + pub fn run(&mut self) -> ! { + assert!(this_cpu_id() == self.get_cpuid()); + this_cpu_data().activate_gpm(); + this_cpu_data().vcpu_state.store(VcpuState::Running); + + let boot_ctx = unsafe { &mut *(CPU_BOOT_CONTEXT_ADDRESS as *mut BootContext) }; + info!("boot_ctx_addr={:#x}", CPU_BOOT_CONTEXT_ADDRESS); + info!("loongarch64: ArchCpu::run: boot_ctx={:#x?}", boot_ctx); + + let vcpu_id = get_vcpuid_from_pcpuid(self.get_cpuid()); + info!("gcsr_cpu_id : {}", vcpu_id); + + for i in 0..32 { + self.ctx.x[i] = 0; } - super::trap::_vcpu_return(ctx_addr as usize); + let mut snap = GcsrSnapshot::from_primary(boot_ctx, vcpu_id); + + let zone_id = this_zone_id(); + if zone_id == 0 { + this_cpu_data().cpu_on_entry = boot_ctx.start_image; + info!( + "boot_ctx.efi_system_table: {:#x?}", + boot_ctx.efi_system_table + ); + self.ctx.x[4] = boot_ctx.image_handle; + self.ctx.x[5] = 0; + self.ctx.x[6] = 0; + info!( + "a0={:#x?} a1={:#x?} a2={:#x?}", + self.ctx.x[4], self.ctx.x[5], self.ctx.x[6] + ); + } else { + let is_acpi = { + let zone = this_zone(); + zone.boot_method.starts_with(b"acpi") + }; + if is_acpi { + self.ctx.x[4] = 1; + self.ctx.x[5] = boot_ctx.cmd_line_ptr; + self.ctx.x[6] = boot_ctx.efi_system_table; + } else { + self.ctx.x[4] = 0; + self.ctx.x[5] = 0; + self.ctx.x[6] = 0; + } + info!("zone: {} boot_method: acpi={}, x[4](a0)={:#x}, x[5](a1/cmd_line_ptr)={:#x}, x[6](a2/efi_system_table)={:#x}", + zone_id, is_acpi, self.ctx.x[4], self.ctx.x[5], self.ctx.x[6]); + + snap.dmw0 = read_csr_dmw0(); + snap.dmw1 = read_csr_dmw1(); + snap.dmw2 = read_csr_dmw2(); + snap.dmw3 = read_csr_dmw3(); + if this_cpu_data().cpu_on_entry & 0xffff_0000_0000_0000 == 0 { + snap.dmw1 &= 0x0000_ffff_ffff_ffff; // for npucore + } + } + + if !self.init { + self.init(this_cpu_data().cpu_on_entry, this_cpu_data().id, 0); + self.init = true; + } + + self.ctx.x[1] = boot_ctx.ra; + self.ctx.x[2] = boot_ctx.tp; + self.ctx.x[3] = boot_ctx.sp; + self.ctx.x[22] = boot_ctx.fp; + self.ctx.x[23] = boot_ctx.s0; + self.ctx.x[24] = boot_ctx.s1; + self.ctx.x[25] = boot_ctx.s2; + self.ctx.x[26] = boot_ctx.s3; + self.ctx.x[27] = boot_ctx.s4; + self.ctx.x[28] = boot_ctx.s5; + self.ctx.x[29] = boot_ctx.s6; + self.ctx.x[30] = boot_ctx.s7; + self.ctx.x[31] = boot_ctx.s8; + self.ctx.x[14] = boot_ctx.t2; + self.ctx.x[15] = boot_ctx.t3; + self.ctx.x[16] = boot_ctx.t4; + self.ctx.x[17] = boot_ctx.t5; + self.ctx.x[18] = boot_ctx.t6; + self.ctx.x[19] = boot_ctx.t7; + self.ctx.x[20] = boot_ctx.t8; - panic!("loongarch64: ArchCpu::run: unreachable"); + snap.write_all(); + self.vcpu_enter(); } + + pub fn run_secondary(&mut self, smpboot_entry: usize) -> ! { + assert!(this_cpu_id() == self.get_cpuid()); + this_cpu_data().activate_gpm(); + this_cpu_data().vcpu_state.store(VcpuState::Running); + this_cpu_data().cpu_on_entry = smpboot_entry; + + if !self.init { + self.init(this_cpu_data().cpu_on_entry, this_cpu_data().id, 0); + self.init = true; + } + for i in 0..32 { + self.ctx.x[i] = 0; + } + + let vcpu_id = get_vcpuid_from_pcpuid(self.get_cpuid()); + let boot_ctx = unsafe { &mut *(CPU_BOOT_CONTEXT_ADDRESS as *mut BootContext) }; + info!("boot_ctx_addr={:#x}", CPU_BOOT_CONTEXT_ADDRESS); + + let snap = GcsrSnapshot::from_secondary(boot_ctx, vcpu_id); + snap.write_all(); + self.vcpu_enter(); + } + pub fn idle(&mut self) -> ! { let ctx_addr = &mut self.ctx as *mut ZoneContext; unsafe { @@ -135,6 +611,7 @@ impl ArchCpu { this_cpu_data().vcpu_state.store(VcpuState::Stopped); // enable ipi on ecfg ecfg_ipi_enable(); + enable_global_interrupt(); loop {} } } @@ -149,6 +626,11 @@ pub fn cpu_start(cpuid: usize, start_addr: usize, opaque: usize) { 1 => &CORE1_IPI, 2 => &CORE2_IPI, 3 => &CORE3_IPI, + // boneinscri, for 3a6000 smp + 4 => &CORE4_IPI, + 5 => &CORE5_IPI, + 6 => &CORE6_IPI, + 7 => &CORE7_IPI, _ => { panic!("loongarch64: cpu_start: invalid cpuid={}", cpuid); } diff --git a/src/arch/loongarch64/eiointc.rs b/src/arch/loongarch64/eiointc.rs new file mode 100644 index 00000000..5b882168 --- /dev/null +++ b/src/arch/loongarch64/eiointc.rs @@ -0,0 +1,731 @@ +// 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: +// Ming Shen +// + +use core::usize::MAX; + +const EIOINTC_IRQS: usize = 256; +const EIOINTC_ROUTE_MAX_VCPUS: usize = 256; +const LOONGSON_IP_NUM: usize = 8; + +const EIOINTC_IRQS_U8_NUMS: usize = EIOINTC_IRQS / 8; +const EIOINTC_IRQS_U16_NUMS: usize = EIOINTC_IRQS_U8_NUMS / 2; +const EIOINTC_IRQS_U32_NUMS: usize = EIOINTC_IRQS_U8_NUMS / 4; +const EIOINTC_IRQS_U64_NUMS: usize = EIOINTC_IRQS_U8_NUMS / 8; +/* map to ipnum per 32 irqs */ +const EIOINTC_IRQS_NODETYPE_COUNT: usize = 16; + +const EIOINTC_NODETYPE_START: usize = 0xa0; +const EIOINTC_NODETYPE_END: usize = 0xbf; +const EIOINTC_IPMAP_START: usize = 0xc0; +const EIOINTC_IPMAP_END: usize = 0xc7; +const EIOINTC_ENABLE_START: usize = 0x200; +const EIOINTC_ENABLE_END: usize = 0x21f; +const EIOINTC_BOUNCE_START: usize = 0x280; +const EIOINTC_BOUNCE_END: usize = 0x29f; +const EIOINTC_ISR_START: usize = 0x300; +const EIOINTC_ISR_END: usize = 0x31f; +const EIOINTC_COREISR_START: usize = 0x400; +const EIOINTC_COREISR_END: usize = 0x41f; +const EIOINTC_COREMAP_START: usize = 0x800; +const EIOINTC_COREMAP_END: usize = 0x8ff; + +pub const EIOINTC_BASE: usize = 0x1400; +// #define EIOINTC_REG_ROUTE 0x1c00 + +// 0x14a0 - 0x1400 = 0xa0 : nodetype +// 0x14c0 - 0x1400 = 0xc0 : ipmap +// 0x1680 - 0x1400 = 0x280 : bounce +// 0x1c00 - 0x1400 = 0x800 : coremap +// 0x1800 - 0x1400 = 0x400 : coreisr +// 0x1600 - 0x1400 = 0x200 : enable + +pub const EIOINTC_SIZE: usize = 0x900; +pub const EIOINTC_VIRT_BASE: usize = 0x40000000; +pub const EIOINTC_VIRT_SIZE: usize = 0x1000; + +pub const EIOINTC_ENABLE: usize = 1; +pub const EIOINTC_ENABLE_INT_ENCODE: usize = 2; +pub const EIOINTC_ENABLE_CPU_ENCODE: usize = 3; + +macro_rules! bit { + ($nr:expr) => { + 1usize << $nr + }; +} + +const BITS_PER_ELEMENT: usize = 64; +const ARRAY_SIZE: usize = (EIOINTC_IRQS + BITS_PER_ELEMENT - 1) / BITS_PER_ELEMENT; +// the size of u64 array +type BitmapArray = [[[u64; ARRAY_SIZE]; LOONGSON_IP_NUM]; EIOINTC_ROUTE_MAX_VCPUS]; + +pub fn set_bit(bitmap: &mut BitmapArray, cpu: usize, ipum: usize, bit: usize) { + if cpu < EIOINTC_ROUTE_MAX_VCPUS && ipum < LOONGSON_IP_NUM && bit < EIOINTC_IRQS { + let word_index = bit / BITS_PER_ELEMENT; + let bit_index = bit % BITS_PER_ELEMENT; + bitmap[cpu][ipum][word_index] |= (1u64 << bit_index); + } else { + panic!("BitmapArray, set_bit, Index out of bounds"); + } +} + +pub fn clear_bit(bitmap: &mut BitmapArray, cpu: usize, ipum: usize, bit: usize) { + if cpu < EIOINTC_ROUTE_MAX_VCPUS && ipum < LOONGSON_IP_NUM && bit < EIOINTC_IRQS { + let word_index = bit / BITS_PER_ELEMENT; + let bit_index = bit % BITS_PER_ELEMENT; + bitmap[cpu][ipum][word_index] &= !(1u64 << bit_index); + } else { + panic!("BitmapArray, clear_bit, Index out of bounds"); + } +} + +pub fn find_first_bit(bitmap: &BitmapArray, cpu: usize, ipum: usize) -> Option { + if cpu >= EIOINTC_ROUTE_MAX_VCPUS || ipum >= LOONGSON_IP_NUM { + panic!("BitmapArray, find_first_bit, Index out of bounds"); + } + + for (word_index, &word) in bitmap[cpu][ipum].iter().enumerate() { + if word != 0 { + let bit_index = word.trailing_zeros() as usize; + return Some(word_index * BITS_PER_ELEMENT + bit_index); + } + } + None +} + +#[derive(Debug)] +pub struct LoongArch64Eiointc { + pub num_cpu: usize, + pub features: usize, + pub status: usize, + pub nodetype: [u8; EIOINTC_IRQS_NODETYPE_COUNT * 2], // u8 * 32 + pub bounce: [u8; EIOINTC_IRQS_U8_NUMS], // 32 + pub isr: [u8; EIOINTC_IRQS_U8_NUMS], // 32 + pub coreisr: [[u8; EIOINTC_IRQS_U8_NUMS]; EIOINTC_ROUTE_MAX_VCPUS], // 32 * 256 + pub enable: [u8; EIOINTC_IRQS_U8_NUMS], // 32 + pub ipmap: [u8; EIOINTC_IRQS_U8_NUMS / 4], // 8 + pub coremap: [u8; EIOINTC_IRQS], // 256 + pub sw_coremap: [u8; EIOINTC_IRQS], // 256 + pub sw_coreisr: BitmapArray, // 256 * 8 * (4 * 64 bits) +} + +impl LoongArch64Eiointc { + pub fn new() -> Self { + Self { + num_cpu: 0, + features: 0, + status: 0, + nodetype: [0; EIOINTC_IRQS_NODETYPE_COUNT * 2], + bounce: [0; EIOINTC_IRQS_U8_NUMS], + isr: [0; EIOINTC_IRQS_U8_NUMS], + coreisr: [[0; EIOINTC_IRQS_U8_NUMS]; EIOINTC_ROUTE_MAX_VCPUS], + enable: [0; EIOINTC_IRQS_U8_NUMS], + ipmap: [0; EIOINTC_IRQS_U8_NUMS / 4], + coremap: [0; EIOINTC_IRQS], + sw_coremap: [0; EIOINTC_IRQS], + sw_coreisr: [[[0; ARRAY_SIZE]; LOONGSON_IP_NUM]; EIOINTC_ROUTE_MAX_VCPUS], + } + } +} + +pub fn do_real_write_iocsr(addr: usize, val: usize, len: usize) { + match len { + 1 => { + // iocsrwr.b + unsafe { + asm!("iocsrwr.b {}, {}", in(reg) val, in(reg) addr); + } + } + 2 => { + // iocsrwr.h + unsafe { + asm!("iocsrwr.h {}, {}", in(reg) val, in(reg) addr); + } + } + 4 => { + // iocsrwr.w + unsafe { + asm!("iocsrwr.w {}, {}", in(reg) val, in(reg) addr); + } + } + 8 => { + // iocsrwr.d + unsafe { + asm!("iocsrwr.d {}, {}", in(reg) val, in(reg) addr); + } + } + _ => { + // should not reach here + panic!("write invalid iocsr type, this is impossible"); + } + } +} + +pub fn do_real_read_iocsr(addr: usize, len: usize) -> usize { + match len { + 1 => { + // iocsrrd.b + let mut val = 0; + unsafe { + asm!("iocsrrd.b {}, {}", out(reg) val, in(reg) addr); + } + val + } + 2 => { + // iocsrrd.h + let mut val = 0; + unsafe { + asm!("iocsrrd.h {}, {}", out(reg) val, in(reg) addr); + } + val + } + 4 => { + // iocsrrd.w + let mut val = 0; + unsafe { + asm!("iocsrrd.w {}, {}", out(reg) val, in(reg) addr); + } + val + } + 8 => { + // iocsrrd.d + let mut val = 0; + unsafe { + asm!("iocsrrd.d {}, {}", out(reg) val, in(reg) addr); + } + val + } + _ => { + // should not reach here + panic!("read invalid iocsr type, this is impossible"); + } + } +} + +pub fn read_masked_data(pbuf: *const u8, len: usize) -> usize { + unsafe { + match len { + 1 => { + let byte_ptr = pbuf as *mut u8; + *byte_ptr as usize + } + 2 => { + let short_ptr = pbuf as *mut u16; + *short_ptr as usize + } + 4 => { + let int_ptr = pbuf as *mut u32; + *int_ptr as usize + } + 8 => { + let long_ptr = pbuf as *mut u64; + *long_ptr as usize + } + _ => { + panic!("write_memory: invalid length {:#x}", len); + } + } + } +} + +pub fn write_masked_data(pbuf: *mut u8, val: usize, len: usize) { + unsafe { + match len { + 1 => { + let byte_ptr = pbuf as *mut u8; + *byte_ptr = val as u8; + } + 2 => { + let short_ptr = pbuf as *mut u16; + *short_ptr = val as u16; + } + 4 => { + let int_ptr = pbuf as *mut u32; + *int_ptr = val as u32; + } + 8 => { + let long_ptr = pbuf as *mut u64; + *long_ptr = val as u64; + } + _ => { + warn!("write_memory: invalid length {:#x}", len); + } + } + } +} +fn get_masked_data(data: usize, len: usize) -> usize { + match len { + 1 => data & 0xff, + 2 => data & 0xffff, + 4 => data & 0xffffffff, + 8 => data, + _ => { + panic!("read_mailbox: unknown data len: {}", len); + } + } +} + +// ffs和__ffs? +// 查找最低有效位(LSB)的1的位置 +// ffs从1开始,__ffs从0开始 +// trailing_zeros? +// 最低有效位(LSB,即最右边的位)开始连续 0 的个数 +fn ffs(x: usize) -> usize { + if x == 0 { + 0 + } else { + x.trailing_zeros() as usize + 1 + } +} + +fn __ffs(x: usize) -> usize { + if x == 0 { + 0 + } else { + x.trailing_zeros() as usize + } +} + +#[inline] +// ref from Linux kernel +fn count_trailing_zeros(x: usize, len: usize) -> i32 { + const COUNT_TRAILING_ZEROS_0: i32 = -1; + + if len == 4 { + ffs(x) as i32 + } else { + if x != 0 { + __ffs(x) as i32 + } else { + COUNT_TRAILING_ZEROS_0 + } + } +} + +pub fn loongarch_eiointc_readl(pcpu_id: usize, addr: usize, len: usize) -> usize { + let mut ret = 0; + let offset = addr - EIOINTC_BASE; + let pcpu_data = get_cpu_data(pcpu_id); + let eiointc = pcpu_data.arch_cpu.eiointc.lock(); + + match offset { + EIOINTC_NODETYPE_START..=EIOINTC_NODETYPE_END => { + // nodetype + let idx_u8 = (offset - EIOINTC_NODETYPE_START); + let pbuf_read = &eiointc.nodetype[idx_u8]; + ret = read_masked_data(pbuf_read, len); + } + EIOINTC_IPMAP_START..=EIOINTC_IPMAP_END => { + let idx_u8 = (offset - EIOINTC_IPMAP_START); + let pbuf_read = &eiointc.ipmap[idx_u8]; + ret = read_masked_data(pbuf_read, len); + } + EIOINTC_ENABLE_START..=EIOINTC_ENABLE_END => { + let idx_u8 = (offset - EIOINTC_ENABLE_START); + let pbuf_read = &eiointc.enable[idx_u8]; + ret = read_masked_data(pbuf_read, len); + } + EIOINTC_BOUNCE_START..=EIOINTC_BOUNCE_END => { + let idx_u8 = (offset - EIOINTC_BOUNCE_START); + let pbuf_read = &eiointc.bounce[idx_u8]; + ret = read_masked_data(pbuf_read, len); + } + EIOINTC_COREISR_START..=EIOINTC_COREISR_END => { + let idx_u8 = (offset - EIOINTC_COREISR_START); + + if pcpu_id == 4 { + let offset = + EIOINTC_BASE + EIOINTC_COREISR_START + 0 * EIOINTC_IRQS_U8_NUMS + idx_u8; + ret = do_real_read_iocsr(offset, len); + } else { + let offset = + EIOINTC_BASE + EIOINTC_COREISR_START + 0 * EIOINTC_IRQS_U8_NUMS + idx_u8; + ret = do_real_read_iocsr(offset, len); + } + } + EIOINTC_COREMAP_START..=EIOINTC_COREMAP_END => { + let idx_u8 = (offset - EIOINTC_COREMAP_START); + let pbuf_read = &eiointc.coremap[idx_u8]; + ret = read_masked_data(pbuf_read, len); + } + _ => { + panic!( + "loongarch_eiointc_readl, Invalid EIOINTC offset: {:#x}", + offset + ); + } + }; + ret +} + +use crate::consts::MAX_CPU_NUM; +use crate::cpu_data::{get_cpu_data, this_zone}; +fn get_real_pcpu_id(target_cpu_id: usize) -> usize { + assert!(target_cpu_id < MAX_CPU_NUM); + let zone = this_zone(); + let cpu_set = zone.read().cpu_set(); + let target_pcpu_real_id = cpu_set.iter().nth(target_cpu_id).unwrap(); + target_pcpu_real_id +} + +pub fn get_vcpuid_from_pcpuid(target_pcpu_id: usize) -> usize { + assert!(target_pcpu_id < MAX_CPU_NUM); + let zone = this_zone(); + let cpu_set = zone.read().cpu_set(); + let target_vcpuid = cpu_set.pcpuid_to_vcpuid(target_pcpu_id).unwrap(); + target_vcpuid +} + +use crate::PHY_TO_DMW_UNCACHED; +const IOCSR_BASE: usize = 0x1fe00000; +const INT_HWI0: usize = 2; +fn eiointc_update_irq( + eiointc: &mut spin::MutexGuard<'_, LoongArch64Eiointc>, + irq: usize, + level: usize, +) { + let ipmap_u8_idx = irq / 32; + let ipmap_pbuf_read = &eiointc.ipmap[ipmap_u8_idx]; + let mut ipnum = read_masked_data(ipmap_pbuf_read, 1); // u8 + + if ((eiointc.status & bit!(EIOINTC_ENABLE_INT_ENCODE)) == 0) { + let ipnum_new = count_trailing_zeros(ipnum, 1); + if ipnum_new >= 4 { + panic!( + "eiointc_update_irq, no ipnum found, irq: {}, level: {}", + irq, level + ); + } + ipnum = (if ipnum_new >= 0 && ipnum_new < 4 { + ipnum_new + } else { + 0 + }) as usize; + } + + let cpu = eiointc.sw_coremap[irq] as usize; + let irq_index = irq / 32; // u32 + // 8 * 32 = 256 + + let irq_mask = bit!(irq & 0x1f); // 1_1111 : 32 bits / 4 bytes + let irq_index_u8 = irq_index * 4; + + let mut found; + if (level != 0) { + // set + let enable_pbuf_read = &eiointc.enable[irq_index_u8]; + let enable_u32 = read_masked_data(enable_pbuf_read, 4); + if ((enable_u32 & irq_mask) == 0) { + return; + } + + let coreisr_pbuf_read = &eiointc.coreisr[cpu][irq_index_u8]; + let coreisr_u32_new = read_masked_data(coreisr_pbuf_read, 4) | irq_mask; + + let mut check_data_before = 0; + let mut check_data_after = 0; + { + let pbuf_read = &eiointc.coreisr[cpu][irq_index_u8]; + check_data_before = read_masked_data(pbuf_read, 4); + } + let coreisr_pbuf_write = &mut eiointc.coreisr[cpu][irq_index_u8]; + write_masked_data(coreisr_pbuf_write, coreisr_u32_new, 4); // TODO: do real write this + { + let pbuf_read = &eiointc.coreisr[cpu][irq_index_u8]; + check_data_after = read_masked_data(pbuf_read, 4); + } + + found = find_first_bit(&eiointc.sw_coreisr, cpu, ipnum); + set_bit(&mut eiointc.sw_coreisr, cpu, ipnum, irq); + } else { + // clear + let coreisr_pbuf_read = &eiointc.coreisr[cpu][irq_index_u8]; + let coreisr_u32_new = read_masked_data(coreisr_pbuf_read, 4) & (!irq_mask); + + let mut check_data_before = 0; + let mut check_data_after = 0; + { + let pbuf_read = &eiointc.coreisr[cpu][irq_index_u8]; + check_data_before = read_masked_data(pbuf_read, 4); + } + let coreisr_pbuf_write = &mut eiointc.coreisr[cpu][irq_index_u8]; + write_masked_data(coreisr_pbuf_write, coreisr_u32_new, 4); // TODO: do real write this + { + let pbuf_read = &eiointc.coreisr[cpu][irq_index_u8]; + check_data_after = read_masked_data(pbuf_read, 4); + } + + clear_bit(&mut eiointc.sw_coreisr, cpu, ipnum, irq); + found = find_first_bit(&eiointc.sw_coreisr, cpu, ipnum); + } + if (found.is_none()) { + } else if (found.unwrap() < EIOINTC_IRQS) { + return; /* other irq is handling, needn't update parent irq */ + } + + return; + + let int_hw_num = INT_HWI0 + ipnum; + + let target_pcpu_data = get_cpu_data(cpu); // check this carefully + if (level != 0) { + } else { + } +} + +pub fn eiointc_set_irq(pcpu_id: usize, irq: usize, level: usize) { + info!( + "eiointc_set_irq, pcpu_id: {}, irq: {}, level: {}", + pcpu_id, irq, level + ); + let pcpu_data = get_cpu_data(pcpu_id); + let mut eiointc = pcpu_data.arch_cpu.eiointc.lock(); + + let isr_bitmap_word = irq / 8; + let isr_bitmap_offset = irq % 8; + if level != 0 { + eiointc.isr[isr_bitmap_word] |= bit!(isr_bitmap_offset) as u8; + warn!("eiointc_set_irq, set, irq: {}", irq); + } else { + eiointc.isr[isr_bitmap_word] &= !bit!(isr_bitmap_offset) as u8; + warn!("eiointc_set_irq, clear, irq: {}", irq); + } + eiointc_update_irq(&mut eiointc, irq, level); +} + +fn eiointc_enable_irq( + eiointc: &mut spin::MutexGuard<'_, LoongArch64Eiointc>, + index: usize, + mask: usize, + level: usize, +) { + let mut val = mask & 0xff; + + let mut irq = ffs(val); + + while (irq != 0) { + eiointc_update_irq(eiointc, irq - 1 + index * 8, level); + + val &= !bit!(irq - 1); + irq = ffs(val); + } +} + +use core::{ + arch::asm, + char, panic, + ptr::{read_volatile, write_volatile}, + sync::atomic::AtomicU64, +}; + +fn eiointc_update_sw_coremap( + eiointc: &mut spin::MutexGuard<'_, LoongArch64Eiointc>, + irq: usize, + pvalue: usize, + len: usize, + notify: bool, +) { + let mut val = pvalue; + for i in 0..len { + let mut cpu = (val & 0xff); + val >>= 8; + + if ((eiointc.status & bit!(EIOINTC_ENABLE_INT_ENCODE)) == 0) { + cpu = __ffs(cpu); + + if cpu >= 4 { + error!( + "eiointc_update_sw_coremap, attention 2, check it, cpu : {}", + cpu + ); + } + cpu = if cpu >= 4 { 0 } else { cpu }; + + assert!(cpu >= 0); + } + + if (eiointc.sw_coremap[irq + i] == cpu as u8) { + // warn!("eiointc_update_sw_coremap, continue, cpu: {}", cpu); + continue; + } + + let pcpu_id: usize = get_real_pcpu_id(cpu); + if pcpu_id != cpu { + warn!( + "[Attention], eiointc_update_sw_coremap, pcpu_id: {}, cpu: {}", + pcpu_id, cpu + ); + } + + if (notify) { + eiointc_update_irq(eiointc, irq + i, 0); // clear original irq + + eiointc.sw_coremap[irq + i] = pcpu_id as u8; + eiointc.coremap[irq + i] = (1 << pcpu_id) as u8; // update it! + + eiointc_update_irq(eiointc, irq + i, 1); // set new irq + } else { + panic!("notify is false, not tested"); + eiointc.sw_coremap[irq + i] = cpu as u8; + } + } +} + +pub fn find_first_bit_single(val: usize, bits: usize) -> usize { + assert!(bits == 8 || bits == 16 || bits == 32 || bits == 64); + let masked_value = get_masked_data(val, bits / 8); + let pos = ffs(masked_value); + + if pos == 0 { + bits + } else { + (pos - 1) as usize + } +} + +pub fn loongarch_eiointc_writel(pcpu_id: usize, addr: usize, val: usize, len: usize) -> usize { + let mut ret = val; + let offset = addr - EIOINTC_BASE; + + let data = get_masked_data(val, len); + + let pcpu_data = get_cpu_data(pcpu_id); + let mut eiointc = pcpu_data.arch_cpu.eiointc.lock(); + + match offset { + EIOINTC_NODETYPE_START..=EIOINTC_NODETYPE_END => { + // nodetype + let idx_u8 = (offset - EIOINTC_NODETYPE_START); + + let pbuf_write = &mut eiointc.nodetype[idx_u8]; + } + EIOINTC_IPMAP_START..=EIOINTC_IPMAP_END => { + // ipmap + let idx_u8 = (offset - EIOINTC_IPMAP_START); + + let pbuf_write = &mut eiointc.ipmap[idx_u8]; + write_masked_data(pbuf_write, val, len); + } + EIOINTC_ENABLE_START..=EIOINTC_ENABLE_END => { + // enable (important) + let idx_u8 = (offset - EIOINTC_ENABLE_START); + + let enable_pbuf_read = &eiointc.enable[idx_u8]; + let old_enable = read_masked_data(enable_pbuf_read, len); + + let enable_pbuf_write = &mut eiointc.enable[idx_u8]; + write_masked_data(enable_pbuf_write, val, len); + + let enable_pbuf_read = &eiointc.enable[idx_u8]; + let enable_val = read_masked_data(enable_pbuf_read, len); + + do_real_write_iocsr(addr, val, len); + + return ret; + /* + * 1: enable irq. + * update irq when isr is set. + */ + let data = enable_val & !old_enable; + info!( + "write enable, set, enable_val & !old_enable : {:#x}/{}", + data, + data.trailing_zeros() + ); + if old_enable != 0 { + for i in 0..len { + let mask = (data >> (i * 8)) & 0xff; + eiointc_enable_irq(&mut eiointc, idx_u8 + i, mask, 1); + } + } + /* + * 0: disable irq. + * update irq when isr is set. + */ + let data = !enable_val & old_enable; + info!( + "write enable, clear, !enable_val & old_enable : {:#x}/{}", + data, + data.trailing_zeros() + ); + if old_enable != 0 { + for i in 0..len { + let mask = (data >> (i * 8)) & 0xff; + eiointc_enable_irq(&mut eiointc, idx_u8 + i, mask, 0); + } + } + } + EIOINTC_BOUNCE_START..=EIOINTC_BOUNCE_END => { + // bounce + let idx_u8 = (offset - EIOINTC_BOUNCE_START); + + let bounce_pbuf_write = &mut eiointc.bounce[idx_u8]; + write_masked_data(bounce_pbuf_write, val, len); + } + + EIOINTC_COREISR_START..=EIOINTC_COREISR_END => { + let idx_u8 = (offset - EIOINTC_COREISR_START); + + /* use attrs to get current cpu index */ + let cpu = pcpu_id; + + let mut coreisr = data; + + let coreisr_pbuf_read = &eiointc.coreisr[cpu][idx_u8]; + let old_coreisr = read_masked_data(coreisr_pbuf_read, len); + + /* write 1 to clear interrupt */ + let coreisr_new = coreisr & !old_coreisr; + + let coreisr_pbuf_write = &mut eiointc.coreisr[cpu][idx_u8]; + write_masked_data(coreisr_pbuf_write, coreisr_new, len); // TODO: do real write this + + coreisr &= old_coreisr; + + let bits = len * 8; // 4 * 8 = 32? + let index = idx_u8 / len; + + let mut irq = find_first_bit_single(coreisr, bits); + while (irq < bits) { + eiointc_update_irq(&mut eiointc, irq + index * bits, 0); + + // update coreisr and irq + coreisr &= !bit!(irq); // clear irq from coreisr + irq = find_first_bit_single(coreisr, bits); + } + } + EIOINTC_COREMAP_START..=EIOINTC_COREMAP_END => { + // coremap (important) + let irq = offset - EIOINTC_COREMAP_START; + let idx_u8 = irq; + + let coremap_pbuf_write = &mut eiointc.coremap[idx_u8]; + write_masked_data(coremap_pbuf_write, val, len); + + eiointc_update_sw_coremap(&mut eiointc, irq, val, len, true); + + let pbuf_read = &eiointc.coremap[idx_u8]; + let coremap_read = read_masked_data(pbuf_read, len); + ret = coremap_read; // update! + } + _ => { + panic!("eiointc_writel, Invalid EIOINTC offset: {:#x}", offset); + } + }; + + do_real_write_iocsr(addr, ret, len); + ret +} diff --git a/src/arch/loongarch64/entry.rs b/src/arch/loongarch64/entry.rs index a66148b5..ae0d6609 100644 --- a/src/arch/loongarch64/entry.rs +++ b/src/arch/loongarch64/entry.rs @@ -13,8 +13,10 @@ // // Authors: // Yulong Han +// Ming Shen // use crate::consts::PER_CPU_SIZE; +use crate::platform::CPU_BOOT_CONTEXT_ADDRESS; const DMW_DA_BITS: usize = 48; const CSR_DMW0_PLV0: usize = 1 << 0; @@ -95,3 +97,166 @@ pub unsafe extern "C" fn arch_entry() -> i32 { options(noreturn), ); } + +#[naked] +#[no_mangle] +#[link_section = ".text.entry"] +pub unsafe extern "C" fn arch_secondary_entry() -> i32 { + core::arch::asm!( + "li.d $r12, {CPU_BOOT_CONTEXT_ADDRESS} + csrrd $r13, {LOONGARCH_CSR_CRMD} + st.d $r13, $r12, (21+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_PRMD} + st.d $r13, $r12, (22+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_EUEN} + st.d $r13, $r12, (23+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_MISC} + st.d $r13, $r12, (24+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_ECFG} + st.d $r13, $r12, (25+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_ESTAT} + st.d $r13, $r12, (26+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_ERA} + st.d $r13, $r12, (27+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_BADV} + st.d $r13, $r12, (28+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_BADI} + st.d $r13, $r12, (29+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_EENTRY} + st.d $r13, $r12, (30+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_TLBIDX} + st.d $r13, $r12, (31+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_TLBEHI} + st.d $r13, $r12, (32+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_TLBELO0} + st.d $r13, $r12, (33+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_TLBELO1} + st.d $r13, $r12, (34+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_ASID} + st.d $r13, $r12, (35+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_PGDL} + st.d $r13, $r12, (36+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_PGDH} + st.d $r13, $r12, (37+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_PWCL} + st.d $r13, $r12, (38+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_PWCH} + st.d $r13, $r12, (39+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_STLBPS} + st.d $r13, $r12, (40+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_RVACFG} + st.d $r13, $r12, (41+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_CPUID} + st.d $r13, $r12, (42+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_PRCFG1} + st.d $r13, $r12, (43+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_PRCFG2} + st.d $r13, $r12, (44+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_PRCFG3} + st.d $r13, $r12, (45+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_SAVE0} + st.d $r13, $r12, (46+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_SAVE1} + st.d $r13, $r12, (47+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_SAVE2} + st.d $r13, $r12, (48+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_SAVE3} + st.d $r13, $r12, (49+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_SAVE4} + st.d $r13, $r12, (50+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_SAVE5} + st.d $r13, $r12, (51+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_SAVE6} + st.d $r13, $r12, (52+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_SAVE7} + st.d $r13, $r12, (53+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_TMID} + st.d $r13, $r12, (54+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_TCFG} + st.d $r13, $r12, (55+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_TVAL} + st.d $r13, $r12, (56+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_CNTC} + st.d $r13, $r12, (57+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_TICLR} + st.d $r13, $r12, (58+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_TLBRENTRY} + st.d $r13, $r12, (59+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_TLBRBADV} + st.d $r13, $r12, (60+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_TLBRERA} + st.d $r13, $r12, (61+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_TLBRSAVE} + st.d $r13, $r12, (62+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_TLBRELO0} + st.d $r13, $r12, (63+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_TLBRELO1} + st.d $r13, $r12, (64+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_TLBREHI} + st.d $r13, $r12, (65+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_TLBRPRMD} + st.d $r13, $r12, (66+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_DMW0} + st.d $r13, $r12, (67+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_DMW1} + st.d $r13, $r12, (68+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_DMW2} + st.d $r13, $r12, (69+3+50)*8 + csrrd $r13, {LOONGARCH_CSR_DMW3} + st.d $r13, $r12, (70+3+50)*8 + bl arch_entry", + CPU_BOOT_CONTEXT_ADDRESS = const CPU_BOOT_CONTEXT_ADDRESS, + LOONGARCH_CSR_CRMD = const 0x0, + LOONGARCH_CSR_PRMD= const 0x1, + LOONGARCH_CSR_EUEN= const 0x2, + LOONGARCH_CSR_MISC = const 0x3, + LOONGARCH_CSR_ECFG = const 0x4, + LOONGARCH_CSR_ESTAT = const 0x5, + LOONGARCH_CSR_ERA = const 0x6, + LOONGARCH_CSR_BADV = const 0x7, + LOONGARCH_CSR_BADI = const 0x8, + LOONGARCH_CSR_EENTRY = const 0xc, + LOONGARCH_CSR_TLBIDX = const 0x10, + LOONGARCH_CSR_TLBEHI = const 0x11, + LOONGARCH_CSR_TLBELO0 = const 0x12, + LOONGARCH_CSR_TLBELO1 = const 0x13, + LOONGARCH_CSR_ASID = const 0x18, + LOONGARCH_CSR_PGDL = const 0x19, + LOONGARCH_CSR_PGDH = const 0x1a, + LOONGARCH_CSR_PWCL = const 0x1c, + LOONGARCH_CSR_PWCH = const 0x1d, + LOONGARCH_CSR_STLBPS = const 0x1e, + LOONGARCH_CSR_RVACFG = const 0x1f, + LOONGARCH_CSR_CPUID = const 0x20, + LOONGARCH_CSR_PRCFG1 = const 0x21, + LOONGARCH_CSR_PRCFG2 = const 0x22, + LOONGARCH_CSR_PRCFG3 = const 0x23, + LOONGARCH_CSR_SAVE0 = const 0x30, + LOONGARCH_CSR_SAVE1 = const 0x31, + LOONGARCH_CSR_SAVE2 = const 0x32, + LOONGARCH_CSR_SAVE3 = const 0x33, + LOONGARCH_CSR_SAVE4 = const 0x34, + LOONGARCH_CSR_SAVE5 = const 0x35, + LOONGARCH_CSR_SAVE6 = const 0x36, + LOONGARCH_CSR_SAVE7 = const 0x37, + LOONGARCH_CSR_TMID = const 0x40, + LOONGARCH_CSR_TCFG = const 0x41, + LOONGARCH_CSR_TVAL = const 0x42, + LOONGARCH_CSR_CNTC = const 0x43, + LOONGARCH_CSR_TICLR = const 0x44, + LOONGARCH_CSR_TLBRENTRY = const 0x88, + LOONGARCH_CSR_TLBRBADV = const 0x89, + LOONGARCH_CSR_TLBRERA = const 0x8a, + LOONGARCH_CSR_TLBRSAVE = const 0x8b, + LOONGARCH_CSR_TLBRELO0 = const 0x8c, + LOONGARCH_CSR_TLBRELO1 = const 0x8d, + LOONGARCH_CSR_TLBREHI = const 0x8e, + LOONGARCH_CSR_TLBRPRMD = const 0x8f, + LOONGARCH_CSR_DMW0 = const 0x180, + LOONGARCH_CSR_DMW1 = const 0x181, + LOONGARCH_CSR_DMW2 = const 0x182, + LOONGARCH_CSR_DMW3 = const 0x183, + options(noreturn), + + ); +} diff --git a/src/arch/loongarch64/ipi.rs b/src/arch/loongarch64/ipi.rs index 1e1f0cfd..6d02dfd2 100644 --- a/src/arch/loongarch64/ipi.rs +++ b/src/arch/loongarch64/ipi.rs @@ -13,10 +13,16 @@ // // Authors: // Yulong Han +// Ming Shen // use crate::arch::cpu::this_cpu_id; -use crate::consts::IPI_EVENT_CLEAR_INJECT_IRQ; +use crate::consts::{IPI_EVENT_CLEAR_INJECT_IRQ, MAX_CPU_NUM}; +use crate::cpu_data::{get_cpu_data, this_zone}; use crate::device::common::MMIODerefWrapper; +use crate::event::{ + IPI_EVENT_SHUTDOWN, IPI_EVENT_VIRTIO_INJECT_IRQ, IPI_EVENT_WAKEUP, + IPI_EVENT_WAKEUP_VIRTIO_DEVICE, +}; use core::arch::asm; use core::ptr::write_volatile; use loongArch64::cpu; @@ -34,8 +40,20 @@ pub fn arch_send_event(cpu_id: u64, sgi_num: u64) { "loongarch64: arch_send_event: sending event to cpu: {}, sgi_num: {}", cpu_id, sgi_num ); - // just call ipi_write_action - ipi_write_action(cpu_id as usize, sgi_num as usize); + + if sgi_num == IPI_EVENT_WAKEUP as u64 { + ipi_send_general(cpu_id as usize, SMP_BOOT_CPU as u32); + } else if sgi_num == IPI_EVENT_SHUTDOWN as u64 { + ipi_send_general(cpu_id as usize, HVISOR_SHUTDOWN as u32); + } else if sgi_num == IPI_EVENT_VIRTIO_INJECT_IRQ as u64 { + ipi_send_general(cpu_id as usize, HVISOR_EVENT_VIRTIO_INJECT_IRQ as u32); + } else if sgi_num == IPI_EVENT_WAKEUP_VIRTIO_DEVICE as u64 { + ipi_send_general(cpu_id as usize, HVISOR_EVENT_WAKEUP_VIRTIO_DEVICE as u32); + } else if sgi_num == IPI_EVENT_CLEAR_INJECT_IRQ as u64 { + ipi_send_general(cpu_id as usize, HVISOR_EVENT_VIRTIO_CLEAR_IRQ as u32); + } else { + panic!("unknown sgi_num, {}", sgi_num); + } } register_bitfields! [ @@ -84,6 +102,18 @@ pub static CORE2_IPI: MMIODerefWrapper = pub static CORE3_IPI: MMIODerefWrapper = unsafe { MMIODerefWrapper::new(IPI_MMIO_BASE + 0x1300) }; +// boneinscri -- 2026.04 (for 3a6000 smp) +const MMIO_BASE_2: usize = 0x8000_0000_1fe1_0000; +const IPI_MMIO_BASE_2: usize = MMIO_BASE_2; +pub static CORE4_IPI: MMIODerefWrapper = + unsafe { MMIODerefWrapper::new(IPI_MMIO_BASE_2 + 0x1000) }; +pub static CORE5_IPI: MMIODerefWrapper = + unsafe { MMIODerefWrapper::new(IPI_MMIO_BASE_2 + 0x1100) }; +pub static CORE6_IPI: MMIODerefWrapper = + unsafe { MMIODerefWrapper::new(IPI_MMIO_BASE_2 + 0x1200) }; +pub static CORE7_IPI: MMIODerefWrapper = + unsafe { MMIODerefWrapper::new(IPI_MMIO_BASE_2 + 0x1300) }; + // ipi actions pub const SMP_BOOT_CPU: usize = 0x1; pub const SMP_RESCHEDULE: usize = 0x2; @@ -91,6 +121,12 @@ pub const SMP_CALL_FUNCTION: usize = 0x4; // customized actions :), since there is no docs on this yet pub const HVISOR_START_VCPU: usize = 0x8; +// boneinscri 2026.04 +pub const HVISOR_SHUTDOWN: usize = 0x40; +pub const HVISOR_EVENT_VIRTIO_INJECT_IRQ: usize = 0x80; +pub const HVISOR_EVENT_WAKEUP_VIRTIO_DEVICE: usize = 0x100; +pub const HVISOR_EVENT_VIRTIO_CLEAR_IRQ: usize = 0x200; + fn iocsr_mbuf_send_box_lo(a: usize) -> usize { a << 1 } @@ -194,6 +230,12 @@ pub fn ipi_write_action(cpu_id: usize, _action: usize) { 1 => &CORE1_IPI, 2 => &CORE2_IPI, 3 => &CORE3_IPI, + + // boneinscri 2026.04 (3a6000 smp) + 4 => &CORE4_IPI, + 5 => &CORE5_IPI, + 6 => &CORE6_IPI, + 7 => &CORE7_IPI, _ => { error!("ipi_write_action_legacy: invalid cpu_id: {}", cpu_id); return; @@ -218,6 +260,12 @@ pub fn mail_send(data: usize, cpu_id: usize, mailbox_id: usize) { 1 => &CORE1_IPI, 2 => &CORE2_IPI, 3 => &CORE3_IPI, + + // boneinscri 2026.04 (3a6000 smp) + 4 => &CORE4_IPI, + 5 => &CORE5_IPI, + 6 => &CORE6_IPI, + 7 => &CORE7_IPI, _ => { error!("mail_send: invalid cpu_id: {}", cpu_id); return; @@ -245,6 +293,12 @@ pub fn enable_ipi(cpu_id: usize) { 1 => &CORE1_IPI, 2 => &CORE2_IPI, 3 => &CORE3_IPI, + + // boneinscri 2026.04 (3a6000 smp) + 4 => &CORE4_IPI, + 5 => &CORE5_IPI, + 6 => &CORE6_IPI, + 7 => &CORE7_IPI, _ => { error!("enable_ipi: invalid cpu_id: {}", cpu_id); return; @@ -260,6 +314,12 @@ pub fn clear_all_ipi(cpu_id: usize) { 1 => &CORE1_IPI, 2 => &CORE2_IPI, 3 => &CORE3_IPI, + + // boneinscri 2026.04 (3a6000 smp) + 4 => &CORE4_IPI, + 5 => &CORE5_IPI, + 6 => &CORE6_IPI, + 7 => &CORE7_IPI, _ => { error!("clear_all_ipi: invalid cpu_id: {}", cpu_id); return; @@ -276,7 +336,7 @@ pub fn clear_all_ipi(cpu_id: usize) { pub fn reset_ipi(cpu_id: usize) { // clear all IPIs and enable all IPIs clear_all_ipi(cpu_id); - enable_ipi(cpu_id); + // enable_ipi(cpu_id); } pub fn get_ipi_status(cpu_id: usize) -> u32 { @@ -285,6 +345,12 @@ pub fn get_ipi_status(cpu_id: usize) -> u32 { 1 => &CORE1_IPI, 2 => &CORE2_IPI, 3 => &CORE3_IPI, + + // boneinscri 2026.04 (3a6000 smp) + 4 => &CORE4_IPI, + 5 => &CORE5_IPI, + 6 => &CORE6_IPI, + 7 => &CORE7_IPI, _ => { error!("get_ipi_status: invalid cpu_id: {}", cpu_id); return 0; @@ -297,22 +363,22 @@ pub fn ecfg_ipi_enable() { let mut lie_ = ecfg::read().lie(); lie_ = lie_ | LineBasedInterrupt::IPI; ecfg::set_lie(lie_); - info!( - "ecfg ipi enabled on cpu {}, current lie: {:?}", - this_cpu_id(), - lie_ - ); + // info!( + // "ecfg ipi enabled on cpu {}, current lie: {:?}", + // this_cpu_id(), + // lie_ + // ); } pub fn ecfg_ipi_disable() { let mut lie_ = ecfg::read().lie(); lie_ = lie_ & !LineBasedInterrupt::IPI; ecfg::set_lie(lie_); - info!( - "ecfg ipi disabled on cpu {}, current lie: {:?}", - this_cpu_id(), - lie_ - ); + // info!( + // "ecfg ipi disabled on cpu {}, current lie: {:?}", + // this_cpu_id(), + // lie_ + // ); } pub fn dump_ipi_registers() { @@ -325,6 +391,12 @@ pub fn dump_ipi_registers() { 1 => &CORE1_IPI, 2 => &CORE2_IPI, 3 => &CORE3_IPI, + + // boneinscri 2026.04 (3a6000 smp) + 4 => &CORE4_IPI, + 5 => &CORE5_IPI, + 6 => &CORE6_IPI, + 7 => &CORE7_IPI, _ => { error!("dump_ipi_registers: invalid cpu_id: {}", this_cpu_id()); return; @@ -365,3 +437,325 @@ pub fn arch_prepare_send_event(cpu_id: usize, ipi_int_id: usize, event_id: usize cpu_id, ipi_int_id, event_id ); } + +// IPI state per cpu (ref to kvm) +// boneinscri --2026.04 +pub const IOCSR_IPI_BASE: usize = 0x1000; +pub const IOCSR_IPI_STATUS: usize = 0x000; +pub const INT_IPI: usize = 12; +pub const IOCSR_IPI_EN: usize = 0x004; +pub const IOCSR_IPI_SET: usize = 0x008; +pub const IOCSR_IPI_CLEAR: usize = 0x00c; +pub const IOCSR_IPI_BUF_20: usize = 0x020; +pub const IOCSR_IPI_BUF_28: usize = 0x028; +pub const IOCSR_IPI_BUF_30: usize = 0x030; +pub const IOCSR_IPI_BUF_38: usize = 0x038; +pub const IOCSR_IPI_SEND: usize = 0x040; +pub const IOCSR_MAIL_SEND: usize = 0x048; +pub const IOCSR_ANY_SEND: usize = 0x158; +pub const IOCSR_IPI_BUF_END: usize = IOCSR_IPI_BUF_38 + 7; + +#[derive(Debug)] +pub struct LoongArch64IpiState { + pub status: u32, + pub en: u32, + pub set: u32, + pub clear: u32, + pub buf: [u64; MAX_CPU_NUM], +} + +impl LoongArch64IpiState { + pub fn new() -> Self { + Self { + status: 0, + en: 0, + set: 0, + clear: 0, + buf: [0; MAX_CPU_NUM], + } + } +} + +pub fn write_mailbox(pcpu_id: usize, offset: usize, len: usize, val: usize) { + let pcpu = get_cpu_data(pcpu_id); + + if offset < 0x20 { + panic!("ipi read mailbox, offset = {:#x}, len = {:#x}", offset, len); + } + + let buf_offset = (offset - 0x20) as usize; + let idx = buf_offset / 8; + + let mut ipistate = pcpu.arch_cpu.ipi_state.lock(); + let pbuf = &mut ipistate.buf[idx]; + + match len { + 1 => { + let byte_ptr = pbuf as *mut u64 as *mut u8; + unsafe { *byte_ptr = val as u8 }; + } + 2 => { + let short_ptr = pbuf as *mut u64 as *mut u16; + unsafe { *short_ptr = val as u16 }; + } + 4 => { + let int_ptr = pbuf as *mut u64 as *mut u32; + unsafe { *int_ptr = val as u32 }; + } + 8 => { + *pbuf = val as u64; + } + _ => { + warn!("write_mailbox, invalid length {:#x}", len); + } + } +} + +pub fn ipi_clear(pcpu_id: usize, data: usize) { + let pcpu = get_cpu_data(pcpu_id); + let mut ipistate = pcpu.arch_cpu.ipi_state.lock(); + ipistate.status &= !(data as u32); + let status = ipistate.status; + drop(ipistate); + + if status == 0 { + let cur_pcpu_id = this_cpu_id(); + if cur_pcpu_id != pcpu_id { + panic!("ipi_clear, need to support vcpu"); + } else { + pcpu.arch_cpu.remove_irq(INT_IPI); + } + // TODO : for vcpu , inject IPI interrupt + } +} + +// TODO: modify to vcpu +pub fn get_target_cpu_id(data: usize) -> usize { + let target_cpu_id = ((data & 0xffffffff) >> 16) & 0x3ff; + if target_cpu_id < MAX_CPU_NUM { + let zone = this_zone(); + let cpu_set = zone.read().cpu_set(); + let result = cpu_set.iter().nth(target_cpu_id); + drop(cpu_set); + match result { + Some(id) => id, + None => { + warn!( + "get_target_cpu_id, invalid target cpu id {:#x}, ignore", + target_cpu_id + ); + usize::MAX + } + } + } else { + panic!("invalid target cpu id {:#x}", target_cpu_id); + } +} + +pub fn ipi_send_general(target_cpu_id: usize, action: u32) { + let target_cpu = get_cpu_data(target_cpu_id); + let mut ipistate = target_cpu.arch_cpu.ipi_state.lock(); + let status = ipistate.status; + ipistate.status |= action; + + if (status == 0) { + // TODO : for vcpu , inject IPI interrupt + // pay attention to the target_cpu_id, it should be the real cpu id, not the vcpu id + ipi_write_action(target_cpu_id as usize, action as usize); + } +} + +pub fn ipi_send(data: usize) { + let target_cpu_id = get_target_cpu_id(data); + if target_cpu_id == usize::MAX { + return; + } + let action = (1usize << (data & 0x1f)) as u32; + ipi_send_general(target_cpu_id, action); +} + +pub fn send_ipi_data(target_cpu_id: usize, addr: usize, data: usize) { + let mut mask = 0; + let mut val = 0; + + if (data >> 27) & 0xf != 0 { + val = loongarch_ipi_readl(target_cpu_id, addr, 4); + if val == usize::MAX { + panic!("send_ipi_data, read data from addr {:#x} failed", addr); + } + for i in 0..4 { + if (data & (1usize << (27 + i))) != 0 { + mask |= 0xff << (i * 8); + } + } + val &= mask; + } + + val |= (data >> 32) & !mask; + let ret = loongarch_ipi_writel(target_cpu_id, addr, val, 4); + if ret != val { + panic!("send_ipi_data, write data to addr {:#x} failed", addr); + } +} + +pub fn any_send(data: usize) { + let cpu = ((data & 0xffffffff) >> 16) & 0x3ff; + if cpu != 0 && cpu != 4 { + error!("cpu_id = {}", cpu); + panic!("any_send 1, check it carefullly"); + } + let target_cpu_id = get_target_cpu_id(data); + if target_cpu_id == usize::MAX { + return; + } + if target_cpu_id != 0 && target_cpu_id != 4 { + error!("cpu_id = {}", cpu); + panic!("any_send 2, check it carefullly"); + } + let offset = data & 0xffff; + warn!( + "[Look this] any_send, offset {:#x}, data {:#x}", + offset, data + ); + send_ipi_data(target_cpu_id, offset, data); +} + +pub fn mail_send_iocsr(data: usize) { + let target_cpu_id = get_target_cpu_id(data); + if target_cpu_id == usize::MAX { + return; + } + let mailbox = ((data & 0xffffffff) >> 2) & 0x7; + let offset = IOCSR_IPI_BASE + IOCSR_IPI_BUF_20 + mailbox * 4; + warn!( + "[Look this]mail_send_iocsr, offset {:#x}, data {:#x}", + offset, data + ); + send_ipi_data(target_cpu_id, offset, data); +} + +pub fn read_mailbox(pcpu_id: usize, offset: usize, len: usize) -> usize { + let res = 0; + let pcpu = get_cpu_data(pcpu_id); + let ipi_state = &pcpu.arch_cpu.ipi_state; + if offset < 0x20 { + panic!( + "ipi read mailbox, offset = {:#x}, len = {:#x}\n", + offset, len + ); + } + let idx: usize = ((offset - 0x20) / 8).try_into().unwrap(); + + let ipistate = ipi_state.lock(); + let data = ipistate.buf[idx]; + + match len { + 1 => data & 0xff, + 2 => data & 0xffff, + 4 => data & 0xffffffff, + 8 => data, + _ => { + panic!("read_mailbox: unknown data len: {}", len); + } + }; + res +} + +// TODO : add vcpu for loongarch_ipi_readl and loongarch_ipi_writel +pub fn loongarch_ipi_readl(pcpu_id: usize, addr: usize, len: usize) -> usize { + let offset = (addr & 0x1ff); + if offset & (len - 1) != 0 { + warn!("Unaligned access"); + } + let mut res = 0; + + match offset { + IOCSR_IPI_STATUS => { + // this overhead is high + let pcpu = get_cpu_data(pcpu_id); + let ipistate = pcpu.arch_cpu.ipi_state.lock(); + res = ipistate.status as usize; + } + IOCSR_IPI_EN => { + let pcpu = get_cpu_data(pcpu_id); + let ipistate = pcpu.arch_cpu.ipi_state.lock(); + res = ipistate.en as usize; + } + IOCSR_IPI_SET => { + res = 0; + } + IOCSR_IPI_CLEAR => { + res = 0; + } + IOCSR_IPI_BUF_20..=IOCSR_IPI_BUF_END => { + if offset + len > IOCSR_IPI_BUF_38 + 8 { + panic!( + "ipi readl IOCSR_IPI_BUF, offset = {:#x}, len = {:#x}", + offset, len + ); + } + res = read_mailbox(pcpu_id, offset, len); + } + _ => { + panic!("Invalid IPI read offset: {:#x}", offset); + } + } + + res +} + +pub fn loongarch_ipi_writel(pcpu_id: usize, addr: usize, val: usize, len: usize) -> usize { + let mut res = val; + let offset = (addr & 0x1ff); + if offset & (len - 1) != 0 { + warn!("Unaligned access"); + } + + match offset { + IOCSR_IPI_SEND => { + // overhead is high + ipi_send(val); + } + IOCSR_IPI_CLEAR => { + // overhead is high + ipi_clear(pcpu_id, val); + } + IOCSR_IPI_STATUS => { + panic!( + "ipi writel IOCSR_IPI_STATUS, pcpu_id = {}, val = {:#x}", + pcpu_id, val + ); + } + IOCSR_IPI_EN => { + let mut pcpu = get_cpu_data(pcpu_id); + let mut ipistate = pcpu.arch_cpu.ipi_state.lock(); + ipistate.en = val as u32; + } + IOCSR_IPI_SET => { + panic!( + "ipi writel IOCSR_IPI_SET, pcpu_id = {}, val = {:#x}", + pcpu_id, val + ); + } + IOCSR_IPI_BUF_20..=IOCSR_IPI_BUF_END => { + if offset + len > IOCSR_IPI_BUF_38 + 8 { + panic!( + "ipi writel IOCSR_IPI_BUF, offset = {:#x}, len = {:#x}", + offset, len + ); + } + write_mailbox(pcpu_id, offset, len, val); + } + IOCSR_MAIL_SEND => { + mail_send_iocsr(val); + } + IOCSR_ANY_SEND => { + // any_send(val); + } + _ => { + panic!("Invalid IPI write offset: {:#x}", offset); + } + } + + res +} diff --git a/src/arch/loongarch64/mod.rs b/src/arch/loongarch64/mod.rs index d592cd94..91ab7af3 100644 --- a/src/arch/loongarch64/mod.rs +++ b/src/arch/loongarch64/mod.rs @@ -19,6 +19,7 @@ pub mod clock; pub mod consts; pub mod cpu; +pub mod eiointc; pub mod entry; pub mod hypercall; pub mod ipi; @@ -28,9 +29,24 @@ pub mod register; pub mod s1pt; pub mod s2pt; pub mod time; +pub mod timer; pub mod trap; pub mod zone; pub use s1pt::Stage1PageTable; pub use s2pt::stage2_mode_detect; pub use s2pt::Stage2PageTable; + +/// Print LoongArch64 specific logo +pub fn print_logo() { + println!( + r" + _ _ _ + | | (_) | | + | |__ __ ___ ___ ___ _ __ | | __ _ + | '_ \ \ \ / / / __|/ _ \| '__| | |/ _` | + | | | | \ V /| \__ \ (_) | | _| | (_| | + |_| |_| \_/ |_|___/\___/|_| (_)_|\__,_| +" + ); +} diff --git a/src/arch/loongarch64/paging.rs b/src/arch/loongarch64/paging.rs index 582760e1..c9bc44b0 100644 --- a/src/arch/loongarch64/paging.rs +++ b/src/arch/loongarch64/paging.rs @@ -29,9 +29,9 @@ use loongArch64::register::pwcl::{ set_ptwidth, }; use loongArch64::register::stlbps::{self, set_ps}; -use loongArch64::register::MemoryAccessType; use loongArch64::register::{crmd, pwch, pwcl, tlbrentry}; use loongArch64::register::{pgd, pgdh, pgdl}; +use loongArch64::register::{tlbidx, MemoryAccessType}; #[derive(Debug)] pub enum PagingError { @@ -655,4 +655,6 @@ pub fn set_pwcl_pwch_stlbps() { set_ptwidth(9); set_pte_width(8); // 64 bits -> 8 bytes stlbps::set_ps(12); // log2(real_page_size), 16KB -> 14, 4KB -> 12 + + tlbidx::set_ps(0xc); // boneinscri : 2026.04 } diff --git a/src/arch/loongarch64/register/macros.rs b/src/arch/loongarch64/register/macros.rs index 775cb0d6..489deac9 100644 --- a/src/arch/loongarch64/register/macros.rs +++ b/src/arch/loongarch64/register/macros.rs @@ -13,7 +13,7 @@ // // Authors: // Yulong Han -// +// Ming Shen /* this file is forked from extern crate loongArch64::register::macros; wheatfox @@ -252,3 +252,37 @@ macro_rules! set_gcsr_loong_bit { write_gcsr_loong!($csr_number, tmp); }; } + +#[macro_export] +macro_rules! gcsr_xchg { + ($v:expr, $m:expr, $csr:literal) => {{ + let mut val = $v; + unsafe { + core::arch::asm!( + "gcsrxchg {}, {}, {}", + out(reg) val, + in(reg) $m, + const $csr, + options(preserves_flags) + ); + } + val + }}; +} + +#[macro_export] +macro_rules! csr_xchg { + ($v:expr, $m:expr, $csr:literal) => {{ + let mut val = $v; + unsafe { + core::arch::asm!( + "csrxchg {}, {}, {}", + out(reg) val, + in(reg) $m, + const $csr, + options(preserves_flags) + ); + } + val + }}; +} diff --git a/src/arch/loongarch64/register/mod.rs b/src/arch/loongarch64/register/mod.rs index 53a8480d..9bca6848 100644 --- a/src/arch/loongarch64/register/mod.rs +++ b/src/arch/loongarch64/register/mod.rs @@ -13,11 +13,12 @@ // // Authors: // Yulong Han -// +// Ming Shen // File: mod.rs // Description: this is the register file of loongarch64's LVZ extension // Authors: wheatfox(wheatfox17@icloud.com) // Created: 2023-12-20 +// Updated: 2026-04-05 #![allow(unused)] @@ -104,7 +105,316 @@ pub const GCSR_DMW2: usize = 0x182; pub const GCSR_DMW3: usize = 0x183; // and some more, which are performance monitoring related +// more interfaces... boneinscri 2026.04 +// write GCSR +pub fn write_gcsr_crmd(value: usize) { + write_gcsr_loong!(0x0, value); +} +pub fn write_gcsr_prmd(value: usize) { + write_gcsr_loong!(0x1, value); +} +pub fn write_gcsr_euen(value: usize) { + write_gcsr_loong!(0x2, value); +} +pub fn write_gcsr_misc(value: usize) { + write_gcsr_loong!(0x3, value); +} +pub fn write_gcsr_ecfg(value: usize) { + write_gcsr_loong!(0x4, value); +} +pub fn write_gcsr_estat(value: usize) { + write_gcsr_loong!(0x5, value); +} +pub fn write_gcsr_era(value: usize) { + write_gcsr_loong!(0x6, value); +} +pub fn write_gcsr_badv(value: usize) { + write_gcsr_loong!(0x7, value); +} +pub fn write_gcsr_badi(value: usize) { + write_gcsr_loong!(0x8, value); +} +pub fn write_gcsr_eentry(value: usize) { + write_gcsr_loong!(0xc, value); +} +pub fn write_gcsr_tlbidx(value: usize) { + write_gcsr_loong!(0x10, value); +} +pub fn write_gcsr_tlbehi(value: usize) { + write_gcsr_loong!(0x11, value); +} +pub fn write_gcsr_tlbelo0(value: usize) { + write_gcsr_loong!(0x12, value); +} +pub fn write_gcsr_tlbelo1(value: usize) { + write_gcsr_loong!(0x13, value); +} +pub fn write_gcsr_asid(value: usize) { + write_gcsr_loong!(0x18, value); +} +pub fn write_gcsr_pgdl(value: usize) { + write_gcsr_loong!(0x19, value); +} +pub fn write_gcsr_pgdh(value: usize) { + write_gcsr_loong!(0x1a, value); +} +pub fn write_gcsr_pwcl(value: usize) { + write_gcsr_loong!(0x1c, value); +} +pub fn write_gcsr_pwch(value: usize) { + write_gcsr_loong!(0x1d, value); +} +pub fn write_gcsr_stlbps(value: usize) { + write_gcsr_loong!(0x1e, value); +} +pub fn write_gcsr_rvacfg(value: usize) { + write_gcsr_loong!(0x1f, value); +} +pub fn write_gcsr_cpuid(value: usize) { + write_gcsr_loong!(0x20, value); +} +pub fn write_gcsr_prcfg1(value: usize) { + write_gcsr_loong!(0x21, value); +} +pub fn write_gcsr_prcfg2(value: usize) { + write_gcsr_loong!(0x22, value); +} +pub fn write_gcsr_prcfg3(value: usize) { + write_gcsr_loong!(0x23, value); +} +pub fn write_gcsr_save0(value: usize) { + write_gcsr_loong!(0x30, value); +} +pub fn write_gcsr_save1(value: usize) { + write_gcsr_loong!(0x31, value); +} +pub fn write_gcsr_save2(value: usize) { + write_gcsr_loong!(0x32, value); +} +pub fn write_gcsr_save3(value: usize) { + write_gcsr_loong!(0x33, value); +} +pub fn write_gcsr_save4(value: usize) { + write_gcsr_loong!(0x34, value); +} +pub fn write_gcsr_save5(value: usize) { + write_gcsr_loong!(0x35, value); +} +pub fn write_gcsr_save6(value: usize) { + write_gcsr_loong!(0x36, value); +} +pub fn write_gcsr_save7(value: usize) { + write_gcsr_loong!(0x37, value); +} +pub fn write_gcsr_tid(value: usize) { + write_gcsr_loong!(0x40, value); +} +pub fn write_gcsr_tcfg(value: usize) { + write_gcsr_loong!(0x41, value); +} +pub fn write_gcsr_tval(value: usize) { + write_gcsr_loong!(0x42, value); +} +pub fn write_gcsr_cntc(value: usize) { + write_gcsr_loong!(0x43, value); +} +pub fn write_gcsr_ticlr(value: usize) { + write_gcsr_loong!(0x44, value); +} +pub fn write_gcsr_tlbrentry(value: usize) { + write_gcsr_loong!(0x88, value); +} +pub fn write_gcsr_tlbrbadv(value: usize) { + write_gcsr_loong!(0x89, value); +} +pub fn write_gcsr_tlbrera(value: usize) { + write_gcsr_loong!(0x8a, value); +} +pub fn write_gcsr_tlbrsave(value: usize) { + write_gcsr_loong!(0x8b, value); +} +pub fn write_gcsr_tlbrelo0(value: usize) { + write_gcsr_loong!(0x8c, value); +} +pub fn write_gcsr_tlbrelo1(value: usize) { + write_gcsr_loong!(0x8d, value); +} +pub fn write_gcsr_tlbrehi(value: usize) { + write_gcsr_loong!(0x8e, value); +} +pub fn write_gcsr_tlbrprmd(value: usize) { + write_gcsr_loong!(0x8f, value); +} +pub fn write_gcsr_dmw0(value: usize) { + write_gcsr_loong!(0x180, value); +} +pub fn write_gcsr_dmw1(value: usize) { + write_gcsr_loong!(0x181, value); +} +pub fn write_gcsr_dmw2(value: usize) { + write_gcsr_loong!(0x182, value); +} +pub fn write_gcsr_dmw3(value: usize) { + write_gcsr_loong!(0x183, value); +} + +// WRITE CSR +pub fn write_csr_crmd(value: usize) { + write_csr_loong!(0x0, value); +} +pub fn write_csr_prmd(value: usize) { + write_csr_loong!(0x1, value); +} +pub fn write_csr_euen(value: usize) { + write_csr_loong!(0x2, value); +} +pub fn write_csr_misc(value: usize) { + write_csr_loong!(0x3, value); +} +pub fn write_csr_ecfg(value: usize) { + write_csr_loong!(0x4, value); +} +pub fn write_csr_estat(value: usize) { + write_csr_loong!(0x5, value); +} +pub fn write_csr_era(value: usize) { + write_csr_loong!(0x6, value); +} +pub fn write_csr_badv(value: usize) { + write_csr_loong!(0x7, value); +} +pub fn write_csr_badi(value: usize) { + write_csr_loong!(0x8, value); +} +pub fn write_csr_eentry(value: usize) { + write_csr_loong!(0xc, value); +} +pub fn write_csr_tlbidx(value: usize) { + write_csr_loong!(0x10, value); +} +pub fn write_csr_tlbehi(value: usize) { + write_csr_loong!(0x11, value); +} +pub fn write_csr_tlbelo0(value: usize) { + write_csr_loong!(0x12, value); +} +pub fn write_csr_tlbelo1(value: usize) { + write_csr_loong!(0x13, value); +} +pub fn write_csr_asid(value: usize) { + write_csr_loong!(0x18, value); +} +pub fn write_csr_pgdl(value: usize) { + write_csr_loong!(0x19, value); +} +pub fn write_csr_pgdh(value: usize) { + write_csr_loong!(0x1a, value); +} +pub fn write_csr_pwcl(value: usize) { + write_csr_loong!(0x1c, value); +} +pub fn write_csr_pwch(value: usize) { + write_csr_loong!(0x1d, value); +} +pub fn write_csr_stlbps(value: usize) { + write_csr_loong!(0x1e, value); +} +pub fn write_csr_rvacfg(value: usize) { + write_csr_loong!(0x1f, value); +} +pub fn write_csr_cpuid(value: usize) { + write_csr_loong!(0x20, value); +} +pub fn write_csr_prcfg1(value: usize) { + write_csr_loong!(0x21, value); +} +pub fn write_csr_prcfg2(value: usize) { + write_csr_loong!(0x22, value); +} +pub fn write_csr_prcfg3(value: usize) { + write_csr_loong!(0x23, value); +} +pub fn write_csr_save0(value: usize) { + write_csr_loong!(0x30, value); +} +pub fn write_csr_save1(value: usize) { + write_csr_loong!(0x31, value); +} +pub fn write_csr_save2(value: usize) { + write_csr_loong!(0x32, value); +} +pub fn write_csr_save3(value: usize) { + write_csr_loong!(0x33, value); +} +pub fn write_csr_save4(value: usize) { + write_csr_loong!(0x34, value); +} +pub fn write_csr_save5(value: usize) { + write_csr_loong!(0x35, value); +} +pub fn write_csr_save6(value: usize) { + write_csr_loong!(0x36, value); +} +pub fn write_csr_save7(value: usize) { + write_csr_loong!(0x37, value); +} +pub fn write_csr_tid(value: usize) { + write_csr_loong!(0x40, value); +} +pub fn write_csr_tcfg(value: usize) { + write_csr_loong!(0x41, value); +} +pub fn write_csr_tval(value: usize) { + write_csr_loong!(0x42, value); +} +pub fn write_csr_cntc(value: usize) { + write_csr_loong!(0x43, value); +} +pub fn write_csr_ticlr(value: usize) { + write_csr_loong!(0x44, value); +} +pub fn write_csr_tlbrentry(value: usize) { + write_csr_loong!(0x88, value); +} +pub fn write_csr_tlbrbadv(value: usize) { + write_csr_loong!(0x89, value); +} +pub fn write_csr_tlbrera(value: usize) { + write_csr_loong!(0x8a, value); +} +pub fn write_csr_tlbrsave(value: usize) { + write_csr_loong!(0x8b, value); +} +pub fn write_csr_tlbrelo0(value: usize) { + write_csr_loong!(0x8c, value); +} +pub fn write_csr_tlbrelo1(value: usize) { + write_csr_loong!(0x8d, value); +} +pub fn write_csr_tlbrehi(value: usize) { + write_csr_loong!(0x8e, value); +} +pub fn write_csr_tlbrprmd(value: usize) { + write_csr_loong!(0x8f, value); +} +pub fn write_csr_dmw0(value: usize) { + write_csr_loong!(0x180, value); +} +pub fn write_csr_dmw1(value: usize) { + write_csr_loong!(0x181, value); +} +pub fn write_csr_dmw2(value: usize) { + write_csr_loong!(0x182, value); +} +pub fn write_csr_dmw3(value: usize) { + write_csr_loong!(0x183, value); +} +pub fn write_csr_gintc(value: usize) { + write_csr_loong!(0x52, value); +} + // READ GCSR + pub fn read_gcsr_crmd() -> usize { read_gcsr_loong!(0x0) } @@ -123,9 +433,6 @@ pub fn read_gcsr_ectl() -> usize { pub fn read_gcsr_estat() -> usize { read_gcsr_loong!(0x5) } -pub fn write_gcsr_estat(value: usize) { - write_gcsr_loong!(0x5, value); -} pub fn read_gcsr_era() -> usize { read_gcsr_loong!(0x6) } @@ -240,24 +547,15 @@ pub fn read_gcsr_tid() -> usize { pub fn read_gcsr_tcfg() -> usize { read_gcsr_loong!(0x41) } -pub fn write_gcsr_tcfg(value: usize) { - write_gcsr_loong!(0x41, value); -} pub fn read_gcsr_tval() -> usize { read_gcsr_loong!(0x42) } -pub fn write_gcsr_tval(value: usize) { - write_gcsr_loong!(0x42, value); -} pub fn read_gcsr_cntc() -> usize { read_gcsr_loong!(0x43) } pub fn read_gcsr_ticlr() -> usize { read_gcsr_loong!(0x44) } -pub fn write_gcsr_ticlr(value: usize) { - write_gcsr_loong!(0x44, value); -} pub fn read_gcsr_llbctl() -> usize { read_gcsr_loong!(0x60) } @@ -297,9 +595,204 @@ pub fn read_gcsr_dmw2() -> usize { pub fn read_gcsr_dmw3() -> usize { read_gcsr_loong!(0x183) } -pub fn write_gcsr_ectl(range: core::ops::RangeInclusive, value: usize) { - set_gcsr_loong_bits!(0x4, range, value); + +// READ CSR +pub fn read_csr_crmd() -> usize { + read_csr_loong!(0x0) +} +pub fn read_csr_prmd() -> usize { + read_csr_loong!(0x1) +} +pub fn read_csr_euen() -> usize { + read_csr_loong!(0x2) +} +pub fn read_csr_misc() -> usize { + read_csr_loong!(0x3) +} +pub fn read_csr_ectl() -> usize { + read_csr_loong!(0x4) +} +pub fn read_csr_estat() -> usize { + read_csr_loong!(0x5) +} +pub fn read_csr_era() -> usize { + read_csr_loong!(0x6) +} +pub fn read_csr_badv() -> usize { + read_csr_loong!(0x7) +} +pub fn read_csr_badi() -> usize { + read_csr_loong!(0x8) +} +pub fn read_csr_eentry() -> usize { + read_csr_loong!(0xc) +} +pub fn read_csr_tlbidx() -> usize { + read_csr_loong!(0x10) +} +pub fn read_csr_tlbehi() -> usize { + read_csr_loong!(0x11) +} +pub fn read_csr_tlbelo0() -> usize { + read_csr_loong!(0x12) +} +pub fn read_csr_tlbelo1() -> usize { + read_csr_loong!(0x13) +} +pub fn read_csr_asid() -> usize { + read_csr_loong!(0x18) +} +pub fn read_csr_pgdl() -> usize { + read_csr_loong!(0x19) +} +pub fn read_csr_pgdh() -> usize { + read_csr_loong!(0x1a) +} +pub fn read_csr_pgd() -> usize { + read_csr_loong!(0x1b) +} +pub fn read_csr_pwcl() -> usize { + read_csr_loong!(0x1c) +} +pub fn read_csr_pwch() -> usize { + read_csr_loong!(0x1d) } -pub fn write_gcsr_eentry(range: core::ops::RangeInclusive, value: usize) { - set_gcsr_loong_bits!(0xc, range, value); +pub fn read_csr_stlbps() -> usize { + read_csr_loong!(0x1e) +} +pub fn read_csr_ravcfg() -> usize { + read_csr_loong!(0x1f) +} +pub fn read_csr_cpuid() -> usize { + read_csr_loong!(0x20) +} +pub fn read_csr_prcfg1() -> usize { + read_csr_loong!(0x21) +} +pub fn read_csr_prcfg2() -> usize { + read_csr_loong!(0x22) +} +pub fn read_csr_prcfg3() -> usize { + read_csr_loong!(0x23) +} +pub fn read_csr_save0() -> usize { + read_csr_loong!(0x30) +} +pub fn read_csr_save1() -> usize { + read_csr_loong!(0x31) +} +pub fn read_csr_save2() -> usize { + read_csr_loong!(0x32) +} +pub fn read_csr_save3() -> usize { + read_csr_loong!(0x33) +} +pub fn read_csr_save4() -> usize { + read_csr_loong!(0x34) +} +pub fn read_csr_save5() -> usize { + read_csr_loong!(0x35) +} +pub fn read_csr_save6() -> usize { + read_csr_loong!(0x36) +} +pub fn read_csr_save7() -> usize { + read_csr_loong!(0x37) +} +pub fn read_csr_save8() -> usize { + read_csr_loong!(0x38) +} +pub fn read_csr_save9() -> usize { + read_csr_loong!(0x39) +} +pub fn read_csr_save10() -> usize { + read_csr_loong!(0x3a) +} +pub fn read_csr_save11() -> usize { + read_csr_loong!(0x3b) +} +pub fn read_csr_save12() -> usize { + read_csr_loong!(0x3c) +} +pub fn read_csr_save13() -> usize { + read_csr_loong!(0x3d) +} +pub fn read_csr_save14() -> usize { + read_csr_loong!(0x3e) +} +pub fn read_csr_save15() -> usize { + read_csr_loong!(0x3f) +} +pub fn read_csr_tid() -> usize { + read_csr_loong!(0x40) +} +pub fn read_csr_tcfg() -> usize { + read_csr_loong!(0x41) +} +pub fn read_csr_tval() -> usize { + read_csr_loong!(0x42) +} +pub fn read_csr_cntc() -> usize { + read_csr_loong!(0x43) +} +pub fn read_csr_ticlr() -> usize { + read_csr_loong!(0x44) +} +pub fn read_csr_llbctl() -> usize { + read_csr_loong!(0x60) +} +pub fn read_csr_tlbrentry() -> usize { + read_csr_loong!(0x88) +} +pub fn read_csr_tlbrbadv() -> usize { + read_csr_loong!(0x89) +} +pub fn read_csr_tlbrera() -> usize { + read_csr_loong!(0x8a) +} +pub fn read_csr_tlbrsave() -> usize { + read_csr_loong!(0x8b) +} +pub fn read_csr_tlbrrelo0() -> usize { + read_csr_loong!(0x8c) +} +pub fn read_csr_tlbrrelo1() -> usize { + read_csr_loong!(0x8d) +} +pub fn read_csr_tlbrrehi() -> usize { + read_csr_loong!(0x8e) +} +pub fn read_csr_tlbrprmd() -> usize { + read_csr_loong!(0x8f) +} +pub fn read_csr_dmw0() -> usize { + read_csr_loong!(0x180) +} +pub fn read_csr_dmw1() -> usize { + read_csr_loong!(0x181) +} +pub fn read_csr_dmw2() -> usize { + read_csr_loong!(0x182) +} +pub fn read_csr_dmw3() -> usize { + read_csr_loong!(0x183) +} +pub fn read_csr_gintc() -> usize { + read_csr_loong!(0x52) +} + +pub fn set_gcsr_estat(val: usize) { + gcsr_xchg!(val, val, 0x5); +} + +pub fn clear_gcsr_estat(val: usize) { + gcsr_xchg!(!(val), val, 0x5); +} + +pub fn set_csr_gintc(val: usize) { + csr_xchg!(val, val, 0x52); +} + +pub fn clear_csr_gintc(val: usize) { + csr_xchg!(!(val), val, 0x52); } diff --git a/src/arch/loongarch64/timer.rs b/src/arch/loongarch64/timer.rs new file mode 100644 index 00000000..ce420994 --- /dev/null +++ b/src/arch/loongarch64/timer.rs @@ -0,0 +1,159 @@ +// 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: +// Ming Shen +// + +use core::sync::atomic::{AtomicU64, Ordering}; + +use loongArch64::{ + register::{tcfg, ticlr}, + time, +}; + +use crate::{ + arch::{ + cpu::this_cpu_id, + register::{ + read_csr_cntc, read_gcsr_estat, read_gcsr_tcfg, read_gcsr_tval, write_csr_cntc, + write_gcsr_estat, write_gcsr_tcfg, write_gcsr_ticlr, write_gcsr_tval, + }, + trap::{ecfg_timer_disable, ktime_get}, + zone::ZoneContext, + }, + cpu_data::get_cpu_data, +}; + +const CSR_TCFG_EN: usize = 1 << 0; +const CSR_TCFG_PERIOD_SHIFT: usize = 1; +const CSR_TCFG_PERIOD: usize = (1 << CSR_TCFG_PERIOD_SHIFT); +const CPU_TIMER: usize = (1 << 11); +const CSR_TINTCLR_TI: usize = 1 << 0; +const CSR_TCFG_VAL_SHIFT: usize = 2; +const CSR_TCFG_VAL: usize = 0x3fffffffffffusize << CSR_TCFG_VAL_SHIFT; +const INT_TI: usize = 11; + +pub fn restore_timer(mut ctx: &mut ZoneContext, pcpu_id: usize) { + // TODO: pcpu_id -> vcpu + // TODO: if it supports vcpu, we should read gcsr from trap context + let gcsr_tcfg = ctx.gcsr_tcfg; + write_gcsr_tcfg(0); + + // TODO: restore gcsr.estat and gcsr.tcfg for vcpu + write_gcsr_estat(ctx.gcsr_estat); + write_gcsr_tcfg(ctx.gcsr_tcfg); + + if (gcsr_tcfg & CSR_TCFG_EN == 0) { + /* Guest timer is disabled, just restore timer registers */ + // TODO: restore gcsr.tval + write_gcsr_tval(ctx.gcsr_tval); + return; + } + + let gcsr_tval = ctx.gcsr_tval; + let gcsr_estat = ctx.gcsr_estat; + + if ((gcsr_tcfg & CSR_TCFG_PERIOD == 0) && (gcsr_tval > gcsr_tcfg)) { + write_gcsr_tval(0); + if (gcsr_estat & CPU_TIMER == 0) { + write_gcsr_ticlr(CSR_TINTCLR_TI); + } + return; + } + + let mut delta = 0; + let now = ktime_get(); + + let pcpu_data = get_cpu_data(pcpu_id); + let expire = pcpu_data.arch_cpu.expire as usize; + + if now < expire { + delta = expire - now; + } else if (gcsr_tcfg & CSR_TCFG_PERIOD != 0) { + let period = gcsr_tcfg & CSR_TCFG_VAL; + delta = now - expire; + delta = period - (delta % period); + + // inject timer interrupt + pcpu_data.arch_cpu.add_irq(INT_TI); + } + write_gcsr_tval(delta); +} + +pub fn do_save_timer(mut ctx: &mut ZoneContext, pcpu_id: usize) { + let mut delta = 0; + // TODO: read gcsr.tcfg from trap context (from vcpu) + let gcsr_tcfg = ctx.gcsr_tcfg; + let gcsr_tval = ctx.gcsr_tval; + + if (gcsr_tval < gcsr_tcfg) { + delta = gcsr_tval; + } else { + delta = 0; + } + let expire = ktime_get() + delta; + + let pcpu_data = get_cpu_data(pcpu_id); + pcpu_data.arch_cpu.expire = expire as isize; +} + +pub fn save_timer(mut ctx: &mut ZoneContext, pcpu_id: usize) { + // TODO: if it supports, pcpu_id -> vcpu + // TODO: if it supports vcpu, we should read gcsr from trap context + + // TODO: save gcsr.tcfg and gcsr.tval for vcpu + ctx.gcsr_tcfg = read_gcsr_tcfg(); + ctx.gcsr_tval = read_gcsr_tval(); + + // TODO: read gcsr.tcfg from trap context + let gcsr_tcfg = ctx.gcsr_tcfg; + if (gcsr_tcfg & CSR_TCFG_EN != 0) { + do_save_timer(ctx, pcpu_id); + } + + // TODO: save gcsr.estat for vcpu + ctx.gcsr_estat = read_gcsr_estat(); +} + +static INIT_OFFSET: AtomicU64 = AtomicU64::new(0); +static GLOBAL_TIMER: AtomicU64 = AtomicU64::new(0); + +pub fn sync_counter() { + let init_offset_val = INIT_OFFSET.load(Ordering::Relaxed); + write_csr_cntc(init_offset_val as usize); +} + +pub fn timer_init() { + const HZ: usize = 100; + // uefi firmware leaves timer interrupt pending, we need to clear it manually + ticlr::clear_timer_interrupt(); + // get timer frequency + let timer_freq = time::get_timer_freq(); + + let pcpu_id = this_cpu_id(); + if pcpu_id == 0 { + let init_offset_val = -(ktime_get() as isize - read_csr_cntc() as isize); + INIT_OFFSET.store(init_offset_val as u64, Ordering::Relaxed); + } + sync_counter(); + + ecfg_timer_disable(); + // 100_000_000 + // 1s = 1000 ms = 1000_000 us + // set timer + let init_val = timer_freq / HZ; + tcfg::set_periodic(true); + tcfg::set_init_val(init_val); + tcfg::set_en(true); // enable timer, not timer interrupt +} diff --git a/src/arch/loongarch64/trap.rs b/src/arch/loongarch64/trap.rs index e6f8b25b..873e0da4 100644 --- a/src/arch/loongarch64/trap.rs +++ b/src/arch/loongarch64/trap.rs @@ -13,20 +13,53 @@ // // Authors: // Yulong Han +// Ming Shen // use super::register::*; use super::zone::ZoneContext; use crate::arch::cpu::this_cpu_id; +use crate::arch::eiointc::{ + do_real_read_iocsr, do_real_write_iocsr, loongarch_eiointc_readl, loongarch_eiointc_writel, + EIOINTC_BASE, EIOINTC_SIZE, EIOINTC_VIRT_BASE, EIOINTC_VIRT_SIZE, +}; use crate::arch::ipi::*; +use crate::arch::timer::{restore_timer, save_timer, timer_init}; 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::cpu_data::{get_cpu_data, this_cpu_data}; use crate::device::irqchip::ls7a2000::chip::*; +use crate::device::irqchip::{inject_irq, ls7a2000::clear_irq}; +use crate::device::virtio_trampoline::handle_virtio_irq; 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::zone::Zone; + +// IOCSR address range classification +const IOCSR_TYPE_IPI: usize = 0; +const IOCSR_TYPE_EIOINTC: usize = 1; +const IOCSR_TYPE_EIOINTC_VIRT: usize = 2; +const IOCSR_TYPE_OTHER: usize = 3; + +fn get_iocsr_type(addr: usize) -> usize { + if addr >= IOCSR_IPI_BASE && addr < IOCSR_IPI_BASE + 0x200 { + IOCSR_TYPE_IPI + } else if addr >= EIOINTC_BASE && addr < EIOINTC_BASE + EIOINTC_SIZE { + IOCSR_TYPE_EIOINTC + } else if addr >= EIOINTC_VIRT_BASE && addr < EIOINTC_VIRT_BASE + EIOINTC_VIRT_SIZE { + IOCSR_TYPE_EIOINTC_VIRT + } else { + IOCSR_TYPE_OTHER + } +} + +// 0 or 7 +// boneinscri : 2026.04 +// VS_VALUE = 0, one handler +// VS_VALUE = 7, interrupt vector +// it can be changed runtime +pub const GLOBAL_VS_VALUE: usize = 0; + use crate::PHY_TO_DMW_UNCACHED; use core::arch; use core::arch::asm; @@ -84,24 +117,22 @@ pub static GLOBAL_TRAP_CONTEXT_HELPER_PER_CPU: [Mutex; MAX_CP pub fn install_trap_vector() { // force disable INT here - crmd::set_ie(false); // clear UEFI firmware's previous timer configs ticlr::clear_timer_interrupt(); + disable_global_interrupt(); + ecfg_ipi_disable(); - timer_init(); tcfg::set_en(false); // we may need to use timer irq to trap for our virtio clear injection // only enable timer irq trap for debugging, because it may cause overheads for realtime nonroots - // set CSR.EENTRY to _hyp_trap_vector and int vector offset to 0 - ecfg::set_vs(0); + // set CSR.EENTRY to _hyp_trap_vector and int vector offset to 0/? + ecfg::set_vs(GLOBAL_VS_VALUE); eentry::set_eentry(_hyp_trap_vector as usize); // enable floating point euen::set_fpe(true); // basic floating point euen::set_sxe(true); // 128-bit SIMD euen::set_asxe(true); // 256-bit SIMD - - enable_global_interrupt() } /// enable CRMD.IE @@ -140,24 +171,59 @@ pub fn ktime_get() -> usize { current_counter_time } -pub fn timer_init() { - // uefi firmware leaves timer interrupt pending, we need to clear it manually - ticlr::clear_timer_interrupt(); - let timer_freq = time::get_timer_freq(); - tcfg::set_periodic(true); - let init_val = get_ms_counter(200); - tcfg::set_init_val(init_val); +pub fn ipi_init() { + let mut lie_ = ecfg::read().lie(); + lie_ = lie_ | LineBasedInterrupt::IPI; + ecfg::set_lie(lie_); +} - tcfg::set_en(true); +pub fn ecfg_timer_disable() { + let mut lie_ = ecfg::read().lie(); + lie_ = lie_ & !LineBasedInterrupt::TIMER; + ecfg::set_lie(lie_); +} +pub fn ecfg_timer_enable() { let mut lie_ = ecfg::read().lie(); lie_ = lie_ | LineBasedInterrupt::TIMER; ecfg::set_lie(lie_); } -pub fn ipi_init() { +pub fn ecfg_swi_enable() { let mut lie_ = ecfg::read().lie(); - lie_ = lie_ | LineBasedInterrupt::IPI; + lie_ = lie_ | LineBasedInterrupt::SWI0 | LineBasedInterrupt::SWI1; + ecfg::set_lie(lie_); +} + +pub fn ecfg_swi_disable() { + let mut lie_ = ecfg::read().lie(); + lie_ = lie_ & !LineBasedInterrupt::SWI0 & !LineBasedInterrupt::SWI1; + ecfg::set_lie(lie_); +} + +pub fn ecfg_hwi_disable() { + let mut lie_ = ecfg::read().lie(); + lie_ = lie_ & !LineBasedInterrupt::HWI0; + lie_ = lie_ & !LineBasedInterrupt::HWI1; + lie_ = lie_ & !LineBasedInterrupt::HWI2; + lie_ = lie_ & !LineBasedInterrupt::HWI3; + lie_ = lie_ & !LineBasedInterrupt::HWI4; + lie_ = lie_ & !LineBasedInterrupt::HWI5; + lie_ = lie_ & !LineBasedInterrupt::HWI6; + lie_ = lie_ & !LineBasedInterrupt::HWI7; + ecfg::set_lie(lie_); +} + +pub fn ecfg_hwi_enable() { + let mut lie_ = ecfg::read().lie(); + lie_ = lie_ | LineBasedInterrupt::HWI0; + lie_ = lie_ | LineBasedInterrupt::HWI1; + lie_ = lie_ | LineBasedInterrupt::HWI2; + lie_ = lie_ | LineBasedInterrupt::HWI3; + lie_ = lie_ | LineBasedInterrupt::HWI4; + lie_ = lie_ | LineBasedInterrupt::HWI5; + lie_ = lie_ | LineBasedInterrupt::HWI6; + lie_ = lie_ | LineBasedInterrupt::HWI7; ecfg::set_lie(lie_); } @@ -223,15 +289,9 @@ pub fn trap_handler(mut ctx: &mut ZoneContext) { trace!("loongarch64: trap_handler: ctx addr = {:p}", &ctx); // save timer - let delta; - let ticks = ctx.gcsr_tval; - let cfg = ctx.gcsr_tcfg; - if ticks < cfg { - delta = ticks; - } else { - delta = 0; - } - let expire = ktime_get() + delta; + // --boneinscri 2026.04 + let pcpu_id = this_cpu_id(); + save_timer(ctx, pcpu_id); // dump trap csr regs let estat_ = estat::read(); @@ -291,46 +351,10 @@ pub fn trap_handler(mut ctx: &mut ZoneContext) { ctx, ); - // restore timer - let cfg = ctx.gcsr_tcfg; - - ctx.gcsr_tcfg = 0; - - // restore GCSR_ESTAT and GCSR_TCFG - ctx.gcsr_estat = 0; - ctx.gcsr_tcfg = 0; - - debug!("loongarch64: trap_handler: restore timer, cfg={:#x}", cfg); - - if cfg & 1 == 0 { - // guest has disabled timer, we just restore the tval - ctx.gcsr_tval = 0; - } else { - let ticks = ctx.gcsr_tval; - let estat = ctx.gcsr_estat; - - if !((cfg & 2) != 0 && (ticks > cfg)) { - ctx.gcsr_tval = 0; // inject irq - let cpu_timer = 1usize << 11; - if estat & cpu_timer == 0 { - ctx.gcsr_ticlr = 1; // clear timer interrupt - } - } else { - let now = ktime_get(); - let mut __delta = 0; - if now < expire { - __delta = expire - now; - } else if (cfg & 2) != 0 { - // tcfg[63:2] || 00 is tval - let period = cfg & (0xffff_ffff_ffff_fffc); - __delta = now - expire; - __delta = period - (__delta % period); - // kvm queued guest timer irq injection here but we do nothing here - } - - ctx.gcsr_tval = __delta; - } - } + // restore timer + inject irq + // --boneinscri 2026.04 + restore_timer(ctx, pcpu_id); + deliver_irq(); debug!("loongarch64: trap_handler: return"); @@ -383,7 +407,7 @@ fn handle_exception( handle_hvc(ctx); } ECODE_PIL | ECODE_PIS | ECODE_PNR => { - debug!("exception: {}: ecode={:#x}, esubcode={:#x}, era={:#x}, is={:#x}, badi={:#x}, badv={:#x}", + info!("exception: {}: ecode={:#x}, esubcode={:#x}, era={:#x}, is={:#x}, badi={:#x}, badv={:#x}", ecode2str(ecode,esubcode), ecode, esubcode, era, is, badi, badv); // we first assume this lies in virtio region // since we didn't add these regions into VMM Pages @@ -577,14 +601,16 @@ fn handle_exception( "mmio access failed, error = {:?}, this is a real page fault", e ); - panic!("unhandled exception: {}: ecode={:#x}, esubcode={:#x}, era={:#x}, is={:#x}, badi={:#x}, badv={:#x}", - ecode2str(ecode,esubcode), ecode, esubcode, era, is, badi, badv) + error!("unhandled exception: {}: ecode={:#x}, esubcode={:#x}, era={:#x}, is={:#x}, badi={:#x}, badv={:#x}", + ecode2str(ecode,esubcode), ecode, esubcode, era, is, badi, badv); + this_cpu_data().arch_cpu.idle(); // boneinscri 2026.04, use shutdown to restart it~ for debugging } } } _ => { - panic!("unhandled exception: {}: ecode={:#x}, esubcode={:#x}, era={:#x}, is={:#x}, badi={:#x}, badv={:#x}", - ecode2str(ecode,esubcode), ecode, esubcode, era, is, badi, badv) + error!("unhandled exception: {}: ecode={:#x}, esubcode={:#x}, era={:#x}, is={:#x}, badi={:#x}, badv={:#x}", + ecode2str(ecode,esubcode), ecode, esubcode, era, is, badi, badv); + this_cpu_data().arch_cpu.idle(); // boneinscri 2026.04, use shutdown to restart it~ for debugging } } } @@ -645,6 +671,15 @@ pub fn _vcpu_return(ctx: usize) { // Enable interrupt prmd::set_pie(true); + + // ecfg_timer_enable(); + + // ecfg_hwi_enable(); + // ecfg_swi_enable(); + + ecfg::set_vs(GLOBAL_VS_VALUE); + eentry::set_eentry(_hyp_trap_vector as usize); + trace!( "loongarch64: _vcpu_return: calling _hyp_trap_return with ctx = {:#x}", ctx @@ -702,126 +737,126 @@ extern "C" fn _hyp_trap_vector() { "st.d $r12, $r3, 256", // save GCSRS - "gcsrrd $r12, {LOONGARCH_GCSR_CRMD}", - "st.d $r12, $r3, 256+8*1", - "gcsrrd $r12, {LOONGARCH_GCSR_PRMD}", - "st.d $r12, $r3, 256+8*2", - "gcsrrd $r12, {LOONGARCH_GCSR_EUEN}", - "st.d $r12, $r3, 256+8*3", - "gcsrrd $r12, {LOONGARCH_GCSR_MISC}", - "st.d $r12, $r3, 256+8*4", - "gcsrrd $r12, {LOONGARCH_GCSR_ECTL}", - "st.d $r12, $r3, 256+8*5", - "gcsrrd $r12, {LOONGARCH_GCSR_ESTAT}", - "st.d $r12, $r3, 256+8*6", - "gcsrrd $r12, {LOONGARCH_GCSR_ERA}", - "st.d $r12, $r3, 256+8*7", - "gcsrrd $r12, {LOONGARCH_GCSR_BADV}", - "st.d $r12, $r3, 256+8*8", - "gcsrrd $r12, {LOONGARCH_GCSR_BADI}", - "st.d $r12, $r3, 256+8*9", - "gcsrrd $r12, {LOONGARCH_GCSR_EENTRY}", - "st.d $r12, $r3, 256+8*10", - "gcsrrd $r12, {LOONGARCH_GCSR_TLBIDX}", - "st.d $r12, $r3, 256+8*11", - "gcsrrd $r12, {LOONGARCH_GCSR_TLBEHI}", - "st.d $r12, $r3, 256+8*12", - "gcsrrd $r12, {LOONGARCH_GCSR_TLBELO0}", - "st.d $r12, $r3, 256+8*13", - "gcsrrd $r12, {LOONGARCH_GCSR_TLBELO1}", - "st.d $r12, $r3, 256+8*14", - "gcsrrd $r12, {LOONGARCH_GCSR_ASID}", - "st.d $r12, $r3, 256+8*15", - "gcsrrd $r12, {LOONGARCH_GCSR_PGDL}", - "st.d $r12, $r3, 256+8*16", - "gcsrrd $r12, {LOONGARCH_GCSR_PGDH}", - "st.d $r12, $r3, 256+8*17", - "gcsrrd $r12, {LOONGARCH_GCSR_PGD}", - "st.d $r12, $r3, 256+8*18", - "gcsrrd $r12, {LOONGARCH_GCSR_PWCL}", - "st.d $r12, $r3, 256+8*19", - "gcsrrd $r12, {LOONGARCH_GCSR_PWCH}", - "st.d $r12, $r3, 256+8*20", - "gcsrrd $r12, {LOONGARCH_GCSR_STLBPS}", - "st.d $r12, $r3, 256+8*21", - "gcsrrd $r12, {LOONGARCH_GCSR_RAVCFG}", - "st.d $r12, $r3, 256+8*22", - "gcsrrd $r12, {LOONGARCH_GCSR_CPUID}", - "st.d $r12, $r3, 256+8*23", - "gcsrrd $r12, {LOONGARCH_GCSR_PRCFG1}", - "st.d $r12, $r3, 256+8*24", - "gcsrrd $r12, {LOONGARCH_GCSR_PRCFG2}", - "st.d $r12, $r3, 256+8*25", - "gcsrrd $r12, {LOONGARCH_GCSR_PRCFG3}", - "st.d $r12, $r3, 256+8*26", - "gcsrrd $r12, {LOONGARCH_GCSR_SAVE0}", - "st.d $r12, $r3, 256+8*27", - "gcsrrd $r12, {LOONGARCH_GCSR_SAVE1}", - "st.d $r12, $r3, 256+8*28", - "gcsrrd $r12, {LOONGARCH_GCSR_SAVE2}", - "st.d $r12, $r3, 256+8*29", - "gcsrrd $r12, {LOONGARCH_GCSR_SAVE3}", - "st.d $r12, $r3, 256+8*30", - "gcsrrd $r12, {LOONGARCH_GCSR_SAVE4}", - "st.d $r12, $r3, 256+8*31", - "gcsrrd $r12, {LOONGARCH_GCSR_SAVE5}", - "st.d $r12, $r3, 256+8*32", - "gcsrrd $r12, {LOONGARCH_GCSR_SAVE6}", - "st.d $r12, $r3, 256+8*33", - "gcsrrd $r12, {LOONGARCH_GCSR_SAVE7}", - "st.d $r12, $r3, 256+8*34", - "gcsrrd $r12, {LOONGARCH_GCSR_SAVE8}", - "st.d $r12, $r3, 256+8*35", - "gcsrrd $r12, {LOONGARCH_GCSR_SAVE9}", - "st.d $r12, $r3, 256+8*36", - "gcsrrd $r12, {LOONGARCH_GCSR_SAVE10}", - "st.d $r12, $r3, 256+8*37", - "gcsrrd $r12, {LOONGARCH_GCSR_SAVE11}", - "st.d $r12, $r3, 256+8*38", - "gcsrrd $r12, {LOONGARCH_GCSR_SAVE12}", - "st.d $r12, $r3, 256+8*39", - "gcsrrd $r12, {LOONGARCH_GCSR_SAVE13}", - "st.d $r12, $r3, 256+8*40", - "gcsrrd $r12, {LOONGARCH_GCSR_SAVE14}", - "st.d $r12, $r3, 256+8*41", - "gcsrrd $r12, {LOONGARCH_GCSR_SAVE15}", - "st.d $r12, $r3, 256+8*42", - "gcsrrd $r12, {LOONGARCH_GCSR_TID}", - "st.d $r12, $r3, 256+8*43", - "gcsrrd $r12, {LOONGARCH_GCSR_TCFG}", - "st.d $r12, $r3, 256+8*44", - "gcsrrd $r12, {LOONGARCH_GCSR_TVAL}", - "st.d $r12, $r3, 256+8*45", - "gcsrrd $r12, {LOONGARCH_GCSR_CNTC}", - "st.d $r12, $r3, 256+8*46", - "gcsrrd $r12, {LOONGARCH_GCSR_TICLR}", - "st.d $r12, $r3, 256+8*47", - "gcsrrd $r12, {LOONGARCH_GCSR_LLBCTL}", - "st.d $r12, $r3, 256+8*48", - "gcsrrd $r12, {LOONGARCH_GCSR_TLBRENTRY}", - "st.d $r12, $r3, 256+8*49", - "gcsrrd $r12, {LOONGARCH_GCSR_TLBRBADV}", - "st.d $r12, $r3, 256+8*50", - "gcsrrd $r12, {LOONGARCH_GCSR_TLBRERA}", - "st.d $r12, $r3, 256+8*51", - "gcsrrd $r12, {LOONGARCH_GCSR_TLBRSAVE}", - "st.d $r12, $r3, 256+8*52", - "gcsrrd $r12, {LOONGARCH_GCSR_TLBRELO0}", - "st.d $r12, $r3, 256+8*53", - "gcsrrd $r12, {LOONGARCH_GCSR_TLBRELO1}", - "st.d $r12, $r3, 256+8*54", - "gcsrrd $r12, {LOONGARCH_GCSR_TLBREHI}", - "st.d $r12, $r3, 256+8*55", - "gcsrrd $r12, {LOONGARCH_GCSR_TLBRPRMD}", - "st.d $r12, $r3, 256+8*56", - "gcsrrd $r12, {LOONGARCH_GCSR_DMW0}", - "st.d $r12, $r3, 256+8*57", - "gcsrrd $r12, {LOONGARCH_GCSR_DMW1}", - "st.d $r12, $r3, 256+8*58", - "gcsrrd $r12, {LOONGARCH_GCSR_DMW2}", - "st.d $r12, $r3, 256+8*59", - "gcsrrd $r12, {LOONGARCH_GCSR_DMW3}", - "st.d $r12, $r3, 256+8*60", + // "gcsrrd $r12, {LOONGARCH_GCSR_CRMD}", + // "st.d $r12, $r3, 256+8*1", + // "gcsrrd $r12, {LOONGARCH_GCSR_PRMD}", + // "st.d $r12, $r3, 256+8*2", + // "gcsrrd $r12, {LOONGARCH_GCSR_EUEN}", + // "st.d $r12, $r3, 256+8*3", + // "gcsrrd $r12, {LOONGARCH_GCSR_MISC}", + // "st.d $r12, $r3, 256+8*4", + // "gcsrrd $r12, {LOONGARCH_GCSR_ECTL}", + // "st.d $r12, $r3, 256+8*5", + // "gcsrrd $r12, {LOONGARCH_GCSR_ESTAT}", + // "st.d $r12, $r3, 256+8*6", + // "gcsrrd $r12, {LOONGARCH_GCSR_ERA}", + // "st.d $r12, $r3, 256+8*7", + // "gcsrrd $r12, {LOONGARCH_GCSR_BADV}", + // "st.d $r12, $r3, 256+8*8", + // "gcsrrd $r12, {LOONGARCH_GCSR_BADI}", + // "st.d $r12, $r3, 256+8*9", + // "gcsrrd $r12, {LOONGARCH_GCSR_EENTRY}", + // "st.d $r12, $r3, 256+8*10", + // "gcsrrd $r12, {LOONGARCH_GCSR_TLBIDX}", + // "st.d $r12, $r3, 256+8*11", + // "gcsrrd $r12, {LOONGARCH_GCSR_TLBEHI}", + // "st.d $r12, $r3, 256+8*12", + // "gcsrrd $r12, {LOONGARCH_GCSR_TLBELO0}", + // "st.d $r12, $r3, 256+8*13", + // "gcsrrd $r12, {LOONGARCH_GCSR_TLBELO1}", + // "st.d $r12, $r3, 256+8*14", + // "gcsrrd $r12, {LOONGARCH_GCSR_ASID}", + // "st.d $r12, $r3, 256+8*15", + // "gcsrrd $r12, {LOONGARCH_GCSR_PGDL}", + // "st.d $r12, $r3, 256+8*16", + // "gcsrrd $r12, {LOONGARCH_GCSR_PGDH}", + // "st.d $r12, $r3, 256+8*17", + // "gcsrrd $r12, {LOONGARCH_GCSR_PGD}", + // "st.d $r12, $r3, 256+8*18", + // "gcsrrd $r12, {LOONGARCH_GCSR_PWCL}", + // "st.d $r12, $r3, 256+8*19", + // "gcsrrd $r12, {LOONGARCH_GCSR_PWCH}", + // "st.d $r12, $r3, 256+8*20", + // "gcsrrd $r12, {LOONGARCH_GCSR_STLBPS}", + // "st.d $r12, $r3, 256+8*21", + // "gcsrrd $r12, {LOONGARCH_GCSR_RAVCFG}", + // "st.d $r12, $r3, 256+8*22", + // "gcsrrd $r12, {LOONGARCH_GCSR_CPUID}", + // "st.d $r12, $r3, 256+8*23", + // "gcsrrd $r12, {LOONGARCH_GCSR_PRCFG1}", + // "st.d $r12, $r3, 256+8*24", + // "gcsrrd $r12, {LOONGARCH_GCSR_PRCFG2}", + // "st.d $r12, $r3, 256+8*25", + // "gcsrrd $r12, {LOONGARCH_GCSR_PRCFG3}", + // "st.d $r12, $r3, 256+8*26", + // "gcsrrd $r12, {LOONGARCH_GCSR_SAVE0}", + // "st.d $r12, $r3, 256+8*27", + // "gcsrrd $r12, {LOONGARCH_GCSR_SAVE1}", + // "st.d $r12, $r3, 256+8*28", + // "gcsrrd $r12, {LOONGARCH_GCSR_SAVE2}", + // "st.d $r12, $r3, 256+8*29", + // "gcsrrd $r12, {LOONGARCH_GCSR_SAVE3}", + // "st.d $r12, $r3, 256+8*30", + // "gcsrrd $r12, {LOONGARCH_GCSR_SAVE4}", + // "st.d $r12, $r3, 256+8*31", + // "gcsrrd $r12, {LOONGARCH_GCSR_SAVE5}", + // "st.d $r12, $r3, 256+8*32", + // "gcsrrd $r12, {LOONGARCH_GCSR_SAVE6}", + // "st.d $r12, $r3, 256+8*33", + // "gcsrrd $r12, {LOONGARCH_GCSR_SAVE7}", + // "st.d $r12, $r3, 256+8*34", + // "gcsrrd $r12, {LOONGARCH_GCSR_SAVE8}", + // "st.d $r12, $r3, 256+8*35", + // "gcsrrd $r12, {LOONGARCH_GCSR_SAVE9}", + // "st.d $r12, $r3, 256+8*36", + // "gcsrrd $r12, {LOONGARCH_GCSR_SAVE10}", + // "st.d $r12, $r3, 256+8*37", + // "gcsrrd $r12, {LOONGARCH_GCSR_SAVE11}", + // "st.d $r12, $r3, 256+8*38", + // "gcsrrd $r12, {LOONGARCH_GCSR_SAVE12}", + // "st.d $r12, $r3, 256+8*39", + // "gcsrrd $r12, {LOONGARCH_GCSR_SAVE13}", + // "st.d $r12, $r3, 256+8*40", + // "gcsrrd $r12, {LOONGARCH_GCSR_SAVE14}", + // "st.d $r12, $r3, 256+8*41", + // "gcsrrd $r12, {LOONGARCH_GCSR_SAVE15}", + // "st.d $r12, $r3, 256+8*42", + // "gcsrrd $r12, {LOONGARCH_GCSR_TID}", + // "st.d $r12, $r3, 256+8*43", + // "gcsrrd $r12, {LOONGARCH_GCSR_TCFG}", + // "st.d $r12, $r3, 256+8*44", + // "gcsrrd $r12, {LOONGARCH_GCSR_TVAL}", + // "st.d $r12, $r3, 256+8*45", + // "gcsrrd $r12, {LOONGARCH_GCSR_CNTC}", + // "st.d $r12, $r3, 256+8*46", + // "gcsrrd $r12, {LOONGARCH_GCSR_TICLR}", + // "st.d $r12, $r3, 256+8*47", + // "gcsrrd $r12, {LOONGARCH_GCSR_LLBCTL}", + // "st.d $r12, $r3, 256+8*48", + // "gcsrrd $r12, {LOONGARCH_GCSR_TLBRENTRY}", + // "st.d $r12, $r3, 256+8*49", + // "gcsrrd $r12, {LOONGARCH_GCSR_TLBRBADV}", + // "st.d $r12, $r3, 256+8*50", + // "gcsrrd $r12, {LOONGARCH_GCSR_TLBRERA}", + // "st.d $r12, $r3, 256+8*51", + // "gcsrrd $r12, {LOONGARCH_GCSR_TLBRSAVE}", + // "st.d $r12, $r3, 256+8*52", + // "gcsrrd $r12, {LOONGARCH_GCSR_TLBRELO0}", + // "st.d $r12, $r3, 256+8*53", + // "gcsrrd $r12, {LOONGARCH_GCSR_TLBRELO1}", + // "st.d $r12, $r3, 256+8*54", + // "gcsrrd $r12, {LOONGARCH_GCSR_TLBREHI}", + // "st.d $r12, $r3, 256+8*55", + // "gcsrrd $r12, {LOONGARCH_GCSR_TLBRPRMD}", + // "st.d $r12, $r3, 256+8*56", + // "gcsrrd $r12, {LOONGARCH_GCSR_DMW0}", + // "st.d $r12, $r3, 256+8*57", + // "gcsrrd $r12, {LOONGARCH_GCSR_DMW1}", + // "st.d $r12, $r3, 256+8*58", + // "gcsrrd $r12, {LOONGARCH_GCSR_DMW2}", + // "st.d $r12, $r3, 256+8*59", + // "gcsrrd $r12, {LOONGARCH_GCSR_DMW3}", + // "st.d $r12, $r3, 256+8*60", // // now let's save the zone's pgd to ZoneContext // "csrrd $r12, {LOONGARCH_CSR_PGDL}", // "st.d $r12, $r3, 256+8*61", // PGDL @@ -846,67 +881,67 @@ extern "C" fn _hyp_trap_vector() { LOONGARCH_CSR_SAVE4 = const 0x34, LOONGARCH_CSR_DESAVE = const 0x502, LOONGARCH_CSR_ERA = const 0x6, - LOONGARCH_GCSR_CRMD = const 0x0, - LOONGARCH_GCSR_PRMD = const 0x1, - LOONGARCH_GCSR_EUEN = const 0x2, - LOONGARCH_GCSR_MISC = const 0x3, - LOONGARCH_GCSR_ECTL = const 0x4, - LOONGARCH_GCSR_ESTAT = const 0x5, - LOONGARCH_GCSR_ERA = const 0x6, - LOONGARCH_GCSR_BADV = const 0x7, - LOONGARCH_GCSR_BADI = const 0x8, - LOONGARCH_GCSR_EENTRY = const 0xc, - LOONGARCH_GCSR_TLBIDX = const 0x10, - LOONGARCH_GCSR_TLBEHI = const 0x11, - LOONGARCH_GCSR_TLBELO0 = const 0x12, - LOONGARCH_GCSR_TLBELO1 = const 0x13, - LOONGARCH_GCSR_ASID = const 0x18, - LOONGARCH_GCSR_PGDL = const 0x19, - LOONGARCH_GCSR_PGDH = const 0x1a, - LOONGARCH_GCSR_PGD = const 0x1b, - LOONGARCH_GCSR_PWCL = const 0x1c, - LOONGARCH_GCSR_PWCH = const 0x1d, - LOONGARCH_GCSR_STLBPS = const 0x1e, - LOONGARCH_GCSR_RAVCFG = const 0x1f, - LOONGARCH_GCSR_CPUID = const 0x20, - LOONGARCH_GCSR_PRCFG1 = const 0x21, - LOONGARCH_GCSR_PRCFG2 = const 0x22, - LOONGARCH_GCSR_PRCFG3 = const 0x23, - LOONGARCH_GCSR_SAVE0 = const 0x30, - LOONGARCH_GCSR_SAVE1 = const 0x31, - LOONGARCH_GCSR_SAVE2 = const 0x32, - LOONGARCH_GCSR_SAVE3 = const 0x33, - LOONGARCH_GCSR_SAVE4 = const 0x34, - LOONGARCH_GCSR_SAVE5 = const 0x35, - LOONGARCH_GCSR_SAVE6 = const 0x36, - LOONGARCH_GCSR_SAVE7 = const 0x37, - LOONGARCH_GCSR_SAVE8 = const 0x38, - LOONGARCH_GCSR_SAVE9 = const 0x39, - LOONGARCH_GCSR_SAVE10 = const 0x3a, - LOONGARCH_GCSR_SAVE11 = const 0x3b, - LOONGARCH_GCSR_SAVE12 = const 0x3c, - LOONGARCH_GCSR_SAVE13 = const 0x3d, - LOONGARCH_GCSR_SAVE14 = const 0x3e, - LOONGARCH_GCSR_SAVE15 = const 0x3f, - LOONGARCH_GCSR_TID = const 0x40, - LOONGARCH_GCSR_TCFG = const 0x41, - LOONGARCH_GCSR_TVAL = const 0x42, - LOONGARCH_GCSR_CNTC = const 0x43, - LOONGARCH_GCSR_TICLR = const 0x44, - LOONGARCH_GCSR_LLBCTL = const 0x60, - LOONGARCH_GCSR_TLBRENTRY = const 0x88, - LOONGARCH_GCSR_TLBRBADV = const 0x89, - LOONGARCH_GCSR_TLBRERA = const 0x8a, - LOONGARCH_GCSR_TLBRSAVE = const 0x8b, - LOONGARCH_GCSR_TLBRELO0 = const 0x8c, - LOONGARCH_GCSR_TLBRELO1 = const 0x8d, - LOONGARCH_GCSR_TLBREHI = const 0x8e, - LOONGARCH_GCSR_TLBRPRMD = const 0x8f, - LOONGARCH_GCSR_DMW0 = const 0x180, - LOONGARCH_GCSR_DMW1 = const 0x181, - LOONGARCH_GCSR_DMW2 = const 0x182, - LOONGARCH_GCSR_DMW3 = const 0x183, - // LOONGARCH_CSR_PGDL = const 0x19, + // LOONGARCH_GCSR_CRMD = const 0x0, + // LOONGARCH_GCSR_PRMD = const 0x1, + // LOONGARCH_GCSR_EUEN = const 0x2, + // LOONGARCH_GCSR_MISC = const 0x3, + // LOONGARCH_GCSR_ECTL = const 0x4, + // LOONGARCH_GCSR_ESTAT = const 0x5, + // LOONGARCH_GCSR_ERA = const 0x6, + // LOONGARCH_GCSR_BADV = const 0x7, + // LOONGARCH_GCSR_BADI = const 0x8, + // LOONGARCH_GCSR_EENTRY = const 0xc, + // LOONGARCH_GCSR_TLBIDX = const 0x10, + // LOONGARCH_GCSR_TLBEHI = const 0x11, + // LOONGARCH_GCSR_TLBELO0 = const 0x12, + // LOONGARCH_GCSR_TLBELO1 = const 0x13, + // LOONGARCH_GCSR_ASID = const 0x18, + // LOONGARCH_GCSR_PGDL = const 0x19, + // LOONGARCH_GCSR_PGDH = const 0x1a, + // LOONGARCH_GCSR_PGD = const 0x1b, + // LOONGARCH_GCSR_PWCL = const 0x1c, + // LOONGARCH_GCSR_PWCH = const 0x1d, + // LOONGARCH_GCSR_STLBPS = const 0x1e, + // LOONGARCH_GCSR_RAVCFG = const 0x1f, + // LOONGARCH_GCSR_CPUID = const 0x20, + // LOONGARCH_GCSR_PRCFG1 = const 0x21, + // LOONGARCH_GCSR_PRCFG2 = const 0x22, + // LOONGARCH_GCSR_PRCFG3 = const 0x23, + // LOONGARCH_GCSR_SAVE0 = const 0x30, + // LOONGARCH_GCSR_SAVE1 = const 0x31, + // LOONGARCH_GCSR_SAVE2 = const 0x32, + // LOONGARCH_GCSR_SAVE3 = const 0x33, + // LOONGARCH_GCSR_SAVE4 = const 0x34, + // LOONGARCH_GCSR_SAVE5 = const 0x35, + // LOONGARCH_GCSR_SAVE6 = const 0x36, + // LOONGARCH_GCSR_SAVE7 = const 0x37, + // LOONGARCH_GCSR_SAVE8 = const 0x38, + // LOONGARCH_GCSR_SAVE9 = const 0x39, + // LOONGARCH_GCSR_SAVE10 = const 0x3a, + // LOONGARCH_GCSR_SAVE11 = const 0x3b, + // LOONGARCH_GCSR_SAVE12 = const 0x3c, + // LOONGARCH_GCSR_SAVE13 = const 0x3d, + // LOONGARCH_GCSR_SAVE14 = const 0x3e, + // LOONGARCH_GCSR_SAVE15 = const 0x3f, + // LOONGARCH_GCSR_TID = const 0x40, + // LOONGARCH_GCSR_TCFG = const 0x41, + // LOONGARCH_GCSR_TVAL = const 0x42, + // LOONGARCH_GCSR_CNTC = const 0x43, + // LOONGARCH_GCSR_TICLR = const 0x44, + // LOONGARCH_GCSR_LLBCTL = const 0x60, + // LOONGARCH_GCSR_TLBRENTRY = const 0x88, + // LOONGARCH_GCSR_TLBRBADV = const 0x89, + // LOONGARCH_GCSR_TLBRERA = const 0x8a, + // LOONGARCH_GCSR_TLBRSAVE = const 0x8b, + // LOONGARCH_GCSR_TLBRELO0 = const 0x8c, + // LOONGARCH_GCSR_TLBRELO1 = const 0x8d, + // LOONGARCH_GCSR_TLBREHI = const 0x8e, + // LOONGARCH_GCSR_TLBRPRMD = const 0x8f, + // LOONGARCH_GCSR_DMW0 = const 0x180, + // LOONGARCH_GCSR_DMW1 = const 0x181, + // LOONGARCH_GCSR_DMW2 = const 0x182, + // LOONGARCH_GCSR_DMW3 = const 0x183, + // // LOONGARCH_CSR_PGDL = const 0x19, // LOONGARCH_CSR_PGDH = const 0x1a, // LOONGARCH_CSR_SAVE5 = const 0x35, // LOONGARCH_CSR_SAVE6 = const 0x36, @@ -925,90 +960,90 @@ pub unsafe extern "C" fn _hyp_trap_return(ctx: usize) { "ld.d $r12, $r3, 256", "csrwr $r12, {LOONGARCH_CSR_ERA}", // restore GCSRS - "ld.d $r12, $r3, 256+8*1", - "gcsrwr $r12, {LOONGARCH_GCSR_CRMD}", - "ld.d $r12, $r3, 256+8*2", - "gcsrwr $r12, {LOONGARCH_GCSR_PRMD}", - "ld.d $r12, $r3, 256+8*3", - "gcsrwr $r12, {LOONGARCH_GCSR_EUEN}", - "ld.d $r12, $r3, 256+8*4", - "gcsrwr $r12, {LOONGARCH_GCSR_MISC}", - "ld.d $r12, $r3, 256+8*5", - "gcsrwr $r12, {LOONGARCH_GCSR_ECTL}", + // "ld.d $r12, $r3, 256+8*1", + // "gcsrwr $r12, {LOONGARCH_GCSR_CRMD}", + // "ld.d $r12, $r3, 256+8*2", + // "gcsrwr $r12, {LOONGARCH_GCSR_PRMD}", + // "ld.d $r12, $r3, 256+8*3", + // "gcsrwr $r12, {LOONGARCH_GCSR_EUEN}", + // "ld.d $r12, $r3, 256+8*4", + // "gcsrwr $r12, {LOONGARCH_GCSR_MISC}", + // "ld.d $r12, $r3, 256+8*5", + // "gcsrwr $r12, {LOONGARCH_GCSR_ECTL}", // "ld.d $r12, $r3, 256+8*6", // "gcsrwr $r12, {LOONGARCH_GCSR_ESTAT}", - "ld.d $r12, $r3, 256+8*7", - "gcsrwr $r12, {LOONGARCH_GCSR_ERA}", - "ld.d $r12, $r3, 256+8*8", - "gcsrwr $r12, {LOONGARCH_GCSR_BADV}", - "ld.d $r12, $r3, 256+8*9", - "gcsrwr $r12, {LOONGARCH_GCSR_BADI}", - "ld.d $r12, $r3, 256+8*10", - "gcsrwr $r12, {LOONGARCH_GCSR_EENTRY}", - "ld.d $r12, $r3, 256+8*11", - "gcsrwr $r12, {LOONGARCH_GCSR_TLBIDX}", - "ld.d $r12, $r3, 256+8*12", - "gcsrwr $r12, {LOONGARCH_GCSR_TLBEHI}", - "ld.d $r12, $r3, 256+8*13", - "gcsrwr $r12, {LOONGARCH_GCSR_TLBELO0}", - "ld.d $r12, $r3, 256+8*14", - "gcsrwr $r12, {LOONGARCH_GCSR_TLBELO1}", - "ld.d $r12, $r3, 256+8*15", - "gcsrwr $r12, {LOONGARCH_GCSR_ASID}", - "ld.d $r12, $r3, 256+8*16", - "gcsrwr $r12, {LOONGARCH_GCSR_PGDL}", - "ld.d $r12, $r3, 256+8*17", - "gcsrwr $r12, {LOONGARCH_GCSR_PGDH}", - "ld.d $r12, $r3, 256+8*18", - "gcsrwr $r12, {LOONGARCH_GCSR_PGD}", - "ld.d $r12, $r3, 256+8*19", - "gcsrwr $r12, {LOONGARCH_GCSR_PWCL}", - "ld.d $r12, $r3, 256+8*20", - "gcsrwr $r12, {LOONGARCH_GCSR_PWCH}", - "ld.d $r12, $r3, 256+8*21", - "gcsrwr $r12, {LOONGARCH_GCSR_STLBPS}", - "ld.d $r12, $r3, 256+8*22", - "gcsrwr $r12, {LOONGARCH_GCSR_RAVCFG}", - "ld.d $r12, $r3, 256+8*23", - "gcsrwr $r12, {LOONGARCH_GCSR_CPUID}", - "ld.d $r12, $r3, 256+8*24", - "gcsrwr $r12, {LOONGARCH_GCSR_PRCFG1}", - "ld.d $r12, $r3, 256+8*25", - "gcsrwr $r12, {LOONGARCH_GCSR_PRCFG2}", - "ld.d $r12, $r3, 256+8*26", - "gcsrwr $r12, {LOONGARCH_GCSR_PRCFG3}", - "ld.d $r12, $r3, 256+8*27", - "gcsrwr $r12, {LOONGARCH_GCSR_SAVE0}", - "ld.d $r12, $r3, 256+8*28", - "gcsrwr $r12, {LOONGARCH_GCSR_SAVE1}", - "ld.d $r12, $r3, 256+8*29", - "gcsrwr $r12, {LOONGARCH_GCSR_SAVE2}", - "ld.d $r12, $r3, 256+8*30", - "gcsrwr $r12, {LOONGARCH_GCSR_SAVE3}", - "ld.d $r12, $r3, 256+8*31", - "gcsrwr $r12, {LOONGARCH_GCSR_SAVE4}", - "ld.d $r12, $r3, 256+8*32", - "gcsrwr $r12, {LOONGARCH_GCSR_SAVE5}", - "ld.d $r12, $r3, 256+8*33", - "gcsrwr $r12, {LOONGARCH_GCSR_SAVE6}", - "ld.d $r12, $r3, 256+8*34", - "gcsrwr $r12, {LOONGARCH_GCSR_SAVE7}", - "ld.d $r12, $r3, 256+8*35", - "gcsrwr $r12, {LOONGARCH_GCSR_SAVE8}", - "ld.d $r12, $r3, 256+8*36", - "gcsrwr $r12, {LOONGARCH_GCSR_SAVE9}", - "ld.d $r12, $r3, 256+8*37", - "gcsrwr $r12, {LOONGARCH_GCSR_SAVE10}", - "ld.d $r12, $r3, 256+8*38", - "gcsrwr $r12, {LOONGARCH_GCSR_SAVE11}", - "ld.d $r12, $r3, 256+8*39", - "gcsrwr $r12, {LOONGARCH_GCSR_SAVE12}", - "ld.d $r12, $r3, 256+8*40", - "gcsrwr $r12, {LOONGARCH_GCSR_SAVE13}", - "ld.d $r12, $r3, 256+8*41", - "gcsrwr $r12, {LOONGARCH_GCSR_SAVE14}", - "ld.d $r12, $r3, 256+8*42", - "gcsrwr $r12, {LOONGARCH_GCSR_SAVE15}", + // "ld.d $r12, $r3, 256+8*7", + // "gcsrwr $r12, {LOONGARCH_GCSR_ERA}", + // "ld.d $r12, $r3, 256+8*8", + // "gcsrwr $r12, {LOONGARCH_GCSR_BADV}", + // "ld.d $r12, $r3, 256+8*9", + // "gcsrwr $r12, {LOONGARCH_GCSR_BADI}", + // "ld.d $r12, $r3, 256+8*10", + // "gcsrwr $r12, {LOONGARCH_GCSR_EENTRY}", + // "ld.d $r12, $r3, 256+8*11", + // "gcsrwr $r12, {LOONGARCH_GCSR_TLBIDX}", + // "ld.d $r12, $r3, 256+8*12", + // "gcsrwr $r12, {LOONGARCH_GCSR_TLBEHI}", + // "ld.d $r12, $r3, 256+8*13", + // "gcsrwr $r12, {LOONGARCH_GCSR_TLBELO0}", + // "ld.d $r12, $r3, 256+8*14", + // "gcsrwr $r12, {LOONGARCH_GCSR_TLBELO1}", + // "ld.d $r12, $r3, 256+8*15", + // "gcsrwr $r12, {LOONGARCH_GCSR_ASID}", + // "ld.d $r12, $r3, 256+8*16", + // "gcsrwr $r12, {LOONGARCH_GCSR_PGDL}", + // "ld.d $r12, $r3, 256+8*17", + // "gcsrwr $r12, {LOONGARCH_GCSR_PGDH}", + // "ld.d $r12, $r3, 256+8*18", + // "gcsrwr $r12, {LOONGARCH_GCSR_PGD}", + // "ld.d $r12, $r3, 256+8*19", + // "gcsrwr $r12, {LOONGARCH_GCSR_PWCL}", + // "ld.d $r12, $r3, 256+8*20", + // "gcsrwr $r12, {LOONGARCH_GCSR_PWCH}", + // "ld.d $r12, $r3, 256+8*21", + // "gcsrwr $r12, {LOONGARCH_GCSR_STLBPS}", + // "ld.d $r12, $r3, 256+8*22", + // "gcsrwr $r12, {LOONGARCH_GCSR_RAVCFG}", + // "ld.d $r12, $r3, 256+8*23", + // "gcsrwr $r12, {LOONGARCH_GCSR_CPUID}", + // "ld.d $r12, $r3, 256+8*24", + // "gcsrwr $r12, {LOONGARCH_GCSR_PRCFG1}", + // "ld.d $r12, $r3, 256+8*25", + // "gcsrwr $r12, {LOONGARCH_GCSR_PRCFG2}", + // "ld.d $r12, $r3, 256+8*26", + // "gcsrwr $r12, {LOONGARCH_GCSR_PRCFG3}", + // "ld.d $r12, $r3, 256+8*27", + // "gcsrwr $r12, {LOONGARCH_GCSR_SAVE0}", + // "ld.d $r12, $r3, 256+8*28", + // "gcsrwr $r12, {LOONGARCH_GCSR_SAVE1}", + // "ld.d $r12, $r3, 256+8*29", + // "gcsrwr $r12, {LOONGARCH_GCSR_SAVE2}", + // "ld.d $r12, $r3, 256+8*30", + // "gcsrwr $r12, {LOONGARCH_GCSR_SAVE3}", + // "ld.d $r12, $r3, 256+8*31", + // "gcsrwr $r12, {LOONGARCH_GCSR_SAVE4}", + // "ld.d $r12, $r3, 256+8*32", + // "gcsrwr $r12, {LOONGARCH_GCSR_SAVE5}", + // "ld.d $r12, $r3, 256+8*33", + // "gcsrwr $r12, {LOONGARCH_GCSR_SAVE6}", + // "ld.d $r12, $r3, 256+8*34", + // "gcsrwr $r12, {LOONGARCH_GCSR_SAVE7}", + // "ld.d $r12, $r3, 256+8*35", + // "gcsrwr $r12, {LOONGARCH_GCSR_SAVE8}", + // "ld.d $r12, $r3, 256+8*36", + // "gcsrwr $r12, {LOONGARCH_GCSR_SAVE9}", + // "ld.d $r12, $r3, 256+8*37", + // "gcsrwr $r12, {LOONGARCH_GCSR_SAVE10}", + // "ld.d $r12, $r3, 256+8*38", + // "gcsrwr $r12, {LOONGARCH_GCSR_SAVE11}", + // "ld.d $r12, $r3, 256+8*39", + // "gcsrwr $r12, {LOONGARCH_GCSR_SAVE12}", + // "ld.d $r12, $r3, 256+8*40", + // "gcsrwr $r12, {LOONGARCH_GCSR_SAVE13}", + // "ld.d $r12, $r3, 256+8*41", + // "gcsrwr $r12, {LOONGARCH_GCSR_SAVE14}", + // "ld.d $r12, $r3, 256+8*42", + // "gcsrwr $r12, {LOONGARCH_GCSR_SAVE15}", // "ld.d $r12, $r3, 256+8*43", // "gcsrwr $r12, {LOONGARCH_GCSR_TID}", // "ld.d $r12, $r3, 256+8*44", @@ -1019,93 +1054,93 @@ pub unsafe extern "C" fn _hyp_trap_return(ctx: usize) { // "gcsrwr $r12, {LOONGARCH_GCSR_CNTC}", // "ld.d $r12, $r3, 256+8*47", // "gcsrwr $r12, {LOONGARCH_GCSR_TICLR}", - "ld.d $r12, $r3, 256+8*48", - "gcsrwr $r12, {LOONGARCH_GCSR_LLBCTL}", - "ld.d $r12, $r3, 256+8*49", - "gcsrwr $r12, {LOONGARCH_GCSR_TLBRENTRY}", - "ld.d $r12, $r3, 256+8*50", - "gcsrwr $r12, {LOONGARCH_GCSR_TLBRBADV}", - "ld.d $r12, $r3, 256+8*51", - "gcsrwr $r12, {LOONGARCH_GCSR_TLBRERA}", - "ld.d $r12, $r3, 256+8*52", - "gcsrwr $r12, {LOONGARCH_GCSR_TLBRSAVE}", - "ld.d $r12, $r3, 256+8*53", - "gcsrwr $r12, {LOONGARCH_GCSR_TLBRELO0}", - "ld.d $r12, $r3, 256+8*54", - "gcsrwr $r12, {LOONGARCH_GCSR_TLBRELO1}", - "ld.d $r12, $r3, 256+8*55", - "gcsrwr $r12, {LOONGARCH_GCSR_TLBREHI}", - "ld.d $r12, $r3, 256+8*56", - "gcsrwr $r12, {LOONGARCH_GCSR_TLBRPRMD}", - "ld.d $r12, $r3, 256+8*57", - "gcsrwr $r12, {LOONGARCH_GCSR_DMW0}", - "ld.d $r12, $r3, 256+8*58", - "gcsrwr $r12, {LOONGARCH_GCSR_DMW1}", - "ld.d $r12, $r3, 256+8*59", - "gcsrwr $r12, {LOONGARCH_GCSR_DMW2}", - "ld.d $r12, $r3, 256+8*60", - "gcsrwr $r12, {LOONGARCH_GCSR_DMW3}", + // "ld.d $r12, $r3, 256+8*48", + // "gcsrwr $r12, {LOONGARCH_GCSR_LLBCTL}", + // "ld.d $r12, $r3, 256+8*49", + // "gcsrwr $r12, {LOONGARCH_GCSR_TLBRENTRY}", + // "ld.d $r12, $r3, 256+8*50", + // "gcsrwr $r12, {LOONGARCH_GCSR_TLBRBADV}", + // "ld.d $r12, $r3, 256+8*51", + // "gcsrwr $r12, {LOONGARCH_GCSR_TLBRERA}", + // "ld.d $r12, $r3, 256+8*52", + // "gcsrwr $r12, {LOONGARCH_GCSR_TLBRSAVE}", + // "ld.d $r12, $r3, 256+8*53", + // "gcsrwr $r12, {LOONGARCH_GCSR_TLBRELO0}", + // "ld.d $r12, $r3, 256+8*54", + // "gcsrwr $r12, {LOONGARCH_GCSR_TLBRELO1}", + // "ld.d $r12, $r3, 256+8*55", + // "gcsrwr $r12, {LOONGARCH_GCSR_TLBREHI}", + // "ld.d $r12, $r3, 256+8*56", + // "gcsrwr $r12, {LOONGARCH_GCSR_TLBRPRMD}", + // "ld.d $r12, $r3, 256+8*57", + // "gcsrwr $r12, {LOONGARCH_GCSR_DMW0}", + // "ld.d $r12, $r3, 256+8*58", + // "gcsrwr $r12, {LOONGARCH_GCSR_DMW1}", + // "ld.d $r12, $r3, 256+8*59", + // "gcsrwr $r12, {LOONGARCH_GCSR_DMW2}", + // "ld.d $r12, $r3, 256+8*60", + // "gcsrwr $r12, {LOONGARCH_GCSR_DMW3}", LOONGARCH_CSR_ERA = const 0x6, - LOONGARCH_GCSR_CRMD = const 0x0, - LOONGARCH_GCSR_PRMD = const 0x1, - LOONGARCH_GCSR_EUEN = const 0x2, - LOONGARCH_GCSR_MISC = const 0x3, - LOONGARCH_GCSR_ECTL = const 0x4, + // LOONGARCH_GCSR_CRMD = const 0x0, + // LOONGARCH_GCSR_PRMD = const 0x1, + // LOONGARCH_GCSR_EUEN = const 0x2, + // LOONGARCH_GCSR_MISC = const 0x3, + // LOONGARCH_GCSR_ECTL = const 0x4, // LOONGARCH_GCSR_ESTAT = const 0x5, - LOONGARCH_GCSR_ERA = const 0x6, - LOONGARCH_GCSR_BADV = const 0x7, - LOONGARCH_GCSR_BADI = const 0x8, - LOONGARCH_GCSR_EENTRY = const 0xc, - LOONGARCH_GCSR_TLBIDX = const 0x10, - LOONGARCH_GCSR_TLBEHI = const 0x11, - LOONGARCH_GCSR_TLBELO0 = const 0x12, - LOONGARCH_GCSR_TLBELO1 = const 0x13, - LOONGARCH_GCSR_ASID = const 0x18, - LOONGARCH_GCSR_PGDL = const 0x19, - LOONGARCH_GCSR_PGDH = const 0x1a, - LOONGARCH_GCSR_PGD = const 0x1b, - LOONGARCH_GCSR_PWCL = const 0x1c, - LOONGARCH_GCSR_PWCH = const 0x1d, - LOONGARCH_GCSR_STLBPS = const 0x1e, - LOONGARCH_GCSR_RAVCFG = const 0x1f, - LOONGARCH_GCSR_CPUID = const 0x20, - LOONGARCH_GCSR_PRCFG1 = const 0x21, - LOONGARCH_GCSR_PRCFG2 = const 0x22, - LOONGARCH_GCSR_PRCFG3 = const 0x23, - LOONGARCH_GCSR_SAVE0 = const 0x30, - LOONGARCH_GCSR_SAVE1 = const 0x31, - LOONGARCH_GCSR_SAVE2 = const 0x32, - LOONGARCH_GCSR_SAVE3 = const 0x33, - LOONGARCH_GCSR_SAVE4 = const 0x34, - LOONGARCH_GCSR_SAVE5 = const 0x35, - LOONGARCH_GCSR_SAVE6 = const 0x36, - LOONGARCH_GCSR_SAVE7 = const 0x37, - LOONGARCH_GCSR_SAVE8 = const 0x38, - LOONGARCH_GCSR_SAVE9 = const 0x39, - LOONGARCH_GCSR_SAVE10 = const 0x3a, - LOONGARCH_GCSR_SAVE11 = const 0x3b, - LOONGARCH_GCSR_SAVE12 = const 0x3c, - LOONGARCH_GCSR_SAVE13 = const 0x3d, - LOONGARCH_GCSR_SAVE14 = const 0x3e, - LOONGARCH_GCSR_SAVE15 = const 0x3f, + // LOONGARCH_GCSR_ERA = const 0x6, + // LOONGARCH_GCSR_BADV = const 0x7, + // LOONGARCH_GCSR_BADI = const 0x8, + // LOONGARCH_GCSR_EENTRY = const 0xc, + // LOONGARCH_GCSR_TLBIDX = const 0x10, + // LOONGARCH_GCSR_TLBEHI = const 0x11, + // LOONGARCH_GCSR_TLBELO0 = const 0x12, + // LOONGARCH_GCSR_TLBELO1 = const 0x13, + // LOONGARCH_GCSR_ASID = const 0x18, + // LOONGARCH_GCSR_PGDL = const 0x19, + // LOONGARCH_GCSR_PGDH = const 0x1a, + // LOONGARCH_GCSR_PGD = const 0x1b, + // LOONGARCH_GCSR_PWCL = const 0x1c, + // LOONGARCH_GCSR_PWCH = const 0x1d, + // LOONGARCH_GCSR_STLBPS = const 0x1e, + // LOONGARCH_GCSR_RAVCFG = const 0x1f, + // LOONGARCH_GCSR_CPUID = const 0x20, + // LOONGARCH_GCSR_PRCFG1 = const 0x21, + // LOONGARCH_GCSR_PRCFG2 = const 0x22, + // LOONGARCH_GCSR_PRCFG3 = const 0x23, + // LOONGARCH_GCSR_SAVE0 = const 0x30, + // LOONGARCH_GCSR_SAVE1 = const 0x31, + // LOONGARCH_GCSR_SAVE2 = const 0x32, + // LOONGARCH_GCSR_SAVE3 = const 0x33, + // LOONGARCH_GCSR_SAVE4 = const 0x34, + // LOONGARCH_GCSR_SAVE5 = const 0x35, + // LOONGARCH_GCSR_SAVE6 = const 0x36, + // LOONGARCH_GCSR_SAVE7 = const 0x37, + // LOONGARCH_GCSR_SAVE8 = const 0x38, + // LOONGARCH_GCSR_SAVE9 = const 0x39, + // LOONGARCH_GCSR_SAVE10 = const 0x3a, + // LOONGARCH_GCSR_SAVE11 = const 0x3b, + // LOONGARCH_GCSR_SAVE12 = const 0x3c, + // LOONGARCH_GCSR_SAVE13 = const 0x3d, + // LOONGARCH_GCSR_SAVE14 = const 0x3e, + // LOONGARCH_GCSR_SAVE15 = const 0x3f, // LOONGARCH_GCSR_TID = const 0x40, // LOONGARCH_GCSR_TCFG = const 0x41, // LOONGARCH_GCSR_TVAL = const 0x42, // LOONGARCH_GCSR_CNTC = const 0x43, // LOONGARCH_GCSR_TICLR = const 0x44, - LOONGARCH_GCSR_LLBCTL = const 0x60, - LOONGARCH_GCSR_TLBRENTRY = const 0x88, - LOONGARCH_GCSR_TLBRBADV = const 0x89, - LOONGARCH_GCSR_TLBRERA = const 0x8a, - LOONGARCH_GCSR_TLBRSAVE = const 0x8b, - LOONGARCH_GCSR_TLBRELO0 = const 0x8c, - LOONGARCH_GCSR_TLBRELO1 = const 0x8d, - LOONGARCH_GCSR_TLBREHI = const 0x8e, - LOONGARCH_GCSR_TLBRPRMD = const 0x8f, - LOONGARCH_GCSR_DMW0 = const 0x180, - LOONGARCH_GCSR_DMW1 = const 0x181, - LOONGARCH_GCSR_DMW2 = const 0x182, - LOONGARCH_GCSR_DMW3 = const 0x183, + // LOONGARCH_GCSR_LLBCTL = const 0x60, + // LOONGARCH_GCSR_TLBRENTRY = const 0x88, + // LOONGARCH_GCSR_TLBRBADV = const 0x89, + // LOONGARCH_GCSR_TLBRERA = const 0x8a, + // LOONGARCH_GCSR_TLBRSAVE = const 0x8b, + // LOONGARCH_GCSR_TLBRELO0 = const 0x8c, + // LOONGARCH_GCSR_TLBRELO1 = const 0x8d, + // LOONGARCH_GCSR_TLBREHI = const 0x8e, + // LOONGARCH_GCSR_TLBRPRMD = const 0x8f, + // LOONGARCH_GCSR_DMW0 = const 0x180, + // LOONGARCH_GCSR_DMW1 = const 0x181, + // LOONGARCH_GCSR_DMW2 = const 0x182, + // LOONGARCH_GCSR_DMW3 = const 0x183, ); // asm!( // // vm-pagetable -> save5 and save6 @@ -1263,32 +1298,115 @@ const HWI4: usize = 1 << 6; const HWI5: usize = 1 << 7; const HWI6: usize = 1 << 8; const HWI7: usize = 1 << 9; +const SWI0: usize = 1 << 0; +const SWI1: usize = 1 << 1; + +fn do_deliver_irq(irq_flags: usize, clear_flag: bool) { + for irq in (0..13).rev() { + let mask = 1 << irq; + if irq_flags & mask != 0 { + if clear_flag { + // clear irq + clear_irq(irq, false); // para is_hardware is invalid here + } else { + // inject irq + inject_irq(irq, false); + } + } + } +} + +fn deliver_irq() { + let pcpu_id = this_cpu_id(); + let pcpu_data = get_cpu_data(pcpu_id); + let irq_pending = pcpu_data.arch_cpu.irq_pending; + let irq_clear = pcpu_data.arch_cpu.irq_clear; + if irq_pending == 0 && irq_clear == 0 { + return; + } + assert!(irq_clear & irq_pending == 0); + + do_deliver_irq(irq_clear, true); + do_deliver_irq(irq_pending, false); + pcpu_data.arch_cpu.irq_pending = 0; + pcpu_data.arch_cpu.irq_clear = 0; +} /// handle loongarch64 interrupts here fn handle_interrupt(is: usize) { // Handle IPI interrupts + let pcpu_id_this: usize = this_cpu_id(); + let pcpu_data = get_cpu_data(pcpu_id_this); + if is & IPI_BIT != 0 { - let cpu_id = this_cpu_id(); - let ipi_status = get_ipi_status(cpu_id); - debug!( - "CPU {} received IPI interrupt, status = {:#x}", - cpu_id, ipi_status - ); + let ipi_status = get_ipi_status(pcpu_id_this); + + let mut ipistate = pcpu_data.arch_cpu.ipi_state.lock(); + let pcpu_ipi_status = ipistate.status as usize; // read - match ipi_status { - status if status == SGI_IPI_ID as _ => { - let events = dump_cpu_events(cpu_id); - debug!("CPU {} events: {:?}", cpu_id, events); - while check_events() {} + reset_ipi(pcpu_id_this); // clear + + if pcpu_ipi_status & SMP_BOOT_CPU != 0 { + if pcpu_data.vcpu_state.is_running() { + panic!( + "pcpu : {} has already power on, this should not happen", + pcpu_id_this + ); } - status if status == 0x8 => { - debug!("CPU {} received unhandled IPI status {:#x}", cpu_id, status); + // this should be done by firmware, but we do this here, because linux kernel does not do it + ipistate.status &= !(ipi_status as u32); + + let first_pcpu_id = pcpu_data + .zone + .as_ref() + .unwrap() + .read() + .cpu_set() + .first_cpu() + .unwrap(); + + if (first_pcpu_id == pcpu_id_this) { + // this is the first cpu in the zone + drop(ipistate); // remember! avoid deadlock + pcpu_data.arch_cpu.run(); + panic!("can't reach here"); + } else { + // this is not the first cpu in the zone, read smpboot_entry from ipistate.buf + // let smpboot_entry = ipistate.buf[first_pcpu_id] as usize; + let smpboot_entry = ipistate.buf[0] as usize; + // note!, always fetch smpboot_entry from cpu[0]! boneinscri 2026.04 + warn!("pcpu_ipi_status = {:#x}, first_pcpu_id = {:#x}, smpboot_entry: {:#x}, pcpu_ipi_status = {:#x}", + pcpu_ipi_status, first_pcpu_id, smpboot_entry, ipistate.status as usize); + drop(ipistate); // remember! avoid deadlock + pcpu_data.arch_cpu.run_secondary(smpboot_entry); + panic!("can't reach here"); } - status => { - warn!("CPU {} received unknown IPI status {:#x}", cpu_id, status); + } else if pcpu_ipi_status & HVISOR_SHUTDOWN != 0 { + // if pcpu_data.arch_cpu.power_on == false { + // panic!("pcpu : {} has not power on, this should not happen", pcpu_id_this); + // } + ipistate.status &= !(ipi_status as u32); + drop(ipistate); + pcpu_data.arch_cpu.idle(); + } else if pcpu_ipi_status & HVISOR_EVENT_VIRTIO_INJECT_IRQ != 0 { + if pcpu_data.vcpu_state.is_running() == false { + panic!( + "pcpu : {} has not power on, this should not happen", + pcpu_id_this + ); } + ipistate.status &= !(ipi_status as u32); + drop(ipistate); + handle_virtio_irq(); + } else if pcpu_ipi_status & HVISOR_EVENT_WAKEUP_VIRTIO_DEVICE != 0 { + panic!("HVISOR_EVENT_WAKEUP_VIRTIO_DEVICE, not tested"); + } else if pcpu_ipi_status & HVISOR_EVENT_VIRTIO_CLEAR_IRQ != 0 { + panic!("HVISOR_EVENT_VIRTIO_CLEAR_IRQ, not tested"); + } else if pcpu_ipi_status != 0 { + drop(ipistate); + pcpu_data.arch_cpu.add_irq(INT_IPI); + } else { } - reset_ipi(cpu_id); return; } @@ -1312,6 +1430,13 @@ fn handle_interrupt(is: usize) { return; } + if is & SWI0 != 0 { + panic!("swi0 not handled"); + } + if is & SWI1 != 0 { + panic!("swi1 not handled"); + } + // Handle unknown interrupts error!("Received unhandled interrupt, status = {:#x}", is); } @@ -1352,10 +1477,10 @@ fn emulate_cpucfg(ins: usize, ctx: &mut ZoneContext) { const MAX_CPUCFG_REGS: usize = 21; - info!( - "cpucfg emulation, target cpucfg index is {:#x}", - cpucfg_target_idx - ); + // info!( + // "cpucfg emulation, target cpucfg index is {:#x}", + // cpucfg_target_idx + // ); if cpucfg_target_idx >= MAX_CPUCFG_REGS { // invalid cpucfg target @@ -1364,46 +1489,60 @@ fn emulate_cpucfg(ins: usize, ctx: &mut ZoneContext) { // according to manual, we should set result to 0 if index is invalid } else { // just run cpucfg here - let result: usize; + let mut result = 0; unsafe { asm!("cpucfg {}, {}", out(reg) result, in(reg) cpucfg_target_idx); } + if cpucfg_target_idx == 0x2 { + result &= !(1 << 10); // shutdown lvz of vm -- boneinscri 2026.04 + } ctx.x[rd] = result; // finish the emulation by tweaking the ZoneContext's registers // as ctx.sepc is already added by 4 which means we will jump to next instruction - wheatfox } } +// modified -- boneinscri 2026.04 fn emulate_csrx(ins: usize, ctx: &mut ZoneContext) { // csrrd csrwr csrxchg - // let ty = (ins >> 5) & 0x1f; // let rd = ins & 0x1f; // let csr = (ins >> 10) & 0x3fff; - let ty = extract_field(ins, 5, 5); + let rj = extract_field(ins, 5, 5); let rd = extract_field(ins, 0, 5); - let csr = extract_field(ins, 10, 14); + let csr_id = extract_field(ins, 10, 14); // ty: [9:5], 0 - csrrd, 1 - csrwr, else - csrxchg // rd [4:0] // csr [23:10] 14 bits - match ty { + assert!(csr_id <= 0x502); + + let pcpu_data_this = this_cpu_data(); + // TODO: pay attention to PERFCTRL0 + match rj { 0 => { // csrrd - info!("csrrd emulation for CSR {:#x}", csr); - ctx.x[rd] = 0; - // just set it to 0 + let val = pcpu_data_this.arch_cpu.csr[csr_id]; + ctx.x[rd] = val; + // info!("csrrd emulation for CSR {:#x}, r val = {:#x}", csr_id, val); } 1 => { // csrwr - info!("csrwr emulation for CSR {:#x}", csr); - ctx.x[rd] = 0; - // do nothing to GCSR, but we also need to set rd to 0 + let val = ctx.x[rd]; + // info!("csrwr emulation for CSR {:#x}, w val = {:#x}", csr_id, val); + pcpu_data_this.arch_cpu.csr[csr_id] = val; + ctx.x[rd] = val; } _ => { // csrxchg - info!("csrxchg emulation for CSR {:#x}", csr); - ctx.x[rd] = 0; - // do nothing to GCSR, but we also need to set rd to 0 + // info!("csrxchg emulation for CSR {:#x}, val : {:#x}, csr_mask : {:#x}", + // csr_id, ctx.x[rd], ctx.x[rj]); + let mut val = ctx.x[rd]; + let csr_mask = ctx.x[rj]; + let mut old = pcpu_data_this.arch_cpu.csr[csr_id]; // read old value from sw csr + val = (old & !csr_mask) | (val & csr_mask); + pcpu_data_this.arch_cpu.csr[csr_id] = val; // record the new value from trap ctx + old = old & csr_mask; + ctx.x[rd] = old; // return old value to guest } } } @@ -1433,6 +1572,53 @@ fn ty2str(ty: usize) -> &'static str { } } +// boneinscri 2026.04 +pub fn loongarch_iocsr_read(pcpu_id: usize, addr: usize, len: usize) -> usize { + let iocsr_type = get_iocsr_type(addr); + match iocsr_type { + IOCSR_TYPE_IPI => { + // IPI + let ret = loongarch_ipi_readl(pcpu_id, addr, len); + ret + } + IOCSR_TYPE_EIOINTC => { + // EIOINTC + let ret = loongarch_eiointc_readl(pcpu_id, addr, len); + ret + } + IOCSR_TYPE_EIOINTC_VIRT => { + panic!("EIOINTC_VIRT detected, this is not supported yet"); + } + _ => { + let mut addr_real = addr; + do_real_read_iocsr(addr_real, len) + } + } +} +pub fn loongarch_iocsr_write(pcpu_id: usize, addr: usize, val: usize, len: usize) -> usize { + let iocsr_type = get_iocsr_type(addr); + match iocsr_type { + IOCSR_TYPE_IPI => { + // IPI + let ret = loongarch_ipi_writel(pcpu_id, addr, val, len); + ret + } + IOCSR_TYPE_EIOINTC => { + // EIOINTC + let ret = loongarch_eiointc_writel(pcpu_id, addr, val, len); + ret + } + IOCSR_TYPE_EIOINTC_VIRT => { + panic!("EIOINTC_VIRT detected, this is not supported yet"); + } + _ => { + let mut addr_real = addr; + do_real_write_iocsr(addr_real, val, len); + 0 + } + } +} + fn emulate_iocsr(ins: usize, ctx: &mut ZoneContext) { // iocsrrd.b rd, rj 0000011001 001000000000 rj[9:5] rd[4:0] // iocsrrd.h rd, rj 0000011001 001000000001 rj[9:5] rd[4:0] @@ -1448,96 +1634,28 @@ fn emulate_iocsr(ins: usize, ctx: &mut ZoneContext) { debug!("iocsr emulation, ty = {}, rd = {}, rj = {}", ty, rd, rj); debug!("GPR[rd] = {:#x}, GPR[rj] = {:#x}", ctx.x[rd], ctx.x[rj]); - const IOCSR_BASE_ADDR_PHY: usize = 0x1fe0_0000; - let mut mmio_access = MMIOAccess { - address: IOCSR_BASE_ADDR_PHY + ctx.x[rj], // iocsr only issues an offset from IOCSR_BASE_ADDR_PHY, so we need the calculate the real phy addr - size: 0, - is_write: false, - value: ctx.x[rd], - }; + let mut len = 0; + let mut is_write = false; + let addr = ctx.x[rj] as usize; + let val = ctx.x[rd] as usize; - match ty { - 0 => { - // iocsrrd.b - mmio_access.size = 1; - mmio_access.is_write = false; - } - 1 => { - // iocsrrd.h - mmio_access.size = 2; - mmio_access.is_write = false; - } - 2 => { - // iocsrrd.w - mmio_access.size = 4; - mmio_access.is_write = false; - } - 3 => { - // iocsrrd.d - mmio_access.size = 8; - mmio_access.is_write = false; - } - 4 => { - // iocsrwr.b - mmio_access.size = 1; - mmio_access.is_write = true; - } - 5 => { - // iocsrwr.h - mmio_access.size = 2; - mmio_access.is_write = true; - } - 6 => { - // iocsrwr.w - mmio_access.size = 4; - mmio_access.is_write = true; - } - 7 => { - // iocsrwr.d - mmio_access.size = 8; - mmio_access.is_write = true; - } - _ => { - // should not reach here - panic!("invalid iocsr type, this is impossible"); - } + if ty < 8 { + len = 1 << (ty % 4); // 0-3:1,2,4,8; 4-7:1,2,4,8 + is_write = ty >= 4; + } else { + panic!("emulate_iocsr, invalid iocsr type, this is impossible"); } - debug!( - "iocsr issues a mmio access: {}, target address: {:#x}, size: {}, {}", - ty2str(ty), - mmio_access.address, - mmio_access.size, - if mmio_access.is_write { "W" } else { "R" } - ); + // TODO : modify to vCPU + let pcpu_id_this = this_cpu_id(); - let res = mmio_handle_access(&mut mmio_access); - match res { - Ok(_) => { - debug!("handle mmio success, v={:#x}", mmio_access.value); - if !mmio_access.is_write { - let mask = match mmio_access.size { - 1 => 0xff, - 2 => 0xffff, - 4 => 0xffffffff, - 8 => 0xffffffffffffffff, - _ => panic!("invalid mmio access size: {}", mmio_access.size), - }; - let trimmed_by_size = mmio_access.value & mask; - let extended = if ty < 4 { - signed_ext(trimmed_by_size, mmio_access.size * 8) - } else { - trimmed_by_size - }; - ctx.x[rd] = extended; - } - } - Err(e) => { - panic!( - "mmio access failed, error = {:?}, this is a real page fault", - e - ); - } + if is_write { + let ret = loongarch_iocsr_write(pcpu_id_this, addr, val, len); + return; + } else { + let ret = loongarch_iocsr_read(pcpu_id_this, addr, len); + ctx.x[rd] = ret; + return; } } diff --git a/src/arch/loongarch64/zone.rs b/src/arch/loongarch64/zone.rs index baa50d13..de01f55e 100644 --- a/src/arch/loongarch64/zone.rs +++ b/src/arch/loongarch64/zone.rs @@ -101,7 +101,7 @@ impl Zone { info!("loongarch64: pt_init: add mmio handler for 0x1fe0_xxxx mmio region"); inner.mmio_region_register(0x1fe0_0000, 0x3000, loongarch_generic_mmio_handler, 0x1234); - info!("zone stage-2 memory set: {:#x?}", inner.gpm()); + // info!("zone stage-2 memory set: {:#x?}", inner.gpm()); unsafe { // test the page table by querying the first page if mem_regions.len() > 0 { diff --git a/src/arch/mod.rs b/src/arch/mod.rs index 997ce3da..c3f62c27 100644 --- a/src/arch/mod.rs +++ b/src/arch/mod.rs @@ -37,3 +37,101 @@ pub use loongarch64::*; #[cfg(target_arch = "x86_64")] pub use x86_64::*; + +// Unified architecture interface +pub mod interface { + /// Get the secondary entry point for CPU startup + /// For architectures that need a special secondary entry (like LoongArch64), + /// this returns the secondary entry function. For other architectures, + /// this returns the same as arch_entry. + pub fn arch_secondary_entry() -> unsafe extern "C" fn() -> i32 { + #[cfg(target_arch = "loongarch64")] + { + use super::loongarch64::entry::arch_secondary_entry; + arch_secondary_entry + } + + #[cfg(not(target_arch = "loongarch64"))] + { + // For non-LoongArch64 architectures, we need to create a wrapper + // that matches the expected signature + unsafe extern "C" fn wrapper() -> i32 { + // Call the actual arch_entry, which may return ! or i32 + // For architectures where arch_entry returns !, this code is unreachable + // For architectures where arch_entry returns i32, we return its value + #[cfg(target_arch = "aarch64")] + { + use super::aarch64::entry::arch_entry; + arch_entry(); + // arch_entry never returns, so this is unreachable + unreachable!() + } + + #[cfg(any(target_arch = "riscv64", target_arch = "x86_64"))] + { + use super::entry::arch_entry; + arch_entry() + } + } + wrapper + } + } + + /// Architecture-specific initialization after heap is set up + pub fn arch_post_heap_init(host_dtb: usize) { + #[cfg(target_arch = "loongarch64")] + { + use super::loongarch64::mm::arch_post_heap_init as la_arch_post_heap_init; + la_arch_post_heap_init(host_dtb); + } + + #[cfg(not(target_arch = "loongarch64"))] + { + use super::mm::arch_post_heap_init as generic_arch_post_heap_init; + generic_arch_post_heap_init(host_dtb); + } + } + + /// Architecture-specific timer initialization + pub fn timer_init() { + #[cfg(target_arch = "loongarch64")] + { + use super::loongarch64::timer::timer_init as la_timer_init; + la_timer_init(); + } + + #[cfg(not(target_arch = "loongarch64"))] + { + // Other architectures may have their own timer init or none at all + } + } + + /// Architecture-specific print logo function + pub fn print_logo() { + #[cfg(target_arch = "loongarch64")] + { + use super::loongarch64::print_logo as la_print_logo; + la_print_logo(); + } + + #[cfg(not(target_arch = "loongarch64"))] + { + // Other architectures may not have a special logo + println!("Hello, HVISOR!"); + } + } + + /// Architecture-specific clear BSS function + pub fn clear_bss() { + #[cfg(target_arch = "loongarch64")] + { + use crate::clear_bss; + clear_bss(); + } + + #[cfg(not(target_arch = "loongarch64"))] + { + // BSS is cleared in arch_entry for other architectures + } + } +} diff --git a/src/config.rs b/src/config.rs index aecc2759..aee49191 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 = 0x5; +pub const CONFIG_MAGIC_VERSION: usize = 0x6; pub const CONFIG_MAX_MEMORY_REGIONS: usize = 64; pub type BitmapWord = u32; @@ -101,6 +101,7 @@ pub struct HvZoneConfig { pub dtb_load_paddr: u64, pub dtb_size: u64, pub name: [u8; CONFIG_NAME_MAXLEN], + pub boot_method: [u8; CONFIG_NAME_MAXLEN], pub arch_config: HvArchZoneConfig, pub num_pci_bus: u64, pub pci_config: [HvPciConfig; CONFIG_PCI_BUS_MAXNUM], @@ -124,6 +125,7 @@ impl HvZoneConfig { dtb_load_paddr: u64, dtb_size: u64, name: [u8; CONFIG_NAME_MAXLEN], + boot_method: [u8; CONFIG_NAME_MAXLEN], arch: HvArchZoneConfig, num_pci_bus: u64, pci: [HvPciConfig; CONFIG_PCI_BUS_MAXNUM], @@ -144,6 +146,7 @@ impl HvZoneConfig { dtb_load_paddr, dtb_size, name, + boot_method, arch_config: arch, num_pci_bus, pci_config: pci, diff --git a/src/consts.rs b/src/consts.rs index 88a3f3e9..ab4cd3c1 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -28,15 +28,25 @@ 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 MiB +#[cfg(target_arch = "loongarch64")] +pub const HV_HEAP_SIZE: usize = 64 * 1024 * 1024; // 64 MiB +#[cfg(not(target_arch = "loongarch64"))] +pub const HV_HEAP_SIZE: usize = 1 * 1024 * 1024; // 1 MiB /// Size of the hypervisor memory pool used for dynamic allocation. +#[cfg(target_arch = "loongarch64")] +pub const HV_MEM_POOL_SIZE: usize = 512 * 1024 * 1024; // 256 MiB +#[cfg(not(target_arch = "loongarch64"))] pub const HV_MEM_POOL_SIZE: usize = 64 * 1024 * 1024; // 64 MiB /// 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. + +#[cfg(target_arch = "loongarch64")] +pub const PER_CPU_SIZE: usize = 1024 * 1024 * 16; // 16MiB +#[cfg(not(target_arch = "loongarch64"))] pub const PER_CPU_SIZE: usize = 512 * 1024; // 512 KiB /// Pointer to the beginning of the per-CPU data array. diff --git a/src/cpu_data.rs b/src/cpu_data.rs index fc151919..24e8045a 100644 --- a/src/cpu_data.rs +++ b/src/cpu_data.rs @@ -17,7 +17,7 @@ use alloc::sync::Arc; use spin::Mutex; use crate::arch::cpu::{store_cpu_pointer_to_reg, this_cpu_id, ArchCpu}; -use crate::consts::{INVALID_ADDRESS, PER_CPU_ARRAY_PTR, PER_CPU_SIZE}; +use crate::consts::{INVALID_ADDRESS, MAX_CPU_NUM, PER_CPU_ARRAY_PTR, PER_CPU_SIZE}; use crate::memory::addr::VirtAddr; use crate::zone::Zone; use crate::ENTERED_CPUS; @@ -235,6 +235,22 @@ pub struct CpuSet { pub bitmap: u64, } +pub fn get_real_pcpu_id(target_cpu_id: usize) -> usize { + assert!(target_cpu_id < MAX_CPU_NUM); + let zone = this_zone(); + let cpu_set = zone.read().cpu_set(); + let target_pcpu_real_id = cpu_set.iter().nth(target_cpu_id).unwrap(); + target_pcpu_real_id +} + +pub fn get_vcpuid_from_pcpuid(target_pcpu_id: usize) -> usize { + assert!(target_pcpu_id < MAX_CPU_NUM); + let zone = this_zone(); + let cpu_set = zone.read().cpu_set(); + let target_vcpuid = cpu_set.pcpuid_to_vcpuid(target_pcpu_id).unwrap(); + target_vcpuid +} + impl CpuSet { pub fn new(max_cpu_id: usize, bitmap: u64) -> Self { Self { max_cpu_id, bitmap } @@ -256,6 +272,14 @@ impl CpuSet { pub fn first_cpu(&self) -> Option { (0..=self.max_cpu_id).find(move |&i| self.contains_cpu(i)) } + // boneinscri 2026.04 + pub fn pcpuid_to_vcpuid(&self, pcpu_id: usize) -> Option { + if !self.contains_cpu(pcpu_id) { + return None; + } + // Count how many CPUs are set before this one + Some((0..pcpu_id).filter(|&i| self.contains_cpu(i)).count()) + } pub fn iter<'a>(&'a self) -> impl Iterator + 'a { (0..=self.max_cpu_id).filter(move |&i| self.contains_cpu(i)) } diff --git a/src/device/irqchip/ls7a2000/mod.rs b/src/device/irqchip/ls7a2000/mod.rs index b34a766c..f94f45ea 100644 --- a/src/device/irqchip/ls7a2000/mod.rs +++ b/src/device/irqchip/ls7a2000/mod.rs @@ -13,6 +13,7 @@ // // Authors: // Yulong Han +// Ming Shen // #![allow(unused)] @@ -21,7 +22,10 @@ use crate::{ clock::*, cpu::this_cpu_id, ipi::*, - register::{read_gcsr_estat, write_gcsr_estat}, + register::{ + clear_gcsr_estat, read_csr_gintc, read_gcsr_estat, set_csr_gintc, set_gcsr_estat, + write_csr_gintc, write_gcsr_estat, + }, }, consts::MAX_CPU_NUM, zone::Zone, @@ -55,8 +59,8 @@ pub fn primary_init_late() { info!("loongarch64: irqchip: primary_init_late: testing UART1"); crate::device::uart::loongson_uart::__test_uart1(); - info!("loongarch64: irqchip: primary_init_late: probing pci"); - probe_pci(); + // info!("loongarch64: irqchip: primary_init_late: probing pci"); + // probe_pci(); info!("loongarch64: irqchip: primary_init_late: clearing extioi SR regs"); clear_extioi_sr(); @@ -89,10 +93,11 @@ pub fn clock_cpucfg_dump() { pub fn percpu_init() { info!("loongarch64: irqchip: percpu_init: running percpu_init"); - clear_all_ipi(this_cpu_id()); - enable_ipi(this_cpu_id()); + let this_pcpu_id = this_cpu_id(); + clear_all_ipi(this_pcpu_id); + enable_ipi(this_pcpu_id); ecfg_ipi_enable(); - clock_cpucfg_dump(); + // clock_cpucfg_dump(); // timer_test_tick(); } @@ -110,10 +115,12 @@ const INT_PERF: usize = 10; const INT_TIMER: usize = 11; const INT_IPI: usize = 12; -/// inject irq to THIS cpu +// ================================ +// inject and clear irq +// --boneinscri 2026.04 pub fn inject_irq(_irq: usize, is_hardware: bool) { debug!( - "loongarch64: inject_irq: _irq: {}, is_hardware: {}", + "loongarch64: inject_irq, _irq: {}, is_hardware: {}", _irq, is_hardware ); if _irq > INT_IPI { @@ -122,21 +129,32 @@ pub fn inject_irq(_irq: usize, is_hardware: bool) { } let bit = 1 << _irq; if _irq >= INT_HWI0 && _irq <= INT_HWI7 { - // use gintc to inject - use crate::arch::register::gintc; - gintc::set_hwis(bit >> INT_HWI0); + set_csr_gintc(bit >> INT_HWI0); } else { - // use gcsr to inject, just set the bit - let mut gcsr_estat = read_gcsr_estat(); - gcsr_estat |= bit; - write_gcsr_estat(gcsr_estat); + set_gcsr_estat(bit); } - let mut status = GLOBAL_IRQ_INJECT_STATUS.lock(); - status.cpu_status[this_cpu_id()].status = InjectionStatus::Injecting; +} - tcfg::set_en(true); // start timer to avoid endless timer injection - // please only enable this for debugging because it may cause overheads for realtime nonroots +pub fn clear_irq(_irq: usize, is_hardware: bool) { + debug!( + "loongarch64: inject_irq, _irq: {}, is_hardware: {}", + _irq, is_hardware + ); + if _irq > INT_IPI { + error!("loongarch64: inject_irq: _irq > {}, not valid", INT_IPI); + return; + } + let bit = 1 << _irq; + if _irq >= INT_HWI0 && _irq <= INT_HWI7 { + use crate::arch::register::gintc; + let mut gintc_raw = read_csr_gintc(); + gintc_raw &= !(bit >> INT_HWI0); + set_csr_gintc(gintc_raw); + } else { + clear_gcsr_estat(bit); + } } +// ================================ /// clear the injecting irq ctrl bit on THIS cpu pub fn clear_hwi_injected_irq() { diff --git a/src/event.rs b/src/event.rs index 0c70b3bd..a55a88a2 100644 --- a/src/event.rs +++ b/src/event.rs @@ -155,6 +155,11 @@ pub fn send_event(cpu_id: usize, ipi_int_id: usize, event_id: usize) { /// Currently, we are not passing parameters, and we will modify the function signature later as needed. arch_prepare_send_event(cpu_id, ipi_int_id, event_id); add_event(cpu_id, event_id); + + #[cfg(target_arch = "loongarch64")] + arch_send_event(cpu_id as _, event_id as _); + + #[cfg(not(target_arch = "loongarch64"))] arch_send_event(cpu_id as _, ipi_int_id as _); } diff --git a/src/hypercall/mod.rs b/src/hypercall/mod.rs index 3a67f20f..2243c9ce 100644 --- a/src/hypercall/mod.rs +++ b/src/hypercall/mod.rs @@ -209,7 +209,9 @@ impl<'a> HyperCall<'a> { error!("hv_zone_start: cpu {} already on", boot_cpu); return hv_result_err!(EBUSY); }; + #[cfg(not(target_arch = "loongarch64"))] self.check_cpu_id(); + add_zone(zone); drop(_lock); HyperCallResult::Ok(0) diff --git a/src/main.rs b/src/main.rs index 736d209b..e61f5428 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,8 +66,10 @@ mod pci; #[cfg(test)] mod tests; -use crate::arch::mm::{arch_post_heap_init, arch_setup_parange}; +use crate::arch::interface; +use crate::arch::mm::arch_setup_parange; use crate::consts::{hv_end, mem_pool_start, MAX_CPU_NUM}; +#[cfg(feature = "iommu")] use crate::device::iommu::iommu_init; use arch::{cpu::cpu_start, entry::arch_entry}; use config::root_zone_config; @@ -175,7 +177,9 @@ fn wakeup_secondary_cpus(this_id: usize, host_dtb: usize) { if cpu_id == this_id { continue; } - cpu_start(cpu_id, arch_entry as _, host_dtb); + + let secondary_entry = interface::arch_secondary_entry(); + cpu_start(cpu_id, secondary_entry as _, host_dtb); } } @@ -192,20 +196,26 @@ fn rust_main(cpuid: usize, host_dtb: usize) { extern "C" { fn skernel(); } - println!("Hello, start HVISOR at {:#x?}!", skernel as usize); + if MASTER_CPU.load(Ordering::Acquire) == -1 { MASTER_CPU.store(cpuid as i32, Ordering::Release); is_primary = true; + + interface::clear_bss(); + interface::print_logo(); + percpu::init(); memory::heap::init(); memory::heap::test(); arch::time::init_timebase(); - arch_post_heap_init(host_dtb); + interface::arch_post_heap_init(host_dtb); } percpu::init_percpu_reg(cpuid); let cpu = PerCpu::new(cpuid); + interface::timer_init(); + println!( "Booting CPU {}: {:p} arch:{:p}, DTB: {:#x}", cpu.id, cpu as *const _, &cpu.arch_cpu as *const _, host_dtb diff --git a/src/memory/mm.rs b/src/memory/mm.rs index 26adab8a..8c12b7d1 100644 --- a/src/memory/mm.rs +++ b/src/memory/mm.rs @@ -59,9 +59,9 @@ impl + Into + Copy> MemoryRegion { /// Test whether this region is overlap with `other`. fn is_overlap_with(&self, other: &Self) -> bool { let p0 = self.start.into(); - let p1 = p0 + self.size; + let p1 = p0.wrapping_add(self.size); let p2 = other.start.into(); - let p3 = p2 + other.size; + let p3 = p2.wrapping_add(other.size); !(p1 <= p2 || p0 >= p3) } } diff --git a/src/platform/mod.rs b/src/platform/mod.rs index d9dd18a6..4fa524db 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -67,6 +67,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 boot_method = [0u8; CONFIG_NAME_MAXLEN]; // root zone does not use boot_method + 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; @@ -100,6 +102,7 @@ pub fn platform_root_zone_config() -> HvZoneConfig { ROOT_ZONE_DTB_ADDR, INVALID_ADDRESS as _, name, + boot_method, ROOT_ARCH_ZONE_CONFIG, _num_pci_bus, _root_pci_cfg, diff --git a/src/zone.rs b/src/zone.rs index 158d8c67..eaf016d9 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -110,6 +110,7 @@ impl VirtualAtuConfigs { pub struct Zone { name: [u8; CONFIG_NAME_MAXLEN], + pub boot_method: [u8; CONFIG_NAME_MAXLEN], id: usize, is_err: AtomicBool, inner: RwLock, @@ -125,13 +126,19 @@ pub struct ZoneInner { vpci_bus: VirtualRootComplex, #[cfg(feature = "dwc_pcie")] atu_configs: VirtualAtuConfigs, + #[cfg(target_arch = "loongarch64")] + pub efi_system_table: usize, } impl Zone { #[allow(dead_code)] - pub fn new(zoneid: usize, name: &[u8]) -> Self { + pub fn new(zoneid: usize, name: &[u8], boot_method: &[u8]) -> Self { + let mut bm = [0u8; CONFIG_NAME_MAXLEN]; + let len = boot_method.len().min(CONFIG_NAME_MAXLEN); + bm[..len].copy_from_slice(&boot_method[..len]); Self { name: name.try_into().unwrap(), + boot_method: bm, id: zoneid, is_err: AtomicBool::new(false), inner: RwLock::new(ZoneInner::new()), @@ -183,6 +190,8 @@ impl ZoneInner { vpci_bus: VirtualRootComplex::new(), #[cfg(feature = "dwc_pcie")] atu_configs: VirtualAtuConfigs::new(), + #[cfg(target_arch = "loongarch64")] + efi_system_table: 0, } } @@ -384,7 +393,7 @@ pub fn zone_create(config: &HvZoneConfig) -> HvResult> { ); } - let mut zone = Zone::new(zone_id, &config.name); + let mut zone = Zone::new(zone_id, &config.name, &config.boot_method); zone.pt_init(config.memory_regions())?; zone.mmio_init(&config.arch_config);