On 4/28/23 20:03, Nikos Nikoleris wrote:
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>
Reviewed-by: Andrew Jones <andrew.jones@xxxxxxxxx>
[ Alex E: Use flexible array member for XSDT struct ]
Signed-off-by: Alexandru Elisei <alexandru.elisei@xxxxxxx>
Reviewed-by: Shaoqin Huang <shahuang@xxxxxxxxxx>
---
lib/acpi.h | 6 ++++++
lib/acpi.c | 40 ++++++++++++++++++++++++++++++++--------
2 files changed, 38 insertions(+), 8 deletions(-)
diff --git a/lib/acpi.h b/lib/acpi.h
index 53e41c4b..74ba00ac 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')
@@ -56,6 +57,11 @@ struct acpi_table_rsdt_rev1 {
u32 table_offset_entry[];
};
+struct acpi_table_xsdt {
+ ACPI_TABLE_HEADER_DEF
+ u64 table_offset_entry[];
+};
+
struct acpi_table_fadt_rev1 {
ACPI_TABLE_HEADER_DEF /* ACPI common table header */
u32 firmware_ctrl; /* Physical address of FACS */
diff --git a/lib/acpi.c b/lib/acpi.c
index 166ffd14..d35f09a6 100644
--- a/lib/acpi.c
+++ b/lib/acpi.c
@@ -37,7 +37,8 @@ static struct acpi_table_rsdp *get_rsdp(void)
void *find_acpi_table_addr(u32 sig)
{
- struct acpi_table_rsdt_rev1 *rsdt;
+ struct acpi_table_rsdt_rev1 *rsdt = NULL;
+ struct acpi_table_xsdt *xsdt = NULL;
struct acpi_table_rsdp *rsdp;
void *end;
int i;
@@ -62,18 +63,41 @@ void *find_acpi_table_addr(u32 sig)
return rsdp;
rsdt = (void *)(ulong) rsdp->rsdt_physical_address;
- if (!rsdt || rsdt->signature != RSDT_SIGNATURE)
- return NULL;
+ if (rsdt && rsdt->signature != RSDT_SIGNATURE)
+ 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 (rsdp->revision >= 2) {
+ xsdt = (void *)rsdp->xsdt_physical_address;
+ if (xsdt && xsdt->signature != XSDT_SIGNATURE)
+ xsdt = NULL;
+ }
- if (t && t->signature == sig)
- return t;
+ if (sig == XSDT_SIGNATURE)
+ return xsdt;
+
+ /*
+ * 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 (xsdt) {
+ end = (void *)xsdt + xsdt->length;
+ for (i = 0; (void *)&xsdt->table_offset_entry[i] < end; i++) {
+ struct acpi_table *t = (void *)(ulong) 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;
--
Shaoqin