]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / QemuFlashFvbServicesRuntimeDxe / FwBlockServiceDxe.c
1 /**@file
2 Functions related to the Firmware Volume Block service whose
3 implementation is specific to the runtime DXE driver build.
4
5 Copyright (C) 2015, Red Hat, Inc.
6 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
7
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9 **/
10
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>
21
22 #include "FwBlockService.h"
23 #include "QemuFlash.h"
24
25 VOID
26 InstallProtocolInterfaces (
27 IN EFI_FW_VOL_BLOCK_DEVICE *FvbDevice
28 )
29 {
30 EFI_STATUS Status;
31 EFI_HANDLE FwbHandle;
32 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;
33
34 ASSERT (!FeaturePcdGet (PcdSmmSmramRequire));
35
36 //
37 // Find a handle with a matching device path that has supports FW Block
38 // protocol
39 //
40 Status = gBS->LocateDevicePath (
41 &gEfiFirmwareVolumeBlockProtocolGuid,
42 &FvbDevice->DevicePath,
43 &FwbHandle
44 );
45 if (EFI_ERROR (Status)) {
46 //
47 // LocateDevicePath fails so install a new interface and device path
48 //
49 FwbHandle = NULL;
50 DEBUG ((DEBUG_INFO, "Installing QEMU flash FVB\n"));
51 Status = gBS->InstallMultipleProtocolInterfaces (
52 &FwbHandle,
53 &gEfiFirmwareVolumeBlockProtocolGuid,
54 &FvbDevice->FwVolBlockInstance,
55 &gEfiDevicePathProtocolGuid,
56 FvbDevice->DevicePath,
57 NULL
58 );
59 ASSERT_EFI_ERROR (Status);
60 } else if (IsDevicePathEnd (FvbDevice->DevicePath)) {
61 //
62 // Device already exists, so reinstall the FVB protocol
63 //
64 Status = gBS->HandleProtocol (
65 FwbHandle,
66 &gEfiFirmwareVolumeBlockProtocolGuid,
67 (VOID **)&OldFwbInterface
68 );
69 ASSERT_EFI_ERROR (Status);
70
71 DEBUG ((DEBUG_INFO, "Reinstalling FVB for QEMU flash region\n"));
72 Status = gBS->ReinstallProtocolInterface (
73 FwbHandle,
74 &gEfiFirmwareVolumeBlockProtocolGuid,
75 OldFwbInterface,
76 &FvbDevice->FwVolBlockInstance
77 );
78 ASSERT_EFI_ERROR (Status);
79 } else {
80 //
81 // There was a FVB protocol on an End Device Path node
82 //
83 ASSERT (FALSE);
84 }
85 }
86
87 STATIC
88 VOID
89 EFIAPI
90 FvbVirtualAddressChangeEvent (
91 IN EFI_EVENT Event,
92 IN VOID *Context
93 )
94
95 /*++
96
97 Routine Description:
98
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.
102
103 Arguments:
104
105 (Standard EFI notify event - EFI_EVENT_NOTIFY)
106
107 Returns:
108
109 None
110
111 --*/
112 {
113 EFI_FW_VOL_INSTANCE *FwhInstance;
114 UINTN Index;
115
116 FwhInstance = mFvbModuleGlobal->FvInstance;
117 EfiConvertPointer (0x0, (VOID **)&mFvbModuleGlobal->FvInstance);
118
119 //
120 // Convert the base address of all the instances
121 //
122 Index = 0;
123 while (Index < mFvbModuleGlobal->NumFv) {
124 EfiConvertPointer (0x0, (VOID **)&FwhInstance->FvBase);
125 FwhInstance = (EFI_FW_VOL_INSTANCE *)
126 (
127 (UINTN)((UINT8 *)FwhInstance) +
128 FwhInstance->VolumeHeader.HeaderLength +
129 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
130 );
131 Index++;
132 }
133
134 EfiConvertPointer (0x0, (VOID **)&mFvbModuleGlobal);
135 QemuFlashConvertPointers ();
136 }
137
138 VOID
139 InstallVirtualAddressChangeHandler (
140 VOID
141 )
142 {
143 EFI_STATUS Status;
144 EFI_EVENT VirtualAddressChangeEvent;
145
146 Status = gBS->CreateEventEx (
147 EVT_NOTIFY_SIGNAL,
148 TPL_NOTIFY,
149 FvbVirtualAddressChangeEvent,
150 NULL,
151 &gEfiEventVirtualAddressChangeGuid,
152 &VirtualAddressChangeEvent
153 );
154 ASSERT_EFI_ERROR (Status);
155 }
156
157 EFI_STATUS
158 MarkIoMemoryRangeForRuntimeAccess (
159 IN EFI_PHYSICAL_ADDRESS BaseAddress,
160 IN UINTN Length
161 )
162 {
163 EFI_STATUS Status;
164 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
165
166 //
167 // Mark flash region as runtime memory
168 //
169 Status = gDS->RemoveMemorySpace (
170 BaseAddress,
171 Length
172 );
173
174 Status = gDS->AddMemorySpace (
175 EfiGcdMemoryTypeMemoryMappedIo,
176 BaseAddress,
177 Length,
178 EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
179 );
180 ASSERT_EFI_ERROR (Status);
181
182 Status = gDS->AllocateMemorySpace (
183 EfiGcdAllocateAddress,
184 EfiGcdMemoryTypeMemoryMappedIo,
185 0,
186 Length,
187 &BaseAddress,
188 gImageHandle,
189 NULL
190 );
191 ASSERT_EFI_ERROR (Status);
192
193 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
194 ASSERT_EFI_ERROR (Status);
195
196 Status = gDS->SetMemorySpaceAttributes (
197 BaseAddress,
198 Length,
199 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
200 );
201 ASSERT_EFI_ERROR (Status);
202
203 //
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
207 // memory range.
208 //
209 if (MemEncryptSevIsEnabled ()) {
210 Status = MemEncryptSevClearMmioPageEncMask (
211 0,
212 BaseAddress,
213 EFI_SIZE_TO_PAGES (Length)
214 );
215 ASSERT_EFI_ERROR (Status);
216 }
217
218 return Status;
219 }
220
221 VOID
222 SetPcdFlashNvStorageBaseAddresses (
223 VOID
224 )
225 {
226 RETURN_STATUS PcdStatus;
227
228 //
229 // Set several PCD values to point to flash
230 //
231 PcdStatus = PcdSet64S (
232 PcdFlashNvStorageVariableBase64,
233 (UINTN)PcdGet32 (PcdOvmfFlashNvStorageVariableBase)
234 );
235 ASSERT_RETURN_ERROR (PcdStatus);
236 PcdStatus = PcdSet32S (
237 PcdFlashNvStorageFtwWorkingBase,
238 PcdGet32 (PcdOvmfFlashNvStorageFtwWorkingBase)
239 );
240 ASSERT_RETURN_ERROR (PcdStatus);
241 PcdStatus = PcdSet32S (
242 PcdFlashNvStorageFtwSpareBase,
243 PcdGet32 (PcdOvmfFlashNvStorageFtwSpareBase)
244 );
245 ASSERT_RETURN_ERROR (PcdStatus);
246 }