67 lines
2.0 KiB
Markdown
67 lines
2.0 KiB
Markdown
# Multiboot Data
|
|
|
|
In this chapter we'll parse the multiboot information structure passed
|
|
to the kernel from the bootloader.
|
|
|
|
## Passing the data to the kernel
|
|
When a multiboot compliant bootloader passes controll to the kernel, the
|
|
registers `eax` and `ebx` contains a magic number and a pointer to the
|
|
multiboot information structure respectively.
|
|
|
|
If we wish to pass those on to the kernel main function, we can do that
|
|
according to the System V ABI calling convention. According to this,
|
|
the first two arguments to a function should be passed in the `rdi` and
|
|
`rsi` registers for x86\_64. Those obviously correspond to `edi` and
|
|
`esi` in 32-bit mode, and luckily those registers are unused throughout
|
|
the entire long mode transition process, untill we call `kmain`.
|
|
|
|
So everything we need to to do preserve the information is to move it
|
|
into those registers. Might as well do that as soon as possible.
|
|
|
|
`src/kernel/boot/boot.S`
|
|
```asm
|
|
...
|
|
_start:
|
|
cli
|
|
|
|
mov edi, eax
|
|
mov esi, ebx
|
|
|
|
...
|
|
```
|
|
|
|
And `kmain` is updated accordingly:
|
|
`src/kernel/boot/kmain.c`
|
|
```c
|
|
...
|
|
void kmain(uint64_t multiboot_magic, void *multiboot_data)
|
|
{
|
|
...
|
|
```
|
|
|
|
## Reading the multiboot information
|
|
|
|
Reading the data passed from the bootloader is actually pretty straight
|
|
forward. It's stored as a list of "tags" with a 32 bit type and 32 bit
|
|
size followed by the data.
|
|
|
|
I just step through the tag list and save the data I want into a global
|
|
structure. The only possible pitfall is that tags are 8 byte alligned,
|
|
so finding the next tag can look like:
|
|
|
|
```c
|
|
int padded_size = tag->size + ((tag->size % 8)?(8-(tag->size%8)):0);
|
|
tag = incptr(tag, padded_size);
|
|
```
|
|
|
|
`incptr` is just a macro I made to move a pointer a number of bytes
|
|
forward or backward. Quite useful.
|
|
|
|
```c
|
|
#define incptr(p, n) ((void *)(((uintptr_t)(p)) + (n)))
|
|
```
|
|
|
|
For now, I only save the bootloader name (type 2) and kernel commandline
|
|
(type 1), and that's just for testing purposes. Later we'll also want to
|
|
save and parse the memory map (type 6) and any modules (type 3).
|