Add tests for fundamental behaviors of the IOAPIC: Edge & level triggered interrupts Level triggered interrupt coalescing Level triggered EOIs Interrupt masking Passes with most recent version of KVM on Intel x86. Signed-off-by: Steve Rutherford <srutherford@xxxxxxxxxx> --- config/config-x86_64.mak | 4 +- x86/ioapic.c | 186 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 181 insertions(+), 9 deletions(-) diff --git a/config/config-x86_64.mak b/config/config-x86_64.mak index dfdeed6..7d4eb34 100644 --- a/config/config-x86_64.mak +++ b/config/config-x86_64.mak @@ -6,10 +6,10 @@ CFLAGS += -mno-red-zone tests = $(TEST_DIR)/access.flat $(TEST_DIR)/apic.flat \ $(TEST_DIR)/emulator.flat $(TEST_DIR)/idt_test.flat \ $(TEST_DIR)/xsave.flat $(TEST_DIR)/rmap_chain.flat \ - $(TEST_DIR)/pcid.flat $(TEST_DIR)/debug.flat + $(TEST_DIR)/pcid.flat $(TEST_DIR)/debug.flat \ + $(TEST_DIR)/ioapic.flat tests += $(TEST_DIR)/svm.flat tests += $(TEST_DIR)/vmx.flat tests += $(TEST_DIR)/tscdeadline_latency.flat -tests += $(TEST_DIR)/ioapic.flat include config/config-x86-common.mak diff --git a/x86/ioapic.c b/x86/ioapic.c index 2afdaa2..1fcf67e 100644 --- a/x86/ioapic.c +++ b/x86/ioapic.c @@ -30,21 +30,87 @@ static void toggle_irq_line(unsigned line) set_irq_line(line, 0); } +static void ioapic_reg_version(void) +{ + u8 version_offset; + uint32_t data_read, data_write; + + version_offset = 0x01; + data_read = ioapic_read_reg(version_offset); + data_write = data_read ^ 0xffffffff; + + ioapic_write_reg(version_offset, data_write); + report("version register read only test", + data_read == ioapic_read_reg(version_offset)); +} + +static void ioapic_reg_id(void) +{ + u8 id_offset; + uint32_t data_read, data_write, diff; + + id_offset = 0x0; + data_read = ioapic_read_reg(id_offset); + data_write = data_read ^ 0xffffffff; + + ioapic_write_reg(id_offset, data_write); + + diff = data_read ^ ioapic_read_reg(id_offset); + report("id register only bits [24:27] writable", + diff == 0x0f000000); +} + +static void ioapic_arbitration_id(void) +{ + u8 id_offset, arb_offset; + uint32_t write; + + id_offset = 0x0; + arb_offset = 0x2; + write = 0x0f000000; + + ioapic_write_reg(id_offset, write); + report("arbitration register set by id", + ioapic_read_reg(arb_offset) == write); + + ioapic_write_reg(arb_offset, 0x0); + report("arbtration register read only", + ioapic_read_reg(arb_offset) == write); +} + +static volatile int g_isr_76; + +static void ioapic_isr_76(isr_regs_t *regs) +{ + ++g_isr_76; + eoi(); +} + +static void test_ioapic_edge_intr(void) +{ + handle_irq(0x76, ioapic_isr_76); + set_ioapic_redir(0x0e, 0x76, EDGE_TRIGGERED); + toggle_irq_line(0x0e); + asm volatile ("nop"); + report("edge triggered intr", g_isr_76 == 1); +} + static volatile int g_isr_77; static void ioapic_isr_77(isr_regs_t *regs) { ++g_isr_77; + set_irq_line(0x0e, 0); eoi(); } -static void test_ioapic_intr(void) +static void test_ioapic_level_intr(void) { handle_irq(0x77, ioapic_isr_77); - set_ioapic_redir(0x0e, 0x77, EDGE_TRIGGERED); - toggle_irq_line(0x0e); + set_ioapic_redir(0x0e, 0x77, LEVEL_TRIGGERED); + set_irq_line(0x0e, 1); asm volatile ("nop"); - report("ioapic interrupt", g_isr_77 == 1); + report("level triggered intr", g_isr_77 == 1); } static int g_78, g_66, g_66_after_78; @@ -77,10 +143,106 @@ static void test_ioapic_simultaneous(void) toggle_irq_line(0x0e); irq_enable(); asm volatile ("nop"); - report("ioapic simultaneous interrupt", - g_66 && g_78 && g_66_after_78 && g_66_rip == g_78_rip); + report("ioapic simultaneous edge interrupts", + g_66 && g_78 && g_66_after_78 && g_66_rip == g_78_rip); } +static int g_isr_98; + +static void ioapic_isr_98(isr_regs_t *regs) +{ + ++g_isr_98; + if (g_isr_98 == 1) { + set_irq_line(0x0e, 0); + set_irq_line(0x0e, 1); + } + set_irq_line(0x0e, 0); + eoi(); +} + +static void test_ioapic_level_coalesce(void) +{ + handle_irq(0x98, ioapic_isr_98); + set_ioapic_redir(0x0e, 0x98, LEVEL_TRIGGERED); + set_irq_line(0x0e, 1); + asm volatile ("nop"); + report("coalesce simultaneous level interrupts", g_isr_98 == 1); +} + +static int g_isr_99; + +static void ioapic_isr_99(isr_regs_t *regs) +{ + ++g_isr_99; + set_irq_line(0x0e, 0); + eoi(); +} + +static void test_ioapic_level_sequential(void) +{ + handle_irq(0x99, ioapic_isr_99); + set_ioapic_redir(0x0e, 0x99, LEVEL_TRIGGERED); + set_irq_line(0x0e, 1); + set_irq_line(0x0e, 1); + asm volatile ("nop"); + report("sequential level interrupts", g_isr_99 == 2); +} + +static volatile int g_isr_81; + +static void ioapic_isr_81(isr_regs_t *regs) +{ + ++g_isr_81; + set_irq_line(0x0e, 0); + eoi(); +} + +static void test_ioapic_edge_mask(void) +{ + handle_irq(0x81, ioapic_isr_81); + set_ioapic_redir(0x0e, 0x81, EDGE_TRIGGERED); + + set_mask(0x0e, true); + set_irq_line(0x0e, 1); + set_irq_line(0x0e, 0); + + asm volatile ("nop"); + report("masked level interrupt", g_isr_81 == 0); + + set_mask(0x0e, false); + set_irq_line(0x0e, 1); + + asm volatile ("nop"); + report("unmasked level interrupt", g_isr_81 == 1); +} + +static volatile int g_isr_82; + +static void ioapic_isr_82(isr_regs_t *regs) +{ + ++g_isr_82; + set_irq_line(0x0e, 0); + eoi(); +} + +static void test_ioapic_level_mask(void) +{ + handle_irq(0x82, ioapic_isr_82); + set_ioapic_redir(0x0e, 0x82, LEVEL_TRIGGERED); + + set_mask(0x0e, true); + set_irq_line(0x0e, 1); + + asm volatile ("nop"); + report("masked level interrupt", g_isr_82 == 0); + + set_mask(0x0e, false); + + asm volatile ("nop"); + report("unmasked level interrupt", g_isr_82 == 1); +} + + int main(void) { setup_vm(); @@ -92,8 +254,18 @@ int main(void) irq_enable(); - test_ioapic_intr(); + ioapic_reg_version(); + ioapic_reg_id(); + ioapic_arbitration_id(); + + test_ioapic_edge_intr(); + test_ioapic_level_intr(); test_ioapic_simultaneous(); + test_ioapic_level_coalesce(); + test_ioapic_level_sequential(); + + test_ioapic_edge_mask(); + test_ioapic_level_mask(); return report_summary(); } -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html