]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/CapsuleOnDiskLoadPei/CapsuleOnDiskLoadPei.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / CapsuleOnDiskLoadPei / CapsuleOnDiskLoadPei.c
CommitLineData
c1227348
WX
1/** @file\r
2 Recovery module.\r
3\r
4 Caution: This module requires additional review when modified.\r
5 This module will have external input - Capsule-on-Disk Temp Relocation image.\r
6 This external input must be validated carefully to avoid security issue like\r
7 buffer overflow, integer overflow.\r
8\r
9 RetrieveRelocatedCapsule() will receive untrusted input and do basic validation.\r
10\r
11 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
12 SPDX-License-Identifier: BSD-2-Clause-Patent\r
13\r
14**/\r
15\r
16//\r
17// The package level header files this module uses\r
18//\r
19#include <Uefi.h>\r
20#include <PiPei.h>\r
21\r
22//\r
23// The protocols, PPI and GUID defintions for this module\r
24//\r
25#include <Ppi/MasterBootMode.h>\r
26#include <Ppi/FirmwareVolumeInfo.h>\r
27#include <Ppi/ReadOnlyVariable2.h>\r
28#include <Ppi/Capsule.h>\r
29#include <Ppi/CapsuleOnDisk.h>\r
30#include <Ppi/DeviceRecoveryModule.h>\r
31\r
32#include <Guid/FirmwareFileSystem2.h>\r
33//\r
34// The Library classes this module consumes\r
35//\r
36#include <Library/DebugLib.h>\r
37#include <Library/PeimEntryPoint.h>\r
38#include <Library/PeiServicesLib.h>\r
39#include <Library/HobLib.h>\r
40#include <Library/BaseMemoryLib.h>\r
41#include <Library/MemoryAllocationLib.h>\r
42#include <Library/PcdLib.h>\r
43#include <Library/CapsuleLib.h>\r
44#include <Library/ReportStatusCodeLib.h>\r
45\r
46/**\r
47 Loads a DXE capsule from some media into memory and updates the HOB table\r
48 with the DXE firmware volume information.\r
49\r
50 @param[in] PeiServices General-purpose services that are available to every PEIM.\r
51 @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.\r
52\r
53 @retval EFI_SUCCESS The capsule was loaded correctly.\r
54 @retval EFI_DEVICE_ERROR A device error occurred.\r
55 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.\r
56\r
57**/\r
58EFI_STATUS\r
59EFIAPI\r
60LoadCapsuleOnDisk (\r
1436aea4
MK
61 IN EFI_PEI_SERVICES **PeiServices,\r
62 IN EDKII_PEI_CAPSULE_ON_DISK_PPI *This\r
c1227348
WX
63 );\r
64\r
1436aea4 65static EDKII_PEI_CAPSULE_ON_DISK_PPI mCapsuleOnDiskPpi = {\r
c1227348
WX
66 LoadCapsuleOnDisk\r
67};\r
68\r
1436aea4 69static EFI_PEI_PPI_DESCRIPTOR mCapsuleOnDiskPpiList = {\r
c1227348
WX
70 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
71 &gEdkiiPeiCapsuleOnDiskPpiGuid,\r
72 &mCapsuleOnDiskPpi\r
73};\r
74\r
75/**\r
76 Determine if capsule comes from memory by checking Capsule PPI.\r
77\r
78 @param[in] PeiServices General purpose services available to every PEIM.\r
79\r
80 @retval TRUE Capsule comes from memory.\r
81 @retval FALSE No capsule comes from memory.\r
82\r
83**/\r
84static\r
85BOOLEAN\r
86CheckCapsuleFromRam (\r
1436aea4 87 IN CONST EFI_PEI_SERVICES **PeiServices\r
c1227348
WX
88 )\r
89{\r
1436aea4
MK
90 EFI_STATUS Status;\r
91 PEI_CAPSULE_PPI *Capsule;\r
c1227348
WX
92\r
93 Status = PeiServicesLocatePpi (\r
94 &gEfiPeiCapsulePpiGuid,\r
95 0,\r
96 NULL,\r
1436aea4 97 (VOID **)&Capsule\r
c1227348 98 );\r
1436aea4 99 if (!EFI_ERROR (Status)) {\r
c1227348 100 Status = Capsule->CheckCapsuleUpdate ((EFI_PEI_SERVICES **)PeiServices);\r
1436aea4 101 if (!EFI_ERROR (Status)) {\r
c1227348
WX
102 return TRUE;\r
103 }\r
104 }\r
105\r
106 return FALSE;\r
107}\r
108\r
109/**\r
110 Determine if it is a Capsule On Disk mode.\r
111\r
112 @retval TRUE Capsule On Disk mode.\r
113 @retval FALSE Not capsule On Disk mode.\r
114\r
115**/\r
116static\r
117BOOLEAN\r
118IsCapsuleOnDiskMode (\r
119 VOID\r
120 )\r
121{\r
1436aea4
MK
122 EFI_STATUS Status;\r
123 UINTN Size;\r
124 EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;\r
125 BOOLEAN CodRelocInfo;\r
c1227348
WX
126\r
127 Status = PeiServicesLocatePpi (\r
128 &gEfiPeiReadOnlyVariable2PpiGuid,\r
129 0,\r
130 NULL,\r
1436aea4 131 (VOID **)&PPIVariableServices\r
c1227348
WX
132 );\r
133 ASSERT_EFI_ERROR (Status);\r
134\r
1436aea4 135 Size = sizeof (BOOLEAN);\r
c1227348
WX
136 Status = PPIVariableServices->GetVariable (\r
137 PPIVariableServices,\r
138 COD_RELOCATION_INFO_VAR_NAME,\r
139 &gEfiCapsuleVendorGuid,\r
140 NULL,\r
141 &Size,\r
142 &CodRelocInfo\r
143 );\r
144\r
1436aea4
MK
145 if (EFI_ERROR (Status) || (Size != sizeof (BOOLEAN)) || !CodRelocInfo) {\r
146 DEBUG ((DEBUG_ERROR, "Error Get CodRelocationInfo variable %r!\n", Status));\r
c1227348
WX
147 return FALSE;\r
148 }\r
149\r
150 return TRUE;\r
151}\r
152\r
153/**\r
154 Gets capsule images from relocated capsule buffer.\r
155 Create Capsule hob for each Capsule.\r
156\r
157 Caution: This function may receive untrusted input.\r
158 Capsule-on-Disk Temp Relocation image is external input, so this function\r
159 will validate Capsule-on-Disk Temp Relocation image to make sure the content\r
160 is read within the buffer.\r
161\r
162 @param[in] RelocCapsuleBuf Buffer pointer to the relocated capsule.\r
163 @param[in] RelocCapsuleTotalSize Total size of the relocated capsule.\r
164\r
165 @retval EFI_SUCCESS Succeed to get capsules and create hob.\r
166 @retval Others Fail to get capsules and create hob.\r
167\r
168**/\r
169static\r
170EFI_STATUS\r
171RetrieveRelocatedCapsule (\r
1436aea4
MK
172 IN UINT8 *RelocCapsuleBuf,\r
173 IN UINTN RelocCapsuleTotalSize\r
c1227348
WX
174 )\r
175{\r
1436aea4
MK
176 UINTN Index;\r
177 UINT8 *CapsuleDataBufEnd;\r
178 UINT8 *CapsulePtr;\r
179 UINT32 CapsuleSize;\r
180 UINT64 TotalImageSize;\r
181 UINTN CapsuleNum;\r
c1227348
WX
182\r
183 //\r
184 // Temp file contains at least 2 capsule (including 1 capsule name capsule) & 1 UINT64\r
185 //\r
1436aea4 186 if (RelocCapsuleTotalSize < sizeof (UINT64) + sizeof (EFI_CAPSULE_HEADER) * 2) {\r
c1227348
WX
187 return EFI_INVALID_PARAMETER;\r
188 }\r
189\r
1436aea4 190 CopyMem (&TotalImageSize, RelocCapsuleBuf, sizeof (UINT64));\r
c1227348 191\r
1436aea4
MK
192 DEBUG ((\r
193 DEBUG_INFO,\r
194 "ProcessRelocatedCapsule CapsuleBuf %x TotalCapSize %lx\n",\r
195 RelocCapsuleBuf,\r
196 TotalImageSize\r
197 ));\r
c1227348 198\r
1436aea4 199 RelocCapsuleBuf += sizeof (UINT64);\r
c1227348
WX
200\r
201 //\r
202 // TempCaspule file length check\r
203 //\r
1436aea4
MK
204 if ((MAX_ADDRESS - TotalImageSize <= sizeof (UINT64)) ||\r
205 ((UINT64)RelocCapsuleTotalSize != TotalImageSize + sizeof (UINT64)) ||\r
206 ((UINTN)(MAX_ADDRESS - (PHYSICAL_ADDRESS)(UINTN)RelocCapsuleBuf) <= TotalImageSize))\r
207 {\r
c1227348
WX
208 return EFI_INVALID_PARAMETER;\r
209 }\r
210\r
211 CapsuleDataBufEnd = RelocCapsuleBuf + TotalImageSize;\r
212\r
213 //\r
214 // TempCapsule file integrity check over Capsule Header to ensure no data corruption in NV Var & Relocation storage\r
215 //\r
216 CapsulePtr = RelocCapsuleBuf;\r
217 CapsuleNum = 0;\r
218\r
219 while (CapsulePtr < CapsuleDataBufEnd) {\r
1436aea4
MK
220 if (((CapsuleDataBufEnd - CapsulePtr) < sizeof (EFI_CAPSULE_HEADER)) ||\r
221 (((EFI_CAPSULE_HEADER *)CapsulePtr)->CapsuleImageSize < sizeof (EFI_CAPSULE_HEADER)) ||\r
222 ((UINTN)(MAX_ADDRESS - (PHYSICAL_ADDRESS)(UINTN)CapsulePtr) < ((EFI_CAPSULE_HEADER *)CapsulePtr)->CapsuleImageSize)\r
223 )\r
224 {\r
c1227348
WX
225 break;\r
226 }\r
1436aea4 227\r
c1227348 228 CapsulePtr += ((EFI_CAPSULE_HEADER *)CapsulePtr)->CapsuleImageSize;\r
1436aea4 229 CapsuleNum++;\r
c1227348
WX
230 }\r
231\r
232 if (CapsulePtr != CapsuleDataBufEnd) {\r
233 return EFI_INVALID_PARAMETER;\r
234 }\r
235\r
236 //\r
237 // Capsule count must be less than PcdCapsuleMax, avoid building too many CvHobs to occupy all the free space in HobList.\r
238 //\r
239 if (CapsuleNum > PcdGet16 (PcdCapsuleMax)) {\r
240 return EFI_INVALID_PARAMETER;\r
241 }\r
242\r
243 //\r
244 // Re-iterate the capsule buffer to create Capsule hob & Capsule Name Str Hob for each Capsule saved in relocated capsule file\r
245 //\r
246 CapsulePtr = RelocCapsuleBuf;\r
247 Index = 0;\r
248 while (CapsulePtr < CapsuleDataBufEnd) {\r
249 CapsuleSize = ((EFI_CAPSULE_HEADER *)CapsulePtr)->CapsuleImageSize;\r
250 BuildCvHob ((EFI_PHYSICAL_ADDRESS)(UINTN)CapsulePtr, CapsuleSize);\r
251\r
1436aea4 252 DEBUG ((DEBUG_INFO, "Capsule saved in address %x size %x\n", CapsulePtr, CapsuleSize));\r
c1227348
WX
253\r
254 CapsulePtr += CapsuleSize;\r
255 Index++;\r
256 }\r
257\r
258 return EFI_SUCCESS;\r
259}\r
260\r
261/**\r
262 Recovery module entrypoint\r
263\r
264 @param[in] FileHandle Handle of the file being invoked.\r
265 @param[in] PeiServices Describes the list of possible PEI Services.\r
266\r
267 @return EFI_SUCCESS Recovery module is initialized.\r
268**/\r
269EFI_STATUS\r
270EFIAPI\r
271InitializeCapsuleOnDiskLoad (\r
272 IN EFI_PEI_FILE_HANDLE FileHandle,\r
273 IN CONST EFI_PEI_SERVICES **PeiServices\r
274 )\r
275{\r
276 EFI_STATUS Status;\r
277 UINTN BootMode;\r
278 UINTN FileNameSize;\r
279\r
1436aea4
MK
280 BootMode = GetBootModeHob ();\r
281 ASSERT (BootMode == BOOT_ON_FLASH_UPDATE);\r
c1227348
WX
282\r
283 //\r
284 // If there are capsules provisioned in memory, quit.\r
285 // Only one capsule resource is accept, CapsuleOnRam's priority is higher than CapsuleOnDisk.\r
286 //\r
1436aea4
MK
287 if (CheckCapsuleFromRam (PeiServices)) {\r
288 DEBUG ((DEBUG_ERROR, "Capsule On Memory Detected! Quit.\n"));\r
c1227348
WX
289 return EFI_ABORTED;\r
290 }\r
291\r
db52c7f7 292 DEBUG_CODE_BEGIN ();\r
1436aea4 293 VOID *CapsuleOnDiskModePpi;\r
c1227348 294\r
1436aea4 295 if (!IsCapsuleOnDiskMode ()) {\r
c1227348
WX
296 return EFI_NOT_FOUND;\r
297 }\r
298\r
299 //\r
300 // Check Capsule On Disk Relocation flag. If exists, load capsule & create Capsule Hob\r
301 //\r
302 Status = PeiServicesLocatePpi (\r
303 &gEdkiiPeiBootInCapsuleOnDiskModePpiGuid,\r
304 0,\r
305 NULL,\r
306 (VOID **)&CapsuleOnDiskModePpi\r
307 );\r
1436aea4
MK
308 if (EFI_ERROR (Status)) {\r
309 DEBUG ((DEBUG_ERROR, "Locate CapsuleOnDiskModePpi error %x\n", Status));\r
310 return Status;\r
311 }\r
312\r
db52c7f7 313 DEBUG_CODE_END ();\r
c1227348
WX
314\r
315 Status = PeiServicesInstallPpi (&mCapsuleOnDiskPpiList);\r
316 ASSERT_EFI_ERROR (Status);\r
317\r
318 FileNameSize = PcdGetSize (PcdCoDRelocationFileName);\r
1436aea4 319 Status = PcdSetPtrS (PcdRecoveryFileName, &FileNameSize, (VOID *)PcdGetPtr (PcdCoDRelocationFileName));\r
c1227348
WX
320 ASSERT_EFI_ERROR (Status);\r
321\r
322 return Status;\r
323}\r
324\r
325/**\r
326 Loads a DXE capsule from some media into memory and updates the HOB table\r
327 with the DXE firmware volume information.\r
328\r
329 @param[in] PeiServices General-purpose services that are available to every PEIM.\r
330 @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.\r
331\r
332 @retval EFI_SUCCESS The capsule was loaded correctly.\r
333 @retval EFI_DEVICE_ERROR A device error occurred.\r
334 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.\r
335\r
336**/\r
337EFI_STATUS\r
338EFIAPI\r
339LoadCapsuleOnDisk (\r
1436aea4
MK
340 IN EFI_PEI_SERVICES **PeiServices,\r
341 IN EDKII_PEI_CAPSULE_ON_DISK_PPI *This\r
c1227348
WX
342 )\r
343{\r
344 EFI_STATUS Status;\r
345 EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *DeviceRecoveryPpi;\r
346 UINTN NumberRecoveryCapsules;\r
347 UINTN Instance;\r
348 UINTN CapsuleInstance;\r
349 UINTN CapsuleSize;\r
350 EFI_GUID CapsuleType;\r
351 VOID *CapsuleBuffer;\r
352\r
353 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Load Capsule On Disk Entry\n"));\r
354\r
355 for (Instance = 0; ; Instance++) {\r
356 Status = PeiServicesLocatePpi (\r
357 &gEfiPeiDeviceRecoveryModulePpiGuid,\r
358 Instance,\r
359 NULL,\r
360 (VOID **)&DeviceRecoveryPpi\r
361 );\r
362 DEBUG ((DEBUG_INFO, "LoadCapsuleOnDisk - LocateRecoveryPpi (%d) - %r\n", Instance, Status));\r
363 if (EFI_ERROR (Status)) {\r
364 if (Instance == 0) {\r
365 REPORT_STATUS_CODE (\r
366 EFI_ERROR_CODE | EFI_ERROR_MAJOR,\r
367 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_RECOVERY_PPI_NOT_FOUND)\r
368 );\r
369 }\r
1436aea4 370\r
c1227348
WX
371 break;\r
372 }\r
1436aea4 373\r
c1227348 374 NumberRecoveryCapsules = 0;\r
1436aea4
MK
375 Status = DeviceRecoveryPpi->GetNumberRecoveryCapsules (\r
376 (EFI_PEI_SERVICES **)PeiServices,\r
377 DeviceRecoveryPpi,\r
378 &NumberRecoveryCapsules\r
379 );\r
c1227348
WX
380 DEBUG ((DEBUG_INFO, "LoadCapsuleOnDisk - GetNumberRecoveryCapsules (%d) - %r\n", NumberRecoveryCapsules, Status));\r
381 if (EFI_ERROR (Status)) {\r
382 continue;\r
383 }\r
384\r
385 for (CapsuleInstance = 1; CapsuleInstance <= NumberRecoveryCapsules; CapsuleInstance++) {\r
386 CapsuleSize = 0;\r
1436aea4
MK
387 Status = DeviceRecoveryPpi->GetRecoveryCapsuleInfo (\r
388 (EFI_PEI_SERVICES **)PeiServices,\r
389 DeviceRecoveryPpi,\r
390 CapsuleInstance,\r
391 &CapsuleSize,\r
392 &CapsuleType\r
393 );\r
c1227348
WX
394 DEBUG ((DEBUG_INFO, "LoadCapsuleOnDisk - GetRecoveryCapsuleInfo (%d - %x) - %r\n", CapsuleInstance, CapsuleSize, Status));\r
395 if (EFI_ERROR (Status)) {\r
396 break;\r
397 }\r
398\r
399 //\r
400 // Allocate the memory so that it gets preserved into DXE.\r
401 // Capsule is special because it may need to populate to system table\r
402 //\r
403 CapsuleBuffer = AllocateRuntimePages (EFI_SIZE_TO_PAGES (CapsuleSize));\r
404\r
405 if (CapsuleBuffer == NULL) {\r
406 DEBUG ((DEBUG_ERROR, "LoadCapsuleOnDisk - AllocateRuntimePages fail\n"));\r
407 continue;\r
408 }\r
409\r
410 Status = DeviceRecoveryPpi->LoadRecoveryCapsule (\r
411 (EFI_PEI_SERVICES **)PeiServices,\r
412 DeviceRecoveryPpi,\r
413 CapsuleInstance,\r
414 CapsuleBuffer\r
415 );\r
416 DEBUG ((DEBUG_INFO, "LoadCapsuleOnDisk - LoadRecoveryCapsule (%d) - %r\n", CapsuleInstance, Status));\r
417 if (EFI_ERROR (Status)) {\r
1436aea4 418 FreePages (CapsuleBuffer, EFI_SIZE_TO_PAGES (CapsuleSize));\r
c1227348
WX
419 break;\r
420 }\r
421\r
422 //\r
423 // Capsule Update Mode, Split relocated Capsule buffer into different capsule vehical hobs.\r
424 //\r
1436aea4 425 Status = RetrieveRelocatedCapsule (CapsuleBuffer, CapsuleSize);\r
c1227348
WX
426\r
427 break;\r
428 }\r
429\r
430 if (EFI_ERROR (Status)) {\r
431 REPORT_STATUS_CODE (\r
432 EFI_ERROR_CODE | EFI_ERROR_MAJOR,\r
433 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_NO_RECOVERY_CAPSULE)\r
434 );\r
435 }\r
436\r
437 return Status;\r
438 }\r
439\r
440 //\r
441 // Any attack against GPT, Relocation Info Variable or temp relocation file will result in no Capsule HOB and return EFI_NOT_FOUND.\r
442 // After flow to DXE phase. since no capsule hob is detected. Platform will clear Info flag and force restart.\r
443 // No volunerability will be exposed\r
444 //\r
445\r
446 return EFI_NOT_FOUND;\r
447}\r