Skip to content

Add RISC-V baremetal fault injection: variable tracing, section/stack targeting, FP registers - #2

Open
HeavenlyDevv wants to merge 1 commit into
ManyCoreResearchTeam:extensionsfrom
HeavenlyDevv:feature/riscv-baremetal-fault-injection
Open

Add RISC-V baremetal fault injection: variable tracing, section/stack targeting, FP registers#2
HeavenlyDevv wants to merge 1 commit into
ManyCoreResearchTeam:extensionsfrom
HeavenlyDevv:feature/riscv-baremetal-fault-injection

Conversation

@HeavenlyDevv

Copy link
Copy Markdown

RISC-V baremetal fault injection: variable tracing, section/stack targeting, FP registers

New feature: fault-injection support for RISC-V baremetal, extending the RISC-V base that already existed (RISCV*.makefile.include). Each piece comes with a reproducible before/after in the real environment (OVP, RISCV64GC baremetal workload).

Summary

# Contribution File(s) What it enables
1 RISC-V NOP encodings in the serviceHandler guard platformOP/intercept/intercept.c Variable tracing works on RISC-V (the guard previously only recognized ARM NOPs → no traces were produced)
2 RISC-V FP registers in the whitelist gui/classification.py + commonStructsAndEnumerators.h Fault-injection campaigns on floating-point registers (ft/fs/fa)
3 Section-based + .stack memory targeting FI.sh + intercept.c + faultInjector.c Inject into .data/.bss/.rodata/.stack instead of a fixed range
4 "Var Inconsistency" column in the report file faultInjector.c SDC classification by comparing the traced variable
5 --minfaulttime gui/options.py + gui/faultlist.py Skip the initialization phase (no faults during boot)
6 RISC-V FPU enable FI.sh --override mstatus_FS=1 enables the FPU on RISCV*GC/F/D variants (needed for FP-register campaigns)

1 — RISC-V NOP encodings

Problem. serviceHandler only acts if the intercepted instruction is a known NOP; the whitelist only had ARM encodings. On RISC-V the guard never matched → the handler returned early → no trace files were produced (trace_gold_variable / trace_fault_variable).

+#define NOP_ARMV7A  0xe320f000  // ARMv7-A
+#define NOP_ARMV7M  0x4770bf00  // ARMv7-M (Cortex-M)
+#define NOP_ARMV6M  0x477046c0  // ARMv6-M (Cortex-M)
+#define NOP_AARCH64 0xd503201f  // AArch64
+#define NOP_RISCV   0x00000013  // RISC-V: addi x0,x0,0 (canonical NOP)
+#define NOP_RISCV_C 0x85020001  // RISC-V: compressed c.nop marker
...
-    if(checker!=0xe320f000 && checker!=0X4770bf00 && checker!=0X477046c0 && checker!=0Xd503201f)
+    if(checker!=NOP_ARMV7A && checker!=NOP_ARMV7M && checker!=NOP_ARMV6M &&
+       checker!=NOP_AARCH64 && checker!=NOP_RISCV && checker!=NOP_RISCV_C)
        return;

Before / after (RISCV64GC campaign, 30 faults, TRACE_VARIABLE=result):

trace_gold_variable trace_fault_variable
BEFORE (ARM-only guard) 0 0
AFTER (RISC-V encodings) 2 60

2 — RISC-V FP registers

Problem. The RISC-V register whitelist (in gui/classification.py, which feeds the fault-list generator faultList2.py → gui/faultlist.py) only had the integer registers. Targeting an FP register failed during generation.

 self.listOfpossibleRegisters = [
     "ra","sp","gp","tp", "t0",...,"t6", "pc",
+    # floating-point ABI
+    "ft0",...,"ft7", "fs0","fs1", "fa0",...,"fa7", "fs2",...,"fs11", "ft8",...,"ft11",
 ]

(The C header possibleRegistersRV gets the same extension, so the FP regs can be read when comparing at runtime.)

Before / after (register campaign with REG_LIST=fa5,fs0,fa0):

Fault-list generation
BEFORE (no FP in the whitelist) ValueError: 'fa5' is not in listfault list not generated
AFTER (FP present) fault list with 20 FP entries, campaign runs

3 — Section-based + .stack memory targeting

Problem. Memory injection used a fixed range (TARGET_MEM_BASE/SIZE). This adds extraction of the real range per ELF section (readelf), plus a special .stack case whose range is obtained from SP tracking during the golden run.

3-file chain for .stack:

  • intercept.c — an SP watchpoint writes Dumps/stack_range.txt (Stack SP Min/Initial)
  • faultInjector.c — appends that file into goldinformation
  • FI.sh — the .stack path reads those keys to bound the campaign

Before / after (.stack with the SP watchpoint on/off):

goldinformation .stack campaign
BEFORE (no watchpoint) no Stack SP Min/Initial fails: "Error: Stack range not found in goldinformation"
AFTER (watchpoint) Stack SP Initial=…, Stack SP Min=…, Stack Size=3664 injects OK

For .data/.bss/.rodata the range comes from EntryAddress + Size of the section (verified: correct range covering the section).


4 — "Var Inconsistency" column

compareTracedVariable() compares the traced-variable dump (gold vs fault) and adds a 14th column to the report file with the verdict (Yes/No), to classify SDC by observing the output variable.

Format contract: the report file goes from 13 to 14 columns (header and rows updated together). Any fixed-format downstream parser must be updated.


5 — --minfaulttime

Bounds the minimum injection time to skip the initialization phase (implemented in gui/faultlist.py:206-208).

Before / after (gold = 3,128,172 instructions, minfaulttime = 50%):

minimum injection time in the fault list
BEFORE (minfaulttime=0) 105,687 (faults during init)
AFTER (minfaulttime=1,564,086) 1,574,341 (≥ threshold, no faults during init)

6 — RISC-V FPU enable

Adds --override mstatus_FS=1 for RISCV*GC/F/D variants so the floating-point unit is enabled — required for the FP-register campaigns in component 2. ARM variants are unaffected.


Notes for the reviewer

  • ARM paths are unchanged: the NOP guard and the compile flags add RISC-V branches without touching the existing ARM ones.
  • Everything above is validated end-to-end on RISC-V baremetal with the before/after tables shown.

… targeting, FP registers

Extends the existing RISC-V baremetal support so full fault-injection
campaigns can run on RV64GC targets. Six additions, each verified end-to-end:

- intercept.c: add RISC-V NOP encodings (0x00000013 addi x0,x0,0; 0x85020001
  compressed c.nop) to the serviceHandler marker guard, so variable tracing
  produces trace files on RISC-V (the guard previously only matched ARM NOPs).

- classification.py (gui + support/tools) and commonStructsAndEnumerators.h:
  add the 32 RISC-V floating-point registers (ft/fs/fa) to the whitelist so
  register campaigns can target FP registers. The register buffer is sized via
  MAX_REGISTERS with a copy-loop clamp to stay within bounds.

- FI.sh + intercept.c + faultInjector.c: section-based and .stack memory
  targeting. An SP write-watchpoint records the stack range into goldinformation;
  FI.sh extracts per-section ELF ranges (readelf) and reads the stack range for
  a .stack campaign.

- faultInjector.c: add a 'Var Inconsistency' report column (compareTracedVariable)
  that classifies SDC by comparing the traced variable gold vs fault dumps.

- gui/options.py + gui/faultlist.py: --minfaulttime option that raises the fault
  insertion-time floor to skip the initialization phase.

- FI.sh: --override mstatus_FS=1 to enable the FPU on RISCV*GC/F/D variants.

Verified: all sources compile cleanly (-Werror) and pass python syntax checks
against a fresh clone of the extensions branch. ARM code paths are untouched.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant