/** 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 ; }
/** Split the original memory map, and add more entries to describe PE code section and data section. This function will set EfiRuntimeServicesData to be EFI_MEMORY_XP. This function will merge entries with same attributes finally. NOTE: It assumes PE code/data section are page aligned. NOTE: It assumes enough entry is prepared for new memory map. Split table: +---------------+ | Record X | +---------------+ | Record RtCode | +---------------+ | Record Y | +---------------+ ==> +---------------+ | Record X | +---------------+ ---- | Record RtData | | +---------------+ | | Record RtCode | |-> PE/COFF1 +---------------+ | | Record RtData | | +---------------+ ---- | Record RtData | | +---------------+ | | Record RtCode | |-> PE/COFF2 +---------------+ | | Record RtData | | +---------------+ ---- | Record Y | +---------------+ @param MemoryMapSize A pointer to the size, in bytes, of the MemoryMap buffer. On input, this is the size of old MemoryMap before split. The actual buffer size of MemoryMap is MemoryMapSize + (AdditionalRecordCount * DescriptorSize) calculated below. On output, it is the size of new MemoryMap after split. @param MemoryMap A pointer to the buffer in which firmware places the current memory map. @param DescriptorSize Size, in bytes, of an individual EFI_MEMORY_DESCRIPTOR. **/ STATIC VOID SplitTable ( IN OUT UINTN *MemoryMapSize, IN OUT EFI_MEMORY_DESCRIPTOR *MemoryMap, IN UINTN DescriptorSize ) { INTN IndexOld; INTN IndexNew; UINTN MaxSplitRecordCount; UINTN RealSplitRecordCount; UINTN TotalSplitRecordCount; UINTN AdditionalRecordCount; AdditionalRecordCount = (2 * mImagePropertiesPrivateData.CodeSegmentCountMax + 1) * mImagePropertiesPrivateData.ImageRecordCount; TotalSplitRecordCount = 0; // // Let old record point to end of valid MemoryMap buffer. // IndexOld = ((*MemoryMapSize) / DescriptorSize) - 1; // // Let new record point to end of full MemoryMap buffer. // IndexNew = ((*MemoryMapSize) / DescriptorSize) - 1 + AdditionalRecordCount; for (; IndexOld >= 0; IndexOld--) { MaxSplitRecordCount = GetMaxSplitRecordCount ((EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize)); // // Split this MemoryMap record // IndexNew -= MaxSplitRecordCount; RealSplitRecordCount = SplitRecord ( (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexOld * DescriptorSize), (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)MemoryMap + IndexNew * DescriptorSize), MaxSplitRecordCount, DescriptorSize ); // // Adjust IndexNew according to real split. // CopyMem ( ((UINT8 *)MemoryMap + (IndexNew + MaxSplitRecordCount - RealSplitRecordCount) * DescriptorSize), ((UINT8 *)MemoryMap + IndexNew * DescriptorSize), RealSplitRecordCount * DescriptorSize ); IndexNew = IndexNew + MaxSplitRecordCount - RealSplitRecordCount; TotalSplitRecordCount += RealSplitRecordCount; IndexNew --; } // // Move all records to the beginning. // CopyMem ( MemoryMap, (UINT8 *)MemoryMap + (AdditionalRecordCount - TotalSplitRecordCount) * DescriptorSize, (*MemoryMapSize) + TotalSplitRecordCount * DescriptorSize ); *MemoryMapSize = (*MemoryMapSize) + DescriptorSize * TotalSplitRecordCount; // // Sort from low to high (Just in case) // SortMemoryMap (MemoryMap, *MemoryMapSize, DescriptorSize); // // Set RuntimeData to XP // EnforceMemoryMapAttribute (MemoryMap, *MemoryMapSize, DescriptorSize); // // Merge same type to save entry size // MergeMemoryMap (MemoryMap, MemoryMapSize, DescriptorSize); return ; }