2 * HPPA interrupt helper routines
4 * Copyright (c) 2017 Richard Henderson
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 #include "qemu/osdep.h"
21 #include "qemu/main-loop.h"
24 #include "exec/helper-proto.h"
25 #include "hw/core/cpu.h"
26 #include "hw/hppa/hppa_hardware.h"
28 static void eval_interrupt(HPPACPU
*cpu
)
30 CPUState
*cs
= CPU(cpu
);
31 if (cpu
->env
.cr
[CR_EIRR
] & cpu
->env
.cr
[CR_EIEM
]) {
32 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);
34 cpu_reset_interrupt(cs
, CPU_INTERRUPT_HARD
);
38 /* Each CPU has a word mapped into the GSC bus. Anything on the GSC bus
39 * can write to this word to raise an external interrupt on the target CPU.
40 * This includes the system controller (DINO) for regular devices, or
41 * another CPU for SMP interprocessor interrupts.
43 static uint64_t io_eir_read(void *opaque
, hwaddr addr
, unsigned size
)
45 HPPACPU
*cpu
= opaque
;
47 /* ??? What does a read of this register over the GSC bus do? */
48 return cpu
->env
.cr
[CR_EIRR
];
51 static void io_eir_write(void *opaque
, hwaddr addr
,
52 uint64_t data
, unsigned size
)
54 HPPACPU
*cpu
= opaque
;
55 CPUHPPAState
*env
= &cpu
->env
;
59 /* The default PSW.W controls the width of EIRR. */
60 if (hppa_is_pa20(env
) && env
->cr
[CR_PSW_DEFAULT
] & PDC_PSW_WIDE_BIT
) {
63 le_bit
= ~data
& widthm1
;
65 env
->cr
[CR_EIRR
] |= 1ull << le_bit
;
69 const MemoryRegionOps hppa_io_eir_ops
= {
71 .write
= io_eir_write
,
72 .valid
.min_access_size
= 4,
73 .valid
.max_access_size
= 4,
74 .impl
.min_access_size
= 4,
75 .impl
.max_access_size
= 4,
78 void hppa_cpu_alarm_timer(void *opaque
)
80 /* Raise interrupt 0. */
81 io_eir_write(opaque
, 0, 0, 4);
84 void HELPER(write_eirr
)(CPUHPPAState
*env
, target_ulong val
)
86 env
->cr
[CR_EIRR
] &= ~val
;
87 qemu_mutex_lock_iothread();
88 eval_interrupt(env_archcpu(env
));
89 qemu_mutex_unlock_iothread();
92 void HELPER(write_eiem
)(CPUHPPAState
*env
, target_ulong val
)
94 env
->cr
[CR_EIEM
] = val
;
95 qemu_mutex_lock_iothread();
96 eval_interrupt(env_archcpu(env
));
97 qemu_mutex_unlock_iothread();
100 void hppa_cpu_do_interrupt(CPUState
*cs
)
102 HPPACPU
*cpu
= HPPA_CPU(cs
);
103 CPUHPPAState
*env
= &cpu
->env
;
104 int i
= cs
->exception_index
;
107 /* As documented in pa2.0 -- interruption handling. */
109 env
->cr
[CR_IPSW
] = old_psw
= cpu_hppa_get_psw(env
);
111 /* step 2 -- Note PSW_W is masked out again for pa1.x */
112 cpu_hppa_put_psw(env
,
113 (env
->cr
[CR_PSW_DEFAULT
] & PDC_PSW_WIDE_BIT
? PSW_W
: 0) |
114 (i
== EXCP_HPMC
? PSW_M
: 0));
118 * For pa1.x, IIASQ is simply a copy of IASQ.
119 * For pa2.0, IIASQ is the top bits of the virtual address,
120 * or zero if translation is disabled.
122 if (!hppa_is_pa20(env
)) {
123 env
->cr
[CR_IIASQ
] = env
->iasq_f
>> 32;
124 env
->cr_back
[0] = env
->iasq_b
>> 32;
125 } else if (old_psw
& PSW_C
) {
127 hppa_form_gva_psw(old_psw
, env
->iasq_f
, env
->iaoq_f
) >> 32;
129 hppa_form_gva_psw(old_psw
, env
->iasq_f
, env
->iaoq_f
) >> 32;
131 env
->cr
[CR_IIASQ
] = 0;
134 env
->cr
[CR_IIAOQ
] = env
->iaoq_f
;
135 env
->cr_back
[1] = env
->iaoq_b
;
137 if (old_psw
& PSW_Q
) {
139 /* ISR and IOR will be set elsewhere. */
145 /* IIR set via translate.c. */
152 case EXCP_NA_ITLB_MISS
:
153 case EXCP_NA_DTLB_MISS
:
161 case EXCP_ASSIST_EMU
:
163 /* Avoid reading directly from the virtual address, lest we
164 raise another exception from some sort of TLB issue. */
165 /* ??? An alternate fool-proof method would be to store the
166 instruction data into the unwind info. That's probably
167 a bit too much in the way of extra storage required. */
168 vaddr vaddr
= env
->iaoq_f
& -4;
169 hwaddr paddr
= vaddr
;
171 if (old_psw
& PSW_C
) {
174 vaddr
= hppa_form_gva_psw(old_psw
, env
->iasq_f
, vaddr
);
175 t
= hppa_get_physical_address(env
, vaddr
, MMU_KERNEL_IDX
,
176 0, &paddr
, &prot
, NULL
);
178 /* We can't re-load the instruction. */
183 env
->cr
[CR_IIR
] = ldl_phys(cs
->as
, paddr
);
188 /* Other exceptions do not set IIR. */
193 env
->shadow
[0] = env
->gr
[1];
194 env
->shadow
[1] = env
->gr
[8];
195 env
->shadow
[2] = env
->gr
[9];
196 env
->shadow
[3] = env
->gr
[16];
197 env
->shadow
[4] = env
->gr
[17];
198 env
->shadow
[5] = env
->gr
[24];
199 env
->shadow
[6] = env
->gr
[25];
204 env
->iaoq_f
= hppa_form_gva(env
, 0, FIRMWARE_START
);
205 /* help SeaBIOS and provide iaoq_b and iasq_back in shadow regs */
206 env
->gr
[24] = env
->cr_back
[0];
207 env
->gr
[25] = env
->cr_back
[1];
209 env
->iaoq_f
= hppa_form_gva(env
, 0, env
->cr
[CR_IVA
] + 32 * i
);
211 env
->iaoq_b
= hppa_form_gva(env
, 0, env
->iaoq_f
+ 4);
215 if (qemu_loglevel_mask(CPU_LOG_INT
)) {
216 static const char * const names
[] = {
217 [EXCP_HPMC
] = "high priority machine check",
218 [EXCP_POWER_FAIL
] = "power fail interrupt",
219 [EXCP_RC
] = "recovery counter trap",
220 [EXCP_EXT_INTERRUPT
] = "external interrupt",
221 [EXCP_LPMC
] = "low priority machine check",
222 [EXCP_ITLB_MISS
] = "instruction tlb miss fault",
223 [EXCP_IMP
] = "instruction memory protection trap",
224 [EXCP_ILL
] = "illegal instruction trap",
225 [EXCP_BREAK
] = "break instruction trap",
226 [EXCP_PRIV_OPR
] = "privileged operation trap",
227 [EXCP_PRIV_REG
] = "privileged register trap",
228 [EXCP_OVERFLOW
] = "overflow trap",
229 [EXCP_COND
] = "conditional trap",
230 [EXCP_ASSIST
] = "assist exception trap",
231 [EXCP_DTLB_MISS
] = "data tlb miss fault",
232 [EXCP_NA_ITLB_MISS
] = "non-access instruction tlb miss",
233 [EXCP_NA_DTLB_MISS
] = "non-access data tlb miss",
234 [EXCP_DMP
] = "data memory protection trap",
235 [EXCP_DMB
] = "data memory break trap",
236 [EXCP_TLB_DIRTY
] = "tlb dirty bit trap",
237 [EXCP_PAGE_REF
] = "page reference trap",
238 [EXCP_ASSIST_EMU
] = "assist emulation trap",
239 [EXCP_HPT
] = "high-privilege transfer trap",
240 [EXCP_LPT
] = "low-privilege transfer trap",
241 [EXCP_TB
] = "taken branch trap",
242 [EXCP_DMAR
] = "data memory access rights trap",
243 [EXCP_DMPI
] = "data memory protection id trap",
244 [EXCP_UNALIGN
] = "unaligned data reference trap",
245 [EXCP_PER_INTERRUPT
] = "performance monitor interrupt",
246 [EXCP_SYSCALL
] = "syscall",
247 [EXCP_SYSCALL_LWS
] = "syscall-lws",
248 [EXCP_TOC
] = "TOC (transfer of control)",
251 const char *name
= NULL
;
254 if (i
>= 0 && i
< ARRAY_SIZE(names
)) {
258 snprintf(unknown
, sizeof(unknown
), "unknown %d", i
);
261 qemu_log("INT %6d: %s @ " TARGET_FMT_lx
":" TARGET_FMT_lx
262 " for " TARGET_FMT_lx
":" TARGET_FMT_lx
"\n",
263 ++count
, name
, env
->cr
[CR_IIASQ
], env
->cr
[CR_IIAOQ
],
264 env
->cr
[CR_ISR
], env
->cr
[CR_IOR
]);
266 cs
->exception_index
= -1;
269 bool hppa_cpu_exec_interrupt(CPUState
*cs
, int interrupt_request
)
271 HPPACPU
*cpu
= HPPA_CPU(cs
);
272 CPUHPPAState
*env
= &cpu
->env
;
274 if (interrupt_request
& CPU_INTERRUPT_NMI
) {
275 /* Raise TOC (NMI) interrupt */
276 cpu_reset_interrupt(cs
, CPU_INTERRUPT_NMI
);
277 cs
->exception_index
= EXCP_TOC
;
278 hppa_cpu_do_interrupt(cs
);
282 /* If interrupts are requested and enabled, raise them. */
283 if ((env
->psw
& PSW_I
) && (interrupt_request
& CPU_INTERRUPT_HARD
)) {
284 cs
->exception_index
= EXCP_EXT_INTERRUPT
;
285 hppa_cpu_do_interrupt(cs
);