]> git.proxmox.com Git - mirror_edk2.git/blob - ArmVirtPkg/Library/NorFlashKvmtoolLib/NorFlashKvmtool.c
ArmVirtPkg: Apply uncrustify changes
[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 {
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
181 /** Return the Flash devices on the platform.
182
183 @param [out] NorFlashDescriptions Pointer to the Flash device description.
184 @param [out] Count Number of Flash devices.
185
186 @retval EFI_SUCCESS Success.
187 @retval EFI_NOT_FOUND Flash device not found.
188 **/
189 EFI_STATUS
190 NorFlashPlatformGetDevices (
191 OUT 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
204 /** Entrypoint for NorFlashPlatformLib.
205
206 @param [in] ImageHandle The handle to the image.
207 @param [in] SystemTable Pointer to the System Table.
208
209 @retval EFI_SUCCESS Success.
210 @retval EFI_INVALID_PARAMETER A parameter is invalid.
211 @retval EFI_NOT_FOUND Flash device not found.
212 **/
213 EFI_STATUS
214 EFIAPI
215 NorFlashPlatformLibConstructor (
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) {
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 __FUNCTION__,
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 __FUNCTION__,
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 return SetupVariableStore (&mNorFlashDevices[UefiVarStoreIndex]);
341 }
342 }
343
344 return EFI_NOT_FOUND;
345 }