This commit is contained in:
2026-09-28 17:46:45 +02:00
committed by Marvin Friedrich
parent 09926f45ee
commit 4a20a5b0af
62 changed files with 1266 additions and 554 deletions
+1 -1
View File
@@ -2,6 +2,6 @@
#include <zinnia/irq.h>
void arch_irq_set_state(bool state);
bool arch_irq_set_state(bool state);
bool arch_irq_get_state();
void arch_irq_wait();
+9 -8
View File
@@ -1,28 +1,29 @@
#pragma once
#include <zinnia/compiler.h>
#include <stddef.h>
#include <stdint.h>
[[gnu::pure]]
[[__pure]]
bool arch_mem_addr_is_user(uintptr_t addr);
[[gnu::pure]]
[[__pure]]
size_t arch_mem_page_size();
[[gnu::pure]]
[[__pure]]
size_t arch_mem_page_bits();
[[gnu::pure]]
[[__pure]]
size_t arch_mem_level_bits();
[[gnu::pure]]
[[__pure]]
size_t arch_mem_num_levels();
[[gnu::pure]]
[[__pure]]
uintptr_t arch_mem_hhdm_addr();
[[gnu::pure]]
[[__pure]]
uintptr_t arch_mem_pfndb_addr();
[[gnu::pure]]
[[__pure]]
uintptr_t arch_mem_mapping_addr();
-21
View File
@@ -1,21 +0,0 @@
#pragma once
typedef enum memory_order {
ATOMIC_RELAXED = __ATOMIC_RELAXED,
ATOMIC_CONSUME = __ATOMIC_CONSUME,
ATOMIC_ACQUIRE = __ATOMIC_ACQUIRE,
ATOMIC_RELEASE = __ATOMIC_RELEASE,
ATOMIC_ACQ_REL = __ATOMIC_ACQ_REL,
ATOMIC_SEQ_CST = __ATOMIC_SEQ_CST
} memory_order;
#define atomic(T) _Atomic(T)
#define atomic_store(ptr, des, order) __atomic_store_n(ptr, des, order)
#define atomic_load(ptr, order) __atomic_load_n(ptr, order)
#define atomic_exchange(ptr, des, order) __atomic_exchange_n(ptr, des, order)
#define atomic_fetch_add(ptr, op, order) __atomic_fetch_add(ptr, op, order)
#define atomic_fetch_sub(ptr, op, order) __atomic_fetch_sub(ptr, op, order)
#define atomic_fetch_or(ptr, op, order) __atomic_fetch_or(ptr, op, order)
#define atomic_fetch_xor(ptr, op, order) __atomic_fetch_xor(ptr, op, order)
#define atomic_fetch_and(ptr, op, order) __atomic_fetch_and(ptr, op, order)
#define atomic_thread_fence(order) __atomic_thread_fence(order)
+1
View File
@@ -14,6 +14,7 @@
#define __format(like, ...) gnu::format(like, __VA_ARGS__)
#define __always_inline gnu::always_inline
#define __visibility gnu::visibility
#define __pure gnu::pure
// Only clang has these hints, GCC would throw a warning here.
// clang::noderef also don't support the C23 attribute format.
+29 -20
View File
@@ -46,26 +46,38 @@
// Internal: grow and rehash.
#define _HASHMAP_GROW(map, hash_fn, eq_fn) \
do { \
({ \
errno_t _grow_status = 0; \
size_t _old_cap = (map)->capacity; \
size_t _new_cap = _old_cap == 0 ? 16 : _old_cap * 2; \
typeof((map)->keys) _old_keys = (map)->keys; \
typeof((map)->values) _old_values = (map)->values; \
uint64_t* _old_hashes = (map)->hashes; \
(map)->keys = mem_alloc(_new_cap * sizeof(*(map)->keys), ALLOC_NOZERO); \
(map)->values = mem_alloc(_new_cap * sizeof(*(map)->values), ALLOC_NOZERO); \
(map)->hashes = mem_alloc(_new_cap * sizeof(uint64_t), 0); \
(map)->capacity = _new_cap; \
(map)->count = 0; \
for (size_t _i = 0; _i < _old_cap; _i++) { \
if (_old_hashes[_i] != 0) { \
_HASHMAP_INSERT_INNER(map, _old_keys[_i], _old_values[_i], _old_hashes[_i]); \
typeof((map)->keys) _new_keys = mem_alloc(_new_cap * sizeof(*(map)->keys), ALLOC_NOZERO); \
typeof((map)->values) _new_values = mem_alloc(_new_cap * sizeof(*(map)->values), ALLOC_NOZERO); \
uint64_t* _new_hashes = mem_alloc(_new_cap * sizeof(uint64_t), 0); \
if (_new_keys == nullptr || _new_values == nullptr || _new_hashes == nullptr) { \
mem_free(_new_keys); \
mem_free(_new_values); \
mem_free(_new_hashes); \
_grow_status = ENOMEM; \
} else { \
typeof((map)->keys) _old_keys = (map)->keys; \
typeof((map)->values) _old_values = (map)->values; \
uint64_t* _old_hashes = (map)->hashes; \
(map)->keys = _new_keys; \
(map)->values = _new_values; \
(map)->hashes = _new_hashes; \
(map)->capacity = _new_cap; \
(map)->count = 0; \
for (size_t _i = 0; _i < _old_cap; _i++) { \
if (_old_hashes[_i] != 0) { \
_HASHMAP_INSERT_INNER(map, _old_keys[_i], _old_values[_i], _old_hashes[_i]); \
} \
} \
mem_free(_old_keys); \
mem_free(_old_values); \
mem_free(_old_hashes); \
} \
mem_free(_old_keys); \
mem_free(_old_values); \
mem_free(_old_hashes); \
} while (0)
_grow_status; \
})
// Internal: insert with a precomputed hash. Used by grow and the public INSERT macro.
#define _HASHMAP_INSERT_INNER(map, k, v, h) \
@@ -126,10 +138,7 @@
} \
if (!_found) { \
if ((map)->count * 4 >= (map)->capacity * 3 || (map)->capacity == 0) { \
_HASHMAP_GROW(map, hash_fn, eq_fn); \
if ((map)->keys == nullptr || (map)->values == nullptr || (map)->hashes == nullptr) { \
_status = ENOMEM; \
} \
_status = _HASHMAP_GROW(map, hash_fn, eq_fn); \
} \
if (_status == 0) { \
_HASHMAP_INSERT_INNER(map, _k, (val), _h); \
+1 -4
View File
@@ -26,16 +26,13 @@ struct boot_info {
uintptr_t hhdm_base;
struct boot_file* files;
size_t num_files;
#if CONFIG_OF
void* dtb;
#endif
#if CONFIG_ACPI
phys_t rsdp;
#endif
};
extern struct boot_info boot_info;
[[__visibility("hidden")]]
extern uint8_t __ld_stack_top[];
[[__visibility("hidden")]]
+26 -10
View File
@@ -2,11 +2,13 @@
#include <zinnia/compiler.h>
#include <zinnia/list.h>
#include <zinnia/types.h>
#include <stddef.h>
#include <stdint.h>
enum irq_status : uint8_t {
IRQ_STATUS_HANDLED,
IRQ_STATUS_IGNORED,
IRQ_STATUS_HANDLED,
};
enum irq_polarity : uint8_t {
@@ -19,34 +21,48 @@ enum irq_trigger_mode : uint8_t {
IRQ_TRIGGER_LEVEL,
};
enum irq_mode : uint8_t {
IRQ_MODE_EOI = 1 << 0,
IRQ_MODE_MASKABLE = 1 << 1,
};
struct irq_handler {
enum irq_status (*handler)(void* self);
enum irq_status (*raise)(struct irq_handler* self);
list_link(struct irq_handler*) next;
};
struct irq_line {
int (*set_config)(enum irq_trigger_mode mode, enum irq_polarity polarity);
enum irq_mode (*set_config)(struct irq_line* self, enum irq_trigger_mode trigger, enum irq_polarity polarity);
void (*mask)(struct irq_line* self);
void (*unmask)(struct irq_line* self);
void (*eoi)(struct irq_line* self);
list_head(struct irq_handler*) handlers;
bool is_busy;
list_head(struct irq_handler*) handlers;
enum irq_mode mode;
};
struct msi_line {
struct irq_line line;
phys_t (*msg_addr)(struct msi_line* self);
uint32_t (*msg_data)(struct msi_line* self);
};
struct irq_percpu {
uint32_t level;
bool in_interrupt;
size_t depth;
bool saved_state;
};
void irq_line_attach(struct irq_line* self, struct irq_handler* handler);
extern struct irq_percpu irq_data;
void irq_line_program(struct irq_line* line, enum irq_trigger_mode trigger, enum irq_polarity polarity);
void irq_line_raise(struct irq_line* line);
void irq_line_attach(struct irq_line* line, struct irq_handler* handler);
void irq_lock();
void irq_unlock();
bool irq_set_interrupted(bool is_interrupted);
void irq_line_raise(struct irq_line* line);
// Hints to stop execution on this CPU until an interrupt happens.
void irq_wait();
bool irq_get_state();
void irq_set_state(bool state);
bool irq_set_state(bool state);
+1 -2
View File
@@ -1,7 +1,6 @@
#pragma once
#include <zinnia/compiler.h>
#include <zinnia/irq.h>
#include <zinnia/sched.h>
#include <zinnia/usercopy.h>
#include <stddef.h>
@@ -33,11 +32,11 @@ struct percpu {
bool online; // Whether this CPU is initialized and active.
uintptr_t kernel_stack; // The kernel mode stack.
uintptr_t user_stack; // The user mode stack.
struct irq_percpu irq; // IRQ information.
struct scheduler sched; // Scheduler information.
};
struct percpu* percpu_new();
size_t percpu_max_cpus();
struct percpu* percpu_get();
void percpu_bsp_init();
void percpu_init();
+1 -1
View File
@@ -16,5 +16,5 @@ void kvprintf(const char* message, va_list args);
auto _time = clock_get_elapsed_ns(); \
auto _cur = percpu_get()->sched.current; \
auto _tid = _cur ? _cur->id : 0; \
kprintf("[%5lu.%06lu] [%5lu] " message, _time / 1'000'000'000, _time % 1'000'000, _tid, ##__VA_ARGS__); \
kprintf("[%5lu.%06lu] [%5lu] " message, _time / 1'000'000'000, _time / 1'000 % 1'000'000, _tid, ##__VA_ARGS__); \
} while (0)
+4 -3
View File
@@ -1,12 +1,13 @@
#pragma once
#include <zinnia/atomic.h>
#include <zinnia/utils.h>
#include <stdatomic.h>
#include <stddef.h>
struct refcount {
atomic(size_t) count;
_Atomic(size_t) count;
};
void refcount_init(struct refcount* rc);
void refcount_inc(struct refcount* rc);
void refcount_dec(struct refcount* rc);
bool refcount_dec(struct refcount* rc);
-1
View File
@@ -1,6 +1,5 @@
#pragma once
#include <zinnia/atomic.h>
#include <zinnia/errno.h>
#include <zinnia/init.h>
#include <zinnia/tailq.h>
+3 -2
View File
@@ -1,12 +1,13 @@
#pragma once
#include <stdatomic.h>
#include <stdint.h>
// Busy-waits in a loop until the lock is freed.
// Does not put the CPU to sleep.
struct spinlock {
uint32_t owner;
uint32_t next;
_Atomic(uint32_t) owner;
_Atomic(uint32_t) next;
};
// Attempts to lock a spinlock. If it's already locked, waits until it's freed.
+2 -2
View File
@@ -1,11 +1,11 @@
#ifndef SYSCALL_DECLARE
#define SYSCALL_DECLARE(number, name, num_args) extern void sys_##name();
#define SYSCALL_DECLARE(number, name, num_args) extern void sys_##name(...);
#endif
// SYSCALL_DECLARE(0, exit, -1)
// SYSCALL_DECLARE(1, syslog, -1)
SYSCALL_DECLARE(2, getuname, 1)
// SYSCALL_DECLARE(3, setuname, -1)
SYSCALL_DECLARE(3, setuname, 1)
SYSCALL_DECLARE(4, archctl, 2)
// SYSCALL_DECLARE(5, reboot, -1)
// SYSCALL_DECLARE(6, mmap, -1)
+17 -17
View File
@@ -34,27 +34,30 @@
// Internal: grow to at least `needed` capacity.
#define _vec_grow(vec, needed) \
do { \
({ \
errno_t _grow_status = 0; \
size_t _new_cap = (vec)->capacity == 0 ? 8 : (vec)->capacity; \
while (_new_cap < (needed)) \
_new_cap *= 2; \
typeof((vec)->data) _new = mem_alloc(_new_cap * sizeof(*(vec)->data), ALLOC_NOZERO); \
if (_new != nullptr && (vec)->length > 0) \
memcpy(_new, (vec)->data, (vec)->length * sizeof(*(vec)->data)); \
mem_free((vec)->data); \
(vec)->data = _new; \
(vec)->capacity = _new_cap; \
} while (0)
if (_new == nullptr) { \
_grow_status = ENOMEM; \
} else { \
if ((vec)->length > 0) \
memcpy(_new, (vec)->data, (vec)->length * sizeof(*(vec)->data)); \
mem_free((vec)->data); \
(vec)->data = _new; \
(vec)->capacity = _new_cap; \
} \
_grow_status; \
})
// Append an element. Returns 0 or ENOMEM.
#define vec_push(vec, val) \
({ \
errno_t _status = 0; \
if ((vec)->length >= (vec)->capacity) { \
_vec_grow(vec, (vec)->length + 1); \
if ((vec)->data == nullptr) \
_status = ENOMEM; \
} \
if ((vec)->length >= (vec)->capacity) \
_status = _vec_grow(vec, (vec)->length + 1); \
if (_status == 0) \
(vec)->data[(vec)->length++] = (val); \
_status; \
@@ -68,11 +71,8 @@
({ \
errno_t _status = 0; \
size_t _idx = (i); \
if ((vec)->length >= (vec)->capacity) { \
_vec_grow(vec, (vec)->length + 1); \
if ((vec)->data == nullptr) \
_status = ENOMEM; \
} \
if ((vec)->length >= (vec)->capacity) \
_status = _vec_grow(vec, (vec)->length + 1); \
if (_status == 0) { \
memmove(&(vec)->data[_idx + 1], &(vec)->data[_idx], ((vec)->length - _idx) * sizeof(*(vec)->data)); \
(vec)->data[_idx] = (val); \
+17 -4
View File
@@ -4,12 +4,25 @@
#include <zinnia/mman.h>
#include <zinnia/mutex.h>
#include <zinnia/pmap.h>
#include <zinnia/spin.h>
#include <zinnia/tailq.h>
#include <zinnia/vmo.h>
struct vma_mapping {
size_t start_page;
size_t end_page;
size_t offset_page;
struct vmo* object;
enum prot_flags prot;
tailq_link(struct vma_mapping) link;
};
// Virtual address space.
struct vma {
// Architecture-specific virtual memory map implementation.
struct pmap pmap;
tailq_head(struct vma_mapping) mappings;
struct spinlock lock;
};
// Try to create a new, empty virtual address space.
@@ -36,10 +49,10 @@ errno_t vma_protect(struct vma* v, uintptr_t vaddr, size_t size, enum prot_flags
struct vma_fault_info {
uintptr_t ip;
uintptr_t addr;
bool caused_by_user;
bool caused_by_write;
bool caused_by_fetch;
bool page_was_present;
bool caused_by_user:1;
bool caused_by_write:1;
bool caused_by_fetch:1;
bool page_was_present:1;
};
// Try to handle a page fault.
+6
View File
@@ -2,15 +2,21 @@
#include <zinnia/errno.h>
#include <zinnia/list.h>
#include <zinnia/refcount.h>
#include <zinnia/spin.h>
#include <zinnia/virt.h>
#include <stddef.h>
#include <stdint.h>
struct vmo {
struct refcount rc;
errno_t (*get_page)(struct vmo* vmo, uintptr_t offset_idx, struct page** out);
void (*destroy)(struct vmo* vmo);
};
void vmo_ref(struct vmo* obj);
void vmo_unref(struct vmo* obj);
errno_t vmo_read(struct vmo* obj, uintptr_t offset, void* buf, size_t len, size_t* actual_read);
errno_t vmo_write(struct vmo* obj, uintptr_t offset, const void* buf, size_t len, size_t* actual_written);
errno_t vmo_copy(
+3 -3
View File
@@ -1,14 +1,14 @@
#pragma once
#include <zinnia/atomic.h>
#include <zinnia/sched.h>
#include <zinnia/spin.h>
#include <zinnia/tailq.h>
#include <stdatomic.h>
// A queue of tasks waiting for an event.
struct waitq {
tailq_head(atomic(struct task)) waiters;
atomic(bool) woken;
tailq_head(_Atomic(struct task)) waiters;
_Atomic(bool) woken;
};
void waitq_init(struct waitq* wq);