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

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
-m32
Member
Member
Posts: 120
Joined: Thu Feb 21, 2008 5:59 am
Location: Ottawa, Canada

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

Post 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.
User avatar
Dex
Member
Member
Posts: 1444
Joined: Fri Jan 27, 2006 12:00 am
Contact:

Post by Dex »

Just a thought, have you try setting the base of the descriptors to DS * 16.
Like in this example ?
Attachments
PM1.ASM
(24.8 KiB) Downloaded 102 times
User avatar
-m32
Member
Member
Posts: 120
Joined: Thu Feb 21, 2008 5:59 am
Location: Ottawa, Canada

Post by -m32 »

Yeah, that doesn't make any difference :|
User avatar
AJ
Member
Member
Posts: 2646
Joined: Sun Oct 22, 2006 7:01 am
Location: Devon, UK
Contact:

Post 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
User avatar
-m32
Member
Member
Posts: 120
Joined: Thu Feb 21, 2008 5:59 am
Location: Ottawa, Canada

Post 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
oscoder
Member
Member
Posts: 59
Joined: Mon Mar 27, 2006 12:00 am
Location: UK

Post 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
User avatar
-m32
Member
Member
Posts: 120
Joined: Thu Feb 21, 2008 5:59 am
Location: Ottawa, Canada

Post 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.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post 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.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
User avatar
-m32
Member
Member
Posts: 120
Joined: Thu Feb 21, 2008 5:59 am
Location: Ottawa, Canada

Post 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:
Post Reply