XSDT provides pointers to other ACPI tables much like RSDT. However, contrary to RSDT that provides 32-bit addresses, XSDT provides 64-bit pointers. ACPI requires that if XSDT is valid then it takes precedence over RSDT. Signed-off-by: Nikos Nikoleris <nikos.nikoleris@xxxxxxx> --- lib/acpi.h | 6 ++++++ lib/acpi.c | 37 +++++++++++++++++++++++++++++++------ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/lib/acpi.h b/lib/acpi.h index b853a55..c5f0aa5 100644 --- a/lib/acpi.h +++ b/lib/acpi.h @@ -14,6 +14,7 @@ #define RSDP_SIGNATURE ACPI_SIGNATURE('R','S','D','P') #define RSDT_SIGNATURE ACPI_SIGNATURE('R','S','D','T') +#define XSDT_SIGNATURE ACPI_SIGNATURE('X','S','D','T') #define FACP_SIGNATURE ACPI_SIGNATURE('F','A','C','P') #define FACS_SIGNATURE ACPI_SIGNATURE('F','A','C','S') @@ -57,6 +58,11 @@ struct rsdt_descriptor_rev1 { u32 table_offset_entry[1]; }; +struct acpi_table_xsdt { + ACPI_TABLE_HEADER_DEF + u64 table_offset_entry[1]; +}; + struct fadt_descriptor_rev1 { ACPI_TABLE_HEADER_DEF /* ACPI common table header */ diff --git a/lib/acpi.c b/lib/acpi.c index b7fd923..240a922 100644 --- a/lib/acpi.c +++ b/lib/acpi.c @@ -40,6 +40,7 @@ void *find_acpi_table_addr(u32 sig) { struct rsdp_descriptor *rsdp; struct rsdt_descriptor_rev1 *rsdt; + struct acpi_table_xsdt *xsdt = NULL; void *end; int i; @@ -64,17 +65,41 @@ void *find_acpi_table_addr(u32 sig) rsdt = (void *)(ulong)rsdp->rsdt_physical_address; if (!rsdt || rsdt->signature != RSDT_SIGNATURE) - return NULL; + rsdt = NULL; if (sig == RSDT_SIGNATURE) return rsdt; - end = (void *)rsdt + rsdt->length; - for (i = 0; (void *)&rsdt->table_offset_entry[i] < end; i++) { - struct acpi_table *t = (void *)(ulong)rsdt->table_offset_entry[i]; - if (t && t->signature == sig) { - return t; + /* + * When the system implements APCI 2.0 and above and XSDT is + * valid we have use XSDT to find other ACPI tables, + * otherwise, we use RSDT. + */ + if (rsdp->revision == 2) + xsdt = (void *)(ulong)rsdp->xsdt_physical_address; + if (!xsdt || xsdt->signature != XSDT_SIGNATURE) + xsdt = NULL; + + if (sig == XSDT_SIGNATURE) + return xsdt; + + if (xsdt) { + end = (void *)(ulong)xsdt + xsdt->length; + for (i = 0; (void *)&xsdt->table_offset_entry[i] < end; i++) { + struct acpi_table *t = (void *)xsdt->table_offset_entry[i]; + + if (t && t->signature == sig) + return t; + } + } else if (rsdt) { + end = (void *)rsdt + rsdt->length; + for (i = 0; (void *)&rsdt->table_offset_entry[i] < end; i++) { + struct acpi_table *t = (void *)(ulong)rsdt->table_offset_entry[i]; + + if (t && t->signature == sig) + return t; } } + return NULL; } -- 2.25.1