From b5040e4c55f6c5438cc8a1623f75afc5f76de43e Mon Sep 17 00:00:00 2001 From: Elvin Li Date: Tue, 26 Aug 2014 12:26:32 +0000 Subject: 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 Signed-off-by: Jiewen Yao git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15909 6f19259b-4bc3-4df7-8a09-765794883524 --- MdeModulePkg/MdeModulePkg.dec | 3 + .../CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf | 10 +- .../CapsuleRuntimeDxe/X64/SaveLongModeContext.c | 186 +++++++++++---------- 3 files changed, 108 insertions(+), 91 deletions(-) diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 7fec666c79..30912c1521 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -951,3 +951,6 @@ # default value is set to Zero. And the PCD is assumed ONLY to be accessed in DxeS3BootScriptLib Library. gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptTablePrivateSmmDataPtr|0x0|UINT64|0x00030001 + ## This dynamic PCD hold an address to point to the memory of page table. The page table establishes a 1:1 + # Virtual to Physical mapping according to the processor physical address bits. + gEfiMdeModulePkgTokenSpaceGuid.PcdIdentifyMappingPageTablePtr|0x0|UINT64|0x00030002 diff --git a/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf b/MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf index 7767e68345..66c438ca63 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.
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
# 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 0cfc352ac0..a5c7c48eee 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.
+Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.
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 #include +#include #include #include @@ -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 (); } } -- cgit v1.2.3