]> git.proxmox.com Git - mirror_edk2.git/blame - EdkNt32Pkg/RuntimeDxe/FvbServices/FWBlockService.c
1. Perfect libraries MSA files
[mirror_edk2.git] / EdkNt32Pkg / RuntimeDxe / FvbServices / FWBlockService.c
CommitLineData
878ddf1f 1/*++\r
2\r
fa332de7 3Copyright (c) 2006 - 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
878ddf1f 11\r
12Module Name:\r
13\r
14 FWBlockService.c\r
fa332de7 15\r
878ddf1f 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
fa332de7 84 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common\r
878ddf1f 85 instance data.\r
86\r
87Arguments:\r
88\r
89 (Standard EFI notify event - EFI_EVENT_NOTIFY)\r
90\r
fa332de7 91Returns:\r
878ddf1f 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
fa332de7 141Returns:\r
878ddf1f 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
fa332de7 185 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS\r
878ddf1f 186 that on successful return, contains the base address\r
fa332de7 187 of the firmware volume.\r
878ddf1f 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
fa332de7 192Returns:\r
878ddf1f 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
fa332de7 225 Instance - The FV instance whose attributes is going to be\r
878ddf1f 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
fa332de7 232Returns:\r
878ddf1f 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
fa332de7 269 LbaAddress - On output, contains the physical starting address\r
878ddf1f 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
fa332de7 280Returns:\r
878ddf1f 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
fa332de7 372Returns:\r
373 EFI_SUCCESS - The firmware volume was read successfully and\r
878ddf1f 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
fa332de7 379 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
878ddf1f 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
fa332de7 458Returns:\r
878ddf1f 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
fa332de7 464 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
878ddf1f 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
fa332de7 536Returns:\r
878ddf1f 537 EFI_SUCCESS - The erase request was successfully completed\r
538 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
fa332de7 539 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
878ddf1f 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
fa332de7 599 OffsetStartLba - Offset into the starting block at which to\r
878ddf1f 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
fa332de7 607Returns:\r
878ddf1f 608 EFI_SUCCESS - The firmware volume was erased successfully\r
609 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
fa332de7 610 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
878ddf1f 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
fa332de7 684 Modifies the current settings of the firmware volume according to the\r
878ddf1f 685 input parameter, and returns the new setting of the volume\r
686\r
687Arguments:\r
fa332de7 688 Instance - The FV instance whose attributes is going to be\r
878ddf1f 689 modified\r
fa332de7 690 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES\r
878ddf1f 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
fa332de7 698Returns:\r
878ddf1f 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
fa332de7 804Returns:\r
878ddf1f 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
fa332de7 839Returns:\r
840 EFI_SUCCESS - The firmware volume was read successfully and\r
878ddf1f 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
fa332de7 875Returns:\r
878ddf1f 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
fa332de7 902Returns:\r
878ddf1f 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
fa332de7 918 ...\r
878ddf1f 919 )\r
920/*++\r
921\r
922Routine Description:\r
923\r
fa332de7 924 The EraseBlock() function erases one or more blocks as denoted by the\r
878ddf1f 925 variable argument list. The entire parameter list of blocks must be verified\r
fa332de7 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
878ddf1f 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
fa332de7 933 ... - Starting LBA followed by Number of Lba to erase.\r
878ddf1f 934 a -1 to terminate the list.\r
935\r
fa332de7 936Returns:\r
878ddf1f 937 EFI_SUCCESS - The erase request was successfully completed\r
938 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
fa332de7 939 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
878ddf1f 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
fa332de7 1040Returns:\r
878ddf1f 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
fa332de7 1046 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
878ddf1f 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
fa332de7 1088Returns:\r
1089 EFI_SUCCESS - The firmware volume was read successfully and\r
878ddf1f 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
fa332de7 1095 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
878ddf1f 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
fa332de7 1128 OffsetStartLba - Offset into the starting block at which to\r
878ddf1f 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
fa332de7 1133Returns:\r
878ddf1f 1134 EFI_SUCCESS - The firmware volume was erased successfully\r
1135 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
fa332de7 1136 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
878ddf1f 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
fa332de7 1170Returns:\r
878ddf1f 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
c91eaa3d 1199 Checksum = Checksum + (*Ptr);\r
878ddf1f 1200 HeaderLength--;\r
c91eaa3d 1201 Ptr++;\r
878ddf1f 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
fa332de7 1255 mFvbModuleGlobal = AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL));\r
1256 ASSERT (mFvbModuleGlobal != NULL);\r
878ddf1f 1257\r
1258 //\r
1259 // Calculate the total size for all firmware volume block instances\r
1260 //\r
1261 BufferSize = 0;\r
1262\r
1263 FvHob.Raw = GetHobList ();\r
1264 while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {\r
1265 BaseAddress = FvHob.FirmwareVolume->BaseAddress;\r
1266 Length = FvHob.FirmwareVolume->Length;\r
1267 //\r
1268 // Check if it is a "real" flash\r
1269 //\r
1270 Status = DxeServices->GetMemorySpaceDescriptor (\r
1271 BaseAddress,\r
1272 &Descriptor\r
1273 );\r
1274 if (EFI_ERROR (Status)) {\r
1275 break;\r
1276 }\r
1277\r
1278 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {\r
1279 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1280 continue;\r
1281 }\r
1282\r
1283 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;\r
1284 Status = ValidateFvHeader (FwVolHeader);\r
1285 if (EFI_ERROR (Status)) {\r
1286 //\r
1287 // Get FvbInfo\r
1288 //\r
1289 Status = GetFvbInfo (Length, &FwVolHeader);\r
1290 if (EFI_ERROR (Status)) {\r
1291 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1292 continue;\r
1293 }\r
1294 }\r
1295\r
1296 BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
1297 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1298 }\r
1299\r
1300 //\r
1301 // Only need to allocate once. There is only one copy of physical memory for\r
1302 // the private data of each FV instance. But in virtual mode or in physical\r
1303 // mode, the address of the the physical memory may be different.\r
1304 //\r
fa332de7 1305 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] = AllocateRuntimePool (BufferSize);\r
1306 ASSERT (mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] != NULL);\r
878ddf1f 1307\r
1308 //\r
1309 // Make a virtual copy of the FvInstance pointer.\r
1310 //\r
1311 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];\r
1312 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;\r
1313\r
1314 mFvbModuleGlobal->NumFv = 0;\r
1315 MaxLbaSize = 0;\r
1316\r
1317 FvHob.Raw = GetHobList ();\r
1318 while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) {\r
1319 BaseAddress = FvHob.FirmwareVolume->BaseAddress;\r
1320 Length = FvHob.FirmwareVolume->Length;\r
1321 //\r
1322 // Check if it is a "real" flash\r
1323 //\r
1324 Status = DxeServices->GetMemorySpaceDescriptor (\r
1325 BaseAddress,\r
1326 &Descriptor\r
1327 );\r
1328 if (EFI_ERROR (Status)) {\r
1329 break;\r
1330 }\r
1331\r
1332 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {\r
1333 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1334 continue;\r
1335 }\r
1336\r
1337 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;\r
1338 Status = ValidateFvHeader (FwVolHeader);\r
1339 if (EFI_ERROR (Status)) {\r
1340 //\r
1341 // Get FvbInfo to provide in FwhInstance.\r
1342 //\r
1343 Status = GetFvbInfo (Length, &FwVolHeader);\r
1344 if (EFI_ERROR (Status)) {\r
1345 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1346 continue;\r
1347 }\r
1348 //\r
1349 // Write healthy FV header back.\r
1350 //\r
1351 CopyMem (\r
1352 (VOID *) (UINTN) BaseAddress,\r
1353 (VOID *) FwVolHeader,\r
1354 FwVolHeader->HeaderLength\r
1355 );\r
1356 }\r
1357\r
1358 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;\r
1359 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress;\r
1360\r
1361 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);\r
1362 FwVolHeader = &(FwhInstance->VolumeHeader);\r
1363 EfiInitializeLock (&(FwhInstance->FvbDevLock), EFI_TPL_HIGH_LEVEL);\r
1364\r
1365 NumOfBlocks = 0;\r
1366\r
1367 for (PtrBlockMapEntry = FwVolHeader->FvBlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
1368 //\r
1369 // Get the maximum size of a block. The size will be used to allocate\r
1370 // buffer for Scratch space, the intermediate buffer for FVB extension\r
1371 // protocol\r
1372 //\r
1373 if (MaxLbaSize < PtrBlockMapEntry->BlockLength) {\r
1374 MaxLbaSize = PtrBlockMapEntry->BlockLength;\r
1375 }\r
1376\r
1377 NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;\r
1378 }\r
1379 //\r
1380 // The total number of blocks in the FV.\r
1381 //\r
1382 FwhInstance->NumOfBlocks = NumOfBlocks;\r
1383\r
1384 //\r
1385 // Add a FVB Protocol Instance\r
1386 //\r
fa332de7 1387 FvbDevice = AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE));\r
1388 ASSERT (FvbDevice != NULL);\r
878ddf1f 1389\r
1390 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));\r
1391\r
1392 FvbDevice->Instance = mFvbModuleGlobal->NumFv;\r
1393 mFvbModuleGlobal->NumFv++;\r
1394\r
1395 //\r
1396 // Set up the devicepath\r
1397 //\r
1398 FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;\r
1399 FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1);\r
1400\r
1401 //\r
1402 // Find a handle with a matching device path that has supports FW Block protocol\r
1403 //\r
1404 TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData;\r
1405 CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH));\r
1406 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);\r
1407 if (EFI_ERROR (Status)) {\r
1408 //\r
1409 // LocateDevicePath fails so install a new interface and device path\r
1410 //\r
1411 FwbHandle = NULL;\r
1412 Status = gBS->InstallMultipleProtocolInterfaces (\r
1413 &FwbHandle,\r
1414 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1415 &FvbDevice->FwVolBlockInstance,\r
1416 &gEfiDevicePathProtocolGuid,\r
1417 &FvbDevice->DevicePath,\r
1418 NULL\r
1419 );\r
1420 ASSERT_EFI_ERROR (Status);\r
1421 } else if (EfiIsDevicePathEnd (TempFwbDevicePath)) {\r
1422 //\r
1423 // Device allready exists, so reinstall the FVB protocol\r
1424 //\r
1425 Status = gBS->HandleProtocol (\r
1426 FwbHandle,\r
1427 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1428 &OldFwbInterface\r
1429 );\r
1430 ASSERT_EFI_ERROR (Status);\r
1431\r
1432 Status = gBS->ReinstallProtocolInterface (\r
1433 FwbHandle,\r
1434 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1435 OldFwbInterface,\r
1436 &FvbDevice->FwVolBlockInstance\r
1437 );\r
1438 ASSERT_EFI_ERROR (Status);\r
1439\r
1440 } else {\r
1441 //\r
1442 // There was a FVB protocol on an End Device Path node\r
1443 //\r
1444 ASSERT (FALSE);\r
1445 }\r
1446 //\r
1447 // Install FVB Extension Protocol on the same handle\r
1448 //\r
1449 Status = gBS->InstallMultipleProtocolInterfaces (\r
1450 &FwbHandle,\r
1451 &gEfiFvbExtensionProtocolGuid,\r
1452 &FvbDevice->FvbExtension,\r
1453 &gEfiAlternateFvBlockGuid,\r
1454 NULL,\r
1455 NULL\r
1456 );\r
1457\r
1458 ASSERT_EFI_ERROR (Status);\r
1459\r
1460 FwhInstance = (EFI_FW_VOL_INSTANCE *)\r
1461 (\r
1462 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +\r
1463 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))\r
1464 );\r
1465\r
1466 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1467 }\r
1468\r
1469 //\r
1470 // Allocate for scratch space, an intermediate buffer for FVB extention\r
1471 //\r
fa332de7 1472 mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL] = AllocateRuntimePool (MaxLbaSize);\r
1473 ASSERT (mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL] != NULL);\r
878ddf1f 1474\r
1475 mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL];\r
1476\r
1477 return EFI_SUCCESS;\r
1478}\r