]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/CapsuleRuntimeDxe/X64/SaveLongModeContext.c
Allocate EfiReservedMemoryType of memory.
[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
b5040e4c 5Copyright (c) 2011 - 2014, 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
33#include <Library/HobLib.h>\r
34\r
35/**\r
fd9abd04 36 Allocate EfiReservedMemoryType below 4G memory address.\r
ab7017fe 37\r
fd9abd04 38 This function allocates EfiReservedMemoryType below 4G memory address.\r
ab7017fe 39\r
fd9abd04 40 @param Size Size of memory to allocate.\r
ab7017fe 41 \r
fd9abd04 42 @return Allocated Address for output.\r
ab7017fe 43\r
44**/\r
45VOID*\r
fd9abd04 46AllocateReservedMemoryBelow4G (\r
ab7017fe 47 IN UINTN Size\r
48 )\r
49{\r
50 UINTN Pages;\r
51 EFI_PHYSICAL_ADDRESS Address;\r
52 EFI_STATUS Status;\r
53 VOID* Buffer;\r
54\r
55 Pages = EFI_SIZE_TO_PAGES (Size);\r
56 Address = 0xffffffff;\r
57\r
58 Status = gBS->AllocatePages (\r
59 AllocateMaxAddress,\r
fd9abd04 60 EfiReservedMemoryType,\r
ab7017fe 61 Pages,\r
62 &Address\r
63 );\r
64 ASSERT_EFI_ERROR (Status);\r
65\r
66 Buffer = (VOID *) (UINTN) Address;\r
67 ZeroMem (Buffer, Size);\r
68\r
69 return Buffer;\r
70}\r
71\r
72/**\r
b5040e4c
EL
73 Register callback function upon VariableLockProtocol\r
74 to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it.\r
ab7017fe 75\r
76 @param[in] Event Event whose notification function is being invoked.\r
77 @param[in] Context Pointer to the notification function's context.\r
78**/\r
79VOID\r
80EFIAPI\r
b5040e4c
EL
81VariableLockCapsuleLongModeBufferVariable (\r
82 IN EFI_EVENT Event,\r
83 IN VOID *Context\r
ab7017fe 84 )\r
85{\r
86 EFI_STATUS Status;\r
b5040e4c 87 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
ab7017fe 88 //\r
b5040e4c 89 // Mark EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to read-only if the Variable Lock protocol exists\r
ab7017fe 90 //\r
b5040e4c 91 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
ab7017fe 92 if (!EFI_ERROR (Status)) {\r
b5040e4c
EL
93 Status = VariableLock->RequestToLock (VariableLock, EFI_CAPSULE_LONG_MODE_BUFFER_NAME, &gEfiCapsuleVendorGuid);\r
94 ASSERT_EFI_ERROR (Status);\r
ab7017fe 95 }\r
b5040e4c
EL
96}\r
97\r
98/**\r
fd9abd04
EL
99 1. Allocate Reserved memory for capsule PEIM to establish a 1:1 Virtual to Physical mapping.\r
100 2. Allocate Reserved memroy as a stack for capsule PEIM to transfer from 32-bit mdoe to 64-bit mode.\r
b5040e4c
EL
101\r
102**/\r
103VOID\r
104EFIAPI\r
105PrepareContextForCapsulePei (\r
106 VOID\r
107 )\r
108{\r
109 UINT32 RegEax;\r
110 UINT32 RegEdx;\r
111 UINTN TotalPagesNum;\r
112 UINT8 PhysicalAddressBits;\r
113 VOID *Hob;\r
114 UINT32 NumberOfPml4EntriesNeeded;\r
115 UINT32 NumberOfPdpEntriesNeeded;\r
116 BOOLEAN Page1GSupport;\r
117 EFI_CAPSULE_LONG_MODE_BUFFER LongModeBuffer;\r
118 EFI_STATUS Status;\r
119 VOID *Registration;\r
ab7017fe 120 \r
b5040e4c 121 LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdIdentifyMappingPageTablePtr);\r
ab7017fe 122\r
b5040e4c 123 if (LongModeBuffer.PageTableAddress == 0x0) {\r
ab7017fe 124 //\r
b5040e4c 125 // Calculate the size of page table, allocate the memory, and set PcdIdentifyMappingPageTablePtr.\r
ab7017fe 126 //\r
b5040e4c
EL
127 Page1GSupport = FALSE;\r
128 if (PcdGetBool(PcdUse1GPageTable)) {\r
129 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
130 if (RegEax >= 0x80000001) {\r
131 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
132 if ((RegEdx & BIT26) != 0) {\r
133 Page1GSupport = TRUE;\r
134 }\r
135 }\r
136 }\r
ab7017fe 137 \r
b5040e4c
EL
138 //\r
139 // Get physical address bits supported.\r
140 //\r
ab7017fe 141 Hob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
142 if (Hob != NULL) {\r
143 PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;\r
b5040e4c
EL
144 } else {\r
145 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
146 if (RegEax >= 0x80000008) {\r
147 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
148 PhysicalAddressBits = (UINT8) RegEax;\r
149 } else {\r
150 PhysicalAddressBits = 36;\r
151 }\r
ab7017fe 152 }\r
153 \r
154 //\r
155 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.\r
156 //\r
157 ASSERT (PhysicalAddressBits <= 52);\r
158 if (PhysicalAddressBits > 48) {\r
159 PhysicalAddressBits = 48;\r
160 }\r
161 \r
162 //\r
b5040e4c 163 // Calculate the table entries needed.\r
ab7017fe 164 //\r
165 if (PhysicalAddressBits <= 39 ) {\r
166 NumberOfPml4EntriesNeeded = 1;\r
b5040e4c 167 NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));\r
ab7017fe 168 } else {\r
b5040e4c 169 NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));\r
ab7017fe 170 NumberOfPdpEntriesNeeded = 512;\r
171 }\r
172 \r
b5040e4c
EL
173 if (!Page1GSupport) {\r
174 TotalPagesNum = (NumberOfPdpEntriesNeeded + 1) * NumberOfPml4EntriesNeeded + 1;\r
175 } else {\r
176 TotalPagesNum = NumberOfPml4EntriesNeeded + 1;\r
177 }\r
178 \r
fd9abd04 179 LongModeBuffer.PageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedMemoryBelow4G (EFI_PAGES_TO_SIZE (TotalPagesNum));\r
ab7017fe 180 ASSERT (LongModeBuffer.PageTableAddress != 0);\r
b5040e4c 181 PcdSet64 (PcdIdentifyMappingPageTablePtr, LongModeBuffer.PageTableAddress); \r
ab7017fe 182 }\r
b5040e4c
EL
183 \r
184 //\r
185 // Allocate stack\r
186 //\r
187 LongModeBuffer.StackSize = PcdGet32 (PcdCapsulePeiLongModeStackSize);\r
fd9abd04 188 LongModeBuffer.StackBaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateReservedMemoryBelow4G (PcdGet32 (PcdCapsulePeiLongModeStackSize));\r
b5040e4c
EL
189 ASSERT (LongModeBuffer.StackBaseAddress != 0); \r
190 \r
ab7017fe 191 Status = gRT->SetVariable (\r
192 EFI_CAPSULE_LONG_MODE_BUFFER_NAME,\r
193 &gEfiCapsuleVendorGuid,\r
b5040e4c 194 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
ab7017fe 195 sizeof (EFI_CAPSULE_LONG_MODE_BUFFER),\r
196 &LongModeBuffer\r
197 );\r
b5040e4c
EL
198 if (!EFI_ERROR (Status)) {\r
199 //\r
200 // Register callback function upon VariableLockProtocol\r
201 // to lock EFI_CAPSULE_LONG_MODE_BUFFER_NAME variable to avoid malicious code to update it.\r
202 //\r
203 EfiCreateProtocolNotifyEvent (\r
204 &gEdkiiVariableLockProtocolGuid,\r
205 TPL_CALLBACK,\r
206 VariableLockCapsuleLongModeBufferVariable,\r
207 NULL,\r
208 &Registration\r
209 ); \r
210 } else {\r
211 DEBUG ((EFI_D_ERROR, "FATAL ERROR: CapsuleLongModeBuffer cannot be saved: %r. Capsule in PEI may fail!\n", Status));\r
212 gBS->FreePages (LongModeBuffer.StackBaseAddress, EFI_SIZE_TO_PAGES (LongModeBuffer.StackSize));\r
213 }\r
ab7017fe 214}\r
215\r
216/**\r
217 Create the variable to save the base address of page table and stack\r
218 for transferring into long mode in IA32 capsule PEI.\r
219**/\r
220VOID\r
221SaveLongModeContext (\r
222 VOID\r
223 )\r
224{\r
ab7017fe 225 if ((FeaturePcdGet(PcdSupportUpdateCapsuleReset)) && (FeaturePcdGet (PcdDxeIplSwitchToLongMode))) {\r
226 //\r
b5040e4c 227 // Allocate memory for Capsule IA32 PEIM, it will create page table to transfer to long mode to access capsule above 4GB.\r
ab7017fe 228 //\r
b5040e4c 229 PrepareContextForCapsulePei ();\r
ab7017fe 230 }\r
231}\r