From ac33b86c3d0ce7560cf70103669eade0590399b1 Mon Sep 17 00:00:00 2001
From: Rafal Kupiec <belliash@codingworkshop.eu.org>
Date: Sun, 19 May 2024 23:45:28 +0200
Subject: [PATCH] Implement AcGetAcpiTable() routine

---
 sdk/xtdk/bltypes.h        |   2 +
 sdk/xtdk/hltypes.h        |  53 ++++++++++++++++++
 sdk/xtdk/xtstruct.h       |   3 ++
 xtldr/modules/acpi/acpi.c | 110 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 168 insertions(+)

diff --git a/sdk/xtdk/bltypes.h b/sdk/xtdk/bltypes.h
index 4d82aaed..7761edba 100644
--- a/sdk/xtdk/bltypes.h
+++ b/sdk/xtdk/bltypes.h
@@ -110,6 +110,7 @@ typedef VOID (XTAPI *PBL_ZERO_MEMORY)(OUT PVOID Destination, IN SIZE_T Length);
 
 /* Module protocols routine pointers */
 typedef EFI_STATUS (*PBL_ACPI_GET_ACPI_DESCRIPTION_POINTER)(OUT PVOID *AcpiTable);
+typedef EFI_STATUS (*PBL_ACPI_GET_ACPI_TABLE)(IN CONST UINT Signature, IN PVOID PreviousTable, OUT PVOID *AcpiTable);
 typedef EFI_STATUS (*PBL_ACPI_GET_APIC_BASE)(OUT PVOID *ApicBase);
 typedef EFI_STATUS (*PBL_ACPI_GET_RSDP_TABLE)(OUT PVOID *AcpiTable);
 typedef EFI_STATUS (*PBL_ACPI_GET_SMBIOS_TABLE)(OUT PVOID *SmBiosTable);
@@ -301,6 +302,7 @@ typedef struct _XTBL_FRAMEBUFFER_INFORMATION
 typedef struct _XTBL_ACPI_PROTOCOL
 {
     PBL_ACPI_GET_ACPI_DESCRIPTION_POINTER GetAcpiDescriptionPointer;
+    PBL_ACPI_GET_ACPI_TABLE GetAcpiTable;
     PBL_ACPI_GET_APIC_BASE GetApicBase;
     PBL_ACPI_GET_RSDP_TABLE GetRsdpTable;
     PBL_ACPI_GET_SMBIOS_TABLE GetSMBiosTable;
diff --git a/sdk/xtdk/hltypes.h b/sdk/xtdk/hltypes.h
index e6c907cf..47b78432 100644
--- a/sdk/xtdk/hltypes.h
+++ b/sdk/xtdk/hltypes.h
@@ -9,9 +9,27 @@
 #ifndef __XTDK_HLTYPES_H
 #define __XTDK_HLTYPES_H
 
+#include <xtdefs.h>
 #include <xttypes.h>
 
 
+/* ACPI table signatures */
+#define ACPI_APIC_SIGNATURE         0x43495041 /* MADT/APIC Description Table */
+#define ACPI_BGRT_SIGNATURE         0x54524742 /* Boot Graphics Record Table */
+#define ACPI_DBGP_SIGNATURE         0x50474244 /* Debug Port Table */
+#define ACPI_DSDT_SIGNATURE         0x54445344 /* Differentiated System Description Table */
+#define ACPI_FADT_SIGNATURE         0x50434146 /* Fixed ACPI Description Table */
+#define ACPI_GTDT_SIGNATURE         0x54445447 /* Generic Timer Description Table */
+#define ACPI_HPET_SIGNATURE         0x54455048 /* High Precision Event Timer */
+#define ACPI_MCFG_SIGNATURE         0x4746434D /* Memory Mapped Configuration Space Access Table */
+#define ACPI_PSDT_SIGNATURE         0x54445350 /* Persistent System Description Table */
+#define ACPI_RSDT_SIGNATURE         0x54445352 /* Root System Description Table */
+#define ACPI_SBST_SIGNATURE         0x54534253 /* Smart Battery Subsystem Table */
+#define ACPI_SSDT_SIGNATURE         0x54445353 /* Secondary System Descriptor Table */
+#define ACPI_SRAT_SIGNATURE         0x54415253 /* Static Resource Affinity Table */
+#define ACPI_WDTT_SIGNATURE         0x54524457 /* Watchdog Timer Resource Table */
+#define ACPI_XSDT_SIGNATURE         0x54445358 /* eXtended System Descriptor Table */
+
 /* Default serial port settings */
 #define COMPORT_CLOCK_RATE          0x1C200
 #define COMPORT_WAIT_TIMEOUT        204800
@@ -134,6 +152,41 @@ typedef enum _HAL_APIC_MODE
     APIC_MODE_X2APIC
 } HAL_APIC_MODE, *PHAL_APIC_MODE;
 
+/* Each ACPI table description header structure */
+typedef struct _ACPI_DESCRIPTION_HEADER
+{
+    UCHAR Signature[4];
+    ULONG Length;
+    UCHAR Revision;
+    UCHAR Checksum;
+    UCHAR OemId[6];
+    UCHAR OemTableID[8];
+    ULONG OemRevision;
+    UCHAR CreatorID[4];
+    ULONG CreatorRev;
+} PACK ACPI_DESCRIPTION_HEADER, *PACPI_DESCRIPTION_HEADER;
+
+/* ACPI Root System Description Table Pointer structure */
+typedef struct _ACPI_RSDP
+{
+    UCHAR Signature[8];
+    UCHAR Checksum;
+    UCHAR OemId[6];
+    UCHAR Revision;
+    ULONG RsdtAddress;
+    ULONG Length;
+    ULONGLONG XsdtAddress;
+    UCHAR XChecksum;
+    UCHAR Reserved[3];
+} PACK ACPI_RSDP, *PACPI_RSDP;
+
+/* ACPI Root System Description Table structure */
+typedef struct _ACPI_RSDT
+{
+    ACPI_DESCRIPTION_HEADER Header;
+    UCHAR Entries[];
+} PACK ACPI_RSDT, *PACPI_RSDT;
+
 /* Serial (COM) port initial state */
 typedef struct _CPPORT
 {
diff --git a/sdk/xtdk/xtstruct.h b/sdk/xtdk/xtstruct.h
index fa7f9cd6..7d80c832 100644
--- a/sdk/xtdk/xtstruct.h
+++ b/sdk/xtdk/xtstruct.h
@@ -52,6 +52,9 @@ typedef enum _SYSTEM_FIRMWARE_TYPE SYSTEM_FIRMWARE_TYPE, *PSYSTEM_FIRMWARE_TYPE;
 typedef enum _WAIT_TYPE WAIT_TYPE, *PWAIT_TYPE;
 
 /* Structures forward references */
+typedef struct _ACPI_DESCRIPTION_HEADER ACPI_DESCRIPTION_HEADER, *PACPI_DESCRIPTION_HEADER;
+typedef struct _ACPI_RSDP ACPI_RSDP, *PACPI_RSDP;
+typedef struct _ACPI_RSDT ACPI_RSDT, *PACPI_RSDT;
 typedef struct _ANSI_STRING ANSI_STRING, *PANSI_STRING;
 typedef struct _ANSI_STRING32 ANSI_STRING32, *PANSI_STRING32;
 typedef struct _ANSI_STRING64 ANSI_STRING64, *PANSI_STRING64;
diff --git a/xtldr/modules/acpi/acpi.c b/xtldr/modules/acpi/acpi.c
index 55ae86ec..d3910eba 100644
--- a/xtldr/modules/acpi/acpi.c
+++ b/xtldr/modules/acpi/acpi.c
@@ -51,6 +51,115 @@ AcGetAcpiDescriptionPointer(OUT PVOID *AcpiTable)
     return STATUS_EFI_NOT_FOUND;
 }
 
+/**
+ * Finds ACPI description table with given signature.
+ *
+ * @param Signature
+ *        Supplies the signature of the desired ACPI table.
+ *
+ * @param PreviousTable
+ *        Supplies a pointer to the table to start searching from.
+ *
+ * @param AcpiTable
+ *        Supplies a pointer to memory area where ACPI table address will be stored, or NULL if not found.
+ *
+ * @return This routine returns a status code.
+ *
+ * @since XT 1.0
+ */
+XTCDECL
+EFI_STATUS
+AcGetAcpiTable(IN CONST UINT Signature,
+               IN PVOID PreviousTable,
+               OUT PVOID *AcpiTable)
+{
+    PACPI_DESCRIPTION_HEADER TableHeader;
+    SIZE_T RsdtIndex, TableIndex;
+    EFI_STATUS Status;
+    SIZE_T TableCount;
+    PACPI_RSDP Rsdp;
+    PACPI_RSDT Rsdt;
+    BOOLEAN Xsdp;
+
+    /* Return NULL address by default if requested table not found */
+    *AcpiTable = NULL;
+
+    /* Get Root System Description Table Pointer */
+    Status = AcGetAcpiDescriptionPointer((PVOID)&Rsdp);
+    if(Status != STATUS_EFI_SUCCESS)
+    {
+        /* ACPI tables not found, return error */
+        return Status;
+    }
+
+    /* Check if it is XSDP (ACPI 2.0) or RSDP (ACPI 1.0) */
+    if(Rsdp->Revision >= 2 && Rsdp->XsdtAddress)
+    {
+        /* XSDP (ACPI 2.0) */
+        Xsdp = TRUE;
+        Rsdt = (PACPI_RSDT)(UINT_PTR)Rsdp->XsdtAddress;
+        TableCount = (Rsdt->Header.Length - sizeof(ACPI_DESCRIPTION_HEADER)) / 8;
+    }
+    else
+    {
+        /* RSDP (ACPI 1.0) */
+        Xsdp = FALSE;
+        Rsdt = (PACPI_RSDT)(UINT_PTR)Rsdp->RsdtAddress;
+        TableCount = (Rsdt->Header.Length - sizeof(ACPI_DESCRIPTION_HEADER)) / 4;
+    }
+
+    /* Iterate over all ACPI tables */
+    for(TableIndex = 0; TableIndex < TableCount; TableIndex++)
+    {
+        /* Get table headers in reverse order */
+        RsdtIndex = TableCount - TableIndex - 1;
+
+        /* Check if XSDP or RSDT is used */
+        if(Xsdp)
+        {
+            /* Get table header from XSDT */
+            TableHeader = (PACPI_DESCRIPTION_HEADER)(ULONG_PTR)((PULONGLONG)Rsdt->Entries)[RsdtIndex];
+        }
+        else
+        {
+            /* Get table header from RSDT */
+            TableHeader = (PACPI_DESCRIPTION_HEADER)(ULONG_PTR)((PULONG)Rsdt->Entries)[RsdtIndex];
+        }
+
+        /* Make sure table header exists */
+        if(TableHeader == NULL)
+        {
+            /* Skip to next ACPI table */
+            continue;
+        }
+
+        /* Check if previous table provided */
+        if(PreviousTable != NULL)
+        {
+            /* Check if this is a table previously found */
+            if(TableHeader == (PVOID)PreviousTable)
+            {
+                /* Unset previous table */
+                PreviousTable = NULL;
+            }
+
+            /* Skip to next ACPI table */
+            continue;
+        }
+
+        /* Verify table signature and checksum */
+        if((*(PLONG)TableHeader->Signature == Signature) && (AcpChecksumTable(TableHeader, TableHeader->Length) == 0))
+        {
+            /* Found valid ACPI table */
+            *AcpiTable = TableHeader;
+            return STATUS_EFI_SUCCESS;
+        }
+    }
+
+    /* ACPI table not found */
+    return STATUS_EFI_NOT_FOUND;
+}
+
 /**
  * Gets the Advanced Programmable Interrupt Controller (APIC) base address.
  *
@@ -284,6 +393,7 @@ XtLdrModuleMain(IN EFI_HANDLE ImageHandle,
 
     /* Set routines available via ACPI protocol */
     AcpAcpiProtocol.GetAcpiDescriptionPointer = AcGetAcpiDescriptionPointer;
+    AcpAcpiProtocol.GetAcpiTable = AcGetAcpiTable;
     AcpAcpiProtocol.GetApicBase = AcGetApicBase;
     AcpAcpiProtocol.GetRsdpTable = AcGetRsdpTable;
     AcpAcpiProtocol.GetSMBiosTable = AcGetSMBiosTable;