2011-06-11 13:58:23 +02:00
|
|
|
/** @file
|
|
|
|
*
|
2015-07-14 16:35:20 +02:00
|
|
|
* Copyright (c) 2011-2015, ARM Limited. All rights reserved.
|
2011-06-11 13:58:23 +02:00
|
|
|
*
|
|
|
|
* 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"
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
BootOptionStart (
|
|
|
|
IN BDS_LOAD_OPTION *BootOption
|
|
|
|
)
|
|
|
|
{
|
2015-07-14 16:36:49 +02:00
|
|
|
EFI_STATUS Status;
|
|
|
|
UINT16 LoadOptionIndexSize;
|
2014-04-11 13:02:59 +02:00
|
|
|
|
2015-07-14 16:36:49 +02:00
|
|
|
// Connect all the drivers if the EFI Application is not a EFI OS Loader
|
|
|
|
if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_APP) {
|
|
|
|
BdsConnectAllDrivers ();
|
|
|
|
}
|
2012-02-09 16:34:16 +01:00
|
|
|
|
2015-07-14 16:36:49 +02:00
|
|
|
// Set BootCurrent variable
|
|
|
|
LoadOptionIndexSize = sizeof (UINT16);
|
|
|
|
gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,
|
|
|
|
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
|
|
LoadOptionIndexSize, &(BootOption->LoadOptionIndex));
|
2012-02-09 16:34:16 +01:00
|
|
|
|
2015-07-14 16:36:49 +02:00
|
|
|
Status = BdsStartEfiApplication (gImageHandle, 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);
|
2011-06-11 13:58:23 +02:00
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
BootOptionList (
|
|
|
|
IN OUT LIST_ENTRY *BootOptionList
|
|
|
|
)
|
|
|
|
{
|
2011-09-09 12:52:31 +02:00
|
|
|
EFI_STATUS Status;
|
|
|
|
UINTN Index;
|
|
|
|
UINT16* BootOrder;
|
|
|
|
UINTN BootOrderSize;
|
|
|
|
BDS_LOAD_OPTION* BdsLoadOption;
|
|
|
|
BDS_LOAD_OPTION_ENTRY* BdsLoadOptionEntry;
|
2011-06-11 13:58:23 +02:00
|
|
|
|
|
|
|
InitializeListHead (BootOptionList);
|
|
|
|
|
|
|
|
// Get the Boot Option Order from the environment variable
|
2013-03-12 01:42:59 +01:00
|
|
|
Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
|
2011-06-11 13:58:23 +02:00
|
|
|
if (EFI_ERROR(Status)) {
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
|
2011-09-09 12:54:33 +02:00
|
|
|
Status = BootOptionFromLoadOptionIndex (BootOrder[Index], &BdsLoadOption);
|
2011-06-11 13:58:23 +02:00
|
|
|
if (!EFI_ERROR(Status)) {
|
2011-09-09 12:52:31 +02:00
|
|
|
BdsLoadOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool(sizeof(BDS_LOAD_OPTION_ENTRY));
|
|
|
|
BdsLoadOptionEntry->BdsLoadOption = BdsLoadOption;
|
|
|
|
InsertTailList (BootOptionList,&BdsLoadOptionEntry->Link);
|
2011-06-11 13:58:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-09 16:29:35 +01:00
|
|
|
FreePool (BootOrder);
|
|
|
|
|
2011-06-11 13:58:23 +02:00
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC
|
|
|
|
EFI_STATUS
|
|
|
|
BootOptionSetFields (
|
2011-06-28 13:55:11 +02:00
|
|
|
IN BDS_LOAD_OPTION* BootOption,
|
|
|
|
IN UINT32 Attributes,
|
|
|
|
IN CHAR16* BootDescription,
|
|
|
|
IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
|
2014-04-11 12:56:02 +02:00
|
|
|
IN UINT8* OptionalData,
|
|
|
|
IN UINTN OptionalDataSize
|
2011-06-11 13:58:23 +02:00
|
|
|
)
|
|
|
|
{
|
2015-05-11 19:37:24 +02:00
|
|
|
EFI_LOAD_OPTION *EfiLoadOption;
|
2011-09-09 12:51:13 +02:00
|
|
|
UINTN EfiLoadOptionSize;
|
|
|
|
UINTN BootDescriptionSize;
|
|
|
|
UINT16 FilePathListLength;
|
|
|
|
UINT8* EfiLoadOptionPtr;
|
2011-06-11 13:58:23 +02:00
|
|
|
|
|
|
|
// If we are overwriting an existent Boot Option then we have to free previously allocated memory
|
|
|
|
if (BootOption->LoadOption) {
|
2014-04-11 12:56:02 +02:00
|
|
|
FreePool (BootOption->LoadOption);
|
2011-06-11 13:58:23 +02:00
|
|
|
}
|
|
|
|
|
2011-09-09 12:51:13 +02:00
|
|
|
BootDescriptionSize = StrSize (BootDescription);
|
2014-04-11 12:56:02 +02:00
|
|
|
|
2011-06-11 13:58:23 +02:00
|
|
|
// Compute the size of the FilePath list
|
2011-09-09 12:51:13 +02:00
|
|
|
FilePathListLength = GetUnalignedDevicePathSize (DevicePath);
|
2011-08-18 15:21:14 +02:00
|
|
|
|
2011-06-11 13:58:23 +02:00
|
|
|
// Allocate the memory for the EFI Load Option
|
2014-04-11 12:56:02 +02:00
|
|
|
EfiLoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + BootDescriptionSize + FilePathListLength + OptionalDataSize;
|
2015-05-11 19:37:24 +02:00
|
|
|
EfiLoadOption = (EFI_LOAD_OPTION *)AllocatePool(EfiLoadOptionSize);
|
|
|
|
EfiLoadOptionPtr = (UINT8 *)EfiLoadOption;
|
2011-06-11 13:58:23 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// 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;
|
2011-09-09 12:51:13 +02:00
|
|
|
CopyMem (EfiLoadOptionPtr, DevicePath, FilePathListLength);
|
|
|
|
EfiLoadOptionPtr += FilePathListLength;
|
2011-06-11 13:58:23 +02:00
|
|
|
|
|
|
|
// Optional Data fields, Do unaligned writes
|
2011-09-09 12:51:13 +02:00
|
|
|
BootOption->OptionalData = EfiLoadOptionPtr;
|
2011-06-11 13:58:23 +02:00
|
|
|
|
2015-07-14 16:36:49 +02:00
|
|
|
if (OptionalData != NULL) {
|
|
|
|
CopyMem (BootOption->OptionalData, OptionalData, OptionalDataSize);
|
2011-08-18 15:21:14 +02:00
|
|
|
}
|
2015-07-14 16:36:49 +02:00
|
|
|
|
2011-09-09 12:51:13 +02:00
|
|
|
BootOption->OptionalDataSize = OptionalDataSize;
|
|
|
|
|
2011-06-15 21:56:50 +02:00
|
|
|
// 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) {
|
2011-09-09 12:51:13 +02:00
|
|
|
BootOption->LoadOptionIndex = BootOptionAllocateBootIndex ();
|
2011-06-15 21:56:50 +02:00
|
|
|
}
|
|
|
|
|
2011-06-11 13:58:23 +02:00
|
|
|
// Fill the EFI Load option fields
|
|
|
|
BootOption->LoadOption = EfiLoadOption;
|
|
|
|
BootOption->LoadOptionSize = EfiLoadOptionSize;
|
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
BootOptionCreate (
|
2011-06-28 13:55:11 +02:00
|
|
|
IN UINT32 Attributes,
|
|
|
|
IN CHAR16* BootDescription,
|
2011-06-11 13:58:23 +02:00
|
|
|
IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
|
2014-04-11 12:56:02 +02:00
|
|
|
IN UINT8* OptionalData,
|
|
|
|
IN UINTN OptionalDataSize,
|
2011-09-09 12:52:31 +02:00
|
|
|
OUT BDS_LOAD_OPTION** BdsLoadOption
|
2011-06-11 13:58:23 +02:00
|
|
|
)
|
|
|
|
{
|
2011-09-09 12:52:31 +02:00
|
|
|
EFI_STATUS Status;
|
|
|
|
BDS_LOAD_OPTION_ENTRY* BootOptionEntry;
|
|
|
|
BDS_LOAD_OPTION* BootOption;
|
|
|
|
CHAR16 BootVariableName[9];
|
|
|
|
UINT16* BootOrder;
|
|
|
|
UINTN BootOrderSize;
|
2011-06-11 13:58:23 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// Allocate and fill the memory for the BDS Load Option structure
|
|
|
|
//
|
2011-09-09 12:52:31 +02:00
|
|
|
BootOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool (sizeof (BDS_LOAD_OPTION_ENTRY));
|
|
|
|
InitializeListHead (&BootOptionEntry->Link);
|
|
|
|
BootOptionEntry->BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
|
2011-06-11 13:58:23 +02:00
|
|
|
|
2011-09-09 12:52:31 +02:00
|
|
|
BootOption = BootOptionEntry->BdsLoadOption;
|
2015-07-14 16:36:49 +02:00
|
|
|
BootOptionSetFields (BootOption, Attributes, BootDescription, DevicePath, OptionalData, OptionalDataSize);
|
2011-06-11 13:58:23 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// 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
|
2013-03-12 01:42:59 +01:00
|
|
|
Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
|
2011-06-11 13:58:23 +02:00
|
|
|
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
|
|
|
|
);
|
|
|
|
|
2012-02-09 16:29:35 +01:00
|
|
|
// We only free it if the UEFI Variable 'BootOrder' was already existing
|
|
|
|
if (BootOrderSize > sizeof(UINT16)) {
|
|
|
|
FreePool (BootOrder);
|
|
|
|
}
|
|
|
|
|
2011-06-11 13:58:23 +02:00
|
|
|
*BdsLoadOption = BootOption;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
BootOptionUpdate (
|
2011-09-09 12:51:13 +02:00
|
|
|
IN BDS_LOAD_OPTION* BdsLoadOption,
|
|
|
|
IN UINT32 Attributes,
|
|
|
|
IN CHAR16* BootDescription,
|
2011-06-11 13:58:23 +02:00
|
|
|
IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
|
2014-04-11 12:56:02 +02:00
|
|
|
IN UINT8* OptionalData,
|
|
|
|
IN UINTN OptionalDataSize
|
2011-06-11 13:58:23 +02:00
|
|
|
)
|
|
|
|
{
|
|
|
|
EFI_STATUS Status;
|
|
|
|
CHAR16 BootVariableName[9];
|
|
|
|
|
|
|
|
// Update the BDS Load Option structure
|
2015-07-14 16:36:49 +02:00
|
|
|
BootOptionSetFields (BdsLoadOption, Attributes, BootDescription, DevicePath, OptionalData, OptionalDataSize);
|
2011-06-11 13:58:23 +02:00
|
|
|
|
|
|
|
// Update the related environment variables
|
2011-06-15 21:56:50 +02:00
|
|
|
UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BdsLoadOption->LoadOptionIndex);
|
|
|
|
|
2011-06-11 13:58:23 +02:00
|
|
|
Status = gRT->SetVariable (
|
|
|
|
BootVariableName,
|
|
|
|
&gEfiGlobalVariableGuid,
|
|
|
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
2011-06-15 21:56:50 +02:00
|
|
|
BdsLoadOption->LoadOptionSize,
|
|
|
|
BdsLoadOption->LoadOption
|
2011-06-11 13:58:23 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
EFI_STATUS
|
|
|
|
BootOptionDelete (
|
|
|
|
IN BDS_LOAD_OPTION *BootOption
|
|
|
|
)
|
|
|
|
{
|
2011-09-09 12:52:31 +02:00
|
|
|
UINTN Index;
|
|
|
|
UINTN BootOrderSize;
|
|
|
|
UINT16* BootOrder;
|
|
|
|
UINTN BootOrderCount;
|
2014-09-09 17:58:33 +02:00
|
|
|
CHAR16 BootVariableName[9];
|
2011-09-09 12:52:31 +02:00
|
|
|
EFI_STATUS Status;
|
2011-06-11 13:58:23 +02:00
|
|
|
|
|
|
|
// Remove the entry from the BootOrder environment variable
|
2013-03-12 01:42:59 +01:00
|
|
|
Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
|
2011-06-11 13:58:23 +02:00
|
|
|
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) {
|
2013-01-25 12:50:59 +01:00
|
|
|
CopyMem (
|
|
|
|
&BootOrder[Index],
|
|
|
|
&BootOrder[Index + 1],
|
|
|
|
(BootOrderCount - (Index + 1)) * sizeof(UINT16)
|
|
|
|
);
|
2011-06-11 13:58:23 +02:00
|
|
|
}
|
|
|
|
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
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2014-09-09 17:58:33 +02:00
|
|
|
// Delete 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,
|
|
|
|
0,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
|
2012-02-09 16:29:35 +01:00
|
|
|
FreePool (BootOrder);
|
|
|
|
|
2014-09-09 17:58:33 +02:00
|
|
|
return Status;
|
2011-06-11 13:58:23 +02:00
|
|
|
}
|