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