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