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