xref: /openbmc/qemu/target/hppa/int_helper.c (revision 49c29d6c)
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
91a19da0dSRichard Henderson  * version 2 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"
221a19da0dSRichard Henderson #include "cpu.h"
231a19da0dSRichard Henderson #include "exec/exec-all.h"
241a19da0dSRichard Henderson #include "exec/helper-proto.h"
251a19da0dSRichard Henderson #include "qom/cpu.h"
261a19da0dSRichard Henderson 
274f5f2548SRichard Henderson #ifndef CONFIG_USER_ONLY
284f5f2548SRichard Henderson static void eval_interrupt(HPPACPU *cpu)
294f5f2548SRichard Henderson {
304f5f2548SRichard Henderson     CPUState *cs = CPU(cpu);
314f5f2548SRichard Henderson     if (cpu->env.cr[CR_EIRR] & cpu->env.cr[CR_EIEM]) {
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.
404f5f2548SRichard Henderson  * This includes the system controler (DINO) for regular devices, or
414f5f2548SRichard Henderson  * another CPU for SMP interprocessor interrupts.
424f5f2548SRichard Henderson  */
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 
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;
554f5f2548SRichard Henderson     int le_bit = ~data & (TARGET_REGISTER_BITS - 1);
564f5f2548SRichard Henderson 
574f5f2548SRichard Henderson     cpu->env.cr[CR_EIRR] |= (target_ureg)1 << le_bit;
584f5f2548SRichard Henderson     eval_interrupt(cpu);
594f5f2548SRichard Henderson }
604f5f2548SRichard Henderson 
614f5f2548SRichard Henderson const MemoryRegionOps hppa_io_eir_ops = {
624f5f2548SRichard Henderson     .read = io_eir_read,
634f5f2548SRichard Henderson     .write = io_eir_write,
644f5f2548SRichard Henderson     .valid.min_access_size = 4,
654f5f2548SRichard Henderson     .valid.max_access_size = 4,
664f5f2548SRichard Henderson     .impl.min_access_size = 4,
674f5f2548SRichard Henderson     .impl.max_access_size = 4,
684f5f2548SRichard Henderson };
694f5f2548SRichard Henderson 
70*49c29d6cSRichard Henderson void hppa_cpu_alarm_timer(void *opaque)
71*49c29d6cSRichard Henderson {
72*49c29d6cSRichard Henderson     /* Raise interrupt 0.  */
73*49c29d6cSRichard Henderson     io_eir_write(opaque, 0, 0, 4);
74*49c29d6cSRichard Henderson }
75*49c29d6cSRichard Henderson 
764f5f2548SRichard Henderson void HELPER(write_eirr)(CPUHPPAState *env, target_ureg val)
774f5f2548SRichard Henderson {
784f5f2548SRichard Henderson     env->cr[CR_EIRR] &= ~val;
794f5f2548SRichard Henderson     qemu_mutex_lock_iothread();
804f5f2548SRichard Henderson     eval_interrupt(hppa_env_get_cpu(env));
814f5f2548SRichard Henderson     qemu_mutex_unlock_iothread();
824f5f2548SRichard Henderson }
834f5f2548SRichard Henderson 
844f5f2548SRichard Henderson void HELPER(write_eiem)(CPUHPPAState *env, target_ureg val)
854f5f2548SRichard Henderson {
864f5f2548SRichard Henderson     env->cr[CR_EIEM] = val;
874f5f2548SRichard Henderson     qemu_mutex_lock_iothread();
884f5f2548SRichard Henderson     eval_interrupt(hppa_env_get_cpu(env));
894f5f2548SRichard Henderson     qemu_mutex_unlock_iothread();
904f5f2548SRichard Henderson }
914f5f2548SRichard Henderson #endif /* !CONFIG_USER_ONLY */
921a19da0dSRichard Henderson 
931a19da0dSRichard Henderson void hppa_cpu_do_interrupt(CPUState *cs)
941a19da0dSRichard Henderson {
951a19da0dSRichard Henderson     HPPACPU *cpu = HPPA_CPU(cs);
961a19da0dSRichard Henderson     CPUHPPAState *env = &cpu->env;
971a19da0dSRichard Henderson     int i = cs->exception_index;
981a19da0dSRichard Henderson     target_ureg iaoq_f = env->iaoq_f;
991a19da0dSRichard Henderson     target_ureg iaoq_b = env->iaoq_b;
100c301f34eSRichard Henderson     uint64_t iasq_f = env->iasq_f;
101c301f34eSRichard Henderson     uint64_t iasq_b = env->iasq_b;
1021a19da0dSRichard Henderson 
1031a19da0dSRichard Henderson #ifndef CONFIG_USER_ONLY
1041a19da0dSRichard Henderson     target_ureg old_psw;
1051a19da0dSRichard Henderson 
1061a19da0dSRichard Henderson     /* As documented in pa2.0 -- interruption handling.  */
1071a19da0dSRichard Henderson     /* step 1 */
1081a19da0dSRichard Henderson     env->cr[CR_IPSW] = old_psw = cpu_hppa_get_psw(env);
1091a19da0dSRichard Henderson 
1101a19da0dSRichard Henderson     /* step 2 -- note PSW_W == 0 for !HPPA64.  */
1111a19da0dSRichard Henderson     cpu_hppa_put_psw(env, PSW_W | (i == EXCP_HPMC ? PSW_M : 0));
1121a19da0dSRichard Henderson 
1131a19da0dSRichard Henderson     /* step 3 */
114c301f34eSRichard Henderson     env->cr[CR_IIASQ] = iasq_f >> 32;
115c301f34eSRichard Henderson     env->cr_back[0] = iasq_b >> 32;
1161a19da0dSRichard Henderson     env->cr[CR_IIAOQ] = iaoq_f;
1171a19da0dSRichard Henderson     env->cr_back[1] = iaoq_b;
1181a19da0dSRichard Henderson 
1191a19da0dSRichard Henderson     if (old_psw & PSW_Q) {
1201a19da0dSRichard Henderson         /* step 5 */
1211a19da0dSRichard Henderson         /* ISR and IOR will be set elsewhere.  */
1221a19da0dSRichard Henderson         switch (i) {
1231a19da0dSRichard Henderson         case EXCP_ILL:
1241a19da0dSRichard Henderson         case EXCP_BREAK:
1251a19da0dSRichard Henderson         case EXCP_PRIV_REG:
1261a19da0dSRichard Henderson         case EXCP_PRIV_OPR:
1271a19da0dSRichard Henderson             /* IIR set via translate.c.  */
1281a19da0dSRichard Henderson             break;
1291a19da0dSRichard Henderson 
1301a19da0dSRichard Henderson         case EXCP_OVERFLOW:
1311a19da0dSRichard Henderson         case EXCP_COND:
1321a19da0dSRichard Henderson         case EXCP_ASSIST:
1331a19da0dSRichard Henderson         case EXCP_DTLB_MISS:
1341a19da0dSRichard Henderson         case EXCP_NA_ITLB_MISS:
1351a19da0dSRichard Henderson         case EXCP_NA_DTLB_MISS:
1361a19da0dSRichard Henderson         case EXCP_DMAR:
1371a19da0dSRichard Henderson         case EXCP_DMPI:
1381a19da0dSRichard Henderson         case EXCP_UNALIGN:
1391a19da0dSRichard Henderson         case EXCP_DMP:
1401a19da0dSRichard Henderson         case EXCP_DMB:
1411a19da0dSRichard Henderson         case EXCP_TLB_DIRTY:
1421a19da0dSRichard Henderson         case EXCP_PAGE_REF:
1431a19da0dSRichard Henderson         case EXCP_ASSIST_EMU:
1441a19da0dSRichard Henderson             {
1451a19da0dSRichard Henderson                 /* Avoid reading directly from the virtual address, lest we
1461a19da0dSRichard Henderson                    raise another exception from some sort of TLB issue.  */
147650cdb2aSRichard Henderson                 /* ??? An alternate fool-proof method would be to store the
148650cdb2aSRichard Henderson                    instruction data into the unwind info.  That's probably
149650cdb2aSRichard Henderson                    a bit too much in the way of extra storage required.  */
1501a19da0dSRichard Henderson                 vaddr vaddr;
1511a19da0dSRichard Henderson                 hwaddr paddr;
1521a19da0dSRichard Henderson 
1531a19da0dSRichard Henderson                 paddr = vaddr = iaoq_f & -4;
154c301f34eSRichard Henderson                 if (old_psw & PSW_C) {
155650cdb2aSRichard Henderson                     int prot, t;
156650cdb2aSRichard Henderson 
157650cdb2aSRichard Henderson                     vaddr = hppa_form_gva_psw(old_psw, iasq_f, vaddr);
158650cdb2aSRichard Henderson                     t = hppa_get_physical_address(env, vaddr, MMU_KERNEL_IDX,
159650cdb2aSRichard Henderson                                                   0, &paddr, &prot);
160650cdb2aSRichard Henderson                     if (t >= 0) {
161650cdb2aSRichard Henderson                         /* We can't re-load the instruction.  */
162650cdb2aSRichard Henderson                         env->cr[CR_IIR] = 0;
163650cdb2aSRichard Henderson                         break;
164650cdb2aSRichard Henderson                     }
165c301f34eSRichard Henderson                 }
1661a19da0dSRichard Henderson                 env->cr[CR_IIR] = ldl_phys(cs->as, paddr);
1671a19da0dSRichard Henderson             }
1681a19da0dSRichard Henderson             break;
1691a19da0dSRichard Henderson 
1701a19da0dSRichard Henderson         default:
1711a19da0dSRichard Henderson             /* Other exceptions do not set IIR.  */
1721a19da0dSRichard Henderson             break;
1731a19da0dSRichard Henderson         }
1741a19da0dSRichard Henderson 
1751a19da0dSRichard Henderson         /* step 6 */
1761a19da0dSRichard Henderson         env->shadow[0] = env->gr[1];
1771a19da0dSRichard Henderson         env->shadow[1] = env->gr[8];
1781a19da0dSRichard Henderson         env->shadow[2] = env->gr[9];
1791a19da0dSRichard Henderson         env->shadow[3] = env->gr[16];
1801a19da0dSRichard Henderson         env->shadow[4] = env->gr[17];
1811a19da0dSRichard Henderson         env->shadow[5] = env->gr[24];
1821a19da0dSRichard Henderson         env->shadow[6] = env->gr[25];
1831a19da0dSRichard Henderson     }
1841a19da0dSRichard Henderson 
1851a19da0dSRichard Henderson     /* step 7 */
1861a19da0dSRichard Henderson     env->iaoq_f = env->cr[CR_IVA] + 32 * i;
1871a19da0dSRichard Henderson     env->iaoq_b = env->iaoq_f + 4;
188c301f34eSRichard Henderson     env->iasq_f = 0;
189c301f34eSRichard Henderson     env->iasq_b = 0;
1901a19da0dSRichard Henderson #endif
1911a19da0dSRichard Henderson 
1921a19da0dSRichard Henderson     if (qemu_loglevel_mask(CPU_LOG_INT)) {
1931a19da0dSRichard Henderson         static const char * const names[] = {
1941a19da0dSRichard Henderson             [EXCP_HPMC]          = "high priority machine check",
1951a19da0dSRichard Henderson             [EXCP_POWER_FAIL]    = "power fail interrupt",
1961a19da0dSRichard Henderson             [EXCP_RC]            = "recovery counter trap",
1971a19da0dSRichard Henderson             [EXCP_EXT_INTERRUPT] = "external interrupt",
1981a19da0dSRichard Henderson             [EXCP_LPMC]          = "low priority machine check",
1991a19da0dSRichard Henderson             [EXCP_ITLB_MISS]     = "instruction tlb miss fault",
2001a19da0dSRichard Henderson             [EXCP_IMP]           = "instruction memory protection trap",
2011a19da0dSRichard Henderson             [EXCP_ILL]           = "illegal instruction trap",
2021a19da0dSRichard Henderson             [EXCP_BREAK]         = "break instruction trap",
2031a19da0dSRichard Henderson             [EXCP_PRIV_OPR]      = "privileged operation trap",
2041a19da0dSRichard Henderson             [EXCP_PRIV_REG]      = "privileged register trap",
2051a19da0dSRichard Henderson             [EXCP_OVERFLOW]      = "overflow trap",
2061a19da0dSRichard Henderson             [EXCP_COND]          = "conditional trap",
2071a19da0dSRichard Henderson             [EXCP_ASSIST]        = "assist exception trap",
2081a19da0dSRichard Henderson             [EXCP_DTLB_MISS]     = "data tlb miss fault",
2091a19da0dSRichard Henderson             [EXCP_NA_ITLB_MISS]  = "non-access instruction tlb miss",
2101a19da0dSRichard Henderson             [EXCP_NA_DTLB_MISS]  = "non-access data tlb miss",
2111a19da0dSRichard Henderson             [EXCP_DMP]           = "data memory protection trap",
2121a19da0dSRichard Henderson             [EXCP_DMB]           = "data memory break trap",
2131a19da0dSRichard Henderson             [EXCP_TLB_DIRTY]     = "tlb dirty bit trap",
2141a19da0dSRichard Henderson             [EXCP_PAGE_REF]      = "page reference trap",
2151a19da0dSRichard Henderson             [EXCP_ASSIST_EMU]    = "assist emulation trap",
2161a19da0dSRichard Henderson             [EXCP_HPT]           = "high-privilege transfer trap",
2171a19da0dSRichard Henderson             [EXCP_LPT]           = "low-privilege transfer trap",
2181a19da0dSRichard Henderson             [EXCP_TB]            = "taken branch trap",
2191a19da0dSRichard Henderson             [EXCP_DMAR]          = "data memory access rights trap",
2201a19da0dSRichard Henderson             [EXCP_DMPI]          = "data memory protection id trap",
2211a19da0dSRichard Henderson             [EXCP_UNALIGN]       = "unaligned data reference trap",
2221a19da0dSRichard Henderson             [EXCP_PER_INTERRUPT] = "performance monitor interrupt",
2231a19da0dSRichard Henderson             [EXCP_SYSCALL]       = "syscall",
2241a19da0dSRichard Henderson             [EXCP_SYSCALL_LWS]   = "syscall-lws",
2251a19da0dSRichard Henderson         };
2261a19da0dSRichard Henderson         static int count;
2271a19da0dSRichard Henderson         const char *name = NULL;
2281a19da0dSRichard Henderson         char unknown[16];
2291a19da0dSRichard Henderson 
2301a19da0dSRichard Henderson         if (i >= 0 && i < ARRAY_SIZE(names)) {
2311a19da0dSRichard Henderson             name = names[i];
2321a19da0dSRichard Henderson         }
2331a19da0dSRichard Henderson         if (!name) {
2341a19da0dSRichard Henderson             snprintf(unknown, sizeof(unknown), "unknown %d", i);
2351a19da0dSRichard Henderson             name = unknown;
2361a19da0dSRichard Henderson         }
2371a19da0dSRichard Henderson         qemu_log("INT %6d: %s @ " TARGET_FMT_lx "," TARGET_FMT_lx
2381a19da0dSRichard Henderson                  " -> " TREG_FMT_lx " " TARGET_FMT_lx "\n",
2391a19da0dSRichard Henderson                  ++count, name,
240c301f34eSRichard Henderson                  hppa_form_gva(env, iasq_f, iaoq_f),
241c301f34eSRichard Henderson                  hppa_form_gva(env, iasq_b, iaoq_b),
2421a19da0dSRichard Henderson                  env->iaoq_f,
243c301f34eSRichard Henderson                  hppa_form_gva(env, (uint64_t)env->cr[CR_ISR] << 32,
244c301f34eSRichard Henderson                                env->cr[CR_IOR]));
2451a19da0dSRichard Henderson     }
2461a19da0dSRichard Henderson     cs->exception_index = -1;
2471a19da0dSRichard Henderson }
2481a19da0dSRichard Henderson 
2491a19da0dSRichard Henderson bool hppa_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
2501a19da0dSRichard Henderson {
2511a19da0dSRichard Henderson #ifndef CONFIG_USER_ONLY
2521a19da0dSRichard Henderson     HPPACPU *cpu = HPPA_CPU(cs);
2531a19da0dSRichard Henderson     CPUHPPAState *env = &cpu->env;
2541a19da0dSRichard Henderson 
2551a19da0dSRichard Henderson     /* If interrupts are requested and enabled, raise them.  */
2561a19da0dSRichard Henderson     if ((env->psw & PSW_I) && (interrupt_request & CPU_INTERRUPT_HARD)) {
2571a19da0dSRichard Henderson         cs->exception_index = EXCP_EXT_INTERRUPT;
2581a19da0dSRichard Henderson         hppa_cpu_do_interrupt(cs);
2591a19da0dSRichard Henderson         return true;
2601a19da0dSRichard Henderson     }
2611a19da0dSRichard Henderson #endif
2621a19da0dSRichard Henderson     return false;
2631a19da0dSRichard Henderson }
264