有时候我们需要得知当前系统中SMRAM的分配情况,这时候需可以使用 EFI_SMM_ACCESS2_PROTOCOL。关于这个 PROTOCOL,可以在PI Spec Vol4 找到。这个 PROTOCOL 接口如下:
其中我们需要关注的是 GetCapabilities。
首先通过 SmramMapSize,获得下面的 EFI_SMRAM_DESCRIPTOR的数量,之后一个个进行枚举即可。
代码中用到的一些结构体定义可以在下面这个文件中找到:
\EdkCompatibilityPkg\Foundation\Framework\Guid\SmramMemoryReserve\SmramMemoryReserve.h
例如:
// // ******************************************************* // EFI_SMRAM_DESCRIPTOR // ******************************************************* // typedef struct { EFI_PHYSICAL_ADDRESS PhysicalStart; // Phsyical location in DRAM EFI_PHYSICAL_ADDRESS CpuStart; // Address CPU uses to access the SMI handler // May or may not match PhysicalStart // UINT64 PhysicalSize; UINT64 RegionState; } EFI_SMRAM_DESCRIPTOR; // // ******************************************************* // EFI_SMRAM_STATE // ******************************************************* // #define EFI_SMRAM_OPEN 0x00000001 #define EFI_SMRAM_CLOSED 0x00000002 #define EFI_SMRAM_LOCKED 0x00000004 #define EFI_CACHEABLE 0x00000008 #define EFI_ALLOCATED 0x00000010 #define EFI_NEEDS_TESTING 0x00000020 #define EFI_NEEDS_ECC_INITIALIZATION 0x00000040 源代码如下: /** @file Dump Capsule image information. Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> 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 <PiDxe.h> #include <Library/BaseLib.h> #include <Library/BaseMemoryLib.h> #include <Library/MemoryAllocationLib.h> #include <Library/UefiBootServicesTableLib.h> #include <Library/UefiLib.h> #include <Protocol/Shell.h> #include <Protocol/ShellParameters.h> #include <Protocol/SmmAccess2.h> EFI_SMRAM_DESCRIPTOR *mSmramRanges; UINTN mSmramRangeCount; /** Print APP usage. **/ VOID PrintUsage ( VOID ) { Print(L"FVBDemo: usage\n"); Print(L" FVBDemo <FileName>\n"); } /** @param[in] ImageHandle The image handle. @param[in] SystemTable The system table. @retval EFI_SUCCESS Command completed successfully. @retval EFI_INVALID_PARAMETER Command usage error. @retval EFI_NOT_FOUND The input file can't be found. **/ EFI_STATUS EFIAPI UefiMain ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status=EFI_SUCCESS; EFI_SMM_ACCESS2_PROTOCOL *SmmAccess; UINTN Size; UINTN Index; // // Locate SMM Access2 Protocol // Status = gBS->LocateProtocol ( &gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess ); if (EFI_ERROR(Status)) { Print(L"Can't find SmmAccess2Protocol\n"); }; // // Get SMRAM range information // Size = 0; Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL); mSmramRanges = (EFI_SMRAM_DESCRIPTOR *) AllocatePool (Size); if (mSmramRanges == NULL) { Print(L"Allocate Memory Error!\n"); return EFI_SUCCESS; } Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmramRanges); if (EFI_ERROR(Status)) { Print(L"GetCapabilities Error!\n"); return EFI_SUCCESS; } mSmramRangeCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR); Print(L"Index PhysicalStart CpuStart PhysicalSize RegionState\n"); for (Index = 0; Index < mSmramRangeCount; Index ++) { Print(L"[%d] %8X %8X %8X %8X\n", Index, mSmramRanges[Index].PhysicalStart, mSmramRanges[Index].CpuStart, mSmramRanges[Index].PhysicalSize, mSmramRanges[Index].RegionState); } //for FreePool (mSmramRanges); return Status; }
最终运行结果如下(测试平台是 KBL-R HDK):
完整的代码下载
SMMAccess
有些CPU的register需要再SMM mode下才能access,
請問如何透過mmio的方式去access, 謝謝
这种的话没有办法直接访问了,只能在 BIOS中留下接口,然后触发 SMI 中断来完成。