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