ported data from nerdcult.net wiki
This commit is contained in:
parent
95f5b9156e
commit
a6f4c7457d
|
@ -0,0 +1,48 @@
|
|||
# Build Instructions
|
||||
|
||||
**DISCLAIMER:** To build this project you need a linux system (WSL could work for windows users, but I haven't tested it)
|
||||
|
||||
First you need to clone the repository:
|
||||
|
||||
`git clone https://git.nerdcult.net/noxos/kernel`
|
||||
|
||||
then there are a few tools required, that need to be installed:
|
||||
* **gcc** - compiler
|
||||
* **ld** - linker
|
||||
* **nasm** - assembler
|
||||
* **cmake** - build system
|
||||
* **xorriso** - ISO creation tools
|
||||
* **qemu** - emulator
|
||||
* **ovmf** - UEFI firmware
|
||||
|
||||
you can check if you have all tools installed, with `./build.sh check`.
|
||||
|
||||
There is a shell script to setup the workspace and compile.
|
||||
Just run it using the following commands:
|
||||
```bash
|
||||
cd noxos
|
||||
./build.sh
|
||||
```
|
||||
If the Bootloader ([limine](https://github.com/limine-bootloader/limine)) isn't downloaded yet, the script will download it.
|
||||
|
||||
The final ISO file will be written to the *build* directory.
|
||||
|
||||
To launch the ISO, run the `run.sh` script.
|
||||
|
||||
# BIOS Emulation
|
||||
To emulate a BIOS system, you can run `./run.sh bios`.
|
||||
|
||||
# Debugging
|
||||
## Logs
|
||||
When running through the script, qemu is configured to write the kernels logs to *STDOUT* and a file called *noxos.log*.
|
||||
|
||||
## GDB
|
||||
You can connect GDB to qemu.
|
||||
To achieve this, run `./run.sh debug`.
|
||||
QEMU will wait until you connect GDB to it as a 'remote' target on `localhost:1234`.
|
||||
```bash
|
||||
gdb build/cmake/kernel/kernel
|
||||
target remote localhost:1234
|
||||
c
|
||||
```
|
||||
(note, that the last to commands have to be 'executed' in gdb not in your shell)
|
|
@ -0,0 +1,66 @@
|
|||
# Code Style
|
||||
**Read this before contributing**
|
||||
|
||||
The following code style should be applied to the whole noxos codebase.
|
||||
Pull Requests that don't follow this code style will be rejected.
|
||||
|
||||
# Naming conventions
|
||||
- **structs** are suffixed with **_T**
|
||||
- **typedefs** are suffixed with **_t**
|
||||
- **enums** are suffixed with **_E**
|
||||
- **global** variables are prefixed with **g_**
|
||||
|
||||
Everything is **snake_case**.
|
||||
|
||||
# Code readability
|
||||
To make the code as readable and self explaining as possible, there are a few patterns that should be used.
|
||||
|
||||
## Avoid abbreviations
|
||||
Give your variables, functions, etc. meaningfully names.
|
||||
The times of 80-char wide screens are over, feel free to use that space :D
|
||||
|
||||
Example: `sym_at_idx` -> `get_symbol_at_index`
|
||||
|
||||
But you're not forced to (anything) write out everything.
|
||||
For example the **Interrupt Descriptor Table** is simply referred to as **idt** (this abbreviation is btw standard).
|
||||
|
||||
## Avoid indentation nesting
|
||||
In a perfect codebase, the maximum indention level would be 3.
|
||||
The goal of NoxOS is not to be a perfect codebase, but please avoid huge indention nesting.
|
||||
To achieve this, you can break parts into extra functions and/or use the early return pattern.
|
||||
|
||||
Example (definitely written 100% sober):
|
||||
```c
|
||||
bool likes_pigs (void* a) {
|
||||
if (a != NULL) {
|
||||
if (a == 0xACAB) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
```
|
||||
->
|
||||
```c
|
||||
bool likes_pigs (void* a) {
|
||||
if (a == NULL) { return true; }
|
||||
if (a != 0xACAB) { return true; }
|
||||
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
## align declarations
|
||||
|
||||
Please align declarations, definitions, etc like in the example:
|
||||
```c
|
||||
char am_i_a_variable = '?';
|
||||
uint64_t number = 0;
|
||||
bool i_waste_bits = true;
|
||||
```
|
||||
|
||||
## namespaces
|
||||
Unlike C++, C has no namespaces.
|
||||
To achieve the goal of namespaces, please prefix your functions, structs, etc. with the "namespace" they are in.
|
||||
|
||||
Example: `out_byte` -> `io_out_byte`
|
|
@ -0,0 +1,4 @@
|
|||
# Codebase
|
||||
|
||||
Every header in the codebase has its own page.
|
||||
The structure is identically to the codebase directory structure.
|
|
@ -0,0 +1,3 @@
|
|||
# boot
|
||||
|
||||
boot process control and bootloader communication
|
|
@ -0,0 +1,13 @@
|
|||
# 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_ |
|
|
@ -0,0 +1,4 @@
|
|||
# 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).
|
|
@ -0,0 +1,3 @@
|
|||
# drivers
|
||||
|
||||
everything from the graphics driver, to the FS drivers
|
|
@ -0,0 +1,5 @@
|
|||
# acpi
|
||||
|
||||
This directory holds everything, that is needed to talk to the ACPI (_Advanced Configuration and Power Interface_).
|
||||
|
||||
OSDev Wiki: [ACPI](https://wiki.osdev.org/ACPI)
|
|
@ -0,0 +1,5 @@
|
|||
# acpi.h
|
||||
|
||||
# `acpi_init(boot_info)` - function (void)
|
||||
Initializes the ACPI implementation.
|
||||
This function needs to be called once during the kernel initialization.
|
|
@ -0,0 +1,33 @@
|
|||
# rsdp.h
|
||||
|
||||
The infrastructure to parse the _Root System Description Pointer_ Table.
|
||||
|
||||
OSDev Wiki: [RSDP](https://wiki.osdev.org/RSDP)
|
||||
|
||||
# `rsdp_descriptor_v1_T` - struct [packed]
|
||||
The RSDP Table used in ACPI v1.0
|
||||
|
||||
| Name | Type | Description |
|
||||
|--------------|----------|-----------------------------------------------------------|
|
||||
| signature | char[8] | Needs to be `"RSD PTR "` (with the withespace at the end) |
|
||||
| checksum | uint8_t | Used to validate the table |
|
||||
| oem_id | char[6] | This string identifies the OEM |
|
||||
| revision | uint8_t | Tells whether the RSDP is version 1 or 2+ |
|
||||
| rsdt_address | uint32_t | The Physical Address of the RSDT |
|
||||
|
||||
# `rsdp_descriptor_v2_T` - struct [packed]
|
||||
The RSDP Table used in ACPI v2.0 or higher
|
||||
|
||||
| Name | Type | Description |
|
||||
|-------------------|-------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
|
||||
| descriptor_v1 | [rsdp_descriptor_v1_T](https://nerdcult.net/projects/noxos/docs/codebase/drivers/acpi/rsdp.h/#rsdp_descriptor_v1_t---struct-packed) | A table in the format of the ACPI 1.0 specification |
|
||||
| length | uint32_t | The size of the whole table |
|
||||
| xsdt_address | uint64_t | The Address of the XSDT (when available this should be used instead of the RSDT) |
|
||||
| checksum_extended | uint8_t | Used to calculate the checksum of the whole table |
|
||||
| reserved | uint8_t[3] | Can be ignored |
|
||||
|
||||
# `rsdp_descriptor_v1_verify(descriptor)` - function (bool)
|
||||
Verifies the integrity of **_descriptor_**.
|
||||
|
||||
# `rsdp_descriptor_v2_verify(descriptor)` - function (bool)
|
||||
Verifies the integrity of **_descriptor_**.
|
|
@ -0,0 +1,3 @@
|
|||
# elf
|
||||
|
||||
ELF executable parser.
|
|
@ -0,0 +1,32 @@
|
|||
# elf.h
|
||||
|
||||
The ELF-parsers' heart.
|
||||
|
||||
#### `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_**.
|
|
@ -0,0 +1,53 @@
|
|||
# header.h
|
||||
|
||||
Definitions needed to parse the ELF Header.
|
||||
|
||||
# `elf_target_architecture_E` - enum
|
||||
Field in elf_header_T: **identity[4]**
|
||||
|
||||
# `elf_endianness_E` - enum
|
||||
Field in elf_header_T: **identity[5]**
|
||||
|
||||
# `elf_sysabi_E` - enum
|
||||
Field in elf_header_T: **identity[7]**
|
||||
|
||||
# `elf_object_type_E` - enum
|
||||
Field in elf_header_T: **type**
|
||||
|
||||
# `elf_instruction_set_E` - enum
|
||||
Field in elf_header_T: **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.
|
|
@ -0,0 +1,18 @@
|
|||
# mapping.h
|
||||
|
||||
Handles the memory mappings that an ELF file can request.
|
||||
|
||||
# `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.
|
|
@ -0,0 +1,34 @@
|
|||
# section.h
|
||||
|
||||
Definitions needed to parse the elf section headers.
|
||||
|
||||
# `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.
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
# segment.h
|
||||
|
||||
Definitions needed to parse the elf program/segment headers.
|
||||
|
||||
# `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.
|
|
@ -0,0 +1,26 @@
|
|||
# symbol.h
|
||||
|
||||
Stuff needed to extract symbols from an ELFs `.symtab` section.
|
||||
|
||||
# `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) | |
|
|
@ -0,0 +1,3 @@
|
|||
# fs
|
||||
|
||||
Filesystem drivers.
|
|
@ -0,0 +1,22 @@
|
|||
# ramfs.h
|
||||
|
||||
Specific driver for RAMFS.
|
||||
|
||||
**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.
|
|
@ -0,0 +1,42 @@
|
|||
# ustar.h
|
||||
|
||||
Specific driver for USTAR.
|
||||
|
||||
**Warning:** This is a filesystem specific driver, by this it should only be accessed by the VFS.
|
||||
|
||||
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 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_ |
|
|
@ -0,0 +1,146 @@
|
|||
# vfs.h
|
||||
|
||||
**VFS** stands for _Virtual File System_ and is an abstraction layer,
|
||||
that merges all mounted filesystems into one big virtual filesystem.
|
||||
It provides a general API for dealing with files, and handles all filesystem 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] [Childs]
|
||||
| |
|
||||
v v
|
||||
. . . . . .
|
||||
```
|
||||
|
||||
If a node is accessed it is linked as the first node in the childs order, to make the 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 stores data 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.
|
||||
The initialization process includes, that the kernel unpacks the initial ramdisk to `/initrd/`
|
||||
|
||||
# `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.
|
|
@ -0,0 +1,4 @@
|
|||
# graphics
|
||||
|
||||
The graphics renderer is just for the development time.
|
||||
As soon as the kernel supports modules, the renderer will be a module, or even an userspace program.
|
|
@ -0,0 +1,30 @@
|
|||
# color.h
|
||||
|
||||
Provides basic color definitions and operations.
|
||||
|
||||
# `color_palette_E` - enum
|
||||
Indexes for g_color_palette. The color palette was designed by [gogh](https://gogh-co.github.io/Gogh/).
|
||||
- **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.
|
|
@ -0,0 +1,15 @@
|
|||
# font.h
|
||||
|
||||
Basic bitmap font definitions.
|
||||
|
||||
# `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 globally usable 8x8 font.
|
|
@ -0,0 +1,18 @@
|
|||
# framebuffer.h
|
||||
|
||||
Framebuffer definitions.
|
||||
|
||||
#### `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 |
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
# renderer.h
|
||||
|
||||
The renderer is maybe a bit over-engineered and slow.
|
||||
|
||||
The renderer has a stack of buffers, which act like canvases.
|
||||
You can create, move, hide and show buffers.
|
||||
|
||||
#### `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 | g_color_palette* | 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_layer_E* | 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_T 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.
|
|
@ -0,0 +1,79 @@
|
|||
# pci.h
|
||||
|
||||
PCI bus stuff.
|
||||
|
||||
# Class and subclasses enums
|
||||
All these enums are not documented in here, because they are basically just the definitions matching the PCI device main and sub classes.
|
||||
A [list of these (sub)classes](https://wiki.osdev.org/PCI#Class_Codes) can be found in the osdev wiki.
|
||||
|
||||
# `pci_device_header_T` - struct
|
||||
| Name | Type | Description |
|
||||
|-----------------|----------|------------------------------------------------------------------------------------------------------------------------------|
|
||||
| vendor_id | uint16_t | The Device manufacturers ID number |
|
||||
| device_id | uint16_t | The devices ID number |
|
||||
| command_reg | uint16_t | Provides control over a device's ability to generate and respond to PCI cycles. |
|
||||
| status | uint16_t | The status register PCI bus related events |
|
||||
| revision_id | uint8_t | The devices revision ID number |
|
||||
| progif | uint8_t | Programming Interface Byte. This can specify special programming interfaces. |
|
||||
| subclass | uint8_t | The special function that the device performs. |
|
||||
| main_class | uint8_t | The general function class, which the device operates in. |
|
||||
| cache_line_size | uint8_t | Specifies the system cache line size in 32-bit units. |
|
||||
| latency_timer | uint8_t | Specifies the latency timer in units of PCI bus clocks. |
|
||||
| header_type | uint8_t | Specifies whether the device is a general device or a bridge. This affects the data representation that follows this header. |
|
||||
| bist | uint8_t | Built-In-Self-Test status and control. |
|
||||
|
||||
# `pci_header_0_T` - struct
|
||||
| Name | Type | Description |
|
||||
|----------------------------|---------------------|-------------------------------------------------------------------------------------------------|
|
||||
| header | pci_device_header_T | The devices base header |
|
||||
| bar0 | uint32_t | Base address 0 |
|
||||
| bar1 | uint32_t | Base address 1 |
|
||||
| bar2 | uint32_t | Base address 2 |
|
||||
| bar3 | uint32_t | Base address 3 |
|
||||
| bar4 | uint32_t | Base address 4 |
|
||||
| bar5 | uint32_t | Base address 5 |
|
||||
| cardbus_cis_pointer | uint32_t | Used by devices that share silicon between CardBus and PCI. |
|
||||
| subsystem_vendor_id | uint16_t | idk, but probably not that important |
|
||||
| subsystem_id | uint16_t | idk, but probably not that important |
|
||||
| expansion_rom_base_address | uint32_t | An optional max 16MB ROM BAR. |
|
||||
| capabilities | uint8_t | An offset in the devices config space that points to a linked list of implemented capabilities. |
|
||||
| reserved | uint8_t[7] | Reserved. |
|
||||
| interrupt_line | uint8_t | The devices interrupt IRQ. |
|
||||
| interrupt_pin | uint8_t | The devices interrupt pin. |
|
||||
| min_grant | uint8_t | Specifies the burst period length, in 1/4 microsecond units, that the device needs. |
|
||||
| max_latency | uint8_t | Specifies how often the device needs access to the PCI bus (in 1/4 microsecond units). |
|
||||
|
||||
# `pci_device_T` - struct
|
||||
| Name | Type | Description |
|
||||
|--------|----------------------|-------------------------|
|
||||
| header | pci_device_header_T* | The devices base header |
|
||||
| prev | pci_device_T* | The previous device. |
|
||||
| next | pci_device_T* | The next device. |
|
||||
|
||||
# `pci_manager_T` - struct
|
||||
| Name | Type | Description |
|
||||
|---------|---------------|-----------------------------------------------|
|
||||
| devices | pci_device_T* | The linked list of devices connected via PCI. |
|
||||
|
||||
# `pci_init()` - function (void)
|
||||
Initializes the global PCI manager and enumerates the PCI bus.
|
||||
This needs to be called after `acpi_init`, because it uses the _MCFG_ table.
|
||||
|
||||
# `pci_manager_add_device(header*)` - function (void)
|
||||
Adds a device to the global PCI manager.
|
||||
This should only be called by the PCI enumerator.
|
||||
|
||||
# `pci_manager_remove_device(device*)` - function (void)
|
||||
Removes a device from the global PCI manager, and frees it resources in the manager.
|
||||
|
||||
# `pci_manager_find_device(class, subclass, progif)` - function (pci_device_T*)
|
||||
Returns the first device with **_class_**, **_subclass_** and **_progif_** that is defined in the global PCI manager.
|
||||
|
||||
# `pci_manager_dump_devices()` - function (void)
|
||||
Logs a list of all registered PCI devices.
|
||||
|
||||
# `pci_get_subclass_string(class, subclass)` - function (string_t)
|
||||
Returns the Name of **_class_** + **_subclass_**.
|
||||
|
||||
# `pci_get_vendor_string(vendor_id)` - function (string_t)
|
||||
Returns the name of the vendor.
|
|
@ -0,0 +1,4 @@
|
|||
# PS/2
|
||||
|
||||
The PS/2 standard for communicating with keyboards and mice.
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# controller.h
|
||||
|
||||
Communicates with the PS/2 controller chip.
|
||||
|
||||
**Warning:** This whole code needs to be reworked!
|
||||
|
||||
# `PS2_CONTROLLER_DATA_PORT` - macro
|
||||
The data transmission IO port.
|
||||
|
||||
# `PS2_CONTROLLER_STATUS_PORT` - macro
|
||||
The Status register IO port.
|
||||
|
||||
# `PS2_CONTROLLER_COMMAND_PORT` - macro
|
||||
The command transmission IO port.
|
||||
|
||||
# `PS2_CONTROLLER_TIMEOUT` - macro
|
||||
The amount of cycles the system waits for the controller before cancelling an operation.
|
||||
|
||||
# `ps2_controller_init()` - function (void)
|
||||
Initializes the PS/2 controller and devices.
|
||||
At the moment it trusts very much stuff blindly.
|
||||
This needs to be changed.
|
||||
The osdev wiki has a list of stuff to do while initializing PS/2.
|
||||
|
||||
# `ps2_controller_command(command)` - function (uint8_t)
|
||||
Sends the PS/2 controller a command.
|
||||
|
||||
# `ps2_controller_command_with_data(command, data)` - function (uint8_t)
|
||||
Sends the PS/2 controller a command that needs additional data on the data port.
|
||||
|
||||
# `ps2_controller_wait_until_ready_for_input()` - function (bool)
|
||||
Halts until the status register says that there can be data read, or the timeout is reached.
|
||||
|
||||
# `ps2_controller_wait_until_ready_for_output()` - function (bool)
|
||||
Halts until the status register says that there can be data written, or the timeout is reached.
|
||||
|
||||
# `ps2_controller_read_data()` - function (uint8_t)
|
||||
Reads data from the PS/2 controller.
|
|
@ -0,0 +1,24 @@
|
|||
# keyboard.h
|
||||
|
||||
The driver for PS/2 keyboards.
|
||||
|
||||
|
||||
# `ps2_keyboard_command_E` - enum
|
||||
Commands that can be issued to the keyboard.
|
||||
|
||||
# `ps2_keyboard_response_E` - enum
|
||||
Responses that a keyboard can reply on a command.
|
||||
|
||||
# `ps2_keyboard_command(command, data)` - function (uint8_t)
|
||||
Sends a command to the keyboard.
|
||||
|
||||
# `ps2_keyboard_init()` - function (void)
|
||||
Initializes the keyboard driver.
|
||||
This should only be called by the PS/2 controller init function.
|
||||
|
||||
# `ps2_keyboard_read()` - function (void)
|
||||
Reads a key from the keyboard and writes it to the tty.
|
||||
This should be called when IRQ1 is fired.
|
||||
|
||||
# `ps2_keyboard_command_to_string(command)` - function (string_t)
|
||||
Returns a matching string for **_command_** in `ps2_keyboard_command_E`.
|
|
@ -0,0 +1,4 @@
|
|||
# scancodes.h
|
||||
|
||||
This holds definitions on which key is mapped to which scancode.
|
||||
Currently only scancode set 1 is supported.
|
|
@ -0,0 +1,5 @@
|
|||
# time
|
||||
|
||||
Drivers for time related hardware.
|
||||
|
||||
Tick. Tack. Tick. Tack.
|
|
@ -0,0 +1,14 @@
|
|||
# pit.h
|
||||
|
||||
Communicates with the _Programmable Interval Timer_.
|
||||
|
||||
#### `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, that noxos 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.
|
|
@ -0,0 +1,45 @@
|
|||
# tty.h
|
||||
|
||||
The TTY is a virtual device, that acts as a text IO layer.
|
||||
It prints keyboard input and process output to the screen.
|
||||
The keyboard input can be directed to a processes stdin and the processes stdout can be printed to the screen.
|
||||
|
||||
Schematic:
|
||||
```
|
||||
+-------------------+
|
||||
| Graphics Renderer |
|
||||
+-------------------+
|
||||
^ ^
|
||||
| | +----------+ +-----------------+
|
||||
| | | TTY | | Process (shell) |
|
||||
| | | | | |
|
||||
| |--|-[Input]--|-<----|-[stdout] |
|
||||
| | | | |
|
||||
-[Keyboard]----->-|-[Output]-|->----| [stdin] |
|
||||
+----------+ +-----------------+
|
||||
|
||||
```
|
||||
|
||||
# `tty_T` - struct
|
||||
| Name | Type | Description |
|
||||
|-----------------|--------------------|---------------------------------------------------------------------------------------------------|
|
||||
| graphics_buffer | graphics_buffer_T* | The graphics buffer where all output will be rendered to. |
|
||||
| output | pipe_T* | Points to the linked processes stdin pipe. |
|
||||
| input | pipe_T | This pipes content will be rendered to the screen. The linked processes stdout should point here. |
|
||||
| cursor | position_T | The cursors position. |
|
||||
| color | color_argb_T | The current drawing color. |
|
||||
|
||||
# `tty_init()` - function (void)
|
||||
Initializes `g_tty`.
|
||||
|
||||
# `tty_update()` - function (void)
|
||||
Renders the text from the ttys _input pipe_ onto the screen.
|
||||
This will be automatically called when writing into the ttys _input pipe_.
|
||||
|
||||
# `tty_write(string)` - function (uint32_t)
|
||||
Renders the text from **_string_** onto the screen.
|
||||
This also writes **_string_** into the ttys _output pipe_.
|
||||
|
||||
# `g_tty` - global variable
|
||||
This is the systems TTY.
|
||||
Currently, there is no support planned for multiple ttys.
|
|
@ -0,0 +1,3 @@
|
|||
# mm
|
||||
|
||||
Memory management.
|
|
@ -0,0 +1,44 @@
|
|||
# heap.h
|
||||
|
||||
Dynamic memory allocator.
|
||||
|
||||
# `heap_segment_T` - struct
|
||||
This header lies in memory, directly before the accessible buffer of the related segment.
|
||||
|
||||
| Name | Type | Description |
|
||||
|-------|-----------------|------------------------------------------------------------------------------------------|
|
||||
| magic | uint32_t | An out of bounds memory write would override this, what would indicate a heap corruption |
|
||||
| size | uint64_t | The size of the segment |
|
||||
| free | bool | If this is set, the segment is reclaimable |
|
||||
| next | heap_segment_T* | The next segment in the heap |
|
||||
| prev | heap_segment_T* | The previous segment in the heap |
|
||||
|
||||
|
||||
# `heap_T` - struct
|
||||
|
||||
| Name | Type | Description |
|
||||
|--------------|-----------------|-------------------------------------------------------------|
|
||||
| start | void* | The start of the heaps segment pool |
|
||||
| end | void* | The current end of the heaps segment pool (growing upwards) |
|
||||
| last_segment | heap_segment_T* | The current last segment in the heaps segment pool |
|
||||
|
||||
# `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 entire heap to find a free segment, it is kinda 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.
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# memory_map.h
|
||||
|
||||
Functions to parse the memory map provided by the bootloader.
|
||||
|
||||
# `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.
|
||||
The total amount of memory is returned in bytes.
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
# page_frame.h
|
||||
|
||||
Physical memory management.
|
||||
|
||||
# `PFRAME_SIZE` - macro
|
||||
The size of one page (4KB).
|
||||
|
||||
# `page_frame_manager_T` - struct
|
||||
|
||||
| Name | Type | Description |
|
||||
|-------------------|----------|------------------------------------------------------------------------------------|
|
||||
| free_memory | uint64_t | The amount of free/usable memory in bytes |
|
||||
| reserved_memory | uint64_t | The amount of reserved memory in bytes |
|
||||
| used_memory | uint64_t | The amount of memory used by noxos in bytes |
|
||||
| page_bitmap_index | uint64_t | The index to the first free page |
|
||||
| page_bitmap | bitmap_T | A huge bitmap, that stores, which pages are claimable and which are already in use |
|
||||
| blocked | bool | Thread safety guard |
|
||||
|
||||
|
||||
#### `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 `memory_allocate`.
|
||||
|
||||
#### `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 `memory_free`.
|
||||
|
||||
#### `pframe_free_multi(address, n)` - function (void) [Thread Safe]
|
||||
Frees the page at the given address, plus *n* pages after that page.
|
|
@ -0,0 +1,95 @@
|
|||
# page_map.h
|
||||
|
||||
Virtual memory management.
|
||||
|
||||
Virtual memory spaces are a bit more tricky than the physical memory space.
|
||||
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.
|
||||
|
||||
# `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.
|
||||
The page map is populated with the mappings for the kernel executable and the loaded IDT.
|
||||
|
||||
# `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` register.
|
||||
|
||||
# `page_map_load(page_map*)` - function (void) [ASM implementation]
|
||||
Loads the given page map.
|
||||
To achieve this, it writes the `cr3` register.
|
||||
|
||||
# `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 automatically.
|
||||
|
||||
# `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_check_memory(page_map*, virtual_address)` - function (bool)
|
||||
Check if there is a page mapped at **_virtual_address_** in **_page_map_**.
|
||||
Returns _true_ if there is a page mapped and _false_ if 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_dump_info(page_map)` - function (void)
|
||||
Logs information about **_page_map_**, including a map of all mapped regions.
|
||||
A region is a block of continuously mapped 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.
|
|
@ -0,0 +1,35 @@
|
|||
# region.h
|
||||
|
||||
Virtual memory space layout.
|
||||
|
||||
The first 4 digits of an address can be ignored, they are also ignored by the MMU,
|
||||
but for clarity / readability reasons they are `FFFF` in the kernel space.
|
||||
See _General Concepts / Memory Layout_(todo: add reference) and _General Concepts / Process Memory Isolation_(todo: add reference) for more details.
|
||||
|
||||
| Name | Start | Description |
|
||||
|----------------------------------|--------------------|---------------------------------------------------|
|
||||
| `MEM_REGION_PROCESS` | 0x0000000000000000 | This is the start of the process space |
|
||||
| `MEM_REGION_PROCESS_EXEC` | 0x0000010000000000 | Every processes' executable will be mapped here |
|
||||
| `MEM_REGION_PROCESS_THREAD_BASE` | 0x0000010100000000 | The start of the _Thread Data_ regions |
|
||||
| `MEM_REGION_KERNEL` | 0xFFFF800000000000 | This is the start of the kernel space |
|
||||
| `MEM_REGION_KERNEL_STACK_DUMMY` | 0xFFFFF00000000000 | This area is used when preparing a threads' stack |
|
||||
| `MEM_REGION_KERNEL_HEAP` | 0xFFFFF80000000000 | The kernels' heap begins here |
|
||||
| `MEM_REGION_KERNEL_THREAD_BASE` | 0xFFFFFF0000000000 | The kernel processes' _Thread Data_ regions |
|
||||
| `MEM_REGION_KERNELEXEC` | 0xFFFFFFFF80000000 | The kernel executable is mapped here |
|
||||
|
||||
# `MEM_REGION_THREAD_OFFSET` - macro
|
||||
This time the threads id specifies its offset in its processes' _Thread Data_ region.
|
||||
|
||||
# `KERNEL_START_ADDRESS` - macro
|
||||
Returns the address of _kernel_start.
|
||||
|
||||
# `KERNEL_END_ADDRESS` - macro
|
||||
Returns the address of _kernel_end.
|
||||
|
||||
# `_kernel_start` - global variable
|
||||
This symbol is inserted by the linker at the beginning of the kernel.
|
||||
To access its value use KERNEL_START_ADDRESS.
|
||||
|
||||
# `_kernel_end` - global variable
|
||||
This symbol is inserted by the linker at the end of the kernel.
|
||||
To access its value use KERNEL_END_ADDRESS.
|
|
@ -0,0 +1,10 @@
|
|||
# stack.h
|
||||
|
||||
Functions to extract data from the call stack.
|
||||
|
||||
# `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` or fails to resolve the calls symbol name.
|
|
@ -0,0 +1,3 @@
|
|||
# platform
|
||||
|
||||
Platform specific code.
|
|
@ -0,0 +1,45 @@
|
|||
# cpu.h
|
||||
|
||||
Stuff related directly with 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
|
||||
- **cs** - Segment selector of the associated IDT descriptor
|
||||
- **flags** - The CPU's FLAGS register, a status bitmap -> cpu_flags_E
|
||||
- **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.
|
||||
Such a state 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**
|
|
@ -0,0 +1,15 @@
|
|||
# exceptions.h
|
||||
|
||||
CPU-exception handling.
|
||||
|
||||
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 CPU-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.
|
|
@ -0,0 +1,49 @@
|
|||
# gdt.h
|
||||
Definitions to handle segments (_Global Descriptor Table_).
|
||||
|
||||
Segmentation is deprecated and is only needed for backwards compatibility.
|
||||
|
||||
OSDev Wiki: [Global Descriptor Table](https://wiki.osdev.org/GDT)
|
||||
|
||||
# `gdt_selector_E` - enum
|
||||
- **Null**
|
||||
- **Kernel Code** - Readable
|
||||
- **Kernel Data** - Readable + Writable
|
||||
- **User Null**
|
||||
- **User Code** - Readable
|
||||
- **User Data** - Readable + Writable
|
||||
|
||||
# `gdt_descriptor_T` - struct [packed]
|
||||
|
||||
| Name | Type | Description |
|
||||
|--------|----------|-----------------------------------------------------|
|
||||
| size | uint16_t | The tables size in bytes (-1) |
|
||||
| offset | uint64_t | The virtual address, where the table lies in memory |
|
||||
|
||||
|
||||
# `gdt_entry_T` - struct [packed]
|
||||
| Name | Type | Description |
|
||||
|--------------|----------|--------------------------------------------------------------|
|
||||
| limit0 | uint16_t | Can be ignored in long mode |
|
||||
| base0 | uint16_t | Can be ignored in long mode |
|
||||
| base1 | uint8_t | Can be ignored in long mode |
|
||||
| access | uint8_t | Specifies permissions (details in osdev wiki) |
|
||||
| limit1_flags | uint8_t | The first 4 bits can be ignored and the last 4 specify flags |
|
||||
| base2 | uint8_t | Can be ignored in long mode |
|
||||
|
||||
# `gdt_T` - struct [packed / page aligned]
|
||||
| Name | Type | Description |
|
||||
|-------------|-------------|------------------------------------------|
|
||||
| null | gdt_entry_T | The entry for `GDT_SELECTOR_NULL` |
|
||||
| kernel_code | gdt_entry_T | The entry for `GDT_SELECTOR_KERNEL_CODE` |
|
||||
| kernel_data | gdt_entry_T | The entry for `GDT_SELECTOR_KERNEL_DATA` |
|
||||
| user_null | gdt_entry_T | The entry for `GDT_SELECTOR_USER_NULL` |
|
||||
| user_code | gdt_entry_T | The entry for `GDT_SELECTOR_USER_CODE` |
|
||||
| user_data | gdt_entry_T | The entry for `GDT_SELECTOR_USER_DATA` |
|
||||
|
||||
# `g_default_gdt` - global variable
|
||||
The systems GDT.
|
||||
|
||||
# `gdt_init` - function (void)
|
||||
Populates and loads g_default_gdt.
|
||||
This will also set all the data segment registers to 0x10 (Kernel Data) and `cs` to 0x08 (Kernel Code).
|
|
@ -0,0 +1,21 @@
|
|||
# interrupts.h
|
||||
|
||||
The infrastructure to handle x86 interrupts.
|
||||
|
||||
# `idt_register_T` - struct [packed]
|
||||
This struct is very similar to gdt_descriptor_T.
|
||||
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.
|
||||
|
||||
# `g_handling_interrupt` - global variable
|
||||
When the system isn't handling an interrupt this is set to 0.
|
||||
If this is greater than 0 the system is currently handling an interrupt,
|
||||
|
||||
# `idt_init()` - function (void)
|
||||
This function fills all the interrupt gates (handlers) into the IDT and loads it.
|
|
@ -0,0 +1,54 @@
|
|||
# proc
|
||||
|
||||
The general processing structure is a bit more complex,
|
||||
so I've split the schematics into multiple parts.
|
||||
|
||||
Processes Schematic:
|
||||
```
|
||||
+----------------+
|
||||
| Kernel Process | <----+
|
||||
| [Threads] | |
|
||||
+----------------+ |
|
||||
| [Parent]
|
||||
[Childs] |
|
||||
| +--------+--------+
|
||||
v / \
|
||||
+-----------+ +-----------+
|
||||
| Process 1 | --[Next]-> | Process 2 |
|
||||
| [Threads] | <-[Prev]-- | [Threads] | . . .
|
||||
+-----------+ +-----------+
|
||||
| |
|
||||
[Childs] [Childs]
|
||||
| |
|
||||
v v
|
||||
. . . . . .
|
||||
```
|
||||
|
||||
Thread Schematics (processes view):
|
||||
```
|
||||
+---------+
|
||||
| Process | <-------+
|
||||
+---------+ |
|
||||
| [Process]
|
||||
[Threads] |
|
||||
| +--------+--------+
|
||||
v / \
|
||||
+----------+ +----------+
|
||||
| Thread 1 | --[LocalNext]-> | Thread 2 |
|
||||
| | <-[LocalPrev]-- | | . . .
|
||||
+----------+ +----------+
|
||||
```
|
||||
|
||||
Thread schematics (schedulers view):
|
||||
```
|
||||
[RunningThread]
|
||||
|
|
||||
v
|
||||
+----------+ +----------+ +----------+
|
||||
+---> | Thread 1 | --[GlobalNext]-> | Thread 2 | --[GlobalNext]-> | Thread 3 | . . . ----+
|
||||
| +-- | | <-[GlobalPrev]-- | | <-[GlobalPrev]-- | | . . . <-+ |
|
||||
| | +----------+ +----------+ +----------+ | |
|
||||
| | | |
|
||||
| +------------------------------------[GlobalPrev]------------------------------------+ |
|
||||
+--------------------------------------[GlobalNext]--------------------------------------+
|
||||
```
|
|
@ -0,0 +1,55 @@
|
|||
# file_descriptor.h
|
||||
|
||||
Processes have no direct access to the VFS, instead they have file descriptors.
|
||||
|
||||
File descriptors are numbers that represent files.
|
||||
They are mostly used in file related syscalls.
|
||||
|
||||
# `FILE_DESCRIPTOR_ARRAY_CHUNK_SIZE` - macro
|
||||
The amount of file descriptors a `file_descriptor_array_chunk_T` (reference needed) can hold.
|
||||
|
||||
# `file_descriptor_t` - typedef
|
||||
This is a typedef of `ìnt32_t` and represents a file descriptor.
|
||||
|
||||
# `std_file_descriptors_E` - enum
|
||||
These are reserved file descriptors.
|
||||
* `FILE_DESCRIPTOR_INVALID` - This represents an invalid file descriptor, just like NULL is an invalid pointer.
|
||||
* `FILE_DESCRIPTOR_STDOUT` - This represents the file descriptor that is used, when writing to the Standard-Output stream.
|
||||
* `FILE_DESCRIPTOR_STDIN` - This represents the file descriptor that is used, when reading from the Standard-Input stream.
|
||||
* `FILE_DESCRIPTOR_STDERR` - This represents the file descriptor that is used, when writing to the Standard-Error stream.
|
||||
|
||||
# `file_descriptor_array_chunk_T` - struct
|
||||
| Name | Type | Description |
|
||||
|--------|------------------------------------------------|----------------------------------------------------------------------------------------|
|
||||
| prev | file_descriptor_array_chunk_T* | The previous chunk |
|
||||
| next | file_descriptor_array_chunk_T* | The next chunk |
|
||||
| lookup | vfs_node_T* [FILE_DESCRIPTOR_ARRAY_CHUNK_SIZE] | The array of file pointers, that the file descriptors reference |
|
||||
| bitmap | bitmap_T | This bitmap indicates which file descriptors of this chunk are free nad which are used |
|
||||
| amount | uint32_t | The amount of file descriptors which the chunk actually holds |
|
||||
|
||||
# `file_descriptor_array_T` - struct
|
||||
| Name | Type | Description |
|
||||
|------------|--------------------------------|------------------------------|
|
||||
| base_chunk | file_descriptor_array_chunk_T* | The first chunk in the array |
|
||||
|
||||
# `file_descriptor_request(fd_array, node)` - function (file_descriptor_t)
|
||||
Requests and returns new file descriptor, which will be linked with _**node**_.
|
||||
|
||||
# `file_descriptor_resolve(fd_array, fd)` - function (vfs_node_T*)
|
||||
Returns the VFS node, with which _**fd**_ is linked.
|
||||
|
||||
# `file_descriptor_free(fd_array, fd)` - function (void)
|
||||
Frees _**fd**_ and marks it as reclaimable.
|
||||
|
||||
# `file_descriptor_array_alloc()` - function (file_descriptor_array_T*)
|
||||
Allocates a new chunked file descriptor array.
|
||||
|
||||
# `file_descriptor_array_destruct(fd_array)` - function (void)
|
||||
Destructs _**fd_array**_ and all its resources, like e.g. chunks.
|
||||
|
||||
# `file_descriptor_array_chunk_alloc(prev)` - function (file_descriptor_array_chunk_T*)
|
||||
Allocates a new chunk for a file descriptor array.
|
||||
_**prev**_ has to be the last chunk of an array or NULL when the chunk is the base chunk for a fresh file descriptor array.
|
||||
|
||||
# `file_descriptor_array_chunk_destruct(chunk)` - function (void)
|
||||
Destructs _**chunk**_ and all its resources.
|
|
@ -0,0 +1,44 @@
|
|||
# pipe.h
|
||||
|
||||
Pipes are data streams between processes.
|
||||
|
||||
# `PIPE_MAX_SENDERS` - macro
|
||||
The maximum amount of processes, which can write data to one pipe.
|
||||
|
||||
# `PIPE_STD_STREAM_SIZE` - macro
|
||||
The size of a pipes stream buffer, in bytes.
|
||||
|
||||
# `pipe_T` - struct
|
||||
| Name | Type | Description |
|
||||
|----------------|-------------------------------|-----------------------------------------------------------------------------------------|
|
||||
| stream | stream_T* | The stream, where the pipes data is saved. |
|
||||
| receiver | process_T* | The process which is allowed to read from the pipe. |
|
||||
| senders | process_T* [PIPE_MAX_SENDERS] | The processes which are allowed to write to the pipe. |
|
||||
| senders_bitmap | bitmap_T | Indicates which fields of _senders_ are currently used. |
|
||||
| on_write | void function pointer | If this is not NULL, this function will be called when data is written into the stream. |
|
||||
|
||||
|
||||
# `pipe_init(pipe*, receiver*, (*on_write)())` - function (void)
|
||||
Initializes **_pipe_** and allocates a stream for it.
|
||||
|
||||
# `pipe_destruct(pipe*)` - function (void)
|
||||
Destructs **_pipe_** and frees all of its resources.
|
||||
|
||||
# `pipe_add_sender(pipe*, sender*)` - function (bool)
|
||||
Adds **_sender_** to the sender list of **_pipe_**.
|
||||
Returns if the operation was successful.
|
||||
|
||||
# `pipe_remove_sender(pipe*, sender*)` - function (void)
|
||||
Removes **_sender_** from the sender list of **_pipe_**.
|
||||
|
||||
# `pipe_write(pipe*, buffer_in*, n)` - function (uint64_t)
|
||||
Writes at most **_n_** bytes from **_buffer_in_** into **_pipe_**.
|
||||
Returns the amount of bytes that were actually written.
|
||||
If the amount of actually written bytes is smaller than **_n_** all sender processes of **_pipe_** will be _PIPE_OUT blocked_.
|
||||
If the receiver is _PIPE_IN blocked_ the blocker will be removed.
|
||||
|
||||
# `pipe_read(pipe*, buffer_out*, n)` - function (uint64_t)
|
||||
Reads at most **_n_** bytes from **_buffer_in_** into **_pipe_**.
|
||||
Returns the amount of bytes that were actually read.
|
||||
If the amount of actually read bytes is smaller than **_n_** the receiver process of **_pipe_** will be _PIPE_IN blocked_.
|
||||
If the senders are _PIPE_OUT blocked_ the blockers will be removed.
|
|
@ -0,0 +1,84 @@
|
|||
# process.h
|
||||
|
||||
Processes are the containers, in which threads are organized.
|
||||
|
||||
# `MAX_THREADS_PER_PROCESS` - macro
|
||||
The maximum amount of threads a process can have.
|
||||
This limitation is just for the bitmap,
|
||||
the overall processing structure would be capable of processes with unlimited threads, in theory.
|
||||
|
||||
# `THREAD_ID_INVALID` - macro
|
||||
If process_get_thread_id() returns this, the process can't spawn one more thread.
|
||||
|
||||
# `pid_t` - typedef
|
||||
A typedef for `uint32_t`, used for process identification.
|
||||
Such an identification number is also called `pid`.
|
||||
|
||||
# `processes_standard_E` - enum
|
||||
These are standard pids
|
||||
- **None** - This pid is invalid, like `NULL` is an invalid pointer
|
||||
- **Kernel** - The kernels' main process
|
||||
|
||||
# `process_blockers_E` - enum
|
||||
- **PIPE_OUT** - This blocker becomes activated, when the process tries to write to a pipe, but the pipe has not enough space for the data. It becomes deactivated, when the pipe has space to fit the rest of the data.
|
||||
- **PIPE_IN** - This blocker becomes activated, when the process tries to read from a pipe, but the pipe has not the requested amount of data. It becomes deactivated, when the pipe contains data again.
|
||||
|
||||
# `process_T` - struct
|
||||
|
||||
| Name | Type | Description |
|
||||
|-------------|----------------------------|-----------------------------------------------------------------------------------------|
|
||||
| name | char[128] | The processes' name |
|
||||
| id | pid_t | The process-identification number |
|
||||
| chunk | void* | A pointer to the chunk, where the process is stored in |
|
||||
| chunk_id | uint32_t | The processes id inside of its chunk |
|
||||
| page_map | page_map_T* | The processes page map. |
|
||||
| executable | elf_executable_T* | The processes executable |
|
||||
| fd_array | file_descriptor_array_T* | Contains the open file descriptors of the process. |
|
||||
| stdout | pipe_T* | Pointer to the pipe, where **stdout** writes to. |
|
||||
| stdin | pipe_T | The pipe, where **stdin** reads from. |
|
||||
| stderr | pipe_T* | Pointer to the pipe, where **stderr** writes to. |
|
||||
| waiting | bitmap_T | A bitmap of process blockers. If this is greater 0 the process is blocked by something. |
|
||||
| num_threads | uint32_t | The amount of spawned threads, that belong to the process |
|
||||
| threads | void* | A pointer to the processes' first thread |
|
||||
| thread_ids | bitmap_T(reference needed) | This bitmap keeps track of the local thread ids the process has |
|
||||
| parent | process_T* | The process, that spawned this process |
|
||||
| childs | process_T* | A pointer to the processes' first child process |
|
||||
| prev | process_T* | The previous process |
|
||||
| next | process_T* | The next process |
|
||||
|
||||
|
||||
# `process_kernel_spawn(executable)` - function (void)
|
||||
Spawns the kernels' main process.
|
||||
|
||||
**Warning:** this should only be called once, when initializing the scheduler!
|
||||
|
||||
# `process_spawn(parent, name, executable, buffer)` - function (pid_t)
|
||||
Spawns a process named **_name_** as child of **_parent_** and returns its pid.
|
||||
The process gets its own page map with the mappings specified in **_executable_**.
|
||||
In order to apply these mappings, this function needs the **_buffer_** where the executable was loaded from.
|
||||
|
||||
# `process_get_thread_id(process)` - function (int32_t)
|
||||
Searches for a free thread id in the process.
|
||||
If it finds one it returns it, else it returns THREAD_ID_INVALID.
|
||||
|
||||
# `process_clear_thread_id(process, id)` - function (void)
|
||||
Frees the thread **_id_** and makes it request-able again.
|
||||
|
||||
# `process_pause_pid(pid)` - function (void)
|
||||
Resolves the pids process and performs `process_pause` on it.
|
||||
|
||||
# `process_pause(process)` - function (void)
|
||||
Pauses **_process_** and all of its threads.
|
||||
|
||||
# `process_start_pid(pid)` - function (void)
|
||||
Resolves the pids process and performs `process_start` on it.
|
||||
|
||||
# `process_start(process)` - function (void)
|
||||
Starts **_process_** and all of its threads.
|
||||
|
||||
# `process_kill_pid(pid)` - function (void)
|
||||
Resolves the pids process and performs `process_kill` on it.
|
||||
|
||||
# `process_kill(process)` - function (void)
|
||||
Kills **_process_** and all of its threads and child processes.
|
||||
This will also destruct the `executable` and `page_map` associated with **_process_**.
|
|
@ -0,0 +1,84 @@
|
|||
# scheduler.h
|
||||
|
||||
The scheduler is responsible for switching between threads and controlling processes.
|
||||
|
||||
#### `scheduler_processes_chunk_T` - struct
|
||||
These chunks are a combination of static array and linked list.
|
||||
They store the process_T pointer for each valid `pid_t`.
|
||||
|
||||
| Name | Type | Description |
|
||||
|------------------|------------------------------|------------------------------------------------------------------------------------|
|
||||
| processes | process_T** | The array of process pointers |
|
||||
| processes_bitmap | bitmap_T(reference needed) | If a bit in this bitmap is set, the _processes_ entry with the same index is valid |
|
||||
| num_free_pids | uint32_t | The amount of free slots in this chunk |
|
||||
| prev | scheduler_processes_chunk_T* | The previous chunk |
|
||||
| next | scheduler_processes_chunk_T* | The next chunk |
|
||||
|
||||
|
||||
#### `scheduler_T` - struct
|
||||
| Name | Type | Description |
|
||||
|----------------|------------------------------|--------------------------------------------------------------------|
|
||||
| num_threads | uint32_t | Total amount of currently spawned threads |
|
||||
| num_processes | uint32_t | Total amount of currently spawned processes |
|
||||
| running_thread | thread_T* | A pointer to the currently running thread. |
|
||||
| processes | scheduler_processes_chunk_T* | The first processes store chunk |
|
||||
| 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(boot_info)` - function (void)
|
||||
Initializes the scheduler and performs a `nx_scheduler_start` kernel syscall.
|
||||
**_boot_info_** is needed in to spawn the kernels' main process.
|
||||
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 `nx_scheduler_start` kernel syscall.
|
||||
|
||||
#### `scheduler_is_initialized()` - function (bool)
|
||||
Returns if the scheduler is initialized (and running) or not.
|
||||
|
||||
#### `scheduler_dump_info(process, indent)` - function (void)
|
||||
This recursively lists information(pid, name, threads) for all child processes of **_process_**.
|
||||
**_indent_** is used intern for the recursive calls and should be set to 0 initially.
|
||||
|
||||
#### `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_register_process(process)` - function (pid_t)
|
||||
Reqisters **_process_** and returns its pid.
|
||||
|
||||
#### `scheduler_pause_process(process)` - function (void)
|
||||
Pauses **_process_** and its threads.
|
||||
|
||||
#### `scheduler_start_process(process)` - function (void)
|
||||
Starts **_process_** and its threads.
|
||||
|
||||
#### `scheduler_kill_process(process)` - function (void)
|
||||
Kills **_process_** and its threads and childs.
|
||||
|
||||
#### `scheduler_get_process(pid)` - function (process_T*)
|
||||
Returns the `process_T` pointer that is associated with **_pid_**.
|
||||
|
||||
#### `scheduler_get_current_thread()` - function (thread_T*)
|
||||
Returns a pointer to the currently running thread.
|
||||
|
||||
#### `scheduler_get_current_process()` - function (process_T*)
|
||||
Returns a pointer to the currently running threads process.
|
||||
|
||||
#### `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.
|
|
@ -0,0 +1,43 @@
|
|||
# thread.h
|
||||
|
||||
Threading infrastructure.
|
||||
|
||||
# `thread_T` - struct
|
||||
| Name | Type | Description |
|
||||
|-------------|--------------|--------------------------------------------------------------------------------------------------|
|
||||
| state | cpu_state_T* | The last saved state of the thread ( -> _context switching_(reference needed)) |
|
||||
| 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) |
|
||||
| process | process_T* | The process, to which the thread belongs to |
|
||||
| global_prev | thread_T* | The previous thread in the scheduling queue (**should only be accessed by the scheduler!**) |
|
||||
| global_next | thread_T* | The next thread in the scheduling queue (**should only be accessed by the scheduler!**) |
|
||||
| local_prev | thread_T* | The previous thread of _process_ (**should only be accessed by the scheduler!**) |
|
||||
| local_next | thread_T* | The next thread of _process_ (**should only be accessed by the scheduler!**) |
|
||||
| local_id | uint32_t | The threads id in its process |
|
||||
|
||||
|
||||
# `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 thread_start().
|
||||
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 thread_start().
|
||||
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.
|
|
@ -0,0 +1,3 @@
|
|||
# utils
|
||||
|
||||
Basic utilities that are used almost everywhere.
|
|
@ -0,0 +1,29 @@
|
|||
# bitmap.h
|
||||
|
||||
Utils to handle 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.
|
|
@ -0,0 +1,19 @@
|
|||
# core.h
|
||||
|
||||
All the utils, which I didn't know how to name.
|
||||
|
||||
|
||||
# `CORE_INTERRUPTABLE_HALT_WHILE(a)` - macro
|
||||
This halts until **_a_** is true.
|
||||
Used when working with blocking variables in e.g. thread safe functions.
|
||||
To avoid deadlocks, this macro won't halt, while the system is handling an interrupt.
|
||||
|
||||
# `CORE_HALT_WHILE(a)` - macro
|
||||
This halts until **_a_** is true.
|
||||
Used when working with blocking variables in e.g. thread safe functions.
|
||||
|
||||
**Warning:** When a function containing this macro is used while handling an interrupt,
|
||||
this could cause deadlocks, consider using CORE_INTERRUPTABLE_HALT_WHILE instead.
|
||||
|
||||
# `CORE_HALT_FOREVER` - macro
|
||||
This halts forever and warns about this in the log.
|
|
@ -0,0 +1,15 @@
|
|||
# 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.
|
|
@ -0,0 +1,18 @@
|
|||
# logger.h
|
||||
|
||||
Functionalities to write logs to QEMU's serial port.
|
||||
|
||||
# `DEBUG(string, ...)` - macro
|
||||
calls `log` with log_level _Debug_.
|
||||
Puts filename and line number in front of the format text.
|
||||
|
||||
# `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.
|
|
@ -0,0 +1,35 @@
|
|||
# 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
|
||||
This describes a position in 2D space.
|
||||
|
||||
| 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.
|
|
@ -0,0 +1,32 @@
|
|||
# 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 marks it claimable again , 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.
|
|
@ -0,0 +1,8 @@
|
|||
# panic.h
|
||||
|
||||
ahhhh - the kernel is burning!
|
||||
|
||||
# `panic(state, message)` - function (void)
|
||||
This prints out the error message, a stack backtrace and a register dump.
|
||||
After that, the kernel halts forever.
|
||||
This function is called, when a fatal error occurs
|
|
@ -0,0 +1,55 @@
|
|||
# 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.
|
|
@ -0,0 +1,27 @@
|
|||
# stream.h
|
||||
|
||||
Streams are cycled buffers, that have __one__ input and __one__ output.
|
||||
|
||||
# `stream_T` - struct
|
||||
|
||||
| Name | Type | Description |
|
||||
|--------------|----------|----------------------------------------------------------------------------------|
|
||||
| buffer | uint8_t* | The buffer where all the streams data is stored in. |
|
||||
| size | uint32_t | The size of _buffer_ in bytes. |
|
||||
| pos_sender | uint32_t | The senders (input) position in the buffer. |
|
||||
| pos_receiver | uint32_t | The receivers (output) position in the buffer. This is always behind the sender. |
|
||||
|
||||
|
||||
# `stream_alloc(size)` - function (stream_T*)
|
||||
Allocates and returns a new stream, with a buffer of size **_size_**.
|
||||
|
||||
# `stream_destruct(stream)` - function (void)
|
||||
Frees the resources of a stream.
|
||||
|
||||
# `stream_write(stream, buffer_in, n)` - function (uint32_t)
|
||||
Writes at most **_n_** bytes from **_buffer_in_** into **_stream_**.
|
||||
Returns the amount of bytes, that where actually written into the stream.
|
||||
|
||||
# `stream_read(stream, buffer_out, n)` - function (uint32_t)
|
||||
Reads at most **_n_** bytes from **_stream_** into **_buffer_out_**.
|
||||
Returns the amount of bytes, that where actually read from the stream.
|
|
@ -0,0 +1,90 @@
|
|||
# string.h
|
||||
|
||||
Basic functions for string manipulation.
|
||||
|
||||
#### `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.
|
|
@ -0,0 +1,22 @@
|
|||
# symbol.h
|
||||
|
||||
Basic functions to define and resolve symbols.
|
||||
|
||||
#### `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_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 symbol (function), where **_rip_** lays in.
|
|
@ -0,0 +1,30 @@
|
|||
# Roadmap
|
||||
|
||||
- [x] Bootable system
|
||||
- [x] Logger
|
||||
- [x] Page frame manager
|
||||
- [x] Interrupts
|
||||
- [x] Page maps
|
||||
- [x] Heap
|
||||
- [x] Format strings
|
||||
- [x] Graphics Renderer
|
||||
- [x] Text
|
||||
- [x] Double buffering
|
||||
- [x] Buffer requests
|
||||
- [x] Panic Screen
|
||||
- [x] Register dump
|
||||
- [x] Stack tracing
|
||||
- [x] Scheduler
|
||||
- [x] (Kernel) Threads
|
||||
- [x] Ramdisk
|
||||
- [x] USTAR
|
||||
- [x] RAMFS
|
||||
- [x] VFS
|
||||
- [x] ELF loading
|
||||
- [x] Processes
|
||||
- [X] Keyboard input (ps/2 int)
|
||||
- [ ] Shell
|
||||
- [X] JSON parser for system config
|
||||
- [ ] FAT32
|
||||
- [ ] Text Editor
|
||||
- [ ] TCC
|
|
@ -0,0 +1,80 @@
|
|||
# SysABI
|
||||
|
||||
Syscalls are a way for programms to communicate with the kernel.
|
||||
|
||||
To perform a syscall, you need to populate the following registers:
|
||||
|
||||
| Register | Value |
|
||||
|----------|-----------------|
|
||||
| rax | The syscalls ID |
|
||||
| rdi | Argument 1 |
|
||||
| rsi | Argument 2 |
|
||||
| rdx | Argument 3 |
|
||||
| rcx | Argument 4 |
|
||||
|
||||
---
|
||||
|
||||
The following calls should be implemented to some degree in noxos 1.0.
|
||||
|
||||
# Categories
|
||||
## Files
|
||||
| ID | Name | Description | Arg1 | Arg2 | Arg3 | Arg4 | Result | Status |
|
||||
|--------|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------|--------|------|-------------|--------|-------------|
|
||||
| 0x0101 | `nx_fopen` | Opens the file at the _len_ bytes long path _path_ and writes a file descriptor to the referenced file into _fd_ (which needs to be a pointer). | path | len | *fd | | status | Implemented |
|
||||
| 0x0102 | `nx_fclose` | Closes the file which is indicated by descriptor _fd_. This should always be called, otherwise the OS will have to unload files without knowledge of usage. | fd | | | | status | Implemented |
|
||||
| 0x0103 | `nx_fread` | Reads at most _n_ bytes from a file given as descriptor _fd_ and at a specific position _offset_ into a given memory region _mem_. | fd | offset | mem | n | status | Implemented |
|
||||
| 0x0104 | `nx_fwrite` | Writes _n_ bytes from a given memory region _mem_ into the file referenced by _fd_ at the given position _offset_, not inserting but either overwriting existing content or appending to the file. | fd | offset | mem | n | status | Implemented |
|
||||
| 0x0105 | `nx_fdelete` | Completely delete the file or folder at a given path _path_, which is _len_ bytes long. | path | len | | | status | Implemented |
|
||||
| 0x0106 | `nx_flist` | List all files and/or directories at the _len_ bytes long path _path_ and write their NULL-separated names into _mem_. When _mem_ is NULL, _needed_mem_ (which needs to be a pointer to an 32-bit integer) is filled with the appropriate value. | path | len | mem | *needed_mem | status | Implemented |
|
||||
| 0x0107 | `nx_finfo` | Writes the information about the files attribute _attr_ into mem. Types of attributes are described below. | fd | attr | mem | | status | N/A |
|
||||
|
||||
**Note:** The _len_ argument of paths isn't used at the moment, rather than using _len_, _path_ needs to be Null-Terminated.
|
||||
|
||||
## Memory
|
||||
| ID | Name | Description | Arg1 | Arg2 | Arg3 | Arg4 | Result | Status |
|
||||
|--------|-------------|-------------------------------------------------------------------------------------------------------------------------------------------------|------|------|-------|------|--------|-------------|
|
||||
| 0x0201 | `nx_mmap` | Maps _n_ 4KB pages to address _addr_. You can provide a bitmap of flags with the _flags_ argument. Which flags can be used, is described below. | addr | n | flags | | status | Implemented |
|
||||
| 0x0202 | `nx_munmap` | Unmaps _n_ 4KB pages at address _addr_. | addr | n | | | status | Implemented |
|
||||
|
||||
## Processes
|
||||
| ID | Name | Description | Arg1 | Arg2 | Arg3 | Arg4 | Result | Status |
|
||||
|-----|------|-------------|------|------|------|------|--------|--------|
|
||||
| | | | | | | | | |
|
||||
|
||||
## Runtime / Dynamic Linker
|
||||
| ID | Name | Description | Arg1 | Arg2 | Arg3 | Arg4 | Result | Status |
|
||||
|-----|------|-------------|------|------|------|------|--------|--------|
|
||||
| | | | | | | | | |
|
||||
|
||||
## Compatibility & Safety
|
||||
| ID | Name | Description | Arg1 | Arg2 | Arg3 | Arg4 | Result | Status |
|
||||
|-----|------|-------------|------|------|------|------|--------|--------|
|
||||
| | | | | | | | | |
|
||||
|
||||
## Kernel
|
||||
The kernel syscalls can only be called from the kernels main process [link to processing article needed].
|
||||
If another process calls them, they will just return without doing anything.
|
||||
|
||||
|
||||
| ID | Name | Description | Arg1 | Arg2 | Arg3 | Arg4 | Result | Status |
|
||||
|-----|------|-------------|------|------|------|------|--------|--------|
|
||||
| | | | | | | | | |
|
||||
|
||||
---
|
||||
|
||||
## Appendixes
|
||||
|
||||
### Types of file attributes
|
||||
|
||||
| ID | Name | Description | Data Type | Status |
|
||||
|-----|---------------|--------------------------------------------|-----------|--------|
|
||||
| 0 | `permissions` | Who has what permission to access the file | uint16_t | N/A |
|
||||
| 1 | `size` | The files size in bytes | uint64_t | N/A |
|
||||
|
||||
|
||||
### Memory mapping flags
|
||||
|
||||
| Bit | Name | Description |
|
||||
|-----|-----------|-------------------------------------------|
|
||||
| 0 | `write` | Enables write access to the mapped pages. |
|
||||
| 1 | `no_exec` | Prevents execution of the mapped pages. |
|
Loading…
Reference in New Issue