foo
This commit is contained in:
+1
-1
@@ -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
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
@@ -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
@@ -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); \
|
||||
|
||||
@@ -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
@@ -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,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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <zinnia/atomic.h>
|
||||
#include <zinnia/errno.h>
|
||||
#include <zinnia/init.h>
|
||||
#include <zinnia/tailq.h>
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user