]> git.proxmox.com Git - mirror_edk2.git/blame - ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
ArmVirtPkg: Add Kvmtool NOR flash lib
[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
12#include <Library/NorFlashPlatformLib.h>\r
13#include <Library/UefiBootServicesTableLib.h>\r
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
22#define MAX_FLASH_DEVICES 4\r
23\r
24/** Macro defining the cfi-flash label describing the UEFI variable store.\r
25*/\r
26#define LABEL_UEFI_VAR_STORE "System-firmware"\r
27\r
28STATIC 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
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
39NorFlashPlatformInitialization (\r
40 VOID\r
41 )\r
42{\r
43 EFI_STATUS Status;\r
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
92 IN NOR_FLASH_DESCRIPTION * FlashDevice\r
93 )\r
94{\r
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
104 FlashNvStorageFtwWorkingSize = PcdGet32 (PcdFlashNvStorageFtwWorkingSize);\r
105 FlashNvStorageFtwSpareSize = PcdGet32 (PcdFlashNvStorageFtwSpareSize);\r
106\r
107 if ((FlashNvStorageVariableSize == 0) ||\r
108 (FlashNvStorageFtwWorkingSize == 0) ||\r
109 (FlashNvStorageFtwSpareSize == 0)) {\r
110 DEBUG ((DEBUG_ERROR, "FlashNvStorage size not defined\n"));\r
111 return EFI_INVALID_PARAMETER;\r
112 }\r
113\r
114 // Setup the variable store\r
115 FlashRegion = FlashDevice->DeviceBaseAddress;\r
116\r
117 FlashNvStorageVariableBase = FlashRegion;\r
118 FlashRegion += PcdGet32 (PcdFlashNvStorageVariableSize);\r
119\r
120 FlashNvStorageFtwWorkingBase = FlashRegion;\r
121 FlashRegion += PcdGet32 (PcdFlashNvStorageFtwWorkingSize);\r
122\r
123 FlashNvStorageFtwSpareBase = FlashRegion;\r
124 FlashRegion += PcdGet32 (PcdFlashNvStorageFtwSpareSize);\r
125\r
126 if (FlashRegion > (FlashDevice->DeviceBaseAddress + FlashDevice->Size)) {\r
127 DEBUG ((DEBUG_ERROR, "Insufficient flash storage size\n"));\r
128 return EFI_OUT_OF_RESOURCES;\r
129 }\r
130\r
131 PcdSet32S (\r
132 PcdFlashNvStorageVariableBase,\r
133 FlashNvStorageVariableBase\r
134 );\r
135\r
136 PcdSet32S (\r
137 PcdFlashNvStorageFtwWorkingBase,\r
138 FlashNvStorageFtwWorkingBase\r
139 );\r
140\r
141 PcdSet32S (\r
142 PcdFlashNvStorageFtwSpareBase,\r
143 FlashNvStorageFtwSpareBase\r
144 );\r
145\r
146 DEBUG ((\r
147 DEBUG_INFO,\r
148 "PcdFlashNvStorageVariableBase = 0x%x\n",\r
149 FlashNvStorageVariableBase\r
150 ));\r
151 DEBUG ((\r
152 DEBUG_INFO,\r
153 "PcdFlashNvStorageVariableSize = 0x%x\n",\r
154 FlashNvStorageVariableSize\r
155 ));\r
156 DEBUG ((\r
157 DEBUG_INFO,\r
158 "PcdFlashNvStorageFtwWorkingBase = 0x%x\n",\r
159 FlashNvStorageFtwWorkingBase\r
160 ));\r
161 DEBUG ((\r
162 DEBUG_INFO,\r
163 "PcdFlashNvStorageFtwWorkingSize = 0x%x\n",\r
164 FlashNvStorageFtwWorkingSize\r
165 ));\r
166 DEBUG ((\r
167 DEBUG_INFO,\r
168 "PcdFlashNvStorageFtwSpareBase = 0x%x\n",\r
169 FlashNvStorageFtwSpareBase\r
170 ));\r
171 DEBUG ((\r
172 DEBUG_INFO,\r
173 "PcdFlashNvStorageFtwSpareSize = 0x%x\n",\r
174 FlashNvStorageFtwSpareSize\r
175 ));\r
176\r
177 return EFI_SUCCESS;\r
178}\r
179\r
180/** Return the Flash devices on the platform.\r
181\r
182 @param [out] NorFlashDescriptions Pointer to the Flash device description.\r
183 @param [out] Count Number of Flash devices.\r
184\r
185 @retval EFI_SUCCESS Success.\r
186 @retval EFI_NOT_FOUND Flash device not found.\r
187**/\r
188EFI_STATUS\r
189NorFlashPlatformGetDevices (\r
190 OUT NOR_FLASH_DESCRIPTION **NorFlashDescriptions,\r
191 OUT UINT32 *Count\r
192 )\r
193{\r
194 if (mNorFlashDeviceCount > 0) {\r
195 *NorFlashDescriptions = mNorFlashDevices;\r
196 *Count = mNorFlashDeviceCount;\r
197 return EFI_SUCCESS;\r
198 }\r
199 return EFI_NOT_FOUND;\r
200}\r
201\r
202/** Entrypoint for NorFlashPlatformLib.\r
203\r
204 @param [in] ImageHandle The handle to the image.\r
205 @param [in] SystemTable Pointer to the System Table.\r
206\r
207 @retval EFI_SUCCESS Success.\r
208 @retval EFI_INVALID_PARAMETER A parameter is invalid.\r
209 @retval EFI_NOT_FOUND Flash device not found.\r
210**/\r
211EFI_STATUS\r
212EFIAPI\r
213NorFlashPlatformLibConstructor (\r
214 IN EFI_HANDLE ImageHandle,\r
215 IN EFI_SYSTEM_TABLE * SystemTable\r
216 )\r
217{\r
218 INT32 Node;\r
219 EFI_STATUS Status;\r
220 EFI_STATUS FindNodeStatus;\r
221 CONST UINT32 *Reg;\r
222 UINT32 PropSize;\r
223 UINT64 Base;\r
224 UINT64 Size;\r
225 UINTN UefiVarStoreIndex;\r
226 CONST CHAR8 *Label;\r
227 UINT32 LabelLen;\r
228\r
229 if (mNorFlashDeviceCount != 0) {\r
230 return EFI_SUCCESS;\r
231 }\r
232\r
233 Status = gBS->LocateProtocol (\r
234 &gFdtClientProtocolGuid,\r
235 NULL,\r
236 (VOID **)&mFdtClient\r
237 );\r
238 ASSERT_EFI_ERROR (Status);\r
239\r
240 UefiVarStoreIndex = MAX_UINTN;\r
241 for (FindNodeStatus = mFdtClient->FindCompatibleNode (\r
242 mFdtClient,\r
243 "cfi-flash",\r
244 &Node\r
245 );\r
246 !EFI_ERROR (FindNodeStatus) &&\r
247 (mNorFlashDeviceCount < MAX_FLASH_DEVICES);\r
248 FindNodeStatus = mFdtClient->FindNextCompatibleNode (\r
249 mFdtClient,\r
250 "cfi-flash",\r
251 Node,\r
252 &Node\r
253 )) {\r
254 Status = mFdtClient->GetNodeProperty (\r
255 mFdtClient,\r
256 Node,\r
257 "label",\r
258 (CONST VOID **)&Label,\r
259 &LabelLen\r
260 );\r
261 if (EFI_ERROR (Status)) {\r
262 DEBUG ((\r
263 DEBUG_ERROR,\r
264 "%a: GetNodeProperty ('label') failed (Status == %r)\n",\r
265 __FUNCTION__,\r
266 Status\r
267 ));\r
268 } else if (AsciiStrCmp (Label, LABEL_UEFI_VAR_STORE) == 0) {\r
269 UefiVarStoreIndex = mNorFlashDeviceCount;\r
270 mUefiVarStoreNode = Node;\r
271 }\r
272\r
273 Status = mFdtClient->GetNodeProperty (\r
274 mFdtClient,\r
275 Node,\r
276 "reg",\r
277 (CONST VOID **)&Reg,\r
278 &PropSize\r
279 );\r
280 if (EFI_ERROR (Status)) {\r
281 DEBUG ((DEBUG_ERROR, "%a: GetNodeProperty () failed (Status == %r)\n",\r
282 __FUNCTION__, Status));\r
283 continue;\r
284 }\r
285\r
286 ASSERT ((PropSize % (4 * sizeof (UINT32))) == 0);\r
287\r
288 while ((PropSize >= (4 * sizeof (UINT32))) &&\r
289 (mNorFlashDeviceCount < MAX_FLASH_DEVICES)) {\r
290 Base = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[0]));\r
291 Size = SwapBytes64 (ReadUnaligned64 ((VOID *)&Reg[2]));\r
292 Reg += 4;\r
293\r
294 PropSize -= 4 * sizeof (UINT32);\r
295\r
296 //\r
297 // Disregard any flash devices that overlap with the primary FV.\r
298 // The firmware is not updatable from inside the guest anyway.\r
299 //\r
300 if ((PcdGet64 (PcdFvBaseAddress) + PcdGet32 (PcdFvSize) > Base) &&\r
301 (Base + Size) > PcdGet64 (PcdFvBaseAddress)) {\r
302 continue;\r
303 }\r
304\r
305 DEBUG ((\r
306 DEBUG_INFO,\r
307 "NOR%d : Base = 0x%lx, Size = 0x%lx\n",\r
308 mNorFlashDeviceCount,\r
309 Base,\r
310 Size\r
311 ));\r
312\r
313 mNorFlashDevices[mNorFlashDeviceCount].DeviceBaseAddress = (UINTN)Base;\r
314 mNorFlashDevices[mNorFlashDeviceCount].RegionBaseAddress = (UINTN)Base;\r
315 mNorFlashDevices[mNorFlashDeviceCount].Size = (UINTN)Size;\r
316 mNorFlashDevices[mNorFlashDeviceCount].BlockSize = KVMTOOL_NOR_BLOCK_SIZE;\r
317 mNorFlashDeviceCount++;\r
318 }\r
319 } // for\r
320\r
321 // Setup the variable store in the last device\r
322 if (mNorFlashDeviceCount > 0) {\r
323 if (UefiVarStoreIndex == MAX_UINTN) {\r
324 // We did not find a label matching the UEFI Variable store. Default to\r
325 // using the last cfi-flash device as the variable store.\r
326 UefiVarStoreIndex = mNorFlashDeviceCount - 1;\r
327 mUefiVarStoreNode = Node;\r
328 }\r
329 if (mNorFlashDevices[UefiVarStoreIndex].DeviceBaseAddress != 0) {\r
330 return SetupVariableStore (&mNorFlashDevices[UefiVarStoreIndex]);\r
331 }\r
332 }\r
333\r
334 return EFI_NOT_FOUND;\r
335}\r