diff options
| author | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
|---|---|---|
| committer | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
| commit | 7e2ccccace24636f29ddc210b94606abd4c7e42b (patch) | |
| tree | 545d43ea12671048956cafeb12303e84d601e571 /MdeModulePkg/Core/Dxe/Misc | |
| parent | 27b044605cd5f6b33a3d231576003850b3fe305b (diff) | |
| download | edk2-trunk.tar.xz | |
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'MdeModulePkg/Core/Dxe/Misc')
| -rw-r--r-- | MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c | 564 | ||||
| -rwxr-xr-x | MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c | 358 | ||||
| -rw-r--r-- | MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c | 1374 | ||||
| -rw-r--r-- | MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c | 2220 | ||||
| -rw-r--r-- | MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c | 132 | ||||
| -rw-r--r-- | MdeModulePkg/Core/Dxe/Misc/Stall.c | 218 |
6 files changed, 2433 insertions, 2433 deletions
diff --git a/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c b/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c index eeb18f6e47..7b96806686 100644 --- a/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c +++ b/MdeModulePkg/Core/Dxe/Misc/DebugImageInfo.c @@ -1,282 +1,282 @@ -/** @file
- Support functions for managing debug image info table when loading and unloading
- images.
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-
-EFI_DEBUG_IMAGE_INFO_TABLE_HEADER mDebugInfoTableHeader = {
- 0, // volatile UINT32 UpdateStatus;
- 0, // UINT32 TableSize;
- NULL // EFI_DEBUG_IMAGE_INFO *EfiDebugImageInfoTable;
-};
-
-UINTN mMaxTableEntries = 0;
-
-EFI_SYSTEM_TABLE_POINTER *mDebugTable = NULL;
-
-#define EFI_DEBUG_TABLE_ENTRY_SIZE (sizeof (VOID *))
-
-/**
- Creates and initializes the DebugImageInfo Table. Also creates the configuration
- table and registers it into the system table.
-
-**/
-VOID
-CoreInitializeDebugImageInfoTable (
- VOID
- )
-{
- EFI_STATUS Status;
- UINTN Pages;
- EFI_PHYSICAL_ADDRESS Memory;
- UINTN AlignedMemory;
- UINTN AlignmentMask;
- UINTN UnalignedPages;
- UINTN RealPages;
-
- //
- // Allocate 4M aligned page for the structure and fill in the data.
- // Ideally we would update the CRC now as well, but the service may not yet be available.
- // See comments in the CoreUpdateDebugTableCrc32() function below for details.
- //
- Pages = EFI_SIZE_TO_PAGES (sizeof (EFI_SYSTEM_TABLE_POINTER));
- AlignmentMask = SIZE_4MB - 1;
- RealPages = Pages + EFI_SIZE_TO_PAGES (SIZE_4MB);
-
- //
- // Attempt to allocate memory below PcdMaxEfiSystemTablePointerAddress
- // If PcdMaxEfiSystemTablePointerAddress is 0, then allocate memory below
- // MAX_ADDRESS
- //
- Memory = PcdGet64 (PcdMaxEfiSystemTablePointerAddress);
- if (Memory == 0) {
- Memory = MAX_ADDRESS;
- }
-
- Status = CoreAllocatePages (
- AllocateMaxAddress,
- EfiBootServicesData,
- RealPages,
- &Memory
- );
- if (EFI_ERROR (Status)) {
- if (PcdGet64 (PcdMaxEfiSystemTablePointerAddress) != 0) {
- DEBUG ((DEBUG_INFO, "Allocate memory for EFI_SYSTEM_TABLE_POINTER below PcdMaxEfiSystemTablePointerAddress failed. \
- Retry to allocate memroy as close to the top of memory as feasible.\n"));
- }
-
- //
- // If the initial memory allocation fails, then reattempt allocation
- // as close to the top of memory as feasible.
- //
- Status = CoreAllocatePages (
- AllocateAnyPages,
- EfiBootServicesData,
- RealPages,
- &Memory
- );
- ASSERT_EFI_ERROR (Status);
- if (EFI_ERROR (Status)) {
- return;
- }
- }
-
- //
- // Free overallocated pages
- //
- AlignedMemory = ((UINTN)Memory + AlignmentMask) & ~AlignmentMask;
- UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN)Memory);
- if (UnalignedPages > 0) {
- //
- // Free first unaligned page(s).
- //
- Status = CoreFreePages (Memory, UnalignedPages);
- ASSERT_EFI_ERROR (Status);
- }
-
- Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages);
- UnalignedPages = RealPages - Pages - UnalignedPages;
- if (UnalignedPages > 0) {
- //
- // Free last unaligned page(s).
- //
- Status = CoreFreePages (Memory, UnalignedPages);
- ASSERT_EFI_ERROR (Status);
- }
-
- //
- // Set mDebugTable to the 4MB aligned allocated pages
- //
- mDebugTable = (EFI_SYSTEM_TABLE_POINTER *)(AlignedMemory);
- ASSERT (mDebugTable != NULL);
-
- //
- // Initialize EFI_SYSTEM_TABLE_POINTER structure
- //
- mDebugTable->Signature = EFI_SYSTEM_TABLE_SIGNATURE;
- mDebugTable->EfiSystemTableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)gDxeCoreST;
- mDebugTable->Crc32 = 0;
-
- //
- // Install the EFI_SYSTEM_TABLE_POINTER structure in the EFI System
- // Configuration Table
- //
- Status = CoreInstallConfigurationTable (&gEfiDebugImageInfoTableGuid, &mDebugInfoTableHeader);
- ASSERT_EFI_ERROR (Status);
-}
-
-/**
- Update the CRC32 in the Debug Table.
- Since the CRC32 service is made available by the Runtime driver, we have to
- wait for the Runtime Driver to be installed before the CRC32 can be computed.
- This function is called elsewhere by the core when the runtime architectural
- protocol is produced.
-
-**/
-VOID
-CoreUpdateDebugTableCrc32 (
- VOID
- )
-{
- ASSERT (mDebugTable != NULL);
- mDebugTable->Crc32 = 0;
- gBS->CalculateCrc32 ((VOID *)mDebugTable, sizeof (EFI_SYSTEM_TABLE_POINTER), &mDebugTable->Crc32);
-}
-
-/**
- Adds a new DebugImageInfo structure to the DebugImageInfo Table. Re-Allocates
- the table if it's not large enough to accomidate another entry.
-
- @param ImageInfoType type of debug image information
- @param LoadedImage pointer to the loaded image protocol for the image being
- loaded
- @param ImageHandle image handle for the image being loaded
-
-**/
-VOID
-CoreNewDebugImageInfoEntry (
- IN UINT32 ImageInfoType,
- IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
- IN EFI_HANDLE ImageHandle
- )
-{
- EFI_DEBUG_IMAGE_INFO *Table;
- EFI_DEBUG_IMAGE_INFO *NewTable;
- UINTN Index;
- UINTN TableSize;
-
- //
- // Set the flag indicating that we're in the process of updating the table.
- //
- mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
-
- Table = mDebugInfoTableHeader.EfiDebugImageInfoTable;
-
- if (mDebugInfoTableHeader.TableSize < mMaxTableEntries) {
- //
- // We still have empty entires in the Table, find the first empty entry.
- //
- Index = 0;
- while (Table[Index].NormalImage != NULL) {
- Index++;
- }
-
- //
- // There must be an empty entry in the in the table.
- //
- ASSERT (Index < mMaxTableEntries);
- } else {
- //
- // Table is full, so re-allocate another page for a larger table...
- //
- TableSize = mMaxTableEntries * EFI_DEBUG_TABLE_ENTRY_SIZE;
- NewTable = AllocateZeroPool (TableSize + EFI_PAGE_SIZE);
- if (NewTable == NULL) {
- mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
- return;
- }
-
- //
- // Copy the old table into the new one
- //
- CopyMem (NewTable, Table, TableSize);
- //
- // Free the old table
- //
- CoreFreePool (Table);
- //
- // Update the table header
- //
- Table = NewTable;
- mDebugInfoTableHeader.EfiDebugImageInfoTable = NewTable;
- //
- // Enlarge the max table entries and set the first empty entry index to
- // be the original max table entries.
- //
- Index = mMaxTableEntries;
- mMaxTableEntries += EFI_PAGE_SIZE / EFI_DEBUG_TABLE_ENTRY_SIZE;
- }
-
- //
- // Allocate data for new entry
- //
- Table[Index].NormalImage = AllocateZeroPool (sizeof (EFI_DEBUG_IMAGE_INFO_NORMAL));
- if (Table[Index].NormalImage != NULL) {
- //
- // Update the entry
- //
- Table[Index].NormalImage->ImageInfoType = (UINT32)ImageInfoType;
- Table[Index].NormalImage->LoadedImageProtocolInstance = LoadedImage;
- Table[Index].NormalImage->ImageHandle = ImageHandle;
- //
- // Increase the number of EFI_DEBUG_IMAGE_INFO elements and set the mDebugInfoTable in modified status.
- //
- mDebugInfoTableHeader.TableSize++;
- mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED;
- }
-
- mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
-}
-
-/**
- Removes and frees an entry from the DebugImageInfo Table.
-
- @param ImageHandle image handle for the image being unloaded
-
-**/
-VOID
-CoreRemoveDebugImageInfoEntry (
- EFI_HANDLE ImageHandle
- )
-{
- EFI_DEBUG_IMAGE_INFO *Table;
- UINTN Index;
-
- mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
-
- Table = mDebugInfoTableHeader.EfiDebugImageInfoTable;
-
- for (Index = 0; Index < mMaxTableEntries; Index++) {
- if ((Table[Index].NormalImage != NULL) && (Table[Index].NormalImage->ImageHandle == ImageHandle)) {
- //
- // Found a match. Free up the record, then NULL the pointer to indicate the slot
- // is free.
- //
- CoreFreePool (Table[Index].NormalImage);
- Table[Index].NormalImage = NULL;
- //
- // Decrease the number of EFI_DEBUG_IMAGE_INFO elements and set the mDebugInfoTable in modified status.
- //
- mDebugInfoTableHeader.TableSize--;
- mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED;
- break;
- }
- }
-
- mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
-}
+/** @file + Support functions for managing debug image info table when loading and unloading + images. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DxeMain.h" + +EFI_DEBUG_IMAGE_INFO_TABLE_HEADER mDebugInfoTableHeader = { + 0, // volatile UINT32 UpdateStatus; + 0, // UINT32 TableSize; + NULL // EFI_DEBUG_IMAGE_INFO *EfiDebugImageInfoTable; +}; + +UINTN mMaxTableEntries = 0; + +EFI_SYSTEM_TABLE_POINTER *mDebugTable = NULL; + +#define EFI_DEBUG_TABLE_ENTRY_SIZE (sizeof (VOID *)) + +/** + Creates and initializes the DebugImageInfo Table. Also creates the configuration + table and registers it into the system table. + +**/ +VOID +CoreInitializeDebugImageInfoTable ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Pages; + EFI_PHYSICAL_ADDRESS Memory; + UINTN AlignedMemory; + UINTN AlignmentMask; + UINTN UnalignedPages; + UINTN RealPages; + + // + // Allocate 4M aligned page for the structure and fill in the data. + // Ideally we would update the CRC now as well, but the service may not yet be available. + // See comments in the CoreUpdateDebugTableCrc32() function below for details. + // + Pages = EFI_SIZE_TO_PAGES (sizeof (EFI_SYSTEM_TABLE_POINTER)); + AlignmentMask = SIZE_4MB - 1; + RealPages = Pages + EFI_SIZE_TO_PAGES (SIZE_4MB); + + // + // Attempt to allocate memory below PcdMaxEfiSystemTablePointerAddress + // If PcdMaxEfiSystemTablePointerAddress is 0, then allocate memory below + // MAX_ADDRESS + // + Memory = PcdGet64 (PcdMaxEfiSystemTablePointerAddress); + if (Memory == 0) { + Memory = MAX_ADDRESS; + } + + Status = CoreAllocatePages ( + AllocateMaxAddress, + EfiBootServicesData, + RealPages, + &Memory + ); + if (EFI_ERROR (Status)) { + if (PcdGet64 (PcdMaxEfiSystemTablePointerAddress) != 0) { + DEBUG ((DEBUG_INFO, "Allocate memory for EFI_SYSTEM_TABLE_POINTER below PcdMaxEfiSystemTablePointerAddress failed. \ + Retry to allocate memroy as close to the top of memory as feasible.\n")); + } + + // + // If the initial memory allocation fails, then reattempt allocation + // as close to the top of memory as feasible. + // + Status = CoreAllocatePages ( + AllocateAnyPages, + EfiBootServicesData, + RealPages, + &Memory + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return; + } + } + + // + // Free overallocated pages + // + AlignedMemory = ((UINTN)Memory + AlignmentMask) & ~AlignmentMask; + UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN)Memory); + if (UnalignedPages > 0) { + // + // Free first unaligned page(s). + // + Status = CoreFreePages (Memory, UnalignedPages); + ASSERT_EFI_ERROR (Status); + } + + Memory = AlignedMemory + EFI_PAGES_TO_SIZE (Pages); + UnalignedPages = RealPages - Pages - UnalignedPages; + if (UnalignedPages > 0) { + // + // Free last unaligned page(s). + // + Status = CoreFreePages (Memory, UnalignedPages); + ASSERT_EFI_ERROR (Status); + } + + // + // Set mDebugTable to the 4MB aligned allocated pages + // + mDebugTable = (EFI_SYSTEM_TABLE_POINTER *)(AlignedMemory); + ASSERT (mDebugTable != NULL); + + // + // Initialize EFI_SYSTEM_TABLE_POINTER structure + // + mDebugTable->Signature = EFI_SYSTEM_TABLE_SIGNATURE; + mDebugTable->EfiSystemTableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)gDxeCoreST; + mDebugTable->Crc32 = 0; + + // + // Install the EFI_SYSTEM_TABLE_POINTER structure in the EFI System + // Configuration Table + // + Status = CoreInstallConfigurationTable (&gEfiDebugImageInfoTableGuid, &mDebugInfoTableHeader); + ASSERT_EFI_ERROR (Status); +} + +/** + Update the CRC32 in the Debug Table. + Since the CRC32 service is made available by the Runtime driver, we have to + wait for the Runtime Driver to be installed before the CRC32 can be computed. + This function is called elsewhere by the core when the runtime architectural + protocol is produced. + +**/ +VOID +CoreUpdateDebugTableCrc32 ( + VOID + ) +{ + ASSERT (mDebugTable != NULL); + mDebugTable->Crc32 = 0; + gBS->CalculateCrc32 ((VOID *)mDebugTable, sizeof (EFI_SYSTEM_TABLE_POINTER), &mDebugTable->Crc32); +} + +/** + Adds a new DebugImageInfo structure to the DebugImageInfo Table. Re-Allocates + the table if it's not large enough to accomidate another entry. + + @param ImageInfoType type of debug image information + @param LoadedImage pointer to the loaded image protocol for the image being + loaded + @param ImageHandle image handle for the image being loaded + +**/ +VOID +CoreNewDebugImageInfoEntry ( + IN UINT32 ImageInfoType, + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, + IN EFI_HANDLE ImageHandle + ) +{ + EFI_DEBUG_IMAGE_INFO *Table; + EFI_DEBUG_IMAGE_INFO *NewTable; + UINTN Index; + UINTN TableSize; + + // + // Set the flag indicating that we're in the process of updating the table. + // + mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; + + Table = mDebugInfoTableHeader.EfiDebugImageInfoTable; + + if (mDebugInfoTableHeader.TableSize < mMaxTableEntries) { + // + // We still have empty entires in the Table, find the first empty entry. + // + Index = 0; + while (Table[Index].NormalImage != NULL) { + Index++; + } + + // + // There must be an empty entry in the in the table. + // + ASSERT (Index < mMaxTableEntries); + } else { + // + // Table is full, so re-allocate another page for a larger table... + // + TableSize = mMaxTableEntries * EFI_DEBUG_TABLE_ENTRY_SIZE; + NewTable = AllocateZeroPool (TableSize + EFI_PAGE_SIZE); + if (NewTable == NULL) { + mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; + return; + } + + // + // Copy the old table into the new one + // + CopyMem (NewTable, Table, TableSize); + // + // Free the old table + // + CoreFreePool (Table); + // + // Update the table header + // + Table = NewTable; + mDebugInfoTableHeader.EfiDebugImageInfoTable = NewTable; + // + // Enlarge the max table entries and set the first empty entry index to + // be the original max table entries. + // + Index = mMaxTableEntries; + mMaxTableEntries += EFI_PAGE_SIZE / EFI_DEBUG_TABLE_ENTRY_SIZE; + } + + // + // Allocate data for new entry + // + Table[Index].NormalImage = AllocateZeroPool (sizeof (EFI_DEBUG_IMAGE_INFO_NORMAL)); + if (Table[Index].NormalImage != NULL) { + // + // Update the entry + // + Table[Index].NormalImage->ImageInfoType = (UINT32)ImageInfoType; + Table[Index].NormalImage->LoadedImageProtocolInstance = LoadedImage; + Table[Index].NormalImage->ImageHandle = ImageHandle; + // + // Increase the number of EFI_DEBUG_IMAGE_INFO elements and set the mDebugInfoTable in modified status. + // + mDebugInfoTableHeader.TableSize++; + mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED; + } + + mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; +} + +/** + Removes and frees an entry from the DebugImageInfo Table. + + @param ImageHandle image handle for the image being unloaded + +**/ +VOID +CoreRemoveDebugImageInfoEntry ( + EFI_HANDLE ImageHandle + ) +{ + EFI_DEBUG_IMAGE_INFO *Table; + UINTN Index; + + mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; + + Table = mDebugInfoTableHeader.EfiDebugImageInfoTable; + + for (Index = 0; Index < mMaxTableEntries; Index++) { + if ((Table[Index].NormalImage != NULL) && (Table[Index].NormalImage->ImageHandle == ImageHandle)) { + // + // Found a match. Free up the record, then NULL the pointer to indicate the slot + // is free. + // + CoreFreePool (Table[Index].NormalImage); + Table[Index].NormalImage = NULL; + // + // Decrease the number of EFI_DEBUG_IMAGE_INFO elements and set the mDebugInfoTable in modified status. + // + mDebugInfoTableHeader.TableSize--; + mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED; + break; + } + } + + mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS; +} diff --git a/MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c b/MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c index f47f3bd804..70fb4dd337 100755 --- a/MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c +++ b/MdeModulePkg/Core/Dxe/Misc/InstallConfigurationTable.c @@ -1,179 +1,179 @@ -/** @file
- UEFI Miscellaneous boot Services InstallConfigurationTable service
-
-Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-
-#define CONFIG_TABLE_SIZE_INCREASED 0x10
-
-UINTN mSystemTableAllocateSize = 0;
-
-/**
- Boot Service called to add, modify, or remove a system configuration table from
- the EFI System Table.
-
- @param Guid Pointer to the GUID for the entry to add, update, or
- remove
- @param Table Pointer to the configuration table for the entry to add,
- update, or remove, may be NULL.
-
- @return EFI_SUCCESS Guid, Table pair added, updated, or removed.
- @return EFI_INVALID_PARAMETER Input GUID is NULL.
- @return EFI_NOT_FOUND Attempted to delete non-existant entry
- @return EFI_OUT_OF_RESOURCES Not enough memory available
-
-**/
-EFI_STATUS
-EFIAPI
-CoreInstallConfigurationTable (
- IN EFI_GUID *Guid,
- IN VOID *Table
- )
-{
- UINTN Index;
- EFI_CONFIGURATION_TABLE *EfiConfigurationTable;
- EFI_CONFIGURATION_TABLE *OldTable;
-
- //
- // If Guid is NULL, then this operation cannot be performed
- //
- if (Guid == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- EfiConfigurationTable = gDxeCoreST->ConfigurationTable;
-
- //
- // Search all the table for an entry that matches Guid
- //
- for (Index = 0; Index < gDxeCoreST->NumberOfTableEntries; Index++) {
- if (CompareGuid (Guid, &(gDxeCoreST->ConfigurationTable[Index].VendorGuid))) {
- break;
- }
- }
-
- if (Index < gDxeCoreST->NumberOfTableEntries) {
- //
- // A match was found, so this is either a modify or a delete operation
- //
- if (Table != NULL) {
- //
- // If Table is not NULL, then this is a modify operation.
- // Modify the table entry and return.
- //
- gDxeCoreST->ConfigurationTable[Index].VendorTable = Table;
-
- //
- // Signal Configuration Table change
- //
- CoreNotifySignalList (Guid);
-
- return EFI_SUCCESS;
- }
-
- //
- // A match was found and Table is NULL, so this is a delete operation.
- //
- gDxeCoreST->NumberOfTableEntries--;
-
- //
- // Copy over deleted entry
- //
- CopyMem (
- &(EfiConfigurationTable[Index]),
- &(gDxeCoreST->ConfigurationTable[Index + 1]),
- (gDxeCoreST->NumberOfTableEntries - Index) * sizeof (EFI_CONFIGURATION_TABLE)
- );
- } else {
- //
- // No matching GUIDs were found, so this is an add operation.
- //
-
- if (Table == NULL) {
- //
- // If Table is NULL on an add operation, then return an error.
- //
- return EFI_NOT_FOUND;
- }
-
- //
- // Assume that Index == gDxeCoreST->NumberOfTableEntries
- //
- if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mSystemTableAllocateSize) {
- //
- // Allocate a table with one additional entry.
- //
- mSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE));
- EfiConfigurationTable = AllocateRuntimePool (mSystemTableAllocateSize);
- if (EfiConfigurationTable == NULL) {
- //
- // If a new table could not be allocated, then return an error.
- //
- return EFI_OUT_OF_RESOURCES;
- }
-
- if (gDxeCoreST->ConfigurationTable != NULL) {
- //
- // Copy the old table to the new table.
- //
- CopyMem (
- EfiConfigurationTable,
- gDxeCoreST->ConfigurationTable,
- Index * sizeof (EFI_CONFIGURATION_TABLE)
- );
-
- //
- // Record the old table pointer.
- //
- OldTable = gDxeCoreST->ConfigurationTable;
-
- //
- // As the CoreInstallConfigurationTable() may be re-entered by CoreFreePool()
- // in its calling stack, updating System table to the new table pointer must
- // be done before calling CoreFreePool() to free the old table.
- // It can make sure the gDxeCoreST->ConfigurationTable point to the new table
- // and avoid the errors of use-after-free to the old table by the reenter of
- // CoreInstallConfigurationTable() in CoreFreePool()'s calling stack.
- //
- gDxeCoreST->ConfigurationTable = EfiConfigurationTable;
-
- //
- // Free the old table after updating System Table to the new table pointer.
- //
- CoreFreePool (OldTable);
- } else {
- //
- // Update System Table
- //
- gDxeCoreST->ConfigurationTable = EfiConfigurationTable;
- }
- }
-
- //
- // Fill in the new entry
- //
- CopyGuid ((VOID *)&EfiConfigurationTable[Index].VendorGuid, Guid);
- EfiConfigurationTable[Index].VendorTable = Table;
-
- //
- // This is an add operation, so increment the number of table entries
- //
- gDxeCoreST->NumberOfTableEntries++;
- }
-
- //
- // Fix up the CRC-32 in the EFI System Table
- //
- CalculateEfiHdrCrc (&gDxeCoreST->Hdr);
-
- //
- // Signal Configuration Table change
- //
- CoreNotifySignalList (Guid);
-
- return EFI_SUCCESS;
-}
+/** @file + UEFI Miscellaneous boot Services InstallConfigurationTable service + +Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DxeMain.h" + +#define CONFIG_TABLE_SIZE_INCREASED 0x10 + +UINTN mSystemTableAllocateSize = 0; + +/** + Boot Service called to add, modify, or remove a system configuration table from + the EFI System Table. + + @param Guid Pointer to the GUID for the entry to add, update, or + remove + @param Table Pointer to the configuration table for the entry to add, + update, or remove, may be NULL. + + @return EFI_SUCCESS Guid, Table pair added, updated, or removed. + @return EFI_INVALID_PARAMETER Input GUID is NULL. + @return EFI_NOT_FOUND Attempted to delete non-existant entry + @return EFI_OUT_OF_RESOURCES Not enough memory available + +**/ +EFI_STATUS +EFIAPI +CoreInstallConfigurationTable ( + IN EFI_GUID *Guid, + IN VOID *Table + ) +{ + UINTN Index; + EFI_CONFIGURATION_TABLE *EfiConfigurationTable; + EFI_CONFIGURATION_TABLE *OldTable; + + // + // If Guid is NULL, then this operation cannot be performed + // + if (Guid == NULL) { + return EFI_INVALID_PARAMETER; + } + + EfiConfigurationTable = gDxeCoreST->ConfigurationTable; + + // + // Search all the table for an entry that matches Guid + // + for (Index = 0; Index < gDxeCoreST->NumberOfTableEntries; Index++) { + if (CompareGuid (Guid, &(gDxeCoreST->ConfigurationTable[Index].VendorGuid))) { + break; + } + } + + if (Index < gDxeCoreST->NumberOfTableEntries) { + // + // A match was found, so this is either a modify or a delete operation + // + if (Table != NULL) { + // + // If Table is not NULL, then this is a modify operation. + // Modify the table entry and return. + // + gDxeCoreST->ConfigurationTable[Index].VendorTable = Table; + + // + // Signal Configuration Table change + // + CoreNotifySignalList (Guid); + + return EFI_SUCCESS; + } + + // + // A match was found and Table is NULL, so this is a delete operation. + // + gDxeCoreST->NumberOfTableEntries--; + + // + // Copy over deleted entry + // + CopyMem ( + &(EfiConfigurationTable[Index]), + &(gDxeCoreST->ConfigurationTable[Index + 1]), + (gDxeCoreST->NumberOfTableEntries - Index) * sizeof (EFI_CONFIGURATION_TABLE) + ); + } else { + // + // No matching GUIDs were found, so this is an add operation. + // + + if (Table == NULL) { + // + // If Table is NULL on an add operation, then return an error. + // + return EFI_NOT_FOUND; + } + + // + // Assume that Index == gDxeCoreST->NumberOfTableEntries + // + if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mSystemTableAllocateSize) { + // + // Allocate a table with one additional entry. + // + mSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE)); + EfiConfigurationTable = AllocateRuntimePool (mSystemTableAllocateSize); + if (EfiConfigurationTable == NULL) { + // + // If a new table could not be allocated, then return an error. + // + return EFI_OUT_OF_RESOURCES; + } + + if (gDxeCoreST->ConfigurationTable != NULL) { + // + // Copy the old table to the new table. + // + CopyMem ( + EfiConfigurationTable, + gDxeCoreST->ConfigurationTable, + Index * sizeof (EFI_CONFIGURATION_TABLE) + ); + + // + // Record the old table pointer. + // + OldTable = gDxeCoreST->ConfigurationTable; + + // + // As the CoreInstallConfigurationTable() may be re-entered by CoreFreePool() + // in its calling stack, updating System table to the new table pointer must + // be done before calling CoreFreePool() to free the old table. + // It can make sure the gDxeCoreST->ConfigurationTable point to the new table + // and avoid the errors of use-after-free to the old table by the reenter of + // CoreInstallConfigurationTable() in CoreFreePool()'s calling stack. + // + gDxeCoreST->ConfigurationTable = EfiConfigurationTable; + + // + // Free the old table after updating System Table to the new table pointer. + // + CoreFreePool (OldTable); + } else { + // + // Update System Table + // + gDxeCoreST->ConfigurationTable = EfiConfigurationTable; + } + } + + // + // Fill in the new entry + // + CopyGuid ((VOID *)&EfiConfigurationTable[Index].VendorGuid, Guid); + EfiConfigurationTable[Index].VendorTable = Table; + + // + // This is an add operation, so increment the number of table entries + // + gDxeCoreST->NumberOfTableEntries++; + } + + // + // Fix up the CRC-32 in the EFI System Table + // + CalculateEfiHdrCrc (&gDxeCoreST->Hdr); + + // + // Signal Configuration Table change + // + CoreNotifySignalList (Guid); + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c b/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c index e9343a2c4e..9abd79b9e4 100644 --- a/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c +++ b/MdeModulePkg/Core/Dxe/Misc/MemoryAttributesTable.c @@ -1,687 +1,687 @@ -/** @file
- UEFI MemoryAttributesTable support
-
-Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiDxe.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/DxeServicesTableLib.h>
-#include <Library/DebugLib.h>
-#include <Library/UefiLib.h>
-#include <Library/ImagePropertiesRecordLib.h>
-
-#include <Guid/EventGroup.h>
-
-#include <Guid/MemoryAttributesTable.h>
-
-#include "DxeMain.h"
-#include "HeapGuard.h"
-
-/**
- This function for GetMemoryMap() with properties table capability.
-
- It calls original GetMemoryMap() to get the original memory map information. Then
- plus the additional memory map entries for PE Code/Data seperation.
-
- @param MemoryMapSize A pointer to the size, in bytes, of the
- MemoryMap buffer. On input, this is the size of
- the buffer allocated by the caller. On output,
- it is the size of the buffer returned by the
- firmware if the buffer was large enough, or the
- size of the buffer needed to contain the map if
- the buffer was too small.
- @param MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param MapKey A pointer to the location in which firmware
- returns the key for the current memory map.
- @param DescriptorSize A pointer to the location in which firmware
- returns the size, in bytes, of an individual
- EFI_MEMORY_DESCRIPTOR.
- @param DescriptorVersion A pointer to the location in which firmware
- returns the version number associated with the
- EFI_MEMORY_DESCRIPTOR.
-
- @retval EFI_SUCCESS The memory map was returned in the MemoryMap
- buffer.
- @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
- buffer size needed to hold the memory map is
- returned in MemoryMapSize.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreGetMemoryMapWithSeparatedImageSection (
- IN OUT UINTN *MemoryMapSize,
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- OUT UINTN *MapKey,
- OUT UINTN *DescriptorSize,
- OUT UINT32 *DescriptorVersion
- );
-
-#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
- ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
-
-#define IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I','P','P','D')
-
-typedef struct {
- UINT32 Signature;
- UINTN ImageRecordCount;
- UINTN CodeSegmentCountMax;
- LIST_ENTRY ImageRecordList;
-} IMAGE_PROPERTIES_PRIVATE_DATA;
-
-STATIC IMAGE_PROPERTIES_PRIVATE_DATA mImagePropertiesPrivateData = {
- IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE,
- 0,
- 0,
- INITIALIZE_LIST_HEAD_VARIABLE (mImagePropertiesPrivateData.ImageRecordList)
-};
-
-STATIC EFI_LOCK mMemoryAttributesTableLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
-
-BOOLEAN mMemoryAttributesTableEnable = TRUE;
-BOOLEAN mMemoryAttributesTableEndOfDxe = FALSE;
-EFI_MEMORY_ATTRIBUTES_TABLE *mMemoryAttributesTable = NULL;
-BOOLEAN mMemoryAttributesTableReadyToBoot = FALSE;
-BOOLEAN gMemoryAttributesTableForwardCfi = TRUE;
-
-/**
- Install MemoryAttributesTable.
-
-**/
-VOID
-InstallMemoryAttributesTable (
- VOID
- )
-{
- UINTN MemoryMapSize;
- EFI_MEMORY_DESCRIPTOR *MemoryMap;
- EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
- UINTN MapKey;
- UINTN DescriptorSize;
- UINT32 DescriptorVersion;
- UINTN Index;
- EFI_STATUS Status;
- UINT32 RuntimeEntryCount;
- EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
- EFI_MEMORY_DESCRIPTOR *MemoryAttributesEntry;
-
- if (gMemoryMapTerminated) {
- //
- // Directly return after MemoryMap terminated.
- //
- return;
- }
-
- if (!mMemoryAttributesTableEnable) {
- DEBUG ((DEBUG_VERBOSE, "Cannot install Memory Attributes Table "));
- DEBUG ((DEBUG_VERBOSE, "because Runtime Driver Section Alignment is not %dK.\n", RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10));
- return;
- }
-
- if (mMemoryAttributesTable == NULL) {
- //
- // InstallConfigurationTable here to occupy one entry for MemoryAttributesTable
- // before GetMemoryMap below, as InstallConfigurationTable may allocate runtime
- // memory for the new entry.
- //
- Status = gBS->InstallConfigurationTable (&gEfiMemoryAttributesTableGuid, (VOID *)(UINTN)MAX_ADDRESS);
- ASSERT_EFI_ERROR (Status);
- }
-
- MemoryMapSize = 0;
- MemoryMap = NULL;
- Status = CoreGetMemoryMapWithSeparatedImageSection (
- &MemoryMapSize,
- MemoryMap,
- &MapKey,
- &DescriptorSize,
- &DescriptorVersion
- );
- ASSERT (Status == EFI_BUFFER_TOO_SMALL);
-
- do {
- MemoryMap = AllocatePool (MemoryMapSize);
- ASSERT (MemoryMap != NULL);
-
- Status = CoreGetMemoryMapWithSeparatedImageSection (
- &MemoryMapSize,
- MemoryMap,
- &MapKey,
- &DescriptorSize,
- &DescriptorVersion
- );
- if (EFI_ERROR (Status)) {
- FreePool (MemoryMap);
- }
- } while (Status == EFI_BUFFER_TOO_SMALL);
-
- MemoryMapStart = MemoryMap;
- RuntimeEntryCount = 0;
- for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {
- switch (MemoryMap->Type) {
- case EfiRuntimeServicesCode:
- case EfiRuntimeServicesData:
- RuntimeEntryCount++;
- break;
- }
-
- MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize);
- }
-
- //
- // Allocate MemoryAttributesTable
- //
- MemoryAttributesTable = AllocatePool (sizeof (EFI_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount);
- ASSERT (MemoryAttributesTable != NULL);
- MemoryAttributesTable->Version = EFI_MEMORY_ATTRIBUTES_TABLE_VERSION;
- MemoryAttributesTable->NumberOfEntries = RuntimeEntryCount;
- MemoryAttributesTable->DescriptorSize = (UINT32)DescriptorSize;
- if (gMemoryAttributesTableForwardCfi) {
- MemoryAttributesTable->Flags = EFI_MEMORY_ATTRIBUTES_FLAGS_RT_FORWARD_CONTROL_FLOW_GUARD;
- } else {
- MemoryAttributesTable->Flags = 0;
- }
-
- DEBUG ((DEBUG_VERBOSE, "MemoryAttributesTable:\n"));
- DEBUG ((DEBUG_VERBOSE, " Version - 0x%08x\n", MemoryAttributesTable->Version));
- DEBUG ((DEBUG_VERBOSE, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable->NumberOfEntries));
- DEBUG ((DEBUG_VERBOSE, " DescriptorSize - 0x%08x\n", MemoryAttributesTable->DescriptorSize));
- MemoryAttributesEntry = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1);
- MemoryMap = MemoryMapStart;
- for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) {
- switch (MemoryMap->Type) {
- case EfiRuntimeServicesCode:
- case EfiRuntimeServicesData:
- CopyMem (MemoryAttributesEntry, MemoryMap, DescriptorSize);
- MemoryAttributesEntry->Attribute &= (EFI_MEMORY_RO|EFI_MEMORY_XP|EFI_MEMORY_RUNTIME);
- DEBUG ((DEBUG_VERBOSE, "Entry (0x%x)\n", MemoryAttributesEntry));
- DEBUG ((DEBUG_VERBOSE, " Type - 0x%x\n", MemoryAttributesEntry->Type));
- DEBUG ((DEBUG_VERBOSE, " PhysicalStart - 0x%016lx\n", MemoryAttributesEntry->PhysicalStart));
- DEBUG ((DEBUG_VERBOSE, " VirtualStart - 0x%016lx\n", MemoryAttributesEntry->VirtualStart));
- DEBUG ((DEBUG_VERBOSE, " NumberOfPages - 0x%016lx\n", MemoryAttributesEntry->NumberOfPages));
- DEBUG ((DEBUG_VERBOSE, " Attribute - 0x%016lx\n", MemoryAttributesEntry->Attribute));
- MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR (MemoryAttributesEntry, DescriptorSize);
- break;
- }
-
- MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize);
- }
-
- MemoryMap = MemoryMapStart;
- FreePool (MemoryMap);
-
- //
- // Update configuratoin table for MemoryAttributesTable.
- //
- Status = gBS->InstallConfigurationTable (&gEfiMemoryAttributesTableGuid, MemoryAttributesTable);
- ASSERT_EFI_ERROR (Status);
-
- if (mMemoryAttributesTable != NULL) {
- FreePool (mMemoryAttributesTable);
- }
-
- mMemoryAttributesTable = MemoryAttributesTable;
-}
-
-/**
- Install MemoryAttributesTable on memory allocation.
-
- @param[in] MemoryType EFI memory type.
-**/
-VOID
-InstallMemoryAttributesTableOnMemoryAllocation (
- IN EFI_MEMORY_TYPE MemoryType
- )
-{
- //
- // Install MemoryAttributesTable after ReadyToBoot on runtime memory allocation.
- //
- if (mMemoryAttributesTableReadyToBoot &&
- ((MemoryType == EfiRuntimeServicesCode) || (MemoryType == EfiRuntimeServicesData)))
- {
- InstallMemoryAttributesTable ();
- }
-}
-
-/**
- Install MemoryAttributesTable on ReadyToBoot.
-
- @param[in] Event The Event this notify function registered to.
- @param[in] Context Pointer to the context data registered to the Event.
-**/
-VOID
-EFIAPI
-InstallMemoryAttributesTableOnReadyToBoot (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- InstallMemoryAttributesTable ();
- mMemoryAttributesTableReadyToBoot = TRUE;
-}
-
-/**
- Install initial MemoryAttributesTable on EndOfDxe.
- Then SMM can consume this information.
-
- @param[in] Event The Event this notify function registered to.
- @param[in] Context Pointer to the context data registered to the Event.
-**/
-VOID
-EFIAPI
-InstallMemoryAttributesTableOnEndOfDxe (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- mMemoryAttributesTableEndOfDxe = TRUE;
- InstallMemoryAttributesTable ();
-
- DEBUG_CODE_BEGIN ();
- if ( mImagePropertiesPrivateData.ImageRecordCount > 0) {
- DEBUG ((DEBUG_INFO, "DXE - Total Runtime Image Count: 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount));
- DEBUG ((DEBUG_INFO, "DXE - Dump Runtime Image Records:\n"));
- DumpImageRecords (&mImagePropertiesPrivateData.ImageRecordList);
- }
-
- DEBUG_CODE_END ();
-}
-
-/**
- Initialize MemoryAttrubutesTable support.
-**/
-VOID
-EFIAPI
-CoreInitializeMemoryAttributesTable (
- VOID
- )
-{
- EFI_STATUS Status;
- EFI_EVENT ReadyToBootEvent;
- EFI_EVENT EndOfDxeEvent;
-
- //
- // Construct the table at ReadyToBoot.
- //
- Status = CoreCreateEventInternal (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- InstallMemoryAttributesTableOnReadyToBoot,
- NULL,
- &gEfiEventReadyToBootGuid,
- &ReadyToBootEvent
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Construct the initial table at EndOfDxe,
- // then SMM can consume this information.
- // Use TPL_NOTIFY here, as such SMM code (TPL_CALLBACK)
- // can run after it.
- //
- Status = CoreCreateEventInternal (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- InstallMemoryAttributesTableOnEndOfDxe,
- NULL,
- &gEfiEndOfDxeEventGroupGuid,
- &EndOfDxeEvent
- );
- ASSERT_EFI_ERROR (Status);
- return;
-}
-
-//
-// Below functions are for MemoryMap
-//
-
-/**
- Acquire memory lock on mMemoryAttributesTableLock.
-**/
-STATIC
-VOID
-CoreAcquiremMemoryAttributesTableLock (
- VOID
- )
-{
- CoreAcquireLock (&mMemoryAttributesTableLock);
-}
-
-/**
- Release memory lock on mMemoryAttributesTableLock.
-**/
-STATIC
-VOID
-CoreReleasemMemoryAttributesTableLock (
- VOID
- )
-{
- CoreReleaseLock (&mMemoryAttributesTableLock);
-}
-
-/**
- Merge continous memory map entries whose have same attributes.
-
- @param MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param MemoryMapSize A pointer to the size, in bytes, of the
- MemoryMap buffer. On input, this is the size of
- the current memory map. On output,
- it is the size of new memory map after merge.
- @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
-**/
-VOID
-MergeMemoryMap (
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN OUT UINTN *MemoryMapSize,
- IN UINTN DescriptorSize
- )
-{
- EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
- UINT64 MemoryBlockLength;
- EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
-
- MemoryMapEntry = MemoryMap;
- NewMemoryMapEntry = MemoryMap;
- MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + *MemoryMapSize);
- while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
- CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
-
- do {
- MergeGuardPages (NewMemoryMapEntry, NextMemoryMapEntry->PhysicalStart);
- MemoryBlockLength = LShiftU64 (NewMemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT);
- if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
- (NewMemoryMapEntry->Type == NextMemoryMapEntry->Type) &&
- (NewMemoryMapEntry->Attribute == NextMemoryMapEntry->Attribute) &&
- ((NewMemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart))
- {
- NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
- continue;
- } else {
- MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
- break;
- }
- } while (TRUE);
-
- MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
- }
-
- *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
-
- return;
-}
-
-/**
- Enforce memory map attributes.
- This function will set EfiRuntimeServicesData/EfiMemoryMappedIO/EfiMemoryMappedIOPortSpace to be EFI_MEMORY_XP.
-
- @param MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
- @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
-**/
-STATIC
-VOID
-EnforceMemoryMapAttribute (
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN UINTN MemoryMapSize,
- IN UINTN DescriptorSize
- )
-{
- EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
-
- MemoryMapEntry = MemoryMap;
- MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
- while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
- switch (MemoryMapEntry->Type) {
- case EfiRuntimeServicesCode:
- // do nothing
- break;
- case EfiRuntimeServicesData:
- case EfiMemoryMappedIO:
- case EfiMemoryMappedIOPortSpace:
- MemoryMapEntry->Attribute |= EFI_MEMORY_XP;
- break;
- case EfiReservedMemoryType:
- case EfiACPIMemoryNVS:
- break;
- }
-
- MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- }
-
- return;
-}
-
-/**
- This function for GetMemoryMap() with properties table capability.
-
- It calls original GetMemoryMap() to get the original memory map information. Then
- plus the additional memory map entries for PE Code/Data seperation.
-
- @param MemoryMapSize A pointer to the size, in bytes, of the
- MemoryMap buffer. On input, this is the size of
- the buffer allocated by the caller. On output,
- it is the size of the buffer returned by the
- firmware if the buffer was large enough, or the
- size of the buffer needed to contain the map if
- the buffer was too small.
- @param MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param MapKey A pointer to the location in which firmware
- returns the key for the current memory map.
- @param DescriptorSize A pointer to the location in which firmware
- returns the size, in bytes, of an individual
- EFI_MEMORY_DESCRIPTOR.
- @param DescriptorVersion A pointer to the location in which firmware
- returns the version number associated with the
- EFI_MEMORY_DESCRIPTOR.
-
- @retval EFI_SUCCESS The memory map was returned in the MemoryMap
- buffer.
- @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current
- buffer size needed to hold the memory map is
- returned in MemoryMapSize.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreGetMemoryMapWithSeparatedImageSection (
- IN OUT UINTN *MemoryMapSize,
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- OUT UINTN *MapKey,
- OUT UINTN *DescriptorSize,
- OUT UINT32 *DescriptorVersion
- )
-{
- EFI_STATUS Status;
- UINTN OldMemoryMapSize;
- UINTN AdditionalRecordCount;
-
- //
- // If PE code/data is not aligned, just return.
- //
- if (!mMemoryAttributesTableEnable) {
- return CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
- }
-
- if (MemoryMapSize == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- CoreAcquiremMemoryAttributesTableLock ();
-
- AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 3) * mImagePropertiesPrivateData.ImageRecordCount;
-
- OldMemoryMapSize = *MemoryMapSize;
- Status = CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion);
- if (Status == EFI_BUFFER_TOO_SMALL) {
- *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
- } else if (Status == EFI_SUCCESS) {
- ASSERT (MemoryMap != NULL);
- if (OldMemoryMapSize - *MemoryMapSize < (*DescriptorSize) * AdditionalRecordCount) {
- *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount;
- //
- // Need update status to buffer too small
- //
- Status = EFI_BUFFER_TOO_SMALL;
- } else {
- //
- // Split PE code/data
- //
- SplitTable (MemoryMapSize, MemoryMap, *DescriptorSize, &mImagePropertiesPrivateData.ImageRecordList, AdditionalRecordCount);
-
- //
- // Set RuntimeData to XP
- //
- EnforceMemoryMapAttribute (MemoryMap, *MemoryMapSize, *DescriptorSize);
-
- //
- // Merge same type to save entry size
- //
- MergeMemoryMap (MemoryMap, MemoryMapSize, *DescriptorSize);
- }
- }
-
- CoreReleasemMemoryAttributesTableLock ();
- return Status;
-}
-
-//
-// Below functions are for ImageRecord
-//
-
-/**
- Insert image record.
-
- @param RuntimeImage Runtime image information
-**/
-VOID
-InsertImageRecord (
- IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
- )
-{
- EFI_STATUS Status;
- IMAGE_PROPERTIES_RECORD *ImageRecord;
- CHAR8 *PdbPointer;
- UINT32 RequiredAlignment;
-
- DEBUG ((DEBUG_VERBOSE, "InsertImageRecord - 0x%x\n", RuntimeImage));
-
- if (mMemoryAttributesTableEndOfDxe) {
- DEBUG ((DEBUG_INFO, "Do not insert runtime image record after EndOfDxe\n"));
- return;
- }
-
- ImageRecord = AllocatePool (sizeof (*ImageRecord));
- if (ImageRecord == NULL) {
- return;
- }
-
- InitializeListHead (&ImageRecord->Link);
- InitializeListHead (&ImageRecord->CodeSegmentList);
-
- PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)RuntimeImage->ImageBase);
- if (PdbPointer != NULL) {
- DEBUG ((DEBUG_VERBOSE, " Image - %a\n", PdbPointer));
- }
-
- RequiredAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
- Status = CreateImagePropertiesRecord (
- RuntimeImage->ImageBase,
- RuntimeImage->ImageSize,
- &RequiredAlignment,
- ImageRecord
- );
-
- if (EFI_ERROR (Status)) {
- if (Status == EFI_ABORTED) {
- mMemoryAttributesTableEnable = FALSE;
- }
-
- Status = EFI_ABORTED;
- goto Finish;
- }
-
- if (ImageRecord->CodeSegmentCount == 0) {
- mMemoryAttributesTableEnable = FALSE;
- DEBUG ((DEBUG_ERROR, "!!!!!!!! InsertImageRecord - CodeSegmentCount is 0 !!!!!!!!\n"));
- if (PdbPointer != NULL) {
- DEBUG ((DEBUG_ERROR, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer));
- }
-
- Status = EFI_ABORTED;
- goto Finish;
- }
-
- //
- // Check overlap all section in ImageBase/Size
- //
- if (!IsImageRecordCodeSectionValid (ImageRecord)) {
- DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n"));
- Status = EFI_ABORTED;
- goto Finish;
- }
-
- InsertTailList (&mImagePropertiesPrivateData.ImageRecordList, &ImageRecord->Link);
- mImagePropertiesPrivateData.ImageRecordCount++;
-
- if (mImagePropertiesPrivateData.CodeSegmentCountMax < ImageRecord->CodeSegmentCount) {
- mImagePropertiesPrivateData.CodeSegmentCountMax = ImageRecord->CodeSegmentCount;
- }
-
- SortImageRecord (&mImagePropertiesPrivateData.ImageRecordList);
-
-Finish:
- if (EFI_ERROR (Status) && (ImageRecord != NULL)) {
- DeleteImagePropertiesRecord (ImageRecord);
- }
-
- return;
-}
-
-/**
- Remove Image record.
-
- @param RuntimeImage Runtime image information
-**/
-VOID
-RemoveImageRecord (
- IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage
- )
-{
- IMAGE_PROPERTIES_RECORD *ImageRecord;
-
- DEBUG ((DEBUG_VERBOSE, "RemoveImageRecord - 0x%x\n", RuntimeImage));
- DEBUG ((DEBUG_VERBOSE, "RemoveImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize));
-
- if (mMemoryAttributesTableEndOfDxe) {
- DEBUG ((DEBUG_INFO, "Do not remove runtime image record after EndOfDxe\n"));
- return;
- }
-
- ImageRecord = FindImageRecord ((EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize, &mImagePropertiesPrivateData.ImageRecordList);
- if (ImageRecord == NULL) {
- DEBUG ((DEBUG_ERROR, "!!!!!!!! ImageRecord not found !!!!!!!!\n"));
- return;
- }
-
- DeleteImagePropertiesRecord (ImageRecord);
-
- mImagePropertiesPrivateData.ImageRecordCount--;
-}
+/** @file + UEFI MemoryAttributesTable support + +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiLib.h> +#include <Library/ImagePropertiesRecordLib.h> + +#include <Guid/EventGroup.h> + +#include <Guid/MemoryAttributesTable.h> + +#include "DxeMain.h" +#include "HeapGuard.h" + +/** + This function for GetMemoryMap() with properties table capability. + + It calls original GetMemoryMap() to get the original memory map information. Then + plus the additional memory map entries for PE Code/Data seperation. + + @param MemoryMapSize A pointer to the size, in bytes, of the + MemoryMap buffer. On input, this is the size of + the buffer allocated by the caller. On output, + it is the size of the buffer returned by the + firmware if the buffer was large enough, or the + size of the buffer needed to contain the map if + the buffer was too small. + @param MemoryMap A pointer to the buffer in which firmware places + the current memory map. + @param MapKey A pointer to the location in which firmware + returns the key for the current memory map. + @param DescriptorSize A pointer to the location in which firmware + returns the size, in bytes, of an individual + EFI_MEMORY_DESCRIPTOR. + @param DescriptorVersion A pointer to the location in which firmware + returns the version number associated with the + EFI_MEMORY_DESCRIPTOR. + + @retval EFI_SUCCESS The memory map was returned in the MemoryMap + buffer. + @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current + buffer size needed to hold the memory map is + returned in MemoryMapSize. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + +**/ +EFI_STATUS +EFIAPI +CoreGetMemoryMapWithSeparatedImageSection ( + IN OUT UINTN *MemoryMapSize, + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + OUT UINTN *MapKey, + OUT UINTN *DescriptorSize, + OUT UINT32 *DescriptorVersion + ); + +#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \ + ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size))) + +#define IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('I','P','P','D') + +typedef struct { + UINT32 Signature; + UINTN ImageRecordCount; + UINTN CodeSegmentCountMax; + LIST_ENTRY ImageRecordList; +} IMAGE_PROPERTIES_PRIVATE_DATA; + +STATIC IMAGE_PROPERTIES_PRIVATE_DATA mImagePropertiesPrivateData = { + IMAGE_PROPERTIES_PRIVATE_DATA_SIGNATURE, + 0, + 0, + INITIALIZE_LIST_HEAD_VARIABLE (mImagePropertiesPrivateData.ImageRecordList) +}; + +STATIC EFI_LOCK mMemoryAttributesTableLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY); + +BOOLEAN mMemoryAttributesTableEnable = TRUE; +BOOLEAN mMemoryAttributesTableEndOfDxe = FALSE; +EFI_MEMORY_ATTRIBUTES_TABLE *mMemoryAttributesTable = NULL; +BOOLEAN mMemoryAttributesTableReadyToBoot = FALSE; +BOOLEAN gMemoryAttributesTableForwardCfi = TRUE; + +/** + Install MemoryAttributesTable. + +**/ +VOID +InstallMemoryAttributesTable ( + VOID + ) +{ + UINTN MemoryMapSize; + EFI_MEMORY_DESCRIPTOR *MemoryMap; + EFI_MEMORY_DESCRIPTOR *MemoryMapStart; + UINTN MapKey; + UINTN DescriptorSize; + UINT32 DescriptorVersion; + UINTN Index; + EFI_STATUS Status; + UINT32 RuntimeEntryCount; + EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable; + EFI_MEMORY_DESCRIPTOR *MemoryAttributesEntry; + + if (gMemoryMapTerminated) { + // + // Directly return after MemoryMap terminated. + // + return; + } + + if (!mMemoryAttributesTableEnable) { + DEBUG ((DEBUG_VERBOSE, "Cannot install Memory Attributes Table ")); + DEBUG ((DEBUG_VERBOSE, "because Runtime Driver Section Alignment is not %dK.\n", RUNTIME_PAGE_ALLOCATION_GRANULARITY >> 10)); + return; + } + + if (mMemoryAttributesTable == NULL) { + // + // InstallConfigurationTable here to occupy one entry for MemoryAttributesTable + // before GetMemoryMap below, as InstallConfigurationTable may allocate runtime + // memory for the new entry. + // + Status = gBS->InstallConfigurationTable (&gEfiMemoryAttributesTableGuid, (VOID *)(UINTN)MAX_ADDRESS); + ASSERT_EFI_ERROR (Status); + } + + MemoryMapSize = 0; + MemoryMap = NULL; + Status = CoreGetMemoryMapWithSeparatedImageSection ( + &MemoryMapSize, + MemoryMap, + &MapKey, + &DescriptorSize, + &DescriptorVersion + ); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + + do { + MemoryMap = AllocatePool (MemoryMapSize); + ASSERT (MemoryMap != NULL); + + Status = CoreGetMemoryMapWithSeparatedImageSection ( + &MemoryMapSize, + MemoryMap, + &MapKey, + &DescriptorSize, + &DescriptorVersion + ); + if (EFI_ERROR (Status)) { + FreePool (MemoryMap); + } + } while (Status == EFI_BUFFER_TOO_SMALL); + + MemoryMapStart = MemoryMap; + RuntimeEntryCount = 0; + for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) { + switch (MemoryMap->Type) { + case EfiRuntimeServicesCode: + case EfiRuntimeServicesData: + RuntimeEntryCount++; + break; + } + + MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize); + } + + // + // Allocate MemoryAttributesTable + // + MemoryAttributesTable = AllocatePool (sizeof (EFI_MEMORY_ATTRIBUTES_TABLE) + DescriptorSize * RuntimeEntryCount); + ASSERT (MemoryAttributesTable != NULL); + MemoryAttributesTable->Version = EFI_MEMORY_ATTRIBUTES_TABLE_VERSION; + MemoryAttributesTable->NumberOfEntries = RuntimeEntryCount; + MemoryAttributesTable->DescriptorSize = (UINT32)DescriptorSize; + if (gMemoryAttributesTableForwardCfi) { + MemoryAttributesTable->Flags = EFI_MEMORY_ATTRIBUTES_FLAGS_RT_FORWARD_CONTROL_FLOW_GUARD; + } else { + MemoryAttributesTable->Flags = 0; + } + + DEBUG ((DEBUG_VERBOSE, "MemoryAttributesTable:\n")); + DEBUG ((DEBUG_VERBOSE, " Version - 0x%08x\n", MemoryAttributesTable->Version)); + DEBUG ((DEBUG_VERBOSE, " NumberOfEntries - 0x%08x\n", MemoryAttributesTable->NumberOfEntries)); + DEBUG ((DEBUG_VERBOSE, " DescriptorSize - 0x%08x\n", MemoryAttributesTable->DescriptorSize)); + MemoryAttributesEntry = (EFI_MEMORY_DESCRIPTOR *)(MemoryAttributesTable + 1); + MemoryMap = MemoryMapStart; + for (Index = 0; Index < MemoryMapSize/DescriptorSize; Index++) { + switch (MemoryMap->Type) { + case EfiRuntimeServicesCode: + case EfiRuntimeServicesData: + CopyMem (MemoryAttributesEntry, MemoryMap, DescriptorSize); + MemoryAttributesEntry->Attribute &= (EFI_MEMORY_RO|EFI_MEMORY_XP|EFI_MEMORY_RUNTIME); + DEBUG ((DEBUG_VERBOSE, "Entry (0x%x)\n", MemoryAttributesEntry)); + DEBUG ((DEBUG_VERBOSE, " Type - 0x%x\n", MemoryAttributesEntry->Type)); + DEBUG ((DEBUG_VERBOSE, " PhysicalStart - 0x%016lx\n", MemoryAttributesEntry->PhysicalStart)); + DEBUG ((DEBUG_VERBOSE, " VirtualStart - 0x%016lx\n", MemoryAttributesEntry->VirtualStart)); + DEBUG ((DEBUG_VERBOSE, " NumberOfPages - 0x%016lx\n", MemoryAttributesEntry->NumberOfPages)); + DEBUG ((DEBUG_VERBOSE, " Attribute - 0x%016lx\n", MemoryAttributesEntry->Attribute)); + MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR (MemoryAttributesEntry, DescriptorSize); + break; + } + + MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, DescriptorSize); + } + + MemoryMap = MemoryMapStart; + FreePool (MemoryMap); + + // + // Update configuratoin table for MemoryAttributesTable. + // + Status = gBS->InstallConfigurationTable (&gEfiMemoryAttributesTableGuid, MemoryAttributesTable); + ASSERT_EFI_ERROR (Status); + + if (mMemoryAttributesTable != NULL) { + FreePool (mMemoryAttributesTable); + } + + mMemoryAttributesTable = MemoryAttributesTable; +} + +/** + Install MemoryAttributesTable on memory allocation. + + @param[in] MemoryType EFI memory type. +**/ +VOID +InstallMemoryAttributesTableOnMemoryAllocation ( + IN EFI_MEMORY_TYPE MemoryType + ) +{ + // + // Install MemoryAttributesTable after ReadyToBoot on runtime memory allocation. + // + if (mMemoryAttributesTableReadyToBoot && + ((MemoryType == EfiRuntimeServicesCode) || (MemoryType == EfiRuntimeServicesData))) + { + InstallMemoryAttributesTable (); + } +} + +/** + Install MemoryAttributesTable on ReadyToBoot. + + @param[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data registered to the Event. +**/ +VOID +EFIAPI +InstallMemoryAttributesTableOnReadyToBoot ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + InstallMemoryAttributesTable (); + mMemoryAttributesTableReadyToBoot = TRUE; +} + +/** + Install initial MemoryAttributesTable on EndOfDxe. + Then SMM can consume this information. + + @param[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data registered to the Event. +**/ +VOID +EFIAPI +InstallMemoryAttributesTableOnEndOfDxe ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + mMemoryAttributesTableEndOfDxe = TRUE; + InstallMemoryAttributesTable (); + + DEBUG_CODE_BEGIN (); + if ( mImagePropertiesPrivateData.ImageRecordCount > 0) { + DEBUG ((DEBUG_INFO, "DXE - Total Runtime Image Count: 0x%x\n", mImagePropertiesPrivateData.ImageRecordCount)); + DEBUG ((DEBUG_INFO, "DXE - Dump Runtime Image Records:\n")); + DumpImageRecords (&mImagePropertiesPrivateData.ImageRecordList); + } + + DEBUG_CODE_END (); +} + +/** + Initialize MemoryAttrubutesTable support. +**/ +VOID +EFIAPI +CoreInitializeMemoryAttributesTable ( + VOID + ) +{ + EFI_STATUS Status; + EFI_EVENT ReadyToBootEvent; + EFI_EVENT EndOfDxeEvent; + + // + // Construct the table at ReadyToBoot. + // + Status = CoreCreateEventInternal ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + InstallMemoryAttributesTableOnReadyToBoot, + NULL, + &gEfiEventReadyToBootGuid, + &ReadyToBootEvent + ); + ASSERT_EFI_ERROR (Status); + + // + // Construct the initial table at EndOfDxe, + // then SMM can consume this information. + // Use TPL_NOTIFY here, as such SMM code (TPL_CALLBACK) + // can run after it. + // + Status = CoreCreateEventInternal ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + InstallMemoryAttributesTableOnEndOfDxe, + NULL, + &gEfiEndOfDxeEventGroupGuid, + &EndOfDxeEvent + ); + ASSERT_EFI_ERROR (Status); + return; +} + +// +// Below functions are for MemoryMap +// + +/** + Acquire memory lock on mMemoryAttributesTableLock. +**/ +STATIC +VOID +CoreAcquiremMemoryAttributesTableLock ( + VOID + ) +{ + CoreAcquireLock (&mMemoryAttributesTableLock); +} + +/** + Release memory lock on mMemoryAttributesTableLock. +**/ +STATIC +VOID +CoreReleasemMemoryAttributesTableLock ( + VOID + ) +{ + CoreReleaseLock (&mMemoryAttributesTableLock); +} + +/** + Merge continous memory map entries whose have same attributes. + + @param MemoryMap A pointer to the buffer in which firmware places + the current memory map. + @param MemoryMapSize A pointer to the size, in bytes, of the + MemoryMap buffer. On input, this is the size of + the current memory map. On output, + it is the size of new memory map after merge. + @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR. +**/ +VOID +MergeMemoryMap ( + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + IN OUT UINTN *MemoryMapSize, + IN UINTN DescriptorSize + ) +{ + EFI_MEMORY_DESCRIPTOR *MemoryMapEntry; + EFI_MEMORY_DESCRIPTOR *MemoryMapEnd; + UINT64 MemoryBlockLength; + EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry; + EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry; + + MemoryMapEntry = MemoryMap; + NewMemoryMapEntry = MemoryMap; + MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + *MemoryMapSize); + while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) { + CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); + NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); + + do { + MergeGuardPages (NewMemoryMapEntry, NextMemoryMapEntry->PhysicalStart); + MemoryBlockLength = LShiftU64 (NewMemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT); + if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) && + (NewMemoryMapEntry->Type == NextMemoryMapEntry->Type) && + (NewMemoryMapEntry->Attribute == NextMemoryMapEntry->Attribute) && + ((NewMemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) + { + NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages; + NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize); + continue; + } else { + MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize); + break; + } + } while (TRUE); + + MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); + NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize); + } + + *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap; + + return; +} + +/** + Enforce memory map attributes. + This function will set EfiRuntimeServicesData/EfiMemoryMappedIO/EfiMemoryMappedIOPortSpace to be EFI_MEMORY_XP. + + @param MemoryMap A pointer to the buffer in which firmware places + the current memory map. + @param MemoryMapSize Size, in bytes, of the MemoryMap buffer. + @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR. +**/ +STATIC +VOID +EnforceMemoryMapAttribute ( + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + IN UINTN MemoryMapSize, + IN UINTN DescriptorSize + ) +{ + EFI_MEMORY_DESCRIPTOR *MemoryMapEntry; + EFI_MEMORY_DESCRIPTOR *MemoryMapEnd; + + MemoryMapEntry = MemoryMap; + MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize); + while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) { + switch (MemoryMapEntry->Type) { + case EfiRuntimeServicesCode: + // do nothing + break; + case EfiRuntimeServicesData: + case EfiMemoryMappedIO: + case EfiMemoryMappedIOPortSpace: + MemoryMapEntry->Attribute |= EFI_MEMORY_XP; + break; + case EfiReservedMemoryType: + case EfiACPIMemoryNVS: + break; + } + + MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); + } + + return; +} + +/** + This function for GetMemoryMap() with properties table capability. + + It calls original GetMemoryMap() to get the original memory map information. Then + plus the additional memory map entries for PE Code/Data seperation. + + @param MemoryMapSize A pointer to the size, in bytes, of the + MemoryMap buffer. On input, this is the size of + the buffer allocated by the caller. On output, + it is the size of the buffer returned by the + firmware if the buffer was large enough, or the + size of the buffer needed to contain the map if + the buffer was too small. + @param MemoryMap A pointer to the buffer in which firmware places + the current memory map. + @param MapKey A pointer to the location in which firmware + returns the key for the current memory map. + @param DescriptorSize A pointer to the location in which firmware + returns the size, in bytes, of an individual + EFI_MEMORY_DESCRIPTOR. + @param DescriptorVersion A pointer to the location in which firmware + returns the version number associated with the + EFI_MEMORY_DESCRIPTOR. + + @retval EFI_SUCCESS The memory map was returned in the MemoryMap + buffer. + @retval EFI_BUFFER_TOO_SMALL The MemoryMap buffer was too small. The current + buffer size needed to hold the memory map is + returned in MemoryMapSize. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + +**/ +EFI_STATUS +EFIAPI +CoreGetMemoryMapWithSeparatedImageSection ( + IN OUT UINTN *MemoryMapSize, + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + OUT UINTN *MapKey, + OUT UINTN *DescriptorSize, + OUT UINT32 *DescriptorVersion + ) +{ + EFI_STATUS Status; + UINTN OldMemoryMapSize; + UINTN AdditionalRecordCount; + + // + // If PE code/data is not aligned, just return. + // + if (!mMemoryAttributesTableEnable) { + return CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion); + } + + if (MemoryMapSize == NULL) { + return EFI_INVALID_PARAMETER; + } + + CoreAcquiremMemoryAttributesTableLock (); + + AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 3) * mImagePropertiesPrivateData.ImageRecordCount; + + OldMemoryMapSize = *MemoryMapSize; + Status = CoreGetMemoryMap (MemoryMapSize, MemoryMap, MapKey, DescriptorSize, DescriptorVersion); + if (Status == EFI_BUFFER_TOO_SMALL) { + *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount; + } else if (Status == EFI_SUCCESS) { + ASSERT (MemoryMap != NULL); + if (OldMemoryMapSize - *MemoryMapSize < (*DescriptorSize) * AdditionalRecordCount) { + *MemoryMapSize = *MemoryMapSize + (*DescriptorSize) * AdditionalRecordCount; + // + // Need update status to buffer too small + // + Status = EFI_BUFFER_TOO_SMALL; + } else { + // + // Split PE code/data + // + SplitTable (MemoryMapSize, MemoryMap, *DescriptorSize, &mImagePropertiesPrivateData.ImageRecordList, AdditionalRecordCount); + + // + // Set RuntimeData to XP + // + EnforceMemoryMapAttribute (MemoryMap, *MemoryMapSize, *DescriptorSize); + + // + // Merge same type to save entry size + // + MergeMemoryMap (MemoryMap, MemoryMapSize, *DescriptorSize); + } + } + + CoreReleasemMemoryAttributesTableLock (); + return Status; +} + +// +// Below functions are for ImageRecord +// + +/** + Insert image record. + + @param RuntimeImage Runtime image information +**/ +VOID +InsertImageRecord ( + IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage + ) +{ + EFI_STATUS Status; + IMAGE_PROPERTIES_RECORD *ImageRecord; + CHAR8 *PdbPointer; + UINT32 RequiredAlignment; + + DEBUG ((DEBUG_VERBOSE, "InsertImageRecord - 0x%x\n", RuntimeImage)); + + if (mMemoryAttributesTableEndOfDxe) { + DEBUG ((DEBUG_INFO, "Do not insert runtime image record after EndOfDxe\n")); + return; + } + + ImageRecord = AllocatePool (sizeof (*ImageRecord)); + if (ImageRecord == NULL) { + return; + } + + InitializeListHead (&ImageRecord->Link); + InitializeListHead (&ImageRecord->CodeSegmentList); + + PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)RuntimeImage->ImageBase); + if (PdbPointer != NULL) { + DEBUG ((DEBUG_VERBOSE, " Image - %a\n", PdbPointer)); + } + + RequiredAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY; + Status = CreateImagePropertiesRecord ( + RuntimeImage->ImageBase, + RuntimeImage->ImageSize, + &RequiredAlignment, + ImageRecord + ); + + if (EFI_ERROR (Status)) { + if (Status == EFI_ABORTED) { + mMemoryAttributesTableEnable = FALSE; + } + + Status = EFI_ABORTED; + goto Finish; + } + + if (ImageRecord->CodeSegmentCount == 0) { + mMemoryAttributesTableEnable = FALSE; + DEBUG ((DEBUG_ERROR, "!!!!!!!! InsertImageRecord - CodeSegmentCount is 0 !!!!!!!!\n")); + if (PdbPointer != NULL) { + DEBUG ((DEBUG_ERROR, "!!!!!!!! Image - %a !!!!!!!!\n", PdbPointer)); + } + + Status = EFI_ABORTED; + goto Finish; + } + + // + // Check overlap all section in ImageBase/Size + // + if (!IsImageRecordCodeSectionValid (ImageRecord)) { + DEBUG ((DEBUG_ERROR, "IsImageRecordCodeSectionValid - FAIL\n")); + Status = EFI_ABORTED; + goto Finish; + } + + InsertTailList (&mImagePropertiesPrivateData.ImageRecordList, &ImageRecord->Link); + mImagePropertiesPrivateData.ImageRecordCount++; + + if (mImagePropertiesPrivateData.CodeSegmentCountMax < ImageRecord->CodeSegmentCount) { + mImagePropertiesPrivateData.CodeSegmentCountMax = ImageRecord->CodeSegmentCount; + } + + SortImageRecord (&mImagePropertiesPrivateData.ImageRecordList); + +Finish: + if (EFI_ERROR (Status) && (ImageRecord != NULL)) { + DeleteImagePropertiesRecord (ImageRecord); + } + + return; +} + +/** + Remove Image record. + + @param RuntimeImage Runtime image information +**/ +VOID +RemoveImageRecord ( + IN EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage + ) +{ + IMAGE_PROPERTIES_RECORD *ImageRecord; + + DEBUG ((DEBUG_VERBOSE, "RemoveImageRecord - 0x%x\n", RuntimeImage)); + DEBUG ((DEBUG_VERBOSE, "RemoveImageRecord - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize)); + + if (mMemoryAttributesTableEndOfDxe) { + DEBUG ((DEBUG_INFO, "Do not remove runtime image record after EndOfDxe\n")); + return; + } + + ImageRecord = FindImageRecord ((EFI_PHYSICAL_ADDRESS)(UINTN)RuntimeImage->ImageBase, RuntimeImage->ImageSize, &mImagePropertiesPrivateData.ImageRecordList); + if (ImageRecord == NULL) { + DEBUG ((DEBUG_ERROR, "!!!!!!!! ImageRecord not found !!!!!!!!\n")); + return; + } + + DeleteImagePropertiesRecord (ImageRecord); + + mImagePropertiesPrivateData.ImageRecordCount--; +} diff --git a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c index 2c069cc12c..9cfd107730 100644 --- a/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c +++ b/MdeModulePkg/Core/Dxe/Misc/MemoryProtection.c @@ -1,1110 +1,1110 @@ -/** @file
- UEFI Memory Protection support.
-
- If the UEFI image is page aligned, the image code section is set to read only
- and the image data section is set to non-executable.
-
- 1) This policy is applied for all UEFI image including boot service driver,
- runtime driver or application.
- 2) This policy is applied only if the UEFI image meets the page alignment
- requirement.
- 3) This policy is applied only if the Source UEFI image matches the
- PcdImageProtectionPolicy definition.
- 4) This policy is not applied to the non-PE image region.
-
- The DxeCore calls CpuArchProtocol->SetMemoryAttributes() to protect
- the image. If the CpuArch protocol is not installed yet, the DxeCore
- enqueues the protection request. Once the CpuArch is installed, the
- DxeCore dequeues the protection request and applies policy.
-
- Once the image is unloaded, the protection is removed automatically.
-
-Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiDxe.h>
-#include <Library/BaseLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/DxeServicesTableLib.h>
-#include <Library/DebugLib.h>
-#include <Library/UefiLib.h>
-#include <Library/ImagePropertiesRecordLib.h>
-
-#include <Guid/EventGroup.h>
-#include <Guid/MemoryAttributesTable.h>
-
-#include <Protocol/FirmwareVolume2.h>
-#include <Protocol/SimpleFileSystem.h>
-
-#include "DxeMain.h"
-#include "Mem/HeapGuard.h"
-
-//
-// Image type definitions
-//
-#define IMAGE_UNKNOWN 0x00000001
-#define IMAGE_FROM_FV 0x00000002
-
-//
-// Protection policy bit definition
-//
-#define DO_NOT_PROTECT 0x00000000
-#define PROTECT_IF_ALIGNED_ELSE_ALLOW 0x00000001
-
-#define MEMORY_TYPE_OS_RESERVED_MIN 0x80000000
-#define MEMORY_TYPE_OEM_RESERVED_MIN 0x70000000
-
-#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \
- ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size)))
-
-UINT32 mImageProtectionPolicy;
-
-extern LIST_ENTRY mGcdMemorySpaceMap;
-
-STATIC LIST_ENTRY mProtectedImageRecordList;
-
-/**
- Get the image type.
-
- @param[in] File This is a pointer to the device path of the file that is
- being dispatched.
-
- @return UINT32 Image Type
-**/
-UINT32
-GetImageType (
- IN CONST EFI_DEVICE_PATH_PROTOCOL *File
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE DeviceHandle;
- EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
-
- if (File == NULL) {
- return IMAGE_UNKNOWN;
- }
-
- //
- // First check to see if File is from a Firmware Volume
- //
- DeviceHandle = NULL;
- TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
- Status = gBS->LocateDevicePath (
- &gEfiFirmwareVolume2ProtocolGuid,
- &TempDevicePath,
- &DeviceHandle
- );
- if (!EFI_ERROR (Status)) {
- Status = gBS->OpenProtocol (
- DeviceHandle,
- &gEfiFirmwareVolume2ProtocolGuid,
- NULL,
- NULL,
- NULL,
- EFI_OPEN_PROTOCOL_TEST_PROTOCOL
- );
- if (!EFI_ERROR (Status)) {
- return IMAGE_FROM_FV;
- }
- }
-
- return IMAGE_UNKNOWN;
-}
-
-/**
- Get UEFI image protection policy based upon image type.
-
- @param[in] ImageType The UEFI image type
-
- @return UEFI image protection policy
-**/
-UINT32
-GetProtectionPolicyFromImageType (
- IN UINT32 ImageType
- )
-{
- if ((ImageType & mImageProtectionPolicy) == 0) {
- return DO_NOT_PROTECT;
- } else {
- return PROTECT_IF_ALIGNED_ELSE_ALLOW;
- }
-}
-
-/**
- Get UEFI image protection policy based upon loaded image device path.
-
- @param[in] LoadedImage The loaded image protocol
- @param[in] LoadedImageDevicePath The loaded image device path protocol
-
- @return UEFI image protection policy
-**/
-UINT32
-GetUefiImageProtectionPolicy (
- IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
- IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
- )
-{
- BOOLEAN InSmm;
- UINT32 ImageType;
- UINT32 ProtectionPolicy;
-
- //
- // Check SMM
- //
- InSmm = FALSE;
- if (gSmmBase2 != NULL) {
- gSmmBase2->InSmm (gSmmBase2, &InSmm);
- }
-
- if (InSmm) {
- return FALSE;
- }
-
- //
- // Check DevicePath
- //
- if (LoadedImage == gDxeCoreLoadedImage) {
- ImageType = IMAGE_FROM_FV;
- } else {
- ImageType = GetImageType (LoadedImageDevicePath);
- }
-
- ProtectionPolicy = GetProtectionPolicyFromImageType (ImageType);
- return ProtectionPolicy;
-}
-
-/**
- Set UEFI image memory attributes.
-
- @param[in] BaseAddress Specified start address
- @param[in] Length Specified length
- @param[in] Attributes Specified attributes
-**/
-VOID
-SetUefiImageMemoryAttributes (
- IN UINT64 BaseAddress,
- IN UINT64 Length,
- IN UINT64 Attributes
- )
-{
- EFI_STATUS Status;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
- UINT64 FinalAttributes;
-
- Status = CoreGetMemorySpaceDescriptor (BaseAddress, &Descriptor);
- ASSERT_EFI_ERROR (Status);
-
- FinalAttributes = (Descriptor.Attributes & EFI_CACHE_ATTRIBUTE_MASK) | (Attributes & EFI_MEMORY_ATTRIBUTE_MASK);
-
- DEBUG ((DEBUG_INFO, "SetUefiImageMemoryAttributes - 0x%016lx - 0x%016lx (0x%016lx)\n", BaseAddress, Length, FinalAttributes));
-
- ASSERT (gCpu != NULL);
- gCpu->SetMemoryAttributes (gCpu, BaseAddress, Length, FinalAttributes);
-}
-
-/**
- Set UEFI image protection attributes.
-
- @param[in] ImageRecord A UEFI image record
-**/
-VOID
-SetUefiImageProtectionAttributes (
- IN IMAGE_PROPERTIES_RECORD *ImageRecord
- )
-{
- IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection;
- LIST_ENTRY *ImageRecordCodeSectionLink;
- LIST_ENTRY *ImageRecordCodeSectionEndLink;
- LIST_ENTRY *ImageRecordCodeSectionList;
- UINT64 CurrentBase;
- UINT64 ImageEnd;
-
- ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList;
-
- CurrentBase = ImageRecord->ImageBase;
- ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize;
-
- ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink;
- ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList;
- while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) {
- ImageRecordCodeSection = CR (
- ImageRecordCodeSectionLink,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION,
- Link,
- IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE
- );
- ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink;
-
- ASSERT (CurrentBase <= ImageRecordCodeSection->CodeSegmentBase);
- if (CurrentBase < ImageRecordCodeSection->CodeSegmentBase) {
- //
- // DATA
- //
- SetUefiImageMemoryAttributes (
- CurrentBase,
- ImageRecordCodeSection->CodeSegmentBase - CurrentBase,
- EFI_MEMORY_XP
- );
- }
-
- //
- // CODE
- //
- SetUefiImageMemoryAttributes (
- ImageRecordCodeSection->CodeSegmentBase,
- ImageRecordCodeSection->CodeSegmentSize,
- EFI_MEMORY_RO
- );
- CurrentBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize;
- }
-
- //
- // Last DATA
- //
- ASSERT (CurrentBase <= ImageEnd);
- if (CurrentBase < ImageEnd) {
- //
- // DATA
- //
- SetUefiImageMemoryAttributes (
- CurrentBase,
- ImageEnd - CurrentBase,
- EFI_MEMORY_XP
- );
- }
-
- return;
-}
-
-/**
- Return the section alignment requirement for the PE image section type.
-
- @param[in] MemoryType PE/COFF image memory type
-
- @retval The required section alignment for this memory type
-
-**/
-STATIC
-UINT32
-GetMemoryProtectionSectionAlignment (
- IN EFI_MEMORY_TYPE MemoryType
- )
-{
- UINT32 SectionAlignment;
-
- switch (MemoryType) {
- case EfiRuntimeServicesCode:
- case EfiACPIMemoryNVS:
- case EfiReservedMemoryType:
- SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
- break;
- case EfiRuntimeServicesData:
- ASSERT (FALSE);
- SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY;
- break;
- case EfiBootServicesCode:
- case EfiLoaderCode:
- SectionAlignment = EFI_PAGE_SIZE;
- break;
- case EfiACPIReclaimMemory:
- default:
- ASSERT (FALSE);
- SectionAlignment = EFI_PAGE_SIZE;
- break;
- }
-
- return SectionAlignment;
-}
-
-/**
- Protect UEFI PE/COFF image.
-
- @param[in] LoadedImage The loaded image protocol
- @param[in] LoadedImageDevicePath The loaded image device path protocol
-**/
-VOID
-ProtectUefiImage (
- IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
- IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
- )
-{
- IMAGE_PROPERTIES_RECORD *ImageRecord;
- UINT32 ProtectionPolicy;
- EFI_STATUS Status;
- UINT32 RequiredAlignment;
-
- DEBUG ((DEBUG_INFO, "ProtectUefiImageCommon - 0x%x\n", LoadedImage));
- DEBUG ((DEBUG_INFO, " - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase, LoadedImage->ImageSize));
-
- if (gCpu == NULL) {
- return;
- }
-
- ProtectionPolicy = GetUefiImageProtectionPolicy (LoadedImage, LoadedImageDevicePath);
- switch (ProtectionPolicy) {
- case DO_NOT_PROTECT:
- return;
- case PROTECT_IF_ALIGNED_ELSE_ALLOW:
- break;
- default:
- ASSERT (FALSE);
- return;
- }
-
- ImageRecord = AllocateZeroPool (sizeof (*ImageRecord));
- if (ImageRecord == NULL) {
- return;
- }
-
- RequiredAlignment = GetMemoryProtectionSectionAlignment (LoadedImage->ImageCodeType);
-
- Status = CreateImagePropertiesRecord (
- LoadedImage->ImageBase,
- LoadedImage->ImageSize,
- &RequiredAlignment,
- ImageRecord
- );
-
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "%a failed to create image properties record\n", __func__));
- FreePool (ImageRecord);
- goto Finish;
- }
-
- //
- // CPU ARCH present. Update memory attribute directly.
- //
- SetUefiImageProtectionAttributes (ImageRecord);
-
- //
- // Record the image record in the list so we can undo the protections later
- //
- InsertTailList (&mProtectedImageRecordList, &ImageRecord->Link);
-
-Finish:
- return;
-}
-
-/**
- Unprotect UEFI image.
-
- @param[in] LoadedImage The loaded image protocol
- @param[in] LoadedImageDevicePath The loaded image device path protocol
-**/
-VOID
-UnprotectUefiImage (
- IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage,
- IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath
- )
-{
- IMAGE_PROPERTIES_RECORD *ImageRecord;
- LIST_ENTRY *ImageRecordLink;
-
- if (PcdGet32 (PcdImageProtectionPolicy) != 0) {
- for (ImageRecordLink = mProtectedImageRecordList.ForwardLink;
- ImageRecordLink != &mProtectedImageRecordList;
- ImageRecordLink = ImageRecordLink->ForwardLink)
- {
- ImageRecord = CR (
- ImageRecordLink,
- IMAGE_PROPERTIES_RECORD,
- Link,
- IMAGE_PROPERTIES_RECORD_SIGNATURE
- );
-
- if (ImageRecord->ImageBase == (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase) {
- SetUefiImageMemoryAttributes (
- ImageRecord->ImageBase,
- ImageRecord->ImageSize,
- 0
- );
- DeleteImagePropertiesRecord (ImageRecord);
- return;
- }
- }
- }
-}
-
-/**
- Return the EFI memory permission attribute associated with memory
- type 'MemoryType' under the configured DXE memory protection policy.
-
- @param MemoryType Memory type.
-**/
-STATIC
-UINT64
-GetPermissionAttributeForMemoryType (
- IN EFI_MEMORY_TYPE MemoryType
- )
-{
- UINT64 TestBit;
-
- if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) {
- TestBit = BIT63;
- } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) {
- TestBit = BIT62;
- } else {
- TestBit = LShiftU64 (1, MemoryType);
- }
-
- if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & TestBit) != 0) {
- return EFI_MEMORY_XP;
- } else {
- return 0;
- }
-}
-
-/**
- Sort memory map entries based upon PhysicalStart, from low to high.
-
- @param MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param MemoryMapSize Size, in bytes, of the MemoryMap buffer.
- @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
-**/
-STATIC
-VOID
-SortMemoryMap (
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN UINTN MemoryMapSize,
- IN UINTN DescriptorSize
- )
-{
- EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
- EFI_MEMORY_DESCRIPTOR TempMemoryMap;
-
- MemoryMapEntry = MemoryMap;
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
- while (MemoryMapEntry < MemoryMapEnd) {
- while (NextMemoryMapEntry < MemoryMapEnd) {
- if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) {
- CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
- CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
- CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof (EFI_MEMORY_DESCRIPTOR));
- }
-
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
- }
-
- MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- }
-}
-
-/**
- Merge adjacent memory map entries if they use the same memory protection policy
-
- @param[in, out] MemoryMap A pointer to the buffer in which firmware places
- the current memory map.
- @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the
- MemoryMap buffer. On input, this is the size of
- the current memory map. On output,
- it is the size of new memory map after merge.
- @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR.
-**/
-STATIC
-VOID
-MergeMemoryMapForProtectionPolicy (
- IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
- IN OUT UINTN *MemoryMapSize,
- IN UINTN DescriptorSize
- )
-{
- EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
- UINT64 MemoryBlockLength;
- EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry;
- UINT64 Attributes;
-
- SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize);
-
- MemoryMapEntry = MemoryMap;
- NewMemoryMapEntry = MemoryMap;
- MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + *MemoryMapSize);
- while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
- CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
-
- do {
- MemoryBlockLength = (UINT64)(EFI_PAGES_TO_SIZE ((UINTN)MemoryMapEntry->NumberOfPages));
- Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);
-
- if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) &&
- (Attributes == GetPermissionAttributeForMemoryType (NextMemoryMapEntry->Type)) &&
- ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart))
- {
- MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
- if (NewMemoryMapEntry != MemoryMapEntry) {
- NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages;
- }
-
- NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
- continue;
- } else {
- MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize);
- break;
- }
- } while (TRUE);
-
- MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize);
- }
-
- *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap;
-
- return;
-}
-
-/**
- Remove exec permissions from all regions whose type is identified by
- PcdDxeNxMemoryProtectionPolicy.
-**/
-STATIC
-VOID
-InitializeDxeNxMemoryProtectionPolicy (
- VOID
- )
-{
- UINTN MemoryMapSize;
- UINTN MapKey;
- UINTN DescriptorSize;
- UINT32 DescriptorVersion;
- EFI_MEMORY_DESCRIPTOR *MemoryMap;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
- EFI_MEMORY_DESCRIPTOR *MemoryMapEnd;
- EFI_STATUS Status;
- UINT64 Attributes;
- LIST_ENTRY *Link;
- EFI_GCD_MAP_ENTRY *Entry;
- EFI_PEI_HOB_POINTERS Hob;
- EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
- EFI_PHYSICAL_ADDRESS StackBase;
-
- //
- // Get the EFI memory map.
- //
- MemoryMapSize = 0;
- MemoryMap = NULL;
-
- Status = gBS->GetMemoryMap (
- &MemoryMapSize,
- MemoryMap,
- &MapKey,
- &DescriptorSize,
- &DescriptorVersion
- );
- ASSERT (Status == EFI_BUFFER_TOO_SMALL);
- do {
- MemoryMap = (EFI_MEMORY_DESCRIPTOR *)AllocatePool (MemoryMapSize);
- ASSERT (MemoryMap != NULL);
- Status = gBS->GetMemoryMap (
- &MemoryMapSize,
- MemoryMap,
- &MapKey,
- &DescriptorSize,
- &DescriptorVersion
- );
- if (EFI_ERROR (Status)) {
- FreePool (MemoryMap);
- }
- } while (Status == EFI_BUFFER_TOO_SMALL);
-
- ASSERT_EFI_ERROR (Status);
-
- StackBase = 0;
- if (PcdGetBool (PcdCpuStackGuard)) {
- //
- // Get the base of stack from Hob.
- //
- Hob.Raw = GetHobList ();
- while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) {
- MemoryHob = Hob.MemoryAllocation;
- if (CompareGuid (&gEfiHobMemoryAllocStackGuid, &MemoryHob->AllocDescriptor.Name)) {
- DEBUG ((
- DEBUG_INFO,
- "%a: StackBase = 0x%016lx StackSize = 0x%016lx\n",
- __func__,
- MemoryHob->AllocDescriptor.MemoryBaseAddress,
- MemoryHob->AllocDescriptor.MemoryLength
- ));
-
- StackBase = MemoryHob->AllocDescriptor.MemoryBaseAddress;
- //
- // Ensure the base of the stack is page-size aligned.
- //
- ASSERT ((StackBase & EFI_PAGE_MASK) == 0);
- break;
- }
-
- Hob.Raw = GET_NEXT_HOB (Hob);
- }
-
- //
- // Ensure the base of stack can be found from Hob when stack guard is
- // enabled.
- //
- ASSERT (StackBase != 0);
- }
-
- DEBUG ((
- DEBUG_INFO,
- "%a: applying strict permissions to active memory regions\n",
- __func__
- ));
-
- MergeMemoryMapForProtectionPolicy (MemoryMap, &MemoryMapSize, DescriptorSize);
-
- MemoryMapEntry = MemoryMap;
- MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize);
- while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) {
- Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type);
- if (Attributes != 0) {
- SetUefiImageMemoryAttributes (
- MemoryMapEntry->PhysicalStart,
- LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT),
- Attributes
- );
-
- //
- // Add EFI_MEMORY_RP attribute for page 0 if NULL pointer detection is
- // enabled.
- //
- if ((MemoryMapEntry->PhysicalStart == 0) &&
- (PcdGet8 (PcdNullPointerDetectionPropertyMask) != 0))
- {
- ASSERT (MemoryMapEntry->NumberOfPages > 0);
- SetUefiImageMemoryAttributes (
- 0,
- EFI_PAGES_TO_SIZE (1),
- EFI_MEMORY_RP | Attributes
- );
- }
-
- //
- // Add EFI_MEMORY_RP attribute for the first page of the stack if stack
- // guard is enabled.
- //
- if ((StackBase != 0) &&
- ((StackBase >= MemoryMapEntry->PhysicalStart) &&
- (StackBase < MemoryMapEntry->PhysicalStart +
- LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT))) &&
- PcdGetBool (PcdCpuStackGuard))
- {
- SetUefiImageMemoryAttributes (
- StackBase,
- EFI_PAGES_TO_SIZE (1),
- EFI_MEMORY_RP | Attributes
- );
- }
- }
-
- MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
- }
-
- FreePool (MemoryMap);
-
- //
- // Apply the policy for RAM regions that we know are present and
- // accessible, but have not been added to the UEFI memory map (yet).
- //
- if (GetPermissionAttributeForMemoryType (EfiConventionalMemory) != 0) {
- DEBUG ((
- DEBUG_INFO,
- "%a: applying strict permissions to inactive memory regions\n",
- __func__
- ));
-
- CoreAcquireGcdMemoryLock ();
-
- Link = mGcdMemorySpaceMap.ForwardLink;
- while (Link != &mGcdMemorySpaceMap) {
- Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE);
-
- if ((Entry->GcdMemoryType == EfiGcdMemoryTypeReserved) &&
- (Entry->EndAddress < MAX_ADDRESS) &&
- ((Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
- (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)))
- {
- Attributes = GetPermissionAttributeForMemoryType (EfiConventionalMemory) |
- (Entry->Attributes & EFI_CACHE_ATTRIBUTE_MASK);
-
- DEBUG ((
- DEBUG_INFO,
- "Untested GCD memory space region: - 0x%016lx - 0x%016lx (0x%016lx)\n",
- Entry->BaseAddress,
- Entry->EndAddress - Entry->BaseAddress + 1,
- Attributes
- ));
-
- ASSERT (gCpu != NULL);
- gCpu->SetMemoryAttributes (
- gCpu,
- Entry->BaseAddress,
- Entry->EndAddress - Entry->BaseAddress + 1,
- Attributes
- );
- }
-
- Link = Link->ForwardLink;
- }
-
- CoreReleaseGcdMemoryLock ();
- }
-}
-
-/**
- A notification for CPU_ARCH protocol.
-
- @param[in] Event Event whose notification function is being invoked.
- @param[in] Context Pointer to the notification function's context,
- which is implementation-dependent.
-
-**/
-VOID
-EFIAPI
-MemoryProtectionCpuArchProtocolNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- EFI_STATUS Status;
- EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
- EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
- UINTN NoHandles;
- EFI_HANDLE *HandleBuffer;
- UINTN Index;
-
- DEBUG ((DEBUG_INFO, "MemoryProtectionCpuArchProtocolNotify:\n"));
- Status = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Apply the memory protection policy on non-BScode/RTcode regions.
- //
- if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) {
- InitializeDxeNxMemoryProtectionPolicy ();
- }
-
- //
- // Call notify function meant for Heap Guard.
- //
- HeapGuardCpuArchProtocolNotify ();
-
- if (mImageProtectionPolicy == 0) {
- goto Done;
- }
-
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiLoadedImageProtocolGuid,
- NULL,
- &NoHandles,
- &HandleBuffer
- );
- if (EFI_ERROR (Status) && (NoHandles == 0)) {
- goto Done;
- }
-
- for (Index = 0; Index < NoHandles; Index++) {
- Status = gBS->HandleProtocol (
- HandleBuffer[Index],
- &gEfiLoadedImageProtocolGuid,
- (VOID **)&LoadedImage
- );
- if (EFI_ERROR (Status)) {
- continue;
- }
-
- Status = gBS->HandleProtocol (
- HandleBuffer[Index],
- &gEfiLoadedImageDevicePathProtocolGuid,
- (VOID **)&LoadedImageDevicePath
- );
- if (EFI_ERROR (Status)) {
- LoadedImageDevicePath = NULL;
- }
-
- ProtectUefiImage (LoadedImage, LoadedImageDevicePath);
- }
-
- FreePool (HandleBuffer);
-
-Done:
- CoreCloseEvent (Event);
-}
-
-/**
- ExitBootServices Callback function for memory protection.
-**/
-VOID
-MemoryProtectionExitBootServicesCallback (
- VOID
- )
-{
- EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage;
- LIST_ENTRY *Link;
-
- //
- // We need remove the RT protection, because RT relocation need write code segment
- // at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time.
- //
- // Firmware does not own page tables after ExitBootServices(), so the OS would
- // have to relax protection of RT code pages across SetVirtualAddressMap(), or
- // delay setting protections on RT code pages until after SetVirtualAddressMap().
- // OS may set protection on RT based upon EFI_MEMORY_ATTRIBUTES_TABLE later.
- //
- if (mImageProtectionPolicy != 0) {
- for (Link = gRuntime->ImageHead.ForwardLink; Link != &gRuntime->ImageHead; Link = Link->ForwardLink) {
- RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link);
- SetUefiImageMemoryAttributes ((UINT64)(UINTN)RuntimeImage->ImageBase, ALIGN_VALUE (RuntimeImage->ImageSize, EFI_PAGE_SIZE), 0);
- }
- }
-}
-
-/**
- Disable NULL pointer detection after EndOfDxe. This is a workaround resort in
- order to skip unfixable NULL pointer access issues detected in OptionROM or
- boot loaders.
-
- @param[in] Event The Event this notify function registered to.
- @param[in] Context Pointer to the context data registered to the Event.
-**/
-VOID
-EFIAPI
-DisableNullDetectionAtTheEndOfDxe (
- EFI_EVENT Event,
- VOID *Context
- )
-{
- EFI_STATUS Status;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc;
-
- DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): start\r\n"));
- //
- // Disable NULL pointer detection by enabling first 4K page
- //
- Status = CoreGetMemorySpaceDescriptor (0, &Desc);
- ASSERT_EFI_ERROR (Status);
-
- if ((Desc.Capabilities & EFI_MEMORY_RP) == 0) {
- Status = CoreSetMemorySpaceCapabilities (
- 0,
- EFI_PAGE_SIZE,
- Desc.Capabilities | EFI_MEMORY_RP
- );
- ASSERT_EFI_ERROR (Status);
- }
-
- Status = CoreSetMemorySpaceAttributes (
- 0,
- EFI_PAGE_SIZE,
- Desc.Attributes & ~EFI_MEMORY_RP
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Page 0 might have be allocated to avoid misuses. Free it here anyway.
- //
- CoreFreePages (0, 1);
-
- CoreCloseEvent (Event);
- DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): end\r\n"));
-
- return;
-}
-
-/**
- Initialize Memory Protection support.
-**/
-VOID
-EFIAPI
-CoreInitializeMemoryProtection (
- VOID
- )
-{
- EFI_STATUS Status;
- EFI_EVENT Event;
- EFI_EVENT EndOfDxeEvent;
- VOID *Registration;
-
- mImageProtectionPolicy = PcdGet32 (PcdImageProtectionPolicy);
-
- InitializeListHead (&mProtectedImageRecordList);
-
- //
- // Sanity check the PcdDxeNxMemoryProtectionPolicy setting:
- // - code regions should have no EFI_MEMORY_XP attribute
- // - EfiConventionalMemory and EfiBootServicesData should use the
- // same attribute
- //
- ASSERT ((GetPermissionAttributeForMemoryType (EfiBootServicesCode) & EFI_MEMORY_XP) == 0);
- ASSERT ((GetPermissionAttributeForMemoryType (EfiRuntimeServicesCode) & EFI_MEMORY_XP) == 0);
- ASSERT ((GetPermissionAttributeForMemoryType (EfiLoaderCode) & EFI_MEMORY_XP) == 0);
- ASSERT (
- GetPermissionAttributeForMemoryType (EfiBootServicesData) ==
- GetPermissionAttributeForMemoryType (EfiConventionalMemory)
- );
-
- Status = CoreCreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- MemoryProtectionCpuArchProtocolNotify,
- NULL,
- &Event
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Register for protocol notifactions on this event
- //
- Status = CoreRegisterProtocolNotify (
- &gEfiCpuArchProtocolGuid,
- Event,
- &Registration
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Register a callback to disable NULL pointer detection at EndOfDxe
- //
- if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT0|BIT7))
- == (BIT0|BIT7))
- {
- Status = CoreCreateEventEx (
- EVT_NOTIFY_SIGNAL,
- TPL_NOTIFY,
- DisableNullDetectionAtTheEndOfDxe,
- NULL,
- &gEfiEndOfDxeEventGroupGuid,
- &EndOfDxeEvent
- );
- ASSERT_EFI_ERROR (Status);
- }
-
- return;
-}
-
-/**
- Returns whether we are currently executing in SMM mode.
-**/
-STATIC
-BOOLEAN
-IsInSmm (
- VOID
- )
-{
- BOOLEAN InSmm;
-
- InSmm = FALSE;
- if (gSmmBase2 != NULL) {
- gSmmBase2->InSmm (gSmmBase2, &InSmm);
- }
-
- return InSmm;
-}
-
-/**
- Manage memory permission attributes on a memory range, according to the
- configured DXE memory protection policy.
-
- @param OldType The old memory type of the range
- @param NewType The new memory type of the range
- @param Memory The base address of the range
- @param Length The size of the range (in bytes)
-
- @return EFI_SUCCESS If we are executing in SMM mode. No permission attributes
- are updated in this case
- @return EFI_SUCCESS If the the CPU arch protocol is not installed yet
- @return EFI_SUCCESS If no DXE memory protection policy has been configured
- @return EFI_SUCCESS If OldType and NewType use the same permission attributes
- @return other Return value of gCpu->SetMemoryAttributes()
-
-**/
-EFI_STATUS
-EFIAPI
-ApplyMemoryProtectionPolicy (
- IN EFI_MEMORY_TYPE OldType,
- IN EFI_MEMORY_TYPE NewType,
- IN EFI_PHYSICAL_ADDRESS Memory,
- IN UINT64 Length
- )
-{
- UINT64 OldAttributes;
- UINT64 NewAttributes;
-
- //
- // The policy configured in PcdDxeNxMemoryProtectionPolicy
- // does not apply to allocations performed in SMM mode.
- //
- if (IsInSmm ()) {
- return EFI_SUCCESS;
- }
-
- //
- // If the CPU arch protocol is not installed yet, we cannot manage memory
- // permission attributes, and it is the job of the driver that installs this
- // protocol to set the permissions on existing allocations.
- //
- if (gCpu == NULL) {
- return EFI_SUCCESS;
- }
-
- //
- // Check if a DXE memory protection policy has been configured
- //
- if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) == 0) {
- return EFI_SUCCESS;
- }
-
- //
- // Don't overwrite Guard pages, which should be the first and/or last page,
- // if any.
- //
- if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL)) {
- if (IsGuardPage (Memory)) {
- Memory += EFI_PAGE_SIZE;
- Length -= EFI_PAGE_SIZE;
- if (Length == 0) {
- return EFI_SUCCESS;
- }
- }
-
- if (IsGuardPage (Memory + Length - EFI_PAGE_SIZE)) {
- Length -= EFI_PAGE_SIZE;
- if (Length == 0) {
- return EFI_SUCCESS;
- }
- }
- }
-
- //
- // Update the executable permissions according to the DXE memory
- // protection policy, but only if
- // - the policy is different between the old and the new type, or
- // - this is a newly added region (OldType == EfiMaxMemoryType)
- //
- NewAttributes = GetPermissionAttributeForMemoryType (NewType);
-
- if (OldType != EfiMaxMemoryType) {
- OldAttributes = GetPermissionAttributeForMemoryType (OldType);
- if (OldAttributes == NewAttributes) {
- // policy is the same between OldType and NewType
- return EFI_SUCCESS;
- }
- } else if (NewAttributes == 0) {
- // newly added region of a type that does not require protection
- return EFI_SUCCESS;
- }
-
- return gCpu->SetMemoryAttributes (gCpu, Memory, Length, NewAttributes);
-}
+/** @file + UEFI Memory Protection support. + + If the UEFI image is page aligned, the image code section is set to read only + and the image data section is set to non-executable. + + 1) This policy is applied for all UEFI image including boot service driver, + runtime driver or application. + 2) This policy is applied only if the UEFI image meets the page alignment + requirement. + 3) This policy is applied only if the Source UEFI image matches the + PcdImageProtectionPolicy definition. + 4) This policy is not applied to the non-PE image region. + + The DxeCore calls CpuArchProtocol->SetMemoryAttributes() to protect + the image. If the CpuArch protocol is not installed yet, the DxeCore + enqueues the protection request. Once the CpuArch is installed, the + DxeCore dequeues the protection request and applies policy. + + Once the image is unloaded, the protection is removed automatically. + +Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <PiDxe.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/DxeServicesTableLib.h> +#include <Library/DebugLib.h> +#include <Library/UefiLib.h> +#include <Library/ImagePropertiesRecordLib.h> + +#include <Guid/EventGroup.h> +#include <Guid/MemoryAttributesTable.h> + +#include <Protocol/FirmwareVolume2.h> +#include <Protocol/SimpleFileSystem.h> + +#include "DxeMain.h" +#include "Mem/HeapGuard.h" + +// +// Image type definitions +// +#define IMAGE_UNKNOWN 0x00000001 +#define IMAGE_FROM_FV 0x00000002 + +// +// Protection policy bit definition +// +#define DO_NOT_PROTECT 0x00000000 +#define PROTECT_IF_ALIGNED_ELSE_ALLOW 0x00000001 + +#define MEMORY_TYPE_OS_RESERVED_MIN 0x80000000 +#define MEMORY_TYPE_OEM_RESERVED_MIN 0x70000000 + +#define PREVIOUS_MEMORY_DESCRIPTOR(MemoryDescriptor, Size) \ + ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)(MemoryDescriptor) - (Size))) + +UINT32 mImageProtectionPolicy; + +extern LIST_ENTRY mGcdMemorySpaceMap; + +STATIC LIST_ENTRY mProtectedImageRecordList; + +/** + Get the image type. + + @param[in] File This is a pointer to the device path of the file that is + being dispatched. + + @return UINT32 Image Type +**/ +UINT32 +GetImageType ( + IN CONST EFI_DEVICE_PATH_PROTOCOL *File + ) +{ + EFI_STATUS Status; + EFI_HANDLE DeviceHandle; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + + if (File == NULL) { + return IMAGE_UNKNOWN; + } + + // + // First check to see if File is from a Firmware Volume + // + DeviceHandle = NULL; + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File; + Status = gBS->LocateDevicePath ( + &gEfiFirmwareVolume2ProtocolGuid, + &TempDevicePath, + &DeviceHandle + ); + if (!EFI_ERROR (Status)) { + Status = gBS->OpenProtocol ( + DeviceHandle, + &gEfiFirmwareVolume2ProtocolGuid, + NULL, + NULL, + NULL, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + return IMAGE_FROM_FV; + } + } + + return IMAGE_UNKNOWN; +} + +/** + Get UEFI image protection policy based upon image type. + + @param[in] ImageType The UEFI image type + + @return UEFI image protection policy +**/ +UINT32 +GetProtectionPolicyFromImageType ( + IN UINT32 ImageType + ) +{ + if ((ImageType & mImageProtectionPolicy) == 0) { + return DO_NOT_PROTECT; + } else { + return PROTECT_IF_ALIGNED_ELSE_ALLOW; + } +} + +/** + Get UEFI image protection policy based upon loaded image device path. + + @param[in] LoadedImage The loaded image protocol + @param[in] LoadedImageDevicePath The loaded image device path protocol + + @return UEFI image protection policy +**/ +UINT32 +GetUefiImageProtectionPolicy ( + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, + IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath + ) +{ + BOOLEAN InSmm; + UINT32 ImageType; + UINT32 ProtectionPolicy; + + // + // Check SMM + // + InSmm = FALSE; + if (gSmmBase2 != NULL) { + gSmmBase2->InSmm (gSmmBase2, &InSmm); + } + + if (InSmm) { + return FALSE; + } + + // + // Check DevicePath + // + if (LoadedImage == gDxeCoreLoadedImage) { + ImageType = IMAGE_FROM_FV; + } else { + ImageType = GetImageType (LoadedImageDevicePath); + } + + ProtectionPolicy = GetProtectionPolicyFromImageType (ImageType); + return ProtectionPolicy; +} + +/** + Set UEFI image memory attributes. + + @param[in] BaseAddress Specified start address + @param[in] Length Specified length + @param[in] Attributes Specified attributes +**/ +VOID +SetUefiImageMemoryAttributes ( + IN UINT64 BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes + ) +{ + EFI_STATUS Status; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; + UINT64 FinalAttributes; + + Status = CoreGetMemorySpaceDescriptor (BaseAddress, &Descriptor); + ASSERT_EFI_ERROR (Status); + + FinalAttributes = (Descriptor.Attributes & EFI_CACHE_ATTRIBUTE_MASK) | (Attributes & EFI_MEMORY_ATTRIBUTE_MASK); + + DEBUG ((DEBUG_INFO, "SetUefiImageMemoryAttributes - 0x%016lx - 0x%016lx (0x%016lx)\n", BaseAddress, Length, FinalAttributes)); + + ASSERT (gCpu != NULL); + gCpu->SetMemoryAttributes (gCpu, BaseAddress, Length, FinalAttributes); +} + +/** + Set UEFI image protection attributes. + + @param[in] ImageRecord A UEFI image record +**/ +VOID +SetUefiImageProtectionAttributes ( + IN IMAGE_PROPERTIES_RECORD *ImageRecord + ) +{ + IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection; + LIST_ENTRY *ImageRecordCodeSectionLink; + LIST_ENTRY *ImageRecordCodeSectionEndLink; + LIST_ENTRY *ImageRecordCodeSectionList; + UINT64 CurrentBase; + UINT64 ImageEnd; + + ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList; + + CurrentBase = ImageRecord->ImageBase; + ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize; + + ImageRecordCodeSectionLink = ImageRecordCodeSectionList->ForwardLink; + ImageRecordCodeSectionEndLink = ImageRecordCodeSectionList; + while (ImageRecordCodeSectionLink != ImageRecordCodeSectionEndLink) { + ImageRecordCodeSection = CR ( + ImageRecordCodeSectionLink, + IMAGE_PROPERTIES_RECORD_CODE_SECTION, + Link, + IMAGE_PROPERTIES_RECORD_CODE_SECTION_SIGNATURE + ); + ImageRecordCodeSectionLink = ImageRecordCodeSectionLink->ForwardLink; + + ASSERT (CurrentBase <= ImageRecordCodeSection->CodeSegmentBase); + if (CurrentBase < ImageRecordCodeSection->CodeSegmentBase) { + // + // DATA + // + SetUefiImageMemoryAttributes ( + CurrentBase, + ImageRecordCodeSection->CodeSegmentBase - CurrentBase, + EFI_MEMORY_XP + ); + } + + // + // CODE + // + SetUefiImageMemoryAttributes ( + ImageRecordCodeSection->CodeSegmentBase, + ImageRecordCodeSection->CodeSegmentSize, + EFI_MEMORY_RO + ); + CurrentBase = ImageRecordCodeSection->CodeSegmentBase + ImageRecordCodeSection->CodeSegmentSize; + } + + // + // Last DATA + // + ASSERT (CurrentBase <= ImageEnd); + if (CurrentBase < ImageEnd) { + // + // DATA + // + SetUefiImageMemoryAttributes ( + CurrentBase, + ImageEnd - CurrentBase, + EFI_MEMORY_XP + ); + } + + return; +} + +/** + Return the section alignment requirement for the PE image section type. + + @param[in] MemoryType PE/COFF image memory type + + @retval The required section alignment for this memory type + +**/ +STATIC +UINT32 +GetMemoryProtectionSectionAlignment ( + IN EFI_MEMORY_TYPE MemoryType + ) +{ + UINT32 SectionAlignment; + + switch (MemoryType) { + case EfiRuntimeServicesCode: + case EfiACPIMemoryNVS: + case EfiReservedMemoryType: + SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY; + break; + case EfiRuntimeServicesData: + ASSERT (FALSE); + SectionAlignment = RUNTIME_PAGE_ALLOCATION_GRANULARITY; + break; + case EfiBootServicesCode: + case EfiLoaderCode: + SectionAlignment = EFI_PAGE_SIZE; + break; + case EfiACPIReclaimMemory: + default: + ASSERT (FALSE); + SectionAlignment = EFI_PAGE_SIZE; + break; + } + + return SectionAlignment; +} + +/** + Protect UEFI PE/COFF image. + + @param[in] LoadedImage The loaded image protocol + @param[in] LoadedImageDevicePath The loaded image device path protocol +**/ +VOID +ProtectUefiImage ( + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, + IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath + ) +{ + IMAGE_PROPERTIES_RECORD *ImageRecord; + UINT32 ProtectionPolicy; + EFI_STATUS Status; + UINT32 RequiredAlignment; + + DEBUG ((DEBUG_INFO, "ProtectUefiImageCommon - 0x%x\n", LoadedImage)); + DEBUG ((DEBUG_INFO, " - 0x%016lx - 0x%016lx\n", (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase, LoadedImage->ImageSize)); + + if (gCpu == NULL) { + return; + } + + ProtectionPolicy = GetUefiImageProtectionPolicy (LoadedImage, LoadedImageDevicePath); + switch (ProtectionPolicy) { + case DO_NOT_PROTECT: + return; + case PROTECT_IF_ALIGNED_ELSE_ALLOW: + break; + default: + ASSERT (FALSE); + return; + } + + ImageRecord = AllocateZeroPool (sizeof (*ImageRecord)); + if (ImageRecord == NULL) { + return; + } + + RequiredAlignment = GetMemoryProtectionSectionAlignment (LoadedImage->ImageCodeType); + + Status = CreateImagePropertiesRecord ( + LoadedImage->ImageBase, + LoadedImage->ImageSize, + &RequiredAlignment, + ImageRecord + ); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a failed to create image properties record\n", __func__)); + FreePool (ImageRecord); + goto Finish; + } + + // + // CPU ARCH present. Update memory attribute directly. + // + SetUefiImageProtectionAttributes (ImageRecord); + + // + // Record the image record in the list so we can undo the protections later + // + InsertTailList (&mProtectedImageRecordList, &ImageRecord->Link); + +Finish: + return; +} + +/** + Unprotect UEFI image. + + @param[in] LoadedImage The loaded image protocol + @param[in] LoadedImageDevicePath The loaded image device path protocol +**/ +VOID +UnprotectUefiImage ( + IN EFI_LOADED_IMAGE_PROTOCOL *LoadedImage, + IN EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath + ) +{ + IMAGE_PROPERTIES_RECORD *ImageRecord; + LIST_ENTRY *ImageRecordLink; + + if (PcdGet32 (PcdImageProtectionPolicy) != 0) { + for (ImageRecordLink = mProtectedImageRecordList.ForwardLink; + ImageRecordLink != &mProtectedImageRecordList; + ImageRecordLink = ImageRecordLink->ForwardLink) + { + ImageRecord = CR ( + ImageRecordLink, + IMAGE_PROPERTIES_RECORD, + Link, + IMAGE_PROPERTIES_RECORD_SIGNATURE + ); + + if (ImageRecord->ImageBase == (EFI_PHYSICAL_ADDRESS)(UINTN)LoadedImage->ImageBase) { + SetUefiImageMemoryAttributes ( + ImageRecord->ImageBase, + ImageRecord->ImageSize, + 0 + ); + DeleteImagePropertiesRecord (ImageRecord); + return; + } + } + } +} + +/** + Return the EFI memory permission attribute associated with memory + type 'MemoryType' under the configured DXE memory protection policy. + + @param MemoryType Memory type. +**/ +STATIC +UINT64 +GetPermissionAttributeForMemoryType ( + IN EFI_MEMORY_TYPE MemoryType + ) +{ + UINT64 TestBit; + + if ((UINT32)MemoryType >= MEMORY_TYPE_OS_RESERVED_MIN) { + TestBit = BIT63; + } else if ((UINT32)MemoryType >= MEMORY_TYPE_OEM_RESERVED_MIN) { + TestBit = BIT62; + } else { + TestBit = LShiftU64 (1, MemoryType); + } + + if ((PcdGet64 (PcdDxeNxMemoryProtectionPolicy) & TestBit) != 0) { + return EFI_MEMORY_XP; + } else { + return 0; + } +} + +/** + Sort memory map entries based upon PhysicalStart, from low to high. + + @param MemoryMap A pointer to the buffer in which firmware places + the current memory map. + @param MemoryMapSize Size, in bytes, of the MemoryMap buffer. + @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR. +**/ +STATIC +VOID +SortMemoryMap ( + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + IN UINTN MemoryMapSize, + IN UINTN DescriptorSize + ) +{ + EFI_MEMORY_DESCRIPTOR *MemoryMapEntry; + EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry; + EFI_MEMORY_DESCRIPTOR *MemoryMapEnd; + EFI_MEMORY_DESCRIPTOR TempMemoryMap; + + MemoryMapEntry = MemoryMap; + NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); + MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize); + while (MemoryMapEntry < MemoryMapEnd) { + while (NextMemoryMapEntry < MemoryMapEnd) { + if (MemoryMapEntry->PhysicalStart > NextMemoryMapEntry->PhysicalStart) { + CopyMem (&TempMemoryMap, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); + CopyMem (MemoryMapEntry, NextMemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); + CopyMem (NextMemoryMapEntry, &TempMemoryMap, sizeof (EFI_MEMORY_DESCRIPTOR)); + } + + NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize); + } + + MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); + NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); + } +} + +/** + Merge adjacent memory map entries if they use the same memory protection policy + + @param[in, out] MemoryMap A pointer to the buffer in which firmware places + the current memory map. + @param[in, out] MemoryMapSize A pointer to the size, in bytes, of the + MemoryMap buffer. On input, this is the size of + the current memory map. On output, + it is the size of new memory map after merge. + @param[in] DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR. +**/ +STATIC +VOID +MergeMemoryMapForProtectionPolicy ( + IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, + IN OUT UINTN *MemoryMapSize, + IN UINTN DescriptorSize + ) +{ + EFI_MEMORY_DESCRIPTOR *MemoryMapEntry; + EFI_MEMORY_DESCRIPTOR *MemoryMapEnd; + UINT64 MemoryBlockLength; + EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry; + EFI_MEMORY_DESCRIPTOR *NextMemoryMapEntry; + UINT64 Attributes; + + SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize); + + MemoryMapEntry = MemoryMap; + NewMemoryMapEntry = MemoryMap; + MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + *MemoryMapSize); + while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) { + CopyMem (NewMemoryMapEntry, MemoryMapEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); + NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); + + do { + MemoryBlockLength = (UINT64)(EFI_PAGES_TO_SIZE ((UINTN)MemoryMapEntry->NumberOfPages)); + Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type); + + if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) && + (Attributes == GetPermissionAttributeForMemoryType (NextMemoryMapEntry->Type)) && + ((MemoryMapEntry->PhysicalStart + MemoryBlockLength) == NextMemoryMapEntry->PhysicalStart)) + { + MemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages; + if (NewMemoryMapEntry != MemoryMapEntry) { + NewMemoryMapEntry->NumberOfPages += NextMemoryMapEntry->NumberOfPages; + } + + NextMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize); + continue; + } else { + MemoryMapEntry = PREVIOUS_MEMORY_DESCRIPTOR (NextMemoryMapEntry, DescriptorSize); + break; + } + } while (TRUE); + + MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); + NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (NewMemoryMapEntry, DescriptorSize); + } + + *MemoryMapSize = (UINTN)NewMemoryMapEntry - (UINTN)MemoryMap; + + return; +} + +/** + Remove exec permissions from all regions whose type is identified by + PcdDxeNxMemoryProtectionPolicy. +**/ +STATIC +VOID +InitializeDxeNxMemoryProtectionPolicy ( + VOID + ) +{ + UINTN MemoryMapSize; + UINTN MapKey; + UINTN DescriptorSize; + UINT32 DescriptorVersion; + EFI_MEMORY_DESCRIPTOR *MemoryMap; + EFI_MEMORY_DESCRIPTOR *MemoryMapEntry; + EFI_MEMORY_DESCRIPTOR *MemoryMapEnd; + EFI_STATUS Status; + UINT64 Attributes; + LIST_ENTRY *Link; + EFI_GCD_MAP_ENTRY *Entry; + EFI_PEI_HOB_POINTERS Hob; + EFI_HOB_MEMORY_ALLOCATION *MemoryHob; + EFI_PHYSICAL_ADDRESS StackBase; + + // + // Get the EFI memory map. + // + MemoryMapSize = 0; + MemoryMap = NULL; + + Status = gBS->GetMemoryMap ( + &MemoryMapSize, + MemoryMap, + &MapKey, + &DescriptorSize, + &DescriptorVersion + ); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + do { + MemoryMap = (EFI_MEMORY_DESCRIPTOR *)AllocatePool (MemoryMapSize); + ASSERT (MemoryMap != NULL); + Status = gBS->GetMemoryMap ( + &MemoryMapSize, + MemoryMap, + &MapKey, + &DescriptorSize, + &DescriptorVersion + ); + if (EFI_ERROR (Status)) { + FreePool (MemoryMap); + } + } while (Status == EFI_BUFFER_TOO_SMALL); + + ASSERT_EFI_ERROR (Status); + + StackBase = 0; + if (PcdGetBool (PcdCpuStackGuard)) { + // + // Get the base of stack from Hob. + // + Hob.Raw = GetHobList (); + while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) { + MemoryHob = Hob.MemoryAllocation; + if (CompareGuid (&gEfiHobMemoryAllocStackGuid, &MemoryHob->AllocDescriptor.Name)) { + DEBUG (( + DEBUG_INFO, + "%a: StackBase = 0x%016lx StackSize = 0x%016lx\n", + __func__, + MemoryHob->AllocDescriptor.MemoryBaseAddress, + MemoryHob->AllocDescriptor.MemoryLength + )); + + StackBase = MemoryHob->AllocDescriptor.MemoryBaseAddress; + // + // Ensure the base of the stack is page-size aligned. + // + ASSERT ((StackBase & EFI_PAGE_MASK) == 0); + break; + } + + Hob.Raw = GET_NEXT_HOB (Hob); + } + + // + // Ensure the base of stack can be found from Hob when stack guard is + // enabled. + // + ASSERT (StackBase != 0); + } + + DEBUG (( + DEBUG_INFO, + "%a: applying strict permissions to active memory regions\n", + __func__ + )); + + MergeMemoryMapForProtectionPolicy (MemoryMap, &MemoryMapSize, DescriptorSize); + + MemoryMapEntry = MemoryMap; + MemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + MemoryMapSize); + while ((UINTN)MemoryMapEntry < (UINTN)MemoryMapEnd) { + Attributes = GetPermissionAttributeForMemoryType (MemoryMapEntry->Type); + if (Attributes != 0) { + SetUefiImageMemoryAttributes ( + MemoryMapEntry->PhysicalStart, + LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT), + Attributes + ); + + // + // Add EFI_MEMORY_RP attribute for page 0 if NULL pointer detection is + // enabled. + // + if ((MemoryMapEntry->PhysicalStart == 0) && + (PcdGet8 (PcdNullPointerDetectionPropertyMask) != 0)) + { + ASSERT (MemoryMapEntry->NumberOfPages > 0); + SetUefiImageMemoryAttributes ( + 0, + EFI_PAGES_TO_SIZE (1), + EFI_MEMORY_RP | Attributes + ); + } + + // + // Add EFI_MEMORY_RP attribute for the first page of the stack if stack + // guard is enabled. + // + if ((StackBase != 0) && + ((StackBase >= MemoryMapEntry->PhysicalStart) && + (StackBase < MemoryMapEntry->PhysicalStart + + LShiftU64 (MemoryMapEntry->NumberOfPages, EFI_PAGE_SHIFT))) && + PcdGetBool (PcdCpuStackGuard)) + { + SetUefiImageMemoryAttributes ( + StackBase, + EFI_PAGES_TO_SIZE (1), + EFI_MEMORY_RP | Attributes + ); + } + } + + MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize); + } + + FreePool (MemoryMap); + + // + // Apply the policy for RAM regions that we know are present and + // accessible, but have not been added to the UEFI memory map (yet). + // + if (GetPermissionAttributeForMemoryType (EfiConventionalMemory) != 0) { + DEBUG (( + DEBUG_INFO, + "%a: applying strict permissions to inactive memory regions\n", + __func__ + )); + + CoreAcquireGcdMemoryLock (); + + Link = mGcdMemorySpaceMap.ForwardLink; + while (Link != &mGcdMemorySpaceMap) { + Entry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); + + if ((Entry->GcdMemoryType == EfiGcdMemoryTypeReserved) && + (Entry->EndAddress < MAX_ADDRESS) && + ((Entry->Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) == + (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED))) + { + Attributes = GetPermissionAttributeForMemoryType (EfiConventionalMemory) | + (Entry->Attributes & EFI_CACHE_ATTRIBUTE_MASK); + + DEBUG (( + DEBUG_INFO, + "Untested GCD memory space region: - 0x%016lx - 0x%016lx (0x%016lx)\n", + Entry->BaseAddress, + Entry->EndAddress - Entry->BaseAddress + 1, + Attributes + )); + + ASSERT (gCpu != NULL); + gCpu->SetMemoryAttributes ( + gCpu, + Entry->BaseAddress, + Entry->EndAddress - Entry->BaseAddress + 1, + Attributes + ); + } + + Link = Link->ForwardLink; + } + + CoreReleaseGcdMemoryLock (); + } +} + +/** + A notification for CPU_ARCH protocol. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context, + which is implementation-dependent. + +**/ +VOID +EFIAPI +MemoryProtectionCpuArchProtocolNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath; + UINTN NoHandles; + EFI_HANDLE *HandleBuffer; + UINTN Index; + + DEBUG ((DEBUG_INFO, "MemoryProtectionCpuArchProtocolNotify:\n")); + Status = CoreLocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&gCpu); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Apply the memory protection policy on non-BScode/RTcode regions. + // + if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) != 0) { + InitializeDxeNxMemoryProtectionPolicy (); + } + + // + // Call notify function meant for Heap Guard. + // + HeapGuardCpuArchProtocolNotify (); + + if (mImageProtectionPolicy == 0) { + goto Done; + } + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiLoadedImageProtocolGuid, + NULL, + &NoHandles, + &HandleBuffer + ); + if (EFI_ERROR (Status) && (NoHandles == 0)) { + goto Done; + } + + for (Index = 0; Index < NoHandles; Index++) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiLoadedImageProtocolGuid, + (VOID **)&LoadedImage + ); + if (EFI_ERROR (Status)) { + continue; + } + + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiLoadedImageDevicePathProtocolGuid, + (VOID **)&LoadedImageDevicePath + ); + if (EFI_ERROR (Status)) { + LoadedImageDevicePath = NULL; + } + + ProtectUefiImage (LoadedImage, LoadedImageDevicePath); + } + + FreePool (HandleBuffer); + +Done: + CoreCloseEvent (Event); +} + +/** + ExitBootServices Callback function for memory protection. +**/ +VOID +MemoryProtectionExitBootServicesCallback ( + VOID + ) +{ + EFI_RUNTIME_IMAGE_ENTRY *RuntimeImage; + LIST_ENTRY *Link; + + // + // We need remove the RT protection, because RT relocation need write code segment + // at SetVirtualAddressMap(). We cannot assume OS/Loader has taken over page table at that time. + // + // Firmware does not own page tables after ExitBootServices(), so the OS would + // have to relax protection of RT code pages across SetVirtualAddressMap(), or + // delay setting protections on RT code pages until after SetVirtualAddressMap(). + // OS may set protection on RT based upon EFI_MEMORY_ATTRIBUTES_TABLE later. + // + if (mImageProtectionPolicy != 0) { + for (Link = gRuntime->ImageHead.ForwardLink; Link != &gRuntime->ImageHead; Link = Link->ForwardLink) { + RuntimeImage = BASE_CR (Link, EFI_RUNTIME_IMAGE_ENTRY, Link); + SetUefiImageMemoryAttributes ((UINT64)(UINTN)RuntimeImage->ImageBase, ALIGN_VALUE (RuntimeImage->ImageSize, EFI_PAGE_SIZE), 0); + } + } +} + +/** + Disable NULL pointer detection after EndOfDxe. This is a workaround resort in + order to skip unfixable NULL pointer access issues detected in OptionROM or + boot loaders. + + @param[in] Event The Event this notify function registered to. + @param[in] Context Pointer to the context data registered to the Event. +**/ +VOID +EFIAPI +DisableNullDetectionAtTheEndOfDxe ( + EFI_EVENT Event, + VOID *Context + ) +{ + EFI_STATUS Status; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR Desc; + + DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): start\r\n")); + // + // Disable NULL pointer detection by enabling first 4K page + // + Status = CoreGetMemorySpaceDescriptor (0, &Desc); + ASSERT_EFI_ERROR (Status); + + if ((Desc.Capabilities & EFI_MEMORY_RP) == 0) { + Status = CoreSetMemorySpaceCapabilities ( + 0, + EFI_PAGE_SIZE, + Desc.Capabilities | EFI_MEMORY_RP + ); + ASSERT_EFI_ERROR (Status); + } + + Status = CoreSetMemorySpaceAttributes ( + 0, + EFI_PAGE_SIZE, + Desc.Attributes & ~EFI_MEMORY_RP + ); + ASSERT_EFI_ERROR (Status); + + // + // Page 0 might have be allocated to avoid misuses. Free it here anyway. + // + CoreFreePages (0, 1); + + CoreCloseEvent (Event); + DEBUG ((DEBUG_INFO, "DisableNullDetectionAtTheEndOfDxe(): end\r\n")); + + return; +} + +/** + Initialize Memory Protection support. +**/ +VOID +EFIAPI +CoreInitializeMemoryProtection ( + VOID + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + EFI_EVENT EndOfDxeEvent; + VOID *Registration; + + mImageProtectionPolicy = PcdGet32 (PcdImageProtectionPolicy); + + InitializeListHead (&mProtectedImageRecordList); + + // + // Sanity check the PcdDxeNxMemoryProtectionPolicy setting: + // - code regions should have no EFI_MEMORY_XP attribute + // - EfiConventionalMemory and EfiBootServicesData should use the + // same attribute + // + ASSERT ((GetPermissionAttributeForMemoryType (EfiBootServicesCode) & EFI_MEMORY_XP) == 0); + ASSERT ((GetPermissionAttributeForMemoryType (EfiRuntimeServicesCode) & EFI_MEMORY_XP) == 0); + ASSERT ((GetPermissionAttributeForMemoryType (EfiLoaderCode) & EFI_MEMORY_XP) == 0); + ASSERT ( + GetPermissionAttributeForMemoryType (EfiBootServicesData) == + GetPermissionAttributeForMemoryType (EfiConventionalMemory) + ); + + Status = CoreCreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + MemoryProtectionCpuArchProtocolNotify, + NULL, + &Event + ); + ASSERT_EFI_ERROR (Status); + + // + // Register for protocol notifactions on this event + // + Status = CoreRegisterProtocolNotify ( + &gEfiCpuArchProtocolGuid, + Event, + &Registration + ); + ASSERT_EFI_ERROR (Status); + + // + // Register a callback to disable NULL pointer detection at EndOfDxe + // + if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT0|BIT7)) + == (BIT0|BIT7)) + { + Status = CoreCreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + DisableNullDetectionAtTheEndOfDxe, + NULL, + &gEfiEndOfDxeEventGroupGuid, + &EndOfDxeEvent + ); + ASSERT_EFI_ERROR (Status); + } + + return; +} + +/** + Returns whether we are currently executing in SMM mode. +**/ +STATIC +BOOLEAN +IsInSmm ( + VOID + ) +{ + BOOLEAN InSmm; + + InSmm = FALSE; + if (gSmmBase2 != NULL) { + gSmmBase2->InSmm (gSmmBase2, &InSmm); + } + + return InSmm; +} + +/** + Manage memory permission attributes on a memory range, according to the + configured DXE memory protection policy. + + @param OldType The old memory type of the range + @param NewType The new memory type of the range + @param Memory The base address of the range + @param Length The size of the range (in bytes) + + @return EFI_SUCCESS If we are executing in SMM mode. No permission attributes + are updated in this case + @return EFI_SUCCESS If the the CPU arch protocol is not installed yet + @return EFI_SUCCESS If no DXE memory protection policy has been configured + @return EFI_SUCCESS If OldType and NewType use the same permission attributes + @return other Return value of gCpu->SetMemoryAttributes() + +**/ +EFI_STATUS +EFIAPI +ApplyMemoryProtectionPolicy ( + IN EFI_MEMORY_TYPE OldType, + IN EFI_MEMORY_TYPE NewType, + IN EFI_PHYSICAL_ADDRESS Memory, + IN UINT64 Length + ) +{ + UINT64 OldAttributes; + UINT64 NewAttributes; + + // + // The policy configured in PcdDxeNxMemoryProtectionPolicy + // does not apply to allocations performed in SMM mode. + // + if (IsInSmm ()) { + return EFI_SUCCESS; + } + + // + // If the CPU arch protocol is not installed yet, we cannot manage memory + // permission attributes, and it is the job of the driver that installs this + // protocol to set the permissions on existing allocations. + // + if (gCpu == NULL) { + return EFI_SUCCESS; + } + + // + // Check if a DXE memory protection policy has been configured + // + if (PcdGet64 (PcdDxeNxMemoryProtectionPolicy) == 0) { + return EFI_SUCCESS; + } + + // + // Don't overwrite Guard pages, which should be the first and/or last page, + // if any. + // + if (IsHeapGuardEnabled (GUARD_HEAP_TYPE_PAGE|GUARD_HEAP_TYPE_POOL)) { + if (IsGuardPage (Memory)) { + Memory += EFI_PAGE_SIZE; + Length -= EFI_PAGE_SIZE; + if (Length == 0) { + return EFI_SUCCESS; + } + } + + if (IsGuardPage (Memory + Length - EFI_PAGE_SIZE)) { + Length -= EFI_PAGE_SIZE; + if (Length == 0) { + return EFI_SUCCESS; + } + } + } + + // + // Update the executable permissions according to the DXE memory + // protection policy, but only if + // - the policy is different between the old and the new type, or + // - this is a newly added region (OldType == EfiMaxMemoryType) + // + NewAttributes = GetPermissionAttributeForMemoryType (NewType); + + if (OldType != EfiMaxMemoryType) { + OldAttributes = GetPermissionAttributeForMemoryType (OldType); + if (OldAttributes == NewAttributes) { + // policy is the same between OldType and NewType + return EFI_SUCCESS; + } + } else if (NewAttributes == 0) { + // newly added region of a type that does not require protection + return EFI_SUCCESS; + } + + return gCpu->SetMemoryAttributes (gCpu, Memory, Length, NewAttributes); +} diff --git a/MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c b/MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c index c3cabc0d36..e1b092176b 100644 --- a/MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c +++ b/MdeModulePkg/Core/Dxe/Misc/SetWatchdogTimer.c @@ -1,66 +1,66 @@ -/** @file
- UEFI Miscellaneous boot Services SetWatchdogTimer service implementation
-
-Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-
-#define WATCHDOG_TIMER_CALIBRATE_PER_SECOND 10000000
-
-/**
- Sets the system's watchdog timer.
-
- @param Timeout The number of seconds to set the watchdog timer to.
- A value of zero disables the timer.
- @param WatchdogCode The numeric code to log on a watchdog timer timeout
- event. The firmware reserves codes 0x0000 to 0xFFFF.
- Loaders and operating systems may use other timeout
- codes.
- @param DataSize The size, in bytes, of WatchdogData.
- @param WatchdogData A data buffer that includes a Null-terminated Unicode
- string, optionally followed by additional binary data.
- The string is a description that the call may use to
- further indicate the reason to be logged with a
- watchdog event.
-
- @return EFI_SUCCESS Timeout has been set
- @return EFI_NOT_AVAILABLE_YET WatchdogTimer is not available yet
- @return EFI_UNSUPPORTED System does not have a timer (currently not used)
- @return EFI_DEVICE_ERROR Could not complete due to hardware error
-
-**/
-EFI_STATUS
-EFIAPI
-CoreSetWatchdogTimer (
- IN UINTN Timeout,
- IN UINT64 WatchdogCode,
- IN UINTN DataSize,
- IN CHAR16 *WatchdogData OPTIONAL
- )
-{
- EFI_STATUS Status;
-
- //
- // Check our architectural protocol
- //
- if (gWatchdogTimer == NULL) {
- return EFI_NOT_AVAILABLE_YET;
- }
-
- //
- // Attempt to set the timeout
- //
- Status = gWatchdogTimer->SetTimerPeriod (gWatchdogTimer, MultU64x32 (Timeout, WATCHDOG_TIMER_CALIBRATE_PER_SECOND));
-
- //
- // Check for errors
- //
- if (EFI_ERROR (Status)) {
- return EFI_DEVICE_ERROR;
- }
-
- return EFI_SUCCESS;
-}
+/** @file + UEFI Miscellaneous boot Services SetWatchdogTimer service implementation + +Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DxeMain.h" + +#define WATCHDOG_TIMER_CALIBRATE_PER_SECOND 10000000 + +/** + Sets the system's watchdog timer. + + @param Timeout The number of seconds to set the watchdog timer to. + A value of zero disables the timer. + @param WatchdogCode The numeric code to log on a watchdog timer timeout + event. The firmware reserves codes 0x0000 to 0xFFFF. + Loaders and operating systems may use other timeout + codes. + @param DataSize The size, in bytes, of WatchdogData. + @param WatchdogData A data buffer that includes a Null-terminated Unicode + string, optionally followed by additional binary data. + The string is a description that the call may use to + further indicate the reason to be logged with a + watchdog event. + + @return EFI_SUCCESS Timeout has been set + @return EFI_NOT_AVAILABLE_YET WatchdogTimer is not available yet + @return EFI_UNSUPPORTED System does not have a timer (currently not used) + @return EFI_DEVICE_ERROR Could not complete due to hardware error + +**/ +EFI_STATUS +EFIAPI +CoreSetWatchdogTimer ( + IN UINTN Timeout, + IN UINT64 WatchdogCode, + IN UINTN DataSize, + IN CHAR16 *WatchdogData OPTIONAL + ) +{ + EFI_STATUS Status; + + // + // Check our architectural protocol + // + if (gWatchdogTimer == NULL) { + return EFI_NOT_AVAILABLE_YET; + } + + // + // Attempt to set the timeout + // + Status = gWatchdogTimer->SetTimerPeriod (gWatchdogTimer, MultU64x32 (Timeout, WATCHDOG_TIMER_CALIBRATE_PER_SECOND)); + + // + // Check for errors + // + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} diff --git a/MdeModulePkg/Core/Dxe/Misc/Stall.c b/MdeModulePkg/Core/Dxe/Misc/Stall.c index 35e045d41a..43a272af6c 100644 --- a/MdeModulePkg/Core/Dxe/Misc/Stall.c +++ b/MdeModulePkg/Core/Dxe/Misc/Stall.c @@ -1,109 +1,109 @@ -/** @file
- UEFI Miscellaneous boot Services Stall service implementation
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-//
-// Include statements
-//
-
-#include "DxeMain.h"
-
-/**
- Internal worker function to call the Metronome Architectural Protocol for
- the number of ticks specified by the UINT64 Counter value. WaitForTick()
- service of the Metronome Architectural Protocol uses a UINT32 for the number
- of ticks to wait, so this function loops when Counter is larger than 0xffffffff.
-
- @param Counter Number of ticks to wait.
-
-**/
-VOID
-CoreInternalWaitForTick (
- IN UINT64 Counter
- )
-{
- while (RShiftU64 (Counter, 32) > 0) {
- gMetronome->WaitForTick (gMetronome, 0xffffffff);
- Counter -= 0xffffffff;
- }
-
- gMetronome->WaitForTick (gMetronome, (UINT32)Counter);
-}
-
-/**
- Introduces a fine-grained stall.
-
- @param Microseconds The number of microseconds to stall execution.
-
- @retval EFI_SUCCESS Execution was stalled for at least the requested
- amount of microseconds.
- @retval EFI_NOT_AVAILABLE_YET gMetronome is not available yet
-
-**/
-EFI_STATUS
-EFIAPI
-CoreStall (
- IN UINTN Microseconds
- )
-{
- UINT64 Counter;
- UINT32 Remainder;
- UINTN Index;
-
- if (gMetronome == NULL) {
- return EFI_NOT_AVAILABLE_YET;
- }
-
- //
- // Counter = Microseconds * 10 / gMetronome->TickPeriod
- // 0x1999999999999999 = (2^64 - 1) / 10
- //
- if ((UINT64)Microseconds > 0x1999999999999999ULL) {
- //
- // Microseconds is too large to multiple by 10 first. Perform the divide
- // operation first and loop 10 times to avoid 64-bit math overflow.
- //
- Counter = DivU64x32Remainder (
- Microseconds,
- gMetronome->TickPeriod,
- &Remainder
- );
- for (Index = 0; Index < 10; Index++) {
- CoreInternalWaitForTick (Counter);
- }
-
- if (Remainder != 0) {
- //
- // If Remainder was not zero, then normally, Counter would be rounded
- // up by 1 tick. In this case, since a loop for 10 counts was used
- // to emulate the multiply by 10 operation, Counter needs to be rounded
- // up by 10 counts.
- //
- CoreInternalWaitForTick (10);
- }
- } else {
- //
- // Calculate the number of ticks by dividing the number of microseconds by
- // the TickPeriod. Calculation is based on 100ns unit.
- //
- Counter = DivU64x32Remainder (
- MultU64x32 (Microseconds, 10),
- gMetronome->TickPeriod,
- &Remainder
- );
- if (Remainder != 0) {
- //
- // If Remainder is not zero, then round Counter up by one tick.
- //
- Counter++;
- }
-
- CoreInternalWaitForTick (Counter);
- }
-
- return EFI_SUCCESS;
-}
+/** @file + UEFI Miscellaneous boot Services Stall service implementation + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +// +// Include statements +// + +#include "DxeMain.h" + +/** + Internal worker function to call the Metronome Architectural Protocol for + the number of ticks specified by the UINT64 Counter value. WaitForTick() + service of the Metronome Architectural Protocol uses a UINT32 for the number + of ticks to wait, so this function loops when Counter is larger than 0xffffffff. + + @param Counter Number of ticks to wait. + +**/ +VOID +CoreInternalWaitForTick ( + IN UINT64 Counter + ) +{ + while (RShiftU64 (Counter, 32) > 0) { + gMetronome->WaitForTick (gMetronome, 0xffffffff); + Counter -= 0xffffffff; + } + + gMetronome->WaitForTick (gMetronome, (UINT32)Counter); +} + +/** + Introduces a fine-grained stall. + + @param Microseconds The number of microseconds to stall execution. + + @retval EFI_SUCCESS Execution was stalled for at least the requested + amount of microseconds. + @retval EFI_NOT_AVAILABLE_YET gMetronome is not available yet + +**/ +EFI_STATUS +EFIAPI +CoreStall ( + IN UINTN Microseconds + ) +{ + UINT64 Counter; + UINT32 Remainder; + UINTN Index; + + if (gMetronome == NULL) { + return EFI_NOT_AVAILABLE_YET; + } + + // + // Counter = Microseconds * 10 / gMetronome->TickPeriod + // 0x1999999999999999 = (2^64 - 1) / 10 + // + if ((UINT64)Microseconds > 0x1999999999999999ULL) { + // + // Microseconds is too large to multiple by 10 first. Perform the divide + // operation first and loop 10 times to avoid 64-bit math overflow. + // + Counter = DivU64x32Remainder ( + Microseconds, + gMetronome->TickPeriod, + &Remainder + ); + for (Index = 0; Index < 10; Index++) { + CoreInternalWaitForTick (Counter); + } + + if (Remainder != 0) { + // + // If Remainder was not zero, then normally, Counter would be rounded + // up by 1 tick. In this case, since a loop for 10 counts was used + // to emulate the multiply by 10 operation, Counter needs to be rounded + // up by 10 counts. + // + CoreInternalWaitForTick (10); + } + } else { + // + // Calculate the number of ticks by dividing the number of microseconds by + // the TickPeriod. Calculation is based on 100ns unit. + // + Counter = DivU64x32Remainder ( + MultU64x32 (Microseconds, 10), + gMetronome->TickPeriod, + &Remainder + ); + if (Remainder != 0) { + // + // If Remainder is not zero, then round Counter up by one tick. + // + Counter++; + } + + CoreInternalWaitForTick (Counter); + } + + return EFI_SUCCESS; +} |
