11a19da0dSRichard Henderson /*
21a19da0dSRichard Henderson * HPPA interrupt helper routines
31a19da0dSRichard Henderson *
41a19da0dSRichard Henderson * Copyright (c) 2017 Richard Henderson
51a19da0dSRichard Henderson *
61a19da0dSRichard Henderson * This library is free software; you can redistribute it and/or
71a19da0dSRichard Henderson * modify it under the terms of the GNU Lesser General Public
81a19da0dSRichard Henderson * License as published by the Free Software Foundation; either
9d6ea4236SChetan Pant * version 2.1 of the License, or (at your option) any later version.
101a19da0dSRichard Henderson *
111a19da0dSRichard Henderson * This library is distributed in the hope that it will be useful,
121a19da0dSRichard Henderson * but WITHOUT ANY WARRANTY; without even the implied warranty of
131a19da0dSRichard Henderson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
141a19da0dSRichard Henderson * Lesser General Public License for more details.
151a19da0dSRichard Henderson *
161a19da0dSRichard Henderson * You should have received a copy of the GNU Lesser General Public
171a19da0dSRichard Henderson * License along with this library; if not, see <http://www.gnu.org/licenses/>.
181a19da0dSRichard Henderson */
191a19da0dSRichard Henderson
201a19da0dSRichard Henderson #include "qemu/osdep.h"
211a19da0dSRichard Henderson #include "qemu/main-loop.h"
220d114d0dSPhilippe Mathieu-Daudé #include "qemu/log.h"
231a19da0dSRichard Henderson #include "cpu.h"
241a19da0dSRichard Henderson #include "exec/helper-proto.h"
252e5b09fdSMarkus Armbruster #include "hw/core/cpu.h"
264a4554c6SHelge Deller #include "hw/hppa/hppa_hardware.h"
271a19da0dSRichard Henderson
eval_interrupt(HPPACPU * cpu)284f5f2548SRichard Henderson static void eval_interrupt(HPPACPU *cpu)
294f5f2548SRichard Henderson {
304f5f2548SRichard Henderson CPUState *cs = CPU(cpu);
316ebebea7SRichard Henderson if (cpu->env.cr[CR_EIRR]) {
324f5f2548SRichard Henderson cpu_interrupt(cs, CPU_INTERRUPT_HARD);
334f5f2548SRichard Henderson } else {
344f5f2548SRichard Henderson cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
354f5f2548SRichard Henderson }
364f5f2548SRichard Henderson }
374f5f2548SRichard Henderson
384f5f2548SRichard Henderson /* Each CPU has a word mapped into the GSC bus. Anything on the GSC bus
394f5f2548SRichard Henderson * can write to this word to raise an external interrupt on the target CPU.
408b81968cSMichael Tokarev * This includes the system controller (DINO) for regular devices, or
414f5f2548SRichard Henderson * another CPU for SMP interprocessor interrupts.
424f5f2548SRichard Henderson */
io_eir_read(void * opaque,hwaddr addr,unsigned size)434f5f2548SRichard Henderson static uint64_t io_eir_read(void *opaque, hwaddr addr, unsigned size)
444f5f2548SRichard Henderson {
454f5f2548SRichard Henderson HPPACPU *cpu = opaque;
464f5f2548SRichard Henderson
474f5f2548SRichard Henderson /* ??? What does a read of this register over the GSC bus do? */
484f5f2548SRichard Henderson return cpu->env.cr[CR_EIRR];
494f5f2548SRichard Henderson }
504f5f2548SRichard Henderson
io_eir_write(void * opaque,hwaddr addr,uint64_t data,unsigned size)514f5f2548SRichard Henderson static void io_eir_write(void *opaque, hwaddr addr,
524f5f2548SRichard Henderson uint64_t data, unsigned size)
534f5f2548SRichard Henderson {
544f5f2548SRichard Henderson HPPACPU *cpu = opaque;
55ab9af359SHelge Deller CPUHPPAState *env = &cpu->env;
56ab9af359SHelge Deller int widthm1 = 31;
57ab9af359SHelge Deller int le_bit;
584f5f2548SRichard Henderson
59ab9af359SHelge Deller /* The default PSW.W controls the width of EIRR. */
60ab9af359SHelge Deller if (hppa_is_pa20(env) && env->cr[CR_PSW_DEFAULT] & PDC_PSW_WIDE_BIT) {
61ab9af359SHelge Deller widthm1 = 63;
62ab9af359SHelge Deller }
63ab9af359SHelge Deller le_bit = ~data & widthm1;
64ab9af359SHelge Deller
65ab9af359SHelge Deller env->cr[CR_EIRR] |= 1ull << le_bit;
664f5f2548SRichard Henderson eval_interrupt(cpu);
674f5f2548SRichard Henderson }
684f5f2548SRichard Henderson
694f5f2548SRichard Henderson const MemoryRegionOps hppa_io_eir_ops = {
704f5f2548SRichard Henderson .read = io_eir_read,
714f5f2548SRichard Henderson .write = io_eir_write,
724f5f2548SRichard Henderson .valid.min_access_size = 4,
734f5f2548SRichard Henderson .valid.max_access_size = 4,
744f5f2548SRichard Henderson .impl.min_access_size = 4,
754f5f2548SRichard Henderson .impl.max_access_size = 4,
764f5f2548SRichard Henderson };
774f5f2548SRichard Henderson
hppa_cpu_alarm_timer(void * opaque)7849c29d6cSRichard Henderson void hppa_cpu_alarm_timer(void *opaque)
7949c29d6cSRichard Henderson {
8049c29d6cSRichard Henderson /* Raise interrupt 0. */
8149c29d6cSRichard Henderson io_eir_write(opaque, 0, 0, 4);
8249c29d6cSRichard Henderson }
8349c29d6cSRichard Henderson
HELPER(write_eirr)84c53e401eSRichard Henderson void HELPER(write_eirr)(CPUHPPAState *env, target_ulong val)
854f5f2548SRichard Henderson {
864f5f2548SRichard Henderson env->cr[CR_EIRR] &= ~val;
87195801d7SStefan Hajnoczi bql_lock();
8825f32708SRichard Henderson eval_interrupt(env_archcpu(env));
89195801d7SStefan Hajnoczi bql_unlock();
904f5f2548SRichard Henderson }
914f5f2548SRichard Henderson
hppa_cpu_do_interrupt(CPUState * cs)921a19da0dSRichard Henderson void hppa_cpu_do_interrupt(CPUState *cs)
931a19da0dSRichard Henderson {
941a19da0dSRichard Henderson HPPACPU *cpu = HPPA_CPU(cs);
951a19da0dSRichard Henderson CPUHPPAState *env = &cpu->env;
961a19da0dSRichard Henderson int i = cs->exception_index;
97b10700d8SRichard Henderson uint64_t old_psw;
981a19da0dSRichard Henderson
991a19da0dSRichard Henderson /* As documented in pa2.0 -- interruption handling. */
1001a19da0dSRichard Henderson /* step 1 */
1011a19da0dSRichard Henderson env->cr[CR_IPSW] = old_psw = cpu_hppa_get_psw(env);
1021a19da0dSRichard Henderson
103ab9af359SHelge Deller /* step 2 -- Note PSW_W is masked out again for pa1.x */
104ab9af359SHelge Deller cpu_hppa_put_psw(env,
105ab9af359SHelge Deller (env->cr[CR_PSW_DEFAULT] & PDC_PSW_WIDE_BIT ? PSW_W : 0) |
106ab9af359SHelge Deller (i == EXCP_HPMC ? PSW_M : 0));
1071a19da0dSRichard Henderson
1081a19da0dSRichard Henderson /* step 3 */
109b10700d8SRichard Henderson /*
11026d93723SRichard Henderson * IIASQ is the top bits of the virtual address, or zero if translation
11126d93723SRichard Henderson * is disabled -- with PSW_W == 0, this will reduce to the space.
112b10700d8SRichard Henderson */
11326d93723SRichard Henderson if (old_psw & PSW_C) {
114b10700d8SRichard Henderson env->cr[CR_IIASQ] =
115b10700d8SRichard Henderson hppa_form_gva_psw(old_psw, env->iasq_f, env->iaoq_f) >> 32;
116b10700d8SRichard Henderson env->cr_back[0] =
117e722e5a1SHelge Deller hppa_form_gva_psw(old_psw, env->iasq_b, env->iaoq_b) >> 32;
118b10700d8SRichard Henderson } else {
119b10700d8SRichard Henderson env->cr[CR_IIASQ] = 0;
120b10700d8SRichard Henderson env->cr_back[0] = 0;
121b10700d8SRichard Henderson }
12226d93723SRichard Henderson /* IIAOQ is the full offset for wide mode, or 32 bits for narrow mode. */
12326d93723SRichard Henderson if (old_psw & PSW_W) {
124b10700d8SRichard Henderson env->cr[CR_IIAOQ] = env->iaoq_f;
125b10700d8SRichard Henderson env->cr_back[1] = env->iaoq_b;
12626d93723SRichard Henderson } else {
12726d93723SRichard Henderson env->cr[CR_IIAOQ] = (uint32_t)env->iaoq_f;
12826d93723SRichard Henderson env->cr_back[1] = (uint32_t)env->iaoq_b;
12926d93723SRichard Henderson }
1301a19da0dSRichard Henderson
1311a19da0dSRichard Henderson if (old_psw & PSW_Q) {
1321a19da0dSRichard Henderson /* step 5 */
1331a19da0dSRichard Henderson /* ISR and IOR will be set elsewhere. */
1341a19da0dSRichard Henderson switch (i) {
1351a19da0dSRichard Henderson case EXCP_ILL:
1361a19da0dSRichard Henderson case EXCP_BREAK:
137a0ea4becSRichard Henderson case EXCP_OVERFLOW:
138269ca0a9SRichard Henderson case EXCP_COND:
1391a19da0dSRichard Henderson case EXCP_PRIV_REG:
1401a19da0dSRichard Henderson case EXCP_PRIV_OPR:
1411a19da0dSRichard Henderson /* IIR set via translate.c. */
1421a19da0dSRichard Henderson break;
1431a19da0dSRichard Henderson
1441a19da0dSRichard Henderson case EXCP_ASSIST:
1451a19da0dSRichard Henderson case EXCP_DTLB_MISS:
1461a19da0dSRichard Henderson case EXCP_NA_ITLB_MISS:
1471a19da0dSRichard Henderson case EXCP_NA_DTLB_MISS:
1481a19da0dSRichard Henderson case EXCP_DMAR:
1491a19da0dSRichard Henderson case EXCP_DMPI:
1501a19da0dSRichard Henderson case EXCP_UNALIGN:
1511a19da0dSRichard Henderson case EXCP_DMP:
1521a19da0dSRichard Henderson case EXCP_DMB:
1531a19da0dSRichard Henderson case EXCP_TLB_DIRTY:
1541a19da0dSRichard Henderson case EXCP_PAGE_REF:
1551a19da0dSRichard Henderson case EXCP_ASSIST_EMU:
1561a19da0dSRichard Henderson {
1571a19da0dSRichard Henderson /* Avoid reading directly from the virtual address, lest we
1581a19da0dSRichard Henderson raise another exception from some sort of TLB issue. */
159650cdb2aSRichard Henderson /* ??? An alternate fool-proof method would be to store the
160650cdb2aSRichard Henderson instruction data into the unwind info. That's probably
161650cdb2aSRichard Henderson a bit too much in the way of extra storage required. */
162b10700d8SRichard Henderson vaddr vaddr = env->iaoq_f & -4;
163b10700d8SRichard Henderson hwaddr paddr = vaddr;
1641a19da0dSRichard Henderson
165c301f34eSRichard Henderson if (old_psw & PSW_C) {
166650cdb2aSRichard Henderson int prot, t;
167650cdb2aSRichard Henderson
168b10700d8SRichard Henderson vaddr = hppa_form_gva_psw(old_psw, env->iasq_f, vaddr);
169650cdb2aSRichard Henderson t = hppa_get_physical_address(env, vaddr, MMU_KERNEL_IDX,
170190d7fa5SRichard Henderson 0, &paddr, &prot);
171650cdb2aSRichard Henderson if (t >= 0) {
172650cdb2aSRichard Henderson /* We can't re-load the instruction. */
173650cdb2aSRichard Henderson env->cr[CR_IIR] = 0;
174650cdb2aSRichard Henderson break;
175650cdb2aSRichard Henderson }
176c301f34eSRichard Henderson }
1771a19da0dSRichard Henderson env->cr[CR_IIR] = ldl_phys(cs->as, paddr);
1781a19da0dSRichard Henderson }
1791a19da0dSRichard Henderson break;
1801a19da0dSRichard Henderson
1811a19da0dSRichard Henderson default:
1821a19da0dSRichard Henderson /* Other exceptions do not set IIR. */
1831a19da0dSRichard Henderson break;
1841a19da0dSRichard Henderson }
1851a19da0dSRichard Henderson
1861a19da0dSRichard Henderson /* step 6 */
1871a19da0dSRichard Henderson env->shadow[0] = env->gr[1];
1881a19da0dSRichard Henderson env->shadow[1] = env->gr[8];
1891a19da0dSRichard Henderson env->shadow[2] = env->gr[9];
1901a19da0dSRichard Henderson env->shadow[3] = env->gr[16];
1911a19da0dSRichard Henderson env->shadow[4] = env->gr[17];
1921a19da0dSRichard Henderson env->shadow[5] = env->gr[24];
1931a19da0dSRichard Henderson env->shadow[6] = env->gr[25];
1941a19da0dSRichard Henderson }
1951a19da0dSRichard Henderson
1961a19da0dSRichard Henderson /* step 7 */
1974a4554c6SHelge Deller if (i == EXCP_TOC) {
198b10700d8SRichard Henderson env->iaoq_f = hppa_form_gva(env, 0, FIRMWARE_START);
1994a4554c6SHelge Deller /* help SeaBIOS and provide iaoq_b and iasq_back in shadow regs */
2004a4554c6SHelge Deller env->gr[24] = env->cr_back[0];
2014a4554c6SHelge Deller env->gr[25] = env->cr_back[1];
2024a4554c6SHelge Deller } else {
203b10700d8SRichard Henderson env->iaoq_f = hppa_form_gva(env, 0, env->cr[CR_IVA] + 32 * i);
2044a4554c6SHelge Deller }
205b10700d8SRichard Henderson env->iaoq_b = hppa_form_gva(env, 0, env->iaoq_f + 4);
206c301f34eSRichard Henderson env->iasq_f = 0;
207c301f34eSRichard Henderson env->iasq_b = 0;
2081a19da0dSRichard Henderson
2091a19da0dSRichard Henderson if (qemu_loglevel_mask(CPU_LOG_INT)) {
2101a19da0dSRichard Henderson static const char * const names[] = {
2111a19da0dSRichard Henderson [EXCP_HPMC] = "high priority machine check",
2121a19da0dSRichard Henderson [EXCP_POWER_FAIL] = "power fail interrupt",
2131a19da0dSRichard Henderson [EXCP_RC] = "recovery counter trap",
2141a19da0dSRichard Henderson [EXCP_EXT_INTERRUPT] = "external interrupt",
2151a19da0dSRichard Henderson [EXCP_LPMC] = "low priority machine check",
2161a19da0dSRichard Henderson [EXCP_ITLB_MISS] = "instruction tlb miss fault",
2171a19da0dSRichard Henderson [EXCP_IMP] = "instruction memory protection trap",
2181a19da0dSRichard Henderson [EXCP_ILL] = "illegal instruction trap",
2191a19da0dSRichard Henderson [EXCP_BREAK] = "break instruction trap",
2201a19da0dSRichard Henderson [EXCP_PRIV_OPR] = "privileged operation trap",
2211a19da0dSRichard Henderson [EXCP_PRIV_REG] = "privileged register trap",
2221a19da0dSRichard Henderson [EXCP_OVERFLOW] = "overflow trap",
2231a19da0dSRichard Henderson [EXCP_COND] = "conditional trap",
2241a19da0dSRichard Henderson [EXCP_ASSIST] = "assist exception trap",
2251a19da0dSRichard Henderson [EXCP_DTLB_MISS] = "data tlb miss fault",
2261a19da0dSRichard Henderson [EXCP_NA_ITLB_MISS] = "non-access instruction tlb miss",
2271a19da0dSRichard Henderson [EXCP_NA_DTLB_MISS] = "non-access data tlb miss",
2281a19da0dSRichard Henderson [EXCP_DMP] = "data memory protection trap",
2291a19da0dSRichard Henderson [EXCP_DMB] = "data memory break trap",
2301a19da0dSRichard Henderson [EXCP_TLB_DIRTY] = "tlb dirty bit trap",
2311a19da0dSRichard Henderson [EXCP_PAGE_REF] = "page reference trap",
2321a19da0dSRichard Henderson [EXCP_ASSIST_EMU] = "assist emulation trap",
2331a19da0dSRichard Henderson [EXCP_HPT] = "high-privilege transfer trap",
2341a19da0dSRichard Henderson [EXCP_LPT] = "low-privilege transfer trap",
2351a19da0dSRichard Henderson [EXCP_TB] = "taken branch trap",
2361a19da0dSRichard Henderson [EXCP_DMAR] = "data memory access rights trap",
2371a19da0dSRichard Henderson [EXCP_DMPI] = "data memory protection id trap",
2381a19da0dSRichard Henderson [EXCP_UNALIGN] = "unaligned data reference trap",
2391a19da0dSRichard Henderson [EXCP_PER_INTERRUPT] = "performance monitor interrupt",
2401a19da0dSRichard Henderson [EXCP_SYSCALL] = "syscall",
2411a19da0dSRichard Henderson [EXCP_SYSCALL_LWS] = "syscall-lws",
2424a4554c6SHelge Deller [EXCP_TOC] = "TOC (transfer of control)",
2431a19da0dSRichard Henderson };
244*12959fcdSRichard Henderson
245*12959fcdSRichard Henderson FILE *logfile = qemu_log_trylock();
246*12959fcdSRichard Henderson if (logfile) {
2471a19da0dSRichard Henderson const char *name = NULL;
2481a19da0dSRichard Henderson
2491a19da0dSRichard Henderson if (i >= 0 && i < ARRAY_SIZE(names)) {
2501a19da0dSRichard Henderson name = names[i];
2511a19da0dSRichard Henderson }
252*12959fcdSRichard Henderson if (name) {
253*12959fcdSRichard Henderson fprintf(logfile, "INT: cpu %d %s\n", cs->cpu_index, name);
254*12959fcdSRichard Henderson } else {
255*12959fcdSRichard Henderson fprintf(logfile, "INT: cpu %d unknown %d\n", cs->cpu_index, i);
2561a19da0dSRichard Henderson }
257*12959fcdSRichard Henderson hppa_cpu_dump_state(cs, logfile, 0);
258*12959fcdSRichard Henderson qemu_log_unlock(logfile);
259*12959fcdSRichard Henderson }
2601a19da0dSRichard Henderson }
2611a19da0dSRichard Henderson cs->exception_index = -1;
2621a19da0dSRichard Henderson }
2631a19da0dSRichard Henderson
hppa_cpu_exec_interrupt(CPUState * cs,int interrupt_request)2641a19da0dSRichard Henderson bool hppa_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
2651a19da0dSRichard Henderson {
2661a19da0dSRichard Henderson HPPACPU *cpu = HPPA_CPU(cs);
2671a19da0dSRichard Henderson CPUHPPAState *env = &cpu->env;
2681a19da0dSRichard Henderson
2694a4554c6SHelge Deller if (interrupt_request & CPU_INTERRUPT_NMI) {
2704a4554c6SHelge Deller /* Raise TOC (NMI) interrupt */
2714a4554c6SHelge Deller cpu_reset_interrupt(cs, CPU_INTERRUPT_NMI);
2724a4554c6SHelge Deller cs->exception_index = EXCP_TOC;
2734a4554c6SHelge Deller hppa_cpu_do_interrupt(cs);
2744a4554c6SHelge Deller return true;
2754a4554c6SHelge Deller }
2764a4554c6SHelge Deller
2771a19da0dSRichard Henderson /* If interrupts are requested and enabled, raise them. */
2786ebebea7SRichard Henderson if ((interrupt_request & CPU_INTERRUPT_HARD)
2796ebebea7SRichard Henderson && (env->psw & PSW_I)
2806ebebea7SRichard Henderson && (env->cr[CR_EIRR] & env->cr[CR_EIEM])) {
2811a19da0dSRichard Henderson cs->exception_index = EXCP_EXT_INTERRUPT;
2821a19da0dSRichard Henderson hppa_cpu_do_interrupt(cs);
2831a19da0dSRichard Henderson return true;
2841a19da0dSRichard Henderson }
2851a19da0dSRichard Henderson return false;
2861a19da0dSRichard Henderson }
287