summaryrefslogtreecommitdiffstats
path: root/sys/amd64
diff options
context:
space:
mode:
authortegge <tegge@FreeBSD.org>2000-08-06 00:04:03 +0000
committertegge <tegge@FreeBSD.org>2000-08-06 00:04:03 +0000
commita83353f91aca54c41c4c861b026dd2e1c2a95cbe (patch)
treec658601adae58dd16d10f4d10628de7a07fed3e9 /sys/amd64
parent38baa3d84afacf843e0afcd466775444d5ef58a0 (diff)
downloadFreeBSD-src-a83353f91aca54c41c4c861b026dd2e1c2a95cbe.zip
FreeBSD-src-a83353f91aca54c41c4c861b026dd2e1c2a95cbe.tar.gz
Be more verbose when changing APIC ID on an IO APIC.
Don't allow cpu entries in the MP table to contain APIC IDs out of range. Don't write outside array boundaries if an IO APIC entry in the MP table contains an APIC ID out of range. Assign APIC IDs for all IO APICs according to section 3.6.6 in the Intel MP spec: - If the current APIC ID on an IO APIC doesn't conflict with other IO APICs or CPUs, that APIC ID should be used. The copy of the MP table must be updated if the corresponding APIC ID in the MP table is different. - If the current APIC ID was in conflict with other units, the corresponding APIC ID specified in the MP table is checked for conflict. - If a conflict is still found then fall back to using a new unique ID. The copy of the MP table must be updated. - IDs out of range is considered to be in conflict. During these operations, the IO_TO_ID array cannot be used, since any conflict would have caused information loss. The array is then corrected, since all APIC ID conflicts should have been resolved. PR: 20312, 18919
Diffstat (limited to 'sys/amd64')
-rw-r--r--sys/amd64/amd64/mp_machdep.c144
-rw-r--r--sys/amd64/amd64/mptable.c144
-rw-r--r--sys/amd64/include/mptable.h144
-rw-r--r--sys/amd64/include/smp.h1
4 files changed, 427 insertions, 6 deletions
diff --git a/sys/amd64/amd64/mp_machdep.c b/sys/amd64/amd64/mp_machdep.c
index 1155e67..f8e77a1 100644
--- a/sys/amd64/amd64/mp_machdep.c
+++ b/sys/amd64/amd64/mp_machdep.c
@@ -1013,6 +1013,105 @@ revoke_apic_irq(int irq)
}
}
+
+
+static void
+swap_apic_id(int apic, int oldid, int newid)
+{
+ int x;
+ int oapic;
+
+
+ if (oldid == newid)
+ return; /* Nothing to do */
+
+ printf("Changing APIC ID for IO APIC #%d from %d to %d in MP table\n",
+ apic, oldid, newid);
+
+ /* Swap physical APIC IDs in interrupt entries */
+ for (x = 0; x < nintrs; x++) {
+ if (io_apic_ints[x].dst_apic_id == oldid)
+ io_apic_ints[x].dst_apic_id = newid;
+ else if (io_apic_ints[x].dst_apic_id == newid)
+ io_apic_ints[x].dst_apic_id = oldid;
+ }
+
+ /* Swap physical APIC IDs in IO_TO_ID mappings */
+ for (oapic = 0; oapic < mp_napics; oapic++)
+ if (IO_TO_ID(oapic) == newid)
+ break;
+
+ if (oapic < mp_napics) {
+ printf("Changing APIC ID for IO APIC #%d from "
+ "%d to %d in MP table\n",
+ oapic, newid, oldid);
+ IO_TO_ID(oapic) = oldid;
+ }
+ IO_TO_ID(apic) = newid;
+}
+
+
+static void
+fix_id_to_io_mapping(void)
+{
+ int x;
+
+ for (x = 0; x < NAPICID; x++)
+ ID_TO_IO(x) = -1;
+
+ for (x = 0; x <= mp_naps; x++)
+ if (CPU_TO_ID(x) < NAPICID)
+ ID_TO_IO(CPU_TO_ID(x)) = x;
+
+ for (x = 0; x < mp_napics; x++)
+ if (IO_TO_ID(x) < NAPICID)
+ ID_TO_IO(IO_TO_ID(x)) = x;
+}
+
+
+static int
+first_free_apic_id(void)
+{
+ int freeid, x;
+
+ for (freeid = 0; freeid < NAPICID; freeid++) {
+ for (x = 0; x <= mp_naps; x++)
+ if (CPU_TO_ID(x) == freeid)
+ break;
+ if (x <= mp_naps)
+ continue;
+ for (x = 0; x < mp_napics; x++)
+ if (IO_TO_ID(x) == freeid)
+ break;
+ if (x < mp_napics)
+ continue;
+ return freeid;
+ }
+ return freeid;
+}
+
+
+static int
+io_apic_id_acceptable(int apic, int id)
+{
+ int cpu; /* Logical CPU number */
+ int oapic; /* Logical IO APIC number for other IO APIC */
+
+ if (id >= NAPICID)
+ return 0; /* Out of range */
+
+ for (cpu = 0; cpu <= mp_naps; cpu++)
+ if (CPU_TO_ID(cpu) == id)
+ return 0; /* Conflict with CPU */
+
+ for (oapic = 0; oapic < mp_napics && oapic < apic; oapic++)
+ if (IO_TO_ID(oapic) == id)
+ return 0; /* Conflict with other APIC */
+
+ return 1; /* ID is acceptable for IO APIC */
+}
+
+
/*
* parse an Intel MP specification table
*/
@@ -1024,6 +1123,9 @@ fix_mp_table(void)
int bus_0 = 0; /* Stop GCC warning */
int bus_pci = 0; /* Stop GCC warning */
int num_pci_bus;
+ int apic; /* IO APIC unit number */
+ int freeid; /* Free physical APIC ID */
+ int physid; /* Current physical IO APIC ID */
/*
* Fix mis-numbering of the PCI bus and its INT entries if the BIOS
@@ -1076,6 +1178,42 @@ fix_mp_table(void)
}
}
}
+
+ /* Assign IO APIC IDs.
+ *
+ * First try the existing ID. If a conflict is detected, try
+ * the ID in the MP table. If a conflict is still detected, find
+ * a free id.
+ *
+ * We cannot use the ID_TO_IO table before all conflicts has been
+ * resolved and the table has been corrected.
+ */
+ for (apic = 0; apic < mp_napics; ++apic) { /* For all IO APICs */
+
+ /* First try to use the value set by the BIOS */
+ physid = io_apic_get_id(apic);
+ if (io_apic_id_acceptable(apic, physid)) {
+ if (IO_TO_ID(apic) != physid)
+ swap_apic_id(apic, IO_TO_ID(apic), physid);
+ continue;
+ }
+
+ /* Then check if the value in the MP table is acceptable */
+ if (io_apic_id_acceptable(apic, IO_TO_ID(apic)))
+ continue;
+
+ /* Last resort, find a free APIC ID and use it */
+ freeid = first_free_apic_id();
+ if (freeid >= NAPICID)
+ panic("No free physical APIC IDs found");
+
+ if (io_apic_id_acceptable(apic, freeid)) {
+ swap_apic_id(apic, IO_TO_ID(apic), freeid);
+ continue;
+ }
+ panic("Free physical APIC ID not usable");
+ }
+ fix_id_to_io_mapping();
}
@@ -1159,6 +1297,8 @@ processor_entry(proc_entry_ptr entry, int cpu)
if (!(entry->cpu_flags & PROCENTRY_FLAG_EN))
return 0;
+ if(entry->apic_id >= NAPICID)
+ panic("CPU APIC ID out of range (0..%d)", NAPICID - 1);
/* check for BSP flag */
if (entry->cpu_flags & PROCENTRY_FLAG_BP) {
boot_cpu_id = entry->apic_id;
@@ -1209,7 +1349,8 @@ io_apic_entry(io_apic_entry_ptr entry, int apic)
return 0;
IO_TO_ID(apic) = entry->apic_id;
- ID_TO_IO(entry->apic_id) = apic;
+ if (entry->apic_id < NAPICID)
+ ID_TO_IO(entry->apic_id) = apic;
return 1;
}
@@ -1602,7 +1743,6 @@ default_mp_table(int type)
{
int ap_cpu_id;
#if defined(APIC_IO)
- u_int32_t ux;
int io_apic_id;
int pin;
#endif /* APIC_IO */
diff --git a/sys/amd64/amd64/mptable.c b/sys/amd64/amd64/mptable.c
index 1155e67..f8e77a1 100644
--- a/sys/amd64/amd64/mptable.c
+++ b/sys/amd64/amd64/mptable.c
@@ -1013,6 +1013,105 @@ revoke_apic_irq(int irq)
}
}
+
+
+static void
+swap_apic_id(int apic, int oldid, int newid)
+{
+ int x;
+ int oapic;
+
+
+ if (oldid == newid)
+ return; /* Nothing to do */
+
+ printf("Changing APIC ID for IO APIC #%d from %d to %d in MP table\n",
+ apic, oldid, newid);
+
+ /* Swap physical APIC IDs in interrupt entries */
+ for (x = 0; x < nintrs; x++) {
+ if (io_apic_ints[x].dst_apic_id == oldid)
+ io_apic_ints[x].dst_apic_id = newid;
+ else if (io_apic_ints[x].dst_apic_id == newid)
+ io_apic_ints[x].dst_apic_id = oldid;
+ }
+
+ /* Swap physical APIC IDs in IO_TO_ID mappings */
+ for (oapic = 0; oapic < mp_napics; oapic++)
+ if (IO_TO_ID(oapic) == newid)
+ break;
+
+ if (oapic < mp_napics) {
+ printf("Changing APIC ID for IO APIC #%d from "
+ "%d to %d in MP table\n",
+ oapic, newid, oldid);
+ IO_TO_ID(oapic) = oldid;
+ }
+ IO_TO_ID(apic) = newid;
+}
+
+
+static void
+fix_id_to_io_mapping(void)
+{
+ int x;
+
+ for (x = 0; x < NAPICID; x++)
+ ID_TO_IO(x) = -1;
+
+ for (x = 0; x <= mp_naps; x++)
+ if (CPU_TO_ID(x) < NAPICID)
+ ID_TO_IO(CPU_TO_ID(x)) = x;
+
+ for (x = 0; x < mp_napics; x++)
+ if (IO_TO_ID(x) < NAPICID)
+ ID_TO_IO(IO_TO_ID(x)) = x;
+}
+
+
+static int
+first_free_apic_id(void)
+{
+ int freeid, x;
+
+ for (freeid = 0; freeid < NAPICID; freeid++) {
+ for (x = 0; x <= mp_naps; x++)
+ if (CPU_TO_ID(x) == freeid)
+ break;
+ if (x <= mp_naps)
+ continue;
+ for (x = 0; x < mp_napics; x++)
+ if (IO_TO_ID(x) == freeid)
+ break;
+ if (x < mp_napics)
+ continue;
+ return freeid;
+ }
+ return freeid;
+}
+
+
+static int
+io_apic_id_acceptable(int apic, int id)
+{
+ int cpu; /* Logical CPU number */
+ int oapic; /* Logical IO APIC number for other IO APIC */
+
+ if (id >= NAPICID)
+ return 0; /* Out of range */
+
+ for (cpu = 0; cpu <= mp_naps; cpu++)
+ if (CPU_TO_ID(cpu) == id)
+ return 0; /* Conflict with CPU */
+
+ for (oapic = 0; oapic < mp_napics && oapic < apic; oapic++)
+ if (IO_TO_ID(oapic) == id)
+ return 0; /* Conflict with other APIC */
+
+ return 1; /* ID is acceptable for IO APIC */
+}
+
+
/*
* parse an Intel MP specification table
*/
@@ -1024,6 +1123,9 @@ fix_mp_table(void)
int bus_0 = 0; /* Stop GCC warning */
int bus_pci = 0; /* Stop GCC warning */
int num_pci_bus;
+ int apic; /* IO APIC unit number */
+ int freeid; /* Free physical APIC ID */
+ int physid; /* Current physical IO APIC ID */
/*
* Fix mis-numbering of the PCI bus and its INT entries if the BIOS
@@ -1076,6 +1178,42 @@ fix_mp_table(void)
}
}
}
+
+ /* Assign IO APIC IDs.
+ *
+ * First try the existing ID. If a conflict is detected, try
+ * the ID in the MP table. If a conflict is still detected, find
+ * a free id.
+ *
+ * We cannot use the ID_TO_IO table before all conflicts has been
+ * resolved and the table has been corrected.
+ */
+ for (apic = 0; apic < mp_napics; ++apic) { /* For all IO APICs */
+
+ /* First try to use the value set by the BIOS */
+ physid = io_apic_get_id(apic);
+ if (io_apic_id_acceptable(apic, physid)) {
+ if (IO_TO_ID(apic) != physid)
+ swap_apic_id(apic, IO_TO_ID(apic), physid);
+ continue;
+ }
+
+ /* Then check if the value in the MP table is acceptable */
+ if (io_apic_id_acceptable(apic, IO_TO_ID(apic)))
+ continue;
+
+ /* Last resort, find a free APIC ID and use it */
+ freeid = first_free_apic_id();
+ if (freeid >= NAPICID)
+ panic("No free physical APIC IDs found");
+
+ if (io_apic_id_acceptable(apic, freeid)) {
+ swap_apic_id(apic, IO_TO_ID(apic), freeid);
+ continue;
+ }
+ panic("Free physical APIC ID not usable");
+ }
+ fix_id_to_io_mapping();
}
@@ -1159,6 +1297,8 @@ processor_entry(proc_entry_ptr entry, int cpu)
if (!(entry->cpu_flags & PROCENTRY_FLAG_EN))
return 0;
+ if(entry->apic_id >= NAPICID)
+ panic("CPU APIC ID out of range (0..%d)", NAPICID - 1);
/* check for BSP flag */
if (entry->cpu_flags & PROCENTRY_FLAG_BP) {
boot_cpu_id = entry->apic_id;
@@ -1209,7 +1349,8 @@ io_apic_entry(io_apic_entry_ptr entry, int apic)
return 0;
IO_TO_ID(apic) = entry->apic_id;
- ID_TO_IO(entry->apic_id) = apic;
+ if (entry->apic_id < NAPICID)
+ ID_TO_IO(entry->apic_id) = apic;
return 1;
}
@@ -1602,7 +1743,6 @@ default_mp_table(int type)
{
int ap_cpu_id;
#if defined(APIC_IO)
- u_int32_t ux;
int io_apic_id;
int pin;
#endif /* APIC_IO */
diff --git a/sys/amd64/include/mptable.h b/sys/amd64/include/mptable.h
index 1155e67..f8e77a1 100644
--- a/sys/amd64/include/mptable.h
+++ b/sys/amd64/include/mptable.h
@@ -1013,6 +1013,105 @@ revoke_apic_irq(int irq)
}
}
+
+
+static void
+swap_apic_id(int apic, int oldid, int newid)
+{
+ int x;
+ int oapic;
+
+
+ if (oldid == newid)
+ return; /* Nothing to do */
+
+ printf("Changing APIC ID for IO APIC #%d from %d to %d in MP table\n",
+ apic, oldid, newid);
+
+ /* Swap physical APIC IDs in interrupt entries */
+ for (x = 0; x < nintrs; x++) {
+ if (io_apic_ints[x].dst_apic_id == oldid)
+ io_apic_ints[x].dst_apic_id = newid;
+ else if (io_apic_ints[x].dst_apic_id == newid)
+ io_apic_ints[x].dst_apic_id = oldid;
+ }
+
+ /* Swap physical APIC IDs in IO_TO_ID mappings */
+ for (oapic = 0; oapic < mp_napics; oapic++)
+ if (IO_TO_ID(oapic) == newid)
+ break;
+
+ if (oapic < mp_napics) {
+ printf("Changing APIC ID for IO APIC #%d from "
+ "%d to %d in MP table\n",
+ oapic, newid, oldid);
+ IO_TO_ID(oapic) = oldid;
+ }
+ IO_TO_ID(apic) = newid;
+}
+
+
+static void
+fix_id_to_io_mapping(void)
+{
+ int x;
+
+ for (x = 0; x < NAPICID; x++)
+ ID_TO_IO(x) = -1;
+
+ for (x = 0; x <= mp_naps; x++)
+ if (CPU_TO_ID(x) < NAPICID)
+ ID_TO_IO(CPU_TO_ID(x)) = x;
+
+ for (x = 0; x < mp_napics; x++)
+ if (IO_TO_ID(x) < NAPICID)
+ ID_TO_IO(IO_TO_ID(x)) = x;
+}
+
+
+static int
+first_free_apic_id(void)
+{
+ int freeid, x;
+
+ for (freeid = 0; freeid < NAPICID; freeid++) {
+ for (x = 0; x <= mp_naps; x++)
+ if (CPU_TO_ID(x) == freeid)
+ break;
+ if (x <= mp_naps)
+ continue;
+ for (x = 0; x < mp_napics; x++)
+ if (IO_TO_ID(x) == freeid)
+ break;
+ if (x < mp_napics)
+ continue;
+ return freeid;
+ }
+ return freeid;
+}
+
+
+static int
+io_apic_id_acceptable(int apic, int id)
+{
+ int cpu; /* Logical CPU number */
+ int oapic; /* Logical IO APIC number for other IO APIC */
+
+ if (id >= NAPICID)
+ return 0; /* Out of range */
+
+ for (cpu = 0; cpu <= mp_naps; cpu++)
+ if (CPU_TO_ID(cpu) == id)
+ return 0; /* Conflict with CPU */
+
+ for (oapic = 0; oapic < mp_napics && oapic < apic; oapic++)
+ if (IO_TO_ID(oapic) == id)
+ return 0; /* Conflict with other APIC */
+
+ return 1; /* ID is acceptable for IO APIC */
+}
+
+
/*
* parse an Intel MP specification table
*/
@@ -1024,6 +1123,9 @@ fix_mp_table(void)
int bus_0 = 0; /* Stop GCC warning */
int bus_pci = 0; /* Stop GCC warning */
int num_pci_bus;
+ int apic; /* IO APIC unit number */
+ int freeid; /* Free physical APIC ID */
+ int physid; /* Current physical IO APIC ID */
/*
* Fix mis-numbering of the PCI bus and its INT entries if the BIOS
@@ -1076,6 +1178,42 @@ fix_mp_table(void)
}
}
}
+
+ /* Assign IO APIC IDs.
+ *
+ * First try the existing ID. If a conflict is detected, try
+ * the ID in the MP table. If a conflict is still detected, find
+ * a free id.
+ *
+ * We cannot use the ID_TO_IO table before all conflicts has been
+ * resolved and the table has been corrected.
+ */
+ for (apic = 0; apic < mp_napics; ++apic) { /* For all IO APICs */
+
+ /* First try to use the value set by the BIOS */
+ physid = io_apic_get_id(apic);
+ if (io_apic_id_acceptable(apic, physid)) {
+ if (IO_TO_ID(apic) != physid)
+ swap_apic_id(apic, IO_TO_ID(apic), physid);
+ continue;
+ }
+
+ /* Then check if the value in the MP table is acceptable */
+ if (io_apic_id_acceptable(apic, IO_TO_ID(apic)))
+ continue;
+
+ /* Last resort, find a free APIC ID and use it */
+ freeid = first_free_apic_id();
+ if (freeid >= NAPICID)
+ panic("No free physical APIC IDs found");
+
+ if (io_apic_id_acceptable(apic, freeid)) {
+ swap_apic_id(apic, IO_TO_ID(apic), freeid);
+ continue;
+ }
+ panic("Free physical APIC ID not usable");
+ }
+ fix_id_to_io_mapping();
}
@@ -1159,6 +1297,8 @@ processor_entry(proc_entry_ptr entry, int cpu)
if (!(entry->cpu_flags & PROCENTRY_FLAG_EN))
return 0;
+ if(entry->apic_id >= NAPICID)
+ panic("CPU APIC ID out of range (0..%d)", NAPICID - 1);
/* check for BSP flag */
if (entry->cpu_flags & PROCENTRY_FLAG_BP) {
boot_cpu_id = entry->apic_id;
@@ -1209,7 +1349,8 @@ io_apic_entry(io_apic_entry_ptr entry, int apic)
return 0;
IO_TO_ID(apic) = entry->apic_id;
- ID_TO_IO(entry->apic_id) = apic;
+ if (entry->apic_id < NAPICID)
+ ID_TO_IO(entry->apic_id) = apic;
return 1;
}
@@ -1602,7 +1743,6 @@ default_mp_table(int type)
{
int ap_cpu_id;
#if defined(APIC_IO)
- u_int32_t ux;
int io_apic_id;
int pin;
#endif /* APIC_IO */
diff --git a/sys/amd64/include/smp.h b/sys/amd64/include/smp.h
index 17b7a3a..cb642ffd 100644
--- a/sys/amd64/include/smp.h
+++ b/sys/amd64/include/smp.h
@@ -166,6 +166,7 @@ int apic_ipi __P((int, int, int));
int selected_apic_ipi __P((u_int, int, int));
int io_apic_setup __P((int));
void io_apic_set_id __P((int, int));
+int io_apic_get_id __P((int));
int ext_int_setup __P((int, int));
#if defined(READY)
OpenPOWER on IntegriCloud