123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438 |
- #include "libcflat.h"
- #include "apic.h"
- #include "vm.h"
- #include "smp.h"
- #include "desc.h"
- #include "isr.h"
- static void set_ioapic_redir(unsigned line, unsigned vec,
- trigger_mode_t 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 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, TRIGGER_EDGE);
- 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_level_intr(void)
- {
- handle_irq(0x77, ioapic_isr_77);
- set_ioapic_redir(0x0e, 0x77, TRIGGER_LEVEL);
- set_irq_line(0x0e, 1);
- asm volatile ("nop");
- report("level triggered intr", 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, TRIGGER_EDGE);
- set_ioapic_redir(0x0f, 0x66, TRIGGER_EDGE);
- irq_disable();
- toggle_irq_line(0x0f);
- toggle_irq_line(0x0e);
- irq_enable();
- asm volatile ("nop");
- report("ioapic simultaneous edge interrupts",
- g_66 && g_78 && g_66_after_78 && g_66_rip == g_78_rip);
- }
- static volatile int g_tmr_79 = -1;
- static void ioapic_isr_79(isr_regs_t *regs)
- {
- g_tmr_79 = apic_read_bit(APIC_TMR, 0x79);
- set_irq_line(0x0e, 0);
- eoi();
- }
- static void test_ioapic_edge_tmr(bool expected_tmr_before)
- {
- int tmr_before;
- handle_irq(0x79, ioapic_isr_79);
- set_ioapic_redir(0x0e, 0x79, TRIGGER_EDGE);
- tmr_before = apic_read_bit(APIC_TMR, 0x79);
- toggle_irq_line(0x0e);
- asm volatile ("nop");
- report("TMR for ioapic edge interrupts (expected %s)",
- tmr_before == expected_tmr_before && !g_tmr_79,
- expected_tmr_before ? "true" : "false");
- }
- static void test_ioapic_level_tmr(bool expected_tmr_before)
- {
- int tmr_before;
- handle_irq(0x79, ioapic_isr_79);
- set_ioapic_redir(0x0e, 0x79, TRIGGER_LEVEL);
- tmr_before = apic_read_bit(APIC_TMR, 0x79);
- set_irq_line(0x0e, 1);
- asm volatile ("nop");
- report("TMR for ioapic level interrupts (expected %s)",
- tmr_before == expected_tmr_before && g_tmr_79,
- expected_tmr_before ? "true" : "false");
- }
- #define IPI_DELAY 1000000
- static void delay(int count)
- {
- while(count--) asm("");
- }
- static void toggle_irq_line_0x0e(void *data)
- {
- irq_disable();
- delay(IPI_DELAY);
- toggle_irq_line(0x0e);
- irq_enable();
- }
- static void test_ioapic_edge_tmr_smp(bool expected_tmr_before)
- {
- int tmr_before;
- int i;
- g_tmr_79 = -1;
- handle_irq(0x79, ioapic_isr_79);
- set_ioapic_redir(0x0e, 0x79, TRIGGER_EDGE);
- tmr_before = apic_read_bit(APIC_TMR, 0x79);
- on_cpu_async(1, toggle_irq_line_0x0e, 0);
- i = 0;
- while(g_tmr_79 == -1) i++;
- printf("%d iterations before interrupt received\n", i);
- report("TMR for ioapic edge interrupts (expected %s)",
- tmr_before == expected_tmr_before && !g_tmr_79,
- expected_tmr_before ? "true" : "false");
- }
- static void set_irq_line_0x0e(void *data)
- {
- irq_disable();
- delay(IPI_DELAY);
- set_irq_line(0x0e, 1);
- irq_enable();
- }
- static void test_ioapic_level_tmr_smp(bool expected_tmr_before)
- {
- int i, tmr_before;
- g_tmr_79 = -1;
- handle_irq(0x79, ioapic_isr_79);
- set_ioapic_redir(0x0e, 0x79, TRIGGER_LEVEL);
- tmr_before = apic_read_bit(APIC_TMR, 0x79);
- on_cpu_async(1, set_irq_line_0x0e, 0);
- i = 0;
- while(g_tmr_79 == -1) i++;
- printf("%d iterations before interrupt received\n", i);
- report("TMR for ioapic level interrupts (expected %s)",
- tmr_before == expected_tmr_before && g_tmr_79,
- expected_tmr_before ? "true" : "false");
- }
- 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, TRIGGER_LEVEL);
- 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, TRIGGER_LEVEL);
- 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_9a;
- static void ioapic_isr_9a(isr_regs_t *regs)
- {
- ++g_isr_9a;
- if (g_isr_9a == 2)
- set_irq_line(0x0e, 0);
- eoi();
- }
- static void test_ioapic_level_retrigger(void)
- {
- int i;
- handle_irq(0x9a, ioapic_isr_9a);
- set_ioapic_redir(0x0e, 0x9a, TRIGGER_LEVEL);
- asm volatile ("cli");
- set_irq_line(0x0e, 1);
- for (i = 0; i < 10; i++) {
- if (g_isr_9a == 2)
- break;
- asm volatile ("sti; hlt; cli");
- }
- asm volatile ("sti");
- report("retriggered level interrupts without masking", g_isr_9a == 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, TRIGGER_EDGE);
- 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, TRIGGER_LEVEL);
- 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);
- }
- static volatile int g_isr_83;
- static void ioapic_isr_83(isr_regs_t *regs)
- {
- ++g_isr_83;
- set_mask(0x0e, true);
- eoi();
- }
- static void test_ioapic_level_retrigger_mask(void)
- {
- handle_irq(0x83, ioapic_isr_83);
- set_ioapic_redir(0x0e, 0x83, TRIGGER_LEVEL);
- set_irq_line(0x0e, 1);
- asm volatile ("nop");
- set_mask(0x0e, false);
- asm volatile ("nop");
- report("retriggered level interrupts with mask", g_isr_83 == 2);
- set_irq_line(0x0e, 0);
- set_mask(0x0e, false);
- }
- int main(void)
- {
- setup_vm();
- smp_init();
- mask_pic_interrupts();
- if (enable_x2apic())
- printf("x2apic enabled\n");
- else
- printf("x2apic not detected\n");
- irq_enable();
- 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_level_retrigger();
- test_ioapic_edge_mask();
- test_ioapic_level_mask();
- test_ioapic_level_retrigger_mask();
- test_ioapic_edge_tmr(false);
- test_ioapic_level_tmr(false);
- test_ioapic_level_tmr(true);
- test_ioapic_edge_tmr(true);
- if (cpu_count() > 1) {
- test_ioapic_edge_tmr_smp(false);
- test_ioapic_level_tmr_smp(false);
- test_ioapic_level_tmr_smp(true);
- test_ioapic_edge_tmr_smp(true);
- }
- return report_summary();
- }
|