OSDev.org

The Place to Start for Operating System Developers
It is currently Fri Apr 19, 2024 4:02 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 6 posts ] 
Author Message
 Post subject: Far jump to higher half 64bit address from 32 bit binary
PostPosted: Fri Feb 04, 2011 10:49 am 
Offline
Member
Member

Joined: Wed Aug 25, 2010 6:35 am
Posts: 52
Location: Bonn, Germany
Hello,
to circumvent the problems I had with GRUB2 loading my AMD64 kernel, I decided to write a small loader binary in 32 bits that resides in the lower half, does the long mode readying stuff, loads the kernel ELF64 binary that is attached as a multiboot1 module and jump to its entry point.

Although the last point on the list might sound simplest, its actually the one I have most of the problems with. To jump to the 64 bit higher half entry point address (somewhere near 0xFFFFFF000000000), I planned to far jump to a 64 bit realm in the loader itself, that performs the jump to the actual entry point. My problem is to embed this 64 bit realm into my elf32 kernel. I tried the following approach, but it did not work out (machine resetting):
Code:
    ; mov rax, [0x1002]
    ; Entry point address QWORD is stored at 0x1002
    db 0x48
    db 0x8b
    db 0x04
    db 0x25
    db 0x02
    db 0x10
    db 0x00
   
    ; Spacer
    db 0x0
   
    ; jmp rax
    db 0xff
    db 0xe0

It's not a really clean approach and I really don't know how to debug the code above, so is there any way of jumping to this high entry point address besides of making the binary elf64 itself (GRUB Legacy, unpatched, and I want it to stay this way) and linking the 64 bit realm to it or adding another module that contains just these few bytes of 64 bit code?

_________________
https://github.com/qero/Hydrogen (Loader for AMD64 kernels running on top of GRUB2)


Top
 Profile  
 
 Post subject: Re: Far jump to higher half 64bit address from 32 bit binary
PostPosted: Fri Feb 04, 2011 12:25 pm 
Offline
Member
Member
User avatar

Joined: Thu Aug 11, 2005 11:00 pm
Posts: 1110
Location: Tartu, Estonia
I don't know which assembler you are using (NASM?), but I don't think you need to hardcode the jump byte by byte. In my kernel, I use a small 64 bit trampoline which is identity mapped in the lower half and to which I can jump from protected mode using a 32 bit far jump. As soon as I am in a 64 bit code segment, I load rax with a higher half address.

Code:
.code32
   // enable paging (activate long mode), enable floating point exception
   movl %cr0, %ecx
   orl $0x8000000a, %ecx
   movl %ecx, %cr0

   lgdt (pGDT64 - KERNEL_OFFSET)

   // jump into long mode
   ljmpl $0x20, $(long_mode - KERNEL_OFFSET)

.code64
long_mode:
   movabsq $(stack + STACK_SIZE), %rsp

   // time for some C!
   movabsq $(KernelEntry), %rax
   callq *%rax // Run the boot module by calling its C++ entry point

_________________
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS


Top
 Profile  
 
 Post subject: Re: Far jump to higher half 64bit address from 32 bit binary
PostPosted: Fri Feb 04, 2011 1:47 pm 
Offline
Member
Member

Joined: Wed Aug 25, 2010 6:35 am
Posts: 52
Location: Bonn, Germany
I actually tried to do so, but as I'm linking my loader as elf32, the object files cannot be elf64 which would be required for embedding the trampoline. I try to stick with elf32 as it should be most compatible among multiboot bootloaders, especially GRUB Legacy. In the ideal case my boot.s would not something like this, but doing this I run into the mentioned linking issues:

Code:
section .text
[BITS 32]
; Code, code, code...
; ------------------------------------------------------------------------------
; Realm 64
; ------------------------------------------------------------------------------
[BITS 64]
realm64:
    mov rax, [0x1002]
    jmp rax


BTW: I'm using NASM (Intel Syntax, I could never really accommodate myself to GAS).

Edit: Typo

_________________
https://github.com/qero/Hydrogen (Loader for AMD64 kernels running on top of GRUB2)


Top
 Profile  
 
 Post subject: Re: Far jump to higher half 64bit address from 32 bit binary
PostPosted: Fri Feb 04, 2011 2:43 pm 
Offline
Member
Member
User avatar

Joined: Thu Aug 11, 2005 11:00 pm
Posts: 1110
Location: Tartu, Estonia
I think I get your point. I guess in that case you really need to replace the 64 bit trampoline code from my example by some hand-written byte code as in your original post. Most importantly, you need to hard-code the higher half entry address of your 64 bit kernel, since you cannot use 64 bit relocations in a 32 bit elf file.

Another possibility would be to include the trampoline in your 64 bit kernel module and to use an identity (or some other temporary lower half) mapping in the early boot phase. Then you can jump from your 32 bit loader to the lower half mapped trampoline in your 64 bit kernel. From there you jump to the higher half and clear the identity mapping.

In any case, you must be in a 64 bit code segment before you can use 64 bit addresses, so either way you will need some trampoline below 4GB.

_________________
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS


Top
 Profile  
 
 Post subject: Re: Far jump to higher half 64bit address from 32 bit binary
PostPosted: Fri Feb 04, 2011 3:50 pm 
Offline
Member
Member

Joined: Wed Aug 25, 2010 6:35 am
Posts: 52
Location: Bonn, Germany
Developing the idea of the hard coded address a bit further, the byte code could dynamically be generated, written to memory and jumped to. That enables me to use the entry point address as it is defined in the ELF64 header and still not requiring it to provide a trampoline by itself. I think I will give this a try.

Edit: Actually this C code seems to create the right opcodes for jumping to 0x1234567890ABCDEF, I hope it will work out...
Edit 2: It does work after having spend several hours debugging my paging code, so this solution seems to be a serious alternative when loading 64 bit kernels.
Code:
    uint8_t *trampoline = (uint8_t *) (BOOT_INFO_OFFSET + 0x1000 - 12);
    trampoline[0] = 0x48;
    trampoline[1] = 0xb8;
    trampoline[10] = 0xff;
    trampoline[11] = 0xe0;
    * ((uint64_t *) (BOOT_INFO_OFFSET + 0x1000 - 10)) = 0x1234567890ABCDEF;

_________________
https://github.com/qero/Hydrogen (Loader for AMD64 kernels running on top of GRUB2)


Last edited by Qeroq on Sat Feb 05, 2011 4:30 am, edited 2 times in total.

Top
 Profile  
 
 Post subject: Re: Far jump to higher half 64bit address from 32 bit binary
PostPosted: Sat Feb 05, 2011 2:19 am 
Offline
Member
Member
User avatar

Joined: Thu Aug 11, 2005 11:00 pm
Posts: 1110
Location: Tartu, Estonia
Nice idea, I think that should work as well. The byte coded mov / jmp looks perfectly fine to me.

_________________
Programmers' Hardware Database // GitHub user: xenos1984; OS project: NOS


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot] and 97 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group