bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v2 gnumach] ACPI: Support XSDT (ACPI >= v2.0)


From: Damien Zammit
Subject: [PATCH v2 gnumach] ACPI: Support XSDT (ACPI >= v2.0)
Date: Tue, 30 Jan 2024 08:04:38 +0000

This enables gnumach to additionally parse the XSDT table
if the revision of ACPI is 2.

NB: I removed a few checksum checks in acpi tables where
there is no checksum present in the table.

TESTED: Still works on qemu (ACPI v1.0)
TESTED: Works on a x86 board with XSDT (ACPI v2.0)

---
 i386/i386at/acpi_parse_apic.c | 243 ++++++++++++++++++++++------------
 i386/i386at/acpi_parse_apic.h |  18 ++-
 i386/i386at/model_dep.c       |   8 +-
 3 files changed, 180 insertions(+), 89 deletions(-)

diff --git a/i386/i386at/acpi_parse_apic.c b/i386/i386at/acpi_parse_apic.c
index 1aef53ed..476d846e 100644
--- a/i386/i386at/acpi_parse_apic.c
+++ b/i386/i386at/acpi_parse_apic.c
@@ -43,13 +43,12 @@ unsigned lapic_addr;
  * and the number of entries stored in RSDT.
  */
 void
-acpi_print_info(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, int 
acpi_rsdt_n)
+acpi_print_info(phys_addr_t rsdp, void *rsdt, int acpi_rsdt_n)
 {
 
     printf("ACPI:\n");
-    printf(" rsdp = %p; rsdp->rsdt_addr = %x\n", rsdp, rsdp->rsdt_addr);
-    printf(" rsdt = %p; rsdt->length = %x (n = %x)\n", rsdt, 
rsdt->header.length,
-           acpi_rsdt_n);
+    printf(" rsdp = 0x%lx\n", rsdp);
+    printf(" rsdt/xsdt = 0x%p (n = %d)\n", rsdt, acpi_rsdt_n);
 }
 
 /*
@@ -69,6 +68,8 @@ acpi_checksum(void *addr, uint32_t length)
     for (i = 0; i < length; i++)
         checksum += bytes[i];
 
+    printf("checksum result = 0x%x\n", checksum);
+
     return checksum;
 }
 
@@ -99,27 +100,45 @@ acpi_check_signature(const uint8_t table_signature[], 
const char *real_signature
  *
  * Preconditions: RSDP pointer must not be NULL.
  *
- * Returns 0 if correct.
+ * Returns 1 if ACPI 1.0 and sets sdt_base
+ * Returns 2 if ACPI >= 2.0 and sets sdt_base
  */
 static int8_t
-acpi_check_rsdp(struct acpi_rsdp *rsdp)
+acpi_check_rsdp(struct acpi_rsdp2 *rsdp, phys_addr_t *sdt_base)
 {
-    uint32_t checksum;
     int is_rsdp;
+    uint8_t cksum;
 
     /* Check if rsdp signature match with the ACPI RSDP signature. */
-    is_rsdp = acpi_check_signature(rsdp->signature, ACPI_RSDP_SIG, 
8*sizeof(uint8_t));
+    is_rsdp = acpi_check_signature(rsdp->v1.signature, ACPI_RSDP_SIG, 
8*sizeof(uint8_t));
 
     if (is_rsdp != ACPI_SUCCESS)
         return ACPI_BAD_SIGNATURE;
 
-    /* If match, calculates rdsp checksum and check It. */
-    checksum = acpi_checksum(rsdp, sizeof(struct acpi_rsdp));
+    if (rsdp->v1.revision == 0) {
+        // ACPI 1.0
+        *sdt_base = rsdp->v1.rsdt_addr;
+        printf("ACPI v1.0\n");
+        cksum = acpi_checksum((void *)(&rsdp->v1), sizeof(struct acpi_rsdp));
 
-    if (checksum != 0)
-        return ACPI_BAD_CHECKSUM;
+        if (cksum != 0)
+            return ACPI_BAD_CHECKSUM;
 
-    return ACPI_SUCCESS;
+        return 1;
+
+    } else if (rsdp->v1.revision == 2) {
+        // ACPI >= 2.0
+        *sdt_base = rsdp->xsdt_addr;
+        printf("ACPI >= v2.0\n");
+        cksum = acpi_checksum((void *)rsdp, sizeof(struct acpi_rsdp2));
+
+        if (cksum != 0)
+            return ACPI_BAD_CHECKSUM;
+
+        return 2;
+    }
+
+    return ACPI_NO_RSDP;
 }
 
 /*
@@ -147,38 +166,41 @@ acpi_check_rsdp_align(void *addr)
  *
  * Preconditions: The start address (addr) must be aligned.
  *
- * Returns the reference to rsdp structure if success, NULL if failure.
+ * Returns the physical address of rsdp structure if success, 0 if failure.
  */
-static struct acpi_rsdp*
-acpi_search_rsdp(void *addr, uint32_t length)
+static phys_addr_t
+acpi_search_rsdp(void *addr, uint32_t length, int *is_64bit)
 {
     void *end;
+    int version = 0;
+    phys_addr_t sdt_base = 0;
 
     /* Search RDSP in memory space between addr and addr+lenght. */
     for (end = addr+length; addr < end; addr += ACPI_RSDP_ALIGN) {
 
         /* Check if the current memory block stores the RDSP. */
-        if ((addr != NULL) && (acpi_check_rsdp(addr) == ACPI_SUCCESS)) {
-            /* If yes, return RSDP address */
-            return (struct acpi_rsdp*) addr;
+        if ((addr != NULL) && ((version = acpi_check_rsdp(addr, &sdt_base)) > 
0)) {
+            /* If yes, return RSDT/XSDT address */
+            *is_64bit = (version == 2);
+            return sdt_base;
         }
     }
 
-    return NULL;
+    return 0;
 }
 
 /*
  * acpi_get_rsdp: tries to find the RSDP table,
  * searching It in many memory ranges, as It's written in ACPI Specification.
  *
- * Returns the reference to RDSP structure if success, NULL if failure.
+ * Returns the reference to RDSP structure if success, 0 if failure.
  */
-static struct acpi_rsdp*
-acpi_get_rsdp(void)
+static phys_addr_t
+acpi_get_rsdp(int *is_64bit)
 {
     uint16_t *start = 0;
     phys_addr_t base = 0;
-    struct acpi_rsdp *rsdp = NULL;
+    phys_addr_t rsdp = 0;
 
     /* EDBA start address. */
     start = (uint16_t*) phystokv(0x040e);
@@ -186,40 +208,17 @@ acpi_get_rsdp(void)
 
     /* check alignment. */
     if (acpi_check_rsdp_align((void *)base) == ACPI_BAD_ALIGN)
-        return NULL;
-    rsdp = acpi_search_rsdp((void *)base, 1024);
+        return 0;
+    rsdp = acpi_search_rsdp((void *)base, 1024, is_64bit);
 
-    if (rsdp == NULL) {
+    if (rsdp == 0) {
         /* If RSDP isn't in EDBA, search in the BIOS read-only memory space 
between 0E0000h and 0FFFFFh */
-        rsdp = acpi_search_rsdp((void *)phystokv(0xe0000), 0x100000 - 
0x0e0000);
+        rsdp = acpi_search_rsdp((void *)phystokv(0xe0000), 0x100000 - 
0x0e0000, is_64bit);
     }
 
     return rsdp;
 }
 
-/*
- * acpi_check_rsdt: check if the RSDT initial address is correct
- * checking its checksum.
- *
- * Receives as input a reference for the RSDT "candidate" table.
- * Returns 0 if success.
- *
- * Preconditions: rsdp must not be NULL.
- *
- */
-static int
-acpi_check_rsdt(struct acpi_rsdt *rsdt)
-{
-    uint8_t checksum;
-
-    checksum = acpi_checksum(rsdt, rsdt->header.length);
-
-    if (checksum != 0)
-        return ACPI_BAD_CHECKSUM;
-
-    return ACPI_SUCCESS;
-}
-
 /*
  * acpi_get_rsdt: Get RSDT table reference from RSDP entries.
  *
@@ -229,16 +228,12 @@ acpi_check_rsdt(struct acpi_rsdt *rsdt)
  * Returns the reference to RSDT table if success, NULL if error.
  */
 static struct acpi_rsdt*
-acpi_get_rsdt(struct acpi_rsdp *rsdp, int* acpi_rsdt_n)
+acpi_get_rsdt(phys_addr_t rsdp_phys, int* acpi_rsdt_n)
 {
-    phys_addr_t rsdt_phys;
     struct acpi_rsdt *rsdt = NULL;
-    int acpi_check;
     int signature_check;
 
-    /* Get rsdt address from rsdp table. */
-    rsdt_phys = rsdp->rsdt_addr;
-    rsdt = (struct acpi_rsdt*) kmem_map_aligned_table(rsdt_phys, sizeof(struct 
acpi_rsdt), VM_PROT_READ);
+    rsdt = (struct acpi_rsdt*) kmem_map_aligned_table(rsdp_phys, sizeof(struct 
acpi_rsdt), VM_PROT_READ);
 
     /* Check if the RSDT mapping is fine. */
     if (rsdt == NULL)
@@ -251,12 +246,6 @@ acpi_get_rsdt(struct acpi_rsdp *rsdp, int* acpi_rsdt_n)
     if (signature_check != ACPI_SUCCESS)
         return NULL;
 
-    /* Check if rsdt is correct. */
-    acpi_check = acpi_check_rsdt(rsdt);
-
-    if (acpi_check != ACPI_SUCCESS)
-        return NULL;
-
     /* Calculated number of elements stored in rsdt. */
     *acpi_rsdt_n = (rsdt->header.length - sizeof(rsdt->header))
                    / sizeof(rsdt->entry[0]);
@@ -264,6 +253,40 @@ acpi_get_rsdt(struct acpi_rsdp *rsdp, int* acpi_rsdt_n)
     return rsdt;
 }
 
+/*
+ * acpi_get_xsdt: Get XSDT table reference from RSDPv2 entries.
+ *
+ * Receives as input a reference for RSDPv2 table
+ * and a reference to store the number of entries of XSDT.
+ *
+ * Returns the reference to XSDT table if success, NULL if error.
+ */
+static struct acpi_xsdt*
+acpi_get_xsdt(phys_addr_t rsdp_phys, int* acpi_xsdt_n)
+{
+    struct acpi_xsdt *xsdt = NULL;
+    int signature_check;
+
+    xsdt = (struct acpi_xsdt*) kmem_map_aligned_table(rsdp_phys, sizeof(struct 
acpi_xsdt), VM_PROT_READ);
+
+    /* Check if the RSDT mapping is fine. */
+    if (xsdt == NULL)
+        return NULL;
+
+    /* Check is rsdt signature is equals to ACPI RSDT signature. */
+    signature_check = acpi_check_signature(xsdt->header.signature, 
ACPI_XSDT_SIG,
+                                           4*sizeof(uint8_t));
+
+    if (signature_check != ACPI_SUCCESS)
+        return NULL;
+
+    /* Calculated number of elements stored in rsdt. */
+    *acpi_xsdt_n = (xsdt->header.length - sizeof(xsdt->header))
+                   / sizeof(xsdt->entry[0]);
+
+    return xsdt;
+}
+
 /*
  * acpi_get_apic: get MADT/APIC table from RSDT entries.
  *
@@ -295,6 +318,37 @@ acpi_get_apic(struct acpi_rsdt *rsdt, int acpi_rsdt_n)
     return NULL;
 }
 
+/*
+ * acpi_get_apic2: get MADT/APIC table from XSDT entries.
+ *
+ * Receives as input the XSDT initial address,
+ * and the number of entries of XSDT table.
+ *
+ * Returns a reference to APIC/MADT table if success, NULL if failure.
+ */
+static struct acpi_apic*
+acpi_get_apic2(struct acpi_xsdt *xsdt, int acpi_xsdt_n)
+{
+    struct acpi_dhdr *descr_header;
+    int check_signature;
+
+    /* Search APIC entries in rsdt table. */
+    for (int i = 0; i < acpi_xsdt_n; i++) {
+        descr_header = (struct acpi_dhdr*) 
kmem_map_aligned_table(xsdt->entry[i], sizeof(struct acpi_dhdr),
+                                                                  
VM_PROT_READ);
+
+        /* Check if the entry contains an APIC. */
+        check_signature = acpi_check_signature(descr_header->signature, 
ACPI_APIC_SIG, 4*sizeof(uint8_t));
+
+        if (check_signature == ACPI_SUCCESS) {
+            /* If yes, return the APIC. */
+            return (struct acpi_apic*) descr_header;
+        }
+    }
+
+    return NULL;
+}
+
 /*
  * acpi_add_lapic: add a new Local APIC to cpu_to_lapic array
  * and increase the number of cpus.
@@ -382,6 +436,8 @@ acpi_apic_parse_table(struct acpi_apic *apic)
     /* Get the end address of APIC table */
     end = (vm_offset_t) apic + apic->header.length;
 
+    printf("APIC entry=0x%p end=0x%x\n", apic_entry, end);
+
     /* Initialize number of cpus */
     numcpus = apic_get_numcpus();
 
@@ -391,6 +447,7 @@ acpi_apic_parse_table(struct acpi_apic *apic)
         struct acpi_apic_ioapic *ioapic_entry;
         struct acpi_apic_irq_override *irq_override_entry;
 
+        printf("APIC entry=0x%p end=0x%x\n", apic_entry, end);
         /* Check entry type. */
         switch(apic_entry->type) {
 
@@ -421,6 +478,9 @@ acpi_apic_parse_table(struct acpi_apic *apic)
             break;
 
         /* FIXME: There is another unhandled case */
+       default:
+           printf("Unhandled APIC entry type 0x%x\n", apic_entry->type);
+           break;
         }
 
         /* Get next APIC entry. */
@@ -452,16 +512,9 @@ acpi_apic_parse_table(struct acpi_apic *apic)
 static int
 acpi_apic_setup(struct acpi_apic *apic)
 {
-    int apic_checksum;
     ApicLocalUnit* lapic_unit;
     uint8_t ncpus, nioapics;
 
-    /* Check the checksum of the APIC */
-    apic_checksum = acpi_checksum(apic, apic->header.length);
-
-    if(apic_checksum != 0)
-        return ACPI_BAD_CHECKSUM;
-
     /* map common lapic address */
     lapic_addr = apic->lapic_addr;
     lapic_unit = kmem_map_aligned_table(apic->lapic_addr, 
sizeof(ApicLocalUnit),
@@ -502,29 +555,47 @@ acpi_apic_setup(struct acpi_apic *apic)
 int
 acpi_apic_init(void)
 {
-    struct acpi_rsdp *rsdp = 0;
+    phys_addr_t rsdp = 0;
     struct acpi_rsdt *rsdt = 0;
+    struct acpi_xsdt *xsdt = 0;
     int acpi_rsdt_n;
     int ret_acpi_setup;
     int apic_init_success = 0;
+    int is_64bit = 0;
 
-    /* Try to get the RSDP pointer. */
-    rsdp = acpi_get_rsdp();
-    if (rsdp == NULL)
+    /* Try to get the RSDP physical address. */
+    rsdp = acpi_get_rsdp(&is_64bit);
+    if (rsdp == 0)
         return ACPI_NO_RSDP;
 
-    /* Try to get the RSDT pointer. */
-    rsdt = acpi_get_rsdt(rsdp, &acpi_rsdt_n);
-    if (rsdt == NULL)
-        return ACPI_NO_RSDT;
-
-    /* Try to get the APIC table pointer. */
-    apic_madt = acpi_get_apic(rsdt, acpi_rsdt_n);
-    if (apic_madt == NULL)
-        return ACPI_NO_APIC;
-
-    /* Print the ACPI tables addresses. */
-    acpi_print_info(rsdp, rsdt, acpi_rsdt_n);
+    if (!is_64bit) {
+        /* Try to get the RSDT pointer. */
+        rsdt = acpi_get_rsdt(rsdp, &acpi_rsdt_n);
+        if (rsdt == NULL)
+            return ACPI_NO_RSDT;
+
+        /* Try to get the APIC table pointer. */
+        apic_madt = acpi_get_apic(rsdt, acpi_rsdt_n);
+        if (apic_madt == NULL)
+            return ACPI_NO_APIC;
+
+        /* Print the ACPI tables addresses. */
+        acpi_print_info(rsdp, rsdt, acpi_rsdt_n);
+
+    } else {
+       /* Try to get the XSDT pointer. */
+        xsdt = acpi_get_xsdt(rsdp, &acpi_rsdt_n);
+        if (xsdt == NULL)
+            return ACPI_NO_RSDT;
+
+        /* Try to get the APIC table pointer. */
+        apic_madt = acpi_get_apic2(xsdt, acpi_rsdt_n);
+        if (apic_madt == NULL)
+            return ACPI_NO_APIC;
+
+        /* Print the ACPI tables addresses. */
+        acpi_print_info(rsdp, xsdt, acpi_rsdt_n);
+    }
 
     apic_init_success = apic_data_init();
     if (apic_init_success != ACPI_SUCCESS)
diff --git a/i386/i386at/acpi_parse_apic.h b/i386/i386at/acpi_parse_apic.h
index bad10054..df36bb31 100644
--- a/i386/i386at/acpi_parse_apic.h
+++ b/i386/i386at/acpi_parse_apic.h
@@ -44,10 +44,17 @@ struct acpi_rsdp {
     uint8_t    signature[8];
     uint8_t    checksum;
     uint8_t    oem_id[6];
-    uint8_t    revision[1];
+    uint8_t    revision;
     uint32_t   rsdt_addr;
 } __attribute__((__packed__));
 
+struct acpi_rsdp2 {
+    struct acpi_rsdp v1;
+    uint32_t   length;
+    uint64_t   xsdt_addr;
+    uint8_t    checksum;
+    uint8_t    reserved[3];
+} __attribute__((__packed__));
 
 /*
  * RSDT Entry Header
@@ -77,6 +84,13 @@ struct acpi_rsdt {
     uint32_t                   entry[0];
 } __attribute__((__packed__));
 
+#define ACPI_XSDT_SIG "XSDT"
+
+struct acpi_xsdt {
+    struct acpi_dhdr   header;
+    uint64_t                   entry[0];
+} __attribute__((__packed__));
+
 /* APIC table signature. */
 #define ACPI_APIC_SIG "APIC"
 
@@ -157,7 +171,7 @@ struct acpi_apic_irq_override {
 } __attribute__((__packed__));
 
 int acpi_apic_init(void);
-void acpi_print_info(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, int 
acpi_rsdt_n);
+void acpi_print_info(phys_addr_t rsdp, void *rsdt, int acpi_rsdt_n);
 
 extern unsigned lapic_addr;
 
diff --git a/i386/i386at/model_dep.c b/i386/i386at/model_dep.c
index fb95029f..a53556e7 100644
--- a/i386/i386at/model_dep.c
+++ b/i386/i386at/model_dep.c
@@ -163,7 +163,13 @@ void machine_init(void)
        hyp_init();
 #else  /* MACH_HYP */
 #if defined(APIC)
-       acpi_apic_init();
+       int err;
+
+       err = acpi_apic_init();
+       if (err) {
+               printf("acpi_apic_init failed with %d\n", err);
+               for (;;);
+       }
 #endif
 #if (NCPUS > 1)
        smp_init();
-- 
2.43.0





reply via email to

[Prev in Thread] Current Thread [Next in Thread]