I'm try to call VESA 3.0 function from BIOS in protected mode but crash with general protection fault. I followed VESA 3.0 specf but no details information how to do this.
I use OpenWatcom C++ 2.0 and MS-DOS 32 bits environment.
and here is my code...
Code: Select all
// VESA 3.0 protected mode info block
typedef struct
{
unsigned char Signature[4]; // PM Info Block signature ('PMID')
unsigned short EntryPoint; // offset of PM entry point within BIOS
unsigned short PMInitialize; // offset of PM initialization entry point
unsigned short BIOSDataSel; // selector to BIOS data area emulation block
unsigned short A0000Sel; // selector to 0xa0000
unsigned short B0000Sel; // selector to 0xb0000
unsigned short B8000Sel; // selector to 0xb8000
unsigned short CodeSegSel; // selector to access code segment as data
unsigned char InProtectMode; // true if in protected mode
unsigned char Checksum; // sum of all bytes in this struct must match 0
} VBE_PM_INFO_BLOCK;
// VESA 3.0 far call memory struct (48 bits address)
typedef struct
{
unsigned int offset; // 32 bits offset
unsigned short segment; // 16 bits segment
} VBE_FAR_CALL;
// switch to 16 bit protect mode stack
void StackSwitch(void *mesp, void *mss)
{
_asm {
mov eax, dr3
mov edx, mesp
pushf
pop ecx
add eax, stackOffset
cli
push ss
cmp [esp], 0x10
je kernelStack
pop eax
jmp switchStack
kernelStack:
pop [eax + 4]
mov esp, [eax]
switchStack:
lss esp, mss
push ecx
popf
jmp fword ptr [edx]
}
}
int main(int argc, char const *argv[])
{
VBE_FAR_CALL fcall;
VBE_DRIVER_INFO drvInfo;
VBE_PM_INFO_BLOCK *pmInfo;
unsigned int val = 0;
unsigned int i = 0;
unsigned char biosCheckSum = 0;
unsigned char *biosCode;
unsigned char *biosData;
unsigned char *biosStack;
unsigned char *biosPtr;
unsigned short biosDataSel;
unsigned short biosCodeSel;
unsigned short a0000Sel;
unsigned short b0000Sel;
unsigned short b8000Sel;
unsigned short biosInitSel;
unsigned short biosStackSel;
unsigned short vbeInfoSel;
// copy BIOS code from physical address 0xC0000 to RAM
biosCode = (unsigned char*)malloc(VBE_CODE_SIZE);
if (!biosCode) return 1;
memcpy(biosCode, (unsigned char*)0xC0000, VBE_CODE_SIZE);
// find VESA 3.0 protected mode info block signature
biosPtr = biosCode;
while ((biosPtr <= biosCode + VBE_CODE_SIZE - sizeof(VBE_PM_INFO_BLOCK)) && memcmp(((VBE_PM_INFO_BLOCK*)biosPtr)->Signature, "PMID", 4)) biosPtr++;
// check for correct signature
pmInfo = (VBE_PM_INFO_BLOCK*)biosPtr;
if (memcmp(pmInfo->Signature, "PMID", 4))
{
printf("VESA PMID not found!\n");
return 1;
}
// calculate BIOS checksum
for (i = 0; i != sizeof(VBE_PM_INFO_BLOCK); i++) biosCheckSum += *biosPtr++;
if (biosCheckSum)
{
printf("VESA BIOS checksum error!\n");
return 1;
}
// setup structure (provide selectors, map video mem, ...)
biosData = (unsigned char *)malloc(VBE_DATA_SIZE);
if (!biosData) return 1;
memset(biosData, 0, VBE_DATA_SIZE);
// setup BIOS data selector
biosDataSel = AllocSelector();
if (biosDataSel == 0 || biosDataSel == 0xFFFF) return 1;
if (!SetSelectorRights(biosDataSel, 0x8092)) return 1;
if (!SetSelectorBase(biosDataSel, (unsigned int)biosData)) return 1;
if (!SetSelectorLimit(biosDataSel, VBE_DATA_SIZE - 1)) return 1;
pmInfo->BIOSDataSel = biosDataSel;
// map video memory
a0000Sel = AllocSelector();
if (a0000Sel == 0 || a0000Sel == 0xFFFF) return 1;
if (!SetSelectorRights(a0000Sel, 0x8092)) return 1;
if (!SetSelectorBase(a0000Sel, (unsigned int)0xA0000)) return 1;
if (!SetSelectorLimit(a0000Sel, 0xFFFF)) return 1;
pmInfo->A0000Sel = a0000Sel;
b0000Sel = AllocSelector();
if (b0000Sel == 0 || b0000Sel == 0xFFFF) return 1;
if (!SetSelectorRights(b0000Sel, 0x8092)) return 1;
if (!SetSelectorBase(b0000Sel, (unsigned int)0xB0000)) return 1;
if (!SetSelectorLimit(b0000Sel, 0xFFFF)) return 1;
pmInfo->B0000Sel = b0000Sel;
b8000Sel = AllocSelector();
if (b8000Sel == 0 || b8000Sel == 0xFFFF) return 1;
if (!SetSelectorRights(b8000Sel, 0x8092)) return 1;
if (!SetSelectorBase(b8000Sel, (unsigned int)0xB8000)) return 1;
if (!SetSelectorLimit(b8000Sel, 0x7FFF)) return 1;
pmInfo->B8000Sel = b8000Sel;
// setup BIOS code selector
biosCodeSel = AllocSelector();
if (biosCodeSel == 0 || biosCodeSel == 0xFFFF) return 1;
if (!SetSelectorRights(biosCodeSel, 0x8092)) return 1;
if (!SetSelectorBase(biosCodeSel, (unsigned int)biosCode)) return 1;
if (!SetSelectorLimit(biosCodeSel, VBE_CODE_SIZE - 1)) return 1;
pmInfo->CodeSegSel = biosCodeSel;
// put BIOS code to run in protect mode
pmInfo->InProtectMode = 1;
// alloc code segment selector for initialize function
biosInitSel = AllocSelector();
if (biosInitSel == 0 || biosInitSel == 0xFFFF) return 1;
if (!SetSelectorRights(biosInitSel, 0x8092)) return 1;
if (!SetSelectorBase(biosInitSel, (unsigned int)biosCode)) return 1;
if (!SetSelectorLimit(biosInitSel, VBE_CODE_SIZE - 1)) return 1;
// alloc stack selector
biosStack = (unsigned char *)malloc(VBE_STACK_SIZE);
if (!biosStack) return 1;
biosStackSel = AllocSelector();
if (biosStackSel == 0 || biosStackSel == 0xFFFF) return 1;
if (!SetSelectorRights(biosStackSel, 0x8092)) return 1;
if (!SetSelectorBase(biosStackSel, (unsigned int)biosStack)) return 1;
if (!SetSelectorLimit(biosStackSel, VBE_STACK_SIZE - 1)) return 1;
// call initialize protect mode function first
fcall.offset = pmInfo->PMInitialize;
fcall.segment = biosInitSel;
_asm {
push biosStackSel
push VBE_STACK_SIZE
call StackSwitch
lea esi, fcall
call fword ptr [esi]
call StackSwitch
}
//// CRASHED HERE: GENERAL PROTECTION FAULT!!!!!!
// call initialize VBE controller
vbeInfoSel = AllocSelector();
if (vbeInfoSel == 0 || vbeInfoSel == 0xFFFF) return 1;
if (!SetSelectorRights(vbeInfoSel, 0x8092)) return 1;
if (!SetSelectorBase(vbeInfoSel, (unsigned int)&drvInfo)) return 1;
if (!SetSelectorLimit(vbeInfoSel, sizeof(VBE_DRIVER_INFO) - 1)) return 1;
fcall.offset = pmInfo->EntryPoint;
fcall.segment = pmInfo->CodeSegSel;
_asm {
push biosStackSel
push VBE_STACK_SIZE
call StackSwitch
mov ax, vbeInfoSel
mov es, ax
mov eax, 0x4F00
xor edi, edi
lea esi, fcall
call fword ptr [esi]
call StackSwitch
mov val, eax
}
if (val == 0x004F && !memcmp(drvInfo.VBESignature, "VESA", 4) && drvInfo.VBEVersion >= 0x0200) printf("OK!\n");
else printf("VESA 3.0 INIT FAILED!\n");
return 0;
}
Thanks in advanced!
PheroSiden