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 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"
27 #ifndef CONFIG_USER_ONLY
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 controler (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 int le_bit
= ~data
& (TARGET_REGISTER_BITS
- 1);
57 cpu
->env
.cr
[CR_EIRR
] |= (target_ureg
)1 << le_bit
;
61 const MemoryRegionOps hppa_io_eir_ops
= {
63 .write
= io_eir_write
,
64 .valid
.min_access_size
= 4,
65 .valid
.max_access_size
= 4,
66 .impl
.min_access_size
= 4,
67 .impl
.max_access_size
= 4,
70 void hppa_cpu_alarm_timer(void *opaque
)
72 /* Raise interrupt 0. */
73 io_eir_write(opaque
, 0, 0, 4);
76 void HELPER(write_eirr
)(CPUHPPAState
*env
, target_ureg val
)
78 env
->cr
[CR_EIRR
] &= ~val
;
79 qemu_mutex_lock_iothread();
80 eval_interrupt(env_archcpu(env
));
81 qemu_mutex_unlock_iothread();
84 void HELPER(write_eiem
)(CPUHPPAState
*env
, target_ureg val
)
86 env
->cr
[CR_EIEM
] = val
;
87 qemu_mutex_lock_iothread();
88 eval_interrupt(env_archcpu(env
));
89 qemu_mutex_unlock_iothread();
91 #endif /* !CONFIG_USER_ONLY */
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
;
103 #ifndef CONFIG_USER_ONLY
106 /* As documented in pa2.0 -- interruption handling. */
108 env
->cr
[CR_IPSW
] = old_psw
= cpu_hppa_get_psw(env
);
110 /* step 2 -- note PSW_W == 0 for !HPPA64. */
111 cpu_hppa_put_psw(env
, PSW_W
| (i
== EXCP_HPMC
? PSW_M
: 0));
114 env
->cr
[CR_IIASQ
] = iasq_f
>> 32;
115 env
->cr_back
[0] = iasq_b
>> 32;
116 env
->cr
[CR_IIAOQ
] = iaoq_f
;
117 env
->cr_back
[1] = iaoq_b
;
119 if (old_psw
& PSW_Q
) {
121 /* ISR and IOR will be set elsewhere. */
127 /* IIR set via translate.c. */
134 case EXCP_NA_ITLB_MISS
:
135 case EXCP_NA_DTLB_MISS
:
143 case EXCP_ASSIST_EMU
:
145 /* Avoid reading directly from the virtual address, lest we
146 raise another exception from some sort of TLB issue. */
147 /* ??? An alternate fool-proof method would be to store the
148 instruction data into the unwind info. That's probably
149 a bit too much in the way of extra storage required. */
153 paddr
= vaddr
= iaoq_f
& -4;
154 if (old_psw
& PSW_C
) {
157 vaddr
= hppa_form_gva_psw(old_psw
, iasq_f
, vaddr
);
158 t
= hppa_get_physical_address(env
, vaddr
, MMU_KERNEL_IDX
,
161 /* We can't re-load the instruction. */
166 env
->cr
[CR_IIR
] = ldl_phys(cs
->as
, paddr
);
171 /* Other exceptions do not set IIR. */
176 env
->shadow
[0] = env
->gr
[1];
177 env
->shadow
[1] = env
->gr
[8];
178 env
->shadow
[2] = env
->gr
[9];
179 env
->shadow
[3] = env
->gr
[16];
180 env
->shadow
[4] = env
->gr
[17];
181 env
->shadow
[5] = env
->gr
[24];
182 env
->shadow
[6] = env
->gr
[25];
186 env
->iaoq_f
= env
->cr
[CR_IVA
] + 32 * i
;
187 env
->iaoq_b
= env
->iaoq_f
+ 4;
192 if (qemu_loglevel_mask(CPU_LOG_INT
)) {
193 static const char * const names
[] = {
194 [EXCP_HPMC
] = "high priority machine check",
195 [EXCP_POWER_FAIL
] = "power fail interrupt",
196 [EXCP_RC
] = "recovery counter trap",
197 [EXCP_EXT_INTERRUPT
] = "external interrupt",
198 [EXCP_LPMC
] = "low priority machine check",
199 [EXCP_ITLB_MISS
] = "instruction tlb miss fault",
200 [EXCP_IMP
] = "instruction memory protection trap",
201 [EXCP_ILL
] = "illegal instruction trap",
202 [EXCP_BREAK
] = "break instruction trap",
203 [EXCP_PRIV_OPR
] = "privileged operation trap",
204 [EXCP_PRIV_REG
] = "privileged register trap",
205 [EXCP_OVERFLOW
] = "overflow trap",
206 [EXCP_COND
] = "conditional trap",
207 [EXCP_ASSIST
] = "assist exception trap",
208 [EXCP_DTLB_MISS
] = "data tlb miss fault",
209 [EXCP_NA_ITLB_MISS
] = "non-access instruction tlb miss",
210 [EXCP_NA_DTLB_MISS
] = "non-access data tlb miss",
211 [EXCP_DMP
] = "data memory protection trap",
212 [EXCP_DMB
] = "data memory break trap",
213 [EXCP_TLB_DIRTY
] = "tlb dirty bit trap",
214 [EXCP_PAGE_REF
] = "page reference trap",
215 [EXCP_ASSIST_EMU
] = "assist emulation trap",
216 [EXCP_HPT
] = "high-privilege transfer trap",
217 [EXCP_LPT
] = "low-privilege transfer trap",
218 [EXCP_TB
] = "taken branch trap",
219 [EXCP_DMAR
] = "data memory access rights trap",
220 [EXCP_DMPI
] = "data memory protection id trap",
221 [EXCP_UNALIGN
] = "unaligned data reference trap",
222 [EXCP_PER_INTERRUPT
] = "performance monitor interrupt",
223 [EXCP_SYSCALL
] = "syscall",
224 [EXCP_SYSCALL_LWS
] = "syscall-lws",
227 const char *name
= NULL
;
230 if (i
>= 0 && i
< ARRAY_SIZE(names
)) {
234 snprintf(unknown
, sizeof(unknown
), "unknown %d", i
);
237 qemu_log("INT %6d: %s @ " TARGET_FMT_lx
"," TARGET_FMT_lx
238 " -> " TREG_FMT_lx
" " TARGET_FMT_lx
"\n",
240 hppa_form_gva(env
, iasq_f
, iaoq_f
),
241 hppa_form_gva(env
, iasq_b
, iaoq_b
),
243 hppa_form_gva(env
, (uint64_t)env
->cr
[CR_ISR
] << 32,
246 cs
->exception_index
= -1;
249 bool hppa_cpu_exec_interrupt(CPUState
*cs
, int interrupt_request
)
251 #ifndef CONFIG_USER_ONLY
252 HPPACPU
*cpu
= HPPA_CPU(cs
);
253 CPUHPPAState
*env
= &cpu
->env
;
255 /* If interrupts are requested and enabled, raise them. */
256 if ((env
->psw
& PSW_I
) && (interrupt_request
& CPU_INTERRUPT_HARD
)) {
257 cs
->exception_index
= EXCP_EXT_INTERRUPT
;
258 hppa_cpu_do_interrupt(cs
);