/* EFI library includes */
#include <EfiBind.h>
#include <EfiTypes.h>
#include <EfiCommon.h>
#include <EfiApi.h>
#include <EfiDriverLib.h>
#include <EfiDevicePath.h>
#include "OSXP.h"
#include "thunk.h"
extern EFI_TPL ProtectedTPL;
#pragma pack(1)
union t_xhl {
UINT16 x;
struct {
UINT8 l;
UINT8 h;
} hl;
};
union t_ex {
UINT32 e;
struct {
UINT16 x;
UINT16 unused;
} ex;
};
union t_exhl {
UINT32 e;
struct {
union t_xhl xhl;
UINT16 unused;
} exhl;
};
struct {
UINT16 gs;
UINT16 fs;
UINT16 es;
UINT16 ds;
union t_ex di;
union t_ex si;
union t_ex bp;
union t_ex sp;
union t_exhl b;
union t_exhl d;
union t_exhl c;
union t_exhl a;
UINT16 interrupt;
UINT16 offset;
UINT16 segment;
UINT16 flags;
} *RealContext;
#define AL RealContext->a.exhl.xhl.hl.l
#define AH RealContext->a.exhl.xhl.hl.h
#define AX RealContext->a.exhl.xhl.x
#define EAX RealContext->a.e
#define BL RealContext->b.exhl.xhl.hl.l
#define BH RealContext->b.exhl.xhl.hl.h
#define BX RealContext->b.exhl.xhl.x
#define EBX RealContext->b.e
#define CL RealContext->c.exhl.xhl.hl.l
#define CH RealContext->c.exhl.xhl.hl.h
#define CX RealContext->c.exhl.xhl.x
#define ECX RealContext->c.e
#define DL RealContext->d.exhl.xhl.hl.l
#define DH RealContext->d.exhl.xhl.hl.h
#define DX RealContext->d.exhl.xhl.x
#define EDX RealContext->d.e
#define DS RealContext->ds
#define ES RealContext->es
#define SI RealContext->si.ex.x
#define ESI RealContext->si.e
#define DI RealContext->di.ex.x
#define EDI RealContext->di.e
typedef struct {
UINT8 PacketSize;
UINT8 Reserved;
UINT16 NumBlocks;
UINT16 DestOff;
UINT16 DestSeg;
UINT64 StartLBA;
} ExtendedBIOSPacket;
typedef struct {
UINT64 Base;
UINT64 Length;
UINT32 Type;
} BIOSMMapDescriptor;
CHAR8 EFIMMapBuf[4096];
#define MMAP_AVAILABLE 0x1
#define MMAP_RESERVED 0x2
#define MMAP_ACPI_RECLAIM 0x3
#define MMAP_ACPI_NVS 0x4
#pragma pack()
UINT16 RealSS;
UINT16 RealSP;
struct breakpoint {
UINT32 addr;
UINT8 inst;
CHAR8 trace;
CHAR8 pause;
};
struct breakpoint breakpoints[] = {
{ 0x20248, 0x0f, 0, 0 }, // is %dx zero? if dx==1, enable paging.
{ 0x20285, 0xc3, 0, 0 }, // where do we return to? whatever was in %dx?
{ 0x2194c, 0x98, 1, 0 }, // start tracing after getting memory map
{ 0x0, 0x00, 0, 0 }
};
#pragma pack(1)
struct Pixel {
CHAR8 Character;
CHAR8 Attribute;
};
#pragma pack()
static struct Pixel LastScreen[25][80];
void ScrapeScreen()
{
struct Pixel *Screen = (struct Pixel *) 0xB8000;
struct Pixel *OldScreen = (struct Pixel *) LastScreen;
int x, y;
for (y = 0; y < 24; y++)
for (x = 0; x < 80; x++, Screen++, OldScreen++) {
if ((Screen->Attribute != OldScreen->Attribute) ||
(Screen->Character != OldScreen->Character)) {
gST->ConOut->SetAttribute(gST->ConOut, Screen->Attribute);
gST->ConOut->SetCursorPosition(gST->ConOut, x+30, y+1);
Print(L"%c", Screen->Character);
OldScreen->Attribute = Screen->Attribute;
OldScreen->Character = Screen->Character;
}
}
gST->ConOut->SetAttribute(gST->ConOut, 7);
gST->ConOut->SetCursorPosition(gST->ConOut, 0, 28);
}
void PMISR()
{
EFI_STATUS rv;
UINT32 Dest;
int i, j;
CHAR8 *iptr;
static int tracing = 0;
static int pausing = 0;
static int Count = 0;
gBS->RestoreTPL(ProtectedTPL);
ScrapeScreen();
Debug(L"(%03d) <%04x:%04x> INT%2x: EAX:%08x EBX:%08x ECX:%08x EDX:%08x "
L"DS:%04x ES:%04x ESI:%08x EDI:%08x SS:%04x SP:%04x ",
Count++,
RealContext->segment,
RealContext->offset,
RealContext->interrupt,
EAX,
EBX,
ECX,
EDX,
DS,
ES,
ESI,
EDI,
RealSS,
RealSP);
switch (RealContext->interrupt) {
case 0x1:
if (tracing) {
Debug(L"SINGLE STEP");
if (pausing)
Pause();
}
else
/* disable single stepping */
RealContext->flags &= 0xfeff;
/* reinstall breakpoints */
for (i=0; breakpoints[i].addr; i++) {
iptr = (CHAR8 *) breakpoints[i].addr;
if (*iptr == breakpoints[i].inst)
*iptr = 0xCC;
}
break;
case 0x3:
Debug(L"BREAKPOINT");
Dest = (RealContext->segment << 4) + RealContext->offset - 1;
int waspatched = 0;
for (i=0; breakpoints[i].addr; i++) {
if (breakpoints[i].addr == Dest) {
RealContext->offset--;
iptr = (CHAR8 *) Dest;
*iptr = breakpoints[i].inst;
waspatched = 1;
tracing = breakpoints[i].trace;
pausing = breakpoints[i].pause;
break;
}
}
if (waspatched)
/* enable single stepping */
RealContext->flags |= 0x0100;
else
Debug(L" (NOT PATCHED)");
break;
case 0x10:
Debug(L"VIDEO BIOS: ");
switch (AH) {
case 0x00: // Set mode
// We currently only run in 160x50
Debug(L"Set mode");
break;
case 0x0A: // Write character
Debug(L"Write character: %c", AL);
break;
case 0x0E: // Teletype output
if ((AL == '\n') || (AL == '\r'))
AL = ' ';
Debug(L"Teletype output: %c", AL);
break;
case 0x12: // Get blanking attribute
Debug(L"Get blanking attribute");
/* This interrupt is called early in NTLDR, so use this
* as an opportunity to install any breakpoints we've
* requested. We can't patch exactly at load time since
* the checksum will fail.
*/
Debug(L"\nPatching breakpoints:\n");
for (i=0; breakpoints[i].addr; i++) {
iptr = (CHAR8 *) breakpoints[i].addr;
if (*iptr == breakpoints[i].inst) {
Debug(L"Patched 0x%08x\n", breakpoints[i].addr);
*iptr = 0xCC;
}
else {
Debug(L"Could not patch 0x%08x: %02x != %02x\n",
breakpoints[i].addr,
*iptr,
breakpoints[i].inst);
/* Print some context. I've been using disassembly
* from the ntldr on my work desktop, and that
* doesn't quite match the version on the SP2 CD.
* This context helps find how many bytes off I
* am so I can correct the breakpoint entry.
*/
for (j=0, iptr = (CHAR8 *)breakpoints[i].addr - 20;
j < 40;
j++, iptr++)
Debug(L"%02x ", *iptr);
Debug(L"\n");
}
}
BH = 7; // grey on black
break;
default:
Debug(L"Unknown function");
}
break;
case 0x11:
Debug(L"EQUIPMENT BIOS: ");
break;
case 0x13:
Debug(L"DISK BIOS: ");
switch (AH) {
case 0x02: // Read sector
Debug(L"Read sectors");
UINT8 Head = DH;
UINT8 Sect = CL & 0x3f;
UINT16 Cyl = CH | ((CL & 0xc0) << 2);
UINT64 LBA = ((Cyl * 256 + Head) * 63) + Sect - 1;
Dest = (ES << 4) + BX;
Debug(L"\n Reading %d blocks to "
L"%04x:%04x (0x%08x) starting from %ld",
AL,
ES,
BX,
Dest,
LBA);
if ((rv = BootDrive->ReadBlocks(BootDrive,
BootDrive->Media->MediaId,
LBA,
AL * BootDrive->Media->BlockSize,
(VOID *) Dest) != EFI_SUCCESS)) {
Debug(L"\n Failed to read disk: %r\n", rv);
HANG;
}
break;
case 0x08: // Get drive parameters
Debug(L"Get drive parameters");
if (DL == 0x80) { // First HD
CX = 0xFEFF;
DX = 0xFE01;
}
break;
case 0x41: // Extended BIOS installation check
Debug(L"Extended BIOS installation check");
if (BX == 0x55AA) {
AH = 0x21;
BX = 0xAA55;
CX = 0x5;
}
break;
case 0x42: // Extended read
Debug(L"Extended read");
ExtendedBIOSPacket *p =
(ExtendedBIOSPacket *) ((DS << 4) + SI);
Dest = (p->DestSeg << 4) + p->DestOff;
Debug(L"\n Reading %d blocks to "
L"%04x:%04x (0x%08x) starting from %ld",
p->NumBlocks,
p->DestSeg,
p->DestOff,
Dest,
p->StartLBA);
if ((rv = BootDrive->ReadBlocks(BootDrive,
BootDrive->Media->MediaId,
p->StartLBA,
BootDrive->Media->BlockSize *
p->NumBlocks,
(VOID *) Dest) != EFI_SUCCESS)) {
Debug(L"\n Failed to read disk: %r\n", rv);
HANG;
}
AH = 0;
break;
default:
Debug(L"Unknown function");
}
break;
case 0x15:
Debug(L"MISC BIOS: ");
switch (AX) {
case 0xE820: // Get memory map
Debug(L"Get system memory map");
EAX = 0x534D4150;
static UINTN EFIMMapSize;
EFI_MEMORY_DESCRIPTOR *EFIMMAP =
(EFI_MEMORY_DESCRIPTOR *)
EFIMMapBuf;
static CHAR8 *pMMAP = (CHAR8 *) EFIMMapBuf;
UINTN EFIMapKey;
static UINTN EFIDescriptorSize;
UINTN EFIDescriptorVersion;
static int MemoryMapIndex = 0;
BIOSMMapDescriptor *BIOSMMAP =
(BIOSMMapDescriptor *)
((ES << 4) + DI);
if (EBX == 0) { // First call to this function
EFIMMapSize = sizeof(EFIMMapBuf);
if ((rv = gBS->GetMemoryMap(&EFIMMapSize,
(EFI_MEMORY_DESCRIPTOR *)
EFIMMapBuf,
&EFIMapKey,
&EFIDescriptorSize,
&EFIDescriptorVersion)) !=
EFI_SUCCESS) {
Debug(L"\nUnable to get memory map: %r\n", rv);
HANG;
}
}
if (EFIMMapSize > 0) {
EFIMMAP = (EFI_MEMORY_DESCRIPTOR *) pMMAP;
BIOSMMAP->Base = EFIMMAP->PhysicalStart;
BIOSMMAP->Length = EFIMMAP->NumberOfPages * 4096;
switch (EFIMMAP->Type) {
case EfiConventionalMemory:
BIOSMMAP->Type = MMAP_AVAILABLE;
break;
case EfiACPIReclaimMemory:
BIOSMMAP->Type = MMAP_ACPI_RECLAIM;
break;
case EfiACPIMemoryNVS:
BIOSMMAP->Type = MMAP_ACPI_NVS;
break;
default:
BIOSMMAP->Type = MMAP_RESERVED;
break;
}
EFIMMapSize -= EFIDescriptorSize;
pMMAP += EFIDescriptorSize;
MemoryMapIndex++;
};
EBX = (EFIMMapSize > EFIDescriptorSize) ?
MemoryMapIndex : 0;
Debug(L"\n MMAP: Base 0x%016lx, Length 0x%016lx, Type %d",
BIOSMMAP->Base,
BIOSMMAP->Length,
BIOSMMAP->Type);
break;
default:
Debug(L"Unknown function");
}
break;
case 0x16:
Debug(L"KEYBOARD BIOS: ");
break;
case 0x19:
Debug(L"REBOOT REQUESTED - ABORTING");
for (;;);
break;
case 0x1A:
Debug(L"TIMER/PCI BIOS: ");
break;
/* Run the native EFI handler for this interrupt? */
/* Keep getting INT68 now and then .. what is that? Seems to work
* without it, must not be that important.
*/
default:
Debug(L"Unknown interrupt");
#if 0
InterruptGate *IG = (InterruptGate *) (ProtectedIDTR.Base +
RealContext->interrupt * 8);
Debug(L"Unknown interrupt (%08x)",
IG->OffsetLow + (IG->OffsetHigh << 16));
void (*func)() = IG->OffsetLow + (IG->OffsetHigh << 16);
func();
#endif
}
ProtectedTPL = gBS->RaiseTPL(EFI_TPL_HIGH_LEVEL);
}