From b873c7904aa8412128bdb9a080ce0efd8d70666f Mon Sep 17 00:00:00 2001 From: dorso <2434317248@qq.com> Date: Wed, 17 Jul 2024 13:15:11 +0800 Subject: [PATCH 1/6] =?UTF-8?q?aia:linux=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + Cargo.toml | 5 + Makefile | 14 +- images/riscv64/devicetree/linux-aia.dts | 80 ++++ images/riscv64/devicetree/linux.dts | 59 +++ images/riscv64/devicetree/linux1-aia.dts | 165 ++++++++ images/riscv64/devicetree/linux1.dts | 11 +- images/riscv64/devicetree/linux2-aia.dts | 80 ++++ images/riscv64/devicetree/linux3-aia.dts | 159 ++++++++ images/riscv64/devicetree/linux3.dts | 156 ++++++++ scripts/qemu-riscv64.mk | 35 +- src/arch/riscv64/cpu.rs | 2 +- src/arch/riscv64/mm.rs | 6 +- src/arch/riscv64/trap.rs | 116 ++++-- src/arch/riscv64/zone.rs | 38 ++ src/device/irqchip/aplic/mod.rs | 471 +++++++++++++++++++++++ src/device/irqchip/mod.rs | 10 + src/main.rs | 2 + src/memory/mod.rs | 3 +- 19 files changed, 1355 insertions(+), 58 deletions(-) create mode 100644 images/riscv64/devicetree/linux-aia.dts create mode 100644 images/riscv64/devicetree/linux.dts create mode 100644 images/riscv64/devicetree/linux1-aia.dts create mode 100644 images/riscv64/devicetree/linux2-aia.dts create mode 100644 images/riscv64/devicetree/linux3-aia.dts create mode 100644 images/riscv64/devicetree/linux3.dts create mode 100644 src/device/irqchip/aplic/mod.rs diff --git a/.gitignore b/.gitignore index d8259cb..a0bd4f1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/images/riscv64/opensbi-1.2 /target /qemu-test /test-img diff --git a/Cargo.toml b/Cargo.toml index 9c47e1f..bcd74d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,11 @@ name = "hvisor" version = "0.1.0" edition = "2021" +[features] +default = ["aia"] +plic = [] +aia = [] + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/Makefile b/Makefile index db489b2..6367f0b 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ STATS ?= off PORT ?= 2333 MODE ?= debug OBJCOPY ?= rust-objcopy --binary-architecture=$(ARCH) +IRQ ?= plic ifeq ($(ARCH),aarch64) RUSTC_TARGET := aarch64-unknown-none @@ -27,12 +28,13 @@ build_path := target/$(RUSTC_TARGET)/$(MODE) hvisor_elf := $(build_path)/hvisor hvisor_bin := $(build_path)/hvisor.bin image_dir := images/$(ARCH) +bios_elf := $(image_dir)/opensbi-1.2/build/platform/generic/firmware/fw_payload.elf # Features based on STATS features := # Build arguments -build_args := --features "$(features)" +build_args := --features "$(IRQ)" build_args := --target $(RUSTC_TARGET) build_args += -Z build-std=core,alloc build_args += -Z build-std-features=compiler-builtins-mem @@ -52,9 +54,17 @@ disa: readelf -a $(hvisor_elf) > hvisor-elf.txt rust-objdump --disassemble $(hvisor_elf) > hvisor.S -run: all +run: build $(QEMU) $(QEMU_ARGS) +$(hvisor_bin): elf + $(OBJCOPY) $(hvisor_elf) --strip-all -O binary $@ + +build: $(hvisor_bin) + make -C $(image_dir)/opensbi-1.2 PLATFORM=generic \ + FW_PAYLOAD=y \ + FW_PAYLOAD_PATH= ../../../$(hvisor_bin) + gdb: all $(QEMU) $(QEMU_ARGS) -s -S diff --git a/images/riscv64/devicetree/linux-aia.dts b/images/riscv64/devicetree/linux-aia.dts new file mode 100644 index 0000000..286a19c --- /dev/null +++ b/images/riscv64/devicetree/linux-aia.dts @@ -0,0 +1,80 @@ +/dts-v1/; + +/ { + #address-cells = <0x2>; + #size-cells = <0x2>; + + cpus { + #address-cells = <0x1>; + #size-cells = <0x0>; + timebase-frequency = <10000000>; + cpu@3 { + device_type = "cpu"; + reg = <0x3>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdch_ssaia_sstc"; + mmu-type = "riscv,sv48"; + + cpu3_intc: interrupt-controller { + #interrupt-cells = <0x1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + }; + }; + + }; + + memory@84000000 { + device_type = "memory"; + reg = <0x0 0x84000000 0x0 0x08000000>; + }; +soc{ + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "simple-bus"; + ranges; + + aplic@d000000 { + phandle = <0x08>; + riscv,num-sources = <0x60>; + reg = <0x00 0xd000000 0x00 0x8000>; + msi-parent = <0x06>; + interrupt-controller; + #interrupt-cells = <0x02>; + compatible = "riscv,aplic"; + }; + + imsics@28000000 { + phandle = <0x06>; + riscv,num-ids = <0xff>; + reg = <0x00 0x28000000 0x00 0x4000>; + interrupts-extended = < + &cpu3_intc 9 + >; + msi-controller; + interrupt-controller; + #interrupt-cells = <0x00>; + compatible = "riscv,imsics"; + }; + + virtio_mmio@10007000 { + interrupts = <0x7 &cpu3_intc>; + interrupt-parent = <0x08>; + reg = <0x0 0x10007000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10006000 { + interrupts = <0x6 &cpu3_intc>; + interrupt-parent = <0x08>; + reg = <0x0 0x10006000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + +}; + + chosen { + bootargs = "root=/dev/vda rw earlycon console=hvc0"; + }; +}; \ No newline at end of file diff --git a/images/riscv64/devicetree/linux.dts b/images/riscv64/devicetree/linux.dts new file mode 100644 index 0000000..ad4a02c --- /dev/null +++ b/images/riscv64/devicetree/linux.dts @@ -0,0 +1,59 @@ +/dts-v1/; + +/ { + #address-cells = <0x2>; + #size-cells = <0x2>; + + cpus { + #address-cells = <0x1>; + #size-cells = <0x0>; + timebase-frequency = <10000000>; + cpu@3 { + device_type = "cpu"; + reg = <0x3>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcsu_sstc"; + mmu-type = "riscv,sv39"; + + cpu3_intc: interrupt-controller { + #interrupt-cells = <0x1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + }; + }; + + }; + + memory@84000000 { + device_type = "memory"; + reg = <0x0 0x84000000 0x0 0x08000000>; + }; +soc{ + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "simple-bus"; + ranges; + plic: interrupt-controller@c000000 { + riscv,ndev = <60>; + reg = <0x0 0xc000000 0x0 0x4000000>; + interrupts-extended = < + &cpu3_intc 11 &cpu3_intc 9 + >; + interrupt-controller; + compatible = "riscv,plic0"; + #interrupt-cells = <0x1>; + }; + + virtio_mmio@10007000 { + interrupts = <0x7>; + interrupt-parent = <&plic>; + reg = <0x0 0x10007000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; +}; + chosen { + bootargs = "root=/dev/vda rw earlycon console=hvc0"; + }; + +}; \ No newline at end of file diff --git a/images/riscv64/devicetree/linux1-aia.dts b/images/riscv64/devicetree/linux1-aia.dts new file mode 100644 index 0000000..30ef0c5 --- /dev/null +++ b/images/riscv64/devicetree/linux1-aia.dts @@ -0,0 +1,165 @@ +/dts-v1/; + +/ { + #address-cells = <0x2>; + #size-cells = <0x2>; + + cpus { + #address-cells = <0x1>; + #size-cells = <0x0>; + timebase-frequency = <10000000>; + cpu@0 { + device_type = "cpu"; + reg = <0x0>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdch_ssaia_sstc"; + mmu-type = "riscv,sv39"; + + cpu0_intc: interrupt-controller { + #interrupt-cells = <0x1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + phandle = <0x04>; + }; + }; + cpu@1 { + device_type = "cpu"; + reg = <0x1>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdch_ssaia_sstc"; + mmu-type = "riscv,sv39"; + + cpu1_intc: interrupt-controller { + #interrupt-cells = <0x1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + }; + }; + cpu@2 { + device_type = "cpu"; + reg = <0x2>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdch_ssaia_sstc"; + mmu-type = "riscv,sv39"; + + cpu2_intc: interrupt-controller { + #interrupt-cells = <0x1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + }; + }; + }; + + memory@83000000 { + device_type = "memory"; + reg = <0x0 0x83000000 0x0 0x25000000>; + }; + + reserved-memory { + #address-cells = <0x02>; + #size-cells = <0x02>; + ranges; + + nonroot@84000000 { + no-map; + reg = <0x0 0x84000000 0x0 0x08000000>; + }; + }; + +soc{ + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "simple-bus"; + ranges; + + aplic@d000000 { + phandle = <0x08>; + riscv,num-sources = <0x60>; + reg = <0x00 0xd000000 0x00 0x8000>; + msi-parent = <0x06>; + interrupt-controller; + #interrupt-cells = <0x02>; + compatible = "riscv,aplic"; + }; + + imsics@28000000 { + phandle = <0x06>; + riscv,num-ids = <0xff>; + reg = <0x00 0x28000000 0x00 0x4000>; + interrupts-extended = < + &cpu0_intc 9 + &cpu1_intc 9 + &cpu2_intc 9 + >; + msi-controller; + interrupt-controller; + #interrupt-cells = <0x00>; + compatible = "riscv,imsics"; + }; + + virtio_mmio@10008000 { + interrupts = <0x8 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10008000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10005000 { + interrupts = <0x5 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10005000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10004000 { + interrupts = <0x4 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10004000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10003000 { + interrupts = <0x3 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10003000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10002000 { + interrupts = <0x2 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10002000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10001000 { + interrupts = <0x1 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10001000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + pci@30000000 { + interrupt-map-mask = <0x1800 0x00 0x00 0x07>; + interrupt-map = <0x00 0x00 0x00 0x01 0x09 0x20 0x00 0x00 0x00 0x02 0x09 0x21 0x00 0x00 0x00 0x03 0x09 0x22 0x00 0x00 0x00 0x04 0x09 0x23 0x800 0x00 0x00 0x01 0x09 0x21 0x800 0x00 0x00 0x02 0x09 0x22 0x800 0x00 0x00 0x03 0x09 0x23 0x800 0x00 0x00 0x04 0x09 0x20 0x1000 0x00 0x00 0x01 0x09 0x22 0x1000 0x00 0x00 0x02 0x09 0x23 0x1000 0x00 0x00 0x03 0x09 0x20 0x1000 0x00 0x00 0x04 0x09 0x21 0x1800 0x00 0x00 0x01 0x09 0x23 0x1800 0x00 0x00 0x02 0x09 0x20 0x1800 0x00 0x00 0x03 0x09 0x21 0x1800 0x00 0x00 0x04 0x09 0x22>; + ranges = <0x1000000 0x00 0x00 0x00 0x3000000 0x00 0x10000 0x2000000 0x00 0x40000000 0x00 0x40000000 0x00 0x40000000 0x3000000 0x04 0x00 0x04 0x00 0x04 0x00>; + reg = <0x00 0x30000000 0x00 0x10000000>; + dma-coherent; + bus-range = <0x00 0xff>; + linux,pci-domain = <0x00>; + device_type = "pci"; + compatible = "pci-host-ecam-generic"; + #size-cells = <0x02>; + #interrupt-cells = <0x01>; + #address-cells = <0x03>; + }; + uart@10000000 { + interrupts = <0x0a 0x04>; + interrupt-parent = <0x08>; + clock-frequency = "\08@"; + reg = <0x00 0x10000000 0x00 0x100>; + compatible = "ns16550a"; + }; + +}; + chosen { + bootargs = "root=/dev/vda rw earlycon console=ttyS0 ip=192.168.42.15"; + }; +}; \ No newline at end of file diff --git a/images/riscv64/devicetree/linux1.dts b/images/riscv64/devicetree/linux1.dts index f5a177b..7130294 100644 --- a/images/riscv64/devicetree/linux1.dts +++ b/images/riscv64/devicetree/linux1.dts @@ -57,7 +57,7 @@ memory@83000000 { device_type = "memory"; - reg = <0x0 0x83000000 0x0 0x1D000000>; + reg = <0x0 0x83000000 0x0 0x25000000>; }; reserved-memory { @@ -65,14 +65,9 @@ #size-cells = <0x02>; ranges; - nonroot@83000000 { + nonroot@84000000 { no-map; - reg = <0x00 0x83000000 0x00 0x09000000>; - }; - - dtbfile@0x8f000000 { - no-map; - reg = <0x00 0x8f000000 0x00 0x01000000>; + reg = <0x0 0x84000000 0x0 0x08000000>; }; }; diff --git a/images/riscv64/devicetree/linux2-aia.dts b/images/riscv64/devicetree/linux2-aia.dts new file mode 100644 index 0000000..5b4c0ab --- /dev/null +++ b/images/riscv64/devicetree/linux2-aia.dts @@ -0,0 +1,80 @@ +/dts-v1/; + +/ { + #address-cells = <0x2>; + #size-cells = <0x2>; + + cpus { + #address-cells = <0x1>; + #size-cells = <0x0>; + timebase-frequency = <10000000>; + cpu@3 { + device_type = "cpu"; + reg = <0x3>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdch_ssaia_sstc"; + mmu-type = "riscv,sv39"; + + cpu3_intc: interrupt-controller { + #interrupt-cells = <0x1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + }; + }; + + }; + + memory@84000000 { + device_type = "memory"; + reg = <0x0 0x84000000 0x0 0x08000000>; + }; +soc{ + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "simple-bus"; + ranges; + + aplic@d000000 { + phandle = <0x08>; + riscv,num-sources = <0x60>; + reg = <0x00 0xd000000 0x00 0x8000>; + msi-parent = <0x06>; + interrupt-controller; + #interrupt-cells = <0x02>; + compatible = "riscv,aplic"; + }; + + imsics@28000000 { + phandle = <0x06>; + riscv,num-ids = <0xff>; + reg = <0x00 0x28000000 0x00 0x4000>; + interrupts-extended = < + &cpu3_intc 9 + >; + msi-controller; + interrupt-controller; + #interrupt-cells = <0x00>; + compatible = "riscv,imsics"; + }; + + virtio_mmio@10007000 { + interrupts = <0x7 &cpu3_intc>; + interrupt-parent = <0x08>; + reg = <0x0 0x10007000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10006000 { + interrupts = <0x6 &cpu3_intc>; + interrupt-parent = <0x08>; + reg = <0x0 0x10006000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + +}; + + chosen { + bootargs = "root=/dev/vda rw earlycon console=hvc0"; + }; +}; \ No newline at end of file diff --git a/images/riscv64/devicetree/linux3-aia.dts b/images/riscv64/devicetree/linux3-aia.dts new file mode 100644 index 0000000..d1cb4b3 --- /dev/null +++ b/images/riscv64/devicetree/linux3-aia.dts @@ -0,0 +1,159 @@ +/dts-v1/; + +/ { + #address-cells = <0x2>; + #size-cells = <0x2>; + + cpus { + #address-cells = <0x1>; + #size-cells = <0x0>; + timebase-frequency = <10000000>; + cpu@0 { + device_type = "cpu"; + reg = <0x0>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdch_ssaia_sstc"; + mmu-type = "riscv,sv48"; + + cpu0_intc: interrupt-controller { + #interrupt-cells = <0x1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + phandle = <0x04>; + }; + }; + cpu@1 { + device_type = "cpu"; + reg = <0x1>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdch_ssaia_sstc"; + mmu-type = "riscv,sv48"; + + cpu1_intc: interrupt-controller { + #interrupt-cells = <0x1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + }; + }; + cpu@2 { + device_type = "cpu"; + reg = <0x2>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdch_ssaia_sstc"; + mmu-type = "riscv,sv48"; + + cpu2_intc: interrupt-controller { + #interrupt-cells = <0x1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + }; + }; + }; + + memory@90000000 { + device_type = "memory"; + reg = <0x0 0x90000000 0x0 0x10000000>; + }; +soc{ + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "simple-bus"; + ranges; + + aplic@d000000 { + phandle = <0x08>; + riscv,num-sources = <0x60>; + reg = <0x00 0xd000000 0x00 0x8000>; + msi-parent = <0x06>; + interrupt-controller; + #interrupt-cells = <0x02>; + compatible = "riscv,aplic"; + }; + + imsics@28000000 { + phandle = <0x06>; + riscv,num-ids = <0xff>; + reg = <0x00 0x28000000 0x00 0x4000>; + interrupts-extended = < + &cpu0_intc 9 + &cpu1_intc 9 + &cpu2_intc 9 + >; + msi-controller; + interrupt-controller; + #interrupt-cells = <0x00>; + compatible = "riscv,imsics"; + }; + + virtio_mmio@10008000 { + interrupts = <0x8 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10008000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10006000 { + interrupts = <0x6 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10006000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10005000 { + interrupts = <0x5 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10005000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10004000 { + interrupts = <0x4 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10004000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10003000 { + interrupts = <0x3 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10003000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10002000 { + interrupts = <0x2 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10002000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10001000 { + interrupts = <0x1 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10001000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + pci@30000000 { + interrupt-map-mask = <0x1800 0x00 0x00 0x07>; + interrupt-map = <0x00 0x00 0x00 0x01 0x09 0x20 0x00 0x00 0x00 0x02 0x09 0x21 0x00 0x00 0x00 0x03 0x09 0x22 0x00 0x00 0x00 0x04 0x09 0x23 0x800 0x00 0x00 0x01 0x09 0x21 0x800 0x00 0x00 0x02 0x09 0x22 0x800 0x00 0x00 0x03 0x09 0x23 0x800 0x00 0x00 0x04 0x09 0x20 0x1000 0x00 0x00 0x01 0x09 0x22 0x1000 0x00 0x00 0x02 0x09 0x23 0x1000 0x00 0x00 0x03 0x09 0x20 0x1000 0x00 0x00 0x04 0x09 0x21 0x1800 0x00 0x00 0x01 0x09 0x23 0x1800 0x00 0x00 0x02 0x09 0x20 0x1800 0x00 0x00 0x03 0x09 0x21 0x1800 0x00 0x00 0x04 0x09 0x22>; + ranges = <0x1000000 0x00 0x00 0x00 0x3000000 0x00 0x10000 0x2000000 0x00 0x40000000 0x00 0x40000000 0x00 0x40000000 0x3000000 0x04 0x00 0x04 0x00 0x04 0x00>; + reg = <0x00 0x30000000 0x00 0x10000000>; + dma-coherent; + bus-range = <0x00 0xff>; + linux,pci-domain = <0x00>; + device_type = "pci"; + compatible = "pci-host-ecam-generic"; + #size-cells = <0x02>; + #interrupt-cells = <0x01>; + #address-cells = <0x03>; + }; + uart@10000000 { + interrupts = <0x0a 0x04>; + interrupt-parent = <0x08>; + clock-frequency = "\08@"; + reg = <0x00 0x10000000 0x00 0x100>; + compatible = "ns16550a"; + }; + +}; + chosen { + bootargs = "root=/dev/vda rw earlycon console=ttyS0 ip=192.168.42.15"; + }; +}; \ No newline at end of file diff --git a/images/riscv64/devicetree/linux3.dts b/images/riscv64/devicetree/linux3.dts new file mode 100644 index 0000000..201d001 --- /dev/null +++ b/images/riscv64/devicetree/linux3.dts @@ -0,0 +1,156 @@ +/dts-v1/; + +/ { + #address-cells = <0x2>; + #size-cells = <0x2>; + + cpus { + #address-cells = <0x1>; + #size-cells = <0x0>; + timebase-frequency = <10000000>; + + cpu@0 { + device_type = "cpu"; + reg = <0x0>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcsu_sstc"; + mmu-type = "riscv,sv39"; + + cpu0_intc: interrupt-controller { + #interrupt-cells = <0x1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + }; + }; + + cpu@1 { + device_type = "cpu"; + reg = <0x1>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcsu_sstc"; + mmu-type = "riscv,sv39"; + + cpu1_intc: interrupt-controller { + #interrupt-cells = <0x1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + }; + }; + cpu@2 { + device_type = "cpu"; + reg = <0x2>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcsu_sstc"; + mmu-type = "riscv,sv39"; + + cpu2_intc: interrupt-controller { + #interrupt-cells = <0x1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + }; + }; + + }; + + memory@90000000 { + device_type = "memory"; + reg = <0x0 0x90000000 0x0 0x10000000>; + }; +soc{ + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "simple-bus"; + ranges; + plic: interrupt-controller@c000000 { + riscv,ndev = <60>; + reg = <0x0 0xc000000 0x0 0x4000000>; + interrupts-extended = < + &cpu0_intc 11 &cpu0_intc 9 + &cpu1_intc 11 &cpu1_intc 9 + &cpu2_intc 11 &cpu2_intc 9 + >; + interrupt-controller; + compatible = "riscv,plic0"; + #interrupt-cells = <0x1>; + }; + uart@10000000 { + interrupts = <0x0a>; + interrupt-parent = <&plic>; + clock-frequency = "\08@"; + reg = <0x00 0x10000000 0x00 0x100>; + compatible = "ns16550a"; + }; + pci@30000000 { + interrupt-map-mask = <0x1800 0x00 0x00 0x07>; + interrupt-map = <0x00 0x00 0x00 0x01 0x09 0x20 0x00 0x00 0x00 0x02 0x09 0x21 0x00 0x00 0x00 0x03 0x09 0x22 0x00 0x00 0x00 0x04 0x09 0x23 0x800 0x00 0x00 0x01 0x09 0x21 0x800 0x00 0x00 0x02 0x09 0x22 0x800 0x00 0x00 0x03 0x09 0x23 0x800 0x00 0x00 0x04 0x09 0x20 0x1000 0x00 0x00 0x01 0x09 0x22 0x1000 0x00 0x00 0x02 0x09 0x23 0x1000 0x00 0x00 0x03 0x09 0x20 0x1000 0x00 0x00 0x04 0x09 0x21 0x1800 0x00 0x00 0x01 0x09 0x23 0x1800 0x00 0x00 0x02 0x09 0x20 0x1800 0x00 0x00 0x03 0x09 0x21 0x1800 0x00 0x00 0x04 0x09 0x22>; + ranges = <0x1000000 0x00 0x00 0x00 0x3000000 0x00 0x10000 0x2000000 0x00 0x40000000 0x00 0x40000000 0x00 0x40000000 0x3000000 0x04 0x00 0x04 0x00 0x04 0x00>; + reg = <0x00 0x30000000 0x00 0x10000000>; + dma-coherent; + bus-range = <0x00 0xff>; + linux,pci-domain = <0x00>; + device_type = "pci"; + compatible = "pci-host-ecam-generic"; + #size-cells = <0x02>; + #interrupt-cells = <0x01>; + #address-cells = <0x03>; + }; + + virtio_mmio@10008000 { + interrupts = <0x8>; + interrupt-parent = <&plic>; + reg = <0x0 0x10008000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10006000 { + interrupts = <0x6>; + interrupt-parent = <&plic>; + reg = <0x0 0x10006000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10005000 { + interrupts = <0x5>; + interrupt-parent = <&plic>; + reg = <0x0 0x10005000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10004000 { + interrupts = <0x4>; + interrupt-parent = <&plic>; + reg = <0x0 0x10004000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10003000 { + interrupts = <0x3>; + interrupt-parent = <&plic>; + reg = <0x0 0x10003000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10002000 { + interrupts = <0x2>; + interrupt-parent = <&plic>; + reg = <0x0 0x10002000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10001000 { + interrupts = <0x1>; + interrupt-parent = <&plic>; + reg = <0x0 0x10001000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + + + +}; + chosen { + bootargs = "root=/dev/vda rw earlycon console=ttyS0 ip=192.168.42.15"; + }; + +}; diff --git a/scripts/qemu-riscv64.mk b/scripts/qemu-riscv64.mk index bfb82ad..35e5045 100644 --- a/scripts/qemu-riscv64.mk +++ b/scripts/qemu-riscv64.mk @@ -1,27 +1,50 @@ QEMU := qemu-system-riscv64 +# Binutils +OBJDUMP := rust-objdump --arch-name=riscv64 +OBJCOPY := rust-objcopy --binary-architecture=riscv64 FSIMG1 := $(image_dir)/virtdisk/rootfs1.ext4 FSIMG2 := $(image_dir)/virtdisk/rootfs-busybox.qcow2 # HVISOR ENTRY HVISOR_ENTRY_PA := 0x80200000 -zone0_kernel := $(image_dir)/kernel/Image +# plic +zone0_kernel := $(image_dir)/kernel/Image-aia zone0_dtb := $(image_dir)/devicetree/linux1.dtb # zone1_kernel := $(image_dir)/kernel/Image -# zone1_dtb := $(image_dir)/devicetree/linux.dtb +# zone1_dtb := $(image_dir)/devicetree/linux2.dtb -QEMU_ARGS := -machine virt -QEMU_ARGS += -bios default +# aia +zone0_aia_kernel := $(image_dir)/kernel/Image-aia +zone0_aia_dtb := $(image_dir)/devicetree/linux1-aia.dtb +# zone1_aia_kernel := $(image_dir)/kernel/Image-aia +# zone1_aia_dtb := $(image_dir)/devicetree/linux2-aia.dtb + +ifeq ($(IRQ),aia) + QEMU_ARGS := -machine virt,aclint=on,aia=aplic-imsic,aia-guests=1 +else ifeq ($(IRQ),plic) + QEMU_ARGS := -machine virt +endif + +QEMU_ARGS += -bios $(bios_elf) QEMU_ARGS += -cpu rv64 QEMU_ARGS += -smp 4 QEMU_ARGS += -m 2G QEMU_ARGS += -nographic -QEMU_ARGS += -kernel $(hvisor_bin) +QEMU_ARGS += -device loader,file=$(hvisor_bin),addr=$(HVISOR_ENTRY_PA) + +ifeq ($(IRQ),aia) +QEMU_ARGS += -device loader,file="$(zone0_aia_kernel)",addr=0x90000000,force-raw=on +QEMU_ARGS += -device loader,file="$(zone0_aia_dtb)",addr=0x8f000000,force-raw=on +# QEMU_ARGS += -device loader,file="$(zone1_aia_kernel)",addr=0x84000000,force-raw=on +# QEMU_ARGS += -device loader,file="$(zone1_aia_dtb)",addr=0x83000000,force-raw=on +else ifeq ($(IRQ),plic) QEMU_ARGS += -device loader,file="$(zone0_kernel)",addr=0x90000000,force-raw=on QEMU_ARGS += -device loader,file="$(zone0_dtb)",addr=0x8f000000,force-raw=on # QEMU_ARGS += -device loader,file="$(zone1_kernel)",addr=0x84000000,force-raw=on # QEMU_ARGS += -device loader,file="$(zone1_dtb)",addr=0x83000000,force-raw=on +endif QEMU_ARGS += -drive if=none,file=$(FSIMG1),id=X10008000,format=raw QEMU_ARGS += -device virtio-blk-device,drive=X10008000 @@ -48,5 +71,3 @@ QEMU_ARGS += -device virtio-blk-device,drive=X10006000 # #QEMU_ARGS += -device virtio-serial-port -chardev pty,id=serial3 -device virtconsole,chardev=serial3 # QEMU_ARGS += -device virtio-serial-device -chardev pty,id=serial3 -device virtconsole,chardev=serial3 -$(hvisor_bin): elf - $(OBJCOPY) $(hvisor_elf) --strip-all -O binary $@ \ No newline at end of file diff --git a/src/arch/riscv64/cpu.rs b/src/arch/riscv64/cpu.rs index 5648d74..86713e4 100644 --- a/src/arch/riscv64/cpu.rs +++ b/src/arch/riscv64/cpu.rs @@ -51,7 +51,7 @@ impl ArchCpu { //self.sepc = guest_test as usize as u64; write_csr!(CSR_SSCRATCH, self as *const _ as usize); //arch cpu pointer self.sepc = entry; - self.hstatus = 1 << 7 | 2 << 32; //HSTATUS_SPV | HSTATUS_VSXL_64 + self.hstatus = 1 << 7 | 2 << 32 | 1 << 12; //HSTATUS_SPV | HSTATUS_VSXL_64 | HSTATUS_VGEIN self.sstatus = 1 << 8 | 1 << 63 | 3 << 13 | 3 << 15; //SPP self.stack_top = self.stack_top() as usize; self.x[10] = cpu_id; //cpu id diff --git a/src/arch/riscv64/mm.rs b/src/arch/riscv64/mm.rs index 258fdbd..c2ad6f7 100644 --- a/src/arch/riscv64/mm.rs +++ b/src/arch/riscv64/mm.rs @@ -4,10 +4,12 @@ use crate::{ arch::s1pt::Stage1PageTable, error::HvResult, memory::{ - addr::align_up, GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet, HV_PT, + addr::align_up, GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet }, }; - +// #[cfg(feature = "plic")] +use crate::memory::HV_PT; +// #[cfg(feature = "plic")] pub fn init_hv_page_table(fdt: &fdt::Fdt) -> HvResult { let mut hv_pt: MemorySet = MemorySet::new(); // let _ = hv_pt.insert(MemoryRegion::new_with_offset_mapper( diff --git a/src/arch/riscv64/trap.rs b/src/arch/riscv64/trap.rs index a3cfd7d..efbcb71 100644 --- a/src/arch/riscv64/trap.rs +++ b/src/arch/riscv64/trap.rs @@ -2,7 +2,10 @@ use super::cpu::ArchCpu; use crate::arch::csr::read_csr; use crate::arch::csr::*; use crate::arch::sbi::sbi_vs_handler; +#[cfg(feature = "plic")] use crate::device::irqchip::plic::{host_plic, vplic_global_emul_handler, vplic_hart_emul_handler}; +#[cfg(feature = "aia")] +use crate::device::irqchip::aplic::{host_aplic, vaplic_emul_handler}; use crate::event::check_events; use crate::memory::{GuestPhysAddr, HostPhysAddr}; use crate::platform::qemu_riscv64::*; @@ -17,14 +20,14 @@ extern "C" { global_asm!(include_str!("trap.S"), sync_exception_handler=sym sync_exception_handler, interrupts_arch_handle=sym interrupts_arch_handle); -#[allow(non_snake_case)] + pub mod ExceptionType { pub const ECALL_VU: usize = 8; pub const ECALL_VS: usize = 10; pub const LOAD_GUEST_PAGE_FAULT: usize = 21; pub const STORE_GUEST_PAGE_FAULT: usize = 23; } -#[allow(non_snake_case)] + pub mod InterruptType { pub const SSI: usize = 1; pub const STI: usize = 5; @@ -87,48 +90,83 @@ pub fn sync_exception_handler(current_cpu: &mut ArchCpu) { pub fn guest_page_fault_handler(current_cpu: &mut ArchCpu) { let addr: HostPhysAddr = read_csr!(CSR_HTVAL) << 2; trace!("guest page fault at {:#x}", addr); - let host_plic_base = host_plic().read().base; - let mut ins_size: usize = 0; - //TODO: get plic addr range from dtb or vpliv object - if addr >= host_plic_base && addr < host_plic_base + PLIC_TOTAL_SIZE { - trace!("PLIC access"); - let mut inst: u32 = read_csr!(CSR_HTINST) as u32; - if inst == 0 { - let inst_addr: GuestPhysAddr = current_cpu.sepc; - //load real ins from guest memmory - inst = read_inst(inst_addr); - ins_size = if inst & 0x3 == 3 { 4 } else { 2 }; - } else if inst == 0x3020 || inst == 0x3000 { - // TODO: we should reinject this in the guest as a fault access - error!("fault on 1st stage page table walk"); + #[cfg(feature = "plic")]{ + let host_plic_base = host_plic().read().base; + let mut ins_size: usize = 0; + //TODO: get plic addr range from dtb or vpliv object + if addr >= host_plic_base && addr < host_plic_base + PLIC_TOTAL_SIZE { + trace!("PLIC access"); + let mut inst: u32 = read_csr!(CSR_HTINST) as u32; + if inst == 0 { + let inst_addr: GuestPhysAddr = current_cpu.sepc; + //load real ins from guest memmory + inst = read_inst(inst_addr); + ins_size = if inst & 0x3 == 3 { 4 } else { 2 }; + } else if inst == 0x3020 || inst == 0x3000 { + // TODO: we should reinject this in the guest as a fault access + error!("fault on 1st stage page table walk"); + } else { + // If htinst is valid and is not a pseudo instructon make sure + // the opcode is valid even if it was a compressed instruction, + // but before save the real instruction size. + ins_size = if (inst) & 0x2 == 0 { 2 } else { 4 }; + inst = inst | 0b10; + // error!("unhandled guest page fault at {:#x}", addr); + // panic!("inst{:#x}", inst); + } + //TODO: decode inst to real instruction + let (len, inst) = decode_inst(inst); + if let Some(inst) = inst { + if addr >= host_plic_base + PLIC_GLOBAL_SIZE { + vplic_hart_emul_handler(current_cpu, addr, inst); + } else { + vplic_global_emul_handler(current_cpu, addr, inst); + } + current_cpu.sepc += ins_size; + } else { + error!("Invalid instruction at {:#x}", current_cpu.sepc); + panic!(); + } } else { - // If htinst is valid and is not a pseudo instructon make sure - // the opcode is valid even if it was a compressed instruction, - // but before save the real instruction size. - ins_size = if (inst) & 0x2 == 0 { 2 } else { 4 }; - inst = inst | 0b10; - // error!("unhandled guest page fault at {:#x}", addr); - // panic!("inst{:#x}", inst); + panic!("CPU {} unmaped memmory at {:#x}", current_cpu.cpuid, addr); } - //TODO: decode inst to real instruction - let (_len, inst) = decode_inst(inst); - if let Some(inst) = inst { - if addr >= host_plic_base + PLIC_GLOBAL_SIZE { - vplic_hart_emul_handler(current_cpu, addr, inst); + } + + #[cfg(feature = "aia")]{ + let host_aplic_base = host_aplic().read().base; + let host_aplic_size = host_aplic().read().size; + + if addr >= host_aplic_base && addr < host_aplic_base + host_aplic_size { + trace!("APLIC access"); + let mut inst: u32 = read_csr!(CSR_HTINST) as u32; + let mut ins_size: usize = 0; + if inst == 0 { + let inst_addr: GuestPhysAddr = current_cpu.sepc; + inst = read_inst(inst_addr); + ins_size = if inst & 0x3 == 3 { 4 } else { 2 }; + } else if inst == 0x3020 || inst == 0x3000 { + error!("fault on 1st stage page table walk"); + } else { + ins_size = if (inst) & 0x2 == 0 { 2 } else { 4 }; + inst = inst | 0b10; + // error!("unhandled guest page fault at {:#x}", addr); + } + // let (len, inst) = decode_inst(inst); + let (_, inst) = decode_inst(inst); + + if let Some(inst) = inst { + vaplic_emul_handler(current_cpu, addr, inst); + current_cpu.sepc += ins_size; } else { - vplic_global_emul_handler(current_cpu, addr, inst); + error!("Invalid instruction at {:#x}", current_cpu.sepc); } - current_cpu.sepc += ins_size; } else { - error!("Invalid instruction at {:#x}", current_cpu.sepc); - panic!(); + panic!("CPU {} unmaped memmory at {:#x}", current_cpu.cpuid, addr); } - } else { - panic!("CPU {} unmaped memmory at {:#x}", current_cpu.cpuid, addr); } } fn read_inst(addr: GuestPhysAddr) -> u32 { - let mut ins: u32; + let mut ins: u32 = 0; if addr & 0b1 != 0 { error!("trying to read guest unaligned instruction"); } @@ -200,14 +238,15 @@ pub fn interrupts_arch_handle(current_cpu: &mut ArchCpu) { /// handle interrupt request(current only external interrupt) pub fn handle_eirq(current_cpu: &mut ArchCpu) { + #[cfg(feature = "plic")]{ // TODO: handle other irq // check external interrupt && handle // sifive plic: context0=>cpu0,M mode,context1=>cpu0,S mode... let context_id = 2 * current_cpu.cpuid + 1; - let host_plic = host_plic(); + let mut host_plic = host_plic(); let claim_and_complete_addr = host_plic.read().base + PLIC_GLOBAL_SIZE + 0x1000 * context_id + 0x4; - let irq = unsafe { core::ptr::read_volatile(claim_and_complete_addr as *const u32) }; + let mut irq = unsafe { core::ptr::read_volatile(claim_and_complete_addr as *const u32) }; debug!( "CPU{} get external irq{}@{:#x}", current_cpu.cpuid, irq, claim_and_complete_addr @@ -215,6 +254,9 @@ pub fn handle_eirq(current_cpu: &mut ArchCpu) { host_plic.write().claim_complete[context_id] = irq; // set external interrupt pending, which trigger guest interrupt unsafe { hvip::set_vseip() }; + } + #[cfg(feature = "aia")]{ + } } pub fn handle_ssi(current_cpu: &mut ArchCpu) { trace!("handle_ssi"); diff --git a/src/arch/riscv64/zone.rs b/src/arch/riscv64/zone.rs index 9a8aa3f..1a88ca4 100644 --- a/src/arch/riscv64/zone.rs +++ b/src/arch/riscv64/zone.rs @@ -5,6 +5,7 @@ use crate::{ }, percpu::get_cpu_data, zone::Zone, + consts::PAGE_SIZE }; impl Zone { pub fn pt_init( @@ -122,6 +123,43 @@ impl Zone { ))?; } } + #[cfg(feature = "aia")]{ + let paddr = 0x2800_0000 as HostPhysAddr; + let size = PAGE_SIZE; + self.gpm.insert(MemoryRegion::new_with_offset_mapper( + paddr as GuestPhysAddr, + paddr + PAGE_SIZE * 1, + size, + MemFlags::READ | MemFlags::WRITE, + ))?; + + let paddr = 0x2800_1000 as HostPhysAddr; + let size = PAGE_SIZE; + self.gpm.insert(MemoryRegion::new_with_offset_mapper( + paddr as GuestPhysAddr, + paddr + PAGE_SIZE * 2, + size, + MemFlags::READ | MemFlags::WRITE, + ))?; + + let paddr = 0x2800_2000 as HostPhysAddr; + let size = PAGE_SIZE; + self.gpm.insert(MemoryRegion::new_with_offset_mapper( + paddr as GuestPhysAddr, + paddr + PAGE_SIZE * 3, + size, + MemFlags::READ | MemFlags::WRITE, + ))?; + + let paddr = 0x2800_3000 as HostPhysAddr; + let size = PAGE_SIZE; + self.gpm.insert(MemoryRegion::new_with_offset_mapper( + paddr as GuestPhysAddr, + paddr + PAGE_SIZE * 4, + size, + MemFlags::READ | MemFlags::WRITE, + ))?; + } info!("VM stage 2 memory set: {:#x?}", self.gpm); Ok(()) diff --git a/src/device/irqchip/aplic/mod.rs b/src/device/irqchip/aplic/mod.rs new file mode 100644 index 0000000..b174f1e --- /dev/null +++ b/src/device/irqchip/aplic/mod.rs @@ -0,0 +1,471 @@ + +use spin::RwLock; +use spin::Once; +use crate::{arch::cpu::ArchCpu, percpu::this_cpu_data, memory::GuestPhysAddr}; + +use riscv_decode::Instruction; +use fdt::Fdt; +use crate::zone::Zone; + +// S-mode interrupt delivery controller +const APLIC_S_IDC: usize = 0xd00_4000; +pub const APLIC_DOMAINCFG_BASE: usize = 0x0000; +pub const APLIC_SOURCECFG_BASE: usize = 0x0004; +pub const APLIC_SOURCECFG_TOP: usize = 0x1000; +pub const APLIC_MSIADDR_BASE: usize = 0x1BC8; +pub const APLIC_PENDING_BASE: usize = 0x1C00; +pub const APLIC_PENDING_TOP: usize = 0x1C80; +pub const APLIC_CLRIP_BASE: usize = 0x1D00; +pub const APLIC_ENABLE_BASE: usize = 0x1E00; +pub const APLIC_ENABLE_TOP: usize = 0x1E7C; +pub const APLIC_ENABLE_NUM: usize = 0x1EDC; +pub const APLIC_CLRIE_BASE: usize = 0x1F00; +pub const APLIC_CLRIE_NUM_BASE: usize = 0x1FDC; +pub const APLIC_IPNUM_LE_BASE: usize = 0x2000; +pub const APLIC_TARGET_BASE: usize = 0x3004; +pub const APLIC_IDC_BASE: usize = 0x4000; + +#[repr(u32)] +#[allow(dead_code)] +pub enum SourceModes { + Inactive = 0, + Detached = 1, + RisingEdge = 4, + FallingEdge = 5, + LevelHigh = 6, + LevelLow = 7, +} + +// offset size register name +// 0x0000 4 bytes domaincfg +// 0x0004 4 bytes sourcecfg[1] +// 0x0008 4 bytes sourcecfg[2] +// . . . . . . +// 0x0FFC 4 bytes sourcecfg[1023] +// 0x1BC0 4 bytes mmsiaddrcfg (machine-level interrupt domains only) +// 0x1BC4 4 bytes mmsiaddrcfgh ” +// 0x1BC8 4 bytes smsiaddrcfg ” +// 0x1BCC 4 bytes smsiaddrcfgh ” +// 0x1C00 4 bytes setip[0] +// 0x1C04 4 bytes setip[1] +// . . . . . . +// 0x1C7C 4 bytes setip[31] +// 0x1CDC 4 bytes setipnum +// 0x1D00 4 bytes in clrip[0] +// 0x1D04 4 bytes in clrip[1] +// . . . . . . +// 0x1D7C 4 bytes in clrip[31] +// 0x1DDC 4 bytes clripnum +// 0x1E00 4 bytes setie[0] +// 0x1E04 4 bytes setie[1] +// . . . . . . +// 0x1E7C 4 bytes setie[31] +// 0x1EDC 4 bytes setienum +// 0x1F00 4 bytes clrie[0] +// 0x1F04 4 bytes clrie[1] +// . . . . . . +// 0x1F7C 4 bytes clrie[31] +// 0x1FDC 4 bytes clrienum +// 0x2000 4 bytes setipnum le +// 0x2004 4 bytes setipnum be +// 0x3000 4 bytes genmsi +// 0x3004 4 bytes target[1] +// 0x3008 4 bytes target[2] +// . . . . . . +// 0x3FFC 4 bytes target[1023] + +pub fn primary_init_early(host_fdt: &Fdt) { + let aplic_debug = host_fdt.find_node("/soc/aplic").unwrap(); + init_aplic( + aplic_debug.reg().unwrap().next().unwrap().starting_address as usize, + aplic_debug.reg().unwrap().next().unwrap().size.unwrap(), + ); +} +pub fn primary_init_late() { + //nothing to do +} +pub fn percpu_init() { + //nothing to do +} +pub fn inject_irq(_irq: usize, is_hardware: bool) { + //nothing to do +} +pub static APLIC: Once> = Once::new(); +pub fn host_aplic<'a>() -> &'a RwLock { + APLIC.get().expect("Uninitialized hypervisor aplic!") +} + +#[repr(C)] +pub struct Aplic { + pub base: usize, + pub size: usize, +} + +#[allow(dead_code)] +impl Aplic { + pub fn new(base: usize, size: usize) -> Self { + Self { + base, + size, + } + } + pub fn set_domaincfg(&self, bigendian: bool, msimode: bool, enabled: bool){ + let enabled = u32::from(enabled); + let msimode = u32::from(msimode); + let bigendian = u32::from(bigendian); + let addr = self.base + APLIC_DOMAINCFG_BASE; + let bigendian = 0 ; + let src = (enabled << 8) | (msimode << 2) | bigendian; + unsafe { + core::ptr::write_volatile(addr as *mut u32, src); + } + } + pub fn read_domaincfg(&self) -> u32{ + let addr = self.base + APLIC_DOMAINCFG_BASE; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn get_msimode(&self) -> bool{ + let addr = self.base + APLIC_DOMAINCFG_BASE; + let value= unsafe { core::ptr::read_volatile(addr as *const u32) }; + ((value >> 2) & 0b11) != 0 + } + pub fn set_sourcecfg(&self, irq: u32, mode: SourceModes){ + assert!(irq > 0 && irq < 1024); + let addr = self.base + APLIC_SOURCECFG_BASE + (irq as usize - 1) * 4; + let src = mode as u32; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + } + } + pub fn set_sourcecfg_delegate(&self, irq: u32, child: u32){ + assert!(irq > 0 && irq < 1024); + let addr = self.base + APLIC_SOURCECFG_BASE + (irq as usize - 1) * 4; + let src = 1 << 10 | child & 0x3ff; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + } + } + pub fn read_sourcecfg(&self, irq: u32) -> u32{ + assert!(irq > 0 && irq < 1024); + let addr = self.base + APLIC_SOURCECFG_BASE + (irq as usize - 1) * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn set_msiaddr(&self, address: usize){ + let addr = self.base + APLIC_MSIADDR_BASE; + let src = (address >> 12) as u32; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + core:: ptr::write_volatile((addr + 4) as *mut u32, 0); + } + } + pub fn read_pending(&self, irqidx: usize) -> u32{ + assert!(irqidx < 32); + let addr = self.base + APLIC_PENDING_BASE + irqidx * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn read_clr_pending(&self, irqidx: usize) -> u32{ + assert!(irqidx < 32); + let addr = self.base + APLIC_CLRIP_BASE + irqidx * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn set_pending(&self, irqidx: usize, value: u32, pending: bool){ + assert!(irqidx < 32); + let addr = self.base + APLIC_PENDING_BASE + irqidx * 4; + let clr_addr = self.base + APLIC_CLRIP_BASE + irqidx * 4; + if pending { + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, value); + } + } else { + unsafe{ + core:: ptr::write_volatile(clr_addr as *mut u32, value); + } + } + } + pub fn read_in_clrip(&self, irqidx: usize) -> u32{ + assert!(irqidx < 32); + let addr = self.base + APLIC_CLRIP_BASE + irqidx * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn read_enable(&self, irqidx: usize) -> u32{ + assert!(irqidx < 32); + let addr = self.base + APLIC_ENABLE_BASE + irqidx * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn read_clr_enable(&self, irqidx: usize) -> u32{ + assert!(irqidx < 32); + let addr = self.base + APLIC_CLRIE_BASE + irqidx * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn set_enable(&self, irqidx: usize, value: u32, enabled: bool){ + assert!(irqidx < 32); + let addr = self.base + APLIC_ENABLE_BASE + irqidx * 4; + let clr_addr = self.base + APLIC_CLRIE_BASE + irqidx * 4; + if enabled { + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, value); + } + } else { + unsafe{ + core:: ptr::write_volatile(clr_addr as *mut u32, value); + } + } + } + pub fn set_enable_num(&self, value: u32){ + let addr = self.base + APLIC_ENABLE_NUM; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, value); + } + } + pub fn set_clr_ienum(&self, value: u32){ + let addr = self.base + APLIC_CLRIE_NUM_BASE; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, value); + } + } + pub fn set_ipnum_le(&self, value: u32){ + let addr = self.base + APLIC_IPNUM_LE_BASE; + // let value_le = u32::from_le_bytes(value.to_be_bytes()); + debug!("value:0x{:08x}", value); + // debug!("value_le:0x{:08x}", value_le); + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, value); + } + } + pub fn set_target_msi(&self, irq: u32, hart: u32, guest: u32, eiid: u32){ + let addr = self.base + APLIC_TARGET_BASE + (irq as usize - 1) * 4; + let src = (hart << 18) | (guest << 12) | eiid; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + } + } + pub fn set_target_direct(&self, irq: u32, hart: u32, prio: u32){ + let addr = self.base + APLIC_TARGET_BASE + (irq as usize - 1) * 4; + let src = (hart << 18) | (prio & 0xFF); + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + } + } +} + +pub fn vaplic_emul_handler( + current_cpu: &mut ArchCpu, + addr: GuestPhysAddr, + inst: Instruction, +) { + let host_aplic = host_aplic(); + let offset = addr.wrapping_sub(host_aplic.read().base); + if offset >= APLIC_DOMAINCFG_BASE && offset < APLIC_SOURCECFG_BASE { + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; // 要写入的 value + let enabled = ((value >> 8) & 0x1) != 0; // IE + let msimode = ((value >> 2) & 0b1) != 0; // DM / MSI + let bigendian = (value & 0b1) != 0; // 大小端 + host_aplic.write().set_domaincfg(bigendian, msimode, enabled); + debug!( + "APLIC set domaincfg write addr@{:#x} bigendian {} msimode {} enabled {}", + addr, bigendian, msimode, enabled + ); + } + Instruction::Lw(i) => { // 直接读取对应的内容 + let value = host_aplic.read().read_domaincfg(); + current_cpu.x[i.rd() as usize] = value as usize; + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } + else if offset >= APLIC_SOURCECFG_BASE && offset < APLIC_SOURCECFG_TOP { + //sourcecfg + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + let irq = ((offset - APLIC_SOURCECFG_BASE) / 4) + 1; + if (value >> 10) & 0b1 == 1 { + //delegate + let child = value & 0x3ff; + host_aplic.write().set_sourcecfg_delegate(irq as u32, child); + debug!( + "APLIC set sourcecfg_delegate write addr@{:#x} irq {} child {}", + addr, + irq, + child + ); + } else { + let mode = match value { + 0 => SourceModes::Inactive, + 1 => SourceModes::Detached, + 4 => SourceModes::RisingEdge, + 5 => SourceModes::FallingEdge, + 6 => SourceModes::LevelHigh, + 7 => SourceModes::LevelLow, + _ => panic!("Unknown sourcecfg mode"), + }; + host_aplic.write().set_sourcecfg(irq as u32, mode); + debug!( + "APLIC set sourcecfg write addr@{:#x} irq {} mode {}", + addr, + irq, + value + ); + } + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } else if offset >= APLIC_MSIADDR_BASE && offset <= 0x1BCC { + // msia + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + let address = (value as usize) << 12; + host_aplic.write().set_msiaddr(address); + debug!( + "APLIC set msiaddr write addr@{:#x} address {}", + addr, address + ); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } else if offset >= APLIC_PENDING_BASE && offset < APLIC_PENDING_TOP { + // pending + panic!("setip Unexpected instruction {:?}", inst); + } + // setipnum 区域 0x1CDC - 0x1CE0 + else if offset >= 0x1CDC && offset < 0x1CE0 { + panic!("setipnum Unexpected instruction {:?}", inst) + } + else if offset >= APLIC_CLRIP_BASE && offset < 0x1D80 { + // panic!("addr@{:#x} in_clrip Unexpected instruction {:?}", offset ,inst); + match inst { + Instruction::Lw(i) => { + let irqidx = (offset - APLIC_CLRIP_BASE) / 4; + let value = host_aplic.read().read_in_clrip(irqidx); + current_cpu.x[i.rd() as usize] = value as usize; + debug!( + "APLIC read in clrip addr@{:#x} irqidx {} value {}", + addr, irqidx, value + ); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } + // clripnum 区域 + else if offset >= 0x1DDC && offset < 0x1DE0 { + panic!("clripnum Unexpected instruction {:?}", inst) + } + // setie + else if offset >= APLIC_ENABLE_BASE && offset < 0x1E80 { + panic!("setie Unexpected instruction {:?}", inst); + } + else if offset >= APLIC_ENABLE_NUM && offset < 0x1EE0 { + // enablenum + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + host_aplic.write().set_enable_num(value); + debug!( + "APLIC set enablenum write addr@{:#x} value {}", + addr, value + ); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } else if offset >= APLIC_CLRIE_BASE && offset < 0x1FDC { + // clrenable + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + let irqidx = (offset - APLIC_CLRIE_BASE) / 4; + host_aplic.write().set_enable(irqidx, value, false); + debug!( + "APLIC set clr_enable write addr@{:#x} irqidx {} value {}", + addr, irqidx, value + ); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } + // clrienum + else if offset >= 0x1FDC && offset < 0x1FE0 { + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + host_aplic.write().set_clr_ienum(value); + debug!( + "APLIC set set_clr_ienum write addr@{:#x} value@{:#x}", + offset, value + ); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + + } + // setipnum_le + else if offset >= 0x2000 && offset < 0x2004 { + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + host_aplic.write().set_ipnum_le(value); + debug!( + "APLIC set set_ipnum_le write addr@{:#x} value@{:#x}", + offset, value + ); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } + // setipnum_be + else if offset >= 0x2004 && offset < 0x2008 { + panic!("setipnum_be Unexpected instruction {:?}", inst) + } + // genmsi + else if offset >= 0x3000 && offset < 0x3004 { + panic!("genmsi Unexpected instruction {:?}", inst) + } + else if offset >= APLIC_TARGET_BASE && offset < APLIC_IDC_BASE { + // target + match inst { + Instruction::Sw(i) => { + let first_cpu = this_cpu_data() + .zone + .as_ref() + .unwrap() + .read() + .cpu_set + .first_cpu() + .unwrap(); + let value = current_cpu.x[i.rs2() as usize] as u32; + let irq = ((offset - APLIC_TARGET_BASE) / 4) as u32 + 1; + let hart = ((value >> 18) & 0x3F) + first_cpu as u32; + if host_aplic.read().get_msimode() { + let guest = ((value >> 12) & 0x3F) + 1; + let eiid = value & 0xFFF; + host_aplic.write().set_target_msi(irq, hart, guest, eiid); + debug!( + "APLIC set msi target write addr@{:#x} irq {} hart {} guest {} eiid {}", + addr, irq, hart, guest, eiid + ); + } else { + let prio = value & 0xFF; + host_aplic.write().set_target_direct(irq, hart, prio); + debug!( + "APLIC set direct target write addr@{:#x} irq {} hart {} prio {}", + addr, irq, hart, prio + ); + } + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } else { + panic!("Invalid address: {:#x}", addr); + } +} +pub fn init_aplic(aplic_base: usize, aplic_size: usize) { + let aplic = Aplic::new(aplic_base, aplic_size); + APLIC.call_once(|| RwLock::new(aplic)); +} +impl Zone { + pub fn arch_irqchip_reset(&self) { + //TODO + } +} \ No newline at end of file diff --git a/src/device/irqchip/mod.rs b/src/device/irqchip/mod.rs index 182ced4..97e8495 100644 --- a/src/device/irqchip/mod.rs +++ b/src/device/irqchip/mod.rs @@ -2,10 +2,20 @@ pub mod gicv3; #[cfg(target_arch = "riscv64")] +#[cfg(feature = "plic")] pub mod plic; +#[cfg(target_arch = "riscv64")] +#[cfg(feature = "aia")] +pub mod aplic; + #[cfg(target_arch = "aarch64")] pub use gicv3::{inject_irq, percpu_init, primary_init_early, primary_init_late}; #[cfg(target_arch = "riscv64")] +#[cfg(feature = "plic")] pub use plic::{inject_irq, percpu_init, primary_init_early, primary_init_late}; + +#[cfg(target_arch = "riscv64")] +#[cfg(feature = "aia")] +pub use aplic::{inject_irq, percpu_init, primary_init_early, primary_init_late}; diff --git a/src/main.rs b/src/main.rs index fe079bc..427f5f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -96,6 +96,7 @@ fn primary_init_early(dtb: usize) { let host_fdt = unsafe { fdt::Fdt::from_ptr(dtb as *const u8) }.unwrap(); device::irqchip::primary_init_early(&host_fdt); + // #[cfg(feature = "plic")] crate::arch::mm::init_hv_page_table(&host_fdt).unwrap(); info!("Primary CPU init hv page table OK."); @@ -114,6 +115,7 @@ fn percpu_hv_pt_install(cpu: &mut PerCpu) { if cpu.zone.is_none() { warn!("zone is not created for cpu {}", cpu.id); } + #[cfg(feature = "plic")] unsafe { memory::hv_page_table().read().activate(); }; diff --git a/src/memory/mod.rs b/src/memory/mod.rs index e602cf7..e29a89a 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -36,8 +36,9 @@ bitflags! { } /// Page table used for hypervisor. +// #[cfg(feature = "plic")] pub static HV_PT: Once>> = Once::new(); - +// #[cfg(feature = "plic")] pub fn hv_page_table<'a>() -> &'a RwLock> { HV_PT.get().expect("Uninitialized hypervisor page table!") } From dca03cb2757ede3afff4fdb1e9ef5bdcc2803872 Mon Sep 17 00:00:00 2001 From: dorso <2434317248@qq.com> Date: Mon, 22 Jul 2024 15:30:14 +0800 Subject: [PATCH 2/6] add imsic --- .gitignore | 1 + images/riscv64/devicetree/linux1-aia.dts | 2 +- images/riscv64/devicetree/linux1.dts | 2 +- scripts/qemu-riscv64.mk | 4 +- src/device/irqchip/aia/aplic.rs | 519 +++++++++++++++++++++++ src/device/irqchip/aia/imsic.rs | 60 +++ 6 files changed, 584 insertions(+), 4 deletions(-) create mode 100644 src/device/irqchip/aia/aplic.rs create mode 100644 src/device/irqchip/aia/imsic.rs diff --git a/.gitignore b/.gitignore index a0bd4f1..98dde9b 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ Module.symvers modules.order driver/main.ko .gdb_history +hvisor.md \ No newline at end of file diff --git a/images/riscv64/devicetree/linux1-aia.dts b/images/riscv64/devicetree/linux1-aia.dts index 30ef0c5..c5ab3cb 100644 --- a/images/riscv64/devicetree/linux1-aia.dts +++ b/images/riscv64/devicetree/linux1-aia.dts @@ -55,7 +55,7 @@ memory@83000000 { device_type = "memory"; - reg = <0x0 0x83000000 0x0 0x25000000>; + reg = <0x0 0x83000000 0x0 0x1D000000>; }; reserved-memory { diff --git a/images/riscv64/devicetree/linux1.dts b/images/riscv64/devicetree/linux1.dts index 7130294..6de3ae4 100644 --- a/images/riscv64/devicetree/linux1.dts +++ b/images/riscv64/devicetree/linux1.dts @@ -57,7 +57,7 @@ memory@83000000 { device_type = "memory"; - reg = <0x0 0x83000000 0x0 0x25000000>; + reg = <0x0 0x83000000 0x0 0x1D000000>; }; reserved-memory { diff --git a/scripts/qemu-riscv64.mk b/scripts/qemu-riscv64.mk index 35e5045..b5da06f 100644 --- a/scripts/qemu-riscv64.mk +++ b/scripts/qemu-riscv64.mk @@ -9,13 +9,13 @@ FSIMG2 := $(image_dir)/virtdisk/rootfs-busybox.qcow2 # HVISOR ENTRY HVISOR_ENTRY_PA := 0x80200000 # plic -zone0_kernel := $(image_dir)/kernel/Image-aia +zone0_kernel := $(image_dir)/kernel/Image-aia-6.10 zone0_dtb := $(image_dir)/devicetree/linux1.dtb # zone1_kernel := $(image_dir)/kernel/Image # zone1_dtb := $(image_dir)/devicetree/linux2.dtb # aia -zone0_aia_kernel := $(image_dir)/kernel/Image-aia +zone0_aia_kernel := $(image_dir)/kernel/Image-aia-6.10 zone0_aia_dtb := $(image_dir)/devicetree/linux1-aia.dtb # zone1_aia_kernel := $(image_dir)/kernel/Image-aia # zone1_aia_dtb := $(image_dir)/devicetree/linux2-aia.dtb diff --git a/src/device/irqchip/aia/aplic.rs b/src/device/irqchip/aia/aplic.rs new file mode 100644 index 0000000..665e03c --- /dev/null +++ b/src/device/irqchip/aia/aplic.rs @@ -0,0 +1,519 @@ + +use riscv::use_sv32; +use spin::RwLock; +use spin::Once; +use crate::count; +use crate::device::irqchip::aia::imsic::imsic_trigger; +use crate::{arch::cpu::ArchCpu, percpu::this_cpu_data, memory::GuestPhysAddr}; +use riscv_decode::Instruction; +use fdt::Fdt; +use crate::zone::Zone; + +// S-mode interrupt delivery controller +const APLIC_S_IDC: usize = 0xd00_4000; +pub const APLIC_DOMAINCFG_BASE: usize = 0x0000; +pub const APLIC_SOURCECFG_BASE: usize = 0x0004; +pub const APLIC_SOURCECFG_TOP: usize = 0x1000; +pub const APLIC_MSIADDR_BASE: usize = 0x1BC8; +pub const APLIC_PENDING_BASE: usize = 0x1C00; +pub const APLIC_PENDING_TOP: usize = 0x1C80; +pub const APLIC_CLRIP_BASE: usize = 0x1D00; +pub const APLIC_ENABLE_BASE: usize = 0x1E00; +pub const APLIC_ENABLE_TOP: usize = 0x1E7C; +pub const APLIC_ENABLE_NUM: usize = 0x1EDC; +pub const APLIC_CLRIE_BASE: usize = 0x1F00; +pub const APLIC_CLRIE_NUM_BASE: usize = 0x1FDC; +pub const APLIC_IPNUM_LE_BASE: usize = 0x2000; +pub const APLIC_TARGET_BASE: usize = 0x3004; +pub const APLIC_IDC_BASE: usize = 0x4000; + +#[repr(u32)] +#[allow(dead_code)] +pub enum SourceModes { + Inactive = 0, + Detached = 1, + RisingEdge = 4, + FallingEdge = 5, + LevelHigh = 6, + LevelLow = 7, +} + +// offset size register name +// 0x0000 4 bytes domaincfg +// 0x0004 4 bytes sourcecfg[1] +// 0x0008 4 bytes sourcecfg[2] +// . . . . . . +// 0x0FFC 4 bytes sourcecfg[1023] +// 0x1BC0 4 bytes mmsiaddrcfg (machine-level interrupt domains only) +// 0x1BC4 4 bytes mmsiaddrcfgh ” +// 0x1BC8 4 bytes smsiaddrcfg ” +// 0x1BCC 4 bytes smsiaddrcfgh ” +// 0x1C00 4 bytes setip[0] +// 0x1C04 4 bytes setip[1] +// . . . . . . +// 0x1C7C 4 bytes setip[31] +// 0x1CDC 4 bytes setipnum +// 0x1D00 4 bytes in clrip[0] +// 0x1D04 4 bytes in clrip[1] +// . . . . . . +// 0x1D7C 4 bytes in clrip[31] +// 0x1DDC 4 bytes clripnum +// 0x1E00 4 bytes setie[0] +// 0x1E04 4 bytes setie[1] +// . . . . . . +// 0x1E7C 4 bytes setie[31] +// 0x1EDC 4 bytes setienum +// 0x1F00 4 bytes clrie[0] +// 0x1F04 4 bytes clrie[1] +// . . . . . . +// 0x1F7C 4 bytes clrie[31] +// 0x1FDC 4 bytes clrienum +// 0x2000 4 bytes setipnum le +// 0x2004 4 bytes setipnum be +// 0x3000 4 bytes genmsi +// 0x3004 4 bytes target[1] +// 0x3008 4 bytes target[2] +// . . . . . . +// 0x3FFC 4 bytes target[1023] + +pub fn primary_init_early(host_fdt: &Fdt) { + let aplic_warn = host_fdt.find_node("/soc/aplic").unwrap(); + init_aplic( + aplic_warn.reg().unwrap().next().unwrap().starting_address as usize, + aplic_warn.reg().unwrap().next().unwrap().size.unwrap(), + ); +} +pub fn primary_init_late() { + //nothing to do +} +pub fn percpu_init() { + //nothing to do +} +pub fn inject_irq(_irq: usize, is_hardware: bool) { + //nothing to do +} +pub static APLIC: Once> = Once::new(); +pub fn host_aplic<'a>() -> &'a RwLock { + APLIC.get().expect("Uninitialized hypervisor aplic!") +} + +#[repr(C)] +pub struct Aplic { + pub base: usize, + pub size: usize, +} + +#[allow(dead_code)] +impl Aplic { + pub fn new(base: usize, size: usize) -> Self { + Self { + base, + size, + } + } + pub fn set_domaincfg(&self, bigendian: bool, msimode: bool, enabled: bool){ + let enabled = u32::from(enabled); + let msimode = u32::from(msimode); + let bigendian = u32::from(bigendian); + let addr = self.base + APLIC_DOMAINCFG_BASE; + let bigendian = 0 ; + let src = (enabled << 8) | (msimode << 2) | bigendian; + unsafe { + core::ptr::write_volatile(addr as *mut u32, src); + } + } + pub fn read_domaincfg(&self) -> u32{ + let addr = self.base + APLIC_DOMAINCFG_BASE; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn get_msimode(&self) -> bool{ + let addr = self.base + APLIC_DOMAINCFG_BASE; + let value= unsafe { core::ptr::read_volatile(addr as *const u32) }; + ((value >> 2) & 0b11) != 0 + } + pub fn set_sourcecfg(&self, irq: u32, mode: SourceModes){ + assert!(irq > 0 && irq < 1024); + let addr = self.base + APLIC_SOURCECFG_BASE + (irq as usize - 1) * 4; + let src = mode as u32; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + } + } + pub fn set_sourcecfg_delegate(&self, irq: u32, child: u32){ + assert!(irq > 0 && irq < 1024); + let addr = self.base + APLIC_SOURCECFG_BASE + (irq as usize - 1) * 4; + let src = 1 << 10 | child & 0x3ff; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + } + } + pub fn read_sourcecfg(&self, irq: u32) -> u32{ + assert!(irq > 0 && irq < 1024); + let addr = self.base + APLIC_SOURCECFG_BASE + (irq as usize - 1) * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn set_msiaddr(&self, address: usize){ + let addr = self.base + APLIC_MSIADDR_BASE; + let src = (address >> 12) as u32; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + core:: ptr::write_volatile((addr + 4) as *mut u32, 0); + } + } + pub fn read_pending(&self, irqidx: usize) -> u32{ + assert!(irqidx < 32); + let addr = self.base + APLIC_PENDING_BASE + irqidx * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn read_clr_pending(&self, irqidx: usize) -> u32{ + assert!(irqidx < 32); + let addr = self.base + APLIC_CLRIP_BASE + irqidx * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn set_pending(&self, irqidx: usize, src: u32, pending: bool){ + assert!(irqidx < 32); + let addr = self.base + APLIC_PENDING_BASE + irqidx * 4; + let clr_addr = self.base + APLIC_CLRIP_BASE + irqidx * 4; + if pending { + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + } + } else { + unsafe{ + core:: ptr::write_volatile(clr_addr as *mut u32, src); + } + } + } + pub fn read_in_clrip(&self, irqidx: usize) -> u32{ + assert!(irqidx < 32); + let addr = self.base + APLIC_CLRIP_BASE + irqidx * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn read_enable(&self, irqidx: usize) -> u32{ + assert!(irqidx < 32); + let addr = self.base + APLIC_ENABLE_BASE + irqidx * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn read_clr_enable(&self, irqidx: usize) -> u32{ + assert!(irqidx < 32); + let addr = self.base + APLIC_CLRIE_BASE + irqidx * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn set_enable(&self, irqidx: usize, value: u32, enabled: bool){ + assert!(irqidx < 32); + let addr = self.base + APLIC_ENABLE_BASE + irqidx * 4; + let clr_addr = self.base + APLIC_CLRIE_BASE + irqidx * 4; + if enabled { + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, value); + } + } else { + unsafe{ + core:: ptr::write_volatile(clr_addr as *mut u32, value); + } + } + } + pub fn set_enable_num(&self, value: u32){ + let addr = self.base + APLIC_ENABLE_NUM; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, value); + } + } + pub fn set_clr_ienum(&self, value: u32){ + let addr = self.base + APLIC_CLRIE_NUM_BASE; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, value); + } + } + // pub fn set_ipnum_le(&self, value: u32){ + // let addr = self.base + APLIC_IPNUM_LE_BASE; + // // let value_le = u32::from_le_bytes(value.to_be_bytes()); + // // warn!("value_le:0x{:08x}", value_le); + // unsafe{ + // core:: ptr::write_volatile(addr as *mut u32, value); + // } + // } + pub fn set_target_msi(&self, irq: u32, hart: u32, guest: u32, eiid: u32){ + let addr = self.base + APLIC_TARGET_BASE + (irq as usize - 1) * 4; + let src = (hart << 18) | (guest << 12) | eiid; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + } + } + pub fn set_target_direct(&self, irq: u32, hart: u32, prio: u32){ + let addr = self.base + APLIC_TARGET_BASE + (irq as usize - 1) * 4; + let src = (hart << 18) | (prio & 0xFF); + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + } + } + pub fn get_target_guest(&self, irq: u32) -> (u32, u32, u32) { + let addr = self.base + APLIC_TARGET_BASE + (irq as usize - 1) * 4; + unsafe { + let src = core::ptr::read_volatile(addr as *const u32); + let hart = (src >> 18) & 0x3F; + let guest = (src >> 12) & 0x3F; + let eiid = src & 0xFFF; + (hart, guest, eiid) + } + } +} +pub fn vaplic_emul_handler( + current_cpu: &mut ArchCpu, + addr: GuestPhysAddr, + inst: Instruction, +) { + let host_aplic = host_aplic(); + let offset = addr.wrapping_sub(host_aplic.read().base); + if offset >= APLIC_DOMAINCFG_BASE && offset < APLIC_SOURCECFG_BASE { + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; // 要写入的 value + let enabled = ((value >> 8) & 0x1) != 0; // IE + let msimode = ((value >> 2) & 0b1) != 0; // DM / MSI + let bigendian = (value & 0b1) != 0; // 大小端 + host_aplic.write().set_domaincfg(bigendian, msimode, enabled); + warn!( + "APLIC set domaincfg write addr@{:#x} bigendian {} msimode {} enabled {}", + addr, bigendian, msimode, enabled + ); + } + Instruction::Lw(i) => { // 直接读取对应的内容 + let value = host_aplic.read().read_domaincfg(); + current_cpu.x[i.rd() as usize] = value as usize; + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } + else if offset >= APLIC_SOURCECFG_BASE && offset < APLIC_SOURCECFG_TOP { + //sourcecfg + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + let irq = ((offset - APLIC_SOURCECFG_BASE) / 4) + 1; + if (value >> 10) & 0b1 == 1 { + //delegate + let child = value & 0x3ff; + host_aplic.write().set_sourcecfg_delegate(irq as u32, child); + warn!( + "APLIC set sourcecfg_delegate write addr@{:#x} irq {} child {}", + addr, + irq, + child + ); + } else { + let mode = match value { + 0 => SourceModes::Inactive, + 1 => SourceModes::Detached, + 4 => SourceModes::RisingEdge, + 5 => SourceModes::FallingEdge, + 6 => SourceModes::LevelHigh, + 7 => SourceModes::LevelLow, + _ => panic!("Unknown sourcecfg mode"), + }; + host_aplic.write().set_sourcecfg(irq as u32, mode); + warn!( + "APLIC set sourcecfg write addr@{:#x} irq {} mode {}", + addr, + irq, + value + ); + } + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } else if offset >= APLIC_MSIADDR_BASE && offset <= 0x1BCC { + // msia + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + let address = (value as usize) << 12; + host_aplic.write().set_msiaddr(address); + warn!( + "APLIC set msiaddr write addr@{:#x} address {}", + addr, address + ); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } else if offset >= APLIC_PENDING_BASE && offset < APLIC_PENDING_TOP { + // pending + panic!("setip Unexpected instruction {:?}", inst); + } + // setipnum 区域 0x1CDC - 0x1CE0 + else if offset >= 0x1CDC && offset < 0x1CE0 { + panic!("setipnum Unexpected instruction {:?}", inst) + } + else if offset >= APLIC_CLRIP_BASE && offset < 0x1D80 { + // panic!("addr@{:#x} in_clrip Unexpected instruction {:?}", offset ,inst); + match inst { + Instruction::Lw(i) => { + let irqidx = (offset - APLIC_CLRIP_BASE) / 4; + let value = host_aplic.read().read_in_clrip(irqidx); + current_cpu.x[i.rd() as usize] = value as usize; + warn!( + "APLIC read in clrip addr@{:#x} irqidx {} value {}", + addr, irqidx, value + ); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } + // clripnum 区域 + else if offset >= 0x1DDC && offset < 0x1DE0 { + panic!("clripnum Unexpected instruction {:?}", inst) + } + // setie + else if offset >= APLIC_ENABLE_BASE && offset < 0x1E80 { + panic!("setie Unexpected instruction {:?}", inst); + } + else if offset >= APLIC_ENABLE_NUM && offset < 0x1EE0 { + // enablenum + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + let irqidx = value as usize / 32; + let irqbit = value as usize % 32; + if (host_aplic.read().read_enable(irqidx) >> irqbit) & 0b1 != 1 { + warn!( + "APLIC enable value {} not set",value + ); + host_aplic.write().set_enable(irqidx, 1 << irqbit, true); + } + if (host_aplic.read().read_enable(irqidx) >> irqbit) & 0b1 != 1 { + warn!( + "APLIC enable value {} not set",value + ); + } else { + warn!( + "APLIC enable value {} set now",value + ); + } + warn!( + "APLIC set enablenum write addr@{:#x} value {}", + addr, value + ); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } else if offset >= APLIC_CLRIE_BASE && offset < 0x1FDC { + // clrenable + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + let irqidx = (offset - APLIC_CLRIE_BASE) / 4; + host_aplic.write().set_enable(irqidx, value, false); + warn!( + "APLIC set clr_enable write addr@{:#x} irqidx {} value {}", + addr, irqidx, value + ); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } + // clrienum + else if offset >= 0x1FDC && offset < 0x1FE0 { + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + host_aplic.write().set_clr_ienum(value); + warn!( + "APLIC set set_clr_ienum write addr@{:#x} value@{:#x}", + offset, value + ); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + + } + // setipnum_le + else if offset >= 0x2000 && offset < 0x2004 { + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + let irqidx = value as usize / 32; + let irqbit = value as usize % 32; + if (host_aplic.read().read_pending(irqidx) >> irqbit) & 0b1 != 1 { + warn!("not set"); + host_aplic.write().set_pending(irqidx, 1 << irqbit, true); + let (hart, guest, eiid) = host_aplic.read().get_target_guest(value); + // imsic_trigger(hart, guest, eiid); + } + if (host_aplic.read().read_pending(irqidx) >> irqbit) & 0b1 != 1 { + warn!( + "APLIC pending value {} not set",value + ); + } else { + warn!( + "APLIC pending value {} set now",value + ); + } + unsafe { + count = count +1 ; + if count == 2000 { + warn!( + "APLIC set set_ipnum_le write addr@{:#x} value@{:#x}", + offset, value + ); + count = 0; + } + } + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } + // setipnum_be + else if offset >= 0x2004 && offset < 0x2008 { + panic!("setipnum_be Unexpected instruction {:?}", inst) + } + // genmsi + else if offset >= 0x3000 && offset < 0x3004 { + panic!("genmsi Unexpected instruction {:?}", inst) + } + else if offset >= APLIC_TARGET_BASE && offset < APLIC_IDC_BASE { + // target + match inst { + Instruction::Sw(i) => { + let first_cpu = this_cpu_data() + .zone + .as_ref() + .unwrap() + .read() + .cpu_set + .first_cpu() + .unwrap(); + let value = current_cpu.x[i.rs2() as usize] as u32; + let irq = ((offset - APLIC_TARGET_BASE) / 4) as u32 + 1; + let hart = ((value >> 18) & 0x3F) + first_cpu as u32; + if host_aplic.read().get_msimode() { + let guest = ((value >> 12) & 0x3F) + 1; + let eiid = value & 0xFFF; + host_aplic.write().set_target_msi(irq, hart, guest, eiid); + warn!( + "APLIC set msi target write addr@{:#x} irq {} hart {} guest {} eiid {}", + addr, irq, hart, guest, eiid + ); + } else { + let prio = value & 0xFF; + host_aplic.write().set_target_direct(irq, hart, prio); + warn!( + "APLIC set direct target write addr@{:#x} irq {} hart {} prio {}", + addr, irq, hart, prio + ); + } + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } else { + panic!("Invalid address: {:#x}", addr); + } +} +pub fn init_aplic(aplic_base: usize, aplic_size: usize) { + let aplic = Aplic::new(aplic_base, aplic_size); + APLIC.call_once(|| RwLock::new(aplic)); +} +impl Zone { + pub fn arch_irqchip_reset(&self) { + //TODO + } +} \ No newline at end of file diff --git a/src/device/irqchip/aia/imsic.rs b/src/device/irqchip/aia/imsic.rs new file mode 100644 index 0000000..f44e7a4 --- /dev/null +++ b/src/device/irqchip/aia/imsic.rs @@ -0,0 +1,60 @@ +use crate::arch::csr::{write_csr ,read_csr ,CSR_VSISELECT ,CSR_VSIREG ,CSR_VSTOPI ,CSR_VSTOPEI}; +pub const IMSIC_VS: usize = 0x2800_1000; +const IMSIC_VS_HART_STRIDE: usize = 0x2000; + +const XLEN: usize = usize::BITS as usize; +const XLEN_STRIDE: usize = XLEN / 32; + +const EIP: usize = 0x80; + +pub const fn imsic_vs(hart: usize) -> usize { + IMSIC_VS + IMSIC_VS_HART_STRIDE * hart +} +fn imsic_write(reg: usize, val: usize) { + unsafe { + match reg { + CSR_VSISELECT => write_csr!(CSR_VSISELECT, val), + CSR_VSIREG => write_csr!(CSR_VSIREG, val), + CSR_VSTOPI => write_csr!(CSR_VSTOPI, val), + CSR_VSTOPEI => write_csr!(CSR_VSTOPEI, val), + _ => panic!("Unknown CSR {}", reg), + } + } +} + +// Read from an IMSIC CSR + +fn imsic_read(reg: usize) -> usize { + let ret: usize; + unsafe { + ret = match reg { + CSR_VSISELECT => read_csr!(CSR_VSISELECT), + CSR_VSIREG => read_csr!(CSR_VSIREG), + CSR_VSTOPI => read_csr!(CSR_VSTOPI), + CSR_VSTOPEI => read_csr!(CSR_VSTOPEI), + _ => panic!("Unknown CSR {}", reg), + } + } + ret +} +// VS-Mode IMSIC CSRs + + +pub fn imsic_trigger(hart: u32, guest: u32, eiid: u32) { + // let eipbyte = EIP + XLEN_STRIDE * irq / XLEN; + // let bit = irq % XLEN; + // imsic_write(CSR_VSISELECT, eipbyte); + // let reg = imsic_read(CSR_VSIREG); + // imsic_write(CSR_VSIREG, reg | 1 << bit); + if guest == 1{ + unsafe { + core::ptr::write_volatile(imsic_vs(hart as usize) as *mut u32, eiid); + } + } else { + panic!( + "Unknown imsic set hart {} guest {} eiid {}", + hart, guest, eiid + ); + } +} + From 1f23df4b39bcd8204ef8f06ec13a6cf2d1ff24fa Mon Sep 17 00:00:00 2001 From: dorso <2434317248@qq.com> Date: Fri, 26 Jul 2024 11:09:21 +0800 Subject: [PATCH 3/6] add aia --- .gitignore | 2 +- images/riscv64/devicetree/linux1-aia.dts | 2 +- src/arch/riscv64/csr.rs | 6 + src/arch/riscv64/trap.rs | 3 +- src/device/irqchip/aia/aplic.rs | 173 ++++----- src/device/irqchip/aia/mod.rs | 2 + src/device/irqchip/aplic/mod.rs | 471 ----------------------- src/device/irqchip/mod.rs | 4 +- src/main.rs | 1 - 9 files changed, 87 insertions(+), 577 deletions(-) create mode 100644 src/device/irqchip/aia/mod.rs delete mode 100644 src/device/irqchip/aplic/mod.rs diff --git a/.gitignore b/.gitignore index 98dde9b..4d9848e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/images/riscv64/opensbi-1.2 +/images/riscv64/opensbi* /target /qemu-test /test-img diff --git a/images/riscv64/devicetree/linux1-aia.dts b/images/riscv64/devicetree/linux1-aia.dts index c5ab3cb..8c47251 100644 --- a/images/riscv64/devicetree/linux1-aia.dts +++ b/images/riscv64/devicetree/linux1-aia.dts @@ -160,6 +160,6 @@ soc{ }; chosen { - bootargs = "root=/dev/vda rw earlycon console=ttyS0 ip=192.168.42.15"; + bootargs = "root=/dev/vda rw earlycon console=ttyS0"; }; }; \ No newline at end of file diff --git a/src/arch/riscv64/csr.rs b/src/arch/riscv64/csr.rs index 9f88ad5..33b4a08 100644 --- a/src/arch/riscv64/csr.rs +++ b/src/arch/riscv64/csr.rs @@ -42,6 +42,12 @@ pub const CSR_HENVCFGH: u64 = 0x61A; pub const CSR_STIMECMP: u64 = 0x14D; pub const CSR_STIMECMPH: u64 = 0x15D; +/* AIA Extension */ +pub const CSR_VSISELECT: usize = 0x250; +pub const CSR_VSIREG: usize = 0x251; +pub const CSR_VSTOPI: usize = 0xEB0; +pub const CSR_VSTOPEI: usize = 0x25C; + macro_rules! read_csr { ($csr_number:expr) => { { diff --git a/src/arch/riscv64/trap.rs b/src/arch/riscv64/trap.rs index efbcb71..82ce5db 100644 --- a/src/arch/riscv64/trap.rs +++ b/src/arch/riscv64/trap.rs @@ -5,7 +5,7 @@ use crate::arch::sbi::sbi_vs_handler; #[cfg(feature = "plic")] use crate::device::irqchip::plic::{host_plic, vplic_global_emul_handler, vplic_hart_emul_handler}; #[cfg(feature = "aia")] -use crate::device::irqchip::aplic::{host_aplic, vaplic_emul_handler}; +use crate::device::irqchip::aia::aplic::{host_aplic, vaplic_emul_handler}; use crate::event::check_events; use crate::memory::{GuestPhysAddr, HostPhysAddr}; use crate::platform::qemu_riscv64::*; @@ -256,6 +256,7 @@ pub fn handle_eirq(current_cpu: &mut ArchCpu) { unsafe { hvip::set_vseip() }; } #[cfg(feature = "aia")]{ + panic!("HS extensional interrupt") } } pub fn handle_ssi(current_cpu: &mut ArchCpu) { diff --git a/src/device/irqchip/aia/aplic.rs b/src/device/irqchip/aia/aplic.rs index 665e03c..ada816f 100644 --- a/src/device/irqchip/aia/aplic.rs +++ b/src/device/irqchip/aia/aplic.rs @@ -2,7 +2,6 @@ use riscv::use_sv32; use spin::RwLock; use spin::Once; -use crate::count; use crate::device::irqchip::aia::imsic::imsic_trigger; use crate::{arch::cpu::ArchCpu, percpu::this_cpu_data, memory::GuestPhysAddr}; use riscv_decode::Instruction; @@ -16,7 +15,8 @@ pub const APLIC_SOURCECFG_BASE: usize = 0x0004; pub const APLIC_SOURCECFG_TOP: usize = 0x1000; pub const APLIC_MSIADDR_BASE: usize = 0x1BC8; pub const APLIC_PENDING_BASE: usize = 0x1C00; -pub const APLIC_PENDING_TOP: usize = 0x1C80; +pub const APLIC_PENDING_TOP: usize = 0x1C7C; +pub const APLIC_IPNUM_BASE: usize = 0x1CDC; pub const APLIC_CLRIP_BASE: usize = 0x1D00; pub const APLIC_ENABLE_BASE: usize = 0x1E00; pub const APLIC_ENABLE_TOP: usize = 0x1E7C; @@ -77,10 +77,10 @@ pub enum SourceModes { // 0x3FFC 4 bytes target[1023] pub fn primary_init_early(host_fdt: &Fdt) { - let aplic_warn = host_fdt.find_node("/soc/aplic").unwrap(); + let aplic_info = host_fdt.find_node("/soc/aplic").unwrap(); init_aplic( - aplic_warn.reg().unwrap().next().unwrap().starting_address as usize, - aplic_warn.reg().unwrap().next().unwrap().size.unwrap(), + aplic_info.reg().unwrap().next().unwrap().starting_address as usize, + aplic_info.reg().unwrap().next().unwrap().size.unwrap(), ); } pub fn primary_init_late() { @@ -122,7 +122,7 @@ impl Aplic { core::ptr::write_volatile(addr as *mut u32, src); } } - pub fn read_domaincfg(&self) -> u32{ + pub fn get_domaincfg(&self) -> u32{ let addr = self.base + APLIC_DOMAINCFG_BASE; unsafe { core::ptr::read_volatile(addr as *const u32) } } @@ -147,7 +147,7 @@ impl Aplic { core:: ptr::write_volatile(addr as *mut u32, src); } } - pub fn read_sourcecfg(&self, irq: u32) -> u32{ + pub fn get_sourcecfg(&self, irq: u32) -> u32{ assert!(irq > 0 && irq < 1024); let addr = self.base + APLIC_SOURCECFG_BASE + (irq as usize - 1) * 4; unsafe { core::ptr::read_volatile(addr as *const u32) } @@ -160,17 +160,17 @@ impl Aplic { core:: ptr::write_volatile((addr + 4) as *mut u32, 0); } } - pub fn read_pending(&self, irqidx: usize) -> u32{ + pub fn get_ip(&self, irqidx: usize) -> u32{ assert!(irqidx < 32); let addr = self.base + APLIC_PENDING_BASE + irqidx * 4; unsafe { core::ptr::read_volatile(addr as *const u32) } } - pub fn read_clr_pending(&self, irqidx: usize) -> u32{ + pub fn get_clrip(&self, irqidx: usize) -> u32{ assert!(irqidx < 32); let addr = self.base + APLIC_CLRIP_BASE + irqidx * 4; unsafe { core::ptr::read_volatile(addr as *const u32) } } - pub fn set_pending(&self, irqidx: usize, src: u32, pending: bool){ + pub fn set_ip(&self, irqidx: usize, src: u32, pending: bool){ assert!(irqidx < 32); let addr = self.base + APLIC_PENDING_BASE + irqidx * 4; let clr_addr = self.base + APLIC_CLRIP_BASE + irqidx * 4; @@ -184,22 +184,28 @@ impl Aplic { } } } - pub fn read_in_clrip(&self, irqidx: usize) -> u32{ + pub fn set_ipnum(&self, value: u32){ + let addr = self.base + APLIC_IPNUM_BASE; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, value); + } + } + pub fn get_in_clrip(&self, irqidx: usize) -> u32{ assert!(irqidx < 32); let addr = self.base + APLIC_CLRIP_BASE + irqidx * 4; unsafe { core::ptr::read_volatile(addr as *const u32) } } - pub fn read_enable(&self, irqidx: usize) -> u32{ + pub fn get_ie(&self, irqidx: usize) -> u32{ assert!(irqidx < 32); let addr = self.base + APLIC_ENABLE_BASE + irqidx * 4; unsafe { core::ptr::read_volatile(addr as *const u32) } } - pub fn read_clr_enable(&self, irqidx: usize) -> u32{ + pub fn get_clrie(&self, irqidx: usize) -> u32{ assert!(irqidx < 32); let addr = self.base + APLIC_CLRIE_BASE + irqidx * 4; unsafe { core::ptr::read_volatile(addr as *const u32) } } - pub fn set_enable(&self, irqidx: usize, value: u32, enabled: bool){ + pub fn setie(&self, irqidx: usize, value: u32, enabled: bool){ assert!(irqidx < 32); let addr = self.base + APLIC_ENABLE_BASE + irqidx * 4; let clr_addr = self.base + APLIC_CLRIE_BASE + irqidx * 4; @@ -213,26 +219,24 @@ impl Aplic { } } } - pub fn set_enable_num(&self, value: u32){ + pub fn setienum(&self, value: u32){ let addr = self.base + APLIC_ENABLE_NUM; unsafe{ core:: ptr::write_volatile(addr as *mut u32, value); } } - pub fn set_clr_ienum(&self, value: u32){ + pub fn clrienum(&self, value: u32){ let addr = self.base + APLIC_CLRIE_NUM_BASE; unsafe{ core:: ptr::write_volatile(addr as *mut u32, value); } } - // pub fn set_ipnum_le(&self, value: u32){ - // let addr = self.base + APLIC_IPNUM_LE_BASE; - // // let value_le = u32::from_le_bytes(value.to_be_bytes()); - // // warn!("value_le:0x{:08x}", value_le); - // unsafe{ - // core:: ptr::write_volatile(addr as *mut u32, value); - // } - // } + pub fn setipnum_le(&self, value: u32){ + let addr = self.base + APLIC_IPNUM_LE_BASE; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, value); + } + } pub fn set_target_msi(&self, irq: u32, hart: u32, guest: u32, eiid: u32){ let addr = self.base + APLIC_TARGET_BASE + (irq as usize - 1) * 4; let src = (hart << 18) | (guest << 12) | eiid; @@ -247,7 +251,7 @@ impl Aplic { core:: ptr::write_volatile(addr as *mut u32, src); } } - pub fn get_target_guest(&self, irq: u32) -> (u32, u32, u32) { + pub fn get_target_info(&self, irq: u32) -> (u32, u32, u32) { let addr = self.base + APLIC_TARGET_BASE + (irq as usize - 1) * 4; unsafe { let src = core::ptr::read_volatile(addr as *const u32); @@ -272,14 +276,16 @@ pub fn vaplic_emul_handler( let enabled = ((value >> 8) & 0x1) != 0; // IE let msimode = ((value >> 2) & 0b1) != 0; // DM / MSI let bigendian = (value & 0b1) != 0; // 大小端 - host_aplic.write().set_domaincfg(bigendian, msimode, enabled); - warn!( - "APLIC set domaincfg write addr@{:#x} bigendian {} msimode {} enabled {}", - addr, bigendian, msimode, enabled - ); + if this_cpu_data().id != 3{ + host_aplic.write().set_domaincfg(bigendian, msimode, enabled); + debug!( + "APLIC set domaincfg write addr@{:#x} bigendian {} msimode {} enabled {}", + addr, bigendian, msimode, enabled + ); + } } Instruction::Lw(i) => { // 直接读取对应的内容 - let value = host_aplic.read().read_domaincfg(); + let value = host_aplic.read().get_domaincfg(); current_cpu.x[i.rd() as usize] = value as usize; } _ => panic!("Unexpected instruction {:?}", inst), @@ -295,7 +301,7 @@ pub fn vaplic_emul_handler( //delegate let child = value & 0x3ff; host_aplic.write().set_sourcecfg_delegate(irq as u32, child); - warn!( + debug!( "APLIC set sourcecfg_delegate write addr@{:#x} irq {} child {}", addr, irq, @@ -311,13 +317,16 @@ pub fn vaplic_emul_handler( 7 => SourceModes::LevelLow, _ => panic!("Unknown sourcecfg mode"), }; - host_aplic.write().set_sourcecfg(irq as u32, mode); - warn!( - "APLIC set sourcecfg write addr@{:#x} irq {} mode {}", - addr, - irq, - value - ); + if this_cpu_data().id != 3 || + this_cpu_data().id == 3 && (irq == 6 || irq == 7){ + host_aplic.write().set_sourcecfg(irq as u32, mode); + debug!( + "APLIC set sourcecfg write addr@{:#x} irq {} mode {}", + addr, + irq, + value + ); + } } } _ => panic!("Unexpected instruction {:?}", inst), @@ -329,7 +338,7 @@ pub fn vaplic_emul_handler( let value = current_cpu.x[i.rs2() as usize] as u32; let address = (value as usize) << 12; host_aplic.write().set_msiaddr(address); - warn!( + debug!( "APLIC set msiaddr write addr@{:#x} address {}", addr, address ); @@ -349,9 +358,9 @@ pub fn vaplic_emul_handler( match inst { Instruction::Lw(i) => { let irqidx = (offset - APLIC_CLRIP_BASE) / 4; - let value = host_aplic.read().read_in_clrip(irqidx); + let value = host_aplic.read().get_in_clrip(irqidx); current_cpu.x[i.rd() as usize] = value as usize; - warn!( + debug!( "APLIC read in clrip addr@{:#x} irqidx {} value {}", addr, irqidx, value ); @@ -372,25 +381,9 @@ pub fn vaplic_emul_handler( match inst { Instruction::Sw(i) => { let value = current_cpu.x[i.rs2() as usize] as u32; - let irqidx = value as usize / 32; - let irqbit = value as usize % 32; - if (host_aplic.read().read_enable(irqidx) >> irqbit) & 0b1 != 1 { - warn!( - "APLIC enable value {} not set",value - ); - host_aplic.write().set_enable(irqidx, 1 << irqbit, true); - } - if (host_aplic.read().read_enable(irqidx) >> irqbit) & 0b1 != 1 { - warn!( - "APLIC enable value {} not set",value - ); - } else { - warn!( - "APLIC enable value {} set now",value - ); - } - warn!( - "APLIC set enablenum write addr@{:#x} value {}", + host_aplic.write().setienum(value); + debug!( + "APLIC setienum write addr@{:#x} value {}", addr, value ); } @@ -402,9 +395,11 @@ pub fn vaplic_emul_handler( Instruction::Sw(i) => { let value = current_cpu.x[i.rs2() as usize] as u32; let irqidx = (offset - APLIC_CLRIE_BASE) / 4; - host_aplic.write().set_enable(irqidx, value, false); - warn!( - "APLIC set clr_enable write addr@{:#x} irqidx {} value {}", + if this_cpu_data().id != 3{ + host_aplic.write().setie(irqidx, value, false); + } + debug!( + "APLIC set clrie write addr@{:#x} irqidx {} value@{:#x}", addr, irqidx, value ); } @@ -416,9 +411,9 @@ pub fn vaplic_emul_handler( match inst { Instruction::Sw(i) => { let value = current_cpu.x[i.rs2() as usize] as u32; - host_aplic.write().set_clr_ienum(value); - warn!( - "APLIC set set_clr_ienum write addr@{:#x} value@{:#x}", + host_aplic.write().clrienum(value); + debug!( + "APLIC set clrienum write addr@{:#x} value{}", offset, value ); } @@ -431,33 +426,8 @@ pub fn vaplic_emul_handler( match inst { Instruction::Sw(i) => { let value = current_cpu.x[i.rs2() as usize] as u32; - let irqidx = value as usize / 32; - let irqbit = value as usize % 32; - if (host_aplic.read().read_pending(irqidx) >> irqbit) & 0b1 != 1 { - warn!("not set"); - host_aplic.write().set_pending(irqidx, 1 << irqbit, true); - let (hart, guest, eiid) = host_aplic.read().get_target_guest(value); - // imsic_trigger(hart, guest, eiid); - } - if (host_aplic.read().read_pending(irqidx) >> irqbit) & 0b1 != 1 { - warn!( - "APLIC pending value {} not set",value - ); - } else { - warn!( - "APLIC pending value {} set now",value - ); - } - unsafe { - count = count +1 ; - if count == 2000 { - warn!( - "APLIC set set_ipnum_le write addr@{:#x} value@{:#x}", - offset, value - ); - count = 0; - } - } + host_aplic.write().setipnum_le(value); + // debug!("APLIC setipnum le write addr@{:#x} value@{:#x}",offset, value); } _ => panic!("Unexpected instruction {:?}", inst), } @@ -488,15 +458,18 @@ pub fn vaplic_emul_handler( if host_aplic.read().get_msimode() { let guest = ((value >> 12) & 0x3F) + 1; let eiid = value & 0xFFF; - host_aplic.write().set_target_msi(irq, hart, guest, eiid); - warn!( - "APLIC set msi target write addr@{:#x} irq {} hart {} guest {} eiid {}", - addr, irq, hart, guest, eiid - ); + if this_cpu_data().id != 3 || + this_cpu_data().id == 3 && (irq == 6 || irq == 7){ + host_aplic.write().set_target_msi(irq, hart, guest, eiid); + debug!( + "APLIC set msi target write addr@{:#x} irq {} hart {} guest {} eiid {}", + addr, irq, hart, guest, eiid + ); + } } else { let prio = value & 0xFF; host_aplic.write().set_target_direct(irq, hart, prio); - warn!( + debug!( "APLIC set direct target write addr@{:#x} irq {} hart {} prio {}", addr, irq, hart, prio ); diff --git a/src/device/irqchip/aia/mod.rs b/src/device/irqchip/aia/mod.rs new file mode 100644 index 0000000..1ead1cd --- /dev/null +++ b/src/device/irqchip/aia/mod.rs @@ -0,0 +1,2 @@ +pub mod aplic; +pub mod imsic; \ No newline at end of file diff --git a/src/device/irqchip/aplic/mod.rs b/src/device/irqchip/aplic/mod.rs deleted file mode 100644 index b174f1e..0000000 --- a/src/device/irqchip/aplic/mod.rs +++ /dev/null @@ -1,471 +0,0 @@ - -use spin::RwLock; -use spin::Once; -use crate::{arch::cpu::ArchCpu, percpu::this_cpu_data, memory::GuestPhysAddr}; - -use riscv_decode::Instruction; -use fdt::Fdt; -use crate::zone::Zone; - -// S-mode interrupt delivery controller -const APLIC_S_IDC: usize = 0xd00_4000; -pub const APLIC_DOMAINCFG_BASE: usize = 0x0000; -pub const APLIC_SOURCECFG_BASE: usize = 0x0004; -pub const APLIC_SOURCECFG_TOP: usize = 0x1000; -pub const APLIC_MSIADDR_BASE: usize = 0x1BC8; -pub const APLIC_PENDING_BASE: usize = 0x1C00; -pub const APLIC_PENDING_TOP: usize = 0x1C80; -pub const APLIC_CLRIP_BASE: usize = 0x1D00; -pub const APLIC_ENABLE_BASE: usize = 0x1E00; -pub const APLIC_ENABLE_TOP: usize = 0x1E7C; -pub const APLIC_ENABLE_NUM: usize = 0x1EDC; -pub const APLIC_CLRIE_BASE: usize = 0x1F00; -pub const APLIC_CLRIE_NUM_BASE: usize = 0x1FDC; -pub const APLIC_IPNUM_LE_BASE: usize = 0x2000; -pub const APLIC_TARGET_BASE: usize = 0x3004; -pub const APLIC_IDC_BASE: usize = 0x4000; - -#[repr(u32)] -#[allow(dead_code)] -pub enum SourceModes { - Inactive = 0, - Detached = 1, - RisingEdge = 4, - FallingEdge = 5, - LevelHigh = 6, - LevelLow = 7, -} - -// offset size register name -// 0x0000 4 bytes domaincfg -// 0x0004 4 bytes sourcecfg[1] -// 0x0008 4 bytes sourcecfg[2] -// . . . . . . -// 0x0FFC 4 bytes sourcecfg[1023] -// 0x1BC0 4 bytes mmsiaddrcfg (machine-level interrupt domains only) -// 0x1BC4 4 bytes mmsiaddrcfgh ” -// 0x1BC8 4 bytes smsiaddrcfg ” -// 0x1BCC 4 bytes smsiaddrcfgh ” -// 0x1C00 4 bytes setip[0] -// 0x1C04 4 bytes setip[1] -// . . . . . . -// 0x1C7C 4 bytes setip[31] -// 0x1CDC 4 bytes setipnum -// 0x1D00 4 bytes in clrip[0] -// 0x1D04 4 bytes in clrip[1] -// . . . . . . -// 0x1D7C 4 bytes in clrip[31] -// 0x1DDC 4 bytes clripnum -// 0x1E00 4 bytes setie[0] -// 0x1E04 4 bytes setie[1] -// . . . . . . -// 0x1E7C 4 bytes setie[31] -// 0x1EDC 4 bytes setienum -// 0x1F00 4 bytes clrie[0] -// 0x1F04 4 bytes clrie[1] -// . . . . . . -// 0x1F7C 4 bytes clrie[31] -// 0x1FDC 4 bytes clrienum -// 0x2000 4 bytes setipnum le -// 0x2004 4 bytes setipnum be -// 0x3000 4 bytes genmsi -// 0x3004 4 bytes target[1] -// 0x3008 4 bytes target[2] -// . . . . . . -// 0x3FFC 4 bytes target[1023] - -pub fn primary_init_early(host_fdt: &Fdt) { - let aplic_debug = host_fdt.find_node("/soc/aplic").unwrap(); - init_aplic( - aplic_debug.reg().unwrap().next().unwrap().starting_address as usize, - aplic_debug.reg().unwrap().next().unwrap().size.unwrap(), - ); -} -pub fn primary_init_late() { - //nothing to do -} -pub fn percpu_init() { - //nothing to do -} -pub fn inject_irq(_irq: usize, is_hardware: bool) { - //nothing to do -} -pub static APLIC: Once> = Once::new(); -pub fn host_aplic<'a>() -> &'a RwLock { - APLIC.get().expect("Uninitialized hypervisor aplic!") -} - -#[repr(C)] -pub struct Aplic { - pub base: usize, - pub size: usize, -} - -#[allow(dead_code)] -impl Aplic { - pub fn new(base: usize, size: usize) -> Self { - Self { - base, - size, - } - } - pub fn set_domaincfg(&self, bigendian: bool, msimode: bool, enabled: bool){ - let enabled = u32::from(enabled); - let msimode = u32::from(msimode); - let bigendian = u32::from(bigendian); - let addr = self.base + APLIC_DOMAINCFG_BASE; - let bigendian = 0 ; - let src = (enabled << 8) | (msimode << 2) | bigendian; - unsafe { - core::ptr::write_volatile(addr as *mut u32, src); - } - } - pub fn read_domaincfg(&self) -> u32{ - let addr = self.base + APLIC_DOMAINCFG_BASE; - unsafe { core::ptr::read_volatile(addr as *const u32) } - } - pub fn get_msimode(&self) -> bool{ - let addr = self.base + APLIC_DOMAINCFG_BASE; - let value= unsafe { core::ptr::read_volatile(addr as *const u32) }; - ((value >> 2) & 0b11) != 0 - } - pub fn set_sourcecfg(&self, irq: u32, mode: SourceModes){ - assert!(irq > 0 && irq < 1024); - let addr = self.base + APLIC_SOURCECFG_BASE + (irq as usize - 1) * 4; - let src = mode as u32; - unsafe{ - core:: ptr::write_volatile(addr as *mut u32, src); - } - } - pub fn set_sourcecfg_delegate(&self, irq: u32, child: u32){ - assert!(irq > 0 && irq < 1024); - let addr = self.base + APLIC_SOURCECFG_BASE + (irq as usize - 1) * 4; - let src = 1 << 10 | child & 0x3ff; - unsafe{ - core:: ptr::write_volatile(addr as *mut u32, src); - } - } - pub fn read_sourcecfg(&self, irq: u32) -> u32{ - assert!(irq > 0 && irq < 1024); - let addr = self.base + APLIC_SOURCECFG_BASE + (irq as usize - 1) * 4; - unsafe { core::ptr::read_volatile(addr as *const u32) } - } - pub fn set_msiaddr(&self, address: usize){ - let addr = self.base + APLIC_MSIADDR_BASE; - let src = (address >> 12) as u32; - unsafe{ - core:: ptr::write_volatile(addr as *mut u32, src); - core:: ptr::write_volatile((addr + 4) as *mut u32, 0); - } - } - pub fn read_pending(&self, irqidx: usize) -> u32{ - assert!(irqidx < 32); - let addr = self.base + APLIC_PENDING_BASE + irqidx * 4; - unsafe { core::ptr::read_volatile(addr as *const u32) } - } - pub fn read_clr_pending(&self, irqidx: usize) -> u32{ - assert!(irqidx < 32); - let addr = self.base + APLIC_CLRIP_BASE + irqidx * 4; - unsafe { core::ptr::read_volatile(addr as *const u32) } - } - pub fn set_pending(&self, irqidx: usize, value: u32, pending: bool){ - assert!(irqidx < 32); - let addr = self.base + APLIC_PENDING_BASE + irqidx * 4; - let clr_addr = self.base + APLIC_CLRIP_BASE + irqidx * 4; - if pending { - unsafe{ - core:: ptr::write_volatile(addr as *mut u32, value); - } - } else { - unsafe{ - core:: ptr::write_volatile(clr_addr as *mut u32, value); - } - } - } - pub fn read_in_clrip(&self, irqidx: usize) -> u32{ - assert!(irqidx < 32); - let addr = self.base + APLIC_CLRIP_BASE + irqidx * 4; - unsafe { core::ptr::read_volatile(addr as *const u32) } - } - pub fn read_enable(&self, irqidx: usize) -> u32{ - assert!(irqidx < 32); - let addr = self.base + APLIC_ENABLE_BASE + irqidx * 4; - unsafe { core::ptr::read_volatile(addr as *const u32) } - } - pub fn read_clr_enable(&self, irqidx: usize) -> u32{ - assert!(irqidx < 32); - let addr = self.base + APLIC_CLRIE_BASE + irqidx * 4; - unsafe { core::ptr::read_volatile(addr as *const u32) } - } - pub fn set_enable(&self, irqidx: usize, value: u32, enabled: bool){ - assert!(irqidx < 32); - let addr = self.base + APLIC_ENABLE_BASE + irqidx * 4; - let clr_addr = self.base + APLIC_CLRIE_BASE + irqidx * 4; - if enabled { - unsafe{ - core:: ptr::write_volatile(addr as *mut u32, value); - } - } else { - unsafe{ - core:: ptr::write_volatile(clr_addr as *mut u32, value); - } - } - } - pub fn set_enable_num(&self, value: u32){ - let addr = self.base + APLIC_ENABLE_NUM; - unsafe{ - core:: ptr::write_volatile(addr as *mut u32, value); - } - } - pub fn set_clr_ienum(&self, value: u32){ - let addr = self.base + APLIC_CLRIE_NUM_BASE; - unsafe{ - core:: ptr::write_volatile(addr as *mut u32, value); - } - } - pub fn set_ipnum_le(&self, value: u32){ - let addr = self.base + APLIC_IPNUM_LE_BASE; - // let value_le = u32::from_le_bytes(value.to_be_bytes()); - debug!("value:0x{:08x}", value); - // debug!("value_le:0x{:08x}", value_le); - unsafe{ - core:: ptr::write_volatile(addr as *mut u32, value); - } - } - pub fn set_target_msi(&self, irq: u32, hart: u32, guest: u32, eiid: u32){ - let addr = self.base + APLIC_TARGET_BASE + (irq as usize - 1) * 4; - let src = (hart << 18) | (guest << 12) | eiid; - unsafe{ - core:: ptr::write_volatile(addr as *mut u32, src); - } - } - pub fn set_target_direct(&self, irq: u32, hart: u32, prio: u32){ - let addr = self.base + APLIC_TARGET_BASE + (irq as usize - 1) * 4; - let src = (hart << 18) | (prio & 0xFF); - unsafe{ - core:: ptr::write_volatile(addr as *mut u32, src); - } - } -} - -pub fn vaplic_emul_handler( - current_cpu: &mut ArchCpu, - addr: GuestPhysAddr, - inst: Instruction, -) { - let host_aplic = host_aplic(); - let offset = addr.wrapping_sub(host_aplic.read().base); - if offset >= APLIC_DOMAINCFG_BASE && offset < APLIC_SOURCECFG_BASE { - match inst { - Instruction::Sw(i) => { - let value = current_cpu.x[i.rs2() as usize] as u32; // 要写入的 value - let enabled = ((value >> 8) & 0x1) != 0; // IE - let msimode = ((value >> 2) & 0b1) != 0; // DM / MSI - let bigendian = (value & 0b1) != 0; // 大小端 - host_aplic.write().set_domaincfg(bigendian, msimode, enabled); - debug!( - "APLIC set domaincfg write addr@{:#x} bigendian {} msimode {} enabled {}", - addr, bigendian, msimode, enabled - ); - } - Instruction::Lw(i) => { // 直接读取对应的内容 - let value = host_aplic.read().read_domaincfg(); - current_cpu.x[i.rd() as usize] = value as usize; - } - _ => panic!("Unexpected instruction {:?}", inst), - } - } - else if offset >= APLIC_SOURCECFG_BASE && offset < APLIC_SOURCECFG_TOP { - //sourcecfg - match inst { - Instruction::Sw(i) => { - let value = current_cpu.x[i.rs2() as usize] as u32; - let irq = ((offset - APLIC_SOURCECFG_BASE) / 4) + 1; - if (value >> 10) & 0b1 == 1 { - //delegate - let child = value & 0x3ff; - host_aplic.write().set_sourcecfg_delegate(irq as u32, child); - debug!( - "APLIC set sourcecfg_delegate write addr@{:#x} irq {} child {}", - addr, - irq, - child - ); - } else { - let mode = match value { - 0 => SourceModes::Inactive, - 1 => SourceModes::Detached, - 4 => SourceModes::RisingEdge, - 5 => SourceModes::FallingEdge, - 6 => SourceModes::LevelHigh, - 7 => SourceModes::LevelLow, - _ => panic!("Unknown sourcecfg mode"), - }; - host_aplic.write().set_sourcecfg(irq as u32, mode); - debug!( - "APLIC set sourcecfg write addr@{:#x} irq {} mode {}", - addr, - irq, - value - ); - } - } - _ => panic!("Unexpected instruction {:?}", inst), - } - } else if offset >= APLIC_MSIADDR_BASE && offset <= 0x1BCC { - // msia - match inst { - Instruction::Sw(i) => { - let value = current_cpu.x[i.rs2() as usize] as u32; - let address = (value as usize) << 12; - host_aplic.write().set_msiaddr(address); - debug!( - "APLIC set msiaddr write addr@{:#x} address {}", - addr, address - ); - } - _ => panic!("Unexpected instruction {:?}", inst), - } - } else if offset >= APLIC_PENDING_BASE && offset < APLIC_PENDING_TOP { - // pending - panic!("setip Unexpected instruction {:?}", inst); - } - // setipnum 区域 0x1CDC - 0x1CE0 - else if offset >= 0x1CDC && offset < 0x1CE0 { - panic!("setipnum Unexpected instruction {:?}", inst) - } - else if offset >= APLIC_CLRIP_BASE && offset < 0x1D80 { - // panic!("addr@{:#x} in_clrip Unexpected instruction {:?}", offset ,inst); - match inst { - Instruction::Lw(i) => { - let irqidx = (offset - APLIC_CLRIP_BASE) / 4; - let value = host_aplic.read().read_in_clrip(irqidx); - current_cpu.x[i.rd() as usize] = value as usize; - debug!( - "APLIC read in clrip addr@{:#x} irqidx {} value {}", - addr, irqidx, value - ); - } - _ => panic!("Unexpected instruction {:?}", inst), - } - } - // clripnum 区域 - else if offset >= 0x1DDC && offset < 0x1DE0 { - panic!("clripnum Unexpected instruction {:?}", inst) - } - // setie - else if offset >= APLIC_ENABLE_BASE && offset < 0x1E80 { - panic!("setie Unexpected instruction {:?}", inst); - } - else if offset >= APLIC_ENABLE_NUM && offset < 0x1EE0 { - // enablenum - match inst { - Instruction::Sw(i) => { - let value = current_cpu.x[i.rs2() as usize] as u32; - host_aplic.write().set_enable_num(value); - debug!( - "APLIC set enablenum write addr@{:#x} value {}", - addr, value - ); - } - _ => panic!("Unexpected instruction {:?}", inst), - } - } else if offset >= APLIC_CLRIE_BASE && offset < 0x1FDC { - // clrenable - match inst { - Instruction::Sw(i) => { - let value = current_cpu.x[i.rs2() as usize] as u32; - let irqidx = (offset - APLIC_CLRIE_BASE) / 4; - host_aplic.write().set_enable(irqidx, value, false); - debug!( - "APLIC set clr_enable write addr@{:#x} irqidx {} value {}", - addr, irqidx, value - ); - } - _ => panic!("Unexpected instruction {:?}", inst), - } - } - // clrienum - else if offset >= 0x1FDC && offset < 0x1FE0 { - match inst { - Instruction::Sw(i) => { - let value = current_cpu.x[i.rs2() as usize] as u32; - host_aplic.write().set_clr_ienum(value); - debug!( - "APLIC set set_clr_ienum write addr@{:#x} value@{:#x}", - offset, value - ); - } - _ => panic!("Unexpected instruction {:?}", inst), - } - - } - // setipnum_le - else if offset >= 0x2000 && offset < 0x2004 { - match inst { - Instruction::Sw(i) => { - let value = current_cpu.x[i.rs2() as usize] as u32; - host_aplic.write().set_ipnum_le(value); - debug!( - "APLIC set set_ipnum_le write addr@{:#x} value@{:#x}", - offset, value - ); - } - _ => panic!("Unexpected instruction {:?}", inst), - } - } - // setipnum_be - else if offset >= 0x2004 && offset < 0x2008 { - panic!("setipnum_be Unexpected instruction {:?}", inst) - } - // genmsi - else if offset >= 0x3000 && offset < 0x3004 { - panic!("genmsi Unexpected instruction {:?}", inst) - } - else if offset >= APLIC_TARGET_BASE && offset < APLIC_IDC_BASE { - // target - match inst { - Instruction::Sw(i) => { - let first_cpu = this_cpu_data() - .zone - .as_ref() - .unwrap() - .read() - .cpu_set - .first_cpu() - .unwrap(); - let value = current_cpu.x[i.rs2() as usize] as u32; - let irq = ((offset - APLIC_TARGET_BASE) / 4) as u32 + 1; - let hart = ((value >> 18) & 0x3F) + first_cpu as u32; - if host_aplic.read().get_msimode() { - let guest = ((value >> 12) & 0x3F) + 1; - let eiid = value & 0xFFF; - host_aplic.write().set_target_msi(irq, hart, guest, eiid); - debug!( - "APLIC set msi target write addr@{:#x} irq {} hart {} guest {} eiid {}", - addr, irq, hart, guest, eiid - ); - } else { - let prio = value & 0xFF; - host_aplic.write().set_target_direct(irq, hart, prio); - debug!( - "APLIC set direct target write addr@{:#x} irq {} hart {} prio {}", - addr, irq, hart, prio - ); - } - } - _ => panic!("Unexpected instruction {:?}", inst), - } - } else { - panic!("Invalid address: {:#x}", addr); - } -} -pub fn init_aplic(aplic_base: usize, aplic_size: usize) { - let aplic = Aplic::new(aplic_base, aplic_size); - APLIC.call_once(|| RwLock::new(aplic)); -} -impl Zone { - pub fn arch_irqchip_reset(&self) { - //TODO - } -} \ No newline at end of file diff --git a/src/device/irqchip/mod.rs b/src/device/irqchip/mod.rs index 97e8495..8a76daf 100644 --- a/src/device/irqchip/mod.rs +++ b/src/device/irqchip/mod.rs @@ -7,7 +7,7 @@ pub mod plic; #[cfg(target_arch = "riscv64")] #[cfg(feature = "aia")] -pub mod aplic; +pub mod aia; #[cfg(target_arch = "aarch64")] pub use gicv3::{inject_irq, percpu_init, primary_init_early, primary_init_late}; @@ -18,4 +18,4 @@ pub use plic::{inject_irq, percpu_init, primary_init_early, primary_init_late}; #[cfg(target_arch = "riscv64")] #[cfg(feature = "aia")] -pub use aplic::{inject_irq, percpu_init, primary_init_early, primary_init_late}; +pub use aia::aplic::{inject_irq, percpu_init, primary_init_early, primary_init_late}; diff --git a/src/main.rs b/src/main.rs index 427f5f9..c765ca4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -96,7 +96,6 @@ fn primary_init_early(dtb: usize) { let host_fdt = unsafe { fdt::Fdt::from_ptr(dtb as *const u8) }.unwrap(); device::irqchip::primary_init_early(&host_fdt); - // #[cfg(feature = "plic")] crate::arch::mm::init_hv_page_table(&host_fdt).unwrap(); info!("Primary CPU init hv page table OK."); From 10bfe150a59136c0a7e577ae9d864f6f265b7525 Mon Sep 17 00:00:00 2001 From: dorso <2434317248@qq.com> Date: Fri, 26 Jul 2024 15:59:48 +0800 Subject: [PATCH 4/6] edit --- Makefile | 10 +--------- scripts/qemu-riscv64.mk | 7 +++++++ src/device/irqchip/aia/aplic.rs | 8 ++------ 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 6367f0b..8cec6c0 100644 --- a/Makefile +++ b/Makefile @@ -54,17 +54,9 @@ disa: readelf -a $(hvisor_elf) > hvisor-elf.txt rust-objdump --disassemble $(hvisor_elf) > hvisor.S -run: build +run: all $(QEMU) $(QEMU_ARGS) -$(hvisor_bin): elf - $(OBJCOPY) $(hvisor_elf) --strip-all -O binary $@ - -build: $(hvisor_bin) - make -C $(image_dir)/opensbi-1.2 PLATFORM=generic \ - FW_PAYLOAD=y \ - FW_PAYLOAD_PATH= ../../../$(hvisor_bin) - gdb: all $(QEMU) $(QEMU_ARGS) -s -S diff --git a/scripts/qemu-riscv64.mk b/scripts/qemu-riscv64.mk index b5da06f..31235c6 100644 --- a/scripts/qemu-riscv64.mk +++ b/scripts/qemu-riscv64.mk @@ -71,3 +71,10 @@ QEMU_ARGS += -device virtio-blk-device,drive=X10006000 # #QEMU_ARGS += -device virtio-serial-port -chardev pty,id=serial3 -device virtconsole,chardev=serial3 # QEMU_ARGS += -device virtio-serial-device -chardev pty,id=serial3 -device virtconsole,chardev=serial3 +$(hvisor_bin): elf + $(OBJCOPY) $(hvisor_elf) --strip-all -O binary $@ + +build: $(hvisor_bin) + make -C $(image_dir)/opensbi-1.2 PLATFORM=generic \ + FW_PAYLOAD=y \ + FW_PAYLOAD_PATH= ../../../$(hvisor_bin) \ No newline at end of file diff --git a/src/device/irqchip/aia/aplic.rs b/src/device/irqchip/aia/aplic.rs index ada816f..20dcc74 100644 --- a/src/device/irqchip/aia/aplic.rs +++ b/src/device/irqchip/aia/aplic.rs @@ -284,10 +284,6 @@ pub fn vaplic_emul_handler( ); } } - Instruction::Lw(i) => { // 直接读取对应的内容 - let value = host_aplic.read().get_domaincfg(); - current_cpu.x[i.rd() as usize] = value as usize; - } _ => panic!("Unexpected instruction {:?}", inst), } } @@ -377,7 +373,7 @@ pub fn vaplic_emul_handler( panic!("setie Unexpected instruction {:?}", inst); } else if offset >= APLIC_ENABLE_NUM && offset < 0x1EE0 { - // enablenum + // setienum match inst { Instruction::Sw(i) => { let value = current_cpu.x[i.rs2() as usize] as u32; @@ -390,7 +386,7 @@ pub fn vaplic_emul_handler( _ => panic!("Unexpected instruction {:?}", inst), } } else if offset >= APLIC_CLRIE_BASE && offset < 0x1FDC { - // clrenable + // clrie match inst { Instruction::Sw(i) => { let value = current_cpu.x[i.rs2() as usize] as u32; From 85b37a83d90a7466c446f8089a3d3a2bdb5b8278 Mon Sep 17 00:00:00 2001 From: dorso <2434317248@qq.com> Date: Fri, 26 Jul 2024 16:06:50 +0800 Subject: [PATCH 5/6] edit --- images/riscv64/devicetree/linux-aia.dts | 80 ------------ images/riscv64/devicetree/linux.dts | 59 --------- images/riscv64/devicetree/linux1.dts | 2 +- images/riscv64/devicetree/linux3-aia.dts | 159 ----------------------- images/riscv64/devicetree/linux3.dts | 156 ---------------------- src/arch/riscv64/mm.rs | 4 +- src/device/irqchip/aia/aplic.rs | 4 + src/device/irqchip/aia/imsic.rs | 5 - src/device/irqchip/mod.rs | 6 +- src/main.rs | 7 +- src/memory/mod.rs | 3 +- 11 files changed, 15 insertions(+), 470 deletions(-) delete mode 100644 images/riscv64/devicetree/linux-aia.dts delete mode 100644 images/riscv64/devicetree/linux.dts delete mode 100644 images/riscv64/devicetree/linux3-aia.dts delete mode 100644 images/riscv64/devicetree/linux3.dts diff --git a/images/riscv64/devicetree/linux-aia.dts b/images/riscv64/devicetree/linux-aia.dts deleted file mode 100644 index 286a19c..0000000 --- a/images/riscv64/devicetree/linux-aia.dts +++ /dev/null @@ -1,80 +0,0 @@ -/dts-v1/; - -/ { - #address-cells = <0x2>; - #size-cells = <0x2>; - - cpus { - #address-cells = <0x1>; - #size-cells = <0x0>; - timebase-frequency = <10000000>; - cpu@3 { - device_type = "cpu"; - reg = <0x3>; - status = "okay"; - compatible = "riscv"; - riscv,isa = "rv64imafdch_ssaia_sstc"; - mmu-type = "riscv,sv48"; - - cpu3_intc: interrupt-controller { - #interrupt-cells = <0x1>; - interrupt-controller; - compatible = "riscv,cpu-intc"; - }; - }; - - }; - - memory@84000000 { - device_type = "memory"; - reg = <0x0 0x84000000 0x0 0x08000000>; - }; -soc{ - #address-cells = <0x02>; - #size-cells = <0x02>; - compatible = "simple-bus"; - ranges; - - aplic@d000000 { - phandle = <0x08>; - riscv,num-sources = <0x60>; - reg = <0x00 0xd000000 0x00 0x8000>; - msi-parent = <0x06>; - interrupt-controller; - #interrupt-cells = <0x02>; - compatible = "riscv,aplic"; - }; - - imsics@28000000 { - phandle = <0x06>; - riscv,num-ids = <0xff>; - reg = <0x00 0x28000000 0x00 0x4000>; - interrupts-extended = < - &cpu3_intc 9 - >; - msi-controller; - interrupt-controller; - #interrupt-cells = <0x00>; - compatible = "riscv,imsics"; - }; - - virtio_mmio@10007000 { - interrupts = <0x7 &cpu3_intc>; - interrupt-parent = <0x08>; - reg = <0x0 0x10007000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - - virtio_mmio@10006000 { - interrupts = <0x6 &cpu3_intc>; - interrupt-parent = <0x08>; - reg = <0x0 0x10006000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - -}; - - chosen { - bootargs = "root=/dev/vda rw earlycon console=hvc0"; - }; -}; \ No newline at end of file diff --git a/images/riscv64/devicetree/linux.dts b/images/riscv64/devicetree/linux.dts deleted file mode 100644 index ad4a02c..0000000 --- a/images/riscv64/devicetree/linux.dts +++ /dev/null @@ -1,59 +0,0 @@ -/dts-v1/; - -/ { - #address-cells = <0x2>; - #size-cells = <0x2>; - - cpus { - #address-cells = <0x1>; - #size-cells = <0x0>; - timebase-frequency = <10000000>; - cpu@3 { - device_type = "cpu"; - reg = <0x3>; - status = "okay"; - compatible = "riscv"; - riscv,isa = "rv64imafdcsu_sstc"; - mmu-type = "riscv,sv39"; - - cpu3_intc: interrupt-controller { - #interrupt-cells = <0x1>; - interrupt-controller; - compatible = "riscv,cpu-intc"; - }; - }; - - }; - - memory@84000000 { - device_type = "memory"; - reg = <0x0 0x84000000 0x0 0x08000000>; - }; -soc{ - #address-cells = <0x02>; - #size-cells = <0x02>; - compatible = "simple-bus"; - ranges; - plic: interrupt-controller@c000000 { - riscv,ndev = <60>; - reg = <0x0 0xc000000 0x0 0x4000000>; - interrupts-extended = < - &cpu3_intc 11 &cpu3_intc 9 - >; - interrupt-controller; - compatible = "riscv,plic0"; - #interrupt-cells = <0x1>; - }; - - virtio_mmio@10007000 { - interrupts = <0x7>; - interrupt-parent = <&plic>; - reg = <0x0 0x10007000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; -}; - chosen { - bootargs = "root=/dev/vda rw earlycon console=hvc0"; - }; - -}; \ No newline at end of file diff --git a/images/riscv64/devicetree/linux1.dts b/images/riscv64/devicetree/linux1.dts index 6de3ae4..394b9d7 100644 --- a/images/riscv64/devicetree/linux1.dts +++ b/images/riscv64/devicetree/linux1.dts @@ -165,7 +165,7 @@ }; }; chosen { - bootargs = "root=/dev/vda rw earlycon console=ttyS0 ip=192.168.42.15"; + bootargs = "root=/dev/vda rw earlycon console=ttyS0"; }; }; diff --git a/images/riscv64/devicetree/linux3-aia.dts b/images/riscv64/devicetree/linux3-aia.dts deleted file mode 100644 index d1cb4b3..0000000 --- a/images/riscv64/devicetree/linux3-aia.dts +++ /dev/null @@ -1,159 +0,0 @@ -/dts-v1/; - -/ { - #address-cells = <0x2>; - #size-cells = <0x2>; - - cpus { - #address-cells = <0x1>; - #size-cells = <0x0>; - timebase-frequency = <10000000>; - cpu@0 { - device_type = "cpu"; - reg = <0x0>; - status = "okay"; - compatible = "riscv"; - riscv,isa = "rv64imafdch_ssaia_sstc"; - mmu-type = "riscv,sv48"; - - cpu0_intc: interrupt-controller { - #interrupt-cells = <0x1>; - interrupt-controller; - compatible = "riscv,cpu-intc"; - phandle = <0x04>; - }; - }; - cpu@1 { - device_type = "cpu"; - reg = <0x1>; - status = "okay"; - compatible = "riscv"; - riscv,isa = "rv64imafdch_ssaia_sstc"; - mmu-type = "riscv,sv48"; - - cpu1_intc: interrupt-controller { - #interrupt-cells = <0x1>; - interrupt-controller; - compatible = "riscv,cpu-intc"; - }; - }; - cpu@2 { - device_type = "cpu"; - reg = <0x2>; - status = "okay"; - compatible = "riscv"; - riscv,isa = "rv64imafdch_ssaia_sstc"; - mmu-type = "riscv,sv48"; - - cpu2_intc: interrupt-controller { - #interrupt-cells = <0x1>; - interrupt-controller; - compatible = "riscv,cpu-intc"; - }; - }; - }; - - memory@90000000 { - device_type = "memory"; - reg = <0x0 0x90000000 0x0 0x10000000>; - }; -soc{ - #address-cells = <0x02>; - #size-cells = <0x02>; - compatible = "simple-bus"; - ranges; - - aplic@d000000 { - phandle = <0x08>; - riscv,num-sources = <0x60>; - reg = <0x00 0xd000000 0x00 0x8000>; - msi-parent = <0x06>; - interrupt-controller; - #interrupt-cells = <0x02>; - compatible = "riscv,aplic"; - }; - - imsics@28000000 { - phandle = <0x06>; - riscv,num-ids = <0xff>; - reg = <0x00 0x28000000 0x00 0x4000>; - interrupts-extended = < - &cpu0_intc 9 - &cpu1_intc 9 - &cpu2_intc 9 - >; - msi-controller; - interrupt-controller; - #interrupt-cells = <0x00>; - compatible = "riscv,imsics"; - }; - - virtio_mmio@10008000 { - interrupts = <0x8 0x04>; - interrupt-parent = <0x08>; - reg = <0x0 0x10008000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - virtio_mmio@10006000 { - interrupts = <0x6 0x04>; - interrupt-parent = <0x08>; - reg = <0x0 0x10006000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - virtio_mmio@10005000 { - interrupts = <0x5 0x04>; - interrupt-parent = <0x08>; - reg = <0x0 0x10005000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - virtio_mmio@10004000 { - interrupts = <0x4 0x04>; - interrupt-parent = <0x08>; - reg = <0x0 0x10004000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - virtio_mmio@10003000 { - interrupts = <0x3 0x04>; - interrupt-parent = <0x08>; - reg = <0x0 0x10003000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - virtio_mmio@10002000 { - interrupts = <0x2 0x04>; - interrupt-parent = <0x08>; - reg = <0x0 0x10002000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - virtio_mmio@10001000 { - interrupts = <0x1 0x04>; - interrupt-parent = <0x08>; - reg = <0x0 0x10001000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - pci@30000000 { - interrupt-map-mask = <0x1800 0x00 0x00 0x07>; - interrupt-map = <0x00 0x00 0x00 0x01 0x09 0x20 0x00 0x00 0x00 0x02 0x09 0x21 0x00 0x00 0x00 0x03 0x09 0x22 0x00 0x00 0x00 0x04 0x09 0x23 0x800 0x00 0x00 0x01 0x09 0x21 0x800 0x00 0x00 0x02 0x09 0x22 0x800 0x00 0x00 0x03 0x09 0x23 0x800 0x00 0x00 0x04 0x09 0x20 0x1000 0x00 0x00 0x01 0x09 0x22 0x1000 0x00 0x00 0x02 0x09 0x23 0x1000 0x00 0x00 0x03 0x09 0x20 0x1000 0x00 0x00 0x04 0x09 0x21 0x1800 0x00 0x00 0x01 0x09 0x23 0x1800 0x00 0x00 0x02 0x09 0x20 0x1800 0x00 0x00 0x03 0x09 0x21 0x1800 0x00 0x00 0x04 0x09 0x22>; - ranges = <0x1000000 0x00 0x00 0x00 0x3000000 0x00 0x10000 0x2000000 0x00 0x40000000 0x00 0x40000000 0x00 0x40000000 0x3000000 0x04 0x00 0x04 0x00 0x04 0x00>; - reg = <0x00 0x30000000 0x00 0x10000000>; - dma-coherent; - bus-range = <0x00 0xff>; - linux,pci-domain = <0x00>; - device_type = "pci"; - compatible = "pci-host-ecam-generic"; - #size-cells = <0x02>; - #interrupt-cells = <0x01>; - #address-cells = <0x03>; - }; - uart@10000000 { - interrupts = <0x0a 0x04>; - interrupt-parent = <0x08>; - clock-frequency = "\08@"; - reg = <0x00 0x10000000 0x00 0x100>; - compatible = "ns16550a"; - }; - -}; - chosen { - bootargs = "root=/dev/vda rw earlycon console=ttyS0 ip=192.168.42.15"; - }; -}; \ No newline at end of file diff --git a/images/riscv64/devicetree/linux3.dts b/images/riscv64/devicetree/linux3.dts deleted file mode 100644 index 201d001..0000000 --- a/images/riscv64/devicetree/linux3.dts +++ /dev/null @@ -1,156 +0,0 @@ -/dts-v1/; - -/ { - #address-cells = <0x2>; - #size-cells = <0x2>; - - cpus { - #address-cells = <0x1>; - #size-cells = <0x0>; - timebase-frequency = <10000000>; - - cpu@0 { - device_type = "cpu"; - reg = <0x0>; - status = "okay"; - compatible = "riscv"; - riscv,isa = "rv64imafdcsu_sstc"; - mmu-type = "riscv,sv39"; - - cpu0_intc: interrupt-controller { - #interrupt-cells = <0x1>; - interrupt-controller; - compatible = "riscv,cpu-intc"; - }; - }; - - cpu@1 { - device_type = "cpu"; - reg = <0x1>; - status = "okay"; - compatible = "riscv"; - riscv,isa = "rv64imafdcsu_sstc"; - mmu-type = "riscv,sv39"; - - cpu1_intc: interrupt-controller { - #interrupt-cells = <0x1>; - interrupt-controller; - compatible = "riscv,cpu-intc"; - }; - }; - cpu@2 { - device_type = "cpu"; - reg = <0x2>; - status = "okay"; - compatible = "riscv"; - riscv,isa = "rv64imafdcsu_sstc"; - mmu-type = "riscv,sv39"; - - cpu2_intc: interrupt-controller { - #interrupt-cells = <0x1>; - interrupt-controller; - compatible = "riscv,cpu-intc"; - }; - }; - - }; - - memory@90000000 { - device_type = "memory"; - reg = <0x0 0x90000000 0x0 0x10000000>; - }; -soc{ - #address-cells = <0x02>; - #size-cells = <0x02>; - compatible = "simple-bus"; - ranges; - plic: interrupt-controller@c000000 { - riscv,ndev = <60>; - reg = <0x0 0xc000000 0x0 0x4000000>; - interrupts-extended = < - &cpu0_intc 11 &cpu0_intc 9 - &cpu1_intc 11 &cpu1_intc 9 - &cpu2_intc 11 &cpu2_intc 9 - >; - interrupt-controller; - compatible = "riscv,plic0"; - #interrupt-cells = <0x1>; - }; - uart@10000000 { - interrupts = <0x0a>; - interrupt-parent = <&plic>; - clock-frequency = "\08@"; - reg = <0x00 0x10000000 0x00 0x100>; - compatible = "ns16550a"; - }; - pci@30000000 { - interrupt-map-mask = <0x1800 0x00 0x00 0x07>; - interrupt-map = <0x00 0x00 0x00 0x01 0x09 0x20 0x00 0x00 0x00 0x02 0x09 0x21 0x00 0x00 0x00 0x03 0x09 0x22 0x00 0x00 0x00 0x04 0x09 0x23 0x800 0x00 0x00 0x01 0x09 0x21 0x800 0x00 0x00 0x02 0x09 0x22 0x800 0x00 0x00 0x03 0x09 0x23 0x800 0x00 0x00 0x04 0x09 0x20 0x1000 0x00 0x00 0x01 0x09 0x22 0x1000 0x00 0x00 0x02 0x09 0x23 0x1000 0x00 0x00 0x03 0x09 0x20 0x1000 0x00 0x00 0x04 0x09 0x21 0x1800 0x00 0x00 0x01 0x09 0x23 0x1800 0x00 0x00 0x02 0x09 0x20 0x1800 0x00 0x00 0x03 0x09 0x21 0x1800 0x00 0x00 0x04 0x09 0x22>; - ranges = <0x1000000 0x00 0x00 0x00 0x3000000 0x00 0x10000 0x2000000 0x00 0x40000000 0x00 0x40000000 0x00 0x40000000 0x3000000 0x04 0x00 0x04 0x00 0x04 0x00>; - reg = <0x00 0x30000000 0x00 0x10000000>; - dma-coherent; - bus-range = <0x00 0xff>; - linux,pci-domain = <0x00>; - device_type = "pci"; - compatible = "pci-host-ecam-generic"; - #size-cells = <0x02>; - #interrupt-cells = <0x01>; - #address-cells = <0x03>; - }; - - virtio_mmio@10008000 { - interrupts = <0x8>; - interrupt-parent = <&plic>; - reg = <0x0 0x10008000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - virtio_mmio@10006000 { - interrupts = <0x6>; - interrupt-parent = <&plic>; - reg = <0x0 0x10006000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - - virtio_mmio@10005000 { - interrupts = <0x5>; - interrupt-parent = <&plic>; - reg = <0x0 0x10005000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - - virtio_mmio@10004000 { - interrupts = <0x4>; - interrupt-parent = <&plic>; - reg = <0x0 0x10004000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - - virtio_mmio@10003000 { - interrupts = <0x3>; - interrupt-parent = <&plic>; - reg = <0x0 0x10003000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - - virtio_mmio@10002000 { - interrupts = <0x2>; - interrupt-parent = <&plic>; - reg = <0x0 0x10002000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - - virtio_mmio@10001000 { - interrupts = <0x1>; - interrupt-parent = <&plic>; - reg = <0x0 0x10001000 0x0 0x1000>; - compatible = "virtio,mmio"; - }; - - - -}; - chosen { - bootargs = "root=/dev/vda rw earlycon console=ttyS0 ip=192.168.42.15"; - }; - -}; diff --git a/src/arch/riscv64/mm.rs b/src/arch/riscv64/mm.rs index c2ad6f7..713356b 100644 --- a/src/arch/riscv64/mm.rs +++ b/src/arch/riscv64/mm.rs @@ -7,9 +7,9 @@ use crate::{ addr::align_up, GuestPhysAddr, HostPhysAddr, MemFlags, MemoryRegion, MemorySet }, }; -// #[cfg(feature = "plic")] + use crate::memory::HV_PT; -// #[cfg(feature = "plic")] + pub fn init_hv_page_table(fdt: &fdt::Fdt) -> HvResult { let mut hv_pt: MemorySet = MemorySet::new(); // let _ = hv_pt.insert(MemoryRegion::new_with_offset_mapper( diff --git a/src/device/irqchip/aia/aplic.rs b/src/device/irqchip/aia/aplic.rs index 20dcc74..55f828f 100644 --- a/src/device/irqchip/aia/aplic.rs +++ b/src/device/irqchip/aia/aplic.rs @@ -284,6 +284,10 @@ pub fn vaplic_emul_handler( ); } } + Instruction::Lw(i) => { + let value = host_aplic.read().get_domaincfg(); + current_cpu.x[i.rd() as usize] = value as usize; + } _ => panic!("Unexpected instruction {:?}", inst), } } diff --git a/src/device/irqchip/aia/imsic.rs b/src/device/irqchip/aia/imsic.rs index f44e7a4..2053b02 100644 --- a/src/device/irqchip/aia/imsic.rs +++ b/src/device/irqchip/aia/imsic.rs @@ -41,11 +41,6 @@ fn imsic_read(reg: usize) -> usize { pub fn imsic_trigger(hart: u32, guest: u32, eiid: u32) { - // let eipbyte = EIP + XLEN_STRIDE * irq / XLEN; - // let bit = irq % XLEN; - // imsic_write(CSR_VSISELECT, eipbyte); - // let reg = imsic_read(CSR_VSIREG); - // imsic_write(CSR_VSIREG, reg | 1 << bit); if guest == 1{ unsafe { core::ptr::write_volatile(imsic_vs(hart as usize) as *mut u32, eiid); diff --git a/src/device/irqchip/mod.rs b/src/device/irqchip/mod.rs index 8a76daf..ba82959 100644 --- a/src/device/irqchip/mod.rs +++ b/src/device/irqchip/mod.rs @@ -14,8 +14,10 @@ pub use gicv3::{inject_irq, percpu_init, primary_init_early, primary_init_late}; #[cfg(target_arch = "riscv64")] #[cfg(feature = "plic")] -pub use plic::{inject_irq, percpu_init, primary_init_early, primary_init_late}; +pub use plic::{inject_irq, percpu_init, primary_init_early, primary_init_late, + host_plic, vplic_global_emul_handler, vplic_hart_emul_handler}; #[cfg(target_arch = "riscv64")] #[cfg(feature = "aia")] -pub use aia::aplic::{inject_irq, percpu_init, primary_init_early, primary_init_late}; +pub use aia::aplic::{inject_irq, percpu_init, primary_init_early, primary_init_late, + host_aplic, vaplic_emul_handler}; diff --git a/src/main.rs b/src/main.rs index c765ca4..5820183 100644 --- a/src/main.rs +++ b/src/main.rs @@ -114,10 +114,9 @@ fn percpu_hv_pt_install(cpu: &mut PerCpu) { if cpu.zone.is_none() { warn!("zone is not created for cpu {}", cpu.id); } - #[cfg(feature = "plic")] - unsafe { - memory::hv_page_table().read().activate(); - }; + // unsafe { + // memory::hv_page_table().read().activate(); + // }; info!("CPU {} hv_pt_install OK.", cpu.id); } diff --git a/src/memory/mod.rs b/src/memory/mod.rs index e29a89a..e602cf7 100644 --- a/src/memory/mod.rs +++ b/src/memory/mod.rs @@ -36,9 +36,8 @@ bitflags! { } /// Page table used for hypervisor. -// #[cfg(feature = "plic")] pub static HV_PT: Once>> = Once::new(); -// #[cfg(feature = "plic")] + pub fn hv_page_table<'a>() -> &'a RwLock> { HV_PT.get().expect("Uninitialized hypervisor page table!") } From cb8b9a3ddcd287348759937c1c715760d828abcc Mon Sep 17 00:00:00 2001 From: dorso <2434317248@qq.com> Date: Wed, 30 Oct 2024 21:34:37 +0800 Subject: [PATCH 6/6] Add AIA and Solve the problem of TAB completion --- Cargo.toml | 3 + Makefile | 5 +- images/riscv64/devicetree/linux1-aia.dts | 171 ++++++++ scripts/qemu-riscv64.mk | 16 +- src/arch/riscv64/cpu.rs | 2 +- src/arch/riscv64/trap.rs | 106 +++-- src/arch/riscv64/zone.rs | 41 +- src/device/irqchip/aia/aplic.rs | 492 +++++++++++++++++++++++ src/device/irqchip/aia/imsic.rs | 55 +++ src/device/irqchip/aia/mod.rs | 1 + src/device/irqchip/mod.rs | 14 +- src/platform/mod.rs | 2 +- src/platform/qemu_riscv64.rs | 3 + 13 files changed, 871 insertions(+), 40 deletions(-) create mode 100644 images/riscv64/devicetree/linux1-aia.dts create mode 100644 src/device/irqchip/aia/aplic.rs create mode 100644 src/device/irqchip/aia/imsic.rs create mode 100644 src/device/irqchip/aia/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 2a1ccea..8e46844 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,9 @@ loongArch64 = "0.2.4" [features] platform_qemu = [] platform_imx8mp = [] +default = ["aia"] +plic = [] +aia = [] [profile.dev] panic = "abort" diff --git a/Makefile b/Makefile index 5de9cce..6488e3d 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # Basic settings -ARCH ?= aarch64 +ARCH ?= riscv64 LOG ?= info STATS ?= off PORT ?= 2333 @@ -7,6 +7,7 @@ MODE ?= debug OBJCOPY ?= rust-objcopy --binary-architecture=$(ARCH) KDIR ?= ../../linux FEATURES ?= platform_qemu +IRQ ?= plic ifeq ($(ARCH),aarch64) RUSTC_TARGET := aarch64-unknown-none @@ -33,7 +34,7 @@ image_dir := images/$(ARCH) # Build arguments build_args := -build_args += --features "$(FEATURES)" +build_args += --features "$(FEATURES)" build_args += --target $(RUSTC_TARGET) build_args += -Z build-std=core,alloc build_args += -Z build-std-features=compiler-builtins-mem diff --git a/images/riscv64/devicetree/linux1-aia.dts b/images/riscv64/devicetree/linux1-aia.dts new file mode 100644 index 0000000..a4f7332 --- /dev/null +++ b/images/riscv64/devicetree/linux1-aia.dts @@ -0,0 +1,171 @@ +/dts-v1/; + +/ { + #address-cells = <0x2>; + #size-cells = <0x2>; + + cpus { + #address-cells = <0x1>; + #size-cells = <0x0>; + timebase-frequency = <10000000>; + cpu@0 { + device_type = "cpu"; + reg = <0x0>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcsu_ssaia_sstc"; + mmu-type = "riscv,sv39"; + + cpu0_intc: interrupt-controller { + #interrupt-cells = <0x1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + phandle = <0x04>; + }; + }; + cpu@1 { + device_type = "cpu"; + reg = <0x1>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcsu_ssaia_sstc"; + mmu-type = "riscv,sv39"; + + cpu1_intc: interrupt-controller { + #interrupt-cells = <0x1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + }; + }; + cpu@2 { + device_type = "cpu"; + reg = <0x2>; + status = "okay"; + compatible = "riscv"; + riscv,isa = "rv64imafdcsu_ssaia_sstc"; + mmu-type = "riscv,sv39"; + + cpu2_intc: interrupt-controller { + #interrupt-cells = <0x1>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + }; + }; + }; + + memory@83000000 { + device_type = "memory"; + reg = <0x0 0x83000000 0x0 0x1D000000>; + }; + + reserved-memory { + #address-cells = <0x02>; + #size-cells = <0x02>; + ranges; + + nonroot@0x83000000 { + no-map; + reg = <0x00 0x83000000 0x00 0x0C000000>; + }; + + dtbfile@0x8f000000 { + no-map; + reg = <0x00 0x8f000000 0x00 0x01000000>; + }; + }; + +soc{ + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "simple-bus"; + ranges; + + aplic@d000000 { + phandle = <0x08>; + riscv,num-sources = <0x60>; + reg = <0x00 0xd000000 0x00 0x8000>; + msi-parent = <0x06>; + interrupt-controller; + #interrupt-cells = <0x02>; + compatible = "riscv,aplic"; + }; + + imsics@28000000 { + phandle = <0x06>; + riscv,num-ids = <0xff>; + reg = <0x00 0x28000000 0x00 0x4000>; + interrupts-extended = < + &cpu0_intc 9 + &cpu1_intc 9 + &cpu2_intc 9 + >; + msi-controller; + interrupt-controller; + #interrupt-cells = <0x00>; + compatible = "riscv,imsics"; + }; + + virtio_mmio@10008000 { + interrupts = <0x8 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10008000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10005000 { + interrupts = <0x5 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10005000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10004000 { + interrupts = <0x4 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10004000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10003000 { + interrupts = <0x3 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10003000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10002000 { + interrupts = <0x2 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10002000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + virtio_mmio@10001000 { + interrupts = <0x1 0x04>; + interrupt-parent = <0x08>; + reg = <0x0 0x10001000 0x0 0x1000>; + compatible = "virtio,mmio"; + }; + pci@30000000 { + interrupt-map-mask = <0x1800 0x00 0x00 0x07>; + interrupt-map = <0x00 0x00 0x00 0x01 0x09 0x20 0x00 0x00 0x00 0x02 0x09 0x21 0x00 0x00 0x00 0x03 0x09 0x22 0x00 0x00 0x00 0x04 0x09 0x23 0x800 0x00 0x00 0x01 0x09 0x21 0x800 0x00 0x00 0x02 0x09 0x22 0x800 0x00 0x00 0x03 0x09 0x23 0x800 0x00 0x00 0x04 0x09 0x20 0x1000 0x00 0x00 0x01 0x09 0x22 0x1000 0x00 0x00 0x02 0x09 0x23 0x1000 0x00 0x00 0x03 0x09 0x20 0x1000 0x00 0x00 0x04 0x09 0x21 0x1800 0x00 0x00 0x01 0x09 0x23 0x1800 0x00 0x00 0x02 0x09 0x20 0x1800 0x00 0x00 0x03 0x09 0x21 0x1800 0x00 0x00 0x04 0x09 0x22>; + ranges = <0x1000000 0x00 0x00 0x00 0x3000000 0x00 0x10000 0x2000000 0x00 0x40000000 0x00 0x40000000 0x00 0x40000000 0x3000000 0x04 0x00 0x04 0x00 0x04 0x00>; + reg = <0x00 0x30000000 0x00 0x10000000>; + dma-coherent; + bus-range = <0x00 0xff>; + linux,pci-domain = <0x00>; + device_type = "pci"; + compatible = "pci-host-ecam-generic"; + #size-cells = <0x02>; + #interrupt-cells = <0x01>; + #address-cells = <0x03>; + }; + uart@10000000 { + interrupts = <0x0a 0x04>; + interrupt-parent = <0x08>; + clock-frequency = "\08@"; + reg = <0x00 0x10000000 0x00 0x100>; + compatible = "ns16550a"; + }; + +}; + chosen { + bootargs = "root=/dev/vda rw earlycon console=ttyS0 init=/bin/bash"; + }; + +}; \ No newline at end of file diff --git a/scripts/qemu-riscv64.mk b/scripts/qemu-riscv64.mk index 833bb24..bb5b7e9 100644 --- a/scripts/qemu-riscv64.mk +++ b/scripts/qemu-riscv64.mk @@ -5,12 +5,17 @@ FSIMG1 := $(image_dir)/virtdisk/rootfs1.ext4 FSIMG2 := $(image_dir)/virtdisk/rootfs-busybox.qcow2 # HVISOR ENTRY HVISOR_ENTRY_PA := 0x80200000 -zone0_kernel := $(image_dir)/kernel/Image +zone0_kernel := $(image_dir)/kernel/Image-aia-6.10 zone0_dtb := $(image_dir)/devicetree/linux1.dtb +zone0_aia_dtb := $(image_dir)/devicetree/linux1-aia.dtb # zone1_kernel := $(image_dir)/kernel/Image # zone1_dtb := $(image_dir)/devicetree/linux.dtb -QEMU_ARGS := -machine virt +ifeq ($(IRQ),aia) + QEMU_ARGS := -machine virt,aclint=on,aia=aplic-imsic,aia-guests=1 +else ifeq ($(IRQ),plic) + QEMU_ARGS := -machine virt +endif QEMU_ARGS += -bios default QEMU_ARGS += -cpu rv64 QEMU_ARGS += -smp 4 @@ -18,10 +23,17 @@ QEMU_ARGS += -m 2G QEMU_ARGS += -nographic QEMU_ARGS += -kernel $(hvisor_bin) +ifeq ($(IRQ),aia) +QEMU_ARGS += -device loader,file="$(zone0_kernel)",addr=0x90000000,force-raw=on +QEMU_ARGS += -device loader,file="$(zone0_aia_dtb)",addr=0x8f000000,force-raw=on +# QEMU_ARGS += -device loader,file="$(zone1_aia_kernel)",addr=0x84000000,force-raw=on +# QEMU_ARGS += -device loader,file="$(zone1_aia_dtb)",addr=0x83000000,force-raw=on +else ifeq ($(IRQ),plic) QEMU_ARGS += -device loader,file="$(zone0_kernel)",addr=0x90000000,force-raw=on QEMU_ARGS += -device loader,file="$(zone0_dtb)",addr=0x8f000000,force-raw=on # QEMU_ARGS += -device loader,file="$(zone1_kernel)",addr=0x84000000,force-raw=on # QEMU_ARGS += -device loader,file="$(zone1_dtb)",addr=0x83000000,force-raw=on +endif QEMU_ARGS += -drive if=none,file=$(FSIMG1),id=X10008000,format=raw QEMU_ARGS += -device virtio-blk-device,drive=X10008000,bus=virtio-mmio-bus.7 diff --git a/src/arch/riscv64/cpu.rs b/src/arch/riscv64/cpu.rs index c159dd4..867f9a4 100644 --- a/src/arch/riscv64/cpu.rs +++ b/src/arch/riscv64/cpu.rs @@ -52,7 +52,7 @@ impl ArchCpu { //self.sepc = guest_test as usize as u64; write_csr!(CSR_SSCRATCH, self as *const _ as usize); //arch cpu pointer self.sepc = entry; - self.hstatus = 1 << 7 | 2 << 32; //HSTATUS_SPV | HSTATUS_VSXL_64 + self.hstatus = 1 << 7 | 2 << 32 | 1 << 12; //HSTATUS_SPV | HSTATUS_VSXL_64 | HSTATUS_VGEIN self.sstatus = 1 << 8 | 1 << 63 | 3 << 13 | 3 << 15; //SPP self.stack_top = self.stack_top() as usize; self.x[10] = cpu_id; //cpu id diff --git a/src/arch/riscv64/trap.rs b/src/arch/riscv64/trap.rs index a3cfd7d..7716a53 100644 --- a/src/arch/riscv64/trap.rs +++ b/src/arch/riscv64/trap.rs @@ -2,7 +2,10 @@ use super::cpu::ArchCpu; use crate::arch::csr::read_csr; use crate::arch::csr::*; use crate::arch::sbi::sbi_vs_handler; +#[cfg(feature = "plic")] use crate::device::irqchip::plic::{host_plic, vplic_global_emul_handler, vplic_hart_emul_handler}; +#[cfg(feature = "aia")] +use crate::device::irqchip::aia::aplic::{host_aplic, vaplic_emul_handler}; use crate::event::check_events; use crate::memory::{GuestPhysAddr, HostPhysAddr}; use crate::platform::qemu_riscv64::*; @@ -87,44 +90,78 @@ pub fn sync_exception_handler(current_cpu: &mut ArchCpu) { pub fn guest_page_fault_handler(current_cpu: &mut ArchCpu) { let addr: HostPhysAddr = read_csr!(CSR_HTVAL) << 2; trace!("guest page fault at {:#x}", addr); - let host_plic_base = host_plic().read().base; - let mut ins_size: usize = 0; - //TODO: get plic addr range from dtb or vpliv object - if addr >= host_plic_base && addr < host_plic_base + PLIC_TOTAL_SIZE { - trace!("PLIC access"); - let mut inst: u32 = read_csr!(CSR_HTINST) as u32; - if inst == 0 { - let inst_addr: GuestPhysAddr = current_cpu.sepc; - //load real ins from guest memmory - inst = read_inst(inst_addr); - ins_size = if inst & 0x3 == 3 { 4 } else { 2 }; - } else if inst == 0x3020 || inst == 0x3000 { - // TODO: we should reinject this in the guest as a fault access - error!("fault on 1st stage page table walk"); + #[cfg(feature = "plic")]{ + let host_plic_base = host_plic().read().base; + let mut ins_size: usize = 0; + //TODO: get plic addr range from dtb or vpliv object + if addr >= host_plic_base && addr < host_plic_base + PLIC_TOTAL_SIZE { + trace!("PLIC access"); + let mut inst: u32 = read_csr!(CSR_HTINST) as u32; + if inst == 0 { + let inst_addr: GuestPhysAddr = current_cpu.sepc; + //load real ins from guest memmory + inst = read_inst(inst_addr); + ins_size = if inst & 0x3 == 3 { 4 } else { 2 }; + } else if inst == 0x3020 || inst == 0x3000 { + // TODO: we should reinject this in the guest as a fault access + error!("fault on 1st stage page table walk"); + } else { + // If htinst is valid and is not a pseudo instructon make sure + // the opcode is valid even if it was a compressed instruction, + // but before save the real instruction size. + ins_size = if (inst) & 0x2 == 0 { 2 } else { 4 }; + inst = inst | 0b10; + // error!("unhandled guest page fault at {:#x}", addr); + // panic!("inst{:#x}", inst); + } + //TODO: decode inst to real instruction + let (_len, inst) = decode_inst(inst); + if let Some(inst) = inst { + if addr >= host_plic_base + PLIC_GLOBAL_SIZE { + vplic_hart_emul_handler(current_cpu, addr, inst); + } else { + vplic_global_emul_handler(current_cpu, addr, inst); + } + current_cpu.sepc += ins_size; + } else { + error!("Invalid instruction at {:#x}", current_cpu.sepc); + panic!(); + } } else { - // If htinst is valid and is not a pseudo instructon make sure - // the opcode is valid even if it was a compressed instruction, - // but before save the real instruction size. - ins_size = if (inst) & 0x2 == 0 { 2 } else { 4 }; - inst = inst | 0b10; - // error!("unhandled guest page fault at {:#x}", addr); - // panic!("inst{:#x}", inst); + panic!("CPU {} unmaped memmory at {:#x}", current_cpu.cpuid, addr); } - //TODO: decode inst to real instruction - let (_len, inst) = decode_inst(inst); - if let Some(inst) = inst { - if addr >= host_plic_base + PLIC_GLOBAL_SIZE { - vplic_hart_emul_handler(current_cpu, addr, inst); + } + #[cfg(feature = "aia")]{ + let host_aplic_base = host_aplic().read().base; + let host_aplic_size = host_aplic().read().size; + + if addr >= host_aplic_base && addr < host_aplic_base + host_aplic_size { + trace!("APLIC access"); + let mut inst: u32 = read_csr!(CSR_HTINST) as u32; + let mut ins_size: usize = 0; + if inst == 0 { + let inst_addr: GuestPhysAddr = current_cpu.sepc; + inst = read_inst(inst_addr); + ins_size = if inst & 0x3 == 3 { 4 } else { 2 }; + } else if inst == 0x3020 || inst == 0x3000 { + error!("fault on 1st stage page table walk"); } else { - vplic_global_emul_handler(current_cpu, addr, inst); + ins_size = if (inst) & 0x2 == 0 { 2 } else { 4 }; + inst = inst | 0b10; + // error!("unhandled guest page fault at {:#x}", addr); + } + // let (len, inst) = decode_inst(inst); + let (_, inst) = decode_inst(inst); + + if let Some(inst) = inst { + vaplic_emul_handler(current_cpu, addr, inst); + current_cpu.sepc += ins_size; + } else { + error!("Invalid instruction at {:#x}", current_cpu.sepc); } - current_cpu.sepc += ins_size; } else { - error!("Invalid instruction at {:#x}", current_cpu.sepc); - panic!(); + panic!("CPU {} unmaped memmory at {:#x}", current_cpu.cpuid, addr); } - } else { - panic!("CPU {} unmaped memmory at {:#x}", current_cpu.cpuid, addr); } } fn read_inst(addr: GuestPhysAddr) -> u32 { @@ -200,6 +237,7 @@ pub fn interrupts_arch_handle(current_cpu: &mut ArchCpu) { /// handle interrupt request(current only external interrupt) pub fn handle_eirq(current_cpu: &mut ArchCpu) { + #[cfg(feature = "plic")]{ // TODO: handle other irq // check external interrupt && handle // sifive plic: context0=>cpu0,M mode,context1=>cpu0,S mode... @@ -215,6 +253,10 @@ pub fn handle_eirq(current_cpu: &mut ArchCpu) { host_plic.write().claim_complete[context_id] = irq; // set external interrupt pending, which trigger guest interrupt unsafe { hvip::set_vseip() }; + } + #[cfg(feature = "aia")]{ + panic!("HS extensional interrupt") + } } pub fn handle_ssi(current_cpu: &mut ArchCpu) { trace!("handle_ssi"); diff --git a/src/arch/riscv64/zone.rs b/src/arch/riscv64/zone.rs index 5b76714..9d166cb 100644 --- a/src/arch/riscv64/zone.rs +++ b/src/arch/riscv64/zone.rs @@ -38,7 +38,44 @@ impl Zone { } } } - + #[cfg(feature = "aia")]{ + use crate::memory::PAGE_SIZE; + let paddr = 0x2800_0000 as HostPhysAddr; + let size = PAGE_SIZE; + self.gpm.insert(MemoryRegion::new_with_offset_mapper( + paddr as GuestPhysAddr, + paddr + PAGE_SIZE * 1, + size, + MemFlags::READ | MemFlags::WRITE, + ))?; + + let paddr = 0x2800_1000 as HostPhysAddr; + let size = PAGE_SIZE; + self.gpm.insert(MemoryRegion::new_with_offset_mapper( + paddr as GuestPhysAddr, + paddr + PAGE_SIZE * 2, + size, + MemFlags::READ | MemFlags::WRITE, + ))?; + + let paddr = 0x2800_2000 as HostPhysAddr; + let size = PAGE_SIZE; + self.gpm.insert(MemoryRegion::new_with_offset_mapper( + paddr as GuestPhysAddr, + paddr + PAGE_SIZE * 3, + size, + MemFlags::READ | MemFlags::WRITE, + ))?; + + let paddr = 0x2800_3000 as HostPhysAddr; + let size = PAGE_SIZE; + self.gpm.insert(MemoryRegion::new_with_offset_mapper( + paddr as GuestPhysAddr, + paddr + PAGE_SIZE * 4, + size, + MemFlags::READ | MemFlags::WRITE, + ))?; + } info!("VM stage 2 memory set: {:#x?}", self.gpm); Ok(()) } @@ -70,4 +107,6 @@ impl Zone { pub struct HvArchZoneConfig { pub plic_base: usize, pub plic_size: usize, + pub aplic_base: usize, + pub aplic_size: usize, } \ No newline at end of file diff --git a/src/device/irqchip/aia/aplic.rs b/src/device/irqchip/aia/aplic.rs new file mode 100644 index 0000000..8764d70 --- /dev/null +++ b/src/device/irqchip/aia/aplic.rs @@ -0,0 +1,492 @@ + +use riscv::use_sv32; +use spin::RwLock; +use spin::Once; +// use crate::device::irqchip::aia::imsic::imsic_trigger; +use crate::{arch::cpu::ArchCpu, percpu::this_cpu_data, memory::GuestPhysAddr}; +use riscv_decode::Instruction; +use fdt::Fdt; +use crate::zone::Zone; +use crate::config::root_zone_config; +// S-mode interrupt delivery controller +const APLIC_S_IDC: usize = 0xd00_4000; +pub const APLIC_DOMAINCFG_BASE: usize = 0x0000; +pub const APLIC_SOURCECFG_BASE: usize = 0x0004; +pub const APLIC_SOURCECFG_TOP: usize = 0x1000; +pub const APLIC_MSIADDR_BASE: usize = 0x1BC8; +pub const APLIC_PENDING_BASE: usize = 0x1C00; +pub const APLIC_PENDING_TOP: usize = 0x1C7C; +pub const APLIC_IPNUM_BASE: usize = 0x1CDC; +pub const APLIC_CLRIP_BASE: usize = 0x1D00; +pub const APLIC_ENABLE_BASE: usize = 0x1E00; +pub const APLIC_ENABLE_TOP: usize = 0x1E7C; +pub const APLIC_ENABLE_NUM: usize = 0x1EDC; +pub const APLIC_CLRIE_BASE: usize = 0x1F00; +pub const APLIC_CLRIE_NUM_BASE: usize = 0x1FDC; +pub const APLIC_IPNUM_LE_BASE: usize = 0x2000; +pub const APLIC_TARGET_BASE: usize = 0x3004; +pub const APLIC_IDC_BASE: usize = 0x4000; + +#[repr(u32)] +#[allow(dead_code)] +pub enum SourceModes { + Inactive = 0, + Detached = 1, + RisingEdge = 4, + FallingEdge = 5, + LevelHigh = 6, + LevelLow = 7, +} + +// offset size register name +// 0x0000 4 bytes domaincfg +// 0x0004 4 bytes sourcecfg[1] +// 0x0008 4 bytes sourcecfg[2] +// . . . . . . +// 0x0FFC 4 bytes sourcecfg[1023] +// 0x1BC0 4 bytes mmsiaddrcfg (machine-level interrupt domains only) +// 0x1BC4 4 bytes mmsiaddrcfgh ” +// 0x1BC8 4 bytes smsiaddrcfg ” +// 0x1BCC 4 bytes smsiaddrcfgh ” +// 0x1C00 4 bytes setip[0] +// 0x1C04 4 bytes setip[1] +// . . . . . . +// 0x1C7C 4 bytes setip[31] +// 0x1CDC 4 bytes setipnum +// 0x1D00 4 bytes in clrip[0] +// 0x1D04 4 bytes in clrip[1] +// . . . . . . +// 0x1D7C 4 bytes in clrip[31] +// 0x1DDC 4 bytes clripnum +// 0x1E00 4 bytes setie[0] +// 0x1E04 4 bytes setie[1] +// . . . . . . +// 0x1E7C 4 bytes setie[31] +// 0x1EDC 4 bytes setienum +// 0x1F00 4 bytes clrie[0] +// 0x1F04 4 bytes clrie[1] +// . . . . . . +// 0x1F7C 4 bytes clrie[31] +// 0x1FDC 4 bytes clrienum +// 0x2000 4 bytes setipnum le +// 0x2004 4 bytes setipnum be +// 0x3000 4 bytes genmsi +// 0x3004 4 bytes target[1] +// 0x3008 4 bytes target[2] +// . . . . . . +// 0x3FFC 4 bytes target[1023] + +pub fn primary_init_early() { + let root_config = root_zone_config(); + init_aplic( + root_config.arch_config.aplic_base as usize, + root_config.arch_config.aplic_size as usize, + ); +} +pub fn primary_init_late() { + //nothing to do +} +pub fn percpu_init() { + //nothing to do +} +pub fn inject_irq(_irq: usize, is_hardware: bool) { + //nothing to do +} +pub static APLIC: Once> = Once::new(); +pub fn host_aplic<'a>() -> &'a RwLock { + APLIC.get().expect("Uninitialized hypervisor aplic!") +} + +#[repr(C)] +pub struct Aplic { + pub base: usize, + pub size: usize, +} + +#[allow(dead_code)] +impl Aplic { + pub fn new(base: usize, size: usize) -> Self { + Self { + base, + size, + } + } + pub fn set_domaincfg(&self, bigendian: bool, msimode: bool, enabled: bool){ + let enabled = u32::from(enabled); + let msimode = u32::from(msimode); + let bigendian = u32::from(bigendian); + let addr = self.base + APLIC_DOMAINCFG_BASE; + let bigendian = 0 ; + let src = (enabled << 8) | (msimode << 2) | bigendian; + unsafe { + core::ptr::write_volatile(addr as *mut u32, src); + } + } + pub fn get_domaincfg(&self) -> u32{ + let addr = self.base + APLIC_DOMAINCFG_BASE; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn get_msimode(&self) -> bool{ + let addr = self.base + APLIC_DOMAINCFG_BASE; + let value= unsafe { core::ptr::read_volatile(addr as *const u32) }; + ((value >> 2) & 0b11) != 0 + } + pub fn set_sourcecfg(&self, irq: u32, mode: SourceModes){ + assert!(irq > 0 && irq < 1024); + let addr = self.base + APLIC_SOURCECFG_BASE + (irq as usize - 1) * 4; + let src = mode as u32; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + } + } + pub fn set_sourcecfg_delegate(&self, irq: u32, child: u32){ + assert!(irq > 0 && irq < 1024); + let addr = self.base + APLIC_SOURCECFG_BASE + (irq as usize - 1) * 4; + let src = 1 << 10 | child & 0x3ff; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + } + } + pub fn get_sourcecfg(&self, irq: u32) -> u32{ + assert!(irq > 0 && irq < 1024); + let addr = self.base + APLIC_SOURCECFG_BASE + (irq as usize - 1) * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn set_msiaddr(&self, address: usize){ + let addr = self.base + APLIC_MSIADDR_BASE; + let src = (address >> 12) as u32; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + core:: ptr::write_volatile((addr + 4) as *mut u32, 0); + } + } + pub fn get_ip(&self, irqidx: usize) -> u32{ + assert!(irqidx < 32); + let addr = self.base + APLIC_PENDING_BASE + irqidx * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn get_clrip(&self, irqidx: usize) -> u32{ + assert!(irqidx < 32); + let addr = self.base + APLIC_CLRIP_BASE + irqidx * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn set_ip(&self, irqidx: usize, src: u32, pending: bool){ + assert!(irqidx < 32); + let addr = self.base + APLIC_PENDING_BASE + irqidx * 4; + let clr_addr = self.base + APLIC_CLRIP_BASE + irqidx * 4; + if pending { + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + } + } else { + unsafe{ + core:: ptr::write_volatile(clr_addr as *mut u32, src); + } + } + } + pub fn set_ipnum(&self, value: u32){ + let addr = self.base + APLIC_IPNUM_BASE; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, value); + } + } + pub fn get_in_clrip(&self, irqidx: usize) -> u32{ + assert!(irqidx < 32); + let addr = self.base + APLIC_CLRIP_BASE + irqidx * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn get_ie(&self, irqidx: usize) -> u32{ + assert!(irqidx < 32); + let addr = self.base + APLIC_ENABLE_BASE + irqidx * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn get_clrie(&self, irqidx: usize) -> u32{ + assert!(irqidx < 32); + let addr = self.base + APLIC_CLRIE_BASE + irqidx * 4; + unsafe { core::ptr::read_volatile(addr as *const u32) } + } + pub fn setie(&self, irqidx: usize, value: u32, enabled: bool){ + assert!(irqidx < 32); + let addr = self.base + APLIC_ENABLE_BASE + irqidx * 4; + let clr_addr = self.base + APLIC_CLRIE_BASE + irqidx * 4; + if enabled { + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, value); + } + } else { + unsafe{ + core:: ptr::write_volatile(clr_addr as *mut u32, value); + } + } + } + pub fn setienum(&self, value: u32){ + let addr = self.base + APLIC_ENABLE_NUM; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, value); + } + } + pub fn clrienum(&self, value: u32){ + let addr = self.base + APLIC_CLRIE_NUM_BASE; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, value); + } + } + pub fn setipnum_le(&self, value: u32){ + let addr = self.base + APLIC_IPNUM_LE_BASE; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, value); + } + } + pub fn set_target_msi(&self, irq: u32, hart: u32, guest: u32, eiid: u32){ + let addr = self.base + APLIC_TARGET_BASE + (irq as usize - 1) * 4; + let src = (hart << 18) | (guest << 12) | eiid; + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + } + } + pub fn set_target_direct(&self, irq: u32, hart: u32, prio: u32){ + let addr = self.base + APLIC_TARGET_BASE + (irq as usize - 1) * 4; + let src = (hart << 18) | (prio & 0xFF); + unsafe{ + core:: ptr::write_volatile(addr as *mut u32, src); + } + } + pub fn get_target_info(&self, irq: u32) -> (u32, u32, u32) { + let addr = self.base + APLIC_TARGET_BASE + (irq as usize - 1) * 4; + unsafe { + let src = core::ptr::read_volatile(addr as *const u32); + let hart = (src >> 18) & 0x3F; + let guest = (src >> 12) & 0x3F; + let eiid = src & 0xFFF; + (hart, guest, eiid) + } + } +} +pub fn vaplic_emul_handler( + current_cpu: &mut ArchCpu, + addr: GuestPhysAddr, + inst: Instruction, +) { + let host_aplic = host_aplic(); + let offset = addr.wrapping_sub(host_aplic.read().base); + if offset >= APLIC_DOMAINCFG_BASE && offset < APLIC_SOURCECFG_BASE { + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; // 要写入的 value + let enabled = ((value >> 8) & 0x1) != 0; // IE + let msimode = ((value >> 2) & 0b1) != 0; // DM / MSI + let bigendian = (value & 0b1) != 0; // 大小端 + if this_cpu_data().id != 3{ + host_aplic.write().set_domaincfg(bigendian, msimode, enabled); + debug!( + "APLIC set domaincfg write addr@{:#x} bigendian {} msimode {} enabled {}", + addr, bigendian, msimode, enabled + ); + } + } + Instruction::Lw(i) => { + let value = host_aplic.read().get_domaincfg(); + current_cpu.x[i.rd() as usize] = value as usize; + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } + else if offset >= APLIC_SOURCECFG_BASE && offset < APLIC_SOURCECFG_TOP { + //sourcecfg + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + let irq = ((offset - APLIC_SOURCECFG_BASE) / 4) + 1; + if (value >> 10) & 0b1 == 1 { + //delegate + let child = value & 0x3ff; + host_aplic.write().set_sourcecfg_delegate(irq as u32, child); + debug!( + "APLIC set sourcecfg_delegate write addr@{:#x} irq {} child {}", + addr, + irq, + child + ); + } else { + let mode = match value { + 0 => SourceModes::Inactive, + 1 => SourceModes::Detached, + 4 => SourceModes::RisingEdge, + 5 => SourceModes::FallingEdge, + 6 => SourceModes::LevelHigh, + 7 => SourceModes::LevelLow, + _ => panic!("Unknown sourcecfg mode"), + }; + if this_cpu_data().id != 3 || + this_cpu_data().id == 3 && (irq == 6 || irq == 7){ + host_aplic.write().set_sourcecfg(irq as u32, mode); + debug!( + "APLIC set sourcecfg write addr@{:#x} irq {} mode {}", + addr, + irq, + value + ); + } + } + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } else if offset >= APLIC_MSIADDR_BASE && offset <= 0x1BCC { + // msia + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + let address = (value as usize) << 12; + host_aplic.write().set_msiaddr(address); + debug!( + "APLIC set msiaddr write addr@{:#x} address {}", + addr, address + ); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } else if offset >= APLIC_PENDING_BASE && offset < APLIC_PENDING_TOP { + // pending + panic!("setip Unexpected instruction {:?}", inst); + } + // setipnum 区域 0x1CDC - 0x1CE0 + else if offset >= 0x1CDC && offset < 0x1CE0 { + panic!("setipnum Unexpected instruction {:?}", inst) + } + else if offset >= APLIC_CLRIP_BASE && offset < 0x1D80 { + // panic!("addr@{:#x} in_clrip Unexpected instruction {:?}", offset ,inst); + match inst { + Instruction::Lw(i) => { + let irqidx = (offset - APLIC_CLRIP_BASE) / 4; + let value = host_aplic.read().get_in_clrip(irqidx); + current_cpu.x[i.rd() as usize] = value as usize; + debug!( + "APLIC read in clrip addr@{:#x} irqidx {} value {}", + addr, irqidx, value + ); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } + // clripnum 区域 + else if offset >= 0x1DDC && offset < 0x1DE0 { + panic!("clripnum Unexpected instruction {:?}", inst) + } + // setie + else if offset >= APLIC_ENABLE_BASE && offset < 0x1E80 { + panic!("setie Unexpected instruction {:?}", inst); + } + else if offset >= APLIC_ENABLE_NUM && offset < 0x1EE0 { + // setienum + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + host_aplic.write().setienum(value); + debug!( + "APLIC setienum write addr@{:#x} value {}", + addr, value + ); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } else if offset >= APLIC_CLRIE_BASE && offset < 0x1FDC { + // clrie + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + let irqidx = (offset - APLIC_CLRIE_BASE) / 4; + if this_cpu_data().id != 3{ + host_aplic.write().setie(irqidx, value, false); + } + debug!( + "APLIC set clrie write addr@{:#x} irqidx {} value@{:#x}", + addr, irqidx, value + ); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } + // clrienum + else if offset >= 0x1FDC && offset < 0x1FE0 { + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + host_aplic.write().clrienum(value); + debug!( + "APLIC set clrienum write addr@{:#x} value{}", + offset, value + ); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + + } + // setipnum_le + else if offset >= 0x2000 && offset < 0x2004 { + match inst { + Instruction::Sw(i) => { + let value = current_cpu.x[i.rs2() as usize] as u32; + host_aplic.write().setipnum_le(value); + // debug!("APLIC setipnum le write addr@{:#x} value@{:#x}",offset, value); + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } + // setipnum_be + else if offset >= 0x2004 && offset < 0x2008 { + panic!("setipnum_be Unexpected instruction {:?}", inst) + } + // genmsi + else if offset >= 0x3000 && offset < 0x3004 { + panic!("genmsi Unexpected instruction {:?}", inst) + } + else if offset >= APLIC_TARGET_BASE && offset < APLIC_IDC_BASE { + // target + match inst { + Instruction::Sw(i) => { + let first_cpu = this_cpu_data() + .zone + .as_ref() + .unwrap() + .read() + .cpu_set + .first_cpu() + .unwrap(); + let value = current_cpu.x[i.rs2() as usize] as u32; + let irq = ((offset - APLIC_TARGET_BASE) / 4) as u32 + 1; + let hart = ((value >> 18) & 0x3F) + first_cpu as u32; + if host_aplic.read().get_msimode() { + let guest = ((value >> 12) & 0x3F) + 1; + let eiid = value & 0xFFF; + if this_cpu_data().id != 3 || + this_cpu_data().id == 3 && (irq == 6 || irq == 7){ + host_aplic.write().set_target_msi(irq, hart, guest, eiid); + debug!( + "APLIC set msi target write addr@{:#x} irq {} hart {} guest {} eiid {}", + addr, irq, hart, guest, eiid + ); + } + } else { + let prio = value & 0xFF; + host_aplic.write().set_target_direct(irq, hart, prio); + debug!( + "APLIC set direct target write addr@{:#x} irq {} hart {} prio {}", + addr, irq, hart, prio + ); + } + } + _ => panic!("Unexpected instruction {:?}", inst), + } + } else { + panic!("Invalid address: {:#x}", addr); + } +} +pub fn init_aplic(aplic_base: usize, aplic_size: usize) { + let aplic = Aplic::new(aplic_base, aplic_size); + APLIC.call_once(|| RwLock::new(aplic)); +} +impl Zone { + pub fn arch_irqchip_reset(&self) { + //TODO + } +} \ No newline at end of file diff --git a/src/device/irqchip/aia/imsic.rs b/src/device/irqchip/aia/imsic.rs new file mode 100644 index 0000000..2053b02 --- /dev/null +++ b/src/device/irqchip/aia/imsic.rs @@ -0,0 +1,55 @@ +use crate::arch::csr::{write_csr ,read_csr ,CSR_VSISELECT ,CSR_VSIREG ,CSR_VSTOPI ,CSR_VSTOPEI}; +pub const IMSIC_VS: usize = 0x2800_1000; +const IMSIC_VS_HART_STRIDE: usize = 0x2000; + +const XLEN: usize = usize::BITS as usize; +const XLEN_STRIDE: usize = XLEN / 32; + +const EIP: usize = 0x80; + +pub const fn imsic_vs(hart: usize) -> usize { + IMSIC_VS + IMSIC_VS_HART_STRIDE * hart +} +fn imsic_write(reg: usize, val: usize) { + unsafe { + match reg { + CSR_VSISELECT => write_csr!(CSR_VSISELECT, val), + CSR_VSIREG => write_csr!(CSR_VSIREG, val), + CSR_VSTOPI => write_csr!(CSR_VSTOPI, val), + CSR_VSTOPEI => write_csr!(CSR_VSTOPEI, val), + _ => panic!("Unknown CSR {}", reg), + } + } +} + +// Read from an IMSIC CSR + +fn imsic_read(reg: usize) -> usize { + let ret: usize; + unsafe { + ret = match reg { + CSR_VSISELECT => read_csr!(CSR_VSISELECT), + CSR_VSIREG => read_csr!(CSR_VSIREG), + CSR_VSTOPI => read_csr!(CSR_VSTOPI), + CSR_VSTOPEI => read_csr!(CSR_VSTOPEI), + _ => panic!("Unknown CSR {}", reg), + } + } + ret +} +// VS-Mode IMSIC CSRs + + +pub fn imsic_trigger(hart: u32, guest: u32, eiid: u32) { + if guest == 1{ + unsafe { + core::ptr::write_volatile(imsic_vs(hart as usize) as *mut u32, eiid); + } + } else { + panic!( + "Unknown imsic set hart {} guest {} eiid {}", + hart, guest, eiid + ); + } +} + diff --git a/src/device/irqchip/aia/mod.rs b/src/device/irqchip/aia/mod.rs new file mode 100644 index 0000000..428e374 --- /dev/null +++ b/src/device/irqchip/aia/mod.rs @@ -0,0 +1 @@ +pub mod aplic; diff --git a/src/device/irqchip/mod.rs b/src/device/irqchip/mod.rs index 7d746ed..3f80493 100644 --- a/src/device/irqchip/mod.rs +++ b/src/device/irqchip/mod.rs @@ -2,8 +2,13 @@ pub mod gicv3; #[cfg(target_arch = "riscv64")] +#[cfg(feature = "plic")] pub mod plic; +#[cfg(target_arch = "riscv64")] +#[cfg(feature = "aia")] +pub mod aia; + #[cfg(target_arch = "loongarch64")] pub mod ls7a2000; @@ -11,7 +16,14 @@ pub mod ls7a2000; pub use gicv3::{inject_irq, percpu_init, primary_init_early, primary_init_late}; #[cfg(target_arch = "riscv64")] -pub use plic::{inject_irq, percpu_init, primary_init_early, primary_init_late}; +#[cfg(feature = "plic")] +pub use plic::{inject_irq, percpu_init, primary_init_early, primary_init_late, + host_plic, vplic_global_emul_handler, vplic_hart_emul_handler}; + +#[cfg(target_arch = "riscv64")] +#[cfg(feature = "aia")] +pub use aia::aplic::{inject_irq, percpu_init, primary_init_early, primary_init_late, + host_aplic, vaplic_emul_handler}; #[cfg(target_arch = "loongarch64")] pub use ls7a2000::{inject_irq, percpu_init, primary_init_early, primary_init_late}; \ No newline at end of file diff --git a/src/platform/mod.rs b/src/platform/mod.rs index b525641..49ed841 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -53,7 +53,7 @@ pub fn platform_root_zone_config() -> HvZoneConfig { let mut pci_devs = [0; CONFIG_MAX_PCI_DEV]; let mut root_pci_cfg = HvPciConfig::new_empty(); let mut num_pci_devs:u64 = 0; - + #[cfg(all(feature = "platform_qemu", target_arch = "aarch64"))] if is_qemu_aarch64 { pci_devs[..ROOT_PCI_DEVS.len()].copy_from_slice(&ROOT_PCI_DEVS); root_pci_cfg = ROOT_PCI_CONFIG; diff --git a/src/platform/qemu_riscv64.rs b/src/platform/qemu_riscv64.rs index 7a23297..06f2e74 100644 --- a/src/platform/qemu_riscv64.rs +++ b/src/platform/qemu_riscv64.rs @@ -1,6 +1,7 @@ use crate::{arch::zone::HvArchZoneConfig, config::*}; pub const PLIC_BASE: usize = 0xc000000; +pub const APLIC_BASE: usize = 0xc000000; pub const PLIC_MAX_IRQ: usize = 1024; pub const PLIC_GLOBAL_SIZE: usize = 0x200000; pub const PLIC_TOTAL_SIZE: usize = 0x400000; @@ -78,4 +79,6 @@ pub const ROOT_ZONE_IRQS: [u32; 11] = [1,2,3,4,5,8,10,33,34,35,36]; // riscv pub const ROOT_ARCH_ZONE_CONFIG: HvArchZoneConfig = HvArchZoneConfig { plic_base: 0xc000000, plic_size: 0x4000000, + aplic_base: 0xd000000, + aplic_size: 0x8000, };