123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446 |
- /*++
- Copyright (c) 2014 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- acpi.c
- Abstract:
- This module implements ACPI table support for the UEFI firmware on PC/AT
- BIOS machines.
- Author:
- Evan Green 26-Mar-2014
- Environment:
- Firmware
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/lib/types.h>
- #include <minoca/fw/acpitabs.h>
- #include <minoca/fw/smbios.h>
- #include <uefifw.h>
- #include "biosfw.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the physical address where the EBDA (Extended BIOS Data Area) address
- // is stored.
- //
- #define EBDA_POINTER_ADDRESS 0x40E
- //
- // Define the address and length of the space to search for the RSDP.
- //
- #define RSDP_SEARCH_ADDRESS (PVOID)0xE0000
- #define RSDP_SEARCH_LENGTH 0x20000
- //
- // Define the search parameters for the SMBIOS table.
- //
- #define SMBIOS_SEARCH_START 0xF0000
- #define SMBIOS_SEARCH_END 0x100000
- #define SMBIOS_SEARCH_INCREMENT 0x10
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- PVOID
- EfipPcatSearchForRsdp (
- PVOID Address,
- ULONGLONG Length
- );
- BOOLEAN
- EfipPcatChecksumTable (
- VOID *Address,
- UINT32 Length
- );
- PVOID
- EfipPcatFindSmbiosTable (
- VOID
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // Save a pointer to the RSDP.
- //
- VOID *EfiRsdpPointer;
- extern EFI_GUID EfiSmbiosTableGuid;
- //
- // ------------------------------------------------------------------ Functions
- //
- VOID *
- EfipPcatFindRsdp (
- VOID
- )
- /*++
- Routine Description:
- This routine attempts to find the ACPI RSDP table pointer on a PC-AT
- compatible system. It looks in the first 1k of the EBDA (Extended BIOS Data
- Area), as well as between the ranges 0xE0000 and 0xFFFFF. This routine
- must be run in physical mode.
- Arguments:
- None.
- Return Value:
- Returns a pointer to the RSDP table on success.
- NULL on failure.
- --*/
- {
- UINT16 *EbdaLocationPointer;
- PVOID EbdaPointer;
- PVOID RsdpPointer;
- //
- // Locate the EBDA, whose address is written into a specific offset.
- //
- EbdaLocationPointer = (UINT16 *)EBDA_POINTER_ADDRESS;
- EbdaPointer = (VOID *)(UINTN)*EbdaLocationPointer;
- //
- // Search the first 1k of the EBDA for the RSDP pointer.
- //
- RsdpPointer = EfipPcatSearchForRsdp(EbdaPointer, 1024);
- if (RsdpPointer != NULL) {
- return RsdpPointer;
- }
- //
- // Search the hardcoded range from 0xE0000 to 0xFFFFF.
- //
- RsdpPointer = EfipPcatSearchForRsdp(RSDP_SEARCH_ADDRESS,
- RSDP_SEARCH_LENGTH);
- if (RsdpPointer != NULL) {
- return RsdpPointer;
- }
- return NULL;
- }
- EFI_STATUS
- EfipPcatInstallRsdp (
- VOID
- )
- /*++
- Routine Description:
- This routine installs the RSDP pointer as a configuration table in EFI.
- Arguments:
- None.
- Return Value:
- EFI status.
- --*/
- {
- EFI_GUID *Guid;
- PRSDP Rsdp;
- EFI_STATUS Status;
- Rsdp = EfiRsdpPointer;
- if (Rsdp == NULL) {
- Rsdp = EfipPcatFindRsdp();
- }
- if (Rsdp == NULL) {
- return EFI_UNSUPPORTED;
- }
- if (Rsdp->Revision >= ACPI_20_RSDP_REVISION) {
- Guid = &EfiAcpiTableGuid;
- } else {
- Guid = &EfiAcpiTable1Guid;
- }
- Status = EfiInstallConfigurationTable(Guid, Rsdp);
- return Status;
- }
- EFI_STATUS
- EfipPcatInstallSmbios (
- VOID
- )
- /*++
- Routine Description:
- This routine installs the SMBIOS entry point structure as a configuration
- table in EFI.
- Arguments:
- None.
- Return Value:
- EFI status.
- --*/
- {
- PSMBIOS_ENTRY_POINT SmbiosTable;
- EFI_STATUS Status;
- SmbiosTable = EfipPcatFindSmbiosTable();
- if (SmbiosTable == NULL) {
- return EFI_SUCCESS;
- }
- Status = EfiInstallConfigurationTable(&EfiSmbiosTableGuid, SmbiosTable);
- return Status;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- PVOID
- EfipPcatFindSmbiosTable (
- VOID
- )
- /*++
- Routine Description:
- This routine attempts to find the SMBIOS table entry point structure.
- Arguments:
- None.
- Return Value:
- Returns a pointer to the SMBIOS entry point structure on success.
- NULL on failure.
- --*/
- {
- UINTN CompareIndex;
- PVOID Intermediate;
- UCHAR Length;
- BOOL Match;
- ULONG Offset;
- PSMBIOS_ENTRY_POINT Table;
- //
- // On PC/AT systems, the SMBIOS table entry point resides somewhere between
- // 0xF0000 and 0x100000, aligned to a 16 byte boundary.
- //
- Table = (PSMBIOS_ENTRY_POINT)SMBIOS_SEARCH_START;
- while (Table < (PSMBIOS_ENTRY_POINT)SMBIOS_SEARCH_END) {
- if (Table->AnchorString == SMBIOS_ANCHOR_STRING_VALUE) {
- Length = Table->EntryPointLength;
- //
- // Check the checksum.
- //
- if (EfipPcatChecksumTable(Table, Length) != FALSE) {
- //
- // Also verify and checksum the second part of the table.
- //
- Match = TRUE;
- for (CompareIndex = 0;
- CompareIndex < SMBIOS_INTERMEDIATE_ANCHOR_SIZE;
- CompareIndex += 1) {
- if (Table->IntermediateAnchor[CompareIndex] !=
- SMBIOS_INTERMEDIATE_ANCHOR[CompareIndex]) {
- Match = FALSE;
- break;
- }
- }
- if (Match != FALSE) {
- Offset = OFFSET_OF(SMBIOS_ENTRY_POINT, IntermediateAnchor);
- Length = sizeof(SMBIOS_ENTRY_POINT) - Offset;
- Intermediate = (((PVOID)Table) + Offset);
- //
- // If this also checksums, then the table really is here.
- //
- if (EfipPcatChecksumTable(Intermediate, Length) != FALSE) {
- return Table;
- }
- }
- }
- }
- //
- // Move up 16 bytes to the next candidate position.
- //
- Table = (PSMBIOS_ENTRY_POINT)(((PVOID)Table) + SMBIOS_SEARCH_INCREMENT);
- }
- return NULL;
- }
- VOID *
- EfipPcatSearchForRsdp (
- VOID *Address,
- UINT64 Length
- )
- /*++
- Routine Description:
- This routine searches the given range for the RSDP table.
- Arguments:
- Address - Supplies the starting address to search for the RSDP. This
- address must be 16 byte aligned.
- Length - Supplies the number of bytes to search.
- Return Value:
- Returns a pointer to the RSDP table on success.
- NULL on failure.
- --*/
- {
- UINT64 *CurrentAddress;
- BOOLEAN GoodChecksum;
- CurrentAddress = Address;
- while (Length >= sizeof(UINT64)) {
- if (*CurrentAddress == RSDP_SIGNATURE) {
- GoodChecksum = EfipPcatChecksumTable(CurrentAddress,
- RSDP_CHECKSUM_SIZE);
- if (GoodChecksum != FALSE) {
- return CurrentAddress;
- }
- }
- //
- // Advance by 16 bytes.
- //
- CurrentAddress = (UINT64 *)((UINT8 *)CurrentAddress + 16);
- }
- return NULL;
- }
- BOOLEAN
- EfipPcatChecksumTable (
- VOID *Address,
- UINT32 Length
- )
- /*++
- Routine Description:
- This routine sums all of the bytes in a given table to determine if its
- checksum is correct. The checksum is set such that all the bytes in the
- table sum to a value of 0.
- Arguments:
- Address - Supplies the address of the table to checksum.
- Length - Supplies the length of the table, in bytes.
- Return Value:
- TRUE if all bytes in the table correctly sum to 0.
- FALSE if the bytes don't properly sum to 0.
- --*/
- {
- UINT8 *CurrentByte;
- UINT8 Sum;
- CurrentByte = Address;
- Sum = 0;
- while (Length != 0) {
- Sum += *CurrentByte;
- CurrentByte += 1;
- Length -= 1;
- }
- if (Sum == 0) {
- return TRUE;
- }
- return FALSE;
- }
|