]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/FlashUpdate.c
IntelFrameworkModulePkg: Clean up source files
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / FirmwareVolume / UpdateDriverDxe / FlashUpdate.c
CommitLineData
b2824a8e 1/** @file\r
2 Functions in this file will program the image into flash area.\r
3\r
0a6f4824 4 Copyright (c) 2002 - 2018, Intel Corporation. All rights reserved.<BR>\r
b2824a8e 5\r
6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions\r
8 of the BSD License which accompanies this distribution. The\r
9 full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "UpdateDriver.h"\r
18\r
19/**\r
20 Write a block size data into flash.\r
21\r
22 @param FvbProtocol Pointer to FVB protocol.\r
23 @param Lba Logic block index to be updated.\r
24 @param BlockSize Block size\r
25 @param Buffer Buffer data to be written.\r
26\r
27 @retval EFI_SUCCESS Write data successfully.\r
28 @retval other errors Write data failed.\r
29\r
30**/\r
31EFI_STATUS\r
32UpdateOneBlock (\r
33 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,\r
34 IN EFI_LBA Lba,\r
35 IN UINTN BlockSize,\r
36 IN UINT8 *Buffer\r
37 )\r
38{\r
39 EFI_STATUS Status;\r
40 UINTN Size;\r
41\r
42 //\r
43 // First erase the block\r
44 //\r
45 Status = FvbProtocol->EraseBlocks (\r
46 FvbProtocol,\r
47 Lba, // Lba\r
48 1, // NumOfBlocks\r
49 EFI_LBA_LIST_TERMINATOR\r
50 );\r
51 if (EFI_ERROR (Status)) {\r
52 return Status;\r
53 }\r
54\r
55 //\r
56 // Write the block\r
57 //\r
58 Size = BlockSize;\r
59 Status = FvbProtocol->Write (\r
60 FvbProtocol,\r
61 Lba, // Lba\r
62 0, // Offset\r
63 &Size, // Size\r
64 Buffer // Buffer\r
65 );\r
66 if ((EFI_ERROR (Status)) || (Size != BlockSize)) {\r
67 return Status;\r
68 }\r
69\r
70 return EFI_SUCCESS;\r
71}\r
72\r
73/**\r
74 Write buffer data in a flash block.\r
75\r
76 @param FvbProtocol Pointer to FVB protocol.\r
77 @param Lba Logic block index to be updated.\r
78 @param Offset The offset within the block.\r
79 @param Length Size of buffer to be updated.\r
80 @param BlockSize Block size.\r
81 @param Buffer Buffer data to be updated.\r
82\r
83 @retval EFI_SUCCESS Write data successfully.\r
84 @retval other errors Write data failed.\r
85\r
86**/\r
87EFI_STATUS\r
88UpdateBufferInOneBlock (\r
89 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,\r
90 IN EFI_LBA Lba,\r
91 IN UINTN Offset,\r
92 IN UINTN Length,\r
93 IN UINTN BlockSize,\r
94 IN UINT8 *Buffer\r
95 )\r
96{\r
97 EFI_STATUS Status;\r
98 UINTN Size;\r
99 UINT8 *ReservedBuffer;\r
100\r
101 //\r
102 // If we are going to update a whole block\r
103 //\r
104 if ((Offset == 0) && (Length == BlockSize)) {\r
105 Status = UpdateOneBlock (\r
106 FvbProtocol,\r
107 Lba,\r
108 BlockSize,\r
109 Buffer\r
110 );\r
111 return Status;\r
112 }\r
113\r
114 //\r
115 // If it is not a full block update, we need to coalesce data in\r
116 // the block that is not going to be updated and new data together.\r
117 //\r
118\r
119 //\r
120 // Allocate a reserved buffer to make up the final buffer for update\r
121 //\r
122 ReservedBuffer = NULL;\r
123 ReservedBuffer = AllocatePool (BlockSize);\r
124 if (ReservedBuffer == NULL) {\r
125 return EFI_OUT_OF_RESOURCES;\r
126 }\r
127 //\r
128 // First get the original content of the block\r
129 //\r
130 Size = BlockSize;\r
131 Status = FvbProtocol->Read (\r
132 FvbProtocol,\r
133 Lba,\r
134 0,\r
135 &Size,\r
136 ReservedBuffer\r
137 );\r
138 if ((EFI_ERROR (Status)) || (Size != BlockSize)) {\r
139 FreePool (ReservedBuffer);\r
140 return Status;\r
141 }\r
142\r
143 //\r
144 // Overwrite the reserved buffer with new content\r
145 //\r
146 CopyMem (ReservedBuffer + Offset, Buffer, Length);\r
147\r
148 Status = UpdateOneBlock (\r
149 FvbProtocol,\r
150 Lba,\r
151 BlockSize,\r
152 ReservedBuffer\r
153 );\r
154\r
155 FreePool (ReservedBuffer);\r
156\r
157 return Status;\r
158}\r
159\r
160/**\r
161 Get the last write log, and check the status of last write.\r
162 If not complete, restart will be taken.\r
163\r
164 @param FvbHandle Handle of FVB protocol.\r
165 @param FtwProtocol FTW protocol instance.\r
166 @param ConfigData Config data on updating driver.\r
167 @param PrivateDataSize bytes from the private data\r
168 stored for this write.\r
169 @param PrivateData A pointer to a buffer. The function will copy.\r
170 @param Lba The logical block address of the last write.\r
171 @param Offset The offset within the block of the last write.\r
172 @param Length The length of the last write.\r
173 @param Pending A Boolean value with TRUE indicating\r
174 that the write was completed.\r
175\r
176 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.\r
177 @retval EFI_ABORTED The FTW work space is damaged.\r
178 @retval EFI_NOT_FOUND The last write is not done by this driver.\r
179 @retval EFI_SUCCESS Last write log is got.\r
180\r
181**/\r
182EFI_STATUS\r
183RetrieveLastWrite (\r
184 IN EFI_HANDLE FvbHandle,\r
185 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol,\r
186 IN UPDATE_CONFIG_DATA *ConfigData,\r
187 IN UINTN PrivateDataSize,\r
188 IN OUT UPDATE_PRIVATE_DATA *PrivateData,\r
189 IN OUT EFI_LBA *Lba,\r
190 IN OUT UINTN *Offset,\r
191 IN OUT UINTN *Length,\r
192 IN OUT BOOLEAN *Pending\r
193 )\r
194{\r
195 EFI_STATUS Status;\r
196 EFI_GUID CallerId;\r
197 UINTN PrivateBufferSize;\r
198 BOOLEAN Complete;\r
199 VOID *PrivateDataBuffer;\r
200\r
201 //\r
202 // Get the last write\r
203 //\r
204 *Pending = FALSE;\r
205 PrivateBufferSize = PrivateDataSize;\r
206 PrivateDataBuffer = NULL;\r
207 Status = FtwProtocol->GetLastWrite (\r
208 FtwProtocol,\r
209 &CallerId,\r
210 Lba,\r
211 Offset,\r
212 Length,\r
213 &PrivateBufferSize,\r
214 PrivateData,\r
215 &Complete\r
216 );\r
217 if (EFI_ERROR (Status)) {\r
218 //\r
219 // If there is no incompleted record, return success.\r
220 //\r
221 if ((Status == EFI_NOT_FOUND) && Complete) {\r
222 return EFI_SUCCESS;\r
223 } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
224 //\r
225 // If buffer too small, reallocate buffer and call getlastwrite again\r
226 //\r
227 PrivateDataBuffer = AllocatePool (PrivateBufferSize);\r
228\r
229 if (PrivateDataBuffer == NULL) {\r
230 return EFI_OUT_OF_RESOURCES;\r
231 }\r
232\r
233 Status = FtwProtocol->GetLastWrite (\r
234 FtwProtocol,\r
235 &CallerId,\r
236 Lba,\r
237 Offset,\r
238 Length,\r
239 &PrivateBufferSize,\r
240 PrivateDataBuffer,\r
241 &Complete\r
242 );\r
243 if (EFI_ERROR (Status)) {\r
244 FreePool ( PrivateDataBuffer);\r
245 return EFI_ABORTED;\r
246 } else {\r
247 CopyMem (PrivateData, PrivateDataBuffer, PrivateDataSize);\r
248 FreePool (PrivateDataBuffer);\r
249 PrivateDataBuffer = NULL;\r
250 }\r
251 } else {\r
252 return EFI_ABORTED;\r
253 }\r
254 }\r
255\r
256 *Pending = TRUE;\r
257\r
258 //\r
259 // If the caller is not the update driver, then return.\r
260 // The update driver cannot continue to perform the update\r
261 //\r
262 if (CompareMem (&CallerId, &gEfiCallerIdGuid, sizeof (EFI_GUID)) != 0) {\r
263 return EFI_NOT_FOUND;\r
264 }\r
265\r
266 //\r
267 // Check the private data and see if it is the one I need.\r
268 //\r
269 if (CompareMem (&(PrivateData->FileGuid), &(ConfigData->FileGuid), sizeof(EFI_GUID)) != 0) {\r
270 return EFI_NOT_FOUND;\r
271 }\r
272\r
273 //\r
274 // If the caller is the update driver and complete is not true, then restart().\r
275 //\r
276 if (!Complete) {\r
277 //\r
278 // Re-start the update\r
279 //\r
280 Status = FtwProtocol->Restart (\r
281 FtwProtocol,\r
282 FvbHandle\r
283 );\r
284 //\r
285 // If restart() error, then abort().\r
286 //\r
287 if (EFI_ERROR (Status)) {\r
288 FtwProtocol->Abort (FtwProtocol);\r
289 //\r
290 // Now set Pending as FALSE as this record has been cleared\r
291 //\r
292 *Pending = FALSE;\r
293 return EFI_SUCCESS;\r
294 }\r
295\r
296 }\r
297\r
298 return Status;\r
299}\r
300\r
301/**\r
302 Update the whole FV image in fault tolerant write method.\r
303\r
304 @param FvbHandle Handle of FVB protocol for the updated flash range.\r
305 @param FvbProtocol FVB protocol.\r
306 @param BlockMap Block array to specify flash area.\r
307 @param ConfigData Config data on updating driver.\r
308 @param ImageBuffer Image buffer to be updated.\r
309 @param ImageSize Image size.\r
310\r
311 @retval EFI_SUCCESS FV image is writed into flash.\r
312 @retval EFI_INVALID_PARAMETER Config data is not valid.\r
313 @retval EFI_NOT_FOUND FTW protocol doesn't exist.\r
314 @retval EFI_OUT_OF_RESOURCES No enough backup space.\r
315 @retval EFI_ABORTED Error happen when update FV.\r
316\r
317**/\r
318EFI_STATUS\r
319FaultTolerantUpdateOnWholeFv (\r
320 IN EFI_HANDLE FvbHandle,\r
321 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,\r
322 IN EFI_FV_BLOCK_MAP_ENTRY *BlockMap,\r
323 IN UPDATE_CONFIG_DATA *ConfigData,\r
324 IN UINT8 *ImageBuffer,\r
325 IN UINTN ImageSize\r
326 )\r
327{\r
328 EFI_STATUS Status;\r
329 EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;\r
330 UINTN MaxBlockSize;\r
331 UINTN FtwMaxBlockSize;\r
332 BOOLEAN Pending;\r
333 UPDATE_PRIVATE_DATA PrivateData;\r
334 EFI_LBA PendingLba;\r
335 EFI_LBA Lba;\r
336 UINTN PendingOffset;\r
337 UINTN Offset;\r
338 UINTN PendingLength;\r
339 UINTN Length;\r
340 EFI_FV_BLOCK_MAP_ENTRY *PtrMap;\r
341 UINTN NumOfBlocks;\r
342 UINTN Index;\r
343 UINT8 *UpdateBuffer;\r
344\r
345 if ((ConfigData->UpdateType != UpdateWholeFV)\r
346 || (!ConfigData->FaultTolerant)) {\r
347 return EFI_INVALID_PARAMETER;\r
348 }\r
349\r
350 //\r
351 // Get the FTW protocol\r
352 //\r
353 Status = gBS->LocateProtocol (\r
354 &gEfiFaultTolerantWriteProtocolGuid,\r
355 NULL,\r
356 (VOID **) &FtwProtocol\r
357 );\r
358 if (EFI_ERROR (Status)) {\r
359 return EFI_NOT_FOUND;\r
360 }\r
361\r
362 //\r
363 // Get the maximum block size of the FV, and number of blocks\r
364 // NumOfBlocks will be the NumOfUdpates.\r
365 //\r
366 MaxBlockSize = 0;\r
367 NumOfBlocks = 0;\r
368 PtrMap = BlockMap;\r
369 while (TRUE) {\r
370 if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {\r
371 break;\r
372 }\r
373 if (MaxBlockSize < PtrMap->Length) {\r
374 MaxBlockSize = PtrMap->Length;\r
375 }\r
376 NumOfBlocks = NumOfBlocks + PtrMap->NumBlocks;\r
377 PtrMap++;\r
378 }\r
379\r
380 FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);\r
381 //\r
382 // Not enough backup space. return directly\r
383 //\r
384 if (FtwMaxBlockSize < MaxBlockSize) {\r
385 return EFI_OUT_OF_RESOURCES;\r
386 }\r
387\r
388 PendingLba = 0;\r
389 PendingOffset = 0;\r
390 PendingLength = 0;\r
391 Pending = FALSE;\r
392\r
393 //\r
394 // Fault Tolerant Write can only support actual fault tolerance if the write\r
395 // is a reclaim operation, which means the data buffer (new and old) are\r
396 // acutally both stored in flash. But for component update write, the data\r
397 // are now in memory. So we cannot actually recover the data after power\r
398 // failure.\r
399 //\r
400 Status = RetrieveLastWrite (\r
401 FvbHandle,\r
402 FtwProtocol,\r
403 ConfigData,\r
404 sizeof (UPDATE_PRIVATE_DATA),\r
405 &PrivateData,\r
406 &PendingLba,\r
407 &PendingOffset,\r
408 &PendingLength,\r
409 &Pending\r
410 );\r
411\r
412 if (Pending && (Status == EFI_NOT_FOUND)) {\r
413 //\r
414 // Cannot continue with the write operation\r
415 //\r
416 return EFI_ABORTED;\r
417 }\r
418\r
419 if (EFI_ERROR(Status)) {\r
420 return EFI_ABORTED;\r
421 }\r
422\r
423 //\r
424 // Currently we start from the pending write if there is any. But as we\r
425 // are going to update a whole FV, we can just abort last write and start\r
426 // from the very begining.\r
427 //\r
428 if (!Pending) {\r
429 //\r
430 // Now allocte the update private data in FTW. If there is pending\r
431 // write, it has already been allocated and no need to allocate here.\r
432 //\r
433 Status = FtwProtocol->Allocate (\r
434 FtwProtocol,\r
435 &gEfiCallerIdGuid,\r
436 sizeof (UPDATE_PRIVATE_DATA),\r
437 NumOfBlocks\r
438 );\r
439 if (EFI_ERROR (Status)) {\r
440 return Status;\r
441 }\r
442 }\r
443\r
444 //\r
445 // Perform the update now. If there are pending writes, we need to\r
446 // start from the pending write instead of the very beginning.\r
447 //\r
448 PtrMap = BlockMap;\r
449 Lba = 0;\r
450 Offset = 0;\r
451 UpdateBuffer = ImageBuffer;\r
452 CopyMem (\r
0a6f4824
LG
453 (VOID *) &PrivateData.FileGuid,\r
454 (VOID *) &ConfigData->FileGuid,\r
455 sizeof (EFI_GUID)\r
b2824a8e 456 );\r
457\r
458 while (TRUE) {\r
459 if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {\r
460 break;\r
461 }\r
462 Length = (UINTN)PtrMap->Length;\r
463 for (Index = 0; Index < PtrMap->NumBlocks; Index++) {\r
464\r
465 //\r
466 // Add an extra check here to see if the pending record is correct\r
467 //\r
468 if (Pending && (Lba == PendingLba)) {\r
469 if ((PendingOffset != Offset) || (PendingLength != Length)) {\r
470 //\r
471 // Error.\r
472 //\r
473 Status = EFI_ABORTED;\r
474 break;\r
475 }\r
476 }\r
477\r
478 if ((!Pending) || (Lba >= PendingLba)) {\r
479 Status = FtwProtocol->Write (\r
480 FtwProtocol,\r
481 Lba, // Lba\r
482 Offset, // Offset\r
483 Length, // Size\r
484 &PrivateData, // Private Data\r
485 FvbHandle, // FVB handle\r
486 UpdateBuffer // Buffer\r
487 );\r
488 }\r
489\r
490 if (EFI_ERROR (Status)) {\r
491 break;\r
492 }\r
493 Lba++;\r
494 UpdateBuffer = (UINT8 *) ((UINTN)UpdateBuffer + Length);\r
495 }\r
496\r
497 if (EFI_ERROR (Status)) {\r
498 break;\r
499 }\r
500 PtrMap++;\r
501 }\r
502\r
503 return Status;\r
504\r
505}\r
506\r
507/**\r
508 Directly update the whole FV image without fault tolerant write method.\r
509\r
510 @param FvbHandle Handle of FVB protocol for the updated flash range.\r
511 @param FvbProtocol FVB protocol.\r
512 @param BlockMap Block array to specify flash area.\r
513 @param ConfigData Config data on updating driver.\r
514 @param ImageBuffer Image buffer to be updated.\r
515 @param ImageSize Image size.\r
516\r
517 @retval EFI_SUCCESS FV image is writed into flash.\r
518 @retval EFI_INVALID_PARAMETER Config data is not valid.\r
519 @retval EFI_ABORTED Error happen when update FV.\r
520\r
521**/\r
522EFI_STATUS\r
523NonFaultTolerantUpdateOnWholeFv (\r
524 IN EFI_HANDLE FvbHandle,\r
525 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,\r
526 IN EFI_FV_BLOCK_MAP_ENTRY *BlockMap,\r
527 IN UPDATE_CONFIG_DATA *ConfigData,\r
528 IN UINT8 *ImageBuffer,\r
529 IN UINTN ImageSize\r
530 )\r
531{\r
532 EFI_STATUS Status;\r
533 EFI_FV_BLOCK_MAP_ENTRY *PtrMap;\r
534 UINTN Index;\r
535 EFI_LBA UpdateLba;\r
536 UINT8 *UpdateBuffer;\r
537 UINTN UpdateSize;\r
538\r
539 if ((ConfigData->UpdateType != UpdateWholeFV )\r
540 || (ConfigData->FaultTolerant)) {\r
541 return EFI_INVALID_PARAMETER;\r
542 }\r
543\r
544 Status = EFI_SUCCESS;\r
545 PtrMap = BlockMap;\r
546 UpdateLba = 0;\r
547 UpdateBuffer = ImageBuffer;\r
548\r
549 //\r
550 // Perform the update now\r
551 //\r
552 while (TRUE) {\r
553 if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {\r
554 break;\r
555 }\r
556 UpdateSize = (UINTN)PtrMap->Length;\r
557 for (Index = 0; Index < PtrMap->NumBlocks; Index++) {\r
558 Status = UpdateOneBlock (\r
559 FvbProtocol,\r
560 UpdateLba,\r
561 UpdateSize,\r
562 UpdateBuffer\r
563 );\r
564 if (EFI_ERROR (Status)) {\r
565 break;\r
566 }\r
567\r
568 UpdateLba++;\r
569 UpdateBuffer = (UINT8 *) ((UINTN)UpdateBuffer + UpdateSize);\r
570 }\r
571\r
572 if (EFI_ERROR (Status)) {\r
573 break;\r
574 }\r
575 PtrMap++;\r
576 }\r
577\r
578 return Status;\r
579}\r
580\r
581/**\r
582 Update the whole FV image, and reinsall FVB protocol for the updated FV image.\r
583\r
584 @param FvbHandle Handle of FVB protocol for the updated flash range.\r
585 @param FvbProtocol FVB protocol.\r
586 @param ConfigData Config data on updating driver.\r
587 @param ImageBuffer Image buffer to be updated.\r
588 @param ImageSize Image size.\r
589\r
590 @retval EFI_INVALID_PARAMETER Update type is not UpdateWholeFV.\r
591 Or Image size is not same to the size of whole FV.\r
592 @retval EFI_OUT_OF_RESOURCES No enoug memory is allocated.\r
593 @retval EFI_SUCCESS FV image is updated, and its FVB protocol is reinstalled.\r
594\r
595**/\r
596EFI_STATUS\r
597PerformUpdateOnWholeFv (\r
598 IN EFI_HANDLE FvbHandle,\r
599 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,\r
600 IN UPDATE_CONFIG_DATA *ConfigData,\r
601 IN UINT8 *ImageBuffer,\r
602 IN UINTN ImageSize\r
603)\r
604{\r
605 EFI_STATUS Status;\r
606 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
607 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
608 CHAR16 *TmpStr;\r
609\r
610 if (ConfigData->UpdateType != UpdateWholeFV) {\r
611 return EFI_INVALID_PARAMETER;\r
612 }\r
613\r
614 //\r
615 // Get the header of the firmware volume\r
616 //\r
617 FwVolHeader = NULL;\r
618 FwVolHeader = AllocatePool (((EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (ConfigData->BaseAddress)))->HeaderLength);\r
619 if (FwVolHeader == NULL) {\r
620 return EFI_OUT_OF_RESOURCES;\r
621 }\r
622 CopyMem (\r
623 FwVolHeader,\r
624 (VOID *) ((UINTN) (ConfigData->BaseAddress)),\r
625 ((EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (ConfigData->BaseAddress)))->HeaderLength\r
626 );\r
627\r
628 //\r
629 // Check if ImageSize is the same as the size of the whole FV\r
630 //\r
631 if ((UINT64)ImageSize != FwVolHeader->FvLength) {\r
632 FreePool (FwVolHeader);\r
633 return EFI_INVALID_PARAMETER;\r
634 }\r
635\r
636 //\r
637 // Print on screen\r
638 //\r
639 TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FIRMWARE_VOLUME), NULL);\r
640 if (TmpStr != NULL) {\r
641 Print (TmpStr, ConfigData->BaseAddress, (FwVolHeader->FvLength + ConfigData->BaseAddress));\r
642 FreePool (TmpStr);\r
643 }\r
644\r
645 DEBUG ((EFI_D_UPDATE, "UpdateDriver: updating whole FV from %08LX to %08LX\n",\r
646 ConfigData->BaseAddress, (FwVolHeader->FvLength + ConfigData->BaseAddress)));\r
647\r
648 //\r
649 // Get the block map of the firmware volume\r
650 //\r
651 BlockMap = &(FwVolHeader->BlockMap[0]);\r
652\r
653 //\r
654 // It is about the same if we are going to fault tolerantly update\r
655 // a certain FV in our current design. But we divide non-fault tolerant\r
656 // and fault tolerant udpate here for better maintenance as fault\r
657 // tolerance may change and may be done more wisely if we have space.\r
658 //\r
659 if (ConfigData->FaultTolerant) {\r
660 Status = FaultTolerantUpdateOnWholeFv (\r
661 FvbHandle,\r
662 FvbProtocol,\r
663 BlockMap,\r
664 ConfigData,\r
665 ImageBuffer,\r
666 ImageSize\r
667 );\r
668 } else {\r
669 Status = NonFaultTolerantUpdateOnWholeFv (\r
670 FvbHandle,\r
671 FvbProtocol,\r
672 BlockMap,\r
673 ConfigData,\r
674 ImageBuffer,\r
675 ImageSize\r
676 );\r
677 }\r
678\r
679 FreePool (FwVolHeader);\r
680\r
681 if (EFI_ERROR (Status)) {\r
682 return Status;\r
683 }\r
684\r
685 //\r
686 // As the whole FV has been replaced, the FV driver shall re-parse the\r
687 // firmware volume. So re-install FVB protocol here\r
688 //\r
689 Status = gBS->ReinstallProtocolInterface (\r
690 FvbHandle,\r
691 &gEfiFirmwareVolumeBlockProtocolGuid,\r
692 FvbProtocol,\r
693 FvbProtocol\r
694 );\r
695\r
696 return Status;\r
697}\r
698\r
699/**\r
700 Update certain file in the FV.\r
701\r
702 @param FvbHandle Handle of FVB protocol for the updated flash range.\r
703 @param FvbProtocol FVB protocol.\r
704 @param ConfigData Config data on updating driver.\r
705 @param ImageBuffer Image buffer to be updated.\r
706 @param ImageSize Image size.\r
707 @param FileType FFS file type.\r
708 @param FileAttributes FFS file attribute\r
709\r
710 @retval EFI_INVALID_PARAMETER Update type is not UpdateFvFile.\r
711 Or Image size is not same to the size of whole FV.\r
712 @retval EFI_UNSUPPORTED PEIM FFS is unsupported to be updated.\r
713 @retval EFI_SUCCESS The FFS file is added into FV.\r
714\r
715**/\r
716EFI_STATUS\r
717PerformUpdateOnFvFile (\r
718 IN EFI_HANDLE FvbHandle,\r
719 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,\r
720 IN UPDATE_CONFIG_DATA *ConfigData,\r
721 IN UINT8 *ImageBuffer,\r
722 IN UINTN ImageSize,\r
723 IN EFI_FV_FILETYPE FileType,\r
724 IN EFI_FV_FILE_ATTRIBUTES FileAttributes\r
725 )\r
726{\r
727 EFI_STATUS Status;\r
728 EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVolProtocol;\r
729 EFI_FV_WRITE_FILE_DATA FileData;\r
730 CHAR16 *TmpStr;\r
731\r
732 if (ConfigData->UpdateType != UpdateFvFile) {\r
733 return EFI_INVALID_PARAMETER;\r
734 }\r
735\r
736 //\r
737 // Print on screen\r
738 //\r
739 TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FIRMWARE_VOLUME_FILE), NULL);\r
740 if (TmpStr != NULL) {\r
741 Print (TmpStr, &(ConfigData->FileGuid));\r
742 FreePool (TmpStr);\r
743 }\r
744\r
745 DEBUG ((EFI_D_UPDATE, "UpdateDriver: updating file: %g\n",\r
746 &(ConfigData->FileGuid)));\r
747\r
748 //\r
749 // Get Firmware volume protocol on this FVB protocol\r
750 //\r
751 Status = gBS->HandleProtocol (\r
752 FvbHandle,\r
753 &gEfiFirmwareVolume2ProtocolGuid,\r
754 (VOID **) &FwVolProtocol\r
755 );\r
756 if (EFI_ERROR (Status)) {\r
757 return Status;\r
758 }\r
759\r
760 //\r
761 // If it is a PEIM, we need first to rebase it before committing\r
762 // the write to target\r
763 //\r
764 if ((FileType == EFI_FV_FILETYPE_PEI_CORE) || (FileType == EFI_FV_FILETYPE_PEIM )\r
765 || (FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)) {\r
766 return EFI_UNSUPPORTED;\r
767 }\r
768\r
769 FileData.NameGuid = &(ConfigData->FileGuid);\r
770 FileData.Type = FileType;\r
771 FileData.FileAttributes = FileAttributes;\r
772 FileData.Buffer = ImageBuffer;\r
773 FileData.BufferSize = (UINT32) ImageSize;\r
774\r
775 Status = FwVolProtocol->WriteFile (\r
776 FwVolProtocol,\r
777 1, // NumberOfFiles\r
778 (EFI_FV_WRITE_POLICY)ConfigData->FaultTolerant,\r
779 &FileData\r
780 );\r
781 return Status;\r
782}\r
783\r
784/**\r
785 Update the buffer into flash area in fault tolerant write method.\r
786\r
787 @param ImageBuffer Image buffer to be updated.\r
788 @param SizeLeft Size of the image buffer.\r
789 @param UpdatedSize Size of the updated buffer.\r
790 @param ConfigData Config data on updating driver.\r
791 @param FlashAddress Flash address to be updated as start address.\r
792 @param FvbProtocol FVB protocol.\r
793 @param FvbHandle Handle of FVB protocol for the updated flash range.\r
794\r
795 @retval EFI_SUCCESS Buffer data is updated into flash.\r
796 @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area.\r
797 @retval EFI_NOT_FOUND FTW protocol doesn't exist.\r
798 @retval EFI_OUT_OF_RESOURCES No enough backup space.\r
799 @retval EFI_ABORTED Error happen when update flash area.\r
800\r
801**/\r
802EFI_STATUS\r
803FaultTolerantUpdateOnPartFv (\r
804 IN UINT8 *ImageBuffer,\r
805 IN UINTN SizeLeft,\r
806 IN OUT UINTN *UpdatedSize,\r
807 IN UPDATE_CONFIG_DATA *ConfigData,\r
808 IN EFI_PHYSICAL_ADDRESS FlashAddress,\r
809 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,\r
810 IN EFI_HANDLE FvbHandle\r
811 )\r
812{\r
813 EFI_STATUS Status;\r
814 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
815 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeaderTmp;\r
816 EFI_PHYSICAL_ADDRESS BaseAddress;\r
817 EFI_PHYSICAL_ADDRESS FvBase;\r
818 EFI_PHYSICAL_ADDRESS NextBlock;\r
819 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
820 EFI_FV_BLOCK_MAP_ENTRY *PtrMap;\r
821 UINTN NumOfUpdates;\r
822 UINTN TotalSize;\r
823 EFI_PHYSICAL_ADDRESS StartAddress;\r
824 EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;\r
825 UINTN MaxBlockSize;\r
826 UINTN FtwMaxBlockSize;\r
827 BOOLEAN Pending;\r
828 UPDATE_PRIVATE_DATA PrivateData;\r
829 EFI_LBA PendingLba;\r
830 EFI_LBA Lba;\r
831 UINTN BlockSize;\r
832 UINTN PendingOffset;\r
833 UINTN Offset;\r
834 UINTN PendingLength;\r
835 UINTN Length;\r
836 UINTN Index;\r
837 UINT8 *Image;\r
838\r
839 //\r
840 // Get the block map to update the block one by one\r
841 //\r
842 Status = FvbProtocol->GetPhysicalAddress (\r
843 FvbProtocol,\r
844 &FvBase\r
845 );\r
846 if (EFI_ERROR (Status)) {\r
847 return Status;\r
848 }\r
849\r
850 FwVolHeaderTmp = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase;\r
851 if ((FlashAddress < FvBase) || (FlashAddress > (FvBase + FwVolHeaderTmp->FvLength))) {\r
852 return EFI_INVALID_PARAMETER;\r
853 }\r
854\r
855 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AllocateCopyPool (\r
856 FwVolHeaderTmp->HeaderLength,\r
857 FwVolHeaderTmp\r
858 );\r
859 if (FwVolHeader == NULL) {\r
860 return EFI_OUT_OF_RESOURCES;\r
861 }\r
862\r
863 //\r
864 // For fault tolerant write, we have to know how many blocks we need to\r
865 // update. So we will calculate number of updates and max block size first\r
866 //\r
867 NumOfUpdates = 0;\r
868 MaxBlockSize = 0;\r
869 TotalSize = SizeLeft;\r
870 StartAddress = FlashAddress;\r
871 BaseAddress = FvBase;\r
872 BlockMap = &(FwVolHeader->BlockMap[0]);\r
873 PtrMap = BlockMap;\r
874\r
875 while (TotalSize > 0) {\r
876 if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {\r
877 break;\r
878 }\r
879\r
880 BlockSize = PtrMap->Length;\r
881 for (Index = 0; Index < PtrMap->NumBlocks; Index++) {\r
882 NextBlock = BaseAddress + BlockSize;\r
883 //\r
884 // Check if this block need to be updated\r
885 //\r
886 if ((StartAddress >= BaseAddress) && (StartAddress < NextBlock)) {\r
887 //\r
888 // Get the maximum block size\r
889 //\r
890 if (MaxBlockSize < BlockSize) {\r
891 MaxBlockSize = BlockSize;\r
892 }\r
893\r
894 //\r
895 // This block shall be udpated. So increment number of updates\r
896 //\r
897 NumOfUpdates++;\r
898 Offset = (UINTN) (StartAddress - BaseAddress);\r
899 Length = TotalSize;\r
900 if ((Length + Offset ) > BlockSize) {\r
901 Length = BlockSize - Offset;\r
902 }\r
903\r
904 StartAddress = StartAddress + Length;\r
905 TotalSize = TotalSize - Length;\r
906 if (TotalSize <= 0) {\r
907 break;\r
908 }\r
909 }\r
910 BaseAddress = NextBlock;\r
911 }\r
912 PtrMap++;\r
913 }\r
914\r
915 //\r
916 // Get the FTW protocol\r
917 //\r
918 Status = gBS->LocateProtocol (\r
919 &gEfiFaultTolerantWriteProtocolGuid,\r
920 NULL,\r
921 (VOID **) &FtwProtocol\r
922 );\r
923 if (EFI_ERROR (Status)) {\r
924 FreePool (FwVolHeader);\r
925 return EFI_NOT_FOUND;\r
926 }\r
927\r
928 FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);\r
929\r
930 //\r
931 // Not enough backup space. return directly\r
932 //\r
933 if (FtwMaxBlockSize < MaxBlockSize) {\r
934 FreePool (FwVolHeader);\r
935 return EFI_OUT_OF_RESOURCES;\r
936 }\r
937\r
938 PendingLba = 0;\r
939 PendingOffset = 0;\r
940 PendingLength = 0;\r
941 Pending = FALSE;\r
942\r
943 //\r
944 // Fault Tolerant Write can only support actual fault tolerance if the write\r
945 // is a reclaim operation, which means the data buffer (new and old) are\r
946 // acutally both stored in flash. But for component update write, the data\r
947 // are now in memory. So we cannot actually recover the data after power\r
948 // failure.\r
949 //\r
950 Status = RetrieveLastWrite (\r
951 FvbHandle,\r
952 FtwProtocol,\r
953 ConfigData,\r
954 sizeof (UPDATE_PRIVATE_DATA),\r
955 &PrivateData,\r
956 &PendingLba,\r
957 &PendingOffset,\r
958 &PendingLength,\r
959 &Pending\r
960 );\r
961 if (Pending && (Status == EFI_NOT_FOUND)) {\r
962 //\r
963 // I'm not the owner of the pending fault tolerant write record\r
964 // Cannot continue with the write operation\r
965 //\r
966 FreePool (FwVolHeader);\r
967 return EFI_ABORTED;\r
968 }\r
969\r
970 if (EFI_ERROR(Status)) {\r
971 FreePool (FwVolHeader);\r
972 return EFI_ABORTED;\r
973 }\r
974\r
975 //\r
976 // Currently we start from the pending write if there is any. But if the\r
977 // caller is exactly the same, and the new data is already a in memory, (it\r
978 // cannot be stored in flash in last write,) we can just abort last write\r
979 // and start from the very begining.\r
980 //\r
981 if (!Pending) {\r
982 //\r
983 // Now allocte the update private data in FTW. If there is pending\r
984 // write, it has already been allocated and no need to allocate here.\r
985 //\r
986 Status = FtwProtocol->Allocate (\r
987 FtwProtocol,\r
988 &gEfiCallerIdGuid,\r
989 sizeof (UPDATE_PRIVATE_DATA),\r
990 NumOfUpdates\r
991 );\r
992 if (EFI_ERROR (Status)) {\r
993 FreePool (FwVolHeader);\r
994 return Status;\r
995 }\r
996 }\r
997\r
998 //\r
999 // Perform the update now. If there are pending writes, we need to\r
1000 // start from the pending write instead of the very beginning.\r
1001 //\r
1002 TotalSize = SizeLeft;\r
1003 Lba = 0;\r
1004 StartAddress = FlashAddress;\r
1005 BaseAddress = FvBase;\r
1006 PtrMap = BlockMap;\r
1007 Image = ImageBuffer;\r
1008 CopyMem (\r
0a6f4824
LG
1009 (VOID *) &PrivateData.FileGuid,\r
1010 (VOID *) &ConfigData->FileGuid,\r
1011 sizeof (EFI_GUID)\r
b2824a8e 1012 );\r
1013\r
1014 while (TotalSize > 0) {\r
1015 if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {\r
1016 break;\r
1017 }\r
1018\r
1019 BlockSize = (UINTN)PtrMap->Length;\r
1020 for (Index = 0; Index < PtrMap->NumBlocks; Index++) {\r
1021 NextBlock = BaseAddress + BlockSize;\r
1022 if ((StartAddress >= BaseAddress) && (StartAddress < NextBlock)) {\r
1023 //\r
1024 // So we need to update this block\r
1025 //\r
1026 Offset = (UINTN) (StartAddress - BaseAddress);\r
1027 Length = TotalSize;\r
1028 if ((Length + Offset ) > BlockSize) {\r
1029 Length = BlockSize - Offset;\r
1030 }\r
1031\r
1032 //\r
1033 // Add an extra check here to see if the pending record is correct\r
1034 //\r
1035 if (Pending && (Lba == PendingLba)) {\r
1036 if ((PendingOffset != Offset) || (PendingLength != Length)) {\r
1037 //\r
1038 // Error.\r
1039 //\r
1040 Status = EFI_ABORTED;\r
1041 break;\r
1042 }\r
1043 }\r
1044\r
1045 if ((!Pending) || (Lba >= PendingLba)) {\r
1046 DEBUG ((EFI_D_UPDATE, "Update Flash area from %08LX to %08LX\n", StartAddress, (UINT64)StartAddress + Length));\r
1047 Status = FtwProtocol->Write (\r
1048 FtwProtocol,\r
1049 Lba, // Lba\r
1050 Offset, // Offset\r
1051 Length, // Size\r
1052 &PrivateData, // Private Data\r
1053 FvbHandle, // FVB handle\r
1054 Image // Buffer\r
1055 );\r
1056 if (EFI_ERROR (Status)) {\r
1057 break;\r
1058 }\r
1059 }\r
1060\r
1061 //\r
1062 // Now increment StartAddress, ImageBuffer and decrease the\r
1063 // left size to prepare for the next block update.\r
1064 //\r
1065 StartAddress = StartAddress + Length;\r
1066 Image = Image + Length;\r
1067 TotalSize = TotalSize - Length;\r
1068 if (TotalSize <= 0) {\r
1069 break;\r
1070 }\r
1071 }\r
1072 BaseAddress = NextBlock;\r
1073 Lba++;\r
1074 }\r
1075\r
1076 if (EFI_ERROR (Status)) {\r
1077 break;\r
1078 }\r
1079 PtrMap++;\r
1080 }\r
1081\r
1082 FreePool (FwVolHeader);\r
1083\r
1084 *UpdatedSize = SizeLeft - TotalSize;\r
1085\r
1086 return EFI_SUCCESS;\r
1087}\r
1088\r
1089/**\r
1090 Directly update the buffer into flash area without fault tolerant write method.\r
1091\r
1092 @param ImageBuffer Image buffer to be updated.\r
1093 @param SizeLeft Size of the image buffer.\r
1094 @param UpdatedSize Size of the updated buffer.\r
1095 @param FlashAddress Flash address to be updated as start address.\r
1096 @param FvbProtocol FVB protocol.\r
1097 @param FvbHandle Handle of FVB protocol for the updated flash range.\r
1098\r
1099 @retval EFI_SUCCESS Buffer data is updated into flash.\r
1100 @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area.\r
1101 @retval EFI_OUT_OF_RESOURCES No enough backup space.\r
1102\r
1103**/\r
1104EFI_STATUS\r
1105NonFaultTolerantUpdateOnPartFv (\r
1106 IN UINT8 *ImageBuffer,\r
1107 IN UINTN SizeLeft,\r
1108 IN OUT UINTN *UpdatedSize,\r
1109 IN EFI_PHYSICAL_ADDRESS FlashAddress,\r
1110 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,\r
1111 IN EFI_HANDLE FvbHandle\r
1112 )\r
1113{\r
1114 EFI_STATUS Status;\r
1115 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
1116 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeaderTmp;\r
1117 EFI_PHYSICAL_ADDRESS BaseAddress;\r
1118 EFI_PHYSICAL_ADDRESS NextBlock;\r
1119 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
1120 UINTN Index;\r
1121 UINTN TotalSize;\r
1122 UINTN BlockSize;\r
1123 EFI_LBA Lba;\r
1124 UINTN Offset;\r
1125 UINTN Length;\r
1126 UINT8 *Image;\r
1127\r
1128 //\r
1129 // Get the block map to update the block one by one\r
1130 //\r
1131 Status = FvbProtocol->GetPhysicalAddress (\r
1132 FvbProtocol,\r
1133 &BaseAddress\r
1134 );\r
1135 if (EFI_ERROR (Status)) {\r
1136 return Status;\r
1137 }\r
1138\r
1139 FwVolHeaderTmp = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;\r
1140 if ((FlashAddress < BaseAddress) || (FlashAddress > ( BaseAddress + FwVolHeaderTmp->FvLength ))) {\r
1141 return EFI_INVALID_PARAMETER;\r
1142 }\r
1143\r
1144 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AllocateCopyPool (\r
1145 FwVolHeaderTmp->HeaderLength,\r
1146 FwVolHeaderTmp\r
1147 );\r
1148 if (FwVolHeader == NULL) {\r
1149 return EFI_OUT_OF_RESOURCES;\r
1150 }\r
1151\r
1152 Image = ImageBuffer;\r
1153 TotalSize = SizeLeft;\r
1154 BlockMap = &(FwVolHeader->BlockMap[0]);\r
1155 Lba = 0;\r
1156\r
1157 while (TotalSize > 0) {\r
1158 if ((BlockMap->NumBlocks == 0) || (BlockMap->Length == 0)) {\r
1159 break;\r
1160 }\r
1161\r
1162 BlockSize = BlockMap->Length;\r
1163 for (Index = 0 ; Index < BlockMap->NumBlocks ; Index++) {\r
1164 NextBlock = BaseAddress + BlockSize;\r
1165 if ((FlashAddress >= BaseAddress) && (FlashAddress < NextBlock)) {\r
1166 //\r
1167 // So we need to update this block\r
1168 //\r
1169 Offset = (UINTN) FlashAddress - (UINTN) BaseAddress;\r
1170 Length = TotalSize;\r
1171 if ((Length + Offset ) > BlockSize) {\r
1172 Length = BlockSize - Offset;\r
1173 }\r
1174\r
1175 DEBUG ((EFI_D_UPDATE, "Update Flash area from %08LX to %08LX\n", FlashAddress, (UINT64)FlashAddress + Length));\r
1176 //\r
1177 // Update the block\r
1178 //\r
1179 Status = UpdateBufferInOneBlock (\r
1180 FvbProtocol,\r
1181 Lba,\r
1182 Offset,\r
1183 Length,\r
1184 BlockSize,\r
1185 Image\r
1186 );\r
1187 if (EFI_ERROR (Status)) {\r
1188 FreePool (FwVolHeader);\r
1189 return Status;\r
1190 }\r
1191\r
1192 //\r
1193 // Now increment FlashAddress, ImageBuffer and decrease the\r
1194 // left size to prepare for the next block update.\r
1195 //\r
1196 FlashAddress = FlashAddress + Length;\r
1197 Image = Image + Length;\r
1198 TotalSize = TotalSize - Length;\r
1199 if (TotalSize <= 0) {\r
1200 break;\r
1201 }\r
1202 }\r
1203 BaseAddress = NextBlock;\r
1204 Lba++;\r
1205 }\r
1206\r
1207 if (EFI_ERROR (Status)) {\r
1208 break;\r
1209 }\r
1210 BlockMap++;\r
1211 }\r
1212\r
1213 FreePool (FwVolHeader);\r
1214\r
1215 *UpdatedSize = SizeLeft - TotalSize;\r
1216\r
1217 return EFI_SUCCESS;\r
1218}\r