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 higher half Limine-compliant kernel in [[C]], and boot it using the [[Limine]] bootloader.
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/kernel.c
* 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/kernel.c===
===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 1, this is recommended as this is the latest
// 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(1);
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
{
{
text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */
requests PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */
rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */
text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */
data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */
rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */
dynamic PT_DYNAMIC FLAGS((1 << 1) | (1 << 2)) ; /* Dynamic PHDR for relocations */
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 : {