--- /dev/null
+/*
+ * 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);
+}
+
--- /dev/null
+/*
+ * 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_
--- /dev/null
+/** @file
+ BDS Lib functions which relate with create or process the boot option.
+
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+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;
+}
+