3 * Copyright (c) 2013-2015, ARM Limited. All rights reserved.
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
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.
15 #include "ArmJunoDxeInternal.h"
16 #include <ArmPlatform.h>
18 #include <Protocol/DevicePathFromText.h>
20 #include <Guid/GlobalVariable.h>
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>
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"
36 #define SKY2_MAC_ADDRESS_BOOTARG_LEN 47
39 // Hardware platform identifiers
48 // Function prototypes
50 STATIC EFI_STATUS
SetJunoR1DefaultBootEntries (
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 } };
58 * Build and Set UEFI Variable Boot####
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
67 * @return EFI_OUT_OF_RESOURCES A memory allocation failed
68 * @return Return value of RT.SetVariable
73 IN CHAR16 BootVariableName
[9],
75 IN CHAR16
* BootDescription
,
76 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
77 IN UINT8
* OptionalData
,
78 IN UINTN OptionalDataSize
84 UINTN FilePathListLength
;
85 UINTN BootDescriptionSize
;
87 FilePathListLength
= GetDevicePathSize (DevicePath
);
88 BootDescriptionSize
= StrSize (BootDescription
);
90 // Each Boot#### variable is built as follow:
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
;
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
);
118 return gRT
->SetVariable (
120 &gEfiGlobalVariableGuid
,
121 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
122 VariableSize
, Variable
129 IN EFI_HANDLE ImageHandle
,
130 IN EFI_SYSTEM_TABLE
*SystemTable
134 EFI_PHYSICAL_ADDRESS HypBase
;
135 CHAR16
*TextDevicePath
;
136 UINTN TextDevicePathSize
;
141 JUNO_REVISION JunoRevision
;
143 JunoRevision
= UNKNOWN
;
144 Status
= PciEmulationEntryPoint ();
145 if (EFI_ERROR (Status
)) {
150 // If a hypervisor has been declared then we need to make sure its region is protected at runtime
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.
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
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
);
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
);
181 if (EFI_ERROR (Status
)) {
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"));
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.
197 Midr
= ArmReadMidr ();
198 CpuType
= (Midr
>> ARM_CPU_TYPE_SHIFT
) & ARM_CPU_TYPE_MASK
;
199 CpuRev
= Midr
& ARM_CPU_REV_MASK
;
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
;
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
;
219 // Set the R1 two boot options if not already done.
222 if (JunoRevision
== JUNO_R1
) {
223 Status
= SetJunoR1DefaultBootEntries ();
224 if (EFI_ERROR (Status
)) {
230 // Set up the device path to the FDT.
232 switch (JunoRevision
) {
234 TextDevicePath
= (CHAR16
*)FixedPcdGetPtr (PcdJunoR0FdtDevicePath
);
238 TextDevicePath
= (CHAR16
*)FixedPcdGetPtr (PcdJunoR1A57x2FdtDevicePath
);
242 TextDevicePath
= NULL
;
245 if (TextDevicePath
!= NULL
) {
246 TextDevicePathSize
= StrSize (TextDevicePath
);
247 Buffer
= PcdSetPtr (PcdFdtDevicePaths
, &TextDevicePathSize
, TextDevicePath
);
248 Status
= (Buffer
!= NULL
) ? EFI_SUCCESS
: EFI_BUFFER_TOO_SMALL
;
250 Status
= EFI_NOT_FOUND
;
253 if (EFI_ERROR (Status
)) {
256 "ArmJunoDxe: Setting of FDT device path in PcdFdtDevicePaths failed - %r\n", Status
)
261 // Try to install the ACPI Tables
262 Status
= LocateAndInstallAcpiFromFv (&mJunoAcpiTableFile
);
268 * If no boot entry is currently defined, define the two default boot entries
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.
280 SetJunoR1DefaultBootEntries (
285 CONST CHAR16
* ExtraBootArgument
= L
" dtb=r1a57a53.dtb";
287 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL
*EfiDevicePathFromTextProtocol
;
288 EFI_DEVICE_PATH
* BootDevicePath
;
291 CHAR16
* DefaultBootArgument
;
292 CHAR16
* DefaultBootArgument1
;
293 UINTN DefaultBootArgument1Size
;
294 CHAR16
* DefaultBootArgument2
;
295 UINTN DefaultBootArgument2Size
;
298 BootDevicePath
= NULL
;
299 DefaultBootArgument1
= NULL
;
300 DefaultBootArgument2
= NULL
;
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.
308 Status
= gRT
->GetVariable (L
"BootOrder", &gEfiGlobalVariableGuid
, NULL
, &Size
, NULL
);
309 if (Status
!= EFI_NOT_FOUND
) {
313 Status
= gBS
->LocateProtocol (
314 &gEfiDevicePathFromTextProtocolGuid
,
316 (VOID
**)&EfiDevicePathFromTextProtocol
318 if (EFI_ERROR (Status
)) {
320 // You must provide an implementation of DevicePathFromTextProtocol
321 // in your firmware (eg: DevicePathDxe)
323 DEBUG ((EFI_D_ERROR
, "Error: Require DevicePathFromTextProtocol\n"));
327 // We use the same default kernel.
329 BootDevicePath
= EfiDevicePathFromTextProtocol
->ConvertTextToDevicePath (
330 (CHAR16
*)PcdGetPtr (PcdDefaultBootDevicePath
)
332 if (BootDevicePath
== NULL
) {
333 return EFI_UNSUPPORTED
;
336 DefaultBootArgument
= (CHAR16
*)PcdGetPtr (PcdDefaultBootArgument
);
337 DefaultBootArgument1Size
= StrSize (DefaultBootArgument
) +
338 (SKY2_MAC_ADDRESS_BOOTARG_LEN
* sizeof (CHAR16
));
339 DefaultBootArgument2Size
= DefaultBootArgument1Size
+ StrSize (ExtraBootArgument
);
341 Status
= EFI_OUT_OF_RESOURCES
;
342 DefaultBootArgument1
= AllocatePool (DefaultBootArgument1Size
);
343 if (DefaultBootArgument1
== NULL
) {
346 DefaultBootArgument2
= AllocatePool (DefaultBootArgument2Size
);
347 if (DefaultBootArgument2
== NULL
) {
351 SysPciGbeL
= MmioRead32 (ARM_JUNO_SYS_PCIGBE_L
);
352 SysPciGbeH
= MmioRead32 (ARM_JUNO_SYS_PCIGBE_H
);
355 DefaultBootArgument1
,
356 DefaultBootArgument1Size
,
357 L
"%s sky2.mac_address=0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x",
359 (SysPciGbeH
>> 8 ) & 0xFF, (SysPciGbeH
) & 0xFF,
360 (SysPciGbeL
>> 24) & 0xFF, (SysPciGbeL
>> 16) & 0xFF,
361 (SysPciGbeL
>> 8 ) & 0xFF, (SysPciGbeL
) & 0xFF
364 CopyMem (DefaultBootArgument2
, DefaultBootArgument1
, DefaultBootArgument1Size
);
366 (UINT8
*)DefaultBootArgument2
+ DefaultBootArgument1Size
- sizeof (CHAR16
),
368 StrSize (ExtraBootArgument
)
372 // Create Boot0001 environment variable
374 Status
= BootOptionCreate (
375 L
"Boot0001", LOAD_OPTION_ACTIVE
| LOAD_OPTION_CATEGORY_BOOT
,
376 L
"Linux with A57x2", BootDevicePath
,
377 (UINT8
*)DefaultBootArgument1
, DefaultBootArgument1Size
379 if (EFI_ERROR (Status
)) {
380 ASSERT_EFI_ERROR (Status
);
385 // Create Boot0002 environment variable
387 Status
= BootOptionCreate (
388 L
"Boot0002", LOAD_OPTION_ACTIVE
| LOAD_OPTION_CATEGORY_BOOT
,
389 L
"Linux with A57x2_A53x4", BootDevicePath
,
390 (UINT8
*)DefaultBootArgument2
, DefaultBootArgument2Size
392 if (EFI_ERROR (Status
)) {
393 ASSERT_EFI_ERROR (Status
);
398 // Add the new Boot Index to the list
400 BootOrder
[0] = 1; // Boot0001
401 BootOrder
[1] = 2; // Boot0002
402 Status
= gRT
->SetVariable (
404 &gEfiGlobalVariableGuid
,
405 EFI_VARIABLE_NON_VOLATILE
|
406 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
407 EFI_VARIABLE_RUNTIME_ACCESS
,
413 if (BootDevicePath
!= NULL
) {
414 FreePool (BootDevicePath
);
416 if (DefaultBootArgument1
!= NULL
) {
417 FreePool (DefaultBootArgument1
);
419 if (DefaultBootArgument2
!= NULL
) {
420 FreePool (DefaultBootArgument2
);
423 if (EFI_ERROR (Status
)) {
426 "ArmJunoDxe - The setting of the default boot entries failed - %r\n",