[RISCV-DV] Change push_gpr_to_kernel_stack to prevent off-by-one store

If the DUT comes out of reset and immediately jumps into debug mode, the first
routine executed is to push the gpr's to the kernel stack. The register used as
the effective stack-pointer is initialized to zero, and the routine reserves the
address space (XLEN/4) * 31 to push the GPR's (excluding x0).

This routine however assumes that the original value in the sp register is valid
to be stored to. This is often not the case out of reset, when it is 0x00000000.
Therefore an address range from 0xffffff80 up to and including
0x00000000 (wrapping) is stored to.

This patch reserves 32 words instead, preventing the final gpr from writing to
an invalid addr in this case.

Signed-off-by: Harry Callahan <hcallahan@lowrisc.org>

[RISCV-DV] Functional changes to fix nested_interrupt_test
This commit is contained in:
Harry Callahan 2022-06-30 14:14:12 +01:00
parent bbda68a0df
commit 8762e0f221
2 changed files with 16 additions and 11 deletions

View file

@ -901,6 +901,7 @@ class core_ibex_nested_irq_test extends core_ibex_directed_test;
bit valid_irq;
bit valid_nested_irq;
int unsigned initial_irq_delay;
vseq.irq_raise_seq_h.max_delay = 5000;
forever begin
send_irq_stimulus_start(1'b1, 1'b0, valid_irq);
if (valid_irq) begin

View file

@ -1379,10 +1379,10 @@ package riscv_instr_pkg;
ref string instr[$]);
string store_instr = (XLEN == 32) ? "sw" : "sd";
if (scratch inside {implemented_csr}) begin
// Use kernal stack for handling exceptions
// Save the user mode stack pointer to the scratch register
instr.push_back($sformatf("csrrw x%0d, 0x%0x, x%0d", sp, scratch, sp));
// Move TP to SP
// Push USP from gpr.SP onto the kernel-mode stack
instr.push_back($sformatf("addi x%0d, x%0d, -4", tp, tp));
instr.push_back($sformatf("%0s x%0d, (x%0d)", store_instr, sp, tp));
// Move KSP to gpr.SP
instr.push_back($sformatf("add x%0d, x%0d, zero", sp, tp));
end
// If MPRV is set and MPP is S/U mode, it means the address translation and memory protection
@ -1404,11 +1404,13 @@ package riscv_instr_pkg;
end
end
// Reserve space from kernel stack to save all 32 GPR except for x0
instr.push_back($sformatf("1: addi x%0d, x%0d, -%0d", sp, sp, 31 * (XLEN/8)));
instr.push_back($sformatf("1: addi x%0d, x%0d, -%0d", sp, sp, 32 * (XLEN/8)));
// Push all GPRs to kernel stack
for(int i = 1; i < 32; i++) begin
instr.push_back($sformatf("%0s x%0d, %0d(x%0d)", store_instr, i, i * (XLEN/8), sp));
end
// Move KSP back to gpr.tp (this is needed if we again take an interrupt before restoring our USP)
instr.push_back($sformatf("add x%0d, x%0d, zero", tp, sp));
endfunction
// Pop general purpose register from stack, this is needed before returning to user program
@ -1419,17 +1421,19 @@ package riscv_instr_pkg;
riscv_reg_t tp,
ref string instr[$]);
string load_instr = (XLEN == 32) ? "lw" : "ld";
// Pop user mode GPRs from kernel stack
// Move KSP to gpr.SP
instr.push_back($sformatf("add x%0d, x%0d, zero", sp, tp));
// Pop GPRs from kernel stack
for(int i = 1; i < 32; i++) begin
instr.push_back($sformatf("%0s x%0d, %0d(x%0d)", load_instr, i, i * (XLEN/8), sp));
end
// Restore kernel stack pointer
instr.push_back($sformatf("addi x%0d, x%0d, %0d", sp, sp, 31 * (XLEN/8)));
instr.push_back($sformatf("addi x%0d, x%0d, %0d", sp, sp, 32 * (XLEN/8)));
if (scratch inside {implemented_csr}) begin
// Move SP to TP
// Move KSP back to gpr.TP
instr.push_back($sformatf("add x%0d, x%0d, zero", tp, sp));
// Restore user mode stack pointer
instr.push_back($sformatf("csrrw x%0d, 0x%0x, x%0d", sp, scratch, sp));
// Pop USP from the kernel stack, move back to gpr.sp
instr.push_back($sformatf("%0s x%0d, (x%0d)", load_instr, sp, tp));
instr.push_back($sformatf("addi x%0d, x%0d, 4", tp, tp));
end
endfunction