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 #ifndef CONFIG_USER_ONLY
29 static void eval_interrupt(HPPACPU
*cpu
)
31 CPUState
*cs
= CPU(cpu
);
32 if (cpu
->env
.cr
[CR_EIRR
] & cpu
->env
.cr
[CR_EIEM
]) {
33 cpu_interrupt(cs
, CPU_INTERRUPT_HARD
);
35 cpu_reset_interrupt(cs
, CPU_INTERRUPT_HARD
);
39 /* Each CPU has a word mapped into the GSC bus. Anything on the GSC bus
40 * can write to this word to raise an external interrupt on the target CPU.
41 * This includes the system controler (DINO) for regular devices, or
42 * another CPU for SMP interprocessor interrupts.
44 static uint64_t io_eir_read(void *opaque
, hwaddr addr
, unsigned size
)
46 HPPACPU
*cpu
= opaque
;
48 /* ??? What does a read of this register over the GSC bus do? */
49 return cpu
->env
.cr
[CR_EIRR
];
52 static void io_eir_write(void *opaque
, hwaddr addr
,
53 uint64_t data
, unsigned size
)
55 HPPACPU
*cpu
= opaque
;
56 int le_bit
= ~data
& (TARGET_REGISTER_BITS
- 1);
58 cpu
->env
.cr
[CR_EIRR
] |= (target_ureg
)1 << le_bit
;
62 const MemoryRegionOps hppa_io_eir_ops
= {
64 .write
= io_eir_write
,
65 .valid
.min_access_size
= 4,
66 .valid
.max_access_size
= 4,
67 .impl
.min_access_size
= 4,
68 .impl
.max_access_size
= 4,
71 void hppa_cpu_alarm_timer(void *opaque
)
73 /* Raise interrupt 0. */
74 io_eir_write(opaque
, 0, 0, 4);
77 void HELPER(write_eirr
)(CPUHPPAState
*env
, target_ureg val
)
79 env
->cr
[CR_EIRR
] &= ~val
;
80 qemu_mutex_lock_iothread();
81 eval_interrupt(env_archcpu(env
));
82 qemu_mutex_unlock_iothread();
85 void HELPER(write_eiem
)(CPUHPPAState
*env
, target_ureg val
)
87 env
->cr
[CR_EIEM
] = val
;
88 qemu_mutex_lock_iothread();
89 eval_interrupt(env_archcpu(env
));
90 qemu_mutex_unlock_iothread();
93 void hppa_cpu_do_interrupt(CPUState
*cs
)
95 HPPACPU
*cpu
= HPPA_CPU(cs
);
96 CPUHPPAState
*env
= &cpu
->env
;
97 int i
= cs
->exception_index
;
98 target_ureg iaoq_f
= env
->iaoq_f
;
99 target_ureg iaoq_b
= env
->iaoq_b
;
100 uint64_t iasq_f
= env
->iasq_f
;
101 uint64_t iasq_b
= env
->iasq_b
;
105 /* As documented in pa2.0 -- interruption handling. */
107 env
->cr
[CR_IPSW
] = old_psw
= cpu_hppa_get_psw(env
);
109 /* step 2 -- note PSW_W == 0 for !HPPA64. */
110 cpu_hppa_put_psw(env
, PSW_W
| (i
== EXCP_HPMC
? PSW_M
: 0));
113 env
->cr
[CR_IIASQ
] = iasq_f
>> 32;
114 env
->cr_back
[0] = iasq_b
>> 32;
115 env
->cr
[CR_IIAOQ
] = iaoq_f
;
116 env
->cr_back
[1] = iaoq_b
;
118 if (old_psw
& PSW_Q
) {
120 /* ISR and IOR will be set elsewhere. */
126 /* IIR set via translate.c. */
133 case EXCP_NA_ITLB_MISS
:
134 case EXCP_NA_DTLB_MISS
:
142 case EXCP_ASSIST_EMU
:
144 /* Avoid reading directly from the virtual address, lest we
145 raise another exception from some sort of TLB issue. */
146 /* ??? An alternate fool-proof method would be to store the
147 instruction data into the unwind info. That's probably
148 a bit too much in the way of extra storage required. */
152 paddr
= vaddr
= iaoq_f
& -4;
153 if (old_psw
& PSW_C
) {
156 vaddr
= hppa_form_gva_psw(old_psw
, iasq_f
, vaddr
);
157 t
= hppa_get_physical_address(env
, vaddr
, MMU_KERNEL_IDX
,
160 /* We can't re-load the instruction. */
165 env
->cr
[CR_IIR
] = ldl_phys(cs
->as
, paddr
);
170 /* Other exceptions do not set IIR. */
175 env
->shadow
[0] = env
->gr
[1];
176 env
->shadow
[1] = env
->gr
[8];
177 env
->shadow
[2] = env
->gr
[9];
178 env
->shadow
[3] = env
->gr
[16];
179 env
->shadow
[4] = env
->gr
[17];
180 env
->shadow
[5] = env
->gr
[24];
181 env
->shadow
[6] = env
->gr
[25];
186 env
->iaoq_f
= FIRMWARE_START
;
187 /* help SeaBIOS and provide iaoq_b and iasq_back in shadow regs */
188 env
->gr
[24] = env
->cr_back
[0];
189 env
->gr
[25] = env
->cr_back
[1];
191 env
->iaoq_f
= env
->cr
[CR_IVA
] + 32 * i
;
193 env
->iaoq_b
= env
->iaoq_f
+ 4;
197 if (qemu_loglevel_mask(CPU_LOG_INT
)) {
198 static const char * const names
[] = {
199 [EXCP_HPMC
] = "high priority machine check",
200 [EXCP_POWER_FAIL
] = "power fail interrupt",
201 [EXCP_RC
] = "recovery counter trap",
202 [EXCP_EXT_INTERRUPT
] = "external interrupt",
203 [EXCP_LPMC
] = "low priority machine check",
204 [EXCP_ITLB_MISS
] = "instruction tlb miss fault",
205 [EXCP_IMP
] = "instruction memory protection trap",
206 [EXCP_ILL
] = "illegal instruction trap",
207 [EXCP_BREAK
] = "break instruction trap",
208 [EXCP_PRIV_OPR
] = "privileged operation trap",
209 [EXCP_PRIV_REG
] = "privileged register trap",
210 [EXCP_OVERFLOW
] = "overflow trap",
211 [EXCP_COND
] = "conditional trap",
212 [EXCP_ASSIST
] = "assist exception trap",
213 [EXCP_DTLB_MISS
] = "data tlb miss fault",
214 [EXCP_NA_ITLB_MISS
] = "non-access instruction tlb miss",
215 [EXCP_NA_DTLB_MISS
] = "non-access data tlb miss",
216 [EXCP_DMP
] = "data memory protection trap",
217 [EXCP_DMB
] = "data memory break trap",
218 [EXCP_TLB_DIRTY
] = "tlb dirty bit trap",
219 [EXCP_PAGE_REF
] = "page reference trap",
220 [EXCP_ASSIST_EMU
] = "assist emulation trap",
221 [EXCP_HPT
] = "high-privilege transfer trap",
222 [EXCP_LPT
] = "low-privilege transfer trap",
223 [EXCP_TB
] = "taken branch trap",
224 [EXCP_DMAR
] = "data memory access rights trap",
225 [EXCP_DMPI
] = "data memory protection id trap",
226 [EXCP_UNALIGN
] = "unaligned data reference trap",
227 [EXCP_PER_INTERRUPT
] = "performance monitor interrupt",
228 [EXCP_SYSCALL
] = "syscall",
229 [EXCP_SYSCALL_LWS
] = "syscall-lws",
230 [EXCP_TOC
] = "TOC (transfer of control)",
233 const char *name
= NULL
;
236 if (i
>= 0 && i
< ARRAY_SIZE(names
)) {
240 snprintf(unknown
, sizeof(unknown
), "unknown %d", i
);
243 qemu_log("INT %6d: %s @ " TARGET_FMT_lx
"," TARGET_FMT_lx
244 " -> " TREG_FMT_lx
" " TARGET_FMT_lx
"\n",
246 hppa_form_gva(env
, iasq_f
, iaoq_f
),
247 hppa_form_gva(env
, iasq_b
, iaoq_b
),
249 hppa_form_gva(env
, (uint64_t)env
->cr
[CR_ISR
] << 32,
252 cs
->exception_index
= -1;
255 bool hppa_cpu_exec_interrupt(CPUState
*cs
, int interrupt_request
)
257 HPPACPU
*cpu
= HPPA_CPU(cs
);
258 CPUHPPAState
*env
= &cpu
->env
;
260 if (interrupt_request
& CPU_INTERRUPT_NMI
) {
261 /* Raise TOC (NMI) interrupt */
262 cpu_reset_interrupt(cs
, CPU_INTERRUPT_NMI
);
263 cs
->exception_index
= EXCP_TOC
;
264 hppa_cpu_do_interrupt(cs
);
268 /* If interrupts are requested and enabled, raise them. */
269 if ((env
->psw
& PSW_I
) && (interrupt_request
& CPU_INTERRUPT_HARD
)) {
270 cs
->exception_index
= EXCP_EXT_INTERRUPT
;
271 hppa_cpu_do_interrupt(cs
);
277 #endif /* !CONFIG_USER_ONLY */