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