// Load Option Type
//
typedef enum {
- LoadOptionTypeBoot,
LoadOptionTypeDriver,
+ LoadOptionTypeSysPrep,
+ LoadOptionTypeBoot,
LoadOptionTypeMax
} EFI_BOOT_MANAGER_LOAD_OPTION_TYPE;
EFI_DEVICE_PATH_PROTOCOL *FilePath; // Load Option Device Path
UINT8 *OptionalData; // Load Option optional data to pass into image
UINT32 OptionalDataSize; // Load Option size of OptionalData
+ EFI_GUID VendorGuid;
//
// Used at runtime
);
/**
- This function will update the Boot####/Driver#### and the BootOrder/DriverOrder
- to add a new load option.
+ This function will update the Boot####/Driver####/SysPrep#### and the
+ BootOrder/DriverOrder/SysPrepOrder to add a new load option.
@param Option Pointer to load option to add.
- @param Position Position of the new load option to put in the BootOrder/DriverOrder.
+ @param Position Position of the new load option to put in the BootOrder/DriverOrder/SysPrepOrder.
@retval EFI_SUCCESS The load option has been successfully added.
@retval Others Error status returned by RT->SetVariable.
/**
This function will create all handles associate with every device
path node. If the handle associate with one device path node can not
- be created successfully, then still give one chance to do the dispatch,
+ be created successfully, then still give chance to do the dispatch,
which load the missing drivers if possible.
- @param DevicePathToConnect The device path which will be connected, it CANNOT be
+ @param DevicePathToConnect The device path which will be connected, it can be
a multi-instance device path
@param MatchingHandle Return the controller handle closest to the DevicePathToConnect
- @retval EFI_INVALID_PARAMETER DevicePathToConnect is NULL.
- @retval EFI_NOT_FOUND Failed to create all handles associate with every device path node.
- @retval EFI_SUCCESS Successful to create all handles associate with every device path node.
-
+ @retval EFI_SUCCESS All handles associate with every device path node
+ have been created.
+ @retval EFI_OUT_OF_RESOURCES There is no resource to create new handles.
+ @retval EFI_NOT_FOUND Create the handle associate with one device path
+ node failed.
+ @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI device
+ drivers on the DevicePath.
**/
EFI_STATUS
EFIAPI
/**
This function will connect all the console devices base on the console
device variable ConIn, ConOut and ErrOut.
+
+ @retval EFI_DEVICE_ERROR All the consoles were not connected due to an error.
+ @retval EFI_SUCCESS Success connect any one instance of the console
+ device path base on the variable ConVarName.
**/
-VOID
+EFI_STATUS
EFIAPI
EfiBootManagerConnectAllDefaultConsoles (
VOID
UINTN Count
);
+/**
+ Process (load and execute) the load option.
+
+ @param LoadOption Pointer to the load option.
+
+ @retval EFI_INVALID_PARAMETER The load option type is invalid,
+ or the load option file path doesn't point to a valid file.
+ @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot.
+ @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerProcessLoadOption (
+ EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
+ );
#endif
**/
BM_BOOT_TYPE
-BmBootTypeFromDevicePath (
+BmDevicePathType (
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
)
{
return BmMiscBoot;
}
-/**
- Free old buffer and reuse the pointer to return new buffer.
-
- @param Orig Pointer to the old buffer.
- @param New Pointer to the new buffer.
-**/
-VOID
-BmFreeAndSet (
- VOID **Orig,
- VOID *New
- )
-{
- FreePool (*Orig);
- *Orig = New;
-}
-
/**
Find the boot option in the NV storage and return the option number.
EFI_STATUS Status;
EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
UINTN OptionNumber;
- CHAR16 OptionName[sizeof ("Boot####")];
+ CHAR16 OptionName[BM_OPTION_NAME_LEN];
EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
UINTN BootOptionCount;
UINTN Index;
// Try to match the variable exactly if the option number is assigned
//
if (OptionToFind->OptionNumber != LoadOptionNumberUnassigned) {
- UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionToFind->OptionNumber);
+ UnicodeSPrint (
+ OptionName, sizeof (OptionName), L"%s%04x",
+ mBmLoadOptionName[OptionToFind->OptionType], OptionToFind->OptionNumber
+ );
Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);
if (!EFI_ERROR (Status)) {
}
/**
- According to a file guild, check a Fv file device path is valid. If it is invalid,
- try to return the valid device path.
- FV address maybe changes for memory layout adjust from time to time, use this function
- could promise the Fv file device path is right.
+ Get the file buffer using a Memory Mapped Device Path.
+
+ FV address may change across reboot. This routine promises the FV file device path is right.
- @param DevicePath The Fv file device path to be fixed up.
+ @param DevicePath The Memory Mapped Device Path to get the file buffer.
+ @param FullPath Receive the updated FV Device Path pointint to the file.
+ @param FileSize Receive the file buffer size.
+ @return The file buffer.
**/
-VOID
-BmFixupMemmapFvFilePath (
- IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+VOID *
+BmGetFileBufferByMemmapFv (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
)
{
EFI_STATUS Status;
UINTN Index;
- EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_DEVICE_PATH_PROTOCOL *FvFileNode;
EFI_HANDLE FvHandle;
- EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
- UINTN Size;
- EFI_FV_FILETYPE Type;
- EFI_FV_FILE_ATTRIBUTES Attributes;
UINT32 AuthenticationStatus;
UINTN FvHandleCount;
- EFI_HANDLE *FvHandleBuffer;
+ EFI_HANDLE *FvHandles;
EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ VOID *FileBuffer;
- Node = *DevicePath;
- Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &Node, &FvHandle);
+ FvFileNode = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &FvFileNode, &FvHandle);
if (!EFI_ERROR (Status)) {
- Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **) &Fv);
- ASSERT_EFI_ERROR (Status);
-
- Status = Fv->ReadFile (
- Fv,
- EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) Node),
- NULL,
- &Size,
- &Type,
- &Attributes,
- &AuthenticationStatus
- );
- if (EFI_ERROR (Status)) {
- BmFreeAndSet ((VOID **) DevicePath, NULL);
+ FileBuffer = GetFileBufferByFilePath (TRUE, DevicePath, FileSize, &AuthenticationStatus);
+ if (FileBuffer != NULL) {
+ *FullPath = DuplicateDevicePath (DevicePath);
}
- return;
+ return FileBuffer;
}
-
- Node = NextDevicePathNode (DevicePath);
+ FvFileNode = NextDevicePathNode (DevicePath);
//
// Firstly find the FV file in current FV
&gEfiLoadedImageProtocolGuid,
(VOID **) &LoadedImage
);
- NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), Node);
- BmFixupMemmapFvFilePath (&NewDevicePath);
+ NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (LoadedImage->DeviceHandle), FvFileNode);
+ FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize);
+ FreePool (NewDevicePath);
- if (NewDevicePath != NULL) {
- BmFreeAndSet ((VOID **) DevicePath, NewDevicePath);
- return;
+ if (FileBuffer != NULL) {
+ return FileBuffer;
}
//
&gEfiFirmwareVolume2ProtocolGuid,
NULL,
&FvHandleCount,
- &FvHandleBuffer
+ &FvHandles
);
- for (Index = 0; Index < FvHandleCount; Index++) {
- if (FvHandleBuffer[Index] == LoadedImage->DeviceHandle) {
+ for (Index = 0; (Index < FvHandleCount) && (FileBuffer == NULL); Index++) {
+ if (FvHandles[Index] == LoadedImage->DeviceHandle) {
//
// Skip current FV
//
continue;
}
- NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandleBuffer[Index]), Node);
- BmFixupMemmapFvFilePath (&NewDevicePath);
-
- if (NewDevicePath != NULL) {
- BmFreeAndSet ((VOID **) DevicePath, NewDevicePath);
- return;
- }
+ NewDevicePath = AppendDevicePathNode (DevicePathFromHandle (FvHandles[Index]), FvFileNode);
+ FileBuffer = BmGetFileBufferByMemmapFv (NewDevicePath, FullPath, FileSize);
+ FreePool (NewDevicePath);
}
+
+ if (FvHandles != NULL) {
+ FreePool (FvHandles);
+ }
+ return FileBuffer;
}
/**
- Check if it's of Fv file device path type.
+ Check if it's a Memory Mapped FV Device Path.
- The function doesn't garentee the device path points to existing Fv file.
+ The function doesn't garentee the device path points to existing FV file.
- @param DevicePath Input device path info.
+ @param DevicePath Input device path.
- @retval TRUE The device path is of Fv file device path type.
- @retval FALSE The device path isn't of Fv file device path type.
+ @retval TRUE The device path is a Memory Mapped FV Device Path.
+ @retval FALSE The device path is NOT a Memory Mapped FV Device Path.
**/
BOOLEAN
BmIsMemmapFvFilePath (
CHAR16 *Description;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
- switch (BmBootTypeFromDevicePath (DevicePathFromHandle (Handle))) {
+ switch (BmDevicePathType (DevicePathFromHandle (Handle))) {
case BmAcpiFloppyBoot:
Description = L"Floppy";
break;
return FALSE;
}
-/**
- Print the device path info.
-
- @param DevicePath The device path need to print.
-
-**/
-VOID
-BmPrintDp (
- EFI_DEVICE_PATH_PROTOCOL *DevicePath
- )
-{
- CHAR16 *Str;
-
- Str = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
- DEBUG ((EFI_D_INFO, "%s", Str));
- if (Str != NULL) {
- FreePool (Str);
- }
-}
-
/**
Find a USB device which match the specified short-form device path start with
USB Class or USB WWID device path. If ParentDevicePath is NULL, this function
contains a USB Class or USB WWID device path node, and ended with Media
FilePath device path.
- @param DevicePath On input, a pointer to an allocated buffer that contains the
- file device path.
- On output, a pointer to an reallocated buffer that contains
- the expanded device path. It would point to NULL if the file
- cannot be read.
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath Return the full device path of the load option after
+ short-form device path expanding.
+ Caller is responsible to free it.
+ @param FileSize Return the load option size.
+ @param ShortformNode Pointer to the USB short-form device path node in the FilePath buffer.
- @param FileSize A pointer to the file size.
-
- @retval !NULL The file buffer.
- @retval NULL The input device path doesn't point to a valid file.
+ @return The load option buffer. Caller is responsible to free the memory.
**/
VOID *
-BmExpandUsbShortFormDevicePath (
- IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
- OUT UINTN *FileSize
+BmExpandUsbDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize,
+ IN EFI_DEVICE_PATH_PROTOCOL *ShortformNode
)
{
UINTN ParentDevicePathSize;
- EFI_DEVICE_PATH_PROTOCOL *ShortformNode;
EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
- EFI_HANDLE *UsbIoHandles;
- UINTN UsbIoHandleCount;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
UINTN Index;
VOID *FileBuffer;
-
- //
- // Search for USB Class or USB WWID device path node.
- //
- for ( ShortformNode = *DevicePath
- ; !IsDevicePathEnd (ShortformNode)
- ; ShortformNode = NextDevicePathNode (ShortformNode)
- ) {
- if ((DevicePathType (ShortformNode) == MESSAGING_DEVICE_PATH) &&
- ((DevicePathSubType (ShortformNode) == MSG_USB_CLASS_DP) ||
- (DevicePathSubType (ShortformNode) == MSG_USB_WWID_DP))) {
- break;
- }
+
+ ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) FilePath;
+ RemainingDevicePath = NextDevicePathNode (ShortformNode);
+ FileBuffer = NULL;
+ Handles = BmFindUsbDevice (FilePath, ParentDevicePathSize, &HandleCount);
+
+ for (Index = 0; (Index < HandleCount) && (FileBuffer == NULL); Index++) {
+ FullDevicePath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), RemainingDevicePath);
+ FileBuffer = BmGetLoadOptionBuffer (FullDevicePath, FullPath, FileSize);
+ FreePool (FullDevicePath);
}
- ASSERT (!IsDevicePathEnd (ShortformNode));
- FullDevicePath = NULL;
- ParentDevicePathSize = (UINTN) ShortformNode - (UINTN) *DevicePath;
- RemainingDevicePath = NextDevicePathNode (ShortformNode);
- FileBuffer = NULL;
- UsbIoHandles = BmFindUsbDevice (*DevicePath, ParentDevicePathSize, &UsbIoHandleCount);
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
- for (Index = 0; Index < UsbIoHandleCount; Index++) {
- FullDevicePath = AppendDevicePath (DevicePathFromHandle (UsbIoHandles[Index]), RemainingDevicePath);
- DEBUG ((EFI_D_INFO, "[Bds] FullDp1[%d]:", Index)); DEBUG_CODE (BmPrintDp (FullDevicePath); ); DEBUG ((EFI_D_INFO, "\n"));
- FileBuffer = BmLoadEfiBootOption (&FullDevicePath, FileSize);
- if (FileBuffer != NULL) {
- DEBUG ((EFI_D_INFO, "-->")); DEBUG_CODE (BmPrintDp (FullDevicePath); ); DEBUG ((EFI_D_INFO, FileBuffer != NULL ? " - Found\n" : "\n"));
- break;
- }
+ return FileBuffer;
+}
+
+/**
+ Save the partition DevicePath to the CachedDevicePath as the first instance.
+
+ @param CachedDevicePath The device path cache.
+ @param DevicePath The partition device path to be cached.
+**/
+VOID
+BmCachePartitionDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **CachedDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ UINTN Count;
+
+ if (BmMatchDevicePaths (*CachedDevicePath, DevicePath)) {
+ TempDevicePath = *CachedDevicePath;
+ *CachedDevicePath = BmDelPartMatchInstance (*CachedDevicePath, DevicePath);
+ FreePool (TempDevicePath);
}
- if (UsbIoHandles != NULL) {
- FreePool (UsbIoHandles);
+ if (*CachedDevicePath == NULL) {
+ *CachedDevicePath = DuplicateDevicePath (DevicePath);
+ return;
}
- if (FileBuffer == NULL) {
+ TempDevicePath = *CachedDevicePath;
+ *CachedDevicePath = AppendDevicePathInstance (DevicePath, *CachedDevicePath);
+ if (TempDevicePath != NULL) {
+ FreePool (TempDevicePath);
+ }
+
+ //
+ // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
+ // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
+ //
+ Count = 0;
+ TempDevicePath = *CachedDevicePath;
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
//
- // Boot Option device path starts with USB Class or USB WWID device path.
- // For Boot Option device path which doesn't begin with the USB Class or
- // USB WWID device path, it's not needed to connect again here.
+ // Parse one instance
//
- if ((DevicePathType (*DevicePath) == MESSAGING_DEVICE_PATH) &&
- ((DevicePathSubType (*DevicePath) == MSG_USB_CLASS_DP) ||
- (DevicePathSubType (*DevicePath) == MSG_USB_WWID_DP))) {
- BmConnectUsbShortFormDevicePath (*DevicePath);
-
- UsbIoHandles = BmFindUsbDevice (*DevicePath, ParentDevicePathSize, &UsbIoHandleCount);
- for (Index = 0; Index < UsbIoHandleCount; Index++) {
- FullDevicePath = AppendDevicePath (DevicePathFromHandle (UsbIoHandles[Index]), RemainingDevicePath);
- DEBUG ((EFI_D_INFO, "[Bds] FullDp2[%d]:", Index)); DEBUG_CODE (BmPrintDp (FullDevicePath); ); DEBUG ((EFI_D_INFO, "\n"));
- FileBuffer = BmLoadEfiBootOption (&FullDevicePath, FileSize);
- if (FileBuffer != NULL) {
- DEBUG ((EFI_D_INFO, "-->")); DEBUG_CODE (BmPrintDp (FullDevicePath); ); DEBUG ((EFI_D_INFO, FileBuffer != NULL ? " - Found\n" : "\n"));
- break;
- }
- }
-
- if (UsbIoHandles != NULL) {
- FreePool (UsbIoHandles);
- }
+ while (!IsDevicePathEndType (TempDevicePath)) {
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+ Count++;
+ //
+ // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
+ //
+ if (Count == 12) {
+ SetDevicePathEndNode (TempDevicePath);
+ break;
}
}
-
- BmFreeAndSet ((VOID **) DevicePath, FullDevicePath);
- return FileBuffer;
}
/**
so a connect all is not required on every boot. All successful history device path
which point to partition node (the front part) will be saved.
- @param DevicePath On input, a pointer to an allocated buffer that contains the
- file device path.
- On output, a pointer to an reallocated buffer that contains
- the expanded device path. It would point to NULL if the file
- cannot be read.
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath Return the full device path of the load option after
+ short-form device path expanding.
+ Caller is responsible to free it.
+ @param FileSize Return the load option size.
+ @return The load option buffer. Caller is responsible to free the memory.
**/
-VOID
-BmExpandPartitionShortFormDevicePath (
- IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+VOID *
+BmExpandPartitionDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
)
{
EFI_STATUS Status;
UINTN BlockIoHandleCount;
EFI_HANDLE *BlockIoBuffer;
- EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
+ VOID *FileBuffer;
EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
UINTN Index;
- UINTN InstanceNum;
EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
UINTN CachedDevicePathSize;
- BOOLEAN DeviceExist;
BOOLEAN NeedAdjust;
EFI_DEVICE_PATH_PROTOCOL *Instance;
UINTN Size;
- FullDevicePath = NULL;
+ FileBuffer = NULL;
//
// Check if there is prestore 'HDDP' variable.
// If exist, search the front path which point to partition node in the variable instants.
if (CachedDevicePath != NULL) {
TempNewDevicePath = CachedDevicePath;
- DeviceExist = FALSE;
NeedAdjust = FALSE;
do {
//
// partial partition boot option. Second, check whether the instance could be connected.
//
Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
- if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) *DevicePath)) {
+ if (BmMatchPartitionDevicePathNode (Instance, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
//
// Connect the device path instance, the device path point to hard drive media device path node
// e.g. ACPI() /PCI()/ATA()/Partition()
//
Status = EfiBootManagerConnectDevicePath (Instance, NULL);
if (!EFI_ERROR (Status)) {
- DeviceExist = TRUE;
- break;
+ TempDevicePath = AppendDevicePath (Instance, NextDevicePathNode (FilePath));
+ FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
+ FreePool (TempDevicePath);
+
+ if (FileBuffer != NULL) {
+ //
+ // Adjust the 'HDDP' instances sequence if the matched one is not first one.
+ //
+ if (NeedAdjust) {
+ BmCachePartitionDevicePath (&CachedDevicePath, Instance);
+ //
+ // Save the matching Device Path so we don't need to do a connect all next time
+ // Failing to save only impacts performance next time expanding the short-form device path
+ //
+ Status = gRT->SetVariable (
+ L"HDDP",
+ &mBmHardDriveBootVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ GetDevicePathSize (CachedDevicePath),
+ CachedDevicePath
+ );
+ }
+
+ FreePool (Instance);
+ FreePool (CachedDevicePath);
+ return FileBuffer;
+ }
}
}
//
NeedAdjust = TRUE;
FreePool(Instance);
} while (TempNewDevicePath != NULL);
-
- if (DeviceExist) {
- //
- // Find the matched device path.
- // Append the file path information from the boot option and return the fully expanded device path.
- //
- FullDevicePath = AppendDevicePath (Instance, NextDevicePathNode (*DevicePath));
-
- //
- // Adjust the 'HDDP' instances sequence if the matched one is not first one.
- //
- if (NeedAdjust) {
- //
- // First delete the matched instance.
- //
- TempNewDevicePath = CachedDevicePath;
- CachedDevicePath = BmDelPartMatchInstance (CachedDevicePath, Instance);
- FreePool (TempNewDevicePath);
-
- //
- // Second, append the remaining path after the matched instance
- //
- TempNewDevicePath = CachedDevicePath;
- CachedDevicePath = AppendDevicePathInstance (Instance, CachedDevicePath );
- FreePool (TempNewDevicePath);
- //
- // Save the matching Device Path so we don't need to do a connect all next time
- // Failing to save only impacts performance next time expanding the short-form device path
- //
- Status = gRT->SetVariable (
- L"HDDP",
- &mBmHardDriveBootVariableGuid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
- GetDevicePathSize (CachedDevicePath),
- CachedDevicePath
- );
- }
-
- FreePool (Instance);
- FreePool (CachedDevicePath);
- FreePool (*DevicePath);
- *DevicePath = FullDevicePath;
- return;
- }
}
//
// Loop through all the device handles that support the BLOCK_IO Protocol
//
for (Index = 0; Index < BlockIoHandleCount; Index++) {
-
- Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);
- if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
+ BlockIoDevicePath = DevicePathFromHandle (BlockIoBuffer[Index]);
+ if (BlockIoDevicePath == NULL) {
continue;
}
- if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) *DevicePath)) {
+ if (BmMatchPartitionDevicePathNode (BlockIoDevicePath, (HARDDRIVE_DEVICE_PATH *) FilePath)) {
//
// Find the matched partition device path
//
- FullDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (*DevicePath));
+ TempDevicePath = AppendDevicePath (BlockIoDevicePath, NextDevicePathNode (FilePath));
+ FileBuffer = BmGetLoadOptionBuffer (TempDevicePath, FullPath, FileSize);
+ FreePool (TempDevicePath);
- //
- // Save the matched partition device path in 'HDDP' variable
- //
- if (CachedDevicePath != NULL) {
- //
- // Save the matched partition device path as first instance of 'HDDP' variable
- //
- if (BmMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) {
- TempNewDevicePath = CachedDevicePath;
- CachedDevicePath = BmDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath);
- FreePool(TempNewDevicePath);
- }
-
- if (CachedDevicePath != NULL) {
- TempNewDevicePath = CachedDevicePath;
- CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
- FreePool(TempNewDevicePath);
- } else {
- CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
- }
+ if (FileBuffer != NULL) {
+ BmCachePartitionDevicePath (&CachedDevicePath, BlockIoDevicePath);
//
- // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
- // If the user try to boot many OS in different HDs or partitions, in theory, the 'HDDP' variable maybe become larger and larger.
+ // Save the matching Device Path so we don't need to do a connect all next time
+ // Failing to save only impacts performance next time expanding the short-form device path
//
- InstanceNum = 0;
- ASSERT (CachedDevicePath != NULL);
- TempNewDevicePath = CachedDevicePath;
- while (!IsDevicePathEnd (TempNewDevicePath)) {
- TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
- //
- // Parse one instance
- //
- while (!IsDevicePathEndType (TempNewDevicePath)) {
- TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
- }
- InstanceNum++;
- //
- // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
- //
- if (InstanceNum >= 12) {
- SetDevicePathEndNode (TempNewDevicePath);
- break;
- }
- }
- } else {
- CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
- }
-
- //
- // Save the matching Device Path so we don't need to do a connect all next time
- // Failing to save only impacts performance next time expanding the short-form device path
- //
- Status = gRT->SetVariable (
- L"HDDP",
- &mBmHardDriveBootVariableGuid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
- GetDevicePathSize (CachedDevicePath),
- CachedDevicePath
- );
+ Status = gRT->SetVariable (
+ L"HDDP",
+ &mBmHardDriveBootVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ GetDevicePathSize (CachedDevicePath),
+ CachedDevicePath
+ );
- break;
+ break;
+ }
}
}
if (BlockIoBuffer != NULL) {
FreePool (BlockIoBuffer);
}
- BmFreeAndSet ((VOID **) DevicePath, FullDevicePath);
+ return FileBuffer;
}
/**
- Algorithm follows the UEFI Spec chapter 3.4 Boot Mechanisms.
-
- @param DevicePath Device Path to a bootable device
+ Expand the media device path which points to a BlockIo or SimpleFileSystem instance
+ by appending EFI_REMOVABLE_MEDIA_FILE_NAME.
- @return The bootable media handle. If the media on the DevicePath is not bootable, NULL will return.
+ @param DevicePath The media device path pointing to a BlockIo or SimpleFileSystem instance.
+ @param FullPath Return the full device path pointing to the load option.
+ @param FileSize Return the size of the load option.
+ @return The load option buffer.
**/
-EFI_HANDLE
-BmGetBootableDeviceHandle (
- IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+VOID *
+BmExpandMediaDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
)
{
EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
EFI_HANDLE Handle;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
VOID *Buffer;
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
UINTN Size;
UINTN TempSize;
- EFI_HANDLE ReturnHandle;
EFI_HANDLE *SimpleFileSystemHandles;
UINTN NumberSimpleFileSystemHandles;
UINTN Index;
- EFI_IMAGE_DOS_HEADER DosHeader;
- EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
- EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
-
- ReturnHandle = NULL;
- UpdatedDevicePath = DevicePath;
+ VOID *FileBuffer;
+ UINT32 AuthenticationStatus;
//
// Check whether the device is connected
//
- Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &UpdatedDevicePath, &Handle);
- if (EFI_ERROR (Status)) {
- //
- // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,
- //
- Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &UpdatedDevicePath, &Handle);
- if (EFI_ERROR (Status)) {
- //
- // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly
- //
- UpdatedDevicePath = DevicePath;
- Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
- gBS->ConnectController (Handle, NULL, NULL, TRUE);
- }
- } else {
- //
- // For removable device boot option, its contained device path only point to the removable device handle,
- // should make sure all its children handles (its child partion or media handles) are created and connected.
- //
- gBS->ConnectController (Handle, NULL, NULL, TRUE);
- //
- // Get BlockIo protocol and check removable attribute
- //
- Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
- //
- // Issue a dummy read to the device to check for media change.
- // When the removable media is changed, any Block IO read/write will
- // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
- // returned. After the Block IO protocol is reinstalled, subsequent
- // Block IO read/write will success.
- //
- Buffer = AllocatePool (BlockIo->Media->BlockSize);
- if (Buffer != NULL) {
- BlockIo->ReadBlocks (
- BlockIo,
- BlockIo->Media->MediaId,
- 0,
- BlockIo->Media->BlockSize,
- Buffer
- );
- FreePool(Buffer);
+ TempDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
+ if (!EFI_ERROR (Status)) {
+ ASSERT (IsDevicePathEnd (TempDevicePath));
+
+ TempDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
+ FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
+ if (FileBuffer == NULL) {
+ FreePool (TempDevicePath);
+ TempDevicePath = NULL;
}
+ *FullPath = TempDevicePath;
+ return FileBuffer;
+ }
+
+ //
+ // For device boot option only pointing to the removable device handle,
+ // should make sure all its children handles (its child partion or media handles) are created and connected.
+ //
+ gBS->ConnectController (Handle, NULL, NULL, TRUE);
+
+ //
+ // Issue a dummy read to the device to check for media change.
+ // When the removable media is changed, any Block IO read/write will
+ // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
+ // returned. After the Block IO protocol is reinstalled, subsequent
+ // Block IO read/write will success.
+ //
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
+ ASSERT_EFI_ERROR (Status);
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ ASSERT_EFI_ERROR (Status);
+ Buffer = AllocatePool (BlockIo->Media->BlockSize);
+ if (Buffer != NULL) {
+ BlockIo->ReadBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ 0,
+ BlockIo->Media->BlockSize,
+ Buffer
+ );
+ FreePool (Buffer);
}
//
// Detect the the default boot file from removable Media
//
- Size = GetDevicePathSize(DevicePath) - END_DEVICE_PATH_LENGTH;
+ FileBuffer = NULL;
+ *FullPath = NULL;
+ Size = GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH;
gBS->LocateHandleBuffer (
ByProtocol,
&gEfiSimpleFileSystemProtocolGuid,
// Get the device path size of SimpleFileSystem handle
//
TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
- TempSize = GetDevicePathSize (TempDevicePath)- END_DEVICE_PATH_LENGTH;
+ TempSize = GetDevicePathSize (TempDevicePath) - END_DEVICE_PATH_LENGTH;
//
// Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
//
if ((Size <= TempSize) && (CompareMem (TempDevicePath, DevicePath, Size) == 0)) {
- //
- // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
- // machinename is ia32, ia64, x64, ...
- //
- Hdr.Union = &HdrData;
- Status = BmGetImageHeader (
- SimpleFileSystemHandles[Index],
- EFI_REMOVABLE_MEDIA_FILE_NAME,
- &DosHeader,
- Hdr
- );
- if (!EFI_ERROR (Status) && EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
- (Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)
- ) {
- ReturnHandle = SimpleFileSystemHandles[Index];
+ TempDevicePath = FileDevicePath (SimpleFileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
+ FileBuffer = GetFileBufferByFilePath (TRUE, TempDevicePath, FileSize, &AuthenticationStatus);
+ if (FileBuffer != NULL) {
+ *FullPath = TempDevicePath;
break;
}
+ FreePool (TempDevicePath);
}
}
if (SimpleFileSystemHandles != NULL) {
- FreePool(SimpleFileSystemHandles);
+ FreePool (SimpleFileSystemHandles);
}
- return ReturnHandle;
+ return FileBuffer;
}
/**
- Get the image file buffer data and buffer size by its device path.
-
- @param FilePath On input, a pointer to an allocated buffer that contains the
- file device path.
- On output the device path pointer could be modified to point to
- a new allocated buffer that contains the full device path.
- It could be caused by either short-form device path expanding,
- or default boot file path appending.
- @param FileSize A pointer to the size of the file buffer.
-
- @retval NULL The file can't be found.
- @retval other The file buffer. The caller is responsible to free memory.
+ Get the load option by its device path.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath Return the full device path of the load option after
+ short-form device path expanding.
+ Caller is responsible to free it.
+ @param FileSize Return the load option size.
+
+ @return The load option buffer. Caller is responsible to free the memory.
**/
VOID *
-BmLoadEfiBootOption (
- IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
- OUT UINTN *FileSize
+BmGetLoadOptionBuffer (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
)
{
EFI_HANDLE Handle;
VOID *FileBuffer;
UINT32 AuthenticationStatus;
EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_STATUS Status;
- ASSERT ((FilePath != NULL) && (*FilePath != NULL) && (FileSize != NULL));
+ ASSERT ((FilePath != NULL) && (FullPath != NULL) && (FileSize != NULL));
- EfiBootManagerConnectDevicePath (*FilePath, NULL);
+ EfiBootManagerConnectDevicePath (FilePath, NULL);
+ *FullPath = NULL;
*FileSize = 0;
FileBuffer = NULL;
+
+ //
+ // Boot from media device by adding a default file name \EFI\BOOT\BOOT{machine type short-name}.EFI
+ //
+ Node = FilePath;
+ Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &Node, &Handle);
+ if (EFI_ERROR (Status)) {
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &Node, &Handle);
+ }
+
+ if (!EFI_ERROR (Status) && IsDevicePathEnd (Node)) {
+ return BmExpandMediaDevicePath (FilePath, FullPath, FileSize);
+ }
+
//
// Expand the short-form device path to full device path
//
- if ((DevicePathType (*FilePath) == MEDIA_DEVICE_PATH) &&
- (DevicePathSubType (*FilePath) == MEDIA_HARDDRIVE_DP)) {
+ if ((DevicePathType (FilePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (FilePath) == MEDIA_HARDDRIVE_DP)) {
//
// Expand the Harddrive device path
//
- BmExpandPartitionShortFormDevicePath (FilePath);
- if (*FilePath == NULL) {
- return NULL;
- }
-
+ return BmExpandPartitionDevicePath (FilePath, FullPath, FileSize);
} else {
- for (Node = *FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
+ for (Node = FilePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) &&
- ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) ||
- (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {
+ ((DevicePathSubType (Node) == MSG_USB_CLASS_DP) || (DevicePathSubType (Node) == MSG_USB_WWID_DP))) {
break;
}
}
//
// Expand the USB WWID/Class device path
//
- FileBuffer = BmExpandUsbShortFormDevicePath (FilePath, FileSize);
- if (FileBuffer == NULL) {
- return NULL;
+ FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
+ if ((FileBuffer == NULL) && (FilePath == Node)) {
+ //
+ // Boot Option device path starts with USB Class or USB WWID device path.
+ // For Boot Option device path which doesn't begin with the USB Class or
+ // USB WWID device path, it's not needed to connect again here.
+ //
+ BmConnectUsbShortFormDevicePath (FilePath);
+ FileBuffer = BmExpandUsbDevicePath (FilePath, FullPath, FileSize, Node);
}
+ return FileBuffer;
}
}
//
// Fix up the boot option path if it points to a FV in memory map style of device path
//
- if (BmIsMemmapFvFilePath (*FilePath)) {
- BmFixupMemmapFvFilePath (FilePath);
- if (*FilePath == NULL) {
- return NULL;
- }
- }
-
- if (FileBuffer == NULL) {
- FileBuffer = GetFileBufferByFilePath (TRUE, *FilePath, FileSize, &AuthenticationStatus);
+ if (BmIsMemmapFvFilePath (FilePath)) {
+ return BmGetFileBufferByMemmapFv (FilePath, FullPath, FileSize);
}
//
- // If we didn't find an image directly, we need to try as if it is a removable device boot option
- // and load the image according to the default boot behavior.
+ // Directly reads the load option when it doesn't reside in simple file system instance (LoadFile/LoadFile2),
+ // or it directly points to a file in simple file system instance.
//
- if (FileBuffer == NULL) {
- //
- // check if there is a bootable media could be found in this device path,
- // and get the bootable media handle
- //
- Handle = BmGetBootableDeviceHandle (*FilePath);
- if (Handle != NULL) {
- //
- // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from the media
- // machinename is ia32, ia64, x64, ...
- //
- BmFreeAndSet ((VOID **) FilePath, FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME));
- ASSERT (*FilePath != NULL);
- FileBuffer = GetFileBufferByFilePath (TRUE, *FilePath, FileSize, &AuthenticationStatus);
- }
- }
-
- if (FileBuffer == NULL) {
- BmFreeAndSet ((VOID **) FilePath, NULL);
+ FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, FileSize, &AuthenticationStatus);
+ if (FileBuffer != NULL) {
+ *FullPath = DuplicateDevicePath (FilePath);
}
return FileBuffer;
return;
}
- if (BootOption->FilePath == NULL) {
+ if (BootOption->FilePath == NULL || BootOption->OptionType != LoadOptionTypeBoot) {
BootOption->Status = EFI_INVALID_PARAMETER;
return;
}
//
OptionNumber = BmFindBootOptionInVariable (BootOption);
if (OptionNumber == LoadOptionNumberUnassigned) {
- Status = BmGetFreeOptionNumber (L"BootOrder", &Uint16);
+ Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);
if (!EFI_ERROR (Status)) {
//
// Save the BootOption->OptionNumber to restore later
DEBUG ((EFI_D_INFO, "[Bds] Booting Boot Manager Menu.\n"));
BmStopHotkeyService (NULL, NULL);
} else {
- REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
EfiSignalEventReadyToBoot();
//
+ // Report Status Code to indicate ReadyToBoot was signalled
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
+ //
// 4. Repair system through DriverHealth protocol
//
BmRepairAllControllers ();
// 5. Load EFI boot option to ImageHandle
//
ImageHandle = NULL;
- if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {
+ if (BmDevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {
Status = EFI_NOT_FOUND;
- FilePath = DuplicateDevicePath (BootOption->FilePath);
- FileBuffer = BmLoadEfiBootOption (&FilePath, &FileSize);
- if (FileBuffer != NULL) {
-
+ FileBuffer = BmGetLoadOptionBuffer (BootOption->FilePath, &FilePath, &FileSize);
+ DEBUG_CODE (
+ if (FileBuffer != NULL && CompareMem (BootOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
+ DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
+ BmPrintDp (BootOption->FilePath);
+ DEBUG ((EFI_D_INFO, " -> "));
+ BmPrintDp (FilePath);
+ DEBUG ((EFI_D_INFO, "\n"));
+ }
+ );
+ if (BmIsLoadOptionPeHeaderValid (BootOption->OptionType, FileBuffer, FileSize)) {
REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
-
Status = gBS->LoadImage (
TRUE,
gImageHandle,
FileSize,
&ImageHandle
);
+ }
+ if (FileBuffer != NULL) {
FreePool (FileBuffer);
+ }
+ if (FilePath != NULL) {
FreePool (FilePath);
}
IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
)
{
- HARDDRIVE_DEVICE_PATH *TmpHdPath;
- EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- BOOLEAN Match;
- EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePathNode;
+ HARDDRIVE_DEVICE_PATH *Node;
if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
return FALSE;
}
- //
- // Make PreviousDevicePath == the device path node before the end node
- //
- DevicePath = BlockIoDevicePath;
- BlockIoHdDevicePathNode = NULL;
-
//
// find the partition device path node
//
- while (!IsDevicePathEnd (DevicePath)) {
- if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
- (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
+ while (!IsDevicePathEnd (BlockIoDevicePath)) {
+ if ((DevicePathType (BlockIoDevicePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (BlockIoDevicePath) == MEDIA_HARDDRIVE_DP)
) {
- BlockIoHdDevicePathNode = DevicePath;
break;
}
- DevicePath = NextDevicePathNode (DevicePath);
+ BlockIoDevicePath = NextDevicePathNode (BlockIoDevicePath);
}
- if (BlockIoHdDevicePathNode == NULL) {
+ if (IsDevicePathEnd (BlockIoDevicePath)) {
return FALSE;
}
+
//
// See if the harddrive device path in blockio matches the orig Hard Drive Node
//
- TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePathNode;
- Match = FALSE;
+ Node = (HARDDRIVE_DEVICE_PATH *) BlockIoDevicePath;
//
- // Check for the match
+ // Match Signature and PartitionNumber.
+ // Unused bytes in Signature are initiaized with zeros.
//
- if ((TmpHdPath->MBRType == HardDriveDevicePath->MBRType) &&
- (TmpHdPath->SignatureType == HardDriveDevicePath->SignatureType)) {
- switch (TmpHdPath->SignatureType) {
- case SIGNATURE_TYPE_GUID:
- Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID *)HardDriveDevicePath->Signature);
- break;
- case SIGNATURE_TYPE_MBR:
- Match = (BOOLEAN) (*((UINT32 *) (&(TmpHdPath->Signature[0]))) == ReadUnaligned32((UINT32 *)(&(HardDriveDevicePath->Signature[0]))));
- break;
- default:
- Match = FALSE;
- break;
- }
- }
-
- return Match;
+ return (BOOLEAN) (
+ (Node->PartitionNumber == HardDriveDevicePath->PartitionNumber) &&
+ (Node->MBRType == HardDriveDevicePath->MBRType) &&
+ (Node->SignatureType == HardDriveDevicePath->SignatureType) &&
+ (CompareMem (Node->Signature, HardDriveDevicePath->Signature, sizeof (Node->Signature)) == 0)
+ );
}
/**
a multi-instance device path
@param MatchingHandle Return the controller handle closest to the DevicePathToConnect
- @retval EFI_SUCCESS All handles associate with every device path node
- have been created
- @retval EFI_OUT_OF_RESOURCES There is no resource to create new handles
- @retval EFI_NOT_FOUND Create the handle associate with one device path
- node failed
-
+ @retval EFI_SUCCESS All handles associate with every device path node
+ have been created.
+ @retval EFI_OUT_OF_RESOURCES There is no resource to create new handles.
+ @retval EFI_NOT_FOUND Create the handle associate with one device path
+ node failed.
+ @retval EFI_SECURITY_VIOLATION The user has no permission to start UEFI device
+ drivers on the DevicePath.
**/
EFI_STATUS
EFIAPI
// Connect all drivers that apply to Handle and RemainingDevicePath,
// the Recursive flag is FALSE so only one level will be expanded.
//
- // Do not check the connect status here, if the connect controller fail,
- // then still give the chance to do dispatch, because partial
- // RemainingDevicepath may be in the new FV
+ // If ConnectController fails to find a driver, then still give the chance to
+ // do dispatch, because partial RemainingDevicePath may be in the new FV
//
// 1. If the connect fail, RemainingDevicepath and handle will not
// change, so next time will do the dispatch, then dispatch's status
// change, then avoid the dispatch, we have chance to continue the
// next connection
//
- gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);
+ Status = gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);
+ if (Status == EFI_NOT_FOUND) {
+ Status = EFI_SUCCESS;
+ }
if (MatchingHandle != NULL) {
*MatchingHandle = Handle;
}
/**
This function will connect all the console devices base on the console
device variable ConIn, ConOut and ErrOut.
+
+ @retval EFI_DEVICE_ERROR All the consoles were not connected due to an error.
+ @retval EFI_SUCCESS Success connect any one instance of the console
+ device path base on the variable ConVarName.
**/
-VOID
+EFI_STATUS
EFIAPI
EfiBootManagerConnectAllDefaultConsoles (
VOID
)
{
+ EFI_STATUS Status;
+ BOOLEAN OneConnected;
BOOLEAN SystemTableUpdated;
- EfiBootManagerConnectConsoleVariable (ConOut);
+ OneConnected = FALSE;
+
+ Status = EfiBootManagerConnectConsoleVariable (ConOut);
+ if (!EFI_ERROR (Status)) {
+ OneConnected = TRUE;
+ }
PERF_START (NULL, "ConOutReady", "BDS", 1);
PERF_END (NULL, "ConOutReady", "BDS", 0);
- EfiBootManagerConnectConsoleVariable (ConIn);
+ Status = EfiBootManagerConnectConsoleVariable (ConIn);
+ if (!EFI_ERROR (Status)) {
+ OneConnected = TRUE;
+ }
PERF_START (NULL, "ConInReady", "BDS", 1);
PERF_END (NULL, "ConInReady", "BDS", 0);
- //
- // The _ModuleEntryPoint err out var is legal.
- //
- EfiBootManagerConnectConsoleVariable (ErrOut);
+ Status = EfiBootManagerConnectConsoleVariable (ErrOut);
+ if (!EFI_ERROR (Status)) {
+ OneConnected = TRUE;
+ }
PERF_START (NULL, "ErrOutReady", "BDS", 1);
PERF_END (NULL, "ErrOutReady", "BDS", 0);
&gST->Hdr.CRC32
);
}
+
+ return OneConnected ? EFI_SUCCESS : EFI_DEVICE_ERROR;
}
#include "InternalBm.h"
+GLOBAL_REMOVE_IF_UNREFERENCED
+ CHAR16 *mBmLoadOptionName[] = {
+ L"Driver",
+ L"SysPrep",
+ L"Boot"
+ };
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+ CHAR16 *mBmLoadOptionOrderName[] = {
+ EFI_DRIVER_ORDER_VARIABLE_NAME,
+ EFI_SYS_PREP_ORDER_VARIABLE_NAME,
+ EFI_BOOT_ORDER_VARIABLE_NAME
+ };
+
+/**
+ Call Visitor function for each variable in variable storage.
+
+ @param Visitor Visitor function.
+ @param Context The context passed to Visitor function.
+**/
+VOID
+BmForEachVariable (
+ VARIABLE_VISITOR Visitor,
+ VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *Name;
+ EFI_GUID Guid;
+ UINTN NameSize;
+ UINTN NewNameSize;
+
+ NameSize = sizeof (CHAR16);
+ Name = AllocateZeroPool (NameSize);
+ ASSERT (Name != NULL);
+ while (TRUE) {
+ NewNameSize = NameSize;
+ Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Name = ReallocatePool (NameSize, NewNameSize, Name);
+ ASSERT (Name != NULL);
+ Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
+ NameSize = NewNameSize;
+ }
+
+ if (Status == EFI_NOT_FOUND) {
+ break;
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ Visitor (Name, &Guid, Context);
+ }
+
+ FreePool (Name);
+}
+
/**
Get the Option Number that wasn't used.
- @param OrderVariableName Could be L"BootOrder" or L"DriverOrder".
- @param FreeOptionNumber To receive the minimal free option number.
+ @param LoadOptionType The load option type.
+ @param FreeOptionNumber Return the minimal free option number.
- @retval EFI_SUCCESS The option number is found
+ @retval EFI_SUCCESS The option number is found and will be returned.
@retval EFI_OUT_OF_RESOURCES There is no free option number that can be used.
@retval EFI_INVALID_PARAMETER FreeOptionNumber is NULL
**/
EFI_STATUS
BmGetFreeOptionNumber (
- IN CHAR16 *OrderVariableName,
- OUT UINT16 *FreeOptionNumber
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,
+ OUT UINT16 *FreeOptionNumber
)
{
UINTN OptionOrderSize;
UINT16 *BootNext;
- if (FreeOptionNumber == NULL) {
- return EFI_INVALID_PARAMETER;
- }
+ ASSERT (FreeOptionNumber != NULL);
+ ASSERT (LoadOptionType == LoadOptionTypeDriver ||
+ LoadOptionType == LoadOptionTypeBoot ||
+ LoadOptionType == LoadOptionTypeSysPrep);
- GetEfiGlobalVariable2 (OrderVariableName, (VOID **) &OptionOrder, &OptionOrderSize);
+ GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);
BootNext = NULL;
- if (*OrderVariableName == L'B') {
+ if (LoadOptionType == LoadOptionTypeBoot) {
GetEfiGlobalVariable2 (L"BootNext", (VOID**) &BootNext, NULL);
}
}
/**
- Update order variable .
-
- @param OptionOrderName Order variable name which need to be updated.
- @param OptionNumber Option number for the new option.
- @param Position Position of the new load option to put in the ****Order variable.
-
- @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered.
- @retval EFI_ALREADY_STARTED The option number of Option is being used already.
- @retval EFI_STATUS Return the status of gRT->SetVariable ().
-
-**/
-EFI_STATUS
-BmAddOptionNumberToOrderVariable (
- IN CHAR16 *OptionOrderName,
- IN UINT16 OptionNumber,
- IN UINTN Position
- )
-{
- EFI_STATUS Status;
- UINTN Index;
- UINT16 *OptionOrder;
- UINT16 *NewOptionOrder;
- UINTN OptionOrderSize;
- //
- // Update the option order variable
- //
- GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, &OptionOrderSize);
-
- Status = EFI_SUCCESS;
- for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
- if (OptionOrder[Index] == OptionNumber) {
- Status = EFI_ALREADY_STARTED;
- break;
- }
- }
-
- if (!EFI_ERROR (Status)) {
- Position = MIN (Position, OptionOrderSize / sizeof (UINT16));
-
- NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16));
- ASSERT (NewOptionOrder != NULL);
- if (OptionOrderSize != 0) {
- CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16));
- CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], OptionOrderSize - Position * sizeof (UINT16));
- }
- NewOptionOrder[Position] = OptionNumber;
-
- Status = gRT->SetVariable (
- OptionOrderName,
- &gEfiGlobalVariableGuid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
- OptionOrderSize + sizeof (UINT16),
- NewOptionOrder
- );
- FreePool (NewOptionOrder);
- }
-
- if (OptionOrder != NULL) {
- FreePool (OptionOrder);
- }
-
- return Status;
-}
-
-/**
- Create the Boot#### or Driver#### variable from the load option.
+ Create the Boot####, Driver####, SysPrep####, variable from the load option.
@param LoadOption Pointer to the load option.
UINTN VariableSize;
UINT8 *Variable;
UINT8 *Ptr;
- CHAR16 OptionName[sizeof ("Driver####")];
+ CHAR16 OptionName[BM_OPTION_NAME_LEN];
CHAR16 *Description;
CHAR16 NullChar;
+ UINT32 VariableAttributes;
if ((Option->OptionNumber == LoadOptionNumberUnassigned) ||
(Option->FilePath == NULL) ||
- (Option->OptionType >= LoadOptionTypeMax)
+ ((UINT32) Option->OptionType >= LoadOptionTypeMax)
) {
return EFI_INVALID_PARAMETER;
}
Variable = AllocatePool (VariableSize);
ASSERT (Variable != NULL);
-
+
Ptr = Variable;
- *(UINT32 *) Ptr = Option->Attributes;
+ WriteUnaligned32 ((UINT32 *) Ptr, Option->Attributes);
Ptr += sizeof (Option->Attributes);
- *(UINT16 *) Ptr = (UINT16) GetDevicePathSize (Option->FilePath);
+
+ WriteUnaligned16 ((UINT16 *) Ptr, (UINT16) GetDevicePathSize (Option->FilePath));
Ptr += sizeof (UINT16);
+
CopyMem (Ptr, Description, StrSize (Description));
Ptr += StrSize (Description);
+
CopyMem (Ptr, Option->FilePath, GetDevicePathSize (Option->FilePath));
Ptr += GetDevicePathSize (Option->FilePath);
+
CopyMem (Ptr, Option->OptionalData, Option->OptionalDataSize);
- UnicodeSPrint (
- OptionName,
- sizeof (OptionName),
- (Option->OptionType == LoadOptionTypeBoot) ? L"Boot%04x" : L"Driver%04x",
- Option->OptionNumber
- );
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[Option->OptionType], Option->OptionNumber);
+
+ VariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;
return gRT->SetVariable (
OptionName,
&gEfiGlobalVariableGuid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ VariableAttributes,
VariableSize,
Variable
);
}
/**
- This function will register the new boot#### or driver#### option.
- After the boot#### or driver#### updated, the BootOrder or DriverOrder will also be updated.
+ Update order variable .
+
+ @param OptionOrderName Order variable name which need to be updated.
+ @param OptionNumber Option number for the new option.
+ @param Position Position of the new load option to put in the ****Order variable.
+
+ @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered.
+ @retval EFI_ALREADY_STARTED The option number of Option is being used already.
+ @retval EFI_STATUS Return the status of gRT->SetVariable ().
+
+**/
+EFI_STATUS
+BmAddOptionNumberToOrderVariable (
+ IN CHAR16 *OptionOrderName,
+ IN UINT16 OptionNumber,
+ IN UINTN Position
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT16 *OptionOrder;
+ UINT16 *NewOptionOrder;
+ UINTN OptionOrderSize;
+ //
+ // Update the option order variable
+ //
+ GetEfiGlobalVariable2 (OptionOrderName, (VOID **) &OptionOrder, &OptionOrderSize);
+
+ Status = EFI_SUCCESS;
+ for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
+ if (OptionOrder[Index] == OptionNumber) {
+ Status = EFI_ALREADY_STARTED;
+ break;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Position = MIN (Position, OptionOrderSize / sizeof (UINT16));
+
+ NewOptionOrder = AllocatePool (OptionOrderSize + sizeof (UINT16));
+ ASSERT (NewOptionOrder != NULL);
+ if (OptionOrderSize != 0) {
+ CopyMem (NewOptionOrder, OptionOrder, Position * sizeof (UINT16));
+ CopyMem (&NewOptionOrder[Position + 1], &OptionOrder[Position], OptionOrderSize - Position * sizeof (UINT16));
+ }
+ NewOptionOrder[Position] = OptionNumber;
+
+ Status = gRT->SetVariable (
+ OptionOrderName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ OptionOrderSize + sizeof (UINT16),
+ NewOptionOrder
+ );
+ FreePool (NewOptionOrder);
+ }
+
+ if (OptionOrder != NULL) {
+ FreePool (OptionOrder);
+ }
+
+ return Status;
+}
+
+/**
+ This function will register the new Boot####, Driver#### or SysPrep#### option.
+ After the *#### is updated, the *Order will also be updated.
@param Option Pointer to load option to add.
@param Position Position of the new load option to put in the ****Order variable.
- @retval EFI_SUCCESS The boot#### or driver#### have been successfully registered.
+ @retval EFI_SUCCESS The *#### have been successfully registered.
@retval EFI_INVALID_PARAMETER The option number exceeds 0xFFFF.
@retval EFI_ALREADY_STARTED The option number of Option is being used already.
Note: this API only adds new load option, no replacement support.
return EFI_INVALID_PARAMETER;
}
+ if (Option->OptionType != LoadOptionTypeDriver &&
+ Option->OptionType != LoadOptionTypeSysPrep &&
+ Option->OptionType != LoadOptionTypeBoot
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
//
// Get the free option number if the option number is unassigned
//
if (Option->OptionNumber == LoadOptionNumberUnassigned) {
- Status = BmGetFreeOptionNumber (
- Option->OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
- &OptionNumber
- );
+ Status = BmGetFreeOptionNumber (Option->OptionType, &OptionNumber);
if (EFI_ERROR (Status)) {
return Status;
}
return EFI_INVALID_PARAMETER;
}
- Status = BmAddOptionNumberToOrderVariable (
- Option->OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
- (UINT16) Option->OptionNumber,
- Position
- );
+ Status = BmAddOptionNumberToOrderVariable (mBmLoadOptionOrderName[Option->OptionType], (UINT16) Option->OptionNumber, Position);
if (!EFI_ERROR (Status)) {
//
// Save the Boot#### or Driver#### variable
Status = EfiBootManagerLoadOptionToVariable (Option);
if (EFI_ERROR (Status)) {
//
- // Remove the #### from *Order variable when the Boot####/Driver#### cannot be saved.
+ // Remove the #### from *Order variable when the Driver####/SysPrep####/Boot#### cannot be saved.
//
EfiBootManagerDeleteLoadOptionVariable (Option->OptionNumber, Option->OptionType);
}
}
Status = gRT->SetVariable (
- OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
+ mBmLoadOptionOrderName[OptionType],
&gEfiGlobalVariableGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
LoadOptionCount * sizeof (UINT16),
return EFI_INVALID_PARAMETER;
}
+ if ((UINT32) OptionType >= LoadOptionTypeMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
Option->OptionNumber = OptionNumber;
Option->OptionType = OptionType;
}
/**
- Update the BootOrder or DriverOrder to delete OptionNumber .
-
- @param OptionOrderVariable Order variable name which need to be updated.
- @param OptionNumber Indicate the option number of load option
-
- @retval EFI_NOT_FOUND The load option cannot be found
- @retval EFI_SUCCESS The load option was deleted
- @retval others Status of RT->SetVariable()
-**/
-EFI_STATUS
-BmDeleteOptionVariable (
- IN CHAR16 *OptionOrderVariable,
- IN UINT16 OptionNumber
- )
-{
- UINT16 *OptionOrder;
- UINTN OptionOrderSize;
- EFI_STATUS Status;
- UINTN Index;
-
- Status = EFI_NOT_FOUND;
- GetEfiGlobalVariable2 (OptionOrderVariable, (VOID **) &OptionOrder, &OptionOrderSize);
- for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
- if (OptionOrder[Index] == OptionNumber) {
- OptionOrderSize -= sizeof (UINT16);
- CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16));
- Status = gRT->SetVariable (
- OptionOrderVariable,
- &gEfiGlobalVariableGuid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
- OptionOrderSize,
- OptionOrder
- );
- break;
- }
- }
- if (OptionOrder != NULL) {
- FreePool (OptionOrder);
- }
-
- return Status;
-}
+ Delete the load option.
-/**
- Update the BootOrder or DriverOrder according to the OptionType to delete OptionNumber .
-
@param OptionNumber Indicate the option number of load option
@param OptionType Indicate the type of load option
@retval EFI_INVALID_PARAMETER OptionType or OptionNumber is invalid.
@retval EFI_NOT_FOUND The load option cannot be found
@retval EFI_SUCCESS The load option was deleted
+ @retval others Status of RT->SetVariable()
**/
EFI_STATUS
EFIAPI
IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType
)
{
- if ((OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) {
+ UINT16 *OptionOrder;
+ UINTN OptionOrderSize;
+ EFI_STATUS Status;
+ UINTN Index;
+
+ if (((UINT32) OptionType >= LoadOptionTypeMax) || (OptionNumber >= LoadOptionNumberMax)) {
return EFI_INVALID_PARAMETER;
}
- return BmDeleteOptionVariable (
- OptionType == LoadOptionTypeBoot ? L"BootOrder" : L"DriverOrder",
- (UINT16) OptionNumber
- );
+ Status = EFI_NOT_FOUND;
+
+ if (OptionType == LoadOptionTypeDriver || OptionType == LoadOptionTypeSysPrep || OptionType == LoadOptionTypeBoot) {
+ //
+ // If the associated *Order exists, just remove the reference in *Order.
+ //
+ GetEfiGlobalVariable2 (mBmLoadOptionOrderName[OptionType], &OptionOrder, &OptionOrderSize);
+ for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
+ if (OptionOrder[Index] == OptionNumber) {
+ OptionOrderSize -= sizeof (UINT16);
+ CopyMem (&OptionOrder[Index], &OptionOrder[Index + 1], OptionOrderSize - Index * sizeof (UINT16));
+ Status = gRT->SetVariable (
+ mBmLoadOptionOrderName[OptionType],
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ OptionOrderSize,
+ OptionOrder
+ );
+ break;
+ }
+ }
+ if (OptionOrder != NULL) {
+ FreePool (OptionOrder);
+ }
+ }
+
+ return Status;
}
/**
}
ASSERT (FALSE);
- return 0;
+ return (UINTN) -1;
}
/**
}
/**
- Validate the EFI Boot#### variable (VendorGuid/Name)
+ Validate the Boot####, Driver####, SysPrep#### variable (VendorGuid/Name)
- @param Variable Boot#### variable data.
- @param VariableSize Returns the size of the EFI variable that was read
+ @param Variable The variable data.
+ @param VariableSize The variable size.
@retval TRUE The variable data is correct.
@retval FALSE The variable data is corrupted.
)
{
UINT16 FilePathSize;
- UINT8 *TempPtr;
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
- UINTN TempSize;
+ UINTN DescriptionSize;
if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
return FALSE;
//
// Skip the option attribute
//
- TempPtr = Variable;
- TempPtr += sizeof (UINT32);
+ Variable += sizeof (UINT32);
//
// Get the option's device path size
//
- FilePathSize = *(UINT16 *) TempPtr;
- TempPtr += sizeof (UINT16);
+ FilePathSize = ReadUnaligned16 ((UINT16 *) Variable);
+ Variable += sizeof (UINT16);
//
// Get the option's description string size
//
- TempSize = BmStrSizeEx ((CHAR16 *) TempPtr, VariableSize - sizeof (UINT16) - sizeof (UINT32));
- TempPtr += TempSize;
+ DescriptionSize = BmStrSizeEx ((CHAR16 *) Variable, VariableSize - sizeof (UINT16) - sizeof (UINT32));
+ Variable += DescriptionSize;
//
// Get the option's device path
//
- DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
- TempPtr += FilePathSize;
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Variable;
//
// Validation boot option variable.
//
- if ((FilePathSize == 0) || (TempSize == 0)) {
+ if ((FilePathSize == 0) || (DescriptionSize == 0)) {
return FALSE;
}
- if (TempSize + FilePathSize + sizeof (UINT16) + sizeof (UINT32) > VariableSize) {
+ if (sizeof (UINT32) + sizeof (UINT16) + DescriptionSize + FilePathSize > VariableSize) {
return FALSE;
}
return (BOOLEAN) (BmGetDevicePathSizeEx (DevicePath, FilePathSize) != 0);
}
+/**
+ Check whether the VariableName is a valid load option variable name
+ and return the load option type and option number.
+
+ @param VariableName The name of the load option variable.
+ @param OptionType Return the load option type.
+ @param OptionNumber Return the load option number.
+
+ @retval TRUE The variable name is valid; The load option type and
+ load option number is returned.
+ @retval FALSE The variable name is NOT valid.
+**/
+BOOLEAN
+BmIsValidLoadOptionVariableName (
+ IN CHAR16 *VariableName,
+ OUT EFI_BOOT_MANAGER_LOAD_OPTION_TYPE *OptionType,
+ OUT UINT16 *OptionNumber
+ )
+{
+ UINTN VariableNameLen;
+ UINTN Index;
+ UINTN Uint;
+
+ VariableNameLen = StrLen (VariableName);
+
+ if (VariableNameLen <= 4) {
+ return FALSE;
+ }
+
+ for (Index = 0; Index < sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0]); Index++) {
+ if ((VariableNameLen - 4 == StrLen (mBmLoadOptionName[Index])) &&
+ (StrnCmp (VariableName, mBmLoadOptionName[Index], VariableNameLen - 4) == 0)
+ ) {
+ break;
+ }
+ }
+
+ if (Index == sizeof (mBmLoadOptionName) / sizeof (mBmLoadOptionName[0])) {
+ return FALSE;
+ }
+
+ *OptionType = (EFI_BOOT_MANAGER_LOAD_OPTION_TYPE) Index;
+ *OptionNumber = 0;
+ for (Index = VariableNameLen - 4; Index < VariableNameLen; Index++) {
+ Uint = BmCharToUint (VariableName[Index]);
+ if (Uint == -1) {
+ break;
+ } else {
+ *OptionNumber = (UINT16) Uint + *OptionNumber * 0x10;
+ }
+ }
+
+ return (BOOLEAN) (Index == VariableNameLen);
+}
+
/**
Build the Boot#### or Driver#### option from the VariableName.
- @param VariableName EFI Variable name indicate if it is Boot#### or
- Driver####
- @param Option Return the Boot#### or Driver#### option.
+ @param VariableName Variable name of the load option
+ @param VendorGuid Variable GUID of the load option
+ @param Option Return the load option.
@retval EFI_SUCCESS Get the option just been created
@retval EFI_NOT_FOUND Failed to get the new option
**/
EFI_STATUS
EFIAPI
-EfiBootManagerVariableToLoadOption (
- IN CHAR16 *VariableName,
- IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
+EfiBootManagerVariableToLoadOptionEx (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
)
{
EFI_STATUS Status;
UINT32 Attribute;
UINT16 FilePathSize;
UINT8 *Variable;
- UINT8 *TempPtr;
+ UINT8 *VariablePtr;
UINTN VariableSize;
EFI_DEVICE_PATH_PROTOCOL *FilePath;
UINT8 *OptionalData;
UINT32 OptionalDataSize;
CHAR16 *Description;
- UINT8 NumOff;
EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;
UINT16 OptionNumber;
return EFI_INVALID_PARAMETER;
}
+ if (!BmIsValidLoadOptionVariableName (VariableName, &OptionType, &OptionNumber)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
//
// Read the variable
//
- GetEfiGlobalVariable2 (VariableName, (VOID **) &Variable, &VariableSize);
+ GetVariable2 (VariableName, VendorGuid, (VOID **) &Variable, &VariableSize);
if (Variable == NULL) {
return EFI_NOT_FOUND;
}
//
- // Validate Boot#### variable data.
+ // Validate *#### variable data.
//
if (!BmValidateOption(Variable, VariableSize)) {
FreePool (Variable);
return EFI_INVALID_PARAMETER;
}
- //
- // Notes: careful defined the variable of Boot#### or
- // Driver####, consider use some macro to abstract the code
- //
//
// Get the option attribute
//
- TempPtr = Variable;
- Attribute = *(UINT32 *) Variable;
- TempPtr += sizeof (UINT32);
+ VariablePtr = Variable;
+ Attribute = ReadUnaligned32 ((UINT32 *) VariablePtr);
+ VariablePtr += sizeof (UINT32);
//
// Get the option's device path size
//
- FilePathSize = *(UINT16 *) TempPtr;
- TempPtr += sizeof (UINT16);
+ FilePathSize = ReadUnaligned16 ((UINT16 *) VariablePtr);
+ VariablePtr += sizeof (UINT16);
//
// Get the option's description string
//
- Description = (CHAR16 *) TempPtr;
+ Description = (CHAR16 *) VariablePtr;
//
// Get the option's description string size
//
- TempPtr += StrSize ((CHAR16 *) TempPtr);
+ VariablePtr += StrSize ((CHAR16 *) VariablePtr);
//
// Get the option's device path
//
- FilePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
- TempPtr += FilePathSize;
+ FilePath = (EFI_DEVICE_PATH_PROTOCOL *) VariablePtr;
+ VariablePtr += FilePathSize;
- OptionalDataSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));
+ OptionalDataSize = (UINT32) (VariableSize - (UINTN) (VariablePtr - Variable));
if (OptionalDataSize == 0) {
OptionalData = NULL;
} else {
- OptionalData = TempPtr;
+ OptionalData = VariablePtr;
}
- if (*VariableName == L'B') {
- OptionType = LoadOptionTypeBoot;
- NumOff = (UINT8) (sizeof (L"Boot") / sizeof (CHAR16) - 1);
- } else {
- OptionType = LoadOptionTypeDriver;
- NumOff = (UINT8) (sizeof (L"Driver") / sizeof (CHAR16) - 1);
- }
-
- //
- // Get the value from VariableName Unicode string
- // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this
- // Unicode stream to ASCII without any loss in meaning.
- //
- OptionNumber = (UINT16) (BmCharToUint (VariableName[NumOff+0]) * 0x1000)
- + (UINT16) (BmCharToUint (VariableName[NumOff+1]) * 0x100)
- + (UINT16) (BmCharToUint (VariableName[NumOff+2]) * 0x10)
- + (UINT16) (BmCharToUint (VariableName[NumOff+3]) * 0x1);
-
Status = EfiBootManagerInitializeLoadOption (
Option,
OptionNumber,
OptionalDataSize
);
ASSERT_EFI_ERROR (Status);
-
+
+ CopyGuid (&Option->VendorGuid, VendorGuid);
+
FreePool (Variable);
return Status;
}
+/**
+Build the Boot#### or Driver#### option from the VariableName.
+
+@param VariableName EFI Variable name indicate if it is Boot#### or Driver####
+@param Option Return the Boot#### or Driver#### option.
+
+@retval EFI_SUCCESS Get the option just been created
+@retval EFI_NOT_FOUND Failed to get the new option
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerVariableToLoadOption (
+ IN CHAR16 *VariableName,
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *Option
+ )
+{
+ return EfiBootManagerVariableToLoadOptionEx (VariableName, &gEfiGlobalVariableGuid, Option);
+}
+
/**
Returns an array of load options based on the EFI variable
L"BootOrder"/L"DriverOrder" and the L"Boot####"/L"Driver####" variables impled by it.
UINTN OptionOrderSize;
UINTN Index;
UINTN OptionIndex;
- EFI_BOOT_MANAGER_LOAD_OPTION *Option;
- CHAR16 OptionName[sizeof ("Driver####")];
+ EFI_BOOT_MANAGER_LOAD_OPTION *Options;
+ CHAR16 OptionName[BM_OPTION_NAME_LEN];
UINT16 OptionNumber;
*OptionCount = 0;
- //
- // Read the BootOrder, or DriverOrder variable.
- //
- GetEfiGlobalVariable2 (
- (LoadOptionType == LoadOptionTypeBoot) ? L"BootOrder" : L"DriverOrder",
- (VOID **) &OptionOrder,
- &OptionOrderSize
- );
- if (OptionOrder == NULL) {
- return NULL;
- }
+ if (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep || LoadOptionType == LoadOptionTypeBoot) {
+ //
+ // Read the BootOrder, or DriverOrder variable.
+ //
+ GetEfiGlobalVariable2 (mBmLoadOptionOrderName[LoadOptionType], (VOID **) &OptionOrder, &OptionOrderSize);
+ if (OptionOrder == NULL) {
+ return NULL;
+ }
- *OptionCount = OptionOrderSize / sizeof (UINT16);
+ *OptionCount = OptionOrderSize / sizeof (UINT16);
- Option = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
- ASSERT (Option != NULL);
+ Options = AllocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
+ ASSERT (Options != NULL);
- OptionIndex = 0;
- for (Index = 0; Index < *OptionCount; Index++) {
- OptionNumber = OptionOrder[Index];
- if (LoadOptionType == LoadOptionTypeBoot) {
- UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionNumber);
- } else {
- UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionNumber);
+ OptionIndex = 0;
+ for (Index = 0; Index < *OptionCount; Index++) {
+ OptionNumber = OptionOrder[Index];
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"%s%04x", mBmLoadOptionName[LoadOptionType], OptionNumber);
+
+ Status = EfiBootManagerVariableToLoadOption (OptionName, &Options[OptionIndex]);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName));
+ EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionType);
+ } else {
+ ASSERT (Options[OptionIndex].OptionNumber == OptionNumber);
+ OptionIndex++;
+ }
}
- Status = EfiBootManagerVariableToLoadOption (OptionName, &Option[OptionIndex]);
- if (EFI_ERROR (Status)) {
- DEBUG ((EFI_D_INFO, "[Bds] %s doesn't exist - Update ****Order variable to remove the reference!!", OptionName));
- EfiBootManagerDeleteLoadOptionVariable (OptionNumber, LoadOptionTypeBoot);
- } else {
- ASSERT (Option[OptionIndex].OptionNumber == OptionNumber);
- OptionIndex++;
+ if (OptionOrder != NULL) {
+ FreePool (OptionOrder);
}
- }
- if (OptionOrder != NULL) {
- FreePool (OptionOrder);
- }
+ if (OptionIndex < *OptionCount) {
+ Options = ReallocatePool (*OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION), Options);
+ ASSERT (Options != NULL);
+ *OptionCount = OptionIndex;
+ }
- if (OptionIndex < *OptionCount) {
- Option = ReallocatePool (
- *OptionCount * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
- OptionIndex * sizeof (EFI_BOOT_MANAGER_LOAD_OPTION),
- Option
- );
- ASSERT (Option != NULL);
- *OptionCount = OptionIndex;
+ } else {
+ return NULL;
}
- return Option;
+ return Options;
}
/**
return EFI_SUCCESS;
}
+
+/**
+ Return whether the PE header of the load option is valid or not.
+
+ @param[in] Type The load option type.
+ @param[in] FileBuffer The PE file buffer of the load option.
+ @param[in] FileSize The size of the load option file.
+
+ @retval TRUE The PE header of the load option is valid.
+ @retval FALSE The PE header of the load option is not valid.
+**/
+BOOLEAN
+BmIsLoadOptionPeHeaderValid (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize
+ )
+{
+ EFI_IMAGE_DOS_HEADER *DosHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHeader;
+ EFI_IMAGE_OPTIONAL_HEADER32 *OptionalHeader;
+ UINT16 Subsystem;
+
+ if (FileBuffer == NULL || FileSize == 0) {
+ return FALSE;
+ }
+
+ //
+ // Read dos header
+ //
+ DosHeader = (EFI_IMAGE_DOS_HEADER *) FileBuffer;
+ if (FileSize >= sizeof (EFI_IMAGE_DOS_HEADER) &&
+ FileSize > DosHeader->e_lfanew && DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE
+ ) {
+ //
+ // Read and check PE signature
+ //
+ PeHeader = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) FileBuffer + DosHeader->e_lfanew);
+ if (FileSize >= DosHeader->e_lfanew + sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) &&
+ PeHeader->Pe32.Signature == EFI_IMAGE_NT_SIGNATURE
+ ) {
+ //
+ // Check PE32 or PE32+ magic, and machine type
+ //
+ OptionalHeader = (EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHeader->Pe32.OptionalHeader;
+ if ((OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC ||
+ OptionalHeader->Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) &&
+ EFI_IMAGE_MACHINE_TYPE_SUPPORTED (PeHeader->Pe32.FileHeader.Machine)
+ ) {
+ //
+ // Check the Subsystem:
+ // Driver#### must be of type BootServiceDriver or RuntimeDriver
+ // SysPrep####, Boot####, OsRecovery####, PlatformRecovery#### must be of type Application
+ //
+ Subsystem = OptionalHeader->Subsystem;
+ if ((Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
+ (Type == LoadOptionTypeDriver && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) ||
+ (Type == LoadOptionTypeSysPrep && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) ||
+ (Type == LoadOptionTypeBoot && Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)
+ ) {
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Process (load and execute) the load option.
+
+ @param LoadOption Pointer to the load option.
+
+ @retval EFI_INVALID_PARAMETER The load option type is invalid,
+ or the load option file path doesn't point to a valid file.
+ @retval EFI_UNSUPPORTED The load option type is of LoadOptionTypeBoot.
+ @retval EFI_SUCCESS The load option is inactive, or successfully loaded and executed.
+**/
+EFI_STATUS
+EFIAPI
+EfiBootManagerProcessLoadOption (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOption
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ EFI_HANDLE ImageHandle;
+ EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
+ VOID *FileBuffer;
+ UINTN FileSize;
+
+ if ((UINT32) LoadOption->OptionType >= LoadOptionTypeMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (LoadOption->OptionType == LoadOptionTypeBoot) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // If a load option is not marked as LOAD_OPTION_ACTIVE,
+ // the boot manager will not automatically load the option.
+ //
+ if ((LoadOption->Attributes & LOAD_OPTION_ACTIVE) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ Status = EFI_INVALID_PARAMETER;
+
+ //
+ // Load and start the load option.
+ //
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD, "Process Load Option (%s%04x) ...\n",
+ mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber
+ ));
+ ImageHandle = NULL;
+ FileBuffer = BmGetLoadOptionBuffer (LoadOption->FilePath, &FilePath, &FileSize);
+ DEBUG_CODE (
+ if (FileBuffer != NULL && CompareMem (LoadOption->FilePath, FilePath, GetDevicePathSize (FilePath)) != 0) {
+ DEBUG ((EFI_D_INFO, "[Bds] DevicePath expand: "));
+ BmPrintDp (LoadOption->FilePath);
+ DEBUG ((EFI_D_INFO, " -> "));
+ BmPrintDp (FilePath);
+ DEBUG ((EFI_D_INFO, "\n"));
+ }
+ );
+ if (BmIsLoadOptionPeHeaderValid (LoadOption->OptionType, FileBuffer, FileSize)) {
+ Status = gBS->LoadImage (
+ FALSE,
+ gImageHandle,
+ FilePath,
+ FileBuffer,
+ FileSize,
+ &ImageHandle
+ );
+ }
+ if (FilePath != NULL) {
+ FreePool (FilePath);
+ }
+ if (FileBuffer != NULL) {
+ FreePool (FileBuffer);
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ ImageInfo->LoadOptionsSize = LoadOption->OptionalDataSize;
+ ImageInfo->LoadOptions = LoadOption->OptionalData;
+ //
+ // Before calling the image, enable the Watchdog Timer for the 5-minute period
+ //
+ gBS->SetWatchdogTimer (5 * 60, 0, 0, NULL);
+
+ LoadOption->Status = gBS->StartImage (ImageHandle, &LoadOption->ExitDataSize, &LoadOption->ExitData);
+ DEBUG ((
+ DEBUG_INFO | DEBUG_LOAD, "Load Option (%s%04x) Return Status = %r\n",
+ mBmLoadOptionName[LoadOption->OptionType], LoadOption->OptionNumber, LoadOption->Status
+ ));
+
+ //
+ // Clear the Watchdog Timer after the image returns
+ //
+ gBS->SetWatchdogTimer (0, 0, 0, NULL);
+ }
+
+ return Status;
+}
return FALSE;
}
-/**
- Get the headers (dos, image, optional header) from an image
-
- @param Device SimpleFileSystem device handle
- @param FileName File name for the image
- @param DosHeader Pointer to dos header
- @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
-
- @retval EFI_SUCCESS Successfully get the machine type.
- @retval EFI_NOT_FOUND The file is not found.
- @retval EFI_LOAD_ERROR File is not a valid image file.
-
-**/
-EFI_STATUS
-BmGetImageHeader (
- IN EFI_HANDLE Device,
- IN CHAR16 *FileName,
- OUT EFI_IMAGE_DOS_HEADER *DosHeader,
- OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
- )
-{
- EFI_STATUS Status;
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
- EFI_FILE_HANDLE Root;
- EFI_FILE_HANDLE ThisFile;
- UINTN BufferSize;
- UINT64 FileSize;
- EFI_FILE_INFO *Info;
-
- Root = NULL;
- ThisFile = NULL;
- //
- // Handle the file system interface to the device
- //
- Status = gBS->HandleProtocol (
- Device,
- &gEfiSimpleFileSystemProtocolGuid,
- (VOID *) &Volume
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- Status = Volume->OpenVolume (
- Volume,
- &Root
- );
- if (EFI_ERROR (Status)) {
- Root = NULL;
- goto Done;
- }
- ASSERT (Root != NULL);
- Status = Root->Open (Root, &ThisFile, FileName, EFI_FILE_MODE_READ, 0);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- ASSERT (ThisFile != NULL);
-
- //
- // Get file size
- //
- BufferSize = SIZE_OF_EFI_FILE_INFO + 200;
- do {
- Info = NULL;
- Status = gBS->AllocatePool (EfiBootServicesData, BufferSize, (VOID **) &Info);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- Status = ThisFile->GetInfo (
- ThisFile,
- &gEfiFileInfoGuid,
- &BufferSize,
- Info
- );
- if (!EFI_ERROR (Status)) {
- break;
- }
- if (Status != EFI_BUFFER_TOO_SMALL) {
- FreePool (Info);
- goto Done;
- }
- FreePool (Info);
- } while (TRUE);
-
- FileSize = Info->FileSize;
- FreePool (Info);
-
- //
- // Read dos header
- //
- BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
- Status = ThisFile->Read (ThisFile, &BufferSize, DosHeader);
- if (EFI_ERROR (Status) ||
- BufferSize < sizeof (EFI_IMAGE_DOS_HEADER) ||
- FileSize <= DosHeader->e_lfanew ||
- DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
- Status = EFI_LOAD_ERROR;
- goto Done;
- }
-
- //
- // Move to PE signature
- //
- Status = ThisFile->SetPosition (ThisFile, DosHeader->e_lfanew);
- if (EFI_ERROR (Status)) {
- Status = EFI_LOAD_ERROR;
- goto Done;
- }
-
- //
- // Read and check PE signature
- //
- BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
- Status = ThisFile->Read (ThisFile, &BufferSize, Hdr.Pe32);
- if (EFI_ERROR (Status) ||
- BufferSize < sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) ||
- Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
- Status = EFI_LOAD_ERROR;
- goto Done;
- }
-
- //
- // Check PE32 or PE32+ magic
- //
- if (Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
- Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
- Status = EFI_LOAD_ERROR;
- goto Done;
- }
-
- Done:
- if (ThisFile != NULL) {
- ThisFile->Close (ThisFile);
- }
- if (Root != NULL) {
- Root->Close (Root);
- }
- return Status;
-}
-
/**
This routine adjust the memory information for different memory type and
save them into the variables for next boot.
return Status;
}
+
+/**
+ Print the device path info.
+
+ @param DevicePath The device path need to print.
+**/
+VOID
+BmPrintDp (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ CHAR16 *Str;
+
+ Str = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
+ DEBUG ((EFI_D_INFO, "%s", Str));
+ if (Str != NULL) {
+ FreePool (Str);
+ }
+}
IN EFI_HANDLE Handle
);
+#define BM_OPTION_NAME_LEN sizeof ("SysPrep####")
+extern CHAR16 *mBmLoadOptionName[];
+
+typedef
+VOID
+(*VARIABLE_VISITOR) (
+ CHAR16 *Name,
+ EFI_GUID *Guid,
+ VOID *Context
+ );
+
+/**
+ Call Visitor function for each variable in variable storage.
+
+ @param Visitor Visitor function.
+ @param Context The context passed to Visitor function.
+**/
+VOID
+ForEachVariable (
+ VARIABLE_VISITOR Visitor,
+ VOID *Context
+ );
+
+/**
+ Repair all the controllers according to the Driver Health status queried.
+**/
+VOID
+BmRepairAllControllers (
+ VOID
+ );
+
#define BM_HOTKEY_SIGNATURE SIGNATURE_32 ('b', 'm', 'h', 'k')
typedef struct {
UINT32 Signature;
/**
Get the Option Number that wasn't used.
- @param OrderVariableName Could be L"BootOrder" or L"DriverOrder".
+ @param LoadOptionType Load option type.
@param FreeOptionNumber To receive the minimal free option number.
@retval EFI_SUCCESS The option number is found
**/
EFI_STATUS
BmGetFreeOptionNumber (
- IN CHAR16 *OrderVariableName,
- OUT UINT16 *FreeOptionNumber
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType,
+ OUT UINT16 *FreeOptionNumber
);
/**
IN VOID *Data
);
+/**
+ Get the load option by its device path.
+
+ @param FilePath The device path pointing to a load option.
+ It could be a short-form device path.
+ @param FullPath Return the full device path of the load option after
+ short-form device path expanding.
+ Caller is responsible to free it.
+ @param FileSize Return the load option size.
+
+ @return The load option buffer. Caller is responsible to free the memory.
+**/
+VOID *
+BmGetLoadOptionBuffer (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
+ OUT UINTN *FileSize
+ );
+
+/**
+ Return whether the PE header of the load option is valid or not.
+
+ @param[in] Type The load option type.
+ @param[in] FileBuffer The PE file buffer of the load option.
+ @param[in] FileSize The size of the load option file.
+
+ @retval TRUE The PE header of the load option is valid.
+ @retval FALSE The PE header of the load option is not valid.
+**/
+BOOLEAN
+BmIsLoadOptionPeHeaderValid (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION_TYPE Type,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize
+ );
+
/**
Function compares a device path data structure to that of all the nodes of a
second device path instance.
VOID
);
+/**
+ Print the device path info.
+
+ @param DevicePath The device path need to print.
+**/
+VOID
+BmPrintDp (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
#endif // _INTERNAL_BM_H_
EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME\r
};\r
\r
+CHAR16 *mBdsLoadOptionName[] = {\r
+ L"Driver",\r
+ L"SysPrep",\r
+ L"Boot"\r
+};\r
+\r
CHAR16 mRecoveryBoot[] = L"Recovery Boot";\r
/**\r
Event to Connect ConIn.\r
// Should not enter this case, if enter, the keyboard will not work.\r
// May need platfrom policy to connect keyboard.\r
//\r
- DEBUG ((EFI_D_WARN, "[Bds] ASSERT Connect ConIn failed!!!\n"));\r
+ DEBUG ((EFI_D_WARN, "[Bds] Connect ConIn failed - %r!!!\n", Status));\r
}\r
}\r
\r
}\r
\r
/**\r
- The function will go through the driver option link list, load and start\r
- every driver the driver option device path point to.\r
+ The function will load and start every Driver####/SysPrep####.\r
\r
- @param DriverOption Input driver option array.\r
- @param DriverOptionCount Input driver option count.\r
+ @param LoadOptions Load option array.\r
+ @param LoadOptionCount Load option count.\r
\r
**/\r
VOID\r
-LoadDrivers (\r
- IN EFI_BOOT_MANAGER_LOAD_OPTION *DriverOption,\r
- IN UINTN DriverOptionCount\r
+ProcessLoadOptions (\r
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions,\r
+ IN UINTN LoadOptionCount\r
)\r
{\r
- EFI_STATUS Status;\r
- UINTN Index;\r
- EFI_HANDLE ImageHandle;\r
- EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;\r
- BOOLEAN ReconnectAll;\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ BOOLEAN ReconnectAll;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;\r
\r
ReconnectAll = FALSE;\r
+ LoadOptionType = LoadOptionTypeMax;\r
\r
//\r
// Process the driver option\r
//\r
- for (Index = 0; Index < DriverOptionCount; Index++) {\r
+ for (Index = 0; Index < LoadOptionCount; Index++) {\r
//\r
- // If a load option is not marked as LOAD_OPTION_ACTIVE,\r
- // the boot manager will not automatically load the option.\r
+ // All the load options in the array should be of the same type.\r
//\r
- if ((DriverOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) {\r
- continue;\r
- }\r
- \r
- //\r
- // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,\r
- // then all of the EFI drivers in the system will be disconnected and\r
- // reconnected after the last driver load option is processed.\r
- //\r
- if ((DriverOption[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0) {\r
- ReconnectAll = TRUE;\r
+ if (LoadOptionType == LoadOptionTypeMax) {\r
+ LoadOptionType = LoadOptions[Index].OptionType;\r
}\r
- \r
- //\r
- // Make sure the driver path is connected.\r
- //\r
- EfiBootManagerConnectDevicePath (DriverOption[Index].FilePath, NULL);\r
+ ASSERT (LoadOptionType == LoadOptions[Index].OptionType);\r
+ ASSERT (LoadOptionType == LoadOptionTypeDriver || LoadOptionType == LoadOptionTypeSysPrep);\r
\r
- //\r
- // Load and start the image that Driver#### describes\r
- //\r
- Status = gBS->LoadImage (\r
- FALSE,\r
- gImageHandle,\r
- DriverOption[Index].FilePath,\r
- NULL,\r
- 0,\r
- &ImageHandle\r
- );\r
+ Status = EfiBootManagerProcessLoadOption (&LoadOptions[Index]);\r
\r
- if (!EFI_ERROR (Status)) {\r
- gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);\r
-\r
- //\r
- // Verify whether this image is a driver, if not,\r
- // exit it and continue to parse next load option\r
- //\r
- if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) {\r
- gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);\r
- continue;\r
- }\r
-\r
- ImageInfo->LoadOptionsSize = DriverOption[Index].OptionalDataSize;\r
- ImageInfo->LoadOptions = DriverOption[Index].OptionalData;\r
- //\r
- // Before calling the image, enable the Watchdog Timer for\r
- // the 5 Minute period\r
- //\r
- gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
-\r
- DriverOption[Index].Status = gBS->StartImage (ImageHandle, &DriverOption[Index].ExitDataSize, &DriverOption[Index].ExitData);\r
- DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Driver Return Status = %r\n", DriverOption[Index].Status));\r
-\r
- //\r
- // Clear the Watchdog Timer after the image returns\r
- //\r
- gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
+ if (!EFI_ERROR (Status) && ((LoadOptions[Index].Attributes & LOAD_OPTION_FORCE_RECONNECT) != 0)) {\r
+ ReconnectAll = TRUE;\r
}\r
}\r
- \r
+\r
//\r
- // Process the LOAD_OPTION_FORCE_RECONNECT driver option\r
+ // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,\r
+ // then all of the EFI drivers in the system will be disconnected and\r
+ // reconnected after the last driver load option is processed.\r
//\r
- if (ReconnectAll) {\r
+ if (ReconnectAll && LoadOptionType == LoadOptionTypeDriver) {\r
EfiBootManagerDisconnectAll ();\r
EfiBootManagerConnectAll ();\r
}\r
-\r
}\r
\r
/**\r
IN EFI_BDS_ARCH_PROTOCOL *This\r
)\r
{\r
- EFI_BOOT_MANAGER_LOAD_OPTION *DriverOption;\r
- EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
- UINTN DriverOptionCount;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION *LoadOptions;\r
+ UINTN LoadOptionCount;\r
CHAR16 *FirmwareVendor;\r
EFI_EVENT HotkeyTriggered;\r
UINT64 OsIndication;\r
UINT16 BootTimeOut;\r
EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
UINTN Index;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
UINT16 *BootNext;\r
CHAR16 BootNextVariableName[sizeof ("Boot####")];\r
+ EFI_BOOT_MANAGER_LOAD_OPTION BootManagerMenu;\r
+ BOOLEAN BootFwUi;\r
\r
HotkeyTriggered = NULL;\r
Status = EFI_SUCCESS;\r
// Initialize L"BootOptionSupport" EFI global variable.\r
// Lazy-ConIn implictly disables BDS hotkey.\r
//\r
- BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP;\r
+ BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP | EFI_BOOT_OPTION_SUPPORT_SYSPREP;\r
if (!PcdGetBool (PcdConInConnectOnDemand)) {\r
BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;\r
SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);\r
EfiBootManagerStartHotkeyService (&HotkeyTriggered);\r
\r
//\r
- // Load Driver Options\r
+ // Execute Driver Options\r
//\r
- DriverOption = EfiBootManagerGetLoadOptions (&DriverOptionCount, LoadOptionTypeDriver);\r
- LoadDrivers (DriverOption, DriverOptionCount);\r
- EfiBootManagerFreeLoadOptions (DriverOption, DriverOptionCount);\r
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeDriver);\r
+ ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
\r
//\r
// Connect consoles\r
PERF_END (NULL, "PlatformBootManagerAfterConsole", "BDS", 0);\r
\r
DEBUG_CODE (\r
- EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;\r
- UINTN BootOptionCount;\r
- UINTN Index;\r
-\r
- BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
- DEBUG ((EFI_D_INFO, "[Bds]=============Dumping Boot Options=============\n"));\r
- for (Index = 0; Index < BootOptionCount; Index++) {\r
+ UINTN Index;\r
+ EFI_BOOT_MANAGER_LOAD_OPTION_TYPE LoadOptionType;\r
+ DEBUG ((EFI_D_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n"));\r
+ for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) {\r
DEBUG ((\r
- EFI_D_INFO, "[Bds]Boot%04x: %s \t\t 0x%04x\n",\r
- BootOptions[Index].OptionNumber, \r
- BootOptions[Index].Description, \r
- BootOptions[Index].Attributes\r
+ EFI_D_INFO, " %s Options:\n",\r
+ mBdsLoadOptionName[LoadOptionType]\r
));\r
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionType);\r
+ for (Index = 0; Index < LoadOptionCount; Index++) {\r
+ DEBUG ((\r
+ EFI_D_INFO, " %s%04x: %s \t\t 0x%04x\n",\r
+ mBdsLoadOptionName[LoadOptionType],\r
+ LoadOptions[Index].OptionNumber,\r
+ LoadOptions[Index].Description,\r
+ LoadOptions[Index].Attributes\r
+ ));\r
+ }\r
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
}\r
- DEBUG ((EFI_D_INFO, "[Bds]=============Dumping Boot Options Finished====\n"));\r
- EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);\r
- );\r
+ DEBUG ((EFI_D_INFO, "[Bds]=============End Load Options Dumping=============\n"));\r
+ );\r
\r
//\r
// Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
&DataSize,\r
&OsIndication\r
);\r
- if (!EFI_ERROR(Status) && ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0)) {\r
- //\r
- // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS\r
- // \r
+ if (EFI_ERROR (Status)) {\r
+ OsIndication = 0;\r
+ }\r
+\r
+ BootFwUi = (BOOLEAN) ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0);\r
+ //\r
+ // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS\r
+ // \r
+ if (BootFwUi) {\r
OsIndication &= ~((UINT64) EFI_OS_INDICATIONS_BOOT_TO_FW_UI);\r
Status = gRT->SetVariable (\r
L"OsIndications",\r
// Changing the content without increasing its size with current variable implementation shouldn't fail.\r
//\r
ASSERT_EFI_ERROR (Status);\r
+ }\r
\r
+ //\r
+ // Launch Boot Manager Menu directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot\r
+ //\r
+ if (BootFwUi) {\r
//\r
// Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI\r
//\r
}\r
\r
//\r
- // Directly boot to Boot Manager Menu.\r
+ // Directly enter the setup page.\r
+ // BootManagerMenu always contains the correct information even call fails.\r
//\r
- EfiBootManagerGetBootManagerMenu (&BootOption);\r
- EfiBootManagerBoot (&BootOption);\r
- EfiBootManagerFreeLoadOption (&BootOption);\r
- } else {\r
- PERF_START (NULL, "BdsWait", "BDS", 0);\r
- BdsWait (HotkeyTriggered);\r
- PERF_END (NULL, "BdsWait", "BDS", 0);\r
-\r
- //\r
- // BdsReadKeys() be removed after all keyboard drivers invoke callback in timer callback.\r
- //\r
- BdsReadKeys ();\r
- \r
- EfiBootManagerHotkeyBoot ();\r
+ EfiBootManagerGetBootManagerMenu (&BootManagerMenu);\r
+ EfiBootManagerBoot (&BootManagerMenu);\r
+ EfiBootManagerFreeLoadOption (&BootManagerMenu);\r
}\r
\r
+ //\r
+ // Execute SysPrep####\r
+ //\r
+ LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);\r
+ ProcessLoadOptions (LoadOptions, LoadOptionCount);\r
+ EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);\r
+\r
+ //\r
+ // Execute Key####\r
+ //\r
+ PERF_START (NULL, "BdsWait", "BDS", 0);\r
+ BdsWait (HotkeyTriggered);\r
+ PERF_END (NULL, "BdsWait", "BDS", 0);\r
+\r
+ //\r
+ // BdsReadKeys() be removed after all keyboard drivers invoke callback in timer callback.\r
+ //\r
+ BdsReadKeys ();\r
+\r
+ EfiBootManagerHotkeyBoot ();\r
+\r
//\r
// Boot to "BootNext"\r
//\r