Query regarding x86_64 purgatory and IA32-e compatibility mode

Eric W. Biederman ebiederm at xmission.com
Thu Oct 25 23:14:58 EDT 2012


Vivek Goyal <vgoyal at redhat.com> writes:

> Hi Eric,
>
> I am reading up x86_64 purgatory code to understand how transition to
> 32bit protected mode happens.
>
> My understanding is that we enter in purgatory_start (setup-x86_64.S).
> Then we jump to entry64 in entry64.S.
>
> We run following code in arch/x86_64/entry64.S
>
>         movq    $stack_init, %rsp
>         pushq   $0x10 /* CS */
>         pushq   $new_cs_exit
>         lretq
> new_cs_exit:
>
>         /* Load the registers */
>         movq    rax(%rip), %rax
>         movq    rbx(%rip), %rbx
>         movq    rcx(%rip), %rcx
>         movq    rdx(%rip), %rdx
>         movq    rsi(%rip), %rsi
>         movq    rdi(%rip), %rdi
>         movq    rsp(%rip), %rsp
>         movq    rbp(%rip), %rbp
>         movq    r8(%rip), %r8
>         movq    r9(%rip), %r9
>         movq    r10(%rip), %r10
>         movq    r11(%rip), %r11
>         movq    r12(%rip), %r12
>         movq    r13(%rip), %r13
>         movq    r14(%rip), %r14
>         movq    r15(%rip), %r15
>
> Will above lretq call not switch us in compatibility mode (from 64bit
> mode)? We have taken a long jump and our new CS seems to have L bit 
> 0.


> Following is our gdt.
>
> gdt:    /* 0x00 unusable segment 
>          * 0x08 unused
>          * so use them as the gdt ptr
>          */
>         .word   gdt_end - gdt - 1
>         .quad   gdt
>         .word   0, 0, 0
>
>         /* 0x10 4GB flat code segment */
>         .word   0xFFFF, 0x0000, 0x9A00, 0x00AF
>
>         /* 0x18 4GB flat data segment */
>         .word   0xFFFF, 0x0000, 0x9200, 0x00CF
> gdt_end:
>
> I see that bit 21  in second doubleword is 0. IIUC, that means that we
> will switch to compatibility mode. If yes, we are still continuing to
> use 64bit instructions and continue to access registers (rip, r8-15)
> which are available in 64bit mode only. Is this correct? How does this
> work?

         /* 0x10 4GB flat code segment */
        .word   0xFFFF, 0x0000, 0x9A00, 0x00AF

The high 16bits of that are:
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
 0  0  0  0  0  0  0  0  1  0  1  0  1  1  1  1

Since L is bit 21 I read that as L=1.

I don't know how you see L=1 there.

The transition happens in entry64-32.S
We get there via:
	jmp	*rip(%rip)

The default value of rip is entry32.

That is where we clear bit 21 in 
	ljmp	*lm_exit_addr(%rip)

Eric



More information about the kexec mailing list