]>
Commit | Line | Data |
---|---|---|
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 |
28 | STATIC VIRT_NOR_FLASH_DESCRIPTION mNorFlashDevices[MAX_FLASH_DEVICES];\r |
29 | STATIC UINTN mNorFlashDeviceCount = 0;\r | |
30 | STATIC INT32 mUefiVarStoreNode = MAX_INT32;\r | |
31 | STATIC 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 | |
38 | EFI_STATUS\r | |
99338ef8 | 39 | VirtNorFlashPlatformInitialization (\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 | |
89 | STATIC\r | |
90 | EFI_STATUS\r | |
91 | SetupVariableStore (\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 | |
189 | EFI_STATUS\r | |
99338ef8 AB |
190 | VirtNorFlashPlatformGetDevices (\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 | |
213 | EFI_STATUS\r | |
214 | EFIAPI\r | |
215 | NorFlashPlatformLibConstructor (\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 |