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