diff --git a/Makefile b/Makefile index 6619f20..91ec694 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,28 @@ all: workloads MULTIHART ?= 0 +PLATFORM ?= $(if $(filter 1,$(MULTIHART)),qemu,nemu) HARTS ?= 2 -LINUX_DEFAULT_DTB := $(if $(DEFAULT_DTB),$(DEFAULT_DTB),) +QEMU_DEFAULT_DTB ?= xiangshan-qemu-nemu-mem2g + +ifeq ($(filter $(PLATFORM),nemu qemu),) +$(error PLATFORM must be either nemu or qemu) +endif +ifeq ($(filter 1,$(MULTIHART)),1) +ifneq ($(PLATFORM),qemu) +$(error MULTIHART=1 requires PLATFORM=qemu) +endif +endif + +LINUX_DEFAULT_DTB := $(if $(DEFAULT_DTB),$(DEFAULT_DTB),$(if $(filter 1,$(MULTIHART)),,$(if $(filter qemu,$(PLATFORM)),$(QEMU_DEFAULT_DTB),))) +LINUX_FIRMWARE_FILENAME := $(if $(filter qemu,$(PLATFORM)),fw_payload.qemu.bin,fw_payload.bin) LINUX_ROOTFS_BUILD_VARS_HASH := $(shell printf '%s\n' \ 'multihart=$(if $(filter 1,$(MULTIHART)),1,0)' \ 'harts=$(if $(filter 1,$(MULTIHART)),$(HARTS),1)' | sha256sum | cut -d ' ' -f 1) LINUX_FIRMWARE_BUILD_VARS_HASH := $(shell printf '%s\n' \ 'multihart=$(if $(filter 1,$(MULTIHART)),1,0)' \ 'harts=$(if $(filter 1,$(MULTIHART)),$(HARTS),1)' \ - 'default_dtb=$(if $(DEFAULT_DTB),$(DEFAULT_DTB),xiangshan)' | sha256sum | cut -d ' ' -f 1) + 'default_dtb=$(if $(LINUX_DEFAULT_DTB),$(LINUX_DEFAULT_DTB),xiangshan)' | sha256sum | cut -d ' ' -f 1) MULTIHART_SUPPORTED_HARTS = $(shell seq 2 128) ifeq ($(filter 1,$(MULTIHART)),1) @@ -51,11 +64,12 @@ GCPT_IMPLEMENTATION := $(if $(filter 1,$(MULTIHART)),libcheckpoint,alpha) GCPT_SOURCE_DIR := $(if $(filter 1,$(MULTIHART)),bootloader/LibCheckpoint,bootloader/LibCheckpointAlpha) GCPT_BUILD_DIR := $(if $(filter 1,$(MULTIHART)),build/LibCheckpoint,build/LibCheckpointAlpha) GCPT_BIN := $(GCPT_BUILD_DIR)/build/gcpt.bin -GCPT_DEFAULT_DTB ?= $(if $(DEFAULT_DTB),$(DEFAULT_DTB),xiangshan) +GCPT_DEFAULT_DTB ?= $(if $(DEFAULT_DTB),$(DEFAULT_DTB),$(if $(filter qemu,$(PLATFORM)),$(QEMU_DEFAULT_DTB),xiangshan)) GCPT_DEFAULT_DTS := dts/$(GCPT_DEFAULT_DTB).dts.in GCPT_CONFIGURE_MODE := $(if $(filter 1,$(MULTIHART)),dual_core,normal) +GCPT_SERIAL_PORT ?= $(if $(filter 1,$(MULTIHART)),0x310b0000,) GCPT_DTB_CONFIG_HASH := $(shell printf '%s\n' "$(GCPT_DEFAULT_DTB)" | sha256sum | cut -d ' ' -f 1) -GCPT_CONFIG_STAMP := $(if $(filter 1,$(MULTIHART)),build/LibCheckpoint-config/mode.$(GCPT_CONFIGURE_MODE),build/LibCheckpointAlpha-config/dtb.$(GCPT_DTB_CONFIG_HASH)) +GCPT_CONFIG_STAMP := $(if $(filter 1,$(MULTIHART)),build/LibCheckpoint-config/mode.$(GCPT_CONFIGURE_MODE).serial-port.$(GCPT_SERIAL_PORT),build/LibCheckpointAlpha-config/dtb.$(GCPT_DTB_CONFIG_HASH)) GCPT_SOURCES := $(if $(filter 1,$(MULTIHART)),$(shell find $(GCPT_SOURCE_DIR) -path '*/.git' -prune -o -path '*/tests' -prune -o -type f -print 2>/dev/null),$(shell find $(GCPT_SOURCE_DIR) -path '*/.git' -prune -o -type f -print 2>/dev/null)) GCPT_DTS_SOURCES := $(if $(filter 1,$(MULTIHART)),,$(GCPT_DEFAULT_DTS)) $(GCPT_CONFIG_STAMP): @@ -67,6 +81,7 @@ $(GCPT_BIN): scripts/build-gcpt.sh scripts/dts-config.sh $(TOOLCHAIN_WRAPPER) $( GCPT_IMPLEMENTATION="$(GCPT_IMPLEMENTATION)" \ GCPT_CONFIGURE_MODE="$(GCPT_CONFIGURE_MODE)" \ GCPT_PAYLOAD_PATH="$(if $(filter 1,$(MULTIHART)),$(abspath $(SBI_BIN)),)" \ + GCPT_SERIAL_PORT="$(GCPT_SERIAL_PORT)" \ DEFAULT_DTB="$(GCPT_DEFAULT_DTB)" \ DTS_TEMPLATE_DIR="$(abspath dts)" \ bash scripts/build-gcpt.sh $(GCPT_SOURCE_DIR) $(GCPT_BUILD_DIR) @@ -110,19 +125,20 @@ build/linux-workloads/$(1)/firmware-vars.$(LINUX_FIRMWARE_BUILD_VARS_HASH).stamp rm -f "$$(@D)"/firmware-vars.*.stamp touch "$$@" -build/linux-workloads/$(1)/fw_payload.bin: $$(shell find $$(abspath dts)) $(GCPT_BIN) dts/xiangshan.dts.in scripts/build-sbi.sh scripts/dts-config.sh scripts/build-firmware-linux.sh build/linux-workloads/$(1)/rootfs.cpio $(LINUX_IMAGE) $(SBI_BIN) build/linux-workloads/$(1)/firmware-vars.$(LINUX_FIRMWARE_BUILD_VARS_HASH).stamp +build/linux-workloads/$(1)/$(LINUX_FIRMWARE_FILENAME): $$(shell find $$(abspath dts)) $(GCPT_BIN) $(GCPT_DEFAULT_DTS) scripts/build-sbi.sh scripts/dts-config.sh scripts/build-firmware-linux.sh build/linux-workloads/$(1)/rootfs.cpio $(LINUX_IMAGE) $(SBI_BIN) build/linux-workloads/$(1)/firmware-vars.$(LINUX_FIRMWARE_BUILD_VARS_HASH).stamp CROSS_COMPILE="$$(abspath $(BUILDROOT_DIR)/output/host/bin)/riscv64-linux-" \ DTC="$$(abspath $(BUILDROOT_DIR)/output/host/bin)/dtc" \ DEFAULT_DTB="$(LINUX_DEFAULT_DTB)" \ + FIRMWARE_OUTPUT="$$(abspath $$@)" \ MULTIHART="$$(MULTIHART)" \ HARTS="$$(HARTS)" \ bash scripts/build-firmware-linux.sh $(GCPT_BIN) $(SBI_BUILD_DIR) dts $(LINUX_IMAGE) build/linux-workloads/$(1) -linux/$(1): build/linux-workloads/$(1)/fw_payload.bin +linux/$(1): build/linux-workloads/$(1)/$(LINUX_FIRMWARE_FILENAME) WORKLOAD_PHONY_TARGETS += linux/$(1) WORKLOAD_DIRS += build/linux-workloads/$(1) -WORKLOADS_LINUX += build/linux-workloads/$(1)/fw_payload.bin +WORKLOADS_LINUX += build/linux-workloads/$(1)/$(LINUX_FIRMWARE_FILENAME) ROOTFS += build/linux-workloads/$(1)/rootfs.cpio DT_DIRS += build/linux-workloads/$(1)/dt TARFLAGS += --transform='s|^build/linux-workloads/$(1)|workloads/linux/$(1)|' @@ -159,13 +175,17 @@ LINUX_WORKLOAD_DIRS := $(patsubst workloads/linux/%/build.sh,%,$(wildcard worklo AM_WORKLOAD_DIRS := $(patsubst workloads/am/%/build.sh,%,$(wildcard workloads/am/*/build.sh)) LINUX_GENERIC_WORKLOADS := $(sort $(filter-out $(LINUX_WORKLOAD_RULE_DIRS),$(LINUX_WORKLOAD_DIRS))) AM_GENERIC_WORKLOADS := $(sort $(filter-out $(AM_WORKLOAD_RULE_DIRS),$(AM_WORKLOAD_DIRS))) +# QEMU support covers the Linux workloads with QEMU-compatible firmware flows. +QEMU_SUPPORTED_LINUX_WORKLOADS := coremark spec2006 spec2017 +LINUX_ENABLED_GENERIC_WORKLOADS := $(if $(filter qemu,$(PLATFORM)),$(filter $(QEMU_SUPPORTED_LINUX_WORKLOADS),$(LINUX_GENERIC_WORKLOADS)),$(LINUX_GENERIC_WORKLOADS)) +LINUX_WORKLOAD_RULE_FILES := $(if $(filter qemu,$(PLATFORM)),$(wildcard $(foreach workload,$(QEMU_SUPPORTED_LINUX_WORKLOADS),workloads/linux/$(workload)/rules.mk)),$(wildcard workloads/linux/*/rules.mk)) -$(foreach workload,$(LINUX_GENERIC_WORKLOADS),$(eval $(call add_workload_linux,$(workload)))) +$(foreach workload,$(LINUX_ENABLED_GENERIC_WORKLOADS),$(eval $(call add_workload_linux,$(workload)))) $(foreach workload,$(AM_GENERIC_WORKLOADS),$(eval $(call add_workload_am,$(workload)))) # Include workload-specific make rules. A workload can add its own targets by # placing rules.mk under its workload directory. --include $(wildcard workloads/linux/*/rules.mk) +-include $(LINUX_WORKLOAD_RULE_FILES) -include $(wildcard workloads/am/*/rules.mk) # Pack all workloads diff --git a/README.md b/README.md index b985a05..4f7863e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ -# NEMU Workload Builder +# NEMU/QEMU Workload Builder -This repository serves as an automated build system to build the workloads of NEMU for testing purpose. It supports two types of workloads: +This repository serves as an automated build system to build workloads for +NEMU and the QEMU NEMU machine. It supports two types of workloads: 1. **Linux workloads**: Traditional Linux-based workloads that run on top of the Linux kernel with initramfs 2. **AM workloads**: Bare-metal applications that run directly on the Abstract Machine (AM) abstraction layer @@ -11,7 +12,7 @@ Simply run `make` under the repository. The Linux kernel, the workloads and the For Linux workloads: -- `build/linux-workloads/workload_name/fw_payload.bin`: The all-in-one image that can be directly loaded by NEMU. +- `build/linux-workloads/workload_name/fw_payload.bin` (NEMU) or `fw_payload.qemu.bin` (QEMU): The all-in-one image that can be directly loaded by the selected machine. - `build/linux-workloads/workload_name/rootfs.cpio`: The initramfs overlay of the workload. - `build/linux-workloads/workload_name/dt/`: The selected device tree source and binary. @@ -24,35 +25,71 @@ You can also build a single workload with: - `make linux/workload_name` for a Linux workload. - `make am/workload_name` for an AM workload. -SPEC Linux workloads can also build multi-hart rootfs images: +Single-core workloads default to NEMU. QEMU support covers CoreMark, SPEC +CPU2006, and SPEC CPU2017, which can be assembled with `PLATFORM=qemu`: ```shell +make linux/coremark PLATFORM=qemu -jN +make linux/spec2006 PLATFORM=qemu BENCH=astar INPUT=biglakes \ + SPEC2006_ISO=/path/to/cpu2006.iso -jN +``` + +QEMU firmware is written beside the NEMU image as `fw_payload.qemu.bin`, so +switching platforms does not overwrite `fw_payload.bin` or rebuild the shared +benchmark/rootfs unnecessarily. Run the completed workload with: + +```shell +QEMU_BIN=/path/to/qemu-system-riscv64 \ + bash scripts/run-qemu.sh \ + build/linux-workloads/coremark/fw_payload.qemu.bin +QEMU_BIN=/path/to/qemu-system-riscv64 \ + bash scripts/run-qemu.sh \ + build/linux-workloads/spec2006/astar_biglakes/fw_payload.qemu.bin +``` + +Building does not require a QEMU installation. The verified baseline is +OpenXiangShan/qemu commit `d6ef1ba720` from `fix/nemu-uart16550`; the runner +requires `QEMU_BIN` and checks for the equivalent `nemu` machine device contract +before booting. It uses TCG and treats only `Hit GOOD TRAP` as success. It +defaults to 2 GiB of RAM; set `QEMU_MEMORY` to match the selected multi-hart DTS +when needed. + +CoreMark, SPEC CPU2006, and SPEC CPU2017 also support multi-hart QEMU rootfs images: + +```shell +make linux/coremark MULTIHART=1 HARTS=2 \ + DEFAULT_DTB=xiangshan-fpga-noAIA-2hart-mem8g-novec -jN + make linux/spec2006 BENCH=astar INPUT=biglakes \ SPEC2006_ISO=/path/to/cpu2006.iso \ MULTIHART=1 HARTS=2 \ - DEFAULT_DTB=xiangshan-fpga-noAIA-2hart-mem8g -jN - -make linux/spec2017 BENCH=mcf MODE=rate INPUT=ref \ - SPEC2017_ISO=/path/to/cpu2017.iso \ - MULTIHART=1 HARTS=2 \ - DEFAULT_DTB=xiangshan-fpga-noAIA-2hart-mem8g -jN + DEFAULT_DTB=xiangshan-fpga-noAIA-2hart-mem8g-novec -jN ``` -`MULTIHART=1` creates per-hart workload directories, uses `/bin/nemu-trap` to -send codes 256 and 257 before each benchmark copy and code 258 after it -returns, and requires `DEFAULT_DTB` to be set to the complete DTS basename. -Its matching template must exist in `dts/`; the build fails rather than -guessing a memory profile or generating a missing multi-hart DTS. +`MULTIHART=1` automatically selects `PLATFORM=qemu`; explicitly combining it +with `PLATFORM=nemu` is rejected. It creates per-hart workload directories, +uses `/bin/nemu-trap` to send codes 256 and 257 before each benchmark copy and +code 258 after it returns, and requires `DEFAULT_DTB` to be set to the complete +DTS basename. Its matching template must exist in `dts/`; the build fails +rather than guessing a memory profile or generating a missing multi-hart DTS. +Other Linux workload targets remain NEMU-only. Single-core firmware uses LibCheckpointAlpha. Multi-core firmware uses LibCheckpoint to restore QEMU multi-hart checkpoints. Set `HARTS` to match the checkpoint and the selected device-tree template; supported multi-hart counts are 2 through 128. All multi-hart images reserve the 131 MiB checkpoint -window `[0x80300000, 0x88600000)` and load Linux at `0x88600000`. +window `[0x80300000, 0x88600000)` and load Linux at `0x88600000`. Multi-hart +builds default `GCPT_SERIAL_PORT` to the QEMU 16550A TX register at +`0x310b0000`; the build passes it to LibCheckpoint as `CONFIG_SERIAL_PORT`. ## Workload Compatibility -Not all workloads can run on all NEMU configurations. The only workload supported by `riscv64-nutshell_defconfig` is `linux/hello`, since all other workloads require hardware floating point, which is not supported by nutshell. RVV related workloads require the vector ISA extension, and hypervisor related workloads require the hypervisor ISA extension. +Not all workloads can run on all NEMU or QEMU configurations. QEMU support is +limited to `linux/coremark`, `linux/spec2006`, and `linux/spec2017`; the only workload supported by +`riscv64-nutshell_defconfig` is `linux/hello`, since all other workloads require +hardware floating point, which is not supported by nutshell. RVV related workloads +require the vector ISA extension, and hypervisor related workloads require the +hypervisor ISA extension. ## Build Requirements @@ -79,10 +116,16 @@ A single-core image contains: |---------|-------------------------------| | 0.0 MiB | LibCheckpointAlpha | | 1.0 MiB | OpenSBI | -| 1.5 MiB | device tree | -| >=2.0 MiB | Linux kernel at the next 2 MiB-aligned address | +| 1.75 MiB | device tree | +| 2.0 MiB | Linux kernel | | -- | initramfs containing workload | +Single-core images place the DTB at 1.75 MiB (`0x801c0000`), providing 768 KiB +for OpenSBI while leaving 256 KiB for the DTB before Linux at 2 MiB. This is an +image-packing choice, not a fixed machine address. The assembler checks both +component sizes. Multi-hart images keep their separate DTB address at +`0x80200000`. + A multi-hart image uses the fixed QEMU checkpoint layout: | Physical address range | Size | Content | @@ -105,6 +148,15 @@ the workload's `dt` directory and the DTB is embedded in the firmware image. For DTS files used with gcpt, the beginning of RAM must be reserved with a `reserved-memory` node so Linux does not allocate or map the gcpt checkpoint buffer. The XiangShan FPGA DTS templates reserve the first 1 MiB of their declared DRAM for this purpose. +```shell +dd conv=notrunc bs=1024 seek=1792 if=dt/some_device.dtb of=fw_payload.bin +``` + +Use `fw_payload.qemu.bin` as the output file for a QEMU image. The supported +QEMU `nemu` machine exposes a no-IRQ 16550A UART at `0x310b0000`. Multi-hart +images use their separate fixed DTB offset of 2048 KiB and must retain a +matching multi-hart device tree. + OpenSBI is patched (see `bootloader/opensbi.patch`) to load the device tree from a fixed offset relative to the DRAM base. The initramfs is placed after the Linux kernel and aligned to 1 MiB. ### AM Workloads diff --git a/bootloader/LibCheckpoint b/bootloader/LibCheckpoint index e4b22d8..1d8905c 160000 --- a/bootloader/LibCheckpoint +++ b/bootloader/LibCheckpoint @@ -1 +1 @@ -Subproject commit e4b22d8df0c462e69fc6ee8955aadbac40ea9fc7 +Subproject commit 1d8905cc2803c242ef257569128c2e68bf4272aa diff --git a/bootloader/LibCheckpointAlpha b/bootloader/LibCheckpointAlpha index eb6ca46..b313732 160000 --- a/bootloader/LibCheckpointAlpha +++ b/bootloader/LibCheckpointAlpha @@ -1 +1 @@ -Subproject commit eb6ca46bb485b64bc4864d48957f84f6706c308c +Subproject commit b3137321622584d35ebb9f8c70fe1a7e2041f506 diff --git a/dts/README.md b/dts/README.md index 05339f2..24ac981 100644 --- a/dts/README.md +++ b/dts/README.md @@ -20,6 +20,12 @@ These parameters are replaced with the corresponding values when building the wo - `xiangshan-fpga-noAIA-mem8g-novec.dts.in`: XiangShan FPGA DTS without vector extensions, with an 8 GiB memory profile. - `xiangshan-fpga-noAIA-mem24g-novec.dts.in`: XiangShan FPGA DTS without vector extensions, with a 24 GiB memory profile. - `xiangshan-fpga-noAIA-mem64g-novec.dts.in`: XiangShan FPGA DTS without vector extensions, with a 64 GiB memory profile. +- `xiangshan-qemu-nemu-mem2g.dts.in`: Single-hart DTS for QEMU's `nemu` + machine, with 2 GiB of memory and a no-IRQ 16550A UART at `0x310b0000`. +- `xiangshan-qemu-nemu-mem8g.dts.in`: The same single-hart QEMU profile with + 8 GiB of memory, used by SPEC2017 rate workloads. +- `xiangshan-qemu-nemu-mem24g.dts.in`: The same single-hart QEMU profile with + 24 GiB of memory, used by SPEC2017 speed workloads. Multi-hart XiangShan builds require the user to select a complete DTS basename with `DEFAULT_DTB`; the build no longer assumes a `mem8g` suffix. For example, @@ -38,12 +44,11 @@ and the `0x88600000` kernel address do not apply. This table shows the default |-------------------------|----------------|------------| | `0x80000000–0x800fffff` | 1 MiB | LibCheckpointAlpha checkpoint-recovery program; reserved as `no-map` in the DTS | | `0x80100000` | +1 MiB | OpenSBI firmware starts here | -| `0x80180000` | +1.5 MiB | Device tree placed here by firmware assembly | -| `0x80200000` and above | >=+2 MiB | Linux kernel at the first 2 MiB-aligned address, then the MiB-aligned initramfs | +| `0x801c0000` | +1.75 MiB | Device tree placed here by firmware assembly | +| `0x80200000` and above | +2 MiB | Linux kernel image, then the MiB-aligned initramfs | -The single-core firmware packer uses `DTB_OFFSET_KB=1536`, -`SBI_OFFSET_KB=1024`, and a minimum kernel offset of 2 MiB. The kernel's -physical address is rounded up to a 2 MiB boundary. The initramfs address is +The single-core firmware packer uses `DTB_OFFSET_KB=1792`, +`SBI_OFFSET_KB=1024`, and `KERNEL_OFFSET_MB=2`. The initramfs address is computed from the actual kernel size and starts at the next MiB boundary. The selected single-core DTS supplies the DRAM base and capacity; no fixed 8 GiB or 64 GiB profile is imposed by this layout. @@ -82,8 +87,8 @@ standard templates retain these profiles: | Template | DRAM | |----------|------| -| `xiangshan-fpga-noAIA-2hart-mem8g` | 8 GiB | -| `xiangshan-fpga-noAIA-2hart-mem16g` | 16 GiB | +| `xiangshan-fpga-noAIA-2hart-mem8g-novec` | 8 GiB | +| `xiangshan-fpga-noAIA-2hart-mem16g-novec` | 16 GiB | | `xiangshan-fpga-noAIA-32hart-mem64g` | 64 GiB | `xiangshan-fpga-noAIA-mem16g-novec` is the single-hart Host profile for @@ -95,8 +100,8 @@ least 16 GiB, and structured ISA extension `h`. Select the complete template basename explicitly when building, for example: ```sh -make linux/hello MULTIHART=1 HARTS=2 \ - DEFAULT_DTB=xiangshan-fpga-noAIA-2hart-mem8g +make linux/coremark MULTIHART=1 HARTS=2 \ + DEFAULT_DTB=xiangshan-fpga-noAIA-2hart-mem8g-novec ``` ## Generate Multi-Hart XiangShan DTS @@ -107,35 +112,33 @@ XiangShan FPGA baseline with: ```shell python3 scripts/generate-xiangshan-multihart-dts.py \ - --base dts/xiangshan-fpga-noAIA-mem8g.dts.in \ + --base dts/xiangshan-fpga-noAIA-mem8g-novec.dts.in \ --harts 2 \ - --output dts/xiangshan-fpga-noAIA-2hart-mem8g.dts.in + --output dts/xiangshan-fpga-noAIA-2hart-mem8g-novec.dts.in ``` Use `--memory-gib` to override the copied DRAM capacity. The checked-in 16 GiB -two-hart profile is generated with: +two-hart profile can be regenerated with: ```shell python3 scripts/generate-xiangshan-multihart-dts.py \ - --base dts/xiangshan-fpga-noAIA-mem8g.dts.in \ + --base dts/xiangshan-fpga-noAIA-mem8g-novec.dts.in \ --harts 2 \ --memory-gib 16 \ - --output dts/xiangshan-fpga-noAIA-2hart-mem16g.dts.in + --output dts/xiangshan-fpga-noAIA-2hart-mem16g-novec.dts.in ``` `--harts` must be in the range 2 through 128, and `--memory-gib` must be a positive integer when specified. The generator copies the CPU node for each -hart, extends the CLINT, PLIC, and debug interrupt contexts, and applies the -NEMU UARTLITE and PLIC settings. Generated multi-hart templates reserve the -fixed 131 MiB checkpoint window `[0x80300000, 0x88600000)`. +hart, extends the CLINT, PLIC, and debug interrupt contexts, sets +`riscv,ndev = <66>`, and emits the no-IRQ 16550A console at `0x310b0000` used +by the supported QEMU `nemu` machine. Generated multi-hart templates reserve +the fixed 131 MiB checkpoint window `[0x80300000, 0x88600000)`. The full capability block describes XiangShan hardware and is not fully -emulated by the current generic OpenSBI/QEMU `nemu` path. In particular, -DT-advertised `smrnmi` requires an OpenSBI platform -`smrnmi_handlers_init` callback, so all generic-platform DTS templates omit -it. The `nemu` timer path likewise cannot execute the DT-advertised `sstc` CSR -sequence; multi-core diagnostic runs may need to omit `sstc` and use -`sstc=false`. +emulated by the current QEMU `nemu` path. In particular, the timer path cannot +execute the DT-advertised `sstc` CSR sequence, so generated multi-hart CPU nodes +omit `sstc`. The build does not invoke this generator automatically. Run it and review the result before building with the corresponding `HARTS` value. diff --git a/dts/xiangshan-fpga-noAIA-2hart-mem16g-novec.dts.in b/dts/xiangshan-fpga-noAIA-2hart-mem16g-novec.dts.in index 0c6e173..969c534 100644 --- a/dts/xiangshan-fpga-noAIA-2hart-mem16g-novec.dts.in +++ b/dts/xiangshan-fpga-noAIA-2hart-mem16g-novec.dts.in @@ -1,8 +1,8 @@ /* - * XiangShan FPGA DTS used by the fpga board flow. + * XiangShan 2-hart/16 GiB DTS used by QEMU's nemu machine. * * 1. AIA is disabled, so Linux should only see the legacy CLINT + PLIC path. - * 2. QEMU/NEMU UARTLITE is exposed as the serial console. + * 2. QEMU's nemu machine exposes a 16550A serial console. */ /dts-v1/; @@ -177,7 +177,7 @@ ranges; /* - * This FPGA image boots without AIA. Describe only the CLINT + PLIC + * This QEMU configuration boots without AIA. Describe only the CLINT + PLIC * interrupt topology that the software stack should probe. */ clint: clint@38000000 { @@ -203,19 +203,20 @@ reg-names = "control"; interrupts-extended = <&intc_cpu0 11 &intc_cpu0 9 &intc_cpu1 11 &intc_cpu1 9>; riscv,max-priority = <7>; - riscv,ndev = <64>; + riscv,ndev = <66>; }; /* - * QEMU/NEMU exposes UARTLITE at 0x40600000. + * QEMU's nemu machine exposes the XiangShan 16550A UART at 0x310b0000. + * It is not connected to the PLIC, matching serial_mm_init(..., NULL, ...). */ - uart0: serial@40600000 { - compatible = "xlnx,xps-uartlite-1.00.a"; - interrupt-parent = <&PLIC>; - interrupts = <3>; + uart0: serial@310b0000 { + compatible = "ns16550a"; current-speed = <115200>; - reg = <0x0 0x40600000 0x0 0x1000>; - reg-names = "control"; + reg = <0x0 0x310b0000 0x0 0x10000>; + reg-shift = <0x2>; + reg-io-width = <0x4>; + clock-frequency = <50000000>; status = "okay"; }; }; diff --git a/dts/xiangshan-fpga-noAIA-2hart-mem8g-novec.dts.in b/dts/xiangshan-fpga-noAIA-2hart-mem8g-novec.dts.in index 781b3bf..454ce43 100644 --- a/dts/xiangshan-fpga-noAIA-2hart-mem8g-novec.dts.in +++ b/dts/xiangshan-fpga-noAIA-2hart-mem8g-novec.dts.in @@ -1,8 +1,8 @@ /* - * XiangShan FPGA DTS used by the fpga board flow. + * XiangShan 2-hart/8 GiB DTS used by QEMU's nemu machine. * * 1. AIA is disabled, so Linux should only see the legacy CLINT + PLIC path. - * 2. QEMU/NEMU UARTLITE is exposed as the serial console. + * 2. QEMU's nemu machine exposes a 16550A serial console. */ /dts-v1/; @@ -178,7 +178,7 @@ ranges; /* - * This FPGA image boots without AIA. Describe only the CLINT + PLIC + * This QEMU configuration boots without AIA. Describe only the CLINT + PLIC * interrupt topology that the software stack should probe. */ clint: clint@38000000 { @@ -204,19 +204,20 @@ reg-names = "control"; interrupts-extended = <&intc_cpu0 11 &intc_cpu0 9 &intc_cpu1 11 &intc_cpu1 9>; riscv,max-priority = <7>; - riscv,ndev = <64>; + riscv,ndev = <66>; }; /* - * QEMU/NEMU exposes UARTLITE at 0x40600000. + * QEMU's nemu machine exposes the XiangShan 16550A UART at 0x310b0000. + * It is not connected to the PLIC, matching serial_mm_init(..., NULL, ...). */ - uart0: serial@40600000 { - compatible = "xlnx,xps-uartlite-1.00.a"; - interrupt-parent = <&PLIC>; - interrupts = <3>; + uart0: serial@310b0000 { + compatible = "ns16550a"; current-speed = <115200>; - reg = <0x0 0x40600000 0x0 0x1000>; - reg-names = "control"; + reg = <0x0 0x310b0000 0x0 0x10000>; + reg-shift = <0x2>; + reg-io-width = <0x4>; + clock-frequency = <50000000>; status = "okay"; }; }; diff --git a/dts/xiangshan-fpga-noAIA-32hart-mem64g.dts.in b/dts/xiangshan-fpga-noAIA-32hart-mem64g.dts.in index 71331f8..767d199 100644 --- a/dts/xiangshan-fpga-noAIA-32hart-mem64g.dts.in +++ b/dts/xiangshan-fpga-noAIA-32hart-mem64g.dts.in @@ -27,7 +27,7 @@ cpus { #address-cells = <1>; #size-cells = <0>; - timebase-frequency = <10000000>; + timebase-frequency = <1000000>; cpu0: cpu@0 { compatible = "riscv"; @@ -1354,7 +1354,7 @@ <&cpu30_intc 11>, <&cpu30_intc 9>, <&cpu31_intc 11>, <&cpu31_intc 9>; riscv,max-priority = <7>; - riscv,ndev = <64>; + riscv,ndev = <66>; }; @@ -1379,13 +1379,13 @@ compatible = "simple-bus"; ranges; - serial@40600000 { - compatible = "xlnx,xps-uartlite-1.00.a"; - reg = <0x0 0x40600000 0x0 0x1000>; - interrupts-extended = <&plic 3>; + serial@310b0000 { + compatible = "ns16550a"; + reg = <0x0 0x310b0000 0x0 0x10000>; + reg-shift = <0x2>; + reg-io-width = <0x4>; + clock-frequency = <50000000>; current-speed = <115200>; - xlnx,data-bits = <8>; - xlnx,use-parity = <0>; }; }; diff --git a/dts/xiangshan-qemu-nemu-mem24g.dts.in b/dts/xiangshan-qemu-nemu-mem24g.dts.in new file mode 100644 index 0000000..bffe840 --- /dev/null +++ b/dts/xiangshan-qemu-nemu-mem24g.dts.in @@ -0,0 +1,142 @@ +/dts-v1/; + +/ { + compatible = "freechips,rocketchip-unknown-dev"; + model = "qemu,nemu-single-core"; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <1000000>; + + cpu0: cpu@0 { + compatible = "ICT,xiangshan", "riscv"; + device_type = "cpu"; + reg = <0>; + status = "okay"; + + d-cache-block-size = <64>; + d-cache-sets = <256>; + d-cache-size = <65536>; + d-tlb-sets = <1>; + d-tlb-size = <48>; + i-cache-block-size = <64>; + i-cache-sets = <256>; + i-cache-size = <65536>; + i-tlb-sets = <1>; + i-tlb-size = <48>; + mmu-type = "riscv,sv48"; + clock-frequency = <0>; + timebase-frequency = <1000000>; + tlb-split; + + riscv,isa = "rv64imafdcvh_smstateen_sscofpmf_zicntr_zihpm_svpbmt_sdtrig_smcsrind_sscsrind_svade"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = + "i", "m", "a", "f", "d", "c", "v", "h", + "sdtrig", "sha", "shcounterenw", "shgatpa", + "shlcofideleg", "shtvala", "shvsatpa", "shvstvala", + "shvstvecd", "smcsrind", "smdbltrp", + "smmpm", "smnpm", "smstateen", + "ss1p13", "ssccptr", "sscofpmf", + "sscounterenw", "sscsrind", "ssdbltrp", "ssnpm", + "sspm", "ssstateen", "ssstrict", + "sstvala", "sstvecd", "ssu64xl", "supm", + "sv39", "sv48", "svade", "svbare", "svinval", + "svnapot", "svpbmt", "za64rs", "zacas", "zawrs", + "zba", "zbb", "zbc", "zbkb", "zbkc", "zbkx", + "zbs", "zca", "zcb", "zcmop", "zfa", "zfh", "zfhmin", + "zic64b", + "ziccamoa", "ziccif", "zicclsm", "ziccrse", + "zicntr", "zicond", "zicsr", "zifencei", + "zihintntl", "zihintpause", "zihpm", "zimop", + "zkn", "zknd", "zkne", "zknh", "zksed", + "zksh", "zkt", "zvbb", "zvfh", "zvfhmin", + "zvkt", "zvl128b", "zvl32b", "zvl64b"; + riscv,cbom-block-size = <0x40>; + riscv,cboz-block-size = <0x40>; + + next-level-cache = <&l2_cache>; + + cpu0_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #interrupt-cells = <1>; + }; + }; + }; + + l2_cache: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-block-size = <64>; + cache-size = <1048576>; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0x6 0x00000000>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + reserved0: buffer@0 { + no-map; + reg = <0x0 0x80000000 0x0 0x100000>; + }; + }; + + soc { + compatible = "freechips,rocketchip-unknown-soc", "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + clint@38000000 { + compatible = "riscv,clint0"; + reg = <0x0 0x38000000 0x0 0x10000>; + reg-names = "control"; + interrupts-extended = <&cpu0_intc 3 &cpu0_intc 7>; + }; + + plic: interrupt-controller@3c000000 { + compatible = "riscv,plic0"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x0 0x3c000000 0x0 0x4000000>; + reg-names = "control"; + interrupts-extended = <&cpu0_intc 11 &cpu0_intc 9>; + riscv,max-priority = <7>; + riscv,ndev = <66>; + }; + + /* QEMU's nemu machine exposes the XiangShan 16550A UART at 0x310b0000. */ + uart0: serial@310b0000 { + compatible = "ns16550a"; + reg = <0x0 0x310b0000 0x0 0x10000>; + reg-shift = <0x2>; + reg-io-width = <0x4>; + clock-frequency = <50000000>; + current-speed = <115200>; + status = "okay"; + }; + }; + + aliases { + serial0 = &uart0; + }; + + chosen { + bootargs = "console=hvc0 earlycon=sbi"; + stdout-path = "serial0:115200n8"; + linux,initrd-start = ; + linux,initrd-end = ; + /* ASCII: "XIANGSHAN_NEMU_BOARD_RANDOM_SEED" */ + rng-seed = /bits/ 8 <0x58 0x49 0x41 0x4e 0x47 0x53 0x48 0x41 0x4e 0x5f 0x4e 0x45 0x4d 0x55 0x5f 0x42 0x4f 0x41 0x52 0x44 0x5f 0x52 0x41 0x4e 0x44 0x4f 0x4d 0x5f 0x53 0x45 0x45 0x44>; + }; +}; diff --git a/dts/xiangshan-qemu-nemu-mem2g.dts.in b/dts/xiangshan-qemu-nemu-mem2g.dts.in new file mode 100644 index 0000000..76fb26a --- /dev/null +++ b/dts/xiangshan-qemu-nemu-mem2g.dts.in @@ -0,0 +1,142 @@ +/dts-v1/; + +/ { + compatible = "freechips,rocketchip-unknown-dev"; + model = "qemu,nemu-single-core"; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <1000000>; + + cpu0: cpu@0 { + compatible = "ICT,xiangshan", "riscv"; + device_type = "cpu"; + reg = <0>; + status = "okay"; + + d-cache-block-size = <64>; + d-cache-sets = <256>; + d-cache-size = <65536>; + d-tlb-sets = <1>; + d-tlb-size = <48>; + i-cache-block-size = <64>; + i-cache-sets = <256>; + i-cache-size = <65536>; + i-tlb-sets = <1>; + i-tlb-size = <48>; + mmu-type = "riscv,sv48"; + clock-frequency = <0>; + timebase-frequency = <1000000>; + tlb-split; + + riscv,isa = "rv64imafdcvh_smstateen_sscofpmf_zicntr_zihpm_svpbmt_sdtrig_smcsrind_sscsrind_svade"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = + "i", "m", "a", "f", "d", "c", "v", "h", + "sdtrig", "sha", "shcounterenw", "shgatpa", + "shlcofideleg", "shtvala", "shvsatpa", "shvstvala", + "shvstvecd", "smcsrind", "smdbltrp", + "smmpm", "smnpm", "smstateen", + "ss1p13", "ssccptr", "sscofpmf", + "sscounterenw", "sscsrind", "ssdbltrp", "ssnpm", + "sspm", "ssstateen", "ssstrict", + "sstvala", "sstvecd", "ssu64xl", "supm", + "sv39", "sv48", "svade", "svbare", "svinval", + "svnapot", "svpbmt", "za64rs", "zacas", "zawrs", + "zba", "zbb", "zbc", "zbkb", "zbkc", "zbkx", + "zbs", "zca", "zcb", "zcmop", "zfa", "zfh", "zfhmin", + "zic64b", + "ziccamoa", "ziccif", "zicclsm", "ziccrse", + "zicntr", "zicond", "zicsr", "zifencei", + "zihintntl", "zihintpause", "zihpm", "zimop", + "zkn", "zknd", "zkne", "zknh", "zksed", + "zksh", "zkt", "zvbb", "zvfh", "zvfhmin", + "zvkt", "zvl128b", "zvl32b", "zvl64b"; + riscv,cbom-block-size = <0x40>; + riscv,cboz-block-size = <0x40>; + + next-level-cache = <&l2_cache>; + + cpu0_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #interrupt-cells = <1>; + }; + }; + }; + + l2_cache: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-block-size = <64>; + cache-size = <1048576>; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0x0 0x80000000>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + reserved0: buffer@0 { + no-map; + reg = <0x0 0x80000000 0x0 0x100000>; + }; + }; + + soc { + compatible = "freechips,rocketchip-unknown-soc", "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + clint@38000000 { + compatible = "riscv,clint0"; + reg = <0x0 0x38000000 0x0 0x10000>; + reg-names = "control"; + interrupts-extended = <&cpu0_intc 3 &cpu0_intc 7>; + }; + + plic: interrupt-controller@3c000000 { + compatible = "riscv,plic0"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x0 0x3c000000 0x0 0x4000000>; + reg-names = "control"; + interrupts-extended = <&cpu0_intc 11 &cpu0_intc 9>; + riscv,max-priority = <7>; + riscv,ndev = <66>; + }; + + /* QEMU's nemu machine exposes the XiangShan 16550A UART at 0x310b0000. */ + uart0: serial@310b0000 { + compatible = "ns16550a"; + reg = <0x0 0x310b0000 0x0 0x10000>; + reg-shift = <0x2>; + reg-io-width = <0x4>; + clock-frequency = <50000000>; + current-speed = <115200>; + status = "okay"; + }; + }; + + aliases { + serial0 = &uart0; + }; + + chosen { + bootargs = "console=hvc0 earlycon=sbi"; + stdout-path = "serial0:115200n8"; + linux,initrd-start = ; + linux,initrd-end = ; + /* ASCII: "XIANGSHAN_NEMU_BOARD_RANDOM_SEED" */ + rng-seed = /bits/ 8 <0x58 0x49 0x41 0x4e 0x47 0x53 0x48 0x41 0x4e 0x5f 0x4e 0x45 0x4d 0x55 0x5f 0x42 0x4f 0x41 0x52 0x44 0x5f 0x52 0x41 0x4e 0x44 0x4f 0x4d 0x5f 0x53 0x45 0x45 0x44>; + }; +}; diff --git a/dts/xiangshan-qemu-nemu-mem8g.dts.in b/dts/xiangshan-qemu-nemu-mem8g.dts.in new file mode 100644 index 0000000..1e5d707 --- /dev/null +++ b/dts/xiangshan-qemu-nemu-mem8g.dts.in @@ -0,0 +1,142 @@ +/dts-v1/; + +/ { + compatible = "freechips,rocketchip-unknown-dev"; + model = "qemu,nemu-single-core"; + #address-cells = <2>; + #size-cells = <2>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + timebase-frequency = <1000000>; + + cpu0: cpu@0 { + compatible = "ICT,xiangshan", "riscv"; + device_type = "cpu"; + reg = <0>; + status = "okay"; + + d-cache-block-size = <64>; + d-cache-sets = <256>; + d-cache-size = <65536>; + d-tlb-sets = <1>; + d-tlb-size = <48>; + i-cache-block-size = <64>; + i-cache-sets = <256>; + i-cache-size = <65536>; + i-tlb-sets = <1>; + i-tlb-size = <48>; + mmu-type = "riscv,sv48"; + clock-frequency = <0>; + timebase-frequency = <1000000>; + tlb-split; + + riscv,isa = "rv64imafdcvh_smstateen_sscofpmf_zicntr_zihpm_svpbmt_sdtrig_smcsrind_sscsrind_svade"; + riscv,isa-base = "rv64i"; + riscv,isa-extensions = + "i", "m", "a", "f", "d", "c", "v", "h", + "sdtrig", "sha", "shcounterenw", "shgatpa", + "shlcofideleg", "shtvala", "shvsatpa", "shvstvala", + "shvstvecd", "smcsrind", "smdbltrp", + "smmpm", "smnpm", "smstateen", + "ss1p13", "ssccptr", "sscofpmf", + "sscounterenw", "sscsrind", "ssdbltrp", "ssnpm", + "sspm", "ssstateen", "ssstrict", + "sstvala", "sstvecd", "ssu64xl", "supm", + "sv39", "sv48", "svade", "svbare", "svinval", + "svnapot", "svpbmt", "za64rs", "zacas", "zawrs", + "zba", "zbb", "zbc", "zbkb", "zbkc", "zbkx", + "zbs", "zca", "zcb", "zcmop", "zfa", "zfh", "zfhmin", + "zic64b", + "ziccamoa", "ziccif", "zicclsm", "ziccrse", + "zicntr", "zicond", "zicsr", "zifencei", + "zihintntl", "zihintpause", "zihpm", "zimop", + "zkn", "zknd", "zkne", "zknh", "zksed", + "zksh", "zkt", "zvbb", "zvfh", "zvfhmin", + "zvkt", "zvl128b", "zvl32b", "zvl64b"; + riscv,cbom-block-size = <0x40>; + riscv,cboz-block-size = <0x40>; + + next-level-cache = <&l2_cache>; + + cpu0_intc: interrupt-controller { + compatible = "riscv,cpu-intc"; + interrupt-controller; + #interrupt-cells = <1>; + }; + }; + }; + + l2_cache: l2-cache { + compatible = "cache"; + cache-level = <2>; + cache-block-size = <64>; + cache-size = <1048576>; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 0x2 0x00000000>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + reserved0: buffer@0 { + no-map; + reg = <0x0 0x80000000 0x0 0x100000>; + }; + }; + + soc { + compatible = "freechips,rocketchip-unknown-soc", "simple-bus"; + #address-cells = <2>; + #size-cells = <2>; + ranges; + + clint@38000000 { + compatible = "riscv,clint0"; + reg = <0x0 0x38000000 0x0 0x10000>; + reg-names = "control"; + interrupts-extended = <&cpu0_intc 3 &cpu0_intc 7>; + }; + + plic: interrupt-controller@3c000000 { + compatible = "riscv,plic0"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x0 0x3c000000 0x0 0x4000000>; + reg-names = "control"; + interrupts-extended = <&cpu0_intc 11 &cpu0_intc 9>; + riscv,max-priority = <7>; + riscv,ndev = <66>; + }; + + /* QEMU's nemu machine exposes the XiangShan 16550A UART at 0x310b0000. */ + uart0: serial@310b0000 { + compatible = "ns16550a"; + reg = <0x0 0x310b0000 0x0 0x10000>; + reg-shift = <0x2>; + reg-io-width = <0x4>; + clock-frequency = <50000000>; + current-speed = <115200>; + status = "okay"; + }; + }; + + aliases { + serial0 = &uart0; + }; + + chosen { + bootargs = "console=hvc0 earlycon=sbi"; + stdout-path = "serial0:115200n8"; + linux,initrd-start = ; + linux,initrd-end = ; + /* ASCII: "XIANGSHAN_NEMU_BOARD_RANDOM_SEED" */ + rng-seed = /bits/ 8 <0x58 0x49 0x41 0x4e 0x47 0x53 0x48 0x41 0x4e 0x5f 0x4e 0x45 0x4d 0x55 0x5f 0x42 0x4f 0x41 0x52 0x44 0x5f 0x52 0x41 0x4e 0x44 0x4f 0x4d 0x5f 0x53 0x45 0x45 0x44>; + }; +}; diff --git a/scripts/build-firmware-linux.sh b/scripts/build-firmware-linux.sh index a562e96..c791a60 100644 --- a/scripts/build-firmware-linux.sh +++ b/scripts/build-firmware-linux.sh @@ -7,16 +7,20 @@ DTS_TEMPLATE_DIR="$(realpath "$3")" KERNEL_IMAGE="$(realpath "$4")" WORKLOAD_BUILD_DIR="$(realpath "$5")" CPIO_ARCHIVE="$WORKLOAD_BUILD_DIR/rootfs.cpio" +FIRMWARE_OUTPUT="$(realpath -m "${FIRMWARE_OUTPUT:-$WORKLOAD_BUILD_DIR/fw_payload.bin}")" source "$(dirname "${BASH_SOURCE[0]}")/dts-config.sh" DEFAULT_DTB="${DEFAULT_DTB:-}" DTB_MEMORY_PROFILE="${DTB_MEMORY_PROFILE:-}" DTB_MIN_MEMORY_BYTES="${DTB_MIN_MEMORY_BYTES:-}" +DTB_REQUIRED_MIN_MEMORY_BYTES="${DTB_REQUIRED_MIN_MEMORY_BYTES:-}" HARTS="${HARTS:-2}" readonly MULTIHART_MAX_HARTS=128 readonly MULTIHART_KERNEL_OFFSET_MB=134 +readonly SINGLEHART_DTB_OFFSET_KB=1792 +readonly MULTIHART_DTB_OFFSET_KB=2048 -DTB_OFFSET_KB=1536 -DTB_MAX_SIZE_KB=512 +DTB_OFFSET_KB="$SINGLEHART_DTB_OFFSET_KB" +DTB_MAX_SIZE_KB=256 SBI_OFFSET_KB=1024 KERNEL_MIN_OFFSET_MB=2 @@ -32,7 +36,7 @@ if [ "${MULTIHART:-0}" = 1 ]; then echo "HARTS must be an integer in the range 2..$MULTIHART_MAX_HARTS" >&2 exit 1 fi - DTB_OFFSET_KB=2048 + DTB_OFFSET_KB="$MULTIHART_DTB_OFFSET_KB" DTB_MAX_SIZE_KB=1024 KERNEL_MIN_OFFSET_MB="$MULTIHART_KERNEL_OFFSET_MB" elif [ -z "$DEFAULT_DTB" ]; then @@ -266,6 +270,12 @@ if [ "${MULTIHART:-0}" = 1 ]; then check_multihart_checkpoint_reservation "$DEFAULT_DTS_FILE" fi check_dtb_cpu_count "$DEFAULT_DTS_FILE" "$expected_harts" +if [ -n "$DTB_REQUIRED_MIN_MEMORY_BYTES" ] && { + [ -z "$DTB_MIN_MEMORY_BYTES" ] || + [ "$DTB_REQUIRED_MIN_MEMORY_BYTES" -gt "$DTB_MIN_MEMORY_BYTES" ] +}; then + DTB_MIN_MEMORY_BYTES="$DTB_REQUIRED_MIN_MEMORY_BYTES" +fi check_dtb_memory_layout "$DEFAULT_DTS_FILE" "$DTB_MIN_MEMORY_BYTES" SBI_IMAGE="$SBI_BUILD_DIR/build/platform/generic/firmware/fw_jump.bin" if [ "${MULTIHART:-0}" = 1 ]; then @@ -275,8 +285,9 @@ else fi check_image_component_size OpenSBI "$SBI_IMAGE" $(( (DTB_OFFSET_KB - SBI_OFFSET_KB) * KILOBYTE )) check_image_component_size DTB "$DEFAULT_DTB_FILE" $(( DTB_MAX_SIZE_KB * KILOBYTE )) -dd if="$STARTUP_FILE" of="$WORKLOAD_BUILD_DIR/fw_payload.bin" bs="$KILOBYTE" count="$SBI_OFFSET_KB" status=none -dd if="$DEFAULT_DTB_FILE" of="$WORKLOAD_BUILD_DIR/fw_payload.bin" bs="$KILOBYTE" seek="$DTB_OFFSET_KB" conv=notrunc status=none -dd if="$SBI_IMAGE" of="$WORKLOAD_BUILD_DIR/fw_payload.bin" bs="$KILOBYTE" seek="$SBI_OFFSET_KB" conv=notrunc status=none -dd if="$KERNEL_IMAGE" of="$WORKLOAD_BUILD_DIR/fw_payload.bin" bs="$KILOBYTE" seek="$KERNEL_OFFSET_KB" conv=notrunc status=none -dd if="$CPIO_ARCHIVE" of="$WORKLOAD_BUILD_DIR/fw_payload.bin" bs="$KILOBYTE" seek="$INITRAMFS_OFFSET_KB" conv=notrunc status=none +mkdir -p "$(dirname "$FIRMWARE_OUTPUT")" +dd if="$STARTUP_FILE" of="$FIRMWARE_OUTPUT" bs="$KILOBYTE" count="$SBI_OFFSET_KB" status=none +dd if="$DEFAULT_DTB_FILE" of="$FIRMWARE_OUTPUT" bs="$KILOBYTE" seek="$DTB_OFFSET_KB" conv=notrunc status=none +dd if="$SBI_IMAGE" of="$FIRMWARE_OUTPUT" bs="$KILOBYTE" seek="$SBI_OFFSET_KB" conv=notrunc status=none +dd if="$KERNEL_IMAGE" of="$FIRMWARE_OUTPUT" bs="$KILOBYTE" seek="$KERNEL_OFFSET_KB" conv=notrunc status=none +dd if="$CPIO_ARCHIVE" of="$FIRMWARE_OUTPUT" bs="$KILOBYTE" seek="$INITRAMFS_OFFSET_KB" conv=notrunc status=none diff --git a/scripts/build-gcpt.sh b/scripts/build-gcpt.sh index b9cb65e..7a6f531 100644 --- a/scripts/build-gcpt.sh +++ b/scripts/build-gcpt.sh @@ -7,6 +7,7 @@ BUILD_DIR="$(dirname "$GCPT_BUILD_DIR")" GCPT_IMPLEMENTATION="${GCPT_IMPLEMENTATION:-alpha}" GCPT_CONFIGURE_MODE="${GCPT_CONFIGURE_MODE:-normal}" GCPT_PAYLOAD_PATH="${GCPT_PAYLOAD_PATH:-${3:-}}" +GCPT_SERIAL_PORT="${GCPT_SERIAL_PORT:-}" source "$(dirname "${BASH_SOURCE[0]}")/dts-config.sh" @@ -28,6 +29,9 @@ case "$GCPT_IMPLEMENTATION" in make -C "$GCPT_BUILD_DIR" ;; libcheckpoint) + if [ -n "$GCPT_SERIAL_PORT" ]; then + CFLAGS="${CFLAGS:-} -DCONFIG_SERIAL_PORT=$GCPT_SERIAL_PORT" + fi case "$GCPT_CONFIGURE_MODE" in normal|dual_core) ;; *) diff --git a/scripts/build-sbi.sh b/scripts/build-sbi.sh index 2c4e2b5..0078a51 100644 --- a/scripts/build-sbi.sh +++ b/scripts/build-sbi.sh @@ -20,7 +20,7 @@ else read -r MEM_BEGIN MEM_SIZE CLINT_MMIO <<< "$DTS_CONFIG" FW_TEXT_START=$((MEM_BEGIN + MEGABYTE)) FW_JUMP_ADDR="$(dts_linux_kernel_address "$MEM_BEGIN" "$((2 * MEGABYTE))")" - FW_JUMP_FDT_ADDR=$((MEM_BEGIN + 1536 * 1024)) + FW_JUMP_FDT_ADDR=$((MEM_BEGIN + 1792 * 1024)) fi # prepare OpenSBI source diff --git a/scripts/export-linux-debug-artifacts.sh b/scripts/export-linux-debug-artifacts.sh index c2d9185..efd94d3 100755 --- a/scripts/export-linux-debug-artifacts.sh +++ b/scripts/export-linux-debug-artifacts.sh @@ -30,7 +30,7 @@ DTB_FILE="$WORKLOAD_BUILD_DIR/dt/$DTB_BASENAME.dtb" DTS_FILE="$WORKLOAD_BUILD_DIR/dt/$DTB_BASENAME.dts" SBI_ELF="$SBI_BUILD_DIR/build/platform/generic/firmware/fw_jump.elf" SBI_CONFIG="$SBI_BUILD_DIR/platform/generic/configs/defconfig" -FIRMWARE_IMAGE="$WORKLOAD_BUILD_DIR/fw_payload.bin" +FIRMWARE_IMAGE="$(realpath "${FIRMWARE_IMAGE:-$WORKLOAD_BUILD_DIR/fw_payload.bin}")" ROOTFS="$WORKLOAD_BUILD_DIR/rootfs.cpio" for file in "$SYSTEM_MAP" "$KERNEL_CONFIG" "$DTB_FILE" "$DTS_FILE" "$SBI_ELF" "$SBI_CONFIG" "$FIRMWARE_IMAGE" "$ROOTFS" "$KERNEL_IMAGE" "$WORKLOAD_ELF" "$BUILD_LOG" "$RUN_COMMAND" "$SPEC_CONFIG" "$GCPT_ELF" "$GCPT_BIN"; do @@ -75,7 +75,7 @@ cp "$SBI_ELF" "$SBI_DIR/fw_jump.elf" cp "$SBI_CONFIG" "$SBI_DIR/defconfig" kernel_min_offset_mb=2 -dtb_offset=$((1536 * 1024)) +dtb_offset=$((1792 * 1024)) multihart=false if [ "${MULTIHART:-0}" = 1 ]; then kernel_min_offset_mb=134 diff --git a/scripts/generate-xiangshan-multihart-dts.py b/scripts/generate-xiangshan-multihart-dts.py index 3333692..4ecc171 100755 --- a/scripts/generate-xiangshan-multihart-dts.py +++ b/scripts/generate-xiangshan-multihart-dts.py @@ -86,31 +86,39 @@ def debug_interrupt_list(harts): return " ".join(f"&intc_cpu{hart} 65535" for hart in range(harts)) -def align_nemu_plic(text): - return re.sub(r"riscv,ndev = <(?:0x42|66)>;", "riscv,ndev = <64>;", text) +def align_qemu_plic(text): + return re.sub(r"riscv,ndev = <(?:0x42|64|66)>;", "riscv,ndev = <66>;", text) -def replace_fpga_uart_with_nemu_uartlite(text): - node_header = "\t\tuart0: serial@310b0000 {" - if node_header not in text: - return text +def replace_uart_with_qemu_16550(text): + match = re.search(r"^\t\tuart0: serial@[0-9a-fA-F]+ \{", text, re.MULTILINE) + if match is None: + raise RuntimeError("DTS does not contain the expected uart0 node") - start, end = extract_node(text, node_header) - comment_start = text.rfind("\n\t\t/*", 0, start) - if comment_start != -1 and "UART16550" in text[comment_start:start]: - start = comment_start + 1 + start, end = extract_node(text, match.group(0)) + prefix = text[:start] + comment_match = re.search( + r"(?P\r?\n[ \t]*/\*(?:[^*]|\*(?!/))*\*/)[ \t]*\r?\n[ \t]*$", + prefix, + ) + if comment_match and re.search( + r"(?i)(?:\bUART(?:LITE|16550)?\b|0x40600000|serial@[0-9a-fA-F]+)", + comment_match.group("comment"), + ): + start = comment_match.start("comment") + 1 uart = "\n".join( [ "\t\t/*", - "\t\t * QEMU/NEMU exposes UARTLITE at 0x40600000.", + "\t\t * QEMU's nemu machine exposes the XiangShan 16550A UART at 0x310b0000.", + "\t\t * It is not connected to the PLIC.", "\t\t */", - "\t\tuart0: serial@40600000 {", - '\t\t\tcompatible = "xlnx,xps-uartlite-1.00.a";', - "\t\t\tinterrupt-parent = <&PLIC>;", - "\t\t\tinterrupts = <3>;", + "\t\tuart0: serial@310b0000 {", + '\t\t\tcompatible = "ns16550a";', "\t\t\tcurrent-speed = <115200>;", - "\t\t\treg = <0x0 0x40600000 0x0 0x1000>;", - '\t\t\treg-names = "control";', + "\t\t\treg = <0x0 0x310b0000 0x0 0x10000>;", + "\t\t\treg-shift = <0x2>;", + "\t\t\treg-io-width = <0x4>;", + "\t\t\tclock-frequency = <50000000>;", '\t\t\tstatus = "okay";', "\t\t};", ] @@ -118,10 +126,22 @@ def replace_fpga_uart_with_nemu_uartlite(text): return text[:start] + uart + text[end:] -def sanitize_nemu_uart_comments(text): +def sanitize_qemu_comments(text): + text = text.replace( + " * XiangShan FPGA DTS used by the fpga board flow.", + " * XiangShan multi-hart DTS used by QEMU's nemu machine.", + ) text = text.replace( " * 2. UART16550 is exposed as the serial console.", + " * 2. QEMU's nemu machine exposes a 16550A serial console.", + ) + text = text.replace( " * 2. QEMU/NEMU UARTLITE is exposed as the serial console.", + " * 2. QEMU's nemu machine exposes a 16550A serial console.", + ) + text = text.replace( + "This FPGA image boots without AIA.", + "This QEMU configuration boots without AIA.", ) chosen_comment = re.compile( r"\n\t\t/\*\n" @@ -197,9 +217,9 @@ def render(base_text, harts, memory_gib=None): "interrupts-extended = <&intc_cpu0 11 &intc_cpu0 9>;", f"interrupts-extended = <{interrupt_list(harts, 11, 9)}>;", ) - text = align_nemu_plic(text) - text = replace_fpga_uart_with_nemu_uartlite(text) - text = sanitize_nemu_uart_comments(text) + text = align_qemu_plic(text) + text = replace_uart_with_qemu_16550(text) + text = sanitize_qemu_comments(text) text = add_checkpoint_reserved_memory(text) if memory_gib is not None: text = override_memory_profile(text, memory_gib) diff --git a/scripts/run-qemu.sh b/scripts/run-qemu.sh new file mode 100755 index 0000000..0230279 --- /dev/null +++ b/scripts/run-qemu.sh @@ -0,0 +1,116 @@ +#!/usr/bin/env bash +set -uo pipefail + +usage() { + echo "Usage: QEMU_BIN=/path/to/qemu-system-riscv64 [HARTS=N] [QEMU_MEMORY=SIZE] $0 " >&2 +} + +if [ "$#" -ne 1 ]; then + usage + exit 2 +fi + +firmware="$1" +if [ ! -s "$firmware" ]; then + echo "QEMU firmware is missing or empty: $firmware" >&2 + exit 2 +fi +firmware="$(realpath "$firmware")" + +qemu_request="${QEMU_BIN:-}" +if [ -z "$qemu_request" ]; then + echo "QEMU_BIN must specify qemu-system-riscv64" >&2 + usage + exit 2 +fi +if [[ "$qemu_request" == */* ]]; then + if [ ! -x "$qemu_request" ]; then + echo "QEMU executable is missing or not executable: $qemu_request" >&2 + exit 2 + fi + qemu_bin="$(realpath "$qemu_request")" +else + qemu_bin="$(command -v "$qemu_request" || true)" + if [ -z "$qemu_bin" ]; then + echo "QEMU executable was not found in PATH: $qemu_request" >&2 + exit 2 + fi +fi + +qemu_contract="$({ + printf 'info mtree\ninfo qtree\nquit\n' | LC_ALL=C timeout 10s "$qemu_bin" \ + -machine nemu \ + -accel tcg \ + -cpu rv64 \ + -smp 1 \ + -m 128M \ + -display none \ + -serial none \ + -bios none \ + -S \ + -monitor stdio +} 2>&1)" +contract_status=$? +if [ "$contract_status" -ne 0 ]; then + echo "Failed to inspect the QEMU 'nemu' machine from $qemu_bin" >&2 + printf '%s\n' "$qemu_contract" >&2 + exit "$contract_status" +fi +if ! grep -Eq '0*310b0000-0*310bffff.*riscv\.nemu\.uart' <<< "$qemu_contract" || + ! grep -Fq 'dev: serial-mm' <<< "$qemu_contract" || + ! grep -Eq 'regshift = 2([[:space:]]|\()' <<< "$qemu_contract" || + ! grep -Eq 'num-sources = 67([[:space:]]|\()' <<< "$qemu_contract" || + ! grep -Eq 'timebase-freq = 1000000([[:space:]]|\()' <<< "$qemu_contract"; then + echo "QEMU 'nemu' machine does not match the required XiangShan device contract: $qemu_bin" >&2 + echo "Expected a 16550A UART at 0x310b0000, PLIC with 67 sources, and a 1 MHz timer." >&2 + echo "Use OpenXiangShan/qemu commit d6ef1ba720 or a compatible descendant." >&2 + exit 2 +fi + +qemu_cpu="rv64,zicond=true,v=true,vlen=128,h=true,sv39=true,sv48=true,sv57=false,sv64=false,smstateen=true,sscofpmf=true,smcntrpmf=true,svade=true,svinval=true,svnapot=true,svpbmt=true,zacas=true,zawrs=true,zba=true,zbb=true,zbc=true,zbkb=true,zbkc=true,zbkx=true,zbs=true,zca=true,zcb=true,zcmop=true,zfa=true,zfh=true,zfhmin=true,zicntr=true,zicsr=true,zifencei=true,zihintntl=true,zihintpause=true,zihpm=true,zimop=true,zkn=true,zknd=true,zkne=true,zknh=true,zksed=true,zksh=true,zkt=true,zvbb=true,zvfh=true,zvfhmin=true,zvkt=true" +harts="${HARTS:-1}" +case "$harts" in + ''|*[!0-9]*) echo "HARTS must be an integer in the range 1..128" >&2; exit 2 ;; +esac +if [ "$harts" -lt 1 ] || [ "$harts" -gt 128 ]; then + echo "HARTS must be an integer in the range 1..128" >&2 + exit 2 +fi +qemu_memory="${QEMU_MEMORY:-2G}" +log_file="$(mktemp)" +cleanup() { + rm -f -- "$log_file" +} +trap cleanup EXIT + +set +e +"$qemu_bin" \ + -machine nemu \ + -accel tcg \ + -cpu "$qemu_cpu" \ + -smp "$harts" \ + -m "$qemu_memory" \ + -nographic \ + -no-reboot \ + -bios "$firmware" 2>&1 | tee "$log_file" +qemu_status=${PIPESTATUS[0]} +set -e + +if grep -Fq 'Hit BAD TRAP' "$log_file"; then + echo "QEMU reported Hit BAD TRAP" >&2 + exit 1 +fi +if grep -Fq 'Hit GOOD TRAP' "$log_file"; then + if [ "$qemu_status" -ne 0 ]; then + echo "QEMU reported Hit GOOD TRAP but exited with status $qemu_status" >&2 + exit "$qemu_status" + fi + exit 0 +fi +if [ "$qemu_status" -ne 0 ]; then + echo "QEMU exited with status $qemu_status before a terminal trap" >&2 + exit "$qemu_status" +fi + +echo "QEMU exited normally without Hit GOOD TRAP or Hit BAD TRAP" >&2 +exit 1 diff --git a/workloads/linux/coremark/README.md b/workloads/linux/coremark/README.md index d529737..57c45db 100644 --- a/workloads/linux/coremark/README.md +++ b/workloads/linux/coremark/README.md @@ -17,15 +17,43 @@ The benchmark runs with these parameters, which is a "standard" verification run - 0x0 0x0 0x66 0 7 1 2000 +## Single-core QEMU build + +Build a firmware image for the QEMU NEMU machine: + +```bash +make linux/coremark PLATFORM=qemu -jN +``` + +The result is `build/linux-workloads/coremark/fw_payload.qemu.bin`. Run it with +a compatible QEMU using: + +```bash +QEMU_BIN=/path/to/qemu-system-riscv64 \ + bash scripts/run-qemu.sh \ + build/linux-workloads/coremark/fw_payload.qemu.bin +``` + +Building does not require QEMU. The runner requires `QEMU_BIN`; it does not +enable profiling or checkpoint generation. + ## Multi-hart builds Build a multi-hart CoreMark workload with: ```bash -make linux/coremark MULTIHART=1 HARTS= -jN +make linux/coremark MULTIHART=1 HARTS=2 \ + DEFAULT_DTB=xiangshan-fpga-noAIA-2hart-mem8g-novec -jN ``` The generated root filesystem starts one CoreMark process per hart. Each process is pinned with `taskset` and uses the same verification arguments listed above. Set `HARTS` to the number of harts in the matching QEMU checkpoint; the build -selects `xiangshan-fpga-noAIA-hart-mem8g` by default. +automatically selects `PLATFORM=qemu` and requires a matching `DEFAULT_DTB`. +Run with the same hart count and enough memory for that DTS, for example: + +```bash +QEMU_BIN=/path/to/qemu-system-riscv64 QEMU_MEMORY=8G \ + HARTS=2 bash scripts/run-qemu.sh \ + build/linux-workloads/coremark/fw_payload.qemu.bin +``` diff --git a/workloads/linux/spec2006/README.md b/workloads/linux/spec2006/README.md index b3adbf1..a014606 100644 --- a/workloads/linux/spec2006/README.md +++ b/workloads/linux/spec2006/README.md @@ -32,6 +32,31 @@ The build flow is: build/linux-workloads/spec2006//fw_payload.bin ``` +## Build and run with QEMU + +Use `PLATFORM=qemu` to assemble the same single-core benchmark/rootfs for the +QEMU NEMU machine: + +```sh +make linux/spec2006 PLATFORM=qemu BENCH=astar INPUT=biglakes \ + SPEC2006_ISO=/path/to/cpu2006.iso -jN +``` + +This writes +`build/linux-workloads/spec2006//fw_payload.qemu.bin` without replacing +the NEMU `fw_payload.bin`. Run the Astar BigLakes case with: + +```sh +QEMU_BIN=/path/to/qemu-system-riscv64 \ + bash scripts/run-qemu.sh \ + build/linux-workloads/spec2006/astar_biglakes/fw_payload.qemu.bin +``` + +Building does not require QEMU. The runner requires `QEMU_BIN` to name a +compatible executable. Single-core QEMU mode uses the 2 GiB NEMU-machine DTS +with a no-IRQ 16550A UART at `0x310b0000` and does not enable SimPoint +profiling or checkpoint generation. + ## Build and export images Export all selected cases to `build/images/spec2006`: @@ -55,9 +80,13 @@ make spec2006-images BENCH=mcf SPEC2006_ISO=/path/to/cpu2006.iso -jN make spec2006-images BENCH=astar_biglakes SPEC2006_ISO=/path/to/cpu2006.iso -jN ``` -By default, SPEC2006 firmware images embed -`dts/xiangshan-fpga-noAIA-novec.dts.in`. Override that baseline with -`DEFAULT_DTB` if you need another DTS template: +Adding `PLATFORM=qemu` exports the complete QEMU artifact tree to the same +`build/images/spec2006` directory. Its firmware is +`bin/.fw_payload.bin`. + +By default, NEMU firmware embeds `dts/xiangshan-fpga-noAIA-novec.dts.in`, while +QEMU firmware embeds `dts/xiangshan-qemu-nemu-mem2g.dts.in`. Override the +platform default with `DEFAULT_DTB` if you need another DTS template: ```sh make linux/spec2006 BENCH=astar INPUT=biglakes \ @@ -74,7 +103,18 @@ and the selected device-tree template. Supported counts are 2 through 128: make linux/spec2006 BENCH=astar INPUT=biglakes \ SPEC2006_ISO=/path/to/cpu2006.iso \ MULTIHART=1 HARTS=2 \ - DEFAULT_DTB=xiangshan-fpga-noAIA-2hart-mem8g -jN + DEFAULT_DTB=xiangshan-fpga-noAIA-2hart-mem8g-novec -jN +``` + +`MULTIHART=1` automatically selects `PLATFORM=qemu`; explicitly setting +`PLATFORM=nemu` is rejected. The resulting firmware is +`build/linux-workloads/spec2006//fw_payload.qemu.bin`. When running it, +set `HARTS` and `QEMU_MEMORY` to match the selected DTS: + +```sh +QEMU_BIN=/path/to/qemu-system-riscv64 QEMU_MEMORY=8G \ + HARTS=2 bash scripts/run-qemu.sh \ + build/linux-workloads/spec2006/astar_biglakes/fw_payload.qemu.bin ``` The package step creates one SPEC tree per hart: @@ -126,12 +166,15 @@ build/images/spec2006/ `kernel/` contains the ELF kernel plus its symbol map and configuration for debugging; `dt/` contains the exact DTB and generated DTS used by that case. `manifest/` records component hashes and load addresses. `gcpt/`, `cfg/`, and -`opensbi/` are shared by the export tree. +`opensbi/` are shared by cases within the export tree. -Re-running `make spec2006-images` rebuilds the export tree so the directory -layout and contents stay complete and consistent. +Re-running `make spec2006-images` rebuilds the export tree for the selected +platform, so a QEMU export replaces the previously exported NEMU artifacts in +the same directory. -Override the destination with `SPEC2006_IMAGE_DIR=/path/to/image`. +Override the destination with `SPEC2006_IMAGE_DIR=/path/to/image`; the explicit +path is used as-is. Use a separate custom directory if both NEMU and QEMU +exports must be kept, because each run replaces the complete output tree. ## Build ELF only diff --git a/workloads/linux/spec2006/rules.mk b/workloads/linux/spec2006/rules.mk index 89b7e0e..f084b6c 100644 --- a/workloads/linux/spec2006/rules.mk +++ b/workloads/linux/spec2006/rules.mk @@ -9,7 +9,7 @@ SPEC2006_BUILD_DIR ?= $(SPEC2006_REPO_ROOT)/build/linux-workloads/spec2006 SPEC2006_CASE_CONFIG := $(SPEC2006_WORKLOAD_DIR)/spec06.json SPEC2006_CFG ?= $(SPEC2006_WORKLOAD_DIR)/configs/gcc16-linux-riscv64-rva23u64_novec.cfg SPEC2006_HELPER := $(SPEC2006_WORKLOAD_DIR)/spec2006-package.py -SPEC2006_IMAGE_DIR ?= $(SPEC2006_REPO_ROOT)/build/images/spec2006 +QEMU_DEFAULT_DTB ?= xiangshan-qemu-nemu-mem2g SPEC2006_SOURCE_SPEC_ISO := $(SPEC2006_ISO) SPEC2006_PREPARED_SPEC_ROOT := $(SPEC2006_BUILD_DIR)/spec-src SPEC2006_SOURCE_SPEC_HASH := $(shell printf '%s\n' "$(SPEC2006_SOURCE_SPEC_ISO)" | sha256sum | cut -d ' ' -f 1) @@ -21,7 +21,18 @@ SPEC2006_GNU_TOOLCHAIN_ROOT ?= SPEC2006_JEMALLOC_ROOT ?= SPEC2006_MULTIHART ?= $(MULTIHART) SPEC2006_HARTS ?= $(if $(HARTS),$(HARTS),2) -SPEC2006_DEFAULT_DTB ?= $(if $(DEFAULT_DTB),$(DEFAULT_DTB),$(if $(filter 1,$(SPEC2006_MULTIHART)),,xiangshan-fpga-noAIA-novec)) +PLATFORM ?= $(if $(filter 1,$(SPEC2006_MULTIHART)),qemu,nemu) +ifeq ($(filter $(PLATFORM),nemu qemu),) +$(error PLATFORM must be either nemu or qemu) +endif +ifeq ($(filter 1,$(SPEC2006_MULTIHART)),1) +ifneq ($(PLATFORM),qemu) +$(error MULTIHART=1 requires PLATFORM=qemu) +endif +endif +SPEC2006_IMAGE_DIR ?= $(SPEC2006_REPO_ROOT)/build/images/spec2006 +SPEC2006_DEFAULT_DTB ?= $(if $(DEFAULT_DTB),$(DEFAULT_DTB),$(if $(filter 1,$(SPEC2006_MULTIHART)),,$(if $(filter qemu,$(PLATFORM)),$(QEMU_DEFAULT_DTB),xiangshan-fpga-noAIA-novec))) +SPEC2006_FIRMWARE_FILENAME := $(if $(filter qemu,$(PLATFORM)),fw_payload.qemu.bin,fw_payload.bin) ifeq ($(filter 1,$(SPEC2006_MULTIHART)),1) ifeq ($(strip $(SPEC2006_DEFAULT_DTB)),) $(error DEFAULT_DTB or SPEC2006_DEFAULT_DTB must be specified when MULTIHART=1; use the complete DTS basename without .dts.in) @@ -146,22 +157,23 @@ $(SPEC2006_BUILD_DIR)/$(1)/rootfs.cpio: $(SPEC2006_PREPARE_STAMP) $(SPEC2006_BUI MULTIHART_PAYLOAD_DIR=spec \ bash "$$(SPEC2006_SCRIPTS_DIR)/build-workload-linux.sh" "$$(SPEC2006_WORKLOAD_DIR)" "$(SPEC2006_BUILD_DIR)/$(1)" -$(SPEC2006_BUILD_DIR)/$(1)/fw_payload.bin: $$(SPEC2006_DTS_SOURCES) $$(SPEC2006_DEFAULT_DTB_STAMP) $$(SPEC2006_GCPT_BIN) $$(SPEC2006_SCRIPTS_DIR)/build-firmware-linux.sh $$(SPEC2006_SCRIPTS_DIR)/dts-config.sh $(SPEC2006_BUILD_DIR)/$(1)/rootfs.cpio $$(SPEC2006_LINUX_IMAGE) $$(SPEC2006_SBI_BIN) +$(SPEC2006_BUILD_DIR)/$(1)/$(SPEC2006_FIRMWARE_FILENAME): $$(SPEC2006_DTS_SOURCES) $$(SPEC2006_DEFAULT_DTB_STAMP) $$(SPEC2006_GCPT_BIN) $$(SPEC2006_SCRIPTS_DIR)/build-firmware-linux.sh $$(SPEC2006_SCRIPTS_DIR)/dts-config.sh $(SPEC2006_BUILD_DIR)/$(1)/rootfs.cpio $$(SPEC2006_LINUX_IMAGE) $$(SPEC2006_SBI_BIN) @printf '$(SPEC2006_PROGRESS_PREFIX) Assembling firmware for $(1)\n' @CROSS_COMPILE="$$(SPEC2006_BUILDROOT_CROSS_COMPILE)" \ DTC="$$(SPEC2006_DTC)" \ DEFAULT_DTB="$$(SPEC2006_DEFAULT_DTB)" \ + FIRMWARE_OUTPUT="$$(abspath $$@)" \ MULTIHART="$$(SPEC2006_MULTIHART)" \ HARTS="$$(SPEC2006_HARTS)" \ SPEC2006_PROGRESS_K="$$(SPEC2006_PROGRESS_K)" \ SPEC2006_PROGRESS_N="$$(SPEC2006_PROGRESS_N)" \ bash "$$(SPEC2006_SCRIPTS_DIR)/build-firmware-linux.sh" "$$(SPEC2006_GCPT_BIN)" "$$(SPEC2006_SBI_BUILD_DIR)" "$$(SPEC2006_DTS_DIR)" "$$(SPEC2006_LINUX_IMAGE)" "$(SPEC2006_BUILD_DIR)/$(1)" -linux/$(1): $(SPEC2006_BUILD_DIR)/$(1)/fw_payload.bin +linux/$(1): $(SPEC2006_BUILD_DIR)/$(1)/$(SPEC2006_FIRMWARE_FILENAME) WORKLOAD_PHONY_TARGETS += linux/$(1) -$(call spec2006_case_image_stamp,$(1)): $(SPEC2006_PREPARE_STAMP) $(SPEC2006_BUILD_DIR)/$(1)/fw_payload.bin $(SPEC2006_GCPT_ELF) $(SPEC2006_GCPT_BIN) $(SPEC2006_LINUX_IMAGE) $(SPEC2006_SBI_BIN) $$(SPEC2006_SCRIPTS_DIR)/export-linux-debug-artifacts.sh $$(SPEC2006_SCRIPTS_DIR)/dts-config.sh | spec2006-check-spec-iso +$(call spec2006_case_image_stamp,$(1)): $(SPEC2006_PREPARE_STAMP) $(SPEC2006_BUILD_DIR)/$(1)/$(SPEC2006_FIRMWARE_FILENAME) $(SPEC2006_GCPT_ELF) $(SPEC2006_GCPT_BIN) $(SPEC2006_LINUX_IMAGE) $(SPEC2006_SBI_BIN) $$(SPEC2006_SCRIPTS_DIR)/export-linux-debug-artifacts.sh $$(SPEC2006_SCRIPTS_DIR)/dts-config.sh | spec2006-check-spec-iso @printf '$(SPEC2006_PROGRESS_PREFIX) Exporting $(1) artifacts to $(SPEC2006_IMAGE_DIR)\n' @run_command="$(SPEC2006_BUILD_DIR)/$(1)/package/spec/run.sh"; \ if [ ! -f "$$$$run_command" ]; then run_command="$(SPEC2006_BUILD_DIR)/$(1)/package/spec_common/launch_multihart.sh"; fi; \ @@ -172,6 +184,7 @@ $(call spec2006_case_image_stamp,$(1)): $(SPEC2006_PREPARE_STAMP) $(SPEC2006_BUI SPEC_CONFIG="$(SPEC2006_CFG)" \ GCPT_ELF="$(SPEC2006_GCPT_ELF)" \ GCPT_BIN="$(SPEC2006_GCPT_BIN)" \ + FIRMWARE_IMAGE="$(SPEC2006_BUILD_DIR)/$(1)/$(SPEC2006_FIRMWARE_FILENAME)" \ bash "$(SPEC2006_SCRIPTS_DIR)/export-linux-debug-artifacts.sh" "$(SPEC2006_BUILDROOT_DIR)" "$(SPEC2006_SBI_BUILD_DIR)" "$(SPEC2006_BUILD_DIR)/$(1)" "$(SPEC2006_IMAGE_DIR)" "$(1)" "$(SPEC2006_DEFAULT_DTB)" "$(SPEC2006_LINUX_IMAGE)" @touch "$$@" endef @@ -184,7 +197,7 @@ linux/spec2006: spec2006-check-spec-iso echo " or: make linux/spec2006 BENCH=astar_biglakes SPEC2006_ISO=/path/to/cpu2006.iso -jN"; \ exit 1; \ fi - @$(MAKE) --no-print-directory -f "$(SPEC2006_RECURSE_MAKEFILE)" GCPT_DEFAULT_DTB="$(SPEC2006_DEFAULT_DTB)" $(SPEC2006_BUILD_DIR)/$(SPEC2006_CASE)/fw_payload.bin + @$(MAKE) --no-print-directory -f "$(SPEC2006_RECURSE_MAKEFILE)" GCPT_DEFAULT_DTB="$(SPEC2006_DEFAULT_DTB)" $(SPEC2006_BUILD_DIR)/$(SPEC2006_CASE)/$(SPEC2006_FIRMWARE_FILENAME) spec2006-elf: spec2006-check-spec-iso @if [ -z "$(BENCH)" ]; then \ diff --git a/workloads/linux/spec2017/README.md b/workloads/linux/spec2017/README.md index edab6fb..c25975c 100644 --- a/workloads/linux/spec2017/README.md +++ b/workloads/linux/spec2017/README.md @@ -16,6 +16,15 @@ make linux/spec2017 BENCH=mcf MODE=rate INPUT=ref SPEC2017_ISO=/path/to/cpu2017. make linux/spec2017 BENCH=mcf MODE=speed INPUT=ref SPEC2017_ISO=/path/to/cpu2017.iso -jN ``` +On QEMU, rate and speed builds automatically select the QEMU-compatible 8 GiB +and 24 GiB DTS profiles respectively. Match the QEMU RAM size when running the +resulting firmware: + +```sh +QEMU_MEMORY=8G bash scripts/run-qemu.sh build/linux-workloads/spec2017/mcf_rate_refrate/fw_payload.qemu.bin +QEMU_MEMORY=24G bash scripts/run-qemu.sh build/linux-workloads/spec2017/mcf_speed_refspeed/fw_payload.qemu.bin +``` + `MODE=rate` selects `_r` benchmarks and maps `INPUT=ref` to `refrate`. `MODE=speed` selects `_s` benchmarks and maps `INPUT=ref` to `refspeed`. Full case names are also accepted: @@ -33,7 +42,7 @@ matching multi-hart DTS template explicitly: make linux/spec2017 BENCH=mcf MODE=rate INPUT=ref \ SPEC2017_ISO=/path/to/cpu2017.iso \ MULTIHART=1 HARTS=2 \ - DEFAULT_DTB=xiangshan-fpga-noAIA-2hart-mem16g -jN + DEFAULT_DTB=xiangshan-fpga-noAIA-2hart-mem16g-novec -jN ``` The same options apply to split image exports: @@ -42,7 +51,7 @@ The same options apply to split image exports: make spec2017-images BENCH=mcf MODE=rate INPUT=ref \ SPEC2017_ISO=/path/to/cpu2017.iso \ MULTIHART=1 HARTS=2 \ - DEFAULT_DTB=xiangshan-fpga-noAIA-2hart-mem16g -jN + DEFAULT_DTB=xiangshan-fpga-noAIA-2hart-mem16g-novec -jN ``` The package step creates `/spec0` through `/spec` and starts one copy on @@ -167,9 +176,9 @@ The final `nemu-trap ` is always emitted for single-hart images. Multi-hart images use the per-hart task wrappers and aggregate launcher described above instead. -The repository provides static `xiangshan-fpga-noAIA-novec` DTS templates for the -SPEC2017 memory profiles used by default. The embedded DTB is selected per -case: +The repository provides static DTS templates for the SPEC2017 memory profiles +used by default. NEMU uses the `xiangshan-fpga-noAIA-novec` family and QEMU uses +the `xiangshan-qemu-nemu` family. The embedded DTB is selected per case: ```text rate -> 8g @@ -209,6 +218,8 @@ The source templates live in: ```text dts/xiangshan-fpga-noAIA-mem8g-novec.dts.in dts/xiangshan-fpga-noAIA-mem24g-novec.dts.in +dts/xiangshan-qemu-nemu-mem8g.dts.in +dts/xiangshan-qemu-nemu-mem24g.dts.in ``` They are compiled into each case's `dt/` directory during firmware assembly. diff --git a/workloads/linux/spec2017/rules.mk b/workloads/linux/spec2017/rules.mk index b4e213b..47979bc 100644 --- a/workloads/linux/spec2017/rules.mk +++ b/workloads/linux/spec2017/rules.mk @@ -22,8 +22,21 @@ SPEC2017_GNU_TOOLCHAIN_ROOT ?= SPEC2017_JEMALLOC_ROOT ?= SPEC2017_MULTIHART ?= $(MULTIHART) SPEC2017_HARTS ?= $(if $(HARTS),$(HARTS),2) +PLATFORM ?= $(if $(filter 1,$(SPEC2017_MULTIHART)),qemu,nemu) +ifeq ($(filter $(PLATFORM),nemu qemu),) +$(error PLATFORM must be either nemu or qemu) +endif +ifeq ($(filter 1,$(SPEC2017_MULTIHART)),1) +ifneq ($(PLATFORM),qemu) +$(error MULTIHART=1 requires PLATFORM=qemu) +endif +endif +QEMU_DEFAULT_DTB ?= xiangshan-qemu-nemu-mem2g +SPEC2017_QEMU_DEFAULT_DTB ?= xiangshan-qemu-nemu SPEC2017_EXPLICIT_DEFAULT_DTB := $(if $(DEFAULT_DTB),1,$(if $(filter undefined,$(origin SPEC2017_DEFAULT_DTB)),,1)) -SPEC2017_DEFAULT_DTB ?= $(if $(DEFAULT_DTB),$(DEFAULT_DTB),$(if $(filter 1,$(SPEC2017_MULTIHART)),,xiangshan-fpga-noAIA-novec)) +SPEC2017_DEFAULT_DTB ?= $(if $(DEFAULT_DTB),$(DEFAULT_DTB),$(if $(filter 1,$(SPEC2017_MULTIHART)),,$(if $(filter qemu,$(PLATFORM)),$(SPEC2017_QEMU_DEFAULT_DTB),xiangshan-fpga-noAIA-novec))) +SPEC2017_GCPT_DEFAULT_DTB := $(if $(and $(filter qemu,$(PLATFORM)),$(filter-out 1,$(SPEC2017_MULTIHART))),$(QEMU_DEFAULT_DTB),$(SPEC2017_DEFAULT_DTB)) +SPEC2017_FIRMWARE_FILENAME := $(if $(filter qemu,$(PLATFORM)),fw_payload.qemu.bin,fw_payload.bin) ifeq ($(filter 1,$(SPEC2017_MULTIHART)),1) ifeq ($(strip $(SPEC2017_DEFAULT_DTB)),) $(error DEFAULT_DTB or SPEC2017_DEFAULT_DTB must be specified when MULTIHART=1; use the complete DTS basename without .dts.in) @@ -187,11 +200,12 @@ $(SPEC2017_BUILD_DIR)/$(1)/firmware/dtb-$(call spec2017_case_dtb_tag,$(1)).stamp "required_min_memory_bytes=$(call spec2017_case_dtb_required_min_memory_bytes,$(1))" > "$$@.tmp" @if [ -f "$$@" ] && cmp -s "$$@.tmp" "$$@"; then rm "$$@.tmp"; else mv "$$@.tmp" "$$@"; fi -$(SPEC2017_BUILD_DIR)/$(1)/fw_payload.bin: $$(SPEC2017_DTS_SOURCES) $$(SPEC2017_GCPT_BIN) $$(SPEC2017_SCRIPTS_DIR)/build-firmware-linux.sh $$(SPEC2017_SCRIPTS_DIR)/dts-config.sh $(SPEC2017_BUILD_DIR)/$(1)/rootfs.cpio $$(SPEC2017_LINUX_IMAGE) $$(SPEC2017_SBI_BIN) $(SPEC2017_BUILD_DIR)/$(1)/firmware/dtb-$(call spec2017_case_dtb_tag,$(1)).stamp +$(SPEC2017_BUILD_DIR)/$(1)/$(SPEC2017_FIRMWARE_FILENAME): $$(SPEC2017_DTS_SOURCES) $$(SPEC2017_GCPT_BIN) $$(SPEC2017_SCRIPTS_DIR)/build-firmware-linux.sh $$(SPEC2017_SCRIPTS_DIR)/dts-config.sh $(SPEC2017_BUILD_DIR)/$(1)/rootfs.cpio $$(SPEC2017_LINUX_IMAGE) $$(SPEC2017_SBI_BIN) $(SPEC2017_BUILD_DIR)/$(1)/firmware/dtb-$(call spec2017_case_dtb_tag,$(1)).stamp @printf '$(SPEC2017_PROGRESS_PREFIX) Assembling firmware for $(1)\n' @CROSS_COMPILE="$$(SPEC2017_BUILDROOT_CROSS_COMPILE)" \ DTC="$$(SPEC2017_DTC)" \ DEFAULT_DTB="$$(SPEC2017_DEFAULT_DTB)" \ + FIRMWARE_OUTPUT="$$(abspath $$@)" \ DTB_MEMORY_PROFILE="$(call spec2017_case_dtb_profile,$(1))" \ DTB_MIN_MEMORY_BYTES="$(call spec2017_case_dtb_min_memory_bytes,$(1))" \ DTB_REQUIRED_MIN_MEMORY_BYTES="$(call spec2017_case_dtb_required_min_memory_bytes,$(1))" \ @@ -201,7 +215,7 @@ $(SPEC2017_BUILD_DIR)/$(1)/fw_payload.bin: $$(SPEC2017_DTS_SOURCES) $$(SPEC2017_ SPEC2017_PROGRESS_N="$$(SPEC2017_PROGRESS_N)" \ bash "$$(SPEC2017_SCRIPTS_DIR)/build-firmware-linux.sh" "$$(SPEC2017_GCPT_BIN)" "$$(SPEC2017_SBI_BUILD_DIR)" "$$(SPEC2017_DTS_DIR)" "$$(SPEC2017_LINUX_IMAGE)" "$(SPEC2017_BUILD_DIR)/$(1)" -linux/$(1): $(SPEC2017_BUILD_DIR)/$(1)/fw_payload.bin +linux/$(1): $(SPEC2017_BUILD_DIR)/$(1)/$(SPEC2017_FIRMWARE_FILENAME) WORKLOAD_PHONY_TARGETS += linux/$(1) @@ -241,6 +255,7 @@ $(SPEC2017_IMAGE_DIR)/stamps/$(1).images.stamp: $(SPEC2017_PREPARE_STAMP) $(SPEC DTB_REQUIRED_MIN_MEMORY_BYTES="$(call spec2017_case_dtb_required_min_memory_bytes,$(1))" \ MULTIHART="$$(SPEC2017_MULTIHART)" \ HARTS="$$(SPEC2017_HARTS)" \ + FIRMWARE_OUTPUT="$$$$build_dir/$(SPEC2017_FIRMWARE_FILENAME)" \ SPEC2017_PROGRESS_K="$$(SPEC2017_PROGRESS_K)" \ SPEC2017_PROGRESS_N="$$(SPEC2017_PROGRESS_N)" \ bash "$$(SPEC2017_SCRIPTS_DIR)/build-firmware-linux.sh" "$$(SPEC2017_GCPT_BIN)" "$$(SPEC2017_SBI_BUILD_DIR)" "$$(SPEC2017_DTS_DIR)" "$$(SPEC2017_LINUX_IMAGE)" "$$$$build_dir"; \ @@ -253,6 +268,7 @@ $(SPEC2017_IMAGE_DIR)/stamps/$(1).images.stamp: $(SPEC2017_PREPARE_STAMP) $(SPEC SPEC_CONFIG="$(abspath $(call spec2017_case_cfg,$(1)))" \ GCPT_ELF="$$(SPEC2017_GCPT_ELF)" \ GCPT_BIN="$$(SPEC2017_GCPT_BIN)" \ + FIRMWARE_IMAGE="$$$$build_dir/$(SPEC2017_FIRMWARE_FILENAME)" \ bash "$$(SPEC2017_SCRIPTS_DIR)/export-linux-debug-artifacts.sh" "$$(SPEC2017_BUILDROOT_DIR)" "$$(SPEC2017_SBI_BUILD_DIR)" "$$$$build_dir" "$(SPEC2017_IMAGE_DIR)" "$$$$variant" "$(call spec2017_case_dtb_name,$(1))" "$$(SPEC2017_LINUX_IMAGE)"; \ done @touch "$$@" @@ -270,7 +286,7 @@ linux/spec2017: spec2017-check-spec-config echo "Cannot resolve SPEC2017 case from BENCH=$(BENCH), MODE=$(SPEC2017_MODE), INPUT=$(SPEC2017_INPUT)"; \ exit 1; \ fi - @$(MAKE) --no-print-directory -f "$(SPEC2017_RECURSE_MAKEFILE)" GCPT_DEFAULT_DTB="$(SPEC2017_DEFAULT_DTB)" $(SPEC2017_BUILD_DIR)/$(SPEC2017_CASE)/fw_payload.bin + @$(MAKE) --no-print-directory -f "$(SPEC2017_RECURSE_MAKEFILE)" GCPT_DEFAULT_DTB="$(SPEC2017_GCPT_DEFAULT_DTB)" $(SPEC2017_BUILD_DIR)/$(SPEC2017_CASE)/$(SPEC2017_FIRMWARE_FILENAME) spec2017-elf: spec2017-check-spec-config @if [ -z "$(BENCH)" ]; then \ @@ -309,7 +325,7 @@ spec2017-images: spec2017-check-spec-config i=0; \ for case in $(SPEC2017_IMAGE_CASES); do \ i=$$((i + 1)); \ - SPEC2017_PROGRESS_K="$$i" SPEC2017_PROGRESS_N="$$total" $(MAKE) --no-print-directory -f "$(SPEC2017_RECURSE_MAKEFILE)" GCPT_DEFAULT_DTB="$(SPEC2017_DEFAULT_DTB)" "$(SPEC2017_IMAGE_DIR)/stamps/$$case.images.stamp" || exit $$?; \ + SPEC2017_PROGRESS_K="$$i" SPEC2017_PROGRESS_N="$$total" $(MAKE) --no-print-directory -f "$(SPEC2017_RECURSE_MAKEFILE)" GCPT_DEFAULT_DTB="$(SPEC2017_GCPT_DEFAULT_DTB)" "$(SPEC2017_IMAGE_DIR)/stamps/$$case.images.stamp" || exit $$?; \ done @printf '[spec2017 %s/%s] Output written to %s\n' "$(words $(SPEC2017_IMAGE_CASES))" "$(words $(SPEC2017_IMAGE_CASES))" "$(abspath $(SPEC2017_IMAGE_DIR))"