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>
19 #include <Protocol/PciRootBridgeIo.h>
21 #include <Guid/EventGroup.h>
22 #include <Guid/GlobalVariable.h>
24 #include <Library/ArmShellCmdLib.h>
25 #include <Library/AcpiLib.h>
26 #include <Library/BaseMemoryLib.h>
27 #include <Library/DevicePathLib.h>
28 #include <Library/MemoryAllocationLib.h>
29 #include <Library/UefiRuntimeServicesTableLib.h>
30 #include <Library/IoLib.h>
31 #include <Library/PrintLib.h>
34 // Size in number of characters of the Linux boot argument
35 // passing the MAC address to be used by the PCI GigaByte
36 // Ethernet device : " sky2.mac_address=0x11,0x22,0x33,0x44,0x55,0x66"
38 #define SKY2_MAC_ADDRESS_BOOTARG_LEN 47
41 // Hardware platform identifiers
50 // Function prototypes
52 STATIC EFI_STATUS
SetJunoR1DefaultBootEntries (
56 // This GUID must match the FILE_GUID in ArmPlatformPkg/ArmJunoPkg/AcpiTables/AcpiTables.inf
57 STATIC CONST EFI_GUID mJunoAcpiTableFile
= { 0xa1dd808e, 0x1e95, 0x4399, { 0xab, 0xc0, 0x65, 0x3c, 0x82, 0xe8, 0x53, 0x0c } };
60 ACPI_HID_DEVICE_PATH AcpiDevicePath
;
61 EFI_DEVICE_PATH_PROTOCOL EndDevicePath
;
62 } EFI_PCI_ROOT_BRIDGE_DEVICE_PATH
;
64 STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mPciRootComplexDevicePath
= {
68 { (UINT8
) (sizeof (ACPI_HID_DEVICE_PATH
)),
69 (UINT8
) ((sizeof (ACPI_HID_DEVICE_PATH
)) >> 8) }
76 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
77 { END_DEVICE_PATH_LENGTH
, 0 }
82 * Build and Set UEFI Variable Boot####
84 * @param BootVariableName Name of the UEFI Variable
85 * @param Attributes 'Attributes' for the Boot#### variable as per UEFI spec
86 * @param BootDescription Description of the Boot#### variable
87 * @param DevicePath EFI Device Path of the EFI Application to boot
88 * @param OptionalData Parameters to pass to the EFI application
89 * @param OptionalDataSize Size of the parameters to pass to the EFI application
91 * @return EFI_OUT_OF_RESOURCES A memory allocation failed
92 * @return Return value of RT.SetVariable
97 IN CHAR16 BootVariableName
[9],
99 IN CHAR16
* BootDescription
,
100 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
101 IN UINT8
* OptionalData
,
102 IN UINTN OptionalDataSize
108 UINTN FilePathListLength
;
109 UINTN BootDescriptionSize
;
111 FilePathListLength
= GetDevicePathSize (DevicePath
);
112 BootDescriptionSize
= StrSize (BootDescription
);
114 // Each Boot#### variable is built as follow:
116 // UINT16 FilePathListLength
117 // CHAR16* Description
118 // EFI_DEVICE_PATH_PROTOCOL FilePathList[]
119 // UINT8 OptionalData[]
120 VariableSize
= sizeof (UINT32
) + sizeof (UINT16
) +
121 BootDescriptionSize
+ FilePathListLength
+ OptionalDataSize
;
122 Variable
= AllocateZeroPool (VariableSize
);
123 if (Variable
== NULL
) {
124 return EFI_OUT_OF_RESOURCES
;
127 // 'Attributes' field
128 *(UINT32
*)Variable
= Attributes
;
129 // 'FilePathListLength' field
130 VariablePtr
= Variable
+ sizeof (UINT32
);
131 *(UINT16
*)VariablePtr
= FilePathListLength
;
132 // 'Description' field
133 VariablePtr
+= sizeof (UINT16
);
134 CopyMem (VariablePtr
, BootDescription
, BootDescriptionSize
);
135 // 'FilePathList' field
136 VariablePtr
+= BootDescriptionSize
;
137 CopyMem (VariablePtr
, DevicePath
, FilePathListLength
);
138 // 'OptionalData' field
139 VariablePtr
+= FilePathListLength
;
140 CopyMem (VariablePtr
, OptionalData
, OptionalDataSize
);
142 return gRT
->SetVariable (
144 &gEfiGlobalVariableGuid
,
145 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
146 VariableSize
, Variable
151 Notification function of the event defined as belonging to the
152 EFI_END_OF_DXE_EVENT_GROUP_GUID event group that was created in
153 the entry point of the driver.
155 This function is called when an event belonging to the
156 EFI_END_OF_DXE_EVENT_GROUP_GUID event group is signalled. Such an
157 event is signalled once at the end of the dispatching of all
158 drivers (end of the so called DXE phase).
160 @param[in] Event Event declared in the entry point of the driver whose
161 notification function is being invoked.
162 @param[in] Context NULL
171 EFI_DEVICE_PATH_PROTOCOL
* PciRootComplexDevicePath
;
176 // PCI Root Complex initialization
177 // At the end of the DXE phase, we should get all the driver dispatched.
178 // Force the PCI Root Complex to be initialized. It allows the OS to skip
181 PciRootComplexDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &mPciRootComplexDevicePath
;
182 Status
= gBS
->LocateDevicePath (&gEfiPciRootBridgeIoProtocolGuid
,
183 &PciRootComplexDevicePath
,
186 Status
= gBS
->ConnectController (Handle
, NULL
, PciRootComplexDevicePath
, FALSE
);
187 ASSERT_EFI_ERROR (Status
);
193 IN EFI_HANDLE ImageHandle
,
194 IN EFI_SYSTEM_TABLE
*SystemTable
198 EFI_PHYSICAL_ADDRESS HypBase
;
199 CHAR16
*TextDevicePath
;
200 UINTN TextDevicePathSize
;
205 JUNO_REVISION JunoRevision
;
207 JunoRevision
= UNKNOWN
;
208 Status
= PciEmulationEntryPoint ();
209 if (EFI_ERROR (Status
)) {
214 // If a hypervisor has been declared then we need to make sure its region is protected at runtime
216 // Note: This code is only a workaround for our dummy hypervisor (ArmPkg/Extra/AArch64ToAArch32Shim/)
217 // that does not set up (yet) the stage 2 translation table to hide its own memory to EL1.
219 if (FixedPcdGet32 (PcdHypFvSize
) != 0) {
220 // Ensure the hypervisor region is strictly contained into a EFI_PAGE_SIZE-aligned region.
221 // The memory must be a multiple of EFI_PAGE_SIZE to ensure we do not reserve more memory than the hypervisor itself.
222 // A UEFI Runtime region size granularity cannot be smaller than EFI_PAGE_SIZE. If the hypervisor size is not rounded
223 // to this size then there is a risk some non-runtime memory could be visible to the OS view.
224 if (((FixedPcdGet32 (PcdHypFvSize
) & EFI_PAGE_MASK
) == 0) && ((FixedPcdGet32 (PcdHypFvBaseAddress
) & EFI_PAGE_MASK
) == 0)) {
225 // The memory needs to be declared because the DXE core marked it as reserved and removed it from the memory space
226 // as it contains the Firmware.
227 Status
= gDS
->AddMemorySpace (
228 EfiGcdMemoryTypeSystemMemory
,
229 FixedPcdGet32 (PcdHypFvBaseAddress
), FixedPcdGet32 (PcdHypFvSize
),
230 EFI_MEMORY_WB
| EFI_MEMORY_RUNTIME
232 if (!EFI_ERROR (Status
)) {
233 // We allocate the memory to ensure it is marked as runtime memory
234 HypBase
= FixedPcdGet32 (PcdHypFvBaseAddress
);
235 Status
= gBS
->AllocatePages (AllocateAddress
, EfiRuntimeServicesCode
,
236 EFI_SIZE_TO_PAGES (FixedPcdGet32 (PcdHypFvSize
)), &HypBase
);
239 // The hypervisor must be contained into a EFI_PAGE_SIZE-aligned region and its size must also be aligned
240 // on a EFI_PAGE_SIZE boundary (ie: 4KB).
241 Status
= EFI_UNSUPPORTED
;
242 ASSERT_EFI_ERROR (Status
);
245 if (EFI_ERROR (Status
)) {
251 // Create an event belonging to the "gEfiEndOfDxeEventGroupGuid" group.
252 // The "OnEndOfDxe()" function is declared as the call back function.
253 // It will be called at the end of the DXE phase when an event of the
254 // same group is signalled to inform about the end of the DXE phase.
255 // Install the INSTALL_FDT_PROTOCOL protocol.
257 Status
= gBS
->CreateEventEx (
262 &gEfiEndOfDxeEventGroupGuid
,
266 // Install dynamic Shell command to run baremetal binaries.
267 Status
= ShellDynCmdRunAxfInstall (ImageHandle
);
268 if (EFI_ERROR (Status
)) {
269 DEBUG ((EFI_D_ERROR
, "ArmJunoDxe: Failed to install ShellDynCmdRunAxf\n"));
273 // We detect whether we are running on a Juno r0 or Juno r1 board at
274 // runtime by checking the value of the MIDR register.
277 Midr
= ArmReadMidr ();
278 CpuType
= (Midr
>> ARM_CPU_TYPE_SHIFT
) & ARM_CPU_TYPE_MASK
;
279 CpuRev
= Midr
& ARM_CPU_REV_MASK
;
282 case ARM_CPU_TYPE_A53
:
283 if (CpuRev
== ARM_CPU_REV (0, 0)) {
284 JunoRevision
= JUNO_R0
;
285 } else if (CpuRev
== ARM_CPU_REV (0, 3)) {
286 JunoRevision
= JUNO_R1
;
290 case ARM_CPU_TYPE_A57
:
291 if (CpuRev
== ARM_CPU_REV (0, 0)) {
292 JunoRevision
= JUNO_R0
;
293 } else if (CpuRev
== ARM_CPU_REV (1, 1)) {
294 JunoRevision
= JUNO_R1
;
299 // Set the R1 two boot options if not already done.
302 if (JunoRevision
== JUNO_R1
) {
303 Status
= SetJunoR1DefaultBootEntries ();
304 if (EFI_ERROR (Status
)) {
310 // Set up the device path to the FDT.
312 switch (JunoRevision
) {
314 TextDevicePath
= (CHAR16
*)FixedPcdGetPtr (PcdJunoR0FdtDevicePath
);
318 TextDevicePath
= (CHAR16
*)FixedPcdGetPtr (PcdJunoR1A57x2FdtDevicePath
);
322 TextDevicePath
= NULL
;
325 if (TextDevicePath
!= NULL
) {
326 TextDevicePathSize
= StrSize (TextDevicePath
);
327 Buffer
= PcdSetPtr (PcdFdtDevicePaths
, &TextDevicePathSize
, TextDevicePath
);
328 Status
= (Buffer
!= NULL
) ? EFI_SUCCESS
: EFI_BUFFER_TOO_SMALL
;
330 Status
= EFI_NOT_FOUND
;
333 if (EFI_ERROR (Status
)) {
336 "ArmJunoDxe: Setting of FDT device path in PcdFdtDevicePaths failed - %r\n", Status
)
341 // Try to install the ACPI Tables
342 Status
= LocateAndInstallAcpiFromFv (&mJunoAcpiTableFile
);
348 * If no boot entry is currently defined, define the two default boot entries
351 * @return EFI_SUCCESS Some boot entries were already defined or
352 * the default boot entries were set successfully.
353 * @return EFI_OUT_OF_RESOURCES A memory allocation failed.
354 * @return EFI_DEVICE_ERROR An UEFI variable could not be saved due to a hardware failure.
355 * @return EFI_WRITE_PROTECTED An UEFI variable is read-only.
356 * @return EFI_SECURITY_VIOLATION An UEFI variable could not be written.
360 SetJunoR1DefaultBootEntries (
365 CONST CHAR16
* ExtraBootArgument
= L
" dtb=r1a57a53.dtb";
367 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL
*EfiDevicePathFromTextProtocol
;
368 EFI_DEVICE_PATH
* BootDevicePath
;
371 CHAR16
* DefaultBootArgument
;
372 CHAR16
* DefaultBootArgument1
;
373 UINTN DefaultBootArgument1Size
;
374 CHAR16
* DefaultBootArgument2
;
375 UINTN DefaultBootArgument2Size
;
378 BootDevicePath
= NULL
;
379 DefaultBootArgument1
= NULL
;
380 DefaultBootArgument2
= NULL
;
383 // Because the driver has a dependency on gEfiVariable(Write)ArchProtocolGuid
384 // (see [Depex] section of the INF file), we know we can safely access the
385 // UEFI Variable at that stage.
388 Status
= gRT
->GetVariable (L
"BootOrder", &gEfiGlobalVariableGuid
, NULL
, &Size
, NULL
);
389 if (Status
!= EFI_NOT_FOUND
) {
393 Status
= gBS
->LocateProtocol (
394 &gEfiDevicePathFromTextProtocolGuid
,
396 (VOID
**)&EfiDevicePathFromTextProtocol
398 if (EFI_ERROR (Status
)) {
400 // You must provide an implementation of DevicePathFromTextProtocol
401 // in your firmware (eg: DevicePathDxe)
403 DEBUG ((EFI_D_ERROR
, "Error: Require DevicePathFromTextProtocol\n"));
407 // We use the same default kernel.
409 BootDevicePath
= EfiDevicePathFromTextProtocol
->ConvertTextToDevicePath (
410 (CHAR16
*)PcdGetPtr (PcdDefaultBootDevicePath
)
412 if (BootDevicePath
== NULL
) {
413 return EFI_UNSUPPORTED
;
416 DefaultBootArgument
= (CHAR16
*)PcdGetPtr (PcdDefaultBootArgument
);
417 DefaultBootArgument1Size
= StrSize (DefaultBootArgument
) +
418 (SKY2_MAC_ADDRESS_BOOTARG_LEN
* sizeof (CHAR16
));
419 DefaultBootArgument2Size
= DefaultBootArgument1Size
+ StrSize (ExtraBootArgument
);
421 Status
= EFI_OUT_OF_RESOURCES
;
422 DefaultBootArgument1
= AllocatePool (DefaultBootArgument1Size
);
423 if (DefaultBootArgument1
== NULL
) {
426 DefaultBootArgument2
= AllocatePool (DefaultBootArgument2Size
);
427 if (DefaultBootArgument2
== NULL
) {
431 SysPciGbeL
= MmioRead32 (ARM_JUNO_SYS_PCIGBE_L
);
432 SysPciGbeH
= MmioRead32 (ARM_JUNO_SYS_PCIGBE_H
);
435 DefaultBootArgument1
,
436 DefaultBootArgument1Size
,
437 L
"%s sky2.mac_address=0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x",
439 (SysPciGbeH
>> 8 ) & 0xFF, (SysPciGbeH
) & 0xFF,
440 (SysPciGbeL
>> 24) & 0xFF, (SysPciGbeL
>> 16) & 0xFF,
441 (SysPciGbeL
>> 8 ) & 0xFF, (SysPciGbeL
) & 0xFF
444 CopyMem (DefaultBootArgument2
, DefaultBootArgument1
, DefaultBootArgument1Size
);
446 (UINT8
*)DefaultBootArgument2
+ DefaultBootArgument1Size
- sizeof (CHAR16
),
448 StrSize (ExtraBootArgument
)
452 // Create Boot0001 environment variable
454 Status
= BootOptionCreate (
455 L
"Boot0001", LOAD_OPTION_ACTIVE
| LOAD_OPTION_CATEGORY_BOOT
,
456 L
"Linux with A57x2", BootDevicePath
,
457 (UINT8
*)DefaultBootArgument1
, DefaultBootArgument1Size
459 if (EFI_ERROR (Status
)) {
460 ASSERT_EFI_ERROR (Status
);
465 // Create Boot0002 environment variable
467 Status
= BootOptionCreate (
468 L
"Boot0002", LOAD_OPTION_ACTIVE
| LOAD_OPTION_CATEGORY_BOOT
,
469 L
"Linux with A57x2_A53x4", BootDevicePath
,
470 (UINT8
*)DefaultBootArgument2
, DefaultBootArgument2Size
472 if (EFI_ERROR (Status
)) {
473 ASSERT_EFI_ERROR (Status
);
478 // Add the new Boot Index to the list
480 BootOrder
[0] = 1; // Boot0001
481 BootOrder
[1] = 2; // Boot0002
482 Status
= gRT
->SetVariable (
484 &gEfiGlobalVariableGuid
,
485 EFI_VARIABLE_NON_VOLATILE
|
486 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
487 EFI_VARIABLE_RUNTIME_ACCESS
,
493 if (BootDevicePath
!= NULL
) {
494 FreePool (BootDevicePath
);
496 if (DefaultBootArgument1
!= NULL
) {
497 FreePool (DefaultBootArgument1
);
499 if (DefaultBootArgument2
!= NULL
) {
500 FreePool (DefaultBootArgument2
);
503 if (EFI_ERROR (Status
)) {
506 "ArmJunoDxe - The setting of the default boot entries failed - %r\n",