Call gate not returning

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
_OScoder

Call gate not returning

Post by _OScoder »

Ok, I've set up my first call gate in my OS (many thanks to candy for the help), but when I return from the function (written in gcc), bochs gives out the error:

Code: Select all

>>PANIC<< fetch_raw_descriptor: LDTR.valid=0
The call gate is a gdt one, and returns using the [tt]lret[/tt] (AT&T equiv for RET FAR), and it is called from an asm function. It certainly gets activated fine, which I know due to the message shown on the screen. I've tested it without the lret instruction (ie putting it into a loop) and it has worked fine.

The thing is I don't actually have an LDT, so this makes me think somehow the stack is getting messed up somehow.

This is the c code:

Code: Select all

void start_tests();
void call_test();   /*Function in the asm file*/
void ring0();
void ring3();

void start_tests()
{
   gdt_add_gate(   (unsigned long int)&ring0,      /*Pointer to our funtion*/
               _DESCRIPTOR_CALL_GATE | _DPL_0,   /*Make our gate a call gate, with DPL 0 (ring0)*/
               0x08,                     /*Our currect code segment*/
               9);                        /*Put it in the 9th GDT entry*/
   call_test();   /*Call our asm test function*/
}

void ring0()
{
   _print("In ring0",0x0C,3);
   asm("lret");            /*The AT&T 'long return' instruction. For ret'ing to a different segment*/
}

void ring3()
{
   _print("In ring3",0x0B,4);
   for(;;)
    asm("nop");
}
and the asm code:

Code: Select all

[bits 32]
[global _call_test]

_call_test:
 CALL 0x48:0x00   ; The call gate's place in the gdt
 _loopage:   ; This loop is to make sure any errors caused
  NOP      ;can only be the fault of the code we are
 JMP _loopage    ;trying to test.
RET
Thanks in advance,
Me
AR

Re:Call gate not returning

Post by AR »

That will not work, like an interrupt gate, you will need as assembly wrapper stub, you cannot call the C code directly.

Your "ring0" function looks like:

Code: Select all

ring0:
push %ebp
mov %esp, %ebp
push $string
.extern _print
call _print
lret
pop %ebp
ret
You can resolve this by hacking the C code (which will most likely break if you change or upgrade the compiler, and is just plain confusing) by adding -fomit-frame-pointer to the GCC command line or manually poping %EBP, I emphasise that hacking it like this is not a good idea.

You will be better off with an ASM Wrapper:

Code: Select all

ring0_callgate_entry:
#pushf   # I can't remember if call gates need EFLAGS to be saved manually, I think it does
pusha
push %ds
push %es

mov %ss, %eax
mov %eax, %ds
mov %eax, %es

.extern ring0
call ring0

pop %es
pop %ds
popa
#popf
lret
0Scoder
Member
Member
Posts: 53
Joined: Sat Nov 11, 2006 8:02 am

Re:Call gate not returning

Post by 0Scoder »

Thanks, my code work fine now (which is a relief)! I just put in a 'pop %ebp' instruction before the lret, is there anything that could go wrong with this?

Also, is there a way I can capture the asm code that gcc makes next time so I can fix problems like this easier?
AR

Re:Call gate not returning

Post by AR »

The things that can go wrong are that different compilers and different versions of GCC may have different start/end code which will break, using the "POP %EBP" hack will itself break if you enable optimizations above level 1.

You can ask GCC to compile to assembly instead of directly compiling and then hack it each time you rebuild that file but this is almost as bad as before, simply because it would quickly become irritating, the optimal solution as I already said is to use the Assembly stub (you need to save EFLAGS and all the general registers when the system call starts because entering C code directly will cause GCC to trash the register states by loading whatever it feels like into them which will make it hard to send parameters in the calls)
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Call gate not returning

Post by Pype.Clicker »

fetch_raw_descriptor: LDTR.valid=0
Many of you have said "but ... i do not have an LDT and i read it wasn't mandatory!?". You're right. And so is BOCHS. This message usually means that your program tried to load a selector with some garbage value, which happened to have the 3rd bit (Table Indicator) set. The CPU will try to look up the descriptor in the LDT, but there's no LDT registered! In most cases, the error comes from some mispairing of push and pop on the stack, which lead to a non-selector value to be loaded in a segment register.

-- as seen on the FAQ
Post Reply