Handle X2APIC entries in the MADT for APICs with an ID < 255. At least one
BIOS has been seen to include such entries even though the relevant specs require that X2APIC entries only be used for CPUs with an APIC ID >= 255. This was tested on a system with "plain" local APIC entries in the MADT to ensure no regressions, but it has not yet been tested on a system with X2APIC entries in the MADT. Currently such systems do not boot at all, and with this change they might now boot correctly. Differential Revision: https://reviews.freebsd.org/D2521 Reviewed by: kib MFC after: 2 weeks
This commit is contained in:
parent
3259f3f35f
commit
8d7fa71fca
@ -56,8 +56,8 @@ static struct {
|
||||
} *ioapics;
|
||||
|
||||
static struct lapic_info {
|
||||
u_int la_enabled:1;
|
||||
u_int la_acpi_id:8;
|
||||
u_int la_enabled;
|
||||
u_int la_acpi_id;
|
||||
} lapics[MAX_APIC_ID + 1];
|
||||
|
||||
int madt_found_sci_override;
|
||||
@ -254,35 +254,49 @@ madt_walk_table(acpi_subtable_handler *handler, void *arg)
|
||||
handler, arg);
|
||||
}
|
||||
|
||||
static void
|
||||
madt_add_cpu(u_int acpi_id, u_int apic_id, u_int flags)
|
||||
{
|
||||
struct lapic_info *la;
|
||||
|
||||
/*
|
||||
* The MADT does not include a BSP flag, so we have to let the
|
||||
* MP code figure out which CPU is the BSP on its own.
|
||||
*/
|
||||
if (bootverbose)
|
||||
printf("MADT: Found CPU APIC ID %u ACPI ID %u: %s\n",
|
||||
apic_id, acpi_id, flags & ACPI_MADT_ENABLED ?
|
||||
"enabled" : "disabled");
|
||||
if (!(flags & ACPI_MADT_ENABLED))
|
||||
return;
|
||||
if (apic_id > MAX_APIC_ID) {
|
||||
printf("MADT: Ignoring local APIC ID %u (too high)\n",
|
||||
apic_id);
|
||||
return;
|
||||
}
|
||||
|
||||
la = &lapics[apic_id];
|
||||
KASSERT(la->la_enabled == 0, ("Duplicate local APIC ID %u", apic_id));
|
||||
la->la_enabled = 1;
|
||||
la->la_acpi_id = acpi_id;
|
||||
lapic_create(apic_id, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
madt_probe_cpus_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
|
||||
{
|
||||
ACPI_MADT_LOCAL_APIC *proc;
|
||||
struct lapic_info *la;
|
||||
ACPI_MADT_LOCAL_X2APIC *x2apic;
|
||||
|
||||
switch (entry->Type) {
|
||||
case ACPI_MADT_TYPE_LOCAL_APIC:
|
||||
/*
|
||||
* The MADT does not include a BSP flag, so we have to
|
||||
* let the MP code figure out which CPU is the BSP on
|
||||
* its own.
|
||||
*/
|
||||
proc = (ACPI_MADT_LOCAL_APIC *)entry;
|
||||
if (bootverbose)
|
||||
printf("MADT: Found CPU APIC ID %u ACPI ID %u: %s\n",
|
||||
proc->Id, proc->ProcessorId,
|
||||
(proc->LapicFlags & ACPI_MADT_ENABLED) ?
|
||||
"enabled" : "disabled");
|
||||
if (!(proc->LapicFlags & ACPI_MADT_ENABLED))
|
||||
break;
|
||||
if (proc->Id > MAX_APIC_ID)
|
||||
panic("%s: CPU ID %u too high", __func__, proc->Id);
|
||||
la = &lapics[proc->Id];
|
||||
KASSERT(la->la_enabled == 0,
|
||||
("Duplicate local APIC ID %u", proc->Id));
|
||||
la->la_enabled = 1;
|
||||
la->la_acpi_id = proc->ProcessorId;
|
||||
lapic_create(proc->Id, 0);
|
||||
madt_add_cpu(proc->ProcessorId, proc->Id, proc->LapicFlags);
|
||||
break;
|
||||
case ACPI_MADT_TYPE_LOCAL_X2APIC:
|
||||
x2apic = (ACPI_MADT_LOCAL_X2APIC *)entry;
|
||||
madt_add_cpu(x2apic->Uid, x2apic->LocalApicId,
|
||||
x2apic->LapicFlags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -551,29 +565,44 @@ madt_parse_nmi(ACPI_MADT_NMI_SOURCE *nmi)
|
||||
* Parse an entry for an NMI routed to a local APIC LVT pin.
|
||||
*/
|
||||
static void
|
||||
madt_parse_local_nmi(ACPI_MADT_LOCAL_APIC_NMI *nmi)
|
||||
madt_handle_local_nmi(u_int acpi_id, UINT8 Lint, UINT16 IntiFlags)
|
||||
{
|
||||
u_int apic_id, pin;
|
||||
|
||||
if (nmi->ProcessorId == 0xff)
|
||||
if (acpi_id == 0xffffffff)
|
||||
apic_id = APIC_ID_ALL;
|
||||
else if (madt_find_cpu(nmi->ProcessorId, &apic_id) != 0) {
|
||||
else if (madt_find_cpu(acpi_id, &apic_id) != 0) {
|
||||
if (bootverbose)
|
||||
printf("MADT: Ignoring local NMI routed to "
|
||||
"ACPI CPU %u\n", nmi->ProcessorId);
|
||||
"ACPI CPU %u\n", acpi_id);
|
||||
return;
|
||||
}
|
||||
if (nmi->Lint == 0)
|
||||
if (Lint == 0)
|
||||
pin = APIC_LVT_LINT0;
|
||||
else
|
||||
pin = APIC_LVT_LINT1;
|
||||
lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_NMI);
|
||||
if (!(nmi->IntiFlags & ACPI_MADT_TRIGGER_CONFORMS))
|
||||
if (!(IntiFlags & ACPI_MADT_TRIGGER_CONFORMS))
|
||||
lapic_set_lvt_triggermode(apic_id, pin,
|
||||
interrupt_trigger(nmi->IntiFlags, 0));
|
||||
if (!(nmi->IntiFlags & ACPI_MADT_POLARITY_CONFORMS))
|
||||
interrupt_trigger(IntiFlags, 0));
|
||||
if (!(IntiFlags & ACPI_MADT_POLARITY_CONFORMS))
|
||||
lapic_set_lvt_polarity(apic_id, pin,
|
||||
interrupt_polarity(nmi->IntiFlags, 0));
|
||||
interrupt_polarity(IntiFlags, 0));
|
||||
}
|
||||
|
||||
static void
|
||||
madt_parse_local_nmi(ACPI_MADT_LOCAL_APIC_NMI *nmi)
|
||||
{
|
||||
|
||||
madt_handle_local_nmi(nmi->ProcessorId == 0xff ? 0xffffffff :
|
||||
nmi->ProcessorId, nmi->Lint, nmi->IntiFlags);
|
||||
}
|
||||
|
||||
static void
|
||||
madt_parse_local_x2apic_nmi(ACPI_MADT_LOCAL_X2APIC_NMI *nmi)
|
||||
{
|
||||
|
||||
madt_handle_local_nmi(nmi->Uid, nmi->Lint, nmi->IntiFlags);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -594,6 +623,10 @@ madt_parse_ints(ACPI_SUBTABLE_HEADER *entry, void *arg __unused)
|
||||
case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
|
||||
madt_parse_local_nmi((ACPI_MADT_LOCAL_APIC_NMI *)entry);
|
||||
break;
|
||||
case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI:
|
||||
madt_parse_local_x2apic_nmi(
|
||||
(ACPI_MADT_LOCAL_X2APIC_NMI *)entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user