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