Booting 64bit 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
antoni
Member
Member
Posts: 61
Joined: Sun May 24, 2020 9:11 am
Location: /dev/null

Booting 64bit kernel

Post by antoni »

I'm just starting to program operating systems. I have already created a 32-bit OS that had a shell and was able to display the date or read data from the disk. Now I'd like to create a 64bit system. I saw article about this in osdev wiki - https://wiki.osdev.org/Creating_a_64-bit_kernel . However, I can't create code that GRUB2 is able to run. In my 32bit systems I used this code:

init.asm:

Code: Select all

global init

; some useful macro values
FLAGS		equ	0		; this is the multiboot 'flag' field
MAGIC		equ	0x1BADB002	; 'magic number' lets bootloader find the header
CHECKSUM	equ	-(MAGIC + FLAGS); checksum required
STACKSIZE	equ	0x4000		; 16 KiB for stack

section .text
align 4

; setting multiboot header
multiboot_header:

	dd	MAGIC
   	dd	FLAGS
   	dd	CHECKSUM

init:

	hlt         ;It was code calling kernel here.
	jmp init

section .bss
align 4

	stack:
   	resb 	STACKSIZE		; reserve stack space
make.sh:

Code: Select all

#!/bin/bash

nasm -f elf32 init.asm -o init.o
x86_64-elf-ld -T init.ld init.o -o init.bin -nostdlib -melf_i386

mkdir iso
cd iso
mkdir boot
cd boot
mkdir grub

cd ..
cd ..

cp init.bin iso/boot/grub
rm init.bin

cd iso
cd boot
cd grub

touch grub.cfg
printf "menuentry \'MY OS\' {\nmultiboot /boot/grub/init.bin\n}" > grub.cfg

cd ..
cd ..
cd ..

grub-mkrescue -o init.iso iso
rm -r iso
I replaced the kernel calling code with halt because my problem is only with booting. In the article it was written that I have to make a 32bit bootstrap, which I think means that I should give the BITS 32 directive and compile the code to elf64 like following:

Code: Select all

nasm -f elf64 init.asm -o init.o
x86_64-elf-ld -T init.ld init.o -o init.bin -nostdlib
instead of:

Code: Select all

nasm -f elf32 init.asm -o init.o
x86_64-elf-ld -T init.ld init.o -o init.bin -nostdlib -melf_i386
After this changes, I start OS with the command:

Code: Select all

qemu-system-x86_64 -hda init.iso
32bit code works. 64bit code shows the GRUB window, and after pressing "MY OS" information appears that GRUB didn't find multiboot header. Maybe 64bit multiboot header looks different? How to boot elf64 kernel with GRUB2?
nexos
Member
Member
Posts: 1081
Joined: Tue Feb 18, 2020 3:29 pm
Libera.chat IRC: nexos

Re: Booting 64bit kernel

Post by nexos »

GRUB2 can only load 32 bit kernels. The common solution is to have boot.asm set up 64 bit mode. This requires a fair amount of overhead. You must set up 64 bit paging, a 64 bit Global Descriptor Table, and other things. I would recommend reading the [intel manuals/url], and look at the wiki article at [url]https://wiki.osdev.org/Long_Mode. I haven't implemented long mode before, however, so that is all I know.
"How did you do this?"
"It's very simple — you read the protocol and write the code." - Bill Joy
Projects: NexNix | libnex | nnpkg
antoni
Member
Member
Posts: 61
Joined: Sun May 24, 2020 9:11 am
Location: /dev/null

Re: Booting 64bit kernel

Post by antoni »

nexos wrote:GRUB2 can only load 32 bit kernels.
I know. But it is compatible with elf64. For now, I just want to boot 32bit code in elf64 format. How to do it with GRUB2?

That's how I understand "32bit bootstrap". As 32bit code in elf64 format. May be I'm wrong?
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Booting 64bit kernel

Post by iansjack »

Why not make the 32-bit code ELF32 and the 64-bit code ELF64. You then load the 64-bit code using the "module" command in "grub.cfg". That way you're not trying to force new wine into old bottles.
antoni
Member
Member
Posts: 61
Joined: Sun May 24, 2020 9:11 am
Location: /dev/null

Re: Booting 64bit kernel

Post by antoni »

I don't know much about GRUB and I didn't know it's possible. Do linux also loads this way? It looks like a trick, not method used in real operating systems.
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: Booting 64bit kernel

Post by pvc »

AFAIK GRUB can load 64 bit ELF files perfectly fine, as long as physical load addresses fit in 32 bits. Your problem might be related to your linker script. You have to make sure that your multiboot_header symbol is located in the first 8KiB of the ELF file (open it in hex editor and try to locate 0x1BADB002 value manually).

For x86-64, ld often likes to align some sections to 4MiB instead of 4KiB. That could push multiboot_header way farther than required 8K. Try adding -z max-page-size=4096 to your ld invocation.
antoni
Member
Member
Posts: 61
Joined: Sun May 24, 2020 9:11 am
Location: /dev/null

Re: Booting 64bit kernel

Post by antoni »

You're right. The problem was caused by linker script that looked like this:

Code: Select all

ENTRY (init)

SECTIONS {
    . = 0x00100000;
}
After changing to this:

Code: Select all

ENTRY (init)

SECTIONS {
    . = 0x001000;
}
I managed to boot. What address is a good starting point for kernel?
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: Booting 64bit kernel

Post by pvc »

I would rather avoid anything below 1MiB, since there is quite some stuff going on there (IVT, BDA, EBDA, Video RAM window, BIOS, option ROM, part ot the GRUB itself, multiboot structures, SMP trampoline and maybe even more I forgot). 1MiB (0x100000) would be a good load address. You just need to make sure that multiboot_header is in the right place (it has to be below 8K and 4 byte aligned in the file, not in the memory).
MichaelPetch
Member
Member
Posts: 797
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Booting 64bit kernel

Post by MichaelPetch »

pvc wrote:I would rather avoid anything below 1MiB, since there is quite some stuff going on there (IVT, BDA, EBDA, Video RAM window, BIOS, option ROM, part ot the GRUB itself, multiboot structures, SMP trampoline and maybe even more I forgot). 1MiB (0x100000) would be a good load address. You just need to make sure that multiboot_header is in the right place (it has to be below 8K and 4 byte aligned in the file, not in the memory).
I recently answered a [url=https://stackoverflow.com/questions/61904276/qemu-doesnt-reboot-my-os-after-resetting-via-the-8042-ps-2-controller/61944341#61944341] question on Stackoverflow
[/url] that caused some unusual behaviour when someone went to reboot QEMU. The problem was that they had told GRUB to load their multiboot header at 0x500. I wholeheartedly agree that you shouldn't be letting GRUB load below of 0x100000.

That's not to say that once GRUB is loaded you can't use the available (non-reserved, EBDA etc) and move code and data into that area afterwards.
User avatar
pvc
Member
Member
Posts: 201
Joined: Mon Jan 15, 2018 2:27 pm

Re: Booting 64bit kernel

Post by pvc »

MichaelPetch wrote:That's not to say that once GRUB is loaded you can't use the available (non-reserved, EBDA etc) and move code and data into that area afterwards.
Of course you can do that, if you know what you're doing. But that could possibly create unnecessary complications for a beginner. IMO, better to just avoid it for now.
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Booting 64bit kernel

Post by iansjack »

antoni wrote:I don't know much about GRUB and I didn't know it's possible. Do linux also loads this way? It looks like a trick, not method used in real operating systems.
So why do you think GRUB allows the loading of modules?
MichaelPetch
Member
Member
Posts: 797
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: Booting 64bit kernel

Post by MichaelPetch »

Assemble and Compile all your assembly and C/C++ (or whatever language you are using) to 64-bit ELF objects. Link them all together into a 64-bit static ELF executable. Use objcopy to convert the 64-bit ELF executable to a 32-bit ELF executable. If you use Multiboot1 the result should be loadable by GRUB legacy and GRUB 2, and QEMU's `-kernel` option.
Post Reply