8 typedef unsigned char u8
;
9 typedef unsigned short u16
;
11 typedef unsigned long ulong
;
14 unsigned short offset0
;
15 unsigned short selector
;
16 unsigned short ist
: 3;
18 unsigned short type
: 4;
20 unsigned short dpl
: 2;
22 unsigned short offset1
;
34 ulong regs
[sizeof(ulong
)*2];
43 extern char isr_entry_point
[];
67 "callq *8*16(%rsp) \n\t"
70 "calll *4+4*8(%esp) \n\t"
100 static idt_entry_t idt
[256];
105 static void report(const char *msg
, int pass
)
108 printf("%s: %s\n", msg
, (pass
? "PASS" : "FAIL"));
113 static u32
apic_read(unsigned reg
)
115 return *(volatile u32
*)(g_apic
+ reg
);
118 static void apic_write(unsigned reg
, u32 val
)
120 *(volatile u32
*)(g_apic
+ reg
) = val
;
123 static void test_lapic_existence(void)
127 lvr
= apic_read(APIC_LVR
);
128 printf("apic version: %x\n", lvr
);
129 report("apic existence", (u16
)lvr
== 0x14);
132 static u16
read_cs(void)
136 asm("mov %%cs, %0" : "=rm"(v
));
140 static void init_idt(void)
145 } __attribute__((packed
)) idt_ptr
= {
146 sizeof(idt_entry_t
) * 256 - 1,
150 asm volatile("lidt %0" : : "m"(idt_ptr
));
153 static void set_idt_entry(unsigned vec
, void (*func
)(isr_regs_t
*regs
))
155 u8
*thunk
= vmalloc(50);
156 ulong ptr
= (ulong
)thunk
;
159 .selector
= read_cs(),
164 .offset1
= ptr
>> 16,
166 .offset2
= ptr
>> 32,
171 *thunk
++ = 0x48; *thunk
++ = 0x83; *thunk
++ = 0xec; *thunk
++ = 0x08;
172 /* mov $func_low, %(rsp) */
173 *thunk
++ = 0xc7; *thunk
++ = 0x04; *thunk
++ = 0x24;
174 *(u32
*)thunk
= (ulong
)func
; thunk
+= 4;
175 /* mov $func_high, %(rsp+4) */
176 *thunk
++ = 0xc7; *thunk
++ = 0x44; *thunk
++ = 0x24; *thunk
++ = 0x04;
177 *(u32
*)thunk
= (ulong
)func
>> 32; thunk
+= 4;
178 /* jmp isr_entry_point */
180 *(u32
*)thunk
= (ulong
)isr_entry_point
- (ulong
)(thunk
+ 4);
184 *(u32
*)thunk
= (ulong
)func
;
185 /* jmp isr_entry_point */
187 *(u32
*)thunk
= (ulong
)isr_entry_point
- (ulong
)(thunk
+ 4);
192 static void irq_disable(void)
197 static void irq_enable(void)
202 static void eoi(void)
204 apic_write(APIC_EOI
, 0);
207 static int ipi_count
;
209 static void self_ipi_isr(isr_regs_t
*regs
)
215 static void test_self_ipi(void)
219 set_idt_entry(vec
, self_ipi_isr
);
222 APIC_DEST_SELF
| APIC_DEST_PHYSICAL
| APIC_DM_FIXED
| vec
);
223 asm volatile ("nop");
224 report("self ipi", ipi_count
== 1);
227 static void ioapic_write_reg(unsigned reg
, u32 value
)
229 *(volatile u32
*)g_ioapic
= reg
;
230 *(volatile u32
*)(g_ioapic
+ 0x10) = value
;
237 u8 delivery_status
:1;
245 } ioapic_redir_entry_t
;
247 static void ioapic_write_redir(unsigned line
, ioapic_redir_entry_t e
)
249 ioapic_write_reg(0x10 + line
* 2 + 0, ((u32
*)&e
)[0]);
250 ioapic_write_reg(0x10 + line
* 2 + 1, ((u32
*)&e
)[1]);
253 static void set_ioapic_redir(unsigned line
, unsigned vec
)
255 ioapic_redir_entry_t e
= {
261 ioapic_write_redir(line
, e
);
264 static void set_irq_line(unsigned line
, int val
)
266 asm volatile("out %0, %1" : : "a"((u8
)val
), "d"((u16
)(0x2000 + line
)));
269 static void toggle_irq_line(unsigned line
)
271 set_irq_line(line
, 1);
272 set_irq_line(line
, 0);
277 static void ioapic_isr_77(isr_regs_t
*regs
)
283 static void test_ioapic_intr(void)
285 set_idt_entry(0x77, ioapic_isr_77
);
286 set_ioapic_redir(0x10, 0x77);
287 toggle_irq_line(0x10);
288 asm volatile ("nop");
289 report("ioapic interrupt", g_isr_77
== 1);
292 static int g_78
, g_66
, g_66_after_78
;
293 static ulong g_66_rip
, g_78_rip
;
295 static void ioapic_isr_78(isr_regs_t
*regs
)
298 g_78_rip
= regs
->rip
;
302 static void ioapic_isr_66(isr_regs_t
*regs
)
307 g_66_rip
= regs
->rip
;
311 static void test_ioapic_simultaneous(void)
313 set_idt_entry(0x78, ioapic_isr_78
);
314 set_idt_entry(0x66, ioapic_isr_66
);
315 set_ioapic_redir(0x10, 0x78);
316 set_ioapic_redir(0x11, 0x66);
318 toggle_irq_line(0x11);
319 toggle_irq_line(0x10);
321 asm volatile ("nop");
322 report("ioapic simultaneous interrupt",
323 g_66
&& g_78
&& g_66_after_78
&& g_66_rip
== g_78_rip
);
326 static void enable_apic(void)
328 apic_write(0xf0, 0x1ff); /* spurious vector register */
335 g_apic
= vmap(0xfee00000, 0x1000);
336 g_ioapic
= vmap(0xfec00000, 0x1000);
338 test_lapic_existence();
346 test_ioapic_simultaneous();
348 printf("\nsummary: %d tests, %d failures\n", g_tests
, g_fail
);