]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c
ArmPlatformPkg/ArmJunoDxe: Fixed returned value
[mirror_edk2.git] / ArmPlatformPkg / ArmJunoPkg / Drivers / ArmJunoDxe / ArmJunoDxe.c
CommitLineData
9f38945f
OM
1/** @file\r
2*\r
21a76332 3* Copyright (c) 2013-2015, ARM Limited. All rights reserved.\r
9f38945f
OM
4*\r
5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12*\r
13**/\r
14\r
15#include "ArmJunoDxeInternal.h"\r
c1fee786 16#include <ArmPlatform.h>\r
6d60dfea
OM
17\r
18#include <Protocol/DevicePathFromText.h>\r
19\r
20#include <Guid/GlobalVariable.h>\r
21\r
9f38945f 22#include <Library/ArmShellCmdLib.h>\r
21a76332 23#include <Library/AcpiLib.h>\r
6d60dfea
OM
24#include <Library/BaseMemoryLib.h>\r
25#include <Library/DevicePathLib.h>\r
26#include <Library/MemoryAllocationLib.h>\r
27#include <Library/UefiRuntimeServicesTableLib.h>\r
c1fee786
RC
28#include <Library/IoLib.h>\r
29#include <Library/PrintLib.h>\r
30\r
31//\r
32// Size in number of characters of the Linux boot argument\r
33// passing the MAC address to be used by the PCI GigaByte\r
34// Ethernet device : " sky2.mac_address=0x11,0x22,0x33,0x44,0x55,0x66"\r
35//\r
36#define SKY2_MAC_ADDRESS_BOOTARG_LEN 47\r
37\r
38//\r
39// Hardware platform identifiers\r
40//\r
41typedef enum {\r
42 UNKNOWN,\r
43 JUNO_R0,\r
44 JUNO_R1\r
45} JUNO_REVISION;\r
46\r
47//\r
48// Function prototypes\r
49//\r
50STATIC EFI_STATUS SetJunoR1DefaultBootEntries (\r
51 VOID\r
52 );\r
9f38945f 53\r
05e56470
OM
54// This GUID must match the FILE_GUID in ArmPlatformPkg/ArmJunoPkg/AcpiTables/AcpiTables.inf\r
55STATIC CONST EFI_GUID mJunoAcpiTableFile = { 0xa1dd808e, 0x1e95, 0x4399, { 0xab, 0xc0, 0x65, 0x3c, 0x82, 0xe8, 0x53, 0x0c } };\r
56\r
6d60dfea
OM
57/**\r
58 * Build and Set UEFI Variable Boot####\r
59 *\r
60 * @param BootVariableName Name of the UEFI Variable\r
61 * @param Attributes 'Attributes' for the Boot#### variable as per UEFI spec\r
62 * @param BootDescription Description of the Boot#### variable\r
63 * @param DevicePath EFI Device Path of the EFI Application to boot\r
64 * @param OptionalData Parameters to pass to the EFI application\r
65 * @param OptionalDataSize Size of the parameters to pass to the EFI application\r
66 *\r
67 * @return EFI_OUT_OF_RESOURCES A memory allocation failed\r
68 * @return Return value of RT.SetVariable\r
69 */\r
70STATIC\r
71EFI_STATUS\r
72BootOptionCreate (\r
73 IN CHAR16 BootVariableName[9],\r
74 IN UINT32 Attributes,\r
75 IN CHAR16* BootDescription,\r
76 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
77 IN UINT8* OptionalData,\r
78 IN UINTN OptionalDataSize\r
79 )\r
80{\r
81 UINTN VariableSize;\r
82 UINT8 *Variable;\r
83 UINT8 *VariablePtr;\r
84 UINTN FilePathListLength;\r
85 UINTN BootDescriptionSize;\r
86\r
87 FilePathListLength = GetDevicePathSize (DevicePath);\r
88 BootDescriptionSize = StrSize (BootDescription);\r
89\r
90 // Each Boot#### variable is built as follow:\r
91 // UINT32 Attributes\r
92 // UINT16 FilePathListLength\r
93 // CHAR16* Description\r
94 // EFI_DEVICE_PATH_PROTOCOL FilePathList[]\r
95 // UINT8 OptionalData[]\r
96 VariableSize = sizeof (UINT32) + sizeof (UINT16) +\r
97 BootDescriptionSize + FilePathListLength + OptionalDataSize;\r
98 Variable = AllocateZeroPool (VariableSize);\r
99 if (Variable == NULL) {\r
100 return EFI_OUT_OF_RESOURCES;\r
101 }\r
102\r
103 // 'Attributes' field\r
104 *(UINT32*)Variable = Attributes;\r
105 // 'FilePathListLength' field\r
106 VariablePtr = Variable + sizeof (UINT32);\r
107 *(UINT16*)VariablePtr = FilePathListLength;\r
108 // 'Description' field\r
109 VariablePtr += sizeof (UINT16);\r
110 CopyMem (VariablePtr, BootDescription, BootDescriptionSize);\r
111 // 'FilePathList' field\r
112 VariablePtr += BootDescriptionSize;\r
113 CopyMem (VariablePtr, DevicePath, FilePathListLength);\r
114 // 'OptionalData' field\r
115 VariablePtr += FilePathListLength;\r
116 CopyMem (VariablePtr, OptionalData, OptionalDataSize);\r
117\r
118 return gRT->SetVariable (\r
119 BootVariableName,\r
120 &gEfiGlobalVariableGuid,\r
121 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
122 VariableSize, Variable\r
123 );\r
124}\r
125\r
9f38945f
OM
126EFI_STATUS\r
127EFIAPI\r
128ArmJunoEntryPoint (\r
129 IN EFI_HANDLE ImageHandle,\r
130 IN EFI_SYSTEM_TABLE *SystemTable\r
131 )\r
132{\r
7aec2926
RC
133 EFI_STATUS Status;\r
134 EFI_PHYSICAL_ADDRESS HypBase;\r
135 CHAR16 *TextDevicePath;\r
136 UINTN TextDevicePathSize;\r
137 VOID *Buffer;\r
138 UINT32 Midr;\r
139 UINT32 CpuType;\r
140 UINT32 CpuRev;\r
c1fee786 141 JUNO_REVISION JunoRevision;\r
9f38945f 142\r
c1fee786 143 JunoRevision = UNKNOWN;\r
9f38945f
OM
144 Status = PciEmulationEntryPoint ();\r
145 if (EFI_ERROR (Status)) {\r
146 return Status;\r
147 }\r
148\r
149 //\r
150 // If a hypervisor has been declared then we need to make sure its region is protected at runtime\r
151 //\r
152 // Note: This code is only a workaround for our dummy hypervisor (ArmPkg/Extra/AArch64ToAArch32Shim/)\r
153 // that does not set up (yet) the stage 2 translation table to hide its own memory to EL1.\r
154 //\r
155 if (FixedPcdGet32 (PcdHypFvSize) != 0) {\r
156 // Ensure the hypervisor region is strictly contained into a EFI_PAGE_SIZE-aligned region.\r
157 // The memory must be a multiple of EFI_PAGE_SIZE to ensure we do not reserve more memory than the hypervisor itself.\r
158 // A UEFI Runtime region size granularity cannot be smaller than EFI_PAGE_SIZE. If the hypervisor size is not rounded\r
159 // to this size then there is a risk some non-runtime memory could be visible to the OS view.\r
160 if (((FixedPcdGet32 (PcdHypFvSize) & EFI_PAGE_MASK) == 0) && ((FixedPcdGet32 (PcdHypFvBaseAddress) & EFI_PAGE_MASK) == 0)) {\r
161 // The memory needs to be declared because the DXE core marked it as reserved and removed it from the memory space\r
162 // as it contains the Firmware.\r
163 Status = gDS->AddMemorySpace (\r
164 EfiGcdMemoryTypeSystemMemory,\r
165 FixedPcdGet32 (PcdHypFvBaseAddress), FixedPcdGet32 (PcdHypFvSize),\r
166 EFI_MEMORY_WB | EFI_MEMORY_RUNTIME\r
167 );\r
168 if (!EFI_ERROR (Status)) {\r
169 // We allocate the memory to ensure it is marked as runtime memory\r
170 HypBase = FixedPcdGet32 (PcdHypFvBaseAddress);\r
171 Status = gBS->AllocatePages (AllocateAddress, EfiRuntimeServicesCode,\r
172 EFI_SIZE_TO_PAGES (FixedPcdGet32 (PcdHypFvSize)), &HypBase);\r
173 }\r
174 } else {\r
175 // The hypervisor must be contained into a EFI_PAGE_SIZE-aligned region and its size must also be aligned\r
176 // on a EFI_PAGE_SIZE boundary (ie: 4KB).\r
177 Status = EFI_UNSUPPORTED;\r
178 ASSERT_EFI_ERROR (Status);\r
179 }\r
180\r
181 if (EFI_ERROR (Status)) {\r
182 return Status;\r
183 }\r
184 }\r
185\r
186 // Install dynamic Shell command to run baremetal binaries.\r
187 Status = ShellDynCmdRunAxfInstall (ImageHandle);\r
188 if (EFI_ERROR (Status)) {\r
189 DEBUG ((EFI_D_ERROR, "ArmJunoDxe: Failed to install ShellDynCmdRunAxf\n"));\r
190 }\r
191\r
7aec2926 192 //\r
7aec2926
RC
193 // We detect whether we are running on a Juno r0 or Juno r1 board at\r
194 // runtime by checking the value of the MIDR register.\r
195 //\r
196\r
c1fee786
RC
197 Midr = ArmReadMidr ();\r
198 CpuType = (Midr >> ARM_CPU_TYPE_SHIFT) & ARM_CPU_TYPE_MASK;\r
199 CpuRev = Midr & ARM_CPU_REV_MASK;\r
7aec2926
RC
200\r
201 switch (CpuType) {\r
202 case ARM_CPU_TYPE_A53:\r
203 if (CpuRev == ARM_CPU_REV (0, 0)) {\r
c1fee786 204 JunoRevision = JUNO_R0;\r
7aec2926 205 } else if (CpuRev == ARM_CPU_REV (0, 3)) {\r
c1fee786 206 JunoRevision = JUNO_R1;\r
7aec2926
RC
207 }\r
208 break;\r
209\r
210 case ARM_CPU_TYPE_A57:\r
211 if (CpuRev == ARM_CPU_REV (0, 0)) {\r
c1fee786 212 JunoRevision = JUNO_R0;\r
7aec2926 213 } else if (CpuRev == ARM_CPU_REV (1, 1)) {\r
c1fee786
RC
214 JunoRevision = JUNO_R1;\r
215 }\r
216 }\r
217\r
218 //\r
219 // Set the R1 two boot options if not already done.\r
220 //\r
221\r
222 if (JunoRevision == JUNO_R1) {\r
223 Status = SetJunoR1DefaultBootEntries ();\r
224 if (EFI_ERROR (Status)) {\r
225 return Status;\r
7aec2926
RC
226 }\r
227 }\r
228\r
c1fee786
RC
229 //\r
230 // Set up the device path to the FDT.\r
231 //\r
232 switch (JunoRevision) {\r
233 case JUNO_R0:\r
234 TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoR0FdtDevicePath);\r
235 break;\r
236\r
237 case JUNO_R1:\r
238 TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoR1A57x2FdtDevicePath);\r
239 break;\r
240\r
241 default:\r
242 TextDevicePath = NULL;\r
243 }\r
244\r
7aec2926
RC
245 if (TextDevicePath != NULL) {\r
246 TextDevicePathSize = StrSize (TextDevicePath);\r
247 Buffer = PcdSetPtr (PcdFdtDevicePaths, &TextDevicePathSize, TextDevicePath);\r
248 Status = (Buffer != NULL) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;\r
249 } else {\r
250 Status = EFI_NOT_FOUND;\r
251 }\r
252\r
05e56470 253 if (EFI_ERROR (Status)) {\r
7aec2926
RC
254 DEBUG (\r
255 (EFI_D_ERROR,\r
256 "ArmJunoDxe: Setting of FDT device path in PcdFdtDevicePaths failed - %r\n", Status)\r
257 );\r
05e56470
OM
258 return Status;\r
259 }\r
21a76332 260\r
7aec2926
RC
261 // Try to install the ACPI Tables\r
262 Status = LocateAndInstallAcpiFromFv (&mJunoAcpiTableFile);\r
263\r
c1fee786
RC
264 return Status;\r
265}\r
266\r
267/**\r
268 * If no boot entry is currently defined, define the two default boot entries\r
269 * for Juno R1.\r
270 *\r
271 * @return EFI_SUCCESS Some boot entries were already defined or\r
272 * the default boot entries were set successfully.\r
273 * @return EFI_OUT_OF_RESOURCES A memory allocation failed.\r
274 * @return EFI_DEVICE_ERROR An UEFI variable could not be saved due to a hardware failure.\r
275 * @return EFI_WRITE_PROTECTED An UEFI variable is read-only.\r
276 * @return EFI_SECURITY_VIOLATION An UEFI variable could not be written.\r
277 */\r
278STATIC\r
279EFI_STATUS\r
280SetJunoR1DefaultBootEntries (\r
281 VOID\r
282 )\r
283{\r
284 EFI_STATUS Status;\r
1667d2e1 285 CONST CHAR16* ExtraBootArgument = L" dtb=r1a57a53.dtb";\r
c1fee786
RC
286 UINTN Size;\r
287 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;\r
288 EFI_DEVICE_PATH* BootDevicePath;\r
289 UINT32 SysPciGbeL;\r
290 UINT32 SysPciGbeH;\r
291 CHAR16* DefaultBootArgument;\r
292 CHAR16* DefaultBootArgument1;\r
293 UINTN DefaultBootArgument1Size;\r
294 CHAR16* DefaultBootArgument2;\r
295 UINTN DefaultBootArgument2Size;\r
296 UINT16 BootOrder[2];\r
297\r
298 BootDevicePath = NULL;\r
299 DefaultBootArgument1 = NULL;\r
300 DefaultBootArgument2 = NULL;\r
301\r
6d60dfea 302 //\r
c1fee786
RC
303 // Because the driver has a dependency on gEfiVariable(Write)ArchProtocolGuid\r
304 // (see [Depex] section of the INF file), we know we can safely access the\r
305 // UEFI Variable at that stage.\r
6d60dfea 306 //\r
c1fee786
RC
307 Size = 0;\r
308 Status = gRT->GetVariable (L"BootOrder", &gEfiGlobalVariableGuid, NULL, &Size, NULL);\r
309 if (Status != EFI_NOT_FOUND) {\r
8debfa0c 310 return EFI_SUCCESS;\r
c1fee786
RC
311 }\r
312\r
313 Status = gBS->LocateProtocol (\r
314 &gEfiDevicePathFromTextProtocolGuid,\r
315 NULL,\r
316 (VOID **)&EfiDevicePathFromTextProtocol\r
317 );\r
318 if (EFI_ERROR (Status)) {\r
319 //\r
320 // You must provide an implementation of DevicePathFromTextProtocol\r
321 // in your firmware (eg: DevicePathDxe)\r
322 //\r
323 DEBUG ((EFI_D_ERROR, "Error: Require DevicePathFromTextProtocol\n"));\r
324 return Status;\r
325 }\r
326 //\r
327 // We use the same default kernel.\r
328 //\r
329 BootDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath (\r
330 (CHAR16*)PcdGetPtr (PcdDefaultBootDevicePath)\r
331 );\r
332 if (BootDevicePath == NULL) {\r
333 return EFI_UNSUPPORTED;\r
334 }\r
335\r
336 DefaultBootArgument = (CHAR16*)PcdGetPtr (PcdDefaultBootArgument);\r
337 DefaultBootArgument1Size = StrSize (DefaultBootArgument) +\r
338 (SKY2_MAC_ADDRESS_BOOTARG_LEN * sizeof (CHAR16));\r
339 DefaultBootArgument2Size = DefaultBootArgument1Size + StrSize (ExtraBootArgument);\r
340\r
341 Status = EFI_OUT_OF_RESOURCES;\r
342 DefaultBootArgument1 = AllocatePool (DefaultBootArgument1Size);\r
343 if (DefaultBootArgument1 == NULL) {\r
344 goto Error;\r
345 }\r
346 DefaultBootArgument2 = AllocatePool (DefaultBootArgument2Size);\r
347 if (DefaultBootArgument2 == NULL) {\r
348 goto Error;\r
349 }\r
350\r
351 SysPciGbeL = MmioRead32 (ARM_JUNO_SYS_PCIGBE_L);\r
352 SysPciGbeH = MmioRead32 (ARM_JUNO_SYS_PCIGBE_H);\r
353\r
354 UnicodeSPrint (\r
355 DefaultBootArgument1,\r
356 DefaultBootArgument1Size,\r
357 L"%s sky2.mac_address=0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x",\r
358 DefaultBootArgument,\r
359 (SysPciGbeH >> 8 ) & 0xFF, (SysPciGbeH ) & 0xFF,\r
360 (SysPciGbeL >> 24) & 0xFF, (SysPciGbeL >> 16) & 0xFF,\r
361 (SysPciGbeL >> 8 ) & 0xFF, (SysPciGbeL ) & 0xFF\r
362 );\r
363\r
364 CopyMem (DefaultBootArgument2, DefaultBootArgument1, DefaultBootArgument1Size);\r
365 CopyMem (\r
366 (UINT8*)DefaultBootArgument2 + DefaultBootArgument1Size - sizeof (CHAR16),\r
367 ExtraBootArgument,\r
368 StrSize (ExtraBootArgument)\r
369 );\r
370\r
371 //\r
372 // Create Boot0001 environment variable\r
373 //\r
374 Status = BootOptionCreate (\r
375 L"Boot0001", LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT,\r
376 L"Linux with A57x2", BootDevicePath,\r
377 (UINT8*)DefaultBootArgument1, DefaultBootArgument1Size\r
378 );\r
379 if (EFI_ERROR (Status)) {\r
8debfa0c 380 ASSERT_EFI_ERROR (Status);\r
c1fee786
RC
381 goto Error;\r
382 }\r
383\r
384 //\r
385 // Create Boot0002 environment variable\r
386 //\r
387 Status = BootOptionCreate (\r
388 L"Boot0002", LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT,\r
389 L"Linux with A57x2_A53x4", BootDevicePath,\r
390 (UINT8*)DefaultBootArgument2, DefaultBootArgument2Size\r
391 );\r
392 if (EFI_ERROR (Status)) {\r
8debfa0c 393 ASSERT_EFI_ERROR (Status);\r
c1fee786
RC
394 goto Error;\r
395 }\r
396\r
397 //\r
398 // Add the new Boot Index to the list\r
399 //\r
400 BootOrder[0] = 1; // Boot0001\r
401 BootOrder[1] = 2; // Boot0002\r
402 Status = gRT->SetVariable (\r
403 L"BootOrder",\r
404 &gEfiGlobalVariableGuid,\r
405 EFI_VARIABLE_NON_VOLATILE |\r
406 EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
407 EFI_VARIABLE_RUNTIME_ACCESS,\r
408 sizeof (BootOrder),\r
409 BootOrder\r
410 );\r
411\r
8debfa0c 412Error:\r
c1fee786
RC
413 if (BootDevicePath != NULL) {\r
414 FreePool (BootDevicePath);\r
415 }\r
416 if (DefaultBootArgument1 != NULL) {\r
417 FreePool (DefaultBootArgument1);\r
418 }\r
419 if (DefaultBootArgument2 != NULL) {\r
420 FreePool (DefaultBootArgument2);\r
421 }\r
422\r
423 if (EFI_ERROR (Status)) {\r
424 DEBUG ((\r
425 EFI_D_ERROR,\r
426 "ArmJunoDxe - The setting of the default boot entries failed - %r\n",\r
427 Status\r
428 ));\r
6d60dfea
OM
429 }\r
430\r
9f38945f
OM
431 return Status;\r
432}\r