]> git.proxmox.com Git - mirror_edk2.git/blame - ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
ArmVirtPkg/ArmVirtKvmTool: Migrate to OVMF's VirtNorFlashDxe
[mirror_edk2.git] / ArmVirtPkg / Library / NorFlashKvmtoolLib / NorFlashKvmtool.c
CommitLineData
69f8ef04
SM
1/** @file\r
2 An instance of the NorFlashPlatformLib for Kvmtool platform.\r
3\r
4 Copyright (c) 2020, ARM Ltd. All rights reserved.<BR>\r
5\r
6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8 **/\r
9\r
10#include <Library/BaseLib.h>\r
11#include <Library/DebugLib.h>\r
69f8ef04 12#include <Library/UefiBootServicesTableLib.h>\r
99338ef8 13#include <Library/VirtNorFlashPlatformLib.h>\r
69f8ef04
SM
14#include <Protocol/FdtClient.h>\r
15\r
16/** Macro defining the NOR block size configured in Kvmtool.\r
17*/\r
18#define KVMTOOL_NOR_BLOCK_SIZE SIZE_64KB\r
19\r
20/** Macro defining the maximum number of Flash devices.\r
21*/\r
2b16a4fb 22#define MAX_FLASH_DEVICES 4\r
69f8ef04
SM
23\r
24/** Macro defining the cfi-flash label describing the UEFI variable store.\r
25*/\r
2b16a4fb 26#define LABEL_UEFI_VAR_STORE "System-firmware"\r
69f8ef04 27\r
99338ef8
AB
28STATIC VIRT_NOR_FLASH_DESCRIPTION mNorFlashDevices[MAX_FLASH_DEVICES];\r
29STATIC UINTN mNorFlashDeviceCount = 0;\r
30STATIC INT32 mUefiVarStoreNode = MAX_INT32;\r
31STATIC FDT_CLIENT_PROTOCOL *mFdtClient;\r
69f8ef04
SM
32\r
33/** This function performs platform specific actions to initialise\r
34 the NOR flash, if required.\r
35\r
36 @retval EFI_SUCCESS Success.\r
37**/\r
38EFI_STATUS\r
99338ef8 39VirtNorFlashPlatformInitialization (\r
69f8ef04
SM
40 VOID\r
41 )\r
42{\r
2b16a4fb 43 EFI_STATUS Status;\r
69f8ef04
SM
44\r
45 DEBUG ((DEBUG_INFO, "NorFlashPlatformInitialization\n"));\r
46\r
47 if ((mNorFlashDeviceCount > 0) && (mUefiVarStoreNode != MAX_INT32)) {\r
48 //\r
49 // UEFI takes ownership of the cfi-flash hardware, and exposes its\r
50 // functionality through the UEFI Runtime Variable Service. This means we\r
51 // need to disable it in the device tree to prevent the OS from attaching\r
52 // its device driver as well.\r
53 // Note: This library is loaded twice. First by FaultTolerantWriteDxe to\r
54 // setup the PcdFlashNvStorageFtw* and later by NorFlashDxe to provide the\r
55 // NorFlashPlatformLib interfaces. If the node is disabled when the library\r
56 // is first loaded, then during the subsequent loading of the library the\r
57 // call to FindNextCompatibleNode() from the library constructor skips the\r
58 // FDT node used for UEFI storage variable. Due to this we cannot setup the\r
59 // NOR flash device description i.e. mNorFlashDevices[].\r
60 // Since NorFlashPlatformInitialization() is called only by NorFlashDxe,\r
61 // we know it is safe to disable the node here.\r
62 //\r
63 Status = mFdtClient->SetNodeProperty (\r
64 mFdtClient,\r
65 mUefiVarStoreNode,\r
66 "status",\r
67 "disabled",\r
68 sizeof ("disabled")\r
69 );\r
70 if (EFI_ERROR (Status)) {\r
71 DEBUG ((DEBUG_WARN, "Failed to set cfi-flash status to 'disabled'\n"));\r
72 }\r
73 } else {\r
74 Status = EFI_NOT_FOUND;\r
75 DEBUG ((DEBUG_ERROR, "Flash device for UEFI variable storage not found\n"));\r
76 }\r
77\r
78 return Status;\r
79}\r
80\r
81/** Initialise Non volatile Flash storage variables.\r
82\r
83 @param [in] FlashDevice Pointer to the NOR Flash device.\r
84\r
85 @retval EFI_SUCCESS Success.\r
86 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
87 @retval EFI_OUT_OF_RESOURCES Insufficient flash storage space.\r
88**/\r
89STATIC\r
90EFI_STATUS\r
91SetupVariableStore (\r
99338ef8 92 IN VIRT_NOR_FLASH_DESCRIPTION *FlashDevice\r
69f8ef04
SM
93 )\r
94{\r
2b16a4fb
MK
95 UINTN FlashRegion;\r
96 UINTN FlashNvStorageVariableBase;\r
97 UINTN FlashNvStorageFtwWorkingBase;\r
98 UINTN FlashNvStorageFtwSpareBase;\r
99 UINTN FlashNvStorageVariableSize;\r
100 UINTN FlashNvStorageFtwWorkingSize;\r
101 UINTN FlashNvStorageFtwSpareSize;\r
102\r
103 FlashNvStorageVariableSize = PcdGet32 (PcdFlashNvStorageVariableSize);\r
69f8ef04 104 FlashNvStorageFtwWorkingSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize);\r
2b16a4fb 105 FlashNvStorageFtwSpareSize = PcdGet32 (PcdFlashNvStorageFtwSpareSize);\r
69f8ef04
SM
106\r
107 if ((FlashNvStorageVariableSize == 0) ||\r
108 (FlashNvStorageFtwWorkingSize == 0) ||\r
2b16a4fb
MK
109 (FlashNvStorageFtwSpareSize == 0))\r
110 {\r
69f8ef04
SM
111 DEBUG ((DEBUG_ERROR, "FlashNvStorage size not defined\n"));\r
112 return EFI_INVALID_PARAMETER;\r
113 }\r
114\r
115 // Setup the variable store\r
116 FlashRegion = FlashDevice->DeviceBaseAddress;\r
117\r
118 FlashNvStorageVariableBase = FlashRegion;\r
2b16a4fb 119 FlashRegion += PcdGet32 (PcdFlashNvStorageVariableSize);\r
69f8ef04
SM
120\r
121 FlashNvStorageFtwWorkingBase = FlashRegion;\r
2b16a4fb 122 FlashRegion += PcdGet32 (PcdFlashNvStorageFtwWorkingSize);\r
69f8ef04
SM
123\r
124 FlashNvStorageFtwSpareBase = FlashRegion;\r
2b16a4fb 125 FlashRegion += PcdGet32 (PcdFlashNvStorageFtwSpareSize);\r
69f8ef04
SM
126\r
127 if (FlashRegion > (FlashDevice->DeviceBaseAddress + FlashDevice->Size)) {\r
128 DEBUG ((DEBUG_ERROR, "Insufficient flash storage size\n"));\r
129 return EFI_OUT_OF_RESOURCES;\r
130 }\r
131\r
132 PcdSet32S (\r
133 PcdFlashNvStorageVariableBase,\r
134 FlashNvStorageVariableBase\r
135 );\r
136\r
137 PcdSet32S (\r
138 PcdFlashNvStorageFtwWorkingBase,\r
139 FlashNvStorageFtwWorkingBase\r
140 );\r
141\r
142 PcdSet32S (\r
143 PcdFlashNvStorageFtwSpareBase,\r
144 FlashNvStorageFtwSpareBase\r
145 );\r
146\r
147 DEBUG ((\r
148 DEBUG_INFO,\r
149 "PcdFlashNvStorageVariableBase = 0x%x\n",\r
150 FlashNvStorageVariableBase\r
151 ));\r
152 DEBUG ((\r
153 DEBUG_INFO,\r
154 "PcdFlashNvStorageVariableSize = 0x%x\n",\r
155 FlashNvStorageVariableSize\r
156 ));\r
157 DEBUG ((\r
158 DEBUG_INFO,\r
159 "PcdFlashNvStorageFtwWorkingBase = 0x%x\n",\r
160 FlashNvStorageFtwWorkingBase\r
161 ));\r
162 DEBUG ((\r
163 DEBUG_INFO,\r
164 "PcdFlashNvStorageFtwWorkingSize = 0x%x\n",\r
165 FlashNvStorageFtwWorkingSize\r
166 ));\r
167 DEBUG ((\r
168 DEBUG_INFO,\r
169 "PcdFlashNvStorageFtwSpareBase = 0x%x\n",\r
170 FlashNvStorageFtwSpareBase\r
171 ));\r
172 DEBUG ((\r
173 DEBUG_INFO,\r
174 "PcdFlashNvStorageFtwSpareSize = 0x%x\n",\r
175 FlashNvStorageFtwSpareSize\r
176 ));\r
177\r
178 return EFI_SUCCESS;\r
179}\r
180\r
181/** Return the Flash devices on the platform.\r
182\r
183 @param [out] NorFlashDescriptions Pointer to the Flash device description.\r
184 @param [out] Count Number of Flash devices.\r
185\r
186 @retval EFI_SUCCESS Success.\r
187 @retval EFI_NOT_FOUND Flash device not found.\r
188**/\r
189EFI_STATUS\r
99338ef8
AB
190VirtNorFlashPlatformGetDevices (\r
191 OUT VIRT_NOR_FLASH_DESCRIPTION **NorFlashDescriptions,\r
192 OUT UINT32 *Count\r
69f8ef04
SM
193 )\r
194{\r
195 if (mNorFlashDeviceCount > 0) {\r
196 *NorFlashDescriptions = mNorFlashDevices;\r
2b16a4fb 197 *Count = mNorFlashDeviceCount;\r
69f8ef04
SM
198 return EFI_SUCCESS;\r
199 }\r
2b16a4fb 200\r
69f8ef04
SM
201 return EFI_NOT_FOUND;\r
202}\r
203\r
204/** Entrypoint for NorFlashPlatformLib.\r
205\r
206 @param [in] ImageHandle The handle to the image.\r
207 @param [in] SystemTable Pointer to the System Table.\r
208\r
209 @retval EFI_SUCCESS Success.\r
210 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
211 @retval EFI_NOT_FOUND Flash device not found.\r
212**/\r
213EFI_STATUS\r
214EFIAPI\r
215NorFlashPlatformLibConstructor (\r
2b16a4fb
MK
216 IN EFI_HANDLE ImageHandle,\r
217 IN EFI_SYSTEM_TABLE *SystemTable\r
69f8ef04
SM
218 )\r
219{\r
2b16a4fb
MK
220 INT32 Node;\r
221 EFI_STATUS Status;\r
222 EFI_STATUS FindNodeStatus;\r
223 CONST UINT32 *Reg;\r
224 UINT32 PropSize;\r
225 UINT64 Base;\r
226 UINT64 Size;\r
227 UINTN UefiVarStoreIndex;\r
228 CONST CHAR8 *Label;\r
229 UINT32 LabelLen;\r
69f8ef04
SM
230\r
231 if (mNorFlashDeviceCount != 0) {\r
232 return EFI_SUCCESS;\r
233 }\r
234\r
235 Status = gBS->LocateProtocol (\r
236 &gFdtClientProtocolGuid,\r
237 NULL,\r
238 (VOID **)&mFdtClient\r
239 );\r
240 ASSERT_EFI_ERROR (Status);\r
241\r
242 UefiVarStoreIndex = MAX_UINTN;\r
243 for (FindNodeStatus = mFdtClient->FindCompatibleNode (\r
244 mFdtClient,\r
245 "cfi-flash",\r
246 &Node\r
247 );\r
248 !EFI_ERROR (FindNodeStatus) &&\r
2b16a4fb 249 (mNorFlashDeviceCount < MAX_FLASH_DEVICES);\r
69f8ef04
SM
250 FindNodeStatus = mFdtClient->FindNextCompatibleNode (\r
251 mFdtClient,\r
252 "cfi-flash",\r
253 Node,\r
254 &Node\r
2b16a4fb
MK
255 ))\r
256 {\r
69f8ef04
SM
257 Status = mFdtClient->GetNodeProperty (\r
258 mFdtClient,\r
259 Node,\r
260 "label",\r
261 (CONST VOID **)&Label,\r
262 &LabelLen\r
263 );\r
264 if (EFI_ERROR (Status)) {\r
265 DEBUG ((\r
266 DEBUG_ERROR,\r
267 "%a: GetNodeProperty ('label') failed (Status == %r)\n",\r
268 __FUNCTION__,\r
269 Status\r
270 ));\r
271 } else if (AsciiStrCmp (Label, LABEL_UEFI_VAR_STORE) == 0) {\r
272 UefiVarStoreIndex = mNorFlashDeviceCount;\r
273 mUefiVarStoreNode = Node;\r
274 }\r
275\r
276 Status = mFdtClient->GetNodeProperty (\r
277 mFdtClient,\r
278 Node,\r
279 "reg",\r
280 (CONST VOID **)&Reg,\r
281 &PropSize\r
282 );\r
283 if (EFI_ERROR (Status)) {\r
2b16a4fb
MK
284 DEBUG ((\r
285 DEBUG_ERROR,\r
286 "%a: GetNodeProperty () failed (Status == %r)\n",\r
287 __FUNCTION__,\r
288 Status\r
289 ));\r
69f8ef04
SM
290 continue;\r
291 }\r
292\r
293 ASSERT ((PropSize % (4 * sizeof (UINT32))) == 0);\r
294\r
295 while ((PropSize >= (4 * sizeof (UINT32))) &&\r
2b16a4fb
MK
296 (mNorFlashDeviceCount < MAX_FLASH_DEVICES))\r
297 {\r
69f8ef04
SM
298 Base = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[0]));\r
299 Size = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[2]));\r
300 Reg += 4;\r
301\r
302 PropSize -= 4 * sizeof (UINT32);\r
303\r
304 //\r
305 // Disregard any flash devices that overlap with the primary FV.\r
306 // The firmware is not updatable from inside the guest anyway.\r
307 //\r
308 if ((PcdGet64 (PcdFvBaseAddress) + PcdGet32 (PcdFvSize) > Base) &&\r
2b16a4fb
MK
309 ((Base + Size) > PcdGet64 (PcdFvBaseAddress)))\r
310 {\r
69f8ef04
SM
311 continue;\r
312 }\r
313\r
314 DEBUG ((\r
315 DEBUG_INFO,\r
316 "NOR%d : Base = 0x%lx, Size = 0x%lx\n",\r
317 mNorFlashDeviceCount,\r
318 Base,\r
319 Size\r
320 ));\r
321\r
322 mNorFlashDevices[mNorFlashDeviceCount].DeviceBaseAddress = (UINTN)Base;\r
323 mNorFlashDevices[mNorFlashDeviceCount].RegionBaseAddress = (UINTN)Base;\r
2b16a4fb
MK
324 mNorFlashDevices[mNorFlashDeviceCount].Size = (UINTN)Size;\r
325 mNorFlashDevices[mNorFlashDeviceCount].BlockSize = KVMTOOL_NOR_BLOCK_SIZE;\r
69f8ef04
SM
326 mNorFlashDeviceCount++;\r
327 }\r
328 } // for\r
329\r
330 // Setup the variable store in the last device\r
331 if (mNorFlashDeviceCount > 0) {\r
332 if (UefiVarStoreIndex == MAX_UINTN) {\r
333 // We did not find a label matching the UEFI Variable store. Default to\r
334 // using the last cfi-flash device as the variable store.\r
335 UefiVarStoreIndex = mNorFlashDeviceCount - 1;\r
336 mUefiVarStoreNode = Node;\r
337 }\r
2b16a4fb 338\r
69f8ef04
SM
339 if (mNorFlashDevices[UefiVarStoreIndex].DeviceBaseAddress != 0) {\r
340 return SetupVariableStore (&mNorFlashDevices[UefiVarStoreIndex]);\r
341 }\r
342 }\r
343\r
344 return EFI_NOT_FOUND;\r
345}\r