aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/hppa/machine.c35
-rw-r--r--target/hppa/cpu.c2
-rw-r--r--target/hppa/cpu.h5
-rw-r--r--target/hppa/helper.h1
-rw-r--r--target/hppa/insns.decode1
-rw-r--r--target/hppa/int_helper.c19
-rw-r--r--target/hppa/op_helper.c7
-rw-r--r--target/hppa/translate.c10
8 files changed, 76 insertions, 4 deletions
diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c
index 2a46af5..98b30e0 100644
--- a/hw/hppa/machine.c
+++ b/hw/hppa/machine.c
@@ -17,6 +17,7 @@
#include "hw/timer/i8254.h"
#include "hw/char/serial.h"
#include "hw/net/lasi_82596.h"
+#include "hw/nmi.h"
#include "hppa_sys.h"
#include "qemu/units.h"
#include "qapi/error.h"
@@ -355,6 +356,14 @@ static void hppa_machine_reset(MachineState *ms)
cpu[0]->env.gr[19] = FW_CFG_IO_BASE;
}
+static void hppa_nmi(NMIState *n, int cpu_index, Error **errp)
+{
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ cpu_interrupt(cs, CPU_INTERRUPT_NMI);
+ }
+}
static void machine_hppa_machine_init(MachineClass *mc)
{
@@ -371,4 +380,28 @@ static void machine_hppa_machine_init(MachineClass *mc)
mc->default_ram_id = "ram";
}
-DEFINE_MACHINE("hppa", machine_hppa_machine_init)
+static void machine_hppa_machine_init_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ machine_hppa_machine_init(mc);
+
+ NMIClass *nc = NMI_CLASS(oc);
+ nc->nmi_monitor_handler = hppa_nmi;
+}
+
+static const TypeInfo machine_hppa_machine_init_typeinfo = {
+ .name = ("hppa" "-machine"),
+ .parent = "machine",
+ .class_init = machine_hppa_machine_init_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_NMI },
+ { }
+ },
+};
+
+static void machine_hppa_machine_init_register_types(void)
+{
+ type_register_static(&machine_hppa_machine_init_typeinfo);
+}
+
+type_init(machine_hppa_machine_init_register_types)
diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c
index 23eb254..37b763f 100644
--- a/target/hppa/cpu.c
+++ b/target/hppa/cpu.c
@@ -62,7 +62,7 @@ static void hppa_cpu_synchronize_from_tb(CPUState *cs,
static bool hppa_cpu_has_work(CPUState *cs)
{
- return cs->interrupt_request & CPU_INTERRUPT_HARD;
+ return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI);
}
static void hppa_cpu_disas_set_info(CPUState *cs, disassemble_info *info)
diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h
index 45fd338..93c1195 100644
--- a/target/hppa/cpu.h
+++ b/target/hppa/cpu.h
@@ -69,6 +69,11 @@
#define EXCP_SYSCALL 30
#define EXCP_SYSCALL_LWS 31
+/* Emulated hardware TOC button */
+#define EXCP_TOC 32 /* TOC = Transfer of control (NMI) */
+
+#define CPU_INTERRUPT_NMI CPU_INTERRUPT_TGT_EXT_3 /* TOC */
+
/* Taken from Linux kernel: arch/parisc/include/asm/psw.h */
#define PSW_I 0x00000001
#define PSW_D 0x00000002
diff --git a/target/hppa/helper.h b/target/hppa/helper.h
index 0a629ff..fe8a9ce 100644
--- a/target/hppa/helper.h
+++ b/target/hppa/helper.h
@@ -80,6 +80,7 @@ DEF_HELPER_FLAGS_0(read_interval_timer, TCG_CALL_NO_RWG, tr)
#ifndef CONFIG_USER_ONLY
DEF_HELPER_1(halt, noreturn, env)
DEF_HELPER_1(reset, noreturn, env)
+DEF_HELPER_1(getshadowregs, void, env)
DEF_HELPER_1(rfi, void, env)
DEF_HELPER_1(rfi_r, void, env)
DEF_HELPER_FLAGS_2(write_interval_timer, TCG_CALL_NO_RWG, void, env, tr)
diff --git a/target/hppa/insns.decode b/target/hppa/insns.decode
index d4eefc0..c7a7e99 100644
--- a/target/hppa/insns.decode
+++ b/target/hppa/insns.decode
@@ -111,6 +111,7 @@ rfi_r 000000 ----- ----- --- 01100101 00000
# They are allocated from the unassigned instruction space.
halt 1111 1111 1111 1101 1110 1010 1101 0000
reset 1111 1111 1111 1101 1110 1010 1101 0001
+getshadowregs 1111 1111 1111 1101 1110 1010 1101 0010
####
# Memory Management
diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c
index 13073ae..f599dcc 100644
--- a/target/hppa/int_helper.c
+++ b/target/hppa/int_helper.c
@@ -23,6 +23,7 @@
#include "cpu.h"
#include "exec/helper-proto.h"
#include "hw/core/cpu.h"
+#include "hw/hppa/hppa_hardware.h"
#ifndef CONFIG_USER_ONLY
static void eval_interrupt(HPPACPU *cpu)
@@ -181,7 +182,14 @@ void hppa_cpu_do_interrupt(CPUState *cs)
}
/* step 7 */
- env->iaoq_f = env->cr[CR_IVA] + 32 * i;
+ if (i == EXCP_TOC) {
+ env->iaoq_f = FIRMWARE_START;
+ /* help SeaBIOS and provide iaoq_b and iasq_back in shadow regs */
+ env->gr[24] = env->cr_back[0];
+ env->gr[25] = env->cr_back[1];
+ } else {
+ env->iaoq_f = env->cr[CR_IVA] + 32 * i;
+ }
env->iaoq_b = env->iaoq_f + 4;
env->iasq_f = 0;
env->iasq_b = 0;
@@ -219,6 +227,7 @@ void hppa_cpu_do_interrupt(CPUState *cs)
[EXCP_PER_INTERRUPT] = "performance monitor interrupt",
[EXCP_SYSCALL] = "syscall",
[EXCP_SYSCALL_LWS] = "syscall-lws",
+ [EXCP_TOC] = "TOC (transfer of control)",
};
static int count;
const char *name = NULL;
@@ -248,6 +257,14 @@ bool hppa_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
HPPACPU *cpu = HPPA_CPU(cs);
CPUHPPAState *env = &cpu->env;
+ if (interrupt_request & CPU_INTERRUPT_NMI) {
+ /* Raise TOC (NMI) interrupt */
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_NMI);
+ cs->exception_index = EXCP_TOC;
+ hppa_cpu_do_interrupt(cs);
+ return true;
+ }
+
/* If interrupts are requested and enabled, raise them. */
if ((env->psw & PSW_I) && (interrupt_request & CPU_INTERRUPT_HARD)) {
cs->exception_index = EXCP_EXT_INTERRUPT;
diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c
index 1b86557..b0dec4e 100644
--- a/target/hppa/op_helper.c
+++ b/target/hppa/op_helper.c
@@ -694,7 +694,7 @@ void HELPER(rfi)(CPUHPPAState *env)
cpu_hppa_put_psw(env, env->cr[CR_IPSW]);
}
-void HELPER(rfi_r)(CPUHPPAState *env)
+void HELPER(getshadowregs)(CPUHPPAState *env)
{
env->gr[1] = env->shadow[0];
env->gr[8] = env->shadow[1];
@@ -703,6 +703,11 @@ void HELPER(rfi_r)(CPUHPPAState *env)
env->gr[17] = env->shadow[4];
env->gr[24] = env->shadow[5];
env->gr[25] = env->shadow[6];
+}
+
+void HELPER(rfi_r)(CPUHPPAState *env)
+{
+ helper_getshadowregs(env);
helper_rfi(env);
}
#endif
diff --git a/target/hppa/translate.c b/target/hppa/translate.c
index c619559..5c0b1eb 100644
--- a/target/hppa/translate.c
+++ b/target/hppa/translate.c
@@ -2393,6 +2393,16 @@ static bool trans_reset(DisasContext *ctx, arg_reset *a)
#endif
}
+static bool trans_getshadowregs(DisasContext *ctx, arg_getshadowregs *a)
+{
+ CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
+#ifndef CONFIG_USER_ONLY
+ nullify_over(ctx);
+ gen_helper_getshadowregs(cpu_env);
+ return nullify_end(ctx);
+#endif
+}
+
static bool trans_nop_addrx(DisasContext *ctx, arg_ldst *a)
{
if (a->m) {