/** @file * * Copyright (c) 2013-2015, ARM Limited. All rights reserved. * * This program and the accompanying materials * are licensed and made available under the terms and conditions of the BSD License * which accompanies this distribution. The full text of the license may be found at * http://opensource.org/licenses/bsd-license.php * * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. * **/ #include "ArmJunoDxeInternal.h" #include #include #include #include #include #include #include #include #include #include #include #include #include // // Hardware platform identifiers // typedef enum { UNKNOWN, JUNO_R0, JUNO_R1 } JUNO_REVISION; // This GUID must match the FILE_GUID in ArmPlatformPkg/ArmJunoPkg/AcpiTables/AcpiTables.inf STATIC CONST EFI_GUID mJunoAcpiTableFile = { 0xa1dd808e, 0x1e95, 0x4399, { 0xab, 0xc0, 0x65, 0x3c, 0x82, 0xe8, 0x53, 0x0c } }; typedef struct { ACPI_HID_DEVICE_PATH AcpiDevicePath; PCI_DEVICE_PATH PciDevicePath; EFI_DEVICE_PATH_PROTOCOL EndDevicePath; } EFI_PCI_ROOT_BRIDGE_DEVICE_PATH; STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mPciRootComplexDevicePath = { { { ACPI_DEVICE_PATH, ACPI_DP, { (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) } }, EISA_PNP_ID (0x0A03), 0 }, { { HARDWARE_DEVICE_PATH, HW_PCI_DP, { (UINT8) (sizeof (PCI_DEVICE_PATH)), (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) } }, 0, 0 }, { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { END_DEVICE_PATH_LENGTH, 0 } } }; EFI_EVENT mAcpiRegistration = NULL; /** Notification function of the event defined as belonging to the EFI_END_OF_DXE_EVENT_GROUP_GUID event group that was created in the entry point of the driver. This function is called when an event belonging to the EFI_END_OF_DXE_EVENT_GROUP_GUID event group is signalled. Such an event is signalled once at the end of the dispatching of all drivers (end of the so called DXE phase). @param[in] Event Event declared in the entry point of the driver whose notification function is being invoked. @param[in] Context NULL **/ STATIC VOID OnEndOfDxe ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_DEVICE_PATH_PROTOCOL* PciRootComplexDevicePath; EFI_HANDLE Handle; EFI_STATUS Status; // // PCI Root Complex initialization // At the end of the DXE phase, we should get all the driver dispatched. // Force the PCI Root Complex to be initialized. It allows the OS to skip // this step. // PciRootComplexDevicePath = (EFI_DEVICE_PATH_PROTOCOL*) &mPciRootComplexDevicePath; Status = gBS->LocateDevicePath (&gEfiPciRootBridgeIoProtocolGuid, &PciRootComplexDevicePath, &Handle); Status = gBS->ConnectController (Handle, NULL, PciRootComplexDevicePath, FALSE); ASSERT_EFI_ERROR (Status); } STATIC BOOLEAN AcpiTableJunoR0Check ( IN EFI_ACPI_DESCRIPTION_HEADER *AcpiHeader ) { return TRUE; } STATIC BOOLEAN AcpiTableJunoR1Check ( IN EFI_ACPI_DESCRIPTION_HEADER *AcpiHeader ) { return TRUE; } EFI_STATUS EFIAPI ArmJunoEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; EFI_PHYSICAL_ADDRESS HypBase; CHAR16 *TextDevicePath; UINTN TextDevicePathSize; VOID *Buffer; UINT32 Midr; UINT32 CpuType; UINT32 CpuRev; JUNO_REVISION JunoRevision; EFI_EVENT EndOfDxeEvent; JunoRevision = UNKNOWN; Status = PciEmulationEntryPoint (); if (EFI_ERROR (Status)) { return Status; } // // If a hypervisor has been declared then we need to make sure its region is protected at runtime // // Note: This code is only a workaround for our dummy hypervisor (ArmPkg/Extra/AArch64ToAArch32Shim/) // that does not set up (yet) the stage 2 translation table to hide its own memory to EL1. // if (FixedPcdGet32 (PcdHypFvSize) != 0) { // Ensure the hypervisor region is strictly contained into a EFI_PAGE_SIZE-aligned region. // The memory must be a multiple of EFI_PAGE_SIZE to ensure we do not reserve more memory than the hypervisor itself. // A UEFI Runtime region size granularity cannot be smaller than EFI_PAGE_SIZE. If the hypervisor size is not rounded // to this size then there is a risk some non-runtime memory could be visible to the OS view. if (((FixedPcdGet32 (PcdHypFvSize) & EFI_PAGE_MASK) == 0) && ((FixedPcdGet32 (PcdHypFvBaseAddress) & EFI_PAGE_MASK) == 0)) { // The memory needs to be declared because the DXE core marked it as reserved and removed it from the memory space // as it contains the Firmware. Status = gDS->AddMemorySpace ( EfiGcdMemoryTypeSystemMemory, FixedPcdGet32 (PcdHypFvBaseAddress), FixedPcdGet32 (PcdHypFvSize), EFI_MEMORY_WB | EFI_MEMORY_RUNTIME ); if (!EFI_ERROR (Status)) { // We allocate the memory to ensure it is marked as runtime memory HypBase = FixedPcdGet32 (PcdHypFvBaseAddress); Status = gBS->AllocatePages (AllocateAddress, EfiRuntimeServicesCode, EFI_SIZE_TO_PAGES (FixedPcdGet32 (PcdHypFvSize)), &HypBase); } } else { // The hypervisor must be contained into a EFI_PAGE_SIZE-aligned region and its size must also be aligned // on a EFI_PAGE_SIZE boundary (ie: 4KB). Status = EFI_UNSUPPORTED; ASSERT_EFI_ERROR (Status); } if (EFI_ERROR (Status)) { return Status; } } // // Create an event belonging to the "gEfiEndOfDxeEventGroupGuid" group. // The "OnEndOfDxe()" function is declared as the call back function. // It will be called at the end of the DXE phase when an event of the // same group is signalled to inform about the end of the DXE phase. // Install the INSTALL_FDT_PROTOCOL protocol. // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_CALLBACK, OnEndOfDxe, NULL, &gEfiEndOfDxeEventGroupGuid, &EndOfDxeEvent ); // Install dynamic Shell command to run baremetal binaries. Status = ShellDynCmdRunAxfInstall (ImageHandle); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "ArmJunoDxe: Failed to install ShellDynCmdRunAxf\n")); } // // We detect whether we are running on a Juno r0 or Juno r1 board at // runtime by checking the value of the MIDR register. // Midr = ArmReadMidr (); CpuType = (Midr >> ARM_CPU_TYPE_SHIFT) & ARM_CPU_TYPE_MASK; CpuRev = Midr & ARM_CPU_REV_MASK; switch (CpuType) { case ARM_CPU_TYPE_A53: if (CpuRev == ARM_CPU_REV (0, 0)) { JunoRevision = JUNO_R0; } else if (CpuRev == ARM_CPU_REV (0, 3)) { JunoRevision = JUNO_R1; } break; case ARM_CPU_TYPE_A57: if (CpuRev == ARM_CPU_REV (0, 0)) { JunoRevision = JUNO_R0; } else if (CpuRev == ARM_CPU_REV (1, 1)) { JunoRevision = JUNO_R1; } } // // Try to install the ACPI Tables // if (JunoRevision == JUNO_R0) { Status = LocateAndInstallAcpiFromFvConditional (&mJunoAcpiTableFile, AcpiTableJunoR0Check); } else if (JunoRevision == JUNO_R1) { Status = LocateAndInstallAcpiFromFvConditional (&mJunoAcpiTableFile, AcpiTableJunoR1Check); } ASSERT_EFI_ERROR (Status); // // Set the R1 two boot options if not already done. // if (JunoRevision == JUNO_R1) { // Enable PCI enumeration PcdSetBool (PcdPciDisableBusEnumeration, FALSE); // Declare the related ACPI Tables EfiCreateProtocolNotifyEvent ( &gEfiAcpiTableProtocolGuid, TPL_CALLBACK, AcpiPciNotificationEvent, NULL, &mAcpiRegistration ); } // // Set up the device path to the FDT. // TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoFdtDevicePath); if (TextDevicePath != NULL) { TextDevicePathSize = StrSize (TextDevicePath); Buffer = PcdSetPtr (PcdFdtDevicePaths, &TextDevicePathSize, TextDevicePath); Status = (Buffer != NULL) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL; } else { Status = EFI_NOT_FOUND; } if (EFI_ERROR (Status)) { DEBUG ( (EFI_D_ERROR, "ArmJunoDxe: Setting of FDT device path in PcdFdtDevicePaths failed - %r\n", Status) ); return Status; } return Status; }