With SecureIbex + BranchPredictor, a dummy instruction destroys a predicted-taken conditional branch

Abierto
#2,568 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 2 días

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
57/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo

Línea de trabajo

Start by tracing branch_req, insert_dummy_instr, and stall_dummy_instr in rtl/ibex_if_stage.sv, then inspect the fetch FIFO and IF-ID handoff around the reported line 555. Reproduce with wrongpath_m.elf on the SecureIbex plus BranchPredictor configuration and compare against the no-dummy control. Done means the branch reaches execution and the test records the fall-through marker with all 15 guard increments.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

Type:Bug

Observed Behavior

On an Ibex elaboration with SecureIbex=1 (dummy instruction insertion enabled) and BranchPredictor=1, a conditional branch at the fetch-FIFO head is dropped when insert_dummy_instr asserts. In the matched test below, the branch is a backward blt x20,x21 with x20 == x21 == 0, so its condition is false and it must fall through; the predictor nevertheless marks the negative-offset branch as taken.

Compare the clean build against the same test with dummy insertion forced off (mut_nodummy), both from the same run:

build retired guard increments (addi x11,x11,1) last marker stored
secbp (SecureIbex + BP) 33 2 0x00000bad at 0x00100190
mut_nodummy (dummies disarmed) 57 15 0x00005eed at 0x001002dc

ibex_simple_system_pcount.csv (divergence marked):

secbp: Cycles,73 Instructions Retired,33
mut_nodummy: Cycles,89 Instructions Retired,57 <--

The clean build's tracer log shows only the first two guard increments, then control lands at 0x00100180 (the predicted-taken target) and stores the wrong-path marker 0xBAD:

 86 39 00100250 f35a48e3 blt x20,x21,100180 x20:0x00000000 x21:0x00000000
 92 42 00100254 00158593 addi x11,x11,1 x11:0x00000000 x11=0x00000001
 94 43 00100258 f35a44e3 blt x20,x21,100180 x20:0x00000000 x21:0x00000000
 98 45 0010025c 00158593 addi x11,x11,1 x11:0x00000001 x11=0x00000002
 120 56 0010018c bad60613 addi x12,x12,-1107 x12:0x00001000 x12=0x00000bad
 124 58 00100190 00c4aa23 sw x12,20(x9) <-- wrong-path marker 0xBAD

0xf35a48e3 is blt x20, x21, -208. Bits [24:20] are rs2=x21 (21), bits [19:15] are rs1=x20, and bits [11:7] are immediate bits, not a register. 0x100250 + (-208) = 0x100180, which is the target printed on that line. wrongpath_m.S encodes the same word (.word 0xf35a48e3) after li x20, 0 / li x21, 0. The register names in the tracer line match the encoding.

The no-dummy control reaches all 15 increments and stores the fall-through marker 0x5EED:

 160 76 001002c4 00158593 addi x11,x11,1 x11:0x0000000e x11=0x0000000f
 176 84 001002dc 0064a623 sw x6,12(x9) <-- 0x5EED

No exception or ecall occurs in the test window.

Expected Behavior

Per the RISC-V Unprivileged Specification, "Conditional Branches" (rv32.adoc, section 2.5):

Branch instructions compare two registers. ... BLT and BLTU take the branch if rs1 is less than rs2, using signed and unsigned comparison respectively.

With x20 == x21 the blt must fall through and must not change the PC. Ibex's own doc/03_reference/security.rst ("Dummy Instruction Insertion") states:

The dummy instructions have no functional impact on processor state, but add some difficult-to-predict timing and power disruption to executed code.

So inserting a dummy should not remove an architectural branch. The secbp build is expected to run the same 15 guard increments as the no-dummy control.

Steps to reproduce the issue

Configuration (prebuilt elaborations):

  • secbp: SecureIbex=1, BranchPredictor=1, ICache=0, RV32E=0, WritebackStage=0.
  • mut_nodummy: the same elaboration, with assign insert_dummy_instr = 1'b0; added before assign stall_dummy_instr = insert_dummy_instr; (rtl/ibex_if_stage.sv:555). rtl/ibex_top.sv:214 sets localparam bit DummyInstructions = SecureIbex.
  • Test: wrongpath_m.elf, built by gen_wrongpath.py from wrongpath_m.S.
# Vibex_simple_system.secbp: SecureIbex=1, BranchPredictor=1
# Vibex_simple_system.mut_nodummy: same elaboration, insert_dummy_instr forced to 0
ELF=wrongpath_m.elf
for b in secbp mut_nodummy; do
 mkdir -p runs/$b
 ( cd runs/$b && timeout 120 "./Vibex_simple_system.$b" \
 --meminit=ram,"$ELF" -c 20000 > sim.out 2>&1 )
 grep -aE 'Instructions Retired|Cycles' \
 runs/$b/ibex_simple_system_pcount.csv
 grep -ac 'addi.*x11,x11,1' runs/$b/trace_core_00000000.log
done
secbp: Cycles,73 Instructions Retired,33 guard_count=2
mut_nodummy: Cycles,89 Instructions Retired,57 guard_count=15

Attached: wrongpath_m.S, wrongpath_m.elf, logs/secbp/trace_core_00000000.log, logs/secbp/ibex_simple_system_pcount.csv (Cycles,73 / Instructions Retired,33), logs/mut_nodummy/trace_core_00000000.log, logs/mut_nodummy/ibex_simple_system_pcount.csv (Cycles,89 / Instructions Retired,57), gen_wrongpath.py (emits wrongpath_m.S).

My Environment

EDA tool and version: Verilator (prebuilt Vibex_simple_system.secbp and Vibex_simple_system.mut_nodummy elaborations).

Operating system: Linux 6.8.0-90-generic x86_64.

Version of the Ibex source code: official-tree commit d513671dae09e701ceb6cd732d2da5fb52c13856. The secbp elaboration is stock at that commit. The mut_nodummy control adds assign insert_dummy_instr = 1'b0; before rtl/ibex_if_stage.sv:555.

I suspect branch_req (pc_set_i | predict_branch_taken) clears the fetch FIFO without a stall_dummy_instr gate, so the dummy replaces the branch in IF-ID and the branch never reaches ID, but I have not traced it. This test runs in M-mode.

#1479 describes a predicted branch or jal that never reaches ID while insert_dummy_instr is high. The reply on that issue is about instr_valid_id_d staying low so the inserter can take a PC. Here x20 == x21 == 0, the DUT stores 0xBAD, and the no-dummy control stores 0x5EED.

testcase.zip

Lenguaje dominante
SystemVerilog
Estrellas
2.2k
Forks
836
Merge medio
5 d 8 h
PR fusionados (30 d)
22

Preparar el entorno

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de lowRISC/ibex

Todos los issues de lowRISC/ibex

Issues similares

Más issues de Backend & API Design

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.