Page 1 of 1

LGDT and RETF

Posted: Tue May 17, 2005 11:50 am
by fraserjgordon
My kernel uses dynamically allocated segment selectors so I cannot do the traditional "ljmp Selector, Offset" jump after loading the GDT without resorting to self-modifying code, which I prefer to avoid.

Is it safe (and portable among Intel-compatible processors) to instead use:

Code: Select all

pushl %edx;
pushl $Offset;
lgdt (%ecx);
lret
Where edx contains the selector and ecx contains the GDT Descriptor address.

I believe pushing 32-bits is correct for the selector, as a lret (retf) pops 32-bits for the selector and discards the top 16-bits (according to Intel ;))

This seems to work on Bochs and my Pentium 4, but I don't have other PCs to test it on. Does anyone else have experience of using this method?

Thanks in advance,
Fraser

Re:LGDT and RETF

Posted: Tue May 17, 2005 2:28 pm
by gaf
Hello,
I don't know about the portability of your code, but there's an alternative from which I know that it's supported by all 386+. These processors support a (far) jump that gets its destination selector and offset from the memory address that is given as an operator.

Code: Select all

; still in real-mode..
mov dword [pmode_jump], pmode_entry
mov  word [pmode_jump+4], selector

lgdt [label]

pmode_entry:
...
pmode_jump:
offset   dd 0
selector dw 0
http://alien.dowling.edu/~rohit/nasmdocb.html#section-B.133

"The JMP FAR mem forms execute a far jump by loading the destination address out of memory. The address loaded consists of 16 or 32 bits of offset (depending on the operand size), and 16 bits of segment. The operand size may be overridden using JMP WORD FAR mem or JMP DWORD FAR mem."

regards,
gaf

Re:LGDT and RETF

Posted: Wed May 18, 2005 5:27 am
by Pype.Clicker
afaik, the 'retf' technique should work. you could also make sure that a few segments are pre-allocated so that you can hardcode the jump to pmode.

@gaf: what you suggest actually do use 'self-modifying code' which Gordon seems to try to avoid. Note that iirc, a 'jmp .next" would be welcome after the mov [pmode_jmp+4] instruction to flush pre-decoded instructions.

Re:LGDT and RETF

Posted: Wed May 18, 2005 9:31 am
by gaf
Hi,
what I've posted is not self-modifying code, it's just wrong ;)
For some reason I have forgotten the all important jump-instruction..

Code: Select all

mov dword [destination], pmode_entry
mov  word [destination+4], selector

lgdt [my_gdt]
mov eax, cr0
or  eax, 1
mov cr0, eax

jmp far dword [destination] ; <---

pmode_entry:
; add tons of pmode code here

destination:
dd 0  ; offset
dw 0  ; selector to be used
It works (more or less) the same way as the retf-trick, except that it's more offical and therefore probably also more reliable..

regards,
gaf

Re:LGDT and RETF

Posted: Wed May 18, 2005 5:12 pm
by fraserjgordon
Thanks very much for the quick replies. If you were wondering, I'm not using self-modifying code because the pages covering kernel code are marked as read-only and this reloading of the GDT is after enabling paging to update it to the new linear address. The entire read-only code thing is to allow for post-mortem debugging of crashes. I know Bochs lets you do this, but it doesn't really help you when on real hardware!

Thanks again,
Fraser

Re:LGDT and RETF

Posted: Thu May 26, 2005 1:12 pm
by Kim
Using retf should work without any probs (tested it on a old 386), even intel docs say you can use it as an option to setup CS.

[tt]
Implied load instructions such as the far pointer versions of the CALL, JMP, and RET
instructions, the SYSENTER and SYSEXIT instructions, and the IRET, INTn, INTO and
INT3 instructions. These instructions change the contents of the CS register (and
sometimes other segment registers) as an incidental part of their operation.
[/tt]

Code: Select all

procedure kload_gdt(); assembler; [public, alias: 'kload_gdt'];
asm
   push dword GDT_KERNEL_CODE_SEL
   push dword offset @loadedcs
   lgdt gdtr
   retf
@loadedcs:
   mov ax, GDT_KERNEL_DATA_SEL
   mov ss, ax
   mov ds, ax
   mov es, ax
   mov fs, ax
   mov gs, ax
end ['EAX'];