aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-rw-r--r--hw/core/nmi.c24
-rw-r--r--hw/i386/kvmvapic.c2
-rw-r--r--hw/i386/pc.c20
-rw-r--r--hw/intc/ioapic.c33
-rw-r--r--hw/scsi/esp.c17
-rw-r--r--hw/watchdog/watchdog.c2
6 files changed, 67 insertions, 31 deletions
diff --git a/hw/core/nmi.c b/hw/core/nmi.c
index f616a79312..bfd0896daf 100644
--- a/hw/core/nmi.c
+++ b/hw/core/nmi.c
@@ -20,16 +20,11 @@
*/
#include "qemu/osdep.h"
-#include "qom/cpu.h"
#include "hw/nmi.h"
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
#include "monitor/monitor.h"
-#if defined(TARGET_I386)
-#include "cpu.h"
-#endif
-
struct do_nmi_s {
int cpu_index;
Error *err;
@@ -78,25 +73,6 @@ void nmi_monitor_handle(int cpu_index, Error **errp)
}
}
-void inject_nmi(void)
-{
-#if defined(TARGET_I386)
- CPUState *cs;
-
- CPU_FOREACH(cs) {
- X86CPU *cpu = X86_CPU(cs);
-
- if (!cpu->apic_state) {
- cpu_interrupt(cs, CPU_INTERRUPT_NMI);
- } else {
- apic_deliver_nmi(cpu->apic_state);
- }
- }
-#else
- nmi_monitor_handle(0, NULL);
-#endif
-}
-
static const TypeInfo nmi_info = {
.name = TYPE_NMI,
.parent = TYPE_INTERFACE,
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index 8fd27ba2f4..5b71b1ba46 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -397,7 +397,7 @@ static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip)
CPUX86State *env = &cpu->env;
VAPICHandlers *handlers;
uint8_t opcode[2];
- uint32_t imm32;
+ uint32_t imm32 = 0;
target_ulong current_pc = 0;
target_ulong current_cs_base = 0;
uint32_t current_flags = 0;
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 99437e0b78..e29ccc8341 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -67,6 +67,7 @@
#include "qapi/visitor.h"
#include "qapi-visit.h"
#include "qom/cpu.h"
+#include "hw/nmi.h"
/* debug PC/ISA interrupts */
//#define DEBUG_IRQ
@@ -1963,11 +1964,28 @@ static CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *machine)
return list;
}
+static void x86_nmi(NMIState *n, int cpu_index, Error **errp)
+{
+ /* cpu index isn't used */
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ X86CPU *cpu = X86_CPU(cs);
+
+ if (!cpu->apic_state) {
+ cpu_interrupt(cs, CPU_INTERRUPT_NMI);
+ } else {
+ apic_deliver_nmi(cpu->apic_state);
+ }
+ }
+}
+
static void pc_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
PCMachineClass *pcmc = PC_MACHINE_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
+ NMIClass *nc = NMI_CLASS(oc);
pcmc->get_hotplug_handler = mc->get_hotplug_handler;
pcmc->pci_enabled = true;
@@ -1993,6 +2011,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
hc->plug = pc_machine_device_plug_cb;
hc->unplug_request = pc_machine_device_unplug_request_cb;
hc->unplug = pc_machine_device_unplug_cb;
+ nc->nmi_monitor_handler = x86_nmi;
}
static const TypeInfo pc_machine_info = {
@@ -2005,6 +2024,7 @@ static const TypeInfo pc_machine_info = {
.class_init = pc_machine_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
+ { TYPE_NMI },
{ }
},
};
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index 4f42b911a2..273bb0854c 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -255,6 +255,34 @@ ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size)
return val;
}
+/*
+ * This is to satisfy the hack in Linux kernel. One hack of it is to
+ * simulate clearing the Remote IRR bit of IOAPIC entry using the
+ * following:
+ *
+ * "For IO-APIC's with EOI register, we use that to do an explicit EOI.
+ * Otherwise, we simulate the EOI message manually by changing the trigger
+ * mode to edge and then back to level, with RTE being masked during
+ * this."
+ *
+ * (See linux kernel __eoi_ioapic_pin() comment in commit c0205701)
+ *
+ * This is based on the assumption that, Remote IRR bit will be
+ * cleared by IOAPIC hardware when configured as edge-triggered
+ * interrupts.
+ *
+ * Without this, level-triggered interrupts in IR mode might fail to
+ * work correctly.
+ */
+static inline void
+ioapic_fix_edge_remote_irr(uint64_t *entry)
+{
+ if (!(*entry & IOAPIC_LVT_TRIGGER_MODE)) {
+ /* Edge-triggered interrupts, make sure remote IRR is zero */
+ *entry &= ~((uint64_t)IOAPIC_LVT_REMOTE_IRR);
+ }
+}
+
static void
ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
unsigned int size)
@@ -281,6 +309,7 @@ ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
default:
index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
if (index >= 0 && index < IOAPIC_NUM_PINS) {
+ uint64_t ro_bits = s->ioredtbl[index] & IOAPIC_RO_BITS;
if (s->ioregsel & 1) {
s->ioredtbl[index] &= 0xffffffff;
s->ioredtbl[index] |= (uint64_t)val << 32;
@@ -288,6 +317,10 @@ ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
s->ioredtbl[index] &= ~0xffffffffULL;
s->ioredtbl[index] |= val;
}
+ /* restore RO bits */
+ s->ioredtbl[index] &= IOAPIC_RW_BITS;
+ s->ioredtbl[index] |= ro_bits;
+ ioapic_fix_edge_remote_irr(&s->ioredtbl[index]);
ioapic_service(s);
}
}
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 8961be2f34..591c8172d5 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -82,7 +82,7 @@ void esp_request_cancelled(SCSIRequest *req)
}
}
-static uint32_t get_cmd(ESPState *s, uint8_t *buf)
+static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
{
uint32_t dmalen;
int target;
@@ -92,6 +92,9 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
dmalen = s->rregs[ESP_TCLO];
dmalen |= s->rregs[ESP_TCMID] << 8;
dmalen |= s->rregs[ESP_TCHI] << 16;
+ if (dmalen > buflen) {
+ return 0;
+ }
s->dma_memory_read(s->dma_opaque, buf, dmalen);
} else {
dmalen = s->ti_size;
@@ -166,7 +169,7 @@ static void handle_satn(ESPState *s)
s->dma_cb = handle_satn;
return;
}
- len = get_cmd(s, buf);
+ len = get_cmd(s, buf, sizeof(buf));
if (len)
do_cmd(s, buf);
}
@@ -180,7 +183,7 @@ static void handle_s_without_atn(ESPState *s)
s->dma_cb = handle_s_without_atn;
return;
}
- len = get_cmd(s, buf);
+ len = get_cmd(s, buf, sizeof(buf));
if (len) {
do_busid_cmd(s, buf, 0);
}
@@ -192,7 +195,7 @@ static void handle_satn_stop(ESPState *s)
s->dma_cb = handle_satn_stop;
return;
}
- s->cmdlen = get_cmd(s, s->cmdbuf);
+ s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
if (s->cmdlen) {
trace_esp_handle_satn_stop(s->cmdlen);
s->do_cmd = 1;
@@ -448,7 +451,11 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
break;
case ESP_FIFO:
if (s->do_cmd) {
- s->cmdbuf[s->cmdlen++] = val & 0xff;
+ if (s->cmdlen < TI_BUFSZ) {
+ s->cmdbuf[s->cmdlen++] = val & 0xff;
+ } else {
+ trace_esp_error_fifo_overrun();
+ }
} else if (s->ti_size == TI_BUFSZ - 1) {
trace_esp_error_fifo_overrun();
} else {
diff --git a/hw/watchdog/watchdog.c b/hw/watchdog/watchdog.c
index bbf3646bae..2aeaf1fbc9 100644
--- a/hw/watchdog/watchdog.c
+++ b/hw/watchdog/watchdog.c
@@ -143,7 +143,7 @@ void watchdog_perform_action(void)
case WDT_NMI:
qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_INJECT_NMI,
&error_abort);
- inject_nmi();
+ nmi_monitor_handle(0, NULL);
break;
}
}