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 */