mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-10 09:40:53 +01:00
42cece9885
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
1628 lines
56 KiB
C++
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
|