Page 1 of 1

Calling PXE functions from protected mode

Posted: Sun Aug 03, 2008 6:46 am
by sevobal
Hi,
I've written a bootloader which starts in real mode and than switches to protected mode. I boot this one over PXE and it worked. But now I want to use some functions from the PXE API. Therefor my code detects the "!PXE" structur and saves the value of EntryPointESP into [PXE_API_Entry]. I can verify that the value is correct. Now I want to call the GET CHACHED INFO function from the PXE API and tried following:

Code: Select all

...
    push es
    push s_PXENV_GET_CACHED_INFO
    push 0x0071
    call far [PXE_API_Entry]
    add sp,6
...

s_PXENV_GET_CACHED_INFO:
    status      db 0x00 
    packetType  dw 0x0002
    bufferSize  dw 0x0000
    buffer      dw 0x0000
    bufferLimit dw 0x0000
By doing the far call my Kernel ends up with an CPU Triple Fault. Has anyone an idea what's wrong?

Thank you :)

Re: Calling PXE functions from protected mode

Posted: Sun Aug 03, 2008 8:12 am
by AJ
Hi,

I don't know abut PXE, but one thing that stands out is this:

Code: Select all

add sp,6
If you are in 32 bit PMode in a 32 bit default operand size, each time you push a word, it is actually a double word that is pushed to the stack (and you will be using ESP, not SP).

Cheers,
Adam

Re: Calling PXE functions from protected mode

Posted: Sun Aug 03, 2008 8:20 am
by sevobal
thanks you're right, but using esp instead of sp doesn't solve my triple fault. I guess I've missed something, but I don't know what so I hope someone here knows something about working with PXE in PM.

Re: Calling PXE functions from protected mode

Posted: Sun Aug 03, 2008 8:26 am
by Brendan
Hi,
sevobal wrote:By doing the far call my Kernel ends up with an CPU Triple Fault. Has anyone an idea what's wrong?
I've never used the protected mode interface for PXE, however there's some things you could check...

1) The code segment used by the PXE API *must* be a 16-bit code segment, even if your code is 32-bit protected mode, and even if the stack is 32-bit.

2) If you're using a 32-bit segment for the stack, then "add sp,6" is dodgy. For a 32-bit stack everything is aligned on a 4-byte boundary, so "push word foo" would decrement ESP/SP by 4 bytes (even though you're only pushing 2 bytes). This means that if you push 3 parameters on the stack before calling a function then you need to do "add esp,3*4" to clean up the stack after the function returns. I'd also recommend using ESP instead of SP (note: I'm not entirely sure if it's necessary to use ESP, but I'd still recommend using ESP even if it's not necessary).

3) There's a "StatusCallout" field in the !PXE structure (at offset 0x18), which points to a real mode routine that uses BIOS interrupts. For protected mode, you need to replace this routine with a protected mode routine that doesn't use BIOS interrupts *or* disable status callouts by setting this field to -1 (or 0xFFFF:0xFFFF?).

4) AFAIK you need to build 5 or more contiguous GDT descriptors to match details found in the !PXE structure (starting at offset 0x20), and set the "FirstSelector" field in the !PXE structure (at offset 0x1E) to the first selector you've used. The "SegDescCnt" field (at offset 0x1D) tells you how many descriptors you need to create.

I'm not sure if there's any other hassles you need to take care of...


Cheers,

Brendan

Re: Calling PXE functions from protected mode

Posted: Sun Aug 03, 2008 6:52 pm
by Dex
You could try setting real and pmode addressing the same, at run time as i do eg:

Code: Select all

	xor   ebx,ebx
	mov   bx,ds			       ; BX=segment
	shl   ebx,4			       ; BX="linear" address of segment base
	mov   eax,ebx
	mov   [sys_code_1 + 2],ax	       ; set base address of 32-bit segments
	mov   [sys_data_1 + 2],ax
	mov   [Real_code_1 + 2],ax	       ; set base address of 16-bit segments
	mov   [Real_data_1 + 2],ax
	shr   eax,16
	mov   [sys_code_1 + 4],al
	mov   [sys_data_1 + 4],al
	mov   [Real_code_1 + 4],al
	mov   [Real_data_1 + 4],al

	mov   [sys_code_1 + 7],ah
	mov   [sys_data_1 + 7],ah
	mov   [Real_code_1 + 7],ah
	mov   [Real_data_1 + 7],ah
	add   ebx,gdt			       ; EBX=linear address of gdt
	mov   [gdtr + 2],ebx
	
	cli				       ; Disable interrupts, 
	mov   ax,cs
	mov   [RealModeCS],ax
	lgdt  [gdtr]			       ; Load the GDT descriptor

	mov   eax, cr0			       ; Copy the contents of CR0 into EAX
	or    eax, 1			       ; Set bit 0
	mov   cr0, eax			       ; Copy the contents of EAX into CR0

	jmp   10h:clear_pipe		       ; Jump to code segment, offset clear_pipe

USE32					       ; We now need 32-bit instructions
clear_pipe:

              ; MORE CODE HERE
But i think your best going to and from Pmode.

Re: Calling PXE functions from protected mode

Posted: Mon Aug 04, 2008 12:12 pm
by sevobal
Okay,
now I've added the 7 deskriptors to my GDT:

Code: Select all

; PXE Stack segment descriptor
PXE_STACK_SEL	equ	$-gdt
gdt9:
            dw 0xFFFF              
	dw 0x2000
	db 0
	db 0x91	
            db 0x4F
	db 0
	
PXE_UNDIDATA_SEL	equ	$-gdt
gdt10:
            dw 0xFFFF
	dw 0x3000
	db 0
	db 0x91	
            db 0x4F
	db 0
	
PXE_UNDICODE_SEL	equ	$-gdt
gdt11:
            dw 0xFFFF             
	dw 0x4000	             
	db 0
	db 0x95 		       
            db 0x4F                 
	db 0
	
PXE_UNDICODEWRITE_SEL	equ	$-gdt
gdt12:
            dw 0xFFFF              
	dw 0x5000	            
	db 0
	db 0x91			            
            db 0x4F                 
	db 0
	
PXE_BCDATA_SEL	equ	$-gdt
gdt13:
            dw 0xFFFF  
	dw 0x6000
	db 0
	db 0x91			           
            db 0x4F                 
	db 0
	
PXE_BCCODE_SEL	equ	$-gdt
gdt14:
            dw 0xFFFF               
	dw 0x7000	             
	db 0
	db 0x95			            
            db 0x4F                 
	db 0
	
PXE_BCWRITE_SEL	equ	$-gdt
gdt15:
            dw 0xFFFF               
	dw 0x8000
	db 0
	db 0x91		
            db 0x4F                
	db 0
And than I've written the excepted values at offset 0x1E and following of the PXE Structur Table:

Code: Select all

pxe_found:
    add edi, 0x14
    mov dword esi, [es:edi]
    mov dword [PXE_API_Entry], esi
    
    add edi, 0x04
    mov dword [es:edi], -1
    
    add edi, 0x05
    cmp byte [es:edi], 0x04
    je sel4
    cmp byte [es:edi], 0x07
    je sel7
    
    jmp detect_pxe_done
    
sel4:
    mov ebx, 0xB83D8
    mov byte [es:ebx], '4'
    jmp detect_pxe_done
    
sel7:
    mov ebx, 0xB83D8
    mov byte [es:ebx], '7'
    
    add edi, 0x01
    mov word [es:edi], PXE_STACK_SEL
    
    add edi, 0x02
    mov word [es:edi], PXE_STACK_SEL
    add edi, 0x02
    mov dword [es:edi], 0x00002000
    add edi, 0x04
    mov word [es:edi], 0xFFFF
    
    add edi, 0x02
    mov word [es:edi], PXE_UNDIDATA_SEL
    add edi, 0x02
    mov dword [es:edi], 0x00003000
    add edi, 0x04
    mov word [es:edi], 0xFFFF
    
    add edi, 0x02
    mov word [es:edi], PXE_UNDICODE_SEL
    add edi, 0x02
    mov dword [es:edi], 0x00004000
    add edi, 0x04
    mov word [es:edi], 0xFFFF
    
    add edi, 0x02
    mov word [es:edi], PXE_UNDICODEWRITE_SEL
    add edi, 0x02
    mov dword [es:edi], 0x00005000
    add edi, 0x04
    mov word [es:edi], 0xFFFF
    
    add edi, 0x02
    mov word [es:edi], PXE_BCDATA_SEL
    add edi, 0x02
    mov dword [es:edi], 0x00006000
    add edi, 0x04
    mov word [es:edi], 0xFFFF
    
    add edi, 0x02
    mov word [es:edi], PXE_BCCODE_SEL
    add edi, 0x02
    mov dword [es:edi], 0x00007000
    add edi, 0x04
    mov word [es:edi], 0xFFFF
    
    add edi, 0x02
    mov word [es:edi], PXE_BCWRITE_SEL
    add edi, 0x02
    mov dword [es:edi], 0x00008000
    add edi, 0x04
    mov word [es:edi], 0xFFFF
    
    jmp detect_pxe_done
But if I want to call the function...

Code: Select all

    mov ax, PXE_UNDICODE_SEL
    mov es, ax
        
    push es
    push s_PXENV_GET_CACHED_INFO
    push 0x0071
    call far [PXE_API_Entry]
    add esp, 3 * 4
...I'm still ending in a system crash :(

Re: Calling PXE functions from protected mode

Posted: Wed Aug 06, 2008 12:41 am
by sevobal
Nobody, how has an idea? Maybe I did something wrong with des descriptors and didn't realized that...

Re: Calling PXE functions from protected mode

Posted: Wed Aug 06, 2008 1:40 am
by Brendan
Hi,
sevobal wrote:Nobody, how has an idea? Maybe I did something wrong with des descriptors and didn't realized that...
Your code to setup descriptors does look dodgy - it should be more like:

Code: Select all

    totalPXEdescriptors = *(PXE_structure + 0x17);
    for(i = 0; i < totalPXEdescriptors; i++) {
        base = *(PXE_structure + 0x20 + i * 8);
        setGDTdescriptorBase(firstPXEdescriptor + i, base);
    }
Note: The code above is pseudo-code, not C (I know it won't compile!)...

If it doesn't work after this, then you might want to re-read the specification (I don't use the protected mode interface so I don't know that much about it - someone who read the specification carefully would know more than me), and/or install some exception handlers so you can starting finding out some details about what happens when it crashes.


Cheers,

Brendan