64-bit Higher half with grub2

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
AlfaOmega08
Member
Member
Posts: 226
Joined: Wed Nov 07, 2007 12:15 pm
Location: Italy

64-bit Higher half with grub2

Post by AlfaOmega08 »

After many problems in getting the GRUB2 menu show up using an ISO, I'm still not able to boot my 64bit kernel in higher half. The linker script as suggested on the wiki is:

Code: Select all

ENTRY(_entry)
OUTPUT_FORMAT(elf64-x86-64)

KERNEL_VIRT_ADDR = 0xFFFFFFFF80100000;
KERNEL_PHYS_ADDR = 0x0000000000100000;
KERNEL_BASE_ADDR = (KERNEL_VIRT_ADDR - KERNEL_PHYS_ADDR);

SECTIONS
{
    . = KERNEL_PHYS_ADDR;

    bootstrap :
    {
        build/Debug/Cross-x64-Windows/Boot.o *(.header)
        build/Debug/Cross-x64-Windows/Boot.o *(.text)
        build/Debug/Cross-x64-Windows/Boot.o *(.data)
        build/Debug/Cross-x64-Windows/Boot.o *(.bss)
    }

    . += KERNEL_BASE_ADDR;

    _start = .;

    .text : AT(ADDR(.text) - KERNEL_BASE_ADDR)
    {
        . = ALIGN(64);
        _code = .;
        *(EXCLUDE_FILE(*build/Debug/Cross-x64-Windows/Boot.o) .text)
        *(.rodata*)
        . = ALIGN(4096);
    }

    .data : AT(ADDR(.data) - KERNEL_BASE_ADDR)
    {
        _data = .;
        *(EXCLUDE_FILE(*build/Debug/Cross-x64-Windows/Boot.o) .data)
        . = ALIGN(4096);
    }

    .eh_frame : AT(ADDR(.eh_frame) - KERNEL_BASE_ADDR)
    {
        EhFrame = .;
        *(.eh_frame)
        QUAD(0)
        . = ALIGN(4096);
    }

    .bss : AT(ADDR(.bss) - KERNEL_BASE_ADDR)
    {
       _bss = .;
       *(EXCLUDE_FILE(*build/Debug/Cross-x64-Windows/Boot.o) .bss)
        *(COMMON)
        . = ALIGN(4096);
    }

    _end = .;

    /DISCARD/ :
    {
        *(.comment)
    }
}
I'm using Netbeans on Windows, using a cygwin x86_64 cross compiler and Nasm. Compiling with

Code: Select all

x86_64-elf-ld.exe -nostdlib -nodefaultlibs -Tlinker.ld -z max-page-size=0x1000 -o $(OUTPUT) $(OBJECTS) -L. libgcc.a libsupc++.a
Actually the only object is this asm file:

Code: Select all

MB2_MAGIC       EQU 0xE85250D6
MB2_ARCH        EQU 0
MB2_HDRLEN      EQU (Mb2HdrEnd - Mb2Hdr)
MB2_CHECKSUM    EQU -(MB2_MAGIC + MB2_ARCH + MB2_HDRLEN)

[SECTION .header]
ALIGN 64
Mb2Hdr:
    DD  MB2_MAGIC
    DD  MB2_ARCH
    DD  MB2_HDRLEN
    DD  MB2_CHECKSUM   
    DW  0, 0
    DD  8
Mb2HdrEnd:
[BITS 32]
[SECTION .text]
[GLOBAL _entry]
_entry:
    CLI
    HLT
But GRUB2, after finding the Multiboot2 Header (which I'm sure it finds, it was the previous error and I fixed it), says:
error: invalid offset in section header.

The output of objdump on my test kernel is:

Code: Select all

test.sys:     file format elf64-x86-64
test.sys
architecture: i386:x86-64, flags 0x00000012:
EXEC_P, HAS_SYMS
start address 0x0000000000100020

Program Header:
    LOAD off    0x00000000000000f0 vaddr 0x0000000000100000 paddr 0x0000000000100000 align 2**4
         filesz 0x000000000000006a memsz 0x000000000000006a flags r-x
    LOAD off    0x000000000000015a vaddr 0xffffffff8010006a paddr 0x000000000010006a align 2**0
         filesz 0x0000000000000000 memsz 0x0000000000000f96 flags r-x
    LOAD off    0x000000000000015a vaddr 0xffffffff80101000 paddr 0x0000000000101000 align 2**0
         filesz 0x0000000000001000 memsz 0x0000000000001000 flags rw-

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 bootstrap     0000006a  0000000000100000  0000000000100000  000000f0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .text         00000f96  ffffffff8010006a  000000000010006a  0000015a  2**0
                  ALLOC, READONLY, CODE
  2 .eh_frame     00001000  ffffffff80101000  0000000000101000  0000015a  2**0
                  CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
0000000000100000 l    d  bootstrap	0000000000000000 bootstrap
ffffffff8010006a l    d  .text	0000000000000000 .text
ffffffff80101000 l    d  .eh_frame	0000000000000000 .eh_frame
0000000000000000 l    df *ABS*	0000000000000000 Boot.asm
00000000e85250d6 l       *ABS*	0000000000000000 MB2_MAGIC
0000000000000000 l       *ABS*	0000000000000000 MB2_ARCH
0000000000000018 l       *ABS*	0000000000000000 MB2_HDRLEN
ffffffff17adaf12 l       *ABS*	0000000000000000 MB2_CHECKSUM
0000000000100000 l     O bootstrap	0000000000000004 Mb2Hdr
0000000000100018 l       bootstrap	0000000000000000 Mb2HdrEnd
ffffffff80100000 g       *ABS*	0000000000000000 KERNEL_VIRT_ADDR
ffffffff80102000 g       .eh_frame	0000000000000000 _bss
ffffffff8010006a g       *ABS*	0000000000000000 _start
0000000000100020 g       bootstrap	0000000000000000 _entry
ffffffff80101000 g       .eh_frame	0000000000000000 EhFrame
ffffffff80000000 g       *ABS*	0000000000000000 KERNEL_BASE_ADDR
ffffffff80101000 g       .text	0000000000000000 _data
ffffffff80102000 g       *ABS*	0000000000000000 _end
0000000000100000 g       *ABS*	0000000000000000 KERNEL_PHYS_ADDR
ffffffff80100080 g       .text	0000000000000000 _code
Someone has an idea? Thanks

EDIT: There was an empty c++ file which added a lot of sections in the objdump output. I cleared them out and removed the file from the project
Last edited by AlfaOmega08 on Sun Apr 03, 2011 11:43 am, edited 3 times in total.
Please, correct my English...
Motherboard: ASUS Rampage II Extreme
CPU: Core i7 950 @ 3.06 GHz OC at 3.6 GHz
RAM: 4 GB 1600 MHz DDR3
Video: nVidia GeForce 210 GTS... it sucks...
User avatar
turdus
Member
Member
Posts: 496
Joined: Tue Feb 08, 2011 1:58 pm

Re: 64-bit Higher half with grub2

Post by turdus »

The error message is clear, easy to understand, what's the matter?
Hint: there's no _entry in your MB header
User avatar
AlfaOmega08
Member
Member
Posts: 226
Joined: Wed Nov 07, 2007 12:15 pm
Location: Italy

Re: 64-bit Higher half with grub2

Post by AlfaOmega08 »

I forgot to add a [GLOBAL _entry]... However the problem persists even if I add that line. I doesn't work if compiled on linux either
Please, correct my English...
Motherboard: ASUS Rampage II Extreme
CPU: Core i7 950 @ 3.06 GHz OC at 3.6 GHz
RAM: 4 GB 1600 MHz DDR3
Video: nVidia GeForce 210 GTS... it sucks...
User avatar
turdus
Member
Member
Posts: 496
Joined: Tue Feb 08, 2011 1:58 pm

Re: 64-bit Higher half with grub2

Post by turdus »

Read the Multiboot specification again, namely section 3.1.1 and 3.1.3
User avatar
AlfaOmega08
Member
Member
Posts: 226
Joined: Wed Nov 07, 2007 12:15 pm
Location: Italy

Re: 64-bit Higher half with grub2

Post by AlfaOmega08 »

turdus wrote:Read the Multiboot specification again, namely section 3.1.1 and 3.1.3
Done... They're definitely like they were two days ago... Can you be more clearer, please? My asm file seems ok...
Please, correct my English...
Motherboard: ASUS Rampage II Extreme
CPU: Core i7 950 @ 3.06 GHz OC at 3.6 GHz
RAM: 4 GB 1600 MHz DDR3
Video: nVidia GeForce 210 GTS... it sucks...
User avatar
turdus
Member
Member
Posts: 496
Joined: Tue Feb 08, 2011 1:58 pm

Re: 64-bit Higher half with grub2

Post by turdus »

I mean you call the flags MB2_ARCH in MB header (flags has nothing to do with architecture), and specifying the entry address in the header is always a good thing to do, as well as defining where to load your kernel (Grub cannot find out which page tables you will have, which physical memory address is mapped to fff800...h. So define it, it won't hurt anyway, just a few bytes more, and probably it would solve your problem. Grub does not parse the binary if the info is already there, so you won't get "bad section" error. Grub does not know ELF64, only ELF32, so you'll have to write a 32->64 stub.)
User avatar
AlfaOmega08
Member
Member
Posts: 226
Joined: Wed Nov 07, 2007 12:15 pm
Location: Italy

Re: 64-bit Higher half with grub2

Post by AlfaOmega08 »

turdus, you're great... it works. I don't really like it, seems like an hack to put an header to load an ELF file which grub should be able to load (grub2 should be loading 64bit images), but it works. If anyone has a "nicer" solution it's well accepted
Please, correct my English...
Motherboard: ASUS Rampage II Extreme
CPU: Core i7 950 @ 3.06 GHz OC at 3.6 GHz
RAM: 4 GB 1600 MHz DDR3
Video: nVidia GeForce 210 GTS... it sucks...
shikhin
Member
Member
Posts: 274
Joined: Sat Oct 09, 2010 3:35 am
Libera.chat IRC: shikhin
Contact:

Re: 64-bit Higher half with grub2

Post by shikhin »

I never had experience with GRUB2, nor have I yet made a 64-bit kernel (still on the legacy and PAE one, would move on to the 64-bit one, once this is finished), still I have designed something which I call an "intermediate loader" which can be used to load the 64-bit ELF.

What I do is, I get GRUB (legacy, mind it) load my "intermediate loader" and three modules:

a) PAE & Legacy Kernel: This is the kernel used in cases where long mode isn't supported. In both of these cases, just the VMM is different, which is just a module anyway, so this doesn't cause any problem.

b) Long Mode Kernel: Currently I don't load this (and keep the above kernel only) since I don't support long mode, but soon I would. I would simply load it.

c) Module Image: This is a compressed image of all the modules required by the Kernel, and is mapped at a "nice" virtual address.

The intermediate loader, now checks the amount of RAM, whether 64-bit, PAE and NX is supported or not, and on the basis of that loads one of the above kernel's. It also enables paging (depending on the kernel, the mode varies), and maps the kernel to higher half. Currently I don't do this, but you could get the intermediate loader to find the tables such as MPS, ACPI, etc too, making things neater. I also re-allocate the multiboot header, the memory map and the other "things" to a higher half address, giving me a clean environment. Moreover, the kernel is now running on dynamically allocated frames. 8)

Hope this helps, and if someone finds some quirk with my design, I am sure to listen to the comments.

Regards,
Shikhin
http://shikhin.in/

Current status: Gandr.
User avatar
turdus
Member
Member
Posts: 496
Joined: Tue Feb 08, 2011 1:58 pm

Re: 64-bit Higher half with grub2

Post by turdus »

I use a similar approach, I also have an intermediate loader, but my single image can be booted via legacy BIOS and by GRUB Multiboot as well. Although I never felt the need to test it, because legacy mode boots within 0.5 sec, but it only switches back to real mode, sets dl and continue where the BIOS starts, so it should work.

Because of this, I don't use modules in GRUB, only one kernel. I leave the rest to the logic implemented in the loader (locating a valid root disk, creating a ramdisk of it, and looking up required modules within. It's also able to use a FAT32 file as root disk image.

This approach has several benefits. Root disks should be small, a few mega bytes. A microkernel can locate any driver or server it ever needs in memory precached. The file hierarchy standard demands that on a root filesystem should be enough to boot, restore, repair and backup the system, and must include userspace tool to mount other filesystems. It's not hard to put all of this functionality in 16M. TinyCore Linux also has a GUI and it's less in size (Android is a port of it by the way).
Post Reply