Create the variable to save the base address of page table and stack\r
for transferring into long mode in IA32 capsule PEI.\r
\r
-Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
which accompanies this distribution. The full text of the license may be found at\r
\r
#include <Protocol/Capsule.h>\r
#include <Protocol/DxeSmmReadyToLock.h>\r
+#include <Protocol/VariableLock.h>\r
\r
#include <Guid/CapsuleVendor.h>\r
#include <Guid/AcpiS3Context.h>\r
}\r
\r
/**\r
- DxeSmmReadyToLock Protocol notification event handler.\r
- We reuse S3 ACPI NVS reserved memory to do capsule process\r
- after reset.\r
+ Register callback function upon VariableLockProtocol\r
+ to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it.\r
\r
@param[in] Event Event whose notification function is being invoked.\r
@param[in] Context Pointer to the notification function's context.\r
**/\r
VOID\r
EFIAPI\r
-DxeSmmReadyToLockNotification (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
+VariableLockCapsuleLongModeBufferVariable (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
)\r
{\r
EFI_STATUS Status;\r
- VOID *DxeSmmReadyToLock;\r
- UINTN VarSize;\r
- EFI_PHYSICAL_ADDRESS TempAcpiS3Context;\r
- ACPI_S3_CONTEXT *AcpiS3Context;\r
- EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer;\r
- UINTN TotalPagesNum;\r
- UINT8 PhysicalAddressBits;\r
- VOID *Hob;\r
- UINT32 NumberOfPml4EntriesNeeded;\r
- UINT32 NumberOfPdpEntriesNeeded;\r
- BOOLEAN LockBoxFound;\r
-\r
- Status = gBS->LocateProtocol (\r
- &gEfiDxeSmmReadyToLockProtocolGuid,\r
- NULL,\r
- &DxeSmmReadyToLock\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return ;\r
- }\r
-\r
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
//\r
- // Get the ACPI NVS pages reserved by AcpiS3Save\r
+ // Mark EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to read-only if the Variable Lock protocol exists\r
//\r
- LockBoxFound = FALSE;\r
- VarSize = sizeof (EFI_PHYSICAL_ADDRESS);\r
- Status = RestoreLockBox (\r
- &gEfiAcpiVariableGuid,\r
- &TempAcpiS3Context,\r
- &VarSize\r
- );\r
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
if (!EFI_ERROR (Status)) {\r
- AcpiS3Context = (ACPI_S3_CONTEXT *)(UINTN)TempAcpiS3Context;\r
- ASSERT (AcpiS3Context != NULL);\r
- \r
- Status = RestoreLockBox (\r
- &gEfiAcpiS3ContextGuid,\r
- NULL,\r
- NULL\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- LongModeBuffer.PageTableAddress = AcpiS3Context->S3NvsPageTableAddress;\r
- LongModeBuffer.StackBaseAddress = AcpiS3Context->BootScriptStackBase;\r
- LongModeBuffer.StackSize = AcpiS3Context->BootScriptStackSize;\r
- LockBoxFound = TRUE;\r
- }\r
+ Status = VariableLock->RequestToLock (VariableLock, EFI_CAPSULE_LONG_MODE_BUFFER_NAME, &gEfiCapsuleVendorGuid);\r
+ ASSERT_EFI_ERROR (Status);\r
}\r
+}\r
+\r
+/**\r
+ 1. Allocate NVS memory for capsule PEIM to establish a 1:1 Virtual to Physical mapping.\r
+ 2. Allocate NVS memroy as a stack for capsule PEIM to transfer from 32-bit mdoe to 64-bit mode.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PrepareContextForCapsulePei (\r
+ VOID\r
+ )\r
+{\r
+ UINT32 RegEax;\r
+ UINT32 RegEdx;\r
+ UINTN TotalPagesNum;\r
+ UINT8 PhysicalAddressBits;\r
+ VOID *Hob;\r
+ UINT32 NumberOfPml4EntriesNeeded;\r
+ UINT32 NumberOfPdpEntriesNeeded;\r
+ BOOLEAN Page1GSupport;\r
+ EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer;\r
+ EFI_STATUS Status;\r
+ VOID *Registration;\r
\r
- if (!LockBoxFound) {\r
- //\r
- // Page table base address and stack base address can not be found in lock box,\r
- // allocate both here. \r
- //\r
+ LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdIdentifyMappingPageTablePtr);\r
\r
+ if (LongModeBuffer.PageTableAddress == 0x0) {\r
//\r
- // Get physical address bits supported from CPU HOB.\r
+ // Calculate the size of page table, allocate the memory, and set PcdIdentifyMappingPageTablePtr.\r
//\r
- PhysicalAddressBits = 36;\r
+ Page1GSupport = FALSE;\r
+ if (PcdGetBool(PcdUse1GPageTable)) {\r
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+ if (RegEax >= 0x80000001) {\r
+ AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
+ if ((RegEdx & BIT26) != 0) {\r
+ Page1GSupport = TRUE;\r
+ }\r
+ }\r
+ }\r
\r
+ //\r
+ // Get physical address bits supported.\r
+ //\r
Hob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
if (Hob != NULL) {\r
PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;\r
+ } else {\r
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+ if (RegEax >= 0x80000008) {\r
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+ PhysicalAddressBits = (UINT8) RegEax;\r
+ } else {\r
+ PhysicalAddressBits = 36;\r
+ }\r
}\r
\r
//\r
}\r
\r
//\r
- // Calculate page table size and allocate memory for it.\r
+ // Calculate the table entries needed.\r
//\r
if (PhysicalAddressBits <= 39 ) {\r
NumberOfPml4EntriesNeeded = 1;\r
- NumberOfPdpEntriesNeeded = 1 << (PhysicalAddressBits - 30);\r
+ NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));\r
} else {\r
- NumberOfPml4EntriesNeeded = 1 << (PhysicalAddressBits - 39);\r
+ NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));\r
NumberOfPdpEntriesNeeded = 512;\r
}\r
\r
- TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;\r
+ if (!Page1GSupport) {\r
+ TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;\r
+ } else {\r
+ TotalPagesNum = NumberOfPml4EntriesNeeded + 1;\r
+ }\r
+ \r
LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (EFI_PAGES_TO_SIZE (TotalPagesNum));\r
ASSERT (LongModeBuffer.PageTableAddress != 0);\r
- \r
- //\r
- // Allocate stack\r
- //\r
- LongModeBuffer.StackSize = PcdGet32 (PcdCapsulePeiLongModeStackSize);\r
- LongModeBuffer.StackBaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize));\r
- ASSERT (LongModeBuffer.StackBaseAddress != 0);\r
+ PcdSet64 (PcdIdentifyMappingPageTablePtr, LongModeBuffer.PageTableAddress); \r
}\r
-\r
+ \r
+ //\r
+ // Allocate stack\r
+ //\r
+ LongModeBuffer.StackSize = PcdGet32 (PcdCapsulePeiLongModeStackSize);\r
+ LongModeBuffer.StackBaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize));\r
+ ASSERT (LongModeBuffer.StackBaseAddress != 0); \r
+ \r
Status = gRT->SetVariable (\r
EFI_CAPSULE_LONG_MODE_BUFFER_NAME,\r
&gEfiCapsuleVendorGuid,\r
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
sizeof (EFI_CAPSULE_LONG_MODE_BUFFER),\r
&LongModeBuffer\r
);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Close event, so it will not be invoked again.\r
- //\r
- gBS->CloseEvent (Event);\r
-\r
- return ;\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Register callback function upon VariableLockProtocol\r
+ // to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it.\r
+ //\r
+ EfiCreateProtocolNotifyEvent (\r
+ &gEdkiiVariableLockProtocolGuid,\r
+ TPL_CALLBACK,\r
+ VariableLockCapsuleLongModeBufferVariable,\r
+ NULL,\r
+ &Registration\r
+ ); \r
+ } else {\r
+ DEBUG ((EFI_D_ERROR, "FATAL ERROR: CapsuleLongModeBuffer cannot be saved: %r. Capsule in PEI may fail!\n", Status));\r
+ gBS->FreePages (LongModeBuffer.StackBaseAddress, EFI_SIZE_TO_PAGES (LongModeBuffer.StackSize));\r
+ }\r
}\r
\r
/**\r
VOID\r
)\r
{\r
- VOID *Registration;\r
- \r
if ((FeaturePcdGet(PcdSupportUpdateCapsuleReset)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode))) {\r
//\r
- // Register event to get ACPI NVS pages reserved from lock box, these pages will be used by\r
- // Capsule IA32 PEI to transfer to long mode to access capsule above 4GB.\r
+ // Allocate memory for Capsule IA32 PEIM, it will create page table to transfer to long mode to access capsule above 4GB.\r
//\r
- EfiCreateProtocolNotifyEvent (\r
- &gEfiDxeSmmReadyToLockProtocolGuid,\r
- TPL_CALLBACK,\r
- DxeSmmReadyToLockNotification,\r
- NULL,\r
- &Registration\r
- );\r
+ PrepareContextForCapsulePei ();\r
}\r
}\r