pOn amd64 we lie about the interrupts established during i8254_initclocks(). We claim they are MP-safe in order to mollify a KASSERT in intr_establish() and continue booting.
See amd64/isa/clock.c: 279 void 280 i8254_initclocks(void) 281 { 282 i8254_inittimecounter(); /* hook the interrupt-based i8254 tc */ 283 284 stathz = 128; 285 profhz = 1024; /* XXX does not divide into 1 billion */ 286 clockintr_init(0); 287 288 clockintr_cpu_init(NULL); 289 290 /* 291 * While the clock interrupt handler isn't really MPSAFE, the 292 * i8254 can't really be used as a clock on a true MP system. 293 */ 294 isa_intr_establish(NULL, 0, IST_PULSE, IPL_CLOCK | IPL_MPSAFE, 295 clockintr, 0, "clock"); 296 isa_intr_establish(NULL, 8, IST_PULSE, IPL_STATCLOCK | IPL_MPSAFE, 297 rtcintr, 0, "rtc"); and amd64/amd64/intr.c: 332 void * 333 intr_establish(int legacy_irq, struct pic *pic, int pin, int type, int level, 334 struct cpu_info *ci, int (*handler)(void *), void *arg, const char *what) 335 { 336 struct intrhand **p, *q, *ih; 337 int slot, error, idt_vec; 338 struct intrsource *source; 339 struct intrstub *stubp; 340 int flags; 341 342 #ifdef DIAGNOSTIC 343 if (legacy_irq != -1 && (legacy_irq < 0 || legacy_irq > 15)) 344 panic("intr_establish: bad legacy IRQ value"); 345 346 if (legacy_irq == -1 && pic == &i8259_pic) 347 panic("intr_establish: non-legacy IRQ on i8259"); 348 #endif 349 350 flags = level & IPL_MPSAFE; 351 level &= ~IPL_MPSAFE; 352 353 KASSERT(level <= IPL_TTY || level >= IPL_CLOCK || flags & IPL_MPSAFE); Can we do the same on i386? I'm trying to test the i8254 path on modern hardware and I'm tripping the equivalent KASSERT in apic_intr_establish(). See i386/i386/ioapic.c: 661 void * 662 apic_intr_establish(int irq, int type, int level, int (*ih_fun)(void *), 663 void *ih_arg, const char *ih_what) 664 { 665 unsigned int ioapic = APIC_IRQ_APIC(irq); 666 unsigned int intr = APIC_IRQ_PIN(irq); 667 struct ioapic_softc *sc = ioapic_find(ioapic); 668 struct ioapic_pin *pin; 669 struct intrhand **p, *q, *ih; 670 extern int cold; 671 int minlevel, maxlevel; 672 extern void intr_calculatemasks(void); /* XXX */ 673 int flags; 674 675 flags = level & IPL_MPSAFE; 676 level &= ~IPL_MPSAFE; 677 678 KASSERT(level <= IPL_TTY || flags & IPL_MPSAFE); The patch below lets me test the i8254 clockintr path on modern hardware in 32-bit mode without needing to rototill the GENERIC config to delete all the things that implicitly depend upon the ioapic. I don't think lying in this case is harmful. We can only get to i8254_initclocks() if we have no local APIC, or if lapic_calibrate_timer() fails. ok? Index: clock.c =================================================================== RCS file: /cvs/src/sys/arch/i386/isa/clock.c,v retrieving revision 1.65 diff -u -p -r1.65 clock.c --- clock.c 25 Jul 2023 18:16:20 -0000 1.65 +++ clock.c 21 Aug 2023 03:26:39 -0000 @@ -431,9 +431,9 @@ i8254_initclocks(void) clockintr_cpu_init(NULL); /* When using i8254 for clock, we also use the rtc for profclock */ - (void)isa_intr_establish(NULL, 0, IST_PULSE, IPL_CLOCK, + (void)isa_intr_establish(NULL, 0, IST_PULSE, IPL_CLOCK | IPL_MPSAFE, clockintr, 0, "clock"); - (void)isa_intr_establish(NULL, 8, IST_PULSE, IPL_STATCLOCK, + (void)isa_intr_establish(NULL, 8, IST_PULSE, IPL_STATCLOCK | IPL_MPSAFE, rtcintr, 0, "rtc"); rtcstart(); /* start the mc146818 clock */