2 Create the variable to save the base address of page table and stack
3 for transferring into long mode in IA32 capsule PEI.
5 Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 #include <Protocol/Capsule.h>
19 #include <Protocol/DxeSmmReadyToLock.h>
21 #include <Guid/CapsuleVendor.h>
22 #include <Guid/AcpiS3Context.h>
24 #include <Library/DebugLib.h>
25 #include <Library/PcdLib.h>
26 #include <Library/UefiBootServicesTableLib.h>
27 #include <Library/UefiRuntimeServicesTableLib.h>
28 #include <Library/UefiRuntimeLib.h>
29 #include <Library/BaseLib.h>
30 #include <Library/LockBoxLib.h>
31 #include <Library/UefiLib.h>
32 #include <Library/BaseMemoryLib.h>
33 #include <Library/HobLib.h>
36 Allocate EfiACPIMemoryNVS below 4G memory address.
38 This function allocates EfiACPIMemoryNVS below 4G memory address.
40 @param Size Size of memory to allocate.
42 @return Allocated address for output.
46 AllocateAcpiNvsMemoryBelow4G (
51 EFI_PHYSICAL_ADDRESS Address
;
55 Pages
= EFI_SIZE_TO_PAGES (Size
);
58 Status
= gBS
->AllocatePages (
64 ASSERT_EFI_ERROR (Status
);
66 Buffer
= (VOID
*) (UINTN
) Address
;
67 ZeroMem (Buffer
, Size
);
73 DxeSmmReadyToLock Protocol notification event handler.
74 We reuse S3 ACPI NVS reserved memory to do capsule process
77 @param[in] Event Event whose notification function is being invoked.
78 @param[in] Context Pointer to the notification function's context.
82 DxeSmmReadyToLockNotification (
88 VOID
*DxeSmmReadyToLock
;
90 EFI_PHYSICAL_ADDRESS TempAcpiS3Context
;
91 ACPI_S3_CONTEXT
*AcpiS3Context
;
92 EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer
;
94 UINT8 PhysicalAddressBits
;
96 UINT32 NumberOfPml4EntriesNeeded
;
97 UINT32 NumberOfPdpEntriesNeeded
;
100 Status
= gBS
->LocateProtocol (
101 &gEfiDxeSmmReadyToLockProtocolGuid
,
105 if (EFI_ERROR (Status
)) {
110 // Get the ACPI NVS pages reserved by AcpiS3Save
112 LockBoxFound
= FALSE
;
113 VarSize
= sizeof (EFI_PHYSICAL_ADDRESS
);
114 Status
= RestoreLockBox (
115 &gEfiAcpiVariableGuid
,
119 if (!EFI_ERROR (Status
)) {
120 AcpiS3Context
= (ACPI_S3_CONTEXT
*)(UINTN
)TempAcpiS3Context
;
121 ASSERT (AcpiS3Context
!= NULL
);
123 Status
= RestoreLockBox (
124 &gEfiAcpiS3ContextGuid
,
128 if (!EFI_ERROR (Status
)) {
129 LongModeBuffer
.PageTableAddress
= AcpiS3Context
->S3NvsPageTableAddress
;
130 LongModeBuffer
.StackBaseAddress
= AcpiS3Context
->BootScriptStackBase
;
131 LongModeBuffer
.StackSize
= AcpiS3Context
->BootScriptStackSize
;
138 // Page table base address and stack base address can not be found in lock box,
139 // allocate both here.
143 // Get physical address bits supported from CPU HOB.
145 PhysicalAddressBits
= 36;
147 Hob
= GetFirstHob (EFI_HOB_TYPE_CPU
);
149 PhysicalAddressBits
= ((EFI_HOB_CPU
*) Hob
)->SizeOfMemorySpace
;
153 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
155 ASSERT (PhysicalAddressBits
<= 52);
156 if (PhysicalAddressBits
> 48) {
157 PhysicalAddressBits
= 48;
161 // Calculate page table size and allocate memory for it.
163 if (PhysicalAddressBits
<= 39 ) {
164 NumberOfPml4EntriesNeeded
= 1;
165 NumberOfPdpEntriesNeeded
= 1 << (PhysicalAddressBits
- 30);
167 NumberOfPml4EntriesNeeded
= 1 << (PhysicalAddressBits
- 39);
168 NumberOfPdpEntriesNeeded
= 512;
171 TotalPagesNum
= (NumberOfPdpEntriesNeeded
+ 1) * NumberOfPml4EntriesNeeded
+ 1;
172 LongModeBuffer
.PageTableAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateAcpiNvsMemoryBelow4G (EFI_PAGES_TO_SIZE (TotalPagesNum
));
173 ASSERT (LongModeBuffer
.PageTableAddress
!= 0);
178 LongModeBuffer
.StackSize
= PcdGet32 (PcdCapsulePeiLongModeStackSize
);
179 LongModeBuffer
.StackBaseAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)AllocateAcpiNvsMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize
));
180 ASSERT (LongModeBuffer
.StackBaseAddress
!= 0);
183 Status
= gRT
->SetVariable (
184 EFI_CAPSULE_LONG_MODE_BUFFER_NAME
,
185 &gEfiCapsuleVendorGuid
,
186 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
187 sizeof (EFI_CAPSULE_LONG_MODE_BUFFER
),
190 ASSERT_EFI_ERROR (Status
);
193 // Close event, so it will not be invoked again.
195 gBS
->CloseEvent (Event
);
201 Create the variable to save the base address of page table and stack
202 for transferring into long mode in IA32 capsule PEI.
205 SaveLongModeContext (
211 if ((FeaturePcdGet(PcdSupportUpdateCapsuleReset
)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode
))) {
213 // Register event to get ACPI NVS pages reserved from lock box, these pages will be used by
214 // Capsule IA32 PEI to transfer to long mode to access capsule above 4GB.
216 EfiCreateProtocolNotifyEvent (
217 &gEfiDxeSmmReadyToLockProtocolGuid
,
219 DxeSmmReadyToLockNotification
,