[SeaBIOS] [PATCH 1/2] fw/acpi: Build MADT the way commodity BIOSes do

Filippo Sironi sironi at amazon.de
Fri Jan 27 02:18:39 CET 2017


When running Linux on an Intel machine with a commodity BIOS, CPUs are
numbered starting from 0 and the first half refers to the first logical
CPU on each core while the second half refers to the second logical CPU
on each core.
As an example, on machine with 2 sockets, 4 cores per socket, and 2
logical CPUs per core, CPUs would be numbered:

*  0  1  2  3 - first logical CPU on each core of socket 0
*  4  5  6  7 - first logical CPU on each core of socket 1
*  8  9 10 11 - second logical CPU on each core of socket 0
* 12 13 14 15 - second logical CPU on each core of socket 1

With seabios (prior to this patch), CPU 0 would be the first logical CPU
on core 0 of socket 0, CPU 1 would be the second logical CPU on core 0
of socket 0, and so on.
This is due to the fact that processor_id and local_apic_id are assigned
with the same value when building MADT.

Exhaust the most-significant 7 bits of the 8-bit APIC ID and then come
back to the least-significant bit when assigning local_apic_id, since
the least-significant bit identifies the second logical CPU on a core.

If HTT isn't available, keep the previous behavior.

Signed-off-by: Filippo Sironi <sironi at amazon.de>
---
 src/fw/acpi.c | 42 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/src/fw/acpi.c b/src/fw/acpi.c
index 8bc2ca6..864c247 100644
--- a/src/fw/acpi.c
+++ b/src/fw/acpi.c
@@ -158,13 +158,53 @@ build_madt(void)
     memset(madt, 0, madt_size);
     madt->local_apic_address = cpu_to_le32(BUILD_APIC_ADDR);
     madt->flags = cpu_to_le32(1);
+    u32 eax, ebx, ecx, edx;
+    cpuid(1, &eax, &ebx, &ecx, &edx);
+    int htt = 0;
+    if (!eax) {
+        dprintf(1, "No cpuid\n");
+    } else {
+        htt = !!(edx & (1 << 28));
+        /* assuming at most 2 logical CPUs per core */
+        if (htt)
+            dprintf(4, "Found HTT feature\n");
+    }
     struct madt_processor_apic *apic = (void*)&madt[1];
     int i;
     for (i=0; i<MaxCountCPUs; i++) {
         apic->type = APIC_PROCESSOR;
         apic->length = sizeof(*apic);
         apic->processor_id = i;
-        apic->local_apic_id = i;
+        if (htt) {
+            /*
+             * In a system with 2 packages, 4 cores per package, and 2 CPUs per
+             * core we want to achieve the following coupling:
+             * CPU#  APIC ID
+             *    0        0  [first socket, first logical CPUs]
+             *    1        2
+             *    2        4
+             *    3        6
+             *    4        8  [second socket, first logical CPUs]
+             *    5       10
+             *    6       12
+             *    7       14
+             *    8        1  [first socket, second logical CPUs]
+             *    9        3
+             *   10        5
+             *   11        7
+             *   12        9  [second socket, second logical CPUs]
+             *   13       11
+             *   14       13
+             *   15       15
+             * where the least-significant bit of the APIC ID identifies the
+             * first (0) or second (1) logical CPU in a core.
+             */
+            apic->local_apic_id = i * 2;
+            if (apic->local_apic_id >= MaxCountCPUs)
+                apic->local_apic_id -= MaxCountCPUs - 1;
+        } else {
+            apic->local_apic_id = i;
+        }
         if (apic_id_is_present(apic->local_apic_id))
             apic->flags = cpu_to_le32(1);
         else
-- 
2.7.4




More information about the SeaBIOS mailing list