Summer 2025: RSD and Superscalar CVA6 - Jayden Over the summer, I joined Secure and Trustworthy Hardware (SETH) Lab as an undergraduate researcher working with the hardware fuzzing group on finding functional vulnerabilities in open-source processors. In order to properly detect vulnerabilities, these processors had to be integrated into the existing hardware fuzzing framework "TheHuzz". The first processor integrated was RSD.

RSD

RSD is a standalone processor, not part of the Chipyard SoC hardware development framework like the existing processors (or more accurately generators): CVA6, RocketCore, and BOOM. This requires a separate process for RTL simulation (if using VCS) or verilation (if using Verilator).

Memory Mismatch

Before fuzzing the RSD processor, we noticed that the entry point address of RSD binary was different compared to the Spike Golden Reference Model binary, 0x1000 and 0x8000_0000, respectively, when compiled with the RSD compiler. This means that during the bug detection process, the registers that relied on memory addresses, such as the program counter PC, would not match. Given these circumstances, there were three potential strategies to this issue: change RSD to match Spike, change Spike to match RSD, or ignoring registers like PC. To achieve each of these three strategies, we devised a solution for each of the three strategies: linker script modification, device tree modification, and state divergence masking, respectively.

Stage affected:

Pasted image 20250806165307.png

Linker Script Modification

This strategy involves changing the RSD binary to entry at 0x8000_0000 from the default 0x1000. During the compile process of C code to hex for RSD, a linking script is included at Processor/Src/Verification/TestCode/rsd-ld.script which contains the memory mapping location:

MEMORY {
    ROM(rxai) :     ORIGIN = 0x00001000, LENGTH = 32k
    RAM(wa) :       ORIGIN = 0x80000000, LENGTH = 32k
}

An initial survey of the situation seemed to suggest that it was theoretically possible modify the entry point by modifying the linking script, however, attempts to modify these values were not successful in changing the executable entry point. Regardless of the values changed, the RSD binary would not compile to have an entry point other than 0x1000. This could be because of some internal issue with the compiler limiting the text memory regions which would require further research to confirm.

The respective file in TheHuzz setup is: TheHuzz_USENIX_22/software/rsd/bm/rsd-ld.script.

Device Tree Peripherals

An alternative we noticed from compiling the RSD hex executable is that the compiler also generated a .riscv binary that started at 0x1000 (but could not generate at 0x8000_0000). Since this is the executable format that Spike used, we tried loading this binary for Spike simulation. Unfortunately, the program would throw a trap exception because Spike was expecting an entry point of 0x8000_0000. Luckily, there was a potential workaround with the Device Tree configuration.

Devicetree is a data structure that describes peripherals, specifically Memory-Mapped I/O addresses, to the kernel during boot time. Using this information, we attempted to compile the test instruction binary with a Device Tree Blob to coerce the entry point for Spike to start at 0x1000.

spike_for_rsd.dts

	memory@1000 {
		device_type = "memory";
		reg = <0x1000 0x10000>;
		status = "disabled";
		phandle = <0x3>;
	};

	memory@1000 {
		device_type = "memory";
		reg = <0x1000 0x10000000>;
		phandle = <0x2>;
	};

Binaries could be compiled to the entry point 0x1000, however, the Spike simulation would not run them, possibly because of lower level process operating in that memory region.

There was also another method of coercing the entry point using the -m flag when running the Spike simulation, however, this method was also not successful as trap exceptions would also occur during simulation.

State Divergence Masking