aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Ogilvie <mmogilvi_qemu@miniinfo.net>2012-08-23 00:24:43 -0600
committermalc <av1474@comtv.ru>2012-08-24 07:44:39 +0400
commitf278d4947fff814dcde2ef2acad36d172ff8be35 (patch)
treec483f5871bb83294728a3b3026206c56ad7485a9
parent482f7bf86b43af9f6903c52726fedf82b28bf953 (diff)
i8259: add -no-spurious-interrupt-hack option
This patch provides a way to optionally suppress spurious interrupts, as a workaround for systems described below: Some old operating systems do not handle spurious interrupts well, and qemu tends to generate them significantly more often than real hardware. Examples: - Microport UNIX System V/386 v 2.1 (ca 1987) (The main problem I'm fixing: Without this patch, it panics sporadically when accessing the hard disk.) - AT&T UNIX System V/386 Release 4.0 Version 2.1a (ca 1991) See screenshot in "QEMU Official OS Support List": http://www.claunia.com/qemu/objectManager.php?sClass=application&iId=9 (I don't have this system to test.) - A report about OS/2 boot lockup from 2004 by Hampa Hug: http://lists.nongnu.org/archive/html/qemu-devel/2004-09/msg00367.html (My patch was partially inspired by his.) Also: http://lists.nongnu.org/archive/html/qemu-devel/2005-06/msg00243.html (I don't have this system to test.) Signed-off-by: Matthew Ogilvie <mmogilvi_qemu@miniinfo.net> Signed-off-by: malc <av1474@comtv.ru>
-rw-r--r--cpu-exec.c14
-rw-r--r--hw/i8259.c18
-rw-r--r--qemu-options.hx12
-rw-r--r--sysemu.h1
-rw-r--r--vl.c4
5 files changed, 44 insertions, 5 deletions
diff --git a/cpu-exec.c b/cpu-exec.c
index 134b3c4fcf..625fbb0e0f 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -329,11 +329,15 @@ int cpu_exec(CPUArchState *env)
0);
env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
intno = cpu_get_pic_interrupt(env);
- qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
- do_interrupt_x86_hardirq(env, intno, 1);
- /* ensure that no TB jump will be modified as
- the program flow was changed */
- next_tb = 0;
+ if (intno >= 0) {
+ qemu_log_mask(CPU_LOG_TB_IN_ASM,
+ "Servicing hardware INT=0x%02x\n",
+ intno);
+ do_interrupt_x86_hardirq(env, intno, 1);
+ /* ensure that no TB jump will be modified as
+ the program flow was changed */
+ next_tb = 0;
+ }
#if !defined(CONFIG_USER_ONLY)
} else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
(env->eflags & IF_MASK) &&
diff --git a/hw/i8259.c b/hw/i8259.c
index 65876662a1..7ecb7e1de6 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -26,6 +26,7 @@
#include "isa.h"
#include "monitor.h"
#include "qemu-timer.h"
+#include "sysemu.h"
#include "i8259_internal.h"
/* debug PIC */
@@ -193,6 +194,20 @@ int pic_read_irq(DeviceState *d)
pic_intack(slave_pic, irq2);
} else {
/* spurious IRQ on slave controller */
+ if (no_spurious_interrupt_hack) {
+ /* Pretend it was delivered and acknowledged. If
+ * it was spurious due to slave_pic->imr, then
+ * as soon as the mask is cleared, the slave will
+ * re-trigger IRQ2 on the master. If it is spurious for
+ * some other reason, make sure we don't keep trying
+ * to half-process the same spurious interrupt over
+ * and over again.
+ */
+ s->irr &= ~(1<<irq);
+ s->last_irr &= ~(1<<irq);
+ s->isr &= ~(1<<irq);
+ return -1;
+ }
irq2 = 7;
}
intno = slave_pic->irq_base + irq2;
@@ -202,6 +217,9 @@ int pic_read_irq(DeviceState *d)
pic_intack(s, irq);
} else {
/* spurious IRQ on host controller */
+ if (no_spurious_interrupt_hack) {
+ return -1;
+ }
irq = 7;
intno = s->irq_base + irq;
}
diff --git a/qemu-options.hx b/qemu-options.hx
index 0682338e9f..2a6d829551 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -1189,6 +1189,18 @@ Windows 2000 is installed, you no longer need this option (this option
slows down the IDE transfers).
ETEXI
+DEF("no-spurious-interrupt-hack", 0, QEMU_OPTION_no_spurious_interrupt_hack,
+ "-no-spurious-interrupt-hack disable delivery of spurious interrupts\n",
+ QEMU_ARCH_I386)
+STEXI
+@item -no-spurious-interrupt-hack
+@findex -no-spurious-interrupt-hack
+Use it as a workaround for operating systems that drive PICs in a way that
+can generate spurious interrupts, but the OS doesn't handle spurious
+interrupts gracefully. (e.g. late 80s/early 90s versions of ATT UNIX
+and derivatives)
+ETEXI
+
HXCOMM Deprecated by -rtc
DEF("rtc-td-hack", 0, QEMU_OPTION_rtc_td_hack, "", QEMU_ARCH_I386)
diff --git a/sysemu.h b/sysemu.h
index 65552acee5..0170109e12 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -117,6 +117,7 @@ extern int graphic_depth;
extern DisplayType display_type;
extern const char *keyboard_layout;
extern int win2k_install_hack;
+extern int no_spurious_interrupt_hack;
extern int alt_grab;
extern int ctrl_grab;
extern int usb_enabled;
diff --git a/vl.c b/vl.c
index 16d04a2ee2..6de41c124d 100644
--- a/vl.c
+++ b/vl.c
@@ -204,6 +204,7 @@ CharDriverState *serial_hds[MAX_SERIAL_PORTS];
CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
int win2k_install_hack = 0;
+int no_spurious_interrupt_hack = 0;
int usb_enabled = 0;
int singlestep = 0;
int smp_cpus = 1;
@@ -3046,6 +3047,9 @@ int main(int argc, char **argv, char **envp)
case QEMU_OPTION_win2k_hack:
win2k_install_hack = 1;
break;
+ case QEMU_OPTION_no_spurious_interrupt_hack:
+ no_spurious_interrupt_hack = 1;
+ break;
case QEMU_OPTION_rtc_td_hack: {
static GlobalProperty slew_lost_ticks[] = {
{