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