TianoCore EDK2 master
Loading...
Searching...
No Matches
NorFlashKvmtool.c
Go to the documentation of this file.
1
10#include <Library/BaseLib.h>
11#include <Library/DebugLib.h>
14#include <Protocol/FdtClient.h>
15
18#define KVMTOOL_NOR_BLOCK_SIZE SIZE_64KB
19
22#define MAX_FLASH_DEVICES 4
23
26#define LABEL_UEFI_VAR_STORE "System-firmware"
27
29STATIC UINTN mNorFlashDeviceCount = 0;
30STATIC INT32 mUefiVarStoreNode = MAX_INT32;
31STATIC FDT_CLIENT_PROTOCOL *mFdtClient;
32
40 VOID
41 )
42{
43 EFI_STATUS Status;
44
45 DEBUG ((DEBUG_INFO, "NorFlashPlatformInitialization\n"));
46
47 if ((mNorFlashDeviceCount > 0) && (mUefiVarStoreNode != MAX_INT32)) {
48 //
49 // UEFI takes ownership of the cfi-flash hardware, and exposes its
50 // functionality through the UEFI Runtime Variable Service. This means we
51 // need to disable it in the device tree to prevent the OS from attaching
52 // its device driver as well.
53 // Note: This library is loaded twice. First by FaultTolerantWriteDxe to
54 // setup the PcdFlashNvStorageFtw* and later by NorFlashDxe to provide the
55 // NorFlashPlatformLib interfaces. If the node is disabled when the library
56 // is first loaded, then during the subsequent loading of the library the
57 // call to FindNextCompatibleNode() from the library constructor skips the
58 // FDT node used for UEFI storage variable. Due to this we cannot setup the
59 // NOR flash device description i.e. mNorFlashDevices[].
60 // Since NorFlashPlatformInitialization() is called only by NorFlashDxe,
61 // we know it is safe to disable the node here.
62 //
63 Status = mFdtClient->SetNodeProperty (
64 mFdtClient,
65 mUefiVarStoreNode,
66 "status",
67 "disabled",
68 sizeof ("disabled")
69 );
70 if (EFI_ERROR (Status)) {
71 DEBUG ((DEBUG_WARN, "Failed to set cfi-flash status to 'disabled'\n"));
72 }
73 } else {
74 Status = EFI_NOT_FOUND;
75 DEBUG ((DEBUG_ERROR, "Flash device for UEFI variable storage not found\n"));
76 }
77
78 return Status;
79}
80
93 )
94{
95 UINTN FlashRegion;
96 UINTN FlashNvStorageVariableBase;
97 UINTN FlashNvStorageFtwWorkingBase;
98 UINTN FlashNvStorageFtwSpareBase;
99 UINTN FlashNvStorageVariableSize;
100 UINTN FlashNvStorageFtwWorkingSize;
101 UINTN FlashNvStorageFtwSpareSize;
102
103 FlashNvStorageVariableSize = PcdGet32 (PcdFlashNvStorageVariableSize);
104 FlashNvStorageFtwWorkingSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
105 FlashNvStorageFtwSpareSize = PcdGet32 (PcdFlashNvStorageFtwSpareSize);
106
107 if ((FlashNvStorageVariableSize == 0) ||
108 (FlashNvStorageFtwWorkingSize == 0) ||
109 (FlashNvStorageFtwSpareSize == 0))
110 {
111 DEBUG ((DEBUG_ERROR, "FlashNvStorage size not defined\n"));
112 return EFI_INVALID_PARAMETER;
113 }
114
115 // Setup the variable store
116 FlashRegion = FlashDevice->DeviceBaseAddress;
117
118 FlashNvStorageVariableBase = FlashRegion;
119 FlashRegion += PcdGet32 (PcdFlashNvStorageVariableSize);
120
121 FlashNvStorageFtwWorkingBase = FlashRegion;
122 FlashRegion += PcdGet32 (PcdFlashNvStorageFtwWorkingSize);
123
124 FlashNvStorageFtwSpareBase = FlashRegion;
125 FlashRegion += PcdGet32 (PcdFlashNvStorageFtwSpareSize);
126
127 if (FlashRegion > (FlashDevice->DeviceBaseAddress + FlashDevice->Size)) {
128 DEBUG ((DEBUG_ERROR, "Insufficient flash storage size\n"));
129 return EFI_OUT_OF_RESOURCES;
130 }
131
132 PcdSet32S (
133 PcdFlashNvStorageVariableBase,
134 FlashNvStorageVariableBase
135 );
136
137 PcdSet32S (
138 PcdFlashNvStorageFtwWorkingBase,
139 FlashNvStorageFtwWorkingBase
140 );
141
142 PcdSet32S (
143 PcdFlashNvStorageFtwSpareBase,
144 FlashNvStorageFtwSpareBase
145 );
146
147 DEBUG ((
148 DEBUG_INFO,
149 "PcdFlashNvStorageVariableBase = 0x%x\n",
150 FlashNvStorageVariableBase
151 ));
152 DEBUG ((
153 DEBUG_INFO,
154 "PcdFlashNvStorageVariableSize = 0x%x\n",
155 FlashNvStorageVariableSize
156 ));
157 DEBUG ((
158 DEBUG_INFO,
159 "PcdFlashNvStorageFtwWorkingBase = 0x%x\n",
160 FlashNvStorageFtwWorkingBase
161 ));
162 DEBUG ((
163 DEBUG_INFO,
164 "PcdFlashNvStorageFtwWorkingSize = 0x%x\n",
165 FlashNvStorageFtwWorkingSize
166 ));
167 DEBUG ((
168 DEBUG_INFO,
169 "PcdFlashNvStorageFtwSpareBase = 0x%x\n",
170 FlashNvStorageFtwSpareBase
171 ));
172 DEBUG ((
173 DEBUG_INFO,
174 "PcdFlashNvStorageFtwSpareSize = 0x%x\n",
175 FlashNvStorageFtwSpareSize
176 ));
177
178 return EFI_SUCCESS;
179}
180
191 OUT VIRT_NOR_FLASH_DESCRIPTION **NorFlashDescriptions,
192 OUT UINT32 *Count
193 )
194{
195 if (mNorFlashDeviceCount > 0) {
196 *NorFlashDescriptions = mNorFlashDevices;
197 *Count = mNorFlashDeviceCount;
198 return EFI_SUCCESS;
199 }
200
201 return EFI_NOT_FOUND;
202}
203
214EFIAPI
216 IN EFI_HANDLE ImageHandle,
217 IN EFI_SYSTEM_TABLE *SystemTable
218 )
219{
220 INT32 Node;
221 EFI_STATUS Status;
222 EFI_STATUS FindNodeStatus;
223 CONST UINT32 *Reg;
224 UINT32 PropSize;
225 UINT64 Base;
226 UINT64 Size;
227 UINTN UefiVarStoreIndex;
228 CONST CHAR8 *Label;
229 UINT32 LabelLen;
230
231 if ((mNorFlashDeviceCount != 0) || PcdGetBool (PcdEmuVariableNvModeEnable)) {
232 return EFI_SUCCESS;
233 }
234
235 Status = gBS->LocateProtocol (
236 &gFdtClientProtocolGuid,
237 NULL,
238 (VOID **)&mFdtClient
239 );
240 ASSERT_EFI_ERROR (Status);
241
242 UefiVarStoreIndex = MAX_UINTN;
243 for (FindNodeStatus = mFdtClient->FindCompatibleNode (
244 mFdtClient,
245 "cfi-flash",
246 &Node
247 );
248 !EFI_ERROR (FindNodeStatus) &&
249 (mNorFlashDeviceCount < MAX_FLASH_DEVICES);
250 FindNodeStatus = mFdtClient->FindNextCompatibleNode (
251 mFdtClient,
252 "cfi-flash",
253 Node,
254 &Node
255 ))
256 {
257 Status = mFdtClient->GetNodeProperty (
258 mFdtClient,
259 Node,
260 "label",
261 (CONST VOID **)&Label,
262 &LabelLen
263 );
264 if (EFI_ERROR (Status)) {
265 DEBUG ((
266 DEBUG_ERROR,
267 "%a: GetNodeProperty ('label') failed (Status == %r)\n",
268 __func__,
269 Status
270 ));
271 } else if (AsciiStrCmp (Label, LABEL_UEFI_VAR_STORE) == 0) {
272 UefiVarStoreIndex = mNorFlashDeviceCount;
273 mUefiVarStoreNode = Node;
274 }
275
276 Status = mFdtClient->GetNodeProperty (
277 mFdtClient,
278 Node,
279 "reg",
280 (CONST VOID **)&Reg,
281 &PropSize
282 );
283 if (EFI_ERROR (Status)) {
284 DEBUG ((
285 DEBUG_ERROR,
286 "%a: GetNodeProperty () failed (Status == %r)\n",
287 __func__,
288 Status
289 ));
290 continue;
291 }
292
293 ASSERT ((PropSize % (4 * sizeof (UINT32))) == 0);
294
295 while ((PropSize >= (4 * sizeof (UINT32))) &&
296 (mNorFlashDeviceCount < MAX_FLASH_DEVICES))
297 {
298 Base = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[0]));
299 Size = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[2]));
300 Reg += 4;
301
302 PropSize -= 4 * sizeof (UINT32);
303
304 //
305 // Disregard any flash devices that overlap with the primary FV.
306 // The firmware is not updatable from inside the guest anyway.
307 //
308 if ((PcdGet64 (PcdFvBaseAddress) + PcdGet32 (PcdFvSize) > Base) &&
309 ((Base + Size) > PcdGet64 (PcdFvBaseAddress)))
310 {
311 continue;
312 }
313
314 DEBUG ((
315 DEBUG_INFO,
316 "NOR%d : Base = 0x%lx, Size = 0x%lx\n",
317 mNorFlashDeviceCount,
318 Base,
319 Size
320 ));
321
322 mNorFlashDevices[mNorFlashDeviceCount].DeviceBaseAddress = (UINTN)Base;
323 mNorFlashDevices[mNorFlashDeviceCount].RegionBaseAddress = (UINTN)Base;
324 mNorFlashDevices[mNorFlashDeviceCount].Size = (UINTN)Size;
325 mNorFlashDevices[mNorFlashDeviceCount].BlockSize = KVMTOOL_NOR_BLOCK_SIZE;
326 mNorFlashDeviceCount++;
327 }
328 } // for
329
330 // Setup the variable store in the last device
331 if (mNorFlashDeviceCount > 0) {
332 if (UefiVarStoreIndex == MAX_UINTN) {
333 // We did not find a label matching the UEFI Variable store. Default to
334 // using the last cfi-flash device as the variable store.
335 UefiVarStoreIndex = mNorFlashDeviceCount - 1;
336 mUefiVarStoreNode = Node;
337 }
338
339 if (mNorFlashDevices[UefiVarStoreIndex].DeviceBaseAddress != 0) {
340 Status = SetupVariableStore (&mNorFlashDevices[UefiVarStoreIndex]);
341 if (EFI_ERROR (Status)) {
342 DEBUG ((
343 DEBUG_ERROR,
344 "ERROR: Failed to setup variable store, Status = %r\n",
345 Status
346 ));
347 ASSERT (0);
348 }
349 } else {
350 DEBUG ((
351 DEBUG_ERROR,
352 "ERROR: Invalid Flash device Base address\n"
353 ));
354 ASSERT (0);
355 Status = EFI_NOT_FOUND;
356 }
357 } else {
358 // No Flash device found fallback to Runtime Variable Emulation.
359 DEBUG ((
360 DEBUG_INFO,
361 "INFO: No Flash device found fallback to Runtime Variable Emulation.\n"
362 ));
363 Status = PcdSetBoolS (PcdEmuVariableNvModeEnable, TRUE);
364 if (EFI_ERROR (Status)) {
365 DEBUG ((
366 DEBUG_ERROR,
367 "ERROR: Failed to set PcdEmuVariableNvModeEnable, Status = %r\n",
368 Status
369 ));
370 ASSERT (0);
371 }
372 }
373
374 return Status;
375}
UINT64 UINTN
UINT64 EFIAPI ReadUnaligned64(IN CONST UINT64 *Buffer)
Definition: Unaligned.c:204
INTN EFIAPI AsciiStrCmp(IN CONST CHAR8 *FirstString, IN CONST CHAR8 *SecondString)
Definition: String.c:716
UINT64 EFIAPI SwapBytes64(IN UINT64 Value)
Definition: SwapBytes64.c:25
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
EFI_STATUS EFIAPI NorFlashPlatformLibConstructor(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
EFI_STATUS VirtNorFlashPlatformInitialization(VOID)
STATIC EFI_STATUS SetupVariableStore(IN VIRT_NOR_FLASH_DESCRIPTION *FlashDevice)
#define KVMTOOL_NOR_BLOCK_SIZE
EFI_STATUS VirtNorFlashPlatformGetDevices(OUT VIRT_NOR_FLASH_DESCRIPTION **NorFlashDescriptions, OUT UINT32 *Count)
#define LABEL_UEFI_VAR_STORE
#define MAX_FLASH_DEVICES
#define PcdGet64(TokenName)
Definition: PcdLib.h:375
#define PcdSetBoolS(TokenName, Value)
Definition: PcdLib.h:549
#define PcdGet32(TokenName)
Definition: PcdLib.h:362
#define PcdGetBool(TokenName)
Definition: PcdLib.h:401
#define PcdSet32S(TokenName, Value)
Definition: PcdLib.h:497
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS