mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-24 16:27:42 +01:00
70988228c4
Enclose access to getOemDir... by if (selfOem.oemDirExists()). Enclose access to getKextsDir... by if (selfOem.isKextsDirFound()). closeDebugLog() in UninitRefitLib(). Prevent DBG loop.
1161 lines
35 KiB
C++
1161 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 "LegacyBiosThunk.h"
|
|
//#include <Protocol/Bds.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
|
|
|
|
extern XObjArray<REFIT_VOLUME> Volumes;
|
|
|
|
#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: %hhX 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;
|
|
}
|
|
|
|
}
|