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
This commit is contained in:
Elvin Li 2014-08-26 12:26:32 +00:00 committed by li-elvin
parent 5b38a703b2
commit b5040e4c55
3 changed files with 109 additions and 92 deletions

View File

@ -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

View File

@ -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

View File

@ -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);
}
if (!LockBoxFound) {
//
// Page table base address and stack base address can not be found in lock box,
// allocate both here.
//
}
/**
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;
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 ();
}
}