diff options
Diffstat (limited to 'ReferenceCode/ME/SampleCode/AsfSupport/AsfSupport.c')
-rw-r--r-- | ReferenceCode/ME/SampleCode/AsfSupport/AsfSupport.c | 1517 |
1 files changed, 1517 insertions, 0 deletions
diff --git a/ReferenceCode/ME/SampleCode/AsfSupport/AsfSupport.c b/ReferenceCode/ME/SampleCode/AsfSupport/AsfSupport.c new file mode 100644 index 0000000..c5324aa --- /dev/null +++ b/ReferenceCode/ME/SampleCode/AsfSupport/AsfSupport.c @@ -0,0 +1,1517 @@ +/** @file + Support routines for ASF boot options in the BDS + +@copyright + Copyright (c) 2005-2012 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains a 'Sample Driver' and is licensed as such + under the terms of your license agreement with Intel or your + vendor. This file may be modified by the user, subject to + the additional terms of the license agreement + +**/ + +#include "AsfSupport.h" + +#pragma pack(push,1) + +typedef struct { + UINT32 Attributes; + UINT16 FilePathListLength; +} EFI_LOAD_OPTION; + +#pragma pack(pop) + +// +// Global variables +// +EFI_ASF_BOOT_OPTIONS *mAsfBootOptions; +EFI_GUID gAsfRestoreBootSettingsGuid = RESTORE_SECURE_BOOT_GUID; + +/** + Retrieve the ASF boot options previously recorded by the ASF driver. + + @param[in] None. + + @retval EFI_SUCCESS Initialized Boot Options global variable and AMT protocol +**/ +EFI_STATUS +BdsAsfInitialization ( + IN VOID + ) +{ + EFI_STATUS Status; + EFI_ALERT_STANDARD_FORMAT_PROTOCOL *Asf; + + mAsfBootOptions = NULL; + + // + // Amt Library Init + // + Status = AmtLibInit (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Info : Error init AmtLibInit -> %r\n", Status)); + return Status; + } + // + // Get Protocol for ASF + // + Status = gBS->LocateProtocol ( + &gEfiAlertStandardFormatProtocolGuid, + NULL, + &Asf + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Info : Error getting ASF protocol -> %r\n", Status)); + return Status; + } + + Status = Asf->GetBootOptions (Asf, &mAsfBootOptions); + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR, "Info : Error getting ASF BootOptions -> %r\n", Status)); + return Status; + } + + Status = ManageSecureBootState(); + + return Status; +} + +/** + Get current Secure Boot state (enabled/disabled) + + @param[in] None. + + @retval UINT8 Secure Boot State +**/ +UINT8 +GetSecureBootState( + IN VOID + ) +{ + // + // This function is BIOS implementation specific + // and should be implemented in platform code + // + + return SECURE_BOOT_DISABLED; +} + +/** + Set current Secure Boot state (enabled/disabled) + + @param[in] SecureBootState Secure Boot State + + @retval EFI_SUCCESS Secure Boot State successfully changed +**/ +EFI_STATUS +SetSecureBootState( + IN UINT8 SecureBootState + ) +{ + // + // This function is BIOS implementation specific + // and should be implemented in platform code + // + + return EFI_SUCCESS; +} + +/** + This routine makes necessary Secure Boot & CSM state changes for IDEr boot + + @param[in] None. + + @retval EFI_SUCCESS Changes applied succesfully +**/ +EFI_STATUS +ManageSecureBootState( + IN VOID + ) +{ + EFI_STATUS Status; + BOOLEAN EnforceSecureBoot; + UINT8 SecureBootState; + UINT8 RestoreBootSettings; + UINT8 IderBoot; + UINTN VarSize; + + VarSize = sizeof(UINT8); + + // + // Get boot parameters (IDER boot?, EnforceSecureBoot flag set?, secure boot enabled?) + // + EnforceSecureBoot = ActiveManagementEnforceSecureBoot(); + IderBoot = ActiveManagementEnableIdeR(); + SecureBootState = GetSecureBootState(); + + // + // Check whether we need to restore SecureBootEnable value changed in previous IDER boot + // + Status = gRT->GetVariable( + L"RestoreBootSettings", + &gAsfRestoreBootSettingsGuid, + NULL, + &VarSize, + &RestoreBootSettings + ); + + if (Status == EFI_SUCCESS && RestoreBootSettings != RESTORE_SECURE_BOOT_NONE) { + if (RestoreBootSettings == RESTORE_SECURE_BOOT_ENABLED && SecureBootState == SECURE_BOOT_DISABLED && + !(IderBoot && !EnforceSecureBoot)) { + + SecureBootState = SECURE_BOOT_ENABLED; + + Status = SetSecureBootState(SecureBootState); + ASSERT_EFI_ERROR (Status); + + // + // Delete RestoreBootSettings variable + // + Status = gRT->SetVariable( + L"RestoreBootSettings", + &gAsfRestoreBootSettingsGuid, + 0, + 0, + NULL + ); + ASSERT_EFI_ERROR (Status); + + DEBUG ((EFI_D_INFO, "Secure Boot settings restored after IDER boot - Cold Reset!\n")); + gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + EFI_DEADLOOP(); + } + } + + Status = EFI_SUCCESS; + + if (IderBoot) { + if (SecureBootState == SECURE_BOOT_ENABLED && !EnforceSecureBoot) { + // + // Secure boot needs to be disabled if we're doing IDER and EnforceSecureBoot not set + // + SecureBootState = SECURE_BOOT_DISABLED; + RestoreBootSettings = RESTORE_SECURE_BOOT_ENABLED; + + Status = SetSecureBootState(SecureBootState); + ASSERT_EFI_ERROR (Status); + + // + // Set variable to restore previous secure boot state + // + Status = gRT->SetVariable( + L"RestoreBootSettings", + &gAsfRestoreBootSettingsGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(UINT8), + &RestoreBootSettings + ); + ASSERT_EFI_ERROR (Status); + + DEBUG ((EFI_D_INFO, "Secure Boot disabled for IDER boot - Cold Reset!\n")); + gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL); + EFI_DEADLOOP(); + } + } + + return Status; +} + +/** + This function will create a BootOption from the give device path and + description string. + + @param[in] DevicePath The device path which the option represent + @param[in] Description The description of the boot option + + @retval BDS_COMMON_OPTION - Pointer to created boot option +**/ +BDS_COMMON_OPTION * +BdsCreateBootOption ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN CHAR16 *Description + ) +{ + BDS_COMMON_OPTION *Option; + + Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION)); + if (Option == NULL) { + return NULL; + } + + Option->Signature = BDS_LOAD_OPTION_SIGNATURE; + Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath)); + CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath)); + + Option->Attribute = LOAD_OPTION_ACTIVE; + Option->Description = AllocateZeroPool (EfiStrSize (Description)); + CopyMem (Option->Description, Description, EfiStrSize (Description)); + + return Option; +} + +/** + This function will create a SHELL BootOption to boot. + + @param[in] None. + + @retval EFI_DEVICE_PATH_PROTOCOL Shell Device path for booting. +**/ +EFI_DEVICE_PATH_PROTOCOL * +BdsCreateShellDevicePath ( + VOID + ) +{ + UINTN FvHandleCount; + EFI_HANDLE *FvHandleBuffer; + UINTN Index; + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_PROTOCOL *Fv; + EFI_FV_FILETYPE Type; + UINTN Size; + EFI_FV_FILE_ATTRIBUTES Attributes; + UINT32 AuthenticationStatus; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode; + + DevicePath = NULL; + Status = EFI_SUCCESS; + + gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolumeProtocolGuid, + NULL, + &FvHandleCount, + &FvHandleBuffer + ); + + for (Index = 0; Index < FvHandleCount; Index++) { + gBS->HandleProtocol ( + FvHandleBuffer[Index], + &gEfiFirmwareVolumeProtocolGuid, + (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; + } else { + // + // Found the shell + // + break; + } + } + + if (EFI_ERROR (Status)) { + // + // No shell present + // + if (FvHandleCount) { + FreePool (FvHandleBuffer); + } + return NULL; + } + // + // Build the shell boot option + // + DevicePath = DevicePathFromHandle (FvHandleBuffer[Index]); + + // + // Build the shell device path + // + ShellNode.Header.Type = MEDIA_DEVICE_PATH; + ShellNode.Header.SubType = MEDIA_FV_FILEPATH_DP; + SetDevicePathNodeLength (&ShellNode.Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH)); + CopyMem (&ShellNode.NameGuid, &gEfiShellFileGuid, sizeof (EFI_GUID)); + DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode); + + if (FvHandleCount) { + FreePool (FvHandleBuffer); + } + + return DevicePath; +} + +/** + This function will create a PXE BootOption to boot. + + @param[in] DeviceIndex PXE handle index + + @retval EFI_DEVICE_PATH_PROTOCOL PXE Device path for booting. +**/ +EFI_DEVICE_PATH_PROTOCOL * +BdsCreatePxeDevicePath ( + IN UINT16 DeviceIndex + ) +{ + UINTN Index; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN NumberLoadFileHandles; + EFI_HANDLE *LoadFileHandles; + VOID *ProtocolInstance; + + DevicePath = NULL; + Status = EFI_SUCCESS; + + // + // We want everything connected up for PXE + // + BdsLibConnectAllDriversToAllControllers (); + + // + // 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)) { + // + // try next handle + // + continue; + } else { + if (Index == DeviceIndex) { + // + // Found a PXE handle + // + break; + } else { + Status = EFI_UNSUPPORTED; + } + } + } + + if (EFI_ERROR (Status)) { + // + // No PXE present + // + if (NumberLoadFileHandles) { + FreePool (LoadFileHandles); + } + return NULL; + } + // + // Build the PXE device path + // + DevicePath = DevicePathFromHandle (LoadFileHandles[Index]); + + if (NumberLoadFileHandles) { + FreePool (LoadFileHandles); + } + + return DevicePath; +} + +BOOLEAN +ComparePathNode( + IN EFI_DEVICE_PATH_PROTOCOL *PathNode1, + IN EFI_DEVICE_PATH_PROTOCOL *PathNode2 +) +{ + BOOLEAN st = FALSE; + UINTN Size1, Size2; + UINT8 *p1, *p2; + + if ((PathNode1 == NULL) || (PathNode2 == NULL)) { + return FALSE; + } + + if (PathNode1 == PathNode2) { + st = TRUE; + } else { + Size1 = DevicePathNodeLength(PathNode1); + Size2 = DevicePathNodeLength(PathNode2); + p1 = (UINT8 *)PathNode1; + p2 = (UINT8 *)PathNode2; + if ((Size1 == Size2) + && (DevicePathType(PathNode1) == DevicePathType(PathNode2)) + && (CompareMem(p1+1, p2+1, Size1-1) == 0)) { + st = TRUE; + } + } + + return st; +} + +/** + Compare two device paths node by node up to MEDIA_DEVICE_PATH node + + @param[in] BootOptionDP Device path acquired from BootXXXX EFI variable + @param[in] FileSysDP Device path acquired through EFI_SIMPLE_FILE_SYSTEM_PROTOCOL Handles buffer + + @retval TRUE Both device paths point to the same device + @retval FALSE Device paths point to different devices +**/ +BOOLEAN +CompareDevicePaths( + IN EFI_DEVICE_PATH_PROTOCOL *BootOptionDP, + IN EFI_DEVICE_PATH_PROTOCOL *FileSysDP +) +{ + EFI_DEVICE_PATH_PROTOCOL *DevPathNodeA; + EFI_DEVICE_PATH_PROTOCOL *DevPathNodeB; + + if (BootOptionDP == NULL || FileSysDP == NULL) { + return FALSE; + } + + DevPathNodeA = BdsLibUnpackDevicePath(BootOptionDP); + if (DevPathNodeA == NULL) { + return FALSE; + } + + DevPathNodeB = BdsLibUnpackDevicePath(FileSysDP); + if (DevPathNodeB == NULL) { + return FALSE; + } + + while (!IsDevicePathEnd(DevPathNodeB)) { + if (DevicePathType(DevPathNodeB) == MEDIA_DEVICE_PATH) { + // + // If we have reached MEDIA_DEVICE_PATH node and all previous + // nodes matched - we can be sure path points to the same device + // + return TRUE; + } + + if (!ComparePathNode(DevPathNodeA, DevPathNodeB)) { + break; + } + + DevPathNodeA = NextDevicePathNode(DevPathNodeA); + DevPathNodeB = NextDevicePathNode(DevPathNodeB); + } + + return FALSE; +} + +/** + Get EFI device path through EFI_SIMPLE_FILE_SYSTEM_PROTOCOL Handles buffer. Acquired path must + point to the same device as argument DevicePath passed to the function. + + @param[in] DevicePath Device path acquired from BootXXXX EFI variable + + @retval EFI_DEVICE_PATH_PROTOCOL Device path for booting +**/ +EFI_DEVICE_PATH_PROTOCOL * +GetFullBootDevicePath( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath +) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DPath; + EFI_DEVICE_PATH_PROTOCOL *DevPath; + UINTN HandleNum; + EFI_HANDLE *HandleBuf; + UINTN Index; + + DevPath = NULL; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &HandleNum, + &HandleBuf + ); + if ((EFI_ERROR (Status)) || (HandleBuf == NULL)) { + return NULL; + } + + for (Index = 0; Index < HandleNum; Index++) { + Status = gBS->HandleProtocol ( + HandleBuf[Index], + &gEfiDevicePathProtocolGuid, + &DPath + ); + + if (CompareDevicePaths(DevicePath, DPath)) { + DevPath = DuplicateDevicePath(DPath); + break; + } + } + + return DevPath; +} + +/*++ + Translate ASF request type to BBS or EFI device path type + + @param[in] DeviceType - ASF request type + @param[in] Efi - Set to TRUE if DeviceType is to be translated + to EFI device path type; FALSE if BBS type + @retval UINTN Translated device type +--*/ +UINTN +GetBootDeviceType ( + IN UINTN DeviceType, + IN BOOLEAN Efi + ) +{ + UINTN Type = 0; + + switch (DeviceType) { + case FORCE_PXE: + if (Efi) { + Type = MEDIA_FILEPATH_DP; + } else { + Type = BBS_EMBED_NETWORK; + } + break; + case FORCE_HARDDRIVE: + case FORCE_SAFEMODE: + if (Efi) { + Type = MEDIA_HARDDRIVE_DP; + } else { + Type = BBS_TYPE_HARDDRIVE; + } + break; + case FORCE_DIAGNOSTICS: + if (Efi) { + Type = MEDIA_FILEPATH_DP; + } + break; + case FORCE_CDDVD: + if (Efi) { + Type = MEDIA_CDROM_DP; + } else { + Type = BBS_TYPE_CDROM; + } + break; + default: + break; + } + + return Type; +} + +/** + Update the BBS table with our required boot device + + @param[in] DeviceIndex Boot device whose device index + @param[in] DevType Boot device whose device type + @param[in] BbsCount Number of BBS_TABLE structures + @param[in] BbsTable BBS entry + @param[in] IderBoot set to TRUE if this is IDER boot + + @retval EFI_SUCCESS BBS table successfully updated +**/ +EFI_STATUS +RefreshBbsTableForBoot ( + IN UINT16 DeviceIndex, + IN UINT16 DevType, + IN BOOLEAN IderBoot + ) +{ + EFI_STATUS Status; + UINTN Index; + UINT16 TempIndex; + BOOLEAN IderBootDevice; + BOOLEAN RegularBootDevice; + HDD_INFO *LocalHddInfo; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + BBS_TABLE *BbsTable; + UINT16 HddCount; + UINT16 BbsCount; + + TempIndex = (IderBoot) ? 0 : ((DeviceIndex <= 1) ? DeviceIndex : 1); + + // + // Make sure the Legacy Boot Protocol is available + // + Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, &LegacyBios); + if (LegacyBios == NULL) { + return EFI_ABORTED; + } + + // + // Get BBS table instance + // + Status = LegacyBios->GetBbsInfo ( + LegacyBios, + &HddCount, + &LocalHddInfo, + &BbsCount, + &BbsTable + ); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + + Status = EFI_NOT_FOUND; + + // + // For debug + // + PrintBbsTable (BbsTable); + + // + // Find the first present boot device whose device type + // matches the DevType, we use it to boot first. This is different + // from the other Bbs table refresh since we are looking for the device type + // index instead of the first device to match the device type. + // + // And set other present boot devices' priority to BBS_UNPRIORITIZED_ENTRY + // their priority will be set by LegacyBiosPlatform protocol by default + // + for (Index = 0; Index < BbsCount; Index++) { + if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) { + continue; + } + + BbsTable[Index].BootPriority = BBS_DO_NOT_BOOT_FROM; + IderBootDevice = IderBoot && IS_IDER(BbsTable[Index].Bus, BbsTable[Index].Device, BbsTable[Index].Function) && + BbsTable[Index].DeviceType == DevType; + RegularBootDevice = !IderBoot && (BbsTable[Index].DeviceType == DevType || + (DevType == BBS_EMBED_NETWORK && IS_PXE(BbsTable[Index].DeviceType, BbsTable[Index].Class)) || + (DevType == BBS_TYPE_CDROM && IS_CDROM(BbsTable[Index].DeviceType, BbsTable[Index].Class))); + + if ((IderBootDevice || RegularBootDevice) && Status != EFI_SUCCESS) { + if (IderBoot || (TempIndex++ == DeviceIndex)) { + BbsTable[Index].BootPriority = 0; + Status = EFI_SUCCESS; + continue; + } + } + } + + // + // For debug + // + PrintBbsTable (BbsTable); + + return Status; +} + +EFI_DEVICE_PATH_PROTOCOL * +BdsCreateBootDevicePath ( + IN UINT16 DeviceType, + IN UINT16 DeviceIndex, + IN BOOLEAN IdeRBoot, + IN BOOLEAN EfiBoot + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; + EFI_DEVICE_PATH_PROTOCOL *FullDevicePath; + UINTN OptionOrderSize; + UINT16 *OptionOrder; + EFI_LOAD_OPTION *Option; + CHAR16 OptionName[sizeof ("Driver####")]; + UINT16 OptionNumber; + UINTN OptionIndex; + UINTN OptionCount; + UINTN Index; + UINTN OptionSize; + UINTN TempIndex; + EFI_DEVICE_PATH_PROTOCOL *DevPathNode; + EFI_DEVICE_PATH_PROTOCOL *DevPathNodeBackup; + ATAPI_DEVICE_PATH *AtaPath; + BOOLEAN AtaDeviceMatch; + PCI_DEVICE_PATH *PciPath; + BOOLEAN PciDeviceMatch; + UINT8 PrimarySecondary; + UINT8 SlaveMaster; + UINTN EfiDeviceType; + UINTN LegacyDeviceType; + BOOLEAN TypeMatched; + + PrimarySecondary = ((mAsfBootOptions->SpecialCommandParam >> IDER_BOOT_DEVICE_SHIFT) & IDER_PRIMARY_SECONDARY_MASK) + >> IDER_PRIMARY_SECONDARY_SHIFT; + SlaveMaster = (mAsfBootOptions->SpecialCommandParam >> IDER_BOOT_DEVICE_SHIFT) & IDER_MASTER_SLAVE_MASK; + DevicePath = NULL; + FullDevicePath = NULL; + TempIndex = 1; + AtaDeviceMatch = FALSE; + PciDeviceMatch = FALSE; + EfiDeviceType = GetBootDeviceType(DeviceType, TRUE); + LegacyDeviceType = GetBootDeviceType(DeviceType, FALSE); + TypeMatched = FALSE; + + if (IdeRBoot && !EfiBoot) { + LegacyDeviceType = (SlaveMaster == 1) ? BBS_CDROM : BBS_HARDDISK; + } + + // + // Read the BootOrder variable. + // + OptionOrder = BdsLibGetVariableAndSize (L"BootOrder", &gEfiGlobalVariableGuid, &OptionOrderSize); + if (OptionOrder == NULL) { + return NULL; + } + + OptionCount = OptionOrderSize/sizeof(UINT16); + OptionIndex = 0; + + for (Index = 0; Index < OptionCount; Index++) { + + OptionNumber = OptionOrder[Index]; + UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionNumber); + Option = BdsLibGetVariableAndSize (OptionName, &gEfiGlobalVariableGuid, &OptionSize); + if (Option == NULL) { + continue; + } + + // + // Extract device path from the boot order entry + // + TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL*) + ( //skip the header + (UINT8*)(Option+1) + //skip the string + +(EfiStrLen((CHAR16*)(Option+1))+1)*sizeof(CHAR16) + ); + + if (DevicePathType(TempDevicePath) == BBS_DEVICE_PATH && DevicePathSubType(TempDevicePath) == BBS_BBS_DP) { + FullDevicePath = DuplicateDevicePath(TempDevicePath); + } else { + // + // If this is EFI boot option, we need to get full device path from EFI_SIMPLE_FILE_SYSTEM_PROTOCOL + // to determine type of device and provide LoadImage with proper path to bootloader image later on + // + FullDevicePath = GetFullBootDevicePath(TempDevicePath); + if (FullDevicePath == NULL) { + continue; + } + } + + TempDevicePath = FullDevicePath; + DevPathNode = BdsLibUnpackDevicePath(TempDevicePath); + if (DevPathNode == NULL) { + continue; + } + + DevPathNodeBackup = DevPathNode; + + // + // Check if this is our requested boot device + // + while (!IsDevicePathEnd(DevPathNode)) { + if (IdeRBoot && EfiBoot) { + // + // IDER EFI boot, check for PCI/ATA device match + // + if ((DevicePathType(DevPathNode) == HARDWARE_DEVICE_PATH) && + (DevicePathSubType(DevPathNode) == HW_PCI_DP)) { + PciPath = (PCI_DEVICE_PATH*) DevPathNode; + + if ((PciPath->Device == IDER_DEVICE_NUMBER) + && (PciPath->Function == IDER_FUNCTION_NUMBER)) { + PciDeviceMatch = TRUE; + } + } else if ((DevicePathType(DevPathNode) == MESSAGING_DEVICE_PATH) && + (DevicePathSubType(DevPathNode) == MSG_ATAPI_DP)) { + AtaPath = (ATAPI_DEVICE_PATH*) DevPathNode; + + if ((AtaPath->PrimarySecondary == PrimarySecondary) + && (AtaPath->SlaveMaster == SlaveMaster)) { + AtaDeviceMatch = TRUE; + } + } + + if (PciDeviceMatch && AtaDeviceMatch) { + TypeMatched = TRUE; + } + } else { + if (DevicePathType(DevPathNode) == BBS_DEVICE_PATH && DevicePathSubType(DevPathNode) == BBS_BBS_DP) { + // + // Legacy boot option + // + if (((BBS_BBS_DEVICE_PATH *)DevPathNode)->DeviceType == LegacyDeviceType) { + TypeMatched = TRUE; + } + } else { + // + // EFI boot option + // + if (DevicePathType(DevPathNode) == MEDIA_DEVICE_PATH && DevicePathSubType(DevPathNode) == EfiDeviceType) { + TypeMatched = TRUE; + } + } + } + + if (TypeMatched) { + // + // Type matched, check for device index + // + if (!IdeRBoot && TempIndex < DeviceIndex) { + TempIndex++; + TypeMatched = FALSE; + break; + } + + DevicePath = DuplicateDevicePath(TempDevicePath); + // + // Refresh BBS table if legacy option + // + if (DevicePathType(DevicePath) == BBS_DEVICE_PATH && DevicePathSubType(DevicePath) == BBS_BBS_DP) { + RefreshBbsTableForBoot(DeviceIndex, (UINT16)LegacyDeviceType, IdeRBoot); + } + break; + } + + DevPathNode = NextDevicePathNode(DevPathNode); + } + + if (FullDevicePath != NULL) { + FreePool(FullDevicePath); + FullDevicePath = NULL; + } + + FreePool(DevPathNodeBackup); + FreePool(Option); + + if (DevicePath != NULL) { + // + // Set Boot Current and leave + // + gRT->SetVariable ( + L"BootCurrent", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + sizeof (UINT16), + &OptionNumber + ); + break; + } + } + + FreePool(OptionOrder); + + return DevicePath; +} + +/** + Boot the legacy system with the boot option + + @param[in] Option The legacy boot option which have BBS device path + + @retval EFI_UNSUPPORTED - There is no legacybios protocol, do not support legacy boot. + @retval EFI_STATUS - Return the status of LegacyBios->LegacyBoot (). +**/ +EFI_STATUS +AsfDoLegacyBoot ( + IN BDS_COMMON_OPTION *Option + ) +{ + 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; + } + // + // Write boot to OS performance data to a file + // + WRITE_BOOT_TO_OS_PERFORMANCE_DATA; + + 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 + ); +} + +/** + Process the boot option follow the EFI 1.1 specification and + special treat the legacy boot option with BBS_DEVICE_PATH. + + @param[in] Option The boot option need to be processed + @param[in] DevicePath The device path which describe where to load + the boot image or the legcy BBS device path + to boot the legacy OS + @param[in] ExitDataSize Returned directly from gBS->StartImage () + @param[in] ExitData Returned directly from gBS->StartImage () + + @retval EFI_SUCCESS - Status from gBS->StartImage (), + or BdsBootByDiskSignatureAndPartition () + @retval EFI_NOT_FOUND - If the Device Path is not found in the system +**/ +EFI_STATUS +AsfBootViaBootOption ( + IN BDS_COMMON_OPTION * Option, + IN EFI_DEVICE_PATH_PROTOCOL * DevicePath, + OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL + ) +{ + 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_EVENT ReadyToBootEvent; + EFI_ACPI_S3_SAVE_PROTOCOL *AcpiS3Save; + UINTN DataSize; + EFI_INPUT_KEY Key; + UINTN EventIndex; +#ifdef EFI_DEBUG + UINT8 SecureBootState; +#endif + + *ExitDataSize = 0; + *ExitData = NULL; + DataSize = sizeof(UINT16); + + // + // 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, + // 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; + } + + // + // Set Option's BootCurrent field + // + gRT->GetVariable ( + L"BootCurrent", + &gEfiGlobalVariableGuid, + 0, + &DataSize, + &Option->BootCurrent + ); + + DEBUG ((EFI_D_INFO, "AsfBootViaBootOption: BootCurrent = %d, DevicePath = %s\n", Option->BootCurrent, DevicePathToStr(DevicePath))); + + // + // Signal the EFI_EVENT_SIGNAL_READY_TO_BOOT event + // + Status = EfiCreateEventReadyToBoot (&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 AsfDoLegacyBoot (Option); + } + + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Booting EFI 1.1 way %S\n", Option->Description)); + + // + // If this is RCO/IDER EFI Boot, don't allow returning to regular boot + // and booting other devices + // + while (1) { + 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, DEFAULT_REMOVABLE_FILE_NAME); + if (FilePath) { + Status = gBS->LoadImage ( + TRUE, + mBdsImageHandle, + FilePath, + NULL, + 0, + &ImageHandle + ); + } else { + Status = EFI_NOT_FOUND; + } + } else { + Status = EFI_NOT_FOUND; + } + } + + if (!EFI_ERROR (Status)) { + // + // 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; + } + +#ifdef EFI_DEBUG + // + // Get SecureBoot state + // + SecureBootState = GetSecureBootState(); + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "SecureBootEnable value prior to image execution %d\n", SecureBootState)); +#endif + // + // 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); + } + + // + // Display message to user before attempting another RCO/IDER boot + // + gST->ConOut->ClearScreen (gST->ConOut); + gST->ConOut->OutputString ( + gST->ConOut, + L"EFI RCO/IDER boot failed. Press ENTER to try again\r\n" + ); + Key.ScanCode = 0; + Key.UnicodeChar = 0; + while (!(Key.ScanCode == 0 && Key.UnicodeChar == L'\r')) { + gBS->WaitForEvent (1, &(gST->ConIn->WaitForKey), &EventIndex); + gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + } + } + + // + // Clear Boot Current + // + gRT->SetVariable ( + L"BootCurrent", + &gEfiGlobalVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + 0, + &Option->BootCurrent + ); + + return Status; +} + +/** + Found out ASF boot options. + + @param[in] EfiBoot Set to TRUE if this is EFI boot + + @retval EFI_DEVICE_PATH_PROTOCOL Device path for booting. +**/ +EFI_DEVICE_PATH_PROTOCOL * +BdsAsfBoot ( + IN BOOLEAN EfiBoot + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + DevicePath = NULL; + + // + // First we check ASF boot options Special Command + // + switch (mAsfBootOptions->SpecialCommand) { + // + // No additional special command is included; the Special Command Parameter has no + // meaning. + // + case NOP: + break; + + // + // The Special Command Parameter can be used to specify a PXE + // parameter. When the parameter value is 0, the system default PXE device is booted. All + // other values for the PXE parameter are reserved for future definition by this specification. + // + case FORCE_PXE: + if (mAsfBootOptions->SpecialCommandParam != 0) { + // + // ASF spec says 0 currently only option + // + break; + } + + if (EfiBoot == TRUE) { + DevicePath = BdsCreatePxeDevicePath (mAsfBootOptions->SpecialCommandParam); + } else { + DevicePath = BdsCreateBootDevicePath (FORCE_PXE, mAsfBootOptions->SpecialCommandParam, FALSE, EfiBoot); + } + break; + + // + // The Special Command Parameter identifies the boot-media index for + // the managed client. When the parameter value is 0, the default hard-drive is booted, when the + // parameter value is 1, the primary hard-drive is booted; when the value is 2, the secondary + // hard-drive is booted and so on. + // + case FORCE_HARDDRIVE: + // + // The Special Command Parameter identifies the boot-media + // index for the managed client. When the parameter value is 0, the default hard-drive is + // booted, when the parameter value is 1, the primary hard-drive is booted; when the value is 2, + // the secondary hard-drive is booted and so on. + // + case FORCE_SAFEMODE: + DevicePath = BdsCreateBootDevicePath(FORCE_HARDDRIVE, mAsfBootOptions->SpecialCommandParam, FALSE, EfiBoot); + break; + + // + // The Special Command Parameter can be used to specify a + // diagnostic parameter. When the parameter value is 0, the default diagnostic media is booted. + // All other values for the diagnostic parameter are reserved for future definition by this + // specification. + // + case FORCE_DIAGNOSTICS: + if (mAsfBootOptions->SpecialCommandParam != 0) { + // + // ASF spec says 0 currently only option + // + break; + } + + DevicePath = BdsCreateShellDevicePath (); + + // + // We want everything connected up for shell + // + BdsLibConnectAllDriversToAllControllers (); + break; + + // + // The Special Command Parameter identifies the boot-media index for + // the managed client. When the parameter value is 0, the default CD/DVD is booted, when the + // parameter value is 1, the primary CD/DVD is booted; when the value is 2, the secondary + // CD/DVD is booted and so on. + // + case FORCE_CDDVD: + DevicePath = BdsCreateBootDevicePath (FORCE_CDDVD, mAsfBootOptions->SpecialCommandParam, FALSE, EfiBoot); + break; + + default: + break;; + } + + return DevicePath; +} + +/** + Check IdeR boot device and Asf boot device + + @param[in] EfiBoot Set to TRUE if this is EFI boot + + @retval EFI_DEVICE_PATH_PROTOCOL Device path for booting. +**/ +EFI_DEVICE_PATH_PROTOCOL * +BdsForcedBoot ( + IN BOOLEAN EfiBoot + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + DevicePath = NULL; + + // + // OEM command values; the interpretation of the Special Command and associated Special + // Command Parameters is defined by the entity associated with the Enterprise ID. + // + if (ActiveManagementEnableIdeR ()) { + // + // Check if any media exist in Ider device + // + if (BdsCheckIderMedia ()) { + DevicePath = BdsCreateBootDevicePath ( + FORCE_CDDVD, + 0, + TRUE, + EfiBoot + ); + } + } else if (mAsfBootOptions->IanaId != ASF_INDUSTRY_CONVERTED_IANA) { + DevicePath = BdsAsfBoot (EfiBoot); + } + + return DevicePath; +} + +/** + Process ASF boot options and if available, attempt the boot + + @param[in] None. + + @retval EFI_SUCCESS The command completed successfully +**/ +EFI_STATUS +BdsBootViaAsf ( + IN VOID + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + BDS_COMMON_OPTION *BootOption; + UINTN ExitDataSize; + CHAR16 *ExitData; + BOOLEAN EfiBoot; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + + Status = EFI_SUCCESS; + DevicePath = NULL; + EfiBoot = FALSE; + + // + // Check if this is legacy or efi boot + // + Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, &LegacyBios); + if (LegacyBios == NULL) { + EfiBoot = TRUE; + } + + // + // Check if ASF Boot Options is present. + // + if (mAsfBootOptions->SubCommand != ASF_BOOT_OPTIONS_PRESENT) { + return EFI_NOT_FOUND; + } + + DevicePath = BdsForcedBoot (EfiBoot); + // + // If device path was set, the we have a boot option to use + // + if (DevicePath == NULL) { + return EFI_UNSUPPORTED; + } + + BootOption = BdsCreateBootOption (DevicePath, L"ASF Boot"); + if (BootOption == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = AsfBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData); + + FreePool (BootOption); + FreePool (DevicePath); + + return Status; +} + +/** + This will return if Media in IDE-R is present. + + @param[in] None. + + @retval TRUE Media is present. + @retval FALSE Media is not present. +**/ +BOOLEAN +BdsCheckIderMedia ( + IN VOID + ) +{ + UINTN HandleNum; + EFI_HANDLE *HandleBuf; + EFI_HANDLE Handle; + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL *DPath; + UINTN Index; + UINTN EventIndex; + EFI_INPUT_KEY Key; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + EFI_DISK_INFO_PROTOCOL *DiskInfo; + EFI_BLOCK_IO_MEDIA *BlkMedia; + VOID *Buffer; + UINT8 IdeBootDevice; + UINT32 IdeChannel; + UINT32 IdeDevice; + + IdeBootDevice = ActiveManagementIderBootDeviceGet (); + + DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Ide Channel Device Index = %d\n", IdeBootDevice)); + + // + // Make sure the Legacy Boot Protocol is available + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &HandleNum, + &HandleBuf + ); + if ((EFI_ERROR (Status)) || (HandleBuf == NULL)) { + goto Exit; + } + + for (Index = 0; Index < HandleNum; Index++) { + Status = gBS->HandleProtocol ( + HandleBuf[Index], + &gEfiDevicePathProtocolGuid, + &DPath + ); + if (EFI_ERROR (Status)) { + continue; + } + + Status = gBS->LocateDevicePath ( + &gEfiIderControllerDriverProtocolGuid, + &DPath, + &Handle + ); + if (EFI_ERROR (Status)) { + continue; + } + + Status = gBS->HandleProtocol ( + HandleBuf[Index], + &gEfiBlockIoProtocolGuid, + &BlkIo + ); + + if (EFI_ERROR(Status)) { + continue; + } + + Status = gBS->HandleProtocol ( + HandleBuf[Index], + &gEfiDiskInfoProtocolGuid, + &DiskInfo + ); + + if (EFI_ERROR(Status)) { + continue; + } + + DiskInfo->WhichIde (DiskInfo, &IdeChannel, &IdeDevice); + + if (IdeBootDevice != (UINT8) (IdeChannel * 2 + IdeDevice)) { + continue; + } + + if (BlkIo->Media->MediaPresent) { + if (HandleBuf != NULL) { + FreePool (HandleBuf); + } + return TRUE; + } + + while (TRUE) { + BlkMedia = BlkIo->Media; + Buffer = AllocatePool (BlkMedia->BlockSize); + if (Buffer) { + BlkIo->ReadBlocks ( + BlkIo, + BlkMedia->MediaId, + 0, + BlkMedia->BlockSize, + Buffer + ); + FreePool (Buffer); + } + + if (BlkMedia->MediaPresent) { + if (HandleBuf != NULL) { + FreePool (HandleBuf); + } + return TRUE; + } + + gST->ConOut->OutputString ( + gST->ConOut, + L"Boot disk missing, please insert boot disk and press ENTER\r\n" + ); + Key.ScanCode = 0; + Key.UnicodeChar = 0; + gBS->RestoreTPL (EFI_TPL_APPLICATION); + while (!(Key.ScanCode == 0 && Key.UnicodeChar == L'\r')) { + Status = gBS->WaitForEvent (1, &(gST->ConIn->WaitForKey), &EventIndex); + gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + } + + gBS->RaiseTPL (EFI_TPL_DRIVER); + } + + break; + } + +Exit: + if (HandleBuf != NULL) { + FreePool (HandleBuf); + } + return FALSE; +} |