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