PnP BIOS
Posted: Sun Sep 12, 2004 2:07 pm
Hi,
I'm having some problems calling the PnP BIOS. My code is a bit lenghty so I'll try to post the most important parts of it only. Please take some time and read through it, I've now been working on this for 2 weeks and I just can't find the error.
Descriptors involved in the BIOS call:
The descriptors' base addresses are set at run-time because the BIOS runs in 16bit pmode and therefore can't access anything in a segment beyond 64k. I set them up as follows:
'BIOS_Selector' and 'BIOS_Offset' are defined in the asm part of my code and will be used for the final jump.
The asm-code (sorry this is somewhat long...):
Thanks you,
gaf
I'm having some problems calling the PnP BIOS. My code is a bit lenghty so I'll try to post the most important parts of it only. Please take some time and read through it, I've now been working on this for 2 weeks and I just can't find the error.
Descriptors involved in the BIOS call:
Code: Select all
; 0x20 descriptor - PnP call segment
; base : (set at runtime) limit: 0x10 (64 KB)
; DPL : 0 32 bit
dd 0x00000010 dd 0x00c09A00
; 0x28 descriptor - PnP BIOS data segment
; base : (set at runtime) limit: 0xFFFF (64 KB)
; DPL : 0 16 bit
dd 0x0000FFFF dd 0x00009200
; 0x30 descriptor - PnP BIOS code segment
; base : (set at runtime) limit: 0xFFFF (64 KB)
; DPL : 0 16 bit
dd 0x0000FFFF dd 0x00009A00
; 0x38 descriptor - PnP BIOS stack segment
; base : (set at runtime) limit: 0x1000 (4 KB)
; DPL : 0 16 bit
dd 0x00001000 dd 0x00009200
; 0x40 descriptor - PnP transfer segment (1)
; base : (set at runtime) limit: 0xFFFF (64 KB)
; DPL : 0 16 bit
dd 0x0000FFFF dd 0x00009200
; 0x48 descriptor - PnP transfer segment (2)
; base : (set at runtime) limit: 0xFFFF (64 KB)
; DPL : 0 16 bit
dd 0x0000FFFF dd 0x00009200
Code: Select all
SetDescriptorBase(GDT_BIOS_CODE, (u32)pnp_block.P16_code_segment);
SetDescriptorBase(GDT_BIOS_DATA, (u32)pnp_block.P16_data_segment);
SetDescriptorBase(GDT_BIOS_STACK, 0);
// CallBIOS2 is the asm procedure that calls the BIOS, see below
u32 call_bios2 = (u32) pager().LinearToPhysical((void*)((u32)CallBIOS2 &0xfffff000));
call_bios2 += (u32) CallBIOS2 &0xfff;
SetDescriptorBase(GDT_CALL, call_bios2);
BIOS_Selector = GDT_BIOS_CODE;
BIOS_Offset = pnp_block.P16_code_offset;
The asm-code (sorry this is somewhat long...):
Code: Select all
CallBIOS:
; We're about to disable paging for the BIOS call
; This will make all selectors invalide which
; means that we have to save the parameters by
; putting them into the CPU's registers
push esi
push edi
push ebp
mov ebp, esp
; Don't worry about the way I've stacked the args - I've checked that
mov eax, [ss:ebp+20]
shl eax, 16
or eax, [ss:ebp+16]
mov ebx, [ss:ebp+28]
shl ebx, 16
or ebx, [ss:ebp+24]
mov ecx, [ss:ebp+36]
shl ecx, 16
or ecx, [ss:ebp+32]
mov edx, [ss:ebp+44]
shl edx, 16
or edx, [ss:ebp+40]
; Switch to the BIOS stack
mov bp, 0x38
mov ss, bp
mov [Vstack], esp
mov esp, 0x400
; Disable paging
mov ebp, cr0
xor ebp, 0x80000000
mov cr0, ebp
push ds
push es
push fs
push gs
pushf
call 0x20:0 ; Far call to GDT_CALL:CallBIOS2
popf
pop gs
pop fs
pop es
pop ds
; Re-enable paging
mov ebx, cr0
or ebx, 0x80000000
mov cr0, ebx
; Restore the stack
mov bx, 0x18
mov ss, bx
mov esp, [Vstack]
pop ebp
pop edi
pop esi
ret
Vstack dd 0
CallBIOS2:
; Push the parameters on a 16bit stack
push edx
push ecx
push ebx
push eax
; Call the entrypoint
call far word [BIOS_ENTRYPOINT]
add esp, 16
retf
BIOS_ENTRYPOINT:
BIOS_Offset dw 0
BIOS_Selector dw 0
gaf