1 #include "libcflat.h" 2 #include "apic.h" 3 #include "vm.h" 4 #include "smp.h" 5 #include "desc.h" 6 #include "isr.h" 7 8 #define EDGE_TRIGGERED 0 9 #define LEVEL_TRIGGERED 1 10 11 static void set_ioapic_redir(unsigned line, unsigned vec, unsigned trig_mode) 12 { 13 ioapic_redir_entry_t e = { 14 .vector = vec, 15 .delivery_mode = 0, 16 .trig_mode = trig_mode, 17 }; 18 19 ioapic_write_redir(line, e); 20 } 21 22 static void set_irq_line(unsigned line, int val) 23 { 24 asm volatile("out %0, %1" : : "a"((u8)val), "d"((u16)(0x2000 + line))); 25 } 26 27 static void toggle_irq_line(unsigned line) 28 { 29 set_irq_line(line, 1); 30 set_irq_line(line, 0); 31 } 32 33 static void ioapic_reg_version(void) 34 { 35 u8 version_offset; 36 uint32_t data_read, data_write; 37 38 version_offset = 0x01; 39 data_read = ioapic_read_reg(version_offset); 40 data_write = data_read ^ 0xffffffff; 41 42 ioapic_write_reg(version_offset, data_write); 43 report("version register read only test", 44 data_read == ioapic_read_reg(version_offset)); 45 } 46 47 static void ioapic_reg_id(void) 48 { 49 u8 id_offset; 50 uint32_t data_read, data_write, diff; 51 52 id_offset = 0x0; 53 data_read = ioapic_read_reg(id_offset); 54 data_write = data_read ^ 0xffffffff; 55 56 ioapic_write_reg(id_offset, data_write); 57 58 diff = data_read ^ ioapic_read_reg(id_offset); 59 report("id register only bits [24:27] writable", 60 diff == 0x0f000000); 61 } 62 63 static void ioapic_arbitration_id(void) 64 { 65 u8 id_offset, arb_offset; 66 uint32_t write; 67 68 id_offset = 0x0; 69 arb_offset = 0x2; 70 write = 0x0f000000; 71 72 ioapic_write_reg(id_offset, write); 73 report("arbitration register set by id", 74 ioapic_read_reg(arb_offset) == write); 75 76 ioapic_write_reg(arb_offset, 0x0); 77 report("arbtration register read only", 78 ioapic_read_reg(arb_offset) == write); 79 } 80 81 static volatile int g_isr_76; 82 83 static void ioapic_isr_76(isr_regs_t *regs) 84 { 85 ++g_isr_76; 86 eoi(); 87 } 88 89 static void test_ioapic_edge_intr(void) 90 { 91 handle_irq(0x76, ioapic_isr_76); 92 set_ioapic_redir(0x0e, 0x76, EDGE_TRIGGERED); 93 toggle_irq_line(0x0e); 94 asm volatile ("nop"); 95 report("edge triggered intr", g_isr_76 == 1); 96 } 97 98 static volatile int g_isr_77; 99 100 static void ioapic_isr_77(isr_regs_t *regs) 101 { 102 ++g_isr_77; 103 set_irq_line(0x0e, 0); 104 eoi(); 105 } 106 107 static void test_ioapic_level_intr(void) 108 { 109 handle_irq(0x77, ioapic_isr_77); 110 set_ioapic_redir(0x0e, 0x77, LEVEL_TRIGGERED); 111 set_irq_line(0x0e, 1); 112 asm volatile ("nop"); 113 report("level triggered intr", g_isr_77 == 1); 114 } 115 116 static int g_78, g_66, g_66_after_78; 117 static ulong g_66_rip, g_78_rip; 118 119 static void ioapic_isr_78(isr_regs_t *regs) 120 { 121 ++g_78; 122 g_78_rip = regs->rip; 123 eoi(); 124 } 125 126 static void ioapic_isr_66(isr_regs_t *regs) 127 { 128 ++g_66; 129 if (g_78) 130 ++g_66_after_78; 131 g_66_rip = regs->rip; 132 eoi(); 133 } 134 135 static void test_ioapic_simultaneous(void) 136 { 137 handle_irq(0x78, ioapic_isr_78); 138 handle_irq(0x66, ioapic_isr_66); 139 set_ioapic_redir(0x0e, 0x78, EDGE_TRIGGERED); 140 set_ioapic_redir(0x0f, 0x66, EDGE_TRIGGERED); 141 irq_disable(); 142 toggle_irq_line(0x0f); 143 toggle_irq_line(0x0e); 144 irq_enable(); 145 asm volatile ("nop"); 146 report("ioapic simultaneous edge interrupts", 147 g_66 && g_78 && g_66_after_78 && g_66_rip == g_78_rip); 148 } 149 150 static int g_tmr_79 = -1; 151 152 static void ioapic_isr_79(isr_regs_t *regs) 153 { 154 g_tmr_79 = apic_read_bit(APIC_TMR, 0x79); 155 eoi(); 156 } 157 158 static void test_ioapic_edge_tmr(void) 159 { 160 int tmr_before; 161 162 handle_irq(0x79, ioapic_isr_79); 163 set_ioapic_redir(0x0e, 0x79, EDGE_TRIGGERED); 164 tmr_before = apic_read_bit(APIC_TMR, 0x79); 165 toggle_irq_line(0x0e); 166 asm volatile ("nop"); 167 report("TMR for ioapic edge interrupts", 168 !tmr_before && !g_tmr_79); 169 } 170 171 static int g_isr_98; 172 173 static void ioapic_isr_98(isr_regs_t *regs) 174 { 175 ++g_isr_98; 176 if (g_isr_98 == 1) { 177 set_irq_line(0x0e, 0); 178 set_irq_line(0x0e, 1); 179 } 180 set_irq_line(0x0e, 0); 181 eoi(); 182 } 183 184 static void test_ioapic_level_coalesce(void) 185 { 186 handle_irq(0x98, ioapic_isr_98); 187 set_ioapic_redir(0x0e, 0x98, LEVEL_TRIGGERED); 188 set_irq_line(0x0e, 1); 189 asm volatile ("nop"); 190 report("coalesce simultaneous level interrupts", g_isr_98 == 1); 191 } 192 193 static int g_isr_99; 194 195 static void ioapic_isr_99(isr_regs_t *regs) 196 { 197 ++g_isr_99; 198 set_irq_line(0x0e, 0); 199 eoi(); 200 } 201 202 static void test_ioapic_level_sequential(void) 203 { 204 handle_irq(0x99, ioapic_isr_99); 205 set_ioapic_redir(0x0e, 0x99, LEVEL_TRIGGERED); 206 set_irq_line(0x0e, 1); 207 set_irq_line(0x0e, 1); 208 asm volatile ("nop"); 209 report("sequential level interrupts", g_isr_99 == 2); 210 } 211 212 static volatile int g_isr_9a; 213 214 static void ioapic_isr_9a(isr_regs_t *regs) 215 { 216 ++g_isr_9a; 217 if (g_isr_9a == 2) 218 set_irq_line(0x0e, 0); 219 eoi(); 220 } 221 222 static void test_ioapic_level_retrigger(void) 223 { 224 int i; 225 226 handle_irq(0x9a, ioapic_isr_9a); 227 set_ioapic_redir(0x0e, 0x9a, LEVEL_TRIGGERED); 228 229 asm volatile ("cli"); 230 set_irq_line(0x0e, 1); 231 232 for (i = 0; i < 10; i++) { 233 if (g_isr_9a == 2) 234 break; 235 236 asm volatile ("sti; hlt; cli"); 237 } 238 239 asm volatile ("sti"); 240 241 report("retriggered level interrupts without masking", g_isr_9a == 2); 242 } 243 244 static int g_tmr_9b = -1; 245 246 static void ioapic_isr_9b(isr_regs_t *regs) 247 { 248 g_tmr_9b = apic_read_bit(APIC_TMR, 0x9b); 249 set_irq_line(0x0e, 0); 250 eoi(); 251 } 252 253 static void test_ioapic_level_tmr(void) 254 { 255 int tmr_before; 256 257 handle_irq(0x9b, ioapic_isr_9b); 258 set_ioapic_redir(0x0e, 0x9b, LEVEL_TRIGGERED); 259 tmr_before = apic_read_bit(APIC_TMR, 0x9b); 260 set_irq_line(0x0e, 1); 261 asm volatile ("nop"); 262 report("TMR for ioapic level interrupts", 263 !tmr_before && g_tmr_9b); 264 } 265 266 static volatile int g_isr_81; 267 268 static void ioapic_isr_81(isr_regs_t *regs) 269 { 270 ++g_isr_81; 271 set_irq_line(0x0e, 0); 272 eoi(); 273 } 274 275 static void test_ioapic_edge_mask(void) 276 { 277 handle_irq(0x81, ioapic_isr_81); 278 set_ioapic_redir(0x0e, 0x81, EDGE_TRIGGERED); 279 280 set_mask(0x0e, true); 281 set_irq_line(0x0e, 1); 282 set_irq_line(0x0e, 0); 283 284 asm volatile ("nop"); 285 report("masked level interrupt", g_isr_81 == 0); 286 287 set_mask(0x0e, false); 288 set_irq_line(0x0e, 1); 289 290 asm volatile ("nop"); 291 report("unmasked level interrupt", g_isr_81 == 1); 292 } 293 294 static volatile int g_isr_82; 295 296 static void ioapic_isr_82(isr_regs_t *regs) 297 { 298 ++g_isr_82; 299 set_irq_line(0x0e, 0); 300 eoi(); 301 } 302 303 static void test_ioapic_level_mask(void) 304 { 305 handle_irq(0x82, ioapic_isr_82); 306 set_ioapic_redir(0x0e, 0x82, LEVEL_TRIGGERED); 307 308 set_mask(0x0e, true); 309 set_irq_line(0x0e, 1); 310 311 asm volatile ("nop"); 312 report("masked level interrupt", g_isr_82 == 0); 313 314 set_mask(0x0e, false); 315 316 asm volatile ("nop"); 317 report("unmasked level interrupt", g_isr_82 == 1); 318 } 319 320 static volatile int g_isr_83; 321 322 static void ioapic_isr_83(isr_regs_t *regs) 323 { 324 ++g_isr_83; 325 set_mask(0x0e, true); 326 eoi(); 327 } 328 329 static void test_ioapic_level_retrigger_mask(void) 330 { 331 handle_irq(0x83, ioapic_isr_83); 332 set_ioapic_redir(0x0e, 0x83, LEVEL_TRIGGERED); 333 334 set_irq_line(0x0e, 1); 335 asm volatile ("nop"); 336 set_mask(0x0e, false); 337 asm volatile ("nop"); 338 report("retriggered level interrupts with mask", g_isr_83 == 2); 339 340 set_irq_line(0x0e, 0); 341 set_mask(0x0e, false); 342 } 343 344 345 int main(void) 346 { 347 setup_vm(); 348 smp_init(); 349 setup_idt(); 350 351 mask_pic_interrupts(); 352 353 if (enable_x2apic()) 354 printf("x2apic enabled\n"); 355 else 356 printf("x2apic not detected\n"); 357 358 irq_enable(); 359 360 ioapic_reg_version(); 361 ioapic_reg_id(); 362 ioapic_arbitration_id(); 363 364 test_ioapic_edge_intr(); 365 test_ioapic_level_intr(); 366 test_ioapic_simultaneous(); 367 368 test_ioapic_edge_tmr(); 369 test_ioapic_level_tmr(); 370 371 test_ioapic_level_coalesce(); 372 test_ioapic_level_sequential(); 373 test_ioapic_level_retrigger(); 374 375 test_ioapic_edge_mask(); 376 test_ioapic_level_mask(); 377 test_ioapic_level_retrigger_mask(); 378 379 return report_summary(); 380 } 381