[haiku-commits] r42133 - in haiku/trunk: headers/private/kernel/arch/x86 src/system/boot/platform/bios_ia32

  • From: anevilyak@xxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 13 Jun 2011 00:01:43 +0200 (CEST)

Author: anevilyak
Date: 2011-06-13 00:01:43 +0200 (Mon, 13 Jun 2011)
New Revision: 42133
Changeset: https://dev.haiku-os.org/changeset/42133

Modified:
   haiku/trunk/headers/private/kernel/arch/x86/arch_acpi.h
   haiku/trunk/src/system/boot/platform/bios_ia32/acpi.cpp
Log:
* Add validation of the RSDP checksums.
* If we detect ACPI 2.0 or higher, the spec says we should use the XSDT rather
  than the RSDT. Attempt to do so, falling back to the RSDT if the former fails
  to be mapped/validated.
* Refactored acpi_find_table into a templated version to account for the fact
  that the XSDT exports different pointer widths for its links to other tables
  than the RSDT.



Modified: haiku/trunk/headers/private/kernel/arch/x86/arch_acpi.h
===================================================================
--- haiku/trunk/headers/private/kernel/arch/x86/arch_acpi.h     2011-06-12 
20:51:27 UTC (rev 42132)
+++ haiku/trunk/headers/private/kernel/arch/x86/arch_acpi.h     2011-06-12 
22:01:43 UTC (rev 42133)
@@ -8,22 +8,33 @@
 
 #define ACPI_RSDP_SIGNATURE            "RSD PTR "
 #define ACPI_RSDT_SIGNATURE            "RSDT"
+#define ACPI_XSDT_SIGNATURE            "XSDT"
 #define ACPI_MADT_SIGNATURE            "APIC"
 
 #define ACPI_LOCAL_APIC_ENABLED        0x01
 
-typedef struct acpi_rsdp {
+typedef struct acpi_rsdp_legacy {
        char    signature[8];                   /* "RSD PTR " including blank */
        uint8   checksum;                               /* checksum of bytes 
0-19 (per ACPI 1.0) */
        char    oem_id[6];                              /* not null terminated 
*/
        uint8   revision;                               /* 0 = ACPI 1.0, 2 = 
ACPI 3.0 */
        uint32  rsdt_address;                   /* physical memory address of 
RSDT */
+} _PACKED acpi_rsdp_legacy;
+
+typedef struct acpi_rsdp_extended {
+       char    signature[8];                   /* "RSD PTR " including blank */
+       uint8   checksum;                               /* checksum of bytes 
0-19 (per ACPI 1.0) */
+       char    oem_id[6];                              /* not null terminated 
*/
+       uint8   revision;                               /* 0 = ACPI 1.0, 2 = 
ACPI 3.0 */
+       uint32  rsdt_address;                   /* physical memory address of 
RSDT */
        uint32  xsdt_length;                    /* length in bytes including 
header */
        uint64  xsdt_address;                   /* 64bit physical memory 
address of XSDT */
        uint8   extended_checksum;              /* including entire table */
        uint8   reserved[3];
-} _PACKED acpi_rsdp;
+} _PACKED acpi_rsdp_extended;
 
+typedef acpi_rsdp_extended acpi_rsdp;
+
 typedef struct acpi_descriptor_header {
        char    signature[4];                   /* table identifier as ASCII 
string */
        uint32  length;                                 /* length in bytes of 
the entire table */

Modified: haiku/trunk/src/system/boot/platform/bios_ia32/acpi.cpp
===================================================================
--- haiku/trunk/src/system/boot/platform/bios_ia32/acpi.cpp     2011-06-12 
20:51:27 UTC (rev 42132)
+++ haiku/trunk/src/system/boot/platform/bios_ia32/acpi.cpp     2011-06-12 
22:01:43 UTC (rev 42133)
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2011, Rene Gollent, rene@xxxxxxxxxxxx
  * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved.
  * Copyright 2007, Michael Lotz, mmlr@xxxxxxxx
  * Copyright 2004-2005, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx
@@ -33,10 +34,41 @@
 };
 
 static acpi_descriptor_header* sAcpiRsdt; // System Description Table
+static acpi_descriptor_header* sAcpiXsdt; // Extended System Description Table
 static int32 sNumEntries = -1;
 
 
 static status_t
+acpi_validate_rsdp(acpi_rsdp* rsdp)
+{
+       const char* data = (const char*)rsdp;
+       unsigned char checksum = 0;
+       for (uint32 i = 0; i < sizeof(acpi_rsdp_legacy); i++)
+               checksum += data[i];
+
+       if ((checksum & 0xff) != 0) {
+               TRACE(("acpi: rsdp failed basic checksum\n"));
+               return B_BAD_DATA;
+       }
+
+       // for ACPI 2.0+ we need to also validate the extended checksum
+       if (rsdp->revision > 0) {
+               for (uint32 i = sizeof(acpi_rsdp_legacy);
+                       i < sizeof(acpi_rsdp_extended); i++) {
+                               checksum += data[i];
+               }
+
+               if ((checksum & 0xff) != 0) {
+                       TRACE(("acpi: rsdp failed extended checksum\n"));
+                       return B_BAD_DATA;
+               }
+       }
+
+       return B_OK;
+}
+
+
+static status_t
 acpi_validate_rsdt(acpi_descriptor_header* rsdt)
 {
        const char* data = (const char*)rsdt;
@@ -51,37 +83,66 @@
 static status_t
 acpi_check_rsdt(acpi_rsdp* rsdp)
 {
+       if (acpi_validate_rsdp(rsdp) != B_OK)
+               return B_BAD_DATA;
+
+       bool usingXsdt = false;
+
        TRACE(("acpi: found rsdp at %p oem id: %.6s, rev %d\n",
                rsdp, rsdp->oem_id, rsdp->revision));
        TRACE(("acpi: rsdp points to rsdt at 0x%lx\n", rsdp->rsdt_address));
 
-       // map and validate the root system description table
-       acpi_descriptor_header* rsdt
-               = (acpi_descriptor_header*)mmu_map_physical_memory(
-               rsdp->rsdt_address, sizeof(acpi_descriptor_header),
-               kDefaultPageFlags);
-       if (rsdt == NULL
-               || strncmp(rsdt->signature, ACPI_RSDT_SIGNATURE, 4) != 0) {
-               if (rsdt != NULL)
-                       mmu_free(rsdt, sizeof(acpi_descriptor_header));
-               TRACE(("acpi: invalid root system description table\n"));
-               return B_ERROR;
+       uint32 length = 0;
+       acpi_descriptor_header* rsdt = NULL;
+       if (rsdp->revision > 0) {
+               length = rsdp->xsdt_length;
+               rsdt = (acpi_descriptor_header*)mmu_map_physical_memory(
+                       (uint32)rsdp->xsdt_address, rsdp->xsdt_length, 
kDefaultPageFlags);
+               if (rsdt != NULL
+                       && strncmp(rsdt->signature, ACPI_XSDT_SIGNATURE, 4) != 
0) {
+                       mmu_free(rsdt, rsdp->xsdt_length);
+                       rsdt = NULL;
+                       TRACE(("acpi: invalid extended system description 
table\n"));
+               } else
+                       usingXsdt = true;
        }
 
-       // Map the whole table, not just the header
-       uint32 length = rsdt->length;
-       TRACE(("acpi: rsdt length: %lu\n", length));
-       mmu_free(rsdt, sizeof(acpi_descriptor_header));
+       // if we're ACPI v1 or we fail to map the XSDT for some reason,
+       // attempt to use the RSDT instead.
+       if (rsdt == NULL) {
+               // map and validate the root system description table
+               rsdt = (acpi_descriptor_header*)mmu_map_physical_memory(
+                       rsdp->rsdt_address, sizeof(acpi_descriptor_header),
+                       kDefaultPageFlags);
+               if (rsdt != NULL
+                       && strncmp(rsdt->signature, ACPI_RSDT_SIGNATURE, 4) != 
0) {
+                       mmu_free(rsdt, sizeof(acpi_descriptor_header));
+                       rsdt = NULL;
+                       TRACE(("acpi: invalid root system description 
table\n"));
+                       return B_ERROR;
+               }
 
-       sAcpiRsdt = 
(acpi_descriptor_header*)mmu_map_physical_memory(rsdp->rsdt_address,
-               length, kDefaultPageFlags);
+               length = rsdt->length;
+               // Map the whole table, not just the header
+               TRACE(("acpi: rsdt length: %lu\n", length));
+               mmu_free(rsdt, sizeof(acpi_descriptor_header));
+               rsdt = (acpi_descriptor_header*)mmu_map_physical_memory(
+                       rsdp->rsdt_address, length, kDefaultPageFlags);
+       }
 
-       if (sAcpiRsdt != NULL) {
-               if (acpi_validate_rsdt(sAcpiRsdt) != B_OK) {
-                       TRACE(("acpi: rsdt failed validation\n"));
-                       mmu_free(sAcpiRsdt, length);
-                       sAcpiRsdt = NULL;
+       if (rsdt != NULL) {
+               if (acpi_validate_rsdt(rsdt) != B_OK) {
+                       TRACE(("acpi: rsdt failed checksum validation\n"));
+                       mmu_free(rsdt, length);
                        return B_ERROR;
+               } else {
+                       if (usingXsdt)
+                               sAcpiXsdt = rsdt;
+                       else
+                               sAcpiRsdt = rsdt;
+                       TRACE(("acpi: found valid %s at %p\n",
+                               usingXsdt ? ACPI_XSDT_SIGNATURE : 
ACPI_RSDT_SIGNATURE,
+                               rsdt));
                }
        } else
                return B_ERROR;
@@ -90,15 +151,18 @@
 }
 
 
+template<typename PointerType>
 acpi_descriptor_header*
-acpi_find_table(const char* signature)
+acpi_find_table_generic(const char* signature, acpi_descriptor_header* acpiSdt)
 {
-       if (sAcpiRsdt == NULL)
+       if (acpiSdt == NULL)
                return NULL;
 
        if (sNumEntries == -1) {
-               sNumEntries = (sAcpiRsdt->length
-                       - sizeof(acpi_descriptor_header)) / 4;
+               // if using the xsdt, our entries are 64 bits wide.
+               sNumEntries = (acpiSdt->length
+                       - sizeof(acpi_descriptor_header))
+                               / sizeof(PointerType);
        }
 
        if (sNumEntries <= 0) {
@@ -109,14 +173,15 @@
        TRACE(("acpi: searching %ld entries for table '%.4s'\n", sNumEntries,
                signature));
 
-       uint32* pointer = (uint32*)((uint8*)sAcpiRsdt
+       PointerType* pointer = (PointerType*)((uint8*)acpiSdt
                + sizeof(acpi_descriptor_header));
 
        acpi_descriptor_header* header = NULL;
        for (int32 j = 0; j < sNumEntries; j++, pointer++) {
                header = (acpi_descriptor_header*)
-                       mmu_map_physical_memory(*pointer,
-                                       sizeof(acpi_descriptor_header), 
kDefaultPageFlags);
+                       mmu_map_physical_memory((uint32)*pointer,
+                               sizeof(acpi_descriptor_header), 
kDefaultPageFlags);
+
                if (header == NULL
                        || strncmp(header->signature, signature, 4) != 0) {
                        // not interesting for us
@@ -127,6 +192,7 @@
                                mmu_free(header, 
sizeof(acpi_descriptor_header));
                                header = NULL;
                        }
+
                        continue;
                }
 
@@ -134,7 +200,7 @@
                break;
        }
 
-       
+
        if (header == NULL)
                return NULL;
 
@@ -142,11 +208,23 @@
        uint32 length = header->length;
        mmu_free(header, sizeof(acpi_descriptor_header));
 
-       return (acpi_descriptor_header*)mmu_map_physical_memory(*pointer,
-               length, kDefaultPageFlags);
+       return (acpi_descriptor_header*)mmu_map_physical_memory(
+               (uint32)*pointer, length, kDefaultPageFlags);
 }
 
 
+acpi_descriptor_header*
+acpi_find_table(const char* signature)
+{
+       if (sAcpiRsdt != NULL)
+               return acpi_find_table_generic<uint32>(signature, sAcpiRsdt);
+       else if (sAcpiXsdt != NULL)
+               return acpi_find_table_generic<uint64>(signature, sAcpiXsdt);
+
+       return NULL;
+}
+
+
 void
 acpi_init()
 {


Other related posts:

  • » [haiku-commits] r42133 - in haiku/trunk: headers/private/kernel/arch/x86 src/system/boot/platform/bios_ia32 - anevilyak