/** 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 ; }
/** 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. **/ STATIC 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 { MemoryBlockLength = (UINT64) (EfiPagesToSize (MemoryMapEntry->NumberOfPages)); if (((UINTN)NextMemoryMapEntry < (UINTN)MemoryMapEnd) && (MemoryMapEntry->Type == NextMemoryMapEntry->Type) && (MemoryMapEntry->Attribute == NextMemoryMapEntry->Attribute) && ((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 ; }
/** 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 ; }
VOID EFIAPI PrintMemMap( IN UINTN MemoryMapSize, IN EFI_MEMORY_DESCRIPTOR *MemoryMap, IN UINTN DescriptorSize, IN UINT32 DescriptorVersion ) { UINTN NumEntries; UINTN Index; UINT64 Bytes; EFI_MEMORY_DESCRIPTOR *Desc; Desc = MemoryMap; NumEntries = MemoryMapSize / DescriptorSize; PRINT("MEMMAP: Size=%d, Addr=%p, DescSize=%d, DescVersion: 0x%x\n", MemoryMapSize, MemoryMap, DescriptorSize, DescriptorVersion); PRINT("Type Start End VStart # Pages Attributes\n"); for (Index = 0; Index < NumEntries; Index++) { Bytes = (((UINTN) Desc->NumberOfPages) * EFI_PAGE_SIZE); PRINT("%-12s %lX-%lX %lX %lX %lX\n", EfiMemoryTypeDesc[Desc->Type], Desc->PhysicalStart, Desc->PhysicalStart + Bytes - 1, Desc->VirtualStart, Desc->NumberOfPages, Desc->Attribute ); Desc = NEXT_MEMORY_DESCRIPTOR(Desc, DescriptorSize); //if ((Index + 1) % 16 == 0) { // WaitForKeyPress(L"press a key to continue\n"); //} } //WaitForKeyPress(L"End: press a key to continue\n"); }
/** 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; }
VOID EFIAPI FixMemMap( IN UINTN MemoryMapSize, IN EFI_MEMORY_DESCRIPTOR *MemoryMap, IN UINTN DescriptorSize, IN UINT32 DescriptorVersion ) { UINTN NumEntries; UINTN Index; EFI_MEMORY_DESCRIPTOR *Desc; UINTN BlockSize; UINTN PhysicalEnd; DBG("FixMemMap: Size=%d, Addr=%p, DescSize=%d\n", MemoryMapSize, MemoryMap, DescriptorSize); DBGnvr("FixMemMap ...\n"); Desc = MemoryMap; NumEntries = MemoryMapSize / DescriptorSize; for (Index = 0; Index < NumEntries; Index++) { BlockSize = EFI_PAGES_TO_SIZE((UINTN)Desc->NumberOfPages); PhysicalEnd = Desc->PhysicalStart + BlockSize; // // Some UEFIs end up with "reserved" area with EFI_MEMORY_RUNTIME flag set // when Intel HD3000 or HD4000 is used. We will remove that flag here. // if ((Desc->Attribute & EFI_MEMORY_RUNTIME) != 0 && Desc->Type == EfiReservedMemoryType) { DBGnvr(" %s as RT: %lx (0x%x) - Att: %lx", EfiMemoryTypeDesc[Desc->Type], Desc->PhysicalStart, Desc->NumberOfPages, Desc->Attribute); Desc->Attribute = Desc->Attribute & (~EFI_MEMORY_RUNTIME); DBGnvr(" -> %lx\n", Desc->Attribute); /* This one is not working - blocks during DefragmentRuntimeServices() DBGnvr(" %s as RT: %lx (0x%x) - %s", EfiMemoryTypeDesc[Desc->Type], Desc->PhysicalStart, Desc->NumberOfPages, EfiMemoryTypeDesc[Desc->Type]); Desc->Type = EfiMemoryMappedIO; DBGnvr(" -> %s\n", EfiMemoryTypeDesc[Desc->Type]); */ /* Another possible solution - mark the range as MMIO. DBGnvr(" %s as RT: %lx (0x%x) - %s", EfiMemoryTypeDesc[Desc->Type], Desc->PhysicalStart, Desc->NumberOfPages, EfiMemoryTypeDesc[Desc->Type]); Desc->Type = EfiRuntimeServicesData; DBGnvr(" -> %s\n", EfiMemoryTypeDesc[Desc->Type]); */ } // // Fix by Slice - fixes sleep/wake on GB boards. // // if ((Desc->PhysicalStart >= 0x9e000) && (Desc->PhysicalStart < 0xa0000)) { if ((Desc->PhysicalStart < 0xa0000) && (PhysicalEnd >= 0x9e000)) { Desc->Type = EfiACPIMemoryNVS; Desc->Attribute = 0; } // // Also do some checking // if ((Desc->Attribute & EFI_MEMORY_RUNTIME) != 0) { // // block with RT flag. // if it is not RT or MMIO, then report to log // if (Desc->Type != EfiRuntimeServicesCode && Desc->Type != EfiRuntimeServicesData && Desc->Type != EfiMemoryMappedIO && Desc->Type != EfiMemoryMappedIOPortSpace ) { DBGnvr(" %s with RT flag: %lx (0x%x) - ???\n", EfiMemoryTypeDesc[Desc->Type], Desc->PhysicalStart, Desc->NumberOfPages); } } else { // // block without RT flag. // if it is RT or MMIO, then report to log // if (Desc->Type == EfiRuntimeServicesCode || Desc->Type == EfiRuntimeServicesData || Desc->Type == EfiMemoryMappedIO || Desc->Type == EfiMemoryMappedIOPortSpace ) { DBGnvr(" %s without RT flag: %lx (0x%x) - ???\n", EfiMemoryTypeDesc[Desc->Type], Desc->PhysicalStart, Desc->NumberOfPages); } } Desc = NEXT_MEMORY_DESCRIPTOR(Desc, DescriptorSize); } }
/*prints the memory status*/ void st_memmgr_print_stat(){ uint16_t i; MEMORY_DESCRIPTOR *mem_desc; uint16_t free_space=0; uint16_t allocated_space=0; uint8_t allocation_overhead=0; uint16_t largest_free_block=0; uint16_t cont_free_space=0; /*BANK_0*/ i=0; mem_desc=(MEMORY_DESCRIPTOR*)st_memory.BANK_0; printf("\n\n======================BANK 0==========================\n"); while(i<BANK_0_SIZE){ i+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); printMemoryDescriptorInfo((*mem_desc)); if(IS_ALLOCATED((*mem_desc))){ allocated_space+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); allocation_overhead+=sizeof(MEMORY_DESCRIPTOR); cont_free_space=0; } else{ free_space+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); cont_free_space+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); if(largest_free_block < cont_free_space) largest_free_block=cont_free_space; } mem_desc=NEXT_MEMORY_DESCRIPTOR(mem_desc); } /*BANK_1*/ i=0; mem_desc=(MEMORY_DESCRIPTOR*)st_memory.BANK_1; printf("\n\n======================BANK 1==========================\n"); while(i<BANK_1_SIZE){ i+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); printMemoryDescriptorInfo((*mem_desc)); if(IS_ALLOCATED((*mem_desc))){ allocated_space+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); allocation_overhead+=sizeof(MEMORY_DESCRIPTOR); cont_free_space=0; } else{ free_space+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); cont_free_space+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); if(largest_free_block < cont_free_space) largest_free_block=cont_free_space; } mem_desc=NEXT_MEMORY_DESCRIPTOR(mem_desc); } printf("\n================================================================================================="); printf("\nTotal Allocated Space : %d bytes",allocated_space); printf("\nTotal Free Space : %d bytes",free_space); printf("\nCurrent Allocation Overhead : %d bytes",allocation_overhead); printf("\nActual Allocation : %d bytes approx. (Internal Fragmentation taken into account)",allocated_space-allocation_overhead); printf("\nPeak Memory Utilization : %d bytes",peak_memory_utilization); printf("\nLargest Serviceable memory : %d bytes",largest_free_block); printf("\nlast requested size : %d bytes",lastRequestSize); printf("\nlast request status : %s\n",lastRequestStatus?"SUCCESS":"FAILED"); printf("=================================================================================================\n"); }
/* * Make a e820 memory map */ void e820_map_from_efi_map (struct e820_entry *e820_map, int *e820_nr_map, grub_efi_memory_descriptor_t *memory_map, grub_efi_uintn_t desc_size, grub_efi_uintn_t memory_map_size) { grub_efi_memory_descriptor_t *desc; unsigned long long start = 0; unsigned long long end = 0; unsigned long long size = 0; grub_efi_memory_descriptor_t *memory_map_end; memory_map_end = NEXT_MEMORY_DESCRIPTOR (memory_map, memory_map_size); *e820_nr_map = 0; for (desc = memory_map; desc < memory_map_end; desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) { switch (desc->type) { case GRUB_EFI_ACPI_RECLAIM_MEMORY: add_memory_region (e820_map, e820_nr_map, desc->physical_start, desc->num_pages << 12, E820_ACPI); break; case GRUB_EFI_RUNTIME_SERVICES_CODE: case GRUB_EFI_RUNTIME_SERVICES_DATA: case GRUB_EFI_RESERVED_MEMORY_TYPE: case GRUB_EFI_MEMORY_MAPPED_IO: case GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE: case GRUB_EFI_UNUSABLE_MEMORY: case GRUB_EFI_PAL_CODE: add_memory_region (e820_map, e820_nr_map, desc->physical_start, desc->num_pages << 12, E820_RESERVED); break; case GRUB_EFI_LOADER_CODE: case GRUB_EFI_LOADER_DATA: case GRUB_EFI_BOOT_SERVICES_CODE: case GRUB_EFI_BOOT_SERVICES_DATA: case GRUB_EFI_CONVENTIONAL_MEMORY: start = desc->physical_start; size = desc->num_pages << 12; end = start + size; if (start < 0x100000ULL && end > 0xA0000ULL) { if (start < 0xA0000ULL) add_memory_region (e820_map, e820_nr_map, start, 0xA0000ULL-start, E820_RAM); if (end <= 0x100000ULL) continue; start = 0x100000ULL; size = end - start; } add_memory_region (e820_map, e820_nr_map, start, size, E820_RAM); break; case GRUB_EFI_ACPI_MEMORY_NVS: add_memory_region (e820_map, e820_nr_map, desc->physical_start, desc->num_pages << 12, E820_NVS); break; } } }
/** Dump out the EFI memory map Argv[0] - "memmap" @param Argc Number of command arguments in Argv @param Argv Array of strings that represent the parsed command line. Argv[0] is the command name @return EFI_SUCCESS **/ EFI_STATUS EblMemMapCmd ( IN UINTN Argc, IN CHAR8 **Argv ) { EFI_STATUS Status; EFI_MEMORY_DESCRIPTOR *MemMap; EFI_MEMORY_DESCRIPTOR *OrigMemMap; UINTN MemMapSize; UINTN MapKey; UINTN DescriptorSize; UINT32 DescriptorVersion; UINT64 PageCount[EfiMaxMemoryType]; UINTN Index; UINT64 EntrySize; UINTN CurrentRow; UINT64 TotalMemory; ZeroMem (PageCount, sizeof (PageCount)); AsciiPrint ("EFI Memory Map\n"); // First call is to figure out how big the buffer needs to be MemMapSize = 0; MemMap = NULL; Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion); if (Status == EFI_BUFFER_TOO_SMALL) { // In case the AllocatPool changes the memory map we added in some extra descriptors MemMapSize += (DescriptorSize * 0x100); OrigMemMap = MemMap = AllocatePool (MemMapSize); if (OrigMemMap != NULL) { // 2nd time we get the data Status = gBS->GetMemoryMap (&MemMapSize, MemMap, &MapKey, &DescriptorSize, &DescriptorVersion); if (!EFI_ERROR (Status)) { for (Index = 0, CurrentRow = 0; Index < MemMapSize/DescriptorSize; Index++) { EntrySize = LShiftU64 (MemMap->NumberOfPages, 12); AsciiPrint ("\n%a %016lx - %016lx: # %08lx %016lx", gMemMapType[MemMap->Type % EfiMaxMemoryType], MemMap->PhysicalStart, MemMap->PhysicalStart + EntrySize -1, MemMap->NumberOfPages, MemMap->Attribute); if (EblAnyKeyToContinueQtoQuit (&CurrentRow, TRUE)) { break; } PageCount[MemMap->Type % EfiMaxMemoryType] += MemMap->NumberOfPages; MemMap = NEXT_MEMORY_DESCRIPTOR (MemMap, DescriptorSize); } } for (Index = 0, TotalMemory = 0; Index < EfiMaxMemoryType; Index++) { if (PageCount[Index] != 0) { AsciiPrint ("\n %a %,7ld Pages (%,14ld)", gMemMapType[Index], PageCount[Index], LShiftU64 (PageCount[Index], 12)); if (Index == EfiLoaderCode || Index == EfiLoaderData || Index == EfiBootServicesCode || Index == EfiBootServicesData || Index == EfiRuntimeServicesCode || Index == EfiRuntimeServicesData || Index == EfiConventionalMemory || Index == EfiACPIReclaimMemory || Index == EfiACPIMemoryNVS || Index == EfiPalCode ) { // Count total memory TotalMemory += PageCount[Index]; } } } AsciiPrint ("\nTotal Memory: %,ld MB (%,ld bytes)\n", RShiftU64 (TotalMemory, 8), LShiftU64 (TotalMemory, 12)); FreePool (OrigMemMap); } } return EFI_SUCCESS; }
/** Split the memory map to new entries, according to one old entry, based upon PE code section and data section. @param OldRecord A pointer to one old memory map entry. @param NewRecord A pointer to several new memory map entries. The caller gurantee the buffer size be 1 + (SplitRecordCount * DescriptorSize) calculated below. @param MaxSplitRecordCount The max number of splitted entries @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR. @retval 0 no entry is splitted. @return the real number of splitted record. **/ STATIC UINTN SplitRecord ( IN EFI_MEMORY_DESCRIPTOR *OldRecord, IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord, IN UINTN MaxSplitRecordCount, IN UINTN DescriptorSize ) { EFI_MEMORY_DESCRIPTOR TempRecord; IMAGE_PROPERTIES_RECORD *ImageRecord; IMAGE_PROPERTIES_RECORD *NewImageRecord; UINT64 PhysicalStart; UINT64 PhysicalEnd; UINTN NewRecordCount; UINTN TotalNewRecordCount; BOOLEAN IsLastRecordData; if (MaxSplitRecordCount == 0) { CopyMem (NewRecord, OldRecord, DescriptorSize); return 0; } TotalNewRecordCount = 0; // // Override previous record // CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR)); PhysicalStart = TempRecord.PhysicalStart; PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages); ImageRecord = NULL; do { NewImageRecord = GetImageRecordByAddress (PhysicalStart, PhysicalEnd - PhysicalStart); if (NewImageRecord == NULL) { // // No more image covered by this range, stop // if ((PhysicalEnd > PhysicalStart) && (ImageRecord != NULL)) { // // If this is still address in this record, need record. // NewRecord = PREVIOUS_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize); IsLastRecordData = FALSE; if (!mPropertiesTableEnable) { if ((NewRecord->Attribute & EFI_MEMORY_XP) != 0) { IsLastRecordData = TRUE; } } else { if (NewRecord->Type == EfiRuntimeServicesData) { IsLastRecordData = TRUE; } } if (IsLastRecordData) { // // Last record is DATA, just merge it. // NewRecord->NumberOfPages = EfiSizeToPages(PhysicalEnd - NewRecord->PhysicalStart); } else { // // Last record is CODE, create a new DATA entry. // NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize); if (!mPropertiesTableEnable) { NewRecord->Type = TempRecord.Type; } else { NewRecord->Type = EfiRuntimeServicesData; } NewRecord->PhysicalStart = TempRecord.PhysicalStart; NewRecord->VirtualStart = 0; NewRecord->NumberOfPages = TempRecord.NumberOfPages; NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP; TotalNewRecordCount ++; } } break; } ImageRecord = NewImageRecord; // // Set new record // NewRecordCount = SetNewRecord (ImageRecord, NewRecord, &TempRecord, DescriptorSize); TotalNewRecordCount += NewRecordCount; NewRecord = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)NewRecord + NewRecordCount * DescriptorSize); // // Update PhysicalStart, in order to exclude the image buffer already splitted. // PhysicalStart = ImageRecord->ImageBase + ImageRecord->ImageSize; TempRecord.PhysicalStart = PhysicalStart; TempRecord.NumberOfPages = EfiSizeToPages (PhysicalEnd - PhysicalStart); } while ((ImageRecord != NULL) && (PhysicalStart < PhysicalEnd)); return TotalNewRecordCount - 1; }
/** Set the memory map to new entries, according to one old entry, based upon PE code section and data section in image record @param ImageRecord An image record whose [ImageBase, ImageSize] covered by old memory map entry. @param NewRecord A pointer to several new memory map entries. The caller gurantee the buffer size be 1 + (SplitRecordCount * DescriptorSize) calculated below. @param OldRecord A pointer to one old memory map entry. @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR. **/ STATIC UINTN SetNewRecord ( IN IMAGE_PROPERTIES_RECORD *ImageRecord, IN OUT EFI_MEMORY_DESCRIPTOR *NewRecord, IN EFI_MEMORY_DESCRIPTOR *OldRecord, IN UINTN DescriptorSize ) { EFI_MEMORY_DESCRIPTOR TempRecord; IMAGE_PROPERTIES_RECORD_CODE_SECTION *ImageRecordCodeSection; LIST_ENTRY *ImageRecordCodeSectionLink; LIST_ENTRY *ImageRecordCodeSectionEndLink; LIST_ENTRY *ImageRecordCodeSectionList; UINTN NewRecordCount; UINT64 PhysicalEnd; UINT64 ImageEnd; CopyMem (&TempRecord, OldRecord, sizeof(EFI_MEMORY_DESCRIPTOR)); PhysicalEnd = TempRecord.PhysicalStart + EfiPagesToSize(TempRecord.NumberOfPages); NewRecordCount = 0; ImageRecordCodeSectionList = &ImageRecord->CodeSegmentList; 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; if (TempRecord.PhysicalStart <= ImageRecordCodeSection->CodeSegmentBase) { // // DATA // if (!mPropertiesTableEnable) { NewRecord->Type = TempRecord.Type; } else { NewRecord->Type = EfiRuntimeServicesData; } NewRecord->PhysicalStart = TempRecord.PhysicalStart; NewRecord->VirtualStart = 0; NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentBase - NewRecord->PhysicalStart); NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP; if (NewRecord->NumberOfPages != 0) { NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize); NewRecordCount ++; } // // CODE // if (!mPropertiesTableEnable) { NewRecord->Type = TempRecord.Type; } else { NewRecord->Type = EfiRuntimeServicesCode; } NewRecord->PhysicalStart = ImageRecordCodeSection->CodeSegmentBase; NewRecord->VirtualStart = 0; NewRecord->NumberOfPages = EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize); NewRecord->Attribute = (TempRecord.Attribute & (~EFI_MEMORY_XP)) | EFI_MEMORY_RO; if (NewRecord->NumberOfPages != 0) { NewRecord = NEXT_MEMORY_DESCRIPTOR (NewRecord, DescriptorSize); NewRecordCount ++; } TempRecord.PhysicalStart = ImageRecordCodeSection->CodeSegmentBase + EfiPagesToSize (EfiSizeToPages(ImageRecordCodeSection->CodeSegmentSize)); TempRecord.NumberOfPages = EfiSizeToPages(PhysicalEnd - TempRecord.PhysicalStart); if (TempRecord.NumberOfPages == 0) { break; } } } ImageEnd = ImageRecord->ImageBase + ImageRecord->ImageSize; // // Final DATA // if (TempRecord.PhysicalStart < ImageEnd) { if (!mPropertiesTableEnable) { NewRecord->Type = TempRecord.Type; } else { NewRecord->Type = EfiRuntimeServicesData; } NewRecord->PhysicalStart = TempRecord.PhysicalStart; NewRecord->VirtualStart = 0; NewRecord->NumberOfPages = EfiSizeToPages (ImageEnd - TempRecord.PhysicalStart); NewRecord->Attribute = TempRecord.Attribute | EFI_MEMORY_XP; NewRecordCount ++; } return NewRecordCount; }
/** Determines the new virtual address that is to be used on subsequent memory accesses. @param DebugDisposition Supplies type information for the pointer being converted. @param ConvertAddress A pointer to a pointer that is to be fixed to be the value needed for the new virtual address mappings being applied. @retval EFI_SUCCESS The pointer pointed to by Address was modified. @retval EFI_NOT_FOUND The pointer pointed to by Address was not found to be part of the current memory map. This is normally fatal. @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. **/ EFI_STATUS EFIAPI RuntimeDriverConvertPointer ( IN UINTN DebugDisposition, IN OUT VOID **ConvertAddress ) { UINTN Address; UINT64 VirtEndOfRange; EFI_MEMORY_DESCRIPTOR *VirtEntry; UINTN Index; // // Make sure ConvertAddress is a valid pointer // if (ConvertAddress == NULL) { return EFI_INVALID_PARAMETER; } // // Get the address to convert // Address = (UINTN) *ConvertAddress; // // If this is a null pointer, return if it's allowed // if (Address == 0) { if ((DebugDisposition & EFI_OPTIONAL_PTR) != 0) { return EFI_SUCCESS; } return EFI_INVALID_PARAMETER; } VirtEntry = mVirtualMap; for (Index = 0; Index < mVirtualMapMaxIndex; Index++) { // // To prevent the inclusion of 64-bit math functions a UINTN was placed in // front of VirtEntry->NumberOfPages to cast it to a 32-bit thing on IA-32 // platforms. If you get this ASSERT remove the UINTN and do a 64-bit // multiply. // ASSERT (((UINTN) VirtEntry->NumberOfPages < 0xffffffff) || (sizeof (UINTN) > 4)); if ((VirtEntry->Attribute & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) { if (Address >= VirtEntry->PhysicalStart) { VirtEndOfRange = VirtEntry->PhysicalStart + (((UINTN) VirtEntry->NumberOfPages) * EFI_PAGE_SIZE); if (Address < VirtEndOfRange) { // // Compute new address // *ConvertAddress = (VOID *) (Address - (UINTN) VirtEntry->PhysicalStart + (UINTN) VirtEntry->VirtualStart); return EFI_SUCCESS; } } } VirtEntry = NEXT_MEMORY_DESCRIPTOR (VirtEntry, mVirtualMapDescriptorSize); } return EFI_NOT_FOUND; }
/*attempts to allocate the requested number bytes, as a contigous chunk of memory, returns the pointer to the first byte on success * or returns NULL on failure*/ void* st_memmgr_alloc(uint16_t size){ MEMORY_DESCRIPTOR *mem_desc; uint8_t bank_visit_counter=0; uint16_t i; uint16_t cont_free_block_size; void* return_addr=NULL; size+=sizeof(MEMORY_DESCRIPTOR); //account for the memory descriptor if(size > BANK_1_SIZE) //if size is greater than the size of BANK_1 then allocation will fail goto RETURN_ALLOCATE; if(size<=MEM_REQUEST_SMALL) goto MEMORY_BANK_0; else goto MEMORY_BANK_1; MEMORY_BANK_0:; bank_visit_counter++; if(bank_visit_counter==MAX_ATTEMPTS) //all banks visited goto RETURN_ALLOCATE; i=0; cont_free_block_size=0; mem_desc=(MEMORY_DESCRIPTOR*)st_memory.BANK_0; //start of BANK_0 while(i<BANK_0_SIZE){ //search till the end of BANK_0 boundary if(IS_ALLOCATED((*mem_desc))){ //this bank is allocated i+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); mem_desc=NEXT_MEMORY_DESCRIPTOR(mem_desc); cont_free_block_size=0; continue; }else{ cont_free_block_size+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); if(cont_free_block_size >= size) break; //found a free block large enough to satisfy memory request i+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); mem_desc=NEXT_MEMORY_DESCRIPTOR(mem_desc); } } if(i>=BANK_0_SIZE) //failed to satisfy request in MEMORY_BANK_0 goto MEMORY_BANK_1; /*free block found, allocate whatever is required and make the rest space as a free block*/ if(calculateBlockOffset(size) < calculateBlockOffset(cont_free_block_size)){ mem_desc=(MEMORY_DESCRIPTOR*)(((uint8_t*)NEXT_MEMORY_DESCRIPTOR(mem_desc))-cont_free_block_size); SET_ALLOCATED((*mem_desc)); SET_BLOCK_OFFSET((*mem_desc),calculateBlockOffset(size)); return_addr=((void*)mem_desc)+sizeof(MEMORY_DESCRIPTOR); //actual data to be stored here /*make a new free block*/ mem_desc=NEXT_MEMORY_DESCRIPTOR(mem_desc); CLEAR_ALLOCATED((*mem_desc)); SET_BLOCK_OFFSET((*mem_desc), (calculateBlockOffset(cont_free_block_size)-calculateBlockOffset(size))); }else{ mem_desc=(MEMORY_DESCRIPTOR*)(((uint8_t*)NEXT_MEMORY_DESCRIPTOR(mem_desc))-cont_free_block_size); SET_ALLOCATED((*mem_desc)); SET_BLOCK_OFFSET((*mem_desc),calculateBlockOffset(size)); return_addr=((void*)mem_desc)+sizeof(MEMORY_DESCRIPTOR); //actual data to be stored here } goto RETURN_ALLOCATE; MEMORY_BANK_1:; bank_visit_counter++; if(bank_visit_counter==MAX_ATTEMPTS) //all banks visited goto RETURN_ALLOCATE; i=0; cont_free_block_size=0; mem_desc=(MEMORY_DESCRIPTOR*)st_memory.BANK_1; //start of BANK_1 while(i<BANK_1_SIZE){ //search till the end of BANK_0 boundary if(IS_ALLOCATED((*mem_desc))){ //this bank is allocated i+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); mem_desc=NEXT_MEMORY_DESCRIPTOR(mem_desc); cont_free_block_size=0; continue; }else{ cont_free_block_size+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); if(cont_free_block_size >= size) break; //found a free block large enough to satisfy memory request i+=(GET_BLOCK_OFFSET((*mem_desc))*BLOCK_SIZE); mem_desc=NEXT_MEMORY_DESCRIPTOR(mem_desc); } } if(i>=BANK_1_SIZE) //failed to satisfy request in MEMORY_BANK_1 goto MEMORY_BANK_0; /*free block found, allocate whatever is required and make the rest space as a free block*/ if(calculateBlockOffset(size) < calculateBlockOffset(cont_free_block_size)){ mem_desc=(MEMORY_DESCRIPTOR*)(((uint8_t*)NEXT_MEMORY_DESCRIPTOR(mem_desc))-cont_free_block_size); SET_ALLOCATED((*mem_desc)); SET_BLOCK_OFFSET((*mem_desc),calculateBlockOffset(size)); return_addr=((void*)mem_desc)+sizeof(MEMORY_DESCRIPTOR); //actual data to be stored here /*make a new free block*/ mem_desc=NEXT_MEMORY_DESCRIPTOR(mem_desc); CLEAR_ALLOCATED((*mem_desc)); SET_BLOCK_OFFSET((*mem_desc), (calculateBlockOffset(cont_free_block_size)-calculateBlockOffset(size))); }else{ mem_desc=(MEMORY_DESCRIPTOR*)(((uint8_t*)NEXT_MEMORY_DESCRIPTOR(mem_desc))-cont_free_block_size); SET_ALLOCATED((*mem_desc)); SET_BLOCK_OFFSET((*mem_desc),calculateBlockOffset(size)); return_addr=((void*)mem_desc)+sizeof(MEMORY_DESCRIPTOR); //actual data to be stored here } goto RETURN_ALLOCATE; RETURN_ALLOCATE:; lastRequestSize=size; if(return_addr!=NULL){ actual_memory_utilization+=size; lastRequestStatus=1; if(actual_memory_utilization>peak_memory_utilization) peak_memory_utilization=actual_memory_utilization; }else lastRequestStatus=0; return return_addr; }
VOID EFIAPI ShrinkMemMap( IN UINTN *MemoryMapSize, IN EFI_MEMORY_DESCRIPTOR *MemoryMap, IN UINTN DescriptorSize, IN UINT32 DescriptorVersion ) { UINTN SizeFromDescToEnd; UINT64 Bytes; EFI_MEMORY_DESCRIPTOR *PrevDesc; EFI_MEMORY_DESCRIPTOR *Desc; BOOLEAN CanBeJoined; BOOLEAN HasEntriesToRemove; PrevDesc = MemoryMap; Desc = NEXT_MEMORY_DESCRIPTOR(PrevDesc, DescriptorSize); SizeFromDescToEnd = *MemoryMapSize - DescriptorSize; *MemoryMapSize = DescriptorSize; HasEntriesToRemove = FALSE; while (SizeFromDescToEnd > 0) { Bytes = (((UINTN) PrevDesc->NumberOfPages) * EFI_PAGE_SIZE); CanBeJoined = FALSE; if ((Desc->Attribute == PrevDesc->Attribute) && (PrevDesc->PhysicalStart + Bytes == Desc->PhysicalStart)) { if (Desc->Type == EfiBootServicesCode || Desc->Type == EfiBootServicesData //|| Desc->Type == EfiConventionalMemory //|| Desc->Type == EfiLoaderCode //|| Desc->Type == EfiLoaderData ) { CanBeJoined = PrevDesc->Type == EfiBootServicesCode || PrevDesc->Type == EfiBootServicesData //|| PrevDesc->Type == EfiConventionalMemory //|| PrevDesc->Type == EfiLoaderCode //|| PrevDesc->Type == EfiLoaderData ; } } if (CanBeJoined) { // two entries are the same/similar - join them PrevDesc->NumberOfPages += Desc->NumberOfPages; HasEntriesToRemove = TRUE; } else { // can not be joined - we need to move to next *MemoryMapSize += DescriptorSize; PrevDesc = NEXT_MEMORY_DESCRIPTOR(PrevDesc, DescriptorSize); if (HasEntriesToRemove) { // have entries between PrevDesc and Desc which are joined to PrevDesc // we need to copy [Desc, end of list] to PrevDesc + 1 CopyMem(PrevDesc, Desc, SizeFromDescToEnd); Desc = PrevDesc; } HasEntriesToRemove = FALSE; } // move to next Desc = NEXT_MEMORY_DESCRIPTOR(Desc, DescriptorSize); SizeFromDescToEnd -= DescriptorSize; } }
grub_err_t grub_machine_mmap_iterate (grub_memory_hook_t hook) { grub_efi_uintn_t mmap_size = 0; grub_efi_memory_descriptor_t *map_buf = 0; grub_efi_uintn_t map_key = 0; grub_efi_uintn_t desc_size = 0; grub_efi_uint32_t desc_version = 0; grub_efi_memory_descriptor_t *desc; if (grub_efi_get_memory_map (&mmap_size, map_buf, &map_key, &desc_size, &desc_version) < 0) return grub_errno; map_buf = grub_malloc (mmap_size); if (! map_buf) return grub_errno; if (grub_efi_get_memory_map (&mmap_size, map_buf, &map_key, &desc_size, &desc_version) <= 0) { grub_free (map_buf); return grub_errno; } for (desc = map_buf; desc < NEXT_MEMORY_DESCRIPTOR (map_buf, mmap_size); desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) { grub_dprintf ("mmap", "EFI memory region 0x%llx-0x%llx: %d\n", (unsigned long long) desc->physical_start, (unsigned long long) desc->physical_start + desc->num_pages * 4096, desc->type); switch (desc->type) { case GRUB_EFI_RUNTIME_SERVICES_CODE: hook (desc->physical_start, desc->num_pages * 4096, GRUB_MEMORY_CODE); break; case GRUB_EFI_UNUSABLE_MEMORY: hook (desc->physical_start, desc->num_pages * 4096, GRUB_MEMORY_BADRAM); break; default: grub_printf ("Unknown memory type %d, considering reserved\n", desc->type); case GRUB_EFI_RESERVED_MEMORY_TYPE: case GRUB_EFI_RUNTIME_SERVICES_DATA: case GRUB_EFI_MEMORY_MAPPED_IO: case GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE: case GRUB_EFI_PAL_CODE: hook (desc->physical_start, desc->num_pages * 4096, GRUB_MEMORY_RESERVED); break; case GRUB_EFI_LOADER_CODE: case GRUB_EFI_LOADER_DATA: case GRUB_EFI_BOOT_SERVICES_CODE: case GRUB_EFI_BOOT_SERVICES_DATA: case GRUB_EFI_CONVENTIONAL_MEMORY: hook (desc->physical_start, desc->num_pages * 4096, GRUB_MEMORY_AVAILABLE); break; case GRUB_EFI_ACPI_RECLAIM_MEMORY: hook (desc->physical_start, desc->num_pages * 4096, GRUB_MEMORY_ACPI); break; case GRUB_EFI_ACPI_MEMORY_NVS: hook (desc->physical_start, desc->num_pages * 4096, GRUB_MEMORY_NVS); break; } } return GRUB_ERR_NONE; }
/** Alloctes Pages from the top of mem, up to address specified in Memory. Returns allocated address in Memory. */ EFI_STATUS EFIAPI AllocatePagesFromTop( IN EFI_MEMORY_TYPE MemoryType, IN UINTN Pages, IN OUT EFI_PHYSICAL_ADDRESS *Memory ) { EFI_STATUS Status; UINTN MemoryMapSize; EFI_MEMORY_DESCRIPTOR *MemoryMap; UINTN MapKey; UINTN DescriptorSize; UINT32 DescriptorVersion; EFI_MEMORY_DESCRIPTOR *MemoryMapEnd; EFI_MEMORY_DESCRIPTOR *Desc; Status = GetMemoryMapAlloc(gBS->GetMemoryMap, &MemoryMapSize, &MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion); if (EFI_ERROR(Status)) { return Status; } Status = EFI_NOT_FOUND; //PRINT("Search for Pages=%x, TopAddr=%lx\n", Pages, *Memory); //PRINT("MEMMAP: Size=%d, Addr=%p, DescSize=%d, DescVersion: 0x%x\n", MemoryMapSize, MemoryMap, DescriptorSize, DescriptorVersion); //PRINT("Type Start End VStart # Pages Attributes\n"); MemoryMapEnd = NEXT_MEMORY_DESCRIPTOR(MemoryMap, MemoryMapSize); Desc = PREV_MEMORY_DESCRIPTOR(MemoryMapEnd, DescriptorSize); for ( ; Desc >= MemoryMap; Desc = PREV_MEMORY_DESCRIPTOR(Desc, DescriptorSize)) { /* PRINT("%-12s %lX-%lX %lX %lX %lX\n", EfiMemoryTypeDesc[Desc->Type], Desc->PhysicalStart, Desc->PhysicalStart + EFI_PAGES_TO_SIZE(Desc->NumberOfPages) - 1, Desc->VirtualStart, Desc->NumberOfPages, Desc->Attribute ); */ if ( (Desc->Type == EfiConventionalMemory) // free mem && (Pages <= Desc->NumberOfPages) // contains enough space && (Desc->PhysicalStart + EFI_PAGES_TO_SIZE(Pages) <= *Memory) // contains space below specified Memory ) { // free block found if (Desc->PhysicalStart + EFI_PAGES_TO_SIZE((UINTN)Desc->NumberOfPages) <= *Memory) { // the whole block is unded Memory - allocate from the top of the block *Memory = Desc->PhysicalStart + EFI_PAGES_TO_SIZE((UINTN)Desc->NumberOfPages - Pages); //PRINT("found the whole block under top mem, allocating at %lx\n", *Memory); } else { // the block contains enough pages under Memory, but spans above it - allocate below Memory. *Memory = *Memory - EFI_PAGES_TO_SIZE(Pages); //PRINT("found the whole block under top mem, allocating at %lx\n", *Memory); } Status = gBS->AllocatePages(AllocateAddress, MemoryType, Pages, Memory); //PRINT("Alloc Pages=%x, Addr=%lx, Status=%r\n", Pages, *Memory, Status); break; } } // release mem FreePool(MemoryMap); return Status; }
/** return the UEFI memory information. @param[out] Below4GMemoryLimit The below 4GiB memory limit @param[out] Above4GMemoryLimit The above 4GiB memory limit **/ VOID ReturnUefiMemoryMap ( OUT UINT64 *Below4GMemoryLimit, OUT UINT64 *Above4GMemoryLimit ) { EFI_STATUS Status; EFI_MEMORY_DESCRIPTOR *EfiMemoryMap; EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd; EFI_MEMORY_DESCRIPTOR *EfiEntry; EFI_MEMORY_DESCRIPTOR *NextEfiEntry; EFI_MEMORY_DESCRIPTOR TempEfiEntry; UINTN EfiMemoryMapSize; UINTN EfiMapKey; UINTN EfiDescriptorSize; UINT32 EfiDescriptorVersion; UINT64 MemoryBlockLength; *Below4GMemoryLimit = 0; *Above4GMemoryLimit = 0; // // Get the EFI memory map. // EfiMemoryMapSize = 0; EfiMemoryMap = NULL; Status = gBS->GetMemoryMap ( &EfiMemoryMapSize, EfiMemoryMap, &EfiMapKey, &EfiDescriptorSize, &EfiDescriptorVersion ); ASSERT (Status == EFI_BUFFER_TOO_SMALL); do { // // Use size returned back plus 1 descriptor for the AllocatePool. // We don't just multiply by 2 since the "for" loop below terminates on // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize // we process bogus entries and create bogus E820 entries. // EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize); ASSERT (EfiMemoryMap != NULL); Status = gBS->GetMemoryMap ( &EfiMemoryMapSize, EfiMemoryMap, &EfiMapKey, &EfiDescriptorSize, &EfiDescriptorVersion ); if (EFI_ERROR (Status)) { FreePool (EfiMemoryMap); } } while (Status == EFI_BUFFER_TOO_SMALL); ASSERT_EFI_ERROR (Status); // // Sort memory map from low to high // EfiEntry = EfiMemoryMap; NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize); while (EfiEntry < EfiMemoryMapEnd) { while (NextEfiEntry < EfiMemoryMapEnd) { if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) { CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR)); } NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize); } EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); } // // // DEBUG ((DEBUG_INFO, "MemoryMap:\n")); EfiEntry = EfiMemoryMap; EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize); while (EfiEntry < EfiMemoryMapEnd) { MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12)); DEBUG ((DEBUG_INFO, "Entry(0x%02x) 0x%016lx - 0x%016lx\n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->PhysicalStart + MemoryBlockLength)); switch (EfiEntry->Type) { case EfiLoaderCode: case EfiLoaderData: case EfiBootServicesCode: case EfiBootServicesData: case EfiConventionalMemory: case EfiRuntimeServicesCode: case EfiRuntimeServicesData: case EfiACPIReclaimMemory: case EfiACPIMemoryNVS: case EfiReservedMemoryType: if ((EfiEntry->PhysicalStart + MemoryBlockLength) <= BASE_1MB) { // // Skip the memory block is under 1MB // } else if (EfiEntry->PhysicalStart >= BASE_4GB) { if (*Above4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) { *Above4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength; } } else { if (*Below4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) { *Below4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength; } } break; } EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize); } FreePool (EfiMemoryMap); DEBUG ((DEBUG_INFO, "Result:\n")); DEBUG ((DEBUG_INFO, "Below4GMemoryLimit: 0x%016lx\n", *Below4GMemoryLimit)); DEBUG ((DEBUG_INFO, "Above4GMemoryLimit: 0x%016lx\n", *Above4GMemoryLimit)); return ; }