Слияние кода завершено, страница обновится автоматически
/** @file
Copyright (C) 2019, vit9696. All rights reserved.
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include <Uefi.h>
#include <Guid/MemoryAttributesTable.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/OcGuardLib.h>
#include <Library/OcMemoryLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
/**
Determine actual memory type from the attribute.
@param[in] MemoryAttribute Attribute to inspect.
**/
STATIC
UINT32
OcRealMemoryType (
IN EFI_MEMORY_DESCRIPTOR *MemoryAttribte
)
{
ASSERT (MemoryAttribte->Type == EfiRuntimeServicesCode
|| MemoryAttribte->Type == EfiRuntimeServicesData);
//
// Use code for write-protected areas.
//
if ((MemoryAttribte->Attribute & EFI_MEMORY_RO) != 0) {
return EfiRuntimeServicesCode;
}
//
// Use data for executable-protected areas.
//
if ((MemoryAttribte->Attribute & EFI_MEMORY_XP) != 0) {
return EfiRuntimeServicesData;
}
//
// Use whatever is set.
//
return MemoryAttribte->Type;
}
/**
Split memory map descriptor by attribute.
@param[in,out] RetMemoryMapEntry Pointer to descriptor in the memory map, updated to next proccessed.
@param[in,out] CurrentEntryIndex Current index of the descriptor in the memory map, updated on increase.
@param[in,out] CurrentEntryCount Number of descriptors in the memory map, updated on increase.
@param[in] TotalEntryCount Max number of descriptors in the memory map.
@param[in] MemoryAttribute Memory attribute used for splitting.
@param[in] DescriptorSize Memory map descriptor size.
@retval EFI_SUCCESS on success.
@retval EFI_OUT_OF_RESOURCES when there are not enough free descriptor slots.
**/
STATIC
EFI_STATUS
OcSplitMemoryEntryByAttribute (
IN OUT EFI_MEMORY_DESCRIPTOR **RetMemoryMapEntry,
IN OUT UINTN *CurrentEntryIndex,
IN OUT UINTN *CurrentEntryCount,
IN UINTN TotalEntryCount,
IN EFI_MEMORY_DESCRIPTOR *MemoryAttribute,
IN UINTN DescriptorSize
)
{
EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
EFI_MEMORY_DESCRIPTOR *NewMemoryMapEntry;
UINTN DiffPages;
MemoryMapEntry = *RetMemoryMapEntry;
//
// Memory attribute starts after our descriptor.
// Shorten the existing descriptor and insert the new one after it.
// [DESC1] -> [DESC1][DESC2]
//
if (MemoryAttribute->PhysicalStart > MemoryMapEntry->PhysicalStart) {
if (*CurrentEntryCount == TotalEntryCount) {
return EFI_OUT_OF_RESOURCES;
}
NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
DiffPages = (UINTN) EFI_SIZE_TO_PAGES (MemoryAttribute->PhysicalStart - MemoryMapEntry->PhysicalStart);
CopyMem (
NewMemoryMapEntry,
MemoryMapEntry,
DescriptorSize * (*CurrentEntryCount - *CurrentEntryIndex)
);
MemoryMapEntry->NumberOfPages = DiffPages;
NewMemoryMapEntry->PhysicalStart = MemoryAttribute->PhysicalStart;
NewMemoryMapEntry->NumberOfPages -= DiffPages;
MemoryMapEntry = NewMemoryMapEntry;
//
// Current processed entry is now the one we inserted.
//
++(*CurrentEntryIndex);
++(*CurrentEntryCount);
}
ASSERT (MemoryAttribute->PhysicalStart == MemoryMapEntry->PhysicalStart);
//
// Memory attribute matches our descriptor.
// Simply update its protection.
// [DESC1] -> [DESC1*]
//
if (MemoryMapEntry->NumberOfPages == MemoryAttribute->NumberOfPages) {
MemoryMapEntry->Type = OcRealMemoryType (MemoryAttribute);
*RetMemoryMapEntry = MemoryMapEntry;
return EFI_SUCCESS;
}
//
// Memory attribute is shorter than our descriptor.
// Shorten current descriptor, update its type, and inseret the new one after it.
// [DESC1] -> [DESC1*][DESC2]
//
if (*CurrentEntryCount == TotalEntryCount) {
return EFI_OUT_OF_RESOURCES;
}
NewMemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (MemoryMapEntry, DescriptorSize);
CopyMem (
NewMemoryMapEntry,
MemoryMapEntry,
DescriptorSize * (*CurrentEntryCount - *CurrentEntryIndex)
);
MemoryMapEntry->Type = OcRealMemoryType (MemoryAttribute);
MemoryMapEntry->NumberOfPages = MemoryAttribute->NumberOfPages;
NewMemoryMapEntry->PhysicalStart += EFI_PAGES_TO_SIZE (MemoryAttribute->NumberOfPages);
NewMemoryMapEntry->NumberOfPages -= MemoryAttribute->NumberOfPages;
//
// Current processed entry is now the one we need to process.
//
++(*CurrentEntryIndex);
++(*CurrentEntryCount);
*RetMemoryMapEntry = NewMemoryMapEntry;
return EFI_SUCCESS;
}
STATIC
EFI_STATUS
OcExpandAttributeWrite (
IN OUT EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable,
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryAttributesEntry OPTIONAL,
IN UINTN MaxDescriptors,
IN EFI_MEMORY_DESCRIPTOR *MemoryMapEntry,
IN EFI_PHYSICAL_ADDRESS CurrentMapAddress
)
{
EFI_PHYSICAL_ADDRESS NextMatAddress;
//
// Simply abort on failing to write any new entry.
//
if (MemoryAttributesTable->NumberOfEntries >= MaxDescriptors) {
return EFI_OUT_OF_RESOURCES;
}
if (MemoryAttributesEntry != NULL) {
//
// Insert to the middle of MAT table at current MAT entry position.
// Assert that this MAT entry follows this map entry.
//
ASSERT (MemoryAttributesEntry->PhysicalStart > CurrentMapAddress);
//
// Create a free MAT entry inbetween.
//
CopyMem (
NEXT_MEMORY_DESCRIPTOR (MemoryAttributesEntry, MemoryAttributesTable->DescriptorSize),
MemoryAttributesEntry,
MemoryAttributesTable->NumberOfEntries * MemoryAttributesTable->DescriptorSize
- ((UINTN) MemoryAttributesEntry - (UINTN) MemoryAttributesTable - sizeof (*MemoryAttributesTable))
);
//
// Calculate the location of the next MAT entry to get the size of this one.
// This MAT entry will either:
// - fill the whole gap right away, by reaching the next MAT entry.
// MA: [ GAP ][ MAT ]
// MM: [ MAP ]
// - fill part of the gap up to MAP entry end.
// MA: [ GAP ][ MAT ]
// MM: [ MAP ][ OTHER MAP ]
//
NextMatAddress = LAST_DESCRIPTOR_ADDR (MemoryMapEntry) + 1;
if (MemoryAttributesEntry->PhysicalStart < NextMatAddress) {
NextMatAddress = MemoryAttributesEntry->PhysicalStart;
}
} else {
//
// Append to the end of MAT table.
//
MemoryAttributesEntry = (VOID *) ((UINTN) MemoryAttributesTable + sizeof (*MemoryAttributesTable)
+ MemoryAttributesTable->NumberOfEntries * MemoryAttributesTable->DescriptorSize);
NextMatAddress = LAST_DESCRIPTOR_ADDR (MemoryMapEntry) + 1;
}
//
// Write the new attribute.
//
MemoryAttributesEntry->Type = OcRealMemoryType (MemoryMapEntry);
MemoryAttributesEntry->PhysicalStart = CurrentMapAddress;
MemoryAttributesEntry->VirtualStart = 0;
MemoryAttributesEntry->NumberOfPages = EFI_SIZE_TO_PAGES (NextMatAddress - CurrentMapAddress);
MemoryAttributesEntry->Attribute = EFI_MEMORY_RUNTIME;
if (MemoryAttributesEntry->Type == EfiRuntimeServicesCode) {
MemoryAttributesEntry->Attribute |= EFI_MEMORY_RO;
} else {
MemoryAttributesEntry->Attribute |= EFI_MEMORY_XP;
}
++MemoryAttributesTable->NumberOfEntries;
return EFI_SUCCESS;
}
/**
Expand attributes table by adding memory map runtime entries into it.
Requires sorted memory map.
@param[in,out] MemoryAttributesTable Memory attributes table.
@param[in,out] MemoryAttributesEntry Memory attributes descriptor.
@param[in] MaxDescriptors Maximum amount of descriptors in the attributes table.
@param[in] MemoryMapDescriptors Memory map descriptor count.
@param[in] MemoryMap Memory map.
@param[in] DescriptorSize Memory map descriptor size.
@retval EFI_SUCCESS on success.
@retval EFI_NOT_FOUND nothing to do.
**/
STATIC
EFI_STATUS
OcExpandAttributesByMap (
IN OUT EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable,
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryAttributesEntry,
IN UINTN MaxDescriptors,
IN UINTN MemoryMapDescriptors,
IN EFI_MEMORY_DESCRIPTOR *MemoryMap,
IN UINTN DescriptorSize
)
{
EFI_STATUS Status;
UINTN MapIndex;
UINTN MatIndex;
EFI_PHYSICAL_ADDRESS NextMapAddress;
EFI_PHYSICAL_ADDRESS LastMatAddress;
EFI_PHYSICAL_ADDRESS CurrentMapAddress;
MatIndex = 0;
Status = EFI_NOT_FOUND;
for (MapIndex = 0; MapIndex < MemoryMapDescriptors; ++MapIndex) {
//
// Skip MAP entries, which are not RTCode or RTData.
//
if (MemoryMap->Type != EfiRuntimeServicesCode
&& MemoryMap->Type != EfiRuntimeServicesData) {
goto NEXT_MEMORY_MAP_DESCRIPTOR;
}
NextMapAddress = LAST_DESCRIPTOR_ADDR (MemoryMap) + 1;
CurrentMapAddress = MemoryMap->PhysicalStart;
//
// Iterate MAT entries till we are over them or till
// we finish iterating this MAP entry memory.
//
while (MatIndex < MemoryAttributesTable->NumberOfEntries
&& CurrentMapAddress < NextMapAddress) {
//
// Skip MAT entries, which are not RTCode or RTData.
//
if (MemoryAttributesEntry->Type != EfiRuntimeServicesCode
&& MemoryAttributesEntry->Type != EfiRuntimeServicesData) {
goto NEXT_MEMORY_ATTRIBUTE_DESCRIPTOR;
}
//
// Skip MAT entries which end before this MAP entry. This should
// not happen normally, as each MAT entry is supposed to be within
// a single RTCode/RTData MAP entry according to UEFI spec, and
// our memory map is sorted.
//
LastMatAddress = LAST_DESCRIPTOR_ADDR (MemoryAttributesEntry);
if (LastMatAddress < MemoryMap->PhysicalStart) {
goto NEXT_MEMORY_ATTRIBUTE_DESCRIPTOR;
}
//
// Advance MAP iterator if we found a MAT entry that follows the
// current MAP entry address.
//
if (CurrentMapAddress == MemoryAttributesEntry->PhysicalStart) {
//
// MAT is required to be smaller or equal than MAP by UEFI spec.
// For now just assert on this, but if we find anybody violating this,
// we will have to adapt this code.
//
ASSERT (MemoryAttributesEntry->NumberOfPages <= MemoryMap->NumberOfPages);
CurrentMapAddress = LastMatAddress + 1;
goto NEXT_MEMORY_ATTRIBUTE_DESCRIPTOR;
}
//
// At this step we have a hole between the current MAP entry address
// and the MAT entry. Fill it in.
//
Status = OcExpandAttributeWrite (
MemoryAttributesTable,
MemoryAttributesEntry,
MaxDescriptors,
MemoryMap,
CurrentMapAddress
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Advance MAP iterator with the entry we have just added and continue
// processing the next MAT entry.
//
CurrentMapAddress = LAST_DESCRIPTOR_ADDR (MemoryAttributesEntry) + 1;
NEXT_MEMORY_ATTRIBUTE_DESCRIPTOR:
MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR (
MemoryAttributesEntry,
MemoryAttributesTable->DescriptorSize
);
++MatIndex;
}
//
// We completed to process this MAP entry, proceed to the next one.
//
if (CurrentMapAddress == NextMapAddress) {
goto NEXT_MEMORY_MAP_DESCRIPTOR;
}
//
// We have finished processing all the available MAT entries,
// but this MAP entry has more memory, which is not reflected
// in the MAT table. Add this memory and continue processing
// the next MAP entry.
//
ASSERT (CurrentMapAddress < NextMapAddress);
ASSERT (MatIndex == MemoryAttributesTable->NumberOfEntries);
Status = OcExpandAttributeWrite (
MemoryAttributesTable,
NULL,
MaxDescriptors,
MemoryMap,
CurrentMapAddress
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Increment MatIndex to ensure that we no longer enter the MAT entry
// loop on the next iteration. Do not care updating CurrentMapAddress
// as we will overwrite it immediate on the next MAP entry iteration.
// Do not care updating MemoryAttribute as we will no longer use it.
//
++MatIndex;
NEXT_MEMORY_MAP_DESCRIPTOR:
MemoryMap = NEXT_MEMORY_DESCRIPTOR (
MemoryMap,
DescriptorSize
);
}
return Status;
}
EFI_MEMORY_ATTRIBUTES_TABLE *
OcGetMemoryAttributes (
OUT EFI_MEMORY_DESCRIPTOR **MemoryAttributesEntry OPTIONAL
)
{
EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
UINTN Index;
for (Index = 0; Index < gST->NumberOfTableEntries; ++Index) {
if (CompareGuid (&gST->ConfigurationTable[Index].VendorGuid, &gEfiMemoryAttributesTableGuid)) {
MemoryAttributesTable = gST->ConfigurationTable[Index].VendorTable;
if (MemoryAttributesEntry != NULL) {
*MemoryAttributesEntry = (EFI_MEMORY_DESCRIPTOR *) (MemoryAttributesTable + 1);
}
return MemoryAttributesTable;
}
}
return NULL;
}
EFI_STATUS
OcRebuildAttributes (
IN EFI_PHYSICAL_ADDRESS Address,
IN EFI_GET_MEMORY_MAP GetMemoryMap OPTIONAL
)
{
EFI_STATUS Status;
EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
EFI_MEMORY_DESCRIPTOR *MemoryAttributesEntry;
UINTN MaxDescriptors;
UINTN MemoryMapSize;
EFI_MEMORY_DESCRIPTOR *MemoryMap;
UINTN DescriptorSize;
UINTN MapKey;
UINT32 DescriptorVersion;
MemoryAttributesTable = OcGetMemoryAttributes (&MemoryAttributesEntry);
if (MemoryAttributesTable == NULL || MemoryAttributesTable->NumberOfEntries == 0) {
return EFI_UNSUPPORTED;
}
//
// MAT is normally sorted, and so far nobody had issues
// caused by unsorted MAT, but we do not want to risk.
//
OcSortMemoryMap (
MemoryAttributesTable->NumberOfEntries * MemoryAttributesTable->DescriptorSize,
MemoryAttributesEntry,
MemoryAttributesTable->DescriptorSize
);
//
// Some boards create entry duplicates and lose all non-PE entries
// after loading runtime drivers after EndOfDxe.
// REF: https://github.com/acidanthera/bugtracker/issues/491#issuecomment-609014334
//
MaxDescriptors = MemoryAttributesTable->NumberOfEntries;
Status = OcDeduplicateDescriptors (
&MemoryAttributesTable->NumberOfEntries,
MemoryAttributesEntry,
MemoryAttributesTable->DescriptorSize
);
if (!EFI_ERROR (Status)) {
//
// Statically allocate memory for the memory map to avoid allocations.
//
STATIC UINT8 mMemoryMap[OC_DEFAULT_MEMORY_MAP_SIZE];
//
// Assume effected and add missing entries.
//
if (GetMemoryMap == NULL) {
GetMemoryMap = gBS->GetMemoryMap;
}
MemoryMapSize = sizeof (mMemoryMap);
MemoryMap = (EFI_MEMORY_DESCRIPTOR *) mMemoryMap;
Status = GetMemoryMap (
&MemoryMapSize,
MemoryMap,
&MapKey,
&DescriptorSize,
&DescriptorVersion
);
if (!EFI_ERROR (Status)) {
OcSortMemoryMap (
MemoryMapSize,
MemoryMap,
DescriptorSize
);
OcExpandAttributesByMap (
MemoryAttributesTable,
MemoryAttributesEntry,
MaxDescriptors,
MemoryMapSize / DescriptorSize,
MemoryMap,
DescriptorSize
);
} else {
//
// TODO: Scream in fear here? We cannot log, but for a fatal error it is "fine".
//
}
}
//
// Some types of firmware do not update MAT after loading runtime drivers after EndOfDxe.
// Since the memory used to allocate runtime driver resides in BINs, MAT has whatever
// permissions designated for unused memory. Mark unused memory containing our driver
// as executable here.
// REF: https://github.com/acidanthera/bugtracker/issues/491#issuecomment-606835337
//
if (Address != 0) {
Status = OcUpdateDescriptors (
MemoryAttributesTable->NumberOfEntries * MemoryAttributesTable->DescriptorSize,
MemoryAttributesEntry,
MemoryAttributesTable->DescriptorSize,
Address,
EfiRuntimeServicesCode,
EFI_MEMORY_RO,
EFI_MEMORY_XP
);
}
return Status;
}
UINTN
OcCountSplitDescriptors (
VOID
)
{
UINTN Index;
UINTN DescriptorCount;
CONST EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
EFI_MEMORY_DESCRIPTOR *MemoryAttributesEntry;
MemoryAttributesTable = OcGetMemoryAttributes (&MemoryAttributesEntry);
if (MemoryAttributesTable == NULL) {
return 0;
}
DescriptorCount = 0;
for (Index = 0; Index < MemoryAttributesTable->NumberOfEntries; ++Index) {
if (MemoryAttributesEntry->Type == EfiRuntimeServicesCode
|| MemoryAttributesEntry->Type == EfiRuntimeServicesData) {
++DescriptorCount;
}
MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR (
MemoryAttributesEntry,
MemoryAttributesTable->DescriptorSize
);
}
return DescriptorCount;
}
EFI_STATUS
OcSplitMemoryMapByAttributes (
IN UINTN MaxMemoryMapSize,
IN OUT UINTN *MemoryMapSize,
IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap,
IN UINTN DescriptorSize
)
{
EFI_STATUS Status;
CONST EFI_MEMORY_ATTRIBUTES_TABLE *MemoryAttributesTable;
EFI_MEMORY_DESCRIPTOR *MemoryAttributesEntry;
EFI_MEMORY_DESCRIPTOR *MemoryMapEntry;
EFI_MEMORY_DESCRIPTOR *LastAttributeEntry;
UINTN LastAttributeIndex;
UINTN Index;
UINTN Index2;
UINTN CurrentEntryCount;
UINTN TotalEntryCount;
UINTN AttributeCount;
BOOLEAN CanSplit;
BOOLEAN InDescAttrs;
ASSERT (MaxMemoryMapSize >= *MemoryMapSize);
MemoryAttributesTable = OcGetMemoryAttributes (&MemoryAttributesEntry);
if (MemoryAttributesTable == NULL) {
return EFI_UNSUPPORTED;
}
LastAttributeEntry = MemoryAttributesEntry;
LastAttributeIndex = 0;
MemoryMapEntry = MemoryMap;
CurrentEntryCount = *MemoryMapSize / DescriptorSize;
TotalEntryCount = MaxMemoryMapSize / DescriptorSize;
AttributeCount = MemoryAttributesTable->NumberOfEntries;
//
// We assume that the memory map and attribute table are sorted.
//
Index = 0;
while (Index < CurrentEntryCount) {
//
// Split entry by as many attributes as possible.
//
CanSplit = TRUE;
while ((MemoryMapEntry->Type == EfiRuntimeServicesCode
|| MemoryMapEntry->Type == EfiRuntimeServicesData) && CanSplit) {
//
// Find corresponding memory attribute.
//
InDescAttrs = FALSE;
MemoryAttributesEntry = LastAttributeEntry;
for (Index2 = LastAttributeIndex; Index2 < AttributeCount; ++Index2) {
if (MemoryAttributesEntry->Type == EfiRuntimeServicesCode
|| MemoryAttributesEntry->Type == EfiRuntimeServicesData) {
//
// UEFI spec says attribute entries are fully within memory map entries.
// Find first one of a different type.
//
if (AREA_WITHIN_DESCRIPTOR (
MemoryMapEntry,
MemoryAttributesEntry->PhysicalStart,
EFI_PAGES_TO_SIZE (MemoryAttributesEntry->NumberOfPages))) {
//
// We are within descriptor attribute sequence.
//
InDescAttrs = TRUE;
//
// No need to process the attribute of the same type.
//
if (OcRealMemoryType (MemoryAttributesEntry) != MemoryMapEntry->Type) {
//
// Start with the next attribute on the second iteration.
//
LastAttributeEntry = NEXT_MEMORY_DESCRIPTOR (
MemoryAttributesEntry,
MemoryAttributesTable->DescriptorSize
);
LastAttributeIndex = Index2 + 1;
break;
}
} else if (InDescAttrs) {
//
// Reached the end of descriptor attribute sequence, abort.
//
InDescAttrs = FALSE;
break;
}
}
MemoryAttributesEntry = NEXT_MEMORY_DESCRIPTOR (
MemoryAttributesEntry,
MemoryAttributesTable->DescriptorSize
);
}
if (Index2 < AttributeCount && InDescAttrs) {
//
// Split current memory map entry.
//
Status = OcSplitMemoryEntryByAttribute (
&MemoryMapEntry,
&Index,
&CurrentEntryCount,
TotalEntryCount,
MemoryAttributesEntry,
DescriptorSize
);
if (EFI_ERROR (Status)) {
*MemoryMapSize = CurrentEntryCount * DescriptorSize;
return Status;
}
continue;
} else {
//
// Did not find a suitable attribute or processed all the attributes.
//
CanSplit = FALSE;
}
}
MemoryMapEntry = NEXT_MEMORY_DESCRIPTOR (
MemoryMapEntry,
DescriptorSize
);
++Index;
}
*MemoryMapSize = CurrentEntryCount * DescriptorSize;
return EFI_SUCCESS;
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )