Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ endif
# from it through the print-buildroot-version target, so a bump here is enough.
BUILDROOT_VERSION := 2026.08
BUILDROOT_DIR := build/buildroot
# DEFAULT_DTB=nutshell or nutshell-* -> nutshell_defconfig; otherwise xiangshan_defconfig.
BUILDROOT_DEFCONFIG := $(if $(filter nutshell nutshell-%,$(DEFAULT_DTB)),nutshell_defconfig,xiangshan_defconfig)
# Select a matching userspace, kernel, and workload-launch protocol.
BUILDROOT_DEFCONFIG := $(if $(filter boom-mem2g boom-fpga-mem2g,$(DEFAULT_DTB)),boom_defconfig,$(if $(filter nutshell nutshell-%,$(DEFAULT_DTB)),nutshell_defconfig,xiangshan_defconfig))
BUILDROOT_CONFIG_STAMP := build/buildroot-config/$(BUILDROOT_DEFCONFIG)
$(BUILDROOT_DIR)/Makefile:
mkdir -p build
Expand All @@ -68,12 +68,13 @@ $(BUILDROOT_CONFIG_STAMP): br2-external/configs/$(BUILDROOT_DEFCONFIG) $(BUILDRO
TOOLCHAIN_WRAPPER := $(BUILDROOT_DIR)/output/host/bin/toolchain-wrapper
$(TOOLCHAIN_WRAPPER): $(BUILDROOT_CONFIG_STAMP)
$(MAKE) -C $(BUILDROOT_DIR) BR2_EXTERNAL=$(abspath br2-external) $(BUILDROOT_DEFCONFIG)
$(MAKE) -C $(BUILDROOT_DIR) BR2_EXTERNAL=$(abspath br2-external) nemu-exec-dirclean
$(MAKE) -C $(BUILDROOT_DIR) BR2_EXTERNAL=$(abspath br2-external) prepare-sdk
touch $(TOOLCHAIN_WRAPPER)

# Build Linux kernel
LINUX_IMAGE := $(BUILDROOT_DIR)/output/images/Image
$(LINUX_IMAGE): $(TOOLCHAIN_WRAPPER) $(BUILDROOT_CONFIG_STAMP) br2-external/board/openxiangshan/nemu/linux.config $(if $(filter nutshell_defconfig,$(BUILDROOT_DEFCONFIG)),br2-external/board/openxiangshan/nemu/linux-nutshell.fragment)
$(LINUX_IMAGE): $(TOOLCHAIN_WRAPPER) $(BUILDROOT_CONFIG_STAMP) br2-external/board/openxiangshan/nemu/linux.config $(if $(filter nutshell_defconfig,$(BUILDROOT_DEFCONFIG)),br2-external/board/openxiangshan/nemu/linux-nutshell.fragment) $(if $(filter boom_defconfig,$(BUILDROOT_DEFCONFIG)),br2-external/board/openxiangshan/nemu/linux-boom.fragment)
$(MAKE) -C $(BUILDROOT_DIR) BR2_EXTERNAL=$(abspath br2-external) $(BUILDROOT_DEFCONFIG)
$(MAKE) -C $(BUILDROOT_DIR) BR2_EXTERNAL=$(abspath br2-external)

Expand Down
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,30 @@ See the
[SPEC2006 configuration](workloads/linux/spec2006/README.md#configuration)
section for `riscv_gcc16_rv64imac_lp64.cfg`.

## BOOM FPGA profile

Use `DEFAULT_DTB=boom-mem2g` for the single-hart 2 GiB BOOM board:

```sh
make linux/coremark DEFAULT_DTB=boom-mem2g
make linux/spec2006 BENCH=mcf INPUT=ref DEFAULT_DTB=boom-mem2g \
SPEC2006_CFG=workloads/linux/spec2006/configs/gcc16-linux-riscv64-rv64gc_zba_zbb_zbs.cfg \
SPEC2006_ISO=/path/to/cpu2006.iso
```

This selects `boom_defconfig`: RV64GC userspace, a kernel without V/H,
no startup profiling traps, and the existing BOOM DTS with
`rv64gc_zba_zbb_zbs`. SPEC2006 also selects the shown cfg by default for this
DTS. Set the SPEC compiler and jemalloc inputs as described in its README.
GCPT, OpenSBI, the kernel and initramfs use the existing firmware flow and
DTS-derived addresses; no private boot stub or PMP/time workaround is applied.
This is a build profile, not evidence of a completed Linux or board run.

`BR2_PACKAGE_NEMU_EXEC_PROFILE` defaults to enabled for existing profiles.
BOOM disables only the two startup traps; the final raw `waitpid` status is
preserved (`exit 1` reports `0x100`). Run `python3 scripts/test-nemu-exec.py`
for a native launcher regression that replaces only the hardware trap.

## Build Requirements

Any modern Linux distributions should be okay. The build system of this project is using the toolchain provided by buildroot, so you do not have to set up the toolchains manually to build most workloads. Some workloads require additional toolchians not provided by buildroot. Please refer to the README file of each workload (`README.md` in the workload directory) for details.
Expand Down
4 changes: 4 additions & 0 deletions br2-external/board/openxiangshan/nemu/linux-boom.fragment
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# BOOM implements RV64GC with Zba/Zbb/Zbs, without V or H.
# CONFIG_RISCV_ISA_V is not set
# CONFIG_VIRTUALIZATION is not set
# CONFIG_KVM is not set
16 changes: 16 additions & 0 deletions br2-external/configs/boom_defconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# BOOM RV64GC, 2 GiB, single hart. Bootlin rv64gc toolchain.
BR2_riscv=y
BR2_RISCV_ISA_RVC=y
BR2_TOOLCHAIN_EXTERNAL=y
BR2_TARGET_GENERIC_HOSTNAME="boom"
BR2_TARGET_GENERIC_ISSUE="BOOM FPGA Test Image"
BR2_TARGET_GENERIC_ROOT_PASSWD="xiangshan"
BR2_LINUX_KERNEL=y
BR2_LINUX_KERNEL_USE_CUSTOM_CONFIG=y
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="${BR2_EXTERNAL}/board/openxiangshan/nemu/linux.config"
BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES="${BR2_EXTERNAL}/board/openxiangshan/nemu/linux-boom.fragment"
BR2_TARGET_ROOTFS_INITRAMFS=y
BR2_PACKAGE_BUSYBOX_CONFIG_FRAGMENT_FILES="${BR2_EXTERNAL}/board/openxiangshan/nemu/busybox-taskset.fragment"
BR2_PACKAGE_NEMU_TRAP=y
BR2_PACKAGE_NEMU_EXEC=y
# BR2_PACKAGE_NEMU_EXEC_PROFILE is not set
9 changes: 9 additions & 0 deletions br2-external/package/nemu-exec/Config.in
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,12 @@ config BR2_PACKAGE_NEMU_EXEC
NEMU workload shim.

https://github.com/scratch-er/nemu-workloads

config BR2_PACKAGE_NEMU_EXEC_PROFILE
bool "emit startup profiling markers"
depends on BR2_PACKAGE_NEMU_EXEC
default y
help
Emit trap codes 0x100 and 0x101 before starting the workload.
Disable on BOOM, where every trap terminates the simulation.
The final waitpid status is always reported, including 0x100.
14 changes: 8 additions & 6 deletions br2-external/package/nemu-exec/main.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#include <unistd.h>
#include <sys/wait.h>

#ifndef NEMU_EXEC_PROFILE
#define NEMU_EXEC_PROFILE 1
#endif

#define DISABLE_TIME_INTR 0x100
#define NOTIFY_PROFILER 0x101
#define GOOD_TRAP 0
Expand All @@ -21,8 +25,10 @@ int main(int argc, char *argv[]) {
trap(BAD_TRAP);
} else if (pid == 0) {
// child process, enable profiling and run workload
trap(DISABLE_TIME_INTR);
trap(NOTIFY_PROFILER);
if (NEMU_EXEC_PROFILE) {
trap(DISABLE_TIME_INTR);
trap(NOTIFY_PROFILER);
}
execvp(argv[1], argv+1);
// should not reach here
trap(BAD_TRAP);
Expand All @@ -40,7 +46,3 @@ int main(int argc, char *argv[]) {
// should not reach here
return 0;
}

void trap(int code) {
asm volatile("mv a0, %0; .word 0x0005006b" : :"r"(code));
}
2 changes: 1 addition & 1 deletion br2-external/package/nemu-exec/nemu-exec.mk
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ NEMU_EXEC_SITE_METHOD = local
NEMU_EXEC_INSTALL_STAGING = NO

define NEMU_EXEC_BUILD_CMDS
$(TARGET_CC) $(TARGET_CFLAGS) $(@D)/main.c -o $(@D)/nemu-exec
$(TARGET_CC) $(TARGET_CFLAGS) -DNEMU_EXEC_PROFILE=$(if $(BR2_PACKAGE_NEMU_EXEC_PROFILE),1,0) $(@D)/main.c $(@D)/trap.c -o $(@D)/nemu-exec
endef

define NEMU_EXEC_INSTALL_TARGET_CMDS
Expand Down
3 changes: 3 additions & 0 deletions br2-external/package/nemu-exec/trap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
void trap(int code) {
asm volatile("mv a0, %0; .word 0x0005006b" : : "r"(code) : "a0", "memory");
}
57 changes: 55 additions & 2 deletions dts/generate-nemu-board-dts.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ def parse_name(name):
"spike-2core": (2, 2 << 30),
"yanqihu": (1, 128 << 20),
"yanqihu-2core": (2, 128 << 20),
"boom-mem2g": (1, 2 << 30),
"boom-fpga-mem2g": (1, 2 << 30),
"xiangshan-fpga-AIA-mem16g": (1, 16 << 30),
}
if name in fixed:
Expand Down Expand Up @@ -99,15 +101,26 @@ def cache_properties(nemu=False, timebase=False):
return "\n".join(result)


def serial16550():
return """uart0: serial@310b0000 {
def serial16550(label="uart0"):
return f"""{label}: serial@310b0000 {{
compatible = "ns16550a";
reg = <0x0 0x310b0000 0x0 0x10000>;
reg-shift = <2>;
reg-io-width = <4>;
clock-frequency = <50000000>;
current-speed = <115200>;
status = "okay";
}};"""


def serial_boom():
return """serial0: ns16550@10000000 {
compatible = "ns16550a";
clock-frequency = <10000000>;
reg = <0x0 0x10000000 0x0 0x100>;
reg-shift = <0>;
reg-io-width = <1>;
status = "okay";
};"""


Expand Down Expand Up @@ -377,6 +390,46 @@ def render(name, isa_config_name=None):
reserved_memories=[], plic_machine_first=False,
chosen_properties=chosen_properties("nemu"),
bootargs="console=hvc0 earlycon=sbi")
elif name == "boom-mem2g":
gen = DTSGen(
compatible="freechips,rocketchip-unknown",
model="freechips,rocketchip-unknown",
cpu_compatibles=["riscv"],
isa_extensions=DTSGen.sort_isa_extensions(
"i m a f d c zicsr zifencei zba zbb zbs".split()),
legacy_isa="rv64imafdc_zba_zbb_zbs",
mmu_type="riscv,sv39",
timebase_freq=1000000,
nr_harts=1,
clint_addr=0x02000000,
plic_addr=0x0c000000,
plic_ndev=31,
memories=[(DRAM_BASE, 2 << 30)],
reserved_memories=[],
uartlite_addr=None,
chosen_properties=chosen_properties("spike"),
bootargs="console=ttyS0,115200 earlycon=uart8250,mmio,0x10000000")
gen.add_device(serial_boom())
elif name == "boom-fpga-mem2g":
gen = DTSGen(
compatible="freechips,rocketchip-unknown",
model="freechips,rocketchip-unknown",
cpu_compatibles=["riscv"],
isa_extensions=DTSGen.sort_isa_extensions(
"i m a f d c zicsr zifencei zba zbb zbs".split()),
legacy_isa="rv64imafdc_zba_zbb_zbs",
mmu_type="riscv,sv39",
timebase_freq=1000000,
nr_harts=1,
clint_addr=0x02000000,
plic_addr=0x0c000000,
plic_ndev=31,
memories=[(DRAM_BASE, 2 << 30)],
reserved_memories=[],
uartlite_addr=None,
chosen_properties=chosen_properties("spike"),
bootargs="console=ttyS0,115200 earlycon=uart8250,mmio32,0x310b0000")
gen.add_device(serial16550("serial0"))
elif name.startswith("spike"):
nr_harts = 2 if name == "spike-2core" else 1
gen = DTSGen(compatible="ucbbar,spike-bare-dev", model="ucbbar,spike-bare",
Expand Down
48 changes: 48 additions & 0 deletions scripts/test-nemu-exec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env python3
"""Run the real fork/exec/wait launcher, replacing only the RISC-V trap."""
import os
from pathlib import Path
import subprocess
import tempfile

ROOT = Path(__file__).resolve().parents[1]
TRAP = r'''#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static pid_t parent;
__attribute__((constructor)) static void init(void) { parent = getpid(); }
void trap(int code) {
FILE *log = fopen(getenv("TRAP_LOG"), "a");
if (!log) _exit(99);
fprintf(log, "trap:%d\n", code);
fclose(log);
if (getpid() == parent) _exit(0);
if (code == -1) _exit(1);
}
'''

with tempfile.TemporaryDirectory() as tmp:
tmp = Path(tmp)
(tmp / "trap.c").write_text(TRAP)
for profile in (0, 1):
exe = tmp / f"nemu-exec-{profile}"
subprocess.run([os.environ.get("CC", "cc"), "-Wall", "-Wextra", "-Werror",
f"-DNEMU_EXEC_PROFILE={profile}",
str(ROOT / "br2-external/package/nemu-exec/main.c"),
str(tmp / "trap.c"), "-o", str(exe)], check=True)
for status in (0, 1):
log = tmp / "events"
log.write_text("")
env = dict(os.environ, TRAP_LOG=str(log))
subprocess.run([str(exe), "/bin/sh", "-c",
f'printf "workload\\n" >> "$TRAP_LOG"; exit {status}'],
env=env, check=True, timeout=5)
expected = (["trap:256", "trap:257"] if profile else [])
expected += ["workload", f"trap:{status << 8}"]
assert log.read_text().splitlines() == expected, log.read_text()
for command in ([], ["/this-command-does-not-exist"]):
log.write_text("")
subprocess.run([str(exe), *command], env=env, check=True, timeout=5)
events = log.read_text().splitlines()
assert "trap:-1" in events, events
print("PASS: profiling enabled/disabled, actual exec, exit 0/1, missing command")
Loading
Loading