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