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