On Sun, Aug 20, 2023 at 10:39:46PM -0500, Scott Cheloha wrote:
> 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 */
I think this is fine. I tried to come up with a scenario where you'd be doing
smp i386 without a local apic and even the ancient 82489 (for 80486 systems)
acted as a lapic. And since we don't run on real 80386 anymore, I think we can
ignore someone trying to do smp there.
ok mlarkin if it makes your work easier.