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