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