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

Đang mở
#2,568 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 2 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
57/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Lĩnh vực
backend-api-design

Hướng nghiên cứu

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.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

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

Ngôn ngữ chính
SystemVerilog
Star
2.2k
Fork
836
Merge trung bình
5 ngày 8 giờ
Pull request đã merge (30 ngày)
22

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của lowRISC/ibex

Tất cả issue của lowRISC/ibex

Issue tương tự

Thêm issue về Backend & API Design

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.