TianoCore EDK2 master
Loading...
Searching...
No Matches
AcpiS3ContextSave.c
Go to the documentation of this file.
1
10#include <PiDxe.h>
11#include <Library/BaseLib.h>
14#include <Library/HobLib.h>
15#include <Library/LockBoxLib.h>
16#include <Library/PcdLib.h>
17#include <Library/DebugLib.h>
18#include <Library/UefiLib.h>
19#include <Guid/AcpiS3Context.h>
21#include <Protocol/LockBox.h>
22
23//
24// 8 extra pages for PF handler.
25//
26#define EXTRA_PAGE_TABLE_PAGES 8
27
28EFI_GUID mAcpiS3IdtrProfileGuid = {
29 0xdea652b0, 0xd587, 0x4c54, { 0xb5, 0xb4, 0xc6, 0x82, 0xe7, 0xa0, 0xaa, 0x3d }
30};
31
43VOID *
45 IN EFI_MEMORY_TYPE MemoryType,
46 IN UINTN Size
47 )
48{
49 UINTN Pages;
51 EFI_STATUS Status;
52 VOID *Buffer;
53
54 Pages = EFI_SIZE_TO_PAGES (Size);
55 Address = 0xffffffff;
56
57 Status = gBS->AllocatePages (
59 MemoryType,
60 Pages,
61 &Address
62 );
63 ASSERT_EFI_ERROR (Status);
64
65 Buffer = (VOID *)(UINTN)Address;
66 ZeroMem (Buffer, Size);
67
68 return Buffer;
69}
70
80BOOLEAN
83 )
84{
85 if ((Facs == NULL) ||
87 {
88 //
89 // Something wrong with FACS.
90 //
91 return FALSE;
92 }
93
95 ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0))
96 {
97 //
98 // BIOS supports 64bit waking vector.
99 //
100 if (sizeof (UINTN) == sizeof (UINT64)) {
101 return TRUE;
102 }
103 }
104
105 return FALSE;
106}
107
124 IN BOOLEAN LongModeWakingVectorSupport
125 )
126{
127 if ((FeaturePcdGet (PcdDxeIplSwitchToLongMode)) || (sizeof (UINTN) == sizeof (UINT64))) {
128 UINTN ExtraPageTablePages;
129 UINT32 RegEax;
130 UINT32 RegEdx;
131 UINT8 PhysicalAddressBits;
132 UINT32 NumberOfPml4EntriesNeeded;
133 UINT32 NumberOfPdpEntriesNeeded;
134 EFI_PHYSICAL_ADDRESS S3NvsPageTableAddress;
135 UINTN TotalPageTableSize;
136 VOID *Hob;
137 BOOLEAN Page1GSupport;
138
139 Page1GSupport = FALSE;
140 if (PcdGetBool (PcdUse1GPageTable)) {
141 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
142 if (RegEax >= 0x80000001) {
143 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
144 if ((RegEdx & BIT26) != 0) {
145 Page1GSupport = TRUE;
146 }
147 }
148 }
149
150 //
151 // Get physical address bits supported.
152 //
153 Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
154 if (Hob != NULL) {
155 PhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;
156 } else {
157 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
158 if (RegEax >= 0x80000008) {
159 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
160 PhysicalAddressBits = (UINT8)RegEax;
161 } else {
162 PhysicalAddressBits = 36;
163 }
164 }
165
166 //
167 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
168 //
169 ASSERT (PhysicalAddressBits <= 52);
170 if (PhysicalAddressBits > 48) {
171 PhysicalAddressBits = 48;
172 }
173
174 ExtraPageTablePages = 0;
175 if (!LongModeWakingVectorSupport) {
176 //
177 // Create 4G page table when BIOS does not support long mode waking vector,
178 // and let PF handler to handle > 4G request.
179 //
180 PhysicalAddressBits = 32;
181 ExtraPageTablePages = EXTRA_PAGE_TABLE_PAGES;
182 }
183
184 //
185 // Calculate the table entries needed.
186 //
187 if (PhysicalAddressBits <= 39 ) {
188 NumberOfPml4EntriesNeeded = 1;
189 NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
190 } else {
191 NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));
192 NumberOfPdpEntriesNeeded = 512;
193 }
194
195 //
196 // We need calculate whole page size then allocate once, because S3 restore page table does not know each page in Nvs.
197 //
198 if (!Page1GSupport) {
199 TotalPageTableSize = 1 + NumberOfPml4EntriesNeeded + NumberOfPml4EntriesNeeded * NumberOfPdpEntriesNeeded;
200 } else {
201 TotalPageTableSize = 1 + NumberOfPml4EntriesNeeded;
202 }
203
204 TotalPageTableSize += ExtraPageTablePages;
205 DEBUG ((DEBUG_INFO, "AcpiS3ContextSave TotalPageTableSize - 0x%x pages\n", TotalPageTableSize));
206
207 //
208 // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
209 //
210 S3NvsPageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGES_TO_SIZE (TotalPageTableSize));
211 ASSERT (S3NvsPageTableAddress != 0);
212 return S3NvsPageTableAddress;
213 } else {
214 //
215 // If DXE is running 32-bit mode, no need to establish page table.
216 //
217 return (EFI_PHYSICAL_ADDRESS)0;
218 }
219}
220
228VOID
229EFIAPI
231 IN EFI_EVENT Event,
232 IN VOID *Context
233 )
234{
235 EFI_STATUS Status;
236 EFI_PHYSICAL_ADDRESS AcpiS3ContextBuffer;
237 ACPI_S3_CONTEXT *AcpiS3Context;
238 IA32_DESCRIPTOR *Idtr;
239 IA32_IDT_GATE_DESCRIPTOR *IdtGate;
241 VOID *Interface;
242
243 DEBUG ((DEBUG_INFO, "AcpiS3ContextSave!\n"));
244
245 Status = gBS->LocateProtocol (&gEfiLockBoxProtocolGuid, NULL, &Interface);
246 if (EFI_ERROR (Status)) {
247 DEBUG ((DEBUG_INFO | DEBUG_WARN, "ACPI S3 context can't be saved without LockBox!\n"));
248 goto Done;
249 }
250
251 AcpiS3Context = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof (*AcpiS3Context));
252 ASSERT (AcpiS3Context != NULL);
253 AcpiS3ContextBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;
254
255 //
256 // Get ACPI Table because we will save its position to variable
257 //
260 );
261 AcpiS3Context->AcpiFacsTable = (EFI_PHYSICAL_ADDRESS)(UINTN)Facs;
262 ASSERT (AcpiS3Context->AcpiFacsTable != 0);
263
264 IdtGate = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 0x100 + sizeof (IA32_DESCRIPTOR));
265 Idtr = (IA32_DESCRIPTOR *)(IdtGate + 0x100);
266 Idtr->Base = (UINTN)IdtGate;
267 Idtr->Limit = (UINT16)(sizeof (IA32_IDT_GATE_DESCRIPTOR) * 0x100 - 1);
268 AcpiS3Context->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)Idtr;
269
270 Status = SaveLockBox (
271 &mAcpiS3IdtrProfileGuid,
272 (VOID *)(UINTN)Idtr,
273 (UINTN)sizeof (IA32_DESCRIPTOR)
274 );
275 ASSERT_EFI_ERROR (Status);
276
277 Status = SetLockBoxAttributes (&mAcpiS3IdtrProfileGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
278 ASSERT_EFI_ERROR (Status);
279
280 //
281 // Allocate page table
282 //
283 AcpiS3Context->S3NvsPageTableAddress = S3AllocatePageTablesBuffer (IsLongModeWakingVectorSupport (Facs));
284
285 //
286 // Allocate stack
287 //
288 AcpiS3Context->BootScriptStackSize = PcdGet32 (PcdS3BootScriptStackSize);
289 AcpiS3Context->BootScriptStackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3BootScriptStackSize));
290 ASSERT (AcpiS3Context->BootScriptStackBase != 0);
291
292 //
293 // Allocate a code buffer < 4G for S3 debug to load external code, set invalid code instructions in it.
294 //
295 AcpiS3Context->S3DebugBufferAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGE_SIZE);
296 SetMem ((VOID *)(UINTN)AcpiS3Context->S3DebugBufferAddress, EFI_PAGE_SIZE, 0xff);
297
298 DEBUG ((DEBUG_INFO, "AcpiS3Context: AcpiFacsTable is 0x%8x\n", AcpiS3Context->AcpiFacsTable));
299 DEBUG ((DEBUG_INFO, "AcpiS3Context: IdtrProfile is 0x%8x\n", AcpiS3Context->IdtrProfile));
300 DEBUG ((DEBUG_INFO, "AcpiS3Context: S3NvsPageTableAddress is 0x%8x\n", AcpiS3Context->S3NvsPageTableAddress));
301 DEBUG ((DEBUG_INFO, "AcpiS3Context: S3DebugBufferAddress is 0x%8x\n", AcpiS3Context->S3DebugBufferAddress));
302 DEBUG ((DEBUG_INFO, "AcpiS3Context: BootScriptStackBase is 0x%8x\n", AcpiS3Context->BootScriptStackBase));
303 DEBUG ((DEBUG_INFO, "AcpiS3Context: BootScriptStackSize is 0x%8x\n", AcpiS3Context->BootScriptStackSize));
304
305 Status = SaveLockBox (
306 &gEfiAcpiVariableGuid,
307 &AcpiS3ContextBuffer,
308 sizeof (AcpiS3ContextBuffer)
309 );
310 ASSERT_EFI_ERROR (Status);
311
312 Status = SaveLockBox (
313 &gEfiAcpiS3ContextGuid,
314 (VOID *)(UINTN)AcpiS3Context,
315 (UINTN)sizeof (*AcpiS3Context)
316 );
317 ASSERT_EFI_ERROR (Status);
318
319 Status = SetLockBoxAttributes (&gEfiAcpiS3ContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
320 ASSERT_EFI_ERROR (Status);
321
322Done:
323 //
324 // Close the event, deregistering the callback and freeing resources.
325 //
326 Status = gBS->CloseEvent (Event);
327 ASSERT_EFI_ERROR (Status);
328}
UINT64 UINTN
#define EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE
Definition: Acpi40.h:1180
#define EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION
Definition: Acpi40.h:238
EFI_PHYSICAL_ADDRESS S3AllocatePageTablesBuffer(IN BOOLEAN LongModeWakingVectorSupport)
VOID EFIAPI AcpiS3ContextSaveOnEndOfDxe(IN EFI_EVENT Event, IN VOID *Context)
BOOLEAN IsLongModeWakingVectorSupport(IN EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs)
VOID * AllocateMemoryBelow4G(IN EFI_MEMORY_TYPE MemoryType, IN UINTN Size)
VOID *EFIAPI GetFirstHob(IN UINT16 Type)
Definition: HobLib.c:142
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: LShiftU64.c:28
VOID *EFIAPI SetMem(OUT VOID *Buffer, IN UINTN Length, IN UINT8 Value)
Definition: SetMemWrapper.c:38
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
RETURN_STATUS EFIAPI SetLockBoxAttributes(IN GUID *Guid, IN UINT64 Attributes)
RETURN_STATUS EFIAPI SaveLockBox(IN GUID *Guid, IN VOID *Buffer, IN UINTN Length)
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
UINT32 EFIAPI AsmCpuid(IN UINT32 Index, OUT UINT32 *RegisterEax OPTIONAL, OUT UINT32 *RegisterEbx OPTIONAL, OUT UINT32 *RegisterEcx OPTIONAL, OUT UINT32 *RegisterEdx OPTIONAL)
Definition: CpuId.c:36
#define PcdGet32(TokenName)
Definition: PcdLib.h:362
#define PcdGetBool(TokenName)
Definition: PcdLib.h:401
#define FeaturePcdGet(TokenName)
Definition: PcdLib.h:50
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
#define EFI_PAGES_TO_SIZE(Pages)
Definition: UefiBaseType.h:213
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
EFI_BOOT_SERVICES * gBS
EFI_ACPI_COMMON_HEADER *EFIAPI EfiLocateFirstAcpiTable(IN UINT32 Signature)
Definition: Acpi.c:441
EFI_MEMORY_TYPE
@ EfiReservedMemoryType
@ AllocateMaxAddress
Definition: UefiSpec.h:38
Definition: Base.h:213