Initial commit

This commit is contained in:
2026-02-04 01:58:49 +01:00
commit 0e01345abf
117 changed files with 5076 additions and 0 deletions
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include <kernel/compiler.h>
#include <kernel/panic.h>
#include <kernel/print.h>
#define ASSERT(expr, msg, ...) \
({ \
if (__unlikely(!(expr))) { \
kprintf( \
"\e[31mKernel panic - Environment is unsound!\n" \
"In function \"%s\" (%s:%u):\n" \
"Assertion \"%s\" failed! " msg "\n", \
__FUNCTION__, \
__FILE__, \
__LINE__, \
#expr, \
##__VA_ARGS__ \
); \
panic(); \
} \
})
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include <kernel/common.h>
#include <kernel/compiler.h>
#define CMDLINE_MAX 0x1000
#define CMDLINE_OPTION(opt_name, opt_func) \
[[__used, __section(".cmdline")]] \
static const struct cmdline_option UNIQUE_IDENT(__cmline_option_) = { \
.name = opt_name, \
.func = opt_func, \
}
struct cmdline_option {
// The name of this option.
const char* name;
// Gets called if this option is present on the command line.
// If an option is specified as `name=value`, then the `value` is passed as well.
// Otherwise, it's NULL.
void (*func)(const char* value);
};
// Parses the command line and invokes all options.
void cmdline_parse(const char* cmdline);
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
#define ROUND_UP(value, to) (((value) + ((to) - 1)) / (to))
#define ALIGN_DOWN(value, align) (((value) / (align)) * (align))
#define ALIGN_UP(value, align) (ROUND_UP(value, align) * align)
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define BIT_TEST(value, bit) (((value) & (1 << bit)) == (1 << bit))
#define CONTAINER_OF(value, p, field) ((p*)((char*)(&(value)) + offsetof(p, field)))
#define CONCAT(A, B) _CONCAT(A, B)
#define _CONCAT(A, B) A##B
// Creates a unique identifier for a compilation unit.
#define UNIQUE_IDENT(ident) CONCAT(__unique_##ident, __COUNTER__)
// Ensures that a type is properly defined at this point.
// This is used to ensure that e.g. architecture-specific structures are defined.
#define ASSERT_TYPE(type) static_assert(sizeof(type) == sizeof(type))
+46
View File
@@ -0,0 +1,46 @@
#pragma once
// These hints may improve code generation, but are optional and can be stubbed.
#if defined(__GNUC__) || defined(__clang__)
#define __cold gnu::cold
#define __hot gnu::hot
#define __used gnu::used
#define __unused gnu::unused
#define __format(like, ...) gnu::format(like, __VA_ARGS__)
#define __likely(x) __builtin_expect(!!(x), 1)
#define __unlikely(x) __builtin_expect(!!(x), 0)
#define __always_inline gnu::always_inline
#else
#define __cold
#define __hot
#define __used
#define __unused
#define __format(like, ...)
#define __likely(x) x
#define __unlikely(x) x
#define __always_inline
#endif
// Only clang has these hints, GCC will throw a warning here.
// They also don't support the C23 attribute format.
#ifdef __clang__
#define __user __attribute__((noderef, address_space(1)))
#define __phys __attribute__((noderef, address_space(2)))
#else
#define __user
#define __phys
#endif
// Attributes that affect data layout. Not optional.
#if defined(__GNUC__) || defined(__clang__)
#define __weak gnu::weak
#define __section(x) gnu::section(x)
#define __aligned(x) gnu::aligned(x)
#define __packed gnu::packed
#define __naked gnu::naked
#else
#error "Unsupported compiler!"
#endif
// Intrinsics
#define __unreachable() __builtin_unreachable()
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <kernel/common.h>
#include <kernel/compiler.h>
#include <stddef.h>
struct console {
const char* name;
void* private;
// Initializes the console.
bool (*init)(struct console* con);
// Writes to the console.
void (*write)(struct console* con, const char* buf, size_t count);
};
// Initializes a console for logging.
void console_init();
// Writes a message to a console.
void console_write(const char* buf, size_t len);
// Defines a new early console which can be used to log early boot messages.
// An early console must not make any heap allocations.
#define DEFINE_CONSOLE(con) \
[[__used, __section(".console")]] \
static struct console* UNIQUE_IDENT(console) = (con)
+227
View File
@@ -0,0 +1,227 @@
#pragma once
#include <bits/elf.h>
#include <stdint.h>
constexpr char ELF_MAG[4] = {0x7F, 'E', 'L', 'F'};
typedef uint64_t elf64_addr_t;
typedef uint64_t elf64_off_t;
typedef uint32_t elf32_addr_t;
typedef uint32_t elf32_off_t;
enum : uint8_t {
EI_MAG0 = 0,
EI_MAG1 = 1,
EI_MAG2 = 2,
EI_MAG3 = 3,
EI_CLASS = 4,
EI_DATA = 5,
EI_VERSION = 6,
EI_OSABI = 7,
EI_ABIVERSION = 8,
EI_PAD = 9,
EI_NIDENT = 16,
};
enum : uint16_t {
EM_X86_64 = 62,
EM_AARCH64 = 183,
EM_RISCV = 243,
EM_LOONGARCH = 258,
};
enum : uint32_t {
ELFCLASS32 = 1,
ELFCLASS64 = 2,
};
enum : uint32_t {
ELFDATA2LSB = 1,
ELFDATA2MSB = 2,
};
enum : uint32_t {
EV_NONE = 0,
EV_CURRENT = 1,
EV_NUM = 2,
};
enum : uint32_t {
ELFOSABI_SYSV = 0,
ELFOSABI_HPUX = 1,
ELFOSABI_STANDALONE = 255,
};
enum : uint32_t {
ET_NONE = 0,
ET_REL = 1,
ET_EXEC = 2,
ET_DYN = 3,
ET_CORE = 4,
};
enum : uint32_t {
PT_NULL = 0x00000000,
PT_LOAD = 0x00000001,
PT_DYNAMIC = 0x00000002,
PT_INTERP = 0x00000003,
PT_NOTE = 0x00000004,
PT_SHLIB = 0x00000005,
PT_PHDR = 0x00000006,
PT_TLS = 0x00000007,
};
enum : uint32_t {
PF_X = 0x00000001,
PF_W = 0x00000002,
PF_R = 0x00000004,
};
enum : uint32_t {
DT_NULL = 0,
DT_NEEDED = 1,
DT_PLTRELSZ = 2,
DT_PLTGOT = 3,
DT_HASH = 4,
DT_STRTAB = 5,
DT_SYMTAB = 6,
DT_RELA = 7,
DT_RELASZ = 8,
DT_RELAENT = 9,
DT_STRSZ = 10,
DT_SYMENT = 11,
DT_INIT = 12,
DT_FINI = 13,
DT_SONAME = 14,
DT_RPATH = 15,
DT_SYMBOLIC = 16,
DT_REL = 17,
DT_RELSZ = 18,
DT_RELENT = 19,
DT_PLTREL = 20,
DT_DEBUG = 21,
DT_TEXTREL = 22,
DT_JMPREL = 23,
DT_BIND_NOW = 24,
DT_INIT_ARRAY = 25,
DT_FINI_ARRAY = 26,
DT_INIT_ARRAYSZ = 27,
DT_FINI_ARRAYSZ = 28,
DT_LOOS = 0x60000000,
DT_HIOS = 0x6FFFFFFF,
DT_LOPROC = 0x70000000,
DT_HIPROC = 0x7FFFFFFF,
};
enum : uint32_t {
AT_NULL = 0,
AT_IGNORE = 1,
AT_EXECFD = 2,
AT_PHDR = 3,
AT_PHENT = 4,
AT_PHNUM = 5,
AT_PAGESZ = 6,
AT_BASE = 7,
AT_FLAGS = 8,
AT_ENTRY = 9,
AT_NOTELF = 10,
AT_UID = 11,
AT_EUID = 12,
AT_GID = 13,
AT_EGID = 14,
};
struct elf64_ehdr {
uint8_t e_ident[EI_NIDENT];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
elf64_addr_t e_entry;
elf64_off_t e_phoff;
elf64_off_t e_shoff;
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
};
struct elf32_ehdr {
uint8_t e_ident[EI_NIDENT];
uint16_t e_type;
uint16_t e_machine;
uint32_t e_version;
elf32_addr_t e_entry;
elf32_off_t e_phoff;
elf32_off_t e_shoff;
uint32_t e_flags;
uint16_t e_ehsize;
uint16_t e_phentsize;
uint16_t e_phnum;
uint16_t e_shentsize;
uint16_t e_shnum;
uint16_t e_shstrndx;
};
struct elf64_phdr {
uint32_t p_type;
uint32_t p_flags;
elf64_off_t p_offset;
elf64_addr_t p_vaddr;
elf64_addr_t p_paddr;
uint64_t p_filesz;
uint64_t p_memsz;
uint64_t p_align;
};
struct elf32_phdr {
uint32_t p_type;
elf32_off_t p_offset;
elf32_addr_t p_vaddr;
elf32_addr_t p_paddr;
uint32_t p_filesz;
uint32_t p_memsz;
uint32_t p_flags;
uint32_t p_align;
};
struct elf64_dyn {
int64_t d_tag;
union {
uint64_t d_val;
elf64_addr_t d_ptr;
} d_un;
};
struct elf32_dyn {
int32_t r_offset;
union {
uint32_t d_val;
elf32_addr_t d_ptr;
} d_un;
};
struct elf64_nhdr {
uint64_t n_namesz;
uint64_t n_descsz;
uint64_t n_type;
};
struct elf32_nhdr {
uint32_t n_namesz;
uint32_t n_descsz;
uint32_t n_type;
};
struct elf64_auxv {
uint64_t atype;
uint64_t avalue;
};
struct elf32_auxv {
uint32_t atype;
uint32_t avalue;
};
+3
View File
@@ -0,0 +1,3 @@
#pragma once
#include <zinnia/handle.h>
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include <kernel/common.h>
#include <kernel/compiler.h>
#include <kernel/types.h>
#include <stddef.h>
#include <stdint.h>
#define __init __used, __section(".init.text"), __cold
#define __initdata __used, __section(".init.data")
#define __initdata_sorted(name) __used, __section(".init.data." name)
struct boot_file {
uint8_t* data;
size_t length;
const char* path;
};
struct boot_info {
char* cmdline;
struct phys_mem* mem_map;
size_t num_mem_maps;
phys_t phys_base;
virt_t virt_base;
virt_t hhdm_base;
struct boot_file* files;
size_t num_files;
};
extern uint8_t __ld_stack_top[];
extern uint8_t __ld_stack_bottom[];
// Entry point for the kernel after arch-specific setup has finished.
void kernel_entry();
// Initializes the early parts of the kernel.
void kernel_early_init();
[[noreturn]]
void kernel_main(struct boot_info* info);
[[noreturn]]
void kernel_main_task();
+59
View File
@@ -0,0 +1,59 @@
#pragma once
#include <bits/irq.h>
#include <kernel/compiler.h>
#include <kernel/list.h>
#include <kernel/vector.h>
#include <stdint.h>
enum irq_status : uint8_t {
IRQ_STATUS_HANDLED,
IRQ_STATUS_IGNORED,
};
enum irq_polarity : uint8_t {
IRQ_POLARITY_LOW,
IRQ_POLARITY_HIGH,
};
enum irq_trigger_mode : uint8_t {
IRQ_TRIGGER_EDGE,
IRQ_TRIGGER_LEVEL,
};
struct irq_handler {
enum irq_status (*handler)(void* self);
SLIST_LINK(struct irq_handler*) next;
};
struct irq_line {
int (*set_config)(enum irq_trigger_mode mode, enum irq_polarity polarity);
void (*mask)(struct irq_line* self);
void (*unmask)(struct irq_line* self);
void (*eoi)(struct irq_line* self);
SLIST_HEAD(struct irq_handler*) handlers;
bool is_busy;
};
void irq_line_attach(struct irq_line* self, struct irq_handler* handler);
struct irq_percpu {
uint32_t level;
};
void irq_lock();
void irq_unlock();
// Enables or disables interrupts on this CPU.
// Don't use this function directly.
static inline void irq_set_state(bool state) {
return arch_irq_set_state(state);
}
// Returns true if interrupts are enabled on this CPU.
// Don't use this function directly.
static inline bool irq_get_state() {
return arch_irq_get_state();
}
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#define SLIST_HEAD(type) \
struct { \
type sl_head; \
}
#define SLIST_LINK(type) \
struct { \
type sl_link; \
}
#define SLIST_EMPTY(head) ((head)->sl_head == NULL)
#define SLIST_FIRST(head) ((head)->sl_head)
#define SLIST_NEXT(elm, field) ((elm)->field.sl_link)
#define SLIST_INSERT_END(slistelm, elm, field) \
do { \
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
SLIST_NEXT((slistelm), field) = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) \
do { \
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
SLIST_FIRST((head)) = (elm); \
} while (0)
#define SLIST_FOREACH(var, head, field) for ((var) = SLIST_FIRST((head)); (var); (var) = SLIST_NEXT((var), field))
+180
View File
@@ -0,0 +1,180 @@
#pragma once
#include <zinnia/status.h>
#include <kernel/compiler.h>
#include <kernel/spin.h>
#include <kernel/types.h>
#include <bits/mem.h>
#include <stddef.h>
ASSERT_TYPE(pte_t);
enum pte_flags {
PTE_READ = 1 << 0, // Can read from this page.
PTE_WRITE = 1 << 1, // Can write to this page.
PTE_EXEC = 1 << 2, // Can execute code on this page.
PTE_USER = 1 << 3, // Can be accessed by the user.
PTE_DIR = 1 << 4, // Is a non-leaf page.
};
enum cache_mode {
CACHE_NONE,
CACHE_WRITE_COMBINE,
CACHE_WRITE_THROUGH,
CACHE_WRITE_BACK,
CACHE_MMIO,
};
struct page_table {
phys_t root;
struct spinlock lock;
};
enum alloc_flags {
ALLOC_NOZERO = 1 << 0, // Don't zero out the allocated memory.
ALLOC_MEM32 = 1 << 1, // Allocated memory needs to fit inside 32 bits.
ALLOC_MEM20 = 1 << 2, // Allocated memory needs to fit inside 20 bits.
};
enum phys_mem_usage {
PHYS_RESERVED,
PHYS_USABLE,
PHYS_RECLAIMABLE,
};
struct phys_mem {
phys_t address;
size_t length;
enum phys_mem_usage usage;
};
enum page_type {
PAGE_PHYS = 0, // Regular physical memory.
};
struct page {
enum page_type type;
int32_t flags;
size_t refcount;
union {
struct {
struct page* next; // Pointer to the next chunk.
size_t count; // Amount of free pages.
} freelist;
};
};
static_assert(0x1000 % sizeof(struct page) == 0, "struct must be a multiple of the page size!");
static_assert(sizeof(struct page) <= 64, "struct must be smaller than 64 bytes!");
struct address_space {
// TODO
};
extern struct page_table mem_kernel_table;
// Base address of the `struct page` array.
extern struct page* mem_pfndb;
// Base address of the HHDM.
extern virt_t mem_hhdm_base;
#define HHDM_PTR(paddr) (void*)((paddr) + mem_hhdm_base)
void mem_init(struct phys_mem* map, size_t length, virt_t kernel_virt, phys_t kernel_phys, virt_t tmp_hhdm);
void mem_phys_bootstrap(struct phys_mem* mem);
void mem_phys_init(struct phys_mem* map, size_t length);
// Allocates a region of memory which can be smaller than the page size.
// Returns `nullptr` if the allocator cannot provide an allocation for the
// given `length` + `flags`. Always returns `nullptr` if `length` is 0.
zn_status_t mem_alloc(size_t length, enum alloc_flags flags, void** out);
// Frees an allocation created by `mem_alloc`.
// Passing `nullptr` is a no-op.
zn_status_t mem_free(void* mem);
// Allocates an amount of contiguous physical pages.
zn_status_t mem_phys_alloc(size_t num_pages, enum alloc_flags flags, phys_t* out);
// Frees an allocated region of physical pages.
zn_status_t mem_phys_free(phys_t start, size_t num_pages);
// Creates a new page table for the kernel.
zn_status_t mem_pt_new_kernel(struct page_table* pt, enum alloc_flags flags);
// Creates a new page table for a user process.
zn_status_t mem_pt_new_user(struct page_table* pt, enum alloc_flags flags);
// Sets a page table on the current processor.
static inline void mem_pt_set(struct page_table* pt) {
arch_mem_pt_set(pt);
}
// Maps a single page to a virtual address in the given page table.
zn_status_t mem_pt_map(struct page_table* pt, virt_t vaddr, phys_t paddr, enum pte_flags flags, enum cache_mode cache);
// Changes the protection of a page.
zn_status_t mem_pt_protect(struct page_table* pt, virt_t vaddr, enum pte_flags flags);
// Unmaps a page.
zn_status_t mem_pt_unmap(struct page_table* pt, virt_t vaddr);
// Base address used to access physical memory.
static inline virt_t mem_hhdm_addr() {
return arch_mem_hhdm_addr();
}
// Base address used to access the page array.
static inline virt_t mem_pfndb_addr() {
return arch_mem_pfndb_addr();
}
// Base address used to access kernel memory mappings.
static inline virt_t mem_mapping_addr() {
return arch_mem_mapping_addr();
}
// Bit shift in a page.
static inline size_t mem_page_bits() {
return arch_mem_page_bits();
}
// Gets the page size in bytes.
static inline size_t mem_page_size() {
return 1 << mem_page_bits();
}
// The amount of bits in a level.
static inline size_t mem_level_bits() {
return arch_mem_level_bits();
}
// The amount of levels in an address.
static inline size_t mem_num_levels() {
return arch_mem_num_levels();
}
// Clears out a page table entry.
static inline void mem_pte_clear(pte_t* pte) {
return arch_mem_pte_clear(pte);
}
// Builds a page table entry from the given info.
static inline pte_t mem_pte_build(phys_t addr, enum pte_flags flags, enum cache_mode cache) {
return arch_mem_pte_build(addr, flags, cache);
}
// Returns true if the given PTE is present and valid.
static inline bool mem_pte_is_present(pte_t* pte) {
return arch_mem_pte_is_present(pte);
}
// Returns true if the given PTE contains another level.
static inline bool mem_pte_is_dir(pte_t* pte) {
return arch_mem_pte_is_dir(pte);
}
// Returns the address component of the page table entry.
static inline phys_t mem_pte_address(pte_t* pte) {
return arch_mem_pte_address(pte);
}
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include <kernel/sched.h>
struct mutex {
struct task* owner;
bool flag;
};
void mutex_lock(struct mutex* mutex);
void mutex_unlock(struct mutex* mutex);
+5
View File
@@ -0,0 +1,5 @@
#pragma once
// Stop all execution upon panic.
[[noreturn]]
void panic();
+35
View File
@@ -0,0 +1,35 @@
#pragma once
#include <bits/percpu.h>
#include <kernel/compiler.h>
#include <kernel/irq.h>
#include <kernel/sched.h>
#include <stddef.h>
ASSERT_TYPE(struct arch_percpu);
// CPU-relative information.
struct percpu {
struct percpu* self; // A pointer to this structure.
size_t id; // The virtual ID of this CPU.
bool online; // Whether this CPU is initialized and active.
virt_t kernel_stack; // The kernel mode stack.
virt_t user_stack; // The user mode stack.
struct arch_percpu arch; // Architecture-specific fields.
struct irq_percpu irq; // IRQ information.
struct sched_percpu sched; // Scheduler information.
};
// Per-CPU data for the bootstrap processor.
extern struct percpu percpu_bsp;
// Gets the per-CPU data on the current CPU.
static inline struct percpu* percpu_get() {
return arch_percpu_get();
}
// Allocates a block of memory for a new CPU.
struct percpu* percpu_new();
// Initializes the bootstrap processor.
void percpu_bsp_early_init();
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include <kernel/compiler.h>
[[__format(printf, 1, 2)]]
void kprintf(const char* message, ...);
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include <bits/sched.h>
#include <kernel/mem.h>
#include <kernel/types.h>
#include <stddef.h>
#include <stdint.h>
ASSERT_TYPE(struct arch_context);
ASSERT_TYPE(struct arch_task_context);
typedef size_t tid_t;
enum task_state {
TASK_STATE_RUNNING, // Task is active and running.
TASK_STATE_READY, // Task is active, but not currently scheduled.
TASK_STATE_BLOCKED, // Task is waiting on another object.
};
// A task is the smallest unit of the scheduler.
struct task {
tid_t id;
struct process* process;
enum task_state state;
struct arch_context context;
virt_t kernel_stack;
virt_t user_stack;
size_t time_slice;
int8_t priority;
};
// Per-CPU data for scheduling.
struct sched_percpu {
struct task* current;
};
void sched_init();
+13
View File
@@ -0,0 +1,13 @@
#pragma once
// Busy-waits in a loop until the lock is freed.
// Does not put the CPU to sleep.
struct spinlock {
bool locked;
};
// Attempts to lock a spinlock. If it's already locked, waits until it's freed.
void spin_lock(struct spinlock* spin);
// Unlocks a spinlock.
void spin_unlock(struct spinlock* spin);
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include <zinnia/status.h>
#include <kernel/compiler.h>
#include <kernel/types.h>
#include <stddef.h>
#include <stdint.h>
zn_status_t syscall_dispatch(reg_t num, reg_t a0, reg_t a1, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6);
[[noreturn]]
void syscall_panic(zn_status_t err);
zn_status_t syscall_log(__user const char* msg, size_t len);
zn_status_t syscall_archctl(uint32_t op, size_t value);
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <bits/types.h>
#include <kernel/common.h>
ASSERT_TYPE(phys_t);
ASSERT_TYPE(virt_t);
ASSERT_TYPE(reg_t);
+5
View File
@@ -0,0 +1,5 @@
#pragma once
#include <uapi/uio.h>
struct iovec_iter {};
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#include <bits/usercopy.h>
#include <kernel/compiler.h>
#include <stddef.h>
#include <stdint.h>
struct usercopy_region {
void (*start_ip)();
void (*end_ip)();
void (*fault_ip)();
};
// Copies a block of data from user to kernel memory.
bool usercopy_read(uint8_t* dst, const __user uint8_t* src, size_t len) {
return arch_usercopy_read(dst, src, len);
}
// Copies a block of data from kernel to user memory.
bool usercopy_write(__user uint8_t* dst, const uint8_t* src, size_t len) {
return arch_usercopy_write(dst, src, len);
}
// Performs a strlen() on a user string.
bool usercopy_strlen(const __user uint8_t* str, size_t max, size_t* len) {
return arch_usercopy_strlen(str, max, len);
}
+85
View File
@@ -0,0 +1,85 @@
#pragma once
#include <kernel/mem.h>
#include <stddef.h>
#include <string.h>
#define VEC(type) \
struct { \
type* items; \
size_t capacity; \
size_t length; \
}
// Initializes a vector that can hold `cap` entries.
#define VEC_INIT(vec, cap) \
do { \
*(vec) = (typeof(*(vec))){ \
.items = nullptr, \
.capacity = (cap), \
.length = 0, \
}; \
} while (0)
// Frees the memory associated with the `vec`.
#define VEC_FREE(vec) \
do { \
kfree((vec)->items); \
(vec)->items = NULL; \
(vec)->capacity = 0; \
(vec)->length = 0; \
} while (0)
// Pushes a new `item` to the `vec`.
#define VEC_PUSH(vec, item) \
do { \
auto __vec = (vec); \
/* Default capacity. */ \
if (__vec->capacity == 0) \
__vec->capacity = 16; \
/* If no container was allocated, do it now.*/ \
if (__vec->items == nullptr) { \
__vec->items = kmalloc(sizeof(typeof(*(__vec->items))) * __vec->capacity, KMF_ZEROED); \
__vec->length = 0; \
} \
/* If the new entry would overflow the buffer, double the capacity. */ \
if (__vec->length + 1 > __vec->capacity) { \
__vec->capacity *= 2; \
__vec->items = krealloc(__vec->items, sizeof(typeof(*(__vec->items))) * __vec->capacity); \
} \
__vec->items[__vec->length] = (item); \
__vec->length++; \
} while (0)
// Removes the element at index `idx` and moves all other members so the vec is contiguous again.
#define VEC_POP(vec, idx) \
do { \
auto __vec = (vec); \
if ((idx) >= __vec->length) \
break; \
/* Move all data back by one entry. */ \
memmove( \
__vec->items + (idx), \
__vec->items + (idx) + 1, \
sizeof(typeof(*(__vec->items))) * (__vec->length - (idx)) \
); \
__vec->length--; \
} while (0)
// Iterates over `vec` with iterator variable `var_name`.
#define VEC_ITER(vec, var_name) \
for (typeof(((vec)->items)) var_name = (vec)->items + 0; (var_name) < (vec)->items + (vec)->length; var_name++)
// Looks for a `value` in the `vec` and returns the index of the first match in `result`.
// If unsuccessful, returns -1.
#define VEC_FIND(vec, result, value) \
do { \
result = -1; \
for (usize __i = 0; __i < (vec)->length; __i++) { \
if ((vec)->items[__i] == value) { \
result = __i; \
break; \
} \
} \
true; \
} while (0)
+10
View File
@@ -0,0 +1,10 @@
#ifndef ZINNIA_STDARG_H
#define ZINNIA_STDARG_H
typedef __builtin_va_list va_list;
#define va_start(v, l) __builtin_va_start(v, l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v, T) __builtin_va_arg(v, T)
#define va_copy(d, s) __builtin_va_copy(d, s)
#endif
+37
View File
@@ -0,0 +1,37 @@
#ifndef ZINNIA_STDATOMIC_H
#define ZINNIA_STDATOMIC_H
typedef enum memory_order {
memory_order_relaxed = __ATOMIC_RELAXED,
memory_order_consume = __ATOMIC_CONSUME,
memory_order_acquire = __ATOMIC_ACQUIRE,
memory_order_release = __ATOMIC_RELEASE,
memory_order_acq_rel = __ATOMIC_ACQ_REL,
memory_order_seq_cst = __ATOMIC_SEQ_CST
} memory_order;
#define atomic_store_explicit(ptr, des, ord) __atomic_store_n(ptr, des, ord)
#define atomic_store(ptr, des) atomic_store_explicit(ptr, des, __ATOMIC_SEQ_CST)
#define atomic_load_explicit(ptr, ord) __atomic_load_n(ptr, ord)
#define atomic_load(ptr) atomic_load_explicit(ptr, __ATOMIC_SEQ_CST)
#define atomic_exchange_explicit(ptr, des, ord) __atomic_exchange_n(ptr, des, ord)
#define atomic_exchange(ptr, des) atomic_exchange_explicit(ptr, des, __ATOMIC_SEQ_CST)
#define atomic_fetch_add_explicit(ptr, op, ord) __atomic_fetch_add(ptr, op, ord)
#define atomic_fetch_add(ptr, op) atomic_fetch_add_explicit(ptr, op, __ATOMIC_SEQ_CST)
#define atomic_fetch_sub_explicit(ptr, op, ord) __atomic_fetch_sub(ptr, op, ord)
#define atomic_fetch_sub(ptr, op) atomic_fetch_sub_explicit(ptr, op, __ATOMIC_SEQ_CST)
#define atomic_fetch_or_explicit(ptr, op, ord) __atomic_fetch_or(ptr, op, ord)
#define atomic_fetch_or(ptr, op) atomic_fetch_or_explicit(ptr, op, __ATOMIC_SEQ_CST)
#define atomic_fetch_xor_explicit(ptr, op, ord) __atomic_fetch_xor(ptr, op, ord)
#define atomic_fetch_xor(ptr, op) atomic_fetch_xor_explicit(ptr, op, __ATOMIC_SEQ_CST)
#define atomic_fetch_and_explicit(ptr, op, ord) __atomic_fetch_and(ptr, op, ord)
#define atomic_fetch_and(ptr, op) atomic_fetch_and_explicit(ptr, op, __ATOMIC_SEQ_CST)
#endif
+9
View File
@@ -0,0 +1,9 @@
#ifndef ZINNIA_STDDEF_H
#define ZINNIA_STDDEF_H
typedef unsigned long size_t;
typedef signed long ssize_t;
#define offsetof(type, member) __builtin_offsetof(type, member)
#endif
+29
View File
@@ -0,0 +1,29 @@
#ifndef ZINNIA_STDINT_H
#define ZINNIA_STDINT_H
typedef __INT8_TYPE__ int8_t;
typedef __UINT8_TYPE__ uint8_t;
#define INT8_MAX __INT8_MAX__
#define UINT8_MAX __UINT8_MAX__
typedef __INT16_TYPE__ int16_t;
typedef __UINT16_TYPE__ uint16_t;
#define INT16_MAX __INT16_MAX__
#define UINT16_MAX __UINT16_MAX__
typedef __INT32_TYPE__ int32_t;
typedef __UINT32_TYPE__ uint32_t;
#define INT32_MAX __INT32_MAX__
#define UINT32_MAX __UINT32_MAX__
typedef __INT64_TYPE__ int64_t;
typedef __UINT64_TYPE__ uint64_t;
#define INT64_MAX __INT64_MAX__
#define UINT64_MAX __UINT64_MAX__
typedef __INTPTR_TYPE__ intptr_t;
typedef __UINTPTR_TYPE__ uintptr_t;
#define INTPTR_MAX __INTPTR_MAX__
#define UINTPTR_MAX __UINTPTR_MAX__
#endif
+17
View File
@@ -0,0 +1,17 @@
#ifndef ZINNIA_STRING_H
#define ZINNIA_STRING_H
#include <stddef.h>
size_t strlen(const char* str);
size_t strnlen(const char* str, size_t len);
int memcmp(const void* s1, const void* s2, size_t size);
void* memcpy(void* restrict dest, const void* restrict src, size_t n);
void* memmove(void* dstptr, const void* srcptr, size_t size);
void* memset(void* dest, int value, size_t n);
char* strncpy(char* restrict dst, const char* restrict src, size_t len);
int strcmp(const char* str1, const char* str2);
int strncmp(const char* str1, const char* str2, size_t len);
char* strchr(const char* c, int s);
#endif