]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/ArmJunoPkg/Drivers/ArmJunoDxe/ArmJunoDxe.c
ArmPlatformPkg/ArmJunoPkg: Create two default boot entries on first boot on Juno R1
[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
6d60dfea
OM
16\r
17#include <Protocol/DevicePathFromText.h>\r
18\r
19#include <Guid/GlobalVariable.h>\r
20\r
9f38945f 21#include <Library/ArmShellCmdLib.h>\r
21a76332 22#include <Library/AcpiLib.h>\r
6d60dfea
OM
23#include <Library/BaseMemoryLib.h>\r
24#include <Library/DevicePathLib.h>\r
25#include <Library/MemoryAllocationLib.h>\r
26#include <Library/UefiRuntimeServicesTableLib.h>\r
9f38945f 27\r
05e56470
OM
28// This GUID must match the FILE_GUID in ArmPlatformPkg/ArmJunoPkg/AcpiTables/AcpiTables.inf\r
29STATIC CONST EFI_GUID mJunoAcpiTableFile = { 0xa1dd808e, 0x1e95, 0x4399, { 0xab, 0xc0, 0x65, 0x3c, 0x82, 0xe8, 0x53, 0x0c } };\r
30\r
6d60dfea
OM
31/**\r
32 * Build and Set UEFI Variable Boot####\r
33 *\r
34 * @param BootVariableName Name of the UEFI Variable\r
35 * @param Attributes 'Attributes' for the Boot#### variable as per UEFI spec\r
36 * @param BootDescription Description of the Boot#### variable\r
37 * @param DevicePath EFI Device Path of the EFI Application to boot\r
38 * @param OptionalData Parameters to pass to the EFI application\r
39 * @param OptionalDataSize Size of the parameters to pass to the EFI application\r
40 *\r
41 * @return EFI_OUT_OF_RESOURCES A memory allocation failed\r
42 * @return Return value of RT.SetVariable\r
43 */\r
44STATIC\r
45EFI_STATUS\r
46BootOptionCreate (\r
47 IN CHAR16 BootVariableName[9],\r
48 IN UINT32 Attributes,\r
49 IN CHAR16* BootDescription,\r
50 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,\r
51 IN UINT8* OptionalData,\r
52 IN UINTN OptionalDataSize\r
53 )\r
54{\r
55 UINTN VariableSize;\r
56 UINT8 *Variable;\r
57 UINT8 *VariablePtr;\r
58 UINTN FilePathListLength;\r
59 UINTN BootDescriptionSize;\r
60\r
61 FilePathListLength = GetDevicePathSize (DevicePath);\r
62 BootDescriptionSize = StrSize (BootDescription);\r
63\r
64 // Each Boot#### variable is built as follow:\r
65 // UINT32 Attributes\r
66 // UINT16 FilePathListLength\r
67 // CHAR16* Description\r
68 // EFI_DEVICE_PATH_PROTOCOL FilePathList[]\r
69 // UINT8 OptionalData[]\r
70 VariableSize = sizeof (UINT32) + sizeof (UINT16) +\r
71 BootDescriptionSize + FilePathListLength + OptionalDataSize;\r
72 Variable = AllocateZeroPool (VariableSize);\r
73 if (Variable == NULL) {\r
74 return EFI_OUT_OF_RESOURCES;\r
75 }\r
76\r
77 // 'Attributes' field\r
78 *(UINT32*)Variable = Attributes;\r
79 // 'FilePathListLength' field\r
80 VariablePtr = Variable + sizeof (UINT32);\r
81 *(UINT16*)VariablePtr = FilePathListLength;\r
82 // 'Description' field\r
83 VariablePtr += sizeof (UINT16);\r
84 CopyMem (VariablePtr, BootDescription, BootDescriptionSize);\r
85 // 'FilePathList' field\r
86 VariablePtr += BootDescriptionSize;\r
87 CopyMem (VariablePtr, DevicePath, FilePathListLength);\r
88 // 'OptionalData' field\r
89 VariablePtr += FilePathListLength;\r
90 CopyMem (VariablePtr, OptionalData, OptionalDataSize);\r
91\r
92 return gRT->SetVariable (\r
93 BootVariableName,\r
94 &gEfiGlobalVariableGuid,\r
95 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
96 VariableSize, Variable\r
97 );\r
98}\r
99\r
9f38945f
OM
100EFI_STATUS\r
101EFIAPI\r
102ArmJunoEntryPoint (\r
103 IN EFI_HANDLE ImageHandle,\r
104 IN EFI_SYSTEM_TABLE *SystemTable\r
105 )\r
106{\r
7aec2926
RC
107 EFI_STATUS Status;\r
108 EFI_PHYSICAL_ADDRESS HypBase;\r
109 CHAR16 *TextDevicePath;\r
110 UINTN TextDevicePathSize;\r
111 VOID *Buffer;\r
112 UINT32 Midr;\r
113 UINT32 CpuType;\r
114 UINT32 CpuRev;\r
6d60dfea 115 BOOLEAN IsJunoR1;\r
9f38945f
OM
116\r
117 Status = PciEmulationEntryPoint ();\r
118 if (EFI_ERROR (Status)) {\r
119 return Status;\r
120 }\r
121\r
122 //\r
123 // If a hypervisor has been declared then we need to make sure its region is protected at runtime\r
124 //\r
125 // Note: This code is only a workaround for our dummy hypervisor (ArmPkg/Extra/AArch64ToAArch32Shim/)\r
126 // that does not set up (yet) the stage 2 translation table to hide its own memory to EL1.\r
127 //\r
128 if (FixedPcdGet32 (PcdHypFvSize) != 0) {\r
129 // Ensure the hypervisor region is strictly contained into a EFI_PAGE_SIZE-aligned region.\r
130 // The memory must be a multiple of EFI_PAGE_SIZE to ensure we do not reserve more memory than the hypervisor itself.\r
131 // A UEFI Runtime region size granularity cannot be smaller than EFI_PAGE_SIZE. If the hypervisor size is not rounded\r
132 // to this size then there is a risk some non-runtime memory could be visible to the OS view.\r
133 if (((FixedPcdGet32 (PcdHypFvSize) & EFI_PAGE_MASK) == 0) && ((FixedPcdGet32 (PcdHypFvBaseAddress) & EFI_PAGE_MASK) == 0)) {\r
134 // The memory needs to be declared because the DXE core marked it as reserved and removed it from the memory space\r
135 // as it contains the Firmware.\r
136 Status = gDS->AddMemorySpace (\r
137 EfiGcdMemoryTypeSystemMemory,\r
138 FixedPcdGet32 (PcdHypFvBaseAddress), FixedPcdGet32 (PcdHypFvSize),\r
139 EFI_MEMORY_WB | EFI_MEMORY_RUNTIME\r
140 );\r
141 if (!EFI_ERROR (Status)) {\r
142 // We allocate the memory to ensure it is marked as runtime memory\r
143 HypBase = FixedPcdGet32 (PcdHypFvBaseAddress);\r
144 Status = gBS->AllocatePages (AllocateAddress, EfiRuntimeServicesCode,\r
145 EFI_SIZE_TO_PAGES (FixedPcdGet32 (PcdHypFvSize)), &HypBase);\r
146 }\r
147 } else {\r
148 // The hypervisor must be contained into a EFI_PAGE_SIZE-aligned region and its size must also be aligned\r
149 // on a EFI_PAGE_SIZE boundary (ie: 4KB).\r
150 Status = EFI_UNSUPPORTED;\r
151 ASSERT_EFI_ERROR (Status);\r
152 }\r
153\r
154 if (EFI_ERROR (Status)) {\r
155 return Status;\r
156 }\r
157 }\r
158\r
159 // Install dynamic Shell command to run baremetal binaries.\r
160 Status = ShellDynCmdRunAxfInstall (ImageHandle);\r
161 if (EFI_ERROR (Status)) {\r
162 DEBUG ((EFI_D_ERROR, "ArmJunoDxe: Failed to install ShellDynCmdRunAxf\n"));\r
163 }\r
164\r
7aec2926
RC
165 //\r
166 // Set up the device path to the FDT.\r
167 // We detect whether we are running on a Juno r0 or Juno r1 board at\r
168 // runtime by checking the value of the MIDR register.\r
169 //\r
170\r
6d60dfea
OM
171 Midr = ArmReadMidr ();\r
172 CpuType = (Midr >> ARM_CPU_TYPE_SHIFT) & ARM_CPU_TYPE_MASK;\r
173 CpuRev = Midr & ARM_CPU_REV_MASK;\r
7aec2926 174 TextDevicePath = NULL;\r
6d60dfea 175 IsJunoR1 = FALSE;\r
7aec2926
RC
176\r
177 switch (CpuType) {\r
178 case ARM_CPU_TYPE_A53:\r
179 if (CpuRev == ARM_CPU_REV (0, 0)) {\r
1ccc0fd7 180 TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoR0FdtDevicePath);\r
7aec2926 181 } else if (CpuRev == ARM_CPU_REV (0, 3)) {\r
1ccc0fd7 182 TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoR1A57x2FdtDevicePath);\r
6d60dfea 183 IsJunoR1 = TRUE;\r
7aec2926
RC
184 }\r
185 break;\r
186\r
187 case ARM_CPU_TYPE_A57:\r
188 if (CpuRev == ARM_CPU_REV (0, 0)) {\r
1ccc0fd7 189 TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoR0FdtDevicePath);\r
7aec2926 190 } else if (CpuRev == ARM_CPU_REV (1, 1)) {\r
1ccc0fd7 191 TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoR1A57x2FdtDevicePath);\r
6d60dfea 192 IsJunoR1 = TRUE;\r
7aec2926
RC
193 }\r
194 }\r
195\r
196 if (TextDevicePath != NULL) {\r
197 TextDevicePathSize = StrSize (TextDevicePath);\r
198 Buffer = PcdSetPtr (PcdFdtDevicePaths, &TextDevicePathSize, TextDevicePath);\r
199 Status = (Buffer != NULL) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;\r
200 } else {\r
201 Status = EFI_NOT_FOUND;\r
202 }\r
203\r
05e56470 204 if (EFI_ERROR (Status)) {\r
7aec2926
RC
205 DEBUG (\r
206 (EFI_D_ERROR,\r
207 "ArmJunoDxe: Setting of FDT device path in PcdFdtDevicePaths failed - %r\n", Status)\r
208 );\r
05e56470
OM
209 return Status;\r
210 }\r
21a76332 211\r
7aec2926
RC
212 // Try to install the ACPI Tables\r
213 Status = LocateAndInstallAcpiFromFv (&mJunoAcpiTableFile);\r
214\r
6d60dfea
OM
215 //\r
216 // If Juno R1 and it is the first boot then default boot entries will be created\r
217 //\r
218 if (IsJunoR1) {\r
219 CONST CHAR16* ExtraBootArgument = L" dtb=juno-r1-ca57x2_ca53x4.dtb";\r
220 UINTN Size;\r
221 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL* EfiDevicePathFromTextProtocol;\r
222 EFI_DEVICE_PATH* BootDevicePath;\r
223 CHAR16* DefaultBootArgument;\r
224 UINTN DefaultBootArgumentSize;\r
225 CHAR16* DefaultBootArgument2;\r
226 UINTN DefaultBootArgument2Size;\r
227 UINT16 BootOrder[2];\r
228\r
229 // Because the driver has a dependency on gEfiVariable(Write)ArchProtocolGuid (see [Depex]\r
230 // section of the INF file), we know we can safely access the UEFI Variable at that stage.\r
231 Size = 0;\r
232 Status = gRT->GetVariable (L"BootOrder", &gEfiGlobalVariableGuid, NULL, &Size, NULL);\r
233 if (Status == EFI_NOT_FOUND) {\r
234 Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);\r
235 if (EFI_ERROR (Status)) {\r
236 // You must provide an implementation of DevicePathFromTextProtocol in your firmware (eg: DevicePathDxe)\r
237 DEBUG ((EFI_D_ERROR, "Error: Require DevicePathFromTextProtocol\n"));\r
238 return Status;\r
239 }\r
240 // We use the same default kernel\r
241 BootDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr (PcdDefaultBootDevicePath));\r
242\r
243 // Create the entry if the Default values are correct\r
244 if (BootDevicePath != NULL) {\r
245 DefaultBootArgument = (CHAR16*)PcdGetPtr (PcdDefaultBootArgument);\r
246 DefaultBootArgumentSize = StrSize (DefaultBootArgument);\r
247 DefaultBootArgument2Size = DefaultBootArgumentSize + StrSize (ExtraBootArgument);\r
248\r
249 DefaultBootArgument2 = AllocatePool (DefaultBootArgument2Size);\r
250 if (DefaultBootArgument2 == NULL) {\r
251 FreePool (BootDevicePath);\r
252 return EFI_OUT_OF_RESOURCES;\r
253 }\r
254 CopyMem (DefaultBootArgument2, DefaultBootArgument, DefaultBootArgumentSize);\r
255 CopyMem ((UINT8*)DefaultBootArgument2 + (StrLen (DefaultBootArgument2) * sizeof (CHAR16)), ExtraBootArgument, StrSize (ExtraBootArgument));\r
256\r
257 // Create Boot0001 environment variable\r
258 Status = BootOptionCreate (L"Boot0001", LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT,\r
259 L"Linux with A57x2", BootDevicePath,\r
260 (UINT8*)DefaultBootArgument, DefaultBootArgumentSize);\r
261 ASSERT_EFI_ERROR (Status);\r
262\r
263 // Create Boot0002 environment variable\r
264 Status = BootOptionCreate (L"Boot0002", LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT,\r
265 L"Linux with A57x2_A53x4", BootDevicePath,\r
266 (UINT8*)DefaultBootArgument2, DefaultBootArgument2Size);\r
267 ASSERT_EFI_ERROR (Status);\r
268\r
269 // Add the new Boot Index to the list\r
270 BootOrder[0] = 1; // Boot0001\r
271 BootOrder[1] = 2; // Boot0002\r
272 Status = gRT->SetVariable (\r
273 L"BootOrder",\r
274 &gEfiGlobalVariableGuid,\r
275 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
276 sizeof (BootOrder),\r
277 BootOrder\r
278 );\r
279\r
280 FreePool (BootDevicePath);\r
281 FreePool (DefaultBootArgument2);\r
282 } else {\r
283 Status = EFI_UNSUPPORTED;\r
284 }\r
285 }\r
286 }\r
287\r
9f38945f
OM
288 return Status;\r
289}\r