Split apart the APIC tests into constituent parts (IOAPIC and APIC tests). Signed-off-by: Steve Rutherford <srutherford@xxxxxxxxxx> --- config/config-x86-common.mak | 2 + config/config-x86_64.mak | 1 + lib/x86/apic.c | 29 +++++++++++++ lib/x86/apic.h | 6 +++ x86/apic.c | 80 ----------------------------------- x86/eventinj.c | 5 --- x86/ioapic.c | 99 ++++++++++++++++++++++++++++++++++++++++++++ x86/unittests.cfg | 5 +++ 8 files changed, 142 insertions(+), 85 deletions(-) create mode 100644 x86/ioapic.c diff --git a/config/config-x86-common.mak b/config/config-x86-common.mak index 8fc3490..d45c9a8 100644 --- a/config/config-x86-common.mak +++ b/config/config-x86-common.mak @@ -69,6 +69,8 @@ $(TEST_DIR)/tsc_adjust.elf: $(cstart.o) $(TEST_DIR)/tsc_adjust.o $(TEST_DIR)/apic.elf: $(cstart.o) $(TEST_DIR)/apic.o +$(TEST_DIR)/ioapic.elf: $(cstart.o) $(TEST_DIR)/ioapic.o + $(TEST_DIR)/tscdeadline_latency.elf: $(cstart.o) $(TEST_DIR)/tscdeadline_latency.o $(TEST_DIR)/init.elf: $(cstart.o) $(TEST_DIR)/init.o diff --git a/config/config-x86_64.mak b/config/config-x86_64.mak index d62c1e9..dfdeed6 100644 --- a/config/config-x86_64.mak +++ b/config/config-x86_64.mak @@ -10,5 +10,6 @@ tests = $(TEST_DIR)/access.flat $(TEST_DIR)/apic.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/lib/x86/apic.c b/lib/x86/apic.c index 9c42c4d..80b96d8 100644 --- a/lib/x86/apic.c +++ b/lib/x86/apic.c @@ -17,6 +17,11 @@ static void outb(unsigned char data, unsigned short port) asm volatile ("out %0, %1" : : "a"(data), "d"(port)); } +void eoi(void) +{ + apic_write(APIC_EOI, 0); +} + static u32 xapic_read(unsigned reg) { return *(volatile u32 *)(g_apic + reg); @@ -117,6 +122,12 @@ int enable_x2apic(void) } } +u32 ioapic_read_reg(unsigned reg) +{ + *(volatile u32 *)g_ioapic = reg; + return *(volatile u32 *)(g_ioapic + 0x10); +} + void ioapic_write_reg(unsigned reg, u32 value) { *(volatile u32 *)g_ioapic = reg; @@ -129,6 +140,24 @@ void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e) ioapic_write_reg(0x10 + line * 2 + 1, ((u32 *)&e)[1]); } +ioapic_redir_entry_t ioapic_read_redir(unsigned line) +{ + ioapic_redir_entry_t e; + + ((u32 *)&e)[0] = ioapic_read_reg(0x10 + line * 2 + 0); + ((u32 *)&e)[1] = ioapic_read_reg(0x10 + line * 2 + 1); + return e; + +} + +void set_mask(unsigned line, int mask) +{ + ioapic_redir_entry_t e = ioapic_read_redir(line); + + e.mask = mask; + ioapic_write_redir(line, e); +} + void enable_apic(void) { printf("enabling apic\n"); diff --git a/lib/x86/apic.h b/lib/x86/apic.h index e325e9a..216b98d 100644 --- a/lib/x86/apic.h +++ b/lib/x86/apic.h @@ -20,8 +20,14 @@ typedef struct { void mask_pic_interrupts(void); +void eoi(void); + void ioapic_write_redir(unsigned line, ioapic_redir_entry_t e); void ioapic_write_reg(unsigned reg, uint32_t value); +ioapic_redir_entry_t ioapic_read_redir(unsigned line); +uint32_t ioapic_read_reg(unsigned reg); + +void set_mask(unsigned line, int mask); void enable_apic(void); uint32_t apic_read(unsigned reg); diff --git a/x86/apic.c b/x86/apic.c index 365c281..d4eec52 100644 --- a/x86/apic.c +++ b/x86/apic.c @@ -140,11 +140,6 @@ static void test_apicbase(void) report_prefix_pop(); } -static void eoi(void) -{ - apic_write(APIC_EOI, 0); -} - static int ipi_count; static void self_ipi_isr(isr_regs_t *regs) @@ -165,79 +160,6 @@ static void test_self_ipi(void) report("self ipi", ipi_count == 1); } -static void set_ioapic_redir(unsigned line, unsigned vec) -{ - ioapic_redir_entry_t e = { - .vector = vec, - .delivery_mode = 0, - .trig_mode = 0, - }; - - ioapic_write_redir(line, e); -} - -static void set_irq_line(unsigned line, int val) -{ - asm volatile("out %0, %1" : : "a"((u8)val), "d"((u16)(0x2000 + line))); -} - -static void toggle_irq_line(unsigned line) -{ - set_irq_line(line, 1); - set_irq_line(line, 0); -} - -static int g_isr_77; - -static void ioapic_isr_77(isr_regs_t *regs) -{ - ++g_isr_77; - eoi(); -} - -static void test_ioapic_intr(void) -{ - handle_irq(0x77, ioapic_isr_77); - set_ioapic_redir(0x0e, 0x77); - toggle_irq_line(0x0e); - asm volatile ("nop"); - report("ioapic interrupt", g_isr_77 == 1); -} - -static int g_78, g_66, g_66_after_78; -static ulong g_66_rip, g_78_rip; - -static void ioapic_isr_78(isr_regs_t *regs) -{ - ++g_78; - g_78_rip = regs->rip; - eoi(); -} - -static void ioapic_isr_66(isr_regs_t *regs) -{ - ++g_66; - if (g_78) - ++g_66_after_78; - g_66_rip = regs->rip; - eoi(); -} - -static void test_ioapic_simultaneous(void) -{ - handle_irq(0x78, ioapic_isr_78); - handle_irq(0x66, ioapic_isr_66); - set_ioapic_redir(0x0e, 0x78); - set_ioapic_redir(0x0f, 0x66); - irq_disable(); - toggle_irq_line(0x0f); - 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); -} - volatile int nmi_counter_private, nmi_counter, nmi_hlt_counter, sti_loop_active; void sti_nop(char *p) @@ -390,8 +312,6 @@ int main() test_self_ipi(); - test_ioapic_intr(); - test_ioapic_simultaneous(); test_sti_nmi(); test_multiple_nmi(); diff --git a/x86/eventinj.c b/x86/eventinj.c index 32de6f0..bddedce 100644 --- a/x86/eventinj.c +++ b/x86/eventinj.c @@ -32,11 +32,6 @@ void apic_self_nmi(void) apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0); } -static void eoi(void) -{ - apic_write(APIC_EOI, 0); -} - #define flush_phys_addr(__s) outl(0xe4, __s) #define flush_stack() do { \ int __l; \ diff --git a/x86/ioapic.c b/x86/ioapic.c new file mode 100644 index 0000000..2afdaa2 --- /dev/null +++ b/x86/ioapic.c @@ -0,0 +1,99 @@ +#include "libcflat.h" +#include "apic.h" +#include "vm.h" +#include "smp.h" +#include "desc.h" +#include "isr.h" + +#define EDGE_TRIGGERED 0 +#define LEVEL_TRIGGERED 1 + +static void set_ioapic_redir(unsigned line, unsigned vec, unsigned trig_mode) +{ + ioapic_redir_entry_t e = { + .vector = vec, + .delivery_mode = 0, + .trig_mode = trig_mode, + }; + + ioapic_write_redir(line, e); +} + +static void set_irq_line(unsigned line, int val) +{ + asm volatile("out %0, %1" : : "a"((u8)val), "d"((u16)(0x2000 + line))); +} + +static void toggle_irq_line(unsigned line) +{ + set_irq_line(line, 1); + set_irq_line(line, 0); +} + +static volatile int g_isr_77; + +static void ioapic_isr_77(isr_regs_t *regs) +{ + ++g_isr_77; + eoi(); +} + +static void test_ioapic_intr(void) +{ + handle_irq(0x77, ioapic_isr_77); + set_ioapic_redir(0x0e, 0x77, EDGE_TRIGGERED); + toggle_irq_line(0x0e); + asm volatile ("nop"); + report("ioapic interrupt", g_isr_77 == 1); +} + +static int g_78, g_66, g_66_after_78; +static ulong g_66_rip, g_78_rip; + +static void ioapic_isr_78(isr_regs_t *regs) +{ + ++g_78; + g_78_rip = regs->rip; + eoi(); +} + +static void ioapic_isr_66(isr_regs_t *regs) +{ + ++g_66; + if (g_78) + ++g_66_after_78; + g_66_rip = regs->rip; + eoi(); +} + +static void test_ioapic_simultaneous(void) +{ + handle_irq(0x78, ioapic_isr_78); + handle_irq(0x66, ioapic_isr_66); + set_ioapic_redir(0x0e, 0x78, EDGE_TRIGGERED); + set_ioapic_redir(0x0f, 0x66, EDGE_TRIGGERED); + irq_disable(); + toggle_irq_line(0x0f); + 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); +} + +int main(void) +{ + setup_vm(); + smp_init(); + setup_idt(); + + mask_pic_interrupts(); + enable_apic(); + + irq_enable(); + + test_ioapic_intr(); + test_ioapic_simultaneous(); + + return report_summary(); +} diff --git a/x86/unittests.cfg b/x86/unittests.cfg index badb08a..a38544f 100644 --- a/x86/unittests.cfg +++ b/x86/unittests.cfg @@ -12,6 +12,11 @@ smp = 2 extra_params = -cpu qemu64,+x2apic,+tsc-deadline arch = x86_64 +[ioapic] +file = ioapic.flat +extra_params = -cpu qemu64 +arch = x86_64 + [smptest] file = smptest.flat smp = 2 -- 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