From: srs5694 Date: Sun, 30 Sep 2012 18:27:16 +0000 (-0400) Subject: New files to support legacy BIOS boots on UEFI-based PCs X-Git-Url: https://code.delx.au/refind/commitdiff_plain/35c7b1041c43abf31924dcf70c55f79b05fd9216 New files to support legacy BIOS boots on UEFI-based PCs --- diff --git a/EfiLib/BdsHelper.c b/EfiLib/BdsHelper.c new file mode 100644 index 0000000..80eb7f2 --- /dev/null +++ b/EfiLib/BdsHelper.c @@ -0,0 +1,153 @@ +/* + * EfiLib/BdsHelper.c + * Functions to call legacy BIOS API. + * + */ + + +#include "BdsHelper.h" + +/** + Internal helper function. + + Update the BBS Table so that devices of DeviceType have their boot priority + updated to a high/bootable value. + + See "DeviceType values" in + http://www.intel.com/content/dam/doc/reference-guide/efi-compatibility-support-module-specification-v097.pdf + + NOTE: This function should probably be refactored! Currently, all devices of + type are enabled. This should be updated so that only a specific device is + enabled. The wrong device could boot if there are multiple targets of the same + type. + + @param DeviceType The device type that we wish to enable +**/ +VOID +UpdateBbsTable ( + IN UINT16 DeviceType + ) +{ + UINT16 Idx; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + EFI_GUID EfiLegacyBootProtocolGuid = { 0xdb9a1e3d, 0x45cb, 0x4abb, { 0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d }}; + EFI_STATUS Status; + UINT16 HddCount = 0; + HDD_INFO *HddInfo = NULL; + UINT16 BbsCount = 0; + BBS_TABLE *LocalBbsTable = NULL; + + Status = gBS->LocateProtocol (&EfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + return; + } + + Status = LegacyBios->GetBbsInfo (LegacyBios, &HddCount, &HddInfo, &BbsCount, &LocalBbsTable); + + //Print (L"\n"); + //Print (L" NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"); + //Print (L"=============================================\n"); + + for (Idx = 0; Idx < BbsCount; Idx++) + { + if(LocalBbsTable[Idx].DeviceType == 0){ + continue; + } + + // Set devices of a particular type to BootPriority of 0. I believe 0 is the highest priority + if(LocalBbsTable[Idx].DeviceType == DeviceType){ + LocalBbsTable[Idx].BootPriority = 0; + } + +/* + Print ( + L" %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n", + (UINTN) Idx, + (UINTN) LocalBbsTable[Idx].BootPriority, + (UINTN) LocalBbsTable[Idx].Bus, + (UINTN) LocalBbsTable[Idx].Device, + (UINTN) LocalBbsTable[Idx].Function, + (UINTN) LocalBbsTable[Idx].Class, + (UINTN) LocalBbsTable[Idx].SubClass, + (UINTN) LocalBbsTable[Idx].DeviceType, + (UINTN) * (UINT16 *) &LocalBbsTable[Idx].StatusFlags, + (UINTN) LocalBbsTable[Idx].BootHandlerSegment, + (UINTN) LocalBbsTable[Idx].BootHandlerOffset, + (UINTN) ((LocalBbsTable[Idx].MfgStringSegment << 4) + LocalBbsTable[Idx].MfgStringOffset), + (UINTN) ((LocalBbsTable[Idx].DescStringSegment << 4) + LocalBbsTable[Idx].DescStringOffset) + ); +*/ + } + + //Print(L"\n"); +} + +// Internal helper function +BOOLEAN ArrayContains(UINT16* Arr, UINT8 ArrLen, UINT8 Target) +{ + UINT8 i; + for(i = 0; i < ArrLen; i++) + { + if(Arr[i] == Target) + return TRUE; + } + + return FALSE; +} + +/** + True if the DeviceType is supported by rEFInd, false otherwise. +*/ +BOOLEAN IsBbsDeviceTypeSupported(UINT16 DeviceType) +{ + return ArrayContains(SupportedLegacyDevices, sizeof(SupportedLegacyDevices), DeviceType); +} + +/** + Boot the legacy system with the boot option + + @param 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 +BdsLibDoLegacyBoot ( + IN BDS_COMMON_OPTION *Option + ) +{ + EFI_STATUS Status; + EFI_LEGACY_BIOS_PROTOCOL *LegacyBios; + EFI_GUID EfiLegacyBootProtocolGuid = { 0xdb9a1e3d, 0x45cb, 0x4abb, { 0x85, 0x3b, 0xe5, 0x38, 0x7f, 0xdb, 0x2e, 0x2d }}; + EFI_GUID EfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }}; + BBS_BBS_DEVICE_PATH *OptionBBS; + + Status = gBS->LocateProtocol (&EfiLegacyBootProtocolGuid, NULL, (VOID **) &LegacyBios); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + OptionBBS = (BBS_BBS_DEVICE_PATH *) Option->DevicePath; + + //Print(L"\n\n"); + //Print(L"Option->Name='%s'\n", Option->OptionName); + //Print(L"Option->Number='%d'\n", Option->OptionNumber); + //Print(L"Option->Description='%s'\n", Option->Description); + //Print(L"Option->LoadOptionsSize='%d'\n",Option->LoadOptionsSize); + //Print(L"Option->BootCurrent='%d'\n",Option->BootCurrent); + //Print(L"Option->DevicePath->Type= '%d'\n", Option->DevicePath->Type); + //Print(L"Option->DevicePath->SubType= '%d'\n", Option->DevicePath->SubType); + //Print(L"Option->DevicePath->Length[0]= '%d'\n", Option->DevicePath->Length[0]); + //Print(L"Option->DevicePath->Length[1]= '%d'\n", Option->DevicePath->Length[1]); + //Print(L"OptionBBS->DeviceType='%d'\n",OptionBBS->DeviceType); + //Print(L"OptionBBS->StatusFlag='%d'\n",OptionBBS->StatusFlag); + //Print(L"OptionBBS->String[0]='%c'\n",OptionBBS->String[0]); + //Print(L"About to legacy boot!\n"); + //PauseForKey(); + + UpdateBbsTable(OptionBBS->DeviceType); + + return LegacyBios->LegacyBoot (LegacyBios, (BBS_BBS_DEVICE_PATH *) Option->DevicePath, Option->LoadOptionsSize, Option->LoadOptions); +} + diff --git a/EfiLib/BdsHelper.h b/EfiLib/BdsHelper.h new file mode 100644 index 0000000..6739b85 --- /dev/null +++ b/EfiLib/BdsHelper.h @@ -0,0 +1,37 @@ +/* + * EfiLib/BdsHelper.c + * Functions to call legacy BIOS API. + * + */ + +#include "../include/tiano_includes.h" + +#ifndef _BDS_HELPER_H_ +#define _BDS_HELPER_H_ + +//TODO: may want to make this configurable via config file +static UINT16 SupportedLegacyDevices[] = {BBS_HARDDISK, BBS_CDROM, BBS_USB}; + + +/** + True if the DeviceType is supported by rEFInd, false otherwise. +*/ +BOOLEAN IsBbsDeviceTypeSupported(UINT16 DeviceType); + + +/** + Boot the legacy system with the boot option + + @param 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 +BdsLibDoLegacyBoot ( + IN BDS_COMMON_OPTION *Option + ); + +#endif //_BDS_HELPER_H_ diff --git a/EfiLib/BdsTianoCore.c b/EfiLib/BdsTianoCore.c new file mode 100644 index 0000000..2163b99 --- /dev/null +++ b/EfiLib/BdsTianoCore.c @@ -0,0 +1,201 @@ +/** @file + BDS Lib functions which relate with create or process the boot option. + +Copyright (c) 2004 - 2011, 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. + +**/ + +#include "../include/tiano_includes.h" + +/** + Build the boot#### or driver#### option from the VariableName, the + build boot#### or driver#### will also be linked to BdsCommonOptionList. + + @param BdsCommonOptionList The header of the boot#### or driver#### option + link list + @param VariableName EFI Variable name indicate if it is boot#### or + driver#### + + @retval BDS_COMMON_OPTION Get the option just been created + @retval NULL Failed to get the new option + +**/ +BDS_COMMON_OPTION * +EFIAPI +BdsLibVariableToOption ( + IN OUT LIST_ENTRY *BdsCommonOptionList, + IN CHAR16 *VariableName + ) +{ + UINT32 Attribute; + UINT16 FilePathSize; + UINT8 *Variable; + UINT8 *TempPtr; + UINTN VariableSize; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + BDS_COMMON_OPTION *Option; + VOID *LoadOptions; + UINT32 LoadOptionsSize; + CHAR16 *Description; + UINT8 NumOff; + EFI_GUID EfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }}; + + // + // Read the variable. We will never free this data. + // + Variable = BdsLibGetVariableAndSize ( + VariableName, + &EfiGlobalVariableGuid, + &VariableSize + ); + if (Variable == NULL) { + return NULL; + } + // + // Notes: careful defined the variable of Boot#### or + // Driver####, consider use some macro to abstract the code + // + // + // Get the option attribute + // + TempPtr = Variable; + Attribute = *(UINT32 *) Variable; + TempPtr += sizeof (UINT32); + + // + // Get the option's device path size + // + FilePathSize = *(UINT16 *) TempPtr; + TempPtr += sizeof (UINT16); + + // + // Get the option's description string + // + Description = (CHAR16 *) TempPtr; + + // + // Get the option's description string size + // + TempPtr += StrSize ((CHAR16 *) TempPtr); + + // + // Get the option's device path + // + DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr; + TempPtr += FilePathSize; + + LoadOptions = TempPtr; + LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable)); + + // + // The Console variables may have multiple device paths, so make + // an Entry for each one. + // + Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION)); + if (Option == NULL) { + return NULL; + } + + Option->Signature = BDS_LOAD_OPTION_SIGNATURE; + Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath)); + ASSERT(Option->DevicePath != NULL); + CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath)); + + Option->Attribute = Attribute; + Option->Description = AllocateZeroPool (StrSize (Description)); + ASSERT(Option->Description != NULL); + CopyMem (Option->Description, Description, StrSize (Description)); + + Option->LoadOptions = AllocateZeroPool (LoadOptionsSize); + ASSERT(Option->LoadOptions != NULL); + CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize); + Option->LoadOptionsSize = LoadOptionsSize; + + // + // Get the value from VariableName Unicode string + // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this + // Unicode stream to ASCII without any loss in meaning. + // + if (*VariableName == 'B') { + NumOff = (UINT8) (sizeof (L"Boot") / sizeof(CHAR16) - 1); + Option->BootCurrent = (UINT16) ((VariableName[NumOff] -'0') * 0x1000); + Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+1]-'0') * 0x100)); + Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+2]-'0') * 0x10)); + Option->BootCurrent = (UINT16) (Option->BootCurrent + ((VariableName[NumOff+3]-'0'))); + } + // + // Insert active entry to BdsDeviceList + // + if ((Option->Attribute & LOAD_OPTION_ACTIVE) == LOAD_OPTION_ACTIVE) { + InsertTailList (BdsCommonOptionList, &Option->Link); + FreePool (Variable); + return Option; + } + + FreePool (Variable); + FreePool (Option); + return NULL; + +} + + +/** + Read the EFI variable (VendorGuid/Name) and return a dynamically allocated + buffer, and the size of the buffer. If failure return NULL. + + @param Name String part of EFI variable name + @param VendorGuid GUID part of EFI variable name + @param VariableSize Returns the size of the EFI variable that was read + + @return Dynamically allocated memory that contains a copy of the EFI variable + Caller is responsible freeing the buffer. + @retval NULL Variable was not read + +**/ +VOID * +EFIAPI +BdsLibGetVariableAndSize ( + IN CHAR16 *Name, + IN EFI_GUID *VendorGuid, + OUT UINTN *VariableSize + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + VOID *Buffer; + + Buffer = NULL; + + // + // Pass in a zero size buffer to find the required buffer size. + // + BufferSize = 0; + Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer); + if (Status == EFI_BUFFER_TOO_SMALL) { + // + // Allocate the buffer to return + // + Buffer = AllocateZeroPool (BufferSize); + if (Buffer == NULL) { + return NULL; + } + // + // Read variable into the allocated buffer. + // + Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer); + if (EFI_ERROR (Status)) { + BufferSize = 0; + } + } + + *VariableSize = BufferSize; + return Buffer; +} +