Vystem 0.2

This commit is contained in:
2026-05-27 19:34:54 +02:00
parent a43c08b893
commit d238606b75
372 changed files with 51320 additions and 83217 deletions

View File

@@ -1,7 +1,9 @@
# Heap memory allocations
The Shelter standard library provide a single API for memory allocations on the heap. The heap is only initialized at the end of the memory subsystem and can't be used before. It's not adapted for memory mapped I/O or big buffers allocations (larger than one hundrer pages). The heap internal documentation can be found inside the memory subsystem documentation.
The Shelter standard library provide a single API for memory allocations on the heap. The heap is only initialized at the end of the memory subsystem and can't be used before. It's not adapted for memory mapped I/O or big buffers allocations (roughly than one hundred pages). The heap internal documentation can be found inside the memory subsystem documentation.
The memory allocations API provide the two following functions (defined inside `shelter/lib/include/std/malloc.h` and implemented inside `shelter/lib/src/std/malloc.c`):
- `void* sh_malloc(sh_uint64 size)`: allocate `size` amount of bytes. Return `SH_NULLPTR` if an error occured. The heap internal will trigger a heap crash (essentially a `while (SH_TRUE)` loop) to prevent any further damage if something very bad happen.
- `void sh_free(void *ptr)`: free the memory allocated at `ptr`. The heap internal will trigger a heap crash (essentially a `while (SH_TRUE)` loop) to prevent any further damage if something very bad happen.
To prevent any race conditions, there is a global lock on the entry point of the heap in the standard library. After APs bootstrap, only those entry point should be used for basic memory allocation.

View File

@@ -1,6 +1,6 @@
# Basic memory operations
The Shelter standard library provide very basic memory operations primitives, defined in `shelter/lib/include/std/mem.h` and implemented inside `shelter/lib/src/std/mem.c`:
The Shelter standard library provides very basic memory operations primitives, defined in `shelter/lib/include/std/mem.h` and implemented inside `shelter/lib/src/std/mem.c`:
- `SH_STATUS sh_mem_compare(const void *a,const void *b,sh_uint64 size)`: compare two memory regions with the same size. Return `SH_STATUS_SUCCESS` if both regions are equal, or `SH_STATUS_MEM_NOT_EQUAL` if one byte is different.
- `SH_STATUS sh_mem_copy(const void *destination,const void *source,sh_uint64 size)`: copy one region of memory to another. Return `SH_STATUS_SUCCESS`
- `SH_STATUS sh_mem_set_8(sh_uint8 *ptr,const sh_uint8 byte,sh_uint64 count)`: set a provided amount of bytes to the value of one provided byte. Return `SH_STATUS_SUCCESS`

53
docs/shelter/std/print.md Normal file
View File

@@ -0,0 +1,53 @@
# Print primitives
## Introduction
The standard library provides his own abstraction to print strings. This abstraction can be used before the APs bootstrap and must be used after the APs bootstrap. The print implementation in the standard library is fully thread-safe. The print implementation is defined inside `shelter/lib/include/std/print.h` and implemented inside `shelter/lib/include/std/print.c`.
The format syntax is the same used in the kernel logging API. See [format syntax](../kernel/log.md).
## Print initialization
Before the initialization of the print implementation, all output using `sh_print` and `sh_printf` is redirected to the kernel logging API.
The initialization of the print implementation is done through `sh_print_setup_ring_buffers_per_ap()`. This function initializes a ring buffer for each CPU, including the bootstrap CPU. The size of each ring buffer is the amount of bytes for the global logging ring buffer divided by the amount of CPU.
Every single print primitives (except `sh_sprintf`, which doesn't print anything) respect the log level specified in the kernel boot configuration.
## Characteristics
This print implementation differ of the kernel logging API by these differences:
- It doesn't support displaying the name of the subsystem
- It shows the logical CPU id of the AP that called the print implementation
It also defines its own macros for the type of output: `SH_DEBUG`, `SH_LOG`, `SH_WARNING`, `SH_ERROR`, `SH_CRITICAL`, `SH_FATAL`, `SH_TEST`, `SH_FAULT`
## Normal printing
### API
The print implementation provide two functions for normal printing:
- `sh_print(sh_log_OUTPUT_TYPE output_type,char *text)`: print a normal string without formatting the text before hand
- `sh_printf(sh_log_OUTPUT_TYPE output_type,char* format,...)`: format and print the formatted string byte by byte
### Detailled processus
For normal printing, the outputed text goes through two main steps:
First, each byte is outputed into the local printing ring buffer. We keep track of the amount of bytes outputed using the attribute in the per-CPU struct of this CPU.
Then, extracting the outputed byte from the local printing ring buffer, all outputed bytes are sent to the serial port, no without locking a global serial spinlock before.
## Interrupts printing
The print system also provides a dedicated path for interrupt handlers. In this mode, output bypasses the local ring buffer and is written directly to the serial port after acquiring the serial spinlock. If the lock is already held by another CPU, the function will block until it becomes available.
The API is as follows:
- `sh_iprint(sh_log_OUTPUT_TYPE output_type,char *text)`: same as `sh_print` but for interrupt handlers
- `SH_STATUS sh_iprintf(sh_log_OUTPUT_TYPE output_type,char* format,...)`: same as `sh_iprintf` but for interrupt handlers
## String formatting
Finally, the print implementation provides a way to easely format strings using the same format syntax, using `sh_sprintf(char *output_string,sh_uint64 output_len,char *format,...)`.
This function writes into the provided buffer only. It doesn't print to the serial port, doesn't use ring buffers, and doesn't allocate memory via `sh_malloc`.

View File

@@ -0,0 +1,23 @@
# Queues
## Introduction
The standard library provides various queues implementations for various objects sizes. Queue objects aren't thread safe. It is defined inside `shelter/lib/include/std/queue.h` and implemented in `shelter/lib/src/std/queue.c`.
## Keyboard events queue
This queue is represented by the following object:
``` C
typedef struct {
sh_kbd_EVENT *buffer;
sh_uint32 capacity;
sh_uint32 write_index;
} sh_queue_KBD_EVENT;
```
These queues automatically overwrite the oldest object when the caller try to push an object when the queue is full.
The API is as follows:
- `sh_queue_event_init(sh_queue_KBD_EVENT *q,sh_uint32 capacity)`: initialize a keyboard events queue, allocate the queue buffer
- `sh_queue_event_push(sh_queue_KBD_EVENT *q,sh_kbd_EVENT ev)`: push an event into the provided queue
- `sh_queue_event_destroy(sh_queue_KBD_EVENT *q)`: destroy the provided queue, free the queue buffer

54
docs/shelter/std/smp.md Normal file
View File

@@ -0,0 +1,54 @@
# SMP services
## Introduction
The SMP services provide various abstractions related to SMP programming. It is defined inside `shelter/lib/include/std/smp.h` and implemented in `shelter/lib/src/std/smp.c`
## GS register
Regarding the GS register, two functions are provided:
- `sh_smp_write_gs_base(sh_uint64 value)`: Write the `IA32_GS_BASE` MSR. with a value, return nothing
- `sh_smp_gs_base()`: take no argument and return a `sh_ap_CPU_STRUCT*`
## Spinlocks
The SMP services provide a basic implementation for a spinlock, which look like this:
``` C
typedef struct {
volatile sh_uint32 spinlock;
sh_uint32 lapic_id;
} sh_SPIN_LOCK;
```
Two macros are provided to initialize an unlocked spinlock:
- `SH_LOCK()`: intended for spinlocks stored as global variables
- `SH_LOCK_LOCAL()`: intended for spinlocks stored as local variables or into structs
This spinlock implementation requires `sh_smp_gs_base()` to return a valid pointer to a CPU struct. It uses the atomics primitives provided by compilers. Spinlock operations provide full memory ordering guarantees.
Four functions are provided for spinlock manipulation:
- `sh_spin_lock(sh_SPIN_LOCK *lock)`: lock a spinlock, block until the lock is acquired. Return nothing
- `sh_spin_unlock(sh_SPIN_LOCK *lock)`: unlock a spinlock, return nothing
- `sh_spin_trylock(sh_SPIN_LOCK *lock)`: Attempt to acquire the lock without blocking., return `SH_TRUE` if successfull, `SH_FALSE` otherwise.
- `sh_spin_wholock(sh_SPIN_LOCK *lock)`: return the LAPIC id of the CPU locking the spinlock. Return `SH_UINT32_MAX` if the spinlock isn't owned by any CPU
Current implementation doesn't disable interrupts while holding locks.
## CPU count
SMP services can store the amount of CPU cores using the following functions:
- `sh_smp_set_cpu_count(sh_int16 cpu_count)`: set the count of CPU. It is only called one time by `sh_ap_prepare_for_smp_launch()`
- `sh_smp_get_cpu_count()`: return the count of CPU, return `-1` if value isn't initialized
## Memory barrier
The SMP services provide the following primitives:
Function name | Role
--------------|-----
`sh_mb()` | Full memory barrier
`sh_rmb()` | Read memory barrier
`sh_wmb()` | Write memory barrier
Current x86_64 implementation uses mfence/lfence/sfence.

View File

@@ -10,5 +10,9 @@ In order to function properly, any kernel need a standard library. Shelter defin
2) [Return status](status.md)
3) [Basic memory operations](mem.md)
4) [Heap memory allocations](malloc.md)
5) [Print primitives](print.md)
6) [String operations](strings.md)
7) [SMP services](smp.md)
8) [Queues](queues.md)
You can include the file `shelter/lib/include/std/stdlib.h` to include all necessary headers to access the Shelter standard library.

View File

@@ -0,0 +1,9 @@
# Strings operations
The Shelter standard library provides basic strings operations primitives, defined in `shelter/lib/include/std/string.h` and implemented inside `shelter/lib/src/std/string.c`:
- `sh_string_len(char *str)`: return the length of a null terminated string
- `sh_string_compare(char *str1,char* str2,sh_uint64 length)`: compare two null terminated string, both strings must not exceed the provided length. return `SH_TRUE` if both strings are equal on the provided length
- `sh_string_find_char(char *str,char character)`: return the index of the first occurence of the provide character into the string, return `SH_UINT64_MAX` if not found or error
- `sh_string_find(char *str,char *substr)`: return the index of the start of the first occurence of the provided substring into the string, return `SH_UINT64_MAX` if not found or error
- `sh_string_substring(char *source_str,sh_uint64 start_index,sh_uint64 length,char *output)`: copy a substring from a string to another string, and return the pointer to the new null terminated string (aka the provided `output` pointer). Return `SH_NULLPTR` if error
- `sh_string_to_uint64(char *str)`: convert a string to a `sh_uint64` and return this `sh_uint64`