kernel/.wiki/Kernel-documentation.md

13 KiB

Kernel Documentation

The kernel is booted using the limine boot protocol.

Directory structure

  • boot - all stuff related to booting / jumping into the kernel
  • drivers - everything from the graphics driver, to the FS drivers
  • mm - memory management stuff like page frames and page maps
  • platform - universal API to the platform specific code in the subdirs
  • proc - all the process/thread related stuff like the scheduler
  • utils - utilities like type definitions, math functions, high-level memory management

General concepts

kernel initialization

The single parts of the kernel are initialized in the following order:

  • Global Descriptor Table
  • Page Frame Manager
  • Interrupt Descriptor Table

interrupt handling

OSDev Wiki: Interrupts

Unfortunatly the x86 architecture doesn't provide a method to get the ID of the current interrupt. To solve this problem, there is a simple assembly function for every interrupt used by NoxOS. This function pushes its ID on the stack. After that it calls a common Interrupt handler, this handler will generate the current cpu_state_T and call the C interrupt handler implementation. The C implementation returns a cpu_state_T that will then be loaded.

paging

OSDev Wiki: Paging

There is a difference between Virtual Memory Spaces and the Physical Memory Space. The Physical memory space is how the data lies directly in the RAM.

Virtual memory spaces are a bit more tricky. To understand them, we have to understand first, that the physical memory space is divided into so-called pages / page frames. These pages have a size of 4KB.

A virtual memory space is a table of page mappings. Per default there are no pages mapped to such a table. When the OS maps a page to a page table, it says: "This page is now accessible from this virtual space, at this address". When the Computer is in paging mode, only mapped pages are accessible. Now every Process gets its own page table and tada: we have successfully isolated the processes from each other, because every process can only access the data that it needs to access.


DISCLAIMER: Only the headers are documented, because documenting the whole code itself would be very time intensive and the headers as 'public' API are the most important to document.

boot

boot_info.h

The goal of this file is to provide a universal struct of information needed by the kernel at start time. At the moment this information is very limine specific, but the goal is to make it easy to add support for other boot protocols.

boot_info_T - struct

  • framebuffer - struct with information about the graphics buffer
  • terminal - bootloader terminal / log
  • memory_map - information about the memory layout / regions
  • rsdp - pointer to RSDP

limine.h

This header provides the API to "communicate" with the limine bootloader. More information can be found on the limine project's GitHub.

mm

page_frame.h

This header provides the functions for basic interactions with pages (in the physical memory space).

pframe_manager_init() - function (void)

Initializes the page frame manager, needs to be called once at kernel init.

pframe_reserve(address) - function (void) [Thread Safe]

Blocks a page, so it can't be requested or anything else. If the page is already blocked by anything else, e.g. by a request, it won't be reserved.

pframe_reserve_multi(address, n) - function (void) [Thread Safe]

Reserves the page at the given address, plus n pages after that page.

pframe_unreserve(address) - function (void) [Thread Safe]

Unreserves a reserved page and makes it accessible again.

pframe_unreserve_multi(address, n) - function (void) [Thread Safe]

Unreserves the page at the given address, plus n pages after that page.

pframe_request() - function (void*) [Thread Safe]

Returns the physical address of a page. This is kind of the low level version of malloc.

pframe_free(address) - function (void) [Thread Safe]

Needs a valid page address produced by pframe_request() as argument. Invalidates the address and frees it, so it can be requested again. This is kind of the low level version of free.

pframe_free_multi(address, n) - function (void) [Thread Safe]

Frees the page at the given address, plus n pages after that page.

platform

cpu.h

This header contains stuff directly related to the CPU.

OSDev Wiki: x86 CPU Registers

cpu_state_T - struct

  • cr3 - Control register 3, holds the current page table
  • rax - General purpose register
  • rbx - General purpose register
  • rcx - General purpose register
  • rdx - General purpose register
  • rsi - General purpose register
  • rdi - General purpose register
  • rbp - The Bottom of the current stack frame
  • interrupt_id - The ID of the interrupt, that captured the cpu state
  • error_code - Some exceptions such as the Page fault push more detailed information into here
  • rip - The current instruction address
  • crs - Segment selector of the associated IDT descriptor
  • flags - The CPU's FLAGS register, a status bitmap
  • rsp - The Top of the current stack frame
  • ss - Not totally sure, what this does, but it has to do with security rings

This struct defines a complete CPU state, that can be saved and restored. It is saved when the CPU fires an interrupt and restored by the interrupt handler when it's finished. This allows multithreading and exception analysis.

cpu_flags_E - enum

  • CPU_FLAG_CARRY
  • CPU_FLAG_PARITY
  • CPU_FLAG_AUXILIARY
  • CPU_FLAG_ZERO
  • CPU_FLAG_SIGN
  • CPU_FLAG_TRAP
  • CPU_FLAG_INTERRUPT_ENABLE
  • CPU_FLAG_DIRECTION
  • CPU_FLAG_OVERFLOW
  • CPU_FLAG_IO_PRIVILEGE_0
  • CPU_FLAG_IO_PRIVILEGE_1
  • CPU_FLAG_NESTED_TASK
  • CPU_FLAG_RESUME
  • CPU_FLAG_VIRTUAL_8086
  • CPU_FLAG_ALIGNMENT_CHECK
  • CPU_FLAG_VIRTUAL_INTERRUPT
  • CPU_FLAG_VIRTUAL_INTERRUPT_PENDING
  • CPU_FLAG_CPUID

exceptions.h

OSDev Wiki: Exceptions

exception_type_E - enum

These are just the definitions of the CPU-exception interrupt IDs.

g_exception_type_strings - global variable

This array of strings defines the names of the Exceptions.

exception_handle(cpu_state) - function (cpu_state_T*)

If an interrupt is an exception, the interrupt handler will call this function to handle the exception. At the moment it will just panic, but in far future this could get expanded for page swapping, etc.

gdt.h

OSDev Wiki: Global Descriptor Table

gdt_selector_E - enum

  • Null
  • Kernel Code
  • Kernel Data
  • User Null
  • User Code
  • User Data

gdt_descriptor_T - struct [packed]

Well documented on the osdev wiki.

gdt_entry_T - struct [packed]

Well documented on the osdev wiki.

gdt_T - struct [packed / page aligned]

A template that holds a gdt_entry_T for every selector

g_default_gdt - global variable

The default GDT configuration loaded when the GDT gets initialized.

gdt_init() - function (void)

Loads a descriptor of g_default_gdt as the system GDT.

interrupts.h

This header contains all the stuff, needed to init and handle Interrupts.

idt_register_T - struct [packed]

This struct is very similar to the GDT descriptor. It holds the size and address of the Table, where the interrupt handlers are looked up.

idt_descriptor_entry_T - struct

This struct stores information about one interrupt handler. The osdev wiki explains this more detailed.

g_idt_register - global variable

The default IDT configuration loaded when the IDT gets initialized.

idt_init() - function (void)

This function fills all the interrupt gates (handlers) into the IDT and loads it.

utils

bitmap.h

Provides functionalities to create, destruct and work with bitmaps.

bitmap_T - struct

This struct holds a buffer for a bitmap and its size. The size is the size of the buffer in bytes, to get the amount of storable bits multiply size with 8.

bitmap_init_from_buffer(buffer, size) - function (bitmap_T)

Creates a bitmap object from a given buffer and size

bitmap_init(size) - function (bitmap_T) [NOT IMPLEMENTED YET]

Allocates memory to hold a bitmap in the given size and returns a bitmap_T with that buffer and size.

bitmap_destruct(bitmap*) - function (void) [NOT IMPLEMENTED YET]

Frees the memory of the given bitmap created with bitmap_init.

bitmap_set(bitmap*, index, value) - function (bool)

Sets the bit at the given index in the given bitmap to the given boolean value. Returns false, if the index is out of the bitmaps size bounds. Returns true, if the operation was successful.

bitmap_get(bitmap*, index) - function (bool)

Returns the boolean value stored at the given index in the given bitmap. Always returns false, if the index is out of the bitmaps size bounds.

core.h

All the utils, which I didn't know how to name.

CORE_HALT_WHILE(a) - macro

This halts until a is true. Used when working with blocking variables in e.g. thread safe functions.

CORE_HALT_FOREVER - macro

This halts forever and warns about this in the log.

io.h

Provides basic Input/Output functionalities.

io_out_byte(port, data) - function (void)

Writes one byte of data to port. This is a wrapper around the assembly outb instruction.

io_in_byte(port) - function (uint8_t)

Reads one byte from port and returns it. This is a wrapper around the assembly inb instruction.

logger.h

Functionalities to write logs to QEMU's serial port.

log_level_E - enum

  • Info - General information, that could be useful
  • Debug - Should only be used to find bugs and removed (or commented out) after the bug is found
  • Warning - Used for warnings and not important errors
  • Error - Used for Fatal Errors / Will be printed to the screen (graphics driver is not Implemented yet)

log(log_level, string) - function (void)

Logs the given string to QEMU's log port, the string is prefixed with the log type.

math.h

Mathematical functions, definitions, etc.

MAX(a, b) - macro

Returns the bigger one of the given values.

MIN(a, b) - macro

Returns the smaller one of the given values.

CEIL_TO(a, b) - macro

Aligns a upwards to b. Example: CEIL_TO(13, 8) would return 16, because 16 is the next higher multiple of 8 after 13.

FLOOR_TO(a, b) - macro

Aligns a downwards to b. Example: FLOOR_TO(13, 8) would return 8, because 8 is the next smaller multiple of 8 before 13.

pow(base, exponent) - function (uint64_t)

Returns the power of base ^ exponent.

memory.h

Basic memory functionalities.

memory_copy(source, destination, num) - function (void)

Copies num bytes from source to destination. On linux this function is called memcpy.

memory_set(destination, data, num) - function (void)

Sets num bytes at destination to data. On linux this function is called memset.

memory_compare(a, b, num) - function (bool)

Compares the first num bytes at a and b. Returns false if there is a different byte. Returns true if the data is the same. There is a similar function on linux called memcmp.

panic.h

Ahhhhh - the kernel is burning!

panic(state, message) - function (void)

This prints out the error message, a stack backtrace (planned) and a register dump (planned). After that, the kernel halts forever. This function is called, when a fatal error occurs

stdtypes.h

Standard type definitions, that are used almost everywhere.

uint8_t - typedef

8-bit wide unsigned int.

Range: 0 - 255

int8_t - typedef

8-bit wide signed int.

Range: -128 - 127

uint16_t - typedef

16-bit wide unsigned int.

Range: 0 - 65536

int16_t - typedef

16-bit wide signed int.

Range: -32768 - 32767

uint32_t - typedef

32-bit wide unsigned int.

Range: 0 - 4294967296

int32_t - typedef

32-bit wide signed int.

Range: -2147483648 - 2147483647

uint64_t - typedef

64-bit wide unsigned int.

Range: 0 - 18446744073709551616

int64_t - typedef

64-bit wide unsigned int.

Range: -9223372036854775808 - 9223372036854775807

bool - typedef

Boolean type, can hold a logical value true or false.

true - macro

Logical true value.

false - macro

Logical false value

NULL - macro

A pointer to nowhere.

string.h

string_t - typedef

A null-terminated array of chars.

string_length(string) - function (uint32_t)

Returns the amount of chars a string has before it's null-terminator.

string_compare(a, b) - function (bool)

Returns true when the strings a and b are equal. Returns false if they aren't equal.