From f278d4947fff814dcde2ef2acad36d172ff8be35 Mon Sep 17 00:00:00 2001 From: Matthew Ogilvie Date: Thu, 23 Aug 2012 00:24:43 -0600 Subject: [PATCH] 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 Signed-off-by: malc --- cpu-exec.c | 14 +++++++++----- hw/i8259.c | 18 ++++++++++++++++++ qemu-options.hx | 12 ++++++++++++ sysemu.h | 1 + vl.c | 4 ++++ 5 files changed, 44 insertions(+), 5 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index 134b3c4..625fbb0 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 6587666..7ecb7e1 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<last_irr &= ~(1<isr &= ~(1<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 0682338..2a6d829 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 65552ac..0170109 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 16d04a2..6de41c1 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[] = { { -- 2.7.4