]> git.proxmox.com Git - mirror_edk2.git/blame - DuetPkg/FvbRuntimeService/FWBlockService.c
Patch to remove STATIC modifier. This is on longer recommended by EFI Framework codin...
[mirror_edk2.git] / DuetPkg / FvbRuntimeService / FWBlockService.c
CommitLineData
9071550e 1/**@file\r
2Copyright (c) 2007, Intel Corporation \r
3All rights reserved. This program and the accompanying materials \r
4are licensed and made available under the terms and conditions of the BSD License \r
5which accompanies this distribution. The full text of the license may be found at \r
6http://opensource.org/licenses/bsd-license.php \r
7 \r
8THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
9WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
10\r
11Module Name:\r
12\r
13 FWBlockService.c\r
14 \r
15Abstract:\r
16\r
17Revision History\r
18\r
19**/\r
20#include "FWBlockService.h"\r
21#include "EfiFlashMap.h"\r
22#include "FileIo.h"\r
23#include "FlashLayout.h"\r
24\r
25ESAL_FWB_GLOBAL *mFvbModuleGlobal;\r
26VOID *mSFSRegistration;\r
27#define TRY_ASSIGN(var, value) if(var != NULL) {*var = value;}\r
28\r
29EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {\r
30 FVB_DEVICE_SIGNATURE,\r
31 {\r
32 {\r
33 {\r
34 HARDWARE_DEVICE_PATH,\r
35 HW_MEMMAP_DP,\r
36 {\r
37 sizeof (MEMMAP_DEVICE_PATH),\r
38 0\r
39 }\r
40 },\r
41 EfiMemoryMappedIO,\r
42 0,\r
43 0,\r
44 },\r
45 {\r
46 END_DEVICE_PATH_TYPE,\r
47 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
48 {\r
49 sizeof (EFI_DEVICE_PATH_PROTOCOL),\r
50 0\r
51 }\r
52 }\r
53 },\r
54 0,\r
55 {\r
56 FvbProtocolGetAttributes,\r
57 FvbProtocolSetAttributes,\r
58 FvbProtocolGetPhysicalAddress,\r
59 FvbProtocolGetBlockSize,\r
60 FvbProtocolRead,\r
61 FvbProtocolWrite,\r
62 FvbProtocolEraseBlocks,\r
63 NULL\r
64 },\r
65 {\r
66 FvbExtendProtocolEraseCustomBlockRange\r
67 }\r
68};\r
69\r
70\r
71EFI_STATUS\r
72FlashFdWrite (\r
73 IN UINTN Address,\r
74 IN EFI_FW_VOL_INSTANCE *FwhInstance,\r
75 IN OUT UINTN *NumBytes,\r
76 IN UINT8 *Buffer\r
77 )\r
78/*++\r
79\r
80Routine Description:\r
81 Writes specified number of bytes from the input buffer to the address\r
82\r
83Arguments:\r
84\r
85Returns: \r
86\r
87--*/\r
88{\r
89 EFI_STATUS Status;\r
90 EFI_FILE *File;\r
91 UINTN FileOffset;\r
92 UINTN BufferForFile;\r
93 UINTN Length;\r
94\r
95 Status = EFI_SUCCESS;\r
96 CopyMem ((VOID *) Address, Buffer, *NumBytes);\r
97\r
98 if (!EfiAtRuntime () && (FwhInstance->Device != NULL)) {\r
99 Status = FileOpen (FwhInstance->Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE);\r
100 ASSERT_EFI_ERROR (Status);\r
101 if (!EFI_ERROR (Status)) {\r
102 if (Address - FwhInstance->FvBase[FVB_PHYSICAL] < FwhInstance->Offset) {\r
103 FileOffset = 0;\r
104 BufferForFile = FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset;\r
105 Length = *NumBytes - (FwhInstance->Offset - (Address - FwhInstance->FvBase[FVB_PHYSICAL]));\r
106 } else {\r
107 FileOffset = Address - FwhInstance->FvBase[FVB_PHYSICAL] - FwhInstance->Offset;\r
108 BufferForFile = Address;\r
109 Length = *NumBytes;\r
110 }\r
111 \r
112 Status = FileWrite (File, FileOffset, BufferForFile, Length);\r
113 ASSERT_EFI_ERROR (Status);\r
114 FileClose (File);\r
115 }\r
116 }\r
117 return Status;\r
118}\r
119\r
120EFI_STATUS\r
121FlashFdErase (\r
122 IN UINTN Address,\r
123 IN EFI_FW_VOL_INSTANCE *FwhInstance,\r
124 IN UINTN LbaLength\r
125 )\r
126/*++\r
127\r
128Routine Description:\r
129 Erase a certain block from address LbaWriteAddress\r
130\r
131Arguments:\r
132\r
133Returns: \r
134\r
135--*/\r
136{\r
137 EFI_STATUS Status;\r
138 EFI_FILE *File;\r
139 UINTN FileOffset;\r
140 UINTN BufferForFile;\r
141 UINTN Length;\r
142\r
143 Status = EFI_SUCCESS;\r
144\r
145 SetMem ((VOID *)Address, LbaLength, 0xff);\r
146\r
147 if (!EfiAtRuntime () && (FwhInstance->Device != NULL)) {\r
148 Status = FileOpen (FwhInstance->Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE);\r
149 ASSERT_EFI_ERROR (Status);\r
150 if (!EFI_ERROR (Status)) {\r
151 if (Address - FwhInstance->FvBase[FVB_PHYSICAL] < FwhInstance->Offset) {\r
152 FileOffset = 0;\r
153 BufferForFile = FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset;\r
154 Length = LbaLength - (FwhInstance->Offset - (Address - FwhInstance->FvBase[FVB_PHYSICAL]));\r
155 } else {\r
156 FileOffset = Address - FwhInstance->FvBase[FVB_PHYSICAL] - FwhInstance->Offset;\r
157 BufferForFile = Address;\r
158 Length = LbaLength;\r
159 }\r
160 \r
161 Status = FileWrite (File, FileOffset, BufferForFile, Length);\r
162 ASSERT_EFI_ERROR (Status);\r
163 FileClose (File);\r
164 }\r
165 }\r
166 return Status;\r
167}\r
168\r
169VOID\r
170EFIAPI\r
171FvbVirtualddressChangeEvent (\r
172 IN EFI_EVENT Event,\r
173 IN VOID *Context\r
174 )\r
175/*++\r
176\r
177Routine Description:\r
178\r
179 Fixup internal data so that EFI and SAL can be call in virtual mode.\r
180 Call the passed in Child Notify event and convert the mFvbModuleGlobal\r
181 date items to there virtual address.\r
182\r
183 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data\r
184 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common \r
185 instance data.\r
186\r
187Arguments:\r
188\r
189 (Standard EFI notify event - EFI_EVENT_NOTIFY)\r
190\r
191Returns: \r
192\r
193 None\r
194\r
195--*/\r
196{\r
197 EFI_FW_VOL_INSTANCE *FwhInstance;\r
198 UINTN Index;\r
199\r
200 EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]);\r
201\r
202 //\r
203 // Convert the base address of all the instances\r
204 //\r
205 Index = 0;\r
206 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];\r
207 while (Index < mFvbModuleGlobal->NumFv) {\r
208 EfiConvertPointer (0, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]);\r
209 FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) + FwhInstance->VolumeHeader.HeaderLength\r
210 + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));\r
211 Index++;\r
212 }\r
213\r
214 EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]);\r
215 EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal);\r
216}\r
217\r
218EFI_STATUS\r
219GetFvbInstance (\r
220 IN UINTN Instance,\r
221 IN ESAL_FWB_GLOBAL *Global,\r
222 OUT EFI_FW_VOL_INSTANCE **FwhInstance,\r
223 IN BOOLEAN Virtual\r
224 )\r
225/*++\r
226\r
227Routine Description:\r
228 Retrieves the physical address of a memory mapped FV\r
229\r
230Arguments:\r
231 Instance - The FV instance whose base address is going to be\r
232 returned\r
233 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
234 instance data\r
235 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure\r
236 Virtual - Whether CPU is in virtual or physical mode\r
237\r
238Returns: \r
239 EFI_SUCCESS - Successfully returns\r
240 EFI_INVALID_PARAMETER - Instance not found\r
241\r
242--*/\r
243{\r
244 EFI_FW_VOL_INSTANCE *FwhRecord;\r
245\r
246 if (Instance >= Global->NumFv) {\r
247 return EFI_INVALID_PARAMETER;\r
248 }\r
249 //\r
250 // Find the right instance of the FVB private data\r
251 //\r
252 FwhRecord = Global->FvInstance[Virtual];\r
253 while (Instance > 0) {\r
254 FwhRecord = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhRecord) + FwhRecord->VolumeHeader.HeaderLength \r
255 + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));\r
256 Instance--;\r
257 }\r
258\r
259 *FwhInstance = FwhRecord;\r
260\r
261 return EFI_SUCCESS;\r
262}\r
263\r
264EFI_STATUS\r
265FvbGetPhysicalAddress (\r
266 IN UINTN Instance,\r
267 OUT EFI_PHYSICAL_ADDRESS *Address,\r
268 IN ESAL_FWB_GLOBAL *Global,\r
269 IN BOOLEAN Virtual\r
270 )\r
271/*++\r
272\r
273Routine Description:\r
274 Retrieves the physical address of a memory mapped FV\r
275\r
276Arguments:\r
277 Instance - The FV instance whose base address is going to be\r
278 returned\r
279 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS \r
280 that on successful return, contains the base address\r
281 of the firmware volume. \r
282 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
283 instance data\r
284 Virtual - Whether CPU is in virtual or physical mode\r
285\r
286Returns: \r
287 EFI_SUCCESS - Successfully returns\r
288 EFI_INVALID_PARAMETER - Instance not found\r
289\r
290--*/\r
291{\r
292 EFI_FW_VOL_INSTANCE *FwhInstance;\r
293 EFI_STATUS Status;\r
294\r
295 //\r
296 // Find the right instance of the FVB private data\r
297 //\r
298 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
299 ASSERT_EFI_ERROR (Status);\r
300 *Address = FwhInstance->FvBase[Virtual];\r
301\r
302 return EFI_SUCCESS;\r
303}\r
304\r
305EFI_STATUS\r
306FvbGetVolumeAttributes (\r
307 IN UINTN Instance,\r
8ee3a199 308 OUT EFI_FVB_ATTRIBUTES_2 *Attributes,\r
9071550e 309 IN ESAL_FWB_GLOBAL *Global,\r
310 IN BOOLEAN Virtual\r
311 )\r
312/*++\r
313\r
314Routine Description:\r
315 Retrieves attributes, insures positive polarity of attribute bits, returns\r
316 resulting attributes in output parameter\r
317\r
318Arguments:\r
319 Instance - The FV instance whose attributes is going to be \r
320 returned\r
321 Attributes - Output buffer which contains attributes\r
322 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
323 instance data\r
324 Virtual - Whether CPU is in virtual or physical mode\r
325\r
326Returns: \r
327 EFI_SUCCESS - Successfully returns\r
328 EFI_INVALID_PARAMETER - Instance not found\r
329\r
330--*/\r
331{\r
332 EFI_FW_VOL_INSTANCE *FwhInstance;\r
333 EFI_STATUS Status;\r
334\r
335 //\r
336 // Find the right instance of the FVB private data\r
337 //\r
338 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
339 ASSERT_EFI_ERROR (Status);\r
340 *Attributes = FwhInstance->VolumeHeader.Attributes;\r
341\r
342 return EFI_SUCCESS;\r
343}\r
344\r
345EFI_STATUS\r
346FvbGetLbaAddress (\r
347 IN UINTN Instance,\r
348 IN EFI_LBA Lba,\r
349 OUT UINTN *LbaAddress OPTIONAL,\r
350 OUT UINTN *LbaLength OPTIONAL,\r
351 OUT UINTN *NumOfBlocks OPTIONAL,\r
352 IN ESAL_FWB_GLOBAL *Global,\r
353 IN BOOLEAN Virtual\r
354 )\r
355/*++\r
356\r
357Routine Description:\r
358 Retrieves the starting address of an LBA in an FV\r
359\r
360Arguments:\r
361 Instance - The FV instance which the Lba belongs to\r
362 Lba - The logical block address\r
363 LbaAddress - On output, contains the physical starting address\r
364 of the Lba for writing\r
365 LbaLength - On output, contains the length of the block\r
366 NumOfBlocks - A pointer to a caller allocated UINTN in which the\r
367 number of consecutive blocks starting with Lba is\r
368 returned. All blocks in this range have a size of\r
369 BlockSize\r
370 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
371 instance data\r
372 Virtual - Whether CPU is in virtual or physical mode\r
373\r
374Returns: \r
375 EFI_SUCCESS - Successfully returns\r
376 EFI_INVALID_PARAMETER - Instance not found\r
377\r
378--*/\r
379{\r
380 UINT32 NumBlocks;\r
381 UINT32 BlockLength;\r
382 UINTN Offset;\r
383 EFI_LBA StartLba;\r
384 EFI_LBA NextLba;\r
385 EFI_FW_VOL_INSTANCE *FwhInstance;\r
386 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
387 EFI_STATUS Status;\r
388\r
389 //\r
390 // Find the right instance of the FVB private data\r
391 //\r
392 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
393 ASSERT_EFI_ERROR (Status);\r
394\r
395 StartLba = 0;\r
396 Offset = 0;\r
397 BlockMap = &(FwhInstance->VolumeHeader.BlockMap[0]);\r
398\r
399 //\r
400 // Parse the blockmap of the FV to find which map entry the Lba belongs to\r
401 //\r
402 while (TRUE) {\r
403 NumBlocks = BlockMap->NumBlocks;\r
404 BlockLength = BlockMap->Length;\r
405\r
406 if (NumBlocks == 0 || BlockLength == 0) {\r
407 return EFI_INVALID_PARAMETER;\r
408 }\r
409\r
410 NextLba = StartLba + NumBlocks;\r
411\r
412 //\r
413 // The map entry found\r
414 //\r
415 if (Lba >= StartLba && Lba < NextLba) {\r
416 Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);\r
417\r
418 if (LbaAddress) {\r
419 *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;\r
420 }\r
421\r
422 if (LbaLength) {\r
423 *LbaLength = BlockLength;\r
424 }\r
425\r
426 if (NumOfBlocks) {\r
427 *NumOfBlocks = (UINTN) (NextLba - Lba);\r
428 }\r
429\r
430 return EFI_SUCCESS;\r
431 }\r
432\r
433 StartLba = NextLba;\r
434 Offset = Offset + NumBlocks * BlockLength;\r
435 BlockMap++;\r
436 }\r
437}\r
438\r
439EFI_STATUS\r
440FvbReadBlock (\r
441 IN UINTN Instance,\r
442 IN EFI_LBA Lba,\r
443 IN UINTN BlockOffset,\r
444 IN OUT UINTN *NumBytes,\r
445 IN UINT8 *Buffer,\r
446 IN ESAL_FWB_GLOBAL *Global,\r
447 IN BOOLEAN Virtual\r
448 )\r
449/*++\r
450\r
451Routine Description:\r
452 Reads specified number of bytes into a buffer from the specified block\r
453\r
454Arguments:\r
455 Instance - The FV instance to be read from\r
456 Lba - The logical block address to be read from\r
457 BlockOffset - Offset into the block at which to begin reading\r
458 NumBytes - Pointer that on input contains the total size of\r
459 the buffer. On output, it contains the total number\r
460 of bytes read\r
461 Buffer - Pointer to a caller allocated buffer that will be\r
462 used to hold the data read\r
463 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
464 instance data\r
465 Virtual - Whether CPU is in virtual or physical mode\r
466\r
467Returns: \r
468 EFI_SUCCESS - The firmware volume was read successfully and \r
469 contents are in Buffer\r
470 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,\r
471 NumBytes contains the total number of bytes returned\r
472 in Buffer\r
473 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state\r
474 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
475 could not be read\r
476 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL\r
477\r
478--*/\r
479{\r
8ee3a199 480 EFI_FVB_ATTRIBUTES_2 Attributes;\r
481 UINTN LbaAddress;\r
482 UINTN LbaLength;\r
483 EFI_STATUS Status;\r
9071550e 484\r
485 //\r
486 // Check for invalid conditions\r
487 //\r
488 if ((NumBytes == NULL) || (Buffer == NULL)) {\r
489 return EFI_INVALID_PARAMETER;\r
490 }\r
491\r
492 if (*NumBytes == 0) {\r
493 return EFI_INVALID_PARAMETER;\r
494 }\r
495\r
496 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);\r
497 if (EFI_ERROR (Status)) {\r
498 return Status;\r
499 }\r
500 //\r
501 // Check if the FV is read enabled\r
502 //\r
503 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
504\r
505 if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {\r
506 return EFI_ACCESS_DENIED;\r
507 }\r
508 //\r
509 // Perform boundary checks and adjust NumBytes\r
510 //\r
511 if (BlockOffset > LbaLength) {\r
512 return EFI_INVALID_PARAMETER;\r
513 }\r
514\r
515 if (LbaLength < (*NumBytes + BlockOffset)) {\r
516 *NumBytes = (UINT32) (LbaLength - BlockOffset);\r
517 Status = EFI_BAD_BUFFER_SIZE;\r
518 }\r
519\r
520 CopyMem (Buffer, (VOID *) (LbaAddress + BlockOffset), (UINTN) *NumBytes);\r
521\r
522 return Status;\r
523}\r
524EFI_STATUS\r
525FvbWriteBlock (\r
526 IN UINTN Instance,\r
527 IN EFI_LBA Lba,\r
528 IN UINTN BlockOffset,\r
529 IN OUT UINTN *NumBytes,\r
530 IN UINT8 *Buffer,\r
531 IN ESAL_FWB_GLOBAL *Global,\r
532 IN BOOLEAN Virtual\r
533 )\r
534/*++\r
535\r
536Routine Description:\r
537 Writes specified number of bytes from the input buffer to the block\r
538\r
539Arguments:\r
540 Instance - The FV instance to be written to\r
541 Lba - The starting logical block index to write to\r
542 BlockOffset - Offset into the block at which to begin writing\r
543 NumBytes - Pointer that on input contains the total size of\r
544 the buffer. On output, it contains the total number\r
545 of bytes actually written\r
546 Buffer - Pointer to a caller allocated buffer that contains\r
547 the source for the write\r
548 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
549 instance data\r
550 Virtual - Whether CPU is in virtual or physical mode\r
551\r
552Returns: \r
553 EFI_SUCCESS - The firmware volume was written successfully\r
554 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,\r
555 NumBytes contains the total number of bytes\r
556 actually written\r
557 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
558 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
559 could not be written\r
560 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL\r
561\r
562--*/\r
563{\r
8ee3a199 564 EFI_FVB_ATTRIBUTES_2 Attributes;\r
565 UINTN LbaAddress;\r
566 UINTN LbaLength;\r
567 EFI_FW_VOL_INSTANCE *FwhInstance;\r
568 EFI_STATUS Status;\r
569 EFI_STATUS ReturnStatus;\r
9071550e 570\r
571 //\r
572 // Find the right instance of the FVB private data\r
573 //\r
574 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
575 ASSERT_EFI_ERROR (Status);\r
576\r
577 //\r
578 // Writes are enabled in the init routine itself\r
579 //\r
580 if (!FwhInstance->WriteEnabled) {\r
581 return EFI_ACCESS_DENIED;\r
582 }\r
583 //\r
584 // Check for invalid conditions\r
585 //\r
586 if ((NumBytes == NULL) || (Buffer == NULL)) {\r
587 return EFI_INVALID_PARAMETER;\r
588 }\r
589\r
590 if (*NumBytes == 0) {\r
591 return EFI_INVALID_PARAMETER;\r
592 }\r
593\r
594 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);\r
595 if (EFI_ERROR (Status)) {\r
596 return Status;\r
597 }\r
598 //\r
599 // Check if the FV is write enabled\r
600 //\r
601 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
602\r
603 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {\r
604 return EFI_ACCESS_DENIED;\r
605 }\r
606 //\r
607 // Perform boundary checks and adjust NumBytes\r
608 //\r
609 if (BlockOffset > LbaLength) {\r
610 return EFI_INVALID_PARAMETER;\r
611 }\r
612\r
613 if (LbaLength < (*NumBytes + BlockOffset)) {\r
614 *NumBytes = (UINT32) (LbaLength - BlockOffset);\r
615 Status = EFI_BAD_BUFFER_SIZE;\r
616 }\r
617\r
618 ReturnStatus = FlashFdWrite (\r
619 LbaAddress + BlockOffset,\r
620 FwhInstance,\r
621 NumBytes,\r
622 Buffer\r
623 );\r
624 if (EFI_ERROR (ReturnStatus)) {\r
625 return ReturnStatus;\r
626 }\r
627\r
628 return Status;\r
629}\r
630\r
631EFI_STATUS\r
632FvbEraseBlock (\r
633 IN UINTN Instance,\r
634 IN EFI_LBA Lba,\r
635 IN ESAL_FWB_GLOBAL *Global,\r
636 IN BOOLEAN Virtual\r
637 )\r
638/*++\r
639\r
640Routine Description:\r
641 Erases and initializes a firmware volume block\r
642\r
643Arguments:\r
644 Instance - The FV instance to be erased\r
645 Lba - The logical block index to be erased\r
646 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
647 instance data\r
648 Virtual - Whether CPU is in virtual or physical mode\r
649\r
650Returns: \r
651 EFI_SUCCESS - The erase request was successfully completed\r
652 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
653 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
654 could not be written. Firmware device may have been\r
655 partially erased\r
656 EFI_INVALID_PARAMETER - Instance not found\r
657\r
658--*/\r
659{\r
660\r
8ee3a199 661 EFI_FVB_ATTRIBUTES_2 Attributes;\r
662 UINTN LbaAddress;\r
663 EFI_FW_VOL_INSTANCE *FwhInstance;\r
664 UINTN LbaLength;\r
665 EFI_STATUS Status;\r
9071550e 666\r
667 //\r
668 // Find the right instance of the FVB private data\r
669 //\r
670 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
671 ASSERT_EFI_ERROR (Status);\r
672\r
673 //\r
674 // Writes are enabled in the init routine itself\r
675 //\r
676 if (!FwhInstance->WriteEnabled) {\r
677 return EFI_ACCESS_DENIED;\r
678 }\r
679 //\r
680 // Check if the FV is write enabled\r
681 //\r
682 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);\r
683\r
684 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {\r
685 return EFI_ACCESS_DENIED;\r
686 }\r
687 //\r
688 // Get the starting address of the block for erase. For debug reasons,\r
689 // LbaWriteAddress may not be the same as LbaAddress.\r
690 //\r
691 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);\r
692 if (EFI_ERROR (Status)) {\r
693 return Status;\r
694 }\r
695\r
696 return FlashFdErase (\r
697 LbaAddress,\r
698 FwhInstance,\r
699 LbaLength\r
700 );\r
701}\r
702\r
703EFI_STATUS\r
704FvbEraseCustomBlockRange (\r
705 IN UINTN Instance,\r
706 IN EFI_LBA StartLba,\r
707 IN UINTN OffsetStartLba,\r
708 IN EFI_LBA LastLba,\r
709 IN UINTN OffsetLastLba,\r
710 IN ESAL_FWB_GLOBAL *Global,\r
711 IN BOOLEAN Virtual\r
712 )\r
713/*++\r
714\r
715Routine Description:\r
716 Erases and initializes a specified range of a firmware volume\r
717\r
718Arguments:\r
719 Instance - The FV instance to be erased\r
720 StartLba - The starting logical block index to be erased\r
721 OffsetStartLba - Offset into the starting block at which to \r
722 begin erasing\r
723 LastLba - The last logical block index to be erased\r
724 OffsetStartLba - Offset into the last block at which to end erasing\r
725 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
726 instance data\r
727 Virtual - Whether CPU is in virtual or physical mode\r
728\r
729Returns: \r
730 EFI_SUCCESS - The firmware volume was erased successfully\r
731 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
732 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
733 could not be written. Firmware device may have been\r
734 partially erased\r
735 EFI_INVALID_PARAMETER - Instance not found\r
736\r
737--*/\r
738{\r
739 EFI_LBA Index;\r
740 UINTN LbaSize;\r
741 UINTN ScratchLbaSizeData;\r
742\r
743 //\r
744 // First LBA.\r
745 //\r
746 FvbGetLbaAddress (Instance, StartLba, NULL, &LbaSize, NULL, Global, Virtual);\r
747\r
748 //\r
749 // Use the scratch space as the intermediate buffer to transfer data\r
750 // Back up the first LBA in scratch space.\r
751 //\r
752 FvbReadBlock (Instance, StartLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);\r
753\r
754 //\r
755 // erase now\r
756 //\r
757 FvbEraseBlock (Instance, StartLba, Global, Virtual);\r
758 ScratchLbaSizeData = OffsetStartLba;\r
759\r
760 //\r
761 // write the data back to the first block\r
762 //\r
763 if (ScratchLbaSizeData > 0) {\r
764 FvbWriteBlock (Instance, StartLba, 0, &ScratchLbaSizeData, Global->FvbScratchSpace[Virtual], Global, Virtual);\r
765 }\r
766 //\r
767 // Middle LBAs\r
768 //\r
769 if (LastLba > (StartLba + 1)) {\r
770 for (Index = (StartLba + 1); Index <= (LastLba - 1); Index++) {\r
771 FvbEraseBlock (Instance, Index, Global, Virtual);\r
772 }\r
773 }\r
774 //\r
775 // Last LBAs, the same as first LBAs\r
776 //\r
777 if (LastLba > StartLba) {\r
778 FvbGetLbaAddress (Instance, LastLba, NULL, &LbaSize, NULL, Global, Virtual);\r
779 FvbReadBlock (Instance, LastLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);\r
780 FvbEraseBlock (Instance, LastLba, Global, Virtual);\r
781 }\r
782\r
783 ScratchLbaSizeData = LbaSize - (OffsetStartLba + 1);\r
784\r
785 return FvbWriteBlock (\r
786 Instance,\r
787 LastLba,\r
788 (OffsetLastLba + 1),\r
789 &ScratchLbaSizeData,\r
790 Global->FvbScratchSpace[Virtual],\r
791 Global,\r
792 Virtual\r
793 );\r
794}\r
795\r
796EFI_STATUS\r
797FvbSetVolumeAttributes (\r
798 IN UINTN Instance,\r
8ee3a199 799 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes,\r
9071550e 800 IN ESAL_FWB_GLOBAL *Global,\r
801 IN BOOLEAN Virtual\r
802 )\r
803/*++\r
804\r
805Routine Description:\r
806 Modifies the current settings of the firmware volume according to the \r
807 input parameter, and returns the new setting of the volume\r
808\r
809Arguments:\r
810 Instance - The FV instance whose attributes is going to be \r
811 modified\r
8ee3a199 812 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2 \r
9071550e 813 containing the desired firmware volume settings.\r
814 On successful return, it contains the new settings\r
815 of the firmware volume\r
816 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
817 instance data\r
818 Virtual - Whether CPU is in virtual or physical mode\r
819\r
820Returns: \r
821 EFI_SUCCESS - Successfully returns\r
822 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified\r
823 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are\r
824 in conflict with the capabilities as declared in the\r
825 firmware volume header\r
826\r
827--*/\r
828{\r
8ee3a199 829 EFI_FW_VOL_INSTANCE *FwhInstance;\r
830 EFI_FVB_ATTRIBUTES_2 OldAttributes;\r
831 EFI_FVB_ATTRIBUTES_2 *AttribPtr;\r
832 UINT32 Capabilities;\r
833 UINT32 OldStatus;\r
834 UINT32 NewStatus;\r
835 EFI_STATUS Status;\r
9071550e 836\r
837 //\r
838 // Find the right instance of the FVB private data\r
839 //\r
840 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
841 ASSERT_EFI_ERROR (Status);\r
842\r
8ee3a199 843 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);\r
9071550e 844 OldAttributes = *AttribPtr;\r
845 Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES;\r
846 OldStatus = OldAttributes & EFI_FVB2_STATUS;\r
847 NewStatus = *Attributes & EFI_FVB2_STATUS;\r
848\r
849 //\r
850 // If firmware volume is locked, no status bit can be updated\r
851 //\r
852 if (OldAttributes & EFI_FVB2_LOCK_STATUS) {\r
853 if (OldStatus ^ NewStatus) {\r
854 return EFI_ACCESS_DENIED;\r
855 }\r
856 }\r
857 //\r
858 // Test read disable\r
859 //\r
860 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {\r
861 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {\r
862 return EFI_INVALID_PARAMETER;\r
863 }\r
864 }\r
865 //\r
866 // Test read enable\r
867 //\r
868 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {\r
869 if (NewStatus & EFI_FVB2_READ_STATUS) {\r
870 return EFI_INVALID_PARAMETER;\r
871 }\r
872 }\r
873 //\r
874 // Test write disable\r
875 //\r
876 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {\r
877 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {\r
878 return EFI_INVALID_PARAMETER;\r
879 }\r
880 }\r
881 //\r
882 // Test write enable\r
883 //\r
884 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {\r
885 if (NewStatus & EFI_FVB2_WRITE_STATUS) {\r
886 return EFI_INVALID_PARAMETER;\r
887 }\r
888 }\r
889 //\r
890 // Test lock\r
891 //\r
892 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {\r
893 if (NewStatus & EFI_FVB2_LOCK_STATUS) {\r
894 return EFI_INVALID_PARAMETER;\r
895 }\r
896 }\r
897\r
898 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));\r
899 *AttribPtr = (*AttribPtr) | NewStatus;\r
900 *Attributes = *AttribPtr;\r
901\r
902 return EFI_SUCCESS;\r
903}\r
904//\r
905// FVB protocol APIs\r
906//\r
907EFI_STATUS\r
908EFIAPI\r
909FvbProtocolGetPhysicalAddress (\r
910 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
911 OUT EFI_PHYSICAL_ADDRESS *Address\r
912 )\r
913/*++\r
914\r
915Routine Description:\r
916\r
917 Retrieves the physical address of the device.\r
918\r
919Arguments:\r
920\r
921 This - Calling context\r
922 Address - Output buffer containing the address.\r
923\r
924Returns:\r
925\r
926Returns: \r
927 EFI_SUCCESS - Successfully returns\r
928\r
929--*/\r
930{\r
931 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
932\r
933 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
934\r
935 return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());\r
936}\r
937\r
938EFI_STATUS\r
939EFIAPI\r
940FvbProtocolGetBlockSize (\r
941 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
942 IN EFI_LBA Lba,\r
943 OUT UINTN *BlockSize,\r
944 OUT UINTN *NumOfBlocks\r
945 )\r
946/*++\r
947\r
948Routine Description:\r
949 Retrieve the size of a logical block\r
950\r
951Arguments:\r
952 This - Calling context\r
953 Lba - Indicates which block to return the size for.\r
954 BlockSize - A pointer to a caller allocated UINTN in which\r
955 the size of the block is returned\r
956 NumOfBlocks - a pointer to a caller allocated UINTN in which the\r
957 number of consecutive blocks starting with Lba is\r
958 returned. All blocks in this range have a size of\r
959 BlockSize\r
960\r
961Returns: \r
962 EFI_SUCCESS - The firmware volume was read successfully and \r
963 contents are in Buffer\r
964\r
965--*/\r
966{\r
967 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
968\r
969 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
970\r
971 return FvbGetLbaAddress (\r
972 FvbDevice->Instance,\r
973 Lba,\r
974 NULL,\r
975 BlockSize,\r
976 NumOfBlocks,\r
977 mFvbModuleGlobal,\r
978 EfiGoneVirtual ()\r
979 );\r
980}\r
981\r
982EFI_STATUS\r
983EFIAPI\r
984FvbProtocolGetAttributes (\r
985 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
8ee3a199 986 OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
9071550e 987 )\r
988/*++\r
989\r
990Routine Description:\r
991 Retrieves Volume attributes. No polarity translations are done.\r
992\r
993Arguments:\r
994 This - Calling context\r
995 Attributes - output buffer which contains attributes\r
996\r
997Returns: \r
998 EFI_SUCCESS - Successfully returns\r
999\r
1000--*/\r
1001{\r
1002 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1003\r
1004 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1005\r
1006 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());\r
1007}\r
1008\r
1009EFI_STATUS\r
1010EFIAPI\r
1011FvbProtocolSetAttributes (\r
1012 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
8ee3a199 1013 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
9071550e 1014 )\r
1015/*++\r
1016\r
1017Routine Description:\r
1018 Sets Volume attributes. No polarity translations are done.\r
1019\r
1020Arguments:\r
1021 This - Calling context\r
1022 Attributes - output buffer which contains attributes\r
1023\r
1024Returns: \r
1025 EFI_SUCCESS - Successfully returns\r
1026\r
1027--*/\r
1028{\r
1029 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1030\r
1031 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1032\r
1033 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());\r
1034}\r
1035\r
1036EFI_STATUS\r
1037EFIAPI\r
1038FvbProtocolEraseBlocks (\r
1039 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1040 ... \r
1041 )\r
1042/*++\r
1043\r
1044Routine Description:\r
1045\r
1046 The EraseBlock() function erases one or more blocks as denoted by the \r
1047 variable argument list. The entire parameter list of blocks must be verified\r
1048 prior to erasing any blocks. If a block is requested that does not exist \r
1049 within the associated firmware volume (it has a larger index than the last \r
1050 block of the firmware volume), the EraseBlock() function must return\r
1051 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.\r
1052\r
1053Arguments:\r
1054 This - Calling context\r
1055 ... - Starting LBA followed by Number of Lba to erase. \r
1056 a -1 to terminate the list.\r
1057\r
1058Returns: \r
1059 EFI_SUCCESS - The erase request was successfully completed\r
1060 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
1061 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
1062 could not be written. Firmware device may have been\r
1063 partially erased\r
1064\r
1065--*/\r
1066{\r
1067 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1068 EFI_FW_VOL_INSTANCE *FwhInstance;\r
1069 UINTN NumOfBlocks;\r
1070 VA_LIST args;\r
1071 EFI_LBA StartingLba;\r
1072 UINTN NumOfLba;\r
1073 EFI_STATUS Status;\r
1074\r
1075 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1076\r
1077 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());\r
1078 ASSERT_EFI_ERROR (Status);\r
1079\r
1080 NumOfBlocks = FwhInstance->NumOfBlocks;\r
1081\r
1082 VA_START (args, This);\r
1083\r
1084 do {\r
1085 StartingLba = VA_ARG (args, EFI_LBA);\r
1086 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
1087 break;\r
1088 }\r
1089\r
1090 NumOfLba = VA_ARG (args, UINT32);\r
1091\r
1092 //\r
1093 // Check input parameters\r
1094 //\r
1095 if ((NumOfLba == 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) {\r
1096 VA_END (args);\r
1097 return EFI_INVALID_PARAMETER;\r
1098 }\r
1099 } while (1);\r
1100\r
1101 VA_END (args);\r
1102\r
1103 VA_START (args, This);\r
1104 do {\r
1105 StartingLba = VA_ARG (args, EFI_LBA);\r
1106 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
1107 break;\r
1108 }\r
1109\r
1110 NumOfLba = VA_ARG (args, UINT32);\r
1111\r
1112 while (NumOfLba > 0) {\r
1113 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());\r
1114 if (EFI_ERROR (Status)) {\r
1115 VA_END (args);\r
1116 return Status;\r
1117 }\r
1118\r
1119 StartingLba++;\r
1120 NumOfLba--;\r
1121 }\r
1122\r
1123 } while (1);\r
1124\r
1125 VA_END (args);\r
1126\r
1127 return EFI_SUCCESS;\r
1128}\r
1129\r
1130EFI_STATUS\r
1131EFIAPI\r
1132FvbProtocolWrite (\r
1133 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1134 IN EFI_LBA Lba,\r
1135 IN UINTN Offset,\r
1136 IN OUT UINTN *NumBytes,\r
1137 IN UINT8 *Buffer\r
1138 )\r
1139/*++\r
1140\r
1141Routine Description:\r
1142\r
1143 Writes data beginning at Lba:Offset from FV. The write terminates either\r
1144 when *NumBytes of data have been written, or when a block boundary is\r
1145 reached. *NumBytes is updated to reflect the actual number of bytes\r
1146 written. The write opertion does not include erase. This routine will\r
1147 attempt to write only the specified bytes. If the writes do not stick,\r
1148 it will return an error.\r
1149\r
1150Arguments:\r
1151 This - Calling context\r
1152 Lba - Block in which to begin write\r
1153 Offset - Offset in the block at which to begin write\r
1154 NumBytes - On input, indicates the requested write size. On\r
1155 output, indicates the actual number of bytes written\r
1156 Buffer - Buffer containing source data for the write.\r
1157\r
1158Returns: \r
1159 EFI_SUCCESS - The firmware volume was written successfully\r
1160 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,\r
1161 NumBytes contains the total number of bytes\r
1162 actually written\r
1163 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
1164 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
1165 could not be written\r
1166 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL\r
1167\r
1168--*/\r
1169{\r
1170\r
1171 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1172\r
1173 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1174\r
1175 return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());\r
1176}\r
1177\r
1178EFI_STATUS\r
1179EFIAPI\r
1180FvbProtocolRead (\r
1181 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1182 IN EFI_LBA Lba,\r
1183 IN UINTN Offset,\r
1184 IN OUT UINTN *NumBytes,\r
1185 IN UINT8 *Buffer\r
1186 )\r
1187/*++\r
1188\r
1189Routine Description:\r
1190\r
1191 Reads data beginning at Lba:Offset from FV. The Read terminates either\r
1192 when *NumBytes of data have been read, or when a block boundary is\r
1193 reached. *NumBytes is updated to reflect the actual number of bytes\r
1194 written. The write opertion does not include erase. This routine will\r
1195 attempt to write only the specified bytes. If the writes do not stick,\r
1196 it will return an error.\r
1197\r
1198Arguments:\r
1199 This - Calling context\r
1200 Lba - Block in which to begin Read\r
1201 Offset - Offset in the block at which to begin Read\r
1202 NumBytes - On input, indicates the requested write size. On\r
1203 output, indicates the actual number of bytes Read\r
1204 Buffer - Buffer containing source data for the Read.\r
1205\r
1206Returns: \r
1207 EFI_SUCCESS - The firmware volume was read successfully and \r
1208 contents are in Buffer\r
1209 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,\r
1210 NumBytes contains the total number of bytes returned\r
1211 in Buffer\r
1212 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state\r
1213 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
1214 could not be read\r
1215 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL\r
1216\r
1217--*/\r
1218{\r
1219\r
1220 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1221\r
1222 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1223\r
1224 return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());\r
1225}\r
1226//\r
1227// FVB Extension Protocols\r
1228//\r
1229EFI_STATUS\r
1230EFIAPI\r
1231FvbExtendProtocolEraseCustomBlockRange (\r
1232 IN EFI_FVB_EXTENSION_PROTOCOL *This,\r
1233 IN EFI_LBA StartLba,\r
1234 IN UINTN OffsetStartLba,\r
1235 IN EFI_LBA LastLba,\r
1236 IN UINTN OffsetLastLba\r
1237 )\r
1238/*++\r
1239\r
1240Routine Description:\r
1241 Erases and initializes a specified range of a firmware volume\r
1242\r
1243Arguments:\r
1244 This - Calling context\r
1245 StartLba - The starting logical block index to be erased\r
1246 OffsetStartLba - Offset into the starting block at which to \r
1247 begin erasing\r
1248 LastLba - The last logical block index to be erased\r
1249 OffsetStartLba - Offset into the last block at which to end erasing\r
1250\r
1251Returns: \r
1252 EFI_SUCCESS - The firmware volume was erased successfully\r
1253 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
1254 EFI_DEVICE_ERROR - The block device is not functioning correctly and \r
1255 could not be written. Firmware device may have been\r
1256 partially erased\r
1257\r
1258--*/\r
1259{\r
1260 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1261\r
1262 FvbDevice = FVB_EXTEND_DEVICE_FROM_THIS (This);\r
1263\r
1264 return FvbEraseCustomBlockRange (\r
1265 FvbDevice->Instance,\r
1266 StartLba,\r
1267 OffsetStartLba,\r
1268 LastLba,\r
1269 OffsetLastLba,\r
1270 mFvbModuleGlobal,\r
1271 EfiGoneVirtual ()\r
1272 );\r
1273}\r
1274\r
9071550e 1275EFI_STATUS\r
1276ValidateFvHeader (\r
1277 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader\r
1278 )\r
1279/*++\r
1280\r
1281Routine Description:\r
1282 Check the integrity of firmware volume header\r
1283\r
1284Arguments:\r
1285 FwVolHeader - A pointer to a firmware volume header\r
1286\r
1287Returns: \r
1288 EFI_SUCCESS - The firmware volume is consistent\r
1289 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV\r
1290\r
1291--*/\r
1292{\r
1293 UINT16 *Ptr;\r
1294 UINT16 HeaderLength;\r
1295 UINT16 Checksum;\r
1296\r
1297 //\r
1298 // Verify the header revision, header signature, length\r
1299 // Length of FvBlock cannot be 2**64-1\r
1300 // HeaderLength cannot be an odd number\r
1301 //\r
1302 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||\r
1303 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||\r
1304 (FwVolHeader->FvLength == ((UINTN) -1)) ||\r
1305 ((FwVolHeader->HeaderLength & 0x01) != 0)\r
1306 ) {\r
1307 return EFI_NOT_FOUND;\r
1308 }\r
1309 //\r
1310 // Verify the header checksum\r
1311 //\r
1312 HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2);\r
1313 Ptr = (UINT16 *) FwVolHeader;\r
1314 Checksum = 0;\r
1315 while (HeaderLength > 0) {\r
1316 Checksum = Checksum + (*Ptr);\r
1317 HeaderLength--;\r
1318 Ptr++;\r
1319 }\r
1320\r
1321 if (Checksum != 0) {\r
1322 return EFI_NOT_FOUND;\r
1323 }\r
1324\r
1325 return EFI_SUCCESS;\r
1326}\r
1327\r
1328\r
1329EFI_STATUS\r
1330GetFvbHeader (\r
eb16e240 1331 IN OUT EFI_PEI_HOB_POINTERS *HobList,\r
9071550e 1332 OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader,\r
1333 OUT EFI_PHYSICAL_ADDRESS *BaseAddress OPTIONAL,\r
1334 OUT UINT32 *VolumeId OPTIONAL,\r
1335 OUT CHAR16 **MappedFile OPTIONAL,\r
1336 OUT UINT32 *ActuralSize OPTIONAL,\r
1337 OUT UINT32 *Offset OPTIONAL,\r
1338 OUT BOOLEAN *WriteBack OPTIONAL\r
1339 )\r
1340{\r
1341 EFI_STATUS Status;\r
9071550e 1342 EFI_FLASH_MAP_FS_ENTRY_DATA *FlashMapEntry;\r
1343 EFI_FLASH_SUBAREA_ENTRY *FlashMapSubEntry;\r
1344\r
1345 Status = EFI_SUCCESS;\r
1346 *FwVolHeader = NULL;\r
1347 TRY_ASSIGN (WriteBack, FALSE);\r
1348\r
eb16e240 1349 DEBUG ((EFI_D_INFO, "Hob start is 0x%x\n", (UINTN)(*HobList).Raw));\r
1350 (*HobList).Raw = GetNextGuidHob (&gEfiFlashMapHobGuid, (*HobList).Raw);\r
1351 if ((*HobList).Raw == NULL) {\r
9071550e 1352 return EFI_NOT_FOUND;\r
1353 }\r
1354\r
eb16e240 1355 FlashMapEntry = (EFI_FLASH_MAP_FS_ENTRY_DATA *) GET_GUID_HOB_DATA ((*HobList).Guid);\r
9071550e 1356 FlashMapSubEntry = &FlashMapEntry->Entries[0];\r
eb16e240 1357 \r
9071550e 1358 //\r
1359 // Check if it is a "FVB" area\r
1360 //\r
1361 if (!CompareGuid (&FlashMapSubEntry->FileSystem, &gEfiFirmwareVolumeBlockProtocolGuid)) {\r
1362 return Status;\r
1363 }\r
1364 //\r
1365 // Check if it is a "real" flash\r
1366 //\r
1367 if (FlashMapSubEntry->Attributes != (EFI_FLASH_AREA_FV | EFI_FLASH_AREA_MEMMAPPED_FV)) {\r
1368 return Status;\r
1369 }\r
1370\r
1371 TRY_ASSIGN (BaseAddress, FlashMapSubEntry->Base);\r
1372\r
1373 //\r
1374 // Cast buffer to FLASH_AREA_INFO to get extra information related to the special FVB driver\r
1375 //\r
1376 TRY_ASSIGN (VolumeId, FlashMapEntry->VolumeId);\r
1377 TRY_ASSIGN (ActuralSize, FlashMapEntry->ActuralSize);\r
1378 TRY_ASSIGN (MappedFile, ((CHAR16 *) FlashMapEntry->FilePath));\r
1379 TRY_ASSIGN (Offset, FlashMapEntry->Offset);\r
1380\r
1381 DEBUG ((\r
be768885 1382 EFI_D_INFO, \r
9071550e 1383 "FlashMap HOB: BaseAddress = 0x%x, Length = 0x%x, ActuralLength = 0x%x, Offset = 0x%x\n", \r
1384 (UINTN) FlashMapSubEntry->Base, (UINTN) FlashMapSubEntry->Length, \r
1385 (UINTN) FlashMapEntry->ActuralSize, (UINTN) FlashMapEntry->Offset\r
1386 ));\r
1387 DEBUG ((\r
be768885 1388 EFI_D_INFO,\r
9071550e 1389 "FlashMap HOB: VolumeId = 0x%lx, MappedFile = %s\n",\r
1390 (UINTN) FlashMapEntry->VolumeId, (UINTN) FlashMapEntry->FilePath\r
1391 ));\r
1392 *FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (FlashMapSubEntry->Base);\r
1393 Status = ValidateFvHeader (*FwVolHeader);\r
1394 if (EFI_ERROR (Status)) {\r
1395 //\r
1396 // Get FvbInfo\r
1397 //\r
1398 TRY_ASSIGN (WriteBack, TRUE);\r
1399 Status = GetFvbInfo (FlashMapSubEntry->Length, FwVolHeader);\r
1400 DEBUG ((EFI_D_ERROR, "Fvb: FV header invalid, GetFvbInfo - %r\n", Status));\r
1401 ASSERT_EFI_ERROR (Status);\r
1402 }\r
1403\r
1404 return EFI_SUCCESS;\r
1405}\r
1406\r
9071550e 1407VOID\r
1408EFIAPI\r
1409OnSimpleFileSystemInstall (\r
1410 IN EFI_EVENT Event,\r
1411 IN VOID *Context\r
1412 )\r
1413{\r
1414 EFI_STATUS Status;\r
1415 UINTN HandleSize;\r
1416 EFI_HANDLE Handle;\r
1417 UINTN Instance;\r
1418 EFI_DEVICE_PATH_PROTOCOL *Device;\r
1419 EFI_FILE *File;\r
1420 EFI_FW_VOL_INSTANCE *FwhInstance;\r
1421 while (TRUE) {\r
1422 HandleSize = sizeof (EFI_HANDLE);\r
1423 Status = gBS->LocateHandle (\r
1424 ByRegisterNotify,\r
1425 NULL,\r
1426 mSFSRegistration,\r
1427 &HandleSize,\r
1428 &Handle\r
1429 );\r
1430 if (Status == EFI_NOT_FOUND) {\r
1431 break;\r
1432 }\r
1433 DEBUG ((EFI_D_ERROR, "Fwh: New FileSystem Installed!\n"));\r
1434 ASSERT_EFI_ERROR (Status);\r
1435 //\r
1436 // Check if this is the storage we care about, and store it in FwhInstance\r
1437 //\r
1438 for (Instance = 0; Instance < mFvbModuleGlobal->NumFv; ++Instance) {\r
1439 Status = GetFvbInstance (Instance, mFvbModuleGlobal, &FwhInstance, FALSE);\r
1440 ASSERT_EFI_ERROR (Status);\r
1441\r
1442 if (FwhInstance->MappedFile[0] == L'\0') {\r
1443 //\r
1444 // The instance of FVB isn't mapped to file.\r
1445 //\r
1446 continue;\r
1447 }\r
1448\r
1449 if ((FwhInstance->Device != NULL) && \r
1450 !EFI_ERROR (CheckStoreExists (FwhInstance->Device))\r
1451 ) {\r
1452 //\r
1453 // The instance of FVB has already associated to a device\r
1454 // and the device is not removed from system.\r
1455 //\r
1456 DEBUG ((\r
1457 EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Already mapped, Skip!\n", \r
1458 (UINTN) FwhInstance->FvBase[FVB_PHYSICAL],\r
1459 (UINTN) FwhInstance->Offset\r
1460 ));\r
1461 continue;\r
1462 }\r
1463\r
1464 Status = CheckStore (Handle, FwhInstance->VolumeId, &Device);\r
1465 if (!EFI_ERROR (Status)) {\r
1466 //\r
1467 // Write back memory content to file\r
1468 //\r
1469 Status = FileOpen (Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ | EFI_FILE_MODE_CREATE);\r
1470 ASSERT_EFI_ERROR (Status); \r
1471 if (!EFI_ERROR (Status)) {\r
1472 DEBUG ((\r
1473 EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Write back to mapped file!\n", \r
1474 (UINTN) FwhInstance->FvBase[FVB_PHYSICAL],\r
1475 (UINTN) FwhInstance->Offset\r
1476 ));\r
1477 Status = FileWrite (\r
1478 File, \r
1479 0, \r
1480 FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset, \r
1481 FwhInstance->ActuralSize - FwhInstance->Offset\r
1482 );\r
1483 ASSERT_EFI_ERROR (Status); \r
1484 if (!EFI_ERROR (Status)) {\r
1485 if (FwhInstance->Device != NULL) {\r
1486 gBS->FreePool (FwhInstance->Device);\r
1487 }\r
1488 FwhInstance->Device = Device;\r
1489 DEBUG ((\r
1490 EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Mapped!\n",\r
1491 (UINTN) FwhInstance->FvBase[FVB_PHYSICAL],\r
1492 (UINTN) FwhInstance->Offset\r
1493 ));\r
1494 }\r
1495 FileClose (File);\r
1496 }\r
1497 }\r
1498 }\r
1499 }\r
1500}\r
1501\r
9071550e 1502VOID\r
1503FvbInstallSfsNotify (\r
1504 VOID\r
1505)\r
1506{\r
1507 EFI_STATUS Status;\r
1508 EFI_EVENT Event;\r
1509\r
1510 Status = gBS->CreateEvent (\r
e53a6ea9 1511 EVT_NOTIFY_SIGNAL,\r
9071550e 1512 TPL_CALLBACK,\r
1513 OnSimpleFileSystemInstall,\r
1514 NULL,\r
1515 &Event\r
1516 );\r
1517 ASSERT_EFI_ERROR (Status);\r
1518\r
1519 Status = gBS->RegisterProtocolNotify (\r
1520 &gEfiSimpleFileSystemProtocolGuid,\r
1521 Event,\r
1522 &mSFSRegistration\r
1523 );\r
1524 ASSERT_EFI_ERROR (Status);\r
1525}\r
1526\r
1527\r
1528EFI_STATUS\r
1529EFIAPI\r
1530FvbInitialize (\r
1531 IN EFI_HANDLE ImageHandle,\r
1532 IN EFI_SYSTEM_TABLE *SystemTable\r
1533 )\r
1534/*++\r
1535\r
1536Routine Description:\r
1537 This function does common initialization for FVB services\r
1538\r
1539Arguments:\r
1540\r
1541Returns:\r
1542\r
1543--*/\r
1544{\r
1545 EFI_STATUS Status;\r
1546 EFI_FW_VOL_INSTANCE *FwhInstance;\r
1547 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
eb16e240 1548 EFI_PEI_HOB_POINTERS FirmwareVolumeHobList;\r
9071550e 1549 UINT32 BufferSize;\r
1550 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
1551 UINTN LbaAddress;\r
1552 EFI_HANDLE FwbHandle;\r
1553 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1554 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;\r
1555 EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath;\r
1556 FV_DEVICE_PATH TempFvbDevicePathData;\r
1557 UINT32 MaxLbaSize;\r
1558 EFI_PHYSICAL_ADDRESS BaseAddress;\r
1559 UINT32 VolumeId;\r
1560 CHAR16 *MappedFile;\r
1561 UINT32 ActuralSize;\r
1562 UINT32 Offset;\r
1563 BOOLEAN WriteBack;\r
1564 UINTN NumOfBlocks;\r
1565 UINTN HeaderLength;\r
1566 BOOLEAN InstallSfsNotify;\r
1567\r
9071550e 1568 HeaderLength = 0;\r
1569 InstallSfsNotify = FALSE;\r
1570\r
1571 //\r
1572 // Allocate runtime services data for global variable, which contains\r
1573 // the private data of all firmware volume block instances\r
1574 //\r
1575 Status = gBS->AllocatePool (\r
1576 EfiRuntimeServicesData,\r
1577 sizeof (ESAL_FWB_GLOBAL),\r
1578 &mFvbModuleGlobal\r
1579 );\r
1580 ASSERT_EFI_ERROR (Status);\r
1581 //\r
1582 // Calculate the total size for all firmware volume block instances\r
1583 //\r
1584 BufferSize = 0;\r
eb16e240 1585 FirmwareVolumeHobList.Raw = GetHobList();\r
9071550e 1586 do {\r
1587 Status = GetFvbHeader (&FirmwareVolumeHobList, &FwVolHeader, NULL, NULL, NULL, NULL, NULL, NULL);\r
1588 if (EFI_ERROR (Status)) {\r
1589 break;\r
1590 }\r
eb16e240 1591 FirmwareVolumeHobList.Raw = GET_NEXT_HOB (FirmwareVolumeHobList);\r
9071550e 1592\r
1593 if (FwVolHeader) {\r
1594 BufferSize += (FwVolHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
1595 }\r
1596 } while (TRUE);\r
1597\r
1598 //\r
1599 // Only need to allocate once. There is only one copy of physical memory for\r
1600 // the private data of each FV instance. But in virtual mode or in physical\r
1601 // mode, the address of the the physical memory may be different.\r
1602 //\r
1603 Status = gBS->AllocatePool (\r
1604 EfiRuntimeServicesData,\r
1605 BufferSize,\r
1606 &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]\r
1607 );\r
1608 ASSERT_EFI_ERROR (Status);\r
1609\r
1610 //\r
1611 // Make a virtual copy of the FvInstance pointer.\r
1612 //\r
1613 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];\r
1614 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;\r
1615\r
eb16e240 1616 mFvbModuleGlobal->NumFv = 0;\r
1617 FirmwareVolumeHobList.Raw = GetHobList();\r
1618 MaxLbaSize = 0;\r
9071550e 1619\r
1620 //\r
1621 // Fill in the private data of each firmware volume block instance\r
1622 //\r
1623 do {\r
1624 Status = GetFvbHeader (\r
1625 &FirmwareVolumeHobList, &FwVolHeader, \r
1626 &BaseAddress, &VolumeId, &MappedFile, &ActuralSize, &Offset,\r
1627 &WriteBack\r
1628 );\r
1629 if (EFI_ERROR (Status)) {\r
1630 break;\r
1631 }\r
eb16e240 1632 FirmwareVolumeHobList.Raw = GET_NEXT_HOB (FirmwareVolumeHobList);\r
9071550e 1633\r
1634 if (!FwVolHeader) {\r
1635 continue;\r
1636 }\r
be768885 1637 \r
9071550e 1638 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);\r
1639 FwVolHeader = &(FwhInstance->VolumeHeader);\r
1640\r
1641 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;\r
1642 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress;\r
1643 FwhInstance->Device = NULL;\r
1644 FwhInstance->Offset = Offset;\r
1645\r
1646 if (*MappedFile != '\0') {\r
1647 FwhInstance->VolumeId = VolumeId;\r
1648 FwhInstance->ActuralSize = ActuralSize;\r
1649 StrCpy (FwhInstance->MappedFile, MappedFile);\r
1650\r
1651 InstallSfsNotify = TRUE;\r
1652 } else {\r
1653 FwhInstance->VolumeId = (UINT32) -1;\r
1654 FwhInstance->ActuralSize = (UINT32) -1;\r
1655 FwhInstance->MappedFile[0] = L'\0';\r
1656 }\r
1657 \r
be768885 1658 DEBUG ((EFI_D_INFO, "FirmVolume Found! BaseAddress=0x%lx, VolumeId=0x%x, MappedFile=%s, Size=0x%x\n",\r
1659 (UINTN) BaseAddress, VolumeId, MappedFile, ActuralSize));\r
9071550e 1660 //\r
1661 // We may expose readonly FVB in future.\r
1662 //\r
be768885 1663 FwhInstance->WriteEnabled = TRUE; // Ken: Why enable write?\r
9071550e 1664 EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);\r
1665\r
1666 LbaAddress = (UINTN) FwhInstance->FvBase[0];\r
1667 NumOfBlocks = 0;\r
1668\r
1669 if (FwhInstance->WriteEnabled) {\r
1670 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
1671\r
1672 LbaAddress += PtrBlockMapEntry->NumBlocks * PtrBlockMapEntry->Length;\r
1673 //\r
1674 // Get the maximum size of a block. The size will be used to allocate\r
1675 // buffer for Scratch space, the intermediate buffer for FVB extension\r
1676 // protocol\r
1677 //\r
1678 if (MaxLbaSize < PtrBlockMapEntry->Length) {\r
1679 MaxLbaSize = PtrBlockMapEntry->Length;\r
1680 }\r
1681\r
1682 NumOfBlocks += PtrBlockMapEntry->NumBlocks;\r
1683 }\r
1684 //\r
1685 // Write back a healthy FV header\r
1686 //\r
1687 if (WriteBack) {\r
1688 Status = FlashFdErase (\r
1689 (UINTN) FwhInstance->FvBase[0],\r
1690 FwhInstance,\r
1691 FwVolHeader->BlockMap->Length\r
1692 );\r
1693\r
1694 HeaderLength = (UINTN) FwVolHeader->HeaderLength;\r
1695\r
1696 Status = FlashFdWrite (\r
1697 (UINTN) FwhInstance->FvBase[0],\r
1698 FwhInstance,\r
1699 (UINTN *) &HeaderLength,\r
1700 (UINT8 *) FwVolHeader\r
1701 );\r
1702\r
1703 FwVolHeader->HeaderLength = (UINT16) HeaderLength;\r
1704\r
1705 DEBUG ((EFI_D_ERROR, "Fvb (0x%x): FV header invalid, write back - %r\n", (UINTN) FwhInstance->FvBase[0], Status));\r
1706 }\r
1707 }\r
1708 //\r
1709 // The total number of blocks in the FV.\r
1710 //\r
1711 FwhInstance->NumOfBlocks = NumOfBlocks;\r
1712\r
1713 //\r
1714 // Add a FVB Protocol Instance\r
1715 //\r
1716 Status = gBS->AllocatePool (\r
1717 EfiRuntimeServicesData,\r
1718 sizeof (EFI_FW_VOL_BLOCK_DEVICE),\r
1719 &FvbDevice\r
1720 );\r
1721 ASSERT_EFI_ERROR (Status);\r
1722\r
1723 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));\r
1724\r
1725 FvbDevice->Instance = mFvbModuleGlobal->NumFv;\r
1726 mFvbModuleGlobal->NumFv++;\r
1727\r
1728 //\r
1729 // Set up the devicepath\r
1730 //\r
1731 FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;\r
1732 FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1);\r
1733\r
1734 //\r
1735 // Find a handle with a matching device path that has supports FW Block protocol\r
1736 //\r
1737 TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData;\r
1738 CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH));\r
1739 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);\r
1740 if (EFI_ERROR (Status)) {\r
1741 //\r
1742 // LocateDevicePath fails so install a new interface and device path\r
1743 //\r
1744 FwbHandle = NULL;\r
1745 Status = gBS->InstallMultipleProtocolInterfaces (\r
1746 &FwbHandle,\r
1747 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1748 &FvbDevice->FwVolBlockInstance,\r
1749 &gEfiDevicePathProtocolGuid,\r
1750 &FvbDevice->DevicePath,\r
1751 NULL\r
1752 );\r
1753 ASSERT_EFI_ERROR (Status);\r
1754 } else if (EfiIsDevicePathEnd (TempFwbDevicePath)) {\r
1755 //\r
1756 // Device allready exists, so reinstall the FVB protocol\r
1757 //\r
1758 Status = gBS->HandleProtocol (\r
1759 FwbHandle,\r
1760 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1761 &OldFwbInterface\r
1762 );\r
1763 ASSERT_EFI_ERROR (Status);\r
1764\r
1765 Status = gBS->ReinstallProtocolInterface (\r
1766 FwbHandle,\r
1767 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1768 OldFwbInterface,\r
1769 &FvbDevice->FwVolBlockInstance\r
1770 );\r
1771 ASSERT_EFI_ERROR (Status);\r
1772\r
1773 } else {\r
1774 //\r
1775 // There was a FVB protocol on an End Device Path node\r
1776 //\r
1777 ASSERT (FALSE);\r
1778 }\r
1779 //\r
1780 // Install FVB Extension Protocol on the same handle\r
1781 //\r
1782 Status = gBS->InstallMultipleProtocolInterfaces (\r
1783 &FwbHandle,\r
1784 &gEfiFvbExtensionProtocolGuid,\r
1785 &FvbDevice->FvbExtension,\r
1786 &gEfiAlternateFvBlockGuid,\r
1787 NULL,\r
1788 NULL\r
1789 );\r
1790\r
1791 ASSERT_EFI_ERROR (Status);\r
1792\r
1793 FwhInstance = (EFI_FW_VOL_INSTANCE *)\r
1794 (\r
1795 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +\r
1796 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))\r
1797 );\r
1798 } while (TRUE);\r
1799\r
1800 //\r
1801 // Allocate for scratch space, an intermediate buffer for FVB extention\r
1802 //\r
1803 Status = gBS->AllocatePool (\r
1804 EfiRuntimeServicesData,\r
1805 MaxLbaSize,\r
1806 &mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL]\r
1807 );\r
1808 ASSERT_EFI_ERROR (Status);\r
1809\r
1810 mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL];\r
1811\r
1812 if (InstallSfsNotify) {\r
1813 FvbInstallSfsNotify ();\r
1814 }\r
1815 return EFI_SUCCESS;\r
1816}\r