2 Functions related to the Firmware Volume Block service whose
3 implementation is specific to the runtime DXE driver build.
5 Copyright (C) 2015, Red Hat, Inc.
6 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include <Guid/EventGroup.h>
12 #include <Library/DebugLib.h>
13 #include <Library/DevicePathLib.h>
14 #include <Library/DxeServicesTableLib.h>
15 #include <Library/MemEncryptSevLib.h>
16 #include <Library/PcdLib.h>
17 #include <Library/UefiBootServicesTableLib.h>
18 #include <Library/UefiRuntimeLib.h>
19 #include <Protocol/DevicePath.h>
20 #include <Protocol/FirmwareVolumeBlock.h>
22 #include "FwBlockService.h"
23 #include "QemuFlash.h"
26 InstallProtocolInterfaces (
27 IN EFI_FW_VOL_BLOCK_DEVICE
*FvbDevice
32 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*OldFwbInterface
;
34 ASSERT (!FeaturePcdGet (PcdSmmSmramRequire
));
37 // Find a handle with a matching device path that has supports FW Block
40 Status
= gBS
->LocateDevicePath (
41 &gEfiFirmwareVolumeBlockProtocolGuid
,
42 &FvbDevice
->DevicePath
,
45 if (EFI_ERROR (Status
)) {
47 // LocateDevicePath fails so install a new interface and device path
50 DEBUG ((DEBUG_INFO
, "Installing QEMU flash FVB\n"));
51 Status
= gBS
->InstallMultipleProtocolInterfaces (
53 &gEfiFirmwareVolumeBlockProtocolGuid
,
54 &FvbDevice
->FwVolBlockInstance
,
55 &gEfiDevicePathProtocolGuid
,
56 FvbDevice
->DevicePath
,
59 ASSERT_EFI_ERROR (Status
);
60 } else if (IsDevicePathEnd (FvbDevice
->DevicePath
)) {
62 // Device already exists, so reinstall the FVB protocol
64 Status
= gBS
->HandleProtocol (
66 &gEfiFirmwareVolumeBlockProtocolGuid
,
67 (VOID
**)&OldFwbInterface
69 ASSERT_EFI_ERROR (Status
);
71 DEBUG ((DEBUG_INFO
, "Reinstalling FVB for QEMU flash region\n"));
72 Status
= gBS
->ReinstallProtocolInterface (
74 &gEfiFirmwareVolumeBlockProtocolGuid
,
76 &FvbDevice
->FwVolBlockInstance
78 ASSERT_EFI_ERROR (Status
);
81 // There was a FVB protocol on an End Device Path node
90 FvbVirtualAddressChangeEvent (
99 Fixup internal data so that EFI and SAL can be call in virtual mode.
100 Call the passed in Child Notify event and convert the mFvbModuleGlobal
101 date items to there virtual address.
105 (Standard EFI notify event - EFI_EVENT_NOTIFY)
113 EFI_FW_VOL_INSTANCE
*FwhInstance
;
116 FwhInstance
= mFvbModuleGlobal
->FvInstance
;
117 EfiConvertPointer (0x0, (VOID
**)&mFvbModuleGlobal
->FvInstance
);
120 // Convert the base address of all the instances
123 while (Index
< mFvbModuleGlobal
->NumFv
) {
124 EfiConvertPointer (0x0, (VOID
**)&FwhInstance
->FvBase
);
125 FwhInstance
= (EFI_FW_VOL_INSTANCE
*)
127 (UINTN
)((UINT8
*)FwhInstance
) +
128 FwhInstance
->VolumeHeader
.HeaderLength
+
129 (sizeof (EFI_FW_VOL_INSTANCE
) - sizeof (EFI_FIRMWARE_VOLUME_HEADER
))
134 EfiConvertPointer (0x0, (VOID
**)&mFvbModuleGlobal
);
135 QemuFlashConvertPointers ();
139 InstallVirtualAddressChangeHandler (
144 EFI_EVENT VirtualAddressChangeEvent
;
146 Status
= gBS
->CreateEventEx (
149 FvbVirtualAddressChangeEvent
,
151 &gEfiEventVirtualAddressChangeGuid
,
152 &VirtualAddressChangeEvent
154 ASSERT_EFI_ERROR (Status
);
158 MarkIoMemoryRangeForRuntimeAccess (
159 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
164 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor
;
167 // Mark flash region as runtime memory
169 Status
= gDS
->RemoveMemorySpace (
174 Status
= gDS
->AddMemorySpace (
175 EfiGcdMemoryTypeMemoryMappedIo
,
178 EFI_MEMORY_UC
| EFI_MEMORY_RUNTIME
180 ASSERT_EFI_ERROR (Status
);
182 Status
= gDS
->AllocateMemorySpace (
183 EfiGcdAllocateAddress
,
184 EfiGcdMemoryTypeMemoryMappedIo
,
191 ASSERT_EFI_ERROR (Status
);
193 Status
= gDS
->GetMemorySpaceDescriptor (BaseAddress
, &GcdDescriptor
);
194 ASSERT_EFI_ERROR (Status
);
196 Status
= gDS
->SetMemorySpaceAttributes (
199 GcdDescriptor
.Attributes
| EFI_MEMORY_RUNTIME
201 ASSERT_EFI_ERROR (Status
);
204 // When SEV is active, AmdSevDxe mapped the BaseAddress with C=0 but
205 // SetMemorySpaceAttributes() remaps the range with C=1. Let's restore
206 // the mapping so that both guest and hyervisor can access the flash
209 if (MemEncryptSevIsEnabled ()) {
210 Status
= MemEncryptSevClearMmioPageEncMask (
213 EFI_SIZE_TO_PAGES (Length
)
215 ASSERT_EFI_ERROR (Status
);
222 SetPcdFlashNvStorageBaseAddresses (
226 RETURN_STATUS PcdStatus
;
229 // Set several PCD values to point to flash
231 PcdStatus
= PcdSet64S (
232 PcdFlashNvStorageVariableBase64
,
233 (UINTN
)PcdGet32 (PcdOvmfFlashNvStorageVariableBase
)
235 ASSERT_RETURN_ERROR (PcdStatus
);
236 PcdStatus
= PcdSet32S (
237 PcdFlashNvStorageFtwWorkingBase
,
238 PcdGet32 (PcdOvmfFlashNvStorageFtwWorkingBase
)
240 ASSERT_RETURN_ERROR (PcdStatus
);
241 PcdStatus
= PcdSet32S (
242 PcdFlashNvStorageFtwSpareBase
,
243 PcdGet32 (PcdOvmfFlashNvStorageFtwSpareBase
)
245 ASSERT_RETURN_ERROR (PcdStatus
);