How to switch from IA-32e to compatibility mode?

Started by MasmNew, November 08, 2007, 05:56:20 PM

Previous topic - Next topic

MasmNew

Dear All,

as title, I can't use jmp or call at IA-32e mode So, how to switch to compatibility?
I want to exercise which how to entry IA-32e and switching out IA-32e.
Thanks a  lot!

MasmNew

Sorry ..It should how to from 64-bit mode to compatibility mode!

feryno

1. there must be a descriptor in Global Descriptor Table (see e.g. Linux kernel for a sample of such GDT, perhaps something in arch/x86_64/???.s)
perhaps something like this, please read manuals, untested...

GDTR: ; Global Descriptors Table Register
dw ((GDT_end-GDT)/8)*8 - 1 ; limit of GDT (size minus one)
dq GDT ; linear address of GDT

GDT:
NULL_SELECTOR = $ - GDT
GDT0 dw 0,0,0,0 ; null descriptor
; ... other descriptors
; ...
; ... other desctiptors
CODE64_COMPACTIBILITY_SELECTOR = $ - GDT
dw 0FFFFh ; Segment Limit
dw base_address and 0FFFFh ; Base Address (bits 15â€"0)
db (base_address shr 16) and 0FFh ; Base Address (bits 23-16)
db 10011010b ; Present=1, DPL=00b privilege level=0, bit 4. allways 1, bit 3. Code/Data = 1 for code, bit 2. Conforming=0. bit 1. Readable=1, bit 0. Accessed=0
db 10001111b ; bit 7. Granularity=1, bit 6. D Default operand size = 0, bit 5. L=0 Long this is the main difference between 64-bit and compactibility mode 0=compactibility 1=64 bit mode., bit 4. AVL available to software = 0, bits 3.-0. Segment limit (bits 19-16) = 1111b
db (base_address shr 24) and 0FFh ; Base Address (bits 31-24)
;
; other descriptors...
GDT_END:

2. switch from 64-bit mode to desired compactibility mode using jmp (or perhaps push+push+retf instructions should work too...)
e.g.
jmp CODE64_COMPACTIBILITY_SELECTOR:start_of_64bit_code
or perhaps this is another way too?
lea rax,[start_of_64bit_code]
mov cx,CODE64_COMPACTIBILITY_SELECTOR ; please note that you can set something in low 3 bits of the selector... but for a first sample you needn't..., read manuals for more
push rax
push rcx
retf

feryno

iretd (db 0CFh) should be used to switch from 64-bit to compactibility
iretq (db 48h, 0CFh) to jump to 64-bit (from 64-bit surely, or perhaps from compactibility too?)

sample how to switch from 64-bit to 64-bit (do some tests for 64->compatibility please)
assume you have all target registers prepared in memory (e.g. 1 thread context from more when multitasking)

movzx eax,word [target_SS]
push rax
push qword [target_RSP]
push qword [target_RFLAGS]
movzx eax,word [target_CS]
push rax
push qword [target_RIP]
iretq ; (or perhaps iretd to switch from 64 to compactibility ?)

(I didn't tested these instructions for such a purpose yet... just my thoughts)
you certainly must have correct code descriptor and load it to CS so the instructions in that code segment are recognized as 32-bit and not as 64-bit

feryno

I'm still doing tests how to switch from 64-bit to "lower" modes without success.

I think that there are mistakes in my first post in this topic:

L=0 this is correct
D=1 (1 for default operand size 32bit) (there is D=0 in my post, it means 16-bit operand size)

jmp selector:addr
this instruction is illegal in 64-bit mode
we can use only indirect far jmp, perhaps:
jmp fword [where_to_jump]
where_to_jump:
dd target_addr
dw target_selector

method by iretq should work fine