Re: [PATCH] x86/apic: Switch to x2apic driver early if x2apic is enabled
From: Grzegorz Jaszczyk
Date: Fri Sep 11 2026 - 11:33:25 EST
On Thu, Sep 10, 2026 at 5:23 PM Dave Hansen <dave.hansen@xxxxxxxxx> wrote:
>
> On 9/10/26 02:04, Grzegorz Jaszczyk wrote:
> > During early boot, the generic x86 kernel defaults to the MMIO-based
> > APIC driver (apic_physflat). However, if the kernel is booted (e.g. via
> > kexec) when x2apic is already enabled in hardware, the MMIO interface to
> > the APIC is disabled.
>
> There's also some new hardware that locks the hardware in x2apic mode. I
> wonder if it has a similar problem.
You are probably referring to "x86/apic: Don't disable x2APIC if
locked" - if so, it seems it will have the same problem whenever ACPI
MADT probing doesn't run early (e.g. in CONFIG_ACPI=n crashdump
kernels).
In both cases (locked by hardware/BIOS or handed over via kexec), the
CPU starts with x2APIC enabled. As Intel SDM section "11.12.2 x2APIC
Register Availability" states: "In x2APIC mode, the memory mapped
interface is not available and any access to the MMIO interface will
behave similar to that of a legacy xAPIC in globally disabled state."
>
> > Normally, ACPI MADT probing would install an x2APIC driver early.
> > However, if ACPI is disabled (e.g., CONFIG_ACPI is not set, as in
> > crashdump kernels), x86_64_probe_apic() does not run until late_time_init()
> > via apic_intr_mode_init().
>
> Is this "default_acpi_madt_oem_check()" that uses apic_install_driver()?
Yes
> > apic_driver(apic_x2apic_phys);
> > +
> > +void __init x2apic_phys_early_init(void)
> > +{
> > + if (x2apic_enabled()) {
> > + apic = &apic_x2apic_phys;
> > + if (apic->x2apic_set_max_apicid)
> > + apic->max_apic_id = x2apic_max_apicid;
> > + pr_info("Switched default APIC to: %s\n", apic->name);
> > + }
> > +}
>
> This seems to be a subset of what apic_install_driver() and
> apic_x2apic_phys->probe() do, down do the pr_info().
>
> Even if those are overkill for this, it would be nice to use them for
> consistency if they function.
Ok, I can use apic_install_driver() instead. When it comes to
apic_x2apic_phys->probe() it can't really be used in current form
because at this early stage x2apic_phys_probe() will return 0, since
x2apic_mode is set quite late in setup.c (check_x2apic()).
>
> It also seems like some of the more obscure apic drivers depend on
> x2apic_mode. They also seem like they might be selected by the MADT
> search. Could this end up overwriting those?
It should be the other way around: MADT is called after
apic_setup_apic_calls() and it will overwirte it as normal: just this
time instead of overwriting apic_physflat it will overwrite
apic_x2apic_phys.
>
> Maybe this is too much work for the task at hand, but this does seem to
> show that there's some information missing from 'struct apic'. Say
> apic_physflat had an ->initialized() that was false until its MMIO was
> unmapped and apic_x2apic_phys->initialized() pointed over to:
> x2apic_enabled().
>
> apic_setup_apic_calls()
> {
> // Search for an APIC driver that is initialized:
> for_each(drv) {
> if (!drv->initialized())
> continue;
>
> apic_install_driver(drv);
> }
> }
>
> Basically, I'm wondering if it's worth continuing to special-case x2apic
> handling or whether it should just be a part of the apic driver
> infrastructure.
Yeah, something like this will work. Following your suggestion I was
thinking about something like this:
void __init apic_setup_apic_calls(void)
{
+ struct apic **drv;
+
+ for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
+ if ((*drv)->early_probe && (*drv)->early_probe()) {
+ apic_install_driver(*drv);
+ break;
+ }
+ }
and as apic_x2apic_phys.early_probe() we could use existing
x2apic_enabled(). And in apic_physflat, an early_probe returning
!x2apic_enabled(). But I see that Thomas also responded, and I think
he is looking into a different approach.
Thanks,
Grzegorz