1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
id = 1636
title = "RISCV: Interrupt not cleared correctly (supervisor external IRQ)"
state = "opened"
created_at = "2023-05-04T15:09:09.127Z"
closed_at = "n/a"
labels = ["target: riscv", "workflow::Triaged"]
url = "https://gitlab.com/qemu-project/qemu/-/issues/1636"
host-os = "N/A"
host-arch = "riscv"
qemu-version = "QEMU emulator version 8.0.50 (v8.0.0-244-g1eb95e1bae-dirty)"
guest-os = "n/a"
guest-arch = "n/a"
description = """"""
reproduce = """1. Set mie -> 0
2. Assert all interrupt sources which can be taken in M-mode (i.e. set mei, msi, mti, sei, ssi, sti)
3. I'm using the imsic for the external interrupts and the clint for timer interrupts.
4. Once all IRQs are pending set mie -> 0xFFFF
5. IRQs are taken one by one, all M-level IRQs are cleared without issues.
6. The issue occurs when trying to clear the S-external IRQ, when writing stopei to clear the IRQ mip is not updated correctly.
I believe I have located the issue in target/riscv/cpu.c:1314
**Old code:**
```
riscv_cpu_update_mip(cpu, 1 << irq,
BOOL_TO_MASK(level | env->software_seip));
```
**Changed code:**
```
riscv_cpu_update_mip(cpu, 1 << irq,
BOOL_TO_MASK(level));
```
When we reach the next code snippet (cpu_helper.c:628) we enter cpu_interrupt instead of cpu_reset_interrupt and thus end up in an infinite loop since the imsic message from that point on will be 0. It looks weird to me to use env->software_seip and not env->external_seip, in any case I changed it to BOOL_TO_MASK(level) and I now see the behavior I expect from my test program.
```c
env->mip = (env->mip & ~mask) | (value & mask);
if (env->mip | vsgein | vstip) {
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
} else {
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
}
```"""
additional = """Log when getting the error.
```
TRACE: [src/hart_ctrl.c:35] STARTING CPU 0
DEBUG: [src/trap_handling.c: 938] Setting up trap handlers
TRACE: [src/page_tables.c:341] Setting up page tables between 0x80000000 -> 0x81c00000
TRACE: [src/page_tables.c:355] Setting up page tables for UART 0x10000000
TRACE: [src/page_tables.c:365] Setting up page tables for CLINT 0x2000000
DEBUG: [src/page_tables.c: 383] Mapping IMISIC 0x24000000
DEBUG: [src/page_tables.c: 383] Mapping IMISIC 0x28000000
DEBUG: [src/page_tables.c: 383] Mapping IMISIC 0x28001000
DEBUG: [src/util_fn.c: 339] Setting satp: 0x8000100000081017
DEBUG: [src/util_fn.c: 342] Setting hgatp: 0x8000000000081014
TRACE: [src/main.c:40] Asserting M-level interrupts simultaneously
DEBUG: [src/irq_trigger.c: 121] Setting inteded cause to: Cause machine external interrupt
DEBUG: [src/irq_trigger.c: 121] Setting inteded cause to: Cause machine software interrupt
DEBUG: [src/irq_trigger.c: 121] Setting inteded cause to: Cause machine timer interrupt
DEBUG: [src/irq_trigger.c: 121] Setting inteded cause to: Cause supervisor external interrupt
DEBUG: [src/irq_trigger.c: 121] Setting inteded cause to: Cause supervisor software interrupt
DEBUG: [src/irq_trigger.c: 121] Setting inteded cause to: Cause supervisor timer interrupt
riscv_cpu_do_interrupt: hart:0, async:1, cause:000000000000000b, epc:0x0000000080004d80, tval:0x0000000000000000, desc=m_external
DEBUG: [src/trap_handling.c: 315] mtvec_mei
DEBUG: [src/trap_handling.c: 65] Cause to check is currently Cause machine external interrupt
DEBUG: [src/trap_handling.c: 76] Cause machine external interrupt exception: MEPC = 0x80004d80, MTVAL = 0x0
DEBUG: [src/aia_ctrl.c: 352] Popped IMSIC message = 1
riscv_cpu_do_interrupt: hart:0, async:1, cause:0000000000000003, epc:0x0000000080004d80, tval:0x0000000000000000, desc=m_software
DEBUG: [src/trap_handling.c: 65] Cause to check is currently Cause machine software interrupt
DEBUG: [src/trap_handling.c: 76] Cause machine software interrupt exception: MEPC = 0x80004d80, MTVAL = 0x0
riscv_cpu_do_interrupt: hart:0, async:1, cause:0000000000000007, epc:0x0000000080004d80, tval:0x0000000000000000, desc=m_timer
DEBUG: [src/trap_handling.c: 65] Cause to check is currently Cause machine timer interrupt
DEBUG: [src/trap_handling.c: 76] Cause machine timer interrupt exception: MEPC = 0x80004d80, MTVAL = 0x0
riscv_cpu_do_interrupt: hart:0, async:1, cause:0000000000000009, epc:0x0000000080004d80, tval:0x0000000000000000, desc=s_external
DEBUG: [src/trap_handling.c: 296] mtvec_sei
DEBUG: [src/trap_handling.c: 65] Cause to check is currently Cause supervisor external interrupt
DEBUG: [src/trap_handling.c: 76] Cause supervisor external interrupt exception: MEPC = 0x80004d80, MTVAL = 0x0
mip
ssip (1) = 1
vssip(2) = 0
msip (3) = 0
stip (5) = 1
vstip(6) = 0
mtip (7) = 0
seip (9) = 1
vseip(10) = 0
meip (11) = 0
sgeip(12) = 0
DEBUG: [src/aia_ctrl.c: 339] Writing stopei -> 0
DEBUG: [src/aia_ctrl.c: 344] stopei = 0x0000000000000000
DEBUG: [src/aia_ctrl.c: 352] Popped IMSIC message = 1
mip
ssip (1) = 1
vssip(2) = 0
msip (3) = 0
stip (5) = 1
vstip(6) = 0
mtip (7) = 0
seip (9) = 1
vseip(10) = 0
meip (11) = 0
sgeip(12) = 0
riscv_cpu_do_interrupt: hart:0, async:1, cause:0000000000000009, epc:0x0000000080004d80, tval:0x0000000000000000, desc=s_external
DEBUG: [src/trap_handling.c: 296] mtvec_sei
DEBUG: [src/trap_handling.c: 65] Cause to check is currently Cause supervisor software interrupt
DEBUG: [src/trap_handling.c: 76] Cause supervisor external interrupt exception: MEPC = 0x80004d80, MTVAL = 0x0
ERROR: [src/trap_handling.c:121] The following assert failed: masked_cause == cause2check
masked_cause = 9"""
|