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