* Modifications copyright (c) 2012-2015 Roderick W. Smith
*
* Modifications distributed under the terms of the GNU General Public
- * License (GPL) version 3 (GPLv3), a copy of which must be distributed
- * with this source code or binaries made from it.
+ * License (GPL) version 3 (GPLv3), or (at your option) any later version.
*
*/
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
#include "global.h"
#include "config.h"
L"Insert or F2 for more options; Esc to refresh" };
static REFIT_MENU_SCREEN AboutMenu = { L"About", NULL, 0, NULL, 0, NULL, 0, NULL, L"Press Enter to return to main menu", L"" };
-REFIT_CONFIG GlobalConfig = { FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0, 0, DONT_CHANGE_TEXT_MODE, 20, 0, 0, GRAPHICS_FOR_OSX, LEGACY_TYPE_MAC,
- 0, 0, { DEFAULT_BIG_ICON_SIZE / 4, DEFAULT_SMALL_ICON_SIZE, DEFAULT_BIG_ICON_SIZE }, BANNER_NOSCALE,
- NULL, NULL, NULL, CONFIG_FILE_NAME, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- { TAG_SHELL, TAG_MEMTEST, TAG_GDISK, TAG_APPLE_RECOVERY, TAG_WINDOWS_RECOVERY, TAG_MOK_TOOL,
- TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, TAG_FIRMWARE, 0, 0, 0, 0, 0, 0, 0, 0 }
+REFIT_CONFIG GlobalConfig = { FALSE, TRUE, FALSE, FALSE, TRUE, 0, 0, 0, DONT_CHANGE_TEXT_MODE,
+ 20, 0, 0, GRAPHICS_FOR_OSX, LEGACY_TYPE_MAC,
+ 0, 0, { DEFAULT_BIG_ICON_SIZE / 4, DEFAULT_SMALL_ICON_SIZE, DEFAULT_BIG_ICON_SIZE },
+ BANNER_NOSCALE, NULL, NULL, NULL, NULL, CONFIG_FILE_NAME, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ { TAG_SHELL, TAG_MEMTEST, TAG_GDISK, TAG_APPLE_RECOVERY, TAG_WINDOWS_RECOVERY,
+ TAG_MOK_TOOL, TAG_ABOUT, TAG_SHUTDOWN, TAG_REBOOT, TAG_FIRMWARE,
+ 0, 0, 0, 0, 0, 0, 0, 0 }
};
EFI_GUID GlobalGuid = EFI_GLOBAL_VARIABLE;
if (AboutMenu.EntryCount == 0) {
AboutMenu.TitleImage = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
- AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.9.0.4");
+ AddMenuInfoLine(&AboutMenu, L"rEFInd Version 0.9.2.3");
AddMenuInfoLine(&AboutMenu, L"");
AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2006-2010 Christoph Pfisterer");
AddMenuInfoLine(&AboutMenu, L"Copyright (c) 2012-2015 Roderick W. Smith");
IN BOOLEAN IsDriver)
{
EFI_STATUS Status, ReturnStatus;
- EFI_HANDLE ChildImageHandle;
+ EFI_HANDLE ChildImageHandle, ChildImageHandle2;
EFI_LOADED_IMAGE *ChildLoadedImage = NULL;
REFIT_VOLUME *Volume = NULL;
UINTN DevicePathIndex;
if (Verbose)
Print(L"Starting %s\nUsing load options '%s'\n", ImageTitle, FullLoadOptions ? FullLoadOptions : L"");
- // load the image into memory (and execute it, in the case of a shim/MOK image).
+ // load the image into memory
ReturnStatus = Status = EFI_NOT_FOUND; // in case the list is empty
for (DevicePathIndex = 0; DevicePaths[DevicePathIndex] != NULL; DevicePathIndex++) {
FindVolumeAndFilename(DevicePaths[DevicePathIndex], &Volume, &Filename);
// ImageData, ImageSize, &ChildImageHandle);
ReturnStatus = Status = refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, DevicePaths[DevicePathIndex],
NULL, 0, &ChildImageHandle);
+ if (secure_mode() && ShimLoaded()) {
+ // Load ourself into memory. This is a trick to work around a bug in Shim 0.8,
+ // which ties itself into the BS->LoadImage() and BS->StartImage() functions and
+ // then unregisters itself from the EFI system table when its replacement
+ // StartImage() function is called *IF* the previous LoadImage() was for the same
+ // program. The result is that rEFInd can validate only the first program it
+ // launches (often a filesystem driver). Loading a second program (rEFInd itself,
+ // here, to keep it smaller than a kernel) works around this problem. See the
+ // replacements.c file in Shim, and especially its start_image() function, for
+ // the source of the problem.
+ // NOTE: This doesn't check the return status or handle errors. It could
+ // conceivably do weird things if, say, rEFInd were on a USB drive that the
+ // user pulls before launching a program.
+ refit_call6_wrapper(BS->LoadImage, FALSE, SelfImageHandle, GlobalConfig.SelfDevicePath,
+ NULL, 0, &ChildImageHandle2);
+ }
} else {
Print(L"Invalid loader file!\n");
ReturnStatus = EFI_LOAD_ERROR;
Success = TRUE;
} else {
Print(L"Failed to install MOK Secure Boot extensions");
+ PauseForKey();
}
}
return Success;
// If an error is encountered, leaves the value alone (it should be set to
// CONFIG_FILE_NAME when GlobalConfig is initialized).
static VOID SetConfigFilename(EFI_HANDLE ImageHandle) {
-EFI_LOADED_IMAGE *Info;
-CHAR16 *Options, *FileName;
-EFI_STATUS Status;
-INTN Where;
+ EFI_LOADED_IMAGE *Info;
+ CHAR16 *Options, *FileName, *SubString;
+ EFI_STATUS Status;
-Status = refit_call3_wrapper(BS->HandleProtocol, ImageHandle, &LoadedImageProtocol, (VOID **) &Info);
+ Status = refit_call3_wrapper(BS->HandleProtocol, ImageHandle, &LoadedImageProtocol, (VOID **) &Info);
if ((Status == EFI_SUCCESS) && (Info->LoadOptionsSize > 0)) {
Options = (CHAR16 *) Info->LoadOptions;
- Where = FindSubString(L" -c ", Options);
- if (Where >= 0) {
- FileName = StrDuplicate(&Options[Where + 4]);
- Where = FindSubString(L" ", FileName);
- if (Where > 0)
- FileName[Where] = L'\0';
+ SubString = MyStrStr(Options, L" -c ");
+ if (SubString) {
+ FileName = StrDuplicate(&SubString[4]);
+ if (FileName) {
+ LimitStringLength(FileName, 256);
+ }
if (FileExists(SelfDir, FileName)) {
GlobalConfig.ConfigFilename = FileName;
} // if
} // VOID SetConfigFilename()
+/*
+ * The below definitions and SetAppleOSInfo() function are based on a GRUB patch
+ * by Andreas Heider:
+ * https://lists.gnu.org/archive/html/grub-devel/2013-12/msg00442.html
+ */
+
+#define EFI_APPLE_SET_OS_PROTOCOL_GUID \
+ { 0xc5c5da95, 0x7d5c, 0x45e6, \
+ { 0xb2, 0xf1, 0x3f, 0xd5, 0x2b, 0xb1, 0x00, 0x77 } \
+ }
+
+typedef struct EfiAppleSetOsInterface {
+ UINT64 Version;
+ EFI_STATUS EFIAPI (*SetOsVersion) (IN CHAR8 *Version);
+ EFI_STATUS EFIAPI (*SetOsVendor) (IN CHAR8 *Vendor);
+} EfiAppleSetOsInterface;
+
+// Function to tell the firmware that OS X is being launched. This is
+// required to work around problems on some Macs that don't fully
+// initialize some hardware (especially video displays) when third-party
+// OSes are launched in EFI mode.
+static EFI_STATUS SetAppleOSInfo() {
+ CHAR16 *AppleOSVersion = NULL;
+ CHAR8 *AppleOSVersion8 = NULL;
+ EFI_STATUS Status;
+ EFI_GUID apple_set_os_guid = EFI_APPLE_SET_OS_PROTOCOL_GUID;
+ EfiAppleSetOsInterface *SetOs = NULL;
+
+ Status = refit_call3_wrapper(BS->LocateProtocol, &apple_set_os_guid, NULL, (VOID**) &SetOs);
+
+ // Not a Mac, so ignore the call....
+ if ((Status != EFI_SUCCESS) || (!SetOs))
+ return EFI_SUCCESS;
+
+ if ((SetOs->Version != 0) && GlobalConfig.SpoofOSXVersion) {
+ AppleOSVersion = StrDuplicate(L"Mac OS X");
+ MergeStrings(&AppleOSVersion, GlobalConfig.SpoofOSXVersion, ' ');
+ if (AppleOSVersion) {
+ AppleOSVersion8 = AllocateZeroPool((StrLen(AppleOSVersion) + 1) * sizeof(CHAR8));
+ UnicodeStrToAsciiStr(AppleOSVersion, AppleOSVersion8);
+ if (AppleOSVersion8) {
+ Status = refit_call1_wrapper (SetOs->SetOsVersion, AppleOSVersion8);
+ if (!EFI_ERROR(Status))
+ Status = EFI_SUCCESS;
+ MyFreePool(AppleOSVersion8);
+ } else {
+ Status = EFI_OUT_OF_RESOURCES;
+ Print(L"Out of resources in SetAppleOSInfo!\n");
+ }
+ if ((Status == EFI_SUCCESS) && (SetOs->Version == 2))
+ Status = refit_call1_wrapper (SetOs->SetOsVendor, "Apple Inc.");
+ MyFreePool(AppleOSVersion);
+ } // if (AppleOSVersion)
+ } // if
+ if (Status != EFI_SUCCESS)
+ Print(L"Unable to set firmware boot type!\n");
+
+ return (Status);
+} // EFI_STATUS SetAppleOSInfo()
+
//
// main entry point
//
SetConfigFilename(ImageHandle);
ReadConfig(GlobalConfig.ConfigFilename);
+ if (GlobalConfig.SpoofOSXVersion && GlobalConfig.SpoofOSXVersion[0] != L'\0')
+ SetAppleOSInfo();
+
InitScreen();
WarnIfLegacyProblems();
MainMenu.TimeoutSeconds = GlobalConfig.Timeout;