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