]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c
MdeModulePkg: Clean up source files
[mirror_edk2.git] / MdeModulePkg / Universal / CapsuleRuntimeDxe / X64 / SaveLongModeContext.c
CommitLineData
ab7017fe 1/** @file\r
2 Create the variable to save the base address of page table and stack\r
3 for transferring into long mode in IA32 capsule PEI.\r
4\r
d1102dba 5Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>\r
ab7017fe 6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include <Uefi.h>\r
17\r
18#include <Protocol/Capsule.h>\r
19#include <Protocol/DxeSmmReadyToLock.h>\r
b5040e4c 20#include <Protocol/VariableLock.h>\r
ab7017fe 21\r
22#include <Guid/CapsuleVendor.h>\r
23#include <Guid/AcpiS3Context.h>\r
24\r
25#include <Library/DebugLib.h>\r
26#include <Library/PcdLib.h>\r
27#include <Library/UefiBootServicesTableLib.h>\r
28#include <Library/UefiRuntimeServicesTableLib.h>\r
29#include <Library/UefiRuntimeLib.h>\r
30#include <Library/BaseLib.h>\r
ab7017fe 31#include <Library/UefiLib.h>\r
32#include <Library/BaseMemoryLib.h>\r
b2d2a7f3
SZ
33\r
34//\r
35// 8 extra pages for PF handler.\r
36//\r
37#define EXTRA_PAGE_TABLE_PAGES 8\r
ab7017fe 38\r
39/**\r
fd9abd04 40 Allocate EfiReservedMemoryType below 4G memory address.\r
ab7017fe 41\r
fd9abd04 42 This function allocates EfiReservedMemoryType below 4G memory address.\r
ab7017fe 43\r
fd9abd04 44 @param Size Size of memory to allocate.\r
d1102dba 45\r
fd9abd04 46 @return Allocated Address for output.\r
ab7017fe 47\r
48**/\r
49VOID*\r
fd9abd04 50AllocateReservedMemoryBelow4G (\r
ab7017fe 51 IN UINTN Size\r
52 )\r
53{\r
54 UINTN Pages;\r
55 EFI_PHYSICAL_ADDRESS Address;\r
56 EFI_STATUS Status;\r
57 VOID* Buffer;\r
58\r
59 Pages = EFI_SIZE_TO_PAGES (Size);\r
60 Address = 0xffffffff;\r
61\r
62 Status = gBS->AllocatePages (\r
63 AllocateMaxAddress,\r
fd9abd04 64 EfiReservedMemoryType,\r
ab7017fe 65 Pages,\r
66 &Address\r
67 );\r
68 ASSERT_EFI_ERROR (Status);\r
69\r
70 Buffer = (VOID *) (UINTN) Address;\r
71 ZeroMem (Buffer, Size);\r
72\r
73 return Buffer;\r
74}\r
75\r
76/**\r
b5040e4c
EL
77 Register callback function upon VariableLockProtocol\r
78 to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it.\r
ab7017fe 79\r
80 @param[in] Event Event whose notification function is being invoked.\r
81 @param[in] Context Pointer to the notification function's context.\r
82**/\r
83VOID\r
84EFIAPI\r
b5040e4c
EL
85VariableLockCapsuleLongModeBufferVariable (\r
86 IN EFI_EVENT Event,\r
87 IN VOID *Context\r
ab7017fe 88 )\r
89{\r
90 EFI_STATUS Status;\r
b5040e4c 91 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
ab7017fe 92 //\r
b5040e4c 93 // Mark EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to read-only if the Variable Lock protocol exists\r
ab7017fe 94 //\r
b5040e4c 95 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
ab7017fe 96 if (!EFI_ERROR (Status)) {\r
b5040e4c
EL
97 Status = VariableLock->RequestToLock (VariableLock, EFI_CAPSULE_LONG_MODE_BUFFER_NAME, &gEfiCapsuleVendorGuid);\r
98 ASSERT_EFI_ERROR (Status);\r
ab7017fe 99 }\r
b5040e4c
EL
100}\r
101\r
102/**\r
fd9abd04
EL
103 1. Allocate Reserved memory for capsule PEIM to establish a 1:1 Virtual to Physical mapping.\r
104 2. Allocate Reserved memroy as a stack for capsule PEIM to transfer from 32-bit mdoe to 64-bit mode.\r
b5040e4c
EL
105\r
106**/\r
107VOID\r
108EFIAPI\r
109PrepareContextForCapsulePei (\r
110 VOID\r
111 )\r
112{\r
b2d2a7f3 113 UINTN ExtraPageTablePages;\r
b5040e4c
EL
114 UINT32 RegEax;\r
115 UINT32 RegEdx;\r
116 UINTN TotalPagesNum;\r
117 UINT8 PhysicalAddressBits;\r
b5040e4c
EL
118 UINT32 NumberOfPml4EntriesNeeded;\r
119 UINT32 NumberOfPdpEntriesNeeded;\r
120 BOOLEAN Page1GSupport;\r
121 EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer;\r
122 EFI_STATUS Status;\r
123 VOID *Registration;\r
b2d2a7f3
SZ
124\r
125 //\r
126 // Calculate the size of page table, allocate the memory.\r
127 //\r
128 Page1GSupport = FALSE;\r
129 if (PcdGetBool(PcdUse1GPageTable)) {\r
130 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
131 if (RegEax >= 0x80000001) {\r
132 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
133 if ((RegEdx & BIT26) != 0) {\r
134 Page1GSupport = TRUE;\r
b5040e4c 135 }\r
ab7017fe 136 }\r
ab7017fe 137 }\r
b2d2a7f3
SZ
138\r
139 //\r
140 // Create 4G page table by default,\r
141 // and let PF handler to handle > 4G request.\r
142 //\r
143 PhysicalAddressBits = 32;\r
144 ExtraPageTablePages = EXTRA_PAGE_TABLE_PAGES;\r
145\r
146 //\r
147 // Calculate the table entries needed.\r
148 //\r
149 if (PhysicalAddressBits <= 39 ) {\r
150 NumberOfPml4EntriesNeeded = 1;\r
151 NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));\r
152 } else {\r
153 NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));\r
154 NumberOfPdpEntriesNeeded = 512;\r
155 }\r
156\r
157 if (!Page1GSupport) {\r
158 TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;\r
159 } else {\r
160 TotalPagesNum = NumberOfPml4EntriesNeeded + 1;\r
161 }\r
162 TotalPagesNum += ExtraPageTablePages;\r
558f58e3 163 DEBUG ((DEBUG_INFO, "CapsuleRuntimeDxe X64 TotalPagesNum - 0x%x pages\n", TotalPagesNum));\r
b2d2a7f3
SZ
164\r
165 LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedMemoryBelow4G (EFI_PAGES_TO_SIZE (TotalPagesNum));\r
166 ASSERT (LongModeBuffer.PageTableAddress != 0);\r
d1102dba 167\r
b5040e4c
EL
168 //\r
169 // Allocate stack\r
170 //\r
171 LongModeBuffer.StackSize = PcdGet32 (PcdCapsulePeiLongModeStackSize);\r
fd9abd04 172 LongModeBuffer.StackBaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize));\r
d1102dba
LG
173 ASSERT (LongModeBuffer.StackBaseAddress != 0);\r
174\r
ab7017fe 175 Status = gRT->SetVariable (\r
176 EFI_CAPSULE_LONG_MODE_BUFFER_NAME,\r
177 &gEfiCapsuleVendorGuid,\r
b5040e4c 178 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
ab7017fe 179 sizeof (EFI_CAPSULE_LONG_MODE_BUFFER),\r
180 &LongModeBuffer\r
181 );\r
b5040e4c
EL
182 if (!EFI_ERROR (Status)) {\r
183 //\r
184 // Register callback function upon VariableLockProtocol\r
185 // to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it.\r
186 //\r
187 EfiCreateProtocolNotifyEvent (\r
188 &gEdkiiVariableLockProtocolGuid,\r
189 TPL_CALLBACK,\r
190 VariableLockCapsuleLongModeBufferVariable,\r
191 NULL,\r
192 &Registration\r
d1102dba 193 );\r
b5040e4c
EL
194 } else {\r
195 DEBUG ((EFI_D_ERROR, "FATAL ERROR: CapsuleLongModeBuffer cannot be saved: %r. Capsule in PEI may fail!\n", Status));\r
196 gBS->FreePages (LongModeBuffer.StackBaseAddress, EFI_SIZE_TO_PAGES (LongModeBuffer.StackSize));\r
197 }\r
ab7017fe 198}\r
199\r
200/**\r
201 Create the variable to save the base address of page table and stack\r
202 for transferring into long mode in IA32 capsule PEI.\r
203**/\r
204VOID\r
205SaveLongModeContext (\r
206 VOID\r
207 )\r
208{\r
ab7017fe 209 if ((FeaturePcdGet(PcdSupportUpdateCapsuleReset)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode))) {\r
210 //\r
b5040e4c 211 // Allocate memory for Capsule IA32 PEIM, it will create page table to transfer to long mode to access capsule above 4GB.\r
ab7017fe 212 //\r
b5040e4c 213 PrepareContextForCapsulePei ();\r
ab7017fe 214 }\r
215}\r