]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FwBlockServiceDxe.c
69b20916bc7ce582430a88470281eeee30be4b66
[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 (&gEfiFirmwareVolumeBlockProtocolGuid,
41 &FvbDevice->DevicePath, &FwbHandle);
42 if (EFI_ERROR (Status)) {
43 //
44 // LocateDevicePath fails so install a new interface and device path
45 //
46 FwbHandle = NULL;
47 DEBUG ((EFI_D_INFO, "Installing QEMU flash FVB\n"));
48 Status = gBS->InstallMultipleProtocolInterfaces (
49 &FwbHandle,
50 &gEfiFirmwareVolumeBlockProtocolGuid,
51 &FvbDevice->FwVolBlockInstance,
52 &gEfiDevicePathProtocolGuid,
53 FvbDevice->DevicePath,
54 NULL
55 );
56 ASSERT_EFI_ERROR (Status);
57 } else if (IsDevicePathEnd (FvbDevice->DevicePath)) {
58 //
59 // Device already exists, so reinstall the FVB protocol
60 //
61 Status = gBS->HandleProtocol (
62 FwbHandle,
63 &gEfiFirmwareVolumeBlockProtocolGuid,
64 (VOID**)&OldFwbInterface
65 );
66 ASSERT_EFI_ERROR (Status);
67
68 DEBUG ((EFI_D_INFO, "Reinstalling FVB for QEMU flash region\n"));
69 Status = gBS->ReinstallProtocolInterface (
70 FwbHandle,
71 &gEfiFirmwareVolumeBlockProtocolGuid,
72 OldFwbInterface,
73 &FvbDevice->FwVolBlockInstance
74 );
75 ASSERT_EFI_ERROR (Status);
76 } else {
77 //
78 // There was a FVB protocol on an End Device Path node
79 //
80 ASSERT (FALSE);
81 }
82 }
83
84
85 STATIC
86 VOID
87 EFIAPI
88 FvbVirtualAddressChangeEvent (
89 IN EFI_EVENT Event,
90 IN VOID *Context
91 )
92 /*++
93
94 Routine Description:
95
96 Fixup internal data so that EFI and SAL can be call in virtual mode.
97 Call the passed in Child Notify event and convert the mFvbModuleGlobal
98 date items to there virtual address.
99
100 Arguments:
101
102 (Standard EFI notify event - EFI_EVENT_NOTIFY)
103
104 Returns:
105
106 None
107
108 --*/
109 {
110 EFI_FW_VOL_INSTANCE *FwhInstance;
111 UINTN Index;
112
113 FwhInstance = mFvbModuleGlobal->FvInstance;
114 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvInstance);
115
116 //
117 // Convert the base address of all the instances
118 //
119 Index = 0;
120 while (Index < mFvbModuleGlobal->NumFv) {
121 EfiConvertPointer (0x0, (VOID **) &FwhInstance->FvBase);
122 FwhInstance = (EFI_FW_VOL_INSTANCE *)
123 (
124 (UINTN) ((UINT8 *) FwhInstance) +
125 FwhInstance->VolumeHeader.HeaderLength +
126 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
127 );
128 Index++;
129 }
130
131 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal);
132 QemuFlashConvertPointers ();
133 }
134
135
136 VOID
137 InstallVirtualAddressChangeHandler (
138 VOID
139 )
140 {
141 EFI_STATUS Status;
142 EFI_EVENT VirtualAddressChangeEvent;
143
144 Status = gBS->CreateEventEx (
145 EVT_NOTIFY_SIGNAL,
146 TPL_NOTIFY,
147 FvbVirtualAddressChangeEvent,
148 NULL,
149 &gEfiEventVirtualAddressChangeGuid,
150 &VirtualAddressChangeEvent
151 );
152 ASSERT_EFI_ERROR (Status);
153 }
154
155 EFI_STATUS
156 MarkIoMemoryRangeForRuntimeAccess (
157 IN EFI_PHYSICAL_ADDRESS BaseAddress,
158 IN UINTN Length
159 )
160 {
161 EFI_STATUS Status;
162 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
163
164 //
165 // Mark flash region as runtime memory
166 //
167 Status = gDS->RemoveMemorySpace (
168 BaseAddress,
169 Length
170 );
171
172 Status = gDS->AddMemorySpace (
173 EfiGcdMemoryTypeMemoryMappedIo,
174 BaseAddress,
175 Length,
176 EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
177 );
178 ASSERT_EFI_ERROR (Status);
179
180 Status = gDS->AllocateMemorySpace (
181 EfiGcdAllocateAddress,
182 EfiGcdMemoryTypeMemoryMappedIo,
183 0,
184 Length,
185 &BaseAddress,
186 gImageHandle,
187 NULL
188 );
189 ASSERT_EFI_ERROR (Status);
190
191 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
192 ASSERT_EFI_ERROR (Status);
193
194 Status = gDS->SetMemorySpaceAttributes (
195 BaseAddress,
196 Length,
197 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
198 );
199 ASSERT_EFI_ERROR (Status);
200
201 //
202 // When SEV is active, AmdSevDxe mapped the BaseAddress with C=0 but
203 // SetMemorySpaceAttributes() remaps the range with C=1. Let's restore
204 // the mapping so that both guest and hyervisor can access the flash
205 // memory range.
206 //
207 if (MemEncryptSevIsEnabled ()) {
208 Status = MemEncryptSevClearPageEncMask (
209 0,
210 BaseAddress,
211 EFI_SIZE_TO_PAGES (Length),
212 FALSE
213 );
214 ASSERT_EFI_ERROR (Status);
215 }
216
217 return Status;
218 }