summaryrefslogtreecommitdiff
path: root/HisiPkg/D01BoardPkg/Bds/BootOption.c
diff options
context:
space:
mode:
authorwei.xu <xuwei5@huawei.com>2014-04-24 20:43:55 +0800
committerWei Xu <xuwei5@huawei.com>2014-12-10 08:33:43 +0800
commit172269412ce362437c5c11b176707eedeb8eb683 (patch)
tree2211def6fd0a4241f3c9ddc3388ab2d738103010 /HisiPkg/D01BoardPkg/Bds/BootOption.c
parent71f02911b176657c1c8dc952f93a022719ea878a (diff)
HisiPkg: merge Hisilicon UEFI package
Signed-off-by: Wei Xu <xuwei5@huawei.com>
Diffstat (limited to 'HisiPkg/D01BoardPkg/Bds/BootOption.c')
-rw-r--r--HisiPkg/D01BoardPkg/Bds/BootOption.c414
1 files changed, 414 insertions, 0 deletions
diff --git a/HisiPkg/D01BoardPkg/Bds/BootOption.c b/HisiPkg/D01BoardPkg/Bds/BootOption.c
new file mode 100644
index 000000000..d677687f7
--- /dev/null
+++ b/HisiPkg/D01BoardPkg/Bds/BootOption.c
@@ -0,0 +1,414 @@
+/** @file
+*
+* Copyright (c) 2011-2012, ARM Limited. All rights reserved.
+* Copyright (c) Huawei Technologies Co., Ltd. 2013. 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 <Guid/ArmGlobalVariableHob.h>
+#include "BdsInternal.h"
+
+extern EFI_HANDLE mImageHandle;
+
+EFI_STATUS
+BootOptionStart (
+ IN BDS_LOAD_OPTION *BootOption
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL* EfiDevicePathFromTextProtocol;
+ UINT32 LoaderType;
+ ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
+ ARM_BDS_LINUX_ARGUMENTS* LinuxArguments;
+ EFI_DEVICE_PATH_PROTOCOL* FdtDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL* DefaultFdtDevicePath;
+ UINTN FdtDevicePathSize;
+ UINTN CmdLineSize;
+ UINTN InitrdSize;
+ EFI_DEVICE_PATH* Initrd;
+ UINTN FdtLocalSize;
+ UINT16 LoadOptionIndexSize;
+
+ if (IS_ARM_BDS_BOOTENTRY (BootOption)) {
+ Status = EFI_UNSUPPORTED;
+ OptionalData = BootOption->OptionalData;
+ LoaderType = ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);
+
+ if (LoaderType == BDS_LOADER_EFI_APPLICATION) {
+ // Need to connect every drivers to ensure no dependencies are missing for the application
+ BdsConnectAllDrivers();
+
+ Status = BdsStartEfiApplication (mImageHandle, BootOption->FilePathList, 0, NULL);
+ } else if (LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) {
+ LinuxArguments = &(OptionalData->Arguments.LinuxArguments);
+ CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);
+ InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize);
+
+ if (InitrdSize > 0) {
+ Initrd = GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize));
+ } else {
+ Initrd = NULL;
+ }
+
+ Status = BdsBootLinuxAtag (BootOption->FilePathList,
+ Initrd, // Initrd
+ (CHAR8*)(LinuxArguments + 1)); // CmdLine
+ } else if ((LoaderType == BDS_LOADER_KERNEL_LINUX_GLOBAL_FDT) || (LoaderType == BDS_LOADER_KERNEL_LINUX_LOCAL_FDT)) {
+ LinuxArguments = &(OptionalData->Arguments.LinuxArguments);
+ CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);
+ InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize);
+
+ if (InitrdSize > 0) {
+ Initrd = GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize));
+ } else {
+ Initrd = NULL;
+ }
+
+ if (LoaderType == BDS_LOADER_KERNEL_LINUX_LOCAL_FDT) {
+ FdtLocalSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->FdtLocalSize);
+
+ if (FdtLocalSize > 0) {
+ FdtDevicePath = GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize + InitrdSize));
+ } else {
+ FdtDevicePath = NULL;
+ }
+ } else {
+ // Get the default FDT device path
+ Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
+ ASSERT_EFI_ERROR(Status);
+ DefaultFdtDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdFdtDevicePath));
+
+ // Get the FDT device path
+ FdtDevicePathSize = GetDevicePathSize (DefaultFdtDevicePath);
+ Status = GetEnvironmentVariable ((CHAR16 *)L"Fdt", &gArmGlobalVariableGuid,
+ DefaultFdtDevicePath, &FdtDevicePathSize, (VOID **)&FdtDevicePath);
+ ASSERT_EFI_ERROR(Status);
+ FreePool (DefaultFdtDevicePath);
+ }
+ Status = BdsBootLinuxFdt (BootOption->FilePathList,
+ Initrd, // Initrd
+ (CHAR8*)(LinuxArguments + 1),
+ FdtDevicePath);
+
+ FreePool (FdtDevicePath);
+ }
+ } else {
+ // Set BootCurrent variable
+ LoadOptionIndexSize = sizeof(UINT16);
+ gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ LoadOptionIndexSize, &(BootOption->LoadOptionIndex));
+
+ Status = BdsStartEfiApplication (mImageHandle, BootOption->FilePathList, BootOption->OptionalDataSize, BootOption->OptionalData);
+
+ // Clear BootCurrent variable
+ LoadOptionIndexSize = sizeof(UINT16);
+ gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ 0, NULL);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+BootOptionList (
+ IN OUT LIST_ENTRY *BootOptionList
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT16* BootOrder;
+ UINTN BootOrderSize;
+ BDS_LOAD_OPTION* BdsLoadOption;
+ BDS_LOAD_OPTION_ENTRY* BdsLoadOptionEntry;
+
+ InitializeListHead (BootOptionList);
+
+ // Get the Boot Option Order from the environment variable
+ Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
+ Status = BootOptionFromLoadOptionIndex (BootOrder[Index], &BdsLoadOption);
+ if (!EFI_ERROR(Status)) {
+ BdsLoadOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool(sizeof(BDS_LOAD_OPTION_ENTRY));
+ BdsLoadOptionEntry->BdsLoadOption = BdsLoadOption;
+ InsertTailList (BootOptionList,&BdsLoadOptionEntry->Link);
+ }
+ }
+
+ FreePool (BootOrder);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+BootOptionSetFields (
+ IN BDS_LOAD_OPTION* BootOption,
+ IN UINT32 Attributes,
+ IN CHAR16* BootDescription,
+ IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
+ IN ARM_BDS_LOADER_TYPE BootType,
+ IN ARM_BDS_LOADER_ARGUMENTS* BootArguments
+ )
+{
+ EFI_LOAD_OPTION EfiLoadOption;
+ UINTN EfiLoadOptionSize;
+ UINTN BootDescriptionSize;
+ UINTN BootOptionalDataSize;
+ UINT16 FilePathListLength;
+ UINT8* EfiLoadOptionPtr;
+ UINT8* InitrdPathListPtr;
+ UINT8* FdtLocalPathListPtr;
+ UINTN OptionalDataSize;
+ ARM_BDS_LINUX_ARGUMENTS* DestLinuxArguments;
+ ARM_BDS_LINUX_ARGUMENTS* SrcLinuxArguments;
+
+ // If we are overwriting an existent Boot Option then we have to free previously allocated memory
+ if (BootOption->LoadOption) {
+ FreePool(BootOption->LoadOption);
+ }
+
+ BootDescriptionSize = StrSize (BootDescription);
+ BootOptionalDataSize = sizeof(ARM_BDS_LOADER_OPTIONAL_DATA_HEADER);
+ if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_GLOBAL_FDT) || (BootType == BDS_LOADER_KERNEL_LINUX_LOCAL_FDT)) {
+ BootOptionalDataSize += sizeof(ARM_BDS_LINUX_ARGUMENTS) + BootArguments->LinuxArguments.CmdLineSize + BootArguments->LinuxArguments.InitrdSize + BootArguments->LinuxArguments.FdtLocalSize;
+ }
+
+ // Compute the size of the FilePath list
+ FilePathListLength = GetUnalignedDevicePathSize (DevicePath);
+
+ // Allocate the memory for the EFI Load Option
+ EfiLoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + BootDescriptionSize + FilePathListLength + BootOptionalDataSize;
+ EfiLoadOption = (EFI_LOAD_OPTION)AllocatePool(EfiLoadOptionSize);
+ EfiLoadOptionPtr = EfiLoadOption;
+
+ //
+ // Populate the EFI Load Option and BDS Boot Option structures
+ //
+
+ // Attributes fields
+ BootOption->Attributes = Attributes;
+ *(UINT32*)EfiLoadOptionPtr = Attributes;
+ EfiLoadOptionPtr += sizeof(UINT32);
+
+ // FilePath List fields
+ BootOption->FilePathListLength = FilePathListLength;
+ *(UINT16*)EfiLoadOptionPtr = FilePathListLength;
+ EfiLoadOptionPtr += sizeof(UINT16);
+
+ // Boot description fields
+ BootOption->Description = (CHAR16*)EfiLoadOptionPtr;
+ CopyMem (EfiLoadOptionPtr, BootDescription, BootDescriptionSize);
+ EfiLoadOptionPtr += BootDescriptionSize;
+
+ // File path fields
+ BootOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)EfiLoadOptionPtr;
+ CopyMem (EfiLoadOptionPtr, DevicePath, FilePathListLength);
+ EfiLoadOptionPtr += FilePathListLength;
+
+ // Optional Data fields, Do unaligned writes
+ BootOption->OptionalData = EfiLoadOptionPtr;
+ WriteUnaligned32 ((UINT32 *)EfiLoadOptionPtr, ARM_BDS_OPTIONAL_DATA_SIGNATURE);
+ WriteUnaligned32 ((UINT32 *)(EfiLoadOptionPtr + 4), BootType);
+
+ OptionalDataSize = sizeof(ARM_BDS_LOADER_OPTIONAL_DATA_HEADER);
+
+ if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_GLOBAL_FDT) || (BootType == BDS_LOADER_KERNEL_LINUX_LOCAL_FDT)) {
+ SrcLinuxArguments = &(BootArguments->LinuxArguments);
+ DestLinuxArguments = &((ARM_BDS_LOADER_OPTIONAL_DATA*)EfiLoadOptionPtr)->Arguments.LinuxArguments;
+
+ WriteUnaligned16 ((UINT16 *)&(DestLinuxArguments->CmdLineSize), SrcLinuxArguments->CmdLineSize);
+ WriteUnaligned16 ((UINT16 *)&(DestLinuxArguments->InitrdSize), SrcLinuxArguments->InitrdSize);
+ WriteUnaligned16 ((UINT16 *)&(DestLinuxArguments->FdtLocalSize), SrcLinuxArguments->FdtLocalSize);
+ OptionalDataSize += sizeof (ARM_BDS_LINUX_ARGUMENTS);
+
+ if (SrcLinuxArguments->CmdLineSize > 0) {
+ CopyMem ((VOID*)(DestLinuxArguments + 1), (VOID*)(SrcLinuxArguments + 1), SrcLinuxArguments->CmdLineSize);
+ OptionalDataSize += SrcLinuxArguments->CmdLineSize;
+ }
+
+ if (SrcLinuxArguments->InitrdSize > 0) {
+ InitrdPathListPtr = (UINT8*)((UINTN)(DestLinuxArguments + 1) + SrcLinuxArguments->CmdLineSize);
+ CopyMem (InitrdPathListPtr, (VOID*)((UINTN)(SrcLinuxArguments + 1) + SrcLinuxArguments->CmdLineSize), SrcLinuxArguments->InitrdSize);
+ }
+
+ if (SrcLinuxArguments->FdtLocalSize > 0) {
+ FdtLocalPathListPtr = (UINT8*)((UINTN)(DestLinuxArguments + 1) + SrcLinuxArguments->CmdLineSize + SrcLinuxArguments->InitrdSize);
+ CopyMem (FdtLocalPathListPtr, (VOID*)((UINTN)(SrcLinuxArguments + 1) + SrcLinuxArguments->CmdLineSize + SrcLinuxArguments->InitrdSize), SrcLinuxArguments->FdtLocalSize);
+ }
+ }
+ BootOption->OptionalDataSize = OptionalDataSize;
+
+ // If this function is called at the creation of the Boot Device entry (not at the update) the
+ // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
+ if (BootOption->LoadOptionSize == 0) {
+ BootOption->LoadOptionIndex = BootOptionAllocateBootIndex ();
+ }
+
+ // Fill the EFI Load option fields
+ BootOption->LoadOption = EfiLoadOption;
+ BootOption->LoadOptionSize = EfiLoadOptionSize;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+BootOptionCreate (
+ IN UINT32 Attributes,
+ IN CHAR16* BootDescription,
+ IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
+ IN ARM_BDS_LOADER_TYPE BootType,
+ IN ARM_BDS_LOADER_ARGUMENTS* BootArguments,
+ OUT BDS_LOAD_OPTION** BdsLoadOption
+ )
+{
+ EFI_STATUS Status;
+ BDS_LOAD_OPTION_ENTRY* BootOptionEntry;
+ BDS_LOAD_OPTION* BootOption;
+ CHAR16 BootVariableName[9];
+ UINT16* BootOrder;
+ UINTN BootOrderSize;
+
+ //
+ // Allocate and fill the memory for the BDS Load Option structure
+ //
+ BootOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool (sizeof (BDS_LOAD_OPTION_ENTRY));
+ InitializeListHead (&BootOptionEntry->Link);
+ BootOptionEntry->BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
+
+ BootOption = BootOptionEntry->BdsLoadOption;
+ BootOptionSetFields (BootOption, Attributes, BootDescription, DevicePath, BootType, BootArguments);
+
+ //
+ // Set the related environment variables
+ //
+
+ // Create Boot#### environment variable
+ UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);
+ Status = gRT->SetVariable (
+ BootVariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ BootOption->LoadOptionSize,
+ BootOption->LoadOption
+ );
+
+ // Add the new Boot Index to the list
+ Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
+ if (!EFI_ERROR(Status)) {
+ BootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof(UINT16), BootOrder);
+ // Add the new index at the end
+ BootOrder[BootOrderSize / sizeof(UINT16)] = BootOption->LoadOptionIndex;
+ BootOrderSize += sizeof(UINT16);
+ } else {
+ // BootOrder does not exist. Create it
+ BootOrderSize = sizeof(UINT16);
+ BootOrder = &(BootOption->LoadOptionIndex);
+ }
+
+ // Update (or Create) the BootOrder environment variable
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ BootOrderSize,
+ BootOrder
+ );
+
+ // We only free it if the UEFI Variable 'BootOrder' was already existing
+ if (BootOrderSize > sizeof(UINT16)) {
+ FreePool (BootOrder);
+ }
+
+ *BdsLoadOption = BootOption;
+ return Status;
+}
+
+EFI_STATUS
+BootOptionUpdate (
+ IN BDS_LOAD_OPTION* BdsLoadOption,
+ IN UINT32 Attributes,
+ IN CHAR16* BootDescription,
+ IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
+ IN ARM_BDS_LOADER_TYPE BootType,
+ IN ARM_BDS_LOADER_ARGUMENTS* BootArguments
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 BootVariableName[9];
+
+ // Update the BDS Load Option structure
+ BootOptionSetFields (BdsLoadOption, Attributes, BootDescription, DevicePath, BootType, BootArguments);
+
+ // Update the related environment variables
+ UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BdsLoadOption->LoadOptionIndex);
+
+ Status = gRT->SetVariable (
+ BootVariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ BdsLoadOption->LoadOptionSize,
+ BdsLoadOption->LoadOption
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+BootOptionDelete (
+ IN BDS_LOAD_OPTION *BootOption
+ )
+{
+ UINTN Index;
+ UINTN BootOrderSize;
+ UINT16* BootOrder;
+ UINTN BootOrderCount;
+ EFI_STATUS Status;
+
+ // Remove the entry from the BootOrder environment variable
+ Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
+ if (!EFI_ERROR(Status)) {
+ BootOrderCount = BootOrderSize / sizeof(UINT16);
+
+ // Find the index of the removed entry
+ for (Index = 0; Index < BootOrderCount; Index++) {
+ if (BootOrder[Index] == BootOption->LoadOptionIndex) {
+ // If it the last entry we do not need to rearrange the BootOrder list
+ if (Index + 1 != BootOrderCount) {
+ CopyMem (
+ &BootOrder[Index],
+ &BootOrder[Index + 1],
+ (BootOrderCount - (Index + 1)) * sizeof(UINT16)
+ );
+ }
+ break;
+ }
+ }
+
+ // Update the BootOrder environment variable
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ BootOrderSize - sizeof(UINT16),
+ BootOrder
+ );
+ }
+
+ FreePool (BootOrder);
+
+ return EFI_SUCCESS;
+}