Re: Jumping to IA-32e / Long mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Does Linux made the transition from 16bit at  bootup to 64bit?   Or
does it first go into 16bit->32bit->64bit?

I am not sure....

On Sat, May 24, 2008 at 7:41 AM, tejas khatiwala <socretez@xxxxxxxxx> wrote:
>
>
>
> Hello,
>
> I'm working on a 32-bit BIOS program for some embedded system with 64-bit
> CPU and I'm trying to test 64-bit mode. The BIOS normally runs in 32-bit
> mode. It, however, needs to performs some test for the 64-bit mode. So the
> drill is to jump to Long mode, perform some test (for now, I just want to
> print a character) and jump back to 32-bit mode.
>
> The Problem:
> For compatibility reasons, I _cannot_ compile the BIOS to be elf64 along
> with 64-bit test code to link them together to create binary image. So I
> _have_ to compile BIOS to elf32 and still be able to call 64-bit code and
> resume running 32-bit code on return.
>
> The Solution:
> that I've approached is to run 64-bit code as stream of binary bytes. (I
> compile 64-bit code using 64-bit NASM to _binary_ file separately to produce
> hex code). For example,
>
> char hexcode[] =  "\xba\xf8\x03\x00\x00";  // this is arbitrary code
> void (*fptr)(void);
> fptr = (void (*)(void)) hexcode;
> (*fptr)();
>
> For this solution, the code has to Position Independent and I use techniques
> to write shellcode (as demonstrated here
> http://www.safemode.org/files/zillion/shellcode/doc/Writing_shellcode.html)
> to make sure of that.
>
> I'm following steps as followed:
> (At the point when I execute this code, GDT is setup with entry (also) for
> 64-bit CS/DS discriptors, the PE = 1 (protected mode enabled) and PG = 0
> (paging disabled))
>
> C -          1) Setup PML4 pages (these are identity mapped.. for sure) and
> load cr3.
> --> I got this working. The permission bit in PDT and PDPT were not right
> although they _were_ identity mapped.
>
> C -          2) Setup new IDT for 64-bit mode
>
> ASM32 - 3) Disable Interrupts
> ASM32 - 4) Install IDT that was setup in step-2
> ASM32 - 5) Setup all data-segment registers (ds, es, fs, gs, ss) to point to
> 64-bit DS Descriptor
> --> This step had to be done after we switch to 64-bit mode.
>
> ASM32 - 6) Enable PAE mode
> ASM32 - 7) Enable Long mode
> ASM32 - 8) Turn on Paging (this is the last step that does the transition to
> 64-bit mode)

Specifically for this,  I found the following document useful:
Documentation/i386/boot.txt from linux kernel source codes:

At entry, the CPU must be in 32-bit protected mode with paging
disabled; a GDT must be loaded with the descriptors for selectors
__BOOT_CS(0x10) and __BOOT_DS(0x18); both descriptors must be 4G flat
segment; __BOOS_CS must have execute/read permission, and __BOOT_DS
must have read/write permission; CS must be __BOOT_CS and DS, ES, SS
must be __BOOT_DS; interrupt must be disabled; %esi must hold the base
address of the struct boot_params; %ebp, %edi and %ebx must be zero.

these are steps just for enabling 32bit paging...which is step
8....but not sure if all the above preconditions are needed for 64bit
operations (step 9)

> ASM32 - 9) Far jump to 64-bit code
> ASM64 - 10) Print a Character
> ASM64 - 10) return
>
> Currently, I'm just testing code _only_ to transition to IA-32e mode and not
> to jump back to 32-bit mode. I've some mechanism through which I can confirm
> that the addresses in hexcode are good. I've found out from probing that it
> fails on step-8 and gets general protection fault. I've tested this code in
> different order too and it just gets frozen on step-8.
>
> Any idea, what I could be doing wrong? Please help.
>
> Thanks,
> /tejas
>
> PS: "C" and "ASM" prefix in steps designates what language the part of the
> code is written in.
>
>
>

but looking at x86 source code - this is the part that enable paging:

arch/x86/kernel/head_32.S:

/*
 * Enable paging
 */
        movl $pa(swapper_pg_dir),%eax
        movl %eax,%cr3          /* set the page table pointer.. */
        movl %cr0,%eax
        orl  $X86_CR0_PG,%eax
        movl %eax,%cr0          /* ..and set paging (PG) bit */
        ljmp $__BOOT_CS,$1f     /* Clear prefetch and normalize %eip */
1:
        /* Set up the stack pointer */
        lss stack_start,%esp

And for 32-bit to 64bit transition:

arch/x86/boot/compressed/head_64.S:

        /* Setup for the jump to 64bit mode
         *
         * When the jump is performend we will be in long mode but
         * in 32bit compatibility mode with EFER.LME = 1, CS.L = 0, CS.D = 1
         * (and in turn EFER.LMA = 1).  To jump into 64bit mode we use
         * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
         * We place all of the values on our mini stack so lret can
         * used to perform that far jump.
         */
        pushl   $__KERNEL_CS
        leal    startup_64(%ebp), %eax
        pushl   %eax

        /* Enter paged protected Mode, activating Long Mode */
        movl    $0x80000001, %eax /* Enable Paging and Protected mode */
        movl    %eax, %cr0

        /* Jump from 32bit compatibility mode into 64bit mode. */
        lret

Hope if that helps....

-- 
Regards,
Peter Teoh

--
To unsubscribe from this list: send an email with
"unsubscribe kernelnewbies" to ecartis@xxxxxxxxxxxx
Please read the FAQ at http://kernelnewbies.org/FAQ


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux