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 // Hardware platform identifiers
42 // This GUID must match the FILE_GUID in ArmPlatformPkg/ArmJunoPkg/AcpiTables/AcpiTables.inf
43 STATIC CONST EFI_GUID mJunoAcpiTableFile
= { 0xa1dd808e, 0x1e95, 0x4399, { 0xab, 0xc0, 0x65, 0x3c, 0x82, 0xe8, 0x53, 0x0c } };
46 ACPI_HID_DEVICE_PATH AcpiDevicePath
;
47 PCI_DEVICE_PATH PciDevicePath
;
48 EFI_DEVICE_PATH_PROTOCOL EndDevicePath
;
49 } EFI_PCI_ROOT_BRIDGE_DEVICE_PATH
;
51 STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mPciRootComplexDevicePath
= {
55 { (UINT8
) (sizeof (ACPI_HID_DEVICE_PATH
)),
56 (UINT8
) ((sizeof (ACPI_HID_DEVICE_PATH
)) >> 8) }
62 { HARDWARE_DEVICE_PATH
,
64 { (UINT8
) (sizeof (PCI_DEVICE_PATH
)),
65 (UINT8
) ((sizeof (PCI_DEVICE_PATH
)) >> 8) }
72 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
73 { END_DEVICE_PATH_LENGTH
, 0 }
77 EFI_EVENT mAcpiRegistration
= NULL
;
80 Notification function of the event defined as belonging to the
81 EFI_END_OF_DXE_EVENT_GROUP_GUID event group that was created in
82 the entry point of the driver.
84 This function is called when an event belonging to the
85 EFI_END_OF_DXE_EVENT_GROUP_GUID event group is signalled. Such an
86 event is signalled once at the end of the dispatching of all
87 drivers (end of the so called DXE phase).
89 @param[in] Event Event declared in the entry point of the driver whose
90 notification function is being invoked.
91 @param[in] Context NULL
100 EFI_DEVICE_PATH_PROTOCOL
* PciRootComplexDevicePath
;
105 // PCI Root Complex initialization
106 // At the end of the DXE phase, we should get all the driver dispatched.
107 // Force the PCI Root Complex to be initialized. It allows the OS to skip
110 PciRootComplexDevicePath
= (EFI_DEVICE_PATH_PROTOCOL
*) &mPciRootComplexDevicePath
;
111 Status
= gBS
->LocateDevicePath (&gEfiPciRootBridgeIoProtocolGuid
,
112 &PciRootComplexDevicePath
,
115 Status
= gBS
->ConnectController (Handle
, NULL
, PciRootComplexDevicePath
, FALSE
);
116 ASSERT_EFI_ERROR (Status
);
121 AcpiTableJunoR0Check (
122 IN EFI_ACPI_DESCRIPTION_HEADER
*AcpiHeader
130 AcpiTableJunoR1Check (
131 IN EFI_ACPI_DESCRIPTION_HEADER
*AcpiHeader
140 IN EFI_HANDLE ImageHandle
,
141 IN EFI_SYSTEM_TABLE
*SystemTable
145 EFI_PHYSICAL_ADDRESS HypBase
;
146 CHAR16
*TextDevicePath
;
147 UINTN TextDevicePathSize
;
152 JUNO_REVISION JunoRevision
;
153 EFI_EVENT EndOfDxeEvent
;
155 JunoRevision
= UNKNOWN
;
156 Status
= PciEmulationEntryPoint ();
157 if (EFI_ERROR (Status
)) {
162 // If a hypervisor has been declared then we need to make sure its region is protected at runtime
164 // Note: This code is only a workaround for our dummy hypervisor (ArmPkg/Extra/AArch64ToAArch32Shim/)
165 // that does not set up (yet) the stage 2 translation table to hide its own memory to EL1.
167 if (FixedPcdGet32 (PcdHypFvSize
) != 0) {
168 // Ensure the hypervisor region is strictly contained into a EFI_PAGE_SIZE-aligned region.
169 // The memory must be a multiple of EFI_PAGE_SIZE to ensure we do not reserve more memory than the hypervisor itself.
170 // A UEFI Runtime region size granularity cannot be smaller than EFI_PAGE_SIZE. If the hypervisor size is not rounded
171 // to this size then there is a risk some non-runtime memory could be visible to the OS view.
172 if (((FixedPcdGet32 (PcdHypFvSize
) & EFI_PAGE_MASK
) == 0) && ((FixedPcdGet32 (PcdHypFvBaseAddress
) & EFI_PAGE_MASK
) == 0)) {
173 // The memory needs to be declared because the DXE core marked it as reserved and removed it from the memory space
174 // as it contains the Firmware.
175 Status
= gDS
->AddMemorySpace (
176 EfiGcdMemoryTypeSystemMemory
,
177 FixedPcdGet32 (PcdHypFvBaseAddress
), FixedPcdGet32 (PcdHypFvSize
),
178 EFI_MEMORY_WB
| EFI_MEMORY_RUNTIME
180 if (!EFI_ERROR (Status
)) {
181 // We allocate the memory to ensure it is marked as runtime memory
182 HypBase
= FixedPcdGet32 (PcdHypFvBaseAddress
);
183 Status
= gBS
->AllocatePages (AllocateAddress
, EfiRuntimeServicesCode
,
184 EFI_SIZE_TO_PAGES (FixedPcdGet32 (PcdHypFvSize
)), &HypBase
);
187 // The hypervisor must be contained into a EFI_PAGE_SIZE-aligned region and its size must also be aligned
188 // on a EFI_PAGE_SIZE boundary (ie: 4KB).
189 Status
= EFI_UNSUPPORTED
;
190 ASSERT_EFI_ERROR (Status
);
193 if (EFI_ERROR (Status
)) {
199 // Create an event belonging to the "gEfiEndOfDxeEventGroupGuid" group.
200 // The "OnEndOfDxe()" function is declared as the call back function.
201 // It will be called at the end of the DXE phase when an event of the
202 // same group is signalled to inform about the end of the DXE phase.
203 // Install the INSTALL_FDT_PROTOCOL protocol.
205 Status
= gBS
->CreateEventEx (
210 &gEfiEndOfDxeEventGroupGuid
,
214 // Install dynamic Shell command to run baremetal binaries.
215 Status
= ShellDynCmdRunAxfInstall (ImageHandle
);
216 if (EFI_ERROR (Status
)) {
217 DEBUG ((EFI_D_ERROR
, "ArmJunoDxe: Failed to install ShellDynCmdRunAxf\n"));
221 // We detect whether we are running on a Juno r0 or Juno r1 board at
222 // runtime by checking the value of the MIDR register.
225 Midr
= ArmReadMidr ();
226 CpuType
= (Midr
>> ARM_CPU_TYPE_SHIFT
) & ARM_CPU_TYPE_MASK
;
227 CpuRev
= Midr
& ARM_CPU_REV_MASK
;
230 case ARM_CPU_TYPE_A53
:
231 if (CpuRev
== ARM_CPU_REV (0, 0)) {
232 JunoRevision
= JUNO_R0
;
233 } else if (CpuRev
== ARM_CPU_REV (0, 3)) {
234 JunoRevision
= JUNO_R1
;
238 case ARM_CPU_TYPE_A57
:
239 if (CpuRev
== ARM_CPU_REV (0, 0)) {
240 JunoRevision
= JUNO_R0
;
241 } else if (CpuRev
== ARM_CPU_REV (1, 1)) {
242 JunoRevision
= JUNO_R1
;
247 // Try to install the ACPI Tables
249 if (JunoRevision
== JUNO_R0
) {
250 Status
= LocateAndInstallAcpiFromFvConditional (&mJunoAcpiTableFile
, AcpiTableJunoR0Check
);
251 } else if (JunoRevision
== JUNO_R1
) {
252 Status
= LocateAndInstallAcpiFromFvConditional (&mJunoAcpiTableFile
, AcpiTableJunoR1Check
);
254 ASSERT_EFI_ERROR (Status
);
258 // Set the R1 two boot options if not already done.
260 if (JunoRevision
== JUNO_R1
) {
261 // Enable PCI enumeration
262 PcdSetBool (PcdPciDisableBusEnumeration
, FALSE
);
264 // Declare the related ACPI Tables
265 EfiCreateProtocolNotifyEvent (
266 &gEfiAcpiTableProtocolGuid
,
268 AcpiPciNotificationEvent
,
275 // Set up the device path to the FDT.
277 TextDevicePath
= (CHAR16
*)FixedPcdGetPtr (PcdJunoFdtDevicePath
);
278 if (TextDevicePath
!= NULL
) {
279 TextDevicePathSize
= StrSize (TextDevicePath
);
280 Buffer
= PcdSetPtr (PcdFdtDevicePaths
, &TextDevicePathSize
, TextDevicePath
);
281 Status
= (Buffer
!= NULL
) ? EFI_SUCCESS
: EFI_BUFFER_TOO_SMALL
;
283 Status
= EFI_NOT_FOUND
;
286 if (EFI_ERROR (Status
)) {
289 "ArmJunoDxe: Setting of FDT device path in PcdFdtDevicePaths failed - %r\n", Status
)