From 0c037b5fa7d14bc40294b4fa4edd42b4a5111f64 Mon Sep 17 00:00:00 2001 From: Jiaxin Wu Date: Mon, 24 Jun 2024 23:53:34 +0800 Subject: [PATCH] UefiCpuPkg/PiSmmCpuDxeSmm: Create extended protection MemRegion in func MM can not use the gDS service, so move the extended protection MemRegion creation into function. This can make InitProtectedMemRange() to be a common function for both SMM and MM. Signed-off-by: Jiaxin Wu Cc: Ray Ni Cc: Rahul Kumar Cc: Gerd Hoffmann Cc: Star Zeng Cc: Dun Tan Cc: Hongbin1 Zhang Cc: Wei6 Xu Cc: Yuanhao Xie --- UefiCpuPkg/PiSmmCpuDxeSmm/NonMmramMapDxeSmm.c | 78 ++++++++ UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuCommon.h | 30 +++ UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c | 182 ++++++++---------- 3 files changed, 191 insertions(+), 99 deletions(-) diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/NonMmramMapDxeSmm.c b/UefiCpuPkg/PiSmmCpuDxeSmm/NonMmramMapDxeSmm.c index 4f6f040bc8..be5b333cd1 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/NonMmramMapDxeSmm.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/NonMmramMapDxeSmm.c @@ -523,3 +523,81 @@ IsSmmCommBufferForbiddenAddress ( return FALSE; } + +/** + Create extended protection MemoryRegion. + Return all MMIO ranges that are reported in GCD service at EndOfDxe. + + The caller is responsible for freeing MemoryRegion via FreePool(). + + @param[out] MemoryRegion Returned Non-Mmram Memory regions. + @param[out] MemoryRegionCount A pointer to the number of Memory regions. +**/ +VOID +CreateExtendedProtectionRange ( + OUT MM_CPU_MEMORY_REGION **MemoryRegion, + OUT UINTN *MemoryRegionCount + ) +{ + UINTN Index; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap; + UINTN NumberOfSpaceDescriptors; + UINTN MemoryRegionIndex; + UINTN Count; + + MemorySpaceMap = NULL; + NumberOfSpaceDescriptors = 0; + Count = 0; + + ASSERT (MemoryRegion != NULL && MemoryRegionCount != NULL); + + *MemoryRegion = NULL; + *MemoryRegionCount = 0; + + // + // Get MMIO ranges from GCD. + // + gDS->GetMemorySpaceMap ( + &NumberOfSpaceDescriptors, + &MemorySpaceMap + ); + for (Index = 0; Index < NumberOfSpaceDescriptors; Index++) { + if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) { + if (ADDRESS_IS_ALIGNED (MemorySpaceMap[Index].BaseAddress, SIZE_4KB) && + (MemorySpaceMap[Index].Length % SIZE_4KB == 0)) + { + Count++; + } else { + // + // Skip the MMIO range that BaseAddress and Length are not 4k aligned since + // the minimum granularity of the page table is 4k + // + DEBUG (( + DEBUG_WARN, + "MMIO range [0x%lx, 0x%lx] is skipped since it is not 4k aligned.\n", + MemorySpaceMap[Index].BaseAddress, + MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length + )); + } + } + } + + *MemoryRegionCount = Count; + + *MemoryRegion = (MM_CPU_MEMORY_REGION *)AllocateZeroPool (sizeof (MM_CPU_MEMORY_REGION) * Count); + ASSERT (*MemoryRegion != NULL); + + MemoryRegionIndex = 0; + for (Index = 0; Index < NumberOfSpaceDescriptors; Index++) { + if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) && + ADDRESS_IS_ALIGNED (MemorySpaceMap[Index].BaseAddress, SIZE_4KB) && + (MemorySpaceMap[Index].Length % SIZE_4KB == 0)) + { + (*MemoryRegion)[MemoryRegionIndex].Base = MemorySpaceMap[Index].BaseAddress; + (*MemoryRegion)[MemoryRegionIndex].Length = MemorySpaceMap[Index].Length; + MemoryRegionIndex++; + } + } + + return; +} diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuCommon.h b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuCommon.h index a5b40f864e..ed0badf431 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuCommon.h +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuCommon.h @@ -479,6 +479,21 @@ extern UINT64 mAddressEncMask; extern UINT64 mTimeoutTicker; extern UINT64 mTimeoutTicker2; +typedef struct { + /// + /// Address of the first byte in the memory region. + /// + EFI_PHYSICAL_ADDRESS Base; + /// + /// Length in bytes of the memory region. + /// + UINT64 Length; + /// + /// Attributes of the memory region + /// + UINT64 Attribute; +} MM_CPU_MEMORY_REGION; + /** Create 4G PageTable in SMRAM. @@ -940,6 +955,21 @@ IsSmmCommBufferForbiddenAddress ( IN UINT64 Address ); +/* + Build extended protection MemoryRegion. + + The caller is responsible for freeing MemoryRegion via FreePool(). + + @param[out] MemoryRegion Returned Non-Mmram Memory regions. + @param[out] MemoryRegionCount A pointer to the number of Memory regions. + +*/ +VOID +CreateExtendedProtectionRange ( + OUT MM_CPU_MEMORY_REGION **MemoryRegion, + OUT UINTN *MemoryRegionCount + ); + /** This function caches the UEFI memory map information. **/ diff --git a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c index e775b7d7ef..a6f7697c63 100644 --- a/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c +++ b/UefiCpuPkg/PiSmmCpuDxeSmm/SmmProfile.c @@ -404,116 +404,100 @@ InitProtectedMemRange ( VOID ) { - UINTN Index; - UINTN NumberOfDescriptors; - UINTN NumberOfAddedDescriptors; - UINTN NumberOfProtectRange; - UINTN NumberOfSpliteRange; - EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap; - UINTN TotalSize; - EFI_PHYSICAL_ADDRESS ProtectBaseAddress; - EFI_PHYSICAL_ADDRESS ProtectEndAddress; - EFI_PHYSICAL_ADDRESS Top2MBAlignedAddress; - EFI_PHYSICAL_ADDRESS Base2MBAlignedAddress; - UINT64 High4KBPageSize; - UINT64 Low4KBPageSize; - MEMORY_PROTECTION_RANGE MemProtectionRange; + UINTN Index; + MM_CPU_MEMORY_REGION *MemoryRegion; + UINTN MemoryRegionCount; + UINTN NumberOfAddedDescriptors; + UINTN NumberOfProtectRange; + UINTN NumberOfSpliteRange; + UINTN TotalSize; + EFI_PHYSICAL_ADDRESS ProtectBaseAddress; + EFI_PHYSICAL_ADDRESS ProtectEndAddress; + EFI_PHYSICAL_ADDRESS Top2MBAlignedAddress; + EFI_PHYSICAL_ADDRESS Base2MBAlignedAddress; + UINT64 High4KBPageSize; + UINT64 Low4KBPageSize; + MEMORY_PROTECTION_RANGE MemProtectionRange; - NumberOfDescriptors = 0; + MemoryRegion = NULL; + MemoryRegionCount = 0; NumberOfAddedDescriptors = mSmmCpuSmramRangeCount; NumberOfSpliteRange = 0; - MemorySpaceMap = NULL; // - // Get MMIO ranges from GCD and add them into protected memory ranges. + // Create extended protection MemoryRegion and add them into protected memory ranges. + // Retrieve the accessible regions when SMM profile is enabled. + // In SMM: only MMIO is accessible. // - gDS->GetMemorySpaceMap ( - &NumberOfDescriptors, - &MemorySpaceMap - ); - for (Index = 0; Index < NumberOfDescriptors; Index++) { - if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo)) { - if (ADDRESS_IS_ALIGNED (MemorySpaceMap[Index].BaseAddress, SIZE_4KB) && - (MemorySpaceMap[Index].Length % SIZE_4KB == 0)) - { - NumberOfAddedDescriptors++; - } else { - // - // Skip the MMIO range that BaseAddress and Length are not 4k aligned since - // the minimum granularity of the page table is 4k - // - DEBUG (( - DEBUG_WARN, - "MMIO range [0x%lx, 0x%lx] is skipped since it is not 4k aligned.\n", - MemorySpaceMap[Index].BaseAddress, - MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - )); - } + CreateExtendedProtectionRange (&MemoryRegion, &MemoryRegionCount); + ASSERT (MemoryRegion != NULL); + + NumberOfAddedDescriptors += MemoryRegionCount; + + ASSERT (NumberOfAddedDescriptors != 0); + + TotalSize = NumberOfAddedDescriptors * sizeof (MEMORY_PROTECTION_RANGE) + sizeof (mProtectionMemRangeTemplate); + mProtectionMemRange = (MEMORY_PROTECTION_RANGE *)AllocateZeroPool (TotalSize); + ASSERT (mProtectionMemRange != NULL); + mProtectionMemRangeCount = TotalSize / sizeof (MEMORY_PROTECTION_RANGE); + + // + // Copy existing ranges. + // + CopyMem (mProtectionMemRange, mProtectionMemRangeTemplate, sizeof (mProtectionMemRangeTemplate)); + + // + // Create split ranges which come from protected ranges. + // + TotalSize = (TotalSize / sizeof (MEMORY_PROTECTION_RANGE)) * sizeof (MEMORY_RANGE); + mSplitMemRange = (MEMORY_RANGE *)AllocateZeroPool (TotalSize); + ASSERT (mSplitMemRange != NULL); + + // + // Create SMM ranges which are set to present and execution-enable. + // + NumberOfProtectRange = sizeof (mProtectionMemRangeTemplate) / sizeof (MEMORY_PROTECTION_RANGE); + for (Index = 0; Index < mSmmCpuSmramRangeCount; Index++) { + if ((mSmmCpuSmramRanges[Index].CpuStart >= mProtectionMemRange[0].Range.Base) && + (mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize < mProtectionMemRange[0].Range.Top)) + { + // + // If the address have been already covered by mCpuHotPlugData.SmrrBase/mCpuHotPlugData.SmrrSiz + // + break; } + + mProtectionMemRange[NumberOfProtectRange].Range.Base = mSmmCpuSmramRanges[Index].CpuStart; + mProtectionMemRange[NumberOfProtectRange].Range.Top = mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize; + mProtectionMemRange[NumberOfProtectRange].Present = TRUE; + mProtectionMemRange[NumberOfProtectRange].Nx = FALSE; + NumberOfProtectRange++; } - if (NumberOfAddedDescriptors != 0) { - TotalSize = NumberOfAddedDescriptors * sizeof (MEMORY_PROTECTION_RANGE) + sizeof (mProtectionMemRangeTemplate); - mProtectionMemRange = (MEMORY_PROTECTION_RANGE *)AllocateZeroPool (TotalSize); - ASSERT (mProtectionMemRange != NULL); - mProtectionMemRangeCount = TotalSize / sizeof (MEMORY_PROTECTION_RANGE); - - // - // Copy existing ranges. - // - CopyMem (mProtectionMemRange, mProtectionMemRangeTemplate, sizeof (mProtectionMemRangeTemplate)); - - // - // Create split ranges which come from protected ranges. - // - TotalSize = (TotalSize / sizeof (MEMORY_PROTECTION_RANGE)) * sizeof (MEMORY_RANGE); - mSplitMemRange = (MEMORY_RANGE *)AllocateZeroPool (TotalSize); - ASSERT (mSplitMemRange != NULL); - - // - // Create SMM ranges which are set to present and execution-enable. - // - NumberOfProtectRange = sizeof (mProtectionMemRangeTemplate) / sizeof (MEMORY_PROTECTION_RANGE); - for (Index = 0; Index < mSmmCpuSmramRangeCount; Index++) { - if ((mSmmCpuSmramRanges[Index].CpuStart >= mProtectionMemRange[0].Range.Base) && - (mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize < mProtectionMemRange[0].Range.Top)) - { - // - // If the address have been already covered by mCpuHotPlugData.SmrrBase/mCpuHotPlugData.SmrrSiz - // - break; - } - - mProtectionMemRange[NumberOfProtectRange].Range.Base = mSmmCpuSmramRanges[Index].CpuStart; - mProtectionMemRange[NumberOfProtectRange].Range.Top = mSmmCpuSmramRanges[Index].CpuStart + mSmmCpuSmramRanges[Index].PhysicalSize; - mProtectionMemRange[NumberOfProtectRange].Present = TRUE; - mProtectionMemRange[NumberOfProtectRange].Nx = FALSE; - NumberOfProtectRange++; - } - - // - // Create MMIO ranges which are set to present and execution-disable. - // - for (Index = 0; Index < NumberOfDescriptors; Index++) { - if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) && - ADDRESS_IS_ALIGNED (MemorySpaceMap[Index].BaseAddress, SIZE_4KB) && - (MemorySpaceMap[Index].Length % SIZE_4KB == 0)) - { - mProtectionMemRange[NumberOfProtectRange].Range.Base = MemorySpaceMap[Index].BaseAddress; - mProtectionMemRange[NumberOfProtectRange].Range.Top = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length; - mProtectionMemRange[NumberOfProtectRange].Present = TRUE; - mProtectionMemRange[NumberOfProtectRange].Nx = TRUE; - NumberOfProtectRange++; - } - } - - // - // Check and updated actual protected memory ranges count - // - ASSERT (NumberOfProtectRange <= mProtectionMemRangeCount); - mProtectionMemRangeCount = NumberOfProtectRange; + // + // Create MMIO ranges which are set to present and execution-disable. + // + for (Index = 0; Index < MemoryRegionCount; Index++) { + mProtectionMemRange[NumberOfProtectRange].Range.Base = MemoryRegion[Index].Base; + mProtectionMemRange[NumberOfProtectRange].Range.Top = MemoryRegion[Index].Base + MemoryRegion[Index].Length; + mProtectionMemRange[NumberOfProtectRange].Present = TRUE; + mProtectionMemRange[NumberOfProtectRange].Nx = TRUE; + NumberOfProtectRange++; } + // + // Free the MemoryRegion + // + if (MemoryRegion != NULL) { + FreePool (MemoryRegion); + } + + // + // Check and updated actual protected memory ranges count + // + ASSERT (NumberOfProtectRange <= mProtectionMemRangeCount); + mProtectionMemRangeCount = NumberOfProtectRange; + // // According to protected ranges, create the ranges which will be mapped by 2KB page. //