Limine Bare Bones: Difference between revisions

[unchecked revision][unchecked revision]
Content deleted Content added
Force ELF file type to ET_DYN
Tag: Reverted
Qookie (talk | contribs)
→‎Compiling the kernel on macOS: Bring back mention of KLD
 
(10 intermediate revisions by 3 users not shown)
Line 11:
This article will demonstrate how to write a small Limine-compliant x86-64 kernel in (GNU) [[C]], and boot it using the [[Limine]] bootloader.
 
ItAdditionally, isit alsois veryhighly recommended to check out [https://github.com/limine-bootloader/limine-c-template this template project] as it provides example buildable code to go along with this guide.
 
===Overview===
 
For this example, we will create these 2 files to create the basic directory tree of our project:
Line 21:
As one may notice, there is no "entry point" assembly stub, as one is not necessary with the Limine protocol when using a language which can make use of a standard SysV x86 [[Calling Conventions|calling convention]].
 
Furthermore, we will download the header file '''<code>limine.h'''</code> which defines structures and constants that we will use to interact with the bootloader from [https://github.com/limine-bootloader/limine/raw/trunk/limine.h here], and place it in the '''<code>src'''</code> directory.
 
Obviously, this is just a bare bones example, and one should always refer to the [https://github.com/limine-bootloader/limine/blob/trunk/PROTOCOL.md Limine protocol specification] for more details and information.
Line 29:
This is the kernel "main".
 
<sourcesyntaxhighlight lang="c">
#include <stdint.h>
#include <stddef.h>
Line 155:
}
 
</syntaxhighlight>
</source>
 
===linker.ld===
Line 161:
This is going to be our linker script describing where our sections will end up in memory.
 
<sourcesyntaxhighlight lang="c">
/* Tell the linker that we want an x86_64 ELF64 output file */
OUTPUT_FORMAT(elf64-x86-64)
Line 170:
 
/* Define the program headers we want so the bootloader gives us the right */
/* MMU permissions; this also allows us to exert more control over the linking */
/* process. */
PHDRS
{
headers PT_PHDR PHDRS;
text PT_LOAD FLAGS(0x05); /* Execute + Read */
rodatatext PT_LOAD FILEHDR FLAGS(0x04)PHDRS; /* Read only */
data rodata PT_LOAD FLAGS(0x06); /* Write + Read */
data PT_LOAD;
dynamic PT_DYNAMIC FLAGS(0x06); /* Dynamic PHDR for relocations */
dynamic PT_DYNAMIC;
}
 
SECTIONS
{
/* We wannawant to be placed in the topmost 2GiB of the address space, for optimisations */
/* and because that is what the Limine spec mandates. */
/* Any address in this region will do, but often 0xffffffff80000000 is chosen as */
/* that is the beginning of the region. */
/* Additionally, leave space for the ELF headers by adding SIZEOF_HEADERS to the */
. = 0xffffffff80000000;
/* base load address. */
. = 0xffffffff80000000 + SIZEOF_HEADERS;
 
.text : {
Line 211 ⟶ 215:
} :data
 
/* Dynamic section for relocations, both in its own PHDR and inside data PHDR. */
.dynamic : {
*(.dynamic)
Line 236 ⟶ 240:
}
 
</syntaxhighlight>
</source>
 
==Building the kernel and creating an image==
Line 243 ⟶ 247:
 
In order to build our kernel, we are going to use a Makefile. Since we're going to use
GNU make specific features, we call this file '''<code>GNUmakefile'''</code> instead, so only
GNU make will process it.
 
<sourcesyntaxhighlight lang="make">
# Nuke built-in rules and variables.
override MAKEFLAGS += -rR
Line 349 ⟶ 353:
mkdir -p "$$(dirname $@)"
$(KLD) $(OBJ) $(KLDFLAGS) -o $@
printf '\x03003' | dd of=$@ bs=1 count=1 seek=16 conv=notrunc 2>/dev/null
 
# Include header dependencies.
Line 373 ⟶ 377:
clean:
rm -rf bin obj
</syntaxhighlight>
</source>
 
===limine.cfg===
Line 379 ⟶ 383:
This file is parsed by Limine and it describes boot entries and other bootloader configuration variables. Further information [https://github.com/limine-bootloader/limine/blob/trunk/CONFIG.md here].
 
<sourcesyntaxhighlight lang="ini">
# Timeout in seconds that Limine will use before automatically booting.
TIMEOUT=5
Line 399 ⟶ 403:
 
KERNEL_PATH=boot:///boot/myos
</syntaxhighlight>
</source>
 
===Compiling the kernel===
 
We can now build our example kernel by running '''<code>make'''</code>. This command, if successful, should generate, inside the '''<code>bin'''</code> directory, a file called '''<code>myos'''</code> (or the chosen kernel name). This is our Limine protocol-compliant kernel executable.
 
===Compiling the kernel on macOS===
Line 409 ⟶ 413:
''If you are not using macOS, you can skip this section.''
 
The macOS Xcode toolchain uses Mach-O binaries, and not the ELF binaries required for this Limine-compliant kernel. A solution is to build a [[GCC Cross-Compiler]], or to obtain one from [https://brew.sh homebrew] by installing the '''<code>x86_64-elf-gcc'''</code> package. After one of these is done, build using '''<code>make CCKCC=x86_64-elf-gcc LDKLD=x86_64-elf-ld'''</code>.
 
===Creating the image===
Line 419 ⟶ 423:
In this example we are going to create a CD-ROM ISO capable of booting on both [[UEFI]] and legacy [[BIOS]] systems.
 
For this to work, we will need the '''<code>xorriso'''</code> utility.
 
These are shell commands. They can also be compiled into a script or Makefile.
 
<sourcesyntaxhighlight lang="bash">
# Download the latest Limine binary release for the 7.x branch.
git clone https://github.com/limine-bootloader/limine.git --branch=v7.x-binary --depth=1
Line 454 ⟶ 458:
# Install Limine stage 1 and 2 for legacy BIOS boot.
./limine/limine bios-install image.iso
</syntaxhighlight>
</source>
 
====Creating a hard disk/USB drive image====
 
In this example, we'll create a [[GPT]] partition table using '''<code>sgdisk'''</code>, containing a single FAT partition, also known as the ESP in EFI terminology, which will store our kernel, configs, and bootloader.
 
This example is more involved and is made up of more steps than creating an ISO image.
Line 464 ⟶ 468:
These are shell commands. They can also be compiled into a script or Makefile.
 
<sourcesyntaxhighlight lang="bash">
# Create an empty zeroed-out 64MiB image file.
dd if=/dev/zero bs=1M count=0 seek=64 of=image.hdd
Line 491 ⟶ 495:
mcopy -i image.hdd@@1M limine/BOOTX64.EFI ::/EFI/BOOT
mcopy -i image.hdd@@1M limine/BOOTIA32.EFI ::/EFI/BOOT
</syntaxhighlight>
</source>
 
==Conclusions==