Problem with VESA 3.0 in Protect Mode
Posted: Wed Jun 20, 2018 10:32 pm
Hello World!
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...
Anyone help me,
Thanks in advanced!
PheroSiden
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