summaryrefslogtreecommitdiff
path: root/ArmPlatformPkg/Bds/BootOption.c
diff options
context:
space:
mode:
authoroliviermartin <oliviermartin@6f19259b-4bc3-4df7-8a09-765794883524>2011-06-11 11:58:23 +0000
committeroliviermartin <oliviermartin@6f19259b-4bc3-4df7-8a09-765794883524>2011-06-11 11:58:23 +0000
commitea46ebbe6a5a579ff341071a13ae625e15edae64 (patch)
tree81c578dd645ee737ad63614288fb43d67613ceb8 /ArmPlatformPkg/Bds/BootOption.c
parenta355a3654f0af22db9f68d988dbb4c72b835f414 (diff)
downloadedk2-platforms-ea46ebbe6a5a579ff341071a13ae625e15edae64.tar.xz
ArmPlatformPkg/Bds: Upgrade the BDS to be more conformed to the UEFI Specification
The UEFI Specification defines some requirement related to the Boot Manager. This new version of the BDS support most of the features: - TimeOut, BootNext, BootOrder, Boot### environment variable for boot device selection - ConOut. ConIn, ConErr environment variables for console intialization - Boot EFI application defined by a Device Path - Support removable devices - Support FileSystem, MemMap, PXE and TFTP boot devices git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11800 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'ArmPlatformPkg/Bds/BootOption.c')
-rw-r--r--ArmPlatformPkg/Bds/BootOption.c407
1 files changed, 407 insertions, 0 deletions
diff --git a/ArmPlatformPkg/Bds/BootOption.c b/ArmPlatformPkg/Bds/BootOption.c
new file mode 100644
index 0000000000..a8ba23fe73
--- /dev/null
+++ b/ArmPlatformPkg/Bds/BootOption.c
@@ -0,0 +1,407 @@
+/** @file
+*
+* Copyright (c) 2011, ARM Limited. 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 "BdsInternal.h"
+
+extern EFI_HANDLE mImageHandle;
+
+EFI_STATUS
+BootOptionStart (
+ IN BDS_LOAD_OPTION *BootOption
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH* FdtDevicePath;
+ EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *EfiDevicePathFromTextProtocol;
+
+ Status = EFI_UNSUPPORTED;
+
+ if (BootOption->OptionalData->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);
+ } else if (BootOption->OptionalData->LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) {
+ Status = BdsBootLinux (BootOption->FilePathList, BootOption->OptionalData->Arguments, NULL);
+ } else if (BootOption->OptionalData->LoaderType == BDS_LOADER_KERNEL_LINUX_FDT) {
+ // Convert the FDT path into a Device Path
+ Status = gBS->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid, NULL, (VOID **)&EfiDevicePathFromTextProtocol);
+ ASSERT_EFI_ERROR(Status);
+ FdtDevicePath = EfiDevicePathFromTextProtocol->ConvertTextToDevicePath ((CHAR16*)PcdGetPtr(PcdFdtDevicePath));
+
+ Status = BdsBootLinux (BootOption->FilePathList, BootOption->OptionalData->Arguments, FdtDevicePath);
+ FreePool(FdtDevicePath);
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+BootOptionParseLoadOption (
+ IN EFI_LOAD_OPTION EfiLoadOption,
+ IN UINTN EfiLoadOptionSize,
+ OUT BDS_LOAD_OPTION **BdsLoadOption
+ )
+{
+ BDS_LOAD_OPTION *LoadOption;
+ UINTN FilePathListLength;
+ UINTN DescriptionLength;
+
+ if (EfiLoadOption == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (EfiLoadOptionSize < sizeof(UINT32) + sizeof(UINT16) + sizeof(CHAR16) + sizeof(EFI_DEVICE_PATH_PROTOCOL)) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ LoadOption = (BDS_LOAD_OPTION*)AllocatePool(sizeof(BDS_LOAD_OPTION));
+ if (LoadOption == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ LoadOption->LoadOption = EfiLoadOption;
+ LoadOption->LoadOptionSize = EfiLoadOptionSize;
+
+ LoadOption->Attributes = *(UINT32*)EfiLoadOption;
+ 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)((UINT8*)LoadOption->FilePathList + FilePathListLength - EfiLoadOption) == EfiLoadOptionSize) {
+ LoadOption->OptionalData = NULL;
+ } else {
+ LoadOption->OptionalData = (BDS_LOADER_OPTIONAL_DATA *)((UINT8*)LoadOption->FilePathList + FilePathListLength);
+ }
+
+ *BdsLoadOption = LoadOption;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+BootOptionFromLoadOptionVariable (
+ IN UINT16 LoadOptionIndex,
+ OUT BDS_LOAD_OPTION **BdsLoadOption
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 BootVariableName[9];
+ EFI_LOAD_OPTION EfiLoadOption;
+ UINTN EfiLoadOptionSize;
+
+ UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", LoadOptionIndex);
+
+ Status = GetEnvironmentVariable (BootVariableName, NULL, &EfiLoadOptionSize, (VOID**)&EfiLoadOption);
+ if (!EFI_ERROR(Status)) {
+ Status = BootOptionParseLoadOption (EfiLoadOption,EfiLoadOptionSize,BdsLoadOption);
+ if (!EFI_ERROR(Status)) {
+ (*BdsLoadOption)->LoadOptionIndex = LoadOptionIndex;
+ }
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+BootOptionList (
+ IN OUT LIST_ENTRY *BootOptionList
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT16 *BootOrder;
+ UINTN BootOrderSize;
+ BDS_LOAD_OPTION *BdsLoadOption;
+
+ InitializeListHead (BootOptionList);
+
+ // Get the Boot Option Order from the environment variable
+ Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
+ Status = BootOptionFromLoadOptionVariable (BootOrder[Index],&BdsLoadOption);
+ if (!EFI_ERROR(Status)) {
+ InsertTailList (BootOptionList,&BdsLoadOption->Link);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+UINT16
+BootOptionAllocateBootIndex (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT32 BootIndex;
+ UINT16 *BootOrder;
+ UINTN BootOrderSize;
+ BOOLEAN Found;
+
+ // Get the Boot Option Order from the environment variable
+ Status = GetEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
+ if (!EFI_ERROR(Status)) {
+ for (BootIndex = 0; BootIndex <= 0xFFFF; BootIndex++) {
+ Found = FALSE;
+ for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
+ if (BootOrder[Index] == BootIndex) {
+ Found = TRUE;
+ break;
+ }
+ }
+ if (!Found) {
+ return BootIndex;
+ }
+ }
+ }
+ // Return the first index
+ return 0;
+}
+
+STATIC
+EFI_STATUS
+BootOptionSetFields (
+ IN BDS_LOAD_OPTION *BootOption,
+ IN UINT32 Attributes,
+ IN CHAR16* BootDescription,
+ IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
+ IN BDS_LOADER_TYPE BootType,
+ IN CHAR8* BootArguments
+ )
+{
+ EFI_LOAD_OPTION EfiLoadOption;
+ UINTN EfiLoadOptionSize;
+ UINTN BootDescriptionSize;
+ UINTN BootOptionalDataSize;
+ UINT16 FilePathListLength;
+ EFI_DEVICE_PATH_PROTOCOL* DevicePathNode;
+ UINTN NodeLength;
+ UINT8* EfiLoadOptionPtr;
+
+ // 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(BDS_LOADER_OPTIONAL_DATA) +
+ (BootArguments == NULL ? 0 : AsciiStrSize(BootArguments));
+
+ // Compute the size of the FilePath list
+ FilePathListLength = 0;
+ DevicePathNode = DevicePath;
+ while (!IsDevicePathEndType (DevicePathNode)) {
+ FilePathListLength += DevicePathNodeLength (DevicePathNode);
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+ // Add the length of the DevicePath EndType
+ FilePathListLength += DevicePathNodeLength (DevicePathNode);
+
+ // 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;
+ DevicePathNode = DevicePath;
+ while (!IsDevicePathEndType (DevicePathNode)) {
+ NodeLength = DevicePathNodeLength(DevicePathNode);
+ CopyMem (EfiLoadOptionPtr, DevicePathNode, NodeLength);
+ EfiLoadOptionPtr += NodeLength;
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+
+ // Set the End Device Path Type
+ SetDevicePathEndNode (EfiLoadOptionPtr);
+ EfiLoadOptionPtr = (UINT8 *)EfiLoadOptionPtr + sizeof(EFI_DEVICE_PATH);
+
+ // Optional Data fields, Do unaligned writes
+ WriteUnaligned32 ((UINT32 *)EfiLoadOptionPtr, BootType);
+
+ CopyMem (&((BDS_LOADER_OPTIONAL_DATA*)EfiLoadOptionPtr)->Arguments, BootArguments, AsciiStrSize(BootArguments));
+ BootOption->OptionalData = (BDS_LOADER_OPTIONAL_DATA *)EfiLoadOptionPtr;
+
+ // Fill the EFI Load option fields
+ BootOption->LoadOptionIndex = BootOptionAllocateBootIndex();
+ 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 BDS_LOADER_TYPE BootType,
+ IN CHAR8* BootArguments,
+ OUT BDS_LOAD_OPTION **BdsLoadOption
+ )
+{
+ EFI_STATUS Status;
+ BDS_LOAD_OPTION *BootOption;
+ CHAR16 BootVariableName[9];
+ UINT16 *BootOrder;
+ UINTN BootOrderSize;
+
+ //
+ // Allocate and fill the memory for the BDS Load Option structure
+ //
+ BootOption = (BDS_LOAD_OPTION*)AllocateZeroPool(sizeof(BDS_LOAD_OPTION));
+
+ InitializeListHead (&BootOption->Link);
+ 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 = GetEnvironmentVariable (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
+ );
+
+ *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 BDS_LOADER_TYPE BootType,
+ IN CHAR8* BootArguments
+ )
+{
+ EFI_STATUS Status;
+ BDS_LOAD_OPTION *BootOption;
+ 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", BootOption->LoadOptionIndex);
+ Status = gRT->SetVariable (
+ BootVariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ BootOption->LoadOptionSize,
+ BootOption->LoadOption
+ );
+
+ return Status;
+}
+
+EFI_STATUS
+BootOptionDelete (
+ IN BDS_LOAD_OPTION *BootOption
+ )
+{
+ UINTN Index;
+ UINTN BootOrderSize;
+ UINT16* BootOrder;
+ UINTN BootOrderCount;
+ EFI_STATUS Status;
+
+ // If the Boot Optiono was attached to a list remove it
+ if (!IsListEmpty (&BootOption->Link)) {
+ // Remove the entry from the list
+ RemoveEntryList (&BootOption->Link);
+ }
+
+ // Remove the entry from the BootOrder environment variable
+ Status = GetEnvironmentVariable (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));
+ }
+ 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
+ );
+ }
+
+ return EFI_SUCCESS;
+}