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