| /** @file |
| * |
| * Copyright (c) 2015, Linaro Ltd. All rights reserved. |
| * Copyright (c) 2015, Hisilicon Ltd. 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 <Library/BaseMemoryLib.h> |
| #include <Library/BdsLib.h> |
| #include <Library/CacheMaintenanceLib.h> |
| #include <Library/DevicePathLib.h> |
| #include <Library/IoLib.h> |
| #include <Library/MemoryAllocationLib.h> |
| #include <Library/PrintLib.h> |
| #include <Library/UefiBootServicesTableLib.h> |
| #include <Library/UefiLib.h> |
| #include <Library/UefiRuntimeServicesTableLib.h> |
| |
| #include <Protocol/BlockIo.h> |
| #include <Protocol/DevicePathFromText.h> |
| #include <Protocol/DevicePathToText.h> |
| #include <Protocol/EmbeddedGpio.h> |
| #include <Protocol/SimpleFileSystem.h> |
| |
| #include <Guid/Fdt.h> |
| #include <Guid/FileInfo.h> |
| #include <Guid/EventGroup.h> |
| #include <Guid/GlobalVariable.h> |
| #include <Guid/HiKeyVariable.h> |
| #include <Guid/VariableFormat.h> |
| |
| #include "HiKeyDxeInternal.h" |
| |
| typedef enum { |
| HIKEY_DTB_ANDROID = 0, /* DTB is attached at the end of boot.img */ |
| HIKEY_DTB_LINUX = 1, /* DTB is in partition */ |
| HIKEY_DTB_SD = 2, /* DTB is already in SD Card */ |
| } HiKeyDtbType; |
| |
| #define HIKEY_IO_BLOCK_SIZE 512 |
| |
| #define MAX_BOOT_ENTRIES 16 |
| // Jumper on pin5-6 of J15 determines whether boot to fastboot |
| #define DETECT_J15_FASTBOOT 24 // GPIO 3_0 |
| |
| #define USER_LED1 32 // GPIO 4_0 |
| #define USER_LED2 33 // GPIO 4_1 |
| #define USER_LED3 34 // GPIO 4_2 |
| #define USER_LED4 35 // GPIO 4_3 |
| |
| struct HiKeyBootEntry { |
| CHAR16 *Path; |
| CHAR16 *Args; |
| CHAR16 *Description; |
| UINT16 LoadType; |
| }; |
| |
| STATIC CONST BOOLEAN mIsEndOfDxeEvent = TRUE; |
| STATIC UINT16 *mBootOrder = NULL; |
| STATIC UINT16 mBootCount = 0; |
| STATIC UINT16 mBootIndex = 0; |
| |
| #define HIKEY_BOOT_ENTRY_FASTBOOT 0 |
| #define HIKEY_BOOT_ENTRY_BOOT_EMMC 1 /* boot from eMMC */ |
| #define HIKEY_BOOT_ENTRY_BOOT_SD 2 /* boot from SD card */ |
| |
| STATIC struct HiKeyBootEntry LinuxEntries[] = { |
| [HIKEY_BOOT_ENTRY_FASTBOOT] = { |
| L"FvFile(9588502a-5370-11e3-8631-d7c5951364c8)", |
| //L"VenHw(B549F005-4BD4-4020-A0CB-06F42BDA68C3)/HD(6,GPT,5C0F213C-17E1-4149-88C8-8B50FB4EC70E,0x7000,0x20000)/\\EFI\\BOOT\\FASTBOOT.EFI", |
| NULL, |
| L"fastboot", |
| LOAD_OPTION_CATEGORY_APP |
| }, |
| [HIKEY_BOOT_ENTRY_BOOT_EMMC] = { |
| L"VenHw(B549F005-4BD4-4020-A0CB-06F42BDA68C3)/HD(6,GPT,5C0F213C-17E1-4149-88C8-8B50FB4EC70E,0x7000,0x20000)/\\EFI\\BOOT\\GRUBAA64.EFI", |
| NULL, |
| L"boot from eMMC", |
| LOAD_OPTION_CATEGORY_APP |
| }, |
| [HIKEY_BOOT_ENTRY_BOOT_SD] = { |
| L"VenHw(594BFE73-5E18-4F12-8119-19DB8C5FC849)/HD(1,MBR,0x00000000,0x3F,0x21FC0)/Image", |
| L"dtb=hi6220-hikey.dtb console=ttyAMA3,115200 earlycon=pl011,0xf7113000 root=/dev/mmcblk1p2 rw rootwait initrd=initrd.img efi=noruntime", |
| L"boot from SD card", |
| LOAD_OPTION_CATEGORY_BOOT |
| } |
| }; |
| |
| STATIC struct HiKeyBootEntry AndroidEntries[] = { |
| [HIKEY_BOOT_ENTRY_FASTBOOT] = { |
| L"FvFile(9588502a-5370-11e3-8631-d7c5951364c8)", |
| //L"VenHw(B549F005-4BD4-4020-A0CB-06F42BDA68C3)/HD(6,GPT,5C0F213C-17E1-4149-88C8-8B50FB4EC70E,0x7000,0x20000)/\\EFI\\BOOT\\FASTBOOT.EFI", |
| NULL, |
| L"fastboot", |
| LOAD_OPTION_CATEGORY_APP |
| }, |
| [HIKEY_BOOT_ENTRY_BOOT_EMMC] = { |
| L"VenHw(B549F005-4BD4-4020-A0CB-06F42BDA68C3)/HD(6,GPT,5C0F213C-17E1-4149-88C8-8B50FB4EC70E,0x7000,0x20000)/Offset(0x0000,0x20000)", |
| L"console=ttyAMA3,115200 earlycon=pl011,0xf7113000 root=/dev/mmcblk0p9 rw rootwait efi=noruntime", |
| L"boot from eMMC", |
| LOAD_OPTION_CATEGORY_BOOT |
| }, |
| [HIKEY_BOOT_ENTRY_BOOT_SD] = { |
| L"VenHw(594BFE73-5E18-4F12-8119-19DB8C5FC849)/HD(1,MBR,0x00000000,0x3F,0x21FC0)/Image", |
| L"dtb=hi6220-hikey.dtb console=ttyAMA3,115200 earlycon=pl011,0xf7113000 root=/dev/mmcblk1p2 rw rootwait initrd=initrd.img efi=noruntime", |
| L"boot from SD card", |
| LOAD_OPTION_CATEGORY_BOOT |
| } |
| }; |
| |
| |
| STATIC |
| BOOLEAN |
| EFIAPI |
| HiKeyVerifyBootEntry ( |
| IN CHAR16 *BootVariableName, |
| IN CHAR16 *BootDevicePathText, |
| IN CHAR16 *BootArgs, |
| IN CHAR16 *BootDescription, |
| IN UINT16 LoadOptionAttr |
| ) |
| { |
| EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevicePathToTextProtocol; |
| CHAR16 *DevicePathText; |
| UINTN EfiLoadOptionSize; |
| EFI_LOAD_OPTION *EfiLoadOption; |
| BDS_LOAD_OPTION *LoadOption; |
| EFI_STATUS Status; |
| UINTN DescriptionLength; |
| |
| Status = GetGlobalEnvironmentVariable (BootVariableName, NULL, &EfiLoadOptionSize, (VOID**)&EfiLoadOption); |
| if (EFI_ERROR (Status)) { |
| return FALSE; |
| } |
| if (EfiLoadOption == NULL) { |
| return FALSE; |
| } |
| if (EfiLoadOptionSize < sizeof(UINT32) + sizeof(UINT16) + sizeof(CHAR16) + sizeof(EFI_DEVICE_PATH_PROTOCOL)) { |
| return FALSE; |
| } |
| LoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION)); |
| if (LoadOption == NULL) { |
| return FALSE; |
| } |
| |
| LoadOption->LoadOption = EfiLoadOption; |
| LoadOption->Attributes = *(UINT32*)EfiLoadOption; |
| LoadOption->FilePathListLength = *(UINT16*)(EfiLoadOption + sizeof(UINT32)); |
| LoadOption->Description = (CHAR16*)(EfiLoadOption + sizeof(UINT32) + sizeof(UINT16)); |
| DescriptionLength = StrSize (LoadOption->Description); |
| LoadOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)(EfiLoadOption + sizeof(UINT32) + sizeof(UINT16) + DescriptionLength); |
| if ((UINTN)((UINTN)LoadOption->FilePathList + LoadOption->FilePathListLength - (UINTN)EfiLoadOption) == EfiLoadOptionSize) { |
| LoadOption->OptionalData = NULL; |
| LoadOption->OptionalDataSize = 0; |
| } else { |
| LoadOption->OptionalData = (VOID*)((UINTN)(LoadOption->FilePathList) + LoadOption->FilePathListLength); |
| LoadOption->OptionalDataSize = EfiLoadOptionSize - ((UINTN)LoadOption->OptionalData - (UINTN)EfiLoadOption); |
| } |
| |
| if (((BootArgs == NULL) && (LoadOption->OptionalDataSize)) || |
| (BootArgs && (LoadOption->OptionalDataSize == 0))) { |
| return FALSE; |
| } else if (BootArgs && LoadOption->OptionalDataSize) { |
| if (StrCmp (BootArgs, LoadOption->OptionalData) != 0) |
| return FALSE; |
| } |
| if ((LoadOption->Description == NULL) || (BootDescription == NULL)) { |
| return FALSE; |
| } |
| if (StrCmp (BootDescription, LoadOption->Description) != 0) { |
| return FALSE; |
| } |
| if ((LoadOption->Attributes & LOAD_OPTION_CATEGORY) != (LoadOptionAttr & LOAD_OPTION_CATEGORY)) { |
| return FALSE; |
| } |
| |
| Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol); |
| ASSERT_EFI_ERROR(Status); |
| DevicePathText = DevicePathToTextProtocol->ConvertDevicePathToText(LoadOption->FilePathList, TRUE, TRUE); |
| if (StrCmp (DevicePathText, BootDevicePathText) != 0) { |
| return FALSE; |
| } |
| |
| FreePool (LoadOption); |
| return TRUE; |
| } |
| |
| STATIC |
| EFI_STATUS |
| EFIAPI |
| HiKeyCreateBootEntry ( |
| IN CHAR16 *DevicePathText, |
| IN CHAR16 *BootArgs, |
| IN CHAR16 *BootDescription, |
| IN UINT16 LoadOption |
| ) |
| { |
| BDS_LOAD_OPTION *BdsLoadOption; |
| EFI_STATUS Status; |
| UINTN DescriptionSize; |
| UINTN BootOrderSize; |
| CHAR16 BootVariableName[9]; |
| UINT8 *EfiLoadOptionPtr; |
| EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; |
| UINTN NodeLength; |
| EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *DevicePathFromTextProtocol; |
| |
| if ((DevicePathText == NULL) || (BootDescription == NULL)) { |
| DEBUG ((EFI_D_ERROR, "%a: Invalid Parameters\n", __func__)); |
| return EFI_INVALID_PARAMETER; |
| } |
| |
| UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", mBootCount); |
| if (HiKeyVerifyBootEntry (BootVariableName, DevicePathText, BootArgs, BootDescription, LoadOption) == TRUE) { |
| // The boot entry is already created. |
| Status = EFI_SUCCESS; |
| goto done; |
| } |
| |
| BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION)); |
| ASSERT (BdsLoadOption != NULL); |
| |
| Status = gBS->LocateProtocol ( |
| &gEfiDevicePathFromTextProtocolGuid, |
| NULL, |
| (VOID**)&DevicePathFromTextProtocol |
| ); |
| ASSERT_EFI_ERROR(Status); |
| |
| BdsLoadOption->FilePathList = DevicePathFromTextProtocol->ConvertTextToDevicePath (DevicePathText); |
| ASSERT (BdsLoadOption->FilePathList != NULL); |
| BdsLoadOption->FilePathListLength = GetDevicePathSize (BdsLoadOption->FilePathList); |
| BdsLoadOption->Attributes = LOAD_OPTION_ACTIVE | (LoadOption & LOAD_OPTION_CATEGORY); |
| |
| if (BootArgs) { |
| /* Always force the BootArgs to save 512 characters. */ |
| ASSERT (StrSize(BootArgs) <= 512); |
| BdsLoadOption->OptionalDataSize = 512; |
| BdsLoadOption->OptionalData = (CHAR16*)AllocateZeroPool (BdsLoadOption->OptionalDataSize); |
| ASSERT (BdsLoadOption->OptionalData != NULL); |
| StrCpy (BdsLoadOption->OptionalData, BootArgs); |
| } |
| |
| BdsLoadOption->LoadOptionIndex = mBootCount; |
| DescriptionSize = StrSize (BootDescription); |
| BdsLoadOption->Description = (VOID*)AllocateZeroPool (DescriptionSize); |
| StrCpy (BdsLoadOption->Description, BootDescription); |
| |
| BdsLoadOption->LoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + DescriptionSize + BdsLoadOption->FilePathListLength + BdsLoadOption->OptionalDataSize; |
| BdsLoadOption->LoadOption = (EFI_LOAD_OPTION*)AllocateZeroPool (BdsLoadOption->LoadOptionSize); |
| ASSERT (BdsLoadOption->LoadOption != NULL); |
| |
| EfiLoadOptionPtr = (VOID*)BdsLoadOption->LoadOption; |
| |
| // |
| // Populate the EFI Load Option and BDS Boot Option structures |
| // |
| |
| // Attributes fields |
| *(UINT32*)EfiLoadOptionPtr = BdsLoadOption->Attributes; |
| EfiLoadOptionPtr += sizeof(UINT32); |
| |
| // FilePath List fields |
| *(UINT16*)EfiLoadOptionPtr = BdsLoadOption->FilePathListLength; |
| EfiLoadOptionPtr += sizeof(UINT16); |
| |
| // Boot description fields |
| CopyMem (EfiLoadOptionPtr, BdsLoadOption->Description, DescriptionSize); |
| EfiLoadOptionPtr += DescriptionSize; |
| |
| // File path fields |
| DevicePathNode = BdsLoadOption->FilePathList; |
| while (!IsDevicePathEndType (DevicePathNode)) { |
| NodeLength = DevicePathNodeLength(DevicePathNode); |
| CopyMem (EfiLoadOptionPtr, DevicePathNode, NodeLength); |
| EfiLoadOptionPtr += NodeLength; |
| DevicePathNode = NextDevicePathNode (DevicePathNode); |
| } |
| |
| // Set the End Device Path Type |
| SetDevicePathEndNode (EfiLoadOptionPtr); |
| EfiLoadOptionPtr += sizeof(EFI_DEVICE_PATH); |
| |
| // Fill the Optional Data |
| if (BdsLoadOption->OptionalDataSize > 0) { |
| CopyMem (EfiLoadOptionPtr, BdsLoadOption->OptionalData, BdsLoadOption->OptionalDataSize); |
| } |
| |
| Status = gRT->SetVariable ( |
| BootVariableName, |
| &gEfiGlobalVariableGuid, |
| EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, |
| BdsLoadOption->LoadOptionSize, |
| BdsLoadOption->LoadOption |
| ); |
| if (EFI_ERROR (Status)) { |
| DEBUG ((EFI_D_ERROR, "%a: failed to set BootVariable\n", __func__)); |
| return Status; |
| } |
| |
| done: |
| BootOrderSize = mBootCount * sizeof (UINT16); |
| mBootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof (UINT16), mBootOrder); |
| mBootOrder[mBootCount] = mBootCount; |
| mBootCount++; |
| return Status; |
| } |
| |
| STATIC |
| EFI_STATUS |
| EFIAPI |
| HiKeyCreateBootOrder ( |
| IN VOID |
| ) |
| { |
| UINT16 *BootOrder; |
| UINTN BootOrderSize; |
| UINTN Index; |
| EFI_STATUS Status; |
| |
| Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder); |
| if (EFI_ERROR(Status) == 0) { |
| if (BootOrderSize == mBootCount) { |
| for (Index = 0; Index < mBootCount; Index++) { |
| if (BootOrder[Index] != mBootOrder[Index]) { |
| break; |
| } |
| } |
| if (Index == mBootCount) { |
| // Found BootOrder variable with expected value. |
| return EFI_SUCCESS; |
| } |
| } |
| } |
| |
| Status = gRT->SetVariable ( |
| (CHAR16*)L"BootOrder", |
| &gEfiGlobalVariableGuid, |
| EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, |
| mBootCount * sizeof(UINT16), |
| mBootOrder |
| ); |
| return Status; |
| } |
| |
| STATIC |
| EFI_STATUS |
| EFIAPI |
| HiKeyCreateBootNext ( |
| IN VOID |
| ) |
| { |
| EFI_STATUS Status; |
| UINT16 *BootNext; |
| UINTN BootNextSize; |
| |
| BootNextSize = sizeof(UINT16); |
| Status = GetGlobalEnvironmentVariable (L"BootNext", NULL, &BootNextSize, (VOID**)&BootNext); |
| if (EFI_ERROR(Status) == 0) { |
| if (BootNextSize == sizeof (UINT16)) { |
| if (*BootNext == mBootOrder[mBootIndex]) { |
| // Found the BootNext variable with expected value. |
| return EFI_SUCCESS; |
| } |
| } |
| } |
| BootNext = &mBootOrder[mBootIndex]; |
| Status = gRT->SetVariable ( |
| (CHAR16*)L"BootNext", |
| &gEfiGlobalVariableGuid, |
| EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, |
| sizeof (UINT16), |
| BootNext |
| ); |
| return Status; |
| } |
| |
| STATIC |
| VOID |
| EFIAPI |
| HiKeyTestLed ( |
| IN EMBEDDED_GPIO *Gpio |
| ) |
| { |
| EFI_STATUS Status; |
| |
| Status = Gpio->Set (Gpio, USER_LED1, GPIO_MODE_OUTPUT_0); |
| if (EFI_ERROR (Status)) { |
| DEBUG ((EFI_D_ERROR, "%a: failed to set LED1\n", __func__)); |
| return; |
| } |
| Status = Gpio->Set (Gpio, USER_LED2, GPIO_MODE_OUTPUT_1); |
| if (EFI_ERROR (Status)) { |
| DEBUG ((EFI_D_ERROR, "%a: failed to set LED2\n", __func__)); |
| return; |
| } |
| Status = Gpio->Set (Gpio, USER_LED3, GPIO_MODE_OUTPUT_0); |
| if (EFI_ERROR (Status)) { |
| DEBUG ((EFI_D_ERROR, "%a: failed to set LED3\n", __func__)); |
| return; |
| } |
| Status = Gpio->Set (Gpio, USER_LED4, GPIO_MODE_OUTPUT_1); |
| if (EFI_ERROR (Status)) { |
| DEBUG ((EFI_D_ERROR, "%a: failed to set LED4\n", __func__)); |
| return; |
| } |
| } |
| |
| |
| #define REBOOT_REASON_ADDR 0x05F01000 |
| #define REBOOT_REASON_BOOTLOADER 0x77665500 |
| #define REBOOT_REASON_NONE 0x77665501 |
| STATIC |
| BOOLEAN |
| EFIAPI |
| HiKeyDetectRebootReason ( |
| IN VOID |
| ) |
| { |
| UINT32 *addr = (UINT32*)REBOOT_REASON_ADDR; |
| UINT32 val; |
| |
| val = *addr; |
| /* Write NONE to the reason address to clear the state */ |
| *addr = REBOOT_REASON_NONE; |
| /* Check to see if "reboot booloader" was specified */ |
| if (val == REBOOT_REASON_BOOTLOADER) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| STATIC |
| BOOLEAN |
| EFIAPI |
| HiKeyIsJumperConnected ( |
| IN VOID |
| ) |
| { |
| EMBEDDED_GPIO *Gpio; |
| EFI_STATUS Status; |
| UINTN Value; |
| |
| Status = gBS->LocateProtocol (&gEmbeddedGpioProtocolGuid, NULL, (VOID **)&Gpio); |
| ASSERT_EFI_ERROR (Status); |
| |
| Status = Gpio->Set (Gpio, DETECT_J15_FASTBOOT, GPIO_MODE_INPUT); |
| if (EFI_ERROR (Status)) { |
| DEBUG ((EFI_D_ERROR, "%a: failed to set jumper as gpio input\n", __func__)); |
| return FALSE; |
| } |
| Status = Gpio->Get (Gpio, DETECT_J15_FASTBOOT, &Value); |
| if (EFI_ERROR (Status)) { |
| DEBUG ((EFI_D_ERROR, "%a: failed to get value from jumper\n", __func__)); |
| return FALSE; |
| } |
| |
| HiKeyTestLed (Gpio); |
| if (Value != 0) |
| return FALSE; |
| return TRUE; |
| } |
| |
| STATIC |
| BOOLEAN |
| EFIAPI |
| HiKeySDCardIsPresent ( |
| IN VOID |
| ) |
| { |
| UINT32 Value; |
| |
| /* |
| * FIXME |
| * At first, reading GPIO pin shouldn't exist in SD driver. We need to |
| * add some callbacks to handle settings for hardware platform. |
| * In the second, reading GPIO pin should be based on GPIO driver. Now |
| * GPIO driver could only be used for one PL061 gpio controller. And it's |
| * used to detect jumper setting. As a workaround, we have to read the gpio |
| * register instead at here. |
| * |
| */ |
| Value = MmioRead32 (0xf8012000 + (1 << 2)); |
| if (Value) |
| return FALSE; |
| return TRUE; |
| } |
| |
| #define BOOT_MAGIC "ANDROID!" |
| #define BOOT_MAGIC_LENGTH sizeof (BOOT_MAGIC) - 1 |
| |
| /* |
| * Check which boot type is valid for eMMC. |
| */ |
| STATIC |
| EFI_STATUS |
| EFIAPI |
| HiKeyCheckEmmcDtbType ( |
| OUT UINTN *DtbType |
| ) |
| { |
| EFI_DEVICE_PATH_PROTOCOL *BlockDevicePath; |
| EFI_BLOCK_IO_PROTOCOL *BlockIoProtocol; |
| EFI_HANDLE Handle; |
| EFI_STATUS Status; |
| VOID *DataPtr, *AlignedPtr; |
| |
| /* Check boot image */ |
| BlockDevicePath = ConvertTextToDevicePath ((CHAR16*)FixedPcdGetPtr (PcdBootImagePath)); |
| Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &BlockDevicePath, &Handle); |
| ASSERT_EFI_ERROR (Status); |
| |
| Status = gBS->OpenProtocol ( |
| Handle, |
| &gEfiBlockIoProtocolGuid, |
| (VOID **) &BlockIoProtocol, |
| gImageHandle, |
| NULL, |
| EFI_OPEN_PROTOCOL_GET_PROTOCOL |
| ); |
| ASSERT_EFI_ERROR (Status); |
| |
| /* Read the header of boot image. */ |
| DataPtr = AllocateZeroPool (HIKEY_IO_BLOCK_SIZE * 2); |
| ASSERT (DataPtr != 0); |
| AlignedPtr = (VOID *)(((UINTN)DataPtr + HIKEY_IO_BLOCK_SIZE - 1) & ~(HIKEY_IO_BLOCK_SIZE - 1)); |
| InvalidateDataCacheRange (AlignedPtr, HIKEY_IO_BLOCK_SIZE); |
| /* TODO: Update 0x7000 by LBA what is fetched from partition. */ |
| Status = BlockIoProtocol->ReadBlocks (BlockIoProtocol, BlockIoProtocol->Media->MediaId, |
| 0x7000, HIKEY_IO_BLOCK_SIZE, AlignedPtr); |
| ASSERT_EFI_ERROR (Status); |
| if (AsciiStrnCmp ((CHAR8 *)AlignedPtr, BOOT_MAGIC, BOOT_MAGIC_LENGTH) != 0) { |
| /* It's debian boot image. */ |
| *DtbType = HIKEY_DTB_LINUX; |
| } else { |
| /* It's android boot image. */ |
| *DtbType = HIKEY_DTB_ANDROID; |
| } |
| FreePool (DataPtr); |
| return Status; |
| } |
| |
| STATIC |
| BOOLEAN |
| EFIAPI |
| HiKeyIsSdBoot ( |
| IN struct HiKeyBootEntry *Entry |
| ) |
| { |
| CHAR16 *Path; |
| EFI_DEVICE_PATH *DevicePath, *NextDevicePath; |
| EFI_STATUS Status; |
| EFI_HANDLE Handle; |
| EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FsProtocol; |
| EFI_FILE_PROTOCOL *Fs; |
| EFI_FILE_INFO *FileInfo; |
| EFI_FILE_PROTOCOL *File; |
| FILEPATH_DEVICE_PATH *FilePathDevicePath; |
| UINTN Index, Size; |
| UINTN HandleCount; |
| EFI_HANDLE *HandleBuffer; |
| EFI_DEVICE_PATH_PROTOCOL *DevicePathProtocol; |
| BOOLEAN Found = FALSE, Result = FALSE; |
| |
| if (HiKeySDCardIsPresent () == FALSE) |
| return FALSE; |
| Path = Entry[HIKEY_BOOT_ENTRY_BOOT_SD].Path; |
| ASSERT (Path != NULL); |
| |
| DevicePath = ConvertTextToDevicePath (Path); |
| if (DevicePath == NULL) { |
| DEBUG ((EFI_D_ERROR, "Warning: Couldn't get device path\n")); |
| return FALSE; |
| } |
| |
| /* Connect handles to drivers. Since simple filesystem driver is loaded later by default. */ |
| do { |
| // Locate all the driver handles |
| Status = gBS->LocateHandleBuffer ( |
| AllHandles, |
| NULL, |
| NULL, |
| &HandleCount, |
| &HandleBuffer |
| ); |
| if (EFI_ERROR (Status)) { |
| break; |
| } |
| |
| // Connect every handles |
| for (Index = 0; Index < HandleCount; Index++) { |
| gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE); |
| } |
| |
| if (HandleBuffer != NULL) { |
| FreePool (HandleBuffer); |
| } |
| |
| // Check if new handles have been created after the start of the previous handles |
| Status = gDS->Dispatch (); |
| } while (!EFI_ERROR(Status)); |
| |
| // List all the Simple File System Protocols |
| Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &HandleBuffer); |
| if (EFI_ERROR (Status)) { |
| DEBUG ((EFI_D_ERROR, "Warning: Failed to list all the simple filesystem protocols (status:%r)\n", Status)); |
| return FALSE; |
| } |
| for (Index = 0; Index < HandleCount; Index++) { |
| Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID **)&DevicePathProtocol); |
| if (EFI_ERROR(Status)) |
| continue; |
| NextDevicePath = NextDevicePathNode (DevicePath); |
| Size = (UINTN)NextDevicePath - (UINTN)DevicePath; |
| if (Size <= GetDevicePathSize (DevicePath)) { |
| if ((CompareMem (DevicePath, DevicePathProtocol, Size)) == 0) { |
| Found = TRUE; |
| break; |
| } |
| } |
| } |
| if (!Found) { |
| DEBUG ((EFI_D_ERROR, "Warning: Failed to find valid device path\n")); |
| return FALSE; |
| } |
| |
| Handle = HandleBuffer[Index]; |
| Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &DevicePath, &Handle); |
| if (EFI_ERROR (Status)) { |
| DEBUG ((EFI_D_ERROR, "Warning: Couldn't locate device (status: %r)\n", Status)); |
| return FALSE; |
| } |
| FilePathDevicePath = (FILEPATH_DEVICE_PATH*)DevicePath; |
| |
| Status = gBS->OpenProtocol ( |
| Handle, |
| &gEfiSimpleFileSystemProtocolGuid, |
| (VOID**)&FsProtocol, |
| gImageHandle, |
| Handle, |
| EFI_OPEN_PROTOCOL_BY_DRIVER |
| ); |
| if (EFI_ERROR (Status)) { |
| DEBUG ((EFI_D_ERROR, "Warning: Failedn't to mount as Simple Filrsystem (status: %r)\n", Status)); |
| return FALSE; |
| } |
| Status = FsProtocol->OpenVolume (FsProtocol, &Fs); |
| if (EFI_ERROR (Status)) { |
| goto CLOSE_PROTOCOL; |
| } |
| |
| Status = Fs->Open (Fs, &File, FilePathDevicePath->PathName, EFI_FILE_MODE_READ, 0); |
| if (EFI_ERROR (Status)) { |
| goto CLOSE_PROTOCOL; |
| } |
| |
| Size = 0; |
| File->GetInfo (File, &gEfiFileInfoGuid, &Size, NULL); |
| FileInfo = AllocatePool (Size); |
| Status = File->GetInfo (File, &gEfiFileInfoGuid, &Size, FileInfo); |
| if (EFI_ERROR (Status)) { |
| goto CLOSE_FILE; |
| } |
| |
| // Get the file size |
| Size = FileInfo->FileSize; |
| FreePool (FileInfo); |
| if (Size != 0) { |
| Result = TRUE; |
| } |
| |
| CLOSE_FILE: |
| File->Close (File); |
| CLOSE_PROTOCOL: |
| gBS->CloseProtocol ( |
| Handle, |
| &gEfiSimpleFileSystemProtocolGuid, |
| gImageHandle, |
| Handle); |
| return Result; |
| } |
| |
| STATIC |
| VOID |
| EFIAPI |
| HiKeyOnEndOfDxe ( |
| EFI_EVENT Event, |
| VOID *Context |
| ) |
| { |
| EFI_STATUS Status; |
| UINTN VariableSize; |
| UINT16 AutoBoot, Count, Index; |
| UINTN DtbType; |
| struct HiKeyBootEntry *Entry; |
| |
| VariableSize = sizeof (UINT16); |
| Status = gRT->GetVariable ( |
| (CHAR16 *)L"HiKeyAutoBoot", |
| &gHiKeyVariableGuid, |
| NULL, |
| &VariableSize, |
| (VOID*)&AutoBoot |
| ); |
| if (Status == EFI_NOT_FOUND) { |
| AutoBoot = 1; |
| Status = gRT->SetVariable ( |
| (CHAR16*)L"HiKeyAutoBoot", |
| &gHiKeyVariableGuid, |
| EFI_VARIABLE_NON_VOLATILE | |
| EFI_VARIABLE_BOOTSERVICE_ACCESS | |
| EFI_VARIABLE_RUNTIME_ACCESS, |
| sizeof (UINT16), |
| &AutoBoot |
| ); |
| ASSERT_EFI_ERROR (Status); |
| } else if (EFI_ERROR (Status) == 0) { |
| if (AutoBoot == 0) { |
| // Select boot entry by manual. |
| // Delete the BootNext environment variable |
| gRT->SetVariable (L"BootNext", |
| &gEfiGlobalVariableGuid, |
| EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, |
| 0, |
| NULL); |
| return; |
| } |
| } |
| |
| Status = HiKeyCheckEmmcDtbType (&DtbType); |
| ASSERT_EFI_ERROR (Status); |
| |
| mBootCount = 0; |
| mBootOrder = NULL; |
| |
| if (DtbType == HIKEY_DTB_LINUX) { |
| Count = sizeof (LinuxEntries) / sizeof (struct HiKeyBootEntry); |
| Entry = LinuxEntries; |
| } else if (DtbType == HIKEY_DTB_ANDROID) { |
| Count = sizeof (AndroidEntries) / sizeof (struct HiKeyBootEntry); |
| Entry = AndroidEntries; |
| } else { |
| ASSERT (0); |
| } |
| ASSERT (HIKEY_DTB_SD < Count); |
| if (HiKeyIsSdBoot (Entry) == TRUE) |
| DtbType = HIKEY_DTB_SD; |
| |
| for (Index = 0; Index < Count; Index++) { |
| Status = HiKeyCreateBootEntry ( |
| Entry->Path, |
| Entry->Args, |
| Entry->Description, |
| Entry->LoadType |
| ); |
| ASSERT_EFI_ERROR (Status); |
| Entry++; |
| } |
| |
| if ((mBootCount == 0) || (mBootCount >= MAX_BOOT_ENTRIES)) { |
| DEBUG ((EFI_D_ERROR, "%a: can't create boot entries\n", __func__)); |
| return; |
| } |
| |
| Status = HiKeyCreateBootOrder (); |
| if (EFI_ERROR (Status)) { |
| DEBUG ((EFI_D_ERROR, "%a: failed to set BootOrder variable\n", __func__)); |
| return; |
| } |
| |
| if (DtbType == HIKEY_DTB_SD) |
| mBootIndex = HIKEY_BOOT_ENTRY_BOOT_SD; |
| else |
| mBootIndex = HIKEY_BOOT_ENTRY_BOOT_EMMC; |
| |
| if (HiKeyIsJumperConnected () == TRUE) |
| mBootIndex = HIKEY_BOOT_ENTRY_FASTBOOT; |
| /* Set mBootIndex as HIKEY_BOOT_ENTRY_FASTBOOT if adb reboot-bootloader is specified */ |
| if (HiKeyDetectRebootReason () == TRUE) |
| mBootIndex = HIKEY_BOOT_ENTRY_FASTBOOT; |
| |
| Status = HiKeyCreateBootNext (); |
| if (EFI_ERROR (Status)) { |
| DEBUG ((EFI_D_ERROR, "%a: failed to set BootNext variable\n", __func__)); |
| return; |
| } |
| } |
| |
| EFI_STATUS |
| HiKeyBootMenuInstall ( |
| IN VOID |
| ) |
| { |
| EFI_STATUS Status; |
| EFI_EVENT EndOfDxeEvent; |
| |
| Status = gBS->CreateEventEx ( |
| EVT_NOTIFY_SIGNAL, |
| TPL_CALLBACK, |
| HiKeyOnEndOfDxe, |
| &mIsEndOfDxeEvent, |
| &gEfiEndOfDxeEventGroupGuid, |
| &EndOfDxeEvent |
| ); |
| ASSERT_EFI_ERROR (Status); |
| return Status; |
| } |
| |