mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 05:38:26 +00:00 
			
		
		
		
	892 Internal Shell sometimes can't boot when boot option is not enumerated git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@4112 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1311 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1311 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*++
 | 
						|
 | 
						|
Copyright (c) 2006 - 2007, Intel Corporation
 | 
						|
All rights reserved. This program and the accompanying materials
 | 
						|
are licensed and made available under the terms and conditions of the BSD License
 | 
						|
which accompanies this distribution.  The full text of the license may be found at
 | 
						|
http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
Module Name:
 | 
						|
 | 
						|
  BdsBoot.c
 | 
						|
 | 
						|
Abstract:
 | 
						|
 | 
						|
  BDS Lib functions which relate with create or process the boot
 | 
						|
  option.
 | 
						|
 | 
						|
--*/
 | 
						|
 | 
						|
#include "EdkGenericBdsLibInternal.h"
 | 
						|
 | 
						|
BOOLEAN mEnumBootDevice = FALSE;
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
BdsLibDoLegacyBoot (
 | 
						|
  IN  BDS_COMMON_OPTION           *Option
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Boot the legacy system with the boot option
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  Option           - The legacy boot option which have BBS device path
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_UNSUPPORTED  - There is no legacybios protocol, do not support
 | 
						|
                     legacy boot.
 | 
						|
 | 
						|
  EFI_STATUS       - Return the status of LegacyBios->LegacyBoot ().
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_LEGACY_BIOS_PROTOCOL  *LegacyBios;
 | 
						|
 | 
						|
  Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, &LegacyBios);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // If no LegacyBios protocol we do not support legacy boot
 | 
						|
    //
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Notes: if we seperate the int 19, then we don't need to refresh BBS
 | 
						|
  //
 | 
						|
  BdsRefreshBbsTableForBoot (Option);
 | 
						|
 | 
						|
  //
 | 
						|
  // Write boot to OS performance data to a file
 | 
						|
  //
 | 
						|
  PERF_CODE (
 | 
						|
    WriteBootToOsPerformanceData ();
 | 
						|
  );
 | 
						|
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Legacy Boot: %S\n", Option->Description));
 | 
						|
  return LegacyBios->LegacyBoot (
 | 
						|
                      LegacyBios,
 | 
						|
                      (BBS_BBS_DEVICE_PATH *) Option->DevicePath,
 | 
						|
                      Option->LoadOptionsSize,
 | 
						|
                      Option->LoadOptions
 | 
						|
                      );
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
BdsLibBootViaBootOption (
 | 
						|
  IN  BDS_COMMON_OPTION             * Option,
 | 
						|
  IN  EFI_DEVICE_PATH_PROTOCOL      * DevicePath,
 | 
						|
  OUT UINTN                         *ExitDataSize,
 | 
						|
  OUT CHAR16                        **ExitData OPTIONAL
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Process the boot option follow the EFI 1.1 specification and
 | 
						|
  special treat the legacy boot option with BBS_DEVICE_PATH.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  Option       - The boot option need to be processed
 | 
						|
 | 
						|
  DevicePath   - The device path which describe where to load
 | 
						|
                 the boot image or the legcy BBS device path
 | 
						|
                 to boot the legacy OS
 | 
						|
 | 
						|
  ExitDataSize - Returned directly from gBS->StartImage ()
 | 
						|
 | 
						|
  ExitData     - Returned directly from gBS->StartImage ()
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS   - Status from gBS->StartImage (),
 | 
						|
                  or BdsBootByDiskSignatureAndPartition ()
 | 
						|
 | 
						|
  EFI_NOT_FOUND - If the Device Path is not found in the system
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_HANDLE                Handle;
 | 
						|
  EFI_HANDLE                ImageHandle;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *FilePath;
 | 
						|
  EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
 | 
						|
  EFI_BLOCK_IO_PROTOCOL     *BlkIo;
 | 
						|
  VOID                      *Buffer;
 | 
						|
  LIST_ENTRY                TempBootLists;
 | 
						|
 | 
						|
  //
 | 
						|
  // Record the performance data for End of BDS
 | 
						|
  //
 | 
						|
  PERF_END (0, BDS_TOK, NULL, 0);
 | 
						|
 | 
						|
  *ExitDataSize = 0;
 | 
						|
  *ExitData     = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Notes: put EFI64 ROM Shadow Solution
 | 
						|
  //
 | 
						|
  EFI64_SHADOW_ALL_LEGACY_ROM ();
 | 
						|
 | 
						|
  //
 | 
						|
  // If it's Device Path that starts with a hard drive path,
 | 
						|
  // this routine will do the booting.
 | 
						|
  //
 | 
						|
  Status = BdsBootByDiskSignatureAndPartition (
 | 
						|
            Option,
 | 
						|
            (HARDDRIVE_DEVICE_PATH *) DevicePath,
 | 
						|
            Option->LoadOptionsSize,
 | 
						|
            Option->LoadOptions,
 | 
						|
            ExitDataSize,
 | 
						|
            ExitData
 | 
						|
            );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // If we found a disk signature and partition device path return success
 | 
						|
    //
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Signal the EFI_EVENT_SIGNAL_READY_TO_BOOT event
 | 
						|
  //
 | 
						|
  EfiSignalEventReadyToBoot ();
 | 
						|
 | 
						|
  //
 | 
						|
  // Set Boot Current
 | 
						|
  //
 | 
						|
  gRT->SetVariable (
 | 
						|
        L"BootCurrent",
 | 
						|
        &gEfiGlobalVariableGuid,
 | 
						|
        EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | 
						|
        sizeof (UINT16),
 | 
						|
        &Option->BootCurrent
 | 
						|
        );
 | 
						|
 | 
						|
  if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
 | 
						|
      (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
 | 
						|
    ) {
 | 
						|
    //
 | 
						|
    // Check to see if we should legacy BOOT. If yes then do the legacy boot
 | 
						|
    //
 | 
						|
    return BdsLibDoLegacyBoot (Option);
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // If the boot option point to Internal FV shell, make sure it is valid
 | 
						|
  //
 | 
						|
  Status = UpdateFvFileDevicePath (&DevicePath, &gEfiShellFileGuid);
 | 
						|
  if (!EFI_ERROR(Status)) {
 | 
						|
    if (Option->DevicePath != NULL) {
 | 
						|
      FreePool (Option->DevicePath);
 | 
						|
    }
 | 
						|
    Option->DevicePath  = AllocateZeroPool (GetDevicePathSize (DevicePath));
 | 
						|
    CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
 | 
						|
    //
 | 
						|
    // Update the shell boot option
 | 
						|
    //
 | 
						|
    InitializeListHead (&TempBootLists);
 | 
						|
    BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder"); 
 | 
						|
  }
 | 
						|
 | 
						|
  DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Booting EFI 1.1 way %S\n", Option->Description));
 | 
						|
 | 
						|
  Status = gBS->LoadImage (
 | 
						|
                  TRUE,
 | 
						|
                  mBdsImageHandle,
 | 
						|
                  DevicePath,
 | 
						|
                  NULL,
 | 
						|
                  0,
 | 
						|
                  &ImageHandle
 | 
						|
                  );
 | 
						|
 | 
						|
  //
 | 
						|
  // If we didn't find an image, we may need to load the default
 | 
						|
  // boot behavior for the device.
 | 
						|
  //
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // Find a Simple File System protocol on the device path. If the remaining
 | 
						|
    // device path is set to end then no Files are being specified, so try
 | 
						|
    // the removable media file name.
 | 
						|
    //
 | 
						|
    TempDevicePath = DevicePath;
 | 
						|
    Status = gBS->LocateDevicePath (
 | 
						|
                    &gEfiSimpleFileSystemProtocolGuid,
 | 
						|
                    &TempDevicePath,
 | 
						|
                    &Handle
 | 
						|
                    );
 | 
						|
    if (!EFI_ERROR (Status) && IsDevicePathEnd (TempDevicePath)) {
 | 
						|
      FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
 | 
						|
      if (FilePath) {
 | 
						|
        //
 | 
						|
        // 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->HandleProtocol (
 | 
						|
                        Handle,
 | 
						|
                        &gEfiBlockIoProtocolGuid,
 | 
						|
                        (VOID **) &BlkIo
 | 
						|
                        );
 | 
						|
        if (!EFI_ERROR (Status)) {
 | 
						|
          Buffer = AllocatePool (BlkIo->Media->BlockSize);
 | 
						|
          if (Buffer != NULL) {
 | 
						|
            BlkIo->ReadBlocks (
 | 
						|
                     BlkIo,
 | 
						|
                     BlkIo->Media->MediaId,
 | 
						|
                     0,
 | 
						|
                     BlkIo->Media->BlockSize,
 | 
						|
                     Buffer
 | 
						|
                     );
 | 
						|
            FreePool (Buffer);
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        Status = gBS->LoadImage (
 | 
						|
                        TRUE,
 | 
						|
                        mBdsImageHandle,
 | 
						|
                        FilePath,
 | 
						|
                        NULL,
 | 
						|
                        0,
 | 
						|
                        &ImageHandle
 | 
						|
                        );
 | 
						|
        if (EFI_ERROR (Status)) {
 | 
						|
          //
 | 
						|
          // The DevicePath failed, and it's not a valid
 | 
						|
          // removable media device.
 | 
						|
          //
 | 
						|
          goto Done;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      Status = EFI_NOT_FOUND;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    //
 | 
						|
    // It there is any error from the Boot attempt exit now.
 | 
						|
    //
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Provide the image with it's load options
 | 
						|
  //
 | 
						|
  Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, &ImageInfo);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  if (Option->LoadOptionsSize != 0) {
 | 
						|
    ImageInfo->LoadOptionsSize  = Option->LoadOptionsSize;
 | 
						|
    ImageInfo->LoadOptions      = Option->LoadOptions;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Before calling the image, enable the Watchdog Timer for
 | 
						|
  // the 5 Minute period
 | 
						|
  //
 | 
						|
  gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
 | 
						|
 | 
						|
  Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);
 | 
						|
  DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Image Return Status = %r\n", Status));
 | 
						|
 | 
						|
  //
 | 
						|
  // Clear the Watchdog Timer after the image returns
 | 
						|
  //
 | 
						|
  gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
 | 
						|
 | 
						|
Done:
 | 
						|
  //
 | 
						|
  // Clear Boot Current
 | 
						|
  //
 | 
						|
  gRT->SetVariable (
 | 
						|
        L"BootCurrent",
 | 
						|
        &gEfiGlobalVariableGuid,
 | 
						|
        EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
 | 
						|
        0,
 | 
						|
        &Option->BootCurrent
 | 
						|
        );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
BdsBootByDiskSignatureAndPartition (
 | 
						|
  IN  BDS_COMMON_OPTION          * Option,
 | 
						|
  IN  HARDDRIVE_DEVICE_PATH      * HardDriveDevicePath,
 | 
						|
  IN  UINT32                     LoadOptionsSize,
 | 
						|
  IN  VOID                       *LoadOptions,
 | 
						|
  OUT UINTN                      *ExitDataSize,
 | 
						|
  OUT CHAR16                     **ExitData OPTIONAL
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Check to see if a hard ware device path was passed in. If it was then search
 | 
						|
  all the block IO devices for the passed in hard drive device path.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  Option - The current processing boot option.
 | 
						|
 | 
						|
  HardDriveDevicePath - EFI Device Path to boot, if it starts with a hard
 | 
						|
                        drive device path.
 | 
						|
 | 
						|
  LoadOptionsSize - Passed into gBS->StartImage ()
 | 
						|
                    via the loaded image protocol.
 | 
						|
 | 
						|
  LoadOptions     - Passed into gBS->StartImage ()
 | 
						|
                    via the loaded image protocol.
 | 
						|
 | 
						|
  ExitDataSize - returned directly from gBS->StartImage ()
 | 
						|
 | 
						|
  ExitData     - returned directly from gBS->StartImage ()
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS   - Status from gBS->StartImage (),
 | 
						|
                  or BootByDiskSignatureAndPartition ()
 | 
						|
 | 
						|
  EFI_NOT_FOUND - If the Device Path is not found in the system
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  UINTN                     BlockIoHandleCount;
 | 
						|
  EFI_HANDLE                *BlockIoBuffer;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *BlockIoDevicePath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *BlockIoHdDevicePath;
 | 
						|
  HARDDRIVE_DEVICE_PATH     *TmpHdPath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
 | 
						|
  UINTN                     Index;
 | 
						|
  BOOLEAN                   DevicePathMatch;
 | 
						|
  HARDDRIVE_DEVICE_PATH     *TempPath;
 | 
						|
 | 
						|
  *ExitDataSize = 0;
 | 
						|
  *ExitData     = NULL;
 | 
						|
 | 
						|
  if ( !((DevicePathType (&HardDriveDevicePath->Header) == MEDIA_DEVICE_PATH) &&
 | 
						|
          (DevicePathSubType (&HardDriveDevicePath->Header) == MEDIA_HARDDRIVE_DP))
 | 
						|
        ) {
 | 
						|
    //
 | 
						|
    // If the HardDriveDevicePath does not start with a Hard Drive Device Path
 | 
						|
    // exit.
 | 
						|
    //
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // The boot device have already been connected
 | 
						|
  //
 | 
						|
  Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
 | 
						|
  if (EFI_ERROR (Status) || BlockIoHandleCount == 0) {
 | 
						|
    //
 | 
						|
    // If there was an error or there are no device handles that support
 | 
						|
    // the BLOCK_IO Protocol, then return.
 | 
						|
    //
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // 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) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Make PreviousDevicePath == the device path node before the end node
 | 
						|
    //
 | 
						|
    DevicePath          = BlockIoDevicePath;
 | 
						|
    BlockIoHdDevicePath = NULL;
 | 
						|
 | 
						|
    //
 | 
						|
    // find HardDriver device path node
 | 
						|
    //
 | 
						|
    while (!IsDevicePathEnd (DevicePath)) {
 | 
						|
      if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
 | 
						|
          (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
 | 
						|
          ) {
 | 
						|
        BlockIoHdDevicePath = DevicePath;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      DevicePath = NextDevicePathNode (DevicePath);
 | 
						|
    }
 | 
						|
 | 
						|
    if (BlockIoHdDevicePath == NULL) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // See if the harddrive device path in blockio matches the orig Hard Drive Node
 | 
						|
    //
 | 
						|
    DevicePathMatch = FALSE;
 | 
						|
 | 
						|
    TmpHdPath       = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePath;
 | 
						|
    TempPath        = (HARDDRIVE_DEVICE_PATH *) BdsLibUnpackDevicePath ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
 | 
						|
 | 
						|
    //
 | 
						|
    // Only several fields will be checked. NOT whole NODE
 | 
						|
    //
 | 
						|
    if ( TmpHdPath->PartitionNumber == TempPath->PartitionNumber &&
 | 
						|
        TmpHdPath->MBRType == TempPath->MBRType &&
 | 
						|
        TmpHdPath->SignatureType == TempPath->SignatureType &&
 | 
						|
        CompareGuid ((EFI_GUID *) TmpHdPath->Signature, (EFI_GUID *) TempPath->Signature)) {
 | 
						|
      //
 | 
						|
      // Get the matched device path
 | 
						|
      //
 | 
						|
      DevicePathMatch = TRUE;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Only do the boot, when devicepath match
 | 
						|
    //
 | 
						|
    if (DevicePathMatch) {
 | 
						|
      //
 | 
						|
      // Combine the Block IO and Hard Drive Device path together and try
 | 
						|
      // to boot from it.
 | 
						|
      //
 | 
						|
      DevicePath    = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
 | 
						|
      NewDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);
 | 
						|
 | 
						|
      //
 | 
						|
      // Recursive boot with new device path
 | 
						|
      //
 | 
						|
      Status = BdsLibBootViaBootOption (Option, NewDevicePath, ExitDataSize, ExitData);
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (BlockIoBuffer);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
BdsLibDeleteOptionFromHandle (
 | 
						|
  IN  EFI_HANDLE                 Handle
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Delete the boot option associated with the handle passed in
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  Handle - The handle which present the device path to create boot option
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS           - Delete the boot option success
 | 
						|
 | 
						|
  EFI_NOT_FOUND         - If the Device Path is not found in the system
 | 
						|
 | 
						|
  EFI_OUT_OF_RESOURCES  - Lack of memory resource
 | 
						|
 | 
						|
  Other                 - Error return value from SetVariable()
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINT16                    *BootOrder;
 | 
						|
  UINT8                     *BootOptionVar;
 | 
						|
  UINTN                     BootOrderSize;
 | 
						|
  UINTN                     BootOptionSize;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  UINTN                     Index;
 | 
						|
  UINT16                    BootOption[BOOT_OPTION_MAX_CHAR];
 | 
						|
  UINTN                     DevicePathSize;
 | 
						|
  UINTN                     OptionDevicePathSize;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *OptionDevicePath;
 | 
						|
  UINT8                     *TempPtr;
 | 
						|
  CHAR16                    *Description;
 | 
						|
 | 
						|
  Status        = EFI_SUCCESS;
 | 
						|
  BootOrder     = NULL;
 | 
						|
  BootOrderSize = 0;
 | 
						|
 | 
						|
  BootOrder = BdsLibGetVariableAndSize (
 | 
						|
                L"BootOrder",
 | 
						|
                &gEfiGlobalVariableGuid,
 | 
						|
                &BootOrderSize
 | 
						|
                );
 | 
						|
  if (NULL == BootOrder) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  DevicePath = DevicePathFromHandle (Handle);
 | 
						|
  if (DevicePath == NULL) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
  DevicePathSize = GetDevicePathSize (DevicePath);
 | 
						|
 | 
						|
  Index = 0;
 | 
						|
  while (Index < BootOrderSize / sizeof (UINT16)) {
 | 
						|
    UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
 | 
						|
    BootOptionVar = BdsLibGetVariableAndSize (
 | 
						|
                      BootOption,
 | 
						|
                      &gEfiGlobalVariableGuid,
 | 
						|
                      &BootOptionSize
 | 
						|
                      );
 | 
						|
    if (NULL == BootOptionVar) {
 | 
						|
      FreePool (BootOrder);
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    TempPtr = BootOptionVar;
 | 
						|
    TempPtr += sizeof (UINT32) + sizeof (UINT16);
 | 
						|
    Description = (CHAR16 *) TempPtr;
 | 
						|
    TempPtr += StrSize ((CHAR16 *) TempPtr);
 | 
						|
    OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
 | 
						|
    OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);
 | 
						|
 | 
						|
    //
 | 
						|
    // Check whether the device path match
 | 
						|
    //
 | 
						|
    if ((OptionDevicePathSize == DevicePathSize) &&
 | 
						|
        (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {
 | 
						|
      BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);
 | 
						|
      FreePool (BootOptionVar);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    FreePool (BootOptionVar);
 | 
						|
    Index++;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gRT->SetVariable (
 | 
						|
                  L"BootOrder",
 | 
						|
                  &gEfiGlobalVariableGuid,
 | 
						|
                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | 
						|
                  BootOrderSize,
 | 
						|
                  BootOrder
 | 
						|
                  );
 | 
						|
 | 
						|
  FreePool (BootOrder);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
BdsDeleteAllInvalidEfiBootOption (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Delete all invalid EFI boot options. The probable invalid boot option could
 | 
						|
  be Removable media or Network boot device.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  VOID
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS           - Delete all invalid boot option success
 | 
						|
 | 
						|
  EFI_NOT_FOUND         - Variable "BootOrder" is not found
 | 
						|
 | 
						|
  EFI_OUT_OF_RESOURCES  - Lack of memory resource
 | 
						|
 | 
						|
  Other                 - Error return value from SetVariable()
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINT16                    *BootOrder;
 | 
						|
  UINT8                     *BootOptionVar;
 | 
						|
  UINTN                     BootOrderSize;
 | 
						|
  UINTN                     BootOptionSize;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  UINTN                     Index;
 | 
						|
  UINTN                     Index2;
 | 
						|
  UINT16                    BootOption[BOOT_OPTION_MAX_CHAR];
 | 
						|
  UINTN                     OptionDevicePathSize;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *LastDeviceNode;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *OptionDevicePath;
 | 
						|
  UINT8                     *TempPtr;
 | 
						|
  CHAR16                    *Description;
 | 
						|
  EFI_HANDLE                Handle;
 | 
						|
  BOOLEAN                   NeedDelete;
 | 
						|
 | 
						|
  Status        = EFI_SUCCESS;
 | 
						|
  BootOrder     = NULL;
 | 
						|
  BootOrderSize = 0;
 | 
						|
 | 
						|
  BootOrder = BdsLibGetVariableAndSize (
 | 
						|
                L"BootOrder",
 | 
						|
                &gEfiGlobalVariableGuid,
 | 
						|
                &BootOrderSize
 | 
						|
                );
 | 
						|
  if (NULL == BootOrder) {
 | 
						|
    return EFI_NOT_FOUND;
 | 
						|
  }
 | 
						|
 | 
						|
  Index = 0;
 | 
						|
  while (Index < BootOrderSize / sizeof (UINT16)) {
 | 
						|
    UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
 | 
						|
    BootOptionVar = BdsLibGetVariableAndSize (
 | 
						|
                      BootOption,
 | 
						|
                      &gEfiGlobalVariableGuid,
 | 
						|
                      &BootOptionSize
 | 
						|
                      );
 | 
						|
    if (NULL == BootOptionVar) {
 | 
						|
      FreePool (BootOrder);
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    TempPtr = BootOptionVar;
 | 
						|
    TempPtr += sizeof (UINT32) + sizeof (UINT16);
 | 
						|
    Description = (CHAR16 *) TempPtr;
 | 
						|
    TempPtr += StrSize ((CHAR16 *) TempPtr);
 | 
						|
    OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
 | 
						|
    OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);
 | 
						|
 | 
						|
    //
 | 
						|
    // Skip legacy boot option (BBS boot device)
 | 
						|
    //
 | 
						|
    if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&
 | 
						|
        (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {
 | 
						|
      FreePool (BootOptionVar);
 | 
						|
      Index++;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    TempDevicePath = OptionDevicePath;
 | 
						|
    LastDeviceNode = OptionDevicePath;
 | 
						|
    while (!EfiIsDevicePathEnd (TempDevicePath)) {
 | 
						|
      LastDeviceNode = TempDevicePath;
 | 
						|
      TempDevicePath = EfiNextDevicePathNode (TempDevicePath);
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Skip the boot option that point to a file, since the device path in
 | 
						|
    // removable media boot option doesn't contains a file name.
 | 
						|
    //
 | 
						|
    if (((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&
 | 
						|
         (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) ||
 | 
						|
        //
 | 
						|
        // Skip boot option for internal Shell, it's always valid
 | 
						|
        //
 | 
						|
        (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL)) {
 | 
						|
      FreePool (BootOptionVar);
 | 
						|
      Index++;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    NeedDelete = TRUE;
 | 
						|
    //
 | 
						|
    // Check if it's a valid boot option for removable media
 | 
						|
    //
 | 
						|
    TempDevicePath = OptionDevicePath;
 | 
						|
    Status = gBS->LocateDevicePath (
 | 
						|
                    &gEfiSimpleFileSystemProtocolGuid,
 | 
						|
                    &TempDevicePath,
 | 
						|
                    &Handle
 | 
						|
                    );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      NeedDelete = FALSE;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Check if it's a valid boot option for network boot device
 | 
						|
    //
 | 
						|
    TempDevicePath = OptionDevicePath;
 | 
						|
    Status = gBS->LocateDevicePath (
 | 
						|
                    &gEfiLoadFileProtocolGuid,
 | 
						|
                    &TempDevicePath,
 | 
						|
                    &Handle
 | 
						|
                    );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      NeedDelete = FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    if (NeedDelete) {
 | 
						|
      //
 | 
						|
      // Delete this invalid boot option "Boot####"
 | 
						|
      //
 | 
						|
      Status = gRT->SetVariable (
 | 
						|
                      BootOption,
 | 
						|
                      &gEfiGlobalVariableGuid,
 | 
						|
                      EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | 
						|
                      0,
 | 
						|
                      NULL
 | 
						|
                      );
 | 
						|
      //
 | 
						|
      // Mark this boot option in boot order as deleted
 | 
						|
      //
 | 
						|
      BootOrder[Index] = 0xffff;
 | 
						|
    }
 | 
						|
 | 
						|
    FreePool (BootOptionVar);
 | 
						|
    Index++;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Adjust boot order array
 | 
						|
  //
 | 
						|
  Index2 = 0;
 | 
						|
  for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
 | 
						|
    if (BootOrder[Index] != 0xffff) {
 | 
						|
      BootOrder[Index2] = BootOrder[Index];
 | 
						|
      Index2 ++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  Status = gRT->SetVariable (
 | 
						|
                  L"BootOrder",
 | 
						|
                  &gEfiGlobalVariableGuid,
 | 
						|
                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | 
						|
                  Index2 * sizeof (UINT16),
 | 
						|
                  BootOrder
 | 
						|
                  );
 | 
						|
 | 
						|
  FreePool (BootOrder);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
BdsLibEnumerateAllBootOption (
 | 
						|
  IN OUT LIST_ENTRY      *BdsBootOptionList
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  This function will enumerate all possible boot device in the system,
 | 
						|
  it will only excute once of every boot.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  BdsBootOptionList - The header of the link list which indexed all
 | 
						|
                      current boot options
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS - Finished all the boot device enumerate and create
 | 
						|
                the boot option base on that boot device
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  UINT16                        BootOptionNumber;
 | 
						|
  UINTN                         NumberFileSystemHandles;
 | 
						|
  EFI_HANDLE                    *FileSystemHandles;
 | 
						|
  EFI_BLOCK_IO_PROTOCOL         *BlkIo;
 | 
						|
  UINTN                         Index;
 | 
						|
  UINTN                         NumberLoadFileHandles;
 | 
						|
  EFI_HANDLE                    *LoadFileHandles;
 | 
						|
  VOID                          *ProtocolInstance;
 | 
						|
  EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
 | 
						|
  UINTN                         FvHandleCount;
 | 
						|
  EFI_HANDLE                    *FvHandleBuffer;
 | 
						|
  EFI_FV_FILETYPE               Type;
 | 
						|
  UINTN                         Size;
 | 
						|
  EFI_FV_FILE_ATTRIBUTES        Attributes;
 | 
						|
  UINT32                        AuthenticationStatus;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL      *FilePath;
 | 
						|
  EFI_HANDLE                    ImageHandle;
 | 
						|
  EFI_LOADED_IMAGE_PROTOCOL     *ImageInfo;
 | 
						|
  BOOLEAN                       NeedDelete;
 | 
						|
 | 
						|
  BootOptionNumber = 0;
 | 
						|
 | 
						|
  //
 | 
						|
  // If the boot device enumerate happened, just get the boot
 | 
						|
  // device from the boot order variable
 | 
						|
  //
 | 
						|
  if (mEnumBootDevice) {
 | 
						|
    BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Notes: this dirty code is to get the legacy boot option from the
 | 
						|
  // BBS table and create to variable as the EFI boot option, it should
 | 
						|
  // be removed after the CSM can provide legacy boot option directly
 | 
						|
  //
 | 
						|
  REFRESH_LEGACY_BOOT_OPTIONS;
 | 
						|
 | 
						|
  //
 | 
						|
  // Delete invalid boot option
 | 
						|
  //
 | 
						|
  BdsDeleteAllInvalidEfiBootOption ();
 | 
						|
  //
 | 
						|
  // Parse removable media
 | 
						|
  //
 | 
						|
  gBS->LocateHandleBuffer (
 | 
						|
        ByProtocol,
 | 
						|
        &gEfiSimpleFileSystemProtocolGuid,
 | 
						|
        NULL,
 | 
						|
        &NumberFileSystemHandles,
 | 
						|
        &FileSystemHandles
 | 
						|
        );
 | 
						|
  for (Index = 0; Index < NumberFileSystemHandles; Index++) {
 | 
						|
    Status = gBS->HandleProtocol (
 | 
						|
                    FileSystemHandles[Index],
 | 
						|
                    &gEfiBlockIoProtocolGuid,
 | 
						|
                    (VOID **) &BlkIo
 | 
						|
                    );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      if (!BlkIo->Media->RemovableMedia) {
 | 
						|
        //
 | 
						|
        // If the file system handle supports a BlkIo protocol,
 | 
						|
        // skip the removable media devices
 | 
						|
        //
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
 | 
						|
    //  machinename is ia32, ia64, x64, ...
 | 
						|
    //
 | 
						|
    FilePath = FileDevicePath (FileSystemHandles[Index], EFI_REMOVABLE_MEDIA_FILE_NAME);
 | 
						|
    NeedDelete = TRUE;
 | 
						|
    Status = gBS->LoadImage (
 | 
						|
                    TRUE,
 | 
						|
                    mBdsImageHandle,
 | 
						|
                    FilePath,
 | 
						|
                    NULL,
 | 
						|
                    0,
 | 
						|
                    &ImageHandle
 | 
						|
                    );
 | 
						|
    if (!EFI_ERROR(Status)) {
 | 
						|
      //
 | 
						|
      // Verify the image is a EFI application (and not a driver)
 | 
						|
      //
 | 
						|
      Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
 | 
						|
      ASSERT (!EFI_ERROR(Status));
 | 
						|
 | 
						|
      if (ImageInfo->ImageCodeType == EfiLoaderCode) {
 | 
						|
        NeedDelete = FALSE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (NeedDelete) {
 | 
						|
      //
 | 
						|
      // No such file or the file is not a EFI application, delete this boot option
 | 
						|
      //
 | 
						|
      BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);
 | 
						|
    } else {
 | 
						|
      BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList);
 | 
						|
      BootOptionNumber++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (NumberFileSystemHandles) {
 | 
						|
    FreePool (FileSystemHandles);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Parse Network Boot Device
 | 
						|
  //
 | 
						|
  gBS->LocateHandleBuffer (
 | 
						|
        ByProtocol,
 | 
						|
        &gEfiSimpleNetworkProtocolGuid,
 | 
						|
        NULL,
 | 
						|
        &NumberLoadFileHandles,
 | 
						|
        &LoadFileHandles
 | 
						|
        );
 | 
						|
  for (Index = 0; Index < NumberLoadFileHandles; Index++) {
 | 
						|
    Status = gBS->HandleProtocol (
 | 
						|
                    LoadFileHandles[Index],
 | 
						|
                    &gEfiLoadFileProtocolGuid,
 | 
						|
                    (VOID **) &ProtocolInstance
 | 
						|
                    );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    BdsLibBuildOptionFromHandle (LoadFileHandles[Index], BdsBootOptionList);
 | 
						|
    BootOptionNumber++;
 | 
						|
  }
 | 
						|
 | 
						|
  if (NumberLoadFileHandles) {
 | 
						|
    FreePool (LoadFileHandles);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Check if we have on flash shell
 | 
						|
  //
 | 
						|
  gBS->LocateHandleBuffer (
 | 
						|
        ByProtocol,
 | 
						|
        &gEfiFirmwareVolume2ProtocolGuid,
 | 
						|
        NULL,
 | 
						|
        &FvHandleCount,
 | 
						|
        &FvHandleBuffer
 | 
						|
        );
 | 
						|
  for (Index = 0; Index < FvHandleCount; Index++) {
 | 
						|
    gBS->HandleProtocol (
 | 
						|
          FvHandleBuffer[Index],
 | 
						|
          &gEfiFirmwareVolume2ProtocolGuid,
 | 
						|
          (VOID **) &Fv
 | 
						|
          );
 | 
						|
 | 
						|
    Status = Fv->ReadFile (
 | 
						|
                  Fv,
 | 
						|
                  &gEfiShellFileGuid,
 | 
						|
                  NULL,
 | 
						|
                  &Size,
 | 
						|
                  &Type,
 | 
						|
                  &Attributes,
 | 
						|
                  &AuthenticationStatus
 | 
						|
                  );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      //
 | 
						|
      // Skip if no shell file in the FV
 | 
						|
      //
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Build the shell boot option
 | 
						|
    //
 | 
						|
    BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);
 | 
						|
    BootOptionNumber++;
 | 
						|
  }
 | 
						|
 | 
						|
  if (FvHandleCount) {
 | 
						|
   FreePool (FvHandleBuffer);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Make sure every boot only have one time
 | 
						|
  // boot device enumerate
 | 
						|
  //
 | 
						|
  BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
 | 
						|
  mEnumBootDevice = TRUE;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
BdsLibBuildOptionFromHandle (
 | 
						|
  IN  EFI_HANDLE             Handle,
 | 
						|
  IN  LIST_ENTRY             *BdsBootOptionList
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Build the boot option with the handle parsed in
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  Handle - The handle which present the device path to create boot option
 | 
						|
 | 
						|
  BdsBootOptionList - The header of the link list which indexed all current
 | 
						|
                      boot options
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  VOID
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
 | 
						|
  CHAR16                    *TempString;
 | 
						|
 | 
						|
  DevicePath  = DevicePathFromHandle (Handle);
 | 
						|
  TempString  = DevicePathToStr (DevicePath);
 | 
						|
 | 
						|
  //
 | 
						|
  // Create and register new boot option
 | 
						|
  //
 | 
						|
  BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, TempString, L"BootOrder");
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
BdsLibBuildOptionFromShell (
 | 
						|
  IN EFI_HANDLE              Handle,
 | 
						|
  IN OUT LIST_ENTRY          *BdsBootOptionList
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Build the on flash shell boot option with the handle parsed in
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  Handle - The handle which present the device path to create on flash shell
 | 
						|
           boot option
 | 
						|
 | 
						|
  BdsBootOptionList - The header of the link list which indexed all current
 | 
						|
                      boot options
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  None
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL          *DevicePath;
 | 
						|
  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;
 | 
						|
 | 
						|
  DevicePath = DevicePathFromHandle (Handle);
 | 
						|
 | 
						|
  //
 | 
						|
  // Build the shell device path
 | 
						|
  //
 | 
						|
  EfiInitializeFwVolDevicepathNode (&ShellNode, &gEfiShellFileGuid);
 | 
						|
  DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);
 | 
						|
 | 
						|
  //
 | 
						|
  // Create and register the shell boot option
 | 
						|
  //
 | 
						|
  BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"Internal EFI Shell", L"BootOrder");
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
BdsLibBootNext (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Boot from the EFI1.1 spec defined "BootNext" variable
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  None
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  None
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  UINT16            *BootNext;
 | 
						|
  UINTN             BootNextSize;
 | 
						|
  CHAR16            Buffer[20];
 | 
						|
  BDS_COMMON_OPTION *BootOption;
 | 
						|
  LIST_ENTRY        TempList;
 | 
						|
  UINTN             ExitDataSize;
 | 
						|
  CHAR16            *ExitData;
 | 
						|
 | 
						|
  //
 | 
						|
  // Init the boot option name buffer and temp link list
 | 
						|
  //
 | 
						|
  InitializeListHead (&TempList);
 | 
						|
  ZeroMem (Buffer, sizeof (Buffer));
 | 
						|
 | 
						|
  BootNext = BdsLibGetVariableAndSize (
 | 
						|
              L"BootNext",
 | 
						|
              &gEfiGlobalVariableGuid,
 | 
						|
              &BootNextSize
 | 
						|
              );
 | 
						|
 | 
						|
  //
 | 
						|
  // Clear the boot next variable first
 | 
						|
  //
 | 
						|
  if (BootNext != NULL) {
 | 
						|
    gRT->SetVariable (
 | 
						|
          L"BootNext",
 | 
						|
          &gEfiGlobalVariableGuid,
 | 
						|
          EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
 | 
						|
          0,
 | 
						|
          BootNext
 | 
						|
          );
 | 
						|
 | 
						|
    //
 | 
						|
    // Start to build the boot option and try to boot
 | 
						|
    //
 | 
						|
    UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);
 | 
						|
    BootOption = BdsLibVariableToOption (&TempList, Buffer);
 | 
						|
    BdsLibConnectDevicePath (BootOption->DevicePath);
 | 
						|
    BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
 | 
						|
  }
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
UpdateFvFileDevicePath (
 | 
						|
  IN  OUT EFI_DEVICE_PATH_PROTOCOL      **DevicePath,
 | 
						|
  IN  EFI_GUID                          *FileGuid
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
   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 funciton 
 | 
						|
   could promise the Fv file device path is right.
 | 
						|
 | 
						|
Arguments:
 | 
						|
  DevicePath - on input, the Fv file device path need to check
 | 
						|
                    on output, the updated valid Fv file device path
 | 
						|
                    
 | 
						|
  FileGuid - the Fv file guild
 | 
						|
  
 | 
						|
Returns:
 | 
						|
  EFI_INVALID_PARAMETER - the input DevicePath or FileGuid is invalid parameter
 | 
						|
  EFI_UNSUPPORTED - the input DevicePath does not contain Fv file guild at all
 | 
						|
  EFI_ALREADY_STARTED - the input DevicePath has pointed to Fv file, it is valid
 | 
						|
  EFI_SUCCESS - has successfully updated the invalid DevicePath, and return the updated
 | 
						|
                          device path in DevicePath
 | 
						|
                
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL      *TempDevicePath;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL      *LastDeviceNode;
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  EFI_GUID                      *GuidPoint;
 | 
						|
  UINTN                         Index;
 | 
						|
  UINTN                         FvHandleCount;
 | 
						|
  EFI_HANDLE                    *FvHandleBuffer;
 | 
						|
  EFI_FV_FILETYPE               Type;
 | 
						|
  UINTN                         Size;
 | 
						|
  EFI_FV_FILE_ATTRIBUTES        Attributes;
 | 
						|
  UINT32                        AuthenticationStatus;
 | 
						|
  BOOLEAN                       FindFvFile;
 | 
						|
  EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;
 | 
						|
  EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
 | 
						|
  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;
 | 
						|
  EFI_HANDLE                    FoundFvHandle;
 | 
						|
  EFI_DEVICE_PATH_PROTOCOL      *NewDevicePath;
 | 
						|
  
 | 
						|
  if ((DevicePath == NULL) || (*DevicePath == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  if (FileGuid == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Check whether the device path point to the default the input Fv file
 | 
						|
  //
 | 
						|
  TempDevicePath = *DevicePath; 
 | 
						|
  LastDeviceNode = TempDevicePath;
 | 
						|
  while (!EfiIsDevicePathEnd (TempDevicePath)) {
 | 
						|
     LastDeviceNode = TempDevicePath;
 | 
						|
     TempDevicePath = EfiNextDevicePathNode (TempDevicePath);
 | 
						|
  }
 | 
						|
 | 
						|
  GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode ((CONST MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)LastDeviceNode);
 | 
						|
 | 
						|
  if (GuidPoint == NULL) {
 | 
						|
    //
 | 
						|
    // if this option does not points to a Fv file, just return EFI_UNSUPPORTED
 | 
						|
    //
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!CompareGuid (GuidPoint, FileGuid)) {
 | 
						|
    //
 | 
						|
    // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
 | 
						|
    //
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
  
 | 
						|
  //
 | 
						|
  // Check whether the input Fv file device path is valid
 | 
						|
  //
 | 
						|
  TempDevicePath = *DevicePath; 
 | 
						|
  FoundFvHandle = NULL;
 | 
						|
  Status = gBS->LocateDevicePath (
 | 
						|
                  &gEfiFirmwareVolume2ProtocolGuid,
 | 
						|
                  &TempDevicePath, 
 | 
						|
                  &FoundFvHandle
 | 
						|
                  );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    Status = gBS->HandleProtocol (
 | 
						|
                    FoundFvHandle,
 | 
						|
                    &gEfiFirmwareVolume2ProtocolGuid,
 | 
						|
                    (VOID **) &Fv
 | 
						|
                    );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      //
 | 
						|
      // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
 | 
						|
      //
 | 
						|
      Status = Fv->ReadFile (
 | 
						|
                    Fv,
 | 
						|
                    FileGuid,
 | 
						|
                    NULL,
 | 
						|
                    &Size,
 | 
						|
                    &Type,
 | 
						|
                    &Attributes,
 | 
						|
                    &AuthenticationStatus
 | 
						|
                    );
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        return EFI_ALREADY_STARTED;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 
 | 
						|
  //
 | 
						|
  // Look for the input wanted FV file in current FV
 | 
						|
  // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV
 | 
						|
  //
 | 
						|
  FindFvFile = FALSE;
 | 
						|
  FoundFvHandle = NULL;
 | 
						|
  Status = gBS->HandleProtocol (
 | 
						|
             mBdsImageHandle,
 | 
						|
             &gEfiLoadedImageProtocolGuid,
 | 
						|
             &LoadedImage
 | 
						|
             );
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    Status = gBS->HandleProtocol (
 | 
						|
                    LoadedImage->DeviceHandle,
 | 
						|
                    &gEfiFirmwareVolume2ProtocolGuid,
 | 
						|
                    (VOID **) &Fv
 | 
						|
                    );
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      Status = Fv->ReadFile (
 | 
						|
                    Fv,
 | 
						|
                    FileGuid,
 | 
						|
                    NULL,
 | 
						|
                    &Size,
 | 
						|
                    &Type,
 | 
						|
                    &Attributes,
 | 
						|
                    &AuthenticationStatus
 | 
						|
                    );
 | 
						|
      if (!EFI_ERROR (Status)) {
 | 
						|
        FindFvFile = TRUE;
 | 
						|
        FoundFvHandle = LoadedImage->DeviceHandle;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Second, if fail to find, try to enumerate all FV
 | 
						|
  //
 | 
						|
  if (!FindFvFile) {
 | 
						|
    gBS->LocateHandleBuffer (
 | 
						|
          ByProtocol,
 | 
						|
          &gEfiFirmwareVolume2ProtocolGuid,
 | 
						|
          NULL,
 | 
						|
          &FvHandleCount,
 | 
						|
          &FvHandleBuffer
 | 
						|
          );
 | 
						|
    for (Index = 0; Index < FvHandleCount; Index++) {
 | 
						|
      gBS->HandleProtocol (
 | 
						|
            FvHandleBuffer[Index],
 | 
						|
            &gEfiFirmwareVolume2ProtocolGuid,
 | 
						|
            (VOID **) &Fv
 | 
						|
            );
 | 
						|
 | 
						|
      Status = Fv->ReadFile (
 | 
						|
                    Fv,
 | 
						|
                    FileGuid,
 | 
						|
                    NULL,
 | 
						|
                    &Size,
 | 
						|
                    &Type,
 | 
						|
                    &Attributes,
 | 
						|
                    &AuthenticationStatus
 | 
						|
                    );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        //
 | 
						|
        // Skip if input Fv file not in the FV
 | 
						|
        //
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
      FindFvFile = TRUE;
 | 
						|
      FoundFvHandle = FvHandleBuffer[Index];
 | 
						|
      break;
 | 
						|
    }  
 | 
						|
  }
 | 
						|
 | 
						|
  if (FindFvFile) {
 | 
						|
    //
 | 
						|
    // Build the shell device path
 | 
						|
    //
 | 
						|
    NewDevicePath = DevicePathFromHandle (FoundFvHandle);
 | 
						|
    EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);
 | 
						|
    NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);
 | 
						|
    *DevicePath = NewDevicePath;
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 |