]> git.proxmox.com Git - mirror_edk2.git/blame - Nt32Pkg/FvbServicesRuntimeDxe/FWBlockService.c
Fix ICC building issue for Nt32 platform.
[mirror_edk2.git] / Nt32Pkg / FvbServicesRuntimeDxe / FWBlockService.c
CommitLineData
6ae81428 1/**@file\r
55e6660f 2\r
3Copyright (c) 2006 - 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 FWBlockService.c\r
15\r
16Abstract:\r
17\r
18Revision History\r
19\r
6ae81428 20**/\r
55e6660f 21\r
22//\r
23// The package level header files this module uses\r
24//\r
25#include <PiDxe.h>\r
26#include <WinNtDxe.h>\r
27//\r
28// The protocols, PPI and GUID defintions for this module\r
29//\r
30#include <Guid/EventGroup.h>\r
31#include <Protocol/FvbExtension.h>\r
32#include <Protocol/FirmwareVolumeBlock.h>\r
33#include <Guid/AlternateFvBlock.h>\r
34#include <Protocol/DevicePath.h>\r
35//\r
36// The Library classes this module consumes\r
37//\r
38#include <Library/UefiLib.h>\r
39#include <Library/UefiDriverEntryPoint.h>\r
40#include <Library/BaseLib.h>\r
41#include <Library/DxeServicesTableLib.h>\r
42#include <Library/UefiRuntimeLib.h>\r
43#include <Library/DebugLib.h>\r
44#include <Library/HobLib.h>\r
45#include <Library/BaseMemoryLib.h>\r
46#include <Library/MemoryAllocationLib.h>\r
47#include <Library/UefiBootServicesTableLib.h>\r
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
8ee3a199 243 OUT EFI_FVB_ATTRIBUTES_2 *Attributes,\r
55e6660f 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
8ee3a199 414 EFI_FVB_ATTRIBUTES_2 Attributes;\r
415 UINTN LbaAddress;\r
416 UINTN LbaLength;\r
417 EFI_STATUS Status;\r
55e6660f 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
8ee3a199 499 EFI_FVB_ATTRIBUTES_2 Attributes;\r
500 UINTN LbaAddress;\r
501 UINTN LbaLength;\r
502 EFI_STATUS Status;\r
55e6660f 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
8ee3a199 576 EFI_FVB_ATTRIBUTES_2 Attributes;\r
577 UINTN LbaAddress;\r
578 UINTN LbaLength;\r
579 EFI_STATUS Status;\r
580 UINT8 Data;\r
55e6660f 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
00d00b6d 649 EFI_STATUS Status;\r
55e6660f 650\r
651 //\r
652 // First LBA\r
653 //\r
00d00b6d
LG
654 Status = FvbGetLbaAddress (Instance, StartLba, NULL, &LbaSize, NULL, Global, Virtual);\r
655 if (EFI_ERROR (Status)) {\r
656 return Status;\r
657 }\r
55e6660f 658\r
659 //\r
660 // Use the scratch space as the intermediate buffer to transfer data\r
661 // Back up the first LBA in scratch space.\r
662 //\r
663 FvbReadBlock (Instance, StartLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);\r
664\r
665 //\r
666 // erase now\r
667 //\r
668 FvbEraseBlock (Instance, StartLba, Global, Virtual);\r
669 ScratchLbaSizeData = OffsetStartLba;\r
670\r
671 //\r
672 // write the data back to the first block\r
673 //\r
674 if (ScratchLbaSizeData > 0) {\r
00d00b6d
LG
675 Status = FvbWriteBlock (Instance, StartLba, 0, &ScratchLbaSizeData, Global->FvbScratchSpace[Virtual], Global, Virtual);\r
676 if (EFI_ERROR (Status)) {\r
677 return Status;\r
678 }\r
55e6660f 679 }\r
680 //\r
681 // Middle LBAs\r
682 //\r
683 if (LastLba > (StartLba + 1)) {\r
684 for (Index = (StartLba + 1); Index <= (LastLba - 1); Index++) {\r
685 FvbEraseBlock (Instance, Index, Global, Virtual);\r
686 }\r
687 }\r
688 //\r
689 // Last LBAs, the same as first LBAs\r
690 //\r
691 if (LastLba > StartLba) {\r
00d00b6d
LG
692 Status = FvbGetLbaAddress (Instance, LastLba, NULL, &LbaSize, NULL, Global, Virtual);\r
693 if (EFI_ERROR (Status)) {\r
694 return Status;\r
695 }\r
55e6660f 696 FvbReadBlock (Instance, LastLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);\r
697 FvbEraseBlock (Instance, LastLba, Global, Virtual);\r
698 }\r
699\r
00d00b6d
LG
700 ScratchLbaSizeData = LbaSize - (OffsetLastLba + 1);\r
701 \r
702 if (ScratchLbaSizeData > 0) {\r
703 Status = FvbWriteBlock (\r
704 Instance,\r
705 LastLba,\r
706 (OffsetLastLba + 1),\r
707 &ScratchLbaSizeData,\r
708 Global->FvbScratchSpace[Virtual] + OffsetLastLba + 1,\r
709 Global,\r
710 Virtual\r
711 );\r
712 }\r
713\r
714 return Status;\r
55e6660f 715}\r
716\r
717EFI_STATUS\r
718FvbSetVolumeAttributes (\r
8ee3a199 719 IN UINTN Instance,\r
720 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes,\r
721 IN ESAL_FWB_GLOBAL *Global,\r
722 IN BOOLEAN Virtual\r
55e6660f 723 )\r
724/*++\r
725\r
726Routine Description:\r
727 Modifies the current settings of the firmware volume according to the\r
728 input parameter, and returns the new setting of the volume\r
729\r
730Arguments:\r
731 Instance - The FV instance whose attributes is going to be\r
732 modified\r
8ee3a199 733 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2\r
55e6660f 734 containing the desired firmware volume settings.\r
735 On successful return, it contains the new settings\r
736 of the firmware volume\r
737 Global - Pointer to ESAL_FWB_GLOBAL that contains all\r
738 instance data\r
739 Virtual - Whether CPU is in virtual or physical mode\r
740\r
741Returns:\r
742 EFI_SUCCESS - Successfully returns\r
743 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified\r
744 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are\r
745 in conflict with the capabilities as declared in the\r
746 firmware volume header\r
747\r
748--*/\r
749{\r
8ee3a199 750 EFI_FW_VOL_INSTANCE *FwhInstance;\r
751 EFI_FVB_ATTRIBUTES_2 OldAttributes;\r
752 EFI_FVB_ATTRIBUTES_2 *AttribPtr;\r
753 UINT32 Capabilities;\r
754 UINT32 OldStatus;\r
755 UINT32 NewStatus;\r
756 EFI_STATUS Status;\r
757 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;\r
55e6660f 758\r
759 //\r
760 // Find the right instance of the FVB private data\r
761 //\r
762 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);\r
763 ASSERT_EFI_ERROR (Status);\r
764\r
8ee3a199 765 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);\r
55e6660f 766 OldAttributes = *AttribPtr;\r
767 Capabilities = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \\r
768 EFI_FVB2_READ_ENABLED_CAP | \\r
769 EFI_FVB2_WRITE_DISABLED_CAP | \\r
770 EFI_FVB2_WRITE_ENABLED_CAP | \\r
771 EFI_FVB2_LOCK_CAP \\r
772 );\r
773 OldStatus = OldAttributes & EFI_FVB2_STATUS;\r
774 NewStatus = *Attributes & EFI_FVB2_STATUS;\r
775\r
a4c9ede5 776 UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \\r
777 EFI_FVB2_READ_ENABLED_CAP | \\r
778 EFI_FVB2_WRITE_DISABLED_CAP | \\r
779 EFI_FVB2_WRITE_ENABLED_CAP | \\r
780 EFI_FVB2_LOCK_CAP | \\r
781 EFI_FVB2_STICKY_WRITE | \\r
782 EFI_FVB2_MEMORY_MAPPED | \\r
783 EFI_FVB2_ERASE_POLARITY | \\r
784 EFI_FVB2_READ_LOCK_CAP | \\r
785 EFI_FVB2_WRITE_LOCK_CAP | \\r
786 EFI_FVB2_ALIGNMENT;\r
787\r
788 //\r
789 // Some attributes of FV is read only can *not* be set\r
790 //\r
791 if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {\r
792 return EFI_INVALID_PARAMETER;\r
793 }\r
55e6660f 794 //\r
795 // If firmware volume is locked, no status bit can be updated\r
796 //\r
797 if (OldAttributes & EFI_FVB2_LOCK_STATUS) {\r
798 if (OldStatus ^ NewStatus) {\r
799 return EFI_ACCESS_DENIED;\r
800 }\r
801 }\r
802 //\r
803 // Test read disable\r
804 //\r
805 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {\r
806 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {\r
807 return EFI_INVALID_PARAMETER;\r
808 }\r
809 }\r
810 //\r
811 // Test read enable\r
812 //\r
813 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {\r
814 if (NewStatus & EFI_FVB2_READ_STATUS) {\r
815 return EFI_INVALID_PARAMETER;\r
816 }\r
817 }\r
818 //\r
819 // Test write disable\r
820 //\r
821 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {\r
822 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {\r
823 return EFI_INVALID_PARAMETER;\r
824 }\r
825 }\r
826 //\r
827 // Test write enable\r
828 //\r
829 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {\r
830 if (NewStatus & EFI_FVB2_WRITE_STATUS) {\r
831 return EFI_INVALID_PARAMETER;\r
832 }\r
833 }\r
834 //\r
835 // Test lock\r
836 //\r
837 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {\r
838 if (NewStatus & EFI_FVB2_LOCK_STATUS) {\r
839 return EFI_INVALID_PARAMETER;\r
840 }\r
841 }\r
842\r
843 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));\r
844 *AttribPtr = (*AttribPtr) | NewStatus;\r
845 *Attributes = *AttribPtr;\r
846\r
847 return EFI_SUCCESS;\r
848}\r
849//\r
850// FVB protocol APIs\r
851//\r
852EFI_STATUS\r
853EFIAPI\r
854FvbProtocolGetPhysicalAddress (\r
855 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
856 OUT EFI_PHYSICAL_ADDRESS *Address\r
857 )\r
858/*++\r
859\r
860Routine Description:\r
861\r
862 Retrieves the physical address of the device.\r
863\r
864Arguments:\r
865\r
866 This - Calling context\r
867 Address - Output buffer containing the address.\r
868\r
869Returns:\r
870\r
871Returns:\r
872 EFI_SUCCESS - Successfully returns\r
873\r
874--*/\r
875{\r
876 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
877\r
878 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
879\r
880 return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());\r
881}\r
882\r
883EFI_STATUS\r
884EFIAPI\r
885FvbProtocolGetBlockSize (\r
886 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
887 IN CONST EFI_LBA Lba,\r
888 OUT UINTN *BlockSize,\r
889 OUT UINTN *NumOfBlocks\r
890 )\r
891/*++\r
892\r
893Routine Description:\r
894 Retrieve the size of a logical block\r
895\r
896Arguments:\r
897 This - Calling context\r
898 Lba - Indicates which block to return the size for.\r
899 BlockSize - A pointer to a caller allocated UINTN in which\r
900 the size of the block is returned\r
901 NumOfBlocks - a pointer to a caller allocated UINTN in which the\r
902 number of consecutive blocks starting with Lba is\r
903 returned. All blocks in this range have a size of\r
904 BlockSize\r
905\r
906Returns:\r
907 EFI_SUCCESS - The firmware volume was read successfully and\r
908 contents are in Buffer\r
909\r
910--*/\r
911{\r
912 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
913\r
914 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
915\r
916 return FvbGetLbaAddress (\r
917 FvbDevice->Instance,\r
918 Lba,\r
919 NULL,\r
920 BlockSize,\r
921 NumOfBlocks,\r
922 mFvbModuleGlobal,\r
923 EfiGoneVirtual ()\r
924 );\r
925}\r
926\r
927EFI_STATUS\r
928EFIAPI\r
929FvbProtocolGetAttributes (\r
930 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
8ee3a199 931 OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
55e6660f 932 )\r
933/*++\r
934\r
935Routine Description:\r
936 Retrieves Volume attributes. No polarity translations are done.\r
937\r
938Arguments:\r
939 This - Calling context\r
940 Attributes - output buffer which contains attributes\r
941\r
942Returns:\r
943 EFI_SUCCESS - Successfully returns\r
944\r
945--*/\r
946{\r
947 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
948\r
949 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
950\r
951 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());\r
952}\r
953\r
954EFI_STATUS\r
955EFIAPI\r
956FvbProtocolSetAttributes (\r
957 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
8ee3a199 958 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes\r
55e6660f 959 )\r
960/*++\r
961\r
962Routine Description:\r
963 Sets Volume attributes. No polarity translations are done.\r
964\r
965Arguments:\r
966 This - Calling context\r
967 Attributes - output buffer which contains attributes\r
968\r
969Returns:\r
970 EFI_SUCCESS - Successfully returns\r
971\r
972--*/\r
973{\r
974 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
975\r
976 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
977\r
978 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());\r
979}\r
980\r
981EFI_STATUS\r
982EFIAPI\r
983FvbProtocolEraseBlocks (\r
984 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
985 ...\r
986 )\r
987/*++\r
988\r
989Routine Description:\r
990\r
991 The EraseBlock() function erases one or more blocks as denoted by the\r
992 variable argument list. The entire parameter list of blocks must be verified\r
993 prior to erasing any blocks. If a block is requested that does not exist\r
994 within the associated firmware volume (it has a larger index than the last\r
995 block of the firmware volume), the EraseBlock() function must return\r
996 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.\r
997\r
998Arguments:\r
999 This - Calling context\r
1000 ... - Starting LBA followed by Number of Lba to erase.\r
1001 a -1 to terminate the list.\r
1002\r
1003Returns:\r
1004 EFI_SUCCESS - The erase request was successfully completed\r
1005 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
1006 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
1007 could not be written. Firmware device may have been\r
1008 partially erased\r
1009\r
1010--*/\r
1011{\r
1012 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1013 EFI_FW_VOL_INSTANCE *FwhInstance;\r
1014 UINTN NumOfBlocks;\r
1015 VA_LIST args;\r
1016 EFI_LBA StartingLba;\r
1017 UINTN NumOfLba;\r
1018 EFI_STATUS Status;\r
1019\r
1020 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1021\r
1022 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());\r
1023 ASSERT_EFI_ERROR (Status);\r
1024\r
1025 NumOfBlocks = FwhInstance->NumOfBlocks;\r
1026\r
1027 VA_START (args, This);\r
1028\r
1029 do {\r
1030 StartingLba = VA_ARG (args, EFI_LBA);\r
1031 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
1032 break;\r
1033 }\r
1034\r
1035 NumOfLba = VA_ARG (args, UINT32);\r
1036\r
1037 //\r
1038 // Check input parameters\r
1039 //\r
1040 if (NumOfLba == 0) {\r
1041 VA_END (args);\r
1042 return EFI_INVALID_PARAMETER;\r
1043 }\r
1044\r
1045 if ((StartingLba + NumOfLba) > NumOfBlocks) {\r
1046 return EFI_INVALID_PARAMETER;\r
1047 }\r
1048 } while (1);\r
1049\r
1050 VA_END (args);\r
1051\r
1052 VA_START (args, This);\r
1053 do {\r
1054 StartingLba = VA_ARG (args, EFI_LBA);\r
1055 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
1056 break;\r
1057 }\r
1058\r
1059 NumOfLba = VA_ARG (args, UINT32);\r
1060\r
1061 while (NumOfLba > 0) {\r
1062 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());\r
1063 if (EFI_ERROR (Status)) {\r
1064 VA_END (args);\r
1065 return Status;\r
1066 }\r
1067\r
1068 StartingLba++;\r
1069 NumOfLba--;\r
1070 }\r
1071\r
1072 } while (1);\r
1073\r
1074 VA_END (args);\r
1075\r
1076 return EFI_SUCCESS;\r
1077}\r
1078\r
1079EFI_STATUS\r
1080EFIAPI\r
1081FvbProtocolWrite (\r
1082 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
0b94e319 1083 IN EFI_LBA Lba,\r
1084 IN UINTN Offset,\r
1085 IN OUT UINTN *NumBytes,\r
1086 IN UINT8 *Buffer\r
55e6660f 1087 )\r
1088/*++\r
1089\r
1090Routine Description:\r
1091\r
1092 Writes data beginning at Lba:Offset from FV. The write terminates either\r
1093 when *NumBytes of data have been written, or when a block boundary is\r
1094 reached. *NumBytes is updated to reflect the actual number of bytes\r
1095 written. The write opertion does not include erase. This routine will\r
1096 attempt to write only the specified bytes. If the writes do not stick,\r
1097 it will return an error.\r
1098\r
1099Arguments:\r
1100 This - Calling context\r
1101 Lba - Block in which to begin write\r
1102 Offset - Offset in the block at which to begin write\r
1103 NumBytes - On input, indicates the requested write size. On\r
1104 output, indicates the actual number of bytes written\r
1105 Buffer - Buffer containing source data for the write.\r
1106\r
1107Returns:\r
1108 EFI_SUCCESS - The firmware volume was written successfully\r
1109 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,\r
1110 NumBytes contains the total number of bytes\r
1111 actually written\r
1112 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
1113 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
1114 could not be written\r
1115 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL\r
1116\r
1117--*/\r
1118{\r
1119\r
1120 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1121\r
1122 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1123\r
042400ab 1124 return FvbWriteBlock (FvbDevice->Instance, (EFI_LBA)Lba, (UINTN)Offset, NumBytes, (UINT8 *)Buffer, mFvbModuleGlobal, EfiGoneVirtual ());\r
55e6660f 1125}\r
1126\r
1127EFI_STATUS\r
1128EFIAPI\r
1129FvbProtocolRead (\r
1130 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,\r
1131 IN CONST EFI_LBA Lba,\r
1132 IN CONST UINTN Offset,\r
1133 IN OUT UINTN *NumBytes,\r
1134 IN UINT8 *Buffer\r
1135 )\r
1136/*++\r
1137\r
1138Routine Description:\r
1139\r
1140 Reads data beginning at Lba:Offset from FV. The Read terminates either\r
1141 when *NumBytes of data have been read, or when a block boundary is\r
1142 reached. *NumBytes is updated to reflect the actual number of bytes\r
1143 written. The write opertion does not include erase. This routine will\r
1144 attempt to write only the specified bytes. If the writes do not stick,\r
1145 it will return an error.\r
1146\r
1147Arguments:\r
1148 This - Calling context\r
1149 Lba - Block in which to begin Read\r
1150 Offset - Offset in the block at which to begin Read\r
1151 NumBytes - On input, indicates the requested write size. On\r
1152 output, indicates the actual number of bytes Read\r
1153 Buffer - Buffer containing source data for the Read.\r
1154\r
1155Returns:\r
1156 EFI_SUCCESS - The firmware volume was read successfully and\r
1157 contents are in Buffer\r
1158 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,\r
1159 NumBytes contains the total number of bytes returned\r
1160 in Buffer\r
1161 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state\r
1162 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
1163 could not be read\r
1164 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL\r
1165\r
1166--*/\r
1167{\r
1168\r
1169 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1170\r
1171 FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
1172\r
1173 return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());\r
1174}\r
1175//\r
1176// FVB Extension Protocols\r
1177//\r
1178EFI_STATUS\r
1179EFIAPI\r
1180FvbExtendProtocolEraseCustomBlockRange (\r
1181 IN EFI_FVB_EXTENSION_PROTOCOL *This,\r
1182 IN EFI_LBA StartLba,\r
1183 IN UINTN OffsetStartLba,\r
1184 IN EFI_LBA LastLba,\r
1185 IN UINTN OffsetLastLba\r
1186 )\r
1187/*++\r
1188\r
1189Routine Description:\r
1190 Erases and initializes a specified range of a firmware volume\r
1191\r
1192Arguments:\r
1193 This - Calling context\r
1194 StartLba - The starting logical block index to be erased\r
1195 OffsetStartLba - Offset into the starting block at which to\r
1196 begin erasing\r
1197 LastLba - The last logical block index to be erased\r
1198 OffsetStartLba - Offset into the last block at which to end erasing\r
1199\r
1200Returns:\r
1201 EFI_SUCCESS - The firmware volume was erased successfully\r
1202 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state\r
1203 EFI_DEVICE_ERROR - The block device is not functioning correctly and\r
1204 could not be written. Firmware device may have been\r
1205 partially erased\r
1206\r
1207--*/\r
1208{\r
1209 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1210\r
1211 FvbDevice = FVB_EXTEND_DEVICE_FROM_THIS (This);\r
1212\r
1213 return FvbEraseCustomBlockRange (\r
1214 FvbDevice->Instance,\r
1215 StartLba,\r
1216 OffsetStartLba,\r
1217 LastLba,\r
1218 OffsetLastLba,\r
1219 mFvbModuleGlobal,\r
1220 EfiGoneVirtual ()\r
1221 );\r
1222}\r
1223\r
1224STATIC\r
1225EFI_STATUS\r
1226ValidateFvHeader (\r
1227 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader\r
1228 )\r
1229/*++\r
1230\r
1231Routine Description:\r
1232 Check the integrity of firmware volume header\r
1233\r
1234Arguments:\r
1235 FwVolHeader - A pointer to a firmware volume header\r
1236\r
1237Returns:\r
1238 EFI_SUCCESS - The firmware volume is consistent\r
1239 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV\r
1240\r
1241--*/\r
1242{\r
1243 UINT16 *Ptr;\r
1244 UINT16 HeaderLength;\r
1245 UINT16 Checksum;\r
1246\r
1247 //\r
1248 // Verify the header revision, header signature, length\r
1249 // Length of FvBlock cannot be 2**64-1\r
1250 // HeaderLength cannot be an odd number\r
1251 //\r
1252 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||\r
1253 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||\r
1254 (FwVolHeader->FvLength == ((UINTN) -1)) ||\r
1255 ((FwVolHeader->HeaderLength & 0x01) != 0)\r
1256 ) {\r
1257 return EFI_NOT_FOUND;\r
1258 }\r
1259 //\r
1260 // Verify the header checksum\r
1261 //\r
1262 HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2);\r
1263 Ptr = (UINT16 *) FwVolHeader;\r
1264 Checksum = 0;\r
1265 while (HeaderLength > 0) {\r
0b94e319 1266 Checksum = (UINT16)(Checksum + (*Ptr));\r
55e6660f 1267 HeaderLength--;\r
1268 Ptr++;\r
1269 }\r
1270\r
1271 if (Checksum != 0) {\r
1272 return EFI_NOT_FOUND;\r
1273 }\r
1274\r
1275 return EFI_SUCCESS;\r
1276}\r
1277\r
1278EFI_STATUS\r
1279EFIAPI\r
1280FvbInitialize (\r
1281 IN EFI_HANDLE ImageHandle,\r
1282 IN EFI_SYSTEM_TABLE *SystemTable\r
1283 )\r
1284/*++\r
1285\r
1286Routine Description:\r
1287 This function does common initialization for FVB services\r
1288\r
1289Arguments:\r
1290\r
1291Returns:\r
1292\r
1293--*/\r
1294{\r
1295 EFI_STATUS Status;\r
1296 EFI_FW_VOL_INSTANCE *FwhInstance;\r
1297 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
1298 EFI_DXE_SERVICES *DxeServices;\r
1299 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r
1300 UINT32 BufferSize;\r
1301 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
1302 EFI_HANDLE FwbHandle;\r
1303 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;\r
1304 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;\r
1305 EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath;\r
1306 FV_DEVICE_PATH TempFvbDevicePathData;\r
1307 UINT32 MaxLbaSize;\r
1308 EFI_PHYSICAL_ADDRESS BaseAddress;\r
1309 UINT64 Length;\r
1310 UINTN NumOfBlocks;\r
1311 EFI_PEI_HOB_POINTERS FvHob;\r
1312\r
1313 //\r
1314 // Get the DXE services table\r
1315 //\r
1316 DxeServices = gDS;\r
1317\r
1318 //\r
1319 // Allocate runtime services data for global variable, which contains\r
1320 // the private data of all firmware volume block instances\r
1321 //\r
1322 mFvbModuleGlobal = AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL));\r
1323 ASSERT (mFvbModuleGlobal != NULL);\r
1324\r
1325 //\r
1326 // Calculate the total size for all firmware volume block instances\r
1327 //\r
1328 BufferSize = 0;\r
1329\r
1330 FvHob.Raw = GetHobList ();\r
1331 while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {\r
1332 BaseAddress = FvHob.FirmwareVolume->BaseAddress;\r
1333 Length = FvHob.FirmwareVolume->Length;\r
1334 //\r
1335 // Check if it is a "real" flash\r
1336 //\r
1337 Status = DxeServices->GetMemorySpaceDescriptor (\r
1338 BaseAddress,\r
1339 &Descriptor\r
1340 );\r
1341 if (EFI_ERROR (Status)) {\r
1342 break;\r
1343 }\r
1344\r
1345 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {\r
1346 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1347 continue;\r
1348 }\r
1349\r
1350 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;\r
1351 Status = ValidateFvHeader (FwVolHeader);\r
1352 if (EFI_ERROR (Status)) {\r
1353 //\r
1354 // Get FvbInfo\r
1355 //\r
1356 Status = GetFvbInfo (Length, &FwVolHeader);\r
1357 if (EFI_ERROR (Status)) {\r
1358 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1359 continue;\r
1360 }\r
1361 }\r
1362\r
1363 BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
1364 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1365 }\r
1366\r
1367 //\r
1368 // Only need to allocate once. There is only one copy of physical memory for\r
1369 // the private data of each FV instance. But in virtual mode or in physical\r
1370 // mode, the address of the the physical memory may be different.\r
1371 //\r
1372 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] = AllocateRuntimePool (BufferSize);\r
1373 ASSERT (mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] != NULL);\r
1374\r
1375 //\r
1376 // Make a virtual copy of the FvInstance pointer.\r
1377 //\r
1378 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];\r
1379 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;\r
1380\r
1381 mFvbModuleGlobal->NumFv = 0;\r
1382 MaxLbaSize = 0;\r
1383\r
1384 FvHob.Raw = GetHobList ();\r
1385 while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) {\r
1386 BaseAddress = FvHob.FirmwareVolume->BaseAddress;\r
1387 Length = FvHob.FirmwareVolume->Length;\r
1388 //\r
1389 // Check if it is a "real" flash\r
1390 //\r
1391 Status = DxeServices->GetMemorySpaceDescriptor (\r
1392 BaseAddress,\r
1393 &Descriptor\r
1394 );\r
1395 if (EFI_ERROR (Status)) {\r
1396 break;\r
1397 }\r
1398\r
1399 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {\r
1400 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1401 continue;\r
1402 }\r
1403\r
1404 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;\r
1405 Status = ValidateFvHeader (FwVolHeader);\r
1406 if (EFI_ERROR (Status)) {\r
1407 //\r
1408 // Get FvbInfo to provide in FwhInstance.\r
1409 //\r
1410 Status = GetFvbInfo (Length, &FwVolHeader);\r
1411 if (EFI_ERROR (Status)) {\r
1412 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1413 continue;\r
1414 }\r
1415 //\r
1416 // Write healthy FV header back.\r
1417 //\r
1418 CopyMem (\r
1419 (VOID *) (UINTN) BaseAddress,\r
1420 (VOID *) FwVolHeader,\r
1421 FwVolHeader->HeaderLength\r
1422 );\r
1423 }\r
1424\r
1425 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;\r
1426 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress;\r
1427\r
1428 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);\r
1429 FwVolHeader = &(FwhInstance->VolumeHeader);\r
1430 EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);\r
1431\r
1432 NumOfBlocks = 0;\r
1433\r
1434 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
1435 //\r
1436 // Get the maximum size of a block. The size will be used to allocate\r
1437 // buffer for Scratch space, the intermediate buffer for FVB extension\r
1438 // protocol\r
1439 //\r
1440 if (MaxLbaSize < PtrBlockMapEntry->Length) {\r
1441 MaxLbaSize = PtrBlockMapEntry->Length;\r
1442 }\r
1443\r
1444 NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;\r
1445 }\r
1446 //\r
1447 // The total number of blocks in the FV.\r
1448 //\r
1449 FwhInstance->NumOfBlocks = NumOfBlocks;\r
1450\r
1451 //\r
1452 // Add a FVB Protocol Instance\r
1453 //\r
1454 FvbDevice = AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE));\r
1455 ASSERT (FvbDevice != NULL);\r
1456\r
1457 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));\r
1458\r
1459 FvbDevice->Instance = mFvbModuleGlobal->NumFv;\r
1460 mFvbModuleGlobal->NumFv++;\r
1461\r
1462 //\r
1463 // Set up the devicepath\r
1464 //\r
1465 FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;\r
1466 FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1);\r
1467\r
1468 //\r
1469 // Find a handle with a matching device path that has supports FW Block protocol\r
1470 //\r
1471 TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData;\r
1472 CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH));\r
1473 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);\r
1474 if (EFI_ERROR (Status)) {\r
1475 //\r
1476 // LocateDevicePath fails so install a new interface and device path\r
1477 //\r
1478 FwbHandle = NULL;\r
1479 Status = gBS->InstallMultipleProtocolInterfaces (\r
1480 &FwbHandle,\r
1481 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1482 &FvbDevice->FwVolBlockInstance,\r
1483 &gEfiDevicePathProtocolGuid,\r
1484 &FvbDevice->DevicePath,\r
1485 NULL\r
1486 );\r
1487 ASSERT_EFI_ERROR (Status);\r
1488 } else if (EfiIsDevicePathEnd (TempFwbDevicePath)) {\r
1489 //\r
1490 // Device allready exists, so reinstall the FVB protocol\r
1491 //\r
1492 Status = gBS->HandleProtocol (\r
1493 FwbHandle,\r
1494 &gEfiFirmwareVolumeBlockProtocolGuid,\r
0b94e319 1495 (VOID**)&OldFwbInterface\r
55e6660f 1496 );\r
1497 ASSERT_EFI_ERROR (Status);\r
1498\r
1499 Status = gBS->ReinstallProtocolInterface (\r
1500 FwbHandle,\r
1501 &gEfiFirmwareVolumeBlockProtocolGuid,\r
1502 OldFwbInterface,\r
1503 &FvbDevice->FwVolBlockInstance\r
1504 );\r
1505 ASSERT_EFI_ERROR (Status);\r
1506\r
1507 } else {\r
1508 //\r
1509 // There was a FVB protocol on an End Device Path node\r
1510 //\r
1511 ASSERT (FALSE);\r
1512 }\r
1513 //\r
1514 // Install FVB Extension Protocol on the same handle\r
1515 //\r
1516 Status = gBS->InstallMultipleProtocolInterfaces (\r
1517 &FwbHandle,\r
1518 &gEfiFvbExtensionProtocolGuid,\r
1519 &FvbDevice->FvbExtension,\r
1520 &gEfiAlternateFvBlockGuid,\r
1521 NULL,\r
1522 NULL\r
1523 );\r
1524\r
1525 ASSERT_EFI_ERROR (Status);\r
1526\r
1527 FwhInstance = (EFI_FW_VOL_INSTANCE *)\r
1528 (\r
1529 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +\r
1530 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))\r
1531 );\r
1532\r
1533 FvHob.Raw = GET_NEXT_HOB (FvHob);\r
1534 }\r
1535\r
1536 //\r
1537 // Allocate for scratch space, an intermediate buffer for FVB extention\r
1538 //\r
1539 mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL] = AllocateRuntimePool (MaxLbaSize);\r
1540 ASSERT (mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL] != NULL);\r
1541\r
1542 mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL];\r
1543\r
1544 return EFI_SUCCESS;\r
1545}\r