1479 lines
67 KiB
Markdown
1479 lines
67 KiB
Markdown
# 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:
|
|
- **Page Frame Manager**
|
|
- **Interrupts**
|
|
- **[IDT] Interrupt Descriptor Table**
|
|
- **[PIC] Programmable Interrupt Controller**
|
|
- **Paging**
|
|
- **Kernel Heap**
|
|
- **Graphics Renderer**
|
|
- **Scheduler**
|
|
|
|
## Interrupt handling
|
|
OSDev Wiki: [Interrupts](https://wiki.osdev.org/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](https://wiki.osdev.org/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.
|
|
|
|
## Panic screen
|
|
When a fatal / not recoverable error occurs, the kernel panics. It logs panic information and then halts forever.
|
|
Such a panic log can look like the following one:
|
|
```
|
|
[ Error ] !=====[ KERNEL PANIC ]=====!
|
|
Error Message: Division Error
|
|
Interrupt ID: 0x00
|
|
Error Code: 0b00000000000000000000000000000000
|
|
|
|
Paging Info:
|
|
Page Map: 0x000000000FAE9000
|
|
|
|
CPU Flags:
|
|
Parity
|
|
Sign
|
|
Interrupt Enable
|
|
|
|
CPU Registers:
|
|
RIP: 0xFFFFFFFF80002745 RAX: 0x0000000000000001 RBX: 0x0000000000000000
|
|
RCX: 0x0000000000000000 RDX: 0x0000000000000000 RSI: 0x000000000001F980
|
|
RDI: 0x00001000005DF7A0 RBP: 0xFFFF80000FAF9F40 RSP: 0xFFFF80000FAF9F30
|
|
|
|
Call Stack:
|
|
0xFFFFFFFF80000000+033F -> _start
|
|
0xFFFFFFFF8000274D+0078 -> kmain
|
|
0xFFFFFFFF80002732+0013 -> test
|
|
[ Warning ] !=====[ HALTING SYSTEM ]=====!
|
|
```
|
|
but what does it say?
|
|
|
|
In most cases, a panic occurs while handling an interrupt.
|
|
If this is the case, we will have the state of the cpu while it was interrupted.
|
|
This cpu state provides us very much information.
|
|
|
|
`Interrup ID` tells us, which interrupt caused the panic.
|
|
In this case the ID is `0x0E`, a `Page Fault Exception`.
|
|
|
|
`Error Code` is a binary representation of the 32 least significant bits of the error code pushed by some interrupts.
|
|
If an interrupt pushes no error code, this will be just zeros.
|
|
In our example the code tells us, that the error happened because of a write attempt to a not present page.
|
|
|
|
`Error Message` tells us, what happened.
|
|
|
|
`Paging Info` contains all information about paging.
|
|
At the moment, this is just the physical address of the loaded page map.
|
|
|
|
`CPU Flags` contains information about which bits are set in the CPU status register.
|
|
If this block doesn't appear, there are no bits set.
|
|
|
|
`CPU Registers` contains the data, in the main cpu registers.
|
|
This is probably the most interesting block, because you get very detailed information out of here,
|
|
if you know what each of these registers does in the cpu.
|
|
|
|
`Call Stack` lists the current function call chain, starting from the least recent call.
|
|
The big hex number is the base of the function and the small hex number is the offset, where the next function was called.
|
|
After the `->` follows the name of the function.
|
|
|
|
### Panic without interrupt
|
|
If the panic wasn't caused by an interrupt, it has no cpu_state, and because of that it has no detailed info about the execution state.
|
|
In this rare case, you will get the following message:
|
|
```
|
|
No detailed Information available (cpu_state null reference)
|
|
```
|
|
The `Error Message` could still be helpful, but good luck finding that bug.
|
|
|
|
## Syscalls
|
|
NoxOS will use interrupt based syscalls.
|
|
To perform a syscall, write its ID into the `rax` register and call interrupt 0x80.
|
|
|
|
**Example:**
|
|
```nasm
|
|
mov rax, 0x0000
|
|
int 0x80
|
|
```
|
|
|
|
The syscalls are grouped into groups and their ID consists of a _group-ID_ (first two digits) and a _syscall-ID_ (last two digits).
|
|
|
|
### Syscall groups
|
|
- **Misc** - 0x00
|
|
- **File** - 0x01
|
|
- **Proc** - 0x02
|
|
- **Kernel** - 0xFF
|
|
|
|
### Misc Syscalls - `0x00--`
|
|
|
|
### File Syscalls - `0x01--`
|
|
|
|
### Proc Syscalls - `0x02--`
|
|
|
|
### Kernel Syscalls - `0xFF--`
|
|
The kernel syscalls can only be called by the kernel process and its childs. All other processes, won't be able to use this functions.
|
|
|
|
| ID | Name | Description |
|
|
|--------|-----------------|------------------------------------------------------------------------------------------------------|
|
|
| 0xFF00 | scheduler_start | Initializes the Kernels main thread from the current cpu_state. This is used to start multithreading |
|
|
|
|
|
|
## Format strings
|
|
Format strings are strings that are formatted at runtime.
|
|
They are created by defining a pattern, like the following one:
|
|
|
|
`"Name: %s / ID: %d"`
|
|
|
|
And giving it arguments at runtime, let's use the following ones for our example:
|
|
|
|
`"Main Process", 42`
|
|
|
|
This would format to that:
|
|
|
|
`Name: Main Process / ID: 42`
|
|
|
|
As you see, `%s` and `%d` are placeholders.
|
|
Placeholders consist of a `%` sign followed by one or two letters.
|
|
When formatting the string, the placeholders are replaced with the arguments.
|
|
The first placeholder is replaced with the first argument, the second with the second and so on.
|
|
|
|
### Numeric specifier
|
|
If you put a `.` followed by a number right after the percentage sign of a placeholder,
|
|
you will set the `Numeric specifier`.
|
|
If the `.` is followed by an astrix, the numeric specifier is passed as its own argument.
|
|
Some placeholders use this numeric specifier to configure their output.
|
|
If you don't set a numeric specifier, the placeholders, that would use it will use a default value instead.
|
|
|
|
### Arguments
|
|
Make sure, that the arguments you pass, are really of the right type.
|
|
If you e.g. pass a negative value of type `int32_t` like `-1312`,
|
|
the formatter will have problems with that, because the `int32_t` representation of that number is as an `int64_t` a positive number.
|
|
|
|
### Placeholders
|
|
#### `%s` - string
|
|
| **Argument Type** | `string_t` |
|
|
|-------------------------------|--------------------------------------------------|
|
|
| **Numeric Specifier Use** | Specifies the maximum length the string can have |
|
|
| **Numeric Specifier Default** | String Length |
|
|
| **Description** | Inserts a string |
|
|
|
|
#### `%c` - char
|
|
| **Argument Type** | `char` |
|
|
|-------------------------------|---------------------|
|
|
| **Numeric Specifier Use** | None |
|
|
| **Numeric Specifier Default** | None |
|
|
| **Description** | Inserts a character |
|
|
|
|
#### `%u` - unsigned decimal
|
|
| **Argument Type** | `uint64_t` |
|
|
|-------------------------------|-----------------------------|
|
|
| **Numeric Specifier Use** | None |
|
|
| **Numeric Specifier Default** | None |
|
|
| **Description** | Inserts an unsigned integer |
|
|
|
|
#### `%d` - signed decimal
|
|
| **Argument Type** | `int64_t` |
|
|
|-------------------------------|--------------------------|
|
|
| **Numeric Specifier Use** | None |
|
|
| **Numeric Specifier Default** | None |
|
|
| **Description** | Inserts a signed integer |
|
|
|
|
#### `%x` - hexadecimal
|
|
| **Argument Type** | `uint64_t` |
|
|
|-------------------------------|------------------------------|
|
|
| **Numeric Specifier Use** | None |
|
|
| **Numeric Specifier Default** | None |
|
|
| **Description** | Inserts a 64 bit hex integer |
|
|
|
|
##### variants
|
|
###### `%xb` - byte hexadecimal
|
|
| **Argument Type** | `uint8_t` |
|
|
|-------------------------------|-----------------------------|
|
|
| **Numeric Specifier Use** | None |
|
|
| **Numeric Specifier Default** | None |
|
|
| **Description** | Inserts a 8 bit hex integer |
|
|
|
|
###### `%xw` - word hexadecimal
|
|
| **Argument Type** | `uint16_t` |
|
|
|-------------------------------|------------------------------|
|
|
| **Numeric Specifier Use** | None |
|
|
| **Numeric Specifier Default** | None |
|
|
| **Description** | Inserts a 16 bit hex integer |
|
|
|
|
###### `%xd` - dword hexadecimal
|
|
| **Argument Type** | `uint32_t` |
|
|
|-------------------------------|------------------------------|
|
|
| **Numeric Specifier Use** | None |
|
|
| **Numeric Specifier Default** | None |
|
|
| **Description** | Inserts a 32 bit hex integer |
|
|
|
|
###### `%xq` - qword hexadecimal
|
|
This variant is the `%x` standard.
|
|
|
|
| **Argument Type** | `uint64_t` |
|
|
|-------------------------------|------------------------------|
|
|
| **Numeric Specifier Use** | None |
|
|
| **Numeric Specifier Default** | None |
|
|
| **Description** | Inserts a 64 bit hex integer |
|
|
|
|
|
|
#### `%?` - boolean
|
|
| **Argument Type** | `bool` |
|
|
|-------------------------------|---------------------------|
|
|
| **Numeric Specifier Use** | None |
|
|
| **Numeric Specifier Default** | None |
|
|
| **Description** | Inserts `true` or `false` |
|
|
|
|
#### `%b` - binary
|
|
| **Argument Type** | `uint64_t` |
|
|
|-------------------------------|-----------------------------------------------|
|
|
| **Numeric Specifier Use** | The amount of bits that are shown |
|
|
| **Numeric Specifier Default** | 64 |
|
|
| **Description** | Inserts the binary string of the given number |
|
|
|
|
#### `%%` - mask
|
|
This is not a really a placeholder, but you can use this to mask the % sign,
|
|
so it will be interpreted as just a `%` instead of a placeholder.
|
|
|
|
|
|
## Executables
|
|
NoxOS uses the **ELF** executable format, which is the linux/unix standard.
|
|
Further information can be found in the `Syscalls` and `drivers/elf/elf.h` documentation.
|
|
|
|
---
|
|
|
|
**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
|
|
| Name | Description |
|
|
|-------------|---------------------------------------------------|
|
|
| framebuffer | struct with information about the graphics buffer |
|
|
| terminal | bootloader terminal / graphical log |
|
|
| memory_map | information about the memory layout / regions |
|
|
| kernel_file | The unparsed kernel ELF file |
|
|
| rsdp | _Root System Description Pointer_ |
|
|
|
|
### limine.h
|
|
This header provides the API to "communicate" with the limine bootloader.
|
|
More information can be found on the limine project's [GitHub](https://github.com/limine-bootloader/limine/blob/trunk/PROTOCOL.md).
|
|
|
|
|
|
## drivers
|
|
|
|
### elf/elf.h
|
|
#### `elf_executable_T` - struct
|
|
This struct holds the parsed data of an ELF executable.
|
|
|
|
| Name | Type | Description |
|
|
|--------------|----------------|----------------------------------------------------------------------------------------------------------------------------------|
|
|
| header | elf_header_T | The header of the elf file |
|
|
| num_symbols | uint64_t | The size of _symbols_ |
|
|
| symbols | symbol_T* | An array containing all symbols of the elf file |
|
|
| num_mappings | uint64_t | The size of _mappings_ |
|
|
| mappings | elf_mapping_T* | An array containing the mappings needed to load the elf file |
|
|
| string_table | void* | A copy of the elf files `.strtab` section, all strings are referenced here to have them available even if the elf file is closed |
|
|
|
|
#### `elf_executable_temp_T` - struct
|
|
This struct is used while generating an `elf_executable_T`.
|
|
It holds parse-time information about the elf file.
|
|
|
|
| Name | Type | Description |
|
|
|-----------------------------|-------------------|------------------------------------------------|
|
|
| executable | elf_executable_T* | A pointer to the final `elf_executable_T` |
|
|
| symbol_table | elf_section_T* | A pointer to `.symtab` in _buffer_ |
|
|
| section_header_string_table | elf_section_T* | A pointer to `.shstrtab` in _buffer_ |
|
|
| buffer | uint8_t* | The buffer where the executable is loaded from |
|
|
|
|
#### `elf_executable_create(buffer)` - function (elf_executable_T*)
|
|
Generates an `elf_executable_T` from an elf file loaded to **_buffer_** and returns a pointer to it.
|
|
|
|
#### `elf_executable_destruct(executable)` - function (void)
|
|
Frees all memory allocated for **_executable_**.
|
|
|
|
### elf/header.h
|
|
The enums in this header describe the possible values that a field of the elf header can have.
|
|
|
|
#### `elf_target_architecture_E` - enum
|
|
Field in header: **identity[4]**
|
|
|
|
#### `elf_endianness_E` - enum
|
|
Field in header: **identity[5]**
|
|
|
|
#### `elf_sysabi_E` - enum
|
|
Field in header: **identity[7]**
|
|
|
|
#### `elf_object_type_E` - enum
|
|
Field in header: **type**
|
|
|
|
#### `elf_instruction_set_E` - enum
|
|
Field in header: **isa**
|
|
|
|
#### `elf_header_T` - struct
|
|
|
|
| Name | Type | Description |
|
|
|----------------------------|-------------|-------------------------------------------------------------------|
|
|
| identity | uint8_t[16] | Information like the used endian and the SysABI is stored in here |
|
|
| type | uint16_t | The type of the elf file -> `elf_object_type_E` |
|
|
| isa | uint16_t | The used instruction set -> `elf_instruction_set_E` |
|
|
| version | uint32_t | ELF version |
|
|
| address_entry_point | uint64_t | The start point for program execution |
|
|
| offset_program_header | uint64_t | The position of the program header array in the file |
|
|
| offset_section_header | uint64_t | The position of the section header array in the file |
|
|
| flags | uint32_t | Architecture dependent, can be ignored |
|
|
| len_header | uint16_t | The size of this header |
|
|
| len_program_header_entry | uint16_t | The size of one program header |
|
|
| num_program_header_entries | uint16_t | The amount of program headers |
|
|
| len_section_header_entry | uint16_t | The size of one section header |
|
|
| num_section_header_entries | uint16_t | The amount of section headers |
|
|
| string_section_index | uint16_t | The section header index of the `.shstrtab` section |
|
|
|
|
|
|
#### `g_elf_target_architecture_strings` - global variable
|
|
An array of strings matching `elf_target_architecture_E`.
|
|
|
|
#### `g_elf_endianness_strings` - global variable
|
|
An array of strings matching `elf_endianess_E`.
|
|
|
|
#### `g_elf_sysabi_strings` - global variable
|
|
An array of strings matching `elf_sysabi_E`.
|
|
|
|
#### `g_elf_object_type_strings` - global variable
|
|
An array of strings matching `elf_object_type_E`.
|
|
|
|
#### `g_elf_instruction_set_strings` - global variable
|
|
An array of strings matching `elf_instruction_set_E`.
|
|
|
|
#### `elf_init_kernel_exec(boot_info)` - function (void) [Will be replaced in near future]
|
|
Loads the kernel elf into `g_kernel_executable`.
|
|
|
|
#### `g_kernel_executable` - global variable [Will be replaced in near future]
|
|
Holds the parsed kernel executable.
|
|
|
|
This will be removed, when processes are implemented, because then this can be accessed via the kernel process control struct.
|
|
|
|
### elf/mapping.h
|
|
#### `elf_mapping_T` - struct
|
|
A mapping describes an area of memory,
|
|
that should be copied from the elf file into the RAM and how/where it should be mapped.
|
|
|
|
| Name | Type | Description |
|
|
|----------------|----------|------------------------------------------------------------------------------------------------------------------|
|
|
| offset_file | uint64_t | The mappings' start in the elf file |
|
|
| offset_virtual | uint64_t | The mappings' start in memory |
|
|
| length_file | uint64_t | The mappings' size in the elf file |
|
|
| length_virtual | uint64_t | The mappings' size in memory, if this is bigger than _length_file_ the remaining space will be filled with zeros |
|
|
|
|
#### `elf_mappings_apply(mappings, num_mappings, buffer, base, page_map)` - function (void)
|
|
Maps all **_mappings_** into **_page_map_** and copies the related data from **_buffer_** (elf file) to the mapped memory.
|
|
**_base_** specifies where the mappings should start in the virtual address space.
|
|
|
|
### elf/section.h
|
|
#### `elf_section_type_E` - enum
|
|
- **Null** - These sections can be ignored
|
|
- **Program Data** - These link to segments, if I remember right
|
|
- **Symbol Table** - Here are all the executables' symbols stored
|
|
- **String Table** - Here are all strings stored
|
|
- **RelocationA** - Contains relocation information
|
|
- **Hash** - Symbol Table hash table
|
|
- **Dynamic Link** - This provides information for the dynamic linker
|
|
- **Note** - notes that were created by the compiler / toolchain
|
|
- **Nobits** - Nulled data like `.bss`
|
|
|
|
#### `elf_section_T` - struct
|
|
|
|
| Name | Type | Description |
|
|
|-----------------|----------|-------------------------------------------------------------------|
|
|
| name_offset | uint32_t | The offset of the sections name in `.shstrtab` |
|
|
| type | uint32_t | The type of the section -> `elf_section_type_E` |
|
|
| flags | uint64_t | Sections attribute flags |
|
|
| virtual_address | uint64_t | The address where the section should be mapped to (if it's not 0) |
|
|
| offset | uint64_t | The sections offset in the file |
|
|
| length | uint64_t | The size of the section |
|
|
| link | uint32_t | Type specific link to another section |
|
|
| info | uint32_t | Type specific information |
|
|
| alignment | uint64_t | If the section is aligned, this value specifies the alignment |
|
|
| entry_size | uint64_t | The size of the sections entries |
|
|
|
|
|
|
#### `g_elf_section_type_strings` - global variable
|
|
An array of strings matching `elf_section_type_E`.
|
|
|
|
### elf/segment.h
|
|
#### `elf_segment_type_E` - enum
|
|
- **Null** - Unused segment
|
|
- **Load** - Segment that should be included into mappings
|
|
- **Dynamic** - Segments of this type contain dynamic linking information
|
|
- **Interpreter** - This holds a path to an interpreter
|
|
- **Note** - These segments hold notes by the compiler / toolchain
|
|
- **Program Header Table** - This points to the table that is holding the segment headers
|
|
- **TLS** - This holds a Thread Local Storage template
|
|
|
|
#### `elf_segment_T` - struct
|
|
|
|
| Name | Type | Description |
|
|
|------------------|----------|-----------------------------------------------------------------|
|
|
| type | uint32_t | The segments type -> `elf_segment_type_E` |
|
|
| flags | uint32_t | The segments flags (Read / Write / Execute) |
|
|
| offset | uint64_t | The segments position in the elf file |
|
|
| address_virtual | uint64_t | Where the segment should be mapped in the virtual address space |
|
|
| address_physical | uint64_t | Not used in the `System V` ABI |
|
|
| length_file | uint64_t | The segments size in the file |
|
|
| length_memory | uint64_t | The size of the area that should be mapped for the segment |
|
|
| align | uint64_t | The segments alignment (has to be a power of 2) |
|
|
|
|
#### `g_elf_segment_type_strings` - global variable
|
|
An array of strings matching `elf_segment_type_E`.
|
|
|
|
### elf/symbol.h
|
|
#### `ELF_SYMBOL_TYPE(info)` - macro
|
|
Extracts the `elf_symbol_type_E` from the symbols info value.
|
|
|
|
#### `elf_symbol_type_E` - enum
|
|
- **None** - Unspecified type
|
|
- **Object** - Data objects like variables, arrays, etc.
|
|
- **Func** - Function
|
|
- **Section** - Associated section
|
|
- **File** - The path to the source file associated with the object
|
|
- **Common** - Uninitialized common blocks
|
|
- **TLS** - Thread Local Storage
|
|
|
|
#### `elf_symbol_T` - struct
|
|
|
|
| Name | Type | Description |
|
|
|-----------------------|-------------------------------------------------------------------|-------------|
|
|
| name_offset | The offset of the symbols name in `.strtab` | |
|
|
| info | Information about the symbol (type, bind) | |
|
|
| other | Information about the symbol (visibility) | |
|
|
| related_section_index | The index of the symbols related section | |
|
|
| value | Value, in most cases this is an address | |
|
|
| length | The size of the symbol (e.g. num bytes if the symbol is an array) | |
|
|
|
|
|
|
### fs/ramfs.h
|
|
**Warning:** This is a filesystem specific driver, by this it should only be accessed by the vfs.
|
|
|
|
The ramfs (ram-filesystem) is not a filesystem in the common sense.
|
|
All data that is stored in ramfs is stored in the virtual file systems cache.
|
|
This means that all data in ramfs is temporary and erased after a reboot.
|
|
|
|
#### `ramfs_file_delete(node)` - function (void)
|
|
Frees the files cache space. This won't delete the node in the vfs.
|
|
|
|
#### `ramfs_file_write(node, size, buffer_in)` - function (void)
|
|
If this file has some cache space allocated, it will be freed.
|
|
Then there will be some cache space (**_size_** bytes) allocated and **_size_** bytes from **_buffer_in_** copied into the cache.
|
|
|
|
This use of the vfs cache isn't a great solution and should be reworked.
|
|
|
|
#### `ramfs_file_read(node, size, buffer_out)` - function (void)
|
|
Copies **_size_** bytes from the files' cache to **_buffer_out_**.
|
|
This won't copy more bytes than the allocated cache space is big.
|
|
|
|
### fs/ustar.h
|
|
The USTAR '_filesystem_' is probably more common known as **tar**-archive.
|
|
It is a really simple concept, where a file consists of a header block followed by data blocks.
|
|
These blocks are aligned at 512 bytes.
|
|
|
|
OSDev Wiki: [USTAR](https://wiki.osdev.org/USTAR)
|
|
|
|
#### `ustar_type_E` - enum
|
|
The types an entry can have:
|
|
- **File**
|
|
- **Hardlink**
|
|
- **Symlink**
|
|
- **Char Device**
|
|
- **Block Device**
|
|
- **Directory**
|
|
- **Pipe**
|
|
|
|
#### `ustar_header_T` - struct [packed / 512B aligned]
|
|
|
|
| Name | Type | Description |
|
|
|-------------------|-----------|------------------------------------------------------------------------------|
|
|
| name | char[100] | The name of the entry |
|
|
| mode | uint64_t | file mode (permissions, etc) |
|
|
| owner_id | uint64_t | The owners ID |
|
|
| group_id | uint64_t | The groups ID |
|
|
| size | char[12] | The size of the entry, represented as a string of an octal number (dafuq) |
|
|
| last_modification | char[12] | The unix-timestamp, when the entry was modified the last time |
|
|
| checksum | uint64_t | I think this is a weird checksum of the header |
|
|
| type | uint8_t | The type (`ustar_type_E`) of the entry, represented as ascii numbers (dafuq) |
|
|
| name_linked | char[100] | The path to the linked entry, if this is a link-entry |
|
|
| indicator | char[6] | This needs to be `ustar` |
|
|
| version | uint16_t | The version of the **tar** command, that created the archive |
|
|
| owner_user_name | char[32] | The name of the file owner |
|
|
| owner_group_name | char[32] | The name of the file group |
|
|
| device_major | uint64_t | The devices major number |
|
|
| device_minor | uint64_t | The devices minor number |
|
|
| name_prefix | char[155] | If this is not null, this acts as a prefix for _name_ |
|
|
|
|
|
|
### fs/vfs.h
|
|
|
|
**VFS** stands for _Virtual File System_ and is an abstraction,
|
|
that kinda merges all mounted filesystems into one.
|
|
It provides a general API for dealing with files, and handles all fs specific stuff in the background.
|
|
This VFS is node based, meaning, that every file, directory, mount point, etc is represented as a node in memory.
|
|
Nodes have a type and a fs.
|
|
Nodes can have children and next and previous nodes.
|
|
|
|
Example node relations:
|
|
```
|
|
+-----------+
|
|
| Root Node | <---------+
|
|
+-----------+ |
|
|
| |
|
|
[Childs] [Parent]
|
|
| +-------------+---------------+
|
|
v / | \
|
|
+-------+ +-------+ +-------+
|
|
| Child | --[Next]-> | Child | --[Next]-> | Child |
|
|
| 1 | <-[Prev]-- | 2 | <-[Prev]-- | 3 | ...
|
|
+-------+ +-------+ +-------+
|
|
|
|
|
[Childs]
|
|
|
|
|
v
|
|
...
|
|
```
|
|
|
|
If a node is accessed it is linked as the first node in the childs order, to make name resolving process faster.
|
|
|
|
#### `VFS_MAX_NAME_LENGTH` - macro
|
|
The maximum length of a nodes name.
|
|
Bigger names will be cut of at the end.
|
|
|
|
#### `fs_type_E` - enum
|
|
This enum specifies all supported filesystems:
|
|
- **RAMFS** - A filesystem, that is bound very tight to the vfs and is completely in the RAM.
|
|
|
|
#### `vfs_node_type_E` - enum
|
|
This enum specifies all types a node can have:
|
|
- **Directory** - A directory can contain other nodes
|
|
- **File** - A file can hold data
|
|
- **Mount Point** - A mount point is like a directory, but in the vfs backend this resolves to the root of a filesystem
|
|
- **Block Device** - Neither used nor implemented yet
|
|
|
|
#### `fs_T` - struct
|
|
This struct specifies a filesystem instance.
|
|
|
|
| Name | Type | Description |
|
|
|-----------|-------------|-------------------------------------------------------------|
|
|
| type | fs_type_E | The type of the filesystem |
|
|
| root_node | vfs_node_T* | A pointer to the vfs node of the filesystems root directory |
|
|
|
|
#### `vfs_node_cache_T` - struct
|
|
The current node caching system is just a small placeholder that will be reworked soon.
|
|
|
|
| Name | Type | Description |
|
|
|-------------|-------------|-----------------------------------------------------|
|
|
| buffer | void* | The actual buffer, where data is cached |
|
|
| buffer_size | uint64_t | The size of _buffer_ |
|
|
| reclaimable | bool | Not used atm, but could be important after refactor |
|
|
| node | vfs_node_T* | The node, that the cache belongs to |
|
|
|
|
|
|
#### `vfs_node_T` - struct
|
|
|
|
| Name | Type | Description |
|
|
|------------|------------------|------------------------------------------------|
|
|
| name | char[] | The name of the node |
|
|
| type | vfs_node_type_E | The type of the node |
|
|
| cache | vfs_node_cache_T | The nodes cache segment |
|
|
| size | uint64_t | The nodes size |
|
|
| specific | void* | General purpose pointer (details below) |
|
|
| filesystem | fs_T* | The filesystem this node actually lies in |
|
|
| prev | vfs_node_T* | The previous node |
|
|
| next | vfs_node_T* | The next node |
|
|
| parent | vfs_node_T* | The parent node (has to be dir or mount point) |
|
|
| childs | vfs_node_T* | The first child node |
|
|
|
|
##### specific
|
|
The usage of this value is specific to th nodes type:
|
|
- **Directories:** NULL
|
|
- **Files:** NULL
|
|
- **Mount points:** a pointer to the mounted filesystem.
|
|
- **Block devices:** NULL
|
|
|
|
#### `g_root_fs` - global variable
|
|
The systems root filesystem.
|
|
Every node resolve will start at this filesystem.
|
|
|
|
#### `vfs_node_cache_create(node, size)` - function (vfs_node_cache_T*)
|
|
Allocates a **_size_** bytes big cache segment for **_node_**.
|
|
|
|
#### `vfs_node_cache_destruct(node_cache)` - function (void)
|
|
Frees **_node_cache_** and its buffer.
|
|
|
|
#### `vfs_node_create(parent, name, type, specific)` - function (vfs_node_T*)
|
|
Allocates a node with the given parameters.
|
|
The nodes _fs_ value is inherited from **_parent_**,
|
|
or from **_parent_**'s specific value if **_parent_** is a mount point.
|
|
|
|
#### `vfs_node_destruct(node)` - function (void)
|
|
Recursively destructs **_node_** and all it's children.
|
|
|
|
#### `vfs_node_dump_info(node, indent)` - function (void)
|
|
Prints the complete directory structure starting at **_node_**.
|
|
**_indent_** is used for the recursive calls and should be set to 0.
|
|
|
|
#### `vfs_node_resolve_child(node, child_name)` - function (vfs_node_T*)
|
|
Searches **_node_** for a child named **_child_name_**.
|
|
Returns the first matching child or NULL if no matching child was found.
|
|
|
|
#### `vfs_file_create(filesystem, path)` - function (vfs_node_T*)
|
|
Creates a file at **_path_** in **_filesystem_** and returns a pointer to it.
|
|
The directory in **_path_** needs to exist and the filename needs to not exist.
|
|
|
|
#### `vfs_file_delete(file)` - function (void)
|
|
Deletes **_file_**.
|
|
|
|
#### `vfs_file_write(file, position, size, buffer_in)` - function (void)
|
|
Writes **_size_** bytes from **_buffer_in_** at **_position_** into **_file_**.
|
|
|
|
**Warning:** the current ramfs implementation will ignore **_position_**!
|
|
|
|
#### `vfs_file_read(file, position, size, buffer_out)` - function (void)
|
|
Reads **_size_** bytes from **_file_** at **_position_** into **_buffer_out_**.
|
|
|
|
**Warning:** the current ramfs implementation will ignore **_position_**!
|
|
|
|
#### `vfs_directory_create(filesystem, path)` - function (vfs_node_T*)
|
|
Creates a directory at **_path_** in **_filesystem_** and returns a pointer to it.
|
|
The directory in **_path_** needs to exist and the name of the new directory (after the last `/`) needs to not exist.
|
|
|
|
#### `vfs_directory_delete(directory)` - function (void) [not implemented yet]
|
|
Deletes a directory.
|
|
|
|
#### `vfs_init(boot_info)` - function (void)
|
|
Initializes the VFS.
|
|
In future this will also unpack the initial ramdisk into the _temp_ directory.
|
|
|
|
#### `vfs_resolve_path(filesystem, path)` - function (vfs_node_T*)
|
|
Returns the node at **_path_** or NULL if **_path_** is invalid.
|
|
|
|
#### `vfs_unpack_archive_ustar(filesystem, archive)` - function (void)
|
|
This will unpack a USTAR-archive (**_archive_**) at **_filesystem_**'s root.
|
|
|
|
### graphics/color.h
|
|
|
|
#### `color_palette_E` - enum
|
|
Indexes for `g_color_palette`
|
|
- **Grey Dark**
|
|
- **Pink**
|
|
- **Signal Green**
|
|
- **Orange**
|
|
- **Blue**
|
|
- **Purple**
|
|
- **Green**
|
|
- **Grey Light**
|
|
- **Red**
|
|
|
|
#### `color_argb_T` - struct
|
|
| Name | Type | Description |
|
|
|-------|---------|---------------------------------|
|
|
| alpha | uint8_t | Transparency value of the color |
|
|
| red | uint8_t | Red value of the color |
|
|
| green | uint8_t | Green value of the color |
|
|
| blue | uint8_t | Blue value of the color |
|
|
|
|
#### `color_argb_blend_alpha(background, foreground)` - function (color_argb_T)
|
|
Blends **_background_** and **_foreground_** with the _alpha_ value of **_foreground_**.
|
|
|
|
#### `g_color_palette` - global variable
|
|
An array of standard colors.
|
|
This array is indexed using `color_palette_E`.
|
|
|
|
### graphics/font.h
|
|
#### `font_T` - struct
|
|
|
|
| Name | Type | Description |
|
|
|------------|----------|------------------------------------------------|
|
|
| width | uint8_t | The width of each char (in pixels) |
|
|
| height | uint8_t | The height of each char (in pixels) |
|
|
| glyph_size | uint8_t | The amount of bytes a char takes in the buffer |
|
|
| buffer | uint8_t* | The buffer, where the char bitmaps lay |
|
|
|
|
#### `g_font` - global variable
|
|
A global usable 8x8 font.
|
|
|
|
### graphics/framebuffer.h
|
|
#### `framebuffer_T` - struct
|
|
|
|
| Name | Type | Description |
|
|
|-----------------|----------|-----------------------------------------------------|
|
|
| address | void* | The address of the framebuffer |
|
|
| width | uint64_t | The pixel width of the framebuffer |
|
|
| height | uint64_t | The pixel height of the framebuffer |
|
|
| pitch | uint64_t | The number of bytes in each row |
|
|
| bits_per_pixel | uint16_t | The amount of bits a pixel consumes in the buffer |
|
|
| bytes_per_pixel | uint8_t | The amount of bytes a pixel consumes in the buffer |
|
|
| shift_red | uint8_t | How many bits the red value is shifted in a pixel |
|
|
| shift_green | uint8_t | How many bits the green value is shifted in a pixel |
|
|
| shift_blue | uint8_t | How many bits the blue value is shifted in a pixel |
|
|
|
|
|
|
### graphics/renderer.h
|
|
#### `graphics_buffer_layer_E` - enum
|
|
- **Standard** - The layer, where almost everything should be on
|
|
- **Overlay** - This layer should be used for stuff like a mouse cursor, that should always be visible
|
|
|
|
#### `graphics_buffer_T` - struct
|
|
|
|
| Name | Type | Description |
|
|
|---------|-------------------------|------------------------------------------------------------------------------|
|
|
| buffer | color_argb_T* | The buffer, where all the pixels are stored |
|
|
| width | uint32_t | The width of the buffer |
|
|
| height | uint32_t | The height of the buffer |
|
|
| pos_x | uint32_t | The buffers x offset (from the top-left corner) in the renderers main buffer |
|
|
| pos_y | uint32_t | The buffers y offset (from the top-left corner) in the renderers main buffer |
|
|
| blocked | bool | Thread safety block variable |
|
|
| render | bool | Controls, if the buffer will be rendered or not |
|
|
| layer | graphics_buffer_layer_E | The layer, on which the buffer will be rendered |
|
|
| prev | graphics_buffer_T* | The previous buffer in the rendering queue |
|
|
| next | graphics_buffer_T* | The next buffer in the rendering queue |
|
|
|
|
#### `graphics_renderer_T` - struct
|
|
|
|
| Name | Type | Description |
|
|
|------------------------|---------------------|------------------------------------------------------------------------------------------|
|
|
| framebuffer | framebuffer_T | The systems framebuffer (requested from bootloader) |
|
|
| back_buffer | uint32_t* | The buffer, where the final image is calculated, before sending it to the framebuffer |
|
|
| buffer_size | uint64_t | The size of `back_buffer` (in bytes) |
|
|
| graphics_buffer_layers | graphics_buffer_T** | List of pointers to the first graphics_buffer of every layer |
|
|
| font | font_T | The font, all graphics buffers use to draw chars (could be moved to `graphics_buffer_T`) |
|
|
| initialized | bool | Indicates whether the renderer is initialized or not |
|
|
| blocked | bool | Blocking variable that is used for thread safety in `graphics_renderer_update` |
|
|
|
|
|
|
#### `graphics_buffer_request(pos_x, pos_y, width, height, layer)` - function (graphics_buffer_T*)
|
|
Allocates a graphics buffer and pushes it on top of the rendering queue of **_layer_**.
|
|
|
|
#### `graphics_buffer_show(graphics_buffer)` - function (void)
|
|
Enables rendering for this buffer.
|
|
Every created buffer will be rendered by default.
|
|
|
|
#### `graphics_buffer_hide(graphics_buffer)` - function (void)
|
|
Disables rendering for this buffer.
|
|
|
|
#### `graphics_buffer_destruct(graphics_buffer)` - function (void)
|
|
Removes **_graphics_buffer_** from the rendering queue and frees its memory allocations.
|
|
|
|
#### `graphics_buffer_shift_up(graphics_buffer, shift)` - function (void)
|
|
Shifts **_graphics_buffer_**'s content **_shift_** rows up.
|
|
|
|
#### `graphics_buffer_set_pixel(graphics_buffer, x, y, color)` - function (void)
|
|
Sets a pixel with the given **_color_** at position(**_x_** | **_y_**) in **_graphics_buffer_**.
|
|
**_x_** and **_y_** are graphics buffer relative.
|
|
|
|
#### `graphics_buffer_get_pixel(graphics_buffer, x, y)` - function (color_argb_T)
|
|
Returns the color of the pixel at position(**_x_** | **_y_**) in **_graphics_buffer_**.
|
|
|
|
#### `graphics_buffer_draw_char(graphics_buffer, x, y, color, chr)` - function (void)
|
|
Draws a character (**_chr_**) at position(**_x_** | **_y_**) in **_graphics_buffer_**.
|
|
The position is the top-left corner of the char.
|
|
|
|
#### `graphics_buffer_draw_string(graphics_buffer, x, y, color, string)` - function (position_T)
|
|
Draws **_string_** at position(**_x_** | **_y_**) in **_graphics_buffer_**.
|
|
The position is the top-left corner of the string.
|
|
Returns the position after the last char of the string.
|
|
|
|
#### `graphics_renderer_init(boot_info)` - function (void)
|
|
Initializes the global graphics renderer.
|
|
Needs a pointer to `boot_info` to extract information about the framebuffer.
|
|
|
|
#### `graphics_renderer_update()` - function (void)
|
|
Updates the renderers back_buffer and swaps it into the framebuffer.
|
|
To update the back_buffer, it iterates over the rendering queue and copies every buffer to the back_buffer.
|
|
If there are overlapping graphics_buffers, it alpha-blends them.
|
|
|
|
#### `graphics_renderer_get_top_buffer(layer)` - function (graphics_buffer_T*)
|
|
Returns a pointer to the graphics_buffer, that is on top of the rendering queue of **_layer_**.
|
|
|
|
#### `graphics_renderer_get_width()` - function (uint32_t)
|
|
Returns the width of the framebuffer.
|
|
|
|
#### `graphics_renderer_get_height()` - function (uint32_t)
|
|
Returns the height of the framebuffer.
|
|
|
|
### time/pit.h
|
|
#### `PIT_CHANNEL_0_PORT` - macro
|
|
The IO port, where channel 0 of the PIT (which is capable of firing IRQs) can be configured.
|
|
|
|
#### `PIT_DIVISOR` - macro
|
|
The standard divisor nox_os loads into channel 0 of the PIT.
|
|
`32768` fires an interrupt every `~27ms`, what is perfect for preemptive multithreading.
|
|
|
|
#### `pit_set_divisor(divisor)` - function (void)
|
|
Loads **_divisor_** into channel 0 of the PIT.
|
|
If **_divisor_** is smaller than 100, it will be set to 100.
|
|
|
|
## mm
|
|
|
|
### heap.h
|
|
|
|
#### `heap_segment_T` - struct
|
|
This is the header for each heap segment.
|
|
It holds its status information and a pointer to the next and previous segments.
|
|
It lies in memory, directly before the accessible buffer of the segment.
|
|
|
|
#### `heap_T` - struct
|
|
This struct describes a heap.
|
|
The area between **_start_** and **_end_** is filled with heap segments.
|
|
|
|
#### `heap_init(heap*, base)` - function (void)
|
|
Initializes **_heap_** at **_base_** (virtual address).
|
|
It will automatically map some page frames to that address.
|
|
|
|
#### `heap_memory_allocate(heap*, size)` - function (void)
|
|
Returns a pointer to a free usable memory location, that has at least the given **_size_**.
|
|
It will return `NULL` and log an error, if the heap is corrupted.
|
|
Because this function iterates over the complete heap to find a free segment, it is slow.
|
|
|
|
#### `heap_memory_free(heap*, address)` - function (void)
|
|
Frees a with `heap_memory_allocate` created heap segment, and makes it usable again.
|
|
Does nothing, if the address doesn't point to a valid heap segment.
|
|
|
|
#### `heap_dump_segments(heap*)` - function (void)
|
|
Logs a complete list, of all heap segments.
|
|
Useful, when debugging / testing the heap.
|
|
|
|
#### `heap_destruct(heap*)` - function (void)
|
|
Invalidates all segments of a heap, frees all used page frames and unmaps them.
|
|
|
|
### memory_map.h
|
|
|
|
#### `memory_map_get_total_memory_size(boot_info*)` - function (uint64_t)
|
|
Calculates the total amount of memory available, by iterating over the memory map.
|
|
The size is stored in a static variable, so no matter how often you call this function, the size will only be calculated once.
|
|
It returns the total amount of memory in bytes.
|
|
|
|
### 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.
|
|
|
|
### page_map.h
|
|
|
|
#### `VIRTUAL_ADDRESS_MAX` - macro
|
|
The highest mappable virtual address.
|
|
4 level page maps have a maximum address space of 256TB.
|
|
|
|
#### `page_map_flag_E` - enum
|
|
- **Present** - This indicates if the entry is used or should be ignored. Automatically set when mapping a page.
|
|
- **Read & Write** - A mapped Page is always readable. This flag allows writing to that page.
|
|
- **User Super** - If set, user mode access to the page is allowed.
|
|
- **Write Through** - Enables _Write Through Caching_ for this page.
|
|
- **Cache Disabled** - If this bit is set, the page won't be cached.
|
|
- **Accessed** - Set by the CPU, when this PDE or PTE was read. Won't be reset by the CPU.
|
|
- **Dirty** - Set when the page has been modified.
|
|
- **Larger Pages** - When this bit is set in a PDE or PTE, the entry points to a 1GB or 2MB page.
|
|
- **Custom 1 - 3** - Not used in NoxOS.
|
|
- **No Execute** - When this bit is set, the CPU won't execute code that lies in that page.
|
|
|
|
#### `page_map_T` - struct [page aligned]
|
|
This struct contains 512 entries.
|
|
These entries contain an address and flags.
|
|
The addresses link like this:
|
|
- **PML4** --> **Page Directory** or _1GB Page_
|
|
- **Page Directory** --> **Page Table** or _2MB Page_
|
|
- **Page Table** --> _4KB Page_
|
|
|
|
A pointer to a `page_map_T` can be loaded into `cr3` to load this pagemap.
|
|
|
|
#### `page_map_create()` - function (page_map_T*)
|
|
Allocates a `page_map_T` and returns a pointer to it.
|
|
|
|
#### `page_map_fetch_current()` - function (page_map_T*) [ASM implementation]
|
|
This function will return the page map, that is currently loaded.
|
|
To achieve this, it just reads the `cr3` value.
|
|
|
|
#### `page_map_load(page_map*)` - function (void) [ASM implementation]
|
|
Loads the given page map.
|
|
To achieve this, it writes the `cr3` value.
|
|
|
|
#### `page_map_map_memory(page_map*, virtual_address, physical_address, flags)` - function (void)
|
|
This maps **_physical_address_** to **_virtual_address_** in **_page_map_**.
|
|
The **_flags_** will be applied to the page mapping / page table entry.
|
|
It always applies the _Present_ flag.
|
|
|
|
#### `page_map_unmap_memory(page_map*, virtual_address)` - function (void)
|
|
Removes a page mapping from the **_page_map_**.
|
|
Page map structure intern pages won't be checked if they're still needed or not.
|
|
|
|
#### `page_map_get_physical_address(page_map*, virtual_address)` - function (void*)
|
|
Returns the physical address of the page, that is mapped to **_virtual_address_**.
|
|
|
|
#### `page_map_destruct(page_map*)` - function (void)
|
|
Clears a page map and frees all page map structure intern pages.
|
|
|
|
#### `page_map_entry_set_flags(entry, uint64_t flags)` - function (void)
|
|
This will set the provided flags to a page map entry.
|
|
|
|
#### `page_map_entry_get_flag(entry, page_map_flag_E flag)` - function (bool)
|
|
Returns if the given flag is set in the page map entry, or not.
|
|
|
|
#### `page_map_entry_set_address(entry, void* address)` - function (void)
|
|
This will set the provided address to a page map entry.
|
|
|
|
#### `page_map_entry_get_address(entry)` - function (void*)
|
|
This will read and return the address set in the page map entry.
|
|
|
|
#### `paging_init()` - function (void)
|
|
Initializes paging.
|
|
This reads the current page map set by the kernel and writes it to `g_kernel_page_map`.
|
|
|
|
#### `g_kernel_page_map` - global variable
|
|
The kernels page map. This page map is provided by the bootloader and read from `cr3` at `paging_init`.
|
|
|
|
|
|
### stack.h
|
|
#### `stack_dump_call_info(rip, symbol)` - function (void)
|
|
Logs information about a call.
|
|
Give this function the **_rip_** of the call and the related **_symbol_**, to make it happy.
|
|
|
|
#### `stack_trace_call_stack(rbp)` - function (void)
|
|
Analyses the stack and recursively dumps information about all calls until it hits a call to `_start`.
|
|
|
|
## platform
|
|
|
|
### cpu.h
|
|
This header contains stuff directly related to the CPU.
|
|
|
|
OSDev Wiki: [x86 CPU Registers](https://wiki.osdev.org/CPU_Registers_x86)
|
|
|
|
#### `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](https://wiki.osdev.org/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](https://wiki.osdev.org/GDT)
|
|
|
|
#### `gdt_selector_E` - enum
|
|
- **Null**
|
|
- **Kernel Code** - Readable
|
|
- **Kernel Data** - Readable + Writable
|
|
|
|
NoxOS uses the GDT loaded by limine, because in 64 bit mode a GDT is only needed for backwards compatability.
|
|
|
|
### 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.
|
|
|
|
|
|
## proc
|
|
|
|
### thread.h
|
|
|
|
#### `thread_T` - struct
|
|
| Name | Type | Description |
|
|
|------------|-------------|--------------------------------------------------------------------------------------------------|
|
|
| state | cpu_state_T | The last saved state of the thread. ( -> _context switching_) |
|
|
| cpu_time | uint64_t | The amount of cpu time the thread had. (currently the amount of context switches the thread had) |
|
|
| stack | void* | The bottom of the threads stack |
|
|
| stack_size | uint32_t | The size of the threads stack (in bytes) |
|
|
| prev | thread_T* | The previous thread in the scheduling queue (**should only be accessed by the scheduler!**) |
|
|
| next | thread_T* | The next thread in the scheduling queue (**should only be accessed by the scheduler!**) |
|
|
|
|
|
|
#### `thread_spawn(function)` - function (thread_T*)
|
|
Allocates a `thread_T` and registers it in the scheduler.
|
|
The thread starts execution at **_function_**.
|
|
The for the thread allocated stack has a size of 16 KB (4 Pages).
|
|
The thread still needs to be started with a `thread_start` call.
|
|
Returns a pointer to the created thread.
|
|
|
|
#### `thread_spawn_from_state(state)` - function (thread_T*)
|
|
Allocates a `thread_T` and registers it in the scheduler.
|
|
The threads' _cpu_state_ is copied from **_state_**.
|
|
This won't allocate a stack for the stack.
|
|
The thread still needs to be started with a `thread_start` call.
|
|
Returns a pointer to the created thread.
|
|
This function should be avoided.
|
|
|
|
#### `thread_start(thread)` - function (void)
|
|
Starts/unpauses **_thread_**.
|
|
|
|
#### `thread_pause(thread)` - function (void)
|
|
Pauses **_thread_**.
|
|
|
|
#### `thread_kill(thread)` - function (void)
|
|
Kills **_thread_**.
|
|
The threads stack and `thread_T` structure will be freed.
|
|
|
|
### scheduler.h
|
|
|
|
#### `scheduler_T` - struct
|
|
| Name | Type | Description |
|
|
|----------------|-----------|--------------------------------------------------------------------|
|
|
| num_threads | uint32_t | Total amount of currently spawned threads |
|
|
| running_thread | thread_T* | A pointer to the currently running thread. |
|
|
| blocked | bool | Set to true, while switching the context. Thread safety mechanism. |
|
|
| initialized | bool | Set to true, if the scheduler is initialized and started. |
|
|
|
|
#### `scheduler_init()` - function (void)
|
|
Initializes the scheduler and performs a `scheduler_start` kernel syscall.
|
|
After this function, the whole kernel is in scheduling mode.
|
|
|
|
#### `scheduler_start(state)` - function (cpu_state_T*)
|
|
Creates and starts a thread from **_state_**.
|
|
It returns the result of a context switch, I forgot, why I did it like that.
|
|
This is basically the backend for the `scheduler_start` kernel syscall.
|
|
|
|
#### `scheduler_is_initialized()` - function (bool)
|
|
Returns if the scheduler is initialized (and running) or not.
|
|
|
|
#### `scheduler_register_thread(thread)` - function (thread_T*)
|
|
Registers **_thread_** in the scheduler.
|
|
|
|
#### `scheduler_pause_thread(thread)` - function (void)
|
|
Pauses **_thread_**, by removing it from the scheduling queue.
|
|
|
|
**Potential Bug:** if **_thread_** was the currently running thread,
|
|
this could cause issues, because it's _prev_ and _next_ values are nulled.
|
|
|
|
#### `scheduler_start_thread(thread)` - function (void)
|
|
Starts **_thread_**, by linking it into the scheduling queue.
|
|
|
|
#### `scheduler_kill_thread(thread)` - function (void)
|
|
Pauses and unregisters **_thread_**.
|
|
|
|
#### `scheduler_get_current_thread()` - function (thread_T*)
|
|
Returns a pointer to the currently running thread.
|
|
|
|
#### `scheduler_switch_context(state)` - function (cpu_state_T*)
|
|
Saves **_state_** in the running threads _state_ value and increments their _cpu_time_ value.
|
|
Then it sets the next thread as the running thread and returns its _state_.
|
|
This needs to be called from an interrupt handler, for the returned state to be loaded.
|
|
|
|
## utils
|
|
|
|
### bitmap.h
|
|
Provides functionalities to create, destruct and work with bitmaps.
|
|
|
|
#### `bitmap_T` - struct
|
|
|
|
| Name | Type | Description |
|
|
|-----------|----------|---------------------------------------|
|
|
| size | uint32_t | The size of _buffer_ (in bytes) |
|
|
| size_bits | uint32_t | The amount of storable bits |
|
|
| buffer | uint8_t* | The buffer, where the bits are stored |
|
|
|
|
#### `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)
|
|
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)
|
|
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.
|
|
|
|
#### `io_wait()` - function (void)
|
|
Waits one IO cycle.
|
|
Should be used to give the devices enough time to respond.
|
|
|
|
### logger.h
|
|
Functionalities to write logs to QEMU's serial port.
|
|
|
|
#### `log_level_E` - enum
|
|
- **None** - Logs just the message without a prefix
|
|
- **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.
|
|
Format strings are supported.
|
|
|
|
### 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.
|
|
|
|
#### `position_T` - struct
|
|
|
|
| Name | Description |
|
|
|------|------------------------------|
|
|
| x | X coordinate of the position |
|
|
| y | Y coordinate of the position |
|
|
|
|
|
|
#### `pow(base, exponent)` - function (uint64_t)
|
|
Returns the power of `base ^ exponent`.
|
|
|
|
#### `abs(number)` - function (uint64_t)
|
|
Returns the absolute value of **_number_**.
|
|
|
|
#### `octal_string_to_int(string, size)` - function (uint64_t)
|
|
Converts a base-8 **_string_** with length **_size_** into an integer and returns it.
|
|
|
|
### 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_.
|
|
|
|
#### `memory_allocate(size)` - function (void*)
|
|
Returns the address to a buffer, that is at least **_size_** bytes big.
|
|
On linux this function is called _malloc_.
|
|
|
|
#### `memory_free(address)` - function (void)
|
|
Free the buffer at address and make it reallocatable , this buffer needs to be a buffer, that was created with `memory_allocate`.
|
|
On linux this function is called _free_.
|
|
|
|
#### `memory_allocator_init(base)` - function (void)
|
|
This initializes the heap, where `memory_allocate` allocates memory.
|
|
|
|
#### `memory_hexdump(address, num)` - function (void)
|
|
Logs **_num_** bytes from **_address_** as 8 byte rows.
|
|
The data is represented in hexadecimal and ascii.
|
|
|
|
### 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 signed 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.
|
|
|
|
#### `string_find_next(string, chr)` - function (uint32_t)
|
|
Returns the index of the next character that matches **_chr_** in **_string_**.
|
|
|
|
#### `string_find_last(string, chr)` - function (uint32_t)
|
|
Returns the index of the last character that matches **_chr_** in **_string_**.
|
|
|
|
#### `variadic_format_size(string, args)` - function (uint64_t)
|
|
Returns how long a format string with the given pattern (**_string_**) and **_args_** would be.
|
|
Useful to create a big enough buffer before formatting a string.
|
|
|
|
#### `format_size(string, ...)` - function (uint64_t)
|
|
This calls `variadic_format_size`, but instead of giving it a `va_list` you can give this function the actual arguments.
|
|
|
|
#### `variadic_format(output, string, args)` - function (void)
|
|
Formats **_string_** with **_args_** and writes the product to **_output_**.
|
|
The rules for format strings are specified on top of this document in the _General concepts_ block.
|
|
|
|
#### `format(output, string, ...)` - function (void)
|
|
This calls `variadic_format`, but instead of giving it a `va_list` you can give this function the actual arguments.
|
|
|
|
#### `string_unsigned_dec_to_alpha(string, value)` - function (void)
|
|
Converts the unsigned integer in **_value_** to an alphanumeric string.
|
|
The representation is decimal.
|
|
This string will be written into **_string_**.
|
|
|
|
#### `string_dec_to_alpha(string, value)` - function (void)
|
|
Converts the signed integer in **_value_** to an alphanumeric string.
|
|
If it is negative it will be prefixed with a hyphen.
|
|
The representation is decimal.
|
|
This string will be written into **_string_**.
|
|
|
|
#### `string_hex_8bit_to_alpha(string, value)` - function (void)
|
|
Converts the byte in **_value_** to an alphanumeric string.
|
|
The representation is hexadecimal.
|
|
This string will be written into **_string_**.
|
|
|
|
#### `string_hex_16bit_to_alpha(string, value)` - function (void)
|
|
Converts the word(16-bits) in **_value_** to an alphanumeric string.
|
|
The representation is hexadecimal.
|
|
This string will be written into **_string_**.
|
|
|
|
#### `string_hex_32bit_to_alpha(string, value)` - function (void)
|
|
Converts the dword(32-bits) in **_value_** to an alphanumeric string.
|
|
The representation is hexadecimal.
|
|
This string will be written into **_string_**.
|
|
|
|
#### `string_hex_64bit_to_alpha(string, value)` - function (void)
|
|
Converts the qword(64-bits) in **_value_** to an alphanumeric string.
|
|
The representation is hexadecimal.
|
|
This string will be written into **_string_**.
|
|
|
|
#### `string_bin_to_alpha(string, num_bits, value)` - function (void)
|
|
Converts the data in **_value_** to an alphanumeric string.
|
|
The representation is binary.
|
|
**_num_bits_** specifies how many bits, starting at the least significant bit, will be converted.
|
|
This string will be written into **_string_**.
|
|
|
|
#### `string_bool_to_alpha(string, value`) - function (void)
|
|
Converts the boolean in **_value_** to an alphanumeric string.
|
|
The representation is `true` or `false`.
|
|
This string will be written into **_string_**.
|
|
|
|
#### `string_is_char_text(chr)` - function (bool)
|
|
Returns whether the char (**_chr_**) contains text(a-z, A-Z, 0-9, special chars) or not.
|
|
|
|
#### `string_is_char_number(chr)` - function (bool)
|
|
Returns whether the char (**_chr_**) is a number(0-9) or not.
|
|
|
|
#### `string_is_char_alpha(chr)` - function (bool)
|
|
Returns whether the char (**_chr_**) is alphanumeric(a-z, A-Z, 0-9) or not.
|
|
|
|
#### `string_is_char_uppercase(chr)` - function (bool)
|
|
Returns whether the char (**_chr_**) is uppercase(A-Z) or not.
|
|
|
|
#### `string_is_char_lowercase(chr)` - function (bool)
|
|
Returns whether the char (**_chr_**) is lowercase(a-z) or not.
|
|
|
|
### symbol.h
|
|
#### `symbol_type_E` - enum
|
|
- **Function**
|
|
- **Variable**
|
|
- **Unknown**
|
|
|
|
#### `symbol_T` - struct
|
|
|
|
| Name | Type | Description |
|
|
|---------|---------------|-------------------------------------------------------------------------------------|
|
|
| name | string_t | The name of the symbol (e.g. the name of the kernels entry symbol would be `_start` |
|
|
| type | symbol_type_E | The symbols type (elf types like `File` are of type `Unknown`) |
|
|
| address | uint64_t | The symbols address |
|
|
|
|
#### `symbol_resolve_from_name(symbols, num_symbols, name);` - function (symbol_T*)
|
|
This searches **_symbols_** for a symbol with a matching **_name_**.
|
|
|
|
#### `symbol_resolve_function_from_rip(symbols, num_symbols, rip);` - function (symbol_T*)
|
|
Give it a list of **_symbols_** and an instruction pointer (**_rip_**) and it will return the function, where **_rip_** lays in. |