Page 1 of 1

VBE3 & 16 bit call gate problem (AND 32 bit call gate)

Posted: Mon Feb 25, 2008 6:08 pm
by -m32
Hi,

Following the VBE3 spec, I have set up the 100 or so 16 bit segment descriptors as specified.

I use a 16 bit call gate to call the PMInitialize procedure pointed to by the Protected Mode Info Block. The call works properly (as in it jumps into the bios procedure as expected) but on return it fails.

I know this is because the ret sees a 16bit memory address on the stack and it returns 'somewhere' but not to where the call was executed obviously.

According to the Intel docs (IA-32 & 64bit blah blah, vol 3A and Volume 2A), in order to return when using a 16 bit call gate the procedure's offset cannot be more than 0xFFFF bytes from the start of the 32 bit segment. Ok, fine, makes perfect sense. Maybe create a 32 bit segment with a base address closer to the 16 bit procedure and then call the 16 bit call gate that way?

So, what I tried to do next was create a 32 bit call gate which uses a 32 bit segment descriptor with the base address of a 32 bit procedure (just to make sure that would work!). I call it using the CALL 0x50:0 (as specified by the Intel docs - the 0x50 was selected arbitrarily here for my example and the 0 of course is ignored by the CPU for a call gate)

But, this one won't return either!! ?? It jumps into the procedure as expected, I tested it by just sending an int 3 to be caught by my interrupt handler and by calling my puts function to display a string but, when it hits the 'ret' instruction, it fails... what's going on?? :x

For example:

Code: Select all

init_callgate(&gdt[10], 0, 0x60, SD_SEG_PRESENT | SD_DPL_RING0 | SD_SYS_CG16, 0);

/* 32 Bit Code Segment */
gdt_init_descriptor(&gdt[13], 0xFFFF, (uint32)test32,
      SD_SEG_PRESENT | SD_DPL_RING0 | SD_DESC_TYPE_CD | SD_SEG_TYPE_CODE,
      SD_GRAN_4KBYTE | SD_OP_SIZE_32 | 0x0F
);
test32 is a function which takes no parmeters and all it looks like in ASM is this:

Code: Select all

GLOBAL test32
test32:
   ; int 3   ; - Commented, this code is reached and executed fine
   ret       ; Fails


Any suggestions would be greatly appreciated..


I'm not using paging. Nor am I using Task Segments yet. Just a simple flat memory model for now.

Posted: Mon Feb 25, 2008 7:32 pm
by Dex
Just a thought, have you try setting the base of the descriptors to DS * 16.
Like in this example ?

Posted: Wed Feb 27, 2008 7:41 am
by -m32
Yeah, that doesn't make any difference :|

Posted: Wed Feb 27, 2008 8:13 am
by AJ
Hi,

Perhaps if the ret is failing, you stack has become mangled? When the ret fails, do the registers (specifically, EIP and ESP) contain what you would expect the to contain? Does bochs give you any error message before the final register dump?

Cheers,
Adam

Posted: Wed Feb 27, 2008 3:57 pm
by -m32
I'll try dumping the stack contents to the screen to see.

I'm not currently using Bochs, but I gather from this forum that it's a good idea since it actually gives some debugging info.

Not that the protected mode interface exist in Bochs anyway ;) Guess I could always just solve one problem at a time.. Call gates, THEN VBE :P

Posted: Wed Feb 27, 2008 4:35 pm
by oscoder
I'm not speaking from an in-depth knowledge here, but aren't you meant to use a long-return opcode ('lret'), rather than your average 'ret' instruction when returning to a different segment?

Here's the macros I use to test call gates (32 bit) in c:

Code: Select all

 #define long_return()\
	__asm__ __volatile__("mov %ebp,%esp"); \
	__asm__ __volatile__("pop %ebp"); \
	__asm__ __volatile__("lret")	/*The AT&T 'long return' instruction. For ret'ing to a different segment*/

 #define gate_return() \
	__asm__ __volatile__("pop %fs"); \
	__asm__ __volatile__("pop %es"); \
	__asm__ __volatile__("pop %ds"); \
	__asm__ __volatile__("pop %gs"); \
	__asm__ __volatile__("pop %ebx"); \
	long_return()
If you're using nasm, the instruction may be different though (gcc inline asm uses at&t syntax, after all)

Hope that helps,
OScoder

Posted: Thu Feb 28, 2008 3:38 pm
by -m32
If you're using nasm, the instruction may be different though
Yeah, in NASM (and Intel code in general) it's just ret. Ret is 'aware' of what kind of call was made. It's supposed to be able to return to the calling segment (as per Intel docs). Thanks for the suggestion though.

Posted: Thu Feb 28, 2008 4:23 pm
by Combuster
-m32 wrote:
If you're using nasm, the instruction may be different though
Yeah, in NASM (and Intel code in general) it's just ret. Ret is 'aware' of what kind of call was made. It's supposed to be able to return to the calling segment (as per Intel docs). Thanks for the suggestion though.
It isn't. the RET opcode will not figure wether it is a near of far return that needs to be done, it will always do the one you chose. In nasm, ret always assembles to a near return. You need to tell it specifically that you want a far return by writing retf instead of ret.

Posted: Fri Feb 29, 2008 4:22 pm
by -m32
It isn't. the RET opcode will not figure wether it is a near of far return that needs to be done, it will always do the one you chose. In nasm, ret always assembles to a near return. You need to tell it specifically that you want a far return by writing retf instead of ret.
Ahh, thanks for the edjumacation ;) I was going by what the Intel docs say, not realizing that "2.2.5 NASM Doesn't Support Memory Models". I gave it a try with the 32 bit call gate and it returns as it should. Thanks :oops: