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