/** Find untested but initialized memory regions in GCD map and convert them to be DXE allocatable. **/ VOID PromoteMemoryResource ( VOID ) { LIST_ENTRY *Link; EFI_GCD_MAP_ENTRY *Entry; DEBUG ((DEBUG_PAGE, "Promote the memory resource\n")); 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)) { // // Update the GCD map // Entry->GcdMemoryType = EfiGcdMemoryTypeSystemMemory; Entry->Capabilities |= EFI_MEMORY_TESTED; Entry->ImageHandle = gDxeCoreImageHandle; Entry->DeviceHandle = NULL; // // Add to allocable system memory resource // CoreAddRange ( EfiConventionalMemory, Entry->BaseAddress, Entry->EndAddress, Entry->Capabilities & ~(EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED | EFI_MEMORY_RUNTIME) ); CoreFreeMemoryMapStack (); } Link = Link->ForwardLink; } CoreReleaseGcdMemoryLock (); 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", __FUNCTION__, 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", __FUNCTION__ )); 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", __FUNCTION__ )); 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 & 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 (); } }
/** This function returns a copy of the current memory map. The map is an array of memory descriptors, each of which describes a contiguous block of memory. @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 CoreGetMemoryMap ( IN OUT UINTN *MemoryMapSize, IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, OUT UINTN *MapKey, OUT UINTN *DescriptorSize, OUT UINT32 *DescriptorVersion ) { EFI_STATUS Status; UINTN Size; UINTN BufferSize; UINTN NumberOfRuntimeEntries; LIST_ENTRY *Link; MEMORY_MAP *Entry; EFI_GCD_MAP_ENTRY *GcdMapEntry; EFI_MEMORY_TYPE Type; // // Make sure the parameters are valid // if (MemoryMapSize == NULL) { return EFI_INVALID_PARAMETER; } CoreAcquireGcdMemoryLock (); // // Count the number of Reserved and MMIO entries that are marked for runtime use // NumberOfRuntimeEntries = 0; for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) { GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) || (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) { if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) { NumberOfRuntimeEntries++; } } } Size = sizeof (EFI_MEMORY_DESCRIPTOR); // // Make sure Size != sizeof(EFI_MEMORY_DESCRIPTOR). This will // prevent people from having pointer math bugs in their code. // now you have to use *DescriptorSize to make things work. // Size += sizeof(UINT64) - (Size % sizeof (UINT64)); if (DescriptorSize != NULL) { *DescriptorSize = Size; } if (DescriptorVersion != NULL) { *DescriptorVersion = EFI_MEMORY_DESCRIPTOR_VERSION; } CoreAcquireMemoryLock (); // // Compute the buffer size needed to fit the entire map // BufferSize = Size * NumberOfRuntimeEntries; for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) { BufferSize += Size; } if (*MemoryMapSize < BufferSize) { Status = EFI_BUFFER_TOO_SMALL; goto Done; } if (MemoryMap == NULL) { Status = EFI_INVALID_PARAMETER; goto Done; } // // Build the map // ZeroMem (MemoryMap, BufferSize); for (Link = gMemoryMap.ForwardLink; Link != &gMemoryMap; Link = Link->ForwardLink) { Entry = CR (Link, MEMORY_MAP, Link, MEMORY_MAP_SIGNATURE); ASSERT (Entry->VirtualStart == 0); // // Convert internal map into an EFI_MEMORY_DESCRIPTOR // MemoryMap->Type = Entry->Type; MemoryMap->PhysicalStart = Entry->Start; MemoryMap->VirtualStart = Entry->VirtualStart; MemoryMap->NumberOfPages = RShiftU64 (Entry->End - Entry->Start + 1, EFI_PAGE_SHIFT); // // If the memory type is EfiConventionalMemory, then determine if the range is part of a // memory type bin and needs to be converted to the same memory type as the rest of the // memory type bin in order to minimize EFI Memory Map changes across reboots. This // improves the chances for a successful S4 resume in the presence of minor page allocation // differences across reboots. // if (MemoryMap->Type == EfiConventionalMemory) { for (Type = (EFI_MEMORY_TYPE) 0; Type < EfiMaxMemoryType; Type++) { if (mMemoryTypeStatistics[Type].Special && mMemoryTypeStatistics[Type].NumberOfPages > 0 && Entry->Start >= mMemoryTypeStatistics[Type].BaseAddress && Entry->End <= mMemoryTypeStatistics[Type].MaximumAddress) { MemoryMap->Type = Type; } } } MemoryMap->Attribute = Entry->Attribute; if (mMemoryTypeStatistics[MemoryMap->Type].Runtime) { MemoryMap->Attribute |= EFI_MEMORY_RUNTIME; } MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size); } for (Link = mGcdMemorySpaceMap.ForwardLink; Link != &mGcdMemorySpaceMap; Link = Link->ForwardLink) { GcdMapEntry = CR (Link, EFI_GCD_MAP_ENTRY, Link, EFI_GCD_MAP_SIGNATURE); if ((GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) || (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) { if ((GcdMapEntry->Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) { // // Create EFI_MEMORY_DESCRIPTOR for every Reserved and MMIO GCD entries // that are marked for runtime use // MemoryMap->PhysicalStart = GcdMapEntry->BaseAddress; MemoryMap->VirtualStart = 0; MemoryMap->NumberOfPages = RShiftU64 ((GcdMapEntry->EndAddress - GcdMapEntry->BaseAddress + 1), EFI_PAGE_SHIFT); MemoryMap->Attribute = GcdMapEntry->Attributes & ~EFI_MEMORY_PORT_IO; if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeReserved) { MemoryMap->Type = EfiReservedMemoryType; } else if (GcdMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) { if ((GcdMapEntry->Attributes & EFI_MEMORY_PORT_IO) == EFI_MEMORY_PORT_IO) { MemoryMap->Type = EfiMemoryMappedIOPortSpace; } else { MemoryMap->Type = EfiMemoryMappedIO; } } MemoryMap = NEXT_MEMORY_DESCRIPTOR (MemoryMap, Size); } } } Status = EFI_SUCCESS; Done: CoreReleaseMemoryLock (); CoreReleaseGcdMemoryLock (); // // Update the map key finally // if (MapKey != NULL) { *MapKey = mMemoryMapKey; } *MemoryMapSize = BufferSize; return Status; }