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