CloverBootloader/rEFIt_UEFI/Platform/LegacyBoot.cpp
jief666 69a47c5fac Create Properties, Arbitrary and AddProperties menu.
hex2bin returns the length when passing NULL for out parameter instead
of 0.
Buildid in OEMString for my own build.
Create TagTypes.h.
Rename AddProperties to AddPropertiesArray.
devprop_generate_string now returns a XString8.
Add cpy method in XBuffer.
Add strsicpy in XString.
2021-04-01 11:06:53 +03:00

1159 lines
35 KiB
C++

/*++
Slice 2011
LegacyBoot.c - support for boot legacy OS such as WindowsXP and Linux
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Portion from XOM project
Copyright (c) 2006 JLA
*/
#include <Platform.h> // Only use angled for Platform, else, xcode project won't compile
#include <Efi.h>
#include "LegacyBiosThunk.h"
#include "AcpiPatcher.h"
#include "Self.h"
#ifndef DEBUG_ALL
#define DEBUG_LBOOT 1
#else
#define DEBUG_LBOOT DEBUG_ALL
#endif
#if DEBUG_LBOOT == 0
#define DBG(...)
#else
#define DBG(...) DebugLog(0, __VA_ARGS__) // until a better solution is found, force DebugLog(0, ...) to prevent saving to DebugLog, which may cause legacy boot to fail
#endif
#pragma pack(push)
#pragma pack(1)
//template
//CONST MBR_PARTITION_INFO tMBR = {0x80, {0xFE, 0xFF, 0xFF}, 0x06, {0xFE, 0xFF, 0xFF}, 0, 0};
CONST MBR_PARTITION_INFO tMBR = {0x80, {0xFE, 0xFF, 0xFF}, 0xEE, {0xFE, 0xFF, 0xFF}, 0, 0};
typedef struct {
UINT8 loader[0x1BE];
MBR_PARTITION_INFO p[4];
UINT16 signature;
} MBR;
typedef struct {
UINT64 signature;
UINT32 revision;
UINT32 headerSize;
UINT32 headerCRC;
UINT32 reserved;
UINT64 myLBA;
UINT64 alternateLBA;
UINT64 firstUsableLBA;
UINT64 lastUsableLBA;
EFI_GUID diskGUID;
UINT64 partitionEntryLBA;
UINT32 numberOfPartitionEntries;
UINT32 sizeOfPartitionEntry;
UINT32 partitionEntryArrayCRC32;
UINT8 filler[4]; //alignment
} GPT_HEADER;
typedef struct {
EFI_GUID partitionType;
EFI_GUID partitionGuid;
UINT64 startingLBA;
UINT64 endingLBA;
UINT64 attributes;
CHAR16 partitionName[72 / 2];
} GPT_ENTRY;
typedef struct Address_t {
UINT32 offset;
UINT16 segment;
UINT8 type;
} Address;
// for BIOS INT 13h AH=42h: Extended Read Sectors From Drive
typedef struct {
UINT8 size; // size of struct = 0x10
UINT8 unused; // should be 0
UINT16 numSectors; // number of sectors
UINT16 buffOffset; // segment and offset to the buffer
UINT16 buffSegment;
UINT64 lba; // LBA of starting sector
} BIOS_DISK_ADDRESS_PACKET;
//located at 0x7F00
CONST UINT8 VideoTest[] = {
0xb8, 0x02, 0x00, //mov ax,2
0xcd, 0x10, //int 0x10
0x66, 0xbb, 0x0f, 0x00, 0x00, 0x00, //mov ebx, 0x0f
0x66, 0xb8, 0x38, 0x0e, 0x00, 0x00, //mov eax, 0x0e38
0x66, 0xb9, 0x10, 0x00, 0x00, 0x00, //mov ecx, 0x10
0xcd, 0x10, //int 0x10
0xed, 0xe4, 0xfc //jmp near 0x7c00
}; //28bytes
#pragma pack(pop)
#define ADDRT_REAL 0 // Segment:Offset (16:16)
#define ADDRT_FLAT 1 // Segment is 0, Offset is 32 bit flat address
EFI_CPU_ARCH_PROTOCOL *mCpu;
EFI_LEGACY_8259_PROTOCOL *gLegacy8259;
THUNK_CONTEXT *mThunkContext = NULL;
UINT8* floppyImage;
EFI_BLOCK_IO* hd82 = NULL;
EFI_BLOCK_IO* hd80 = NULL;
EFI_BLOCK_IO* pCDROMBlockIO = NULL;
EFI_HANDLE hCDROM = NULL;
Address addrRealFromSegOfs(UINT16 segment, UINT16 offset) {
Address address;
address.segment = segment;
address.offset = offset;
address.type = ADDRT_REAL;
return address;
}
Address addrFlatFromOffset(UINT32 offset) {
Address address;
address.segment = 0;
address.offset = offset;
address.type = ADDRT_FLAT;
return address;
}
Address addrNull() {
Address address;
address.type = 0xff;
address.segment = 0;
address.offset = 0;
return address;
}
static UINTN addrPagingEnable;
UINTN addrIsPagingEnabled() {
return addrPagingEnable;
}
void addrEnablePaging(UINTN f) {
addrPagingEnable = f;
}
#define ADDR_FLAT_MAX addrFlatFromOffset(0xFFFFFFFF)
#define ADDR_FLAT_MIN addrFlatFromOffset(0x00000000)
#define ADDR_REAL_MAX addrRealFromSegOfs(0xFFFF, 0xFFFF)
#define ADDR_REAL_MIN addrRealFromSegOfs(0x0000, 0x0000)
#define ADDR_NULL addrNull()
UINT32 addrToOffset(Address address) {
if (address.type == ADDRT_REAL)
return (address.segment << 4) + address.offset;
if (address.type == ADDRT_FLAT)
return addrIsPagingEnabled() ? address.offset & 0x7FFFFFFF : address.offset;
return 0;
}
void* addrToPointer(Address address) {
return (UINT8*)(UINTN)addrToOffset(address);
}
static UINTN addrLT (Address a1, Address a2) { return addrToOffset(a1) < addrToOffset(a2); }
//static UINTN addrLTE(Address a1, Address a2) { return addrToOffset(a1) <= addrToOffset(a2); }
//static UINTN addrGT (Address a1, Address a2) { return addrToOffset(a1) > addrToOffset(a2); }
static UINTN addrGTE(Address a1, Address a2) { return addrToOffset(a1) >= addrToOffset(a2); }
//static UINTN addrEQ (Address a1, Address a2) { return addrToOffset(a1) == addrToOffset(a2); }
Address krnMemoryTop;
/** Reads sectors from given DriveNum with bios into Buffer.
* Requires Dap and Buffer to be allocated in legacy memory region.
*/
EFI_STATUS BiosReadSectorsFromDrive(UINT8 DriveNum, UINT64 Lba, UINTN NumSectors, BIOS_DISK_ADDRESS_PACKET *Dap, void *Buffer)
{
EFI_STATUS Status;
IA32_REGISTER_SET Regs;
// init disk access packet
Dap->size = sizeof(BIOS_DISK_ADDRESS_PACKET);
Dap->unused = 0;
Dap->numSectors = (UINT16)NumSectors;
Dap->buffSegment = (UINT16) (((UINTN) Buffer >> 16) << 12);
Dap->buffOffset = (UINT16) (UINTN) Buffer;
Dap->lba = Lba;
// set registers
SetMem(&Regs, sizeof (Regs), 0);
// first reset disk controller as the controller seems to be in an undefined state sometimes
DBG("Reset disk controller: %hhX\n", DriveNum);
Regs.H.AH = 0x00; // INT 13h AH=00h: Reset disk controller
Regs.H.DL = DriveNum;
Status = EFI_SUCCESS;
if (LegacyBiosInt86(0x13, &Regs)) {
// TRUE = error
DBG("Reset 0 disk controller: %hhX\n", DriveNum);
Regs.H.AH = 0x0D; // INT 13h AH=00h: Reset disk controller
Regs.H.DL = DriveNum;
if (LegacyBiosInt86(0x13, &Regs)) {
Status = EFI_NOT_FOUND;
DBG("reset controller error\n");
return Status;
}
}
// next, read sector
Regs.H.AH = 0x42; // INT 13h AH=42h: Extended Read Sectors From Drive
Regs.H.DL = DriveNum;
Regs.E.DS = (UINT16) (((UINTN) Dap >> 16) << 12);
Regs.X.SI = (UINT16) (UINTN) Dap;
// DBG("Drive: %hhX, Dap=%p, Buffer=%p, d.size=%hhX, d.nsect=%d, d.buff=[%hhX:%hhX]\n",
// DriveNum, Dap, Buffer, Dap->size, Dap->numSectors, Dap->buffSegment, Dap->buffOffset);
// DBG("Dap: Reg.DS:SI = [%hhX:%hhX]\n", Regs.E.DS, Regs.X.SI);
Status = EFI_SUCCESS;
if (LegacyBiosInt86(0x13, &Regs)) {
// TRUE = error
Regs.H.AH = 0x01; // INT 13h AH=01h: Get Status of Last Drive Operation
LegacyBiosInt86(0x13, &Regs);
Status = EFI_NOT_FOUND;
}
DBG("LegacyBiosInt86 status=%s, AH=%hhX\n", efiStrError(Status), Regs.H.AH);
return Status;
}
/** Reads first 2 sectors from given DriveNum with bios and calculates DriveCRC32.
* Requires Dap and Buffer to be allocated in legacy memory region.
*/
EFI_STATUS GetBiosDriveCRC32(UINT8 DriveNum,
UINT32 *DriveCRC32,
BIOS_DISK_ADDRESS_PACKET *Dap,
void *Buffer)
{
EFI_STATUS Status;
// read first 2 sectors
Status = BiosReadSectorsFromDrive(DriveNum, 0, 2, Dap, Buffer);
if (!EFI_ERROR(Status)) {
*DriveCRC32 = GetCrc32((UINT8*)Buffer, 2 * 512);
//gBS->CalculateCrc32(Buffer, 2 * 512, DriveCRC32);
DBG("Bios drive CRC32 = 0x%X\n", *DriveCRC32);
}
return Status;
}
/** Scans bios drives 0x80 and up, calculates CRC32 of first 2 sectors and compares it with Volume->DriveCRC32.
* First 2 sectors whould be enough - covers MBR and GPT header with signatures.
* Requires mThunkContext to be initialiyzed already with InitializeBiosIntCaller().
*/
UINT8 GetBiosDriveNumForVolume(REFIT_VOLUME *Volume)
{
EFI_STATUS Status;
UINT8 DriveNum, BestNum;
UINT32 DriveCRC32;
UINT8 *Buffer;
BIOS_DISK_ADDRESS_PACKET *Dap;
UINTN LegacyRegionPages;
EFI_PHYSICAL_ADDRESS LegacyRegion;
// DBG("Expected volume CRC32 = %hhX\n", Volume->DriveCRC32);
LegacyRegion = 0x0C0000;
LegacyRegionPages = EFI_SIZE_TO_PAGES(sizeof(BIOS_DISK_ADDRESS_PACKET) + 2 * 512)+1 /* dap + 2 sectors */;
Status = gBS->AllocatePages(AllocateMaxAddress,
EfiBootServicesData,
LegacyRegionPages,
&LegacyRegion
);
if (EFI_ERROR(Status)) {
return 0;
}
Dap = (BIOS_DISK_ADDRESS_PACKET *)(UINTN)LegacyRegion;
Buffer = (UINT8 *)(UINTN)(LegacyRegion + 0x200);
//Slice - some CD has BIOS driveNum = 0
// scan drives from 0x80
BestNum = 0;
for (DriveNum = 0x80; DriveNum < 0x88; DriveNum++) {
DriveCRC32 = 0;
Status = GetBiosDriveCRC32(DriveNum, &DriveCRC32, Dap, Buffer);
if (EFI_ERROR(Status)) {
// error or no more disks
//DriveNum = 0;
DBG("Can't get drive 0x%hhX CRC32\n", DriveNum);
continue;
}
BestNum = DriveNum;
DBG("Calculated CRC=%X at drive 0x%hhX\n", Volume->DriveCRC32, BestNum);
if (Volume->DriveCRC32 == DriveCRC32) {
break;
}
}
gBS->FreePages(LegacyRegion, LegacyRegionPages);
DBG("Returning Bios drive %hhX\n", BestNum);
return BestNum;
}
EFI_STATUS bootElTorito(REFIT_VOLUME* volume)
{
EFI_BLOCK_IO* pBlockIO = volume->BlockIO;
Address bootAddress = addrRealFromSegOfs(0x0000, 0x7C00);
UINT8 *sectorBuffer; //[2048];
EFI_STATUS Status = EFI_NOT_FOUND;
UINT64 lba;
UINT16 bootLoadSegment;
Address bootLoadAddress;
UINT32 bootSize;
UINT32 bootSectors;
IA32_REGISTER_SET Regs;
//UINTN LogSize;
sectorBuffer = (__typeof__(sectorBuffer))AllocateAlignedPages (EFI_SIZE_TO_PAGES (2048), 64);
krnMemoryTop = addrRealFromSegOfs(0xA000, 0x0000);
addrEnablePaging(0);
// No device, no game
if (!pBlockIO) {
DBG("CDROMBoot: No CDROM to boot from\n");
if (sectorBuffer) {
FreePages(sectorBuffer, EFI_SIZE_TO_PAGES (2048));
}
return Status;
}
// Load El Torito boot record volume descriptor
Status = pBlockIO->ReadBlocks(pBlockIO, pBlockIO->Media->MediaId, 0x11, 2048, sectorBuffer);
if (EFI_ERROR(Status)) {
// Retry in case the CD was swapped out
Status = gBS->HandleProtocol(volume->DeviceHandle, &gEfiBlockIoProtocolGuid, (void **) &pBlockIO);
if (!EFI_ERROR(Status)) {
// pCDROMBlockIO = pBlockIO;
Status = pBlockIO->ReadBlocks(pBlockIO, pBlockIO->Media->MediaId, 0x11, 2048, sectorBuffer);
}
if (EFI_ERROR(Status)) {
DBG("CDROMBoot: Unable to read block %X: %s\n", 0x11, efiStrError(Status));
return Status;
}
}
if (AsciiStrCmp((CHAR8*)(sectorBuffer + 0x7), "EL TORITO SPECIFICATION")) {
DBG("CDROMBoot: Not an El Torito Specification disk\n");
return Status;
}
// Find the boot catalog
lba = sectorBuffer[0x47] + sectorBuffer[0x48] * 256 + sectorBuffer[0x49] * 65536 + sectorBuffer[0x4A] * 16777216;
Status = pBlockIO->ReadBlocks(pBlockIO, pBlockIO->Media->MediaId, lba, 2048, sectorBuffer);
if (EFI_ERROR(Status)) {
DBG("CDROMBoot: Unable to read block %llX: %s\n", lba, efiStrError(Status));
return Status;
}
if (sectorBuffer[0x00] != 1 || sectorBuffer[0x1E] != 0x55 || sectorBuffer[0x1F] != 0xAA) {
DBG("CDROMBoot: Invalid El Torito validation entry in boot catalog LBA %llX\n", lba);
// DumpHex(0, 0, 64, sectorBuffer);
return Status;
}
if (sectorBuffer[0x01] != 0) {
DBG("CDROMBoot: Platform mismatch: %d\n", sectorBuffer[0x01]);
return Status;
}
if (sectorBuffer[0x20] != 0x88) {
DBG("CDROMBoot: CD-ROM is not bootable\n");
return Status;
}
if (sectorBuffer[0x21] != 0) {
DBG("CDROMBoot: Currently only non-emulated CDROMs are supported");
return Status;
}
bootLoadSegment = sectorBuffer[0x22] + sectorBuffer[0x23] * 256;
if (!bootLoadSegment)
bootLoadSegment = 0x7C0;
bootSectors = sectorBuffer[0x26] + sectorBuffer[0x27] * 256;
bootSize = bootSectors * pBlockIO->Media->BlockSize;
bootLoadAddress = addrRealFromSegOfs(bootLoadSegment, 0);
if (addrLT(bootLoadAddress, bootAddress) || addrGTE(bootLoadAddress, krnMemoryTop)) {
DBG("CDROMBoot: Illegal boot load address %XL%X\n", addrToOffset(bootLoadAddress), bootSize);
return Status;
}
lba = sectorBuffer[0x28] + sectorBuffer[0x29] * 256 + sectorBuffer[0x2A] * 65536 + sectorBuffer[0x2B] * 16777216;
DBG("CDROMBoot: Booting LBA %llu @%X L%X\n", lba, addrToOffset(bootLoadAddress), bootSize);
gBS->FreePages((EFI_PHYSICAL_ADDRESS)(UINTN)sectorBuffer, 1);
// Read the boot sectors into the boot load address
Status = pBlockIO->ReadBlocks(pBlockIO, pBlockIO->Media->MediaId, lba, bootSize, addrToPointer(bootLoadAddress));
if (EFI_ERROR(Status)) {
DBG("CDROMBoot: Unable to read block %llu: %s\n", lba, efiStrError(Status));
return Status;
}
Status = SaveBooterLog(&self.getCloverDir(), LEGBOOT_LOG);
// Jief : don't write outside of SelfDir
// if (EFI_ERROR(Status)) {
// DBG("can't save legacy-boot.log\n");
// Status = SaveBooterLog(NULL, LEGBOOT_LOG);
// }
/*LogSize = msgCursor - msgbuf;
Status = egSaveFile(&self.getSelfRootDir(), LEGBOOT_LOG, (UINT8*)msgbuf, LogSize);
if (EFI_ERROR(Status)) {
DBG("can't save legacy-boot.log\n");
Status = egSaveFile(NULL, LEGBOOT_LOG, (UINT8*)msgbuf, LogSize);
}
*/
// Configure drive
// hd82 = pBlockIO;
// Initialize Registers
// CONTEXT->edx = 0x82;
// Boot it
// dbgStart(bootLoadAddress, enableDebugger);
Status = gBS->LocateProtocol(&gEfiLegacy8259ProtocolGuid, NULL, (void**)&gLegacy8259);
if (EFI_ERROR(Status)) {
return Status;
}
/* mCpu = NULL;
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (void **) &mCpu);
if (EFI_ERROR(Status)) {
return Status;
}
*/
Status = gBS->AllocatePool (EfiBootServicesData,sizeof(THUNK_CONTEXT),(void **)&mThunkContext);
if (EFI_ERROR(Status)) {
return Status;
}
Status = InitializeBiosIntCaller(); //mThunkContext);
if (EFI_ERROR(Status)) {
return Status;
}
// InitializeInterruptRedirection(); //gLegacy8259);
// Status = mCpu->EnableInterrupt(mCpu);
Regs.X.DX = 0; //0x82;
// Regs.X.SI = (UINT16)activePartition;
//Regs.X.ES = EFI_SEGMENT((UINT32) pBootSector);
//Regs.X.BX = EFI_OFFSET ((UINT32) pBootSector);
// LegacyBiosFarCall86(0, 0x7c00, &Regs);
LegacyBiosFarCall86(
EFI_SEGMENT((UINT32) addrToOffset(bootLoadAddress)),
EFI_OFFSET ((UINT32) addrToOffset(bootLoadAddress)),
&Regs
);
// Success - Should never get here unless debugger aborts
return Status;
}
EFI_STATUS bootMBR(REFIT_VOLUME* volume)
{
EFI_STATUS Status;
EFI_BLOCK_IO* pDisk = volume->BlockIO;
//UINT8* pMBR = (void*)0x600;
UINT8* pMBR = (UINT8*)(UINTN)0x7C00;
//UINT8* pBootSector = (void*)0x7C00;
//MBR_PARTITION_INFO* activePartition = NULL;
//UINTN partitionIndex;
IA32_REGISTER_SET Regs;
UINTN i, j;
UINT8 BiosDriveNum;
//UINTN LogSize;
SetMem(&Regs, sizeof (Regs), 0);
addrEnablePaging(0);
Status = gBS->LocateProtocol(&gEfiLegacy8259ProtocolGuid, NULL, (void**)&gLegacy8259);
if (EFI_ERROR(Status)) {
return Status;
}
mCpu = NULL;
Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (void **) &mCpu);
if (EFI_ERROR(Status)) {
return Status;
}
Status = gBS->AllocatePool (EfiBootServicesData,sizeof(THUNK_CONTEXT),(void **)&mThunkContext);
if (EFI_ERROR(Status)) {
return Status;
}
DBG("boot from partition %ls\n", FileDevicePathToXStringW(volume->DevicePath).wc_str());
Status = InitializeBiosIntCaller(); //mThunkContext);
if (EFI_ERROR(Status)) {
return Status;
}
//InitializeInterruptRedirection(); //gLegacy8259);
//Status = mCpu->EnableInterrupt(mCpu);
// Read the MBR
Status = pDisk->ReadBlocks(pDisk, pDisk->Media->MediaId, 0, 512, pMBR);
if (EFI_ERROR(Status)) {
DBG("HDBoot: Unable to read MBR: %s\n", efiStrError(Status));
return Status;
}
for (i=0; i<16; i++) {
DBG("%04llX: ", i*16);
for (j=0; j<16; j++) {
DBG("%02hhX ", pMBR[i*16+j]);
}
DBG("\n");
}
Status = SaveBooterLog(&self.getCloverDir(), LEGBOOT_LOG);
// Jief : don't write outside SelfDir
// if (EFI_ERROR(Status)) {
// Status = SaveBooterLog(NULL, LEGBOOT_LOG);
// }
/*
LogSize = msgCursor - msgbuf;
Status = egSaveFile(&self.getSelfRootDir(), LEGBOOT_LOG, (UINT8*)msgbuf, LogSize);
if (EFI_ERROR(Status)) {
Status = egSaveFile(NULL, LEGBOOT_LOG, (UINT8*)msgbuf, LogSize);
}
*/
// Check validity of MBR
if (pMBR[510] != 0x55 || pMBR[511] != 0xAA) {
DBG("HDBoot: Invalid MBR signature 0x%02hhX%02hhX (not 0xAA55)\n", pMBR[511], pMBR[510]);
Status = EFI_NOT_FOUND;
return Status;
}
BiosDriveNum = GetBiosDriveNumForVolume(volume);
if (BiosDriveNum == 0) {
// not found
DBG("HDBoot: BIOS drive number not found\n");
return EFI_NOT_FOUND;
}
/*
// Traverse partitions
for (partitionIndex = 0; partitionIndex < 4; ++partitionIndex) {
MBR_PARTITION_INFO* partition = (MBR_PARTITION_INFO*)(pMBR + 0x1BE + sizeof(MBR_PARTITION_INFO) * partitionIndex);
// Not the active partition?
if (partition->Flags != 0x80)
continue;
// Is the partition valid?
if (partition->StartLBA == 0 || partition->Size == 0) {
DBG("HDBoot: Invalid active partition %d: (%08hhX L %08hhX)\n", partition->StartLBA, partition->Size);
return Status;
}
activePartition = partition;
break;
}
// No active partitions found?
if (!activePartition) {
DBG("HDBoot: No active partitions found.\n");
Status = EFI_NOT_FOUND;
return Status;
}
DBG("HDBoot: Found active partition #%d.\n", partitionIndex);
// Read the boot sector
Status = pDisk->ReadBlocks(pDisk, pDisk->Media->MediaId, activePartition->StartLBA, 512, pBootSector);
if (EFI_ERROR(Status)) {
DBG("HDBoot: Unable to read partition %d's boot sector: %s\n", partitionIndex, efiStrError(Status));
Status = EFI_NOT_FOUND;
return Status;
}
// Check boot sector
if (pBootSector[0x1FE] != 0x55 || pBootSector[0x1FF] != 0xAA) {
DBG("HDBoot: Invalid Boot Sector signature 0x%02hhX%02hhX (not 0xAA55)\n", pBootSector[0x1FF], pBootSector[0x1FE]);
Status = EFI_NOT_FOUND;
return Status;
}
DBG("HDBoot: Found valid boot sector on partition #%d. Booting...\n", partitionIndex);
*/
DBG("HDBoot: Booting...\n");
Regs.X.DX = BiosDriveNum;
//Regs.X.SI = (UINT16)(UINTN)activePartition;
LegacyBiosFarCall86(0, 0x7c00, &Regs);
// Success - Should never get here
return EFI_SUCCESS;
}
EFI_STATUS bootPBRtest(REFIT_VOLUME* volume)
{
EFI_STATUS Status = EFI_NOT_FOUND;
EFI_BLOCK_IO* pDisk = volume->BlockIO;
UINT8* pBootSector = (UINT8*)(UINTN)0x7C00;
UINT8* mBootSector;
MBR_PARTITION_INFO* pMBR = (MBR_PARTITION_INFO*)(UINTN)0x7BE;
UINT32 LbaOffset = 0;
UINT32 LbaSize = 0;
HARDDRIVE_DEVICE_PATH *HdPath = NULL;
const EFI_DEVICE_PATH_PROTOCOL *DevicePath = volume->DevicePath;
UINT8 BiosDriveNum;
// UINT16 OldMask;
// UINT16 NewMask;
UINTN i, j; //for debug dump
UINT8 *ptr;
// UINT32 MBRCRC32;
//UINTN LogSize;
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtPointer = NULL;
EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs = NULL;
IA32_REGISTER_SET Regs;
SetMem(&Regs, sizeof (Regs), 0);
addrEnablePaging(0);
//
// find the partition device path node
//
while (!IsDevicePathEnd (DevicePath)) {
if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
(DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {
HdPath = (HARDDRIVE_DEVICE_PATH *)DevicePath;
break;
}
DevicePath = NextDevicePathNode (DevicePath);
}
if (HdPath != NULL) {
DBG("boot from partition %ls\n", FileDevicePathToXStringW((EFI_DEVICE_PATH *)HdPath).wc_str());
LbaOffset = (UINT32)HdPath->PartitionStart;
LbaSize = (UINT32)HdPath->PartitionSize;
DBG("starting from 0x%X LBA \n", LbaOffset);
} else {
return Status;
}
Status = gBS->LocateProtocol(&gEfiLegacy8259ProtocolGuid, NULL, (void**)&gLegacy8259);
if (EFI_ERROR(Status)) {
return Status;
}
DBG("gEfiLegacy8259ProtocolGuid found\n");
Status = gBS->AllocatePool (EfiBootServicesData,sizeof(THUNK_CONTEXT),(void **)&mThunkContext);
if (EFI_ERROR(Status)) {
return Status;
}
Status = InitializeBiosIntCaller(); //mThunkContext);
if (EFI_ERROR(Status)) {
return Status;
}
mBootSector = (__typeof__(mBootSector))AllocateAlignedPages(1, 16);
Status = pDisk->ReadBlocks(pDisk, pDisk->Media->MediaId, 0, 2*512, mBootSector);
CopyMem(pBootSector, mBootSector, 1024);
DBG("PBR after readDisk:\n");
for (i=0; i<4; i++) {
DBG("%04llX: ", i*16);
for (j=0; j<16; j++) {
DBG("%02hhX ", pBootSector[i*16+j]);
}
DBG("\n");
}
DBG("Reset disk controller 0x80\n");
Status = SaveBooterLog(&self.getCloverDir(), LEGBOOT_LOG);
if (EFI_ERROR(Status)) {
DBG("can't save legacy-boot.log\n");
// Jief : don't write outside SelfDir
// Status = SaveBooterLog(NULL, LEGBOOT_LOG);
}
//after reset we can't save boot log
Regs.H.AH = 0x0D; // INT 13h AH=00h: Reset floppy disk controller; 0x0D - reset hard disk controller
Regs.H.DL = 0x80;
Status = EFI_SUCCESS;
if (LegacyBiosInt86(0x13, &Regs)) {
// TRUE = error
Status = EFI_NOT_FOUND;
DBG("reset controller 0x80 error\n");
// return Status;
}
BiosDriveNum = GetBiosDriveNumForVolume(volume);
if (BiosDriveNum == 0) {
// not found
DBG("HDBoot: BIOS drive number not found\n");
// BiosDriveNum = 0x80;
// return EFI_NOT_FOUND;
}
//Now I want to start from VideoTest
ptr = (UINT8*)(UINTN)0x7F00;
CopyMem(ptr, &VideoTest[0], 30);
CopyMem(pMBR, &tMBR, 16);
pMBR->StartLBA = LbaOffset;
pMBR->Size = LbaSize;
FadtPointer = GetFadt();
if (FadtPointer == NULL) {
return EFI_NOT_FOUND;
}
Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE*)(UINTN)(FadtPointer->FirmwareCtrl);
Facs->FirmwareWakingVector = 0x7F00;
gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
/*
Regs.X.DX = BiosDriveNum;
Regs.X.SI = 0x07BE;
//Regs.X.ES = EFI_SEGMENT((UINT32) pBootSector);
//Regs.X.BX = EFI_OFFSET ((UINT32) pBootSector);
LegacyBiosFarCall86(0, 0x7F00, &Regs); //0x7c00
*/
//if not success then save legacyboot.log
Status = SaveBooterLog(&self.getCloverDir(), LEGBOOT_LOG);
if (EFI_ERROR(Status)) {
DBG("can't save legacy-boot.log\n");
// Jief : don't write outside SelfDir
// /*Status = */SaveBooterLog(NULL, LEGBOOT_LOG);
}
return EFI_SUCCESS;
}
/*
EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtPointer = GetFadt();
if (FadtPointer == NULL) {
return;
}
Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE*)(UINTN)(FadtPointer->FirmwareCtrl);
Facs->FirmwareWakingVector = 0x7F00;
gRT->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, NULL);
*/
#define EFI_CPU_EFLAGS_IF 0x200
/** For BIOS and some UEFI boots.
* Loads partition boot record (PBR) and starts it.
*/
EFI_STATUS bootPBR(REFIT_VOLUME* volume, BOOLEAN SataReset)
{
EFI_STATUS Status;
EFI_BLOCK_IO *pDisk = volume->BlockIO;
UINT8 *pBootSector = (UINT8*)(UINTN)0x7C00;
UINT8 *mBootSector;
UINT32 LbaOffset = 0;
UINT32 LbaSize = 0;
HARDDRIVE_DEVICE_PATH *HdPath = NULL;
const EFI_DEVICE_PATH_PROTOCOL *DevicePath = volume->DevicePath;
UINT8 BiosDriveNum;
//UINT16 OldMask;
//UINT16 NewMask;
UINTN i, j; //for debug dump
IA32_REGISTER_SET Regs;
//UINTN LogSize;
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
//UINT16 HddCount;
//HDD_INFO *HddInfo = NULL;
UINT16 BbsCount;
BBS_TABLE *BbsTable = NULL;
BBS_TABLE *BbsTableIt = NULL;
CONST CHAR16 *BbsPriorityTxt;
CONST CHAR16 *BbsDevTypeTxt;
MBR_PARTITION_INFO *pMBR = (MBR_PARTITION_INFO*)(UINTN)0x11BE; // typical location boot0 installs it, should be unused otherwise...
//
// get EfiLegacy8259Protocol - mandatory
//
Status = gBS->LocateProtocol(&gEfiLegacy8259ProtocolGuid, NULL, (void**)&gLegacy8259);
DBG("EfiLegacy8259ProtocolGuid: %s\n", efiStrError(Status));
if (EFI_ERROR(Status)) {
return Status;
}
if (SataReset) {
IoWrite8(0x3F2, 0x0C);
}
//
// get EfiLegacyBiosProtocol - optional
//
Status = gBS->LocateProtocol(&gEfiLegacyBiosProtocolGuid, NULL, (void**)&LegacyBios);
DBG("EfiLegacyBiosProtocolGuid: %s\n", efiStrError(Status));
if (!EFI_ERROR(Status)) {
//
// call PrepareToBootEfi() to init BIOS drives
//
//Status = LegacyBios->GetBbsInfo(LegacyBios, &HddCount, &HddInfo, &BbsCount, &BbsTable);
//DBG("GetBbsInfo = %s, HddCnt=%d, HddInfo=%p, BbsCount=%d, BbsTabl%p\n", efiStrError(Status), HddCount, HddInfo, BbsCount, BbsTable);
Status = LegacyBios->PrepareToBootEfi(LegacyBios, &BbsCount, &BbsTable);
DBG("PrepareToBootEfi = %s, BbsCount=%d, BbsTabl%llx\n", efiStrError(Status), BbsCount, (uintptr_t)BbsTable);
//PauseForKey(L"continue ...\n");
//
// debug: dump BbsTable
//
BbsTableIt = BbsTable;
for (i=0; i<BbsCount; i++, BbsTableIt++) {
BbsPriorityTxt = L"";
switch (BbsTableIt->BootPriority) {
case BBS_DO_NOT_BOOT_FROM:
BbsPriorityTxt = L"NOT";
break;
case BBS_LOWEST_PRIORITY:
BbsPriorityTxt = L"LOW";
break;
case BBS_UNPRIORITIZED_ENTRY:
BbsPriorityTxt = L"UNP";
break;
case BBS_IGNORE_ENTRY:
BbsPriorityTxt = L"IGN";
break;
}
BbsDevTypeTxt = L"-";
switch (BbsTableIt->DeviceType) {
case BBS_FLOPPY:
BbsDevTypeTxt = L"FLP";
break;
case BBS_HARDDISK:
BbsDevTypeTxt = L"HDD";
break;
case BBS_CDROM:
BbsDevTypeTxt = L"CDR";
break;
case BBS_PCMCIA:
BbsDevTypeTxt = L"PCM";
break;
case BBS_USB:
BbsDevTypeTxt = L"USB";
break;
case BBS_EMBED_NETWORK:
BbsDevTypeTxt = L"NET";
break;
case BBS_BEV_DEVICE:
BbsDevTypeTxt = L"BEV";
break;
}
DBG("%llu: Drv: %hhX P: %hX %ls PCI(%X,%X,%X), DT: %hX %ls SF: %X Txt: '%s'\n",
i, BbsTableIt->AssignedDriveNumber, BbsTableIt->BootPriority, BbsPriorityTxt,
BbsTableIt->Bus, BbsTableIt->Device, BbsTableIt->Function,
BbsTableIt->DeviceType, BbsDevTypeTxt, *(UINT32*)(&BbsTableIt->StatusFlags),
(CHAR8*)(UINTN)((BbsTableIt->DescStringSegment << 4) + BbsTableIt->DescStringOffset)
);
}
//PauseForKey(L"continue ...\n");
}
//
// find the partition device path node
//
while (!IsDevicePathEnd (DevicePath)) {
if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
(DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {
HdPath = (HARDDRIVE_DEVICE_PATH *)DevicePath;
break;
}
DevicePath = NextDevicePathNode (DevicePath);
}
if (HdPath != NULL) {
DBG("boot from partition %ls\n", FileDevicePathToXStringW((EFI_DEVICE_PATH *)HdPath).wc_str());
LbaOffset = (UINT32)HdPath->PartitionStart;
LbaSize = (UINT32)HdPath->PartitionSize;
DBG("starting from 0x%X LBA \n", LbaOffset);
} else {
return Status;
}
//
// prepare ThunkContext for 16bit BIOS calls
//
if (mThunkContext == NULL) {
Status = gBS->AllocatePool (EfiBootServicesData, sizeof(THUNK_CONTEXT), (void **)&mThunkContext);
if (EFI_ERROR(Status)) {
return Status;
}
DBG("Thunk allocated\n");
Status = InitializeBiosIntCaller(); //mThunkContext);
if (EFI_ERROR(Status)) {
return Status;
}
}
//
// read partition boot record and copy it to BIOS boot area 0000:07C00
//
mBootSector = (__typeof__(mBootSector))AllocatePages(1);
Status = pDisk->ReadBlocks(pDisk, pDisk->Media->MediaId, 0, 1*512, mBootSector);
CopyMem(pBootSector, mBootSector, 1*512);
DBG("PBR:\n");
for (i=0; i<4; i++) {
DBG("%04llX: ", i*16);
for (j=0; j<16; j++) {
DBG("%02hhX ", pBootSector[i*16+j]);
}
DBG("\n");
}
//
// find parent disk volume and it's BIOS drive num
// todo: if we managed to get BbsTable, then we may find
// BIOS drive from there, by matching PCI bus, device, function
//
DBG("Looking for parent disk of %ls\n", FileDevicePathToXStringW(volume->DevicePath).wc_str());
BiosDriveNum = 0;
for (i = 0; i < Volumes.size(); i++) {
if (&Volumes[i] != volume && Volumes[i].BlockIO == volume->WholeDiskBlockIO)
{
BiosDriveNum = GetBiosDriveNumForVolume(&Volumes[i]);
break;
}
}
if (BiosDriveNum == 0) {
// not found
DBG("HDBoot: BIOS drive number not found, using default 0x80\n");
BiosDriveNum = 0x80;
}
//
// prepare 16bit regs:
// DX = BIOS drive num
//
SetMem(&Regs, sizeof (Regs), 0);
Regs.X.DX = BiosDriveNum;
// set up SI to partition table entry, some boot1 boot code (such a boot1f32 and boot1h) depend on it
if (volume->IsMbrPartition) {
CopyMem(pMBR, volume->MbrPartitionTable, 4*16); // copy to lower memory, same location as boot0
Regs.X.SI = (UINT16)(UINTN)&pMBR[volume->MbrPartitionIndex];
}
// apparently gpt without mbr, should this be legacy bootable?
// boot0.s fakes an partition entry, so lets do the same...
else {
CopyMem(pMBR, &tMBR, 16);
pMBR->StartLBA = LbaOffset;
pMBR->Size = LbaSize;
Regs.X.SI = (UINT16)(UINTN)pMBR;
}
DBG("mbr: %d index: %llX pointer: %llX dx: %hX si: %hX\n", volume->IsMbrPartition, volume->MbrPartitionIndex, (uintptr_t)volume->MbrPartitionTable, Regs.X.DX, Regs.X.SI);
DBG("pmbr: %llX start: %X size: %X\n", (uintptr_t)&pMBR[volume->MbrPartitionIndex], pMBR[volume->MbrPartitionIndex].StartLBA, pMBR[volume->MbrPartitionIndex].Size);
//
// call 16bit partition boot code
//
//PauseForKey(L"Doing LegacyBiosFarCall86 ...\n");
LegacyBiosFarCall86(0, 0x7c00, &Regs);
//Status = gLegacy8259->SetMask(gLegacy8259, &OldMask, NULL, NULL, NULL);
PauseForKey(L"save legacy-boot.log ...\n");
Status = SaveBooterLog(&self.getCloverDir(), LEGBOOT_LOG);
if (EFI_ERROR(Status)) {
DBG("can't save legacy-boot.log\n");
// Jief : don't write outside SelfDir
// /*Status = */SaveBooterLog(NULL, LEGBOOT_LOG);
}
return EFI_SUCCESS;
}
/** For DefaultLegacyBios (UEFI)
* Patch BBS Table priorities to allow booting not only from first partition.
*/
static void PatchBbsTable(EFI_LEGACY_BIOS_PROTOCOL *LegacyBios, UINT16 BootEntry)
{
UINT16 Idx;
UINT16 IdxCount = 0;
UINT16 Priority = 1;
UINT16 OldPriority;
UINT16 HddCount;
UINT16 BbsCount;
HDD_INFO *LocalHddInfo;
BBS_TABLE *LocalBbsTable;
LegacyBios->GetBbsInfo (
LegacyBios,
&HddCount,
&LocalHddInfo,
&BbsCount,
&LocalBbsTable
);
DBG("BBS Table of size %d, patching priorities Pold->Pnew:\n", BbsCount);
DBG(" NO: BBS# Pold Pnew bb/dd/ff cl/sc Type Stat segm:offs\n");
DBG(" =====================================================\n");
for (Idx = 0; Idx < BbsCount; Idx++) {
if ((LocalBbsTable[Idx].BootPriority == BBS_IGNORE_ENTRY) ||
(LocalBbsTable[Idx].BootPriority == BBS_DO_NOT_BOOT_FROM) ||
(LocalBbsTable[Idx].BootPriority == BBS_LOWEST_PRIORITY)
) {
continue;
}
OldPriority = LocalBbsTable[Idx].BootPriority;
if (++IdxCount==BootEntry) {
LocalBbsTable[Idx].BootPriority = 0;
} else {
LocalBbsTable[Idx].BootPriority = Priority++;
}
DBG(" %02llu: 0x%02llX %04llX %04llX %02llX/%02llX/%02llX %02llX/%02llX %04llX %04llX %04llX:%04llX\n",
(UINTN) IdxCount,
(UINTN) Idx,
(UINTN) OldPriority,
(UINTN) LocalBbsTable[Idx].BootPriority,
(UINTN) LocalBbsTable[Idx].Bus,
(UINTN) LocalBbsTable[Idx].Device,
(UINTN) LocalBbsTable[Idx].Function,
(UINTN) LocalBbsTable[Idx].Class,
(UINTN) LocalBbsTable[Idx].SubClass,
(UINTN) LocalBbsTable[Idx].DeviceType,
(UINTN) * (UINT16 *) &LocalBbsTable[Idx].StatusFlags,
(UINTN) LocalBbsTable[Idx].BootHandlerSegment,
(UINTN) LocalBbsTable[Idx].BootHandlerOffset/*,
(UINTN) ((LocalBbsTable[Idx].MfgStringSegment << 4) + LocalBbsTable[Idx].MfgStringOffset),
(UINTN) ((LocalBbsTable[Idx].DescStringSegment << 4) + LocalBbsTable[Idx].DescStringOffset)*/
);
}
}
/** For some UEFI boots that have EfiLegacyBiosProtocol.
* Starts legacy boot from the first BIOS drive.
*/
EFI_STATUS bootLegacyBiosDefault(IN UINT16 LegacyBiosDefaultEntry)
{
EFI_STATUS Status;
EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
//BBS_BBS_DEVICE_PATH *BbsDPN;
BBS_BBS_DEVICE_PATH *BbsDP = NULL;
//
// get EfiLegacyBiosProtocol - optional
//
Status = gBS->LocateProtocol(&gEfiLegacyBiosProtocolGuid, NULL, (void**)&LegacyBios);
DBG("EfiLegacyBiosProtocolGuid: %s\n", efiStrError(Status));
if (EFI_ERROR(Status)) {
return Status;
}
// Patch BBS Table
if (LegacyBiosDefaultEntry > 0) {
PatchBbsTable(LegacyBios, LegacyBiosDefaultEntry);
/*Status = SaveBooterLog(&self.getSelfRootDir(), LEGBOOT_LOG);
if (EFI_ERROR(Status)) {
DBG("can't save legacy-boot.log\n");
Status = SaveBooterLog(NULL, LEGBOOT_LOG);
}*/
}
/* commented out - it seems it does not have any effect
//
// create BBS device path for HDD
//
// size - size of struct, no additional String
BbsDPN = (BBS_BBS_DEVICE_PATH *) CreateDeviceNode(BBS_DEVICE_PATH, BBS_BBS_DP, sizeof(BBS_BBS_DEVICE_PATH));
BbsDPN->DeviceType = BBS_TYPE_HARDDRIVE; // BBS_TYPE_CDROM;
BbsDPN->StatusFlag = 0;
BbsDPN->getString()->stringValue()[0] = '\0';
// appends end-of-device-path node and returns complete DP
BbsDP = (BBS_BBS_DEVICE_PATH *) AppendDevicePathNode(NULL, (EFI_DEVICE_PATH_PROTOCOL *) BbsDPN);
FreePool(BbsDPN);
*/
//
// do boot from default MBR hard disk
//
Status = LegacyBios->LegacyBoot(LegacyBios, BbsDP, 0, NULL);
DBG("LegacyBios->LegacyBoot(): %s\n", efiStrError(Status));
return Status;
}
void DumpBiosMemoryMap()
{
EFI_STATUS Status;
INT32 i, Length; //for debug dump
UINT64 Start, Size;
IA32_REGISTER_SET Regs;
UINT8* BiosMap = (UINT8*)(UINTN)0x7C00;
SetMem(&Regs, sizeof (Regs), 0);
addrEnablePaging(0);
Status = gBS->LocateProtocol(&gEfiLegacy8259ProtocolGuid, NULL, (void**)&gLegacy8259);
if (EFI_ERROR(Status)) {
return;
}
DBG("gEfiLegacy8259ProtocolGuid found\n");
Status = gBS->AllocatePool (EfiBootServicesData,sizeof(THUNK_CONTEXT),(void **)&mThunkContext);
if (EFI_ERROR(Status)) {
return;
}
Status = InitializeBiosIntCaller(); //mThunkContext);
if (EFI_ERROR(Status)) {
return;
}
Regs.E.EBX = 0;
Regs.E.EDI = 0x7C00;
do {
Regs.X.AX = 0xE820;
Regs.E.EDX = 0x534d4150;
Regs.X.CX = 24;
if (LegacyBiosInt86(0x15, &Regs)) {
DBG("finished by bit C\n");
break;
}
if (Regs.E.EBX == 0) {
DBG("finished by ebx=0\n");
break;
}
Regs.E.EDI += 24;
} while (Regs.E.EDI < 0x8000);
Length = ((INT32)(Regs.E.EDI - 0x7c00)) / 24 + 1;
DBG("BiosMemoryMap length=%d:\n Start End Type Ext\n", Length);
for (i = 0; i < Length; i++) {
Start = *(UINT64*)BiosMap;
Size = *((UINT64*)BiosMap + 1);
DBG(" %08llx %08llx %X %08X\n", Start, Start + Size - 1, *(UINT32*)(BiosMap + 16), *(UINT32*)(BiosMap + 20));
BiosMap += 24;
}
}