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