]>
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 | |
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 | |
28 | STATIC 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 | |
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 | |
39 | NorFlashPlatformInitialization (\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 | |
89 | STATIC\r | |
90 | EFI_STATUS\r | |
91 | SetupVariableStore (\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 | |
188 | EFI_STATUS\r | |
189 | NorFlashPlatformGetDevices (\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 | |
211 | EFI_STATUS\r | |
212 | EFIAPI\r | |
213 | NorFlashPlatformLibConstructor (\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 |