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