@@ -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,
@@ -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
@@ -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,