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