CloverBootloader/rEFIt_UEFI/refit/lib.cpp
jief 42cece9885 Fix nanosvg leaks.
Move global variable textfaces in XTheme.
Move global variable fontsDB in XTheme.
Remove XTheme member SVGParser. SVGParser is deleted just after use.
Remove XTheme members ImageSVG and ImageSVGnight. All images are
rasterized at load, so no need to keep that.
Remove XIcon setFilled because XIcon knows if it's filled or not by
checking Image & ImageNight
2023-11-08 14:35:22 +01:00

1628 lines
56 KiB
C++

/*
* refit/lib.c
* General library functions
*
* Copyright (c) 2006-2009 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.h> // Only use angled for Platform, else, xcode project won't compile
#include <Efi.h>
#include "../include/OSTypes.h"
#include "lib.h"
#include "screen.h"
#include "../Platform/BasicIO.h"
#include "../Platform/BootLog.h"
#include "../Platform/guid.h"
#include "../Platform/APFS.h"
#include "../refit/lib.h"
#include "../Platform/Settings.h"
#include "../Settings/Self.h"
#include "../Settings/SelfOem.h"
#include "../Platform/Volumes.h"
#include "../libeg/XTheme.h"
#include "../include/OC.h"
#ifndef DEBUG_ALL
#define DEBUG_LIB 1
#else
#define DEBUG_LIB DEBUG_ALL
#endif
#if DEBUG_LIB == 0
#define DBG(...)
#else
#define DBG(...) DebugLog(DEBUG_LIB, __VA_ARGS__)
#endif
// variables
//XStringW ThemePath;
//XBool gBootArgsChanged = false;
XBool gThemeOptionsChanged = false;
//
// Unicode collation protocol interface
//
EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;
// functions
static void UninitVolumes(void);
// S. Mtr
/* Function for parsing nodes from device path
* IN : DevicePath, sizeof(DevicePath)
* OUT: Size of cutted device path
* Description:
* Device path contains device nodes.
* From UEFI specification device node struct looks like:
*typedef struct {
* UINT8 Type; ///< 0x01 Hardware Device Path.
* ///< 0x02 ACPI Device Path.
* ///< 0x03 Messaging Device Path.
* ///< 0x04 Media Device Path.
* ///< 0x05 BIOS Boot Specification Device Path.
* ///< 0x7F End of Hardware Device Path.
*
* UINT8 SubType;///< Varies by Type
* ///< 0xFF End Entire Device Path, or
* ///< 0x01 End This Instance of a Device Path and start a new
* ///< Device Path.
*
* UINT8 Length[2]; ///< Specific Device Path data. Type and Sub-Type define
* ///< type of data. Size of data is included in Length.
*
* } EFI_DEVICE_PATH_PROTOCOL;
*/
UINTN
NodeParser (UINT8 *DevPath, UINTN PathSize, UINT8 Type)
{
UINTN i;
for (i=0; i<PathSize+1;){
if (DevPath[i] == Type)
{
//This type corresponds to Type
//So.. save position and exit from loop
PathSize = i;
break;
}
//Jump to the next device node type
i += (((UINT16)DevPath[i+3]<<8) | DevPath[i+2]);
}
return PathSize;
}
XBool MetaiMatch (
IN CONST CHAR16 *String,
IN CONST CHAR16 *Pattern
);
EFI_STATUS GetRootFromPath(IN EFI_DEVICE_PATH_PROTOCOL* DevicePath, OUT EFI_FILE **Root)
{
EFI_STATUS Status;
EFI_HANDLE NewHandle;
EFI_DEVICE_PATH_PROTOCOL* TmpDevicePath;
// DBG("Try to duplicate DevicePath\n");
TmpDevicePath = DuplicateDevicePath(DevicePath);
// DBG("TmpDevicePath found\n");
NewHandle = NULL;
Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid,
&TmpDevicePath,
&NewHandle);
// DBG("volume handle found =%X\n", NewHandle);
CheckError(Status, L"while reopening volume handle");
*Root = EfiLibOpenRoot(NewHandle);
if (*Root == NULL) {
// DBG("volume Root Dir can't be reopened\n");
return EFI_NOT_FOUND;
}
if (FileExists(*Root, L"mach_kernel")) {
DBG("mach_kernel exists\n");
} else {
DBG("mach_kernel not exists\n");
}
return Status;
}
//
// self recognition stuff
//
EFI_STATUS InitRefitLib(IN EFI_HANDLE ImageHandle)
{
self.initialize(ImageHandle);
DBG("SelfDirPath = %ls\n", self.getCloverDirFullPath().wc_str());
return EFI_SUCCESS;
}
void UninitRefitLib(void)
{
// called before running external programs to close open file handles
selfOem.closeHandle();
self.closeHandle();
closeDebugLog();
UninitVolumes();
}
EFI_STATUS ReinitRefitLib(void)
{
// called after reconnect drivers to re-open file handles
self.reInitialize();
selfOem.reInitialize();
ReinitVolumes();
return EFI_SUCCESS;
}
//
// firmware device path discovery
//
//looks like not used anywhere
static UINT8 LegacyLoaderMediaPathData[] = {
0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B,
0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B,
0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00,
};
static EFI_DEVICE_PATH *LegacyLoaderMediaPath = (EFI_DEVICE_PATH *)LegacyLoaderMediaPathData;
EFI_STATUS ExtractLegacyLoaderPaths(EFI_DEVICE_PATH **PathList, UINTN MaxPaths, EFI_DEVICE_PATH **HardcodedPathList)
{
EFI_STATUS Status;
UINTN HandleCount = 0;
UINTN HandleIndex, HardcodedIndex;
EFI_HANDLE *Handles = NULL;
EFI_HANDLE Handle;
UINTN PathCount = 0;
UINTN PathIndex;
EFI_LOADED_IMAGE *LoadedImage;
EFI_DEVICE_PATH *DevicePath;
XBool Seen;
MaxPaths--; // leave space for the terminating NULL pointer
// get all LoadedImage handles
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiLoadedImageProtocolGuid, NULL,
&HandleCount, &Handles);
if (CheckError(Status, L"while listing LoadedImage handles")) {
if (HardcodedPathList) {
for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++)
PathList[PathCount++] = HardcodedPathList[HardcodedIndex];
}
PathList[PathCount] = NULL;
return Status;
}
for (HandleIndex = 0; HandleIndex < HandleCount && PathCount < MaxPaths; HandleIndex++) {
Handle = Handles[HandleIndex];
Status = gBS->HandleProtocol(Handle, &gEfiLoadedImageProtocolGuid, (void **) &LoadedImage);
if (EFI_ERROR(Status))
continue; // This can only happen if the firmware scewed up, ignore it.
Status = gBS->HandleProtocol(LoadedImage->DeviceHandle, &gEfiDevicePathProtocolGuid, (void **) &DevicePath);
if (EFI_ERROR(Status))
continue; // This happens, ignore it.
// Only grab memory range nodes
if (DevicePathType(DevicePath) != HARDWARE_DEVICE_PATH || DevicePathSubType(DevicePath) != HW_MEMMAP_DP)
continue;
// Check if we have this device path in the list already
// WARNING: This assumes the first node in the device path is unique!
Seen = false;
for (PathIndex = 0; PathIndex < PathCount; PathIndex++) {
if (DevicePathNodeLength(DevicePath) != DevicePathNodeLength(PathList[PathIndex]))
continue;
if (CompareMem(DevicePath, PathList[PathIndex], DevicePathNodeLength(DevicePath)) == 0) {
Seen = true;
break;
}
}
if (Seen)
continue;
PathList[PathCount++] = AppendDevicePath(DevicePath, LegacyLoaderMediaPath);
}
FreePool(Handles);
if (HardcodedPathList) {
for (HardcodedIndex = 0; HardcodedPathList[HardcodedIndex] && PathCount < MaxPaths; HardcodedIndex++)
PathList[PathCount++] = HardcodedPathList[HardcodedIndex];
}
PathList[PathCount] = NULL;
return (PathCount > 0)?EFI_SUCCESS:EFI_NOT_FOUND;
}
//
// volume functions
//
static void ScanVolumeBootcode(IN OUT REFIT_VOLUME *Volume, OUT XBool *Bootable)
{
EFI_STATUS Status;
UINT8 *SectorBuffer;
UINTN i;
//MBR_PARTITION_INFO *MbrTable;
//XBool MbrTableFound;
UINTN BlockSize = 0;
CHAR16 volumeName[255];
CHAR8 tmp[64];
UINT32 VCrc32;
//CHAR16 *kind = NULL;
Volume->HasBootCode = false;
Volume->LegacyOS->IconName.setEmpty();
Volume->LegacyOS->Name.setEmpty();
// Volume->BootType = BOOTING_BY_MBR; //default value
Volume->BootType = BOOTING_BY_EFI;
*Bootable = false;
if ((Volume->BlockIO == NULL) || (!Volume->BlockIO->Media->MediaPresent))
return;
ZeroMem((CHAR8*)&tmp[0], 64);
BlockSize = Volume->BlockIO->Media->BlockSize;
if (BlockSize > 2048)
return; // our buffer is too small... the bred of thieve of cable
SectorBuffer = (__typeof__(SectorBuffer))AllocateAlignedPages(EFI_SIZE_TO_PAGES (2048), 16); //align to 16 byte?! Poher
ZeroMem((CHAR8*)&SectorBuffer[0], 2048);
// look at the boot sector (this is used for both hard disks and El Torito images!)
Status = Volume->BlockIO->ReadBlocks(Volume->BlockIO, Volume->BlockIO->Media->MediaId,
Volume->BlockIOOffset /*start lba*/,
2048, SectorBuffer);
if (!EFI_ERROR(Status) && (SectorBuffer[1] != 0)) {
// calc crc checksum of first 2 sectors - it's used later for legacy boot BIOS drive num detection
// note: possible future issues with AF 4K disks
*Bootable = true;
Volume->HasBootCode = true; //we assume that all CD are bootable
/* DBG("check SectorBuffer\n");
for (i=0; i<32; i++) {
DBG("%2hhX ", SectorBuffer[i]);
}
DBG("\n"); */
VCrc32 = GetCrc32(SectorBuffer, 512 * 2);
Volume->DriveCRC32 = VCrc32;
//gBS->CalculateCrc32 (SectorBuffer, 2 * 512, &Volume->DriveCRC32);
/* switch (Volume->DiskKind ) {
case DISK_KIND_OPTICAL:
kind = L"DVD";
break;
case DISK_KIND_INTERNAL:
kind = L"HDD";
break;
case DISK_KIND_EXTERNAL:
kind = L"USB";
break;
default:
break;
}
DBG("Volume kind=%ls CRC=0x%hhX\n", kind, VCrc32); */
if (Volume->DiskKind == DISK_KIND_OPTICAL) { //CDROM
CHAR8* p = (CHAR8*)&SectorBuffer[8];
while (*p == 0x20) {
p++;
}
for (i=0; i<30 && (*p >= 0x20) && (*p <= 'z'); i++, p++) {
tmp[i] = *p;
}
tmp[i] = 0;
while ((i>0) && (tmp[--i] == 0x20)) {}
tmp[i+1] = 0;
// if (*p != 0) {
AsciiStrToUnicodeStrS((CHAR8*)&tmp[0], volumeName, 255);
// }
DBG("Detected name %ls\n", volumeName);
Volume->VolName.takeValueFrom(volumeName);
for (i=8; i<2000; i++) { //vendor search
if (SectorBuffer[i] == 'A') {
if (AsciiStrStr((CHAR8*)&SectorBuffer[i], "APPLE")) {
// StrCpy(Volume->VolName, volumeName);
DBG(" Found AppleDVD\n");
Volume->LegacyOS->Type = OSTYPE_OSX;
Volume->BootType = BOOTING_BY_CD;
Volume->LegacyOS->IconName = L"mac"_XSW;
break;
}
} else if (SectorBuffer[i] == 'M') {
if (AsciiStrStr((CHAR8*)&SectorBuffer[i], "MICROSOFT")) {
// StrCpy(Volume->VolName, volumeName);
DBG(" Found Windows DVD\n");
Volume->LegacyOS->Type = OSTYPE_WIN;
Volume->BootType = BOOTING_BY_CD;
Volume->LegacyOS->IconName = L"win"_XSW;
break;
}
} else if (SectorBuffer[i] == 'L') {
if (AsciiStrStr((CHAR8*)&SectorBuffer[i], "LINUX")) {
// Volume->DevicePath = DuplicateDevicePath(DevicePath);
// StrCpy(Volume->VolName, volumeName);
DBG(" Found Linux DVD\n");
Volume->LegacyOS->Type = OSTYPE_LIN;
Volume->BootType = BOOTING_BY_CD;
Volume->LegacyOS->IconName = L"linux"_XSW;
break;
}
}
}
}
//else HDD
else { //HDD
/*
// apianti - does this detect every partition as legacy?
if (*((UINT16 *)(SectorBuffer + 510)) == 0xaa55 && SectorBuffer[0] != 0) {
*Bootable = true;
Volume->HasBootCode = true;
// DBG("The volume has bootcode\n");
Volume->LegacyOS->IconName = L"legacy";
Volume->LegacyOS->Name = L"Legacy";
Volume->LegacyOS->Type = OSTYPE_VAR;
Volume->BootType = BOOTING_BY_PBR;
}
// */
// detect specific boot codes
if (CompareMem(SectorBuffer + 2, "LILO", 4) == 0 ||
CompareMem(SectorBuffer + 6, "LILO", 4) == 0 ||
CompareMem(SectorBuffer + 3, "SYSLINUX", 8) == 0 ||
FindMem(SectorBuffer, 2048, "ISOLINUX", 8) >= 0) {
Volume->HasBootCode = true;
Volume->LegacyOS->IconName = L"linux"_XSW;
Volume->LegacyOS->Name = L"Linux"_XSW;
Volume->LegacyOS->Type = OSTYPE_LIN;
Volume->BootType = BOOTING_BY_PBR;
} else if (FindMem(SectorBuffer, 512, "Geom\0Hard Disk\0Read\0 Error", 26) >= 0) { // GRUB
Volume->HasBootCode = true;
Volume->LegacyOS->IconName = L"grub,linux"_XSW;
Volume->LegacyOS->Name = L"Linux"_XSW;
Volume->BootType = BOOTING_BY_PBR;
/*
} else if ((*((UINT32 *)(SectorBuffer)) == 0x4d0062e9 &&
*((UINT16 *)(SectorBuffer + 510)) == 0xaa55) ||
FindMem(SectorBuffer, 2048, "BOOT ", 10) >= 0) { //reboot Clover
Volume->HasBootCode = true;
Volume->LegacyOS->IconName = L"clover";
Volume->LegacyOS->Name = L"Clover";
Volume->LegacyOS->Type = OSTYPE_VAR;
Volume->BootType = BOOTING_BY_PBR;
// DBG("Detected Clover FAT32 bootcode\n");
*/
} else if ((*((UINT32 *)(SectorBuffer + 502)) == 0 &&
*((UINT32 *)(SectorBuffer + 506)) == 50000 &&
*((UINT16 *)(SectorBuffer + 510)) == 0xaa55) ||
FindMem(SectorBuffer, 2048, "Starting the BTX loader", 23) >= 0) {
Volume->HasBootCode = true;
Volume->LegacyOS->IconName = L"freebsd,linux"_XSW;
Volume->LegacyOS->Name = L"FreeBSD"_XSW;
Volume->LegacyOS->Type = OSTYPE_VAR;
Volume->BootType = BOOTING_BY_PBR;
} else if (FindMem(SectorBuffer, 512, "!Loading", 8) >= 0 ||
FindMem(SectorBuffer, 2048, "/cdboot\0/CDBOOT\0", 16) >= 0) {
Volume->HasBootCode = true;
Volume->LegacyOS->IconName = L"openbsd,linux"_XSW;
Volume->LegacyOS->Name = L"OpenBSD"_XSW;
Volume->LegacyOS->Type = OSTYPE_VAR;
Volume->BootType = BOOTING_BY_PBR;
} else if (FindMem(SectorBuffer, 512, "Not a bootxx image", 18) >= 0 ||
*((UINT32 *)(SectorBuffer + 1028)) == 0x7886b6d1) {
Volume->HasBootCode = true;
Volume->LegacyOS->IconName = L"netbsd,linux"_XSW;
Volume->LegacyOS->Name = L"NetBSD"_XSW;
Volume->LegacyOS->Type = OSTYPE_VAR;
Volume->BootType = BOOTING_BY_PBR;
} else if (FindMem(SectorBuffer, 2048, "NTLDR", 5) >= 0) {
Volume->HasBootCode = true;
Volume->LegacyOS->IconName = L"win"_XSW;
Volume->LegacyOS->Name = L"Windows"_XSW;
Volume->LegacyOS->Type = OSTYPE_WIN;
Volume->BootType = BOOTING_BY_PBR;
} else if (FindMem(SectorBuffer, 2048, "BOOTMGR", 7) >= 0) {
Volume->HasBootCode = true;
Volume->LegacyOS->IconName = L"vista,win"_XSW;
Volume->LegacyOS->Name = L"Windows"_XSW;
Volume->LegacyOS->Type = OSTYPE_WIN;
Volume->BootType = BOOTING_BY_PBR;
} else if (FindMem(SectorBuffer, 512, "CPUBOOT SYS", 11) >= 0 ||
FindMem(SectorBuffer, 512, "KERNEL SYS", 11) >= 0) {
Volume->HasBootCode = true;
Volume->LegacyOS->IconName = L"freedos,win"_XSW;
Volume->LegacyOS->Name = L"FreeDOS"_XSW;
Volume->LegacyOS->Type = OSTYPE_VAR;
Volume->BootType = BOOTING_BY_PBR;
} else if (FindMem(SectorBuffer, 512, "OS2LDR", 6) >= 0 ||
FindMem(SectorBuffer, 512, "OS2BOOT", 7) >= 0) {
Volume->HasBootCode = true;
Volume->LegacyOS->IconName = L"ecomstation"_XSW;
Volume->LegacyOS->Name = L"eComStation"_XSW;
Volume->LegacyOS->Type = OSTYPE_VAR;
Volume->BootType = BOOTING_BY_PBR;
} else if (FindMem(SectorBuffer, 512, "Be Boot Loader", 14) >= 0) {
Volume->HasBootCode = true;
Volume->LegacyOS->IconName = L"beos"_XSW;
Volume->LegacyOS->Name = L"BeOS"_XSW;
Volume->LegacyOS->Type = OSTYPE_VAR;
Volume->BootType = BOOTING_BY_PBR;
} else if (FindMem(SectorBuffer, 512, "yT Boot Loader", 14) >= 0) {
Volume->HasBootCode = true;
Volume->LegacyOS->IconName = L"zeta"_XSW;
Volume->LegacyOS->Name = L"ZETA"_XSW;
Volume->LegacyOS->Type = OSTYPE_VAR;
Volume->BootType = BOOTING_BY_PBR;
} else if (FindMem(SectorBuffer, 512, "\x04" "beos\x06" "system\x05" "zbeos", 18) >= 0 ||
FindMem(SectorBuffer, 512, "haiku_loader", 12) >= 0) {
Volume->HasBootCode = true;
Volume->LegacyOS->IconName = L"haiku"_XSW;
Volume->LegacyOS->Name = L"Haiku"_XSW;
Volume->LegacyOS->Type = OSTYPE_VAR;
Volume->BootType = BOOTING_BY_PBR;
}
}
// NOTE: If you add an operating system with a name that starts with 'W' or 'L', you
// need to fix AddLegacyEntry in main.c.
#if REFIT_DEBUG > 0
DBG(" Result of bootcode detection: %ls %ls (%ls)\n",
Volume->HasBootCode ? L"bootable" : L"non-bootable",
Volume->LegacyOS->Name.notEmpty() ? Volume->LegacyOS->Name.wc_str() : L"unknown",
Volume->LegacyOS->IconName.notEmpty() ? Volume->LegacyOS->IconName.wc_str() : L"legacy");
#endif
if (FindMem(SectorBuffer, 512, "Non-system disk", 15) >= 0) // dummy FAT boot sector
Volume->HasBootCode = false;
#ifdef JIEF_DEBUG
////*Bootable = true;
//Volume->HasBootCode = true;
//Volume->LegacyOS->IconName = L"win"_XSW;
//Volume->LegacyOS->Name = L"Windows"_XSW;
//Volume->LegacyOS->Type = OSTYPE_WIN;
//Volume->BootType = BOOTING_BY_PBR;
#endif
// check for MBR partition table
/*
// apianti - this is littered with bugs and probably not needed lol
if (*((UINT16 *)(SectorBuffer + 510)) == 0xaa55) {
MbrTableFound = false;
MbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446);
for (i = 0; i < 4; i++)
if (MbrTable[i].StartLBA && MbrTable[i].Size)
MbrTableFound = true;
for (i = 0; i < 4; i++)
if (MbrTable[i].Flags != 0x00 && MbrTable[i].Flags != 0x80)
MbrTableFound = false;
if (MbrTableFound) {
Volume->MbrPartitionTable = (__typeof__(Volume->MbrPartitionTable))AllocatePool(4 * 16);
CopyMem(Volume->MbrPartitionTable, MbrTable, 4 * 16);
Volume->BootType = BOOTING_BY_MBR;
}
}
// */
}
// gBS->FreePages((EFI_PHYSICAL_ADDRESS)(UINTN)SectorBuffer, 1);
// FreeAlignedPages((EFI_PHYSICAL_ADDRESS)(UINTN)SectorBuffer, 1);
FreeAlignedPages((void*)SectorBuffer, EFI_SIZE_TO_PAGES (2048));
}
//at start we have only Volume->DeviceHandle
static EFI_STATUS ScanVolume(IN OUT REFIT_VOLUME *Volume)
{
EFI_STATUS Status;
EFI_DEVICE_PATH *DevicePath, *NextDevicePath;
EFI_DEVICE_PATH *DiskDevicePath, *RemainingDevicePath = NULL;
HARDDRIVE_DEVICE_PATH *HdPath = NULL;
EFI_HANDLE WholeDiskHandle;
UINTN PartialLength = 0;
UINTN DevicePathSize;
// UINTN BufferSize = 255;
EFI_FILE_SYSTEM_INFO *FileSystemInfoPtr;
EFI_FILE_INFO *RootInfo = NULL;
XBool Bootable;
// EFI_INPUT_KEY Key;
// get device path
DiskDevicePath = DevicePathFromHandle(Volume->DeviceHandle);
//Volume->DevicePath = DuplicateDevicePath(DevicePathFromHandle(Volume->DeviceHandle));
DevicePathSize = GetDevicePathSize (DiskDevicePath);
Volume->DevicePath = (__typeof__(Volume->DevicePath))AllocateAlignedPages(EFI_SIZE_TO_PAGES(DevicePathSize), 64);
CopyMem(Volume->DevicePath, DiskDevicePath, DevicePathSize);
Volume->DevicePathString = FileDevicePathToXStringW(Volume->DevicePath);
#if REFIT_DEBUG > 0
if (Volume->DevicePath != NULL) {
DBG(" %ls\n", FileDevicePathToXStringW(Volume->DevicePath).wc_str());
//#if REFIT_DEBUG >= 2
// DumpHex(1, 0, GetDevicePathSize(Volume->DevicePath), Volume->DevicePath);
//#endif
}
#else
DBG("\n");
#endif
Volume->ApfsFileSystemUUID = APFSPartitionUUIDExtract(Volume->DevicePath); // NullXString8 if it's not an APFS volume
Volume->DiskKind = DISK_KIND_INTERNAL; // default
// get block i/o
Status = gBS->HandleProtocol(Volume->DeviceHandle, &gEfiBlockIoProtocolGuid, (void **) &(Volume->BlockIO));
if (EFI_ERROR(Status)) {
Volume->BlockIO = NULL;
// DBG(" Warning: Can't get BlockIO protocol.\n");
// WaitForSingleEvent (gST->ConIn->WaitForKey, 0);
// gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
return Status;
}
Bootable = false;
if (Volume->BlockIO->Media->BlockSize == 2048){
// DBG(" Found optical drive\n");
Volume->DiskKind = DISK_KIND_OPTICAL;
Volume->BlockIOOffset = 0x10; // offset already applied for FS but not for blockio
ScanVolumeBootcode(Volume, &Bootable);
} else {
// DBG(" Found HD drive\n");
Volume->BlockIOOffset = 0;
// scan for bootcode and MBR table
ScanVolumeBootcode(Volume, &Bootable);
// DBG(" ScanVolumeBootcode success\n");
// detect device type
DevicePath = DuplicateDevicePath(Volume->DevicePath);
while (DevicePath != NULL && !IsDevicePathEndType(DevicePath)) {
NextDevicePath = NextDevicePathNode(DevicePath);
if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
((DevicePathSubType (DevicePath) == MSG_SATA_DP) ||
(DevicePathSubType (DevicePath) == MSG_NVME_NAMESPACE_DP) ||
(DevicePathSubType (DevicePath) == MSG_ATAPI_DP))) {
// DBG(" HDD volume\n");
Volume->DiskKind = DISK_KIND_INTERNAL;
break;
}
if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH &&
(DevicePathSubType(DevicePath) == MSG_USB_DP || DevicePathSubType(DevicePath) == MSG_USB_CLASS_DP)) {
// DBG(" USB volume\n");
Volume->DiskKind = DISK_KIND_EXTERNAL;
// break;
}
// FIREWIRE Devices
if (DevicePathType(DevicePath) == MESSAGING_DEVICE_PATH &&
(DevicePathSubType(DevicePath) == MSG_1394_DP || DevicePathSubType(DevicePath) == MSG_FIBRECHANNEL_DP)) {
// DBG(" FireWire volume\n");
Volume->DiskKind = DISK_KIND_FIREWIRE;
break;
}
// CD-ROM Devices
if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH &&
DevicePathSubType(DevicePath) == MEDIA_CDROM_DP) {
// DBG(" CD-ROM volume\n");
Volume->DiskKind = DISK_KIND_OPTICAL; //it's impossible
break;
}
// VENDOR Specific Path
if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH &&
DevicePathSubType(DevicePath) == MEDIA_VENDOR_DP) {
// DBG(" Vendor volume\n");
if ( Volume->ApfsFileSystemUUID.isNull() ) {
Volume->DiskKind = DISK_KIND_NODISK; // Jief, don't know why DISK_KIND_NODISK in that case. That prevents Recovery badge to appear. If it's not APFS, let's do it like it was before.
}
break;
}
// LEGACY CD-ROM
if (DevicePathType(DevicePath) == BBS_DEVICE_PATH &&
(DevicePathSubType(DevicePath) == BBS_BBS_DP || DevicePathSubType(DevicePath) == BBS_TYPE_CDROM)) {
// DBG(" Legacy CD-ROM volume\n");
Volume->DiskKind = DISK_KIND_OPTICAL;
break;
}
// LEGACY HARDDISK
if (DevicePathType(DevicePath) == BBS_DEVICE_PATH &&
(DevicePathSubType(DevicePath) == BBS_BBS_DP || DevicePathSubType(DevicePath) == BBS_TYPE_HARDDRIVE)) {
// DBG(" Legacy HDD volume\n");
Volume->DiskKind = DISK_KIND_INTERNAL;
break;
}
//one more we must take into account
// subtype = MSG_NVME_NAMESPACE_DP
// diskKind = NVME
//#define MSG_NVME_NAMESPACE_DP 0x17
DevicePath = NextDevicePath;
}
/* what is the bread?
// Bootable = true;
if (DevicePathType(DevicePath) == MEDIA_DEVICE_PATH &&
DevicePathSubType(DevicePath) == MEDIA_VENDOR_DP) {
Volume->IsAppleLegacy = true; // legacy BIOS device entry
// TODO: also check for Boot Camp EFI_GUID
//gEfiPartTypeSystemPartGuid
Bootable = false; // this handle's BlockIO is just an alias for the whole device
DBG("AppleLegacy device\n");
}
*/
}
DevicePath = DuplicateDevicePath(Volume->DevicePath);
RemainingDevicePath = DevicePath; //initial value
//
// find the partition device path node
//
while (DevicePath && !IsDevicePathEnd (DevicePath)) {
if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
(DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {
HdPath = (HARDDRIVE_DEVICE_PATH *)DevicePath;
// break;
}
DevicePath = NextDevicePathNode (DevicePath);
}
// DBG("DevicePath scanned\n");
if (HdPath) {
// printf("Partition found %s\n", DevicePathToStr((EFI_DEVICE_PATH *)HdPath));
PartialLength = (UINTN)((UINT8 *)HdPath - (UINT8 *)(RemainingDevicePath));
if (PartialLength > 0x1000) {
PartialLength = sizeof(EFI_DEVICE_PATH); //something wrong here but I don't want to be freezed
// return EFI_SUCCESS;
}
DiskDevicePath = (EFI_DEVICE_PATH *)AllocatePool(PartialLength + sizeof(EFI_DEVICE_PATH));
CopyMem(DiskDevicePath, Volume->DevicePath, PartialLength);
CopyMem((UINT8 *)DiskDevicePath + PartialLength, DevicePath, sizeof(EFI_DEVICE_PATH)); //EndDevicePath
// DBG("WholeDevicePath %ls\n", DevicePathToStr(DiskDevicePath));
RemainingDevicePath = DiskDevicePath;
Status = gBS->LocateDevicePath(&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &WholeDiskHandle);
if (EFI_ERROR(Status)) {
DBG("Can't find WholeDevicePath: %s\n", efiStrError(Status));
} else {
Volume->WholeDiskDeviceHandle = WholeDiskHandle;
Volume->WholeDiskDevicePath = DuplicateDevicePath(RemainingDevicePath);
// look at the BlockIO protocol
Status = gBS->HandleProtocol(WholeDiskHandle, &gEfiBlockIoProtocolGuid, (void **) &Volume->WholeDiskBlockIO);
if (!EFI_ERROR(Status)) {
// DBG("WholeDiskBlockIO %hhX BlockSize=%d\n", Volume->WholeDiskBlockIO, Volume->WholeDiskBlockIO->Media->BlockSize);
// check the media block size
if (Volume->WholeDiskBlockIO->Media->BlockSize == 2048)
Volume->DiskKind = DISK_KIND_OPTICAL;
} else {
Volume->WholeDiskBlockIO = NULL;
// DBG("no WholeDiskBlockIO: %s\n", efiStrError(Status));
//CheckError(Status, L"from HandleProtocol");
}
}
FreePool(DiskDevicePath);
}
/* else {
DBG("HD path is not found\n"); //master volume!
}*/
// if (GlobalConfig.isFastBoot()) {
// return EFI_SUCCESS;
// }
if (!Bootable) {
#if REFIT_DEBUG > 0
if (Volume->HasBootCode){
DBG(" Volume considered non-bootable, but boot code is present\n");
// WaitForSingleEvent (gST->ConIn->WaitForKey, 0);
// gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
}
#endif
Volume->HasBootCode = false;
}
// open the root directory of the volume
Volume->RootDir = EfiLibOpenRoot(Volume->DeviceHandle);
// DBG("Volume->RootDir OK\n");
if (Volume->RootDir == NULL) {
//Print(L"Error: Can't open volume.\n");
// TODO: signal that we had an error
//Slice - there is LegacyBoot volume
//properties are set before
// DBG("LegacyBoot volume\n");
if (HdPath) {
Volume->VolName = SWPrintf("Legacy HD%d", HdPath->PartitionNumber);
} else if (Volume->VolName.isEmpty()) {
Volume->VolName = L"Whole Disc Boot"_XSW;
}
if (Volume->LegacyOS->IconName.isEmpty())
Volume->LegacyOS->IconName = L"legacy"_XSW;
return EFI_SUCCESS;
}
if ( Volume->ApfsFileSystemUUID.notNull() ) {
APPLE_APFS_CONTAINER_INFO *ApfsContainerInfo;
APPLE_APFS_VOLUME_INFO *ApfsVolumeInfo;
Status = InternalGetApfsSpecialFileInfo(Volume->RootDir, &ApfsVolumeInfo, &ApfsContainerInfo);
if ( !EFI_ERROR(Status) ) {
//DBG("Status : %s, APFS role : %x\n", efiStrError(Status), ApfsVolumeInfo->Role);
Volume->ApfsRole = ApfsVolumeInfo->Role;
Volume->ApfsContainerUUID = ApfsContainerInfo->Uuid;
}else{
MsgLog("Status : %s, APFS role : %x\n", efiStrError(Status), ApfsVolumeInfo->Role);
}
}
if ( Volume->ApfsFileSystemUUID.notNull() ) {
DBG(" apfsFileSystemUUID=%s, ApfsContainerUUID=%s, ApfsRole=0x%x\n", Volume->ApfsFileSystemUUID.toXString8().c_str(), Volume->ApfsContainerUUID.toXString8().c_str(), Volume->ApfsRole);
}
if ( FileExists(Volume->RootDir, L"\\.VolumeLabel.txt") ) {
EFI_FILE* FileHandle;
Status = Volume->RootDir->Open(Volume->RootDir, &FileHandle, L"\\.VolumeLabel.txt", EFI_FILE_MODE_READ, 0);
if (!EFI_ERROR(Status)) {
CHAR8 Buffer[32+1];
UINTN BufferSize = sizeof(Buffer)-sizeof(CHAR8);
SetMem(Buffer, BufferSize+sizeof(CHAR8), 0);
Status = FileHandle->Read(FileHandle, &BufferSize, Buffer);
FileHandle->Close(FileHandle);
if (!EFI_ERROR(Status)) {
// strip line endings
while (BufferSize > 0 && (Buffer[BufferSize-1]=='\n' || Buffer[BufferSize-1]=='\r')) {
Buffer[--BufferSize]='\0';
}
Volume->VolLabel = SWPrintf("%s", Buffer);
}
}
}
// get volume name
if (Volume->VolName.isEmpty()) {
FileSystemInfoPtr = EfiLibFileSystemInfo(Volume->RootDir);
if (FileSystemInfoPtr) {
//DBG(" Volume name from FileSystem: '%ls'\n", FileSystemInfoPtr->VolumeLabel);
Volume->VolName.takeValueFrom(FileSystemInfoPtr->VolumeLabel);
FreePool(FileSystemInfoPtr);
}
}
if (Volume->VolName.isEmpty()) {
Volume->VolName = EfiLibFileSystemVolumeLabelInfo(Volume->RootDir);
//DBG(" Volume name from VolumeLabel: '%ls'\n", Volume->VolName.wc_str());
}
if (Volume->VolName.isEmpty()) {
RootInfo = EfiLibFileInfo (Volume->RootDir);
if (RootInfo) {
//DBG(" Volume name from RootFile: '%ls'\n", RootInfo->FileName);
Volume->VolName.takeValueFrom(RootInfo->FileName);
FreePool(RootInfo);
}
}
if ( Volume->VolName.isEmpty() || Volume->VolName.isEqual("\\") || Volume->VolName.isEqual(L"/") )
{
void *Instance;
if (!EFI_ERROR(gBS->HandleProtocol(Volume->DeviceHandle, &gEfiPartTypeSystemPartGuid, &Instance))) {
Volume->VolName = L"EFI"_XSW;
}
}
if (Volume->VolName.isEmpty()) {
// DBG("Create unknown name\n");
// WaitForSingleEvent (gST->ConIn->WaitForKey, 0);
// gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
if (HdPath) {
Volume->VolName.SWPrintf( "Unknown HD%d", HdPath->PartitionNumber);
// NOTE: this is normal for Apple's VenMedia device paths
} else {
Volume->VolName = L"Unknown HD"_XSW; //To be able to free it
}
}
// Browse all folders under root that looks like an UUID
if ( Volume->ApfsFileSystemUUID.notNull() )
{
REFIT_DIR_ITER DirIter;
EFI_FILE_INFO *DirEntry = NULL;
DirIterOpen(Volume->RootDir, L"\\", &DirIter);
while (DirIterNext(&DirIter, 1, L"*", &DirEntry)) {
if (DirEntry->FileName[0] == '.') {
//DBG("Skip dot entries: %ls\n", DirEntry->FileName);
continue;
}
if ( EFI_GUID::IsValidGuidString(LStringW(DirEntry->FileName)) ) {
EFI_GUID* guid_ptr = new EFI_GUID;
guid_ptr->takeValueFrom(DirEntry->FileName, wcslen(DirEntry->FileName));
if ( guid_ptr->notNull() ) Volume->ApfsTargetUUIDArray.AddReference(guid_ptr, true);
else delete guid_ptr;
}
}
DirIterClose(&DirIter);
}
DBG(" label : %ls\n", Volume->getVolLabelOrOSXVolumeNameOrVolName().wc_str());
//Status = GetOSVersion(Volume); NOTE: Sothor - We will find icon names later once we have found boot.efi on the volume //here we set Volume->IconName (tiger,leo,snow,lion,cougar, etc)
return EFI_SUCCESS;
}
static void ScanExtendedPartition(REFIT_VOLUME *WholeDiskVolume, MBR_PARTITION_INFO *MbrEntry)
{
EFI_STATUS Status;
REFIT_VOLUME *Volume;
UINT32 ExtBase, ExtCurrent, NextExtCurrent;
UINTN i;
UINTN LogicalPartitionIndex = 4;
UINT8 *SectorBuffer;
XBool Bootable;
MBR_PARTITION_INFO *EMbrTable;
ExtBase = MbrEntry->StartLBA;
SectorBuffer = (__typeof__(SectorBuffer))AllocateAlignedPages (EFI_SIZE_TO_PAGES (512), WholeDiskVolume->BlockIO->Media->IoAlign);
for (ExtCurrent = ExtBase; ExtCurrent; ExtCurrent = NextExtCurrent) {
// read current EMBR
Status = WholeDiskVolume->BlockIO->ReadBlocks(WholeDiskVolume->BlockIO,
WholeDiskVolume->BlockIO->Media->MediaId,
ExtCurrent, 512, SectorBuffer);
if (EFI_ERROR(Status))
break;
if (*((UINT16 *)(SectorBuffer + 510)) != 0xaa55)
break;
EMbrTable = (MBR_PARTITION_INFO *)(SectorBuffer + 446);
// scan logical partitions in this EMBR
NextExtCurrent = 0;
for (i = 0; i < 4; i++) {
if ((EMbrTable[i].Flags != 0x00 && EMbrTable[i].Flags != 0x80) ||
EMbrTable[i].StartLBA == 0 || EMbrTable[i].Size == 0)
break;
if (IS_EXTENDED_PART_TYPE(EMbrTable[i].Type)) {
// set next ExtCurrent
NextExtCurrent = ExtBase + EMbrTable[i].StartLBA;
break;
} else {
// found a logical partition
Volume = new REFIT_VOLUME;
Volume->DiskKind = WholeDiskVolume->DiskKind;
Volume->IsMbrPartition = true;
Volume->MbrPartitionIndex = LogicalPartitionIndex++;
Volume->VolName = SWPrintf("Partition %llu", Volume->MbrPartitionIndex + 1);
Volume->BlockIO = WholeDiskVolume->BlockIO;
Volume->BlockIOOffset = ExtCurrent + EMbrTable[i].StartLBA;
Volume->WholeDiskBlockIO = WholeDiskVolume->BlockIO;
Volume->WholeDiskDeviceHandle = WholeDiskVolume->DeviceHandle;
Bootable = false;
ScanVolumeBootcode(Volume, &Bootable);
if (!Bootable)
Volume->HasBootCode = false;
Volumes.AddReference(Volume, false);
// AddListElement((void ***) &Volumes, &VolumesCount, Volume);
}
}
}
gBS->FreePages((EFI_PHYSICAL_ADDRESS)(UINTN)SectorBuffer, 1);
}
void ScanVolumes(void)
{
EFI_STATUS Status;
UINTN HandleCount = 0;
// UINTN HandleIndex;
EFI_HANDLE *Handles = NULL;
REFIT_VOLUME *WholeDiskVolume;
UINTN VolumeIndex, VolumeIndex2;
MBR_PARTITION_INFO *MbrTable;
UINTN PartitionIndex;
UINT8 *SectorBuffer1, *SectorBuffer2;
UINTN SectorSum, i;
// EFI_DEVICE_PATH_PROTOCOL *VolumeDevicePath;
// EFI_GUID *Guid; //for debug only
// EFI_INPUT_KEY Key;
// DBG("Scanning volumes...\n");
DbgHeader("ScanVolumes");
// get all BlockIo handles
Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &HandleCount, &Handles);
if (Status == EFI_NOT_FOUND)
return;
DBG("Found %llu volumes with blockIO\n", HandleCount);
// first pass: collect information about all handles
for (UINTN HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
REFIT_VOLUME* Volume = new REFIT_VOLUME;
Volume->LegacyOS = new LEGACY_OS;
Volume->DeviceHandle = Handles[HandleIndex];
if (Volume->DeviceHandle == self.getSelfDeviceHandle()) {
SelfVolume = Volume;
}
DBG("- [%02llu]: Volume:", HandleIndex);
Volume->Hidden = false; // default to not hidden
Status = ScanVolume(Volume);
if (!EFI_ERROR(Status)) {
Volume->Index = HandleIndex;
Volumes.AddReference(Volume, false);
for (size_t HVi = 0; HVi < gSettings.GUI.HVHideStrings.size(); HVi++) {
if ( Volume->DevicePathString.containsIC(gSettings.GUI.HVHideStrings[HVi]) ||
Volume->VolName.containsIC(gSettings.GUI.HVHideStrings[HVi])
) {
Volume->Hidden = true;
DBG(" hiding this volume\n");
}
}
// Guid = FindGPTPartitionGuidInDevicePath(Volume->DevicePath);
if (Volume->LegacyOS->IconName.isEmpty()) {
Volume->LegacyOS->IconName = L"legacy"_XSW;
}
// DBG(" Volume '%ls', LegacyOS '%ls', LegacyIcon(s) '%ls', EFI_GUID = %s\n",
// Volume->VolName, Volume->LegacyOS->Name ? Volume->LegacyOS->Name : L"", Volume->LegacyOS->IconName, Guid.toXString8().c_str());
if (SelfVolume == Volume) {
DBG(" This is SelfVolume !!\n");
}
} else {
DBG(" wrong volume Nr%llu?!\n", HandleIndex);
FreePool(Volume);
}
}
FreePool(Handles);
// DBG("Found %d volumes\n", VolumesCount);
if (SelfVolume == NULL){
DBG(" WARNING: SelfVolume not found"); //Slice - and what?
SelfVolume = new REFIT_VOLUME;
SelfVolume->DeviceHandle = self.getSelfDeviceHandle();
SelfVolume->DevicePath = DuplicateDevicePath(&self.getSelfDevicePath());
SelfVolume->RootDir = const_cast<EFI_FILE*>(&self.getSelfVolumeRootDir()); // TODO : SelfVolume->RootDir should be const ! we should duplicate ?
SelfVolume->DiskKind = DISK_KIND_BOOTER;
SelfVolume->VolName = L"Clover"_XSW;
SelfVolume->LegacyOS->Type = OSTYPE_EFI;
SelfVolume->HasBootCode = true;
SelfVolume->BootType = BOOTING_BY_PBR;
// AddListElement((void ***) &Volumes, &VolumesCount, SelfVolume);
// DBG("SelfVolume Nr %d created\n", VolumesCount);
}
// second pass: relate partitions and whole disk devices
for (VolumeIndex = 0; VolumeIndex < Volumes.size(); VolumeIndex++) {
REFIT_VOLUME* Volume = &Volumes[VolumeIndex];
// check MBR partition table for extended partitions
if (Volume->BlockIO != NULL && Volume->WholeDiskBlockIO != NULL &&
Volume->BlockIO == Volume->WholeDiskBlockIO && Volume->BlockIOOffset == 0 &&
Volume->MbrPartitionTable != NULL) {
DBG(" Volume %llu has MBR\n", VolumeIndex);
MbrTable = Volume->MbrPartitionTable;
for (PartitionIndex = 0; PartitionIndex < 4; PartitionIndex++) {
if (IS_EXTENDED_PART_TYPE(MbrTable[PartitionIndex].Type)) {
ScanExtendedPartition(Volume, MbrTable + PartitionIndex);
}
}
}
// search for corresponding whole disk volume entry
WholeDiskVolume = NULL;
if (Volume->BlockIO != NULL && Volume->WholeDiskBlockIO != NULL &&
Volume->BlockIO != Volume->WholeDiskBlockIO) {
for (VolumeIndex2 = 0; VolumeIndex2 < Volumes.size(); VolumeIndex2++) {
if (Volumes[VolumeIndex2].BlockIO == Volume->WholeDiskBlockIO &&
Volumes[VolumeIndex2].BlockIOOffset == 0)
WholeDiskVolume = &Volumes[VolumeIndex2];
}
}
if (WholeDiskVolume != NULL && WholeDiskVolume->MbrPartitionTable != NULL) {
// check if this volume is one of the partitions in the table
MbrTable = WholeDiskVolume->MbrPartitionTable;
SectorBuffer1 = (__typeof__(SectorBuffer1))AllocateAlignedPages (EFI_SIZE_TO_PAGES (512), 16);
SectorBuffer2 = (__typeof__(SectorBuffer2))AllocateAlignedPages (EFI_SIZE_TO_PAGES (512), 16);
for (PartitionIndex = 0; PartitionIndex < 4; PartitionIndex++) {
// check size
if ((UINT64)(MbrTable[PartitionIndex].Size) != Volume->BlockIO->Media->LastBlock + 1)
continue;
// compare boot sector read through offset vs. directly
Status = Volume->BlockIO->ReadBlocks(Volume->BlockIO, Volume->BlockIO->Media->MediaId,
Volume->BlockIOOffset, 512, SectorBuffer1);
if (EFI_ERROR(Status))
break;
Status = Volume->WholeDiskBlockIO->ReadBlocks(Volume->WholeDiskBlockIO, Volume->WholeDiskBlockIO->Media->MediaId,
MbrTable[PartitionIndex].StartLBA, 512, SectorBuffer2);
if (EFI_ERROR(Status))
break;
if (CompareMem(SectorBuffer1, SectorBuffer2, 512) != 0)
continue;
SectorSum = 0;
for (i = 0; i < 512; i++)
SectorSum += SectorBuffer1[i];
if (SectorSum < 1000)
continue;
// TODO: mark entry as non-bootable if it is an extended partition
// now we're reasonably sure the association is correct...
Volume->IsMbrPartition = true;
Volume->MbrPartitionTable = MbrTable;
Volume->MbrPartitionIndex = PartitionIndex;
if (Volume->VolName.isEmpty())
Volume->VolName = SWPrintf("Partition %llu", PartitionIndex + 1);
break;
}
gBS->FreePages((EFI_PHYSICAL_ADDRESS)(UINTN)SectorBuffer1, 1);
gBS->FreePages((EFI_PHYSICAL_ADDRESS)(UINTN)SectorBuffer2, 1);
}
}
}
static void UninitVolumes(void)
{
REFIT_VOLUME *Volume;
UINTN VolumeIndex;
for (VolumeIndex = 0; VolumeIndex < Volumes.size(); VolumeIndex++) {
Volume = &Volumes[VolumeIndex];
if (Volume->RootDir != NULL) {
Volume->RootDir->Close(Volume->RootDir);
Volume->RootDir = NULL;
}
Volume->DeviceHandle = NULL;
Volume->BlockIO = NULL;
Volume->WholeDiskBlockIO = NULL;
Volume->WholeDiskDeviceHandle = NULL;
FreePool(Volume);
}
Volumes.setEmpty();
}
void ReinitVolumes(void)
{
EFI_STATUS Status;
REFIT_VOLUME *Volume;
UINTN VolumeIndex;
//UINTN VolumesFound = 0; // Jief not sure what this is, see my comment at the end of this function
const EFI_DEVICE_PATH *RemainingDevicePath;
EFI_HANDLE DeviceHandle, WholeDiskHandle;
for (VolumeIndex = 0; VolumeIndex < Volumes.size(); VolumeIndex++) {
Volume = &Volumes[VolumeIndex];
if (!Volume) {
continue;
}
DBG("Volume %llu at reinit found:\n", VolumeIndex);
DBG("Volume->DevicePath=%ls\n", FileDevicePathToXStringW(Volume->DevicePath).wc_str());
//olumesFound++;
if (Volume->DevicePath != NULL) {
// get the handle for that path
RemainingDevicePath = Volume->DevicePath;
Status = gBS->LocateDevicePath(&gEfiBlockIoProtocolGuid, const_cast<EFI_DEVICE_PATH**>(&RemainingDevicePath), &DeviceHandle);
if (!EFI_ERROR(Status)) {
Volume->DeviceHandle = DeviceHandle;
// get the root directory
Volume->RootDir = EfiLibOpenRoot(Volume->DeviceHandle);
}
//else
// CheckError(Status, L"from LocateDevicePath");
}
if (Volume->WholeDiskDevicePath != NULL) {
// get the handle for that path
RemainingDevicePath = DuplicateDevicePath(Volume->WholeDiskDevicePath);
Status = gBS->LocateDevicePath(&gEfiBlockIoProtocolGuid, const_cast<EFI_DEVICE_PATH**>(&RemainingDevicePath), &WholeDiskHandle);
if (!EFI_ERROR(Status)) {
Volume->WholeDiskBlockIO = (__typeof__(Volume->WholeDiskBlockIO))WholeDiskHandle;
// get the BlockIO protocol
Status = gBS->HandleProtocol(WholeDiskHandle, &gEfiBlockIoProtocolGuid, (void **) &Volume->WholeDiskBlockIO);
if (EFI_ERROR(Status)) {
Volume->WholeDiskBlockIO = NULL;
CheckError(Status, L"from HandleProtocol");
}
}
//else
// CheckError(Status, L"from LocateDevicePath");
}
}
// Jief : I'm not sure to understand the next line. Why would we change the count when we didn't change the array.
// This code is not currently not used.
// Beware if you want to reuse this.
// VolumesCount = VolumesFound;
}
REFIT_VOLUME *FindVolumeByName(IN CONST CHAR16 *VolName)
{
REFIT_VOLUME *Volume;
UINTN VolumeIndex;
if (!VolName) {
return NULL;
}
for (VolumeIndex = 0; VolumeIndex < Volumes.size(); VolumeIndex++) {
Volume = &Volumes[VolumeIndex];
if (!Volume) {
continue;
}
if (Volume->VolName.isEqual(VolName) == 0) {
return Volume;
}
}
return NULL;
}
//
// file and dir functions
//
XBool FileExists(IN CONST EFI_FILE *Root, IN CONST CHAR16 *RelativePath)
{
EFI_STATUS Status;
EFI_FILE *TestFile = NULL;
Status = Root->Open(Root, &TestFile, RelativePath, EFI_FILE_MODE_READ, 0);
if (Status == EFI_SUCCESS) {
if (TestFile && TestFile->Close) {
TestFile->Close(TestFile);
}
return true;
}
return false;
}
XBool FileExists(const EFI_FILE *Root, const XStringW& RelativePath)
{
return FileExists(Root, RelativePath.wc_str());
}
XBool FileExists(const EFI_FILE& Root, const XStringW& RelativePath)
{
return FileExists(&Root, RelativePath.wc_str());
}
EFI_DEVICE_PATH_PROTOCOL* FileDevicePath(IN EFI_HANDLE Device, IN CONST XStringW& FileName)
{
return FileDevicePath(Device, FileName.wc_str());
}
XBool DeleteFile(const EFI_FILE *Root, IN CONST CHAR16 *RelativePath)
{
EFI_STATUS Status;
EFI_FILE *File;
EFI_FILE_INFO *FileInfo;
//DBG("DeleteFile: %ls\n", RelativePath);
// open file for read/write to see if it exists, need write for delete
Status = Root->Open(Root, &File, RelativePath, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE, 0);
//DBG(" Open: %s\n", efiStrError(Status));
if (Status == EFI_SUCCESS) {
// exists - check if it is a file
FileInfo = EfiLibFileInfo(File);
if (FileInfo == NULL) {
// error
//DBG(" FileInfo is NULL\n");
File->Close(File);
return false;
}
//DBG(" FileInfo attr: %hhX\n", FileInfo->Attribute);
if ((FileInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) {
// it's directory - return error
//DBG(" File is DIR\n");
FreePool(FileInfo);
File->Close(File);
return false;
}
FreePool(FileInfo);
// it's a file - delete it
//DBG(" File is file\n");
Status = File->Delete(File);
//DBG(" Delete: %s\n", efiStrError(Status));
return Status == EFI_SUCCESS;
}
return false;
}
EFI_STATUS DirNextEntry(const EFI_FILE *Directory, IN OUT EFI_FILE_INFO **DirEntry, IN UINTN FilterMode)
{
EFI_STATUS Status;
void *Buffer;
UINTN LastBufferSize, BufferSize;
INTN IterCount;
for (;;) {
// free pointer from last call
if (*DirEntry != NULL) {
FreePool(*DirEntry);
*DirEntry = NULL;
}
// read next directory entry
LastBufferSize = BufferSize = 256;
Buffer = (__typeof__(Buffer))AllocateZeroPool(BufferSize);
for (IterCount = 0; ; IterCount++) {
Status = Directory->Read(Directory, &BufferSize, Buffer);
if (Status != EFI_BUFFER_TOO_SMALL || IterCount >= 4)
break;
if (BufferSize <= LastBufferSize) {
DBG("FS Driver requests bad buffer size %llu (was %llu), using %llu instead\n", BufferSize, LastBufferSize, LastBufferSize * 2);
BufferSize = LastBufferSize * 2;
#if REFIT_DEBUG > 0
} else {
DBG("Reallocating buffer from %llu to %llu\n", LastBufferSize, BufferSize);
#endif
}
Buffer = (__typeof__(Buffer))EfiReallocatePool(Buffer, LastBufferSize, BufferSize);
LastBufferSize = BufferSize;
}
if (EFI_ERROR(Status)) {
FreePool(Buffer);
break;
}
// check for end of listing
if (BufferSize == 0) { // end of directory listing
FreePool(Buffer);
break;
}
// entry is ready to be returned
*DirEntry = (EFI_FILE_INFO *)Buffer;
if (*DirEntry) {
// filter results
if (FilterMode == 1) { // only return directories
if (((*DirEntry)->Attribute & EFI_FILE_DIRECTORY))
break;
} else if (FilterMode == 2) { // only return files
if (((*DirEntry)->Attribute & EFI_FILE_DIRECTORY) == 0)
break;
} else // no filter or unknown filter -> return everything
break;
}
}
return Status;
}
void DirIterOpen(const EFI_FILE *BaseDir, IN CONST CHAR16 *RelativePath OPTIONAL, OUT REFIT_DIR_ITER *DirIter)
{
if (RelativePath == NULL) {
DirIter->LastStatus = EFI_SUCCESS;
DirIter->DirHandle = BaseDir;
DirIter->CloseDirHandle = false;
} else {
DirIter->LastStatus = BaseDir->Open(BaseDir, const_cast<EFI_FILE**>(&(DirIter->DirHandle)), RelativePath, EFI_FILE_MODE_READ, 0);
DirIter->CloseDirHandle = EFI_ERROR(DirIter->LastStatus) ? false : true;
}
DirIter->LastFileInfo = NULL;
}
XBool DirIterNext(IN OUT REFIT_DIR_ITER *DirIter, IN UINTN FilterMode, IN CONST CHAR16 *FilePattern OPTIONAL,
OUT EFI_FILE_INFO **DirEntry)
{
if (DirIter->LastFileInfo != NULL) {
FreePool(DirIter->LastFileInfo);
DirIter->LastFileInfo = NULL;
}
if (EFI_ERROR(DirIter->LastStatus))
return false; // stop iteration
for (;;) {
DirIter->LastStatus = DirNextEntry(DirIter->DirHandle, &(DirIter->LastFileInfo), FilterMode);
if (EFI_ERROR(DirIter->LastStatus))
return false;
if (DirIter->LastFileInfo == NULL) // end of listing
return false;
if (FilePattern != NULL) {
if ((DirIter->LastFileInfo->Attribute & EFI_FILE_DIRECTORY))
break;
if (MetaiMatch(DirIter->LastFileInfo->FileName, FilePattern))
break;
// else continue loop
} else
break;
}
*DirEntry = DirIter->LastFileInfo;
return true;
}
EFI_STATUS DirIterClose(IN OUT REFIT_DIR_ITER *DirIter)
{
if (DirIter->LastFileInfo != NULL) {
FreePool(DirIter->LastFileInfo);
DirIter->LastFileInfo = NULL;
}
if (DirIter->CloseDirHandle)
DirIter->DirHandle->Close(DirIter->DirHandle);
return DirIter->LastStatus;
}
//
// file name manipulation
//
XBool
MetaiMatch (
IN CONST CHAR16 *String,
IN CONST CHAR16 *Pattern
)
{
if (!mUnicodeCollation) {
// quick fix for driver loading on UEFIs without UnicodeCollation
//return false;
return true; //this is wrong anyway
}
return mUnicodeCollation->MetaiMatch (mUnicodeCollation, String, Pattern) == TRUE;
}
EFI_STATUS
InitializeUnicodeCollationProtocol (void)
{
EFI_STATUS Status;
if (mUnicodeCollation != NULL) {
return EFI_SUCCESS;
}
//
// BUGBUG: Proper implementation is to locate all Unicode Collation Protocol
// instances first and then select one which support English language.
// Current implementation just pick the first instance.
//
Status = gBS->LocateProtocol (
gEfiUnicodeCollation2ProtocolGuid,
NULL,
(void **) &mUnicodeCollation
);
if (EFI_ERROR(Status)) {
Status = gBS->LocateProtocol (
gEfiUnicodeCollationProtocolGuid,
NULL,
(void **) &mUnicodeCollation
);
}
return Status;
}
CONST CHAR16 * Basename(IN CONST CHAR16 *Path)
{
CONST CHAR16 *FileName;
UINTN i;
FileName = Path;
if (Path != NULL) {
for (i = StrLen(Path); i > 0; i--) {
if (Path[i-1] == '\\' || Path[i-1] == '/') {
FileName = Path + i;
break;
}
}
}
return FileName;
}
void ReplaceExtension(IN OUT CHAR16 *Path, IN CHAR16 *Extension)
{
INTN i;
for (i = StrLen(Path); i >= 0; i--) {
if (Path[i] == '.') {
Path[i] = 0;
break;
}
if (Path[i] == '\\' || Path[i] == '/')
break;
}
StrCatS(Path, StrLen(Path)/sizeof(CHAR16)+1, Extension);
}
CHAR16 * egFindExtension(IN CHAR16 *FileName)
{
INTN i;
for (i = StrLen(FileName); i >= 0; i--) {
if (FileName[i] == '.')
return FileName + i + 1;
if (FileName[i] == '/' || FileName[i] == '\\')
break;
}
return FileName + StrLen(FileName);
}
//
// memory string search
//
INTN FindMem(IN CONST void *Buffer, IN UINTN BufferLength, IN CONST void *SearchString, IN UINTN SearchStringLength)
{
CONST UINT8 *BufferPtr;
UINTN Offset;
BufferPtr = (CONST UINT8 *)Buffer;
BufferLength -= SearchStringLength;
for (Offset = 0; Offset < BufferLength; Offset++, BufferPtr++) {
if (CompareMem(BufferPtr, SearchString, SearchStringLength) == 0)
return (INTN)Offset;
}
return -1;
}
/**
This function converts an input device structure to a Unicode string.
@param DevPath A pointer to the device path structure.
@return A new allocated Unicode string that represents the device path.
**/
XStringW DevicePathToXStringW (
const EFI_DEVICE_PATH_PROTOCOL *DevPath
)
{
CHAR16* DevicePathStr = ConvertDevicePathToText (DevPath, true, true);
XStringW returnValue;
returnValue.stealValueFrom(DevicePathStr); // do not FreePool FilePath, it's now owned by returnValue
return returnValue;
}
//
// Aptio UEFI returns File DevPath as 2 nodes (dir, file)
// and DevicePathToStr connects them with /, but we need '\\'
XStringW FileDevicePathToXStringW(const EFI_DEVICE_PATH_PROTOCOL *DevPath)
{
CHAR16 *FilePath;
CHAR16 *Char;
CONST CHAR16 *Tail;
FilePath = ConvertDevicePathToText(DevPath, true, true);
// fix / into '\\'
if (FilePath != NULL) {
for (Char = FilePath; *Char != L'\0'; Char++) {
if (*Char == L'/') {
*Char = L'\\';
}
}
}
// "\\\\" into '\\'
Char = (CHAR16*)StrStr(FilePath, L"\\\\"); // cast is ok because FilePath is not const, and we know that StrStr returns a pointer in FilePath. Will disappear when using a string object instead of CHAR16*
while (Char != NULL) {
// StrCpyS(Char, 4, Char + 1); //can't overlap
Tail = Char + 1;
while (*Char != 0) {
*(Char++) = *(Tail++);
}
Char = (CHAR16*)StrStr(FilePath, L"\\\\"); // cast is ok because FilePath is not const, and we know that StrStr returns a pointer in FilePath. Will disappear when using a string object instead of CHAR16*
}
XStringW returnValue;
returnValue.stealValueFrom(FilePath); // do not FreePool FilePath, it's now owned by returnValue
return returnValue;
}
XStringW FileDevicePathFileToXStringW(const EFI_DEVICE_PATH_PROTOCOL *DevPath)
{
EFI_DEVICE_PATH_PROTOCOL *Node;
if (DevPath == NULL) {
return NullXStringW;
}
Node = (EFI_DEVICE_PATH_PROTOCOL *)DevPath;
while (!IsDevicePathEnd(Node)) {
if ((Node->Type == MEDIA_DEVICE_PATH) &&
(Node->SubType == MEDIA_FILEPATH_DP)) {
return FileDevicePathToXStringW(Node);
}
Node = NextDevicePathNode(Node);
}
return NullXStringW;
}
XBool DumpVariable(CHAR16* Name, const EFI_GUID& Guid, INTN DevicePathAt)
{
UINTN dataSize = 0;
UINT8 *data = NULL;
UINTN i;
EFI_STATUS Status;
Status = gRT->GetVariable (Name, Guid, NULL, &dataSize, data);
if (Status == EFI_BUFFER_TOO_SMALL) {
data = (__typeof__(data))AllocateZeroPool(dataSize);
Status = gRT->GetVariable (Name, Guid, NULL, &dataSize, data);
if (EFI_ERROR(Status)) {
DBG("Can't get %ls, size=%llu\n", Name, dataSize);
FreePool(data);
data = NULL;
} else {
DBG("%ls var size=%llu\n", Name, dataSize);
for (i = 0; i < dataSize; i++) {
DBG("%02hhX ", data[i]);
}
DBG("\n");
if (DevicePathAt >= 0) {
DBG("%ls: %ls\n", Name, FileDevicePathToXStringW((EFI_DEVICE_PATH_PROTOCOL*)&data[DevicePathAt]).wc_str());
}
}
}
if (data) {
FreePool(data);
return true;
}
return false;
}
// EOF