diff mbox

[RFC,3/7] hw/arm/virt-acpi: Generate RSDP and XSDT, add helper functions

Message ID 1414691643-5593-1-git-send-email-a.spyridakis@virtualopensystems.com
State New
Headers show

Commit Message

Alexander Spyridakis Oct. 30, 2014, 5:54 p.m. UTC
RSDP points to XSDT which in turn points to other tables.
In the case of RSDP things are straightforward as we can point
to XSDT just by adding the binary blob base address plus the size
of RSDP.

For XSDT we traverse the table array and point every other table
by calculating their size (exception being FACS and DSDT which
are pointed from FADT).

Finally implement a common header and checksum helper functions
for usage in all generated ACPI tables.

Signed-off-by: Alexander Spyridakis <a.spyridakis@virtualopensystems.com>
Signed-off-by: Alvise Rigo <a.rigo@virtualopensystems.com>
---
 hw/arm/virt-acpi.c          | 93 +++++++++++++++++++++++++++++++++++++++++++--
 include/hw/acpi/acpi-defs.h |  9 +++++
 include/hw/arm/virt-acpi.h  |  6 +++
 3 files changed, 104 insertions(+), 4 deletions(-)
diff mbox

Patch

diff --git a/hw/arm/virt-acpi.c b/hw/arm/virt-acpi.c
index 5c8df45..0d7bb99 100644
--- a/hw/arm/virt-acpi.c
+++ b/hw/arm/virt-acpi.c
@@ -21,16 +21,101 @@ 
 static void *acpi_table[NUM_ACPI_TABLES];
 static int acpi_size[NUM_ACPI_TABLES];
 
+/*
+ * Many of the ACPI tables use the same header structure
+ * This is a common function to fill such information.
+ */
+static void acpi_fill_common_header_data(void *table, const char *signature,
+                                               uint8_t revision, int length)
+{
+    AcpiTableHeader *h = (AcpiTableHeader *)table;
+
+    memcpy(&h->signature, signature, sizeof(h->signature));
+    memcpy(h->oem_id, ACPI_VIRT_QEMU_STR_4, sizeof(h->oem_id));
+    memcpy(h->oem_table_id, ACPI_VIRT_MACH_STR_8, sizeof(h->oem_table_id));
+    h->revision = revision;
+    h->length = cpu_to_le32(length);
+}
+
+/*
+ * Called at the very end of an ACPI table.
+ * Adding all the data bytes, plus the checksum should equal to zero.
+ */
+static void acpi_do_checksum(void *table, uint32_t length, uint8_t *checksum)
+{
+    uint8_t sum, *ptr;
+
+    sum = 0;
+    ptr = table;
+
+    *checksum = 0;
+    while (length--) {
+        sum = (uint8_t)(sum + (*ptr++));
+    }
+
+    ptr = table;
+    *checksum = (uint8_t) (0xff - sum + 1);
+}
+
 static void acpi_create_rsdp(void)
 {
-    acpi_table[RSDP] = NULL;
-    acpi_size[RSDP] = 0;
+    AcpiRsdpDescriptor *rsdp;
+
+    rsdp = g_malloc0(sizeof(*rsdp));
+
+    /* Set table header information */
+    memcpy(&rsdp->signature, "RSD PTR ", sizeof(rsdp->signature));
+    memcpy(rsdp->oem_id, ACPI_VIRT_QEMU_STR_6, sizeof(rsdp->oem_id));
+    rsdp->length = cpu_to_le32(sizeof(*rsdp));
+    rsdp->revision = 0x02;
+
+    /* Point to XSDT */
+    rsdp->xsdt_physical_address = cpu_to_le64(ACPI_BASE_ADDRESS + rsdp->length);
+
+    /* Calculate normal and extended checksum */
+    acpi_do_checksum(rsdp,
+        offsetof(AcpiRsdpDescriptor, length), &rsdp->checksum);
+    acpi_do_checksum(rsdp, rsdp->length, &rsdp->extended_checksum);
+
+    acpi_table[RSDP] = (void *)rsdp;
+    acpi_size[RSDP] = rsdp->length;
 }
 
 static void acpi_create_xsdt(void)
 {
-    acpi_table[XSDT] = NULL;
-    acpi_size[XSDT] = 0;
+    AcpiXsdtDescriptor *xsdt;
+    int i, xsdt_size;
+
+    /*
+     * The final size of XSDT is the table size plus the number
+     * of pointed tables multiplied by the table_offset_entry size.
+     *
+     * The initial xsdt table size already includes one pointed table and
+     * assuming that FADT is the last pointed table we can calculate the
+     * total based on that.
+     */
+    xsdt_size = sizeof(*xsdt) +
+        ((FADT - (XSDT + 1)) * sizeof(xsdt->table_offset_entry));
+    xsdt = g_malloc0(xsdt_size);
+
+    /* Set table header information */
+    acpi_fill_common_header_data(xsdt, "XSDT", 1, xsdt_size);
+
+    /* Point first table included by default in the xsdt structure */
+    xsdt->table_offset_entry[0] = cpu_to_le64(
+        ACPI_BASE_ADDRESS + acpi_size[RSDP] + xsdt->length);
+
+    /* Point all other tables (excluding FACS and DSDT) */
+    for (i = XSDT; i < FADT - 1; i++) {
+        xsdt->table_offset_entry[i] =
+            xsdt->table_offset_entry[i - 1] + acpi_size[i + 1];
+    }
+
+    /* Calculate checksum */
+    acpi_do_checksum(xsdt, xsdt->length, &xsdt->checksum);
+
+    acpi_table[XSDT] = (void *)xsdt;
+    acpi_size[XSDT] = xsdt->length;
 }
 
 static void acpi_create_madt(uint32_t smp_cpus,
diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h
index c4468f8..779f872 100644
--- a/include/hw/acpi/acpi-defs.h
+++ b/include/hw/acpi/acpi-defs.h
@@ -88,6 +88,15 @@  struct AcpiTableHeader         /* ACPI common table header */
 typedef struct AcpiTableHeader AcpiTableHeader;
 
 /*
+ * Extended System Description Table (XSDT)
+ */
+struct AcpiXsdtDescriptor {
+    ACPI_TABLE_HEADER_DEF
+    uint64_t table_offset_entry[1]; /* Array of pointers to ACPI tables */
+} QEMU_PACKED;
+typedef struct AcpiXsdtDescriptor AcpiXsdtDescriptor;
+
+/*
  * ACPI 1.0 Fixed ACPI Description Table (FADT)
  */
 struct AcpiFadtDescriptorRev1
diff --git a/include/hw/arm/virt-acpi.h b/include/hw/arm/virt-acpi.h
index 5098118..66a73eb 100644
--- a/include/hw/arm/virt-acpi.h
+++ b/include/hw/arm/virt-acpi.h
@@ -23,6 +23,12 @@ 
 
 #define NUM_ACPI_TABLES 7
 
+#define ACPI_VIRT_QEMU_STR_4 "QEMU"
+#define ACPI_VIRT_QEMU_STR_6 "QEMU  "
+#define ACPI_VIRT_MACH_STR_8 "MACHVIRT"
+
+#define ACPI_BASE_ADDRESS 0x47000000
+
 enum {
     RSDP,
     XSDT,