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