forked from xt-sys/exectos
		
	
		
			
				
	
	
		
			440 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			440 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /**
 | |
|  * PROJECT:         ExectOS
 | |
|  * COPYRIGHT:       See COPYING.md in the top level directory
 | |
|  * FILE:            xtldr/modules/acpi/acpi.cc
 | |
|  * DESCRIPTION:     XTLDR ACPI Support Module
 | |
|  * DEVELOPERS:      Rafal Kupiec <belliash@codingworkshop.eu.org>
 | |
|  */
 | |
| 
 | |
| #include <acpi.hh>
 | |
| 
 | |
| 
 | |
| /* ACPI module information */
 | |
| MODULE_AUTHOR(L"Rafal Kupiec <belliash@codingworkshop.eu.org>");
 | |
| MODULE_DESCRIPTION(L"ACPI support");
 | |
| MODULE_LICENSE(L"GPLv3");
 | |
| MODULE_VERSION(L"0.1");
 | |
| 
 | |
| 
 | |
| /**
 | |
|  * Attempts to get XSDP. If it is not found or checksum mismatch, it will try to get RSDP instead.
 | |
|  *
 | |
|  * @param AcpiTable
 | |
|  *        Suplies a pointer to memory area where XSDP or RSRP address will be stored.
 | |
|  *
 | |
|  * @return This routine returns a status code.
 | |
|  *
 | |
|  * @since XT 1.0
 | |
|  */
 | |
| XTCDECL
 | |
| EFI_STATUS
 | |
| Acpi::GetAcpiDescriptionPointer(OUT PVOID *AcpiTable)
 | |
| {
 | |
|     PVOID Rsdp;
 | |
| 
 | |
|     /* Try to get XSDP (ACPI 2.0) from system configuration tables */
 | |
|     if(GetXsdpTable(&Rsdp) == STATUS_EFI_SUCCESS)
 | |
|     {
 | |
|         /* XSDP found, return success */
 | |
|         *AcpiTable = Rsdp;
 | |
|         return STATUS_EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     /* Try to get RSDP (ACPI 1.0) from system configuration tables */
 | |
|     if(GetRsdpTable(&Rsdp) == STATUS_EFI_SUCCESS)
 | |
|     {
 | |
|         /* RSDP found, return success */
 | |
|         *AcpiTable = Rsdp;
 | |
|         return STATUS_EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     /* Neither XSDP nor RSDP found */
 | |
|     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 NULLPTR if not found.
 | |
|  *
 | |
|  * @return This routine returns a status code.
 | |
|  *
 | |
|  * @since XT 1.0
 | |
|  */
 | |
| XTCDECL
 | |
| EFI_STATUS
 | |
| Acpi::GetAcpiTable(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 NULLPTR by default if requested table not found */
 | |
|     *AcpiTable = NULLPTR;
 | |
| 
 | |
|     /* Get Root System Description Table Pointer */
 | |
|     Status = GetAcpiDescriptionPointer((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->Tables)[RsdtIndex];
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             /* Get table header from RSDT */
 | |
|             TableHeader = (PACPI_DESCRIPTION_HEADER)(ULONG_PTR)((PULONG)Rsdt->Tables)[RsdtIndex];
 | |
|         }
 | |
| 
 | |
|         /* Check if previous table provided */
 | |
|         if(PreviousTable != NULLPTR)
 | |
|         {
 | |
|             /* Check if this is a table previously found */
 | |
|             if(TableHeader == (PVOID)PreviousTable)
 | |
|             {
 | |
|                 /* Unset previous table */
 | |
|                 PreviousTable = NULLPTR;
 | |
|             }
 | |
| 
 | |
|             /* Skip to next ACPI table */
 | |
|             continue;
 | |
|         }
 | |
| 
 | |
|         /* Verify table signature */
 | |
|         if((TableHeader->Signature == Signature))
 | |
|         {
 | |
|             /* Found requested ACPI table */
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* Make sure table was found */
 | |
|     if(TableHeader->Signature != Signature)
 | |
|     {
 | |
|         /* ACPI table not found, return error */
 | |
|         return STATUS_EFI_NOT_FOUND;
 | |
|     }
 | |
| 
 | |
|     /* Don't validate FADT on old, broken firmwares with ACPI 2.0 or older */
 | |
|     if(TableHeader->Signature != ACPI_FADT_SIGNATURE || TableHeader->Revision > 2)
 | |
|     {
 | |
|         /* Validate table checksum */
 | |
|         if(!ValidateAcpiTable(TableHeader, TableHeader->Length))
 | |
|         {
 | |
|             /* Checksum mismatch, return error */
 | |
|             return STATUS_EFI_CRC_ERROR;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* Found valid ACPI table, return success */
 | |
|     *AcpiTable = TableHeader;
 | |
|     return STATUS_EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Gets the Advanced Programmable Interrupt Controller (APIC) base address.
 | |
|  *
 | |
|  * @param ApicBase
 | |
|  *        Supplies a pointer to memory area where APIC base address will be stored.
 | |
|  *
 | |
|  * @return This routine returns an EFI status code.
 | |
|  *
 | |
|  * @since XT 1.0
 | |
|  */
 | |
| XTCDECL
 | |
| EFI_STATUS
 | |
| Acpi::GetApicBase(OUT PVOID *ApicBase)
 | |
| {
 | |
|     CPUID_REGISTERS CpuRegisters;
 | |
| 
 | |
|     /* Prepare CPUID registers to query for APIC support */
 | |
|     XtLdrProtocol->Memory.ZeroMemory(&CpuRegisters, sizeof(CPUID_REGISTERS));
 | |
|     CpuRegisters.Leaf = CPUID_GET_STANDARD1_FEATURES;
 | |
| 
 | |
|     /* Query CPUID */
 | |
|     XtLdrProtocol->Cpu.CpuId(&CpuRegisters);
 | |
| 
 | |
|     /* Check if APIC present */
 | |
|     if((CpuRegisters.Edx & CPUID_FEATURES_EDX_APIC) == 0)
 | |
|     {
 | |
|         /* APIC is not supported by the CPU */
 | |
|         return STATUS_EFI_UNSUPPORTED;
 | |
|     }
 | |
| 
 | |
|     /* Get APIC base address */
 | |
|     *ApicBase = (PVOID)((UINT_PTR)XtLdrProtocol->Cpu.ReadModelSpecificRegister(0x1B) & 0xFFFFF000);
 | |
| 
 | |
|     /* Return success */
 | |
|     return STATUS_EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Gets RSDP (ACPI 1.0) from EFI system configuration
 | |
|  *
 | |
|  * @param AcpiTable
 | |
|  *        Suplies a pointer to memory area where RSDP address will be stored.
 | |
|  *
 | |
|  * @return This routine returns a status code.
 | |
|  *
 | |
|  * @since XT 1.0
 | |
|  */
 | |
| XTCDECL
 | |
| EFI_STATUS
 | |
| Acpi::GetRsdpTable(OUT PVOID *AcpiTable)
 | |
| {
 | |
|     EFI_GUID AcpiGuid = EFI_CONFIG_TABLE_ACPI_TABLE_GUID;
 | |
|     EFI_STATUS Status;
 | |
|     PVOID RsdpTable;
 | |
| 
 | |
|     /* Get RSDP (ACPI 1.0) table from system configuration tables */
 | |
|     Status = XtLdrProtocol->Utils.GetConfigurationTable(&AcpiGuid, &RsdpTable);
 | |
|     if(Status != STATUS_EFI_SUCCESS || !ValidateAcpiTable(RsdpTable, 20))
 | |
|     {
 | |
|         /* RSDP not found or checksum mismatch */
 | |
|         *AcpiTable = NULLPTR;
 | |
|         return STATUS_EFI_NOT_FOUND;
 | |
|     }
 | |
| 
 | |
|     /* RSDP found, return success */
 | |
|     *AcpiTable = RsdpTable;
 | |
|     return STATUS_EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Gets SMBIOS from EFI system configuration
 | |
|  *
 | |
|  * @param SmBiosTable
 | |
|  *        Suplies a pointer to memory area where SMBIOS address will be stored.
 | |
|  *
 | |
|  * @return This routine returns a status code.
 | |
|  *
 | |
|  * @since XT 1.0
 | |
|  */
 | |
| XTCDECL
 | |
| EFI_STATUS
 | |
| Acpi::GetSMBiosTable(OUT PVOID *SmBiosTable)
 | |
| {
 | |
|     EFI_GUID SmBiosGuid = EFI_CONFIG_TABLE_SMBIOS_TABLE_GUID;
 | |
|     PSMBIOS_TABLE_HEADER SmBios;
 | |
|     EFI_STATUS Status;
 | |
| 
 | |
|     /* Get SMBIOS table from system configuration tables */
 | |
|     Status = XtLdrProtocol->Utils.GetConfigurationTable(&SmBiosGuid, (PVOID*)&SmBios);
 | |
|     if(Status != STATUS_EFI_SUCCESS || !ValidateAcpiTable(SmBios, SmBios->Length))
 | |
|     {
 | |
|         /* SMBIOS not found or checksum mismatch */
 | |
|         *SmBiosTable = NULLPTR;
 | |
|         return STATUS_EFI_NOT_FOUND;
 | |
|     }
 | |
| 
 | |
|     /* SMBIOS found, return success */
 | |
|     *SmBiosTable = SmBios;
 | |
|     return STATUS_EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Gets SMBIOS3 from EFI system configuration
 | |
|  *
 | |
|  * @param SmBiosTable
 | |
|  *        Suplies a pointer to memory area where SMBIOS3 address will be stored.
 | |
|  *
 | |
|  * @return This routine returns a status code.
 | |
|  *
 | |
|  * @since XT 1.0
 | |
|  */
 | |
| XTCDECL
 | |
| EFI_STATUS
 | |
| Acpi::GetSMBios3Table(OUT PVOID *SmBiosTable)
 | |
| {
 | |
|     EFI_GUID SmBios3Guid = EFI_CONFIG_TABLE_SMBIOS3_TABLE_GUID;
 | |
|     PSMBIOS3_TABLE_HEADER SmBios;
 | |
|     EFI_STATUS Status;
 | |
| 
 | |
|     /* Get SMBIOS3 table from system configuration tables */
 | |
|     Status = XtLdrProtocol->Utils.GetConfigurationTable(&SmBios3Guid, (PVOID*)&SmBios);
 | |
|     if(Status != STATUS_EFI_SUCCESS || !ValidateAcpiTable(SmBios, SmBios->Length))
 | |
|     {
 | |
|         /* SMBIOS3 not found or checksum mismatch */
 | |
|         *SmBiosTable = NULLPTR;
 | |
|         return STATUS_EFI_NOT_FOUND;
 | |
|     }
 | |
| 
 | |
|     /* SMBIOS3 found, return success */
 | |
|     *SmBiosTable = SmBios;
 | |
|     return STATUS_EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Gets XSDP (ACPI 2.0) from EFI system configuration
 | |
|  *
 | |
|  * @param AcpiTable
 | |
|  *        Suplies a pointer to memory area where XSDP address will be stored.
 | |
|  *
 | |
|  * @return This routine returns a status code.
 | |
|  *
 | |
|  * @since XT 1.0
 | |
|  */
 | |
| XTCDECL
 | |
| EFI_STATUS
 | |
| Acpi::GetXsdpTable(OUT PVOID *AcpiTable)
 | |
| {
 | |
|     EFI_GUID AcpiGuid = EFI_CONFIG_TABLE_ACPI20_TABLE_GUID;
 | |
|     EFI_STATUS Status;
 | |
|     PVOID XsdpTable;
 | |
| 
 | |
|     /* Get XSDP (ACPI 2.0) from system configuration tables */
 | |
|     Status = XtLdrProtocol->Utils.GetConfigurationTable(&AcpiGuid, &XsdpTable);
 | |
|     if(Status != STATUS_EFI_SUCCESS || !ValidateAcpiTable(XsdpTable, 36))
 | |
|     {
 | |
|         /* XSDP not found or checksum mismatch */
 | |
|         *AcpiTable = NULLPTR;
 | |
|         return STATUS_EFI_NOT_FOUND;
 | |
|     }
 | |
| 
 | |
|     /* XSDP found, return success */
 | |
|     *AcpiTable = XsdpTable;
 | |
|     return STATUS_EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Initializes ACPI module by opening XTLDR protocol and installing ACPI protocol.
 | |
|  *
 | |
|  * @param ImageHandle
 | |
|  *        Firmware-allocated handle that identifies the image.
 | |
|  *
 | |
|  * @param SystemTable
 | |
|  *        Provides the EFI system table.
 | |
|  *
 | |
|  * @return This routine returns status code.
 | |
|  *
 | |
|  * @since XT 1.0
 | |
|  */
 | |
| XTCDECL
 | |
| EFI_STATUS
 | |
| Acpi::InitializeModule(IN EFI_HANDLE ImageHandle,
 | |
|                        IN PEFI_SYSTEM_TABLE SystemTable)
 | |
| {
 | |
|     EFI_GUID Guid = XT_ACPI_PROTOCOL_GUID;
 | |
|     EFI_STATUS Status;
 | |
| 
 | |
|     /* Open the XTLDR protocol */
 | |
|     Status = BlGetXtLdrProtocol(SystemTable, ImageHandle, &XtLdrProtocol);
 | |
|     if(Status != STATUS_EFI_SUCCESS)
 | |
|     {
 | |
|         /* Failed to open the protocol, return error */
 | |
|         return STATUS_EFI_PROTOCOL_ERROR;
 | |
|     }
 | |
| 
 | |
|     /* Set routines available via ACPI protocol */
 | |
|     AcpiProtocol.GetAcpiDescriptionPointer = GetAcpiDescriptionPointer;
 | |
|     AcpiProtocol.GetAcpiTable = GetAcpiTable;
 | |
|     AcpiProtocol.GetApicBase = GetApicBase;
 | |
|     AcpiProtocol.GetRsdpTable = GetRsdpTable;
 | |
|     AcpiProtocol.GetSMBiosTable = GetSMBiosTable;
 | |
|     AcpiProtocol.GetSMBios3Table = GetSMBios3Table;
 | |
|     AcpiProtocol.GetXsdpTable = GetXsdpTable;
 | |
| 
 | |
|     /* Install ACPI protocol */
 | |
|     return XtLdrProtocol->Protocol.Install(&AcpiProtocol, &Guid);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Validates given ACPI table by calculating its checksum.
 | |
|  *
 | |
|  * @param Buffer
 | |
|  *        Supplies a pointer to the table to checksum.
 | |
|  *
 | |
|  * @param Size
 | |
|  *        Supplies the size of the table, in bytes.
 | |
|  *
 | |
|  * @return This routine returns TRUE if the table is valid, or FALSE otherwise.
 | |
|  *
 | |
|  * @since XT 1.0
 | |
|  */
 | |
| XTCDECL
 | |
| BOOLEAN
 | |
| Acpi::ValidateAcpiTable(IN PVOID Buffer,
 | |
|                         IN UINT_PTR Size)
 | |
| {
 | |
|     PUCHAR Pointer;
 | |
|     UCHAR Sum;
 | |
| 
 | |
|     /* Initialize variables */
 | |
|     Sum = 0;
 | |
|     Pointer = (PUCHAR)Buffer;
 | |
| 
 | |
|     /* Calculate checksum of given table */
 | |
|     while(Size != 0)
 | |
|     {
 | |
|         Sum = (UCHAR)(Sum + *Pointer);
 | |
|         Pointer += 1;
 | |
|         Size -= 1;
 | |
|     }
 | |
| 
 | |
|     /* Return calculated checksum */
 | |
|     return (Sum == 0) ? TRUE : FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * This routine is the entry point of the XT EFI boot loader module.
 | |
|  *
 | |
|  * @param ImageHandle
 | |
|  *        Firmware-allocated handle that identifies the image.
 | |
|  *
 | |
|  * @param SystemTable
 | |
|  *        Provides the EFI system table.
 | |
|  *
 | |
|  * @return This routine returns status code.
 | |
|  *
 | |
|  * @since XT 1.0
 | |
|  */
 | |
| XTCDECL
 | |
| EFI_STATUS
 | |
| XtLdrModuleMain(IN EFI_HANDLE ImageHandle,
 | |
|                 IN PEFI_SYSTEM_TABLE SystemTable)
 | |
| {
 | |
|     /* Initialize ACPI module */
 | |
|     return Acpi::InitializeModule(ImageHandle, SystemTable);
 | |
| }
 |