1 /** @file 2 * 3 * Copyright (c) 2017, Linaro, Ltd. 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 <Library/BaseLib.h> 16 #include <Library/DebugLib.h> 17 #include <Library/DevicePathLib.h> 18 #include <Library/DtPlatformDtbLoaderLib.h> 19 #include <Library/HiiLib.h> 20 #include <Library/MemoryAllocationLib.h> 21 #include <Library/UefiBootServicesTableLib.h> 22 #include <Library/UefiDriverEntryPoint.h> 23 #include <Library/UefiRuntimeServicesTableLib.h> 24 25 #include "DtPlatformDxe.h" 26 27 extern UINT8 DtPlatformHiiBin[]; 28 extern UINT8 DtPlatformDxeStrings[]; 29 30 typedef struct { 31 VENDOR_DEVICE_PATH VendorDevicePath; 32 EFI_DEVICE_PATH_PROTOCOL End; 33 } HII_VENDOR_DEVICE_PATH; 34 35 STATIC HII_VENDOR_DEVICE_PATH mDtPlatformDxeVendorDevicePath = { 36 { 37 { 38 HARDWARE_DEVICE_PATH, 39 HW_VENDOR_DP, 40 { 41 (UINT8) (sizeof (VENDOR_DEVICE_PATH)), 42 (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) 43 } 44 }, 45 DT_PLATFORM_FORMSET_GUID 46 }, 47 { 48 END_DEVICE_PATH_TYPE, 49 END_ENTIRE_DEVICE_PATH_SUBTYPE, 50 { 51 (UINT8) (END_DEVICE_PATH_LENGTH), 52 (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) 53 } 54 } 55 }; 56 57 STATIC 58 EFI_STATUS 59 InstallHiiPages ( 60 VOID 61 ) 62 { 63 EFI_STATUS Status; 64 EFI_HII_HANDLE HiiHandle; 65 EFI_HANDLE DriverHandle; 66 67 DriverHandle = NULL; 68 Status = gBS->InstallMultipleProtocolInterfaces (&DriverHandle, 69 &gEfiDevicePathProtocolGuid, 70 &mDtPlatformDxeVendorDevicePath, 71 NULL); 72 if (EFI_ERROR (Status)) { 73 return Status; 74 } 75 76 HiiHandle = HiiAddPackages (&gDtPlatformFormSetGuid, 77 DriverHandle, 78 DtPlatformDxeStrings, 79 DtPlatformHiiBin, 80 NULL); 81 82 if (HiiHandle == NULL) { 83 gBS->UninstallMultipleProtocolInterfaces (DriverHandle, 84 &gEfiDevicePathProtocolGuid, 85 &mDtPlatformDxeVendorDevicePath, 86 NULL); 87 return EFI_OUT_OF_RESOURCES; 88 } 89 return EFI_SUCCESS; 90 } 91 92 /** 93 The entry point for DtPlatformDxe driver. 94 95 @param[in] ImageHandle The image handle of the driver. 96 @param[in] SystemTable The system table. 97 98 @retval EFI_ALREADY_STARTED The driver already exists in system. 99 @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of 100 resources. 101 @retval EFI_SUCCES All the related protocols are installed on 102 the driver. 103 104 **/ 105 EFI_STATUS 106 EFIAPI 107 DtPlatformDxeEntryPoint ( 108 IN EFI_HANDLE ImageHandle, 109 IN EFI_SYSTEM_TABLE *SystemTable 110 ) 111 { 112 EFI_STATUS Status; 113 DT_ACPI_VARSTORE_DATA DtAcpiPref; 114 UINTN BufferSize; 115 VOID *Dtb; 116 UINTN DtbSize; 117 118 Dtb = NULL; 119 Status = DtPlatformLoadDtb (&Dtb, &DtbSize); 120 if (EFI_ERROR (Status)) { 121 DEBUG ((DEBUG_WARN, 122 "%a: no DTB blob could be loaded, defaulting to ACPI (Status == %r)\n", 123 __FUNCTION__, Status)); 124 DtAcpiPref.Pref = DT_ACPI_SELECT_ACPI; 125 } else { 126 // 127 // Get the current DT/ACPI preference from the DtAcpiPref variable. 128 // 129 BufferSize = sizeof (DtAcpiPref); 130 Status = gRT->GetVariable(DT_ACPI_VARIABLE_NAME, &gDtPlatformFormSetGuid, 131 NULL, &BufferSize, &DtAcpiPref); 132 if (EFI_ERROR (Status)) { 133 DEBUG ((DEBUG_WARN, "%a: no DT/ACPI preference found, defaulting to DT\n", 134 __FUNCTION__)); 135 DtAcpiPref.Pref = DT_ACPI_SELECT_DT; 136 } 137 } 138 139 if (!EFI_ERROR (Status) && 140 DtAcpiPref.Pref != DT_ACPI_SELECT_ACPI && 141 DtAcpiPref.Pref != DT_ACPI_SELECT_DT) { 142 DEBUG ((DEBUG_WARN, "%a: invalid value for %s, defaulting to DT\n", 143 __FUNCTION__, DT_ACPI_VARIABLE_NAME)); 144 DtAcpiPref.Pref = DT_ACPI_SELECT_DT; 145 Status = EFI_INVALID_PARAMETER; // trigger setvar below 146 } 147 148 // 149 // Write the newly selected default value back to the variable store. 150 // 151 if (EFI_ERROR (Status)) { 152 Status = gRT->SetVariable(DT_ACPI_VARIABLE_NAME, &gDtPlatformFormSetGuid, 153 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, 154 sizeof (DtAcpiPref), &DtAcpiPref); 155 if (EFI_ERROR (Status)) { 156 goto FreeDtb; 157 } 158 } 159 160 if (DtAcpiPref.Pref == DT_ACPI_SELECT_ACPI) { 161 // 162 // ACPI was selected: install the gEdkiiPlatformHasAcpiGuid GUID as a 163 // NULL protocol to unlock dispatch of ACPI related drivers. 164 // 165 Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle, 166 &gEdkiiPlatformHasAcpiGuid, NULL, NULL); 167 if (EFI_ERROR (Status)) { 168 DEBUG ((DEBUG_ERROR, 169 "%a: failed to install gEdkiiPlatformHasAcpiGuid as a protocol\n", 170 __FUNCTION__)); 171 goto FreeDtb; 172 } 173 } else if (DtAcpiPref.Pref == DT_ACPI_SELECT_DT) { 174 // 175 // DT was selected: copy the blob into newly allocated memory and install 176 // a reference to it as the FDT configuration table. 177 // 178 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, Dtb); 179 if (EFI_ERROR (Status)) { 180 DEBUG ((DEBUG_ERROR, "%a: failed to install FDT configuration table\n", 181 __FUNCTION__)); 182 goto FreeDtb; 183 } 184 } else { 185 ASSERT (FALSE); 186 } 187 188 // 189 // No point in installing the HII pages if ACPI is the only description 190 // we have 191 // 192 if (Dtb == NULL) { 193 return EFI_SUCCESS; 194 } 195 196 // 197 // Note that we don't uninstall the gEdkiiPlatformHasAcpiGuid protocol nor 198 // the FDT configuration table if the following call fails. While that will 199 // cause loading of this driver to fail, proceeding with ACPI and DT both 200 // disabled will guarantee a failed boot, and so it is better to leave them 201 // installed in that case. 202 // 203 return InstallHiiPages (); 204 205 FreeDtb: 206 if (Dtb != NULL) { 207 FreePool (Dtb); 208 } 209 210 return Status; 211 } 212