Instruction access fault reports mtval = pc+2 when the first half of an unaligned instruction fails its bus access and the second half fails PMP

Ouverte
#2,575 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 2 jours

Personne n'a encore pris cette issue.

Évaluation

Difficulté
4/5
Temps estimé
1-2 jours
Accessibilité débutants
55/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
Active

Piste de recherche

Start with the if_instr_err_plus2 assignment in rtl/ibex_if_stage.sv (lines 435–436) and trace how first-half bus and PMP errors affect the reported fault address. Reproduce with the attached bench and compare the f1_errplus2 and control runs. Done when the PMP case reports mtval = pc while the second-half-only fault behavior remains correct.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

Type:Bug

Observed Behavior

A 32-bit instruction at a halfword address pc (pc[1] = 1) spans two fetch words. If the fetch of the first word gets a bus error (instr_err_i) and the second half (pc + 2) is in a PMP region without execute permission, Ibex takes an instruction access fault with mepc = pc but mtval = pc + 2, as if the first half had been fetched without fault.

run mcause mepc mtval
f1_errplus2 (first half: bus error; second half: bus error + PMP no-X) 1 0xd6cbfffe 0xd6cc0000
f1_errplus2_ctl (same, no PMP region; both halves: bus error only) 1 0xd6cbfffe 0xd6cbfffe

if_instr_err_plus2 is set by a PMP error on the second half and cleared only by a PMP error on the first half (& ~pmp_err_if_i), not by a bus error on the first half: rtl/ibex_if_stage.sv:435-436. When the second half has only a bus error, the prefetch buffer reports it only if the first half had no error, so that case is correct (control run above). mcause and mepc are correct in both runs; only mtval is wrong.

Attached: simulation logs of both runs (evidence/*.log) and a formal counterexample on the same RTL (evidence/formal_ibex_top_u_bp_u_spec_BP5_CAUSE.vcd, 14 cycles from a NOP start state).

Expected Behavior

mtval = pc = 0xd6cbfffe, as in the control run and as Ibex already reports when the first half fails PMP. RISC-V Privileged Specification, "Machine Trap Value Register (mtval)":

If mtval is written with a nonzero value when an instruction access-fault or page-fault exception occurs on a system with variable-length instructions, then mtval will contain the virtual address of the portion of the instruction that caused the fault, while mepc will point to the beginning of the instruction.

The pc + 2 reporting was added for the case where only the second half faults (#709, #713). A possible fix is to clear if_instr_err_plus2 on any first-half fault, not only a PMP one:

  assign if_instr_err_plus2 = ((if_instr_addr[1] & ~instr_is_compressed & pmp_err_if_plus2_i) |
                               fetch_err_plus2) & ~(pmp_err_if_i | fetch_err);

Steps to reproduce the issue

The attached bench tb_ibex_bp.sv instantiates ibex_top with PMPEnable = 1, PMPNumRegions = 4, PMPGranularity = 0, plus the experimental-branch-predictor settings of ibex_configs.yaml (RV32M = RV32MSingleCycle, RV32ZC = RV32ZcaZcbZcmp, BranchTargetALU = 1, WritebackStage = 1, BranchPredictor = 1). Only PMPEnable = 1 and an instruction-bus error are needed; the branch predictor plays no part. The bench answers every fetch from 0xD0000000-0xDFFFFFFF with an error and returns 0xffffffff as data (OBI leaves error-response data undefined).

  • f1_errplus2.S locks PMP region 2 as NAPOT 4 KiB at 0xd6cc0000 with R/W and no X, then jumps to 0xd6cbfffe.
  • f1_errplus2_ctl.S is the same without the PMP region.
  1. git clone https://github.com/lowRISC/ibex && cd ibex && git checkout 626034d7
  2. Run the attached script, which builds the bench with Verilator (defines +define+AB_PMP +define+SYNTHESIS), assembles both programs and runs them:
    sh run.sh <ibex checkout>
    # per program: riscv32-unknown-elf-gcc -march=rv32imc_zicsr_zifencei_zca_zcb_zcmp -mabi=ilp32 -nostdlib -nostartfiles -T link.ld crt.S f1_errplus2.S
    #              simv +hex=f1_errplus2.hex +ierrdata=ffffffff
    
  3. Each run prints three SIG lines: mcause, mepc, mtval. Output:
    == f1_errplus2
    SIG 00000001
    SIG d6cbfffe
    SIG d6cc0000
    == f1_errplus2_ctl
    SIG 00000001
    SIG d6cbfffe
    SIG d6cbfffe
    

No changes to the Ibex source code.

My Environment

EDA tool and version:
Verilator 5.044 (simulation); riscv32-unknown-elf-gcc 16.1.0.
Operating system:
Red Hat Enterprise Linux 8.10

Version of the Ibex source code:
626034d7557ab85a6d989b13011b44296bad26fa (master, 2026-11-06), unmodified.

All of the relevant materials pertaining to the bug:

F1_FETCH_MTVAL_PLUS2.zip

Langage dominant
SystemVerilog
Étoiles
2.2k
Forks
836
Merge moyen
5 j 8 h
PR mergées (30 j)
22

Préparer son environnement

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de lowRISC/ibex

Toutes les issues de lowRISC/ibex

Issues similaires

Plus d'issues Backend & API Design

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.