Skip to contentSkip to conversation

Query regarding x86_64 purgatory and IA32-e compatibility mode

DISCUSSION Vivek Goyal 2 participants 3 messages Oct 25, 2012 – Oct 26, 2012

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

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?

Thanks
Vivek

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#1 lore raw
Quoted 54 lines · Vivek Goyal

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
Quoted 7 lines

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

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec

#2 lore raw

On Thu, Oct 25, 2012 at 08:14:58PM -0700, Eric W. Biederman wrote:

[..]

Quoted 9 lines
Quoted 5 lines

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
Quoted 7 lines

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.

My bad. I did not take care of little endianness and read the bits in reverse order.
0x00AF

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
0 0 0 0 0 0 0 0 1 0 1 0 1 1 1 1

And concluded that bit 21 is 0.

Quoted 9 lines

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)

Ok, now I understand. In entry64-32.S we load a different GDT where bit 21, L = 0. Hence long jump will put it in compatibility mode.

0x00CF

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 1 0 0 1 1 1 1

Thanks for explaining this.

Thanks
Vivek

_______________________________________________
kexec mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kexec