grub can't find multiboot header in a higher-half kernel

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
acccidiccc
Member
Member
Posts: 38
Joined: Sun Mar 21, 2021 1:09 pm
Location: current location

grub can't find multiboot header in a higher-half kernel

Post by acccidiccc »

Hello, I have tried to implement a higher-half kernel. For that i used the tutorial in the Wiki. I am not so sure about the cause, but in the hexeditor, it shows that the multiboot header is at address 0x451c and i am assuming that grub cannot find it, because it is not at the front. ( the header is intact ).
Now how do I modify the linker script to put it earlier into my program? Problem is, I even tested the code for the tutorial without my own. even there grub
could not find my header - with one exception: if I delete the tty.c part of the kernel.c file. The disassembly doesn't help either - objdump shows the multiboot header at the front where it should be, at one megabyte. The linker throws no errors. I have "fixed" it one time by putting the header and bootstrap code into the .text section

Code: Select all

[.text ALIGN (4K) : AT (ADDR (.text) - 0xC0000000)
	{
        *(.multiboot.data) /* the header*/
        *(.multiboot.text)
        *(.text)

	}/code]
but that just page faulted, which is probably for the better. objdump shows the multiboot header in this case in the linker-specified location, the higher half, but it still worked, because like a miracle, it is now at 0x1000. how do i specify the location of the multiboot header in the linker script?
sorry for my bad english, i'm not a native speaker.
iustitiae iniustos iudicat
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: grub can't find multiboot header in a higher-half kernel

Post by bzt »

acccidiccc wrote:it shows that the multiboot header is at address 0x451c
Well, I personally don't like Grub, so I'm no expert on it, but shouldn't be the Multiboot header located in the first 8 kilobytes and aligned at 16 bytes? This address 0x451c is above 0x2000 and it ain't paragraph aligned, so no wonder Grub can't find it.
acccidiccc wrote:Now how do I modify the linker script to put it earlier into my program? Problem is, I even tested the code for the tutorial without my own. even there grub
could not find my header - with one exception: if I delete the tty.c part of the kernel.c file. The disassembly doesn't help either - objdump shows the multiboot header at the front where it should be, at one megabyte.
Link address doesn't matter, only the file offset. Try to use "KEEP()" in the linker script to tell the linker not to rearrange the multiboot section within the file.

Code: Select all

.text ALIGN (4K) : AT (ADDR (.text) - 0xC0000000)
{
KEEP(*(.multiboot.data)) /* the header*/
*(.multiboot.text)
*(.text)

}
Otherwise make sure of it, that the object file which contains the header is the first in the linker's argument list.

Cheers,
bzt
User avatar
acccidiccc
Member
Member
Posts: 38
Joined: Sun Mar 21, 2021 1:09 pm
Location: current location

Re: grub can't find multiboot header in a higher-half kernel

Post by acccidiccc »

Hello, Thanks for your Reply. Sadly this did not solve my problem. I just realized that the cause for my problem was that the .text section was placed first in the binary. It is larger than 8K though, which caused the header to be placed at the odd address. the reason that the "solution", that is putting the header in the .text section, worked, is that the multiboot header was the first thing. However the .text section is the section that is called after the jump to the higher half. The full script read

Code: Select all

ENTRY (_start)

SECTIONS
{
        . = 0x00100000;
	/* The kernel will live at 3GB + 1MB in the virtual address space, */
	/* which will be mapped to 1MB in the physical address space. */
	/* Note that we page-align the sections. */

	_kernel_start = .;
        .multiboot.data : {
            *(.multiboot.data)
        }

       .multiboot.text : {
           *(.multiboot.text)
       }

	. += 0xC0000000;
	/* Add a symbol that indicates the start address of the kernel. */
	.text ALIGN (4K) : AT (ADDR (.text) - 0xC0000000)
	{
		*(.text)
	}
	.rodata ALIGN (4K) : AT (ADDR (.rodata) - 0xC0000000)
	{
		*(.rodata)
	}
	.data ALIGN (4K) : AT (ADDR (.data) - 0xC0000000)
	{
		*(.data)
	}
	.bss ALIGN (4K) : AT (ADDR (.bss) - 0xC0000000)
	{
		*(COMMON)
		*(.bss)
		*(.bootstrap_stack)
	}
	/* Add a symbol that indicates the end address of the kernel. */
	_kernel_end = .;
}
putting the header and bootstrap trampoline code into the higher half is obviously a bad idea. The memory probably gets accessed from the loader and page and yadayada. I probably have to swap .text sections. Is there any way to make the .multiboot.data section to be first in terms of offset?
iustitiae iniustos iudicat
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: grub can't find multiboot header in a higher-half kernel

Post by bzt »

acccidiccc wrote:I just realized that the cause for my problem was that the .text section was placed first in the binary.
With a linker script, you're in full control of which section comes after another.
acccidiccc wrote:However the .text section is the section that is called after the jump to the higher half.
Bad idea. Use the entry point, that's what it is for.
acccidiccc wrote: /* Add a symbol that indicates the start address of the kernel. */
I see no symbol here. (Maybe not needed, just make sure you have an Assembly function called "_start"). Whereever it goes in the text segment, its VMA will be saved in the elf_hdr->e_entry field, use that when you pass control over.
acccidiccc wrote:putting the header and bootstrap trampoline code into the higher half is obviously a bad idea.
As I've said, it doesn't matter. For the header only the file offset counts, not the link address, VMA is totally indifferent. (There's no such thing, higher half file offset.) When you use "readelf -l", you'll see both, for example:

Code: Select all

 LOAD           0x0000000000000e10 0x0000000000600e10 0x0000000000600e10
                      ^file offset       ^Virtual Memory Address
As you can see here 0xe10 != 0x600e10. Furthermore, Multiboot header can be outside of loadable segments, and not loaded into memory in run-time at all.
acccidiccc wrote:Is there any way to make the .multiboot.data section to be first in terms of offset?
Yes, as I've already said, use the KEEP() pseudo function in the linker script. Also make sure you put it in the first segment (that's probably the text segment and not the data segment), and read about section placement, you'll find useful information there.

Cheers,
bzt
User avatar
acccidiccc
Member
Member
Posts: 38
Joined: Sun Mar 21, 2021 1:09 pm
Location: current location

Re: grub can't find multiboot header in a higher-half kernel

Post by acccidiccc »

Thanks again for the response. I've given up trying to combine multiboot and a higher half kernel. Instead I'm now using limine.
iustitiae iniustos iudicat
User avatar
bzt
Member
Member
Posts: 1584
Joined: Thu Oct 13, 2016 4:55 pm
Contact:

Re: grub can't find multiboot header in a higher-half kernel

Post by bzt »

acccidiccc wrote:Thanks again for the response. I've given up trying to combine multiboot and a higher half kernel. Instead I'm now using limine.
Your loss. It would worth learning these things you'll probably need linker script features in the future too.

Cheers,
bzt
User avatar
acccidiccc
Member
Member
Posts: 38
Joined: Sun Mar 21, 2021 1:09 pm
Location: current location

Re: grub can't find multiboot header in a higher-half kernel

Post by acccidiccc »

I think I actually know more about linker scripts now. I just used the KEEP wrong.

Code: Select all

.text : {
    KEEP(*(.multiboot)
    *(.multiboot)
}
if i am not mistaken, this is the correct form of using it:

Code: Select all

.text : {
     KEEP(*(.multiboot))
}
It's also not like I didn't try. I know why it didn't work; The Grub Multiboot header was easy to fix, the problem later was the entry point.
putting the contents of the multiboot header in the start of .text also worked. The issue was mixing the trampoline code and the later higher half code.
Adding 0xc0000000 to .

Code: Select all

. += 0xc0000000;
didn't work. putting .text into the higher-half would make .multiboot.text the entry point, and
grub didn't like that (entry point isn't a segment)

Code: Select all

.set _start, (_trampoline + 0xc0000000)
also didn't work. So I used the limine bootloader, which didn't really change much for me, except make my life easier, by setting up graphics and stuff. Now I actually understand the things in a linker script.
iustitiae iniustos iudicat
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: grub can't find multiboot header in a higher-half kernel

Post by kzinti »

I'd start with ignoring the so-called "higher-half" hack and get your kernel loading first. Once you get it working, you can decide if you want to continue with this hack or not.

I personally don't understand why this forum/wiki encourages people to use such a hack. It's very messy and hard to get right, especially for newbies.

It is far easier to just have a bootloader that will setup virtual memory and load the kernel where you want it directly.
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: grub can't find multiboot header in a higher-half kernel

Post by nullplan »

kzinti wrote:I personally don't understand why this forum/wiki encourages people to use such a hack. It's very messy and hard to get right, especially for newbies.
Yep. I started to dislike that hack from the very first time I saw it. Mixing physical and virtual addresses like that can only lead to confusion. Thankfully, for AMD64 in legacy boot mode I need a separate loader anyway, and that gave me the idea to separate the part that sets up the initial memory mappings from the rest of the kernel, which I did, and now I'm much happier. This also gives me a buffer between the bootloader and the kernel proper, which I can use to adopt new bootloaders. And, all that code for the initial page table setup, that is entirely useless once it has run (doubly so in the AMD64 case, since that code is for the wrong architecture then), can now be freed completely afterwards, for it is contained in a separate binary.
Carpe diem!
Post Reply