1 /** @file 2 * 3 * Copyright (c) 2013-2015, ARM Limited. All rights reserved. 4 * 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 9 * 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. 12 * 13 **/ 14 15 #include "ArmJunoDxeInternal.h" 16 #include <ArmPlatform.h> 17 18 #include <Protocol/DevicePathFromText.h> 19 #include <Protocol/PciRootBridgeIo.h> 20 21 #include <Guid/EventGroup.h> 22 #include <Guid/GlobalVariable.h> 23 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> 32 33 34 // This GUID must match the FILE_GUID in ArmPlatformPkg/ArmJunoPkg/AcpiTables/AcpiTables.inf 35 STATIC CONST EFI_GUID mJunoAcpiTableFile = { 0xa1dd808e, 0x1e95, 0x4399, { 0xab, 0xc0, 0x65, 0x3c, 0x82, 0xe8, 0x53, 0x0c } }; 36 37 typedef struct { 38 ACPI_HID_DEVICE_PATH AcpiDevicePath; 39 PCI_DEVICE_PATH PciDevicePath; 40 EFI_DEVICE_PATH_PROTOCOL EndDevicePath; 41 } EFI_PCI_ROOT_BRIDGE_DEVICE_PATH; 42 43 STATIC CONST EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mPciRootComplexDevicePath = { 44 { 45 { ACPI_DEVICE_PATH, 46 ACPI_DP, 47 { (UINT8) (sizeof (ACPI_HID_DEVICE_PATH)), 48 (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) } 49 }, 50 EISA_PNP_ID (0x0A03), 51 0 52 }, 53 { 54 { HARDWARE_DEVICE_PATH, 55 HW_PCI_DP, 56 { (UINT8) (sizeof (PCI_DEVICE_PATH)), 57 (UINT8) ((sizeof (PCI_DEVICE_PATH)) >> 8) } 58 }, 59 0, 60 0 61 }, 62 { 63 END_DEVICE_PATH_TYPE, 64 END_ENTIRE_DEVICE_PATH_SUBTYPE, 65 { END_DEVICE_PATH_LENGTH, 0 } 66 } 67 }; 68 69 EFI_EVENT mAcpiRegistration = NULL; 70 71 /** 72 Notification function of the event defined as belonging to the 73 EFI_END_OF_DXE_EVENT_GROUP_GUID event group that was created in 74 the entry point of the driver. 75 76 This function is called when an event belonging to the 77 EFI_END_OF_DXE_EVENT_GROUP_GUID event group is signalled. Such an 78 event is signalled once at the end of the dispatching of all 79 drivers (end of the so called DXE phase). 80 81 @param[in] Event Event declared in the entry point of the driver whose 82 notification function is being invoked. 83 @param[in] Context NULL 84 **/ 85 STATIC 86 VOID 87 OnEndOfDxe ( 88 IN EFI_EVENT Event, 89 IN VOID *Context 90 ) 91 { 92 EFI_DEVICE_PATH_PROTOCOL* PciRootComplexDevicePath; 93 EFI_HANDLE Handle; 94 EFI_STATUS Status; 95 96 // 97 // PCI Root Complex initialization 98 // At the end of the DXE phase, we should get all the driver dispatched. 99 // Force the PCI Root Complex to be initialized. It allows the OS to skip 100 // this step. 101 // 102 PciRootComplexDevicePath = (EFI_DEVICE_PATH_PROTOCOL*) &mPciRootComplexDevicePath; 103 Status = gBS->LocateDevicePath (&gEfiPciRootBridgeIoProtocolGuid, 104 &PciRootComplexDevicePath, 105 &Handle); 106 107 Status = gBS->ConnectController (Handle, NULL, PciRootComplexDevicePath, FALSE); 108 ASSERT_EFI_ERROR (Status); 109 } 110 111 STATIC 112 BOOLEAN 113 AcpiTableJunoR0Check ( 114 IN EFI_ACPI_DESCRIPTION_HEADER *AcpiHeader 115 ) 116 { 117 return TRUE; 118 } 119 120 STATIC 121 BOOLEAN 122 AcpiTableJunoR1Check ( 123 IN EFI_ACPI_DESCRIPTION_HEADER *AcpiHeader 124 ) 125 { 126 return TRUE; 127 } 128 129 STATIC 130 BOOLEAN 131 AcpiTableJunoR2Check ( 132 IN EFI_ACPI_DESCRIPTION_HEADER *AcpiHeader 133 ) 134 { 135 return TRUE; 136 } 137 138 139 EFI_STATUS 140 EFIAPI 141 ArmJunoEntryPoint ( 142 IN EFI_HANDLE ImageHandle, 143 IN EFI_SYSTEM_TABLE *SystemTable 144 ) 145 { 146 EFI_STATUS Status; 147 EFI_PHYSICAL_ADDRESS HypBase; 148 CHAR16 *TextDevicePath; 149 UINTN TextDevicePathSize; 150 VOID *Buffer; 151 UINT32 JunoRevision; 152 EFI_EVENT EndOfDxeEvent; 153 154 Status = PciEmulationEntryPoint (); 155 if (EFI_ERROR (Status)) { 156 return Status; 157 } 158 159 // 160 // If a hypervisor has been declared then we need to make sure its region is protected at runtime 161 // 162 // Note: This code is only a workaround for our dummy hypervisor (ArmPkg/Extra/AArch64ToAArch32Shim/) 163 // that does not set up (yet) the stage 2 translation table to hide its own memory to EL1. 164 // 165 if (FixedPcdGet32 (PcdHypFvSize) != 0) { 166 // Ensure the hypervisor region is strictly contained into a EFI_PAGE_SIZE-aligned region. 167 // The memory must be a multiple of EFI_PAGE_SIZE to ensure we do not reserve more memory than the hypervisor itself. 168 // A UEFI Runtime region size granularity cannot be smaller than EFI_PAGE_SIZE. If the hypervisor size is not rounded 169 // to this size then there is a risk some non-runtime memory could be visible to the OS view. 170 if (((FixedPcdGet32 (PcdHypFvSize) & EFI_PAGE_MASK) == 0) && ((FixedPcdGet32 (PcdHypFvBaseAddress) & EFI_PAGE_MASK) == 0)) { 171 // The memory needs to be declared because the DXE core marked it as reserved and removed it from the memory space 172 // as it contains the Firmware. 173 Status = gDS->AddMemorySpace ( 174 EfiGcdMemoryTypeSystemMemory, 175 FixedPcdGet32 (PcdHypFvBaseAddress), FixedPcdGet32 (PcdHypFvSize), 176 EFI_MEMORY_WB | EFI_MEMORY_RUNTIME 177 ); 178 if (!EFI_ERROR (Status)) { 179 // We allocate the memory to ensure it is marked as runtime memory 180 HypBase = FixedPcdGet32 (PcdHypFvBaseAddress); 181 Status = gBS->AllocatePages (AllocateAddress, EfiRuntimeServicesCode, 182 EFI_SIZE_TO_PAGES (FixedPcdGet32 (PcdHypFvSize)), &HypBase); 183 } 184 } else { 185 // The hypervisor must be contained into a EFI_PAGE_SIZE-aligned region and its size must also be aligned 186 // on a EFI_PAGE_SIZE boundary (ie: 4KB). 187 Status = EFI_UNSUPPORTED; 188 ASSERT_EFI_ERROR (Status); 189 } 190 191 if (EFI_ERROR (Status)) { 192 return Status; 193 } 194 } 195 196 // 197 // Create an event belonging to the "gEfiEndOfDxeEventGroupGuid" group. 198 // The "OnEndOfDxe()" function is declared as the call back function. 199 // It will be called at the end of the DXE phase when an event of the 200 // same group is signalled to inform about the end of the DXE phase. 201 // Install the INSTALL_FDT_PROTOCOL protocol. 202 // 203 Status = gBS->CreateEventEx ( 204 EVT_NOTIFY_SIGNAL, 205 TPL_CALLBACK, 206 OnEndOfDxe, 207 NULL, 208 &gEfiEndOfDxeEventGroupGuid, 209 &EndOfDxeEvent 210 ); 211 212 // Install dynamic Shell command to run baremetal binaries. 213 Status = ShellDynCmdRunAxfInstall (ImageHandle); 214 if (EFI_ERROR (Status)) { 215 DEBUG ((EFI_D_ERROR, "ArmJunoDxe: Failed to install ShellDynCmdRunAxf\n")); 216 } 217 218 GetJunoRevision(JunoRevision); 219 220 // 221 // Try to install the ACPI Tables 222 // 223 if (JunoRevision == JUNO_REVISION_R0) { 224 Status = LocateAndInstallAcpiFromFvConditional (&mJunoAcpiTableFile, AcpiTableJunoR0Check); 225 } else if (JunoRevision == JUNO_REVISION_R1) { 226 Status = LocateAndInstallAcpiFromFvConditional (&mJunoAcpiTableFile, AcpiTableJunoR1Check); 227 } else if (JunoRevision == JUNO_REVISION_R2) { 228 Status = LocateAndInstallAcpiFromFvConditional (&mJunoAcpiTableFile, AcpiTableJunoR2Check); 229 } 230 231 ASSERT_EFI_ERROR (Status); 232 233 // 234 // Setup R1/R2 options if not already done. 235 // 236 if (JunoRevision != JUNO_REVISION_R0) { 237 // Enable PCI enumeration 238 PcdSetBool (PcdPciDisableBusEnumeration, FALSE); 239 240 // Declare the related ACPI Tables 241 EfiCreateProtocolNotifyEvent ( 242 &gEfiAcpiTableProtocolGuid, 243 TPL_CALLBACK, 244 AcpiPciNotificationEvent, 245 NULL, 246 &mAcpiRegistration 247 ); 248 } 249 250 // 251 // Set up the device path to the FDT. 252 // 253 TextDevicePath = (CHAR16*)FixedPcdGetPtr (PcdJunoFdtDevicePath); 254 if (TextDevicePath != NULL) { 255 TextDevicePathSize = StrSize (TextDevicePath); 256 Buffer = PcdSetPtr (PcdFdtDevicePaths, &TextDevicePathSize, TextDevicePath); 257 Status = (Buffer != NULL) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL; 258 } else { 259 Status = EFI_NOT_FOUND; 260 } 261 262 if (EFI_ERROR (Status)) { 263 DEBUG ( 264 (EFI_D_ERROR, 265 "ArmJunoDxe: Setting of FDT device path in PcdFdtDevicePaths failed - %r\n", Status) 266 ); 267 return Status; 268 } 269 270 return Status; 271 } 272