From d37fd47e609fd2e10d5f340278f13ea97adef321 Mon Sep 17 00:00:00 2001 From: boneinscri <941388383@qq.com> Date: Sat, 4 Apr 2026 18:37:36 +0800 Subject: [PATCH 01/16] loongarch64: add disa target for ls3a5000/ls3a6000, update .gitignore --- .gitignore | 3 +++ platform/loongarch64/ls3a5000/platform.mk | 7 ++++++- platform/loongarch64/ls3a6000/board.rs | 2 +- platform/loongarch64/ls3a6000/platform.mk | 7 ++++++- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 224a9573..4da91c6d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ /test-img /hvisor.S /hvisor-elf.txt +/hvisor.elf +/hvisor-trap-vector.h +/Doc/compile.md /images/* /platform/*/*/image/kernel/* /platform/*/*/image/virtdisk/* diff --git a/platform/loongarch64/ls3a5000/platform.mk b/platform/loongarch64/ls3a5000/platform.mk index e2abe865..27c10af3 100644 --- a/platform/loongarch64/ls3a5000/platform.mk +++ b/platform/loongarch64/ls3a5000/platform.mk @@ -22,4 +22,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 $@ + + 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.h \ No newline at end of file diff --git a/platform/loongarch64/ls3a6000/board.rs b/platform/loongarch64/ls3a6000/board.rs index 6bd74afa..0ad1f821 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -17,7 +17,7 @@ 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 = 4; diff --git a/platform/loongarch64/ls3a6000/platform.mk b/platform/loongarch64/ls3a6000/platform.mk index e2abe865..27c10af3 100644 --- a/platform/loongarch64/ls3a6000/platform.mk +++ b/platform/loongarch64/ls3a6000/platform.mk @@ -22,4 +22,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 $@ + + 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.h \ No newline at end of file From 68d53e9c706902fe149ad076b3cf27f03e4b7750 Mon Sep 17 00:00:00 2001 From: boneinscri <941388383@qq.com> Date: Sun, 5 Apr 2026 15:52:01 +0800 Subject: [PATCH 02/16] feat(loongarch64): add SMP support for LoongArch 3A5000/3A6000 - Add eiointc driver for extended I/O interrupt controller - Add timer module for per-CPU timer management - Update cpu_start to support multi-core boot via IPI mailbox - Update entry.rs to handle per-CPU initialization for SMP - Update board configs for ls3a5000/ls3a6000 with SMP-aware layout - Update linker scripts and platform.mk for multi-core support - Refactor zone/cpu_data for SMP-aware per-CPU data management --- .gitignore | 2 +- platform/loongarch64/ls3a5000/board.rs | 274 ++++++--- platform/loongarch64/ls3a5000/linker.ld | 6 +- platform/loongarch64/ls3a5000/platform.mk | 5 +- platform/loongarch64/ls3a6000/board.rs | 287 ++++++--- platform/loongarch64/ls3a6000/linker.ld | 8 +- platform/loongarch64/ls3a6000/platform.mk | 5 +- src/arch/loongarch64/cpu.rs | 433 +++++++++++-- src/arch/loongarch64/eiointc.rs | 705 ++++++++++++++++++++++ src/arch/loongarch64/entry.rs | 166 +++++ src/arch/loongarch64/ipi.rs | 361 ++++++++++- src/arch/loongarch64/mod.rs | 2 + src/arch/loongarch64/register/macros.rs | 36 +- src/arch/loongarch64/register/mod.rs | 527 +++++++++++++++- src/arch/loongarch64/timer.rs | 148 +++++ src/arch/loongarch64/trap.rs | 426 +++++++------ src/consts.rs | 8 +- src/cpu_data.rs | 28 +- src/device/irqchip/ls7a2000/mod.rs | 51 +- src/main.rs | 12 + src/memory/mm.rs | 4 +- src/zone.rs | 4 + 22 files changed, 3047 insertions(+), 451 deletions(-) create mode 100644 src/arch/loongarch64/eiointc.rs create mode 100644 src/arch/loongarch64/timer.rs diff --git a/.gitignore b/.gitignore index 4da91c6d..40e37eab 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ /hvisor.S /hvisor-elf.txt /hvisor.elf -/hvisor-trap-vector.h +/hvisor-trap-vector.txt /Doc/compile.md /images/* /platform/*/*/image/kernel/* 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 27c10af3..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 @@ -23,8 +24,8 @@ HVISOR_ENTRY_PA := 0x9000000080000000 $(hvisor_bin): elf $(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.h \ No newline at end of file + 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 0ad1f821..f5fec40d 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -13,142 +13,247 @@ // // Authors: // Yulong Han -// +// Ming Shen use crate::pci_dev; use crate::{arch::zone::HvArchZoneConfig, config::*, pci::vpci_dev::VpciDevType}; pub const BOARD_NAME: &str = "ls3a6000"; -pub const BOARD_NCPUS: usize = 4; +pub const BOARD_NCPUS: usize = 8; + +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: 0x1fe10000, + virtual_start: 0x1fe10000, + 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_RAM, + physical_start: 0x100000000, + virtual_start: 0x100000000, + size: 0x200000000, + // size: 0xe0000000, + }, // RAM + + // HvConfigMemoryRegion { + // 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: 0x10000000, - virtual_start: 0x10000000, - size: 0x1000, - }, // pch-pic irq controller - /* PCI related stuffs ... */ + 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: 0xe8000000000, + virtual_start: 0xe8000000000, + size: 0x15169000 + }, // 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; 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 27c10af3..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 @@ -23,8 +24,8 @@ HVISOR_ENTRY_PA := 0x9000000080000000 $(hvisor_bin): elf $(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.h \ No newline at end of file + 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 9c035d7f..cb81a912 100644 --- a/src/arch/loongarch64/cpu.rs +++ b/src/arch/loongarch64/cpu.rs @@ -13,25 +13,282 @@ // // Authors: // Yulong Han -// +// Ming Shen use super::ipi::*; 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; +use crate::cpu_data::{get_vcpuid_from_pcpuid, this_cpu_data}; use crate::device::common::MMIODerefWrapper; -use crate::zone::find_zone; +use crate::zone::{find_zone, this_zone_id}; +use crate::cpu_data::this_zone; 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 tock_registers::interfaces::Writeable; +use super::register::*; +use super::eiointc::LoongArch64Eiointc; +use spin::Mutex; 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); // NOTE: intentional mapping from original code + write_gcsr_pgdl(self.misc); // NOTE: intentional mapping from original code + write_gcsr_tval(self.ecfg); // NOTE: intentional mapping from original code + 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 { @@ -40,6 +297,14 @@ pub struct ArchCpu { pub cpuid: usize, pub power_on: bool, 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 } impl ArchCpu { @@ -50,9 +315,29 @@ impl ArchCpu { cpuid, power_on: false, init: false, + irq_pending: 0, + irq_clear: 0, + ipi_state: Mutex::new(LoongArch64IpiState::new()), + eiointc: Mutex::new(LoongArch64Eiointc::new()), + expire: 0, }; 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 } @@ -63,45 +348,12 @@ 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(); - self.power_on = true; - 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}", - self.stack_top() - PER_CPU_SIZE - ); - debug!( - "loongarch64: ArchCpu::run: ctx_addr={:#x}, size={}", - ctx_addr as usize, - core::mem::size_of::() - ); - debug!( - "loongarch64: ArchCpu::run: stack_tp={:#x}", - self.stack_top() - ); - + debug!("loongarch64: ArchCpu::vcpu_enter: percpu_s={:#x}", self.stack_top() - PER_CPU_SIZE); + debug!("loongarch64: ArchCpu::vcpu_enter: ctx_addr={:#x}, size={}", ctx_addr as usize, core::mem::size_of::()); + debug!("loongarch64: ArchCpu::vcpu_enter: stack_tp={:#x}", self.stack_top()); unsafe { asm!( "csrwr {}, {LOONGARCH_CSR_SAVE3}", @@ -111,16 +363,100 @@ 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(); + self.power_on = true; + + 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; } + + 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; + this_zone().write().efi_system_table = boot_ctx.efi_system_table; + info!("boot_ctx.efi_system_table: {:#x?}, zone.efi_system_table: {:#x?}", + boot_ctx.efi_system_table, this_zone().read().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 { + snap.dmw0 = read_gcsr_dmw0(); + snap.dmw1 = read_gcsr_dmw1(); + snap.dmw2 = read_gcsr_dmw2(); + snap.dmw3 = read_gcsr_dmw3(); + if this_cpu_data().cpu_on_entry & 0xffff_0000_0000_0000 == 0 { + snap.dmw1 &= 0x0000_ffff_ffff_ffff; // for npucore + } } - super::trap::_vcpu_return(ctx_addr as usize); + 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; + + snap.write_all(); + info!("loongarch64: @{:#x?}", self); + self.vcpu_enter(); + } + + pub fn run_secondary(&mut self, smpboot_entry: usize) -> ! { + assert!(this_cpu_id() == self.get_cpuid()); + this_cpu_data().activate_gpm(); + self.power_on = true; + 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; } - panic!("loongarch64: ArchCpu::run: unreachable"); + 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 { @@ -136,6 +472,8 @@ impl ArchCpu { info!("loongarch64: ArchCpu::idle: cpuid={}", self.get_cpuid()); // enable ipi on ecfg ecfg_ipi_enable(); + enable_global_interrupt(); + self.power_on = false; loop {} } } @@ -150,6 +488,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..4eb8fcf0 --- /dev/null +++ b/src/arch/loongarch64/eiointc.rs @@ -0,0 +1,705 @@ + +// 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::cpu_data::{get_cpu_data, this_zone}; +use crate::consts::MAX_CPU_NUM; +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 +} \ No newline at end of file diff --git a/src/arch/loongarch64/entry.rs b/src/arch/loongarch64/entry.rs index a66148b5..8454c76b 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,167 @@ 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), + + ); +} \ No newline at end of file diff --git a/src/arch/loongarch64/ipi.rs b/src/arch/loongarch64/ipi.rs index 1e1f0cfd..bf1c2389 100644 --- a/src/arch/loongarch64/ipi.rs +++ b/src/arch/loongarch64/ipi.rs @@ -13,9 +13,11 @@ // // 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 core::arch::asm; use core::ptr::write_volatile; @@ -84,6 +86,19 @@ 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 +106,10 @@ 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; + + fn iocsr_mbuf_send_box_lo(a: usize) -> usize { a << 1 } @@ -194,6 +213,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 +243,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 +276,13 @@ 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 +298,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 +320,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 +329,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; @@ -325,6 +375,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 +421,304 @@ 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; 4], +} + +impl LoongArch64IpiState { + pub fn new() -> Self { + Self { + status: 0, + en: 0, + set: 0, + clear: 0, + buf: [0; 4], + } + } +} + +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 +} \ No newline at end of file diff --git a/src/arch/loongarch64/mod.rs b/src/arch/loongarch64/mod.rs index f85dcf53..507ce1e0 100644 --- a/src/arch/loongarch64/mod.rs +++ b/src/arch/loongarch64/mod.rs @@ -19,6 +19,8 @@ pub mod clock; pub mod consts; pub mod cpu; +pub mod eiointc; +pub mod timer; pub mod entry; pub mod hypercall; pub mod iommu; diff --git a/src/arch/loongarch64/register/macros.rs b/src/arch/loongarch64/register/macros.rs index 775cb0d6..77eabb70 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 + }}; +} \ No newline at end of file diff --git a/src/arch/loongarch64/register/mod.rs b/src/arch/loongarch64/register/mod.rs index 53a8480d..e79971cd 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 write_gcsr_eentry(range: core::ops::RangeInclusive, value: usize) { - set_gcsr_loong_bits!(0xc, range, value); +pub fn read_csr_pwch() -> usize { + read_csr_loong!(0x1d) } +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); +} \ No newline at end of file diff --git a/src/arch/loongarch64/timer.rs b/src/arch/loongarch64/timer.rs new file mode 100644 index 00000000..8292dd1f --- /dev/null +++ b/src/arch/loongarch64/timer.rs @@ -0,0 +1,148 @@ + +// 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..e7f56d72 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::ipi::*; +use crate::arch::eiointc::{ + loongarch_eiointc_readl, loongarch_eiointc_writel, + do_real_read_iocsr, do_real_write_iocsr, + EIOINTC_BASE, EIOINTC_SIZE, EIOINTC_VIRT_BASE, EIOINTC_VIRT_SIZE, +}; +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::{inject_irq, ls7a2000::clear_irq}; use crate::device::irqchip::ls7a2000::chip::*; use crate::event::{check_events, dump_cpu_events, dump_events}; use crate::hypercall::{SGI_IPI_ID, *}; use crate::memory::{addr, mmio_handle_access, MMIOAccess}; use crate::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,23 @@ 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 +172,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 +290,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 +352,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"); @@ -645,6 +670,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 @@ -1263,33 +1297,93 @@ 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.arch_cpu.power_on == true { + 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; + 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(); } - reset_ipi(cpu_id); - return; + else if pcpu_ipi_status != 0 { + drop(ipistate); + pcpu_data.arch_cpu.add_irq(INT_IPI); + } else { + } + return ; } // Handle timer interrupts @@ -1312,6 +1406,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); } @@ -1364,10 +1465,13 @@ 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 @@ -1433,6 +1537,54 @@ 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 +1600,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" } - ); - - 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 - ); - } + // TODO : modify to vCPU + let pcpu_id_this = this_cpu_id(); + + 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/consts.rs b/src/consts.rs index 62f93785..7ea8207e 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -28,9 +28,15 @@ 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 = 256 * 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. diff --git a/src/cpu_data.rs b/src/cpu_data.rs index 98b1acec..71c1410f 100644 --- a/src/cpu_data.rs +++ b/src/cpu_data.rs @@ -12,12 +12,12 @@ // https://www.syswonder.org // // Authors: -// +// 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; @@ -111,6 +111,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 } @@ -132,6 +148,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..5d5da69d 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,9 @@ 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, @@ -89,8 +92,9 @@ 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(); // timer_test_tick(); @@ -110,10 +114,13 @@ 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,33 @@ 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/main.rs b/src/main.rs index 92e98022..3a016c8b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,6 +66,7 @@ mod pci; #[cfg(test)] mod tests; +use crate::arch::entry::arch_secondary_entry; use crate::arch::iommu::iommu_init; use crate::arch::mm::{arch_post_heap_init, arch_setup_parange}; use crate::consts::{hv_end, mem_pool_start, MAX_CPU_NUM}; @@ -175,7 +176,13 @@ fn wakeup_secondary_cpus(this_id: usize, host_dtb: usize) { if cpu_id == this_id { continue; } + + #[cfg(not(target_arch = "loongarch64"))] cpu_start(cpu_id, arch_entry as _, host_dtb); + + #[cfg(target_arch = "loongarch64")] + cpu_start(cpu_id, arch_secondary_entry as _, host_dtb); + // restore the boot context, specially for la64 } } @@ -196,6 +203,11 @@ fn rust_main(cpuid: usize, host_dtb: usize) { if MASTER_CPU.load(Ordering::Acquire) == -1 { MASTER_CPU.store(cpuid as i32, Ordering::Release); is_primary = true; + + #[cfg(target_arch = "loongarch64")] + { + clear_bss(); + } percpu::init(); memory::heap::init(); memory::heap::test(); 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/zone.rs b/src/zone.rs index 158d8c67..6214237e 100644 --- a/src/zone.rs +++ b/src/zone.rs @@ -125,6 +125,8 @@ pub struct ZoneInner { vpci_bus: VirtualRootComplex, #[cfg(feature = "dwc_pcie")] atu_configs: VirtualAtuConfigs, + #[cfg(target_arch = "loongarch64")] + pub efi_system_table: usize, } impl Zone { @@ -183,6 +185,8 @@ impl ZoneInner { vpci_bus: VirtualRootComplex::new(), #[cfg(feature = "dwc_pcie")] atu_configs: VirtualAtuConfigs::new(), + #[cfg(target_arch = "loongarch64")] + efi_system_table: 0, } } From 6efe78b8408686961b1285900b7582fc789e0ce5 Mon Sep 17 00:00:00 2001 From: boneinscri <941388383@qq.com> Date: Mon, 6 Apr 2026 11:09:55 +0800 Subject: [PATCH 03/16] loongarch64: smp support, refactor cpu/ipi/trap, add logo and build script --- build-la-nopci.sh | 2 + platform/loongarch64/ls3a6000/board.rs | 128 +++-- src/arch/loongarch64/cpu.rs | 5 +- src/arch/loongarch64/ipi.rs | 20 +- src/arch/loongarch64/paging.rs | 6 +- src/arch/loongarch64/trap.rs | 732 +++++++++++++------------ src/arch/loongarch64/zone.rs | 2 +- src/consts.rs | 6 +- src/device/irqchip/ls7a2000/mod.rs | 6 +- src/main.rs | 20 + 10 files changed, 498 insertions(+), 429 deletions(-) create mode 100755 build-la-nopci.sh 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/platform/loongarch64/ls3a6000/board.rs b/platform/loongarch64/ls3a6000/board.rs index f5fec40d..5d3de399 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -26,11 +26,18 @@ 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 = 0xe71000; -pub const ROOT_ZONE_CPUS: u64 = (1 << 0) | (1 << 1); +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_NAME: &str = "root-linux-la64"; pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ + HvConfigMemoryRegion { + mem_type: MEM_TYPE_RAM, + physical_start: 0x0, + virtual_start: 0x0, + size: 0x200000, + }, // ???? + HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, physical_start: 0x200000, @@ -143,9 +150,9 @@ pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0x7f0000000, - virtual_start: 0x7f0000000, - size: 0x10000000, + physical_start: 0x700000000, + virtual_start: 0x700000000, + size: 0x100000000, }, // RAM // ==== for start_image ==== @@ -213,11 +220,32 @@ pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ 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: 0x15169000 + 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 { @@ -261,22 +289,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 */ @@ -287,34 +316,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/src/arch/loongarch64/cpu.rs b/src/arch/loongarch64/cpu.rs index cb81a912..8a2331bd 100644 --- a/src/arch/loongarch64/cpu.rs +++ b/src/arch/loongarch64/cpu.rs @@ -304,7 +304,8 @@ pub struct ArchCpu { pub irq_clear: usize, pub ipi_state: Mutex, pub eiointc: Mutex, - pub expire: isize + pub expire: isize, + pub csr: [usize; 0x513], } impl ArchCpu { @@ -320,6 +321,7 @@ impl ArchCpu { ipi_state: Mutex::new(LoongArch64IpiState::new()), eiointc: Mutex::new(LoongArch64Eiointc::new()), expire: 0, + csr: [0; 0x513], }; return ret; } @@ -432,7 +434,6 @@ impl ArchCpu { self.ctx.x[20] = boot_ctx.t8; snap.write_all(); - info!("loongarch64: @{:#x?}", self); self.vcpu_enter(); } diff --git a/src/arch/loongarch64/ipi.rs b/src/arch/loongarch64/ipi.rs index bf1c2389..fc5c19d6 100644 --- a/src/arch/loongarch64/ipi.rs +++ b/src/arch/loongarch64/ipi.rs @@ -347,22 +347,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() { diff --git a/src/arch/loongarch64/paging.rs b/src/arch/loongarch64/paging.rs index 582760e1..06368eaf 100644 --- a/src/arch/loongarch64/paging.rs +++ b/src/arch/loongarch64/paging.rs @@ -29,7 +29,7 @@ use loongArch64::register::pwcl::{ set_ptwidth, }; use loongArch64::register::stlbps::{self, set_ps}; -use loongArch64::register::MemoryAccessType; +use loongArch64::register::{MemoryAccessType, tlbidx}; use loongArch64::register::{crmd, pwch, pwcl, tlbrentry}; use loongArch64::register::{pgd, pgdh, pgdl}; @@ -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 +} \ No newline at end of file diff --git a/src/arch/loongarch64/trap.rs b/src/arch/loongarch64/trap.rs index e7f56d72..27e4e3b5 100644 --- a/src/arch/loongarch64/trap.rs +++ b/src/arch/loongarch64/trap.rs @@ -122,7 +122,6 @@ pub fn install_trap_vector() { 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 @@ -736,126 +735,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 @@ -880,67 +879,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, @@ -959,90 +958,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", @@ -1053,93 +1052,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 @@ -1453,10 +1452,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 @@ -1478,36 +1477,47 @@ fn emulate_cpucfg(ins: usize, ctx: &mut ZoneContext) { } } +// 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 } } } 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/consts.rs b/src/consts.rs index 7ea8207e..83e87993 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -35,7 +35,7 @@ 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 = 256 * 1024 * 1024; // 256 MiB +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 @@ -43,6 +43,10 @@ pub const HV_MEM_POOL_SIZE: usize = 64 * 1024 * 1024; // 64 MiB /// /// 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/device/irqchip/ls7a2000/mod.rs b/src/device/irqchip/ls7a2000/mod.rs index 5d5da69d..a4cbffa3 100644 --- a/src/device/irqchip/ls7a2000/mod.rs +++ b/src/device/irqchip/ls7a2000/mod.rs @@ -58,8 +58,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(); @@ -96,7 +96,7 @@ pub fn percpu_init() { clear_all_ipi(this_pcpu_id); enable_ipi(this_pcpu_id); ecfg_ipi_enable(); - clock_cpucfg_dump(); + // clock_cpucfg_dump(); // timer_test_tick(); } diff --git a/src/main.rs b/src/main.rs index 3a016c8b..8e49b55e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -83,6 +83,18 @@ static INIT_EARLY_OK: AtomicU32 = AtomicU32::new(0); static INIT_LATE_OK: AtomicU32 = AtomicU32::new(0); static MASTER_CPU: AtomicI32 = AtomicI32::new(-1); +#[cfg(target_arch = "loongarch64")] +fn print_logo() { + println!(r" + _ _ _ + | | (_) | | + | |__ __ ___ ___ ___ _ __ | | __ _ + | '_ \ \ \ / / / __|/ _ \| '__| | |/ _` | + | | | | \ V /| \__ \ (_) | | _| | (_| | + |_| |_| \_/ |_|___/\___/|_| (_)_|\__,_| +"); +} + pub fn clear_bss() { extern "C" { fn sbss(); @@ -199,6 +211,8 @@ fn rust_main(cpuid: usize, host_dtb: usize) { extern "C" { fn skernel(); } + + #[cfg(not(target_arch = "loongarch64"))] println!("Hello, start HVISOR at {:#x?}!", skernel as usize); if MASTER_CPU.load(Ordering::Acquire) == -1 { MASTER_CPU.store(cpuid as i32, Ordering::Release); @@ -207,6 +221,7 @@ fn rust_main(cpuid: usize, host_dtb: usize) { #[cfg(target_arch = "loongarch64")] { clear_bss(); + print_logo(); } percpu::init(); memory::heap::init(); @@ -218,6 +233,11 @@ fn rust_main(cpuid: usize, host_dtb: usize) { let cpu = PerCpu::new(cpuid); + #[cfg(target_arch = "loongarch64")] { + use crate::arch::timer::timer_init; + timer_init(); + } + println!( "Booting CPU {}: {:p} arch:{:p}, DTB: {:#x}", cpu.id, cpu as *const _, &cpu.arch_cpu as *const _, host_dtb From 688d51164e24f002010b379f9f4b9ff7c583e099 Mon Sep 17 00:00:00 2001 From: boneinscri <941388383@qq.com> Date: Wed, 8 Apr 2026 21:04:51 +0800 Subject: [PATCH 04/16] loongarch64: implement IPI event routing and virtio IRQ injection - Map hvisor IPI events (WAKEUP/SHUTDOWN/VIRTIO_*) to LoongArch64 hardware IPI actions via ipi_send_general() instead of the generic ipi_write_action(); add new IPI action constants for virtio events (HVISOR_EVENT_VIRTIO_INJECT_IRQ/WAKEUP_VIRTIO_DEVICE/CLEAR_IRQ) - Fix arch_send_event() on loongarch64 to dispatch event_id directly rather than ipi_int_id, matching the semantics of other arches; guard the two call sites in send_event() with cfg(target_arch) - Handle HVISOR_EVENT_VIRTIO_INJECT_IRQ in the IPI interrupt handler (trap.rs): call handle_virtio_irq() on the target pcpu; promote MMIO fault log level from debug to info for easier tracing - Pass correct Linux boot arguments (a0=1, a1=cmd_line_ptr, a2=efi_system_table) for non-root zones in ArchCpu::run(); switch DMW snapshot reads from gcsr to csr variants - Restrict ROOT_ZONE_CPUS to 4 cores (bits 0-3) for current testing - Skip check_cpu_id() on loongarch64 in hv_zone_start hypercall --- platform/loongarch64/ls3a6000/board.rs | 3 ++- src/arch/loongarch64/cpu.rs | 20 ++++++++++++-------- src/arch/loongarch64/ipi.rs | 21 ++++++++++++++++++--- src/arch/loongarch64/trap.rs | 19 +++++++++++++++++-- src/event.rs | 6 ++++++ src/hypercall/mod.rs | 6 ++++-- 6 files changed, 59 insertions(+), 16 deletions(-) diff --git a/platform/loongarch64/ls3a6000/board.rs b/platform/loongarch64/ls3a6000/board.rs index 5d3de399..c19ba71f 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -26,7 +26,8 @@ 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 = 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) | (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_NAME: &str = "root-linux-la64"; diff --git a/src/arch/loongarch64/cpu.rs b/src/arch/loongarch64/cpu.rs index 8a2331bd..bea8758c 100644 --- a/src/arch/loongarch64/cpu.rs +++ b/src/arch/loongarch64/cpu.rs @@ -390,18 +390,22 @@ impl ArchCpu { let zone_id = this_zone_id(); if zone_id == 0 { this_cpu_data().cpu_on_entry = boot_ctx.start_image; - this_zone().write().efi_system_table = boot_ctx.efi_system_table; - info!("boot_ctx.efi_system_table: {:#x?}, zone.efi_system_table: {:#x?}", - boot_ctx.efi_system_table, this_zone().read().efi_system_table); + 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 { - snap.dmw0 = read_gcsr_dmw0(); - snap.dmw1 = read_gcsr_dmw1(); - snap.dmw2 = read_gcsr_dmw2(); - snap.dmw3 = read_gcsr_dmw3(); + self.ctx.x[4] = 1; + self.ctx.x[5] = boot_ctx.cmd_line_ptr; + self.ctx.x[6] = boot_ctx.efi_system_table; + info!("zone: {} x[4](a0)={:#x}, x[5](a1/cmd_line_ptr)={:#x}, x[6](a2/efi_system_table)={:#x}", + zone_id, 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 } @@ -409,7 +413,7 @@ impl ArchCpu { if !self.init { self.init(this_cpu_data().cpu_on_entry, this_cpu_data().id, 0); - self.init = true; + self.init= true; } self.ctx.x[1] = boot_ctx.ra; diff --git a/src/arch/loongarch64/ipi.rs b/src/arch/loongarch64/ipi.rs index fc5c19d6..f8ef9a51 100644 --- a/src/arch/loongarch64/ipi.rs +++ b/src/arch/loongarch64/ipi.rs @@ -17,6 +17,7 @@ // use crate::arch::cpu::this_cpu_id; use crate::consts::{IPI_EVENT_CLEAR_INJECT_IRQ, MAX_CPU_NUM}; +use crate::event::{IPI_EVENT_VIRTIO_INJECT_IRQ, IPI_EVENT_WAKEUP, IPI_EVENT_SHUTDOWN, IPI_EVENT_WAKEUP_VIRTIO_DEVICE}; use crate::cpu_data::{get_cpu_data, this_zone}; use crate::device::common::MMIODerefWrapper; use core::arch::asm; @@ -36,8 +37,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! [ @@ -108,7 +121,9 @@ 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 diff --git a/src/arch/loongarch64/trap.rs b/src/arch/loongarch64/trap.rs index 27e4e3b5..d5484f84 100644 --- a/src/arch/loongarch64/trap.rs +++ b/src/arch/loongarch64/trap.rs @@ -30,6 +30,7 @@ use crate::consts::{IPI_EVENT_CLEAR_INJECT_IRQ, MAX_CPU_NUM}; use crate::cpu_data::{get_cpu_data, this_cpu_data}; use crate::device::irqchip::{inject_irq, ls7a2000::clear_irq}; use crate::device::irqchip::ls7a2000::chip::*; +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}; @@ -407,7 +408,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 @@ -1370,12 +1371,26 @@ fn handle_interrupt(is: usize) { } } 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.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(); + 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); diff --git a/src/event.rs b/src/event.rs index f31b1159..9e2fd62d 100644 --- a/src/event.rs +++ b/src/event.rs @@ -147,7 +147,13 @@ pub fn send_event(cpu_id: usize, ipi_int_id: usize, event_id: usize) { // } /// Some arch need do something before send event. /// 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 e7b4bd55..d6df31b4 100644 --- a/src/hypercall/mod.rs +++ b/src/hypercall/mod.rs @@ -208,7 +208,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) @@ -305,7 +307,7 @@ impl<'a> HyperCall<'a> { // cnt as usize, // ) // }; - + for (i, zone_info) in slice.iter_mut().enumerate() { if i < zones_info.len() { *zone_info = zones_info[i].clone(); @@ -313,7 +315,7 @@ impl<'a> HyperCall<'a> { break; } } - + HyperCallResult::Ok(core::cmp::min(cnt as _, zones_info.len())) } } From b016043ee2c433c23cbb331e57f5b62de0774a78 Mon Sep 17 00:00:00 2001 From: boneinscri <941388383@qq.com> Date: Thu, 9 Apr 2026 11:42:09 +0800 Subject: [PATCH 05/16] loongarch64: ls3a6000: update memory regions and ipi buf size - board.rs: clean up ROOT_ZONE_MEMORY_REGIONS, remove unused reserved RAM regions, fix RAM size for 0x100000000 to 0x780000000 (30GB) - ipi.rs: expand LoongArch64IpiState.buf from [u64;4] to [u64;MAX_CPU_NUM] - trap.rs: always fetch smpboot_entry from buf[0]; add debug print for full ipistate.buf --- platform/loongarch64/ls3a6000/board.rs | 70 ++++---------------------- src/arch/loongarch64/ipi.rs | 4 +- src/arch/loongarch64/trap.rs | 4 +- 3 files changed, 14 insertions(+), 64 deletions(-) diff --git a/platform/loongarch64/ls3a6000/board.rs b/platform/loongarch64/ls3a6000/board.rs index c19ba71f..eda6fa89 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -27,7 +27,7 @@ pub const ROOT_ZONE_DTB_ADDR: u64 = 0x10000f000; pub const ROOT_ZONE_KERNEL_ADDR: u64 = 0x200000; 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) ; pub const ROOT_ZONE_NAME: &str = "root-linux-la64"; @@ -102,104 +102,52 @@ pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ size: 0x1000, }, // IO - // 46f000000-47f7fffff - HvConfigMemoryRegion { - mem_type: MEM_TYPE_RAM, - physical_start: 0x46f000000, - virtual_start: 0x46f000000, - size: 0x10800000, - }, // Reserved RAM - - // 47f800000 - 47fffffff - HvConfigMemoryRegion { - mem_type: MEM_TYPE_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: 0x90000000, virtual_start: 0x90000000, size: 0x6a000000, - }, // RAM + }, // RAM 0x90000000 ~ 0xf9ffffff HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, physical_start: 0xfa000000, virtual_start: 0xfa000000, size: 0x5000000, - }, // RAM - - // 0x800000000 ~ 0x87fffffff - HvConfigMemoryRegion { - mem_type: MEM_TYPE_RAM, - physical_start: 0x800000000, - virtual_start: 0x800000000, - size: 0x80000000, - }, // RAM - - HvConfigMemoryRegion { - mem_type: MEM_TYPE_RAM, - physical_start: 0x700000000, - virtual_start: 0x700000000, - size: 0x100000000, - }, // RAM - + }, // RAM 0xfa000000 ~ 0xfeffffff // ==== for start_image ==== // addition HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, - // mem_type: MEM_TYPE_PCH_PCI, physical_start: 0x10000000, virtual_start: 0x10000000, size: 0x1000, - }, // IO!!!!????? PCH-PCI - + }, // IO PCH-PCI + HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x10002000, virtual_start: 0x10002000, size: 0x1000, - }, // IO!!!!????? + }, // IO HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, physical_start: 0x10010000, virtual_start: 0x10010000, size: 0x1000, - }, // IO!!!!????? + }, // IO - // ===========unknown region=============== - // addition + // 0x100000000 ~ 0x87fffffff (30GB) HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, physical_start: 0x100000000, virtual_start: 0x100000000, - size: 0x200000000, - // size: 0xe0000000, + size: 0x780000000, }, // RAM - // HvConfigMemoryRegion { - // 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: 0xe0030000000, diff --git a/src/arch/loongarch64/ipi.rs b/src/arch/loongarch64/ipi.rs index f8ef9a51..2870c9fc 100644 --- a/src/arch/loongarch64/ipi.rs +++ b/src/arch/loongarch64/ipi.rs @@ -463,7 +463,7 @@ pub struct LoongArch64IpiState { pub en: u32, pub set: u32, pub clear: u32, - pub buf: [u64; 4], + pub buf: [u64; MAX_CPU_NUM], } impl LoongArch64IpiState { @@ -473,7 +473,7 @@ impl LoongArch64IpiState { en: 0, set: 0, clear: 0, - buf: [0; 4], + buf: [0; MAX_CPU_NUM], } } } diff --git a/src/arch/loongarch64/trap.rs b/src/arch/loongarch64/trap.rs index d5484f84..f453e9a5 100644 --- a/src/arch/loongarch64/trap.rs +++ b/src/arch/loongarch64/trap.rs @@ -1362,7 +1362,9 @@ fn handle_interrupt(is: usize) { 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[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 From 80b3207264aa47edf12be5afefecb2631d47cacd Mon Sep 17 00:00:00 2001 From: boneinscri <941388383@qq.com> Date: Mon, 13 Apr 2026 22:23:37 +0800 Subject: [PATCH 06/16] la/loongarch64: add boot_method support and improve fault handling config.rs / zone.rs: - add boot_method field to HvZoneConfig and Zone structs - bump CONFIG_MAGIC_VERSION to 0x6 to match hvisor-tool - Zone::new() now accepts boot_method parameter - zone_create() passes config.boot_method to Zone::new() platform/mod.rs: - initialize boot_method as zero for root zone arch/loongarch64/cpu.rs: - check zone.boot_method at boot time to decide EFI vs DTB boot args - if boot_method starts with 'acpi': pass efi_system_table and cmd_line_ptr - otherwise: clear a0/a1/a2 for DTB boot path arch/loongarch64/trap.rs: - replace panic! with error! + idle() on unhandled MMIO and exceptions - prevents hypervisor crash on guest page faults, aids debugging --- src/arch/loongarch64/cpu.rs | 20 +++++++++++++++----- src/arch/loongarch64/trap.rs | 10 ++++++---- src/config.rs | 5 ++++- src/platform/mod.rs | 3 +++ src/zone.rs | 9 +++++++-- 5 files changed, 35 insertions(+), 12 deletions(-) diff --git a/src/arch/loongarch64/cpu.rs b/src/arch/loongarch64/cpu.rs index bea8758c..752f7142 100644 --- a/src/arch/loongarch64/cpu.rs +++ b/src/arch/loongarch64/cpu.rs @@ -396,11 +396,21 @@ impl ArchCpu { 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 { - self.ctx.x[4] = 1; - self.ctx.x[5] = boot_ctx.cmd_line_ptr; - self.ctx.x[6] = boot_ctx.efi_system_table; - info!("zone: {} x[4](a0)={:#x}, x[5](a1/cmd_line_ptr)={:#x}, x[6](a2/efi_system_table)={:#x}", - zone_id, self.ctx.x[4], self.ctx.x[5], self.ctx.x[6]); + 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(); diff --git a/src/arch/loongarch64/trap.rs b/src/arch/loongarch64/trap.rs index f453e9a5..498936e1 100644 --- a/src/arch/loongarch64/trap.rs +++ b/src/arch/loongarch64/trap.rs @@ -602,14 +602,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 } } } 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/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 6214237e..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, @@ -131,9 +132,13 @@ pub struct ZoneInner { 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()), @@ -388,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); From 27483b58c34a6425b543e77410ddabd468ffc85f Mon Sep 17 00:00:00 2001 From: BoneInscri <941388383@qq.com> Date: Sat, 9 May 2026 21:22:35 +0800 Subject: [PATCH 07/16] fix: detect broken symlink in build.rs and expand ROOT_ZONE_CPUS to 7 cores - build.rs: replace exists() with symlink_metadata().is_ok() to correctly detect and remove broken symlinks when re-linking __board.rs - ls3a6000/board.rs: expand ROOT_ZONE_CPUS from 4 cores (bit 0-3) to 7 cores (bit 0-6) for ls3a6000 SMP support --- build.rs | 3 ++- platform/loongarch64/ls3a6000/board.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) 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/ls3a6000/board.rs b/platform/loongarch64/ls3a6000/board.rs index eda6fa89..632ba62d 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -27,7 +27,8 @@ pub const ROOT_ZONE_DTB_ADDR: u64 = 0x10000f000; pub const ROOT_ZONE_KERNEL_ADDR: u64 = 0x200000; 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) ; +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"; From 55ba5505ce1e1ca822dfe6aeac078717c5519435 Mon Sep 17 00:00:00 2001 From: BoneInscri <941388383@qq.com> Date: Sat, 9 May 2026 21:28:48 +0800 Subject: [PATCH 08/16] fix: restore arch_secondary_entry import in main.rs --- src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main.rs b/src/main.rs index 4f61cbf7..cfc85fc4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,6 +66,7 @@ mod pci; #[cfg(test)] mod tests; +use crate::arch::entry::arch_secondary_entry; use crate::arch::mm::{arch_post_heap_init, arch_setup_parange}; use crate::consts::{hv_end, mem_pool_start, MAX_CPU_NUM}; use crate::device::iommu::iommu_init; From 98bc9aa36e4ef30e5e91bb801836f3c823c54fa7 Mon Sep 17 00:00:00 2001 From: BoneInscri <941388383@qq.com> Date: Sat, 9 May 2026 22:32:27 +0800 Subject: [PATCH 09/16] fix: gate arch_secondary_entry and iommu_init imports with cfg attributes --- src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index cfc85fc4..e331c0b9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,9 +66,11 @@ mod pci; #[cfg(test)] mod tests; -use crate::arch::entry::arch_secondary_entry; use crate::arch::mm::{arch_post_heap_init, arch_setup_parange}; use crate::consts::{hv_end, mem_pool_start, MAX_CPU_NUM}; +#[cfg(target_arch = "loongarch64")] +use crate::arch::entry::arch_secondary_entry; +#[cfg(feature = "iommu")] use crate::device::iommu::iommu_init; use arch::{cpu::cpu_start, entry::arch_entry}; use config::root_zone_config; From b611acdba20cf1d94cbee1157caa875b27aebf7b Mon Sep 17 00:00:00 2001 From: BoneInscri <941388383@qq.com> Date: Tue, 12 May 2026 21:57:25 +0800 Subject: [PATCH 10/16] run make fmt --- src/arch/loongarch64/cpu.rs | 499 +++++++++++++++--------- src/arch/loongarch64/eiointc.rs | 220 ++++++----- src/arch/loongarch64/entry.rs | 5 +- src/arch/loongarch64/ipi.rs | 88 +++-- src/arch/loongarch64/mod.rs | 2 +- src/arch/loongarch64/paging.rs | 4 +- src/arch/loongarch64/register/macros.rs | 2 +- src/arch/loongarch64/register/mod.rs | 2 +- src/arch/loongarch64/timer.rs | 45 ++- src/arch/loongarch64/trap.rs | 101 ++--- src/cpu_data.rs | 4 +- src/device/irqchip/ls7a2000/mod.rs | 7 +- src/event.rs | 1 - src/hypercall/mod.rs | 6 +- src/main.rs | 19 +- 15 files changed, 597 insertions(+), 408 deletions(-) diff --git a/src/arch/loongarch64/cpu.rs b/src/arch/loongarch64/cpu.rs index 752f7142..4c4d09cd 100644 --- a/src/arch/loongarch64/cpu.rs +++ b/src/arch/loongarch64/cpu.rs @@ -14,23 +14,23 @@ // 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_zone; use crate::cpu_data::{get_vcpuid_from_pcpuid, this_cpu_data}; use crate::device::common::MMIODerefWrapper; use crate::zone::{find_zone, this_zone_id}; -use crate::cpu_data::this_zone; 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 tock_registers::interfaces::Writeable; -use super::register::*; -use super::eiointc::LoongArch64Eiointc; use spin::Mutex; +use tock_registers::interfaces::Writeable; use crate::{ consts::{PER_CPU_ARRAY_PTR, PER_CPU_SIZE}, @@ -43,201 +43,306 @@ use crate::{ #[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 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 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, + 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, + 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, + 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, + 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, + 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); // NOTE: intentional mapping from original code - write_gcsr_pgdl(self.misc); // NOTE: intentional mapping from original code - write_gcsr_tval(self.ecfg); // NOTE: intentional mapping from original code + 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); @@ -303,7 +408,7 @@ pub struct ArchCpu { pub irq_pending: usize, pub irq_clear: usize, pub ipi_state: Mutex, - pub eiointc: Mutex, + pub eiointc: Mutex, pub expire: isize, pub csr: [usize; 0x513], } @@ -353,9 +458,19 @@ impl ArchCpu { /// 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::vcpu_enter: percpu_s={:#x}", self.stack_top() - PER_CPU_SIZE); - debug!("loongarch64: ArchCpu::vcpu_enter: ctx_addr={:#x}, size={}", ctx_addr as usize, core::mem::size_of::()); - debug!("loongarch64: ArchCpu::vcpu_enter: stack_tp={:#x}", self.stack_top()); + debug!( + "loongarch64: ArchCpu::vcpu_enter: percpu_s={:#x}", + self.stack_top() - PER_CPU_SIZE + ); + debug!( + "loongarch64: ArchCpu::vcpu_enter: ctx_addr={:#x}, size={}", + ctx_addr as usize, + core::mem::size_of::() + ); + debug!( + "loongarch64: ArchCpu::vcpu_enter: stack_tp={:#x}", + self.stack_top() + ); unsafe { asm!( "csrwr {}, {LOONGARCH_CSR_SAVE3}", @@ -383,18 +498,26 @@ impl ArchCpu { 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; } + for i in 0..32 { + self.ctx.x[i] = 0; + } 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); + 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]); + 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(); @@ -423,12 +546,12 @@ impl ArchCpu { if !self.init { self.init(this_cpu_data().cpu_on_entry, this_cpu_data().id, 0); - self.init= true; + 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[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; @@ -461,7 +584,9 @@ impl ArchCpu { 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; } + 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) }; diff --git a/src/arch/loongarch64/eiointc.rs b/src/arch/loongarch64/eiointc.rs index 4eb8fcf0..5b882168 100644 --- a/src/arch/loongarch64/eiointc.rs +++ b/src/arch/loongarch64/eiointc.rs @@ -1,4 +1,3 @@ - // 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. @@ -113,14 +112,14 @@ pub struct LoongArch64Eiointc { 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 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) + 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 { @@ -175,11 +174,11 @@ pub fn do_real_write_iocsr(addr: usize, val: usize, len: usize) { } } -pub fn do_real_read_iocsr(addr: usize, len: usize) -> usize { +pub fn do_real_read_iocsr(addr: usize, len: usize) -> usize { match len { 1 => { // iocsrrd.b - let mut val= 0; + let mut val = 0; unsafe { asm!("iocsrrd.b {}, {}", out(reg) val, in(reg) addr); } @@ -208,7 +207,7 @@ pub fn do_real_read_iocsr(addr: usize, len: usize) -> usize { asm!("iocsrrd.d {}, {}", out(reg) val, in(reg) addr); } val - }, + } _ => { // should not reach here panic!("read invalid iocsr type, this is impossible"); @@ -238,7 +237,7 @@ pub fn read_masked_data(pbuf: *const u8, len: usize) -> usize { _ => { panic!("write_memory: invalid length {:#x}", len); } - } + } } } @@ -264,18 +263,18 @@ pub fn write_masked_data(pbuf: *mut u8, val: usize, len: usize) { _ => { 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); - } + 1 => data & 0xff, + 2 => data & 0xffff, + 4 => data & 0xffffffff, + 8 => data, + _ => { + panic!("read_mailbox: unknown data len: {}", len); + } } } @@ -316,51 +315,51 @@ fn count_trailing_zeros(x: usize, len: usize) -> i32 { } } - 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 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 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 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 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 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) ; - + 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; + 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; + 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); + let idx_u8 = (offset - EIOINTC_COREMAP_START); + let pbuf_read = &eiointc.coremap[idx_u8]; + ret = read_masked_data(pbuf_read, len); } _ => { panic!( @@ -372,8 +371,8 @@ pub fn loongarch_eiointc_readl(pcpu_id: usize, addr: usize, len: usize) -> usize ret } -use crate::cpu_data::{get_cpu_data, this_zone}; 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(); @@ -391,19 +390,24 @@ pub fn get_vcpuid_from_pcpuid(target_pcpu_id: usize) -> usize { } use crate::PHY_TO_DMW_UNCACHED; -const IOCSR_BASE:usize = 0x1fe00000; +const IOCSR_BASE: usize = 0x1fe00000; const INT_HWI0: usize = 2; -fn eiointc_update_irq(eiointc: &mut spin::MutexGuard<'_, LoongArch64Eiointc>, irq: usize, level: usize) { - +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); + panic!( + "eiointc_update_irq, no ipnum found, irq: {}, level: {}", + irq, level + ); } ipnum = (if ipnum_new >= 0 && ipnum_new < 4 { ipnum_new @@ -414,7 +418,7 @@ fn eiointc_update_irq(eiointc: &mut spin::MutexGuard<'_, LoongArch64Eiointc>, ir let cpu = eiointc.sw_coremap[irq] as usize; let irq_index = irq / 32; // u32 - // 8 * 32 = 256 + // 8 * 32 = 256 let irq_mask = bit!(irq & 0x1f); // 1_1111 : 32 bits / 4 bytes let irq_index_u8 = irq_index * 4; @@ -429,8 +433,8 @@ fn eiointc_update_irq(eiointc: &mut spin::MutexGuard<'_, LoongArch64Eiointc>, ir } let coreisr_pbuf_read = &eiointc.coreisr[cpu][irq_index_u8]; - let coreisr_u32_new= read_masked_data(coreisr_pbuf_read, 4) | irq_mask; - + 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; { @@ -438,7 +442,7 @@ fn eiointc_update_irq(eiointc: &mut spin::MutexGuard<'_, LoongArch64Eiointc>, ir 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 + 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); @@ -446,7 +450,6 @@ fn eiointc_update_irq(eiointc: &mut spin::MutexGuard<'_, LoongArch64Eiointc>, ir 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]; @@ -459,7 +462,7 @@ fn eiointc_update_irq(eiointc: &mut spin::MutexGuard<'_, LoongArch64Eiointc>, ir 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 + 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); @@ -467,7 +470,6 @@ fn eiointc_update_irq(eiointc: &mut spin::MutexGuard<'_, LoongArch64Eiointc>, ir 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) { @@ -480,17 +482,18 @@ fn eiointc_update_irq(eiointc: &mut spin::MutexGuard<'_, LoongArch64Eiointc>, ir 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); +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 { @@ -503,11 +506,16 @@ pub fn eiointc_set_irq(pcpu_id: usize, irq: usize, level: usize) { eiointc_update_irq(&mut eiointc, irq, level); } -fn eiointc_enable_irq(eiointc: &mut spin::MutexGuard<'_, LoongArch64Eiointc>, index: usize, mask: usize, level: usize) { +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); @@ -516,11 +524,20 @@ fn eiointc_enable_irq(eiointc: &mut spin::MutexGuard<'_, LoongArch64Eiointc>, in } } -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) { - +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); @@ -530,7 +547,10 @@ fn eiointc_update_sw_coremap(eiointc: &mut spin::MutexGuard<'_, LoongArch64Eioin cpu = __ffs(cpu); if cpu >= 4 { - error!("eiointc_update_sw_coremap, attention 2, check it, cpu : {}", cpu); + error!( + "eiointc_update_sw_coremap, attention 2, check it, cpu : {}", + cpu + ); } cpu = if cpu >= 4 { 0 } else { cpu }; @@ -544,21 +564,20 @@ fn eiointc_update_sw_coremap(eiointc: &mut spin::MutexGuard<'_, LoongArch64Eioin let pcpu_id: usize = get_real_pcpu_id(cpu); if pcpu_id != cpu { - warn!("[Attention], eiointc_update_sw_coremap, 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 - + 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.coremap[irq + i] = (1 << pcpu_id) as u8; // update it! - eiointc_update_irq(eiointc, irq + i, 1);// set new irq - } - else { + 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; } @@ -569,7 +588,7 @@ 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 { @@ -578,12 +597,11 @@ pub fn find_first_bit_single(val: usize, bits: usize) -> 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(); @@ -596,60 +614,68 @@ pub fn loongarch_eiointc_writel(pcpu_id: usize, addr: usize, val: usize, len: us } EIOINTC_IPMAP_START..=EIOINTC_IPMAP_END => { // ipmap - let idx_u8 = (offset - EIOINTC_IPMAP_START) ; - + 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 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) ; - + 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); + 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()); + 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()); + 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 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); @@ -660,7 +686,7 @@ pub fn loongarch_eiointc_writel(pcpu_id: usize, addr: usize, val: usize, len: us 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; @@ -668,16 +694,16 @@ pub fn loongarch_eiointc_writel(pcpu_id: usize, addr: usize, val: usize, len: us 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 bits = len * 8; // 4 * 8 = 32? let index = idx_u8 / len; - + let mut irq = find_first_bit_single(coreisr, bits); - while (irq < bits) { + while (irq < bits) { eiointc_update_irq(&mut eiointc, irq + index * bits, 0); // update coreisr and irq - coreisr &= !bit!(irq);// clear irq from coreisr + coreisr &= !bit!(irq); // clear irq from coreisr irq = find_first_bit_single(coreisr, bits); } } @@ -693,7 +719,7 @@ pub fn loongarch_eiointc_writel(pcpu_id: usize, addr: usize, val: usize, len: us let pbuf_read = &eiointc.coremap[idx_u8]; let coremap_read = read_masked_data(pbuf_read, len); - ret = coremap_read;// update! + ret = coremap_read; // update! } _ => { panic!("eiointc_writel, Invalid EIOINTC offset: {:#x}", offset); @@ -702,4 +728,4 @@ pub fn loongarch_eiointc_writel(pcpu_id: usize, addr: usize, val: usize, len: us do_real_write_iocsr(addr, ret, len); ret -} \ No newline at end of file +} diff --git a/src/arch/loongarch64/entry.rs b/src/arch/loongarch64/entry.rs index 8454c76b..ae0d6609 100644 --- a/src/arch/loongarch64/entry.rs +++ b/src/arch/loongarch64/entry.rs @@ -98,7 +98,6 @@ pub unsafe extern "C" fn arch_entry() -> i32 { ); } - #[naked] #[no_mangle] #[link_section = ".text.entry"] @@ -258,6 +257,6 @@ pub unsafe extern "C" fn arch_secondary_entry() -> i32 { LOONGARCH_CSR_DMW2 = const 0x182, LOONGARCH_CSR_DMW3 = const 0x183, options(noreturn), - + ); -} \ No newline at end of file +} diff --git a/src/arch/loongarch64/ipi.rs b/src/arch/loongarch64/ipi.rs index 2870c9fc..6d02dfd2 100644 --- a/src/arch/loongarch64/ipi.rs +++ b/src/arch/loongarch64/ipi.rs @@ -17,9 +17,12 @@ // use crate::arch::cpu::this_cpu_id; use crate::consts::{IPI_EVENT_CLEAR_INJECT_IRQ, MAX_CPU_NUM}; -use crate::event::{IPI_EVENT_VIRTIO_INJECT_IRQ, IPI_EVENT_WAKEUP, IPI_EVENT_SHUTDOWN, IPI_EVENT_WAKEUP_VIRTIO_DEVICE}; 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; @@ -44,10 +47,10 @@ pub fn arch_send_event(cpu_id: u64, sgi_num: 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 { + } 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); + ipi_send_general(cpu_id as usize, HVISOR_EVENT_VIRTIO_CLEAR_IRQ as u32); } else { panic!("unknown sgi_num, {}", sgi_num); } @@ -111,7 +114,6 @@ pub static CORE6_IPI: MMIODerefWrapper = 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; @@ -292,7 +294,6 @@ pub fn enable_ipi(cpu_id: usize) { 2 => &CORE2_IPI, 3 => &CORE3_IPI, - // boneinscri 2026.04 (3a6000 smp) 4 => &CORE4_IPI, 5 => &CORE5_IPI, @@ -437,8 +438,6 @@ pub fn arch_prepare_send_event(cpu_id: usize, ipi_int_id: usize, event_id: usize ); } - - // IPI state per cpu (ref to kvm) // boneinscri --2026.04 pub const IOCSR_IPI_BASE: usize = 0x1000; @@ -456,7 +455,6 @@ 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, @@ -480,14 +478,14 @@ impl LoongArch64IpiState { 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]; @@ -495,32 +493,32 @@ pub fn write_mailbox(pcpu_id: usize, offset: usize, len: usize, val: usize) { 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) { +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; + let status = ipistate.status; drop(ipistate); - if status == 0 { + if status == 0 { let cur_pcpu_id = this_cpu_id(); if cur_pcpu_id != pcpu_id { panic!("ipi_clear, need to support vcpu"); @@ -542,7 +540,10 @@ pub fn get_target_cpu_id(data: usize) -> usize { match result { Some(id) => id, None => { - warn!("get_target_cpu_id, invalid target cpu id {:#x}, ignore", target_cpu_id); + warn!( + "get_target_cpu_id, invalid target cpu id {:#x}, ignore", + target_cpu_id + ); usize::MAX } } @@ -555,7 +556,7 @@ 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; + ipistate.status |= action; if (status == 0) { // TODO : for vcpu , inject IPI interrupt @@ -612,7 +613,10 @@ pub fn any_send(data: usize) { panic!("any_send 2, check it carefullly"); } let offset = data & 0xffff; - warn!("[Look this] any_send, offset {:#x}, data {:#x}", offset, data); + warn!( + "[Look this] any_send, offset {:#x}, data {:#x}", + offset, data + ); send_ipi_data(target_cpu_id, offset, data); } @@ -623,7 +627,10 @@ pub fn mail_send_iocsr(data: usize) { } 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); + warn!( + "[Look this]mail_send_iocsr, offset {:#x}, data {:#x}", + offset, data + ); send_ipi_data(target_cpu_id, offset, data); } @@ -632,13 +639,16 @@ pub fn read_mailbox(pcpu_id: usize, offset: usize, len: usize) -> usize { 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); + 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]; - + let data = ipistate.buf[idx]; + match len { 1 => data & 0xff, 2 => data & 0xffff, @@ -648,7 +658,7 @@ pub fn read_mailbox(pcpu_id: usize, offset: usize, len: usize) -> usize { panic!("read_mailbox: unknown data len: {}", len); } }; - res + res } // TODO : add vcpu for loongarch_ipi_readl and loongarch_ipi_writel @@ -658,14 +668,14 @@ pub fn loongarch_ipi_readl(pcpu_id: usize, addr: usize, len: usize) -> usize { 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(); @@ -679,7 +689,10 @@ pub fn loongarch_ipi_readl(pcpu_id: usize, addr: usize, len: usize) -> usize { } 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); + panic!( + "ipi readl IOCSR_IPI_BUF, offset = {:#x}, len = {:#x}", + offset, len + ); } res = read_mailbox(pcpu_id, offset, len); } @@ -708,7 +721,10 @@ pub fn loongarch_ipi_writel(pcpu_id: usize, addr: usize, val: usize, len: usize) ipi_clear(pcpu_id, val); } IOCSR_IPI_STATUS => { - panic!("ipi writel IOCSR_IPI_STATUS, pcpu_id = {}, val = {:#x}", pcpu_id, val); + panic!( + "ipi writel IOCSR_IPI_STATUS, pcpu_id = {}, val = {:#x}", + pcpu_id, val + ); } IOCSR_IPI_EN => { let mut pcpu = get_cpu_data(pcpu_id); @@ -716,11 +732,17 @@ pub fn loongarch_ipi_writel(pcpu_id: usize, addr: usize, val: usize, len: usize) ipistate.en = val as u32; } IOCSR_IPI_SET => { - panic!("ipi writel IOCSR_IPI_SET, pcpu_id = {}, val = {:#x}", pcpu_id, val); + 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); + panic!( + "ipi writel IOCSR_IPI_BUF, offset = {:#x}, len = {:#x}", + offset, len + ); } write_mailbox(pcpu_id, offset, len, val); } @@ -736,4 +758,4 @@ pub fn loongarch_ipi_writel(pcpu_id: usize, addr: usize, val: usize, len: usize) } res -} \ No newline at end of file +} diff --git a/src/arch/loongarch64/mod.rs b/src/arch/loongarch64/mod.rs index 37c09d57..20d5bdb2 100644 --- a/src/arch/loongarch64/mod.rs +++ b/src/arch/loongarch64/mod.rs @@ -20,7 +20,6 @@ pub mod clock; pub mod consts; pub mod cpu; pub mod eiointc; -pub mod timer; pub mod entry; pub mod hypercall; pub mod ipi; @@ -30,6 +29,7 @@ pub mod register; pub mod s1pt; pub mod s2pt; pub mod time; +pub mod timer; pub mod trap; pub mod zone; diff --git a/src/arch/loongarch64/paging.rs b/src/arch/loongarch64/paging.rs index 06368eaf..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, tlbidx}; use loongArch64::register::{crmd, pwch, pwcl, tlbrentry}; use loongArch64::register::{pgd, pgdh, pgdl}; +use loongArch64::register::{tlbidx, MemoryAccessType}; #[derive(Debug)] pub enum PagingError { @@ -657,4 +657,4 @@ pub fn set_pwcl_pwch_stlbps() { stlbps::set_ps(12); // log2(real_page_size), 16KB -> 14, 4KB -> 12 tlbidx::set_ps(0xc); // boneinscri : 2026.04 -} \ No newline at end of file +} diff --git a/src/arch/loongarch64/register/macros.rs b/src/arch/loongarch64/register/macros.rs index 77eabb70..489deac9 100644 --- a/src/arch/loongarch64/register/macros.rs +++ b/src/arch/loongarch64/register/macros.rs @@ -285,4 +285,4 @@ macro_rules! csr_xchg { } val }}; -} \ No newline at end of file +} diff --git a/src/arch/loongarch64/register/mod.rs b/src/arch/loongarch64/register/mod.rs index e79971cd..9bca6848 100644 --- a/src/arch/loongarch64/register/mod.rs +++ b/src/arch/loongarch64/register/mod.rs @@ -795,4 +795,4 @@ pub fn set_csr_gintc(val: usize) { pub fn clear_csr_gintc(val: usize) { csr_xchg!(!(val), val, 0x52); -} \ No newline at end of file +} diff --git a/src/arch/loongarch64/timer.rs b/src/arch/loongarch64/timer.rs index 8292dd1f..ce420994 100644 --- a/src/arch/loongarch64/timer.rs +++ b/src/arch/loongarch64/timer.rs @@ -1,4 +1,3 @@ - // 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. @@ -18,9 +17,23 @@ 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}; +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; @@ -47,7 +60,7 @@ pub fn restore_timer(mut ctx: &mut ZoneContext, pcpu_id: usize) { write_gcsr_tval(ctx.gcsr_tval); return; } - + let gcsr_tval = ctx.gcsr_tval; let gcsr_estat = ctx.gcsr_estat; @@ -61,7 +74,7 @@ pub fn restore_timer(mut ctx: &mut ZoneContext, pcpu_id: usize) { 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; @@ -71,7 +84,7 @@ pub fn restore_timer(mut ctx: &mut ZoneContext, pcpu_id: usize) { 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); } @@ -82,15 +95,15 @@ 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; - + 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; } @@ -98,7 +111,7 @@ pub fn do_save_timer(mut ctx: &mut ZoneContext, pcpu_id: usize) { 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(); @@ -113,12 +126,10 @@ pub fn save_timer(mut ctx: &mut ZoneContext, pcpu_id: usize) { ctx.gcsr_estat = read_gcsr_estat(); } - static INIT_OFFSET: AtomicU64 = AtomicU64::new(0); static GLOBAL_TIMER: AtomicU64 = AtomicU64::new(0); -pub fn sync_counter() -{ +pub fn sync_counter() { let init_offset_val = INIT_OFFSET.load(Ordering::Relaxed); write_csr_cntc(init_offset_val as usize); } @@ -133,7 +144,7 @@ pub fn timer_init() { 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); + INIT_OFFSET.store(init_offset_val as u64, Ordering::Relaxed); } sync_counter(); @@ -142,7 +153,7 @@ pub fn timer_init() { // 1s = 1000 ms = 1000_000 us // set timer let init_val = timer_freq / HZ; - tcfg::set_periodic(true); + tcfg::set_periodic(true); tcfg::set_init_val(init_val); - tcfg::set_en(true);// enable timer, not timer interrupt + tcfg::set_en(true); // enable timer, not timer interrupt } diff --git a/src/arch/loongarch64/trap.rs b/src/arch/loongarch64/trap.rs index 498936e1..deef0e07 100644 --- a/src/arch/loongarch64/trap.rs +++ b/src/arch/loongarch64/trap.rs @@ -19,17 +19,16 @@ use super::register::*; use super::zone::ZoneContext; use crate::arch::cpu::this_cpu_id; -use crate::arch::ipi::*; use crate::arch::eiointc::{ - loongarch_eiointc_readl, loongarch_eiointc_writel, - do_real_read_iocsr, do_real_write_iocsr, + 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::{get_cpu_data, this_cpu_data}; -use crate::device::irqchip::{inject_irq, ls7a2000::clear_irq}; 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, *}; @@ -604,14 +603,14 @@ fn handle_exception( ); 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 + this_cpu_data().arch_cpu.idle(); // boneinscri 2026.04, use shutdown to restart it~ for debugging } } } _ => { 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 + this_cpu_data().arch_cpu.idle(); // boneinscri 2026.04, use shutdown to restart it~ for debugging } } } @@ -1302,14 +1301,13 @@ 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 + clear_irq(irq, false); // para is_hardware is invalid here } else { // inject irq inject_irq(irq, false); @@ -1350,16 +1348,26 @@ fn handle_interrupt(is: usize) { if pcpu_ipi_status & SMP_BOOT_CPU != 0 { if pcpu_data.arch_cpu.power_on == true { - panic!("pcpu : {} has already power on, this should not happen", pcpu_id_this); + panic!( + "pcpu : {} has already power on, this should not happen", + pcpu_id_this + ); } // 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) { + 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 + drop(ipistate); // remember! avoid deadlock pcpu_data.arch_cpu.run(); panic!("can't reach here"); } else { @@ -1369,39 +1377,37 @@ fn handle_interrupt(is: 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 + drop(ipistate); // remember! avoid deadlock pcpu_data.arch_cpu.run_secondary(smpboot_entry); - panic!("can't reach here"); + panic!("can't reach here"); } - } - else if pcpu_ipi_status & HVISOR_SHUTDOWN != 0 { + } 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 { + } else if pcpu_ipi_status & HVISOR_EVENT_VIRTIO_INJECT_IRQ != 0 { if pcpu_data.arch_cpu.power_on == false { - panic!("pcpu : {} has not power on, this should not happen", pcpu_id_this); + 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 { + } 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 { + } 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 { + } else if pcpu_ipi_status != 0 { drop(ipistate); pcpu_data.arch_cpu.add_irq(INT_IPI); } else { } - return ; + return; } // Handle timer interrupts @@ -1429,7 +1435,7 @@ fn handle_interrupt(is: usize) { } if is & SWI1 != 0 { panic!("swi1 not handled"); - } + } // Handle unknown interrupts error!("Received unhandled interrupt, status = {:#x}", is); @@ -1483,12 +1489,12 @@ 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 mut result= 0; + 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 + result &= !(1 << 10); // shutdown lvz of vm -- boneinscri 2026.04 } ctx.x[rd] = result; // finish the emulation by tweaking the ZoneContext's registers @@ -1496,7 +1502,7 @@ fn emulate_cpucfg(ins: usize, ctx: &mut ZoneContext) { } } -// modified -- boneinscri 2026.04 +// modified -- boneinscri 2026.04 fn emulate_csrx(ins: usize, ctx: &mut ZoneContext) { // csrrd csrwr csrxchg // let ty = (ins >> 5) & 0x1f; @@ -1528,15 +1534,15 @@ fn emulate_csrx(ins: usize, ctx: &mut ZoneContext) { } _ => { // csrxchg - // info!("csrxchg emulation for CSR {:#x}, val : {:#x}, csr_mask : {:#x}", - // csr_id, ctx.x[rd], ctx.x[rj]); + // 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 + 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 + 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 + ctx.x[rd] = old; // return old value to guest } } } @@ -1566,24 +1572,23 @@ 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 + 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) @@ -1597,15 +1602,15 @@ pub fn loongarch_iocsr_write(pcpu_id: usize, addr: usize, val: usize, len: usize // 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 - }, + 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); @@ -1631,7 +1636,7 @@ fn emulate_iocsr(ins: usize, ctx: &mut ZoneContext) { let mut len = 0; let mut is_write = false; - let addr = ctx.x[rj] as usize; + let addr = ctx.x[rj] as usize; let val = ctx.x[rd] as usize; if ty < 8 { @@ -1643,7 +1648,7 @@ fn emulate_iocsr(ins: usize, ctx: &mut ZoneContext) { // TODO : modify to vCPU let pcpu_id_this = this_cpu_id(); - + if is_write { let ret = loongarch_iocsr_write(pcpu_id_this, addr, val, len); return; diff --git a/src/cpu_data.rs b/src/cpu_data.rs index 71c1410f..82aaece1 100644 --- a/src/cpu_data.rs +++ b/src/cpu_data.rs @@ -12,7 +12,7 @@ // https://www.syswonder.org // // Authors: -// +// use alloc::sync::Arc; use spin::Mutex; @@ -152,7 +152,7 @@ impl CpuSet { 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()) } diff --git a/src/device/irqchip/ls7a2000/mod.rs b/src/device/irqchip/ls7a2000/mod.rs index a4cbffa3..f94f45ea 100644 --- a/src/device/irqchip/ls7a2000/mod.rs +++ b/src/device/irqchip/ls7a2000/mod.rs @@ -23,7 +23,8 @@ use crate::{ cpu::this_cpu_id, ipi::*, register::{ - clear_gcsr_estat, read_csr_gintc, read_gcsr_estat, set_csr_gintc, set_gcsr_estat, write_csr_gintc, write_gcsr_estat + 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, @@ -114,9 +115,8 @@ const INT_PERF: usize = 10; const INT_TIMER: usize = 11; const INT_IPI: usize = 12; - // ================================ -// inject and clear irq +// inject and clear irq // --boneinscri 2026.04 pub fn inject_irq(_irq: usize, is_hardware: bool) { debug!( @@ -156,7 +156,6 @@ pub fn clear_irq(_irq: usize, is_hardware: bool) { } // ================================ - /// clear the injecting irq ctrl bit on THIS cpu pub fn clear_hwi_injected_irq() { use crate::arch::register::gintc; diff --git a/src/event.rs b/src/event.rs index 9e2fd62d..493827b2 100644 --- a/src/event.rs +++ b/src/event.rs @@ -147,7 +147,6 @@ pub fn send_event(cpu_id: usize, ipi_int_id: usize, event_id: usize) { // } /// Some arch need do something before send event. /// 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); diff --git a/src/hypercall/mod.rs b/src/hypercall/mod.rs index d6df31b4..de1f0125 100644 --- a/src/hypercall/mod.rs +++ b/src/hypercall/mod.rs @@ -210,7 +210,7 @@ impl<'a> HyperCall<'a> { }; #[cfg(not(target_arch = "loongarch64"))] self.check_cpu_id(); - + add_zone(zone); drop(_lock); HyperCallResult::Ok(0) @@ -307,7 +307,7 @@ impl<'a> HyperCall<'a> { // cnt as usize, // ) // }; - + for (i, zone_info) in slice.iter_mut().enumerate() { if i < zones_info.len() { *zone_info = zones_info[i].clone(); @@ -315,7 +315,7 @@ impl<'a> HyperCall<'a> { break; } } - + HyperCallResult::Ok(core::cmp::min(cnt as _, zones_info.len())) } } diff --git a/src/main.rs b/src/main.rs index e331c0b9..97d0be21 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,10 +66,10 @@ mod pci; #[cfg(test)] mod tests; -use crate::arch::mm::{arch_post_heap_init, arch_setup_parange}; -use crate::consts::{hv_end, mem_pool_start, MAX_CPU_NUM}; #[cfg(target_arch = "loongarch64")] use crate::arch::entry::arch_secondary_entry; +use crate::arch::mm::{arch_post_heap_init, 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}; @@ -87,14 +87,16 @@ static MASTER_CPU: AtomicI32 = AtomicI32::new(-1); #[cfg(target_arch = "loongarch64")] fn print_logo() { - println!(r" + println!( + r" _ _ _ | | (_) | | | |__ __ ___ ___ ___ _ __ | | __ _ | '_ \ \ \ / / / __|/ _ \| '__| | |/ _` | | | | | \ V /| \__ \ (_) | | _| | (_| | |_| |_| \_/ |_|___/\___/|_| (_)_|\__,_| -"); +" + ); } pub fn clear_bss() { @@ -190,7 +192,7 @@ fn wakeup_secondary_cpus(this_id: usize, host_dtb: usize) { if cpu_id == this_id { continue; } - + #[cfg(not(target_arch = "loongarch64"))] cpu_start(cpu_id, arch_entry as _, host_dtb); @@ -213,13 +215,13 @@ fn rust_main(cpuid: usize, host_dtb: usize) { extern "C" { fn skernel(); } - + #[cfg(not(target_arch = "loongarch64"))] 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; - + #[cfg(target_arch = "loongarch64")] { clear_bss(); @@ -235,7 +237,8 @@ fn rust_main(cpuid: usize, host_dtb: usize) { let cpu = PerCpu::new(cpuid); - #[cfg(target_arch = "loongarch64")] { + #[cfg(target_arch = "loongarch64")] + { use crate::arch::timer::timer_init; timer_init(); } From 6788134754040b72d9f4673d311ee2afe8157e87 Mon Sep 17 00:00:00 2001 From: BoneInscri <941388383@qq.com> Date: Tue, 12 May 2026 22:25:53 +0800 Subject: [PATCH 11/16] fix the bug of merge due to vcpu introduce (power_on and vcpu_state) --- src/arch/loongarch64/cpu.rs | 4 +--- src/arch/loongarch64/trap.rs | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/arch/loongarch64/cpu.rs b/src/arch/loongarch64/cpu.rs index 3ab4f18f..64eba595 100644 --- a/src/arch/loongarch64/cpu.rs +++ b/src/arch/loongarch64/cpu.rs @@ -488,7 +488,6 @@ impl ArchCpu { assert!(this_cpu_id() == self.get_cpuid()); this_cpu_data().activate_gpm(); this_cpu_data().vcpu_state.store(VcpuState::Running); - self.power_on = true; let boot_ctx = unsafe { &mut *(CPU_BOOT_CONTEXT_ADDRESS as *mut BootContext) }; info!("boot_ctx_addr={:#x}", CPU_BOOT_CONTEXT_ADDRESS); @@ -576,7 +575,7 @@ impl ArchCpu { pub fn run_secondary(&mut self, smpboot_entry: usize) -> ! { assert!(this_cpu_id() == self.get_cpuid()); this_cpu_data().activate_gpm(); - self.power_on = true; + this_cpu_data().vcpu_state.store(VcpuState::Running); this_cpu_data().cpu_on_entry = smpboot_entry; if !self.init { @@ -613,7 +612,6 @@ impl ArchCpu { // enable ipi on ecfg ecfg_ipi_enable(); enable_global_interrupt(); - self.power_on = false; loop {} } } diff --git a/src/arch/loongarch64/trap.rs b/src/arch/loongarch64/trap.rs index deef0e07..873e0da4 100644 --- a/src/arch/loongarch64/trap.rs +++ b/src/arch/loongarch64/trap.rs @@ -1347,7 +1347,7 @@ fn handle_interrupt(is: usize) { reset_ipi(pcpu_id_this); // clear if pcpu_ipi_status & SMP_BOOT_CPU != 0 { - if pcpu_data.arch_cpu.power_on == true { + if pcpu_data.vcpu_state.is_running() { panic!( "pcpu : {} has already power on, this should not happen", pcpu_id_this @@ -1389,7 +1389,7 @@ fn handle_interrupt(is: usize) { drop(ipistate); pcpu_data.arch_cpu.idle(); } else if pcpu_ipi_status & HVISOR_EVENT_VIRTIO_INJECT_IRQ != 0 { - if pcpu_data.arch_cpu.power_on == false { + if pcpu_data.vcpu_state.is_running() == false { panic!( "pcpu : {} has not power on, this should not happen", pcpu_id_this From 6a5507322dd4aa753fd039b6e24b169818609c01 Mon Sep 17 00:00:00 2001 From: BoneInscri <941388383@qq.com> Date: Tue, 12 May 2026 23:15:08 +0800 Subject: [PATCH 12/16] remove the target_arch in main.rs --- src/arch/loongarch64/mod.rs | 14 ++++++ src/arch/mod.rs | 98 +++++++++++++++++++++++++++++++++++++ src/main.rs | 45 ++++------------- 3 files changed, 121 insertions(+), 36 deletions(-) diff --git a/src/arch/loongarch64/mod.rs b/src/arch/loongarch64/mod.rs index 20d5bdb2..91ab7af3 100644 --- a/src/arch/loongarch64/mod.rs +++ b/src/arch/loongarch64/mod.rs @@ -36,3 +36,17 @@ 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/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/main.rs b/src/main.rs index 97d0be21..e61f5428 100644 --- a/src/main.rs +++ b/src/main.rs @@ -66,9 +66,8 @@ mod pci; #[cfg(test)] mod tests; -#[cfg(target_arch = "loongarch64")] -use crate::arch::entry::arch_secondary_entry; -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; @@ -85,20 +84,6 @@ static INIT_EARLY_OK: AtomicU32 = AtomicU32::new(0); static INIT_LATE_OK: AtomicU32 = AtomicU32::new(0); static MASTER_CPU: AtomicI32 = AtomicI32::new(-1); -#[cfg(target_arch = "loongarch64")] -fn print_logo() { - println!( - r" - _ _ _ - | | (_) | | - | |__ __ ___ ___ ___ _ __ | | __ _ - | '_ \ \ \ / / / __|/ _ \| '__| | |/ _` | - | | | | \ V /| \__ \ (_) | | _| | (_| | - |_| |_| \_/ |_|___/\___/|_| (_)_|\__,_| -" - ); -} - pub fn clear_bss() { extern "C" { fn sbss(); @@ -193,12 +178,8 @@ fn wakeup_secondary_cpus(this_id: usize, host_dtb: usize) { continue; } - #[cfg(not(target_arch = "loongarch64"))] - cpu_start(cpu_id, arch_entry as _, host_dtb); - - #[cfg(target_arch = "loongarch64")] - cpu_start(cpu_id, arch_secondary_entry as _, host_dtb); - // restore the boot context, specially for la64 + let secondary_entry = interface::arch_secondary_entry(); + cpu_start(cpu_id, secondary_entry as _, host_dtb); } } @@ -216,32 +197,24 @@ fn rust_main(cpuid: usize, host_dtb: usize) { fn skernel(); } - #[cfg(not(target_arch = "loongarch64"))] - 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; - #[cfg(target_arch = "loongarch64")] - { - clear_bss(); - print_logo(); - } + 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); - #[cfg(target_arch = "loongarch64")] - { - use crate::arch::timer::timer_init; - timer_init(); - } + interface::timer_init(); println!( "Booting CPU {}: {:p} arch:{:p}, DTB: {:#x}", From ddf1acb919a3a08e5727dcded511cd55cda12b1c Mon Sep 17 00:00:00 2001 From: BoneInscri <941388383@qq.com> Date: Mon, 1 Jun 2026 06:41:49 +0800 Subject: [PATCH 13/16] set build MODE to debug --- build-la-nopci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build-la-nopci.sh b/build-la-nopci.sh index 0d5cceae..55e436a5 100755 --- a/build-la-nopci.sh +++ b/build-la-nopci.sh @@ -1,2 +1,2 @@ #!/bin/bash -make BID=loongarch64/ls3a6000 LOG=info FEATURES="loongson_3a6000 loongson_7a2000 loongson_uart" +make BID=loongarch64/ls3a6000 LOG=info FEATURES="loongson_3a6000 loongson_7a2000 loongson_uart" MODE=debug \ No newline at end of file From 2c7345bf81b6139d54562c8f26ece75944427bc7 Mon Sep 17 00:00:00 2001 From: BoneInscri <941388383@qq.com> Date: Mon, 1 Jun 2026 08:20:58 +0800 Subject: [PATCH 14/16] loongarch64/ls3a6000: split hi-RAM around hvisor footprint, add layout constants - Add BOARD_TOTAL_RAM_GIB / BOARD_HI_RAM_TOP constants derived from empirical PA layout table (8/16/32 GiB variants) - Add HVISOR_LOAD_PA (0x380000000) and HVISOR_FOOTPRINT_SIZE (768 MB) to centralize the hvisor PA reservation in one place - Split ROOT_ZONE hi-RAM region into two segments around [HVISOR_LOAD_PA, HVISOR_FOOTPRINT_END) so guest Linux stage-2 never maps hvisor's own pages as plain RAM - Add detailed memory layout comment documenting the 3A6000+LS7A2000 PA map and the four files that must stay in sync --- platform/loongarch64/ls3a6000/board.rs | 111 ++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 4 deletions(-) diff --git a/platform/loongarch64/ls3a6000/board.rs b/platform/loongarch64/ls3a6000/board.rs index 632ba62d..49030cf1 100644 --- a/platform/loongarch64/ls3a6000/board.rs +++ b/platform/loongarch64/ls3a6000/board.rs @@ -17,6 +17,85 @@ use crate::pci_dev; use crate::{arch::zone::HvArchZoneConfig, config::*, pci::vpci_dev::VpciDevType}; +// ------------------------------------------------------------------------ +// Memory layout assumptions for LoongArch 3A6000 + LS7A2000 evaluation board +// ------------------------------------------------------------------------ +// +// The 3A6000 / LS7A2000 board exposes physical RAM through a non-contiguous +// PA layout — RAM size != PA span. Always cross-reference `/proc/iomem` on +// the running Linux to confirm before touching this file. +// +// ## Verified layout on 16 GiB dev board (this code's default target) +// +// ``` +// 0x00200000..0x0edfffff ~236 MB low RAM (kernel image, early init) +// 0x90400000..0xf8faffff ~1.65 GB mid RAM lo (ACPI, EFI runtime, SMBIOS) +// 0xf8fc0000..0xfdbaffff ~78 MB mid RAM hi (EFI runtime continuation) +// 0xfe190000..0x47fffffff ~14.5 GB hi RAM (bulk RAM, PA top = 18 GiB) +// ``` +// +// Total RAM = ~16.46 GiB nominal. PA TOP = `0x480000000` (nominal 18 GiB) on +// 16 GiB board because low/mid eat ~2 GiB of PA space. +// +// ## Adapting to other RAM sizes +// +// Only `BOARD_TOTAL_RAM_GIB` should need editing for a different memory size +// on the SAME 3A6000+LS7A2000 board family. Numbers below are based on the +// "low+mid PA ≈ 2 GiB constant" empirical assumption — verify with +// /proc/iomem before trusting. +// +// | RAM | PA top (hi RAM end) | hi RAM span (above 4 GiB) | +// |-------|------------------------|----------------------------| +// | 8 GiB | `0x280000000` ≈ 10 GiB | ~6.0 GiB (TENTATIVE) | +// | 16 GiB | `0x480000000` ≈ 18 GiB | ~14.0 GiB (verified) | +// | 32 GiB | `0x880000000` ≈ 34 GiB | ~30.0 GiB (TENTATIVE) | +// +// Different motherboards (e.g. desktop vs server, different SPD timings, BIOS +// version) may shift PA top — re-measure if /proc/iomem disagrees. +// +// ## hvisor footprint coordination +// +// Three files must agree on where hvisor lives + how big it is: +// 1. `platform/loongarch64/ls3a6000/linker.ld` → BASE_ADDRESS +// 2. this file `HVISOR_LOAD_PA` + `HVISOR_FOOTPRINT_SIZE` +// 3. `/etc/grub.d/09_loongvisor` template's argv[2] passed to loongstub +// 4. `grub2-hvisor/grub-core/loader/loongarch64/loongstub.c` extra-reserve +// +// Keep all four in sync. The hi RAM region below is auto-split around +// `HVISOR_LOAD_PA..HVISOR_FOOTPRINT_END` so guest Linux's stage-2 can never +// see hvisor's own memory as RAM. + +/// Total system RAM in GiB. Change ONLY this and rebuild — the rest of the +/// hi-RAM layout in this file derives from it (best-effort heuristic; verify +/// `/proc/iomem` if you change to non-16). +pub const BOARD_TOTAL_RAM_GIB: u64 = 32; + +/// Top of high RAM physical address (one byte past the last). Derived from +/// `BOARD_TOTAL_RAM_GIB` via the empirical mapping in the table above. If a +/// future 3A6000 board has a different PA top, override here directly. +pub const BOARD_HI_RAM_TOP: u64 = match BOARD_TOTAL_RAM_GIB { + 8 => 0x280000000, // tentative — verify on 8 GiB board + 16 => 0x480000000, // verified on dev board (16 GiB) + 32 => 0x880000000, // tentative — verify on 32 GiB board + _ => panic!("unsupported BOARD_TOTAL_RAM_GIB; add an entry to the match"), +}; + +/// PA where hvisor itself is loaded. MUST match linker.ld `BASE_ADDRESS` +/// (low 48 bits) and grub.cfg `hvisor_loongarch ... argv[1]`. +pub const HVISOR_LOAD_PA: u64 = 0x380000000; // 14 GiB + +/// Reserved PA span owned by hvisor (text + bss + percpu + heap + frame pool). +/// MUST be ≥ actual hvisor build's MEM_SIZE (printed at end of hvisor `make`). +/// MUST match the value loongstub uses for EFI memory reservation, otherwise +/// EFI may place Boot Services Data into this range and hvisor's runtime +/// allocator will then trample EFI structures → DxeCore asserts in +/// `Locate.c`. 768 MB covers our current ~705 MB MEM_SIZE with headroom. +pub const HVISOR_FOOTPRINT_SIZE: u64 = 0x30000000; // 768 MB + +/// One-past-end of the reserved hvisor PA region. +pub const HVISOR_FOOTPRINT_END: u64 = HVISOR_LOAD_PA + HVISOR_FOOTPRINT_SIZE; + + pub const BOARD_NAME: &str = "ls3a6000"; pub const BOARD_NCPUS: usize = 8; @@ -141,13 +220,37 @@ pub const ROOT_ZONE_MEMORY_REGIONS: &[HvConfigMemoryRegion] = &[ size: 0x1000, }, // IO - // 0x100000000 ~ 0x87fffffff (30GB) + // // 0x100000000 ~ 0x87fffffff (30GB) + // HvConfigMemoryRegion { + // mem_type: MEM_TYPE_RAM, + // physical_start: 0x100000000, + // virtual_start: 0x100000000, + // size: 0x780000000, + // }, // RAM + + // === hi RAM (PA 0x100000000 .. BOARD_HI_RAM_TOP) === + // + // Split into two segments around hvisor's own footprint so guest Linux's + // stage-2 never sees hvisor's runtime pages as plain RAM. The hvisor PA + // window [HVISOR_LOAD_PA, HVISOR_FOOTPRINT_END) is OMITTED here on + // purpose; loongstub also marks the same window as EfiReservedMemoryType + // so EFI Boot Services Data won't land in it either. + // + // Sizes are computed from constants — if BOARD_TOTAL_RAM_GIB or the + // hvisor location changes, both regions adjust automatically. HvConfigMemoryRegion { mem_type: MEM_TYPE_RAM, - physical_start: 0x100000000, + physical_start: 0x100000000, // 4 GiB virtual_start: 0x100000000, - size: 0x780000000, - }, // RAM + size: HVISOR_LOAD_PA - 0x100000000, // hi RAM below hvisor + }, // RAM (below hvisor footprint) + + HvConfigMemoryRegion { + mem_type: MEM_TYPE_RAM, + physical_start: HVISOR_FOOTPRINT_END, // hvisor top + virtual_start: HVISOR_FOOTPRINT_END, + size: BOARD_HI_RAM_TOP - HVISOR_FOOTPRINT_END, // hi RAM above hvisor + }, // RAM (above hvisor footprint, up to BOARD_HI_RAM_TOP) HvConfigMemoryRegion { mem_type: MEM_TYPE_IO, From 955d47a81f95d846d53e9dcde0d345a87c6b074d Mon Sep 17 00:00:00 2001 From: BoneInscri <941388383@qq.com> Date: Tue, 2 Jun 2026 21:21:03 +0800 Subject: [PATCH 15/16] change loongarch64-linux-gnu-objdump to loongarch64-unknown-linux-gnu-objdump of platform.mk of ls3a5000 --- platform/loongarch64/ls3a5000/platform.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/loongarch64/ls3a5000/platform.mk b/platform/loongarch64/ls3a5000/platform.mk index b10d4d44..210040d0 100644 --- a/platform/loongarch64/ls3a5000/platform.mk +++ b/platform/loongarch64/ls3a5000/platform.mk @@ -26,6 +26,6 @@ $(hvisor_bin): elf $(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 + loongarch64-unknown-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 From 2015800df490aa7016db849883631233728a041e Mon Sep 17 00:00:00 2001 From: BoneInscri <941388383@qq.com> Date: Wed, 3 Jun 2026 07:35:14 +0800 Subject: [PATCH 16/16] change loongarch64-linux-gnu-objdump to loongarch64-unknown-linux-gnu-objdump of platform.mk of ls3a6000 --- platform/loongarch64/ls3a6000/platform.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/loongarch64/ls3a6000/platform.mk b/platform/loongarch64/ls3a6000/platform.mk index b10d4d44..210040d0 100644 --- a/platform/loongarch64/ls3a6000/platform.mk +++ b/platform/loongarch64/ls3a6000/platform.mk @@ -26,6 +26,6 @@ $(hvisor_bin): elf $(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 + loongarch64-unknown-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