RISCV: Illegal instruction delegated to VS mode sets the wrong vscause value
Host environment
- Operating system: OpenSuse
- OS/kernel version: 5.14.21
- Architecture: x86
- QEMU flavor: qemu-system-riscv64
- QEMU version: QEMU emulator version 8.0.50 (v8.0.0-244-g1eb95e1b-dirty)
- QEMU command line:
qemu-system-riscv64 -m 32M -nographic -bios none -machine virt,aclint=off,aia=aplic-imsic,aia-guests=3 -smp 1 -d int -cpu rv64,sstc=true,c=false,x-epmp=true,x-smstateen=true,x-smaia=true,x-ssaia=true -kernel hypervisor_tests.elf
Emulated/Virtualized environment
- Operating system: None
- OS/kernel version: None
- Architecture: RISC-V
Description of problem
When delegating an illegal instruction exception caused in VS-mode to VS-mode, the vscause value for an illegal instruction is set incorrectly.
Steps to reproduce:
- Delegate 2(,6,10) in medeleg and hedeleg.
- Enter VS-mode
- Cause an illegal instruction fault, cause 6 can't happen in QEMU since there is misaligned support and 10 can't be delegated to VS mode.
- The (v)scause CSR is then set to 1, i.e. instruction access fault which isn't correct.
I have located the issue in the code @ cpu_helper.c:1703
if ((cause == IRQ_VS_TIMER || cause == IRQ_VS_SOFT ||
cause == IRQ_VS_EXT)) {
cause = cause - 1;
}
The if statement should include a check for the async otherwise the cause shouldn't be altered. The patch I propose is simply to and the current statement with async.
if (async & (cause == IRQ_VS_TIMER || cause == IRQ_VS_SOFT ||
cause == IRQ_VS_EXT)) {
cause = cause - 1;
}
Additional information
Log where the incorrect cause is set. Note this line: DEBUG: [src/trap_handling.c: 105] Instruction access fault exception: SEPC = 0x80008850, STVAL = 0x0
TRACE: [src/hart_ctrl.c:35] STARTING CPU 0
TRACE: [src/page_tables.c:343] Setting up page tables between 0x80000000 -> 0x81c00000
TRACE: [src/page_tables.c:359] Setting up page tables between 0x81c01000 -> 0x81c02000
TRACE: [src/page_tables.c:374] Setting up page tables for UART 0x10000000
TRACE: [src/page_tables.c:386] Setting up page tables for CLINT 0x2000000
DEBUG: [src/page_tables.c: 406] Mapping IMISIC 0x24000000
DEBUG: [src/page_tables.c: 406] Mapping IMISIC 0x28000000
DEBUG: [src/page_tables.c: 406] Mapping IMISIC 0x28001000
TRACE: [src/main.c:32] STARTING HYPERVISOR TESTS
DEBUG: [src/util_fn.c:1175] pmpcfg0 = 0x00000000000f000f
DEBUG: [src/util_fn.c:1176] pmpcfg2 = 0x0000000000000000
PMP Entry : 0
Low Address : 0x0
High Address : 0x81c00000
Address Range : 0x0 - 0x81c00000
Mode : TOR
Executable : Yes
Writable : Yes
Readable : Yes
Locked : No
--------------------------------------
PMP Entry : 2
Low Address : 0x82000000
High Address : 0xfffffffffffffffc
Address Range : 0x82000000 - 0xfffffffffffffffc
Mode : TOR
Executable : Yes
Writable : Yes
Readable : Yes
Locked : No
--------------------------------------
DEBUG: [src/trap_trigger.c: 85] Switching mode to VS
riscv_cpu_do_interrupt: hart:0, async:0, cause:0000000000000002, epc:0x00000000800062a4, tval:0x0000000000000000, desc=illegal_instruction
DEBUG: [src/trap_handling.c: 102] Illegal instruction exception: MEPC = 0x800062a4, MTVAL = 0x0
TRACE: [src/util_fn.c:374] Done switching mode
riscv_cpu_do_interrupt: hart:0, async:0, cause:0000000000000002, epc:0x0000000080008850, tval:0x0000000000000000, desc=illegal_instruction
DEBUG: [src/trap_handling.c: 105] Instruction access fault exception: SEPC = 0x80008850, STVAL = 0x0
ERROR: [src/trap_handling.c:158] The following assert failed: mask_cause == cause2check
mask_cause = 0x1 ## cause2check = 0x2
DEBUG: [src/trap_trigger.c: 129] Switching mode to M
TRACE: [src/trap_handling.c:30] Program done, exiting
QEMU: Terminated
Result after patch.
TRACE: [src/hart_ctrl.c:35] STARTING CPU 0
TRACE: [src/page_tables.c:343] Setting up page tables between 0x80000000 -> 0x81c00000
TRACE: [src/page_tables.c:359] Setting up page tables between 0x81c01000 -> 0x81c02000
TRACE: [src/page_tables.c:374] Setting up page tables for UART 0x10000000
TRACE: [src/page_tables.c:386] Setting up page tables for CLINT 0x2000000
DEBUG: [src/page_tables.c: 406] Mapping IMISIC 0x24000000
DEBUG: [src/page_tables.c: 406] Mapping IMISIC 0x28000000
DEBUG: [src/page_tables.c: 406] Mapping IMISIC 0x28001000
TRACE: [src/main.c:32] STARTING HYPERVISOR TESTS
DEBUG: [src/util_fn.c:1175] pmpcfg0 = 0x00000000000f000f
DEBUG: [src/util_fn.c:1176] pmpcfg2 = 0x0000000000000000
PMP Entry : 0
Low Address : 0x0
High Address : 0x81c00000
Address Range : 0x0 - 0x81c00000
Mode : TOR
Executable : Yes
Writable : Yes
Readable : Yes
Locked : No
--------------------------------------
PMP Entry : 2
Low Address : 0x82000000
High Address : 0xfffffffffffffffc
Address Range : 0x82000000 - 0xfffffffffffffffc
Mode : TOR
Executable : Yes
Writable : Yes
Readable : Yes
Locked : No
--------------------------------------
DEBUG: [src/trap_trigger.c: 85] Switching mode to VS
riscv_cpu_do_interrupt: hart:0, async:0, cause:0000000000000002, epc:0x00000000800062a4, tval:0x0000000000000000, desc=illegal_instruction
DEBUG: [src/trap_handling.c: 102] Illegal instruction exception: MEPC = 0x800062a4, MTVAL = 0x0
TRACE: [src/util_fn.c:374] Done switching mode
riscv_cpu_do_interrupt: hart:0, async:0, cause:0000000000000002, epc:0x0000000080008850, tval:0x0000000000000000, desc=illegal_instruction
DEBUG: [src/trap_handling.c: 105] Illegal instruction exception: SEPC = 0x80008850, STVAL = 0x0
DEBUG: [src/trap_trigger.c: 129] Switching mode to M
riscv_cpu_do_interrupt: hart:0, async:0, cause:0000000000000002, epc:0x00000000800062a4, tval:0x0000000000000000, desc=illegal_instruction
DEBUG: [src/trap_handling.c: 69] Illegal instruction handling is delegated, falling back to ECALL
riscv_cpu_do_interrupt: hart:0, async:0, cause:000000000000000a, epc:0x00000000800096e4, tval:0x0000000000000000, desc=hypervisor_ecall
DEBUG: [src/trap_handling.c: 102] Environment call from VS-mode exception: MEPC = 0x800096e4, MTVAL = 0x0
DEBUG: [src/trap_handling.c: 105] Illegal instruction exception: SEPC = 0x800062a4, STVAL = 0x0
TRACE: [src/util_fn.c:374] Done switching mode
TRACE: [src/main.c:57] HYPERVISOR TEST FINISHED SUCCESSFULLY
TRACE: [src/trap_handling.c:30] Program done, exiting