Home | History | Annotate | Download | only in DtPlatformDxe
      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