搜尋此網誌

顯示具有 EFI/UEFI Function Library 標籤的文章。 顯示所有文章
顯示具有 EFI/UEFI Function Library 標籤的文章。 顯示所有文章

2012年10月3日 星期三

BdsLibBootViaBootOption() - Boot up to load drivers


/*You can find the function in EDK1.6 BdsBoot.c*/

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 ()

  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  *FilePath;
  EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
  EFI_EVENT                 ReadyToBootEvent;
  EFI_DEVICE_PATH_PROTOCOL  *WorkingDevicePath;
  EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save;
  EFI_LIST_ENTRY            TempBootLists;
  EFI_TCG_PLATFORM_PROTOCOL *TcgPlatformProtocol;
  //
  // 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 ();

  //
  // Notes: this code can be remove after the s3 script table
  // hook on the event EFI_EVENT_SIGNAL_READY_TO_BOOT or
  // EFI_EVENT_SIGNAL_LEGACY_BOOT
  //
  Status = gBS->LocateProtocol (&gEfiAcpiS3SaveGuid, NULL, &AcpiS3Save);
  if (!EFI_ERROR (Status)) {
    AcpiS3Save->S3Save (AcpiS3Save, NULL);
  }
  //
  // If it's Device Path that starts with a hard drive path, append it with the front part to compose a
  // full device path
  //
  WorkingDevicePath = NULL;
  if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
      (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {
    WorkingDevicePath = BdsExpandPartitionPartialDevicePathToFull (
                          (HARDDRIVE_DEVICE_PATH *)DevicePath
                          );
    if (WorkingDevicePath != NULL) {
      DevicePath = WorkingDevicePath;
    }
  }
  
  //
  // Set Boot Current
  //
  gRT->SetVariable (
        L"BootCurrent",
        &gEfiGlobalVariableGuid,
        EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
        sizeof (UINT16),
        &Option->BootCurrent
        );
        
  //
  // Signal the EFI_EVENT_SIGNAL_READY_TO_BOOT event
  //
  Status = EfiCreateEventReadyToBoot (
             EFI_TPL_CALLBACK,
             NULL,
             NULL,
             &ReadyToBootEvent
             );

  if (!EFI_ERROR (Status)) {
    gBS->SignalEvent (ReadyToBootEvent);
    gBS->CloseEvent (ReadyToBootEvent);
  }


  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 = BdsLibUpdateFvFileDevicePath (&DevicePath, &gEfiShellFileGuid);
  if (!EFI_ERROR(Status)) {
    if (Option->DevicePath != NULL) {
      EfiLibSafeFreePool(Option->DevicePath);
    }
    Option->DevicePath  = EfiLibAllocateZeroPool (EfiDevicePathSize (DevicePath));
    EfiCopyMem (Option->DevicePath, DevicePath, EfiDevicePathSize (DevicePath));
    //
    // Update the shell boot option
    //
    InitializeListHead (&TempBootLists);
    BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder"); 
    //
    // free the temporary device path created by BdsLibUpdateFvFileDevicePath()
    //
    gBS->FreePool (DevicePath); 
    DevicePath = Option->DevicePath;
  }
  //
  // Measure GPT Table
  //
  Status = gBS->LocateProtocol (
                  &gEfiTcgPlatformProtocolGuid,
                  NULL,
                  &TcgPlatformProtocol
                  );  
  if (!EFI_ERROR (Status)) {
    Status = TcgPlatformProtocol->MeasureGptTable (DevicePath);
  }
  
  //
  // Drop the TPL level from EFI_TPL_DRIVER to EFI_TPL_APPLICATION
  //
  gBS->RestoreTPL (EFI_TPL_APPLICATION);

  DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Booting EFI way %S\n", Option->Description));

  Status = gBS->LoadImage (
                  TRUE,
                  mBdsImageHandle,
                  DevicePath,
                  NULL,
                  0,
                  &ImageHandle
                  );
                  
  //
  // If we didn't find an image directly, we need to try as if it is a removable device boot opotion 
  // and load the image according to the default boot behavior for removable device.
  //
  if (EFI_ERROR (Status)) {
    //
    // check if there is a bootable removable media could be found in this device path , 
    // and get the bootable media handle 
    //
    Handle = BdsLibGetBootableHandle(DevicePath);
    if (Handle == NULL) {
       goto Done;
    }
    //
    // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
    //  machinename is ia32, ia64, x64, ...
    //
    FilePath = EfiFileDevicePath (Handle, DEFAULT_REMOVABLE_FILE_NAME); 
    if (FilePath) {
      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;
      }
    }   
  }

  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);

  //
  // Write boot to OS performance data for UEFI boot
  //
  WRITE_BOOT_TO_OS_PERFORMANCE_DATA;
  
  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
        );

  //
  // Raise the TPL level back to EFI_TPL_DRIVER
  //
  gBS->RaiseTPL (EFI_TPL_DRIVER);

  return Status;
}

LoadDriver() - How to load uefi/efi driver in code?

/*You can find the function in Shell load.c*/

STATIC
EFI_STATUS
LoadDriver (
  IN EFI_HANDLE               ParentImage,
  IN SHELL_FILE_ARG           *Arg,
  IN BOOLEAN                  Connect
  )
{
  EFI_HANDLE                ImageHandle;
  EFI_STATUS                Status;
  EFI_DEVICE_PATH_PROTOCOL  *NodePath;
  EFI_DEVICE_PATH_PROTOCOL  *FilePath;
  EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
  CHAR16                    *LoadOptions;
  UINTN                     LoadOptionsSize;
  CHAR16                    *Cwd;
  EFI_IMAGE_DOS_HEADER      DosHeader;
  EFI_IMAGE_FILE_HEADER     ImageHeader;
  EFI_IMAGE_OPTIONAL_HEADER OptionalHeader;

  NodePath  = FileDevicePath (NULL, Arg->FileName);
  FilePath  = AppendDevicePath (Arg->ParentDevicePath, NodePath);
  if (NodePath) {
    FreePool (NodePath);
    NodePath = NULL;
  }

  if (!FilePath) {
    return EFI_OUT_OF_RESOURCES;
  }

  //
  // Check whether Image is valid to be loaded.
  //
  Status = LibGetImageHeader (
    FilePath,
    &DosHeader,
    &ImageHeader,
    &OptionalHeader
    );
  if (!EFI_ERROR (Status) && !EFI_IMAGE_MACHINE_TYPE_SUPPORTED (ImageHeader.Machine) &&
     (OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER ||
      OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) {
    FreePool (FilePath);
    PrintToken (
      STRING_TOKEN (STR_LOAD_IMAGE_TYPE_UNSUPPORTED),
      HiiLoadHandle,
      LibGetMachineTypeString (ImageHeader.Machine),
      LibGetMachineTypeString (EFI_IMAGE_MACHINE_TYPE)
      );
    return EFI_INVALID_PARAMETER;
  }

  Status = BS->LoadImage (
                FALSE,
                ParentImage,
                FilePath,
                NULL,
                0,
                &ImageHandle
                );
  FreePool (FilePath);

  if (EFI_ERROR (Status)) {
    if (Status == EFI_SECURITY_VIOLATION) {
      BS->UnloadImage (ImageHandle);
    }
    PrintToken (STRING_TOKEN (STR_LOAD_NOT_IMAGE), HiiLoadHandle, Arg->FullName);
    return EFI_INVALID_PARAMETER;
  }
  //
  // Verify the image is a driver ?
  //
  BS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID *) &ImageInfo);
  if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) {

    PrintToken (STRING_TOKEN (STR_LOAD_IMAGE_NOT_DRIVER), HiiLoadHandle, Arg->FullName);
    BS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);
    return EFI_INVALID_PARAMETER;
  }
  //
  // Construct a load options buffer containing the command line and
  // current working directory.
  //
  // NOTE: To prevent memory leaks, the protocol is responsible for
  // freeing the memory associated with the load options.
  //
  // One day we'll pass arguments to the protocol....
  //
  Cwd = ShellCurDir (NULL);
  if (NULL == Cwd) {
    Cwd = StrDuplicate (L"");
  }

  LoadOptionsSize = (StrLen (Arg->FullName) + 2 + StrLen (Cwd) + 2) * sizeof (CHAR16);
  LoadOptions     = AllocatePool (LoadOptionsSize);
  ASSERT (LoadOptions);

  StrCpy (LoadOptions, Arg->FullName);
  StrCpy (&LoadOptions[StrLen (LoadOptions) + 1], Cwd);
  FreePool (Cwd);

  if (ImageInfo->LoadOptions) {
    FreePool (ImageInfo->LoadOptions);
  }

  ImageInfo->LoadOptionsSize  = (UINT32) LoadOptionsSize;
  ImageInfo->LoadOptions      = LoadOptions;

  //
  // Start the image
  //
  Status = BS->StartImage (ImageHandle, NULL, NULL);
  if (!EFI_ERROR (Status)) {
    PrintToken (
      STRING_TOKEN (STR_LOAD_IMAGE_LOADED),
      HiiLoadHandle,
      Arg->FullName,
      ImageInfo->ImageBase,
      Status
      );
  } else {
    PrintToken (
      STRING_TOKEN (STR_LOAD_IMAGE_ERROR),
      HiiLoadHandle,
      Arg->FullName,
      Status
      );
  }

  if (Connect) {
    Status = LoadConnectAllDriversToAllControllers ();
  }
  //
  // When any driver starts, turn off the watchdog timer
  //
  BS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
  return Status;
}

2012年10月2日 星期二

LoadEfiDriversFromRomImage() - How to load uefi/efi PCI ROM Image in code?

/*You can find the function in Shell LoadPciRom.c*/

EFI_STATUS
LoadEfiDriversFromRomImage (
  VOID                      *RomBar,
  UINTN                     RomSize,
  CHAR16                    *FileName
  )
/*++

Routine Description:
  Command entry point. 

Arguments:

  RomBar   - Rom
  RomSize  - Rom size
  FileName - The file name

Returns:
  EFI_SUCCESS             - The command completed successfully
  EFI_INVALID_PARAMETER   - Command usage error
  EFI_UNSUPPORTED         - Protocols unsupported
  EFI_OUT_OF_RESOURCES    - Out of memory
  Other value             - Unknown error

--*/
{
  EFI_PCI_EXPANSION_ROM_HEADER  *EfiRomHeader;
  PCI_DATA_STRUCTURE            *Pcir;
  UINTN                         ImageIndex;
  UINTN                         RomBarOffset;
  UINT32                        ImageSize;
  UINT16                        ImageOffset;
  EFI_HANDLE                    ImageHandle;
  EFI_STATUS                    Status;
  EFI_STATUS                    retStatus;
  CHAR16                        RomFileName[280];
  EFI_DEVICE_PATH_PROTOCOL      *FilePath;
  BOOLEAN                       SkipImage;
  UINT32                        DestinationSize;
  UINT32                        ScratchSize;
  UINT8                         *Scratch;
  VOID                          *ImageBuffer;
  VOID                          *DecompressedImageBuffer;
  UINT32                        ImageLength;
  EFI_DECOMPRESS_PROTOCOL       *Decompress;

  ImageIndex    = 0;
  retStatus     = EFI_NOT_FOUND;
  RomBarOffset  = (UINTN) RomBar;

  do {

    EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (UINTN) RomBarOffset;

    if (EfiRomHeader->Signature != 0xaa55) {
      PrintToken (STRING_TOKEN (STR_LOADPCIROM_IMAGE_CORRUPT), HiiHandle, ImageIndex);
      return retStatus;
    }

    Pcir      = (PCI_DATA_STRUCTURE *) (UINTN) (RomBarOffset + EfiRomHeader->PcirOffset);
    ImageSize = Pcir->ImageLength * 512;

    if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&
        (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE)
        ) {

      if ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
          (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)
          ) {
        ImageOffset             = EfiRomHeader->EfiImageHeaderOffset;
        ImageSize               = EfiRomHeader->InitializationSize * 512;

        ImageBuffer             = (VOID *) (UINTN) (RomBarOffset + ImageOffset);
        ImageLength             = ImageSize - ImageOffset;
        DecompressedImageBuffer = NULL;

        //
        // decompress here if needed
        //
        SkipImage = FALSE;
        if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
          SkipImage = TRUE;
        }

        if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
          Status = BS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, &Decompress);
          if (EFI_ERROR (Status)) {
            PrintToken (STRING_TOKEN (STR_LOADPCIROM_DECOMP_NOT_FOUND), HiiHandle);
            SkipImage = TRUE;
          } else {
            SkipImage = TRUE;
            Status = Decompress->GetInfo (
                                  Decompress,
                                  ImageBuffer,
                                  ImageLength,
                                  &DestinationSize,
                                  &ScratchSize
                                  );
            if (!EFI_ERROR (Status)) {
              DecompressedImageBuffer = AllocatePool (DestinationSize);
              if (ImageBuffer != NULL) {
                Scratch = AllocatePool (ScratchSize);
                if (Scratch != NULL) {
                  Status = Decompress->Decompress (
                                        Decompress,
                                        ImageBuffer,
                                        ImageLength,
                                        DecompressedImageBuffer,
                                        DestinationSize,
                                        Scratch,
                                        ScratchSize
                                        );
                  if (!EFI_ERROR (Status)) {
                    ImageBuffer = DecompressedImageBuffer;
                    ImageLength = DestinationSize;
                    SkipImage   = FALSE;
                  }

                  FreePool (Scratch);
                }
              }
            }
          }
        }

        if (SkipImage == FALSE) {
          //
          // load image and start image
          //
          SPrint (RomFileName, sizeof (RomFileName), L"%s[%d]", FileName, ImageIndex);
          FilePath = FileDevicePath (NULL, RomFileName);

          Status = BS->LoadImage (
                        TRUE,
                        gMyImageHandle,
                        FilePath,
                        ImageBuffer,
                        ImageLength,
                        &ImageHandle
                        );
          if (EFI_ERROR (Status)) {
            PrintToken (STRING_TOKEN (STR_LOADPCIROM_LOAD_IMAGE_ERROR), HiiHandle, ImageIndex, Status);
          } else {
            Status = BS->StartImage (ImageHandle, NULL, NULL);
            if (EFI_ERROR (Status)) {
              PrintToken (STRING_TOKEN (STR_LOADPCIROM_START_IMAGE), HiiHandle, ImageIndex, Status);
            } else {
              retStatus = Status;
            }
          }
        }

        if (DecompressedImageBuffer != NULL) {
          FreePool (DecompressedImageBuffer);
        }

      }
    }

    RomBarOffset = RomBarOffset + ImageSize;
    ImageIndex++;
  } while (((Pcir->Indicator & 0x80) == 0x00) && ((RomBarOffset - (UINTN) RomBar) < RomSize));

  return retStatus;
}