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