Home | History | Annotate | Download | only in HiKeyDxe
      1 /** @file
      2 *
      3 *  Copyright (c) 2015, Linaro Ltd. All rights reserved.
      4 *  Copyright (c) 2015, Hisilicon Ltd. All rights reserved.
      5 *
      6 *  This program and the accompanying materials
      7 *  are licensed and made available under the terms and conditions of the BSD License
      8 *  which accompanies this distribution.  The full text of the license may be found at
      9 *  http://opensource.org/licenses/bsd-license.php
     10 *
     11 *  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 *  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 *
     14 **/
     15 
     16 #include <Library/BaseMemoryLib.h>
     17 #include <Library/BdsLib.h>
     18 #include <Library/CacheMaintenanceLib.h>
     19 #include <Library/DevicePathLib.h>
     20 #include <Library/DxeServicesLib.h>
     21 #include <Library/IoLib.h>
     22 #include <Library/MemoryAllocationLib.h>
     23 #include <Library/PrintLib.h>
     24 #include <Library/UefiBootServicesTableLib.h>
     25 #include <Library/UefiLib.h>
     26 #include <Library/UefiRuntimeServicesTableLib.h>
     27 
     28 #include <Protocol/BlockIo.h>
     29 #include <Protocol/DevicePathFromText.h>
     30 #include <Protocol/DevicePathToText.h>
     31 #include <Protocol/DwUsb.h>
     32 #include <Protocol/EmbeddedGpio.h>
     33 #include <Protocol/SimpleFileSystem.h>
     34 
     35 #include <Guid/Fdt.h>
     36 #include <Guid/FileInfo.h>
     37 #include <Guid/EventGroup.h>
     38 #include <Guid/GlobalVariable.h>
     39 #include <Guid/HiKeyVariable.h>
     40 #include <Guid/VariableFormat.h>
     41 
     42 #include "HiKeyDxeInternal.h"
     43 
     44 typedef enum {
     45   HIKEY_DTB_ANDROID = 0,	/* DTB is attached at the end of boot.img */
     46   HIKEY_DTB_LINUX = 1,		/* DTB is in partition */
     47   HIKEY_DTB_SD = 2,		/* DTB is already in SD Card */
     48 } HiKeyDtbType;
     49 
     50 #define HIKEY_IO_BLOCK_SIZE      512
     51 
     52 #define MAX_BOOT_ENTRIES         16
     53 // Jumper on pin5-6 of J15 determines whether boot to fastboot
     54 #define DETECT_J15_FASTBOOT      24    // GPIO 3_0
     55 
     56 #define USER_LED1                32    // GPIO 4_0
     57 #define USER_LED2                33    // GPIO 4_1
     58 #define USER_LED3                34    // GPIO 4_2
     59 #define USER_LED4                35    // GPIO 4_3
     60 
     61 struct HiKeyBootEntry {
     62   CHAR16    *Path;
     63   CHAR16    *Args;
     64   CHAR16    *Description;
     65   UINT16     LoadType;
     66 };
     67 
     68 STATIC CONST BOOLEAN mIsEndOfDxeEvent = TRUE;
     69 STATIC UINT16 *mBootOrder = NULL;
     70 STATIC UINT16 mBootCount = 0;
     71 STATIC UINT16 mBootIndex = 0;
     72 
     73 #define HIKEY_BOOT_ENTRY_FASTBOOT          0
     74 #define HIKEY_BOOT_ENTRY_BOOT_EMMC         1    /* boot from eMMC */
     75 #define HIKEY_BOOT_ENTRY_BOOT_SD           2    /* boot from SD card */
     76 
     77 STATIC struct HiKeyBootEntry LinuxEntries[] = {
     78   [HIKEY_BOOT_ENTRY_FASTBOOT] = {
     79     L"FvFile(9588502a-5370-11e3-8631-d7c5951364c8)",
     80     //L"VenHw(B549F005-4BD4-4020-A0CB-06F42BDA68C3)/HD(6,GPT,5C0F213C-17E1-4149-88C8-8B50FB4EC70E,0x7000,0x20000)/\\EFI\\BOOT\\FASTBOOT.EFI",
     81     NULL,
     82     L"fastboot",
     83     LOAD_OPTION_CATEGORY_APP
     84   },
     85   [HIKEY_BOOT_ENTRY_BOOT_EMMC] = {
     86     L"VenHw(B549F005-4BD4-4020-A0CB-06F42BDA68C3)/HD(6,GPT,5C0F213C-17E1-4149-88C8-8B50FB4EC70E,0x7000,0x20000)/\\EFI\\BOOT\\GRUBAA64.EFI",
     87     NULL,
     88     L"boot from eMMC",
     89     LOAD_OPTION_CATEGORY_APP
     90   },
     91   [HIKEY_BOOT_ENTRY_BOOT_SD] = {
     92     L"VenHw(594BFE73-5E18-4F12-8119-19DB8C5FC849)/HD(1,MBR,0x00000000,0x3F,0x21FC0)/\\EFI\\BOOT\\BOOTAA64.EFI",
     93     NULL,
     94     L"boot from SD card",
     95     LOAD_OPTION_CATEGORY_BOOT
     96   }
     97 };
     98 
     99 STATIC struct HiKeyBootEntry AndroidEntries[] = {
    100   [HIKEY_BOOT_ENTRY_FASTBOOT] = {
    101     L"FvFile(9588502a-5370-11e3-8631-d7c5951364c8)",
    102     //L"VenHw(B549F005-4BD4-4020-A0CB-06F42BDA68C3)/HD(6,GPT,5C0F213C-17E1-4149-88C8-8B50FB4EC70E,0x7000,0x20000)/\\EFI\\BOOT\\FASTBOOT.EFI",
    103     NULL,
    104     L"fastboot",
    105     LOAD_OPTION_CATEGORY_APP
    106   },
    107   [HIKEY_BOOT_ENTRY_BOOT_EMMC] = {
    108     L"VenHw(B549F005-4BD4-4020-A0CB-06F42BDA68C3)/HD(6,GPT,5C0F213C-17E1-4149-88C8-8B50FB4EC70E,0x7000,0x20000)/Offset(0x0000,0x20000)",
    109     L"console=ttyAMA3,115200 earlycon=pl011,0xf7113000 root=/dev/mmcblk0p9 rw rootwait efi=noruntime",
    110     L"boot from eMMC",
    111     LOAD_OPTION_CATEGORY_BOOT
    112   },
    113   [HIKEY_BOOT_ENTRY_BOOT_SD] = {
    114     L"VenHw(594BFE73-5E18-4F12-8119-19DB8C5FC849)/HD(1,MBR,0x00000000,0x3F,0x21FC0)/Image",
    115     L"dtb=hi6220-hikey.dtb console=ttyAMA3,115200 earlycon=pl011,0xf7113000 root=/dev/mmcblk1p2 rw rootwait initrd=initrd.img efi=noruntime",
    116     L"boot from SD card",
    117     LOAD_OPTION_CATEGORY_BOOT
    118   }
    119 };
    120 
    121 
    122 STATIC
    123 BOOLEAN
    124 EFIAPI
    125 HiKeyVerifyBootEntry (
    126   IN CHAR16          *BootVariableName,
    127   IN CHAR16          *BootDevicePathText,
    128   IN CHAR16          *BootArgs,
    129   IN CHAR16          *BootDescription,
    130   IN UINT16           LoadOptionAttr
    131   )
    132 {
    133   EFI_DEVICE_PATH_TO_TEXT_PROTOCOL   *DevicePathToTextProtocol;
    134   CHAR16                             *DevicePathText;
    135   UINTN                               EfiLoadOptionSize;
    136   EFI_LOAD_OPTION                    *EfiLoadOption;
    137   BDS_LOAD_OPTION                    *LoadOption;
    138   EFI_STATUS                          Status;
    139   UINTN                               DescriptionLength;
    140 
    141   Status = GetGlobalEnvironmentVariable (BootVariableName, NULL, &EfiLoadOptionSize, (VOID**)&EfiLoadOption);
    142   if (EFI_ERROR (Status)) {
    143     return FALSE;
    144   }
    145   if (EfiLoadOption == NULL) {
    146     return FALSE;
    147   }
    148   if (EfiLoadOptionSize < sizeof(UINT32) + sizeof(UINT16) + sizeof(CHAR16) + sizeof(EFI_DEVICE_PATH_PROTOCOL)) {
    149     return FALSE;
    150   }
    151   LoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
    152   if (LoadOption == NULL) {
    153     return FALSE;
    154   }
    155 
    156   LoadOption->LoadOption         = EfiLoadOption;
    157   LoadOption->Attributes         = *(UINT32*)EfiLoadOption;
    158   LoadOption->FilePathListLength = *(UINT16*)(EfiLoadOption + sizeof(UINT32));
    159   LoadOption->Description        = (CHAR16*)(EfiLoadOption + sizeof(UINT32) + sizeof(UINT16));
    160   DescriptionLength              = StrSize (LoadOption->Description);
    161   LoadOption->FilePathList       = (EFI_DEVICE_PATH_PROTOCOL*)(EfiLoadOption + sizeof(UINT32) + sizeof(UINT16) + DescriptionLength);
    162   if ((UINTN)((UINTN)LoadOption->FilePathList + LoadOption->FilePathListLength - (UINTN)EfiLoadOption) == EfiLoadOptionSize) {
    163     LoadOption->OptionalData     = NULL;
    164     LoadOption->OptionalDataSize = 0;
    165   } else {
    166     LoadOption->OptionalData     = (VOID*)((UINTN)(LoadOption->FilePathList) + LoadOption->FilePathListLength);
    167     LoadOption->OptionalDataSize = EfiLoadOptionSize - ((UINTN)LoadOption->OptionalData - (UINTN)EfiLoadOption);
    168   }
    169 
    170   if (((BootArgs == NULL) && (LoadOption->OptionalDataSize)) ||
    171       (BootArgs && (LoadOption->OptionalDataSize == 0))) {
    172     return FALSE;
    173   } else if (BootArgs && LoadOption->OptionalDataSize) {
    174     if (StrCmp (BootArgs, LoadOption->OptionalData) != 0)
    175       return FALSE;
    176   }
    177   if ((LoadOption->Description == NULL) || (BootDescription == NULL)) {
    178     return FALSE;
    179   }
    180   if (StrCmp (BootDescription, LoadOption->Description) != 0) {
    181     return FALSE;
    182   }
    183   if ((LoadOption->Attributes & LOAD_OPTION_CATEGORY) != (LoadOptionAttr & LOAD_OPTION_CATEGORY)) {
    184     return FALSE;
    185   }
    186 
    187   Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
    188   ASSERT_EFI_ERROR(Status);
    189   DevicePathText = DevicePathToTextProtocol->ConvertDevicePathToText(LoadOption->FilePathList, TRUE, TRUE);
    190   if (StrCmp (DevicePathText, BootDevicePathText) != 0) {
    191     return FALSE;
    192   }
    193 
    194   FreePool (LoadOption);
    195   return TRUE;
    196 }
    197 
    198 STATIC
    199 EFI_STATUS
    200 EFIAPI
    201 HiKeyCreateBootEntry (
    202   IN CHAR16          *DevicePathText,
    203   IN CHAR16          *BootArgs,
    204   IN CHAR16          *BootDescription,
    205   IN UINT16           LoadOption
    206   )
    207 {
    208   BDS_LOAD_OPTION                    *BdsLoadOption;
    209   EFI_STATUS                          Status;
    210   UINTN                               DescriptionSize;
    211   UINTN                               BootOrderSize;
    212   CHAR16                              BootVariableName[9];
    213   UINT8                              *EfiLoadOptionPtr;
    214   EFI_DEVICE_PATH_PROTOCOL           *DevicePathNode;
    215   UINTN                               NodeLength;
    216   EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *DevicePathFromTextProtocol;
    217 
    218   if ((DevicePathText == NULL) || (BootDescription == NULL)) {
    219     DEBUG ((EFI_D_ERROR, "%a: Invalid Parameters\n", __func__));
    220     return EFI_INVALID_PARAMETER;
    221   }
    222 
    223   UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", mBootCount);
    224   if (HiKeyVerifyBootEntry (BootVariableName, DevicePathText, BootArgs, BootDescription, LoadOption) == TRUE) {
    225     // The boot entry is already created.
    226     Status = EFI_SUCCESS;
    227     goto done;
    228   }
    229 
    230   BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
    231   ASSERT (BdsLoadOption != NULL);
    232 
    233   Status = gBS->LocateProtocol (
    234                   &gEfiDevicePathFromTextProtocolGuid,
    235                   NULL,
    236                   (VOID**)&DevicePathFromTextProtocol
    237                   );
    238   ASSERT_EFI_ERROR(Status);
    239 
    240   BdsLoadOption->FilePathList = DevicePathFromTextProtocol->ConvertTextToDevicePath (DevicePathText);
    241   ASSERT (BdsLoadOption->FilePathList != NULL);
    242   BdsLoadOption->FilePathListLength = GetDevicePathSize (BdsLoadOption->FilePathList);
    243   BdsLoadOption->Attributes = LOAD_OPTION_ACTIVE | (LoadOption & LOAD_OPTION_CATEGORY);
    244 
    245   if (BootArgs) {
    246     /* Always force the BootArgs to save 512 characters. */
    247     ASSERT (StrSize(BootArgs) <= 512);
    248     BdsLoadOption->OptionalDataSize = 512;
    249     BdsLoadOption->OptionalData = (CHAR16*)AllocateZeroPool (BdsLoadOption->OptionalDataSize);
    250     ASSERT (BdsLoadOption->OptionalData != NULL);
    251     StrCpy (BdsLoadOption->OptionalData, BootArgs);
    252   }
    253 
    254   BdsLoadOption->LoadOptionIndex = mBootCount;
    255   DescriptionSize = StrSize (BootDescription);
    256   BdsLoadOption->Description = (VOID*)AllocateZeroPool (DescriptionSize);
    257   StrCpy (BdsLoadOption->Description, BootDescription);
    258 
    259   BdsLoadOption->LoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + DescriptionSize + BdsLoadOption->FilePathListLength + BdsLoadOption->OptionalDataSize;
    260   BdsLoadOption->LoadOption = (EFI_LOAD_OPTION*)AllocateZeroPool (BdsLoadOption->LoadOptionSize);
    261   ASSERT (BdsLoadOption->LoadOption != NULL);
    262 
    263   EfiLoadOptionPtr = (VOID*)BdsLoadOption->LoadOption;
    264 
    265   //
    266   // Populate the EFI Load Option and BDS Boot Option structures
    267   //
    268 
    269   // Attributes fields
    270   *(UINT32*)EfiLoadOptionPtr = BdsLoadOption->Attributes;
    271   EfiLoadOptionPtr += sizeof(UINT32);
    272 
    273   // FilePath List fields
    274   *(UINT16*)EfiLoadOptionPtr = BdsLoadOption->FilePathListLength;
    275   EfiLoadOptionPtr += sizeof(UINT16);
    276 
    277   // Boot description fields
    278   CopyMem (EfiLoadOptionPtr, BdsLoadOption->Description, DescriptionSize);
    279   EfiLoadOptionPtr += DescriptionSize;
    280 
    281   // File path fields
    282   DevicePathNode = BdsLoadOption->FilePathList;
    283   while (!IsDevicePathEndType (DevicePathNode)) {
    284     NodeLength = DevicePathNodeLength(DevicePathNode);
    285     CopyMem (EfiLoadOptionPtr, DevicePathNode, NodeLength);
    286     EfiLoadOptionPtr += NodeLength;
    287     DevicePathNode = NextDevicePathNode (DevicePathNode);
    288   }
    289 
    290   // Set the End Device Path Type
    291   SetDevicePathEndNode (EfiLoadOptionPtr);
    292   EfiLoadOptionPtr += sizeof(EFI_DEVICE_PATH);
    293 
    294   // Fill the Optional Data
    295   if (BdsLoadOption->OptionalDataSize > 0) {
    296     CopyMem (EfiLoadOptionPtr, BdsLoadOption->OptionalData, BdsLoadOption->OptionalDataSize);
    297   }
    298 
    299   Status = gRT->SetVariable (
    300                   BootVariableName,
    301                   &gEfiGlobalVariableGuid,
    302                   EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    303                   BdsLoadOption->LoadOptionSize,
    304                   BdsLoadOption->LoadOption
    305                   );
    306   if (EFI_ERROR (Status)) {
    307     DEBUG ((EFI_D_ERROR, "%a: failed to set BootVariable\n", __func__));
    308     return Status;
    309   }
    310 
    311 done:
    312   BootOrderSize = mBootCount * sizeof (UINT16);
    313   mBootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof (UINT16), mBootOrder);
    314   mBootOrder[mBootCount] = mBootCount;
    315   mBootCount++;
    316   return Status;
    317 }
    318 
    319 STATIC
    320 EFI_STATUS
    321 EFIAPI
    322 HiKeyCreateBootOrder (
    323   IN    VOID
    324   )
    325 {
    326   UINT16             *BootOrder;
    327   UINTN               BootOrderSize;
    328   UINTN               Index;
    329   EFI_STATUS          Status;
    330 
    331   Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
    332   if (EFI_ERROR(Status) == 0) {
    333     if (BootOrderSize == mBootCount) {
    334       for (Index = 0; Index < mBootCount; Index++) {
    335         if (BootOrder[Index] != mBootOrder[Index]) {
    336           break;
    337         }
    338       }
    339       if (Index == mBootCount) {
    340         // Found BootOrder variable with expected value.
    341         return EFI_SUCCESS;
    342       }
    343     }
    344   }
    345 
    346   Status = gRT->SetVariable (
    347                   (CHAR16*)L"BootOrder",
    348                   &gEfiGlobalVariableGuid,
    349                   EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    350                   mBootCount * sizeof(UINT16),
    351                   mBootOrder
    352                   );
    353   return Status;
    354 }
    355 
    356 STATIC
    357 EFI_STATUS
    358 EFIAPI
    359 HiKeyCreateBootNext (
    360   IN     VOID
    361   )
    362 {
    363   EFI_STATUS          Status;
    364   UINT16             *BootNext;
    365   UINTN               BootNextSize;
    366 
    367   BootNextSize = sizeof(UINT16);
    368   Status = GetGlobalEnvironmentVariable (L"BootNext", NULL, &BootNextSize, (VOID**)&BootNext);
    369   if (EFI_ERROR(Status) == 0) {
    370     if (BootNextSize == sizeof (UINT16)) {
    371       if (*BootNext == mBootOrder[mBootIndex]) {
    372         // Found the BootNext variable with expected value.
    373         return EFI_SUCCESS;
    374       }
    375     }
    376   }
    377   BootNext = &mBootOrder[mBootIndex];
    378   Status = gRT->SetVariable (
    379                   (CHAR16*)L"BootNext",
    380                   &gEfiGlobalVariableGuid,
    381                   EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    382                   sizeof (UINT16),
    383                   BootNext
    384                   );
    385   return Status;
    386 }
    387 
    388 STATIC
    389 VOID
    390 EFIAPI
    391 HiKeyTestLed (
    392   IN     EMBEDDED_GPIO   *Gpio
    393   )
    394 {
    395   EFI_STATUS             Status;
    396 
    397   Status = Gpio->Set (Gpio, USER_LED1, GPIO_MODE_OUTPUT_0);
    398   if (EFI_ERROR (Status)) {
    399     DEBUG ((EFI_D_ERROR, "%a: failed to set LED1\n", __func__));
    400     return;
    401   }
    402   Status = Gpio->Set (Gpio, USER_LED2, GPIO_MODE_OUTPUT_1);
    403   if (EFI_ERROR (Status)) {
    404     DEBUG ((EFI_D_ERROR, "%a: failed to set LED2\n", __func__));
    405     return;
    406   }
    407   Status = Gpio->Set (Gpio, USER_LED3, GPIO_MODE_OUTPUT_0);
    408   if (EFI_ERROR (Status)) {
    409     DEBUG ((EFI_D_ERROR, "%a: failed to set LED3\n", __func__));
    410     return;
    411   }
    412   Status = Gpio->Set (Gpio, USER_LED4, GPIO_MODE_OUTPUT_1);
    413   if (EFI_ERROR (Status)) {
    414     DEBUG ((EFI_D_ERROR, "%a: failed to set LED4\n", __func__));
    415     return;
    416   }
    417 }
    418 
    419 
    420 #define REBOOT_REASON_ADDR		0x05F01000
    421 #define REBOOT_REASON_BOOTLOADER	0x77665500
    422 #define REBOOT_REASON_NONE		0x77665501
    423 STATIC
    424 BOOLEAN
    425 EFIAPI
    426 HiKeyDetectRebootReason (
    427   IN     VOID
    428   )
    429 {
    430    UINT32 *addr = (UINT32*)REBOOT_REASON_ADDR;
    431    UINT32  val;
    432 
    433    val = *addr;
    434    /* Write NONE to the reason address to clear the state */
    435    *addr = REBOOT_REASON_NONE;
    436    /* Check to see if "reboot booloader" was specified */
    437    if (val == REBOOT_REASON_BOOTLOADER)
    438      return TRUE;
    439 
    440    return FALSE;
    441 }
    442 
    443 STATIC
    444 BOOLEAN
    445 EFIAPI
    446 HiKeyIsJumperConnected (
    447   IN     VOID
    448   )
    449 {
    450   EMBEDDED_GPIO         *Gpio;
    451   EFI_STATUS             Status;
    452   UINTN                  Value;
    453 
    454   Status = gBS->LocateProtocol (&gEmbeddedGpioProtocolGuid, NULL, (VOID **)&Gpio);
    455   ASSERT_EFI_ERROR (Status);
    456 
    457   Status = Gpio->Set (Gpio, DETECT_J15_FASTBOOT, GPIO_MODE_INPUT);
    458   if (EFI_ERROR (Status)) {
    459     DEBUG ((EFI_D_ERROR, "%a: failed to set jumper as gpio input\n", __func__));
    460     return FALSE;
    461   }
    462   Status = Gpio->Get (Gpio, DETECT_J15_FASTBOOT, &Value);
    463   if (EFI_ERROR (Status)) {
    464     DEBUG ((EFI_D_ERROR, "%a: failed to get value from jumper\n", __func__));
    465     return FALSE;
    466   }
    467 
    468   HiKeyTestLed (Gpio);
    469   if (Value != 0)
    470     return FALSE;
    471   return TRUE;
    472 }
    473 
    474 STATIC
    475 BOOLEAN
    476 EFIAPI
    477 HiKeySDCardIsPresent (
    478   IN      VOID
    479   )
    480 {
    481   UINT32    Value;
    482 
    483   /*
    484    * FIXME
    485    * At first, reading GPIO pin shouldn't exist in SD driver. We need to
    486    * add some callbacks to handle settings for hardware platform.
    487    * In the second, reading GPIO pin should be based on GPIO driver. Now
    488    * GPIO driver could only be used for one PL061 gpio controller. And it's
    489    * used to detect jumper setting. As a workaround, we have to read the gpio
    490    * register instead at here.
    491    *
    492    */
    493   Value = MmioRead32 (0xf8012000 + (1 << 2));
    494   if (Value)
    495     return FALSE;
    496   return TRUE;
    497 }
    498 
    499 #define BOOT_MAGIC        "ANDROID!"
    500 #define BOOT_MAGIC_LENGTH sizeof (BOOT_MAGIC) - 1
    501 
    502 /*
    503  * Check which boot type is valid for eMMC.
    504  */
    505 STATIC
    506 EFI_STATUS
    507 EFIAPI
    508 HiKeyCheckEmmcDtbType (
    509   OUT UINTN       *DtbType
    510   )
    511 {
    512   EFI_DEVICE_PATH_PROTOCOL        *BlockDevicePath;
    513   EFI_BLOCK_IO_PROTOCOL           *BlockIoProtocol;
    514   EFI_HANDLE                      Handle;
    515   EFI_STATUS                      Status;
    516   VOID                            *DataPtr, *AlignedPtr;
    517 
    518   /* Check boot image */
    519   BlockDevicePath = ConvertTextToDevicePath ((CHAR16*)FixedPcdGetPtr (PcdBootImagePath));
    520   Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &BlockDevicePath, &Handle);
    521   ASSERT_EFI_ERROR (Status);
    522 
    523   Status = gBS->OpenProtocol (
    524                       Handle,
    525                       &gEfiBlockIoProtocolGuid,
    526                       (VOID **) &BlockIoProtocol,
    527                       gImageHandle,
    528                       NULL,
    529                       EFI_OPEN_PROTOCOL_GET_PROTOCOL
    530                       );
    531   ASSERT_EFI_ERROR (Status);
    532 
    533   /* Read the header of boot image. */
    534   DataPtr = AllocateZeroPool (HIKEY_IO_BLOCK_SIZE * 2);
    535   ASSERT (DataPtr != 0);
    536   AlignedPtr = (VOID *)(((UINTN)DataPtr + HIKEY_IO_BLOCK_SIZE - 1) & ~(HIKEY_IO_BLOCK_SIZE - 1));
    537   InvalidateDataCacheRange (AlignedPtr, HIKEY_IO_BLOCK_SIZE);
    538   /* TODO: Update 0x7000 by LBA what is fetched from partition. */
    539   Status = BlockIoProtocol->ReadBlocks (BlockIoProtocol, BlockIoProtocol->Media->MediaId,
    540                                         0x7000, HIKEY_IO_BLOCK_SIZE, AlignedPtr);
    541   ASSERT_EFI_ERROR (Status);
    542   if (AsciiStrnCmp ((CHAR8 *)AlignedPtr, BOOT_MAGIC, BOOT_MAGIC_LENGTH) != 0) {
    543     /* It's debian boot image. */
    544     *DtbType = HIKEY_DTB_LINUX;
    545   } else {
    546     /* It's android boot image. */
    547     *DtbType = HIKEY_DTB_ANDROID;
    548   }
    549   FreePool (DataPtr);
    550   return Status;
    551 }
    552 
    553 STATIC
    554 BOOLEAN
    555 EFIAPI
    556 HiKeyIsSdBoot (
    557   IN struct HiKeyBootEntry    *Entry
    558   )
    559 {
    560   CHAR16                           *Path;
    561   EFI_DEVICE_PATH                  *DevicePath, *NextDevicePath;
    562   EFI_STATUS                        Status;
    563   EFI_HANDLE                        Handle;
    564   EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *FsProtocol;
    565   EFI_FILE_PROTOCOL                *Fs;
    566   EFI_FILE_INFO                    *FileInfo;
    567   EFI_FILE_PROTOCOL                *File;
    568   FILEPATH_DEVICE_PATH             *FilePathDevicePath;
    569   UINTN                             Index, Size;
    570   UINTN                             HandleCount;
    571   EFI_HANDLE                       *HandleBuffer;
    572   EFI_DEVICE_PATH_PROTOCOL         *DevicePathProtocol;
    573   BOOLEAN                           Found = FALSE, Result = FALSE;
    574 
    575   if (HiKeySDCardIsPresent () == FALSE)
    576     return FALSE;
    577   Path = Entry[HIKEY_BOOT_ENTRY_BOOT_SD].Path;
    578   ASSERT (Path != NULL);
    579 
    580   DevicePath = ConvertTextToDevicePath (Path);
    581   if (DevicePath == NULL) {
    582     DEBUG ((EFI_D_ERROR, "Warning: Couldn't get device path\n"));
    583     return FALSE;
    584   }
    585 
    586   /* Connect handles to drivers. Since simple filesystem driver is loaded later by default. */
    587   do {
    588     // Locate all the driver handles
    589     Status = gBS->LocateHandleBuffer (
    590                 AllHandles,
    591                 NULL,
    592                 NULL,
    593                 &HandleCount,
    594                 &HandleBuffer
    595                 );
    596     if (EFI_ERROR (Status)) {
    597       break;
    598     }
    599 
    600     // Connect every handles
    601     for (Index = 0; Index < HandleCount; Index++) {
    602       gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
    603     }
    604 
    605     if (HandleBuffer != NULL) {
    606       FreePool (HandleBuffer);
    607     }
    608 
    609     // Check if new handles have been created after the start of the previous handles
    610     Status = gDS->Dispatch ();
    611   } while (!EFI_ERROR(Status));
    612 
    613   // List all the Simple File System Protocols
    614   Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &HandleBuffer);
    615   if (EFI_ERROR (Status)) {
    616     DEBUG ((EFI_D_ERROR, "Warning: Failed to list all the simple filesystem protocols (status:%r)\n", Status));
    617     return FALSE;
    618   }
    619   for (Index = 0; Index < HandleCount; Index++) {
    620     Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol);
    621     if (EFI_ERROR(Status))
    622       continue;
    623     NextDevicePath = NextDevicePathNode (DevicePath);
    624     Size = (UINTN)NextDevicePath - (UINTN)DevicePath;
    625     if (Size <= GetDevicePathSize (DevicePath)) {
    626       if ((CompareMem (DevicePath, DevicePathProtocol, Size)) == 0) {
    627 	Found = TRUE;
    628         break;
    629       }
    630     }
    631   }
    632   if (!Found) {
    633     DEBUG ((EFI_D_ERROR, "Warning: Failed to find valid device path\n"));
    634     return FALSE;
    635   }
    636 
    637   Handle = HandleBuffer[Index];
    638   Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &DevicePath, &Handle);
    639   if (EFI_ERROR (Status)) {
    640     DEBUG ((EFI_D_ERROR, "Warning: Couldn't locate device (status: %r)\n", Status));
    641     return FALSE;
    642   }
    643   FilePathDevicePath = (FILEPATH_DEVICE_PATH*)DevicePath;
    644 
    645   Status = gBS->OpenProtocol (
    646                   Handle,
    647                   &gEfiSimpleFileSystemProtocolGuid,
    648                   (VOID**)&FsProtocol,
    649                   gImageHandle,
    650                   Handle,
    651                   EFI_OPEN_PROTOCOL_BY_DRIVER
    652                   );
    653   if (EFI_ERROR (Status)) {
    654     DEBUG ((EFI_D_ERROR, "Warning: Failedn't to mount as Simple Filrsystem (status: %r)\n", Status));
    655     return FALSE;
    656   }
    657   Status = FsProtocol->OpenVolume (FsProtocol, &Fs);
    658   if (EFI_ERROR (Status)) {
    659     goto CLOSE_PROTOCOL;
    660   }
    661 
    662   Status = Fs->Open (Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0);
    663   if (EFI_ERROR (Status)) {
    664     goto CLOSE_PROTOCOL;
    665   }
    666 
    667   Size = 0;
    668   File->GetInfo (File, &gEfiFileInfoGuid, &Size, NULL);
    669   FileInfo = AllocatePool (Size);
    670   Status = File->GetInfo (File, &gEfiFileInfoGuid, &Size, FileInfo);
    671   if (EFI_ERROR (Status)) {
    672     goto CLOSE_FILE;
    673   }
    674 
    675   // Get the file size
    676   Size = FileInfo->FileSize;
    677   FreePool (FileInfo);
    678   if (Size != 0) {
    679     Result = TRUE;
    680   }
    681 
    682 CLOSE_FILE:
    683   File->Close (File);
    684 CLOSE_PROTOCOL:
    685   gBS->CloseProtocol (
    686          Handle,
    687          &gEfiSimpleFileSystemProtocolGuid,
    688          gImageHandle,
    689          Handle);
    690   return Result;
    691 }
    692 
    693 STATIC
    694 EFI_STATUS
    695 EFIAPI
    696 HiKeyInstallFdt (
    697   VOID
    698   )
    699 {
    700   EFI_STATUS              Status;
    701   VOID                   *Image;
    702   UINTN                   ImageSize, NumPages;
    703   EFI_GUID               *Guid;
    704   EFI_PHYSICAL_ADDRESS    FdtConfigurationTableBase;
    705 
    706   Guid = &gHiKeyTokenSpaceGuid;
    707   Status = GetSectionFromAnyFv (Guid, EFI_SECTION_RAW, 0, &Image, &ImageSize);
    708   if (EFI_ERROR (Status))
    709     return Status;
    710   NumPages = EFI_SIZE_TO_PAGES (ImageSize);
    711   Status = gBS->AllocatePages (
    712 		  AllocateAnyPages, EfiRuntimeServicesData,
    713 		  NumPages, &FdtConfigurationTableBase
    714 		  );
    715   if (EFI_ERROR (Status))
    716     return Status;
    717   CopyMem ((VOID *)(UINTN)FdtConfigurationTableBase, Image, ImageSize);
    718   Status = gBS->InstallConfigurationTable (
    719 		  &gFdtTableGuid,
    720 		  (VOID *)(UINTN)FdtConfigurationTableBase
    721 		  );
    722   if (EFI_ERROR (Status)) {
    723     gBS->FreePages (FdtConfigurationTableBase, NumPages);
    724   }
    725   return Status;
    726 }
    727 
    728 STATIC
    729 VOID
    730 EFIAPI
    731 HiKeyOnEndOfDxe (
    732   EFI_EVENT                               Event,
    733   VOID                                    *Context
    734   )
    735 {
    736   EFI_STATUS          Status;
    737   UINTN               VariableSize;
    738   UINT16              AutoBoot, Count, Index;
    739   UINTN               DtbType;
    740   struct HiKeyBootEntry *Entry;
    741 
    742   VariableSize = sizeof (UINT16);
    743   Status = gRT->GetVariable (
    744                   (CHAR16 *)L"HiKeyAutoBoot",
    745                   &gHiKeyVariableGuid,
    746                   NULL,
    747                   &VariableSize,
    748                   (VOID*)&AutoBoot
    749                   );
    750   if (Status == EFI_NOT_FOUND) {
    751     AutoBoot = 1;
    752     Status = gRT->SetVariable (
    753                     (CHAR16*)L"HiKeyAutoBoot",
    754                     &gHiKeyVariableGuid,
    755                     EFI_VARIABLE_NON_VOLATILE       |
    756                     EFI_VARIABLE_BOOTSERVICE_ACCESS |
    757                     EFI_VARIABLE_RUNTIME_ACCESS,
    758                     sizeof (UINT16),
    759                     &AutoBoot
    760                     );
    761     ASSERT_EFI_ERROR (Status);
    762   } else if (EFI_ERROR (Status) == 0) {
    763     if (AutoBoot == 0) {
    764       // Select boot entry by manual.
    765       // Delete the BootNext environment variable
    766       gRT->SetVariable (L"BootNext",
    767              &gEfiGlobalVariableGuid,
    768              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    769              0,
    770              NULL);
    771       return;
    772     }
    773   }
    774 
    775   Status = HiKeyCheckEmmcDtbType (&DtbType);
    776   ASSERT_EFI_ERROR (Status);
    777 
    778   mBootCount = 0;
    779   mBootOrder = NULL;
    780 
    781   if (DtbType == HIKEY_DTB_LINUX) {
    782     Count = sizeof (LinuxEntries) / sizeof (struct HiKeyBootEntry);
    783     Entry = LinuxEntries;
    784   } else if (DtbType == HIKEY_DTB_ANDROID) {
    785     Count = sizeof (AndroidEntries) / sizeof (struct HiKeyBootEntry);
    786     Entry = AndroidEntries;
    787   } else {
    788     ASSERT (0);
    789   }
    790   ASSERT (HIKEY_DTB_SD < Count);
    791   if (HiKeyIsSdBoot (Entry) == TRUE)
    792     DtbType = HIKEY_DTB_SD;
    793 
    794   for (Index = 0; Index < Count; Index++) {
    795     Status = HiKeyCreateBootEntry (
    796                Entry->Path,
    797                Entry->Args,
    798                Entry->Description,
    799                Entry->LoadType
    800                );
    801     ASSERT_EFI_ERROR (Status);
    802     Entry++;
    803   }
    804 
    805   if ((mBootCount == 0) || (mBootCount >= MAX_BOOT_ENTRIES)) {
    806     DEBUG ((EFI_D_ERROR, "%a: can't create boot entries\n", __func__));
    807     return;
    808   }
    809 
    810   Status = HiKeyCreateBootOrder ();
    811   if (EFI_ERROR (Status)) {
    812     DEBUG ((EFI_D_ERROR, "%a: failed to set BootOrder variable\n", __func__));
    813     return;
    814   }
    815 
    816   if (DtbType == HIKEY_DTB_SD) {
    817     mBootIndex = HIKEY_BOOT_ENTRY_BOOT_SD;
    818   } else {
    819     mBootIndex = HIKEY_BOOT_ENTRY_BOOT_EMMC;
    820   }
    821 
    822   if (HiKeyGetUsbMode () == USB_DEVICE_MODE) {
    823     if (HiKeyIsJumperConnected () == TRUE)
    824       mBootIndex = HIKEY_BOOT_ENTRY_FASTBOOT;
    825     /* Set mBootIndex as HIKEY_BOOT_ENTRY_FASTBOOT if adb reboot-bootloader is specified */
    826     if (HiKeyDetectRebootReason () == TRUE)
    827       mBootIndex = HIKEY_BOOT_ENTRY_FASTBOOT;
    828   }
    829 
    830   Status = HiKeyCreateBootNext ();
    831   if (EFI_ERROR (Status)) {
    832     DEBUG ((EFI_D_ERROR, "%a: failed to set BootNext variable\n", __func__));
    833     return;
    834   }
    835 
    836   /*
    837    * Priority of Loading DTB file:
    838    *   1. Load configured DTB file in grub.cfg.
    839    *   2. Load DTB file in UEFI Fv.
    840    */
    841   /* Load DTB file in UEFI Fv. */
    842   Status = HiKeyInstallFdt ();
    843   if (EFI_ERROR (Status)) {
    844     DEBUG ((EFI_D_ERROR, "%a: failed to install Fdt file\n", __func__));
    845     return;
    846   }
    847 }
    848 
    849 EFI_STATUS
    850 HiKeyBootMenuInstall (
    851   IN VOID
    852   )
    853 {
    854   EFI_STATUS          Status;
    855   EFI_EVENT           EndOfDxeEvent;
    856 
    857   Status = gBS->CreateEventEx (
    858                   EVT_NOTIFY_SIGNAL,
    859                   TPL_CALLBACK,
    860                   HiKeyOnEndOfDxe,
    861                   &mIsEndOfDxeEvent,
    862                   &gEfiEndOfDxeEventGroupGuid,
    863                   &EndOfDxeEvent
    864                   );
    865   ASSERT_EFI_ERROR (Status);
    866   return Status;
    867 }
    868 
    869