diff options
author | Elvin Li <elvin.li@intel.com> | 2014-08-26 12:26:32 +0000 |
---|---|---|
committer | li-elvin <li-elvin@6f19259b-4bc3-4df7-8a09-765794883524> | 2014-08-26 12:26:32 +0000 |
commit | b5040e4c55f6c5438cc8a1623f75afc5f76de43e (patch) | |
tree | 248e933fbe8816969fa018f6954d3ca9acfad255 /MdeModulePkg/Universal/CapsuleRuntimeDxe | |
parent | 5b38a703b2f0d2cda329cbca63d087a4a9509b46 (diff) | |
download | edk2-b5040e4c55f6c5438cc8a1623f75afc5f76de43e.zip edk2-b5040e4c55f6c5438cc8a1623f75afc5f76de43e.tar.gz edk2-b5040e4c55f6c5438cc8a1623f75afc5f76de43e.tar.bz2 |
1. CapsuleLongModeBuffer variable should not have EFI_VARIABLE_RUNTIME_ACCESS attribute.
2. CapsuleLongModeBuffer variable should be set to Read-Only. It should not be changed by someone else.
3. Introduce a new PCD PcdIdentifyMappingPageTablePtr to share the same range of page table between AcpiS3 and Capsule.
4. Capsule stack size is allocated from PcdCapsulePeiLongModeStackSize.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Elvin Li <elvin.li@intel.com>
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15909 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'MdeModulePkg/Universal/CapsuleRuntimeDxe')
-rw-r--r-- | MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf | 10 | ||||
-rw-r--r-- | MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c | 186 |
2 files changed, 105 insertions, 91 deletions
diff --git a/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf b/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf index 7767e68..66c438c 100644 --- a/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf +++ b/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf @@ -5,7 +5,7 @@ # It installs the Capsule Architectural Protocol defined in PI1.0a to signify
# the capsule runtime services are ready.
#
-# Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2006 - 2014, 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
@@ -73,7 +73,9 @@ gEfiCapsuleArchProtocolGuid ## PRODUCED
[Protocols.X64]
- gEfiDxeSmmReadyToLockProtocolGuid # ALWAYS_CONSUMED
+ ## UNDEFINED ## NOTIFY
+ ## SOMETIMES_CONSUMES
+ gEdkiiVariableLockProtocolGuid
[FeaturePcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset
@@ -86,7 +88,11 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxSizePopulateCapsule || gEfiMdeModulePkgTokenSpaceGuid.PcdSupportUpdateCapsuleReset ## Populate Image requires reset support.
[Pcd.X64]
+ ## SOMETIMES_CONSUMES
+ ## SOMETIMES_PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdIdentifyMappingPageTablePtr
gEfiMdeModulePkgTokenSpaceGuid.PcdCapsulePeiLongModeStackSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## SOMETIMES_CONSUMES
[Depex]
gEfiVariableWriteArchProtocolGuid ## Depends on variable write functionality to produce capsule data variable
diff --git a/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c b/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c index 0cfc352..a5c7c48 100644 --- a/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c +++ b/MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c @@ -2,7 +2,7 @@ Create the variable to save the base address of page table and stack
for transferring into long mode in IA32 capsule PEI.
-Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+Copyright (c) 2011 - 2014, 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
@@ -17,6 +17,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include <Protocol/Capsule.h>
#include <Protocol/DxeSmmReadyToLock.h>
+#include <Protocol/VariableLock.h>
#include <Guid/CapsuleVendor.h>
#include <Guid/AcpiS3Context.h>
@@ -70,83 +71,85 @@ AllocateAcpiNvsMemoryBelow4G ( }
/**
- DxeSmmReadyToLock Protocol notification event handler.
- We reuse S3 ACPI NVS reserved memory to do capsule process
- after reset.
+ Register callback function upon VariableLockProtocol
+ to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it.
@param[in] Event Event whose notification function is being invoked.
@param[in] Context Pointer to the notification function's context.
**/
VOID
EFIAPI
-DxeSmmReadyToLockNotification (
- IN EFI_EVENT Event,
- IN VOID *Context
+VariableLockCapsuleLongModeBufferVariable (
+ IN EFI_EVENT Event,
+ IN VOID *Context
)
{
EFI_STATUS Status;
- VOID *DxeSmmReadyToLock;
- UINTN VarSize;
- EFI_PHYSICAL_ADDRESS TempAcpiS3Context;
- ACPI_S3_CONTEXT *AcpiS3Context;
- EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer;
- UINTN TotalPagesNum;
- UINT8 PhysicalAddressBits;
- VOID *Hob;
- UINT32 NumberOfPml4EntriesNeeded;
- UINT32 NumberOfPdpEntriesNeeded;
- BOOLEAN LockBoxFound;
-
- Status = gBS->LocateProtocol (
- &gEfiDxeSmmReadyToLockProtocolGuid,
- NULL,
- &DxeSmmReadyToLock
- );
- if (EFI_ERROR (Status)) {
- return ;
- }
-
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
//
- // Get the ACPI NVS pages reserved by AcpiS3Save
+ // Mark EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to read-only if the Variable Lock protocol exists
//
- LockBoxFound = FALSE;
- VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
- Status = RestoreLockBox (
- &gEfiAcpiVariableGuid,
- &TempAcpiS3Context,
- &VarSize
- );
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
if (!EFI_ERROR (Status)) {
- AcpiS3Context = (ACPI_S3_CONTEXT *)(UINTN)TempAcpiS3Context;
- ASSERT (AcpiS3Context != NULL);
-
- Status = RestoreLockBox (
- &gEfiAcpiS3ContextGuid,
- NULL,
- NULL
- );
- if (!EFI_ERROR (Status)) {
- LongModeBuffer.PageTableAddress = AcpiS3Context->S3NvsPageTableAddress;
- LongModeBuffer.StackBaseAddress = AcpiS3Context->BootScriptStackBase;
- LongModeBuffer.StackSize = AcpiS3Context->BootScriptStackSize;
- LockBoxFound = TRUE;
- }
+ Status = VariableLock->RequestToLock (VariableLock, EFI_CAPSULE_LONG_MODE_BUFFER_NAME, &gEfiCapsuleVendorGuid);
+ ASSERT_EFI_ERROR (Status);
}
+}
+
+/**
+ 1. Allocate NVS memory for capsule PEIM to establish a 1:1 Virtual to Physical mapping.
+ 2. Allocate NVS memroy as a stack for capsule PEIM to transfer from 32-bit mdoe to 64-bit mode.
+
+**/
+VOID
+EFIAPI
+PrepareContextForCapsulePei (
+ VOID
+ )
+{
+ UINT32 RegEax;
+ UINT32 RegEdx;
+ UINTN TotalPagesNum;
+ UINT8 PhysicalAddressBits;
+ VOID *Hob;
+ UINT32 NumberOfPml4EntriesNeeded;
+ UINT32 NumberOfPdpEntriesNeeded;
+ BOOLEAN Page1GSupport;
+ EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer;
+ EFI_STATUS Status;
+ VOID *Registration;
- if (!LockBoxFound) {
- //
- // Page table base address and stack base address can not be found in lock box,
- // allocate both here.
- //
+ LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdIdentifyMappingPageTablePtr);
+ if (LongModeBuffer.PageTableAddress == 0x0) {
//
- // Get physical address bits supported from CPU HOB.
+ // Calculate the size of page table, allocate the memory, and set PcdIdentifyMappingPageTablePtr.
//
- PhysicalAddressBits = 36;
+ Page1GSupport = FALSE;
+ if (PcdGetBool(PcdUse1GPageTable)) {
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000001) {
+ AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & BIT26) != 0) {
+ Page1GSupport = TRUE;
+ }
+ }
+ }
+ //
+ // Get physical address bits supported.
+ //
Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
if (Hob != NULL) {
PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
+ } else {
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000008) {
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
+ PhysicalAddressBits = (UINT8) RegEax;
+ } else {
+ PhysicalAddressBits = 36;
+ }
}
//
@@ -158,43 +161,57 @@ DxeSmmReadyToLockNotification ( }
//
- // Calculate page table size and allocate memory for it.
+ // Calculate the table entries needed.
//
if (PhysicalAddressBits <= 39 ) {
NumberOfPml4EntriesNeeded = 1;
- NumberOfPdpEntriesNeeded = 1 << (PhysicalAddressBits - 30);
+ NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
} else {
- NumberOfPml4EntriesNeeded = 1 << (PhysicalAddressBits - 39);
+ NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));
NumberOfPdpEntriesNeeded = 512;
}
- TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;
+ if (!Page1GSupport) {
+ TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;
+ } else {
+ TotalPagesNum = NumberOfPml4EntriesNeeded + 1;
+ }
+
LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (EFI_PAGES_TO_SIZE (TotalPagesNum));
ASSERT (LongModeBuffer.PageTableAddress != 0);
-
- //
- // Allocate stack
- //
- LongModeBuffer.StackSize = PcdGet32 (PcdCapsulePeiLongModeStackSize);
- LongModeBuffer.StackBaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize));
- ASSERT (LongModeBuffer.StackBaseAddress != 0);
+ PcdSet64 (PcdIdentifyMappingPageTablePtr, LongModeBuffer.PageTableAddress);
}
-
+
+ //
+ // Allocate stack
+ //
+ LongModeBuffer.StackSize = PcdGet32 (PcdCapsulePeiLongModeStackSize);
+ LongModeBuffer.StackBaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize));
+ ASSERT (LongModeBuffer.StackBaseAddress != 0);
+
Status = gRT->SetVariable (
EFI_CAPSULE_LONG_MODE_BUFFER_NAME,
&gEfiCapsuleVendorGuid,
- EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
sizeof (EFI_CAPSULE_LONG_MODE_BUFFER),
&LongModeBuffer
);
- ASSERT_EFI_ERROR (Status);
-
- //
- // Close event, so it will not be invoked again.
- //
- gBS->CloseEvent (Event);
-
- return ;
+ if (!EFI_ERROR (Status)) {
+ //
+ // Register callback function upon VariableLockProtocol
+ // to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it.
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEdkiiVariableLockProtocolGuid,
+ TPL_CALLBACK,
+ VariableLockCapsuleLongModeBufferVariable,
+ NULL,
+ &Registration
+ );
+ } else {
+ DEBUG ((EFI_D_ERROR, "FATAL ERROR: CapsuleLongModeBuffer cannot be saved: %r. Capsule in PEI may fail!\n", Status));
+ gBS->FreePages (LongModeBuffer.StackBaseAddress, EFI_SIZE_TO_PAGES (LongModeBuffer.StackSize));
+ }
}
/**
@@ -206,19 +223,10 @@ SaveLongModeContext ( VOID
)
{
- VOID *Registration;
-
if ((FeaturePcdGet(PcdSupportUpdateCapsuleReset)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode))) {
//
- // Register event to get ACPI NVS pages reserved from lock box, these pages will be used by
- // Capsule IA32 PEI to transfer to long mode to access capsule above 4GB.
+ // Allocate memory for Capsule IA32 PEIM, it will create page table to transfer to long mode to access capsule above 4GB.
//
- EfiCreateProtocolNotifyEvent (
- &gEfiDxeSmmReadyToLockProtocolGuid,
- TPL_CALLBACK,
- DxeSmmReadyToLockNotification,
- NULL,
- &Registration
- );
+ PrepareContextForCapsulePei ();
}
}
|