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