Microport UNIX System V/386 v2.1 (ca. 1987) does something similar to the slave_imr() test, and doesn't run if the "canceling" behavior of IRQ2 doesn't work.
I don't know anything that depends on the canceling behavior of other interrupts (master_basic() or slave_basic() tests), but it seems best to fix the issue generically if possible. Signed-off-by: Matthew Ogilvie <mmogilvi_q...@miniinfo.net> --- tests/Makefile | 2 + tests/pic-test.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 tests/pic-test.c diff --git a/tests/Makefile b/tests/Makefile index b60f0fb..d21b0d5 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -25,6 +25,7 @@ check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh check-qtest-i386-y = tests/fdc-test$(EXESUF) check-qtest-i386-y += tests/hd-geo-test$(EXESUF) check-qtest-i386-y += tests/rtc-test$(EXESUF) +check-qtest-i386-y += tests/pic-test$(EXESUF) check-qtest-x86_64-y = $(check-qtest-i386-y) check-qtest-sparc-y = tests/m48t59-test$(EXESUF) check-qtest-sparc64-y = tests/m48t59-test$(EXESUF) @@ -75,6 +76,7 @@ tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marsh tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y) +tests/pic-test$(EXESUF): tests/pic-test.o $(trace-obj-y) tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y) tests/fdc-test$(EXESUF): tests/fdc-test.o tests/libqtest.o $(trace-obj-y) tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/libqtest.o $(trace-obj-y) diff --git a/tests/pic-test.c b/tests/pic-test.c new file mode 100644 index 0000000..57b8bee --- /dev/null +++ b/tests/pic-test.c @@ -0,0 +1,127 @@ +/* + * QTest testcase for the 8259 interrupt controller + * + * Copyright (c) 2012 Matthew Ogilvie + * + * Authors: + * Matthew Ogilvie <mmogilvi_q...@miniinfo.net> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ +#include "libqtest.h" + +#include <glib.h> + +static void init_i8259(void) +{ + /* master: */ + outb(0x20,0x13); /* ICW1: edge-triggered, multiple 8259s, ICW4 needed */ + outb(0x21,0x08); /* ICW2: map to int08-int0f */ + outb(0x21,0x04); /* ICW3: IR2 connected to slave */ + outb(0x21,0x01); /* ICW4: not-SFNM, not-buffered, manual EOI, 8086 mode */ + + outb(0x21,0xfa); /* OCW1/IMR: mask off all except IRQ2 and IRQ0 */ + + /* slave: */ + outb(0xa0,0x13); /* ICW1: edge-triggered, multiple 8259s, ICW4 needed */ + outb(0xa1,0x70); /* ICW2: map to int70-int77 */ + outb(0xa1,0x02); /* ICW3: connected to master IR2 */ + outb(0xa1,0x01); /* ICW4: not-SFNM, not-buffered, manual EOI, 8086 mode */ + + outb(0xa1,0x3f); /* OCW1/IMR: mask off all except IRQ14 and IRQ15 */ +} + +static void set_irq(int num, int level) +{ + if(num > 8) { + set_irq_in("i8259-slave", num - 8, level); + } else { + set_irq_in("i8259-master", num, level); + } +} + +static void slave_imr(void) +{ + init_i8259(); + + g_assert_cmpint(get_irq(0), ==, 0); + set_irq(14, 1); + g_assert_cmpint(get_irq(0), ==, 1); + + outb(0xa1,0xff); /* OCW1/IMR: mask off all slave IRQs */ + g_assert_cmpint(get_irq(0), ==, 0); + + outb(0xa0,0x0a); /* slave OCW3: read IRR */ + g_assert_cmpint(inb(0xa0)&0x40, ==, 0x40); /* IRR still has IRQ14 */ + outb(0x20,0x0a); /* master OCW3: read IRR */ + g_assert_cmpint(inb(0x20)&0x04, ==, 0x00); /* IRR does not have IRQ2 */ + + outb(0xa1,0x3f); /* OCW1/IMR: unmask IRQ14 and IRQ15 */ + g_assert_cmpint(get_irq(0), ==, 1); + + outb(0xa0,0x0a); /* slave OCW3: read IRR */ + g_assert_cmpint(inb(0xa0)&0x40, ==, 0x40); /* IRR has IRQ14 */ + outb(0x20,0x0a); /* master OCW3: read IRR */ + g_assert_cmpint(inb(0x20)&0x04, ==, 0x04); /* IRR has IRQ2 */ +} + +static void master_cancel(void) +{ + init_i8259(); + + g_assert_cmpint(get_irq(0), ==, 0); + set_irq(0, 1); + g_assert_cmpint(get_irq(0), ==, 1); + set_irq(0, 0); + g_assert_cmpint(get_irq(0), ==, 0); +} + +static void slave_cancel(void) +{ + init_i8259(); + + g_assert_cmpint(get_irq(0), ==, 0); + set_irq(14, 1); + g_assert_cmpint(get_irq(0), ==, 1); + set_irq(14, 0); + g_assert_cmpint(get_irq(0), ==, 0); +} + +int main(int argc, char **argv) +{ + QTestState *s = NULL; + int ret; + + g_test_init(&argc, &argv, NULL); + + s = qtest_start(/*"-qtest-log /dev/tty "*/ "-display none"); + qtest_irq_intercept_out(s, "i8259-master"); + + /* FUTURE: Before testing obscure cases, first test basic + * interrupt delivery to the CPU and EOI functionality. + * But that requires some kind of abstracted hook into + * cpu_get_pic_interrupt() vs other architecture equivalents, + * and the abstraction doesn't currently exist. + */ + + /* I know of at least one (admittedly obscure) guest that depends + * slave_imr() working. (Microport UNIX System V/386 v2.1 (ca. 1987)) + */ + qtest_add_func("/pic/slave-imr", slave_imr); + + /* I don't know any guest that depends on these, but a generic fix + * for slave_imr() issue also fixes these: + */ + qtest_add_func("/pic/master-cancel", master_cancel); + qtest_add_func("/pic/slave-cancel", slave_cancel); + + ret = g_test_run(); + + if (s) { + qtest_quit(s); + } + + return ret; +} -- 1.7.10.2.484.gcd07cc5