libacpi is a tool that is used by libxl (for PVH guests) and hvmloader
(for HVM guests) to construct ACPI tables for guests.

Currently, libacpi only uses APIC entries to enumerate processors for
guests in the MADT.

The APIC ID field in APIC entries is an octet big, which is fine for
xAPIC IDs, but not so for sufficiently large x2APIC IDs.

This patch scans each APIC ID before constructing the MADT, and uses the
x2APIC entry for each vCPU whose APIC ID exceeds the size limit imposed
by regular APIC entries.

Signed-off-by: Matthew Barnes <matthew.bar...@cloud.com>
---
 tools/libacpi/acpi2_0.h | 13 +++++++
 tools/libacpi/build.c   | 75 ++++++++++++++++++++++++++++++-----------
 2 files changed, 68 insertions(+), 20 deletions(-)

diff --git a/tools/libacpi/acpi2_0.h b/tools/libacpi/acpi2_0.h
index 6dfa939a8c0c..10e567686fe6 100644
--- a/tools/libacpi/acpi2_0.h
+++ b/tools/libacpi/acpi2_0.h
@@ -344,6 +344,7 @@ struct acpi_20_waet {
 #define ACPI_IO_SAPIC                       0x06
 #define ACPI_PROCESSOR_LOCAL_SAPIC          0x07
 #define ACPI_PLATFORM_INTERRUPT_SOURCES     0x08
+#define ACPI_PROCESSOR_LOCAL_X2APIC         0x09
 
 /*
  * APIC Structure Definitions.
@@ -360,6 +361,18 @@ struct acpi_20_madt_lapic {
     uint32_t flags;
 };
 
+/*
+ * Processor Local x2APIC Structure Definition.
+ */
+struct acpi_20_madt_x2apic {
+    uint8_t  type;              /* Must refer to x2APIC type (0x09) */
+    uint8_t  length;            /* Must be length of x2APIC struct in bytes 
(0x10) */
+    uint16_t reserved;          /* Must be zero */
+    uint32_t apic_id;           /* Processor's local x2APIC ID */
+    uint32_t flags;             /* Same as Local APIC flags */
+    uint32_t acpi_processor_id; /* Refers to a processor device used to 
associate the X2APIC structure with */
+};
+
 /*
  * Local APIC Flags.  All other bits are reserved and must be 0.
  */
diff --git a/tools/libacpi/build.c b/tools/libacpi/build.c
index 2f29863db154..5b0fd6584b30 100644
--- a/tools/libacpi/build.c
+++ b/tools/libacpi/build.c
@@ -63,6 +63,27 @@ static void set_checksum(
     p[checksum_offset] = -sum;
 }
 
+static unsigned calculate_madt_size(const struct acpi_config *config)
+{
+    uint32_t apic_id;
+    unsigned i, size;
+
+    size  = sizeof(struct acpi_20_madt);
+    size += sizeof(struct acpi_20_madt_intsrcovr) * 16;
+    size += sizeof(struct acpi_20_madt_ioapic);
+
+    for ( i = 0; i < config->hvminfo->nr_vcpus; i++ )
+    {
+        apic_id = config->lapic_id(i);
+        if ( apic_id < 255 )
+            size += sizeof(struct acpi_20_madt_lapic);
+        else
+            size += sizeof(struct acpi_20_madt_x2apic);
+    }
+
+    return size;
+}
+
 static struct acpi_20_madt *construct_madt(struct acpi_ctxt *ctxt,
                                            const struct acpi_config *config,
                                            struct acpi_info *info)
@@ -70,18 +91,14 @@ static struct acpi_20_madt *construct_madt(struct acpi_ctxt 
*ctxt,
     struct acpi_20_madt           *madt;
     struct acpi_20_madt_intsrcovr *intsrcovr;
     struct acpi_20_madt_ioapic    *io_apic;
-    struct acpi_20_madt_lapic     *lapic;
+    void                          *apicid_entry;
     const struct hvm_info_table   *hvminfo = config->hvminfo;
-    int i, sz;
+    unsigned i, sz;
 
     if ( config->lapic_id == NULL )
         return NULL;
 
-    sz  = sizeof(struct acpi_20_madt);
-    sz += sizeof(struct acpi_20_madt_intsrcovr) * 16;
-    sz += sizeof(struct acpi_20_madt_ioapic);
-    sz += sizeof(struct acpi_20_madt_lapic) * hvminfo->nr_vcpus;
-
+    sz = calculate_madt_size(config);
     madt = ctxt->mem_ops.alloc(ctxt, sz, 16);
     if (!madt) return NULL;
 
@@ -134,27 +151,45 @@ static struct acpi_20_madt *construct_madt(struct 
acpi_ctxt *ctxt,
         io_apic->ioapic_id   = config->ioapic_id;
         io_apic->ioapic_addr = config->ioapic_base_address;
 
-        lapic = (struct acpi_20_madt_lapic *)(io_apic + 1);
+        apicid_entry = io_apic + 1;
     }
     else
-        lapic = (struct acpi_20_madt_lapic *)(madt + 1);
+        apicid_entry = madt + 1;
 
     info->nr_cpus = hvminfo->nr_vcpus;
-    info->madt_lapic0_addr = ctxt->mem_ops.v2p(ctxt, lapic);
+    info->madt_lapic0_addr = ctxt->mem_ops.v2p(ctxt, apicid_entry);
     for ( i = 0; i < hvminfo->nr_vcpus; i++ )
     {
-        memset(lapic, 0, sizeof(*lapic));
-        lapic->type    = ACPI_PROCESSOR_LOCAL_APIC;
-        lapic->length  = sizeof(*lapic);
-        /* Processor ID must match processor-object IDs in the DSDT. */
-        lapic->acpi_processor_id = i;
-        lapic->apic_id = config->lapic_id(i);
-        lapic->flags = (test_bit(i, hvminfo->vcpu_online)
-                        ? ACPI_LOCAL_APIC_ENABLED : 0);
-        lapic++;
+        uint32_t apic_id = config->lapic_id(i);
+        if ( apic_id < 255 )
+        {
+            struct acpi_20_madt_lapic *lapic = apicid_entry;
+            memset(lapic, 0, sizeof(*lapic));
+            lapic->type    = ACPI_PROCESSOR_LOCAL_APIC;
+            lapic->length  = sizeof(*lapic);
+            /* Processor ID must match processor-object IDs in the DSDT. */
+            lapic->acpi_processor_id = i;
+            lapic->apic_id = apic_id;
+            lapic->flags = (test_bit(i, hvminfo->vcpu_online)
+                            ? ACPI_LOCAL_APIC_ENABLED : 0);
+            apicid_entry = lapic + 1;
+        }
+        else
+        {
+            struct acpi_20_madt_x2apic *x2apic = apicid_entry;
+            memset(x2apic, 0, sizeof(*x2apic));
+            x2apic->type    = ACPI_PROCESSOR_LOCAL_X2APIC;
+            x2apic->length  = sizeof(*x2apic);
+            x2apic->apic_id = apic_id;
+            x2apic->flags   = (test_bit(i, hvminfo->vcpu_online)
+                                ? ACPI_LOCAL_APIC_ENABLED : 0);
+            /* Processor ID must match processor-object IDs in the DSDT. */
+            x2apic->acpi_processor_id = i;
+            apicid_entry = x2apic + 1;
+        }
     }
 
-    madt->header.length = (unsigned char *)lapic - (unsigned char *)madt;
+    madt->header.length = (unsigned char *)apicid_entry - (unsigned char 
*)madt;
     set_checksum(madt, offsetof(struct acpi_header, checksum),
                  madt->header.length);
     info->madt_csum_addr =
-- 
2.34.1


Reply via email to