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