Re: Call Gates

Thomas Pornin (bip@nostromo.ens.fr)
Fri, 20 Jun 1997 14:17:40 +0200


In article <199706201139.HAA19029@jade.cs.binghamton.edu> you write:
> I am trying to understand how call gates work and as usual the Intel
>documentation sucks. Can someone tell me or point me to a reference that
>says EXACTLY what happens when a call gate is used, eg: from the moment
>the CALL 0007:00000000 (for example) is executed to the time it is
>handled. I was looking through another OS's source code and they use
>0x07 as the designated call gate for system calls, however when looking
>at how they initted the LDT, the table entry was the first line in the
>descriptor array initialization. Is 0x07 an index into the LDT or is it
>some other number (I dont think it is realted to the type, though). I
>would think that once executed, the CALL makes the processor goto LDT[7]
>and pull out that call gate then do the funky address computation and
>stack change and do the other code...

I once played with these. I hope I have not forgotten too much.

In Intel architecture, under protected mode, segment registers contain an
index to a segment descriptor in the GDT or the LDT. The descriptors are
8 bytes long, so the indexes should be multiples of 8. The last three bits
are used to indicate whether the LDT or the GDT should be used, and some
trickery about privilege levels. There are four such levels (ring 0 to
ring 3) and call gates are meant to allow calls from some unpriviledged
code (ring 3 for instance) to a priviledged code (ring 0). Here, the 0007
indicates the first (0) entry in the LDT, and something like "calling from
ring 3 but I want to become ring 0". The offset part is irrelevant, as the
real target address is hardcoded in the call gate descriptor.

Just after the call, the execution continues from the point targeted by
the call gate descriptor, with the priviledge level stored in this
descriptor. This is indeed a way of implementing system calls.

The way chosen for linux is a bit more hacky, but it has some advantages.
Linux uses a user-triggered interrupt; the system call is an "int $80".
I think it might be a bit slower, but it saves the flags automatically,
allow all types of travels between rings, and this opcode is much smaller
than the "call 0007:00000000" one (2 bytes vs 7).
It also has the great characteristic of switching to a kernel stack, as it
would be really BAD is the kernel had to rely on the user-level stack.

When I saw your message, I first thought it came from some Microsoft fan... :)

--Thomas Pornin