Limine Bare Bones: Difference between revisions
Jump to navigation
Jump to search
[unchecked revision] | [unchecked revision] |
Content added Content deleted
No edit summary |
No edit summary |
||
Line 9: | Line 9: | ||
The Limine boot protocol is firmware and architecture agnostic. The Limine bootloader supports x86-64, IA-32, aarch64, and riscv64. |
The Limine boot protocol is firmware and architecture agnostic. The Limine bootloader supports x86-64, IA-32, aarch64, and riscv64. |
||
This article will demonstrate how to write a small x86-64 |
This article will demonstrate how to write a small Limine-compliant x86-64 kernel in (GNU) [[C]], and boot it using the [[Limine]] bootloader. |
||
It is also very 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. |
It is also very 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. |
||
Line 16: | Line 16: | ||
For this example, we will create these 2 files to create the basic directory tree of our project: |
For this example, we will create these 2 files to create the basic directory tree of our project: |
||
* src/ |
* src/main.c |
||
* linker.ld |
* linker.ld |
||
Line 25: | Line 25: | ||
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. |
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. |
||
===src/ |
===src/main.c=== |
||
This is the kernel "main". |
This is the kernel "main". |
||
Line 35: | Line 35: | ||
#include <limine.h> |
#include <limine.h> |
||
// Set the base revision to |
// Set the base revision to 2, this is recommended as this is the latest |
||
// base revision described by the Limine boot protocol specification. |
// base revision described by the Limine boot protocol specification. |
||
// See specification for further info. |
// See specification for further info. |
||
__attribute__((used, section(".requests"))) |
|||
static volatile LIMINE_BASE_REVISION( |
static volatile LIMINE_BASE_REVISION(2); |
||
// The Limine requests can be placed anywhere, but it is important that |
// The Limine requests can be placed anywhere, but it is important that |
||
// the compiler does not optimise them away, so, usually, they should |
// the compiler does not optimise them away, so, usually, they should |
||
// be made volatile or equivalent, _and_ they should be accessed at least |
// be made volatile or equivalent, _and_ they should be accessed at least |
||
// once or marked as used with the "used" attribute as done here. |
|||
// once. |
|||
__attribute__((used, section(".requests"))) |
|||
static volatile struct limine_framebuffer_request framebuffer_request = { |
static volatile struct limine_framebuffer_request framebuffer_request = { |
||
.id = LIMINE_FRAMEBUFFER_REQUEST, |
.id = LIMINE_FRAMEBUFFER_REQUEST, |
||
.revision = 0 |
.revision = 0 |
||
}; |
}; |
||
// Finally, define the start and end markers for the Limine requests. |
|||
// These can also be moved anywhere, to any .c file, as seen fit. |
|||
__attribute__((used, section(".requests_start_marker"))) |
|||
static volatile LIMINE_REQUESTS_START_MARKER; |
|||
__attribute__((used, section(".requests_end_marker"))) |
|||
static volatile LIMINE_REQUESTS_END_MARKER; |
|||
// GCC and Clang reserve the right to generate calls to the following |
// GCC and Clang reserve the right to generate calls to the following |
||
Line 136: | Line 147: | ||
// Note: we assume the framebuffer model is RGB with 32-bit pixels. |
// Note: we assume the framebuffer model is RGB with 32-bit pixels. |
||
for (size_t i = 0; i < 100; i++) { |
for (size_t i = 0; i < 100; i++) { |
||
uint32_t *fb_ptr = framebuffer->address; |
volatile uint32_t *fb_ptr = framebuffer->address; |
||
fb_ptr[i * (framebuffer->pitch / 4) + i] = 0xffffff; |
fb_ptr[i * (framebuffer->pitch / 4) + i] = 0xffffff; |
||
} |
} |
||
Line 162: | Line 173: | ||
PHDRS |
PHDRS |
||
{ |
{ |
||
requests PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */ |
|||
text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */ |
|||
rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */ |
|||
data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */ |
|||
dynamic PT_DYNAMIC FLAGS((1 << 1) | (1 << 2)) ; /* Dynamic PHDR for relocations */ |
|||
} |
} |
||
Line 175: | Line 187: | ||
/* that is the beginning of the region. */ |
/* that is the beginning of the region. */ |
||
. = 0xffffffff80000000; |
. = 0xffffffff80000000; |
||
/* Define a section to contain the Limine requests and assign it to its own PHDR */ |
|||
.requests : { |
|||
*(.requests_start_marker) |
|||
*(.requests) |
|||
*(.requests_end_marker) |
|||
} :requests |
|||
/* Move to the next memory page for .text */ |
|||
. += CONSTANT(MAXPAGESIZE); |
|||
.text : { |
.text : { |