]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockService.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / QemuFlashFvbServicesRuntimeDxe / FwBlockService.c
1 /**@file
2
3 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
4
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 Module Name:
8
9 FWBlockService.c
10
11 Abstract:
12
13 Revision History
14
15 **/
16
17 //
18 // The protocols, PPI and GUID definitions for this module
19 //
20 #include <Protocol/DevicePath.h>
21 #include <Protocol/FirmwareVolumeBlock.h>
22
23 //
24 // The Library classes this module consumes
25 //
26 #include <Library/BaseLib.h>
27 #include <Library/BaseMemoryLib.h>
28 #include <Library/DebugLib.h>
29 #include <Library/DevicePathLib.h>
30 #include <Library/DxeServicesTableLib.h>
31 #include <Library/MemoryAllocationLib.h>
32 #include <Library/UefiBootServicesTableLib.h>
33
34 #include "FwBlockService.h"
35 #include "QemuFlash.h"
36
37 #define EFI_FVB2_STATUS \
38 (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
39
40 ESAL_FWB_GLOBAL *mFvbModuleGlobal;
41
42 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
43 {
44 {
45 HARDWARE_DEVICE_PATH,
46 HW_MEMMAP_DP,
47 {
48 (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
49 (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
50 }
51 },
52 EfiMemoryMappedIO,
53 (EFI_PHYSICAL_ADDRESS)0,
54 (EFI_PHYSICAL_ADDRESS)0,
55 },
56 {
57 END_DEVICE_PATH_TYPE,
58 END_ENTIRE_DEVICE_PATH_SUBTYPE,
59 {
60 END_DEVICE_PATH_LENGTH,
61 0
62 }
63 }
64 };
65
66 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
67 {
68 {
69 MEDIA_DEVICE_PATH,
70 MEDIA_PIWG_FW_VOL_DP,
71 {
72 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
73 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
74 }
75 },
76 { 0 }
77 },
78 {
79 END_DEVICE_PATH_TYPE,
80 END_ENTIRE_DEVICE_PATH_SUBTYPE,
81 {
82 END_DEVICE_PATH_LENGTH,
83 0
84 }
85 }
86 };
87
88 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
89 FVB_DEVICE_SIGNATURE,
90 NULL,
91 0,
92 {
93 FvbProtocolGetAttributes,
94 FvbProtocolSetAttributes,
95 FvbProtocolGetPhysicalAddress,
96 FvbProtocolGetBlockSize,
97 FvbProtocolRead,
98 FvbProtocolWrite,
99 FvbProtocolEraseBlocks,
100 NULL
101 }
102 };
103
104 EFI_STATUS
105 GetFvbInstance (
106 IN UINTN Instance,
107 IN ESAL_FWB_GLOBAL *Global,
108 OUT EFI_FW_VOL_INSTANCE **FwhInstance
109 )
110
111 /*++
112
113 Routine Description:
114 Retrieves the physical address of a memory mapped FV
115
116 Arguments:
117 Instance - The FV instance whose base address is going to be
118 returned
119 Global - Pointer to ESAL_FWB_GLOBAL that contains all
120 instance data
121 FwhInstance - The EFI_FW_VOL_INSTANCE firmware instance structure
122
123 Returns:
124 EFI_SUCCESS - Successfully returns
125 EFI_INVALID_PARAMETER - Instance not found
126
127 --*/
128 {
129 EFI_FW_VOL_INSTANCE *FwhRecord;
130
131 *FwhInstance = NULL;
132 if (Instance >= Global->NumFv) {
133 return EFI_INVALID_PARAMETER;
134 }
135
136 //
137 // Find the right instance of the FVB private data
138 //
139 FwhRecord = Global->FvInstance;
140 while (Instance > 0) {
141 FwhRecord = (EFI_FW_VOL_INSTANCE *)
142 (
143 (UINTN)((UINT8 *)FwhRecord) + FwhRecord->VolumeHeader.HeaderLength +
144 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
145 );
146 Instance--;
147 }
148
149 *FwhInstance = FwhRecord;
150
151 return EFI_SUCCESS;
152 }
153
154 EFI_STATUS
155 FvbGetPhysicalAddress (
156 IN UINTN Instance,
157 OUT EFI_PHYSICAL_ADDRESS *Address,
158 IN ESAL_FWB_GLOBAL *Global
159 )
160
161 /*++
162
163 Routine Description:
164 Retrieves the physical address of a memory mapped FV
165
166 Arguments:
167 Instance - The FV instance whose base address is going to be
168 returned
169 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
170 that on successful return, contains the base
171 address of the firmware volume.
172 Global - Pointer to ESAL_FWB_GLOBAL that contains all
173 instance data
174
175 Returns:
176 EFI_SUCCESS - Successfully returns
177 EFI_INVALID_PARAMETER - Instance not found
178
179 --*/
180 {
181 EFI_FW_VOL_INSTANCE *FwhInstance;
182 EFI_STATUS Status;
183
184 //
185 // Find the right instance of the FVB private data
186 //
187 Status = GetFvbInstance (Instance, Global, &FwhInstance);
188 ASSERT_EFI_ERROR (Status);
189 *Address = FwhInstance->FvBase;
190
191 return EFI_SUCCESS;
192 }
193
194 EFI_STATUS
195 FvbGetVolumeAttributes (
196 IN UINTN Instance,
197 OUT EFI_FVB_ATTRIBUTES_2 *Attributes,
198 IN ESAL_FWB_GLOBAL *Global
199 )
200
201 /*++
202
203 Routine Description:
204 Retrieves attributes, insures positive polarity of attribute bits, returns
205 resulting attributes in output parameter
206
207 Arguments:
208 Instance - The FV instance whose attributes is going to be
209 returned
210 Attributes - Output buffer which contains attributes
211 Global - Pointer to ESAL_FWB_GLOBAL that contains all
212 instance data
213
214 Returns:
215 EFI_SUCCESS - Successfully returns
216 EFI_INVALID_PARAMETER - Instance not found
217
218 --*/
219 {
220 EFI_FW_VOL_INSTANCE *FwhInstance;
221 EFI_STATUS Status;
222
223 //
224 // Find the right instance of the FVB private data
225 //
226 Status = GetFvbInstance (Instance, Global, &FwhInstance);
227 ASSERT_EFI_ERROR (Status);
228 *Attributes = FwhInstance->VolumeHeader.Attributes;
229
230 return EFI_SUCCESS;
231 }
232
233 EFI_STATUS
234 FvbGetLbaAddress (
235 IN UINTN Instance,
236 IN EFI_LBA Lba,
237 OUT UINTN *LbaAddress,
238 OUT UINTN *LbaLength,
239 OUT UINTN *NumOfBlocks,
240 IN ESAL_FWB_GLOBAL *Global
241 )
242
243 /*++
244
245 Routine Description:
246 Retrieves the starting address of an LBA in an FV
247
248 Arguments:
249 Instance - The FV instance which the Lba belongs to
250 Lba - The logical block address
251 LbaAddress - On output, contains the physical starting address
252 of the Lba
253 LbaLength - On output, contains the length of the block
254 NumOfBlocks - A pointer to a caller allocated UINTN in which the
255 number of consecutive blocks starting with Lba is
256 returned. All blocks in this range have a size of
257 BlockSize
258 Global - Pointer to ESAL_FWB_GLOBAL that contains all
259 instance data
260
261 Returns:
262 EFI_SUCCESS - Successfully returns
263 EFI_INVALID_PARAMETER - Instance not found
264
265 --*/
266 {
267 UINT32 NumBlocks;
268 UINT32 BlockLength;
269 UINTN Offset;
270 EFI_LBA StartLba;
271 EFI_LBA NextLba;
272 EFI_FW_VOL_INSTANCE *FwhInstance;
273 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
274 EFI_STATUS Status;
275
276 //
277 // Find the right instance of the FVB private data
278 //
279 Status = GetFvbInstance (Instance, Global, &FwhInstance);
280 ASSERT_EFI_ERROR (Status);
281
282 StartLba = 0;
283 Offset = 0;
284 BlockMap = &(FwhInstance->VolumeHeader.BlockMap[0]);
285
286 //
287 // Parse the blockmap of the FV to find which map entry the Lba belongs to
288 //
289 while (TRUE) {
290 NumBlocks = BlockMap->NumBlocks;
291 BlockLength = BlockMap->Length;
292
293 if ((NumBlocks == 0) || (BlockLength == 0)) {
294 return EFI_INVALID_PARAMETER;
295 }
296
297 NextLba = StartLba + NumBlocks;
298
299 //
300 // The map entry found
301 //
302 if ((Lba >= StartLba) && (Lba < NextLba)) {
303 Offset = Offset + (UINTN)MultU64x32 ((Lba - StartLba), BlockLength);
304 if (LbaAddress != NULL) {
305 *LbaAddress = FwhInstance->FvBase + Offset;
306 }
307
308 if (LbaLength != NULL) {
309 *LbaLength = BlockLength;
310 }
311
312 if (NumOfBlocks != NULL) {
313 *NumOfBlocks = (UINTN)(NextLba - Lba);
314 }
315
316 return EFI_SUCCESS;
317 }
318
319 StartLba = NextLba;
320 Offset = Offset + NumBlocks * BlockLength;
321 BlockMap++;
322 }
323 }
324
325 EFI_STATUS
326 FvbSetVolumeAttributes (
327 IN UINTN Instance,
328 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes,
329 IN ESAL_FWB_GLOBAL *Global
330 )
331
332 /*++
333
334 Routine Description:
335 Modifies the current settings of the firmware volume according to the
336 input parameter, and returns the new setting of the volume
337
338 Arguments:
339 Instance - The FV instance whose attributes is going to be
340 modified
341 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
342 containing the desired firmware volume settings.
343 On successful return, it contains the new settings
344 of the firmware volume
345 Global - Pointer to ESAL_FWB_GLOBAL that contains all
346 instance data
347
348 Returns:
349 EFI_SUCCESS - Successfully returns
350 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
351 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
352 in conflict with the capabilities as declared in
353 the firmware volume header
354
355 --*/
356 {
357 EFI_FW_VOL_INSTANCE *FwhInstance;
358 EFI_FVB_ATTRIBUTES_2 OldAttributes;
359 EFI_FVB_ATTRIBUTES_2 *AttribPtr;
360 UINT32 Capabilities;
361 UINT32 OldStatus;
362 UINT32 NewStatus;
363 EFI_STATUS Status;
364 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;
365
366 //
367 // Find the right instance of the FVB private data
368 //
369 Status = GetFvbInstance (Instance, Global, &FwhInstance);
370 ASSERT_EFI_ERROR (Status);
371
372 AttribPtr =
373 (EFI_FVB_ATTRIBUTES_2 *)&(FwhInstance->VolumeHeader.Attributes);
374 OldAttributes = *AttribPtr;
375 Capabilities = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \
376 EFI_FVB2_READ_ENABLED_CAP | \
377 EFI_FVB2_WRITE_DISABLED_CAP | \
378 EFI_FVB2_WRITE_ENABLED_CAP | \
379 EFI_FVB2_LOCK_CAP \
380 );
381 OldStatus = OldAttributes & EFI_FVB2_STATUS;
382 NewStatus = *Attributes & EFI_FVB2_STATUS;
383
384 UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \
385 EFI_FVB2_READ_ENABLED_CAP | \
386 EFI_FVB2_WRITE_DISABLED_CAP | \
387 EFI_FVB2_WRITE_ENABLED_CAP | \
388 EFI_FVB2_LOCK_CAP | \
389 EFI_FVB2_STICKY_WRITE | \
390 EFI_FVB2_MEMORY_MAPPED | \
391 EFI_FVB2_ERASE_POLARITY | \
392 EFI_FVB2_READ_LOCK_CAP | \
393 EFI_FVB2_WRITE_LOCK_CAP | \
394 EFI_FVB2_ALIGNMENT;
395
396 //
397 // Some attributes of FV is read only can *not* be set
398 //
399 if ((OldAttributes & UnchangedAttributes) ^
400 (*Attributes & UnchangedAttributes))
401 {
402 return EFI_INVALID_PARAMETER;
403 }
404
405 //
406 // If firmware volume is locked, no status bit can be updated
407 //
408 if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
409 if (OldStatus ^ NewStatus) {
410 return EFI_ACCESS_DENIED;
411 }
412 }
413
414 //
415 // Test read disable
416 //
417 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
418 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
419 return EFI_INVALID_PARAMETER;
420 }
421 }
422
423 //
424 // Test read enable
425 //
426 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
427 if (NewStatus & EFI_FVB2_READ_STATUS) {
428 return EFI_INVALID_PARAMETER;
429 }
430 }
431
432 //
433 // Test write disable
434 //
435 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
436 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
437 return EFI_INVALID_PARAMETER;
438 }
439 }
440
441 //
442 // Test write enable
443 //
444 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
445 if (NewStatus & EFI_FVB2_WRITE_STATUS) {
446 return EFI_INVALID_PARAMETER;
447 }
448 }
449
450 //
451 // Test lock
452 //
453 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
454 if (NewStatus & EFI_FVB2_LOCK_STATUS) {
455 return EFI_INVALID_PARAMETER;
456 }
457 }
458
459 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
460 *AttribPtr = (*AttribPtr) | NewStatus;
461 *Attributes = *AttribPtr;
462
463 return EFI_SUCCESS;
464 }
465
466 //
467 // FVB protocol APIs
468 //
469 EFI_STATUS
470 EFIAPI
471 FvbProtocolGetPhysicalAddress (
472 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
473 OUT EFI_PHYSICAL_ADDRESS *Address
474 )
475
476 /*++
477
478 Routine Description:
479
480 Retrieves the physical address of the device.
481
482 Arguments:
483
484 This - Calling context
485 Address - Output buffer containing the address.
486
487 Returns:
488 EFI_SUCCESS - Successfully returns
489
490 --*/
491 {
492 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
493
494 FvbDevice = FVB_DEVICE_FROM_THIS (This);
495
496 return FvbGetPhysicalAddress (
497 FvbDevice->Instance,
498 Address,
499 mFvbModuleGlobal
500 );
501 }
502
503 EFI_STATUS
504 EFIAPI
505 FvbProtocolGetBlockSize (
506 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
507 IN CONST EFI_LBA Lba,
508 OUT UINTN *BlockSize,
509 OUT UINTN *NumOfBlocks
510 )
511
512 /*++
513
514 Routine Description:
515 Retrieve the size of a logical block
516
517 Arguments:
518 This - Calling context
519 Lba - Indicates which block to return the size for.
520 BlockSize - A pointer to a caller allocated UINTN in which
521 the size of the block is returned
522 NumOfBlocks - a pointer to a caller allocated UINTN in which the
523 number of consecutive blocks starting with Lba is
524 returned. All blocks in this range have a size of
525 BlockSize
526
527 Returns:
528 EFI_SUCCESS - The firmware volume was read successfully and
529 contents are in Buffer
530
531 --*/
532 {
533 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
534
535 FvbDevice = FVB_DEVICE_FROM_THIS (This);
536
537 return FvbGetLbaAddress (
538 FvbDevice->Instance,
539 Lba,
540 NULL,
541 BlockSize,
542 NumOfBlocks,
543 mFvbModuleGlobal
544 );
545 }
546
547 EFI_STATUS
548 EFIAPI
549 FvbProtocolGetAttributes (
550 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
551 OUT EFI_FVB_ATTRIBUTES_2 *Attributes
552 )
553
554 /*++
555
556 Routine Description:
557 Retrieves Volume attributes. No polarity translations are done.
558
559 Arguments:
560 This - Calling context
561 Attributes - output buffer which contains attributes
562
563 Returns:
564 EFI_SUCCESS - Successfully returns
565
566 --*/
567 {
568 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
569
570 FvbDevice = FVB_DEVICE_FROM_THIS (This);
571
572 return FvbGetVolumeAttributes (
573 FvbDevice->Instance,
574 Attributes,
575 mFvbModuleGlobal
576 );
577 }
578
579 EFI_STATUS
580 EFIAPI
581 FvbProtocolSetAttributes (
582 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
583 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
584 )
585
586 /*++
587
588 Routine Description:
589 Sets Volume attributes. No polarity translations are done.
590
591 Arguments:
592 This - Calling context
593 Attributes - output buffer which contains attributes
594
595 Returns:
596 EFI_SUCCESS - Successfully returns
597
598 --*/
599 {
600 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
601
602 FvbDevice = FVB_DEVICE_FROM_THIS (This);
603
604 return FvbSetVolumeAttributes (
605 FvbDevice->Instance,
606 Attributes,
607 mFvbModuleGlobal
608 );
609 }
610
611 EFI_STATUS
612 EFIAPI
613 FvbProtocolEraseBlocks (
614 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
615 ...
616 )
617
618 /*++
619
620 Routine Description:
621
622 The EraseBlock() function erases one or more blocks as denoted by the
623 variable argument list. The entire parameter list of blocks must be
624 verified prior to erasing any blocks. If a block is requested that does
625 not exist within the associated firmware volume (it has a larger index than
626 the last block of the firmware volume), the EraseBlock() function must
627 return EFI_INVALID_PARAMETER without modifying the contents of the firmware
628 volume.
629
630 Arguments:
631 This - Calling context
632 ... - Starting LBA followed by Number of Lba to erase.
633 a -1 to terminate the list.
634
635 Returns:
636 EFI_SUCCESS - The erase request was successfully completed
637 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
638 EFI_DEVICE_ERROR - The block device is not functioning correctly and
639 could not be written. Firmware device may have been
640 partially erased
641
642 --*/
643 {
644 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
645 EFI_FW_VOL_INSTANCE *FwhInstance;
646 UINTN NumOfBlocks;
647 VA_LIST args;
648 EFI_LBA StartingLba;
649 UINTN NumOfLba;
650 EFI_STATUS Status;
651
652 FvbDevice = FVB_DEVICE_FROM_THIS (This);
653
654 Status = GetFvbInstance (
655 FvbDevice->Instance,
656 mFvbModuleGlobal,
657 &FwhInstance
658 );
659 ASSERT_EFI_ERROR (Status);
660
661 NumOfBlocks = FwhInstance->NumOfBlocks;
662
663 VA_START (args, This);
664
665 do {
666 StartingLba = VA_ARG (args, EFI_LBA);
667 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
668 break;
669 }
670
671 NumOfLba = VA_ARG (args, UINTN);
672
673 //
674 // Check input parameters
675 //
676 if ((NumOfLba == 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) {
677 VA_END (args);
678 return EFI_INVALID_PARAMETER;
679 }
680 } while (1);
681
682 VA_END (args);
683
684 VA_START (args, This);
685 do {
686 StartingLba = VA_ARG (args, EFI_LBA);
687 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
688 break;
689 }
690
691 NumOfLba = VA_ARG (args, UINTN);
692
693 while (NumOfLba > 0) {
694 Status = QemuFlashEraseBlock (StartingLba);
695 if (EFI_ERROR (Status)) {
696 VA_END (args);
697 return Status;
698 }
699
700 StartingLba++;
701 NumOfLba--;
702 }
703 } while (1);
704
705 VA_END (args);
706
707 return EFI_SUCCESS;
708 }
709
710 EFI_STATUS
711 EFIAPI
712 FvbProtocolWrite (
713 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
714 IN EFI_LBA Lba,
715 IN UINTN Offset,
716 IN OUT UINTN *NumBytes,
717 IN UINT8 *Buffer
718 )
719
720 /*++
721
722 Routine Description:
723
724 Writes data beginning at Lba:Offset from FV. The write terminates either
725 when *NumBytes of data have been written, or when a block boundary is
726 reached. *NumBytes is updated to reflect the actual number of bytes
727 written. The write operation does not include erase. This routine will
728 attempt to write only the specified bytes. If the writes do not stick,
729 it will return an error.
730
731 Arguments:
732 This - Calling context
733 Lba - Block in which to begin write
734 Offset - Offset in the block at which to begin write
735 NumBytes - On input, indicates the requested write size. On
736 output, indicates the actual number of bytes
737 written
738 Buffer - Buffer containing source data for the write.
739
740 Returns:
741 EFI_SUCCESS - The firmware volume was written successfully
742 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
743 NumBytes contains the total number of bytes
744 actually written
745 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
746 EFI_DEVICE_ERROR - The block device is not functioning correctly and
747 could not be written
748 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
749
750 --*/
751 {
752 return QemuFlashWrite (
753 (EFI_LBA)Lba,
754 (UINTN)Offset,
755 NumBytes,
756 (UINT8 *)Buffer
757 );
758 }
759
760 EFI_STATUS
761 EFIAPI
762 FvbProtocolRead (
763 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
764 IN CONST EFI_LBA Lba,
765 IN CONST UINTN Offset,
766 IN OUT UINTN *NumBytes,
767 IN UINT8 *Buffer
768 )
769
770 /*++
771
772 Routine Description:
773
774 Reads data beginning at Lba:Offset from FV. The Read terminates either
775 when *NumBytes of data have been read, or when a block boundary is
776 reached. *NumBytes is updated to reflect the actual number of bytes
777 written. The write operation does not include erase. This routine will
778 attempt to write only the specified bytes. If the writes do not stick,
779 it will return an error.
780
781 Arguments:
782 This - Calling context
783 Lba - Block in which to begin Read
784 Offset - Offset in the block at which to begin Read
785 NumBytes - On input, indicates the requested write size. On
786 output, indicates the actual number of bytes Read
787 Buffer - Buffer containing source data for the Read.
788
789 Returns:
790 EFI_SUCCESS - The firmware volume was read successfully and
791 contents are in Buffer
792 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
793 NumBytes contains the total number of bytes
794 returned in Buffer
795 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
796 EFI_DEVICE_ERROR - The block device is not functioning correctly and
797 could not be read
798 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
799
800 --*/
801 {
802 return QemuFlashRead (
803 (EFI_LBA)Lba,
804 (UINTN)Offset,
805 NumBytes,
806 (UINT8 *)Buffer
807 );
808 }
809
810 EFI_STATUS
811 ValidateFvHeader (
812 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
813 )
814
815 /*++
816
817 Routine Description:
818 Check the integrity of firmware volume header
819
820 Arguments:
821 FwVolHeader - A pointer to a firmware volume header
822
823 Returns:
824 EFI_SUCCESS - The firmware volume is consistent
825 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an
826 FV
827
828 --*/
829 {
830 UINT16 Checksum;
831
832 //
833 // Verify the header revision, header signature, length
834 // Length of FvBlock cannot be 2**64-1
835 // HeaderLength cannot be an odd number
836 //
837 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
838 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
839 (FwVolHeader->FvLength == ((UINTN)-1)) ||
840 ((FwVolHeader->HeaderLength & 0x01) != 0)
841 )
842 {
843 return EFI_NOT_FOUND;
844 }
845
846 //
847 // Verify the header checksum
848 //
849
850 Checksum = CalculateSum16 (
851 (UINT16 *)FwVolHeader,
852 FwVolHeader->HeaderLength
853 );
854 if (Checksum != 0) {
855 UINT16 Expected;
856
857 Expected =
858 (UINT16)(((UINTN)FwVolHeader->Checksum + 0x10000 - Checksum) & 0xffff);
859
860 DEBUG ((
861 DEBUG_INFO,
862 "FV@%p Checksum is 0x%x, expected 0x%x\n",
863 FwVolHeader,
864 FwVolHeader->Checksum,
865 Expected
866 ));
867 return EFI_NOT_FOUND;
868 }
869
870 return EFI_SUCCESS;
871 }
872
873 STATIC
874 EFI_STATUS
875 InitializeVariableFvHeader (
876 VOID
877 )
878 {
879 EFI_STATUS Status;
880 EFI_FIRMWARE_VOLUME_HEADER *GoodFwVolHeader;
881 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
882 UINTN Length;
883 UINTN WriteLength;
884 UINTN BlockSize;
885
886 FwVolHeader =
887 (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)
888 PcdGet32 (PcdOvmfFlashNvStorageVariableBase);
889
890 Length =
891 (FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
892 FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
893 FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize) +
894 FixedPcdGet32 (PcdOvmfFlashNvStorageEventLogSize));
895
896 BlockSize = PcdGet32 (PcdOvmfFirmwareBlockSize);
897
898 Status = ValidateFvHeader (FwVolHeader);
899 if (!EFI_ERROR (Status)) {
900 if ((FwVolHeader->FvLength != Length) ||
901 (FwVolHeader->BlockMap[0].Length != BlockSize))
902 {
903 Status = EFI_VOLUME_CORRUPTED;
904 }
905 }
906
907 if (EFI_ERROR (Status)) {
908 UINTN Offset;
909 UINTN Start;
910
911 DEBUG ((
912 DEBUG_INFO,
913 "Variable FV header is not valid. It will be reinitialized.\n"
914 ));
915
916 //
917 // Get FvbInfo to provide in FwhInstance.
918 //
919 Status = GetFvbInfo (Length, &GoodFwVolHeader);
920 ASSERT (!EFI_ERROR (Status));
921
922 Start = (UINTN)(UINT8 *)FwVolHeader - PcdGet32 (PcdOvmfFdBaseAddress);
923 ASSERT (Start % BlockSize == 0 && Length % BlockSize == 0);
924 ASSERT (GoodFwVolHeader->HeaderLength <= BlockSize);
925
926 //
927 // Erase all the blocks
928 //
929 for (Offset = Start; Offset < Start + Length; Offset += BlockSize) {
930 Status = QemuFlashEraseBlock (Offset / BlockSize);
931 ASSERT_EFI_ERROR (Status);
932 }
933
934 //
935 // Write good FV header
936 //
937 WriteLength = GoodFwVolHeader->HeaderLength;
938 Status = QemuFlashWrite (
939 Start / BlockSize,
940 0,
941 &WriteLength,
942 (UINT8 *)GoodFwVolHeader
943 );
944 ASSERT_EFI_ERROR (Status);
945 ASSERT (WriteLength == GoodFwVolHeader->HeaderLength);
946 }
947
948 return Status;
949 }
950
951 EFI_STATUS
952 EFIAPI
953 FvbInitialize (
954 IN EFI_HANDLE ImageHandle,
955 IN EFI_SYSTEM_TABLE *SystemTable
956 )
957
958 /*++
959
960 Routine Description:
961 This function does common initialization for FVB services
962
963 Arguments:
964
965 Returns:
966
967 --*/
968 {
969 EFI_STATUS Status;
970 EFI_FW_VOL_INSTANCE *FwhInstance;
971 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
972 UINT32 BufferSize;
973 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
974 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
975 UINT32 MaxLbaSize;
976 EFI_PHYSICAL_ADDRESS BaseAddress;
977 UINTN Length;
978 UINTN NumOfBlocks;
979 RETURN_STATUS PcdStatus;
980
981 if (EFI_ERROR (QemuFlashInitialize ())) {
982 //
983 // Return an error so image will be unloaded
984 //
985 DEBUG ((
986 DEBUG_INFO,
987 "QEMU flash was not detected. Writable FVB is not being installed.\n"
988 ));
989 return EFI_WRITE_PROTECTED;
990 }
991
992 //
993 // Allocate runtime services data for global variable, which contains
994 // the private data of all firmware volume block instances
995 //
996 mFvbModuleGlobal = AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL));
997 ASSERT (mFvbModuleGlobal != NULL);
998
999 BaseAddress = (UINTN)PcdGet32 (PcdOvmfFdBaseAddress);
1000 Length = PcdGet32 (PcdOvmfFirmwareFdSize);
1001
1002 Status = InitializeVariableFvHeader ();
1003 if (EFI_ERROR (Status)) {
1004 DEBUG ((
1005 DEBUG_INFO,
1006 "QEMU Flash: Unable to initialize variable FV header\n"
1007 ));
1008 return EFI_WRITE_PROTECTED;
1009 }
1010
1011 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;
1012 Status = ValidateFvHeader (FwVolHeader);
1013 if (EFI_ERROR (Status)) {
1014 //
1015 // Get FvbInfo
1016 //
1017 Status = GetFvbInfo (Length, &FwVolHeader);
1018 if (EFI_ERROR (Status)) {
1019 DEBUG ((DEBUG_INFO, "EFI_ERROR (GetFvbInfo (Length, &FwVolHeader))\n"));
1020 return EFI_WRITE_PROTECTED;
1021 }
1022 }
1023
1024 BufferSize = (sizeof (EFI_FW_VOL_INSTANCE) +
1025 FwVolHeader->HeaderLength -
1026 sizeof (EFI_FIRMWARE_VOLUME_HEADER)
1027 );
1028 mFvbModuleGlobal->FvInstance = AllocateRuntimePool (BufferSize);
1029 ASSERT (mFvbModuleGlobal->FvInstance != NULL);
1030
1031 FwhInstance = mFvbModuleGlobal->FvInstance;
1032
1033 mFvbModuleGlobal->NumFv = 0;
1034 MaxLbaSize = 0;
1035
1036 FwVolHeader =
1037 (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)
1038 PcdGet32 (PcdOvmfFlashNvStorageVariableBase);
1039
1040 FwhInstance->FvBase = (UINTN)BaseAddress;
1041
1042 CopyMem (
1043 (UINTN *)&(FwhInstance->VolumeHeader),
1044 (UINTN *)FwVolHeader,
1045 FwVolHeader->HeaderLength
1046 );
1047 FwVolHeader = &(FwhInstance->VolumeHeader);
1048
1049 NumOfBlocks = 0;
1050
1051 for (PtrBlockMapEntry = FwVolHeader->BlockMap;
1052 PtrBlockMapEntry->NumBlocks != 0;
1053 PtrBlockMapEntry++)
1054 {
1055 //
1056 // Get the maximum size of a block.
1057 //
1058 if (MaxLbaSize < PtrBlockMapEntry->Length) {
1059 MaxLbaSize = PtrBlockMapEntry->Length;
1060 }
1061
1062 NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;
1063 }
1064
1065 //
1066 // The total number of blocks in the FV.
1067 //
1068 FwhInstance->NumOfBlocks = NumOfBlocks;
1069
1070 //
1071 // Add a FVB Protocol Instance
1072 //
1073 FvbDevice = AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE));
1074 ASSERT (FvbDevice != NULL);
1075
1076 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));
1077
1078 FvbDevice->Instance = mFvbModuleGlobal->NumFv;
1079 mFvbModuleGlobal->NumFv++;
1080
1081 //
1082 // Set up the devicepath
1083 //
1084 if (FwVolHeader->ExtHeaderOffset == 0) {
1085 FV_MEMMAP_DEVICE_PATH *FvMemmapDevicePath;
1086
1087 //
1088 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
1089 //
1090 FvMemmapDevicePath = AllocateCopyPool (
1091 sizeof (FV_MEMMAP_DEVICE_PATH),
1092 &mFvMemmapDevicePathTemplate
1093 );
1094 FvMemmapDevicePath->MemMapDevPath.StartingAddress = BaseAddress;
1095 FvMemmapDevicePath->MemMapDevPath.EndingAddress =
1096 BaseAddress + FwVolHeader->FvLength - 1;
1097 FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)FvMemmapDevicePath;
1098 } else {
1099 FV_PIWG_DEVICE_PATH *FvPiwgDevicePath;
1100
1101 FvPiwgDevicePath = AllocateCopyPool (
1102 sizeof (FV_PIWG_DEVICE_PATH),
1103 &mFvPIWGDevicePathTemplate
1104 );
1105 CopyGuid (
1106 &FvPiwgDevicePath->FvDevPath.FvName,
1107 (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
1108 );
1109 FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)FvPiwgDevicePath;
1110 }
1111
1112 //
1113 // Module type specific hook.
1114 //
1115 InstallProtocolInterfaces (FvbDevice);
1116
1117 MarkIoMemoryRangeForRuntimeAccess (BaseAddress, Length);
1118
1119 SetPcdFlashNvStorageBaseAddresses ();
1120
1121 FwhInstance = (EFI_FW_VOL_INSTANCE *)
1122 (
1123 (UINTN)((UINT8 *)FwhInstance) + FwVolHeader->HeaderLength +
1124 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
1125 );
1126
1127 //
1128 // Module type specific hook.
1129 //
1130 InstallVirtualAddressChangeHandler ();
1131
1132 PcdStatus = PcdSetBoolS (PcdOvmfFlashVariablesEnable, TRUE);
1133 ASSERT_RETURN_ERROR (PcdStatus);
1134 return EFI_SUCCESS;
1135 }