mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-27 12:15:19 +01:00
8b5ec83c6a
Signed-off-by: Sergey Isakov <isakov-sl@bk.ru>
3023 lines
110 KiB
C++
3023 lines
110 KiB
C++
/*
|
|
* refit/main.c
|
|
* Main code for the boot menu
|
|
*
|
|
* Copyright (c) 2006-2010 Christoph Pfisterer
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* * Neither the name of Christoph Pfisterer nor the names of the
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "../Platform/Platform.h"
|
|
#include "../cpp_util/globals_ctor.h"
|
|
#include "../cpp_util/globals_dtor.h"
|
|
#include "../cpp_unit_test/all_tests.h"
|
|
|
|
#include "Version.h"
|
|
#include "../entry_scan/entry_scan.h"
|
|
#include "../libeg/nanosvg.h"
|
|
#include "../gui/menu_items/menu_globals.h"
|
|
#include "menu.h"
|
|
#include "../Platform/Settings.h"
|
|
#include "../Platform/DataHubCpu.h"
|
|
#include "../Platform/Events.h"
|
|
#include "screen.h"
|
|
#include "../entry_scan/bootscreen.h"
|
|
#include "../Platform/Nvram.h"
|
|
|
|
#ifndef DEBUG_ALL
|
|
#define DEBUG_MAIN 1
|
|
#else
|
|
#define DEBUG_MAIN DEBUG_ALL
|
|
#endif
|
|
|
|
#if DEBUG_MAIN == 0
|
|
#define DBG(...)
|
|
#else
|
|
#define DBG(...) DebugLog(DEBUG_MAIN, __VA_ARGS__)
|
|
#endif
|
|
|
|
#ifndef HIBERNATE
|
|
#define HIBERNATE 0
|
|
#endif
|
|
|
|
|
|
#ifndef CHECK_SMC
|
|
#define CHECK_SMC 0
|
|
#endif
|
|
|
|
|
|
// variables
|
|
#ifdef FIRMWARE_REVISION
|
|
//CONST CHAR16 gFirmwareRevisionM[] = FIRMWARE_REVISION;
|
|
//CONST CHAR16 *gFirmwareRevision = &gFirmwareRevisionM[0];
|
|
CONST CHAR16 *gFirmwareRevision = FIRMWARE_REVISION;
|
|
|
|
#else
|
|
CONST CHAR16 *gFirmwareRevision = NULL;
|
|
#endif
|
|
|
|
BOOLEAN gGuiIsReady = FALSE;
|
|
BOOLEAN gThemeNeedInit = TRUE;
|
|
BOOLEAN DoHibernateWake = FALSE;
|
|
BOOLEAN APFSSupport = FALSE;
|
|
|
|
DRIVERS_FLAGS gDriversFlags; //the initializer is not needed for global variables
|
|
|
|
EMU_VARIABLE_CONTROL_PROTOCOL *gEmuVariableControl = NULL;
|
|
|
|
EFI_HANDLE ConsoleInHandle;
|
|
EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL* SimpleTextEx;
|
|
EFI_KEY_DATA KeyData;
|
|
|
|
CONST CHAR8* AudioOutputNames[] = {
|
|
"LineOut",
|
|
"Speaker",
|
|
"Headphones",
|
|
"SPDIF",
|
|
"Garniture",
|
|
"HDMI",
|
|
"Other"
|
|
};
|
|
|
|
extern VOID HelpRefit(VOID);
|
|
extern VOID AboutRefit(VOID);
|
|
extern BOOLEAN BooterPatch(IN UINT8 *BooterData, IN UINT64 BooterSize, LOADER_ENTRY *Entry);
|
|
|
|
extern UINTN ThemesNum;
|
|
extern CONST CHAR16 *ThemesList[];
|
|
extern UINTN ConfigsNum;
|
|
extern CHAR16 *ConfigsList[];
|
|
extern UINTN DsdtsNum;
|
|
extern CHAR16 *DsdtsList[];
|
|
extern UINTN AudioNum;
|
|
extern HDA_OUTPUTS AudioList[20];
|
|
extern EFI_AUDIO_IO_PROTOCOL *AudioIo;
|
|
|
|
//#ifdef _cplusplus
|
|
//void FreePool(const wchar_t * A)
|
|
//{
|
|
// FreePool((VOID*)A);
|
|
//}
|
|
//#endif
|
|
|
|
static EFI_STATUS LoadEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
|
|
IN CONST CHAR16 *ImageTitle,
|
|
OUT UINTN *ErrorInStep,
|
|
OUT EFI_HANDLE *NewImageHandle)
|
|
{
|
|
EFI_STATUS Status, ReturnStatus;
|
|
EFI_HANDLE ChildImageHandle = 0;
|
|
UINTN DevicePathIndex;
|
|
CHAR16 ErrorInfo[256];
|
|
|
|
DBG("Loading %ls", ImageTitle);
|
|
if (ErrorInStep != NULL) {
|
|
*ErrorInStep = 0;
|
|
}
|
|
if (NewImageHandle != NULL) {
|
|
*NewImageHandle = NULL;
|
|
}
|
|
|
|
// load the image into memory
|
|
ReturnStatus = Status = EFI_NOT_FOUND; // in case the list is empty
|
|
for (DevicePathIndex = 0; DevicePaths[DevicePathIndex] != NULL; DevicePathIndex++) {
|
|
ReturnStatus = Status = gBS->LoadImage(FALSE, SelfImageHandle, DevicePaths[DevicePathIndex], NULL, 0, &ChildImageHandle);
|
|
DBG(" status=%s", strerror(Status));
|
|
if (ReturnStatus != EFI_NOT_FOUND)
|
|
break;
|
|
}
|
|
UnicodeSPrint(ErrorInfo, 512, L"while loading %s", ImageTitle);
|
|
if (CheckError(Status, ErrorInfo)) {
|
|
if (ErrorInStep != NULL)
|
|
*ErrorInStep = 1;
|
|
PauseForKey(L"press any key");
|
|
goto bailout;
|
|
}
|
|
|
|
if (!EFI_ERROR(ReturnStatus)) { //why unload driver?!
|
|
if (NewImageHandle != NULL) {
|
|
*NewImageHandle = ChildImageHandle;
|
|
}
|
|
#ifdef JIEF_DEBUG
|
|
EFI_LOADED_IMAGE_PROTOCOL* loadedBootImage = NULL;
|
|
if (!EFI_ERROR(Status = gBS->HandleProtocol(ChildImageHandle, &gEfiLoadedImageProtocolGuid, (void**)(&loadedBootImage)))) {
|
|
DBG("%S : Image base = 0x%llx", ImageTitle, (uintptr_t)loadedBootImage->ImageBase); // Jief : Do not change this, it's used by grep to feed the debugger
|
|
}else{
|
|
DBG("Can't get loaded image protocol");
|
|
}
|
|
#endif
|
|
goto bailout;
|
|
}
|
|
|
|
// unload the image, we don't care if it works or not...
|
|
Status = gBS->UnloadImage(ChildImageHandle);
|
|
bailout:
|
|
DBG("\n");
|
|
return ReturnStatus;
|
|
}
|
|
|
|
|
|
static EFI_STATUS StartEFILoadedImage(IN EFI_HANDLE ChildImageHandle,
|
|
IN CONST CHAR16 *LoadOptions, IN CONST CHAR16 *LoadOptionsPrefix,
|
|
IN CONST CHAR16 *ImageTitle,
|
|
OUT UINTN *ErrorInStep)
|
|
{
|
|
EFI_STATUS Status, ReturnStatus;
|
|
EFI_LOADED_IMAGE *ChildLoadedImage;
|
|
CHAR16 ErrorInfo[256];
|
|
CHAR16 *FullLoadOptions = NULL;
|
|
|
|
// DBG("Starting %ls\n", ImageTitle);
|
|
if (ErrorInStep != NULL) {
|
|
*ErrorInStep = 0;
|
|
}
|
|
ReturnStatus = Status = EFI_NOT_FOUND; // in case no image handle was specified
|
|
if (ChildImageHandle == NULL) {
|
|
if (ErrorInStep != NULL) *ErrorInStep = 1;
|
|
goto bailout;
|
|
}
|
|
|
|
// set load options
|
|
if (LoadOptions != NULL) {
|
|
ReturnStatus = Status = gBS->HandleProtocol(ChildImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ChildLoadedImage);
|
|
if (CheckError(Status, L"while getting a LoadedImageProtocol handle")) {
|
|
if (ErrorInStep != NULL)
|
|
*ErrorInStep = 2;
|
|
goto bailout_unload;
|
|
}
|
|
|
|
if (LoadOptionsPrefix != NULL) {
|
|
FullLoadOptions = PoolPrint(L"%s %s ", LoadOptionsPrefix, LoadOptions);
|
|
// NOTE: That last space is also added by the EFI shell and seems to be significant
|
|
// when passing options to Apple's boot.efi...
|
|
LoadOptions = FullLoadOptions;
|
|
}
|
|
// NOTE: We also include the terminating null in the length for safety.
|
|
ChildLoadedImage->LoadOptions = (VOID *)LoadOptions;
|
|
ChildLoadedImage->LoadOptionsSize = (UINT32)StrSize(LoadOptions);
|
|
//((UINT32)StrLen(LoadOptions) + 1) * sizeof(CHAR16);
|
|
// DBG("Using load options '%ls'\n", LoadOptions);
|
|
}
|
|
//DBG("Image loaded at: %p\n", ChildLoadedImage->ImageBase);
|
|
//PauseForKey(L"continue");
|
|
|
|
// close open file handles
|
|
UninitRefitLib();
|
|
|
|
// turn control over to the image
|
|
//
|
|
// Before calling the image, enable the Watchdog Timer for
|
|
// the 5 Minute period - Slice - NO! For slow driver and slow disk we need more
|
|
//
|
|
gBS->SetWatchdogTimer (600, 0x0000, 0x00, NULL);
|
|
|
|
ReturnStatus = Status = gBS->StartImage(ChildImageHandle, NULL, NULL);
|
|
//
|
|
// Clear the Watchdog Timer after the image returns
|
|
//
|
|
gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
|
|
|
|
//PauseForKey(L"Returned from StartImage\n");
|
|
|
|
// control returns here when the child image calls Exit()
|
|
if (ImageTitle) {
|
|
UnicodeSPrint(ErrorInfo, 512, L"returned from %s", ImageTitle);
|
|
}
|
|
|
|
if (CheckError(Status, ErrorInfo)) {
|
|
if (ErrorInStep != NULL)
|
|
*ErrorInStep = 3;
|
|
}
|
|
if (!EFI_ERROR(ReturnStatus)) { //why unload driver?!
|
|
goto bailout;
|
|
}
|
|
|
|
bailout_unload:
|
|
// unload the image, we don't care if it works or not...
|
|
Status = gBS->UnloadImage(ChildImageHandle);
|
|
if (FullLoadOptions != NULL)
|
|
FreePool(FullLoadOptions);
|
|
bailout:
|
|
return ReturnStatus;
|
|
}
|
|
|
|
|
|
static EFI_STATUS LoadEFIImage(IN EFI_DEVICE_PATH *DevicePath,
|
|
IN CONST CHAR16 *ImageTitle,
|
|
OUT UINTN *ErrorInStep,
|
|
OUT EFI_HANDLE *NewImageHandle)
|
|
{
|
|
EFI_DEVICE_PATH *DevicePaths[2];
|
|
|
|
#ifdef ENABLE_SECURE_BOOT
|
|
// Verify secure boot policy
|
|
if (gSettings.SecureBoot && gSettings.SecureBootSetupMode) {
|
|
// Only verify if in forced secure boot mode
|
|
EFI_STATUS Status = VerifySecureBootImage(DevicePath);
|
|
if (EFI_ERROR(Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
#endif // ENABLE_SECURE_BOOT
|
|
|
|
// Load the image now
|
|
DevicePaths[0] = DevicePath;
|
|
DevicePaths[1] = NULL;
|
|
return LoadEFIImageList(DevicePaths, ImageTitle, ErrorInStep, NewImageHandle);
|
|
}
|
|
|
|
|
|
static EFI_STATUS StartEFIImage(IN EFI_DEVICE_PATH *DevicePath,
|
|
IN CONST CHAR16 *LoadOptions, IN CONST CHAR16 *LoadOptionsPrefix,
|
|
IN CONST CHAR16 *ImageTitle,
|
|
OUT UINTN *ErrorInStep,
|
|
OUT EFI_HANDLE *NewImageHandle)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE ChildImageHandle = NULL;
|
|
|
|
Status = LoadEFIImage(DevicePath, ImageTitle, ErrorInStep, &ChildImageHandle);
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = StartEFILoadedImage(ChildImageHandle, LoadOptions, LoadOptionsPrefix, ImageTitle, ErrorInStep);
|
|
}
|
|
|
|
if (NewImageHandle != NULL) {
|
|
*NewImageHandle = ChildImageHandle;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
static EFI_STATUS StartEFIImageList(IN EFI_DEVICE_PATH **DevicePaths,
|
|
IN CHAR16 *LoadOptions, IN CHAR16 *LoadOptionsPrefix,
|
|
IN CHAR16 *ImageTitle,
|
|
OUT UINTN *ErrorInStep,
|
|
OUT EFI_HANDLE *NewImageHandle)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE ChildImageHandle = NULL;
|
|
|
|
Status = LoadEFIImageList(DevicePaths, ImageTitle, ErrorInStep, &ChildImageHandle);
|
|
if (!EFI_ERROR(Status)) {
|
|
Status = StartEFILoadedImage(ChildImageHandle, LoadOptions, LoadOptionsPrefix, ImageTitle, ErrorInStep);
|
|
}
|
|
|
|
if (NewImageHandle != NULL) {
|
|
*NewImageHandle = ChildImageHandle;
|
|
}
|
|
return Status;
|
|
}
|
|
*/
|
|
/*
|
|
static CONST CHAR8 *SearchString(
|
|
IN CONST CHAR8 *Source,
|
|
IN UINT64 SourceSize,
|
|
IN CONST CHAR8 *Search,
|
|
IN UINTN SearchSize
|
|
)
|
|
{
|
|
CONST CHAR8 *End = Source + SourceSize;
|
|
|
|
while (Source < End) {
|
|
if (CompareMem(Source, Search, SearchSize) == 0) {
|
|
return Source;
|
|
} else {
|
|
Source++;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
*/
|
|
#ifdef DUMP_KERNEL_KEXT_PATCHES
|
|
VOID DumpKernelAndKextPatches(KERNEL_AND_KEXT_PATCHES *Patches)
|
|
{
|
|
if (!Patches) {
|
|
DBG("Kernel and Kext Patches null pointer\n");
|
|
return;
|
|
}
|
|
DBG("Kernel and Kext Patches at %p:\n", Patches);
|
|
DBG("\tAllowed: %c\n", gSettings.KextPatchesAllowed ? 'y' : 'n');
|
|
DBG("\tDebug: %c\n", Patches->KPDebug ? 'y' : 'n');
|
|
DBG("\tKernelCpu: %c\n", Patches->KPKernelCpu ? 'y' : 'n');
|
|
DBG("\tKernelLapic: %c\n", Patches->KPKernelLapic ? 'y' : 'n');
|
|
DBG("\tKernelXCPM: %c\n", Patches->KPKernelXCPM ? 'y' : 'n');
|
|
DBG("\tKernelPm: %c\n", Patches->KPKernelPm ? 'y' : 'n');
|
|
DBG("\tAppleIntelCPUPM: %c\n", Patches->KPAppleIntelCPUPM ? 'y' : 'n');
|
|
DBG("\tAppleRTC: %c\n", Patches->KPAppleRTC ? 'y' : 'n');
|
|
// Dell smbios truncate fix
|
|
DBG("\tDellSMBIOSPatch: %c\n", Patches->KPDELLSMBIOS ? 'y' : 'n');
|
|
DBG("\tFakeCPUID: 0x%X\n", Patches->FakeCPUID);
|
|
DBG("\tATIController: %ls\n", (Patches->KPATIConnectorsController == NULL) ? L"null": Patches->KPATIConnectorsController);
|
|
DBG("\tATIDataLength: %d\n", Patches->KPATIConnectorsDataLen);
|
|
DBG("\t%d Kexts to load\n", Patches->NrForceKexts);
|
|
if (Patches->ForceKexts) {
|
|
INTN i = 0;
|
|
for (; i < Patches->NrForceKexts; ++i) {
|
|
DBG("\t KextToLoad[%d]: %ls\n", i, Patches->ForceKexts[i]);
|
|
}
|
|
}
|
|
DBG("\t%d Kexts to patch\n", Patches->NrKexts);
|
|
if (Patches->KextPatches) {
|
|
INTN i = 0;
|
|
for (; i < Patches->NrKexts; ++i) {
|
|
if (Patches->KextPatches[i].IsPlistPatch) {
|
|
DBG("\t KextPatchPlist[%d]: %d bytes, %s\n", i, Patches->KextPatches[i].DataLen, Patches->KextPatches[i].Name);
|
|
} else {
|
|
DBG("\t KextPatch[%d]: %d bytes, %s\n", i, Patches->KextPatches[i].DataLen, Patches->KextPatches[i].Name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
VOID FilterKextPatches(IN LOADER_ENTRY *Entry) //zzzz
|
|
{
|
|
if (gSettings.KextPatchesAllowed && (Entry->KernelAndKextPatches->KextPatches != NULL) && Entry->KernelAndKextPatches->NrKexts) {
|
|
INTN i;
|
|
DBG("Filtering KextPatches:\n");
|
|
for (i = 0; i < Entry->KernelAndKextPatches->NrKexts; i++) {
|
|
DBG(" - [%02lld]: %s :: %s :: [OS: %s | MatchOS: %s | MatchBuild: %s]",
|
|
i,
|
|
Entry->KernelAndKextPatches->KextPatches[i].Label,
|
|
Entry->KernelAndKextPatches->KextPatches[i].IsPlistPatch ? "PlistPatch" : "BinPatch",
|
|
Entry->OSVersion,
|
|
Entry->KernelAndKextPatches->KextPatches[i].MatchOS ? Entry->KernelAndKextPatches->KextPatches[i].MatchOS : "All",
|
|
Entry->KernelAndKextPatches->KextPatches[i].MatchBuild != NULL ? Entry->KernelAndKextPatches->KextPatches[i].MatchBuild : "All"
|
|
);
|
|
if (!Entry->KernelAndKextPatches->KextPatches[i].MenuItem.BValue) {
|
|
DBG(" ==> disabled by user\n");
|
|
continue;
|
|
}
|
|
|
|
if ((Entry->BuildVersion != NULL) && (Entry->KernelAndKextPatches->KextPatches[i].MatchBuild != NULL)) {
|
|
Entry->KernelAndKextPatches->KextPatches[i].MenuItem.BValue = IsPatchEnabled(Entry->KernelAndKextPatches->KextPatches[i].MatchBuild, Entry->BuildVersion);
|
|
DBG(" ==> %s\n", Entry->KernelAndKextPatches->KextPatches[i].MenuItem.BValue ? "allowed" : "not allowed");
|
|
continue;
|
|
}
|
|
|
|
Entry->KernelAndKextPatches->KextPatches[i].MenuItem.BValue = IsPatchEnabled(Entry->KernelAndKextPatches->KextPatches[i].MatchOS, Entry->OSVersion);
|
|
DBG(" ==> %s\n", Entry->KernelAndKextPatches->KextPatches[i].MenuItem.BValue ? "allowed" : "not allowed");
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID FilterKernelPatches(IN LOADER_ENTRY *Entry)
|
|
{
|
|
if (gSettings.KernelPatchesAllowed && (Entry->KernelAndKextPatches->KernelPatches != NULL) && Entry->KernelAndKextPatches->NrKernels) {
|
|
INTN i = 0;
|
|
DBG("Filtering KernelPatches:\n");
|
|
for (; i < Entry->KernelAndKextPatches->NrKernels; ++i) {
|
|
DBG(" - [%02lld]: %s :: [OS: %s | MatchOS: %s | MatchBuild: %s]",
|
|
i,
|
|
Entry->KernelAndKextPatches->KernelPatches[i].Label,
|
|
Entry->OSVersion,
|
|
Entry->KernelAndKextPatches->KernelPatches[i].MatchOS ? Entry->KernelAndKextPatches->KernelPatches[i].MatchOS : "All",
|
|
Entry->KernelAndKextPatches->KernelPatches[i].MatchBuild != NULL ? Entry->KernelAndKextPatches->KernelPatches[i].MatchBuild : "no"
|
|
);
|
|
if (!Entry->KernelAndKextPatches->KernelPatches[i].MenuItem.BValue) {
|
|
DBG(" ==> disabled by user\n");
|
|
continue;
|
|
}
|
|
|
|
if ((Entry->BuildVersion != NULL) && (Entry->KernelAndKextPatches->KernelPatches[i].MatchBuild != NULL)) {
|
|
Entry->KernelAndKextPatches->KernelPatches[i].MenuItem.BValue = IsPatchEnabled(Entry->KernelAndKextPatches->KernelPatches[i].MatchBuild, Entry->BuildVersion);
|
|
DBG(" ==> %s by build\n", Entry->KernelAndKextPatches->KernelPatches[i].MenuItem.BValue ? "allowed" : "not allowed");
|
|
continue;
|
|
}
|
|
|
|
Entry->KernelAndKextPatches->KernelPatches[i].MenuItem.BValue = IsPatchEnabled(Entry->KernelAndKextPatches->KernelPatches[i].MatchOS, Entry->OSVersion);
|
|
DBG(" ==> %s by OS\n", Entry->KernelAndKextPatches->KernelPatches[i].MenuItem.BValue ? "allowed" : "not allowed");
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID FilterBootPatches(IN LOADER_ENTRY *Entry)
|
|
{
|
|
if ((Entry->KernelAndKextPatches->BootPatches != NULL) && Entry->KernelAndKextPatches->NrBoots) {
|
|
INTN i = 0;
|
|
DBG("Filtering BootPatches:\n");
|
|
for (; i < Entry->KernelAndKextPatches->NrBoots; ++i) {
|
|
DBG(" - [%02lld]: %s :: [OS: %s | MatchOS: %s | MatchBuild: %s]",
|
|
i,
|
|
Entry->KernelAndKextPatches->BootPatches[i].Label,
|
|
Entry->OSVersion,
|
|
Entry->KernelAndKextPatches->BootPatches[i].MatchOS ? Entry->KernelAndKextPatches->BootPatches[i].MatchOS : "All",
|
|
Entry->KernelAndKextPatches->BootPatches[i].MatchBuild != NULL ? Entry->KernelAndKextPatches->BootPatches[i].MatchBuild : "no"
|
|
);
|
|
if (!Entry->KernelAndKextPatches->BootPatches[i].MenuItem.BValue) {
|
|
DBG(" ==> disabled by user\n");
|
|
continue;
|
|
}
|
|
|
|
if ((Entry->BuildVersion != NULL) && (Entry->KernelAndKextPatches->BootPatches[i].MatchBuild != NULL)) {
|
|
Entry->KernelAndKextPatches->BootPatches[i].MenuItem.BValue = IsPatchEnabled(Entry->KernelAndKextPatches->BootPatches[i].MatchBuild, Entry->BuildVersion);
|
|
DBG(" ==> %s by build\n", Entry->KernelAndKextPatches->BootPatches[i].MenuItem.BValue ? "allowed" : "not allowed");
|
|
continue;
|
|
}
|
|
|
|
Entry->KernelAndKextPatches->BootPatches[i].MenuItem.BValue = IsPatchEnabled(Entry->KernelAndKextPatches->BootPatches[i].MatchOS, Entry->OSVersion);
|
|
DBG(" ==> %s by OS\n", Entry->KernelAndKextPatches->BootPatches[i].MenuItem.BValue ? "allowed" : "not allowed");
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID ReadSIPCfg()
|
|
{
|
|
UINT32 csrCfg = gSettings.CsrActiveConfig & CSR_VALID_FLAGS;
|
|
CHAR16 *csrLog = (__typeof__(csrLog))AllocateZeroPool(SVALUE_MAX_SIZE);
|
|
|
|
if (csrCfg & CSR_ALLOW_UNTRUSTED_KEXTS)
|
|
StrCatS(csrLog, SVALUE_MAX_SIZE/2, L"CSR_ALLOW_UNTRUSTED_KEXTS");
|
|
if (csrCfg & CSR_ALLOW_UNRESTRICTED_FS)
|
|
StrCatS(csrLog, SVALUE_MAX_SIZE/2, PoolPrint(L"%a%a", StrLen(csrLog) ? " | " : "", "CSR_ALLOW_UNRESTRICTED_FS"));
|
|
if (csrCfg & CSR_ALLOW_TASK_FOR_PID)
|
|
StrCatS(csrLog, SVALUE_MAX_SIZE/2, PoolPrint(L"%a%a", StrLen(csrLog) ? " | " : "", "CSR_ALLOW_TASK_FOR_PID"));
|
|
if (csrCfg & CSR_ALLOW_KERNEL_DEBUGGER)
|
|
StrCatS(csrLog, SVALUE_MAX_SIZE/2, PoolPrint(L"%a%a", StrLen(csrLog) ? " | " : "", "CSR_ALLOW_KERNEL_DEBUGGER"));
|
|
if (csrCfg & CSR_ALLOW_APPLE_INTERNAL)
|
|
StrCatS(csrLog, SVALUE_MAX_SIZE/2, PoolPrint(L"%a%a", StrLen(csrLog) ? " | " : "", "CSR_ALLOW_APPLE_INTERNAL"));
|
|
if (csrCfg & CSR_ALLOW_UNRESTRICTED_DTRACE)
|
|
StrCatS(csrLog, SVALUE_MAX_SIZE/2, PoolPrint(L"%a%a", StrLen(csrLog) ? " | " : "", "CSR_ALLOW_UNRESTRICTED_DTRACE"));
|
|
if (csrCfg & CSR_ALLOW_UNRESTRICTED_NVRAM)
|
|
StrCatS(csrLog, SVALUE_MAX_SIZE/2, PoolPrint(L"%a%a", StrLen(csrLog) ? " | " : "", "CSR_ALLOW_UNRESTRICTED_NVRAM"));
|
|
if (csrCfg & CSR_ALLOW_DEVICE_CONFIGURATION)
|
|
StrCatS(csrLog, SVALUE_MAX_SIZE/2, PoolPrint(L"%a%a", StrLen(csrLog) ? " | " : "", "CSR_ALLOW_DEVICE_CONFIGURATION"));
|
|
if (csrCfg & CSR_ALLOW_ANY_RECOVERY_OS)
|
|
StrCatS(csrLog, SVALUE_MAX_SIZE/2, PoolPrint(L"%a%a", StrLen(csrLog) ? " | " : "", "CSR_ALLOW_ANY_RECOVERY_OS"));
|
|
if (csrCfg & CSR_ALLOW_UNAPPROVED_KEXTS)
|
|
StrCatS(csrLog, SVALUE_MAX_SIZE/2, PoolPrint(L"%a%a", StrLen(csrLog) ? " | " : "", "CSR_ALLOW_UNAPPROVED_KEXTS"));
|
|
|
|
if (StrLen(csrLog)) {
|
|
DBG("CSR_CFG: %ls\n", csrLog);
|
|
}
|
|
|
|
FreePool(csrLog);
|
|
}
|
|
|
|
//
|
|
// Null ConOut OutputString() implementation - for blocking
|
|
// text output from boot.efi when booting in graphics mode
|
|
//
|
|
EFI_STATUS EFIAPI
|
|
NullConOutOutputString(IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, IN CONST CHAR16 *String) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// EFI OS loader functions
|
|
//
|
|
//EG_PIXEL DarkBackgroundPixel = { 0x0, 0x0, 0x0, 0xFF };
|
|
|
|
VOID CheckEmptyFB()
|
|
{
|
|
BOOLEAN EmptyFB = (gSettings.IgPlatform == 0x00050000) ||
|
|
(gSettings.IgPlatform == 0x01620007) ||
|
|
(gSettings.IgPlatform == 0x04120004) ||
|
|
(gSettings.IgPlatform == 0x19120001) ||
|
|
(gSettings.IgPlatform == 0x59120003) ||
|
|
(gSettings.IgPlatform == 0x3E910003);
|
|
if (EmptyFB) {
|
|
gPlatformFeature |= PT_FEATURE_HAS_HEADLESS_GPU;
|
|
} else {
|
|
gPlatformFeature &= ~PT_FEATURE_HAS_HEADLESS_GPU;
|
|
}
|
|
}
|
|
|
|
static VOID StartLoader(IN LOADER_ENTRY *Entry)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_TEXT_STRING ConOutOutputString = 0;
|
|
EFI_HANDLE ImageHandle = NULL;
|
|
EFI_LOADED_IMAGE *LoadedImage = NULL;
|
|
CONST CHAR8 *InstallerVersion;
|
|
TagPtr dict = NULL;
|
|
UINTN i;
|
|
NSVGfont *font; // , *nextFont;
|
|
|
|
// DBG("StartLoader() start\n");
|
|
DbgHeader("StartLoader");
|
|
if (Entry->Settings) {
|
|
DBG("Entry->Settings: %ls\n", Entry->Settings);
|
|
Status = LoadUserSettings(SelfRootDir, Entry->Settings, &dict);
|
|
if (!EFI_ERROR(Status)) {
|
|
DBG(" - found custom settings for this entry: %ls\n", Entry->Settings);
|
|
gBootChanged = TRUE;
|
|
Status = GetUserSettings(SelfRootDir, dict);
|
|
if (EFI_ERROR(Status)) {
|
|
DBG(" - ... but: %s\n", strerror(Status));
|
|
} else {
|
|
if ((gSettings.CpuFreqMHz > 100) && (gSettings.CpuFreqMHz < 20000)) {
|
|
gCPUStructure.MaxSpeed = gSettings.CpuFreqMHz;
|
|
}
|
|
//CopyMem (Entry->KernelAndKextPatches,
|
|
// &gSettings.KernelAndKextPatches,
|
|
// sizeof(KERNEL_AND_KEXT_PATCHES));
|
|
//DBG("Custom KernelAndKextPatches copyed to started entry\n");
|
|
}
|
|
} else {
|
|
DBG(" - [!] LoadUserSettings failed: %s\n", strerror(Status));
|
|
}
|
|
}
|
|
|
|
DBG("Finally: ExternalClock=%lluMHz BusSpeed=%llukHz CPUFreq=%uMHz",
|
|
DivU64x32(gCPUStructure.ExternalClock + kilo - 1, kilo),
|
|
DivU64x32(gCPUStructure.FSBFrequency + kilo - 1, kilo),
|
|
gCPUStructure.MaxSpeed);
|
|
if (gSettings.QPI) {
|
|
DBG(" QPI: hw.busfrequency=%lluHz\n", MultU64x32(gSettings.QPI, Mega));
|
|
} else {
|
|
// to match the value of hw.busfrequency in the terminal
|
|
DBG(" PIS: hw.busfrequency=%lluHz\n", MultU64x32(LShiftU64(DivU64x32(gCPUStructure.ExternalClock + kilo - 1, kilo), 2), Mega));
|
|
}
|
|
|
|
//Free memory
|
|
for (i = 0; i < ThemesNum; i++) {
|
|
if (ThemesList[i]) {
|
|
FreePool(ThemesList[i]);
|
|
ThemesList[i] = NULL;
|
|
}
|
|
}
|
|
for (i = 0; i < ConfigsNum; i++) {
|
|
if (ConfigsList[i]) {
|
|
FreePool(ConfigsList[i]);
|
|
ConfigsList[i] = NULL;
|
|
}
|
|
}
|
|
for (i = 0; i < DsdtsNum; i++) {
|
|
if (DsdtsList[i]) {
|
|
FreePool(DsdtsList[i]);
|
|
DsdtsList[i] = NULL;
|
|
}
|
|
}
|
|
OptionMenu.FreeMenu();
|
|
//there is a place to free memory
|
|
// GuiAnime
|
|
// mainParser
|
|
// BuiltinIcons
|
|
// OSIcons
|
|
NSVGfontChain *fontChain = fontsDB;
|
|
while (fontChain) {
|
|
font = fontChain->font;
|
|
NSVGfontChain *nextChain = fontChain->next;
|
|
if (font) {
|
|
nsvg__deleteFont(font);
|
|
fontChain->font = NULL;
|
|
}
|
|
FreePool(fontChain);
|
|
fontChain = nextChain;
|
|
}
|
|
fontsDB = NULL;
|
|
// nsvg__deleteParser(mainParser); //temporary disabled
|
|
//destruct_globals_objects(NULL); //we can't destruct our globals here. We need, for example, Volumes.
|
|
|
|
//DumpKernelAndKextPatches(Entry->KernelAndKextPatches);
|
|
DBG("start loader\n");
|
|
// Load image into memory (will be started later)
|
|
Status = LoadEFIImage(Entry->DevicePath, Basename(Entry->LoaderPath), NULL, &ImageHandle);
|
|
if (EFI_ERROR(Status)) {
|
|
DBG("Image is not loaded, status=%s\n", strerror(Status));
|
|
return; // no reason to continue if loading image failed
|
|
}
|
|
#if USE_XTHEME
|
|
egClearScreen(&Entry->BootBgColor); //if not set then it is already MenuBackgroundPixel
|
|
#else
|
|
egClearScreen(Entry->BootBgColor ? Entry->BootBgColor : &MenuBackgroundPixel);
|
|
#endif
|
|
|
|
// KillMouse();
|
|
|
|
// if (Entry->LoaderType == OSTYPE_OSX) {
|
|
if (OSTYPE_IS_OSX(Entry->LoaderType) ||
|
|
OSTYPE_IS_OSX_RECOVERY(Entry->LoaderType) ||
|
|
OSTYPE_IS_OSX_INSTALLER(Entry->LoaderType)) {
|
|
|
|
// To display progress bar properly (especially in FV2 mode) boot.efi needs to be in graphics mode.
|
|
// Unfortunately many UEFI implementations change the resolution when SetMode happens.
|
|
// This is not what boot.efi expects, and it freely calls SetMode at its will.
|
|
// As a result we see progress bar at improper resolution and the background is also missing (10.12.x+).
|
|
//
|
|
// libeg already has a workaround for SetMode behaviour, so we extend it for boot.efi support.
|
|
// The approach tries to be follows:
|
|
// 1. Ensure we have graphics mode set (since it is a must in the future).
|
|
// 2. Request text mode for boot.efi, which it expects by default (here a SetMode libeg hack will trigger
|
|
// on problematic UEFI implementations like AMI).
|
|
egSetGraphicsModeEnabled(TRUE);
|
|
egSetGraphicsModeEnabled(FALSE);
|
|
|
|
DBG("GetOSVersion:");
|
|
|
|
//needed for boot.efi patcher
|
|
Status = gBS->HandleProtocol(ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage);
|
|
// Correct OSVersion if it was not found
|
|
// This should happen only for 10.7-10.9 OSTYPE_OSX_INSTALLER
|
|
// For these cases, take OSVersion from loaded boot.efi image in memory
|
|
if (/*Entry->LoaderType == OSTYPE_OSX_INSTALLER ||*/ !Entry->OSVersion) {
|
|
|
|
if (!EFI_ERROR(Status)) {
|
|
// version in boot.efi appears as "Mac OS X 10.?"
|
|
/*
|
|
Start OSName Mac OS X 10.12 End OSName Start OSVendor Apple Inc. End
|
|
*/
|
|
// InstallerVersion = SearchString((CHAR8*)LoadedImage->ImageBase, LoadedImage->ImageSize, "Mac OS X ", 9);
|
|
InstallerVersion = AsciiStrStr((CHAR8*)LoadedImage->ImageBase, "Mac OS X ");
|
|
if (InstallerVersion != NULL) { // string was found
|
|
InstallerVersion += 9; // advance to version location
|
|
|
|
if (AsciiStrnCmp(InstallerVersion, "10.7", 4) &&
|
|
AsciiStrnCmp(InstallerVersion, "10.8", 4) &&
|
|
AsciiStrnCmp(InstallerVersion, "10.9", 4) &&
|
|
AsciiStrnCmp(InstallerVersion, "10.10", 5) &&
|
|
AsciiStrnCmp(InstallerVersion, "10.11", 5) &&
|
|
AsciiStrnCmp(InstallerVersion, "10.12", 5) &&
|
|
AsciiStrnCmp(InstallerVersion, "10.13", 5) &&
|
|
AsciiStrnCmp(InstallerVersion, "10.14", 5) &&
|
|
AsciiStrnCmp(InstallerVersion, "10.15", 5)) {
|
|
InstallerVersion = NULL; // flag known version was not found
|
|
}
|
|
if (InstallerVersion != NULL) { // known version was found in image
|
|
if (Entry->OSVersion != NULL) {
|
|
FreePool(Entry->OSVersion);
|
|
}
|
|
Entry->OSVersion = (__typeof__(Entry->OSVersion))AllocateCopyPool(AsciiStrLen(InstallerVersion)+1, InstallerVersion);
|
|
Entry->OSVersion[AsciiStrLen(InstallerVersion)] = '\0';
|
|
// DBG("Corrected OSVersion: %s\n", Entry->OSVersion);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Entry->BuildVersion != NULL) {
|
|
FreePool(Entry->BuildVersion);
|
|
Entry->BuildVersion = NULL;
|
|
}
|
|
}
|
|
|
|
if (Entry->BuildVersion != NULL) {
|
|
DBG(" %s (%s)\n", Entry->OSVersion, Entry->BuildVersion);
|
|
} else {
|
|
DBG(" %s\n", Entry->OSVersion);
|
|
}
|
|
|
|
if (Entry->OSVersion && (AsciiOSVersionToUint64(Entry->OSVersion) >= AsciiOSVersionToUint64("10.11"))) {
|
|
if (OSFLAG_ISSET(Entry->Flags, OSFLAG_NOSIP)) {
|
|
gSettings.CsrActiveConfig = (UINT32)0x37F;
|
|
gSettings.BooterConfig = 0x28;
|
|
}
|
|
ReadSIPCfg();
|
|
}
|
|
|
|
FilterKextPatches(Entry);
|
|
FilterKernelPatches(Entry);
|
|
FilterBootPatches(Entry);
|
|
if (LoadedImage && !BooterPatch((UINT8*)LoadedImage->ImageBase, LoadedImage->ImageSize, Entry)) {
|
|
DBG("Will not patch boot.efi\n");
|
|
}
|
|
|
|
// Set boot argument for kernel if no caches, this should force kernel loading
|
|
if (OSFLAG_ISSET(Entry->Flags, OSFLAG_NOCACHES) &&
|
|
(StriStr(Entry->LoadOptions, L"Kernel=") == NULL)) {
|
|
CONST CHAR16 *KernelLocation = NULL;
|
|
CHAR16 *TempOptions;
|
|
|
|
if (Entry->OSVersion && AsciiOSVersionToUint64(Entry->OSVersion) <= AsciiOSVersionToUint64("10.9")) {
|
|
KernelLocation =L"\"Kernel=/mach_kernel\"";
|
|
} else {
|
|
// used for 10.10, 10.11, and new version.
|
|
KernelLocation =L"\"Kernel=/System/Library/Kernels/kernel\"";
|
|
}
|
|
|
|
TempOptions = AddLoadOption(Entry->LoadOptions, KernelLocation);
|
|
FreePool(Entry->LoadOptions);
|
|
Entry->LoadOptions = TempOptions;
|
|
}
|
|
|
|
//we are booting OSX - restore emulation if it's not installed before g boot.efi
|
|
if (gEmuVariableControl != NULL) {
|
|
gEmuVariableControl->InstallEmulation(gEmuVariableControl);
|
|
}
|
|
|
|
// first patchACPI and find PCIROOT and RTC
|
|
// but before ACPI patch we need smbios patch
|
|
CheckEmptyFB();
|
|
PatchSmbios();
|
|
// DBG("PatchACPI\n");
|
|
PatchACPI(Entry->Volume, Entry->OSVersion);
|
|
|
|
// If KPDebug is true boot in verbose mode to see the debug messages
|
|
if ((Entry->KernelAndKextPatches != NULL) && Entry->KernelAndKextPatches->KPDebug) {
|
|
CHAR16 *TempOptions = AddLoadOption(Entry->LoadOptions, L"-v");
|
|
FreePool(Entry->LoadOptions);
|
|
Entry->LoadOptions = TempOptions;
|
|
}
|
|
|
|
DbgHeader("RestSetup macOS");
|
|
|
|
// DBG("SetDevices\n");
|
|
SetDevices(Entry);
|
|
// DBG("SetFSInjection\n");
|
|
SetFSInjection(Entry);
|
|
//PauseForKey(L"SetFSInjection");
|
|
// DBG("SetVariablesForOSX\n");
|
|
SetVariablesForOSX(Entry);
|
|
// DBG("SetVariablesForOSX\n");
|
|
EventsInitialize(Entry);
|
|
// DBG("FinalizeSmbios\n");
|
|
FinalizeSmbios();
|
|
|
|
SetCPUProperties();
|
|
|
|
if (OSFLAG_ISSET(Entry->Flags, OSFLAG_HIBERNATED)) {
|
|
DoHibernateWake = PrepareHibernation(Entry->Volume);
|
|
}
|
|
SetupDataForOSX(DoHibernateWake);
|
|
|
|
|
|
if (gDriversFlags.AptioFixLoaded &&
|
|
!DoHibernateWake &&
|
|
!StrStr(Entry->LoadOptions, L"slide=")) {
|
|
// Add slide=0 argument for ML+ if not present
|
|
CHAR16 *TempOptions = AddLoadOption(Entry->LoadOptions, L"slide=0");
|
|
FreePool(Entry->LoadOptions);
|
|
Entry->LoadOptions = TempOptions;
|
|
}
|
|
|
|
|
|
/**
|
|
* syscl - append "-xcpm" argument conditionally if set KernelXCPM on Intel Haswell+ low-end CPUs
|
|
*/
|
|
if ((Entry->KernelAndKextPatches != NULL) && Entry->KernelAndKextPatches->KPKernelXCPM &&
|
|
gCPUStructure.Vendor == CPU_VENDOR_INTEL && gCPUStructure.Model >= CPU_MODEL_HASWELL &&
|
|
(AsciiStrStr(gCPUStructure.BrandString, "Celeron") || AsciiStrStr(gCPUStructure.BrandString, "Pentium")) &&
|
|
(AsciiOSVersionToUint64(Entry->OSVersion) >= AsciiOSVersionToUint64("10.8.5")) &&
|
|
(AsciiOSVersionToUint64(Entry->OSVersion) < AsciiOSVersionToUint64("10.12")) &&
|
|
(!StrStr(Entry->LoadOptions, L"-xcpm"))) {
|
|
// add "-xcpm" argv if not present on Haswell+ Celeron/Pentium
|
|
CHAR16 *tmpArgv = AddLoadOption(Entry->LoadOptions, L"-xcpm");
|
|
FreePool(Entry->LoadOptions);
|
|
Entry->LoadOptions = tmpArgv;
|
|
}
|
|
|
|
// add -xcpm on Ivy Bridge if set KernelXCPM and system version is 10.8.5 - 10.11.x
|
|
if ((Entry->KernelAndKextPatches != NULL) && Entry->KernelAndKextPatches->KPKernelXCPM &&
|
|
gCPUStructure.Model == CPU_MODEL_IVY_BRIDGE &&
|
|
(AsciiOSVersionToUint64(Entry->OSVersion) >= AsciiOSVersionToUint64("10.8.5")) &&
|
|
(AsciiOSVersionToUint64(Entry->OSVersion) < AsciiOSVersionToUint64("10.12")) &&
|
|
(!StrStr(Entry->LoadOptions, L"-xcpm"))) {
|
|
// add "-xcpm" argv if not present on Ivy Bridge
|
|
CHAR16 *tmpArgv = AddLoadOption(Entry->LoadOptions, L"-xcpm");
|
|
FreePool(Entry->LoadOptions);
|
|
Entry->LoadOptions = tmpArgv;
|
|
}
|
|
|
|
if (AudioIo) {
|
|
AudioIo->StopPlayback(AudioIo);
|
|
}
|
|
|
|
// DBG("Set FakeCPUID: 0x%X\n", gSettings.FakeCPUID);
|
|
// DBG("LoadKexts\n");
|
|
// LoadKexts writes to DataHub, where large writes can prevent hibernate wake (happens when several kexts present in Clover's kexts dir)
|
|
if (!DoHibernateWake) {
|
|
LoadKexts(Entry);
|
|
}
|
|
|
|
// blocking boot.efi output if -v is not specified
|
|
// note: this blocks output even if -v is specified in
|
|
// /Library/Preferences/SystemConfiguration/com.apple.Boot.plist
|
|
// which is wrong
|
|
// apianti - only block console output if using graphics
|
|
// but don't block custom boot logo
|
|
if ((Entry->LoadOptions != NULL) &&
|
|
((StrStr(Entry->LoadOptions, L"-v") != NULL) ||
|
|
(StrStr(Entry->LoadOptions, L"-V") != NULL))) {
|
|
Entry->Flags = OSFLAG_UNSET(Entry->Flags, OSFLAG_USEGRAPHICS);
|
|
} else if (!Entry->LoadOptions) {
|
|
CHAR16 *TempOptions = AddLoadOption(Entry->LoadOptions, L" ");
|
|
FreePool(Entry->LoadOptions);
|
|
Entry->LoadOptions = TempOptions;
|
|
}
|
|
}
|
|
else if (OSTYPE_IS_WINDOWS(Entry->LoaderType)) {
|
|
|
|
if (AudioIo) {
|
|
AudioIo->StopPlayback(AudioIo);
|
|
}
|
|
|
|
DBG("Closing events for Windows\n");
|
|
gBS->CloseEvent (OnReadyToBootEvent);
|
|
gBS->CloseEvent (ExitBootServiceEvent);
|
|
gBS->CloseEvent (mSimpleFileSystemChangeEvent);
|
|
|
|
|
|
if (gEmuVariableControl != NULL) {
|
|
gEmuVariableControl->UninstallEmulation(gEmuVariableControl);
|
|
}
|
|
|
|
PatchACPI_OtherOS(L"Windows", FALSE);
|
|
//PauseForKey(L"continue");
|
|
|
|
}
|
|
else if (OSTYPE_IS_LINUX(Entry->LoaderType) || (Entry->LoaderType == OSTYPE_LINEFI)) {
|
|
|
|
DBG("Closing events for Linux\n");
|
|
gBS->CloseEvent (OnReadyToBootEvent);
|
|
gBS->CloseEvent (ExitBootServiceEvent);
|
|
gBS->CloseEvent (mSimpleFileSystemChangeEvent);
|
|
|
|
if (gEmuVariableControl != NULL) {
|
|
gEmuVariableControl->UninstallEmulation(gEmuVariableControl);
|
|
}
|
|
//FinalizeSmbios();
|
|
PatchACPI_OtherOS(L"Linux", FALSE);
|
|
//PauseForKey(L"continue");
|
|
}
|
|
|
|
if (gSettings.LastBootedVolume) {
|
|
SetStartupDiskVolume(Entry->Volume, Entry->LoaderType == OSTYPE_OSX ? NULL : Entry->LoaderPath);
|
|
} else if (gSettings.DefaultVolume != NULL) {
|
|
// DefaultVolume specified in Config.plist or in Boot Option
|
|
// we'll remove macOS Startup Disk vars which may be present if it is used
|
|
// to reboot into another volume
|
|
RemoveStartupDiskVolume();
|
|
}
|
|
/*
|
|
{
|
|
// UINT32 machineSignature = 0;
|
|
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtPointer = NULL;
|
|
EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs = NULL;
|
|
|
|
// DBG("---dump hibernations data---\n");
|
|
FadtPointer = GetFadt();
|
|
if (FadtPointer != NULL) {
|
|
Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE*)(UINTN)(FadtPointer->FirmwareCtrl);
|
|
|
|
DBG(" Firmware wake address=%08lx\n", Facs->FirmwareWakingVector);
|
|
DBG(" Firmware wake 64 addr=%16llx\n", Facs->XFirmwareWakingVector);
|
|
DBG(" Hardware signature =%08lx\n", Facs->HardwareSignature);
|
|
DBG(" GlobalLock =%08lx\n", Facs->GlobalLock);
|
|
DBG(" Flags =%08lx\n", Facs->Flags);
|
|
DBG(" HS at offset 0x%08X\n", OFFSET_OF(EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE, HardwareSignature));
|
|
// machineSignature = Facs->HardwareSignature;
|
|
}
|
|
}
|
|
*/
|
|
|
|
// DBG("BeginExternalScreen\n");
|
|
BeginExternalScreen(OSFLAG_ISSET(Entry->Flags, OSFLAG_USEGRAPHICS)/*, L"Booting OS"*/);
|
|
|
|
if (!OSTYPE_IS_WINDOWS(Entry->LoaderType)) {
|
|
if (OSFLAG_ISSET(Entry->Flags, OSFLAG_USEGRAPHICS)) {
|
|
// save orig OutputString and replace it with
|
|
// null implementation
|
|
ConOutOutputString = gST->ConOut->OutputString;
|
|
gST->ConOut->OutputString = NullConOutOutputString;
|
|
}
|
|
|
|
// Initialize the boot screen
|
|
if (EFI_ERROR(Status = InitBootScreen(Entry))) {
|
|
if (Status != EFI_ABORTED) DBG("Failed to initialize custom boot screen: %s!\n", strerror(Status));
|
|
}
|
|
else if (EFI_ERROR(Status = LockBootScreen())) {
|
|
DBG("Failed to lock custom boot screen: %s!\n", strerror(Status));
|
|
}
|
|
} // !OSTYPE_IS_WINDOWS
|
|
|
|
if (OSTYPE_IS_OSX(Entry->LoaderType) ||
|
|
OSTYPE_IS_OSX_RECOVERY(Entry->LoaderType) ||
|
|
OSTYPE_IS_OSX_INSTALLER(Entry->LoaderType)) {
|
|
|
|
if (DoHibernateWake) {
|
|
DBG("Closing events for wake\n");
|
|
gBS->CloseEvent (OnReadyToBootEvent);
|
|
gBS->CloseEvent (ExitBootServiceEvent);
|
|
gBS->CloseEvent (mSimpleFileSystemChangeEvent);
|
|
// gBS->CloseEvent (mVirtualAddressChangeEvent);
|
|
// When doing hibernate wake, save to DataHub only up to initial size of log
|
|
SavePreBootLog = FALSE;
|
|
} else {
|
|
// delete boot-switch-vars if exists
|
|
Status = gRT->SetVariable(L"boot-switch-vars", &gEfiAppleBootGuid,
|
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
|
|
0, NULL);
|
|
DeleteNvramVariable(L"IOHibernateRTCVariables", &gEfiAppleBootGuid);
|
|
DeleteNvramVariable(L"boot-image", &gEfiAppleBootGuid);
|
|
|
|
}
|
|
SetupBooterLog(!DoHibernateWake);
|
|
}
|
|
|
|
|
|
|
|
DBG("Closing log\n");
|
|
if (SavePreBootLog) {
|
|
Status = SaveBooterLog(SelfRootDir, PREBOOT_LOG);
|
|
if (EFI_ERROR(Status)) {
|
|
/*Status = */SaveBooterLog(NULL, PREBOOT_LOG);
|
|
}
|
|
}
|
|
|
|
// DBG("StartEFIImage\n");
|
|
// StartEFIImage(Entry->DevicePath, Entry->LoadOptions,
|
|
// Basename(Entry->LoaderPath), Basename(Entry->LoaderPath), NULL, NULL);
|
|
|
|
// DBG("StartEFILoadedImage\n");
|
|
StartEFILoadedImage(ImageHandle, Entry->LoadOptions,
|
|
Basename(Entry->LoaderPath), Basename(Entry->LoaderPath), NULL);
|
|
// Unlock boot screen
|
|
if (EFI_ERROR(Status = UnlockBootScreen())) {
|
|
DBG("Failed to unlock custom boot screen: %s!\n", strerror(Status));
|
|
}
|
|
if (OSFLAG_ISSET(Entry->Flags, OSFLAG_USEGRAPHICS)) {
|
|
// return back orig OutputString
|
|
gST->ConOut->OutputString = ConOutOutputString;
|
|
}
|
|
|
|
// PauseForKey(L"FinishExternalScreen");
|
|
FinishExternalScreen();
|
|
// PauseForKey(L"System started?!");
|
|
}
|
|
|
|
#define MAX_DISCOVERED_PATHS (16)
|
|
//#define PREBOOT_LOG L"EFI\\CLOVER\\misc\\preboot.log"
|
|
|
|
static VOID StartLegacy(IN LEGACY_ENTRY *Entry)
|
|
{
|
|
EFI_STATUS Status = EFI_UNSUPPORTED;
|
|
|
|
// Unload EmuVariable before booting legacy.
|
|
// This is not needed in most cases, but it seems to interfere with legacy OS
|
|
// booted on some UEFI bioses, such as Phoenix UEFI 2.0
|
|
if (gEmuVariableControl != NULL) {
|
|
gEmuVariableControl->UninstallEmulation(gEmuVariableControl);
|
|
}
|
|
|
|
if (gSettings.LastBootedVolume) {
|
|
SetStartupDiskVolume(Entry->Volume, NULL);
|
|
} else if (gSettings.DefaultVolume != NULL) {
|
|
// DefaultVolume specified in Config.plist:
|
|
// we'll remove macOS Startup Disk vars which may be present if it is used
|
|
// to reboot into another volume
|
|
RemoveStartupDiskVolume();
|
|
}
|
|
|
|
|
|
#if USE_XTHEME
|
|
egClearScreen(&MenuBackgroundPixel);
|
|
BeginExternalScreen(TRUE/*, L"Booting Legacy OS"*/);
|
|
XImage BootLogoX;
|
|
BootLogoX.LoadXImage(ThemeX.ThemeDir, Entry->Volume->LegacyOS->IconName);
|
|
BootLogoX.Draw((UGAWidth - BootLogoX.GetWidth()) >> 1,
|
|
(UGAHeight - BootLogoX.GetHeight()) >> 1);
|
|
#else
|
|
egClearScreen(&MenuBackgroundPixel);
|
|
BeginExternalScreen(TRUE/*, L"Booting Legacy OS"*/);
|
|
EG_IMAGE *BootLogoImage = LoadOSIcon(Entry->Volume->LegacyOS->IconName, L"legacy", 128, TRUE, TRUE);
|
|
if (BootLogoImage != NULL) {
|
|
BltImageAlpha(BootLogoImage,
|
|
(UGAWidth - BootLogoImage->Width) >> 1,
|
|
(UGAHeight - BootLogoImage->Height) >> 1,
|
|
&StdBackgroundPixel, 16);
|
|
}
|
|
#endif
|
|
|
|
//try my LegacyBoot
|
|
switch (Entry->Volume->BootType) {
|
|
case BOOTING_BY_CD:
|
|
Status = bootElTorito(Entry->Volume);
|
|
break;
|
|
case BOOTING_BY_MBR:
|
|
Status = bootMBR(Entry->Volume);
|
|
break;
|
|
case BOOTING_BY_PBR:
|
|
if (StrCmp(gSettings.LegacyBoot, L"LegacyBiosDefault") == 0) {
|
|
Status = bootLegacyBiosDefault(gSettings.LegacyBiosDefaultEntry);
|
|
} else if (StrCmp(gSettings.LegacyBoot, L"PBRtest") == 0) {
|
|
Status = bootPBRtest(Entry->Volume);
|
|
} else if (StrCmp(gSettings.LegacyBoot, L"PBRsata") == 0) {
|
|
Status = bootPBR(Entry->Volume, TRUE);
|
|
} else {
|
|
// default
|
|
Status = bootPBR(Entry->Volume, FALSE);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
CheckError(Status, L"while LegacyBoot");
|
|
|
|
FinishExternalScreen();
|
|
}
|
|
|
|
//
|
|
// pre-boot tool functions
|
|
//
|
|
|
|
static VOID StartTool(IN REFIT_MENU_ENTRY_LOADER_TOOL *Entry)
|
|
{
|
|
DBG("Start Tool: %ls\n", Entry->LoaderPath);
|
|
egClearScreen(&MenuBackgroundPixel);
|
|
// assumes "Start <title>" as assigned below
|
|
BeginExternalScreen(OSFLAG_ISSET(Entry->Flags, OSFLAG_USEGRAPHICS)/*, &Entry->Title[6]*/); // Shouldn't we check that length of Title is at least 6 ?
|
|
StartEFIImage(Entry->DevicePath, Entry->LoadOptions, Basename(Entry->LoaderPath), Basename(Entry->LoaderPath), NULL, NULL);
|
|
FinishExternalScreen();
|
|
//ReinitSelfLib();
|
|
}
|
|
|
|
//
|
|
// pre-boot driver functions
|
|
//
|
|
|
|
static VOID ScanDriverDir(IN CONST CHAR16 *Path, OUT EFI_HANDLE **DriversToConnect, OUT UINTN *DriversToConnectNum)
|
|
{
|
|
EFI_STATUS Status;
|
|
REFIT_DIR_ITER DirIter;
|
|
EFI_FILE_INFO *DirEntry;
|
|
CHAR16 FileName[256];
|
|
EFI_HANDLE DriverHandle;
|
|
EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
|
|
UINTN DriversArrSize;
|
|
UINTN DriversArrNum;
|
|
EFI_HANDLE *DriversArr;
|
|
INTN i;
|
|
BOOLEAN Skip;
|
|
UINT8 AptioBlessed;
|
|
STATIC CHAR16 CONST * CONST AptioNames[] = {
|
|
L"AptioMemoryFix",
|
|
L"AptioFix3Drv",
|
|
L"AptioFix2Drv",
|
|
L"AptioFixDrv",
|
|
L"LowMemFix"
|
|
};
|
|
STATIC UINT8 CONST AptioIndices[] = {
|
|
OFFSET_OF(DRIVERS_FLAGS, AptioMemFixLoaded),
|
|
OFFSET_OF(DRIVERS_FLAGS, AptioFix3Loaded),
|
|
OFFSET_OF(DRIVERS_FLAGS, AptioFix2Loaded),
|
|
OFFSET_OF(DRIVERS_FLAGS, AptioFixLoaded),
|
|
OFFSET_OF(DRIVERS_FLAGS, MemFixLoaded)
|
|
};
|
|
|
|
DriversArrSize = 0;
|
|
DriversArrNum = 0;
|
|
DriversArr = NULL;
|
|
|
|
//only one driver with highest priority will obtain status "Loaded"
|
|
DirIterOpen(SelfRootDir, Path, &DirIter);
|
|
#define BOOLEAN_AT_INDEX(k) (*(BOOLEAN*)((UINTN)&gDriversFlags + AptioIndices[(k)]))
|
|
for (i = 0; i != ARRAY_SIZE(AptioIndices); ++i)
|
|
BOOLEAN_AT_INDEX(i) = FALSE;
|
|
AptioBlessed = (UINT8) ARRAY_SIZE(AptioNames);
|
|
while (DirIterNext(&DirIter, 2, L"*.efi", &DirEntry)) {
|
|
for (i = 0; i != ARRAY_SIZE(AptioNames); ++i)
|
|
if (StrStr(DirEntry->FileName, AptioNames[i]) != NULL)
|
|
break;
|
|
if (((UINT8) i) >= AptioBlessed)
|
|
continue;
|
|
AptioBlessed = (UINT8) i;
|
|
if (!i)
|
|
break;
|
|
}
|
|
DirIterClose(&DirIter);
|
|
|
|
// look through contents of the directory
|
|
DirIterOpen(SelfRootDir, Path, &DirIter);
|
|
while (DirIterNext(&DirIter, 2, L"*.efi", &DirEntry)) {
|
|
Skip = (DirEntry->FileName[0] == L'.');
|
|
for (i=0; i<gSettings.BlackListCount; i++) {
|
|
if (StrStr(DirEntry->FileName, gSettings.BlackList[i]) != NULL) {
|
|
Skip = TRUE; // skip this
|
|
break;
|
|
}
|
|
}
|
|
if (Skip) {
|
|
continue;
|
|
}
|
|
|
|
// either AptioMem, AptioFix* or LowMemFix exclusively
|
|
for (i = 0; i != ARRAY_SIZE(AptioNames); ++i)
|
|
if (StrStr(DirEntry->FileName, AptioNames[i]) != NULL)
|
|
break;
|
|
if (i != ARRAY_SIZE(AptioNames)) {
|
|
if (((UINT8) i) != AptioBlessed)
|
|
continue;
|
|
if (AptioBlessed < (UINT8) ARRAY_SIZE(AptioIndices))
|
|
BOOLEAN_AT_INDEX(AptioBlessed) = TRUE;
|
|
AptioBlessed = (UINT8) ARRAY_SIZE(AptioNames);
|
|
}
|
|
#undef BOOLEAN_AT_INDEX
|
|
|
|
UnicodeSPrint(FileName, 512, L"%s\\%s", Path, DirEntry->FileName);
|
|
Status = StartEFIImage(FileDevicePath(SelfLoadedImage->DeviceHandle, FileName),
|
|
L"", DirEntry->FileName, DirEntry->FileName, NULL, &DriverHandle);
|
|
if (EFI_ERROR(Status)) {
|
|
continue;
|
|
}
|
|
if (StrStr(FileName, L"EmuVariable") != NULL) {
|
|
gDriversFlags.EmuVariableLoaded = TRUE;
|
|
} else if (StrStr(FileName, L"Video") != NULL) {
|
|
gDriversFlags.VideoLoaded = TRUE;
|
|
} else if (StrStr(FileName, L"Partition") != NULL) {
|
|
gDriversFlags.PartitionLoaded = TRUE;
|
|
} else if (StrStr(FileName, L"HFS") != NULL) {
|
|
gDriversFlags.HFSLoaded = TRUE;
|
|
} else if (StriStr(FileName, L"apfs") != NULL) {
|
|
gDriversFlags.APFSLoaded = TRUE;
|
|
}
|
|
if (DriverHandle != NULL && DriversToConnectNum != NULL && DriversToConnect != NULL) {
|
|
// driver loaded - check for EFI_DRIVER_BINDING_PROTOCOL
|
|
Status = gBS->HandleProtocol(DriverHandle, &gEfiDriverBindingProtocolGuid, (VOID **) &DriverBinding);
|
|
if (!EFI_ERROR(Status) && DriverBinding != NULL) {
|
|
DBG(" - driver needs connecting\n");
|
|
// standard UEFI driver - we would reconnect after loading - add to array
|
|
if (DriversArrSize == 0) {
|
|
// new array
|
|
DriversArrSize = 16;
|
|
DriversArr = (__typeof__(DriversArr))AllocateZeroPool(sizeof(EFI_HANDLE) * DriversArrSize);
|
|
} else if (DriversArrNum + 1 == DriversArrSize) {
|
|
// extend array
|
|
DriversArr = (__typeof__(DriversArr))ReallocatePool(DriversArrSize, DriversArrSize + 16, DriversArr);
|
|
DriversArrSize += 16;
|
|
}
|
|
DriversArr[DriversArrNum] = DriverHandle;
|
|
// DBG(" driver %ls included with Binding=%X\n", FileName, DriverBinding);
|
|
DriversArrNum++;
|
|
// we'll make array terminated
|
|
DriversArr[DriversArrNum] = NULL;
|
|
}
|
|
}
|
|
}
|
|
Status = DirIterClose(&DirIter);
|
|
if (Status != EFI_NOT_FOUND) {
|
|
UnicodeSPrint(FileName, 512, L"while scanning the %s directory", Path);
|
|
CheckError(Status, FileName);
|
|
}
|
|
|
|
if (DriversToConnectNum != NULL && DriversToConnect != NULL) {
|
|
*DriversToConnectNum = DriversArrNum;
|
|
*DriversToConnect = DriversArr;
|
|
}
|
|
//release memory for BlackList
|
|
for (i=0; i<gSettings.BlackListCount; i++) {
|
|
if (gSettings.BlackList[i]) {
|
|
FreePool(gSettings.BlackList[i]);
|
|
gSettings.BlackList[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Some UEFI's (like HPQ EFI from HP notebooks) have DiskIo protocols
|
|
* opened BY_DRIVER (by Partition driver in HP case) even when no file system
|
|
* is produced from this DiskIo. This then blocks our FS drivers from connecting
|
|
* and producing file systems.
|
|
* To fix it: we will disconnect drivers that connected to DiskIo BY_DRIVER
|
|
* if this is partition volume and if those drivers did not produce file system.
|
|
*/
|
|
VOID DisconnectInvalidDiskIoChildDrivers(VOID)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN HandleCount = 0;
|
|
UINTN Index;
|
|
UINTN OpenInfoIndex;
|
|
EFI_HANDLE *Handles = NULL;
|
|
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
|
|
EFI_BLOCK_IO_PROTOCOL *BlockIo;
|
|
EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo;
|
|
UINTN OpenInfoCount;
|
|
BOOLEAN Found;
|
|
|
|
DBG("Searching for invalid DiskIo BY_DRIVER connects:");
|
|
|
|
//
|
|
// Get all DiskIo handles
|
|
//
|
|
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiDiskIoProtocolGuid, NULL, &HandleCount, &Handles);
|
|
if (EFI_ERROR(Status) || HandleCount == 0) {
|
|
DBG(" no DiskIo handles\n");
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Check every DiskIo handle
|
|
//
|
|
Found = FALSE;
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
//DBG("\n");
|
|
//DBG(" - Handle %p:", Handles[Index]);
|
|
//
|
|
// If this is not partition - skip it.
|
|
// This is then whole disk and DiskIo
|
|
// should be opened here BY_DRIVER by Partition driver
|
|
// to produce partition volumes.
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
Handles[Index],
|
|
&gEfiBlockIoProtocolGuid,
|
|
(VOID **) &BlockIo
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
//DBG(" BlockIo: %s - skipping\n", strerror(Status));
|
|
continue;
|
|
}
|
|
if (BlockIo->Media == NULL) {
|
|
//DBG(" BlockIo: no media - skipping\n");
|
|
continue;
|
|
|
|
}
|
|
if (!BlockIo->Media->LogicalPartition) {
|
|
//DBG(" BlockIo: whole disk - skipping\n");
|
|
continue;
|
|
|
|
}
|
|
//DBG(" BlockIo: partition");
|
|
|
|
//
|
|
// If SimpleFileSystem is already produced - skip it, this is ok
|
|
//
|
|
Status = gBS->HandleProtocol (
|
|
Handles[Index],
|
|
&gEfiSimpleFileSystemProtocolGuid,
|
|
(VOID **) &Fs
|
|
);
|
|
if (Status == EFI_SUCCESS) {
|
|
//DBG(" FS: ok - skipping\n");
|
|
continue;
|
|
}
|
|
//DBG(" FS: no");
|
|
|
|
//
|
|
// If no SimpleFileSystem on this handle but DiskIo is opened BY_DRIVER
|
|
// then disconnect this connection
|
|
//
|
|
Status = gBS->OpenProtocolInformation (
|
|
Handles[Index],
|
|
&gEfiDiskIoProtocolGuid,
|
|
&OpenInfo,
|
|
&OpenInfoCount
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
//DBG(" OpenInfo: no - skipping\n");
|
|
continue;
|
|
}
|
|
//DBG(" OpenInfo: %d", OpenInfoCount);
|
|
for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {
|
|
if ((OpenInfo[OpenInfoIndex].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) == EFI_OPEN_PROTOCOL_BY_DRIVER) {
|
|
if (!Found) {
|
|
DBG("\n");
|
|
}
|
|
Found = TRUE;
|
|
Status = gBS->DisconnectController (Handles[Index], OpenInfo[OpenInfoIndex].AgentHandle, NULL);
|
|
//DBG(" BY_DRIVER Agent: %p, Disconnect: %s", OpenInfo[OpenInfoIndex].AgentHandle, strerror(Status));
|
|
DBG(" - Handle %p with DiskIo, is Partition, no Fs, BY_DRIVER Agent: %p, Disconnect: %s\n", Handles[Index], OpenInfo[OpenInfoIndex].AgentHandle, strerror(Status));
|
|
}
|
|
}
|
|
FreePool (OpenInfo);
|
|
}
|
|
FreePool(Handles);
|
|
|
|
if (!Found) {
|
|
DBG(" not found, all ok\n");
|
|
}
|
|
}
|
|
|
|
VOID DisconnectSomeDevices(VOID)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN HandleCount;
|
|
UINTN Index, Index2;
|
|
EFI_HANDLE *Handles ;
|
|
EFI_HANDLE *ControllerHandles;
|
|
UINTN ControllerHandleCount;
|
|
EFI_BLOCK_IO_PROTOCOL *BlockIo = NULL;
|
|
// EFI_DISK_IO_PROTOCOL *DiskIo = NULL;
|
|
EFI_PCI_IO_PROTOCOL *PciIo = NULL;
|
|
// EFI_FILE_PROTOCOL *RootFP = NULL;
|
|
// EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *VolumeFS = NULL;
|
|
PCI_TYPE00 Pci;
|
|
CHAR16 *DriverName;
|
|
EFI_COMPONENT_NAME_PROTOCOL *CompName;
|
|
|
|
if (gDriversFlags.PartitionLoaded) {
|
|
DBG("Partition driver loaded: ");
|
|
// get all BlockIo handles
|
|
HandleCount = 0;
|
|
Handles = NULL;
|
|
|
|
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &HandleCount, &Handles);
|
|
if (Status == EFI_SUCCESS) {
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
Status = gBS->HandleProtocol(Handles[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
|
|
if (EFI_ERROR(Status)) {
|
|
continue;
|
|
}
|
|
if (BlockIo->Media->BlockSize == 2048) {
|
|
// disconnect CD controller
|
|
Status = gBS->DisconnectController(Handles[Index], NULL, NULL);
|
|
DBG("CD disconnect %s", strerror(Status));
|
|
}
|
|
}
|
|
/* for (Index = 0; Index < HandleCount; Index++) {
|
|
Status = gBS->DisconnectController(Handles[Index], NULL, NULL);
|
|
} */
|
|
FreePool(Handles);
|
|
}
|
|
DBG("\n");
|
|
}
|
|
|
|
if ((gDriversFlags.HFSLoaded) || (gDriversFlags.APFSLoaded)) {
|
|
if (gDriversFlags.HFSLoaded) {
|
|
DBG("HFS+ driver loaded\n");
|
|
}
|
|
if (gDriversFlags.APFSLoaded) {
|
|
DBG("APFS driver loaded\n");
|
|
}
|
|
|
|
// get all FileSystem handles
|
|
ControllerHandleCount = 0;
|
|
ControllerHandles = NULL;
|
|
|
|
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &ControllerHandleCount, &ControllerHandles);
|
|
/* if (!EFI_ERROR (Status)) {
|
|
for (Index2 = 0; Index2 < ControllerHandleCount; Index2++) {
|
|
Status = gBS->DisconnectController(ControllerHandles[Index2],
|
|
NULL, NULL);
|
|
DBG("Driver [%d] disconnect %s\n", Index2, strerror(Status));
|
|
}
|
|
} */
|
|
|
|
HandleCount = 0;
|
|
Handles = NULL;
|
|
|
|
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiComponentNameProtocolGuid, NULL, &HandleCount, &Handles);
|
|
if (!EFI_ERROR (Status)) {
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
Status = gBS->OpenProtocol(
|
|
Handles[Index],
|
|
&gEfiComponentNameProtocolGuid,
|
|
(VOID**)&CompName,
|
|
gImageHandle,
|
|
NULL,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
|
|
|
if (EFI_ERROR(Status)) {
|
|
// DBG("CompName %s\n", strerror(Status));
|
|
continue;
|
|
}
|
|
Status = CompName->GetDriverName(CompName, "eng", &DriverName);
|
|
if (EFI_ERROR(Status)) {
|
|
continue;
|
|
}
|
|
if ((StriStr(DriverName, L"HFS")) || (StriStr(DriverName, L"apfs"))) {
|
|
for (Index2 = 0; Index2 < ControllerHandleCount; Index2++) {
|
|
Status = gBS->DisconnectController(ControllerHandles[Index2],
|
|
Handles[Index], NULL);
|
|
// DBG("Disconnect [%ls] from %X: %s\n", DriverName, ControllerHandles[Index2], strerror(Status));
|
|
}
|
|
}
|
|
}
|
|
FreePool(Handles);
|
|
}
|
|
// DBG("\n");
|
|
FreePool(ControllerHandles);
|
|
}
|
|
|
|
|
|
if (gDriversFlags.VideoLoaded) {
|
|
DBG("Video driver loaded: ");
|
|
// get all PciIo handles
|
|
HandleCount = 0;
|
|
Handles = NULL;
|
|
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiPciIoProtocolGuid, NULL, &HandleCount, &Handles);
|
|
if (Status == EFI_SUCCESS) {
|
|
for (Index = 0; Index < HandleCount; Index++) {
|
|
Status = gBS->HandleProtocol(Handles[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
|
|
if (EFI_ERROR(Status)) {
|
|
continue;
|
|
}
|
|
Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci);
|
|
if (!EFI_ERROR (Status)) {
|
|
if(IS_PCI_VGA(&Pci) == TRUE) {
|
|
// disconnect VGA
|
|
Status = gBS->DisconnectController(Handles[Index], NULL, NULL);
|
|
DBG("disconnect %s", strerror(Status));
|
|
}
|
|
}
|
|
}
|
|
FreePool(Handles);
|
|
}
|
|
DBG("\n");
|
|
}
|
|
|
|
if (!gFirmwareClover) {
|
|
DisconnectInvalidDiskIoChildDrivers();
|
|
}
|
|
}
|
|
|
|
|
|
VOID PatchVideoBios(UINT8 *Edid)
|
|
{
|
|
|
|
if (gSettings.PatchVBiosBytesCount > 0 && gSettings.PatchVBiosBytes != NULL) {
|
|
VideoBiosPatchBytes(gSettings.PatchVBiosBytes, gSettings.PatchVBiosBytesCount);
|
|
}
|
|
|
|
if (gSettings.PatchVBios) {
|
|
VideoBiosPatchNativeFromEdid(Edid);
|
|
}
|
|
}
|
|
|
|
|
|
static VOID LoadDrivers(VOID)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_HANDLE *DriversToConnect = NULL;
|
|
UINTN DriversToConnectNum = 0;
|
|
UINT8 *Edid;
|
|
UINTN VarSize = 0;
|
|
BOOLEAN VBiosPatchNeeded;
|
|
|
|
DbgHeader("LoadDrivers");
|
|
|
|
// load drivers from /efi/drivers
|
|
#if defined(MDE_CPU_X64)
|
|
if (gFirmwareClover) {
|
|
if (FileExists(SelfRootDir, L"\\EFI\\CLOVER\\drivers\\BIOS")) {
|
|
ScanDriverDir(L"\\EFI\\CLOVER\\drivers\\BIOS", &DriversToConnect, &DriversToConnectNum);
|
|
} else {
|
|
ScanDriverDir(L"\\EFI\\CLOVER\\drivers64", &DriversToConnect, &DriversToConnectNum);
|
|
}
|
|
} else
|
|
if (FileExists(SelfRootDir, L"\\EFI\\CLOVER\\drivers\\UEFI")) {
|
|
ScanDriverDir(L"\\EFI\\CLOVER\\drivers\\UEFI", &DriversToConnect, &DriversToConnectNum);
|
|
} else {
|
|
ScanDriverDir(L"\\EFI\\CLOVER\\drivers64UEFI", &DriversToConnect, &DriversToConnectNum);
|
|
}
|
|
#else
|
|
ScanDriverDir(L"\\EFI\\CLOVER\\drivers32", &DriversToConnect, &DriversToConnectNum);
|
|
#endif
|
|
|
|
VBiosPatchNeeded = gSettings.PatchVBios || (gSettings.PatchVBiosBytesCount > 0 && gSettings.PatchVBiosBytes != NULL);
|
|
if (VBiosPatchNeeded) {
|
|
// check if it is already done in CloverEFI BiosVideo
|
|
Status = gRT->GetVariable (
|
|
L"CloverVBiosPatchDone",
|
|
&gEfiGlobalVariableGuid,
|
|
NULL,
|
|
&VarSize,
|
|
NULL
|
|
);
|
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
|
// var exists - it's done - let's not do it again
|
|
VBiosPatchNeeded = FALSE;
|
|
}
|
|
}
|
|
|
|
if (((gSettings.CustomEDID != NULL) && gFirmwareClover) || (VBiosPatchNeeded && !gDriversFlags.VideoLoaded)) {
|
|
// we have video bios patch - force video driver reconnect
|
|
DBG("Video bios patch requested or CustomEDID - forcing video reconnect\n");
|
|
gDriversFlags.VideoLoaded = TRUE;
|
|
DriversToConnectNum++;
|
|
}
|
|
|
|
if (DriversToConnectNum > 0) {
|
|
DBG("%llu drivers needs connecting ...\n", DriversToConnectNum);
|
|
// note: our platform driver protocol
|
|
// will use DriversToConnect - do not release it
|
|
RegisterDriversToHighestPriority(DriversToConnect);
|
|
if (VBiosPatchNeeded) {
|
|
if (gSettings.CustomEDID != NULL) {
|
|
Edid = gSettings.CustomEDID;
|
|
} else {
|
|
Edid = getCurrentEdid();
|
|
}
|
|
DisconnectSomeDevices();
|
|
PatchVideoBios(Edid);
|
|
if (gSettings.CustomEDID == NULL) {
|
|
FreePool(Edid);
|
|
}
|
|
} else {
|
|
DisconnectSomeDevices();
|
|
}
|
|
BdsLibConnectAllDriversToAllControllers();
|
|
|
|
// Boot speedup: remove temporary "BiosVideoBlockSwitchMode" RT var
|
|
// to unlock mode switching in CsmVideo
|
|
gRT->SetVariable(L"BiosVideoBlockSwitchMode", &gEfiGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS, 0, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
INTN FindDefaultEntry(VOID)
|
|
{
|
|
INTN Index = -1;
|
|
REFIT_VOLUME *Volume;
|
|
BOOLEAN SearchForLoader;
|
|
|
|
// DBG("FindDefaultEntry ...\n");
|
|
//DbgHeader("FindDefaultEntry");
|
|
|
|
//
|
|
// try to detect volume set by Startup Disk or previous Clover selection
|
|
// with broken nvram this requires emulation to be installed.
|
|
// enable emulation to determin efi-boot-device-data
|
|
if (gEmuVariableControl != NULL) {
|
|
gEmuVariableControl->InstallEmulation(gEmuVariableControl);
|
|
}
|
|
|
|
Index = FindStartupDiskVolume(&MainMenu);
|
|
|
|
if (Index >= 0) {
|
|
DBG("Boot redirected to Entry %lld. '%ls'\n", Index, MainMenu.Entries[Index].Title.s());
|
|
// we got boot-device-data, no need to keep emulating anymore
|
|
if (gEmuVariableControl != NULL) {
|
|
gEmuVariableControl->UninstallEmulation(gEmuVariableControl);
|
|
}
|
|
return Index;
|
|
}
|
|
|
|
//
|
|
// if not found, then try DefaultVolume from config.plist
|
|
// if not null or empty, search volume that matches gSettings.DefaultVolume
|
|
//
|
|
if (gSettings.DefaultVolume != NULL) {
|
|
|
|
// if not null or empty, also search for loader that matches gSettings.DefaultLoader
|
|
SearchForLoader = (gSettings.DefaultLoader != NULL && gSettings.DefaultLoader[0] != L'\0');
|
|
/*
|
|
if (SearchForLoader) {
|
|
DBG("Searching for DefaultVolume '%ls', DefaultLoader '%ls' ...\n", gSettings.DefaultVolume, gSettings.DefaultLoader);
|
|
} else {
|
|
DBG("Searching for DefaultVolume '%ls' ...\n", gSettings.DefaultVolume);
|
|
}
|
|
*/
|
|
for (Index = 0; Index < (INTN)MainMenu.Entries.size() && MainMenu.Entries[Index].getLOADER_ENTRY() && MainMenu.Entries[Index].getLOADER_ENTRY()->Row == 0 ; Index++) {
|
|
|
|
LOADER_ENTRY& Entry = *MainMenu.Entries[Index].getLOADER_ENTRY();
|
|
if (!Entry.Volume) {
|
|
continue;
|
|
}
|
|
|
|
Volume = Entry.Volume;
|
|
if ((Volume->VolName == NULL || StrCmp(Volume->VolName, gSettings.DefaultVolume) != 0) &&
|
|
!StrStr(Volume->DevicePathString, gSettings.DefaultVolume)) {
|
|
continue;
|
|
}
|
|
|
|
// we alreday know that Entry.isLoader
|
|
if (SearchForLoader && (/*Entry.Tag != TAG_LOADER ||*/ !StriStr(Entry.LoaderPath, gSettings.DefaultLoader))) {
|
|
continue;
|
|
}
|
|
|
|
DBG(" - found entry %lld. '%ls', Volume '%ls', DevicePath '%ls'\n", Index, Entry.Title.s(), Volume->VolName, Entry.DevicePathString);
|
|
// if first method failed and second succeeded - uninstall emulation
|
|
if (gEmuVariableControl != NULL) {
|
|
gEmuVariableControl->UninstallEmulation(gEmuVariableControl);
|
|
}
|
|
return Index;
|
|
}
|
|
|
|
}
|
|
|
|
DBG("Default boot entry not found\n");
|
|
// if both methods to determine default boot entry have failed - uninstall emulation before GUI
|
|
if (gEmuVariableControl != NULL) {
|
|
gEmuVariableControl->UninstallEmulation(gEmuVariableControl);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
VOID SetVariablesFromNvram()
|
|
{
|
|
CHAR8 *tmpString;
|
|
UINTN Size = 0;
|
|
UINTN index = 0, index2, len, i;
|
|
CHAR8 *arg = NULL;
|
|
|
|
// DbgHeader("SetVariablesFromNvram");
|
|
|
|
tmpString = (__typeof__(tmpString))GetNvramVariable(L"boot-args", &gEfiAppleBootGuid, NULL, &Size);
|
|
if (tmpString && (Size <= 0x1000) && (Size > 0)) {
|
|
DBG("found boot-args in NVRAM:%s, size=%llu\n", tmpString, Size);
|
|
// use and forget old one
|
|
// DeleteNvramVariable(L"boot-args", &gEfiAppleBootGuid);
|
|
Size = AsciiStrLen(tmpString); // some EFI implementations include '\0' in Size, and others don't, so update Size to string length
|
|
arg = (__typeof__(arg))AllocatePool(Size+1);
|
|
|
|
/* if (AsciiStrStr(tmpString, "nvda_drv=1")) { //found substring
|
|
gSettings.NvidiaWeb = TRUE;
|
|
} */
|
|
//first we will find new args that is not present in main args
|
|
index = 0;
|
|
while ((index < Size) && (tmpString[index] != 0x0)) {
|
|
ZeroMem(arg, Size+1);
|
|
index2 = 0;
|
|
if (tmpString[index] != '\"') {
|
|
// DBG("search space index=%d\n", index);
|
|
while ((index < Size) && (tmpString[index] != 0x20) && (tmpString[index] != 0x0)) {
|
|
arg[index2++] = tmpString[index++];
|
|
}
|
|
DBG("...found arg:%s\n", arg);
|
|
} else {
|
|
index++;
|
|
// DBG("search quote index=%d\n", index);
|
|
while ((index < Size) && (tmpString[index] != '\"') && (tmpString[index] != 0x0)) {
|
|
arg[index2++] = tmpString[index++];
|
|
}
|
|
if (tmpString[index] == '\"') {
|
|
index++;
|
|
}
|
|
DBG("...found quoted arg:\n"/*, arg*/);
|
|
}
|
|
while (tmpString[index] == 0x20) {
|
|
index++;
|
|
}
|
|
// For the moment only arg -s must be ignored
|
|
if (AsciiStrCmp(arg, "-s") == 0) {
|
|
DBG("...ignoring arg:%s\n", arg);
|
|
continue;
|
|
}
|
|
if (!AsciiStrStr(gSettings.BootArgs, arg)) {
|
|
//this arg is not present will add
|
|
DBG("...adding arg:%s\n", arg);
|
|
len = iStrLen(gSettings.BootArgs, 256);
|
|
if (len + index2 > 256) {
|
|
DBG("boot-args overflow... bytes=%llu+%llu\n", len, index2);
|
|
break;
|
|
}
|
|
gSettings.BootArgs[len++] = 0x20;
|
|
for (i = 0; i < index2; i++) {
|
|
gSettings.BootArgs[len++] = arg[i];
|
|
}
|
|
gSettings.BootArgs[len++] = 0x20;
|
|
}
|
|
}
|
|
FreePool(arg);
|
|
}
|
|
if (tmpString) {
|
|
FreePool(tmpString);
|
|
}
|
|
|
|
tmpString = (__typeof__(tmpString))GetNvramVariable(L"nvda_drv", &gEfiAppleBootGuid, NULL, NULL);
|
|
if (tmpString && AsciiStrCmp(tmpString, "1") == 0) {
|
|
gSettings.NvidiaWeb = TRUE;
|
|
}
|
|
if (tmpString) {
|
|
FreePool(tmpString);
|
|
}
|
|
|
|
}
|
|
|
|
VOID ResetNvram ()
|
|
{
|
|
if (gFirmwareClover || gDriversFlags.EmuVariableLoaded) {
|
|
if (gEmuVariableControl != NULL) {
|
|
gEmuVariableControl->InstallEmulation(gEmuVariableControl);
|
|
}
|
|
}
|
|
|
|
ResetNativeNvram ();
|
|
|
|
if (gFirmwareClover || gDriversFlags.EmuVariableLoaded) {
|
|
if (gEmuVariableControl != NULL) {
|
|
gEmuVariableControl->UninstallEmulation(gEmuVariableControl);
|
|
}
|
|
}
|
|
|
|
// Attempt warm reboot
|
|
// gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
|
|
// Warm reboot may not be supported attempt cold reboot
|
|
// gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
|
|
// Terminate the screen and just exit
|
|
// TerminateScreen();
|
|
}
|
|
|
|
extern UINTN nLanCards; // number of LAN cards
|
|
extern UINT16 gLanVendor[4]; // their vendors
|
|
extern UINT8 *gLanMmio[4]; // their MMIO regions
|
|
extern UINT8 gLanMac[4][6]; // their MAC addresses
|
|
extern UINTN nLanPaths; // number of LAN pathes
|
|
|
|
BOOLEAN SetOEMPathIfExists(IN EFI_FILE *Root, IN CHAR16 *path, CONST CHAR16 *ConfName)
|
|
{
|
|
BOOLEAN res = FileExists(Root, path);
|
|
if ( res ) {
|
|
CHAR16 ConfigPath[1024];
|
|
UnicodeSPrint(ConfigPath, sizeof(ConfigPath), L"%s\\%s.plist", path, ConfName);
|
|
BOOLEAN res2 = FileExists(Root, ConfigPath);
|
|
if ( res2 ) {
|
|
OEMPath = path;
|
|
DBG ("CheckOEMPathExists: set OEMPath: %ls\n", OEMPath);
|
|
return 1;
|
|
}else{
|
|
DBG("CheckOEMPathExists tried %ls. '%ls.plist' not exists in dir\n", path, ConfName);
|
|
FreePool(path);
|
|
}
|
|
}else{
|
|
DBG("CheckOEMPathExists tried %ls. Dir not exists\n", path);
|
|
FreePool(path);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
VOID SetOEMPath(CONST CHAR16 *ConfName)
|
|
{
|
|
OEMPath = PoolPrint(L"%s", L"EFI\\CLOVER");
|
|
if (ConfName == NULL) {
|
|
DBG ("set OEMPath (ConfName == NULL): %ls\n", OEMPath);
|
|
} else if ( nLanCards > 0 && SetOEMPathIfExists(SelfRootDir, PoolPrint(L"EFI\\CLOVER\\OEM\\%a--%02x-%02x-%02x-%02x-%02x-%02x", gSettings.OEMProduct, gLanMac[0][0], gLanMac[0][1], gLanMac[0][2], gLanMac[0][3], gLanMac[0][4], gLanMac[0][5]), ConfName)) {
|
|
} else if ( nLanCards > 1 && SetOEMPathIfExists(SelfRootDir, PoolPrint(L"EFI\\CLOVER\\OEM\\%a--%02x-%02x-%02x-%02x-%02x-%02x", gSettings.OEMProduct, gLanMac[1][0], gLanMac[1][1], gLanMac[1][2], gLanMac[1][3], gLanMac[1][4], gLanMac[1][5]), ConfName)) {
|
|
} else if ( nLanCards > 2 && SetOEMPathIfExists(SelfRootDir, PoolPrint(L"EFI\\CLOVER\\OEM\\%a--%02x-%02x-%02x-%02x-%02x-%02x", gSettings.OEMProduct, gLanMac[2][0], gLanMac[2][1], gLanMac[2][2], gLanMac[2][3], gLanMac[2][4], gLanMac[2][5]), ConfName)) {
|
|
} else if ( nLanCards > 3 && SetOEMPathIfExists(SelfRootDir, PoolPrint(L"EFI\\CLOVER\\OEM\\%a--%02x-%02x-%02x-%02x-%02x-%02x", gSettings.OEMProduct, gLanMac[3][0], gLanMac[3][1], gLanMac[3][2], gLanMac[3][3], gLanMac[3][4], gLanMac[3][5]), ConfName)) {
|
|
} else if (!gFirmwareClover && SetOEMPathIfExists(SelfRootDir, PoolPrint(L"EFI\\CLOVER\\OEM\\%a\\UEFI", gSettings.OEMBoard), ConfName)) {
|
|
} else if (SetOEMPathIfExists(SelfRootDir, PoolPrint(L"EFI\\CLOVER\\OEM\\%a", gSettings.OEMProduct), ConfName)) {
|
|
} else if (SetOEMPathIfExists(SelfRootDir, PoolPrint(L"EFI\\CLOVER\\OEM\\%a-%d", gSettings.OEMProduct, (INT32)(DivU64x32(gCPUStructure.CPUFrequency, Mega))), ConfName)) {
|
|
} else if (SetOEMPathIfExists(SelfRootDir, PoolPrint(L"EFI\\CLOVER\\OEM\\%a", gSettings.OEMBoard), ConfName)) {
|
|
} else if (SetOEMPathIfExists(SelfRootDir, PoolPrint(L"EFI\\CLOVER\\OEM\\%a-%d", gSettings.OEMBoard, (INT32)(DivU64x32(gCPUStructure.CPUFrequency, Mega))), ConfName) ) {
|
|
} else {
|
|
DBG ("set OEMPath by default: %ls\n", OEMPath);
|
|
}
|
|
}
|
|
|
|
/* S. Mitrofanov 08.06.2016
|
|
* APFS Container introduced new partitions structure
|
|
* Now we have, for example:
|
|
* /dev/disk0 (internal, physical):
|
|
* #: TYPE NAME SIZE IDENTIFIER
|
|
* 0: GUID_partition_scheme *240.1 GB disk0
|
|
* 1: EFI EFI 209.7 MB disk0s1
|
|
* 2: Apple_APFS Container disk1 239.2 GB disk0s2
|
|
* 3: Apple_KernelCoreDump 655.4 MB disk0s3
|
|
*
|
|
* /dev/disk1 (synthesized):
|
|
* #: TYPE NAME SIZE IDENTIFIER
|
|
* 0: APFS Container Scheme - +239.2 GB disk1
|
|
* Physical Store disk0s2
|
|
* 1: APFS Volume Macintosh SSD 170.8 GB disk1s1
|
|
* 2: APFS Volume Preboot 17.9 MB disk1s2
|
|
* 3: APFS Volume Recovery 521.1 MB disk1s3
|
|
* 4: APFS Volume VM 1.1 GB disk1s4
|
|
*/
|
|
UINTN APFSUUIDBankCounter = 0;
|
|
UINT8 *APFSUUIDBank = NULL;
|
|
//Vednor APFS device path signature
|
|
//BE74FCF7-0B7C-49F3-9147-01F4042E6842
|
|
EFI_GUID APFSSignature = {0xBE74FCF7, 0x0B7C, 0x49F3, { 0x91, 0x47, 0x01, 0xf4, 0x04, 0x2E, 0x68, 0x42 }};
|
|
|
|
//Function for obtaining unique part id from APFS partition
|
|
//IN DevicePath
|
|
//Out: EFI_GUID
|
|
//null if it is not APFS part
|
|
EFI_GUID *APFSPartitionUUIDExtract(
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
)
|
|
{
|
|
while (!IsDevicePathEndType(DevicePath) &&
|
|
!(DevicePathType(DevicePath) == MEDIA_DEVICE_PATH && DevicePathSubType (DevicePath) == MEDIA_VENDOR_DP)) {
|
|
DevicePath = NextDevicePathNode(DevicePath);
|
|
}
|
|
if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH && DevicePathSubType (DevicePath) == MEDIA_VENDOR_DP) {
|
|
//Check that vendor-assigned GUID defines APFS Container Partition
|
|
if (StriCmp(GuidLEToStr((EFI_GUID *)((UINT8 *)DevicePath+0x04)),GuidLEToStr(&APFSSignature)) == 0 ) {
|
|
return (EFI_GUID *)((UINT8 *)DevicePath+0x14);
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
UINT8 *APFSContainer_Support(VOID) {
|
|
/*
|
|
* S. Mtr 2017
|
|
* APFS Container partition support
|
|
* Gather System PartitionUniqueGUID
|
|
* edit: 17.06.2017
|
|
* Fiil UUIDBank only with APFS container UUIDs
|
|
*/
|
|
UINTN VolumeIndex;
|
|
REFIT_VOLUME *Volume;
|
|
EFI_GUID *TmpUUID = NULL;
|
|
|
|
//Fill APFSUUIDBank
|
|
APFSUUIDBank = (__typeof__(APFSUUIDBank))AllocateZeroPool(0x10*Volumes.size());
|
|
for (VolumeIndex = 0; VolumeIndex < Volumes.size(); VolumeIndex++) {
|
|
Volume = &Volumes[VolumeIndex];
|
|
//Check that current volume - apfs partition
|
|
if ((TmpUUID = APFSPartitionUUIDExtract(Volume->DevicePath)) != NULL){
|
|
CopyMem(APFSUUIDBank+APFSUUIDBankCounter*0x10,(UINT8 *)TmpUUID,0x10);
|
|
APFSUUIDBankCounter++;
|
|
}
|
|
}
|
|
return APFSUUIDBank;
|
|
}
|
|
|
|
//System / Install / Recovery version filler
|
|
CONST CHAR16 *SystemVersionPlist = L"\\System\\Library\\CoreServices\\SystemVersion.plist";
|
|
CONST CHAR16 *ServerVersionPlist = L"\\System\\Library\\CoreServices\\ServerVersion.plist";
|
|
CONST CHAR16 *InstallVersionPlist = L"\\macOS Install Data\\Locked Files\\Boot Files\\SystemVersion.plist";
|
|
CONST CHAR16 *RecoveryVersionPlist = L"\\com.apple.recovery.boot\\SystemVersion.plist";
|
|
CONST CHAR16 APFSSysPlistPath[86] = L"\\00000000-0000-0000-0000-000000000000\\System\\Library\\CoreServices\\SystemVersion.plist";
|
|
CONST CHAR16 APFSServerPlistPath[86] = L"\\00000000-0000-0000-0000-000000000000\\System\\Library\\CoreServices\\ServerVersion.plist";
|
|
CONST CHAR16 APFSInstallPlistPath[79] = L"\\00000000-0000-0000-0000-000000000000\\com.apple.installer\\SystemVersion.plist";
|
|
CONST CHAR16 APFSRecPlistPath[58] = L"\\00000000-0000-0000-0000-000000000000\\SystemVersion.plist";
|
|
|
|
|
|
VOID SystemVersionInit(VOID)
|
|
{
|
|
//Plists iterators
|
|
UINTN SysIter = 2;
|
|
UINTN InsIter = 1;
|
|
UINTN RecIter = 1;
|
|
UINTN k = 0;
|
|
UINTN i;
|
|
|
|
// If scanloader starts multiple times, then we need to free systemplists, installplists, recoveryplists variables, also
|
|
// refresh APFSUUIDBank
|
|
if ((SystemPlists != NULL) || (InstallPlists != NULL) || (RecoveryPlists != NULL)) {
|
|
if ((APFSUUIDBank != NULL) && (APFSSupport == TRUE)) {
|
|
FreePool(APFSUUIDBank);
|
|
//Reset APFSUUIDBank counter, we will re-enumerate it
|
|
APFSUUIDBankCounter = 0;
|
|
APFSUUIDBank = APFSContainer_Support();
|
|
if (APFSUUIDBankCounter == 0) {
|
|
APFSSupport = FALSE;
|
|
}
|
|
}
|
|
if (SystemPlists != NULL) {
|
|
k = 0;
|
|
while (SystemPlists[k] != NULL) {
|
|
SystemPlists[k] = NULL;
|
|
k++;
|
|
}
|
|
FreePool(SystemPlists);
|
|
SystemPlists = NULL;
|
|
}
|
|
if (InstallPlists != NULL) {
|
|
k = 0;
|
|
while (InstallPlists[k] != NULL) {
|
|
InstallPlists[k] = NULL;
|
|
k++;
|
|
}
|
|
FreePool(InstallPlists);
|
|
InstallPlists = NULL;
|
|
}
|
|
if (RecoveryPlists != NULL) {
|
|
k = 0;
|
|
while (RecoveryPlists[k] != NULL) {
|
|
RecoveryPlists[k] = NULL;
|
|
k++;
|
|
}
|
|
FreePool(RecoveryPlists);
|
|
RecoveryPlists = NULL;
|
|
}
|
|
}
|
|
/************************************************************************/
|
|
/*Allocate Memory for systemplists, installplists and recoveryplists********************/
|
|
//Check apfs support
|
|
if (APFSSupport == TRUE) {
|
|
SystemPlists = (__typeof__(SystemPlists))AllocateZeroPool((2*APFSUUIDBankCounter+3)*sizeof(CHAR16 *));//array of pointers
|
|
InstallPlists = (__typeof__(InstallPlists))AllocateZeroPool((APFSUUIDBankCounter+2)*sizeof(CHAR16 *));//array of pointers
|
|
RecoveryPlists = (__typeof__(RecoveryPlists))AllocateZeroPool((APFSUUIDBankCounter+2)*sizeof(CHAR16 *));//array of pointers
|
|
} else {
|
|
SystemPlists = (__typeof__(SystemPlists))AllocateZeroPool(sizeof(CHAR16 *)*3);
|
|
InstallPlists = (__typeof__(InstallPlists))AllocateZeroPool(sizeof(CHAR16 *)*2);
|
|
RecoveryPlists = (__typeof__(RecoveryPlists))AllocateZeroPool(sizeof(CHAR16 *)*2);
|
|
}
|
|
/* Fill it with standard paths*******************************************/
|
|
SystemPlists[0] = SystemVersionPlist;
|
|
SystemPlists[1] = ServerVersionPlist;
|
|
SystemPlists[2] = NULL;
|
|
InstallPlists[0] = InstallVersionPlist;
|
|
InstallPlists[1] = NULL;
|
|
RecoveryPlists[0] = RecoveryVersionPlist;
|
|
RecoveryPlists[1] = NULL;
|
|
/************************************************************************/
|
|
//Fill Plists
|
|
for (i = 0; i < APFSUUIDBankCounter+1; i++) {
|
|
//Store UUID from bank
|
|
CHAR16 *CurrentUUID = GuidLEToStr((EFI_GUID *)((UINT8 *)APFSUUIDBank+i*0x10));
|
|
//Init temp string with system/install/recovery APFS path
|
|
CHAR16 *TmpSysPlistPath = (__typeof__(TmpSysPlistPath))AllocateZeroPool(86*sizeof(CHAR16));
|
|
CHAR16 *TmpServerPlistPath = (__typeof__(TmpServerPlistPath))AllocateZeroPool(86*sizeof(CHAR16));
|
|
CHAR16 *TmpInsPlistPath = (__typeof__(TmpInsPlistPath))AllocateZeroPool(79*sizeof(CHAR16));
|
|
CHAR16 *TmpRecPlistPath = (__typeof__(TmpRecPlistPath))AllocateZeroPool(58*sizeof(CHAR16));
|
|
StrnCpy(TmpSysPlistPath, APFSSysPlistPath, 85);
|
|
StrnCpy(TmpServerPlistPath, APFSServerPlistPath, 85);
|
|
StrnCpy(TmpInsPlistPath, APFSInstallPlistPath, 78);
|
|
StrnCpy(TmpRecPlistPath, APFSRecPlistPath, 57);
|
|
StrnCpy(TmpSysPlistPath+1, CurrentUUID, 36);
|
|
StrnCpy(TmpServerPlistPath+1, CurrentUUID, 36);
|
|
StrnCpy(TmpInsPlistPath+1, CurrentUUID, 36);
|
|
StrnCpy(TmpRecPlistPath+1, CurrentUUID, 36);
|
|
//Fill SystemPlists/InstallPlists/RecoveryPlists arrays
|
|
SystemPlists[SysIter] = TmpSysPlistPath;
|
|
SystemPlists[SysIter+1] = TmpServerPlistPath;
|
|
SystemPlists[SysIter+2] = NULL;
|
|
InstallPlists[InsIter] = TmpInsPlistPath;
|
|
InstallPlists[InsIter+1] = NULL;
|
|
RecoveryPlists[RecIter] = TmpRecPlistPath;
|
|
RecoveryPlists[RecIter+1] = NULL;
|
|
SysIter+=2;
|
|
InsIter++;
|
|
RecIter++;
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUG_CLOVER
|
|
XStringW g_str(L"g_str:foobar");
|
|
XStringW g_str2(L"g_str:foobar2");
|
|
//XStringW g_str3(L"g_str:foobar2");
|
|
//XStringW g_str4(L"g_str:foobar2");
|
|
//XStringW g_str5(L"g_str:foobar2");
|
|
//XStringW g_str6(L"g_str:foobar2");
|
|
//XStringW g_str7(L"g_str:foobar2");
|
|
//XStringW g_str8(L"g_str:foobar2");
|
|
//XStringW g_str9(L"g_str:foobar2");
|
|
//XStringW g_str10(L"g_str:foobar2");
|
|
//XStringW g_str11(L"g_str:foobar2");
|
|
//XStringW g_str12(L"g_str:foobar2");
|
|
#endif
|
|
|
|
|
|
//
|
|
// main entry point
|
|
//
|
|
EFI_STATUS
|
|
EFIAPI
|
|
RefitMain (IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable)
|
|
{
|
|
EFI_STATUS Status;
|
|
BOOLEAN MainLoopRunning = TRUE;
|
|
BOOLEAN ReinitDesktop = TRUE;
|
|
BOOLEAN AfterTool = FALSE;
|
|
REFIT_ABSTRACT_MENU_ENTRY *ChosenEntry = NULL;
|
|
REFIT_ABSTRACT_MENU_ENTRY *DefaultEntry = NULL;
|
|
REFIT_ABSTRACT_MENU_ENTRY *OptionEntry = NULL;
|
|
INTN DefaultIndex;
|
|
UINTN MenuExit;
|
|
UINTN Size, i;
|
|
//UINT64 TscDiv;
|
|
//UINT64 TscRemainder = 0;
|
|
// LOADER_ENTRY *LoaderEntry;
|
|
CHAR16 *ConfName = NULL;
|
|
TagPtr smbiosTags = NULL;
|
|
TagPtr UniteTag = NULL;
|
|
BOOLEAN UniteConfigs = FALSE;
|
|
EFI_TIME Now;
|
|
BOOLEAN HaveDefaultVolume;
|
|
#if USE_XTHEME
|
|
REFIT_MENU_SCREEN BootScreen;
|
|
BootScreen.isBootScreen = true; //other screens will be constructed as false
|
|
#else
|
|
CHAR16 *FirstMessage;
|
|
#endif
|
|
// CHAR16 *InputBuffer; //, *Y;
|
|
// EFI_INPUT_KEY Key;
|
|
|
|
// Init assets dir: misc
|
|
/*Status = */ //egMkDir(SelfRootDir, L"EFI\\CLOVER\\misc");
|
|
//Should apply to: "ACPI/origin/" too
|
|
|
|
// get TSC freq and init MemLog if needed
|
|
gCPUStructure.TSCCalibr = GetMemLogTscTicksPerSecond(); //ticks for 1second
|
|
//GlobalConfig.TextOnly = TRUE;
|
|
|
|
// bootstrap
|
|
gST = SystemTable;
|
|
gImageHandle = ImageHandle;
|
|
gBS = SystemTable->BootServices;
|
|
gRT = SystemTable->RuntimeServices;
|
|
/*Status = */EfiGetSystemConfigurationTable (&gEfiDxeServicesTableGuid, (VOID **) &gDS);
|
|
|
|
ConsoleInHandle = SystemTable->ConsoleInHandle;
|
|
|
|
|
|
gRT->GetTime(&Now, NULL);
|
|
|
|
// firmware detection
|
|
gFirmwareClover = StrCmp(gST->FirmwareVendor, L"CLOVER") == 0;
|
|
if (!gFirmwareRevision) {
|
|
gFirmwareRevision = PoolPrint(L"%d", gST->FirmwareRevision);
|
|
}
|
|
InitializeConsoleSim();
|
|
InitBooterLog();
|
|
ZeroMem((VOID*)&gGraphics[0], sizeof(GFX_PROPERTIES) * 4);
|
|
ZeroMem((VOID*)&gAudios[0], sizeof(HDA_PROPERTIES) * 4);
|
|
|
|
DBG("\n");
|
|
if (Now.TimeZone < -1440 || Now.TimeZone > 1440) {
|
|
MsgLog("Now is %02d.%02d.%d, %02d:%02d:%02d (GMT)\n",
|
|
Now.Day, Now.Month, Now.Year, Now.Hour, Now.Minute, Now.Second);
|
|
} else {
|
|
MsgLog("Now is %02d.%02d.%d, %02d:%02d:%02d (GMT+%d)\n",
|
|
Now.Day, Now.Month, Now.Year, Now.Hour, Now.Minute, Now.Second, GlobalConfig.Timezone);
|
|
}
|
|
//MsgLog("Starting Clover rev %ls on %ls EFI\n", FIRMWARE_REVISION, gST->FirmwareVendor);
|
|
MsgLog("Starting %s on %ls EFI\n", REVISION_STR, gST->FirmwareVendor);
|
|
|
|
#ifdef BUILDINFOS_STR
|
|
DBG("Build with: [%s]\n", BUILDINFOS_STR);
|
|
#endif // BUILDINFOS_STR
|
|
|
|
|
|
Status = InitRefitLib(gImageHandle);
|
|
if (EFI_ERROR(Status))
|
|
return Status;
|
|
|
|
DBG("Clover : Image base = 0x%llX\n", (uintptr_t)SelfLoadedImage->ImageBase); // do not change, it's used by grep to feed the debugger
|
|
#ifdef JIEF_DEBUG
|
|
gBS->Stall(1500000); // to give time to gdb to connect
|
|
// PauseForKey(L"press\n");
|
|
#endif
|
|
|
|
construct_globals_objects(); // do this after SelfLoadedImage is initialized
|
|
// all_tests();
|
|
|
|
//dumping SETTING structure
|
|
// if you change something in Platform.h, please uncomment and test that all offsets
|
|
// are natural aligned i.e. pointers are 8 bytes aligned
|
|
/*
|
|
DBG("Settings offsets:\n");
|
|
DBG(" OEMProduct: %X\n", OFFSET_OF(SETTINGS_DATA, OEMProduct));
|
|
DBG(" DefaultVolume: %X\n", OFFSET_OF(SETTINGS_DATA, DefaultVolume));
|
|
DBG(" DefaultLoader: %X\n", OFFSET_OF(SETTINGS_DATA, DefaultLoader));
|
|
DBG(" ResetAddr: %X\n", OFFSET_OF(SETTINGS_DATA, ResetAddr));
|
|
DBG(" FixDsdt: %X\n", OFFSET_OF(SETTINGS_DATA, FixDsdt));
|
|
DBG(" FakeATI: %X\n", OFFSET_OF(SETTINGS_DATA, FakeATI));
|
|
DBG(" PatchVBiosBytes:%X\n", OFFSET_OF(SETTINGS_DATA, PatchVBiosBytes));
|
|
DBG(" VRAM: %X\n", OFFSET_OF(SETTINGS_DATA, VRAM));
|
|
DBG(" SecureBootWhiteListCount: %X\n", OFFSET_OF(SETTINGS_DATA, SecureBootWhiteListCount));
|
|
DBG(" LegacyBoot: %X\n", OFFSET_OF(SETTINGS_DATA, LegacyBoot));
|
|
DBG(" HVHideStrings: %X\n", OFFSET_OF(SETTINGS_DATA, HVHideStrings));
|
|
DBG(" PointerSpeed: %X\n", OFFSET_OF(SETTINGS_DATA, PointerSpeed));
|
|
DBG(" RtMLB: %X\n", OFFSET_OF(SETTINGS_DATA, RtMLB));
|
|
DBG(" ConfigName: %X\n", OFFSET_OF(SETTINGS_DATA, ConfigName));
|
|
DBG(" PointerSpeed: %X\n", OFFSET_OF(SETTINGS_DATA, PointerSpeed));
|
|
DBG(" PatchDsdtNum: %X\n", OFFSET_OF(SETTINGS_DATA, PatchDsdtNum));
|
|
DBG(" LenToReplace: %X\n", OFFSET_OF(SETTINGS_DATA, LenToReplace));
|
|
DBG(" ACPIDropTables: %X\n", OFFSET_OF(SETTINGS_DATA, ACPIDropTables));
|
|
DBG(" CustomEntries: %X\n", OFFSET_OF(SETTINGS_DATA, CustomEntries));
|
|
DBG(" CustomTool: %X\n", OFFSET_OF(SETTINGS_DATA, CustomTool));
|
|
DBG(" AddProperties: %X\n", OFFSET_OF(SETTINGS_DATA, AddProperties));
|
|
DBG(" BlockKexts: %X\n", OFFSET_OF(SETTINGS_DATA, BlockKexts));
|
|
*/
|
|
|
|
// disable EFI watchdog timer
|
|
gBS->SetWatchdogTimer(0x0000, 0x0000, 0x0000, NULL);
|
|
ZeroMem((VOID*)&gSettings, sizeof(SETTINGS_DATA));
|
|
|
|
Status = InitializeUnicodeCollationProtocol();
|
|
if (EFI_ERROR(Status)) {
|
|
DBG("UnicodeCollation Status=%s\n", strerror(Status));
|
|
}
|
|
|
|
Status = gBS->HandleProtocol(ConsoleInHandle, &gEfiSimpleTextInputExProtocolGuid, (VOID **)&SimpleTextEx);
|
|
if ( EFI_ERROR (Status) ) {
|
|
SimpleTextEx = NULL;
|
|
}
|
|
DBG("SimpleTextEx Status=%s\n", strerror(Status));
|
|
|
|
PrepatchSmbios();
|
|
|
|
//#ifdef REVISION_STR
|
|
// DBG(REVISION_STR);
|
|
//#endif
|
|
|
|
//replace / with _
|
|
Size = iStrLen(gSettings.OEMProduct, 64);
|
|
for (i=0; i<Size; i++) {
|
|
if (gSettings.OEMProduct[i] == 0x2F) {
|
|
gSettings.OEMProduct[i] = 0x5F;
|
|
}
|
|
}
|
|
Size = iStrLen(gSettings.OEMBoard, 64);
|
|
for (i=0; i<Size; i++) {
|
|
if (gSettings.OEMBoard[i] == 0x2F) {
|
|
gSettings.OEMBoard[i] = 0x5F;
|
|
}
|
|
}
|
|
DBG("Running on: '%s' with board '%s'\n", gSettings.OEMProduct, gSettings.OEMBoard);
|
|
|
|
GetCPUProperties();
|
|
GetDevices();
|
|
GetDefaultSettings();
|
|
|
|
// LoadOptions Parsing
|
|
DBG("Clover load options size = %d bytes\n", SelfLoadedImage->LoadOptionsSize);
|
|
if ((SelfLoadedImage->LoadOptions != NULL) &&
|
|
(SelfLoadedImage->LoadOptionsSize != 0)){
|
|
if (*(UINT32*)SelfLoadedImage->LoadOptions == CLOVER_SIGN) {
|
|
GetBootFromOption();
|
|
} else {
|
|
ParseLoadOptions(&ConfName, &gConfigDict[1]);
|
|
if (ConfName) {
|
|
if (StrLen(ConfName) == 0) {
|
|
gConfigDict[1] = NULL;
|
|
FreePool(ConfName);
|
|
ConfName = NULL;
|
|
} else {
|
|
SetOEMPath(ConfName);
|
|
Status = LoadUserSettings(SelfRootDir, ConfName, &gConfigDict[1]);
|
|
DBG("%ls\\%ls.plist%ls loaded with name from LoadOptions: %s\n",
|
|
OEMPath, ConfName, EFI_ERROR(Status) ? L" not" : L"", strerror(Status));
|
|
if (EFI_ERROR(Status)) {
|
|
gConfigDict[1] = NULL;
|
|
FreePool(ConfName);
|
|
ConfName = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (gConfigDict[1]) {
|
|
UniteTag = GetProperty(gConfigDict[1], "Unite");
|
|
if(UniteTag) {
|
|
UniteConfigs = (UniteTag->type == kTagTypeTrue) ||
|
|
((UniteTag->type == kTagTypeString) &&
|
|
((UniteTag->string[0] == 'y') || (UniteTag->string[0] == 'Y')));
|
|
DBG("UniteConfigs = %ls", UniteConfigs ? L"TRUE\n": L"FALSE\n" );
|
|
}
|
|
}
|
|
if (!gConfigDict[1] || UniteConfigs) {
|
|
SetOEMPath(L"config");
|
|
Status = LoadUserSettings(SelfRootDir, L"config", &gConfigDict[0]);
|
|
DBG("%ls\\config.plist%ls loaded: %s\n", OEMPath, EFI_ERROR(Status) ? L" not" : L"", strerror(Status));
|
|
}
|
|
UnicodeSPrint(gSettings.ConfigName, 64, L"%s%s%s",
|
|
/* gSettings.ConfigName = PoolPrint(L"%s%s%s", */
|
|
gConfigDict[0] ? L"config": L"",
|
|
(gConfigDict[0] && gConfigDict[1]) ? L" + ": L"",
|
|
!gConfigDict[1] ? L"": (ConfName ? ConfName : L"Load Options"));
|
|
gSettings.MainConfigName = EfiStrDuplicate(gSettings.ConfigName);
|
|
|
|
gSettings.PointerEnabled = TRUE;
|
|
gSettings.PointerSpeed = 2;
|
|
gSettings.DoubleClickTime = 500; //TODO - make it constant as nobody change it
|
|
|
|
#ifdef ENABLE_SECURE_BOOT
|
|
InitializeSecureBoot();
|
|
#endif // ENABLE_SECURE_BOOT
|
|
|
|
|
|
{
|
|
// UINT32 machineSignature = 0;
|
|
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtPointer = NULL;
|
|
EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs = NULL;
|
|
|
|
// DBG("---dump hibernations data---\n");
|
|
FadtPointer = GetFadt();
|
|
if (FadtPointer != NULL) {
|
|
Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE*)(UINTN)(FadtPointer->FirmwareCtrl);
|
|
/*
|
|
DBG(" Firmware wake address=%08lx\n", Facs->FirmwareWakingVector);
|
|
DBG(" Firmware wake 64 addr=%16llx\n", Facs->XFirmwareWakingVector);
|
|
DBG(" Hardware signature =%08lx\n", Facs->HardwareSignature);
|
|
DBG(" GlobalLock =%08lx\n", Facs->GlobalLock);
|
|
DBG(" Flags =%08lx\n", Facs->Flags);
|
|
*/
|
|
machineSignature = Facs->HardwareSignature;
|
|
}
|
|
#if HIBERNATE_DUMP_DATA
|
|
//------------------------------------------------------
|
|
DumpVariable(L"Boot0082", &gEfiGlobalVariableGuid, 8);
|
|
DumpVariable(L"boot-switch-vars", &gEfiAppleBootGuid, -1);
|
|
DumpVariable(L"boot-signature", &gEfiAppleBootGuid, -1);
|
|
DumpVariable(L"boot-image-key", &gEfiAppleBootGuid, -1);
|
|
DumpVariable(L"boot-image", &gEfiAppleBootGuid, 0);
|
|
//-----------------------------------------------------------
|
|
|
|
#endif //
|
|
}
|
|
|
|
#if 0
|
|
//testing place
|
|
{
|
|
CHAR16 *aaa = L"12345";
|
|
DBG(" string %ls, size=%d, len=%d sizeof=%d\n", aaa, StrSize(aaa), StrLen(aaa), sizeof(aaa));
|
|
}
|
|
#endif
|
|
if (!GlobalConfig.FastBoot) {
|
|
GetListOfThemes();
|
|
GetListOfConfigs();
|
|
}
|
|
|
|
#if USE_XTHEME
|
|
ThemeX.FillByEmbedded(); //init XTheme before EarlyUserSettings
|
|
#endif
|
|
|
|
for (i=0; i<2; i++) {
|
|
if (gConfigDict[i]) {
|
|
GetEarlyUserSettings(SelfRootDir, gConfigDict[i]);
|
|
}
|
|
}
|
|
|
|
#ifdef ENABLE_SECURE_BOOT
|
|
// Install secure boot shim
|
|
if (EFI_ERROR(Status = InstallSecureBoot())) {
|
|
PauseForKey(L"Secure boot failure!\n");
|
|
return Status;
|
|
}
|
|
#endif // ENABLE_SECURE_BOOT
|
|
|
|
MainMenu.TimeoutSeconds = GlobalConfig.Timeout >= 0 ? GlobalConfig.Timeout : 0;
|
|
//DBG("LoadDrivers() start\n");
|
|
LoadDrivers();
|
|
//DBG("LoadDrivers() end\n");
|
|
|
|
/* if (!gFirmwareClover &&
|
|
!gDriversFlags.EmuVariableLoaded) {
|
|
GetSmcKeys(FALSE); // later we can get here SMC information
|
|
} */
|
|
|
|
Status = gBS->LocateProtocol (&gEmuVariableControlProtocolGuid, NULL, (VOID**)&gEmuVariableControl);
|
|
if (EFI_ERROR(Status)) {
|
|
gEmuVariableControl = NULL;
|
|
}
|
|
if (gEmuVariableControl != NULL) {
|
|
gEmuVariableControl->InstallEmulation(gEmuVariableControl);
|
|
}
|
|
|
|
DbgHeader("InitScreen");
|
|
|
|
if (!GlobalConfig.FastBoot) {
|
|
// init screen and dump video modes to log
|
|
if (gDriversFlags.VideoLoaded) {
|
|
InitScreen(FALSE);
|
|
} else {
|
|
InitScreen(!gFirmwareClover); // ? FALSE : TRUE);
|
|
}
|
|
//DBG("DBG: setup screen\n");
|
|
SetupScreen();
|
|
} else {
|
|
InitScreen(FALSE);
|
|
}
|
|
|
|
// DBG("DBG: ReinitSelfLib\n");
|
|
//Now we have to reinit handles
|
|
Status = ReinitSelfLib();
|
|
if (EFI_ERROR(Status)){
|
|
DebugLog(2, " %s", strerror(Status));
|
|
PauseForKey(L"Error reinit refit\n");
|
|
#ifdef ENABLE_SECURE_BOOT
|
|
UninstallSecureBoot();
|
|
#endif // ENABLE_SECURE_BOOT
|
|
return Status;
|
|
}
|
|
|
|
// DBG("DBG: messages\n");
|
|
if (!GlobalConfig.NoEarlyProgress && !GlobalConfig.FastBoot && GlobalConfig.Timeout>0) {
|
|
#if USE_XTHEME
|
|
XStringW Message = SWPrintf(" Welcome to Clover %ls ", gFirmwareRevision);
|
|
BootScreen.DrawTextXY(Message, (UGAWidth >> 1), UGAHeight >> 1, X_IS_CENTER);
|
|
BootScreen.DrawTextXY(L"... testing hardware ..."_XSW, (UGAWidth >> 1), (UGAHeight >> 1) + 20, X_IS_CENTER);
|
|
#else
|
|
FirstMessage = PoolPrint(L" Welcome to Clover %s ", gFirmwareRevision);
|
|
DrawTextXY(FirstMessage, (UGAWidth >> 1), UGAHeight >> 1, X_IS_CENTER);
|
|
FreePool(FirstMessage);
|
|
FirstMessage = PoolPrint(L"... testing hardware ...");
|
|
DrawTextXY(FirstMessage, (UGAWidth >> 1), (UGAHeight >> 1) + 20, X_IS_CENTER);
|
|
FreePool(FirstMessage);
|
|
#endif
|
|
}
|
|
|
|
// DumpBiosMemoryMap();
|
|
|
|
GuiEventsInitialize();
|
|
|
|
if (!gSettings.EnabledCores) {
|
|
gSettings.EnabledCores = gCPUStructure.Cores;
|
|
}
|
|
|
|
GetMacAddress();
|
|
//DBG("ScanSPD() start\n");
|
|
ScanSPD();
|
|
//DBG("ScanSPD() end\n");
|
|
|
|
SetPrivateVarProto();
|
|
// GetDefaultSettings();
|
|
GetAcpiTablesList();
|
|
|
|
DBG("Calibrated TSC Frequency = %llu = %lluMHz\n", gCPUStructure.TSCCalibr, DivU64x32(gCPUStructure.TSCCalibr, Mega));
|
|
if (gCPUStructure.TSCCalibr > 200000000ULL) { //200MHz
|
|
gCPUStructure.TSCFrequency = gCPUStructure.TSCCalibr;
|
|
}
|
|
|
|
gCPUStructure.CPUFrequency = gCPUStructure.TSCFrequency;
|
|
gCPUStructure.FSBFrequency = DivU64x32(MultU64x32(gCPUStructure.CPUFrequency, 10),
|
|
(gCPUStructure.MaxRatio == 0) ? 1 : gCPUStructure.MaxRatio);
|
|
gCPUStructure.MaxSpeed = (UINT32)DivU64x32(gCPUStructure.TSCFrequency + (Mega >> 1), Mega);
|
|
|
|
switch (gCPUStructure.Model) {
|
|
case CPU_MODEL_PENTIUM_M:
|
|
case CPU_MODEL_ATOM:// Atom
|
|
case CPU_MODEL_DOTHAN:// Pentium M, Dothan, 90nm
|
|
case CPU_MODEL_YONAH:// Core Duo/Solo, Pentium M DC
|
|
case CPU_MODEL_MEROM:// Core Xeon, Core 2 Duo, 65nm, Mobile
|
|
//case CPU_MODEL_CONROE:// Core Xeon, Core 2 Duo, 65nm, Desktop like Merom but not mobile
|
|
case CPU_MODEL_CELERON:
|
|
case CPU_MODEL_PENRYN:// Core 2 Duo/Extreme, Xeon, 45nm , Mobile
|
|
case CPU_MODEL_NEHALEM:// Core i7 LGA1366, Xeon 5500, "Bloomfield", "Gainstown", 45nm
|
|
case CPU_MODEL_FIELDS:// Core i7, i5 LGA1156, "Clarksfield", "Lynnfield", "Jasper", 45nm
|
|
case CPU_MODEL_DALES:// Core i7, i5, Nehalem
|
|
case CPU_MODEL_CLARKDALE:// Core i7, i5, i3 LGA1156, "Westmere", "Clarkdale", , 32nm
|
|
case CPU_MODEL_WESTMERE:// Core i7 LGA1366, Six-core, "Westmere", "Gulftown", 32nm
|
|
case CPU_MODEL_NEHALEM_EX:// Core i7, Nehalem-Ex Xeon, "Beckton"
|
|
case CPU_MODEL_WESTMERE_EX:// Core i7, Nehalem-Ex Xeon, "Eagleton"
|
|
gCPUStructure.ExternalClock = (UINT32)DivU64x32(gCPUStructure.FSBFrequency + kilo - 1, kilo);
|
|
//DBG(" Read TSC ExternalClock: %d MHz\n", (INT32)(DivU64x32(gCPUStructure.ExternalClock, kilo)));
|
|
break;
|
|
default:
|
|
//DBG(" Read TSC ExternalClock: %d MHz\n", (INT32)(DivU64x32(gCPUStructure.FSBFrequency, Mega)));
|
|
|
|
// for sandy bridge or newer
|
|
// to match ExternalClock 25 MHz like real mac, divide FSBFrequency by 4
|
|
gCPUStructure.ExternalClock = ((UINT32)DivU64x32(gCPUStructure.FSBFrequency + kilo - 1, kilo) + 3) / 4;
|
|
//DBG(" Corrected TSC ExternalClock: %d MHz\n", (INT32)(DivU64x32(gCPUStructure.ExternalClock, kilo)));
|
|
break;
|
|
}
|
|
|
|
if (!GlobalConfig.NoEarlyProgress && !GlobalConfig.FastBoot && GlobalConfig.Timeout>0) {
|
|
#if USE_XTHEME
|
|
XStringW Message = SWPrintf("... user settings ...");
|
|
BootScreen.EraseTextXY();
|
|
BootScreen.DrawTextXY(Message, (UGAWidth >> 1), (UGAHeight >> 1) + 20, X_IS_CENTER);
|
|
#else
|
|
FirstMessage = PoolPrint(L"... user settings ...");
|
|
// i = (UGAWidth - StrLen(FirstMessage) * GlobalConfig.CharWidth) >> 1;
|
|
DrawTextXY(FirstMessage, (UGAWidth >> 1), (UGAHeight >> 1) + 20, X_IS_CENTER);
|
|
FreePool(FirstMessage);
|
|
#endif
|
|
}
|
|
|
|
//Second step. Load config.plist into gSettings
|
|
for (i=0; i<2; i++) {
|
|
if (gConfigDict[i]) {
|
|
Status = GetUserSettings(SelfRootDir, gConfigDict[i]);
|
|
if (EFI_ERROR(Status)) {
|
|
// DBG("Error in Second part of settings%d: %s\n", i, strerror(Status));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (gSettings.QEMU) {
|
|
// UINT64 Msrflex = 0ULL;
|
|
|
|
if (!gSettings.UserChange) {
|
|
gSettings.BusSpeed = 200000;
|
|
}
|
|
gCPUStructure.MaxRatio = (UINT32)DivU64x32(gCPUStructure.TSCCalibr, gSettings.BusSpeed * kilo);
|
|
DBG("Set MaxRatio for QEMU: %d\n", gCPUStructure.MaxRatio);
|
|
gCPUStructure.MaxRatio *= 10;
|
|
gCPUStructure.MinRatio = 60;
|
|
/* AsmWriteMsr64(MSR_FLEX_RATIO, ((6ULL << 40) + //(1ULL << 16) +
|
|
(gCPUStructure.MaxRatio << 8)));
|
|
DBG("check if flex is RW\n");
|
|
Msrflex = AsmReadMsr64(MSR_FLEX_RATIO); //0 == not Rw :(
|
|
DBG("MSR_FLEX_RATIO = %lx\n", Msrflex);
|
|
*/
|
|
gCPUStructure.FSBFrequency = DivU64x32(MultU64x32(gCPUStructure.CPUFrequency, 10),
|
|
(gCPUStructure.MaxRatio == 0) ? 1 : gCPUStructure.MaxRatio);
|
|
gCPUStructure.ExternalClock = (UINT32)DivU64x32(gCPUStructure.FSBFrequency + kilo - 1, kilo);
|
|
}
|
|
|
|
dropDSM = 0xFFFF; //by default we drop all OEM _DSM. They have no sense for us.
|
|
if (defDSM) {
|
|
dropDSM = gSettings.DropOEM_DSM; //if set by user
|
|
}
|
|
// Load any extra SMBIOS information
|
|
if (!EFI_ERROR(LoadUserSettings(SelfRootDir, L"smbios", &smbiosTags)) && (smbiosTags != NULL)) {
|
|
TagPtr dictPointer = GetProperty(smbiosTags,"SMBIOS");
|
|
if (dictPointer) {
|
|
ParseSMBIOSSettings(dictPointer);
|
|
} else {
|
|
DBG("Invalid smbios.plist, not overriding config.plist!\n");
|
|
}
|
|
}
|
|
/*
|
|
if (gFirmwareClover || gDriversFlags.EmuVariableLoaded) {
|
|
if (GlobalConfig.StrictHibernate) {
|
|
DBG(" Don't use StrictHibernate with emulated NVRAM!\n");
|
|
}
|
|
GlobalConfig.StrictHibernate = FALSE;
|
|
}
|
|
*/
|
|
HaveDefaultVolume = gSettings.DefaultVolume != NULL;
|
|
if (!gFirmwareClover &&
|
|
!gDriversFlags.EmuVariableLoaded &&
|
|
!HaveDefaultVolume &&
|
|
GlobalConfig.Timeout == 0 && !ReadAllKeyStrokes()) {
|
|
// UEFI boot: get gEfiBootDeviceGuid from NVRAM.
|
|
// if present, ScanVolumes() will skip scanning other volumes
|
|
// in the first run.
|
|
// this speeds up loading of default macOS volume.
|
|
GetEfiBootDeviceFromNvram();
|
|
}
|
|
|
|
if (!GlobalConfig.NoEarlyProgress && !GlobalConfig.FastBoot && GlobalConfig.Timeout>0) {
|
|
#if USE_XTHEME
|
|
XStringW Message = SWPrintf("... scan entries ...");
|
|
BootScreen.EraseTextXY();
|
|
BootScreen.DrawTextXY(Message, (UGAWidth >> 1), (UGAHeight >> 1) + 20, X_IS_CENTER);
|
|
#else
|
|
FirstMessage = PoolPrint(L"... scan entries ...");
|
|
DrawTextXY(FirstMessage, (UGAWidth >> 1), (UGAHeight >> 1) + 20, X_IS_CENTER);
|
|
FreePool(FirstMessage);
|
|
#endif
|
|
}
|
|
|
|
|
|
GetListOfDsdts(); //only after GetUserSettings
|
|
GetListOfACPI(); //ssdt and other tables
|
|
|
|
AfterTool = FALSE;
|
|
gGuiIsReady = TRUE;
|
|
do {
|
|
MainMenu.Entries.Empty();
|
|
OptionMenu.Entries.Empty();
|
|
InitKextList();
|
|
ScanVolumes();
|
|
|
|
//Check apfs driver loaded state
|
|
//Free APFSUUIDBank
|
|
if (APFSUUIDBank != NULL) {
|
|
//Free mem
|
|
FreePool(APFSUUIDBank);
|
|
//Reset counter
|
|
APFSUUIDBankCounter=0;
|
|
}
|
|
/* APFS container support */
|
|
//Fill APFSUUIDBank
|
|
APFSUUIDBank = APFSContainer_Support();
|
|
if (APFSUUIDBankCounter != 0) {
|
|
APFSSupport = TRUE;
|
|
} else {
|
|
APFSSupport = FALSE;
|
|
}
|
|
//Fill systemversion plists path
|
|
SystemVersionInit();
|
|
|
|
// as soon as we have Volumes, find latest nvram.plist and copy it to RT vars
|
|
if (!AfterTool) {
|
|
if (gFirmwareClover || gDriversFlags.EmuVariableLoaded) {
|
|
PutNvramPlistToRtVars();
|
|
}
|
|
}
|
|
|
|
// log Audio devices in boot-log. Thisis for clients like Clover.app
|
|
GetOutputs();
|
|
for (i = 0; i < AudioNum; i++) {
|
|
if (AudioList[i].Name) {
|
|
// Never change this log, otherwise clients will stop interprete the output.
|
|
MsgLog("Found Audio Device %ls (%s) at index %llu\n", AudioList[i].Name, AudioOutputNames[AudioList[i].Device], i);
|
|
}
|
|
}
|
|
|
|
if (!GlobalConfig.FastBoot) {
|
|
CHAR16 *TmpArgs;
|
|
if (gThemeNeedInit) {
|
|
InitTheme(TRUE, &Now);
|
|
gThemeNeedInit = FALSE;
|
|
} else if (gThemeChanged) {
|
|
DBG("change theme\n");
|
|
InitTheme(FALSE, NULL);
|
|
OptionMenu.FreeMenu();
|
|
}
|
|
DBG("theme inited\n");
|
|
gThemeChanged = FALSE;
|
|
#if USE_XTHEME
|
|
if (ThemeX.embedded) {
|
|
DBG("Chosen embedded theme\n");
|
|
} else {
|
|
DBG("Chosen theme %ls\n", ThemeX.Theme.data());
|
|
}
|
|
#else
|
|
if (GlobalConfig.Theme) {
|
|
DBG("Chosen theme %ls\n", GlobalConfig.Theme);
|
|
} else {
|
|
DBG("Chosen embedded theme\n");
|
|
}
|
|
#endif
|
|
|
|
// DBG("initial boot-args=%s\n", gSettings.BootArgs);
|
|
//now it is a time to set RtVariables
|
|
SetVariablesFromNvram();
|
|
|
|
TmpArgs = PoolPrint(L"%a ", gSettings.BootArgs);
|
|
DBG("after NVRAM boot-args=%s\n", gSettings.BootArgs);
|
|
gSettings.OptionsBits = EncodeOptions(TmpArgs);
|
|
// DBG("initial OptionsBits %X\n", gSettings.OptionsBits);
|
|
FreePool(TmpArgs);
|
|
FillInputs(TRUE);
|
|
|
|
// scan for loaders and tools, add then to the menu
|
|
if (GlobalConfig.LegacyFirst){
|
|
AddCustomLegacy();
|
|
if (!GlobalConfig.NoLegacy) {
|
|
ScanLegacy();
|
|
}
|
|
}
|
|
}
|
|
GetSmcKeys(TRUE);
|
|
|
|
// Add custom entries
|
|
AddCustomEntries();
|
|
if (gSettings.DisableEntryScan) {
|
|
DBG("Entry scan disabled\n");
|
|
} else {
|
|
ScanLoader();
|
|
}
|
|
|
|
if (!GlobalConfig.FastBoot) {
|
|
|
|
if (!GlobalConfig.LegacyFirst) {
|
|
AddCustomLegacy();
|
|
if (!GlobalConfig.NoLegacy) {
|
|
ScanLegacy();
|
|
}
|
|
}
|
|
|
|
// fixed other menu entries
|
|
#if USE_XTHEME
|
|
if (!(ThemeX.HideUIFlags & HIDEUI_FLAG_TOOLS)) {
|
|
AddCustomTool();
|
|
if (!gSettings.DisableToolScan) {
|
|
ScanTool();
|
|
#ifdef ENABLE_SECURE_BOOT
|
|
// Check for secure boot setup mode
|
|
AddSecureBootTool();
|
|
#endif // ENABLE_SECURE_BOOT
|
|
}
|
|
}
|
|
#else
|
|
if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_TOOLS)) {
|
|
AddCustomTool();
|
|
if (!gSettings.DisableToolScan) {
|
|
ScanTool();
|
|
#ifdef ENABLE_SECURE_BOOT
|
|
// Check for secure boot setup mode
|
|
AddSecureBootTool();
|
|
#endif // ENABLE_SECURE_BOOT
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if USE_XTHEME
|
|
MenuEntryOptions.Image = ThemeX.GetIcon(BUILTIN_ICON_FUNC_OPTIONS);
|
|
#else
|
|
MenuEntryOptions.Image = BuiltinIcon(BUILTIN_ICON_FUNC_OPTIONS);
|
|
#endif
|
|
|
|
|
|
if (gSettings.DisableCloverHotkeys)
|
|
MenuEntryOptions.ShortcutLetter = 0x00;
|
|
MainMenu.AddMenuEntry(&MenuEntryOptions, false);
|
|
#if USE_XTHEME
|
|
MenuEntryAbout.Image = ThemeX.GetIcon((INTN)BUILTIN_ICON_FUNC_ABOUT);
|
|
#else
|
|
MenuEntryAbout.Image = BuiltinIcon(BUILTIN_ICON_FUNC_ABOUT);
|
|
#endif
|
|
|
|
|
|
if (gSettings.DisableCloverHotkeys)
|
|
MenuEntryAbout.ShortcutLetter = 0x00;
|
|
MainMenu.AddMenuEntry(&MenuEntryAbout, false);
|
|
|
|
#if USE_XTHEME
|
|
if (!(ThemeX.HideUIFlags & HIDEUI_FLAG_FUNCS) || MainMenu.Entries.size() == 0) {
|
|
if (gSettings.DisableCloverHotkeys)
|
|
MenuEntryReset.ShortcutLetter = 0x00;
|
|
MenuEntryReset.Image = ThemeX.GetIcon(BUILTIN_ICON_FUNC_RESET);
|
|
MainMenu.AddMenuEntry(&MenuEntryReset, false);
|
|
if (gSettings.DisableCloverHotkeys)
|
|
MenuEntryShutdown.ShortcutLetter = 0x00;
|
|
MenuEntryShutdown.Image = ThemeX.GetIcon(BUILTIN_ICON_FUNC_EXIT);
|
|
MainMenu.AddMenuEntry(&MenuEntryShutdown, false);
|
|
}
|
|
#else
|
|
if (!(GlobalConfig.HideUIFlags & HIDEUI_FLAG_FUNCS) || MainMenu.Entries.size() == 0) {
|
|
if (gSettings.DisableCloverHotkeys)
|
|
MenuEntryReset.ShortcutLetter = 0x00;
|
|
MenuEntryReset.Image = BuiltinIcon(BUILTIN_ICON_FUNC_RESET);
|
|
MainMenu.AddMenuEntry(&MenuEntryReset, false);
|
|
if (gSettings.DisableCloverHotkeys)
|
|
MenuEntryShutdown.ShortcutLetter = 0x00;
|
|
MenuEntryShutdown.Image = BuiltinIcon(BUILTIN_ICON_FUNC_EXIT);
|
|
MainMenu.AddMenuEntry(&MenuEntryShutdown, false);
|
|
}
|
|
#endif
|
|
|
|
// font already changed and this message very quirky, clear line here
|
|
if (!GlobalConfig.NoEarlyProgress && !GlobalConfig.FastBoot && GlobalConfig.Timeout>0) {
|
|
#if USE_XTHEME
|
|
// XStringW Message = L" "_XSW;
|
|
BootScreen.EraseTextXY();
|
|
// DrawTextXY(Message, (UGAWidth >> 1), (UGAHeight >> 1) + 20, X_IS_CENTER);
|
|
#else
|
|
DrawTextXY(L" ", (UGAWidth >> 1), (UGAHeight >> 1) + 20, X_IS_CENTER);
|
|
#endif
|
|
|
|
|
|
}
|
|
}
|
|
// wait for user ACK when there were errors
|
|
FinishTextScreen(FALSE);
|
|
#if CHECK_SMC
|
|
DumpSmcKeys();
|
|
#endif
|
|
|
|
DefaultIndex = FindDefaultEntry();
|
|
// DBG("DefaultIndex=%lld and MainMenu.Entries.size()=%llu\n", DefaultIndex, MainMenu.Entries.size());
|
|
if ((DefaultIndex >= 0) && (DefaultIndex < (INTN)MainMenu.Entries.size())) {
|
|
DefaultEntry = &MainMenu.Entries[DefaultIndex];
|
|
} else {
|
|
DefaultEntry = NULL;
|
|
}
|
|
|
|
MainLoopRunning = TRUE;
|
|
// MainMenu.TimeoutSeconds = GlobalConfig.Timeout >= 0 ? GlobalConfig.Timeout : 0;
|
|
if (DefaultEntry && (GlobalConfig.FastBoot ||
|
|
(gSettings.SkipHibernateTimeout &&
|
|
DefaultEntry->getLOADER_ENTRY()
|
|
&& OSFLAG_ISSET(DefaultEntry->getLOADER_ENTRY()->Flags, OSFLAG_HIBERNATED)
|
|
)
|
|
)
|
|
)
|
|
{
|
|
if (DefaultEntry->getLOADER_ENTRY()) {
|
|
StartLoader(DefaultEntry->getLOADER_ENTRY());
|
|
} else if (DefaultEntry->getLEGACY_ENTRY()){
|
|
StartLegacy(DefaultEntry->getLEGACY_ENTRY());
|
|
}
|
|
GlobalConfig.FastBoot = FALSE; //Hmm... will never be here
|
|
}
|
|
MainAnime = MainMenu.GetAnime();
|
|
// DBG("MainAnime=%d\n", MainAnime);
|
|
AfterTool = FALSE;
|
|
gEvent = 0; //clear to cancel loop
|
|
while (MainLoopRunning) {
|
|
// CHAR8 *LastChosenOS = NULL;
|
|
if (GlobalConfig.Timeout == 0 && DefaultEntry != NULL && !ReadAllKeyStrokes()) {
|
|
// go strait to DefaultVolume loading
|
|
MenuExit = MENU_EXIT_TIMEOUT;
|
|
} else {
|
|
MainMenu.AnimeRun = MainAnime;
|
|
MenuExit = MainMenu.RunMainMenu(DefaultIndex, &ChosenEntry);
|
|
}
|
|
// DBG("exit from MainMenu %llu\n", MenuExit); //MENU_EXIT_ENTER=(1) MENU_EXIT_DETAILS=3
|
|
// disable default boot - have sense only in the first run
|
|
GlobalConfig.Timeout = -1;
|
|
if ((DefaultEntry != NULL) && (MenuExit == MENU_EXIT_TIMEOUT)) {
|
|
if (DefaultEntry->getLOADER_ENTRY()) {
|
|
StartLoader(DefaultEntry->getLOADER_ENTRY());
|
|
} else if (DefaultEntry->getLEGACY_ENTRY()){
|
|
StartLegacy(DefaultEntry->getLEGACY_ENTRY());
|
|
}
|
|
// if something goes wrong - break main loop to reinit volumes
|
|
break;
|
|
}
|
|
|
|
if (MenuExit == MENU_EXIT_OPTIONS){
|
|
gBootChanged = FALSE;
|
|
OptionsMenu(&OptionEntry);
|
|
if (gBootChanged) {
|
|
AfterTool = TRUE;
|
|
MainLoopRunning = FALSE;
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (MenuExit == MENU_EXIT_HELP){
|
|
HelpRefit();
|
|
continue;
|
|
}
|
|
|
|
// EjectVolume
|
|
if (MenuExit == MENU_EXIT_EJECT){
|
|
Status = EFI_SUCCESS;
|
|
if (ChosenEntry->getLOADER_ENTRY() ) {
|
|
Status = EjectVolume(ChosenEntry->getLOADER_ENTRY()->Volume);
|
|
}
|
|
if ( ChosenEntry->getLEGACY_ENTRY() ) {
|
|
Status = EjectVolume(ChosenEntry->getLEGACY_ENTRY()->Volume);
|
|
}
|
|
if (!EFI_ERROR(Status)) {
|
|
break; //main loop is broken so Reinit all
|
|
}
|
|
continue;
|
|
}
|
|
|
|
// Hide toggle
|
|
if (MenuExit == MENU_EXIT_HIDE_TOGGLE) {
|
|
gSettings.ShowHiddenEntries = !gSettings.ShowHiddenEntries;
|
|
AfterTool = TRUE;
|
|
break;
|
|
}
|
|
|
|
// We don't allow exiting the main menu with the Escape key.
|
|
if (MenuExit == MENU_EXIT_ESCAPE){
|
|
break; //refresh main menu
|
|
// continue;
|
|
}
|
|
|
|
if ( ChosenEntry->getREFIT_MENU_ITEM_RESET() ) { // Restart
|
|
if (MenuExit == MENU_EXIT_DETAILS) {
|
|
// EFI_KEY_DATA KeyData;
|
|
// ZeroMem(&KeyData, sizeof KeyData);
|
|
// SimpleTextEx->ReadKeyStrokeEx (SimpleTextEx, &KeyData);
|
|
// if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
|
|
//do clear cmos as for AMI BIOS
|
|
// not sure for more robust method
|
|
IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, 0x10);
|
|
IoWrite8 (PCAT_RTC_DATA_REGISTER, 0x0);
|
|
IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, 0x11);
|
|
IoWrite8 (PCAT_RTC_DATA_REGISTER, 0x0);
|
|
// or may be
|
|
// IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, 0x17);
|
|
// IoWrite8 (PCAT_RTC_DATA_REGISTER, 0x17);
|
|
|
|
// }
|
|
}
|
|
// Attempt warm reboot
|
|
gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
|
|
// Warm reboot may not be supported attempt cold reboot
|
|
gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
|
|
// Terminate the screen and just exit
|
|
TerminateScreen();
|
|
MainLoopRunning = FALSE;
|
|
ReinitDesktop = FALSE;
|
|
AfterTool = TRUE;
|
|
}
|
|
|
|
if ( ChosenEntry->getREFIT_MENU_ITEM_SHUTDOWN() ) { // It is not Shut Down, it is Exit from Clover
|
|
TerminateScreen();
|
|
// gRT->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
|
|
MainLoopRunning = FALSE; // just in case we get this far
|
|
ReinitDesktop = FALSE;
|
|
AfterTool = TRUE;
|
|
}
|
|
if ( ChosenEntry->getREFIT_MENU_ITEM_OPTIONS() ) { // Options like KernelFlags, DSDTname etc.
|
|
gBootChanged = FALSE;
|
|
OptionsMenu(&OptionEntry);
|
|
if (gBootChanged)
|
|
AfterTool = TRUE;
|
|
if (gBootChanged || gThemeChanged) // If theme has changed reinit the desktop
|
|
MainLoopRunning = FALSE;
|
|
}
|
|
if ( ChosenEntry->getREFIT_MENU_ITEM_ABOUT() ) { // About rEFIt
|
|
AboutRefit();
|
|
}
|
|
|
|
/* -- not passed here
|
|
// case TAG_HELP:
|
|
HelpRefit();
|
|
break;
|
|
*/
|
|
if ( ChosenEntry->getLOADER_ENTRY() ) { // Boot OS via .EFI loader
|
|
SetBootCurrent(ChosenEntry->getLOADER_ENTRY());
|
|
StartLoader(ChosenEntry->getLOADER_ENTRY());
|
|
//if boot.efi failed we should somehow exit from the loop
|
|
TerminateScreen();
|
|
MainLoopRunning = FALSE;
|
|
ReinitDesktop = FALSE;
|
|
AfterTool = TRUE;
|
|
}
|
|
if ( ChosenEntry->getLEGACY_ENTRY() ) { // Boot legacy OS
|
|
if (StrCmp(gST->FirmwareVendor, L"Phoenix Technologies Ltd.") == 0 &&
|
|
gST->Hdr.Revision >> 16 == 2 && (gST->Hdr.Revision & ((1 << 16) - 1)) == 0){
|
|
// Phoenix SecureCore Tiano 2.0 can't properly initiate LegacyBios protocol when called externally
|
|
// which results in "Operating System not found" message coming from BIOS
|
|
// in this case just quit Clover to enter BIOS again
|
|
TerminateScreen();
|
|
MainLoopRunning = FALSE;
|
|
ReinitDesktop = FALSE;
|
|
AfterTool = TRUE;
|
|
} else {
|
|
SetBootCurrent(ChosenEntry->getLEGACY_ENTRY());
|
|
StartLegacy(ChosenEntry->getLEGACY_ENTRY());
|
|
}
|
|
}
|
|
|
|
if ( ChosenEntry->getREFIT_MENU_ENTRY_LOADER_TOOL() ) { // Start a EFI tool
|
|
StartTool(ChosenEntry->getREFIT_MENU_ENTRY_LOADER_TOOL());
|
|
TerminateScreen(); //does not happen
|
|
// return EFI_SUCCESS;
|
|
// BdsLibConnectAllDriversToAllControllers();
|
|
// PauseForKey(L"Returned from StartTool\n");
|
|
MainLoopRunning = FALSE;
|
|
AfterTool = TRUE;
|
|
}
|
|
|
|
#ifdef ENABLE_SECURE_BOOT
|
|
if ( ChosenEntry->getREFIT_MENU_ENTRY_SECURE_BOOT() ) { // Try to enable secure boot
|
|
EnableSecureBoot();
|
|
MainLoopRunning = FALSE;
|
|
AfterTool = TRUE;
|
|
}
|
|
|
|
if ( ChosenEntry->getREFIT_MENU_ENTRY_SECURE_BOOT_CONFIG() ) { // Configure secure boot
|
|
MainLoopRunning = !ConfigureSecureBoot();
|
|
AfterTool = TRUE;
|
|
}
|
|
#endif // ENABLE_SECURE_BOOT
|
|
|
|
if ( ChosenEntry->getREFIT_MENU_ENTRY_CLOVER() ) { // Clover options
|
|
REFIT_MENU_ENTRY_CLOVER* LoaderEntry = ChosenEntry->getREFIT_MENU_ENTRY_CLOVER();
|
|
if (LoaderEntry->LoadOptions != NULL) {
|
|
// we are uninstalling in case user selected Clover Options and EmuVar is installed
|
|
// because adding bios boot option requires access to real nvram
|
|
//Slice: sure?
|
|
/* if (gEmuVariableControl != NULL) {
|
|
gEmuVariableControl->UninstallEmulation(gEmuVariableControl);
|
|
}
|
|
*/
|
|
if (StrStr(LoaderEntry->LoadOptions, L"BO-ADD") != NULL) {
|
|
CHAR16 *Description;
|
|
CONST CHAR16 *VolName;
|
|
CONST CHAR16 *LoaderName;
|
|
INTN EntryIndex, NameSize, Name2Size;
|
|
LOADER_ENTRY *Entry;
|
|
UINT8 *OptionalData;
|
|
UINTN OptionalDataSize;
|
|
UINTN BootNum;
|
|
|
|
PrintBootOptions(FALSE);
|
|
|
|
for (EntryIndex = 0; EntryIndex < (INTN)MainMenu.Entries.size(); EntryIndex++) {
|
|
if (MainMenu.Entries[EntryIndex].Row != 0) {
|
|
continue;
|
|
}
|
|
if (!MainMenu.Entries[EntryIndex].getLOADER_ENTRY()) {
|
|
continue;
|
|
}
|
|
|
|
Entry = (LOADER_ENTRY *)MainMenu.Entries[EntryIndex].getLOADER_ENTRY();
|
|
VolName = Entry->Volume->VolName;
|
|
if (VolName == NULL) {
|
|
VolName = L"";
|
|
}
|
|
NameSize = StrSize(VolName); //can't use StrSize with NULL! Stupid UEFI!!!
|
|
Name2Size = 0;
|
|
if (Entry->LoaderPath != NULL) {
|
|
LoaderName = Basename(Entry->LoaderPath);
|
|
} else {
|
|
LoaderName = NULL; //legacy boot
|
|
}
|
|
if (LoaderName != NULL) {
|
|
Name2Size = StrSize(LoaderName);
|
|
}
|
|
|
|
Description = PoolPrint(L"Clover start %s at %s", (LoaderName != NULL)?LoaderName:L"legacy", VolName);
|
|
OptionalDataSize = NameSize + Name2Size + 4 + 2; //signature + VolNameSize
|
|
OptionalData = (__typeof__(OptionalData))AllocateZeroPool(OptionalDataSize);
|
|
if (OptionalData == NULL) {
|
|
break;
|
|
}
|
|
CopyMem(OptionalData, "Clvr", 4); //signature = 0x72766c43
|
|
CopyMem(OptionalData + 4, &NameSize, 2);
|
|
CopyMem(OptionalData + 6, VolName, NameSize);
|
|
if (Name2Size != 0) {
|
|
CopyMem(OptionalData + 6 + NameSize, LoaderName, Name2Size);
|
|
}
|
|
|
|
Status = AddBootOptionForFile (
|
|
LoaderEntry->Volume->DeviceHandle,
|
|
LoaderEntry->LoaderPath,
|
|
TRUE,
|
|
Description,
|
|
OptionalData,
|
|
OptionalDataSize,
|
|
EntryIndex,
|
|
(UINT16*)&BootNum
|
|
);
|
|
if (!EFI_ERROR(Status)) {
|
|
DBG("Entry %lld assigned option %04llX\n", EntryIndex, BootNum);
|
|
Entry->BootNum = BootNum;
|
|
}
|
|
FreePool(OptionalData);
|
|
FreePool(Description);
|
|
} //for (EntryIndex
|
|
|
|
|
|
PrintBootOptions(FALSE);
|
|
} else if (StrStr(LoaderEntry->LoadOptions, L"BO-REMOVE") != NULL) {
|
|
PrintBootOptions(FALSE);
|
|
Status = DeleteBootOptionForFile (LoaderEntry->Volume->DeviceHandle,
|
|
LoaderEntry->LoaderPath
|
|
);
|
|
PrintBootOptions(FALSE);
|
|
} else if (StrStr(LoaderEntry->LoadOptions, L"BO-PRINT") != NULL) {
|
|
PrintBootOptions(TRUE);
|
|
}
|
|
|
|
}
|
|
MainLoopRunning = FALSE;
|
|
AfterTool = TRUE;
|
|
}
|
|
} //MainLoopRunning
|
|
UninitRefitLib();
|
|
if (!AfterTool) {
|
|
// PauseForKey(L"After uninit");
|
|
//reconnectAll
|
|
if (!gFirmwareClover) {
|
|
BdsLibConnectAllEfi();
|
|
}
|
|
else {
|
|
DBG("ConnectAll after refresh menu\n");
|
|
BdsLibConnectAllDriversToAllControllers();
|
|
}
|
|
// ReinitRefitLib();
|
|
// PauseForKey(L"After ReinitRefitLib");
|
|
}
|
|
if (ReinitDesktop) {
|
|
DBG("ReinitSelfLib after theme change\n");
|
|
ReinitSelfLib();
|
|
}
|
|
// PauseForKey(L"After ReinitSelfLib");
|
|
} while (ReinitDesktop);
|
|
|
|
// If we end up here, things have gone wrong. Try to reboot, and if that
|
|
// fails, go into an endless loop.
|
|
//Slice - NO!!! Return to EFI GUI
|
|
// gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);
|
|
// EndlessIdleLoop();
|
|
|
|
#ifdef ENABLE_SECURE_BOOT
|
|
UninstallSecureBoot();
|
|
#endif // ENABLE_SECURE_BOOT
|
|
|
|
// Unload EmuVariable before returning to EFI GUI, as it should not be present when booting other Operating Systems.
|
|
// This seems critical in some UEFI implementations, such as Phoenix UEFI 2.0
|
|
if (gEmuVariableControl != NULL) {
|
|
gEmuVariableControl->UninstallEmulation(gEmuVariableControl);
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|