From: srs5694 Date: Sun, 8 Jun 2014 01:05:30 +0000 (-0400) Subject: Added ability to boot the previously-booted loader if X-Git-Url: https://code.delx.au/refind/commitdiff_plain/999e9b76afa9e57b16b54da313a46bdcf08dc412 Added ability to boot the previously-booted loader if default_selection is NOT set. --- diff --git a/NEWS.txt b/NEWS.txt index fac4224..1e5686d 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,6 +1,18 @@ 0.8.2 (5/??/2014): ------------------ +- Changed behavior when default_selection is not set: It now boots the + previously-booted loader, assuming it's still available; if not, rEFInd + boots the first loader (as it does now). Behavior is unchanged if + default_selection is set. Note that this behavior depends on the ability + of rEFInd to store an EFI variable in NVRAM. It therefore fails on + systems with flaky NVRAM storage. You can view the previously-booted + loader in the + /sys/firmware/efi/efivars/PreviousBoot-36d08fa7-cf0b-42f5-8f14-68df73ed3740 + variable under Linux. + +- Added icon for Mageia Linux (os_mageia.png). + - Fixed bug that could misidentify a not-quite-GUID as a GUID in a manual boot stanza's "volume" line. diff --git a/install.sh b/install.sh index cb87606..67df9ee 100755 --- a/install.sh +++ b/install.sh @@ -446,7 +446,27 @@ MountDefaultTarget() { MountOSXESP() { # Identify the ESP. Note: This returns the FIRST ESP found; # if the system has multiple disks, this could be wrong! - Temp=`diskutil list | grep " EFI " | grep -o 'disk.*'` + Temp=$(mount | sed -n -E "/^(\/dev\/disk[0-9]+s[0-9]+) on \/ \(.*$/s//\1/p") + if [ $Temp ]; then + Temp=$(diskutil list $Temp | sed -n -E '/^ *[0-9]+:[ ]+EFI EFI[ ]+[0-9.]+ [A-Z]+[ ]+(disk[0-9]+s[0-9]+)$/ { s//\1/p + q + }' ) + if [ -z $Temp ]; then + echo "Warning: root device doesn't have an EFI partition" + fi + else + echo "Warning: root device could not be found" + fi + if [ -z $Temp ]; then + Temp=$(diskutil list | sed -n -E '/^ *[0-9]+:[ ]+EFI EFI[ ]+[0-9.]+ [A-Z]+[ ]+(disk[0-9]+s[0-9]+)$/ { s//\1/p + q + }' ) + + if [ -z $Temp ]; then + echo "Could not find an EFI partition. Aborting!" + exit 1 + fi + fi Esp=/dev/`echo $Temp` # If the ESP is mounted, use its current mount point.... Temp=`df -P | grep "$Esp"` diff --git a/mok/mok.c b/mok/mok.c index 3948b08..6b47522 100644 --- a/mok/mok.c +++ b/mok/mok.c @@ -47,29 +47,9 @@ #include "global.h" #include "mok.h" #include "../include/refit_call_wrapper.h" +#include "../refind/lib.h" +#include "../refind/screen.h" -static EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid, UINT32 *attributes, UINTN *size, VOID **buffer) -{ - EFI_STATUS efi_status; - char allocate = !(*size); - - efi_status = uefi_call_wrapper(RT->GetVariable, 5, name, &guid, attributes, size, buffer); - - if (efi_status != EFI_BUFFER_TOO_SMALL || !allocate) { - return efi_status; - } - - *buffer = AllocatePool(*size); - - if (!*buffer) { - Print(L"Unable to allocate variable buffer\n"); - return EFI_OUT_OF_RESOURCES; - } - - efi_status = uefi_call_wrapper(RT->GetVariable, 5, name, &guid, attributes, size, *buffer); - - return efi_status; -} // get_variable() /* * Check whether we're in Secure Boot and user mode @@ -79,19 +59,16 @@ BOOLEAN secure_mode (VOID) EFI_STATUS status; EFI_GUID global_var = EFI_GLOBAL_VARIABLE; UINTN charsize = sizeof(char); - UINT8 sb, setupmode; - UINT32 attributes; - - status = get_variable(L"SecureBoot", global_var, &attributes, &charsize, (VOID *)&sb); + UINT8 *sb = NULL, *setupmode = NULL; + status = EfivarGetRaw(&global_var, L"SecureBoot", (CHAR8 **) &sb, &charsize); /* FIXME - more paranoia here? */ - if (status != EFI_SUCCESS || sb != 1) { + if (status != EFI_SUCCESS || charsize != sizeof(CHAR8) || *sb != 1) { return FALSE; } - status = get_variable(L"SetupMode", global_var, &attributes, &charsize, (VOID *)&setupmode); - - if (status == EFI_SUCCESS && setupmode == 1) { + status = EfivarGetRaw(&global_var, L"SetupMode", (CHAR8 **) &setupmode, &charsize); + if (status == EFI_SUCCESS && charsize == sizeof(CHAR8) && *setupmode == 1) { return FALSE; } diff --git a/mok/mok.h b/mok/mok.h index 7648209..d24e2b4 100644 --- a/mok/mok.h +++ b/mok/mok.h @@ -24,6 +24,7 @@ typedef struct _SHIM_LOCK } SHIM_LOCK; #endif +//EFI_STATUS get_variable (CHAR16 *name, EFI_GUID guid, UINT32 *attributes, UINTN *size, VOID **buffer); BOOLEAN ShimLoaded(void); BOOLEAN ShimValidate (VOID *data, UINT32 size); BOOLEAN secure_mode (VOID); diff --git a/refind/config.c b/refind/config.c index 0901815..e261ef8 100644 --- a/refind/config.c +++ b/refind/config.c @@ -50,6 +50,7 @@ #include "config.h" #include "screen.h" #include "../include/refit_call_wrapper.h" +#include "../mok/mok.h" // constants @@ -430,6 +431,7 @@ VOID ReadConfig(CHAR16 *FileName) CHAR16 *FlagName; CHAR16 *TempStr = NULL; UINTN TokenCount, i; + EFI_GUID RefindGuid = REFIND_GUID_VALUE; // Set a few defaults only if we're loading the default file. if (StriCmp(FileName, GlobalConfig.ConfigFilename) == 0) { @@ -454,6 +456,18 @@ VOID ReadConfig(CHAR16 *FileName) MyFreePool(GlobalConfig.DontScanVolumes); GlobalConfig.DontScanVolumes = StrDuplicate(DONT_SCAN_VOLUMES); GlobalConfig.WindowsRecoveryFiles = StrDuplicate(WINDOWS_RECOVERY_FILES); + if (GlobalConfig.DefaultSelection != NULL) { + MyFreePool(GlobalConfig.DefaultSelection); + GlobalConfig.DefaultSelection = NULL; + } +// GlobalConfig.DefaultSelection = AllocatePool(255 * sizeof(CHAR16)); +// Print(L"About to call EfivarGetRaw()\n"); + Status = EfivarGetRaw(&RefindGuid, L"PreviousBoot", (CHAR8**) &(GlobalConfig.DefaultSelection), &i); +// i = 255 * sizeof(CHAR16); +// Print(L"About to call RT->GetVariable()\n"); +// Status = refit_call5_wrapper(RT->GetVariable, L"PreviousBoot", &RefindGuid, &Attributes, &i, GlobalConfig.DefaultSelection); + if (Status != EFI_SUCCESS) + GlobalConfig.DefaultSelection = NULL; } // if if (!FileExists(SelfDir, FileName)) { diff --git a/refind/global.h b/refind/global.h index e7aee62..3b22f1d 100644 --- a/refind/global.h +++ b/refind/global.h @@ -148,7 +148,8 @@ // Files that may be Windows recovery files #define WINDOWS_RECOVERY_FILES L"EFI\\Microsoft\\Boot\\LrsBootmgr.efi" -#define NULL_GUID_VALUE { 00000000, 0000, 0000, {0000, 0000, 0000, 0000} }; +#define NULL_GUID_VALUE { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} }; +#define REFIND_GUID_VALUE { 0x36D08FA7, 0xCF0B, 0x42F5, {0x8F, 0x14, 0x68, 0xDF, 0x73, 0xED, 0x37, 0x40} }; // // global definitions diff --git a/refind/lib.c b/refind/lib.c index 12b5ce3..0570265 100644 --- a/refind/lib.c +++ b/refind/lib.c @@ -265,6 +265,43 @@ static EFI_STATUS FinishInitRefitLib(VOID) return EFI_SUCCESS; } +// +// EFI variable read and write functions +// + +// From gummiboot: Retrieve a raw EFI variable. +// Returns EFI status +EFI_STATUS EfivarGetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size) { + CHAR8 *buf; + UINTN l; + EFI_STATUS err; + + l = sizeof(CHAR16 *) * EFI_MAXIMUM_VARIABLE_SIZE; + buf = AllocatePool(l); + if (!buf) + return EFI_OUT_OF_RESOURCES; + + err = refit_call5_wrapper(RT->GetVariable, name, vendor, NULL, &l, buf); + if (EFI_ERROR(err) == EFI_SUCCESS) { + *buffer = buf; + if (size) + *size = l; + } else + MyFreePool(buf); + return err; +} // EFI_STATUS EfivarGetRaw() + +// From gummiboot: Set an EFI variable +EFI_STATUS EfivarSetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent) { + UINT32 flags; + + flags = EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS; + if (persistent) + flags |= EFI_VARIABLE_NON_VOLATILE; + + return refit_call5_wrapper(RT->SetVariable, name, vendor, flags, size, buf); +} // EFI_STATUS EfivarSetRaw() + // // list functions // diff --git a/refind/lib.h b/refind/lib.h index 15754cd..e6a8c30 100644 --- a/refind/lib.h +++ b/refind/lib.h @@ -85,6 +85,9 @@ EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle); VOID UninitRefitLib(VOID); EFI_STATUS ReinitRefitLib(VOID); +EFI_STATUS EfivarGetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size); +EFI_STATUS EfivarSetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent); + VOID CleanUpPathNameSlashes(IN OUT CHAR16 *PathName); VOID CreateList(OUT VOID ***ListPtr, OUT UINTN *ElementCount, IN UINTN InitialElementCount); VOID AddListElement(IN OUT VOID ***ListPtr, IN OUT UINTN *ElementCount, IN VOID *NewElement); diff --git a/refind/main.c b/refind/main.c index da6026d..f709e59 100644 --- a/refind/main.c +++ b/refind/main.c @@ -147,6 +147,7 @@ REFIT_CONFIG GlobalConfig = { FALSE, FALSE, FALSE, 0, 0, 0, DONT_CHANGE_TEXT_MOD }; EFI_GUID GlobalGuid = EFI_GLOBAL_VARIABLE; +EFI_GUID RefindGuid = REFIND_GUID_VALUE; GPT_DATA *gPartitions = NULL; @@ -168,7 +169,7 @@ static VOID AboutrEFInd(VOID) if (AboutMenu.EntryCount == 0) { AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT); - AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.8.1.2"); + AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.8.1.3"); AddMenuInfoLine(&AboutMenu, L""); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer"); AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2014 Roderick W. Smith"); @@ -385,39 +386,6 @@ static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath, return StartEFIImageList(DevicePaths, LoadOptions, LoaderType, ImageTitle, OSType, ErrorInStep, Verbose); } /* static EFI_STATUS StartEFIImage() */ -// From gummiboot: Retrieve a raw EFI variable. -// Returns EFI status -static EFI_STATUS EfivarGetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 **buffer, UINTN *size) { - CHAR8 *buf; - UINTN l; - EFI_STATUS err; - - l = sizeof(CHAR16 *) * EFI_MAXIMUM_VARIABLE_SIZE; - buf = AllocatePool(l); - if (!buf) - return EFI_OUT_OF_RESOURCES; - - err = refit_call5_wrapper(RT->GetVariable, name, vendor, NULL, &l, buf); - if (EFI_ERROR(err) == EFI_SUCCESS) { - *buffer = buf; - if (size) - *size = l; - } else - MyFreePool(buf); - return err; -} // EFI_STATUS EfivarGetRaw() - -// From gummiboot: Set an EFI variable -static EFI_STATUS EfivarSetRaw(EFI_GUID *vendor, CHAR16 *name, CHAR8 *buf, UINTN size, BOOLEAN persistent) { - UINT32 flags; - - flags = EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS; - if (persistent) - flags |= EFI_VARIABLE_NON_VOLATILE; - - return refit_call5_wrapper(RT->SetVariable, name, vendor, flags, size, buf); -} // EFI_STATUS EfivarSetRaw() - // From gummiboot: Reboot the computer into its built-in user interface static EFI_STATUS RebootIntoFirmware(VOID) { CHAR8 *b; @@ -442,6 +410,20 @@ static EFI_STATUS RebootIntoFirmware(VOID) { return err; } +// Record the value of the loader's name/description in rEFInd's "PreviousBoot" EFI variable. +static VOID StoreLoaderName(IN CHAR16 *Name) { + EFI_STATUS Status; + CHAR16 *OldName = NULL; + UINTN Length; + + if (Name) { + Status = EfivarGetRaw(&RefindGuid, L"PreviousBoot", (CHAR8**) &OldName, &Length); + if ((Status != EFI_SUCCESS) || (StrCmp(OldName, Name) != 0)) { + EfivarSetRaw(&RefindGuid, L"PreviousBoot", (CHAR8*) Name, StrLen(Name) * 2 + 2, TRUE); + } // if + MyFreePool(OldName); + } // if +} // VOID StorePreviousLoader() // // EFI OS loader functions @@ -452,6 +434,7 @@ static VOID StartLoader(LOADER_ENTRY *Entry) UINTN ErrorInStep = 0; BeginExternalScreen(Entry->UseGraphicsMode, L"Booting OS"); + StoreLoaderName(Entry->me.Title); StartEFIImage(Entry->DevicePath, Entry->LoadOptions, TYPE_EFI, Basename(Entry->LoaderPath), Entry->OSType, &ErrorInStep, !Entry->UseGraphicsMode); FinishExternalScreen(); @@ -1016,6 +999,8 @@ LOADER_ENTRY * AddLoaderEntry(IN CHAR16 *LoaderPath, IN CHAR16 *LoaderTitle, IN if (Entry != NULL) { Entry->Title = StrDuplicate((LoaderTitle != NULL) ? LoaderTitle : LoaderPath); Entry->me.Title = AllocateZeroPool(sizeof(CHAR16) * 256); + // Extra space at end of Entry->me.Title enables searching on Volume->VolName even if another volume + // name is identical except for something added to the end (e.g., VolB1 vs. VolB12). SPrint(Entry->me.Title, 255, L"Boot %s from %s ", (LoaderTitle != NULL) ? LoaderTitle : LoaderPath, Volume->VolName); Entry->me.Row = 0; Entry->me.BadgeImage = Volume->VolBadgeImage; @@ -1642,6 +1627,7 @@ static VOID StartLegacy(IN LEGACY_ENTRY *Entry) ExtractLegacyLoaderPaths(DiscoveredPathList, MAX_DISCOVERED_PATHS, LegacyLoaderList); + StoreLoaderName(Entry->me.Title); Status = StartEFIImageList(DiscoveredPathList, Entry->LoadOptions, TYPE_LEGACY, L"legacy loader", 0, &ErrorInStep, TRUE); if (Status == EFI_NOT_FOUND) { if (ErrorInStep == 1) { @@ -1658,6 +1644,7 @@ static VOID StartLegacy(IN LEGACY_ENTRY *Entry) static VOID StartLegacyUEFI(LEGACY_ENTRY *Entry) { BeginExternalScreen(TRUE, L"Booting Legacy OS (UEFI mode)"); + StoreLoaderName(Entry->me.Title); BdsLibConnectDevicePath (Entry->BdsOption->DevicePath); BdsLibDoLegacyBoot(Entry->BdsOption); @@ -1984,6 +1971,7 @@ static VOID ScanLegacyExternal(VOID) static VOID StartTool(IN LOADER_ENTRY *Entry) { BeginExternalScreen(Entry->UseGraphicsMode, Entry->me.Title + 6); // assumes "Start " as assigned below + StoreLoaderName(Entry->me.Title); StartEFIImage(Entry->DevicePath, Entry->LoadOptions, TYPE_EFI, Basename(Entry->LoaderPath), Entry->OSType, NULL, TRUE); FinishExternalScreen();