]> git.proxmox.com Git - mirror_edk2.git/blame - UnixPkg/FvbServicesRuntimeDxe/FWBlockService.c
Update DebugSupportDxe module to pass IPF GCC build.
[mirror_edk2.git] / UnixPkg / FvbServicesRuntimeDxe / FWBlockService.c
CommitLineData
804405e7 1/*++\r
2\r
3Copyright (c) 2006 - 2008, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 FWBlockService.c\r
15 \r
16Abstract:\r
17\r
18Revision History\r
19\r
20--*/\r
21\r
22#include "PiDxe.h"\r
23#include <Guid/EventGroup.h>\r
24#include <Protocol/FvbExtension.h>\r
25#include <Protocol/FirmwareVolumeBlock.h>\r
26#include <Guid/AlternateFvBlock.h>\r
27#include <Protocol/DevicePath.h>\r
28\r
29#include <Library/UefiLib.h>\r
30#include <Library/UefiDriverEntryPoint.h>\r
31#include <Library/BaseLib.h>\r
32#include <Library/DxeServicesTableLib.h>\r
33#include <Library/UefiRuntimeLib.h>\r
34#include <Library/DebugLib.h>\r
35#include <Library/HobLib.h>\r
36#include <Library/BaseMemoryLib.h>\r
37#include <Library/MemoryAllocationLib.h>\r
38#include <Library/UefiBootServicesTableLib.h>\r
39#include "FwBlockService.h"\r
40\r
41ESAL_FWB_GLOBAL *mFvbModuleGlobal;\r
42\r
43#define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)\r
44\r
45EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {\r
46 FVB_DEVICE_SIGNATURE,\r
47 {\r
48 {\r
49 {\r
50 HARDWARE_DEVICE_PATH,\r
51 HW_MEMMAP_DP,\r
52 {\r
53 sizeof (MEMMAP_DEVICE_PATH),\r
54 0\r
55 }\r
56 },\r
57 EfiMemoryMappedIO,\r
58 0,\r
59 0,\r
60 },\r
61 {\r
62 END_DEVICE_PATH_TYPE,\r
63 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
64 {\r
65 sizeof (EFI_DEVICE_PATH_PROTOCOL),\r
66 0\r
67 }\r
68 }\r
69 },\r
70 0,\r
71 {\r
72 FvbProtocolGetAttributes,\r
73 FvbProtocolSetAttributes,\r
74 FvbProtocolGetPhysicalAddress,\r
75 FvbProtocolGetBlockSize,\r
76 FvbProtocolRead,\r
77 FvbProtocolWrite,\r
78 FvbProtocolEraseBlocks,\r
79 NULL\r
80 },\r
81 {\r
82 FvbExtendProtocolEraseCustomBlockRange\r
83 }\r
84};\r
85\r
86\r
87\r
88VOID\r
89EFIAPI\r
90FvbVirtualddressChangeEvent (\r
91 IN EFI_EVENT Event,\r
92 IN VOID *Context\r
93 )\r
94/*++\r
95\r
96Routine Description:\r
97\r
98 Fixup internal data so that EFI and SAL can be call in virtual mode.\r
99 Call the passed in Child Notify event and convert the mFvbModuleGlobal\r
100 date items to there virtual address.\r
101\r
102 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data\r
103 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common \r
104 instance data.\r
105\r
106Arguments:\r
107\r
108 (Standard EFI notify event - EFI_EVENT_NOTIFY)\r
109\r
110Returns: \r
111\r
112 None\r
113\r
114--*/\r
115{\r
116 EFI_FW_VOL_INSTANCE *FwhInstance;\r
117 UINTN Index;\r
118\r
119 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]);\r
120\r
121 //\r
122 // Convert the base address of all the instances\r
123 //\r
124 Index = 0;\r
125 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];\r
126 while (Index < mFvbModuleGlobal->NumFv) {\r
127 EfiConvertPointer (0x0, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]);\r
128 FwhInstance = (EFI_FW_VOL_INSTANCE *)\r
129 (\r
130 (UINTN) ((UINT8 *) FwhInstance) + FwhInstance->VolumeHeader.HeaderLength +\r
131 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))\r
132 );\r
133 Index++;\r
134 }\r
135\r
136 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]);\r
137 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal);\r
138}\r
139\r
140EFI_STATUS\r
141GetFvbInstance (\r
142 IN UINTN Instance,\r
143 IN ESAL_FWB_GLOBAL *Global,\r
144 OUT EFI_FW_VOL_INSTANCE **FwhInstance,\r
145 IN BOOLEAN Virtual\r
146 )\r
147/*++\r
148\r
149Routine Description:\r
150 Retrieves the physical address of a memory mapped FV\r
151\r
152Arguments:\r
153 Instance - The FV instance whose base address is going to be\r
154 returned\r
155 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
156 instance data\r
157 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure\r
158 Virtual - Whether CPU is in virtual or physical mode\r
159\r
160Returns: \r
161 EFI_SUCCESS - Successfully returns\r
162 EFI_INVALID_PARAMETER - Instance not found\r
163\r
164--*/\r
165{\r
166 EFI_FW_VOL_INSTANCE *FwhRecord;\r
167\r
168 if (Instance >= Global->NumFv) {\r
169 return EFI_INVALID_PARAMETER;\r
170 }\r
171 //\r
172 // Find the right instance of the FVB private data\r
173 //\r
174 FwhRecord = Global->FvInstance[Virtual];\r
175 while (Instance > 0) {\r
176 FwhRecord = (EFI_FW_VOL_INSTANCE *)\r
177 (\r
178 (UINTN) ((UINT8 *) FwhRecord) + FwhRecord->VolumeHeader.HeaderLength +\r
179 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))\r
180 );\r
181 Instance--;\r
182 }\r
183\r
184 *FwhInstance = FwhRecord;\r
185\r
186 return EFI_SUCCESS;\r
187}\r
188\r
189EFI_STATUS\r
190FvbGetPhysicalAddress (\r
191 IN UINTN Instance,\r
192 OUT EFI_PHYSICAL_ADDRESS *Address,\r
193 IN ESAL_FWB_GLOBAL *Global,\r
194 IN BOOLEAN Virtual\r
195 )\r
196/*++\r
197\r
198Routine Description:\r
199 Retrieves the physical address of a memory mapped FV\r
200\r
201Arguments:\r
202 Instance - The FV instance whose base address is going to be\r
203 returned\r
204 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS \r
205 that on successful return, contains the base address\r
206 of the firmware volume. \r
207 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
208 instance data\r
209 Virtual - Whether CPU is in virtual or physical mode\r
210\r
211Returns: \r
212 EFI_SUCCESS - Successfully returns\r
213 EFI_INVALID_PARAMETER - Instance not found\r
214\r
215--*/\r
216{\r
217 EFI_FW_VOL_INSTANCE *FwhInstance;\r
218 EFI_STATUS Status;\r
219\r
220 //\r
221 // Find the right instance of the FVB private data\r
222 //\r
223 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
224 ASSERT_EFI_ERROR (Status);\r
225 *Address = FwhInstance->FvBase[Virtual];\r
226\r
227 return EFI_SUCCESS;\r
228}\r
229\r
230EFI_STATUS\r
231FvbGetVolumeAttributes (\r
232 IN UINTN Instance,\r
dfb8993c 233 OUT EFI_FVB_ATTRIBUTES_2 *Attributes,\r
804405e7 234 IN ESAL_FWB_GLOBAL *Global,\r
235 IN BOOLEAN Virtual\r
236 )\r
237/*++\r
238\r
239Routine Description:\r
240 Retrieves attributes, insures positive polarity of attribute bits, returns\r
241 resulting attributes in output parameter\r
242\r
243Arguments:\r
244 Instance - The FV instance whose attributes is going to be \r
245 returned\r
246 Attributes - Output buffer which contains attributes\r
247 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
248 instance data\r
249 Virtual - Whether CPU is in virtual or physical mode\r
250\r
251Returns: \r
252 EFI_SUCCESS - Successfully returns\r
253 EFI_INVALID_PARAMETER - Instance not found\r
254\r
255--*/\r
256{\r
257 EFI_FW_VOL_INSTANCE *FwhInstance;\r
258 EFI_STATUS Status;\r
259\r
260 //\r
261 // Find the right instance of the FVB private data\r
262 //\r
263 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
264 ASSERT_EFI_ERROR (Status);\r
265 *Attributes = FwhInstance->VolumeHeader.Attributes;\r
266\r
267 return EFI_SUCCESS;\r
268}\r
269\r
270EFI_STATUS\r
271FvbGetLbaAddress (\r
272 IN UINTN Instance,\r
273 IN EFI_LBA Lba,\r
274 OUT UINTN *LbaAddress,\r
275 OUT UINTN *LbaLength,\r
276 OUT UINTN *NumOfBlocks,\r
277 IN ESAL_FWB_GLOBAL *Global,\r
278 IN BOOLEAN Virtual\r
279 )\r
280/*++\r
281\r
282Routine Description:\r
283 Retrieves the starting address of an LBA in an FV\r
284\r
285Arguments:\r
286 Instance - The FV instance which the Lba belongs to\r
287 Lba - The logical block address\r
288 LbaAddress - On output, contains the physical starting address \r
289 of the Lba\r
290 LbaLength - On output, contains the length of the block\r
291 NumOfBlocks - A pointer to a caller allocated UINTN in which the\r
292 number of consecutive blocks starting with Lba is\r
293 returned. All blocks in this range have a size of\r
294 BlockSize\r
295 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
296 instance data\r
297 Virtual - Whether CPU is in virtual or physical mode\r
298\r
299Returns: \r
300 EFI_SUCCESS - Successfully returns\r
301 EFI_INVALID_PARAMETER - Instance not found\r
302\r
303--*/\r
304{\r
305 UINT32 NumBlocks;\r
306 UINT32 BlockLength;\r
307 UINTN Offset;\r
308 EFI_LBA StartLba;\r
309 EFI_LBA NextLba;\r
310 EFI_FW_VOL_INSTANCE *FwhInstance;\r
311 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
312 EFI_STATUS Status;\r
313\r
314 //\r
315 // Find the right instance of the FVB private data\r
316 //\r
317 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
318 ASSERT_EFI_ERROR (Status);\r
319\r
320 StartLba = 0;\r
321 Offset = 0;\r
322 BlockMap = &(FwhInstance->VolumeHeader.BlockMap[0]);\r
323\r
324 //\r
325 // Parse the blockmap of the FV to find which map entry the Lba belongs to\r
326 //\r
327 while (TRUE) {\r
328 NumBlocks = BlockMap->NumBlocks;\r
329 BlockLength = BlockMap->Length;\r
330\r
331 if (NumBlocks == 0 || BlockLength == 0) {\r
332 return EFI_INVALID_PARAMETER;\r
333 }\r
334\r
335 NextLba = StartLba + NumBlocks;\r
336\r
337 //\r
338 // The map entry found\r
339 //\r
340 if (Lba >= StartLba && Lba < NextLba) {\r
341 Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);\r
342 if (LbaAddress != NULL) {\r
343 *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;\r
344 }\r
345\r
346 if (LbaLength != NULL) {\r
347 *LbaLength = BlockLength;\r
348 }\r
349\r
350 if (NumOfBlocks != NULL) {\r
351 *NumOfBlocks = (UINTN) (NextLba - Lba);\r
352 }\r
353\r
354 return EFI_SUCCESS;\r
355 }\r
356\r
357 StartLba = NextLba;\r
358 Offset = Offset + NumBlocks * BlockLength;\r
359 BlockMap++;\r
360 }\r
361}\r
362\r
363EFI_STATUS\r
364FvbReadBlock (\r
365 IN UINTN Instance,\r
366 IN EFI_LBA Lba,\r
367 IN UINTN BlockOffset,\r
368 IN OUT UINTN *NumBytes,\r
369 IN UINT8 *Buffer,\r
370 IN ESAL_FWB_GLOBAL *Global,\r
371 IN BOOLEAN Virtual\r
372 )\r
373/*++\r
374\r
375Routine Description:\r
376 Reads specified number of bytes into a buffer from the specified block\r
377\r
378Arguments:\r
379 Instance - The FV instance to be read from\r
380 Lba - The logical block address to be read from\r
381 BlockOffset - Offset into the block at which to begin reading\r
382 NumBytes - Pointer that on input contains the total size of\r
383 the buffer. On output, it contains the total number\r
384 of bytes read\r
385 Buffer - Pointer to a caller allocated buffer that will be\r
386 used to hold the data read\r
387 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
388 instance data\r
389 Virtual - Whether CPU is in virtual or physical mode\r
390\r
391Returns: \r
392 EFI_SUCCESS - The firmware volume was read successfully and \r
393 contents are in Buffer\r
394 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,\r
395 NumBytes contains the total number of bytes returned\r
396 in Buffer\r
397 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state\r
398 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
399 could not be read\r
400 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL\r
401\r
402--*/\r
403{\r
dfb8993c 404 EFI_FVB_ATTRIBUTES_2 Attributes;\r
804405e7 405 UINTN LbaAddress;\r
406 UINTN LbaLength;\r
407 EFI_STATUS Status;\r
408\r
409 //\r
410 // Check for invalid conditions\r
411 //\r
412 if ((NumBytes == NULL) || (Buffer == NULL)) {\r
413 return EFI_INVALID_PARAMETER;\r
414 }\r
415\r
416 if (*NumBytes == 0) {\r
417 return EFI_INVALID_PARAMETER;\r
418 }\r
419\r
420 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);\r
421 if (EFI_ERROR (Status)) {\r
422 return Status;\r
423 }\r
424 //\r
425 // Check if the FV is read enabled\r
426 //\r
427 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
428\r
429 if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {\r
430 return EFI_ACCESS_DENIED;\r
431 }\r
432 //\r
433 // Perform boundary checks and adjust NumBytes\r
434 //\r
435 if (BlockOffset > LbaLength) {\r
436 return EFI_INVALID_PARAMETER;\r
437 }\r
438\r
439 if (LbaLength < (*NumBytes + BlockOffset)) {\r
440 *NumBytes = (UINT32) (LbaLength - BlockOffset);\r
441 Status = EFI_BAD_BUFFER_SIZE;\r
442 }\r
443\r
444 CopyMem (Buffer, (UINT8 *) (LbaAddress + BlockOffset), (UINTN) (*NumBytes));\r
445\r
446 return Status;\r
447}\r
448\r
449EFI_STATUS\r
450FvbWriteBlock (\r
451 IN UINTN Instance,\r
452 IN EFI_LBA Lba,\r
453 IN UINTN BlockOffset,\r
454 IN OUT UINTN *NumBytes,\r
455 IN UINT8 *Buffer,\r
456 IN ESAL_FWB_GLOBAL *Global,\r
457 IN BOOLEAN Virtual\r
458 )\r
459/*++\r
460\r
461Routine Description:\r
462 Writes specified number of bytes from the input buffer to the block\r
463\r
464Arguments:\r
465 Instance - The FV instance to be written to\r
466 Lba - The starting logical block index to write to\r
467 BlockOffset - Offset into the block at which to begin writing\r
468 NumBytes - Pointer that on input contains the total size of\r
469 the buffer. On output, it contains the total number\r
470 of bytes actually written\r
471 Buffer - Pointer to a caller allocated buffer that contains\r
472 the source for the write\r
473 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
474 instance data\r
475 Virtual - Whether CPU is in virtual or physical mode\r
476\r
477Returns: \r
478 EFI_SUCCESS - The firmware volume was written successfully\r
479 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,\r
480 NumBytes contains the total number of bytes\r
481 actually written\r
482 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
483 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
484 could not be written\r
485 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL\r
486\r
487--*/\r
488{\r
dfb8993c 489 EFI_FVB_ATTRIBUTES_2 Attributes;\r
804405e7 490 UINTN LbaAddress;\r
491 UINTN LbaLength;\r
492 EFI_STATUS Status;\r
493\r
494 //\r
495 // Check for invalid conditions\r
496 //\r
497 if ((NumBytes == NULL) || (Buffer == NULL)) {\r
498 return EFI_INVALID_PARAMETER;\r
499 }\r
500\r
501 if (*NumBytes == 0) {\r
502 return EFI_INVALID_PARAMETER;\r
503 }\r
504\r
505 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);\r
506 if (EFI_ERROR (Status)) {\r
507 return Status;\r
508 }\r
509 //\r
510 // Check if the FV is write enabled\r
511 //\r
512 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
513\r
514 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {\r
515 return EFI_ACCESS_DENIED;\r
516 }\r
517 //\r
518 // Perform boundary checks and adjust NumBytes\r
519 //\r
520 if (BlockOffset > LbaLength) {\r
521 return EFI_INVALID_PARAMETER;\r
522 }\r
523\r
524 if (LbaLength < (*NumBytes + BlockOffset)) {\r
525 *NumBytes = (UINT32) (LbaLength - BlockOffset);\r
526 Status = EFI_BAD_BUFFER_SIZE;\r
527 }\r
528 //\r
529 // Write data\r
530 //\r
531 CopyMem ((UINT8 *) (LbaAddress + BlockOffset), Buffer, (UINTN) (*NumBytes));\r
532\r
533 return Status;\r
534}\r
535\r
536EFI_STATUS\r
537FvbEraseBlock (\r
538 IN UINTN Instance,\r
539 IN EFI_LBA Lba,\r
540 IN ESAL_FWB_GLOBAL *Global,\r
541 IN BOOLEAN Virtual\r
542 )\r
543/*++\r
544\r
545Routine Description:\r
546 Erases and initializes a firmware volume block\r
547\r
548Arguments:\r
549 Instance - The FV instance to be erased\r
550 Lba - The logical block index to be erased\r
551 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
552 instance data\r
553 Virtual - Whether CPU is in virtual or physical mode\r
554\r
555Returns: \r
556 EFI_SUCCESS - The erase request was successfully completed\r
557 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
558 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
559 could not be written. Firmware device may have been\r
560 partially erased\r
561 EFI_INVALID_PARAMETER - Instance not found\r
562\r
563--*/\r
564{\r
565\r
dfb8993c 566 EFI_FVB_ATTRIBUTES_2 Attributes;\r
804405e7 567 UINTN LbaAddress;\r
568 UINTN LbaLength;\r
569 EFI_STATUS Status;\r
570 UINT8 Data;\r
571\r
572 //\r
573 // Check if the FV is write enabled\r
574 //\r
575 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
576\r
577 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {\r
578 return EFI_ACCESS_DENIED;\r
579 }\r
580 //\r
581 // Get the starting address of the block for erase.\r
582 //\r
583 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);\r
584\r
585 if (EFI_ERROR (Status)) {\r
586 return Status;\r
587 }\r
588\r
589 if ((Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {\r
590 Data = 0xFF;\r
591 } else {\r
592 Data = 0x0;\r
593 }\r
594\r
595 SetMem ((UINT8 *) LbaAddress, LbaLength, Data);\r
596\r
597 return EFI_SUCCESS;\r
598}\r
599\r
600EFI_STATUS\r
601FvbEraseCustomBlockRange (\r
602 IN UINTN Instance,\r
603 IN EFI_LBA StartLba,\r
604 IN UINTN OffsetStartLba,\r
605 IN EFI_LBA LastLba,\r
606 IN UINTN OffsetLastLba,\r
607 IN ESAL_FWB_GLOBAL *Global,\r
608 IN BOOLEAN Virtual\r
609 )\r
610/*++\r
611\r
612Routine Description:\r
613 Erases and initializes a specified range of a firmware volume\r
614\r
615Arguments:\r
616 Instance - The FV instance to be erased\r
617 StartLba - The starting logical block index to be erased\r
618 OffsetStartLba - Offset into the starting block at which to \r
619 begin erasing\r
620 LastLba - The last logical block index to be erased\r
621 OffsetStartLba - Offset into the last block at which to end erasing\r
622 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
623 instance data\r
624 Virtual - Whether CPU is in virtual or physical mode\r
625\r
626Returns: \r
627 EFI_SUCCESS - The firmware volume was erased successfully\r
628 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
629 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
630 could not be written. Firmware device may have been\r
631 partially erased\r
632 EFI_INVALID_PARAMETER - Instance not found\r
633\r
634--*/\r
635{\r
636 EFI_LBA Index;\r
637 UINTN LbaSize;\r
638 UINTN ScratchLbaSizeData;\r
639 EFI_STATUS Status;\r
640\r
641 //\r
642 // First LBA\r
643 //\r
644 Status = FvbGetLbaAddress (Instance, StartLba, NULL, &LbaSize, NULL, Global, Virtual);\r
645 if (EFI_ERROR (Status)) {\r
646 return Status;\r
647 }\r
648\r
649 //\r
650 // Use the scratch space as the intermediate buffer to transfer data\r
651 // Back up the first LBA in scratch space.\r
652 //\r
653 FvbReadBlock (Instance, StartLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);\r
654\r
655 //\r
656 // erase now\r
657 //\r
658 FvbEraseBlock (Instance, StartLba, Global, Virtual);\r
659 ScratchLbaSizeData = OffsetStartLba;\r
660\r
661 //\r
662 // write the data back to the first block\r
663 //\r
664 if (ScratchLbaSizeData > 0) {\r
665 Status = FvbWriteBlock (Instance, StartLba, 0, &ScratchLbaSizeData, Global->FvbScratchSpace[Virtual], Global, Virtual);\r
666 if (EFI_ERROR (Status)) {\r
667 return Status;\r
668 }\r
669 }\r
670 //\r
671 // Middle LBAs\r
672 //\r
673 if (LastLba > (StartLba + 1)) {\r
674 for (Index = (StartLba + 1); Index <= (LastLba - 1); Index++) {\r
675 FvbEraseBlock (Instance, Index, Global, Virtual);\r
676 }\r
677 }\r
678 //\r
679 // Last LBAs, the same as first LBAs\r
680 //\r
681 if (LastLba > StartLba) {\r
682 Status = FvbGetLbaAddress (Instance, LastLba, NULL, &LbaSize, NULL, Global, Virtual);\r
683 if (EFI_ERROR (Status)) {\r
684 return Status;\r
685 }\r
686 FvbReadBlock (Instance, LastLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);\r
687 FvbEraseBlock (Instance, LastLba, Global, Virtual);\r
688 }\r
689\r
690 ScratchLbaSizeData = LbaSize - (OffsetLastLba + 1);\r
691\r
692 if (ScratchLbaSizeData > 0) {\r
693 Status = FvbWriteBlock (\r
694 Instance,\r
695 LastLba,\r
696 (OffsetLastLba + 1),\r
697 &ScratchLbaSizeData,\r
698 Global->FvbScratchSpace[Virtual] + OffsetLastLba + 1,\r
699 Global,\r
700 Virtual\r
701 );\r
702 }\r
703\r
704 return Status;\r
705}\r
706\r
707EFI_STATUS\r
708FvbSetVolumeAttributes (\r
709 IN UINTN Instance,\r
dfb8993c 710 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes,\r
804405e7 711 IN ESAL_FWB_GLOBAL *Global,\r
712 IN BOOLEAN Virtual\r
713 )\r
714/*++\r
715\r
716Routine Description:\r
717 Modifies the current settings of the firmware volume according to the \r
718 input parameter, and returns the new setting of the volume\r
719\r
720Arguments:\r
721 Instance - The FV instance whose attributes is going to be \r
722 modified\r
dfb8993c 723 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2 \r
804405e7 724 containing the desired firmware volume settings.\r
725 On successful return, it contains the new settings\r
726 of the firmware volume\r
727 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
728 instance data\r
729 Virtual - Whether CPU is in virtual or physical mode\r
730\r
731Returns: \r
732 EFI_SUCCESS - Successfully returns\r
733 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified\r
734 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are\r
735 in conflict with the capabilities as declared in the\r
736 firmware volume header\r
737\r
738--*/\r
739{\r
740 EFI_FW_VOL_INSTANCE *FwhInstance;\r
dfb8993c 741 EFI_FVB_ATTRIBUTES_2 OldAttributes;\r
742 EFI_FVB_ATTRIBUTES_2 *AttribPtr;\r
804405e7 743 UINT32 Capabilities;\r
744 UINT32 OldStatus;\r
745 UINT32 NewStatus;\r
746 EFI_STATUS Status;\r
dfb8993c 747 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;\r
804405e7 748\r
749\r
750 //\r
751 // Find the right instance of the FVB private data\r
752 //\r
753 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
754 ASSERT_EFI_ERROR (Status);\r
755\r
dfb8993c 756 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);\r
804405e7 757 OldAttributes = *AttribPtr;\r
758 Capabilities = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \\r
759 EFI_FVB2_READ_ENABLED_CAP | \\r
760 EFI_FVB2_WRITE_DISABLED_CAP | \\r
761 EFI_FVB2_WRITE_ENABLED_CAP | \\r
762 EFI_FVB2_LOCK_CAP \\r
763 );\r
764\r
765 OldStatus = OldAttributes & EFI_FVB2_STATUS;\r
766 NewStatus = *Attributes & EFI_FVB2_STATUS;\r
767 UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \\r
768 EFI_FVB2_READ_ENABLED_CAP | \\r
769 EFI_FVB2_WRITE_DISABLED_CAP | \\r
770 EFI_FVB2_WRITE_ENABLED_CAP | \\r
771 EFI_FVB2_LOCK_CAP | \\r
772 EFI_FVB2_STICKY_WRITE | \\r
773 EFI_FVB2_MEMORY_MAPPED | \\r
774 EFI_FVB2_ERASE_POLARITY | \\r
775 EFI_FVB2_READ_LOCK_CAP | \\r
776 EFI_FVB2_WRITE_LOCK_CAP | \\r
777 EFI_FVB2_ALIGNMENT;\r
778\r
779 //\r
780 // Some attributes of FV is read only can *not* be set\r
781 //\r
782 if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {\r
783 return EFI_INVALID_PARAMETER;\r
784 }\r
785\r
786 //\r
787 // If firmware volume is locked, no status bit can be updated\r
788 //\r
789 if (OldAttributes & EFI_FVB2_LOCK_STATUS) {\r
790 if (OldStatus ^ NewStatus) {\r
791 return EFI_ACCESS_DENIED;\r
792 }\r
793 }\r
794 //\r
795 // Test read disable\r
796 //\r
797 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {\r
798 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {\r
799 return EFI_INVALID_PARAMETER;\r
800 }\r
801 }\r
802 //\r
803 // Test read enable\r
804 //\r
805 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {\r
806 if (NewStatus & EFI_FVB2_READ_STATUS) {\r
807 return EFI_INVALID_PARAMETER;\r
808 }\r
809 }\r
810 //\r
811 // Test write disable\r
812 //\r
813 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {\r
814 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {\r
815 return EFI_INVALID_PARAMETER;\r
816 }\r
817 }\r
818 //\r
819 // Test write enable\r
820 //\r
821 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {\r
822 if (NewStatus & EFI_FVB2_WRITE_STATUS) {\r
823 return EFI_INVALID_PARAMETER;\r
824 }\r
825 }\r
826 //\r
827 // Test lock\r
828 //\r
829 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {\r
830 if (NewStatus & EFI_FVB2_LOCK_STATUS) {\r
831 return EFI_INVALID_PARAMETER;\r
832 }\r
833 }\r
834\r
835 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));\r
836 *AttribPtr = (*AttribPtr) | NewStatus;\r
837 *Attributes = *AttribPtr;\r
838\r
839 return EFI_SUCCESS;\r
840}\r
841//\r
842// FVB protocol APIs\r
843//\r
844EFI_STATUS\r
845EFIAPI\r
846FvbProtocolGetPhysicalAddress (\r
847 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
848 OUT EFI_PHYSICAL_ADDRESS *Address\r
849 )\r
850/*++\r
851\r
852Routine Description:\r
853\r
854 Retrieves the physical address of the device.\r
855\r
856Arguments:\r
857\r
858 This - Calling context\r
859 Address - Output buffer containing the address.\r
860\r
861Returns:\r
862\r
863Returns: \r
864 EFI_SUCCESS - Successfully returns\r
865\r
866--*/\r
867{\r
868 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
869\r
870 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
871\r
872 return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());\r
873}\r
874\r
875EFI_STATUS\r
876EFIAPI\r
877FvbProtocolGetBlockSize (\r
878 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
879 IN EFI_LBA Lba,\r
880 OUT UINTN *BlockSize,\r
881 OUT UINTN *NumOfBlocks\r
882 )\r
883/*++\r
884\r
885Routine Description:\r
886 Retrieve the size of a logical block\r
887\r
888Arguments:\r
889 This - Calling context\r
890 Lba - Indicates which block to return the size for.\r
891 BlockSize - A pointer to a caller allocated UINTN in which\r
892 the size of the block is returned\r
893 NumOfBlocks - a pointer to a caller allocated UINTN in which the\r
894 number of consecutive blocks starting with Lba is\r
895 returned. All blocks in this range have a size of\r
896 BlockSize\r
897\r
898Returns: \r
899 EFI_SUCCESS - The firmware volume was read successfully and \r
900 contents are in Buffer\r
901\r
902--*/\r
903{\r
904 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
905\r
906 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
907\r
908 return FvbGetLbaAddress (\r
909 FvbDevice->Instance,\r
910 Lba,\r
911 NULL,\r
912 BlockSize,\r
913 NumOfBlocks,\r
914 mFvbModuleGlobal,\r
915 EfiGoneVirtual ()\r
916 );\r
917}\r
918\r
919EFI_STATUS\r
920EFIAPI\r
921FvbProtocolGetAttributes (\r
922 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
dfb8993c 923 OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
804405e7 924 )\r
925/*++\r
926\r
927Routine Description:\r
928 Retrieves Volume attributes. No polarity translations are done.\r
929\r
930Arguments:\r
931 This - Calling context\r
932 Attributes - output buffer which contains attributes\r
933\r
934Returns: \r
935 EFI_SUCCESS - Successfully returns\r
936\r
937--*/\r
938{\r
939 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
940\r
941 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
942\r
943 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());\r
944}\r
945\r
946EFI_STATUS\r
947EFIAPI\r
948FvbProtocolSetAttributes (\r
949 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
dfb8993c 950 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
804405e7 951 )\r
952/*++\r
953\r
954Routine Description:\r
955 Sets Volume attributes. No polarity translations are done.\r
956\r
957Arguments:\r
958 This - Calling context\r
959 Attributes - output buffer which contains attributes\r
960\r
961Returns: \r
962 EFI_SUCCESS - Successfully returns\r
963\r
964--*/\r
965{\r
966 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
967\r
968 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
969\r
970 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());\r
971}\r
972\r
973EFI_STATUS\r
974EFIAPI\r
975FvbProtocolEraseBlocks (\r
976 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
977 ... \r
978 )\r
979/*++\r
980\r
981Routine Description:\r
982\r
983 The EraseBlock() function erases one or more blocks as denoted by the \r
984 variable argument list. The entire parameter list of blocks must be verified\r
985 prior to erasing any blocks. If a block is requested that does not exist \r
986 within the associated firmware volume (it has a larger index than the last \r
987 block of the firmware volume), the EraseBlock() function must return\r
988 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.\r
989\r
990Arguments:\r
991 This - Calling context\r
992 ... - Starting LBA followed by Number of Lba to erase. \r
993 a -1 to terminate the list.\r
994\r
995Returns: \r
996 EFI_SUCCESS - The erase request was successfully completed\r
997 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
998 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
999 could not be written. Firmware device may have been\r
1000 partially erased\r
1001\r
1002--*/\r
1003{\r
1004 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1005 EFI_FW_VOL_INSTANCE *FwhInstance;\r
1006 UINTN NumOfBlocks;\r
1007 VA_LIST args;\r
1008 EFI_LBA StartingLba;\r
1009 UINTN NumOfLba;\r
1010 EFI_STATUS Status;\r
1011\r
1012 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1013\r
1014 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());\r
1015 ASSERT_EFI_ERROR (Status);\r
1016\r
1017 NumOfBlocks = FwhInstance->NumOfBlocks;\r
1018\r
1019 VA_START (args, This);\r
1020\r
1021 do {\r
1022 StartingLba = VA_ARG (args, EFI_LBA);\r
1023 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
1024 break;\r
1025 }\r
1026\r
1027 NumOfLba = VA_ARG (args, UINT32);\r
1028\r
1029 //\r
1030 // Check input parameters\r
1031 //\r
1032 if (NumOfLba == 0) {\r
1033 VA_END (args);\r
1034 return EFI_INVALID_PARAMETER;\r
1035 }\r
1036\r
1037 if ((StartingLba + NumOfLba) > NumOfBlocks) {\r
1038 return EFI_INVALID_PARAMETER;\r
1039 }\r
1040 } while (1);\r
1041\r
1042 VA_END (args);\r
1043\r
1044 VA_START (args, This);\r
1045 do {\r
1046 StartingLba = VA_ARG (args, EFI_LBA);\r
1047 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
1048 break;\r
1049 }\r
1050\r
1051 NumOfLba = VA_ARG (args, UINT32);\r
1052\r
1053 while (NumOfLba > 0) {\r
1054 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());\r
1055 if (EFI_ERROR (Status)) {\r
1056 VA_END (args);\r
1057 return Status;\r
1058 }\r
1059\r
1060 StartingLba++;\r
1061 NumOfLba--;\r
1062 }\r
1063\r
1064 } while (1);\r
1065\r
1066 VA_END (args);\r
1067\r
1068 return EFI_SUCCESS;\r
1069}\r
1070\r
1071EFI_STATUS\r
1072EFIAPI\r
1073FvbProtocolWrite (\r
1074 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1075 IN EFI_LBA Lba,\r
1076 IN UINTN Offset,\r
1077 IN OUT UINTN *NumBytes,\r
1078 IN UINT8 *Buffer\r
1079 )\r
1080/*++\r
1081\r
1082Routine Description:\r
1083\r
1084 Writes data beginning at Lba:Offset from FV. The write terminates either\r
1085 when *NumBytes of data have been written, or when a block boundary is\r
1086 reached. *NumBytes is updated to reflect the actual number of bytes\r
1087 written. The write opertion does not include erase. This routine will\r
1088 attempt to write only the specified bytes. If the writes do not stick,\r
1089 it will return an error.\r
1090\r
1091Arguments:\r
1092 This - Calling context\r
1093 Lba - Block in which to begin write\r
1094 Offset - Offset in the block at which to begin write\r
1095 NumBytes - On input, indicates the requested write size. On\r
1096 output, indicates the actual number of bytes written\r
1097 Buffer - Buffer containing source data for the write.\r
1098\r
1099Returns: \r
1100 EFI_SUCCESS - The firmware volume was written successfully\r
1101 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,\r
1102 NumBytes contains the total number of bytes\r
1103 actually written\r
1104 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
1105 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
1106 could not be written\r
1107 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL\r
1108\r
1109--*/\r
1110{\r
1111\r
1112 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1113\r
1114 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1115\r
1116 return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());\r
1117}\r
1118\r
1119EFI_STATUS\r
1120EFIAPI\r
1121FvbProtocolRead (\r
1122 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1123 IN EFI_LBA Lba,\r
1124 IN UINTN Offset,\r
1125 IN OUT UINTN *NumBytes,\r
1126 IN UINT8 *Buffer\r
1127 )\r
1128/*++\r
1129\r
1130Routine Description:\r
1131\r
1132 Reads data beginning at Lba:Offset from FV. The Read terminates either\r
1133 when *NumBytes of data have been read, or when a block boundary is\r
1134 reached. *NumBytes is updated to reflect the actual number of bytes\r
1135 written. The write opertion does not include erase. This routine will\r
1136 attempt to write only the specified bytes. If the writes do not stick,\r
1137 it will return an error.\r
1138\r
1139Arguments:\r
1140 This - Calling context\r
1141 Lba - Block in which to begin Read\r
1142 Offset - Offset in the block at which to begin Read\r
1143 NumBytes - On input, indicates the requested write size. On\r
1144 output, indicates the actual number of bytes Read\r
1145 Buffer - Buffer containing source data for the Read.\r
1146\r
1147Returns: \r
1148 EFI_SUCCESS - The firmware volume was read successfully and \r
1149 contents are in Buffer\r
1150 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,\r
1151 NumBytes contains the total number of bytes returned\r
1152 in Buffer\r
1153 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state\r
1154 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
1155 could not be read\r
1156 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL\r
1157\r
1158--*/\r
1159{\r
1160\r
1161 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1162\r
1163 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1164\r
1165 return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());\r
1166}\r
1167//\r
1168// FVB Extension Protocols\r
1169//\r
1170EFI_STATUS\r
1171EFIAPI\r
1172FvbExtendProtocolEraseCustomBlockRange (\r
1173 IN EFI_FVB_EXTENSION_PROTOCOL *This,\r
1174 IN EFI_LBA StartLba,\r
1175 IN UINTN OffsetStartLba,\r
1176 IN EFI_LBA LastLba,\r
1177 IN UINTN OffsetLastLba\r
1178 )\r
1179/*++\r
1180\r
1181Routine Description:\r
1182 Erases and initializes a specified range of a firmware volume\r
1183\r
1184Arguments:\r
1185 This - Calling context\r
1186 StartLba - The starting logical block index to be erased\r
1187 OffsetStartLba - Offset into the starting block at which to \r
1188 begin erasing\r
1189 LastLba - The last logical block index to be erased\r
1190 OffsetStartLba - Offset into the last block at which to end erasing\r
1191\r
1192Returns: \r
1193 EFI_SUCCESS - The firmware volume was erased successfully\r
1194 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
1195 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
1196 could not be written. Firmware device may have been\r
1197 partially erased\r
1198\r
1199--*/\r
1200{\r
1201 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1202\r
1203 FvbDevice = FVB_EXTEND_DEVICE_FROM_THIS (This);\r
1204\r
1205 return FvbEraseCustomBlockRange (\r
1206 FvbDevice->Instance,\r
1207 StartLba,\r
1208 OffsetStartLba,\r
1209 LastLba,\r
1210 OffsetLastLba,\r
1211 mFvbModuleGlobal,\r
1212 EfiGoneVirtual ()\r
1213 );\r
1214}\r
1215\r
804405e7 1216EFI_STATUS\r
1217ValidateFvHeader (\r
1218 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader\r
1219 )\r
1220/*++\r
1221\r
1222Routine Description:\r
1223 Check the integrity of firmware volume header\r
1224\r
1225Arguments:\r
1226 FwVolHeader - A pointer to a firmware volume header\r
1227\r
1228Returns: \r
1229 EFI_SUCCESS - The firmware volume is consistent\r
1230 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV\r
1231\r
1232--*/\r
1233{\r
1234 UINT16 *Ptr;\r
1235 UINT16 HeaderLength;\r
1236 UINT16 Checksum;\r
1237\r
1238 //\r
1239 // Verify the header revision, header signature, length\r
1240 // Length of FvBlock cannot be 2**64-1\r
1241 // HeaderLength cannot be an odd number\r
1242 //\r
1243 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||\r
1244 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||\r
1245 (FwVolHeader->FvLength == ((UINTN) -1)) ||\r
1246 ((FwVolHeader->HeaderLength & 0x01) != 0)\r
1247 ) {\r
1248 return EFI_NOT_FOUND;\r
1249 }\r
1250 //\r
1251 // Verify the header checksum\r
1252 //\r
1253 HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2);\r
1254 Ptr = (UINT16 *) FwVolHeader;\r
1255 Checksum = 0;\r
1256 while (HeaderLength > 0) {\r
1257 Checksum = Checksum + (*Ptr);\r
1258 HeaderLength--;\r
1259 Ptr++;\r
1260 }\r
1261\r
1262 if (Checksum != 0) {\r
1263 return EFI_NOT_FOUND;\r
1264 }\r
1265\r
1266 return EFI_SUCCESS;\r
1267}\r
1268\r
1269EFI_STATUS\r
1270EFIAPI\r
1271FvbInitialize (\r
1272 IN EFI_HANDLE ImageHandle,\r
1273 IN EFI_SYSTEM_TABLE *SystemTable\r
1274 )\r
1275/*++\r
1276\r
1277Routine Description:\r
1278 This function does common initialization for FVB services\r
1279\r
1280Arguments:\r
1281\r
1282Returns:\r
1283\r
1284--*/\r
1285{\r
1286 EFI_STATUS Status;\r
1287 EFI_FW_VOL_INSTANCE *FwhInstance;\r
1288 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
1289 EFI_DXE_SERVICES *DxeServices;\r
1290 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
1291 UINT32 BufferSize;\r
1292 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
1293 EFI_HANDLE FwbHandle;\r
1294 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1295 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;\r
1296 EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath;\r
1297 FV_DEVICE_PATH TempFvbDevicePathData;\r
1298 UINT32 MaxLbaSize;\r
1299 EFI_PHYSICAL_ADDRESS BaseAddress;\r
1300 UINT64 Length;\r
1301 UINTN NumOfBlocks;\r
1302 EFI_PEI_HOB_POINTERS FvHob;\r
1303\r
1304 //\r
1305 // Get the DXE services table\r
1306 //\r
1307 DxeServices = gDS;\r
1308\r
1309 //\r
1310 // Allocate runtime services data for global variable, which contains\r
1311 // the private data of all firmware volume block instances\r
1312 //\r
1313 Status = gBS->AllocatePool (\r
1314 EfiRuntimeServicesData,\r
1315 sizeof (ESAL_FWB_GLOBAL),\r
1316 (VOID**) &mFvbModuleGlobal\r
1317 );\r
1318 ASSERT_EFI_ERROR (Status);\r
1319\r
1320 //\r
1321 // Calculate the total size for all firmware volume block instances\r
1322 //\r
1323 BufferSize = 0;\r
1324\r
1325 FvHob.Raw = GetHobList ();\r
1326 while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {\r
1327 BaseAddress = FvHob.FirmwareVolume->BaseAddress;\r
1328 Length = FvHob.FirmwareVolume->Length;\r
1329 //\r
1330 // Check if it is a "real" flash\r
1331 //\r
1332 Status = DxeServices->GetMemorySpaceDescriptor (\r
1333 BaseAddress,\r
1334 &Descriptor\r
1335 );\r
1336 if (EFI_ERROR (Status)) {\r
1337 break;\r
1338 }\r
1339\r
1340 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {\r
1341 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1342 continue;\r
1343 }\r
1344\r
1345 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;\r
1346 Status = ValidateFvHeader (FwVolHeader);\r
1347 if (EFI_ERROR (Status)) {\r
1348 //\r
1349 // Get FvbInfo\r
1350 //\r
1351 Status = GetFvbInfo (Length, &FwVolHeader);\r
1352 if (EFI_ERROR (Status)) {\r
1353 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1354 continue;\r
1355 }\r
1356 }\r
1357\r
1358 BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
1359 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1360 }\r
1361\r
1362 //\r
1363 // Only need to allocate once. There is only one copy of physical memory for\r
1364 // the private data of each FV instance. But in virtual mode or in physical\r
1365 // mode, the address of the the physical memory may be different.\r
1366 //\r
1367 Status = gBS->AllocatePool (\r
1368 EfiRuntimeServicesData,\r
1369 BufferSize,\r
1370 (VOID**) &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]\r
1371 );\r
1372 ASSERT_EFI_ERROR (Status);\r
1373\r
1374 //\r
1375 // Make a virtual copy of the FvInstance pointer.\r
1376 //\r
1377 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];\r
1378 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;\r
1379\r
1380 mFvbModuleGlobal->NumFv = 0;\r
1381 MaxLbaSize = 0;\r
1382\r
1383 FvHob.Raw = GetHobList ();\r
1384 while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) {\r
1385 BaseAddress = FvHob.FirmwareVolume->BaseAddress;\r
1386 Length = FvHob.FirmwareVolume->Length;\r
1387 //\r
1388 // Check if it is a "real" flash\r
1389 //\r
1390 Status = DxeServices->GetMemorySpaceDescriptor (\r
1391 BaseAddress,\r
1392 &Descriptor\r
1393 );\r
1394 if (EFI_ERROR (Status)) {\r
1395 break;\r
1396 }\r
1397\r
1398 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {\r
1399 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1400 continue;\r
1401 }\r
1402\r
1403 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;\r
1404 Status = ValidateFvHeader (FwVolHeader);\r
1405 if (EFI_ERROR (Status)) {\r
1406 //\r
1407 // Get FvbInfo to provide in FwhInstance.\r
1408 //\r
1409 Status = GetFvbInfo (Length, &FwVolHeader);\r
1410 if (EFI_ERROR (Status)) {\r
1411 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1412 continue;\r
1413 }\r
1414 //\r
1415 // Write healthy FV header back.\r
1416 //\r
1417 CopyMem (\r
1418 (VOID *) (UINTN) BaseAddress,\r
1419 (VOID *) FwVolHeader,\r
1420 FwVolHeader->HeaderLength\r
1421 );\r
1422 }\r
1423\r
1424 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;\r
1425 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress;\r
1426\r
1427 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);\r
1428 FwVolHeader = &(FwhInstance->VolumeHeader);\r
1429 EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);\r
1430\r
1431 NumOfBlocks = 0;\r
1432\r
1433 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
1434 //\r
1435 // Get the maximum size of a block. The size will be used to allocate\r
1436 // buffer for Scratch space, the intermediate buffer for FVB extension\r
1437 // protocol\r
1438 //\r
1439 if (MaxLbaSize < PtrBlockMapEntry->Length) {\r
1440 MaxLbaSize = PtrBlockMapEntry->Length;\r
1441 }\r
1442\r
1443 NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;\r
1444 }\r
1445 //\r
1446 // The total number of blocks in the FV.\r
1447 //\r
1448 FwhInstance->NumOfBlocks = NumOfBlocks;\r
1449\r
1450 //\r
1451 // Add a FVB Protocol Instance\r
1452 //\r
1453 Status = gBS->AllocatePool (\r
1454 EfiRuntimeServicesData,\r
1455 sizeof (EFI_FW_VOL_BLOCK_DEVICE),\r
1456 (VOID**) &FvbDevice\r
1457 );\r
1458 ASSERT_EFI_ERROR (Status);\r
1459\r
1460 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));\r
1461\r
1462 FvbDevice->Instance = mFvbModuleGlobal->NumFv;\r
1463 mFvbModuleGlobal->NumFv++;\r
1464\r
1465 //\r
1466 // Set up the devicepath\r
1467 //\r
1468 FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;\r
1469 FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1);\r
1470\r
1471 //\r
1472 // Find a handle with a matching device path that has supports FW Block protocol\r
1473 //\r
1474 TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData;\r
1475 CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH));\r
1476 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);\r
1477 if (EFI_ERROR (Status)) {\r
1478 //\r
1479 // LocateDevicePath fails so install a new interface and device path\r
1480 //\r
1481 FwbHandle = NULL;\r
1482 Status = gBS->InstallMultipleProtocolInterfaces (\r
1483 &FwbHandle,\r
1484 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1485 &FvbDevice->FwVolBlockInstance,\r
1486 &gEfiDevicePathProtocolGuid,\r
1487 &FvbDevice->DevicePath,\r
1488 NULL\r
1489 );\r
1490 ASSERT_EFI_ERROR (Status);\r
1491 } else if (EfiIsDevicePathEnd (TempFwbDevicePath)) {\r
1492 //\r
1493 // Device allready exists, so reinstall the FVB protocol\r
1494 //\r
1495 Status = gBS->HandleProtocol (\r
1496 FwbHandle,\r
1497 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1498 (VOID**)&OldFwbInterface\r
1499 );\r
1500 ASSERT_EFI_ERROR (Status);\r
1501\r
1502 Status = gBS->ReinstallProtocolInterface (\r
1503 FwbHandle,\r
1504 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1505 OldFwbInterface,\r
1506 &FvbDevice->FwVolBlockInstance\r
1507 );\r
1508 ASSERT_EFI_ERROR (Status);\r
1509\r
1510 } else {\r
1511 //\r
1512 // There was a FVB protocol on an End Device Path node\r
1513 //\r
1514 ASSERT (FALSE);\r
1515 }\r
1516 //\r
1517 // Install FVB Extension Protocol on the same handle\r
1518 //\r
1519 Status = gBS->InstallMultipleProtocolInterfaces (\r
1520 &FwbHandle,\r
1521 &gEfiFvbExtensionProtocolGuid,\r
1522 &FvbDevice->FvbExtension,\r
1523 &gEfiAlternateFvBlockGuid,\r
1524 NULL,\r
1525 NULL\r
1526 );\r
1527\r
1528 ASSERT_EFI_ERROR (Status);\r
1529\r
1530 FwhInstance = (EFI_FW_VOL_INSTANCE *)\r
1531 (\r
1532 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +\r
1533 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))\r
1534 );\r
1535\r
1536 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1537 }\r
1538\r
1539 //\r
1540 // Allocate for scratch space, an intermediate buffer for FVB extention\r
1541 //\r
1542 Status = gBS->AllocatePool (\r
1543 EfiRuntimeServicesData,\r
1544 MaxLbaSize,\r
1545 (VOID**)&mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL]\r
1546 );\r
1547 ASSERT_EFI_ERROR (Status);\r
1548\r
1549 mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL];\r
1550\r
1551 return EFI_SUCCESS;\r
1552}\r