OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 9:56 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 5 posts ] 
Author Message
 Post subject: Grub loadable 64 bit kernel (multiboot2)
PostPosted: Sun Apr 10, 2022 2:10 pm 
Offline
Member
Member

Joined: Thu Sep 27, 2018 5:10 pm
Posts: 28
Location: Turkey
Hi,

I am trying to create an 64 bit elf image, that I can load with grub. However, "grub-file --is-x86-multiboot2" command returns error. Here is my boot.S file;

Code:
.set MULTIBOOT2_HEADER_MAGIC, 0xe85250d6
.set GRUB_MULTIBOOT_ARCHITECTURE_I386, 0
.set MULTIBOOT_HEADER_TAG_END, 0

.section .boot,"ax"
.code32

.align 8
multiboot_header:
        .long   MULTIBOOT2_HEADER_MAGIC
        .long   GRUB_MULTIBOOT_ARCHITECTURE_I386
        .long   multiboot_header_end - multiboot_header
        .long   -(MULTIBOOT2_HEADER_MAGIC + GRUB_MULTIBOOT_ARCHITECTURE_I386 + (multiboot_header_end - multiboot_header))

        .short MULTIBOOT_HEADER_TAG_END
        .short 0
        .long 8
multiboot_header_end:

.globl _start
_start:       
loop:   hlt
        jmp     loop


It is pretty much copy/paste from multiboot2 example code. I trimmed it as much as possible to get simplest working thing first.

Here is my linker file;

Code:

ENTRY(_start)

SECTIONS {
    . = 1M;

    .boot ALIGN (4):
    {
        *(.boot)
    }
}


It is also as simple as it gets. Here is my compilation steps;

Quote:
x86_64-elf-gcc -MD -c boot.S -o boot.o -g -O2 -ffreestanding -mno-red-zone -Iinclude
x86_64-elf-gcc -T linker.ld -o kernel.elf -g -O2 -ffreestanding -mno-red-zone -nostdlib -lgcc boot.o
grub-file --is-x86-multiboot2 kernel.elf


As far as I can tell, this is supposed to create a valid elf image. According to objdump, my .boot section looks like this;

Code:
kernel/kernel.elf:     file format elf64-x86-64

Contents of section .boot:
100000 d65052e8 00000000 18000000 12afad17  .PR.............
100010 00000000 08000000 f4ebfd             ...........     


Everthing seems normal to me here too. Finally, "readelf --sections" give me this output;

Code:
There are 11 section headers, starting at offset 0x100308:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .boot             PROGBITS         0000000000100000  00100000
       000000000000001b  0000000000000000  AX       0     0     8
  [ 2] .debug_line       PROGBITS         0000000000000000  0010001b
       000000000000004a  0000000000000000           0     0     1
  [ 3] .debug_line_str   PROGBITS         0000000000000000  00100065
       0000000000000022  0000000000000001  MS       0     0     1
  [ 4] .debug_info       PROGBITS         0000000000000000  00100087
       0000000000000028  0000000000000000           0     0     1
  [ 5] .debug_abbrev     PROGBITS         0000000000000000  001000af
       0000000000000014  0000000000000000           0     0     1
  [ 6] .debug_aranges    PROGBITS         0000000000000000  001000d0
       0000000000000030  0000000000000000           0     0     16
  [ 7] .debug_str        PROGBITS         0000000000000000  00100100
       000000000000002e  0000000000000001  MS       0     0     1
  [ 8] .symtab           SYMTAB           0000000000000000  00100130
       00000000000000d8  0000000000000018           9     8     8
  [ 9] .strtab           STRTAB           0000000000000000  00100208
       000000000000008c  0000000000000000           0     0     1
  [10] .shstrtab         STRTAB           0000000000000000  00100294
       0000000000000071  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)


Again, as far as I can tell, this seems normal to me. ".boot" is the first section to be loaded.

I don't know what I am doing wrong here, so any help is appreciated. Thanks in advance,

Best Regards,


Top
 Profile  
 
 Post subject: Re: Grub loadable 64 bit kernel (multiboot2)
PostPosted: Sun Apr 10, 2022 2:21 pm 
Offline
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 1593
According to the section headers, your .boot section is 1MB into the file. The GRUB2 header however has to occur within the first 8kB (or was it 4?). Anyway, You need to account for the headers in the linker script. My linker script looks like this:
Code:
ENTRY(_kstart)
OUTPUT_FORMAT("elf64-x86-64")

PHDRS {
    headers PT_PHDR PHDRS;
    text PT_LOAD FILEHDR PHDRS;
    data PT_LOAD;
}

SECTIONS {
    . = 0xffffffff80000000 + SIZEOF_HEADERS;
    .text : {
        *(.text)
        *(.text.*)
    } :text
    .rodata : {
        *(.rodata)
        *(.rodata.*)
    }

    /* Normally, the overlap between text and data section is handled by having
     * two different pages for the last bits of text and the first bits of data.
     * That way, if the last bits of text are overwritten, it won't affect the
     * text that is actually used. Unfortunately, for the kernel this is not
     * possible. The whole file is loaded into memory en bloc, so the same page
     * would be mapped twice. Therefore, a write access to the writable page
     * would end up being visible in the non-writable side of things. Therefore,
     * we must actually page-align here.
     */
    . = ALIGN(2M);
    .data : {
        *(.data)
        *(.data.*)
    } :data
    .bss : {
        *(.bss)
        *(COMMON)
        *(.bss.*)
    }
}

_________________
Carpe diem!


Top
 Profile  
 
 Post subject: Re: Grub loadable 64 bit kernel (multiboot2)
PostPosted: Sun Apr 10, 2022 2:39 pm 
Offline
Member
Member

Joined: Thu Sep 27, 2018 5:10 pm
Posts: 28
Location: Turkey
Thanks for the reply, can you give more detail about this part;

Code:
PHDRS {
    headers PT_PHDR PHDRS;
    text PT_LOAD FILEHDR PHDRS;
    data PT_LOAD;
}


From the context, I get that it does something with elf headers, but I don't understand it exactly.


Top
 Profile  
 
 Post subject: Re: Grub loadable 64 bit kernel (multiboot2)
PostPosted: Mon Apr 11, 2022 12:05 am 
Offline
Member
Member

Joined: Thu Sep 27, 2018 5:10 pm
Posts: 28
Location: Turkey
I tried to make it work with PHDRS directive with no success. But I was able to fix it with "-z max-page-size=0x1000" flag at linking stage, as suggested in the wiki.


Top
 Profile  
 
 Post subject: Re: Grub loadable 64 bit kernel (multiboot2)
PostPosted: Mon Apr 11, 2022 10:29 am 
Offline
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 1593
yasar11732 wrote:
Thanks for the reply, can you give more detail about this part;
You know, you can look at the documentation. Anyway, this directive declares what program headers I expect the output to contain. I use it, because current versions of GNU ld have some pretentions to being secure software, and like to introduce extraneous segments for "ROP protection". Uh-huh. But the only ROP protection that actually works long-term is fixing buffer overflow bugs.

Anyway, my directive declares three program headers: one PT_PHDR entry for the headers (not quite sure if I need that, but it is quite small and all the normal ELF files have it, so why not?), and two loadable segments, of which the first contains the headers. If I didn't write that, the first segment would not contain the headers, and consequently they would not be mapped. But my kernel requires the headers to map itself once more (after the bootloader does it the first time). I could do that with linker symbols, but I think doing it with the header is more elegant.

That is also why I set the initial position counter to -2GB + SIZEOF_HEADERS, so the start of the file (including the headers) is mapped to -2GB. This makes it very easy to locate at run-time.

And then in the SECTIONS directive, I can tell the linker to use a specific segment by writing a colon and the name of a segment on the same line as the closing brace of a section definition. The same segment will be used for all following sections until overwritten again.
yasar11732 wrote:
But I was able to fix it with "-z max-page-size=0x1000" flag at linking stage, as suggested in the wiki.
Yes, that is also a very sensible flag, and if I knew how to put it into a linker script, I would. I suspect you have now managed to reduce the offset of the .boot section from 1MB to 4kB, which is enough for GRUB. But I wanted to have as little bloat as possible, so I increased the position counter by SIZEOF_HEADERS, allowing the linker to fit the headers and the code onto the same page.

_________________
Carpe diem!


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

All times are UTC - 6 hours


Who is online

Users browsing this forum: Majestic-12 [Bot] and 60 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