TianoCore EDK2 master
Loading...
Searching...
No Matches
CapsuleOnDiskLoadPei.c
Go to the documentation of this file.
1
16//
17// The package level header files this module uses
18//
19#include <Uefi.h>
20#include <PiPei.h>
21
22//
23// The protocols, PPI and GUID defintions for this module
24//
25#include <Ppi/MasterBootMode.h>
28#include <Ppi/Capsule.h>
29#include <Ppi/CapsuleOnDisk.h>
31
33//
34// The Library classes this module consumes
35//
36#include <Library/DebugLib.h>
39#include <Library/HobLib.h>
42#include <Library/PcdLib.h>
43#include <Library/CapsuleLib.h>
45
59EFIAPI
61 IN EFI_PEI_SERVICES **PeiServices,
63 );
64
65static EDKII_PEI_CAPSULE_ON_DISK_PPI mCapsuleOnDiskPpi = {
67};
68
69static EFI_PEI_PPI_DESCRIPTOR mCapsuleOnDiskPpiList = {
70 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
71 &gEdkiiPeiCapsuleOnDiskPpiGuid,
72 &mCapsuleOnDiskPpi
73};
74
84static
85BOOLEAN
86CheckCapsuleFromRam (
87 IN CONST EFI_PEI_SERVICES **PeiServices
88 )
89{
90 EFI_STATUS Status;
91 PEI_CAPSULE_PPI *Capsule;
92
93 Status = PeiServicesLocatePpi (
94 &gEfiPeiCapsulePpiGuid,
95 0,
96 NULL,
97 (VOID **)&Capsule
98 );
99 if (!EFI_ERROR (Status)) {
100 Status = Capsule->CheckCapsuleUpdate ((EFI_PEI_SERVICES **)PeiServices);
101 if (!EFI_ERROR (Status)) {
102 return TRUE;
103 }
104 }
105
106 return FALSE;
107}
108
116static
117BOOLEAN
118IsCapsuleOnDiskMode (
119 VOID
120 )
121{
122 EFI_STATUS Status;
123 UINTN Size;
124 EFI_PEI_READ_ONLY_VARIABLE2_PPI *PPIVariableServices;
125 BOOLEAN CodRelocInfo;
126
127 Status = PeiServicesLocatePpi (
128 &gEfiPeiReadOnlyVariable2PpiGuid,
129 0,
130 NULL,
131 (VOID **)&PPIVariableServices
132 );
133 ASSERT_EFI_ERROR (Status);
134
135 Size = sizeof (BOOLEAN);
136 Status = PPIVariableServices->GetVariable (
137 PPIVariableServices,
138 COD_RELOCATION_INFO_VAR_NAME,
139 &gEfiCapsuleVendorGuid,
140 NULL,
141 &Size,
142 &CodRelocInfo
143 );
144
145 if (EFI_ERROR (Status) || (Size != sizeof (BOOLEAN)) || !CodRelocInfo) {
146 DEBUG ((DEBUG_ERROR, "Error Get CodRelocationInfo variable %r!\n", Status));
147 return FALSE;
148 }
149
150 return TRUE;
151}
152
169static
171RetrieveRelocatedCapsule (
172 IN UINT8 *RelocCapsuleBuf,
173 IN UINTN RelocCapsuleTotalSize
174 )
175{
176 UINTN Index;
177 UINT8 *CapsuleDataBufEnd;
178 UINT8 *CapsulePtr;
179 UINT32 CapsuleSize;
180 UINT64 TotalImageSize;
181 UINTN CapsuleNum;
182
183 //
184 // Temp file contains at least 2 capsule (including 1 capsule name capsule) & 1 UINT64
185 //
186 if (RelocCapsuleTotalSize < sizeof (UINT64) + sizeof (EFI_CAPSULE_HEADER) * 2) {
187 return EFI_INVALID_PARAMETER;
188 }
189
190 CopyMem (&TotalImageSize, RelocCapsuleBuf, sizeof (UINT64));
191
192 DEBUG ((
193 DEBUG_INFO,
194 "ProcessRelocatedCapsule CapsuleBuf %x TotalCapSize %lx\n",
195 RelocCapsuleBuf,
196 TotalImageSize
197 ));
198
199 RelocCapsuleBuf += sizeof (UINT64);
200
201 //
202 // TempCaspule file length check
203 //
204 if ((MAX_ADDRESS - TotalImageSize <= sizeof (UINT64)) ||
205 ((UINT64)RelocCapsuleTotalSize != TotalImageSize + sizeof (UINT64)) ||
206 ((UINTN)(MAX_ADDRESS - (PHYSICAL_ADDRESS)(UINTN)RelocCapsuleBuf) <= TotalImageSize))
207 {
208 return EFI_INVALID_PARAMETER;
209 }
210
211 CapsuleDataBufEnd = RelocCapsuleBuf + TotalImageSize;
212
213 //
214 // TempCapsule file integrity check over Capsule Header to ensure no data corruption in NV Var & Relocation storage
215 //
216 CapsulePtr = RelocCapsuleBuf;
217 CapsuleNum = 0;
218
219 while (CapsulePtr < CapsuleDataBufEnd) {
220 if (((CapsuleDataBufEnd - CapsulePtr) < sizeof (EFI_CAPSULE_HEADER)) ||
221 (((EFI_CAPSULE_HEADER *)CapsulePtr)->CapsuleImageSize < sizeof (EFI_CAPSULE_HEADER)) ||
222 ((UINTN)(MAX_ADDRESS - (PHYSICAL_ADDRESS)(UINTN)CapsulePtr) < ((EFI_CAPSULE_HEADER *)CapsulePtr)->CapsuleImageSize)
223 )
224 {
225 break;
226 }
227
228 CapsulePtr += ((EFI_CAPSULE_HEADER *)CapsulePtr)->CapsuleImageSize;
229 CapsuleNum++;
230 }
231
232 if (CapsulePtr != CapsuleDataBufEnd) {
233 return EFI_INVALID_PARAMETER;
234 }
235
236 //
237 // Capsule count must be less than PcdCapsuleMax, avoid building too many CvHobs to occupy all the free space in HobList.
238 //
239 if (CapsuleNum > PcdGet16 (PcdCapsuleMax)) {
240 return EFI_INVALID_PARAMETER;
241 }
242
243 //
244 // Re-iterate the capsule buffer to create Capsule hob & Capsule Name Str Hob for each Capsule saved in relocated capsule file
245 //
246 CapsulePtr = RelocCapsuleBuf;
247 Index = 0;
248 while (CapsulePtr < CapsuleDataBufEnd) {
249 CapsuleSize = ((EFI_CAPSULE_HEADER *)CapsulePtr)->CapsuleImageSize;
250 BuildCvHob ((EFI_PHYSICAL_ADDRESS)(UINTN)CapsulePtr, CapsuleSize);
251
252 DEBUG ((DEBUG_INFO, "Capsule saved in address %x size %x\n", CapsulePtr, CapsuleSize));
253
254 CapsulePtr += CapsuleSize;
255 Index++;
256 }
257
258 return EFI_SUCCESS;
259}
260
270EFIAPI
272 IN EFI_PEI_FILE_HANDLE FileHandle,
273 IN CONST EFI_PEI_SERVICES **PeiServices
274 )
275{
276 EFI_STATUS Status;
277 UINTN BootMode;
278 UINTN FileNameSize;
279
280 BootMode = GetBootModeHob ();
281 ASSERT (BootMode == BOOT_ON_FLASH_UPDATE);
282
283 //
284 // If there are capsules provisioned in memory, quit.
285 // Only one capsule resource is accept, CapsuleOnRam's priority is higher than CapsuleOnDisk.
286 //
287 if (CheckCapsuleFromRam (PeiServices)) {
288 DEBUG ((DEBUG_ERROR, "Capsule On Memory Detected! Quit.\n"));
289 return EFI_ABORTED;
290 }
291
293 VOID *CapsuleOnDiskModePpi;
294
295 if (!IsCapsuleOnDiskMode ()) {
296 return EFI_NOT_FOUND;
297 }
298
299 //
300 // Check Capsule On Disk Relocation flag. If exists, load capsule & create Capsule Hob
301 //
302 Status = PeiServicesLocatePpi (
303 &gEdkiiPeiBootInCapsuleOnDiskModePpiGuid,
304 0,
305 NULL,
306 (VOID **)&CapsuleOnDiskModePpi
307 );
308 if (EFI_ERROR (Status)) {
309 DEBUG ((DEBUG_ERROR, "Locate CapsuleOnDiskModePpi error %x\n", Status));
310 return Status;
311 }
312
314
315 Status = PeiServicesInstallPpi (&mCapsuleOnDiskPpiList);
316 ASSERT_EFI_ERROR (Status);
317
318 FileNameSize = PcdGetSize (PcdCoDRelocationFileName);
319 Status = PcdSetPtrS (PcdRecoveryFileName, &FileNameSize, (VOID *)PcdGetPtr (PcdCoDRelocationFileName));
320 ASSERT_EFI_ERROR (Status);
321
322 return Status;
323}
324
338EFIAPI
340 IN EFI_PEI_SERVICES **PeiServices,
342 )
343{
344 EFI_STATUS Status;
345 EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *DeviceRecoveryPpi;
346 UINTN NumberRecoveryCapsules;
347 UINTN Instance;
348 UINTN CapsuleInstance;
349 UINTN CapsuleSize;
350 EFI_GUID CapsuleType;
351 VOID *CapsuleBuffer;
352
353 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Load Capsule On Disk Entry\n"));
354
355 for (Instance = 0; ; Instance++) {
356 Status = PeiServicesLocatePpi (
357 &gEfiPeiDeviceRecoveryModulePpiGuid,
358 Instance,
359 NULL,
360 (VOID **)&DeviceRecoveryPpi
361 );
362 DEBUG ((DEBUG_INFO, "LoadCapsuleOnDisk - LocateRecoveryPpi (%d) - %r\n", Instance, Status));
363 if (EFI_ERROR (Status)) {
364 if (Instance == 0) {
366 EFI_ERROR_CODE | EFI_ERROR_MAJOR,
367 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_RECOVERY_PPI_NOT_FOUND)
368 );
369 }
370
371 break;
372 }
373
374 NumberRecoveryCapsules = 0;
375 Status = DeviceRecoveryPpi->GetNumberRecoveryCapsules (
376 (EFI_PEI_SERVICES **)PeiServices,
377 DeviceRecoveryPpi,
378 &NumberRecoveryCapsules
379 );
380 DEBUG ((DEBUG_INFO, "LoadCapsuleOnDisk - GetNumberRecoveryCapsules (%d) - %r\n", NumberRecoveryCapsules, Status));
381 if (EFI_ERROR (Status)) {
382 continue;
383 }
384
385 for (CapsuleInstance = 1; CapsuleInstance <= NumberRecoveryCapsules; CapsuleInstance++) {
386 CapsuleSize = 0;
387 Status = DeviceRecoveryPpi->GetRecoveryCapsuleInfo (
388 (EFI_PEI_SERVICES **)PeiServices,
389 DeviceRecoveryPpi,
390 CapsuleInstance,
391 &CapsuleSize,
392 &CapsuleType
393 );
394 DEBUG ((DEBUG_INFO, "LoadCapsuleOnDisk - GetRecoveryCapsuleInfo (%d - %x) - %r\n", CapsuleInstance, CapsuleSize, Status));
395 if (EFI_ERROR (Status)) {
396 break;
397 }
398
399 //
400 // Allocate the memory so that it gets preserved into DXE.
401 // Capsule is special because it may need to populate to system table
402 //
403 CapsuleBuffer = AllocateRuntimePages (EFI_SIZE_TO_PAGES (CapsuleSize));
404
405 if (CapsuleBuffer == NULL) {
406 DEBUG ((DEBUG_ERROR, "LoadCapsuleOnDisk - AllocateRuntimePages fail\n"));
407 continue;
408 }
409
410 Status = DeviceRecoveryPpi->LoadRecoveryCapsule (
411 (EFI_PEI_SERVICES **)PeiServices,
412 DeviceRecoveryPpi,
413 CapsuleInstance,
414 CapsuleBuffer
415 );
416 DEBUG ((DEBUG_INFO, "LoadCapsuleOnDisk - LoadRecoveryCapsule (%d) - %r\n", CapsuleInstance, Status));
417 if (EFI_ERROR (Status)) {
418 FreePages (CapsuleBuffer, EFI_SIZE_TO_PAGES (CapsuleSize));
419 break;
420 }
421
422 //
423 // Capsule Update Mode, Split relocated Capsule buffer into different capsule vehical hobs.
424 //
425 Status = RetrieveRelocatedCapsule (CapsuleBuffer, CapsuleSize);
426
427 break;
428 }
429
430 if (EFI_ERROR (Status)) {
432 EFI_ERROR_CODE | EFI_ERROR_MAJOR,
433 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_NO_RECOVERY_CAPSULE)
434 );
435 }
436
437 return Status;
438 }
439
440 //
441 // Any attack against GPT, Relocation Info Variable or temp relocation file will result in no Capsule HOB and return EFI_NOT_FOUND.
442 // After flow to DXE phase. since no capsule hob is detected. Platform will clear Info flag and force restart.
443 // No volunerability will be exposed
444 //
445
446 return EFI_NOT_FOUND;
447}
UINT64 UINTN
#define MAX_ADDRESS
VOID EFIAPI BuildCvHob(IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length)
Definition: HobLib.c:494
EFI_BOOT_MODE EFIAPI GetBootModeHob(VOID)
Definition: HobLib.c:240
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
EFI_STATUS EFIAPI LoadCapsuleOnDisk(IN EFI_PEI_SERVICES **PeiServices, IN EDKII_PEI_CAPSULE_ON_DISK_PPI *This)
EFI_STATUS EFIAPI InitializeCapsuleOnDiskLoad(IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices)
VOID EFIAPI FreePages(IN VOID *Buffer, IN UINTN Pages)
EFI_STATUS EFIAPI PeiServicesLocatePpi(IN CONST EFI_GUID *Guid, IN UINTN Instance, IN OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor, IN OUT VOID **Ppi)
EFI_STATUS EFIAPI PeiServicesInstallPpi(IN CONST EFI_PEI_PPI_DESCRIPTOR *PpiList)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#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_CODE_BEGIN()
Definition: DebugLib.h:564
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define DEBUG_CODE_END()
Definition: DebugLib.h:578
#define REPORT_STATUS_CODE(Type, Value)
#define PcdGet16(TokenName)
Definition: PcdLib.h:349
#define PcdGetSize(TokenName)
Definition: PcdLib.h:440
#define PcdSetPtrS(TokenName, SizeOfBuffer, Buffer)
Definition: PcdLib.h:534
#define PcdGetPtr(TokenName)
Definition: PcdLib.h:388
VOID * EFI_PEI_FILE_HANDLE
Definition: PiPeiCis.h:26
#define EFI_SW_PEI_EC_NO_RECOVERY_CAPSULE
VOID *EFIAPI AllocateRuntimePages(IN UINTN Pages)
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
Definition: Base.h:213