xref: /openbmc/qemu/target/hppa/int_helper.c (revision 12959fcd)
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