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