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