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