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