diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2022-05-29 01:07:48 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2022-05-29 01:07:48 +0300 |
| commit | 0f4a751e60a6c8ac40592ff44c74f1c9e4846d9a (patch) | |
| tree | 96fb1e8479261a128f065ee493ee3a97a3b91949 | |
| parent | 013a27aec9370221e8afae188a8ed08ed2d406b0 (diff) | |
| download | kmi-0f4a751e60a6c8ac40592ff44c74f1c9e4846d9a.tar.gz kmi-0f4a751e60a6c8ac40592ff44c74f1c9e4846d9a.zip | |
continue documentation efforts.
| -rw-r--r-- | arch/riscv64/config.h | 53 | ||||
| -rw-r--r-- | arch/riscv64/gen/asm-offsets.c | 26 | ||||
| -rw-r--r-- | arch/riscv64/include/tcb.h | 8 | ||||
| -rw-r--r-- | arch/riscv64/init/init.c | 29 | ||||
| -rw-r--r-- | arch/riscv64/init/start.S | 1 | ||||
| -rw-r--r-- | arch/riscv64/kernel/irq.c | 12 | ||||
| -rw-r--r-- | common/tcb.c | 10 | ||||
| -rw-r--r-- | docs/boot.md | 11 | ||||
| -rw-r--r-- | docs/doxygen.conf | 4 | ||||
| -rw-r--r-- | include/apos/assert.h | 30 | ||||
| -rw-r--r-- | include/apos/atomic.h | 367 | ||||
| -rw-r--r-- | include/arch/cpu.h | 8 | ||||
| -rw-r--r-- | include/arch/irq.h | 12 | ||||
| -rw-r--r-- | include/arch/pmem.h | 41 | ||||
| -rw-r--r-- | uncrustify.conf | 3 |
15 files changed, 576 insertions, 39 deletions
diff --git a/arch/riscv64/config.h b/arch/riscv64/config.h index 33c84a0..bdf31ae 100644 --- a/arch/riscv64/config.h +++ b/arch/riscv64/config.h @@ -7,44 +7,74 @@ * and immutable parameters. Included on the command line by * -include. * + * Assume Sv39, probably wouldn't be too difficult to use runtime parameters + * instead. First 4K is reserved for NULL, but I suppose it could be mapped + * later if *absolutely* necessary. + * * @todo Consider separating user-specified and immutable parameters. + * @todo Write more thorough documentation, maybe a separate .md file? */ #include <apos/sizes.h> /* --- START ARCH USER CONFIG VALUES --- */ -/* physical address to which the kernel will be loaded */ +/** Physical address to where the OS image will be loaded. */ #define RAM_BASE 0x80000000 +/* --- END ARCH USER CONFIG VALUES --- */ + +/* don't touch >:( */ + +/** Physical address to where the kernel proper will be relocated. */ #define PM_KERN_BASE (RAM_BASE + SZ_512K) + +/** Maximum size of the kernel proper. Largely arbitrary. */ #define PM_KERN_SIZE (SZ_256K) + +/** Highest allowed physical address where kernel stuff may lie. */ #define PM_KERN_TOP (PM_KERN_BASE + PM_KERN_SIZE) -/* --- END ARCH USER CONFIG VALUES --- */ -/* don't touch >:( */ +/** Physical memory stack base. In this case, right after the kernel. */ +#define PM_STACK_BASE (PM_KERN_BASE + PM_KERN_SIZE) -#define PM_STACK_BASE (PM_KERN_BASE + SZ_256K) +/** Size of physical memory stack. */ #define PM_STACK_SIZE (SZ_256K) + +/** Top of physical memory stack. */ #define PM_STACK_TOP (PM_STACK_BASE + PM_STACK_SIZE) -#if __riscv_xlen == 64 +#if defined(riscv64) /* 64bit */ + +/** Direct map offset. */ #define VM_DMAP (0xffffffc000000000) /* testing for now */ + +/** Virtual address of kernel proper inside direct mapping. */ #define VM_KERN (VM_DMAP + SZ_256K) +/** Page reserved for kernel I/O. */ #define IO_PAGE 511UL + +/** Direct mapping starts from this page. */ #define KSTART_PAGE 256UL + +/** The RPC stack page. */ #define CSTACK_PAGE 255UL -/* assume Sv39, probably wouldn't be too difficult to use runtime parameters - * instead. First 4K is reserved for NULL, but I suppose it could be mapped - * later if *absolutely* necessary. */ +/** User virtual memory space start. */ #define UVMEM_START (SZ_4K) + +/** User virtual memory space end. */ #define UVMEM_END (SZ_256G - SZ_1G) -#define PROC_STACK_TOP (SZ_256G) -#define PROC_STACK_BASE (SZ_256G - SZ_1G) +/** RPC stack top. */ +#define RPC_STACK_TOP (SZ_256G) + +/** RPC stack base. */ +#define RPC_STACK_BASE (SZ_256G - SZ_1G) + #else /* 32bit */ + /* TODO: figure this stuff out */ #define VM_DMAP (0x000000000) #define VM_KERN (VM_DMAP + SZ_256K) @@ -55,9 +85,6 @@ #define KSTART_PAGE 512UL #define CSTACK_PAGE 511UL -/* assume Sv39, probably wouldn't be too difficult to use runtime parameters - * instead. First 4K is reserved for NULL, but I suppose it could be mapped - * later if *absolutely* necessary. */ #define UVMEM_START (SZ_4K) #define UVMEM_END (SZ_4G - SZ_8M) diff --git a/arch/riscv64/gen/asm-offsets.c b/arch/riscv64/gen/asm-offsets.c index fbe2726..71a1c9a 100644 --- a/arch/riscv64/gen/asm-offsets.c +++ b/arch/riscv64/gen/asm-offsets.c @@ -7,12 +7,36 @@ #include <apos/utils.h> #include "../kernel/regs.h" -/* largely based on linux */ +/** + * Insert assembly comment with calculated value. + * Largely based on linux + * + * @param sym Name of symbol. + * @param val Value of symbol. + */ #define DEFINE(sym, val) \ __asm__ volatile ("\n#-> " #sym " %0 " #val "\n" : : "i" (val)) + +/** + * Insert offset of member in structure. + * + * @param m Member. + * @param s Structure. + */ #define OFFSETOF(m, s) DEFINE(offsetof_##m, offsetof(s, m)) + +/** + * Insert size of structure. + * + * @param n Name of structure. + * @param s Structure. + */ #define SIZEOF(n, s) DEFINE(sizeof_##n, sizeof(s)) +/** + * Generate assembly with calculated offsets and sizes. + * See arch/riscv64/gen/source.mk for how the assembly is used. + */ void asm_offsets() { OFFSETOF(ra, struct riscv_regs); diff --git a/arch/riscv64/include/tcb.h b/arch/riscv64/include/tcb.h index be6d58a..8cd32ed 100644 --- a/arch/riscv64/include/tcb.h +++ b/arch/riscv64/include/tcb.h @@ -6,9 +6,13 @@ * riscv64 definitions of arch-specific tcb data. */ +/** + * riscv-specific thread handling stuff. + * + * Empty for now, but should probably be filled with stuff like register + * saving of something + */ struct arch_tcbd { - /* empty for now, but should probably be filled with stuff like register - * saving of something */ }; #endif /* ARCH_RISCV_TCB_H */ diff --git a/arch/riscv64/init/init.c b/arch/riscv64/init/init.c index 5fe463a..db428dd 100644 --- a/arch/riscv64/init/init.c +++ b/arch/riscv64/init/init.c @@ -11,13 +11,22 @@ #include <arch/vmem.h> #include "../kernel/csr.h" -/* assume 64 bit for now */ +/** Temporary virtual memory space. + * Assume 64bit riscv for now. + */ struct vmem *root_branch; +/** + * Create page table entry. + * Copy from \ref arch/riscv64/kernel/vmem.c. + * + * @param a Virtual address. + * @param f PTE flags. + */ #define to_pte(a, f) (((a) >> 12) << 10 | (f)) -/* assume Sv39 for now */ -void init_bootmem() +/** Jump into virtual memory. */ +static void init_bootmem() { size_t flags = VM_V | VM_X | VM_R | VM_W; @@ -41,7 +50,8 @@ void init_bootmem() csr_write(CSR_SATP, SATP_MODE_Sv39 | ((uintptr_t)root_branch >> 12)); } -void move_kernel() +/** Relocate kernel proper. */ +static void move_kernel() { extern char *__init_end; extern char *__kernel_size; @@ -53,6 +63,12 @@ void move_kernel() dst[i] = src[i]; } +/** + * Convert an existing physical address in a register to a virtual address. + * There is probably an easier way to do this, but this seems to work alright. + * + * @param reg Register to modify. + */ #define __va_reg(reg) \ { \ vm_t reg = 0; \ @@ -61,6 +77,11 @@ void move_kernel() __asm__ ("mv " QUOTE(reg) ", %0" ::"rK" (reg) :); \ } +/** + * Main driver for the init loader. + * + * @param fdt Global FDT pointer, provided by bootloader. + */ void init(void *fdt) { extern char *__init_end; diff --git a/arch/riscv64/init/start.S b/arch/riscv64/init/start.S index 7842946..f5ed2fe 100644 --- a/arch/riscv64/init/start.S +++ b/arch/riscv64/init/start.S @@ -1,5 +1,6 @@ .section .init.start .global _start +/* Entry point to the kernel loader. */ _start: li sp, PM_STACK_TOP call init diff --git a/arch/riscv64/kernel/irq.c b/arch/riscv64/kernel/irq.c index 15fa750..6fdfe85 100644 --- a/arch/riscv64/kernel/irq.c +++ b/arch/riscv64/kernel/irq.c @@ -8,7 +8,13 @@ #include <arch/irq.h> #include "csr.h" -extern void handle_irq(void); +/** Defined in arch/riscv64/kernel/entry.S. */ +extern void handle_irq(); + +/** Called from arch/riscv64/kernel/entry.S. */ +void handle_sys_irq() +{ +} void init_irq(void *fdt) { @@ -20,10 +26,6 @@ void init_irq(void *fdt) info("CSR_SIE: %lx\n", s); } -void handle_sys_irq() -{ -} - /* very simple for now */ void enable_irq() { diff --git a/common/tcb.c b/common/tcb.c index 84218dc..1382f67 100644 --- a/common/tcb.c +++ b/common/tcb.c @@ -56,7 +56,7 @@ static id_t __alloc_tid(struct tcb *t) } /* TODO: add error checking */ -static vm_t __setup_call_stack(struct tcb *t, size_t bytes) +static vm_t __setup_rpc_stack(struct tcb *t, size_t bytes) { pm_t offset = 0; size_t pages = __pages(bytes); @@ -64,11 +64,11 @@ static vm_t __setup_call_stack(struct tcb *t, size_t bytes) for (size_t i = 1; i <= pages; ++i) { offset = alloc_page(BASE_PAGE, offset); map_vpage(t->proc.vmem, offset, - PROC_STACK_TOP - BASE_PAGE_SIZE * i, + RPC_STACK_TOP - BASE_PAGE_SIZE * i, flags, BASE_PAGE); } - return PROC_STACK_TOP - BASE_PAGE_SIZE * pages; + return RPC_STACK_TOP - BASE_PAGE_SIZE * pages; } static vm_t __setup_thread_stack(struct tcb *t, size_t bytes) @@ -85,9 +85,9 @@ stat_t alloc_stacks(struct tcb *t) if (!t->thread_stack) return ERR_OOMEM; - /* call stack always starts at the same place in vmem. + /* rpc stack always starts at the same place in vmem. * TODO: is this a security issue? */ - if (!__setup_call_stack(p, __call_stack_size)) + if (!__setup_rpc_stack(p, __call_stack_size)) return ERR_OOMEM; /* TODO: this only allows for a global stack size, what if a user wants diff --git a/docs/boot.md b/docs/boot.md new file mode 100644 index 0000000..2131d93 --- /dev/null +++ b/docs/boot.md @@ -0,0 +1,11 @@ +I need to figure out how to write MarkDown files, but the general procedure of a +boot is that we + +1) Assume we start of in real memory mode, i.e. no MMU active. + +2) arch/whatever/init/init.c kickstarts us into virtual memory with a direct +mapping, with offset VM_DMAP aliasing to physical address 0. + +3) The kernel proper is moved to its correct location in this direct mapping. + +4) The kernel proper is jumped to, after which the kernel does whatever. diff --git a/docs/doxygen.conf b/docs/doxygen.conf index d113ff4..32f764f 100644 --- a/docs/doxygen.conf +++ b/docs/doxygen.conf @@ -2214,7 +2214,7 @@ ENABLE_PREPROCESSING = YES # The default value is: NO. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -MACRO_EXPANSION = NO +MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then # the macro expansion is limited to the macros specified with the PREDEFINED and @@ -2254,7 +2254,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = DEBUG +PREDEFINED = DEBUG __GNUC__ riscv64 riscv32 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The diff --git a/include/apos/assert.h b/include/apos/assert.h index 3255481..97523c7 100644 --- a/include/apos/assert.h +++ b/include/apos/assert.h @@ -20,6 +20,12 @@ /* TODO: should this exit or do something explosive like that? */ #if !defined(DNDEBUG) + +/** + * The kernel is in an irrepairable state, just give up. + * + * @param x Condition to check for. + */ #define catastrophic_assert(x) \ do { \ if (unlikely(!(x))) { \ @@ -29,6 +35,15 @@ } \ } while (0); +/** + * The function cannot continue without this assertion, but doesn't necessarily + * mean that the kernel is borked. + * + * @warning Implicit return. + * + * @param x Condition to check for. + * @param r Return value on failed check. + */ #define hard_assert(x, r) \ { \ if (unlikely(!(x))) { \ @@ -37,6 +52,11 @@ } \ } +/** + * Unexpected case, but not likely to cause problems, likely a bug. + * + * @param x Condition to check for. + */ #define soft_assert(x) \ do { \ if (unlikely(!(x))) { \ @@ -49,8 +69,14 @@ #define soft_assert(x) #endif -/* use when return value doesn't exist, like hard_assert(x, - * RETURN_VOID); */ +/** + * Use when return value doesn't exist. + * + * Example: + * @code{.c} + * void func() { hard_assert(x, RETURN_VOID); } + * @endcode + */ #define RETURN_VOID #endif /* APOS_ASSERT_H */ diff --git a/include/apos/atomic.h b/include/apos/atomic.h index a4292d6..d8d5368 100644 --- a/include/apos/atomic.h +++ b/include/apos/atomic.h @@ -4,80 +4,218 @@ /** * @file atomic.h * Atomics, closely modeled after C17 stdatomic.h. Largely dependent on the - * compiler at the moment. + * compiler at the moment, if I run into an architecture that required the OS' + * help to implement these I'll have to look into how to do that, but for now + * this is probably good enough. */ #include <apos/utils.h> /* GLUE */ +/** + * Memory ordering modes. + * + * @remark Look up details somewhere elsewhere, as I'm not an expert on memory ordering. + * Would like to be, though. + */ typedef enum { + /** Relaxed memory ordering. */ memory_order_relaxed = __ATOMIC_RELAXED, + /** Consume memory ordering. */ memory_order_consume = __ATOMIC_CONSUME, + /** Acquire memory ordering. */ memory_order_acquire = __ATOMIC_ACQUIRE, + /** Release memory ordering. */ memory_order_release = __ATOMIC_RELEASE, + /** Acquire and release memory ordering. */ memory_order_acq_rel = __ATOMIC_ACQ_REL, + /** Sequential memory ordering. */ memory_order_seq_cst = __ATOMIC_SEQ_CST } memory_order; +/** Atomic boolean. */ typedef _Atomic _Bool atomic_bool; + +/** Atomic char. */ typedef _Atomic char atomic_char; + +/** Atomic signed char. */ typedef _Atomic signed char atomic_schar; + +/** Atomic unsigned char. */ typedef _Atomic unsigned char atomic_uchar; + +/** Atomic signed short. */ typedef _Atomic short atomic_short; + +/** Atomic unsigned short. */ typedef _Atomic unsigned short atomic_ushort; + +/** Atomic signed int. */ typedef _Atomic int atomic_int; + +/** Atomic unsigned int. */ typedef _Atomic unsigned int atomic_uint; + +/** Atomic signed long. */ typedef _Atomic long atomic_long; + +/** Atomic unsigned long. */ typedef _Atomic unsigned long atomic_ulong; + +/** Atomic signed long long. */ typedef _Atomic long long atomic_llong; + +/** Atomic unsigned long long. */ typedef _Atomic unsigned long long atomic_ullong; + +/** Atomic 16bit char. */ typedef _Atomic __CHAR16_TYPE__ atomic_char16_t; + +/** Atomic 32bit char. */ typedef _Atomic __CHAR32_TYPE__ atomic_char32_t; + +/** Atomic \ref wchar_t. */ typedef _Atomic __WCHAR_TYPE__ atomic_wchar_t; + +/** Atomic \ref int_least8_t. */ typedef _Atomic __INT_LEAST8_TYPE__ atomic_int_least8_t; + +/** Atomic \ref uint_least8_t. */ typedef _Atomic __UINT_LEAST8_TYPE__ atomic_uint_least8_t; + +/** Atomic \ref int_least16_t. */ typedef _Atomic __INT_LEAST16_TYPE__ atomic_int_least16_t; + +/** Atomic \ref uint_least16_t. */ typedef _Atomic __UINT_LEAST16_TYPE__ atomic_uint_least16_t; + +/** Atomic \ref int_least32_t. */ typedef _Atomic __INT_LEAST32_TYPE__ atomic_int_least32_t; + +/** Atomic \ref uint_least32_t. */ typedef _Atomic __UINT_LEAST32_TYPE__ atomic_uint_least32_t; + +/** Atomic \ref int_least64_t. */ typedef _Atomic __INT_LEAST64_TYPE__ atomic_int_least64_t; + +/** Atomic \ref uint_least64_t. */ typedef _Atomic __UINT_LEAST64_TYPE__ atomic_uint_least64_t; + +/** Atomic \ref int_fast8_t. */ typedef _Atomic __INT_FAST8_TYPE__ atomic_int_fast8_t; + +/** Atomic \ref uint_fast8_t. */ typedef _Atomic __UINT_FAST8_TYPE__ atomic_uint_fast8_t; + +/** Atomic \ref int_fast16_t. */ typedef _Atomic __INT_FAST16_TYPE__ atomic_int_fast16_t; + +/** Atomic \ref uint_fast16_t. */ typedef _Atomic __UINT_FAST16_TYPE__ atomic_uint_fast16_t; + +/** Atomic \ref int_fast32_t. */ typedef _Atomic __INT_FAST32_TYPE__ atomic_int_fast32_t; + +/** Atomic \ref uint_fast32_t. */ typedef _Atomic __UINT_FAST32_TYPE__ atomic_uint_fast32_t; + +/** Atomic \ref int_fast64_t. */ typedef _Atomic __INT_FAST64_TYPE__ atomic_int_fast64_t; + +/** Atomic \ref uint_fast64_t. */ typedef _Atomic __UINT_FAST64_TYPE__ atomic_uint_fast64_t; + +/** Atomic \ref intptr_t. */ typedef _Atomic __INTPTR_TYPE__ atomic_intptr_t; + +/** Atomic \ref uintptr_t. */ typedef _Atomic __UINTPTR_TYPE__ atomic_uintptr_t; + +/** Atomic \ref size_t. */ typedef _Atomic __SIZE_TYPE__ atomic_size_t; + +/** Atomic \ref ptrdiff_t. */ typedef _Atomic __PTRDIFF_TYPE__ atomic_ptrdiff_t; + +/** Atomic \ref intmax_t. */ typedef _Atomic __INTMAX_TYPE__ atomic_intmax_t; + +/** Atomic \ref uintmax_t. */ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t; +/** + * Atomic variable initialization. Can safely be ignored. + * + * @param VALUE Value to be used in initialization. + * @return \c VALUE + */ #define ATOMIC_VAR_INIT(VALUE) (VALUE) + +/** + * Atomic pointer initialization. + * + * @param PTR Pointer to where value should be stored. + * @param VAL Value to store. + */ #define atomic_init(PTR, VAL) atomic_store_explicit(PTR, VAL, __ATOMIC_RELAXED) +/** + * Kill dependency. + * @todo Figure out what it means. + * + * @param y Value whose dependencies should be killed. + * @return \c y + */ #define kill_dependency(y) (y) +/** + * Check if given type is lock free. + * + * @param x Type to check. + * @return \c 0 if never lock free, \c 1 if sometimes lock free, \c 2 if always lock + * free. + */ #if defined(__GNUC__) #define CMPLR_LOCK_FREE(x) GLUE(__GCC_ATOMIC_, x)##_LOCK_FREE #elif defined(__clang__) #define CMPLR_LOCK_FREE(x) GLUE(__CLANG_ATOMIC_, x)##_LOCK_FREE #endif +/** Whether \ref atomic_bool is lock free. \see CMPLR_LOCK_FREE(). */ #define ATOMIC_BOOL_LOCK_FREE CMPLR_LOCK_FREE(BOOL) + +/** Whether \ref atomic_char is lock free. \see CMPLR_LOCK_FREE(). */ #define ATOMIC_CHAR_LOCK_FREE CMPLR_LOCK_FREE(CHAR) + +/** Whether \ref atomic_char16_t is lock free. \see CMPLR_LOCK_FREE(). */ #define ATOMIC_CHAR16_T_LOCK_FREE CMPLR_LOCK_FREE(CHAR16_T) + +/** Whether \ref atomic_char32_t is lock free. \see CMPLR_LOCK_FREE(). */ #define ATOMIC_CHAR32_T_LOCK_FREE CMPLR_LOCK_FREE(CHAR32_T) + +/** Whether \ref atomic_wchar_t is lock free. \see CMPLR_LOCK_FREE(). */ #define ATOMIC_WCHAR_T_LOCK_FREE CMPLR_LOCK_FREE(WCHAR32_T) + +/** Whether \ref atomic_short is lock free. \see CMPLR_LOCK_FREE(). */ #define ATOMIC_SHORT_LOCK_FREE CMPLR_LOCK_FREE(SHORT) + +/** Whether \ref atomic_int is lock free. \see CMPLR_LOCK_FREE(). */ #define ATOMIC_INT_LOCK_FREE CMPLR_LOCK_FREE(INT) + +/** Whether \ref atomic_long is lock free. \see CMPLR_LOCK_FREE(). */ #define ATOMIC_LONG_LOCK_FREE CMPLR_LOCK_FREE(LONG) + +/** Whether \ref atomic_llong is lock free. \see CMPLR_LOCK_FREE(). */ #define ATOMIC_LLONG_LOCK_FREE CMPLR_LOCK_FREE(LLONG) + +/** Whether atomic pointers are lock free. \see CMPLR_LOCK_FREE(). */ #define ATOMIC_POINTER_LOCK_FREE CMPLR_LOCK_FREE(POINTER) +/** + * Helper macro for creating builtin symbols. + * + * @param x Base name of symbol. + */ #if defined(__GNUC__) #define C11_ATOMIC(x) GLUE(__atomic_, x) #elif defined(__clang__) @@ -91,37 +229,120 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t; * void atomic_signal_fence(memory_order); */ +/** + * Atomic thread fence. + * + * @param order Memory ordering. \see memory_order. + */ #define atomic_thread_fence(order) C11_ATOMIC(thread_fence)(order) + +/** + * Atomic signal fence. + * + * @param order Memory ordering. \see memory_order. + */ #define atomic_signal_fence(order) C11_ATOMIC(signal_fence)(order) +/** + * Whether object is lock free. + * + * @param obj Object to check. + * @return \ref true if the object is lock free, \ref false otherwise. + */ #if defined(__GNUC__) #define atomic_is_lock_free(obj) C11_ATOMIC(is_lock_free)(sizeof(*(obj)), (obj)) #elif defined(__clang__) #define atomic_is_lock_free(obj) C11_ATOMIC(is_lock_free)(sizeof(*(obj))) #endif +/** + * Helper macro for creating some more builtin symbols. + * GCC uses \c _n suffixes for functions for equivalent functions in Clang, and + * this macro automatically appends \c _n when needed. + * + * @param x Base name of symbol. + */ #if defined(__GNUC__) #define N_ATOMIC(x) GLUE(C11_ATOMIC(x), _n) #elif defined(__clang__) #define N_ATOMIC(x) C11_ATOMIC(x) #endif +/** + * Explicit memory ordering for atomic store. + * + * @param obj Pointer to store destination. + * @param val Value to be stored. + * @param mode Memory ordering. \see memory_order. + */ #define atomic_store_explicit(obj, val, mode) N_ATOMIC(store)(obj, val, mode) -#define atomic_store(obj, val) \ +/** + * Atomic memory store with implicit strongest memory ordering. + * + * @param obj Pointer to store destination. + * @param val Value to be stored. + */ +#define atomic_store(obj, val) \ atomic_store_explicit(obj, val, __ATOMIC_SEQ_CST); +/** + * Explicit memory ordering for atomic load. + * Type is deduced from \c obj. + * + * @param obj Pointer to load source. + * @param mode Memory ordering. \see memory_order. + * @return Value at \c obj. + */ #define atomic_load_explicit(obj, mode) N_ATOMIC(load)(obj, mode) -#define atomic_load(obj) atomic_load_explicit(obj, \ - ATOMIC_SEQ_CST) +/** + * Atomic memory load with implicit strongest memory ordering. + * Type is deduced from \c obj. + * + * @param obj Pointer to load source. + * @return Value at \c obj. + */ +#define atomic_load(obj) \ + atomic_load_explicit(obj, __ATOMIC_SEQ_CST) +/** + * Explicit memory ordering for atomic exchange. + * Type is deduced from \c obj. + * + * @param obj Pointer to exchange destination. + * @param val Value to be inserted at \c obj. + * @param mode Memory ordering. \see memory_order. + * @return Value at \c obj. + */ #define atomic_exchange_explicit(obj, val, mode) \ N_ATOMIC(exchange)(obj, val, mode) +/** + * Atomic memory exchange with implicit strongest memory ordering. + * Type is deduced from \c obj. + * + * @param obj Pointer to exchange destination. + * @param val Value to be inserted at \c obj. + * @return Value at \c obj. + */ #define atomic_exchange(obj, val) \ atomic_exchange_explicit(obj, val, __ATOMIC_SEQ_CST) +/** + * Explicit strong memory compare and exchange. + * If \c obj and \c val are equal, the contents of \c obj are replaced with \c + * des. Otherwise, the contents of \c des is replaced with the contents of \c + * obj. The exchange is not allowed to spuriously fail. + * Type is deduced from \c obj. + * + * @param obj Pointer to object to be compared. + * @param val Value to be compared against. + * @param des Value to be copied if \c obj and \c val equal. + * @param suc Memory ordering of succesful exchange. \see memory_order. + * @param fail Memory ordering of unsuccesful exchange. \see memory_order. + * @return \ref true if \c obj and \c val equal, \ref false otherwise. + */ #if defined(__GNUC__) #define atomic_compare_exchange_strong_explicit(obj, val, des, suc, fail) \ N_ATOMIC(compare_exchange)(obj, val, des, 0, suc, fail) @@ -130,10 +351,35 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t; N_ATOMIC(compare_exchange_strong)(obj, val, des, suc, fail) #endif +/** + * Strong memory compare and exchange with implicit strongest ordering. \see + * atomic_compare_exchange_strong_explicit(). + * Type is deduced from \c obj. + * + * @param obj Pointer to object to be compared. + * @param val Value to be compared agains. + * @param des Value to be copied if \c obj and \c val equal. + * @return \ref true if \c obj and \c val equal, \ref false otherwise. + */ #define atomic_compare_exchange_strong(obj, val, des) \ atomic_compare_exchange_strong_explicit( \ obj, val, des, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +/** + * Explicit weak memory compare and exchange. + * If \c obj and \c val are equal, the contents of \c obj are replaced with \c + * des. Otherwise, the contents of \c des is replaced with the contents of \c + * obj. The exchange is allowed to spuriously fail. + * Type is deduced from \c obj. + * + * @param obj Pointer to object. + * @param val Value to be compared against. + * @param des Value to be copied if \c obj and \c val equal. + * @param suc Memory ordering on succesful exchange. \see memory_order. + * @param fail Memory ordering on unsuccesful exchange. \see memory_order. + * @return \ref true if \c obj and \c val equal and exchange was succesful, \ref + * false otherwise. + */ #if defined(__GNUC__) #define atomic_compare_exchange_weak_explicit(obj, val, des, suc, fail) \ N_ATOMIC(compare_exchange)(obj, val, des, 1, suc, fail) @@ -142,43 +388,156 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t; N_ATOMIC(compare_exchange_weak)(obj, val, des, suc, fail) #endif +/** + * Weak memory compare and exchange with implicit strongest ordering. + * \see atomic_compare_exchange_weak_explicit(). + * Type is deduced from \c obj. + * + * @param obj Pointer to object. + * @param val Value to be compared against. + * @param des Value to be copied if \c obj and \c val equal. + * @return \ref true if \c obj and \c val equal and exchange was succesful, \ref + * false otherwise. + */ #define atomic_compare_exchange_weak(obj, val, des) \ atomic_compare_exchange_weak_explicit(obj, val, des, __ATOMIC_SEQ_CST, \ __ATOMIC_SEQ_CST) +/** + * Explicit atomic in-place addition. + * Type is deduced from \c obj. + * + * @param obj Pointer to object. + * @param val Value to be added to object. + * @param mode Memory ordering. \see memory_order. + * @return Contents of \c obj before addition. + */ #define atomic_fetch_add_explicit(obj, val, mode) \ C11_ATOMIC(fetch_add)(obj, val, mode) +/** + * Atomic in-place addition with implicit strongest memory ordering. + * Type is deduced from \c obj. + * + * @param obj Pointer to object. + * @param val Value to be added to object. + * @return Contents of \c obj before addition. + */ #define atomic_fetch_add(obj, val) \ atomic_fetch_add_explicit(obj, val, __ATOMIC_SEQ_CST) +/** + * Explicit atomic in-place subtraction. + * Type is deduced from \c obj. + * + * @param obj Pointer to object. + * @param val Value to be subtracted from object. + * @param mode Memory ordering. \see memory_order. + * @return Contents of \c obj before subtraction. + */ #define atomic_fetch_sub_explicit(obj, val, mode) \ C11_ATOMIC(fetch_sub)(obj, val, mode) +/** + * Atomic in-place subtraction with implicit strongest memory ordering. + * Type is deduced from \c obj. + * + * @param obj Pointer to object. + * @param val Value to be subtracted from object. + * @return Contents of \c obj before subtraction. + */ #define atomic_fetch_sub(obj, val) \ atomic_fetch_sub_explicit(obj, val, __ATOMIC_SEQ_CST) +/** + * Explicit atomic in-place bitwise \c AND. + * Type is deduced from \c obj. + * + * @param obj Pointer to object. + * @param val Value to bitwise \c AND with contents of object. + * @param mode Memory ordering. \see memory_order. + * @return Contents of \c obj before bitwise \c AND. + */ #define atomic_fetch_and_explicit(obj, val, mode) \ C11_ATOMIC(fetch_and)(obj, val, mode) +/** + * Atomic in-place bitwise \c AND with implicit strongest memory ordering. + * Type is deduced from \c obj. + * + * @param obj Pointer to object. + * @param val Value to bitwise \c AND with contents of object. + * @return Contents of \c obj before bitwise \c AND. + */ #define atomic_fetch_and(obj, val) \ atomic_fetch_and_explicit(obj, val, __ATOMIC_SEQ_CST) +/** + * Explicit atomic in-place bitwise \c XOR. + * Type is deduced from \c obj. + * + * @param obj Pointer to object. + * @param val Value to bitwise \c XOR with contents of object. + * @param mode Memory ordering. \see memory_order. + * @return Contents of \c obj before bitwise \c XOR. + */ #define atomic_fetch_xor_explicit(obj, val, mode) \ C11_ATOMIC(fetch_xor)(obj, val, mode) +/** + * Atomic in-place bitwise \c XOR with implicit strongest memory ordering. + * Type is deduced from \c obj. + * + * @param obj Pointer to object. + * @param val Value to bitwise \c XOR with contents of object. + * @return Contents of \c obj before bitwise \c XOR. + */ #define atomic_fetch_xor(obj, val) \ atomic_fetch_xor_explicit(obj, val, __ATOMIC_SEQ_CST) +/** + * Explicit atomic in-place bitwise \c OR. + * Type is deduced from \c obj. + * + * @param obj Pointer to object. + * @param val Value to bitwise \c OR with contents of object. + * @param mode Memory ordering. \see memory_order. + * @return Contents of \c obj before bitwise \c OR. + */ #define atomic_fetch_or_explicit(obj, val, mode) \ C11_ATOMIC(fetch_or)(obj, val, mode) +/** + * Atomic in-place bitwise \c OR with implicit strongest memory ordering. + * Type is deduced from \c obj. + * + * @param obj Pointer to object. + * @param val Value to bitwise \c OR with contents of object. + * @return Contents of \c obj before bitwise \c OR. + */ #define atomic_fetch_or(obj, val) \ atomic_fetch_or_explicit(obj, val, __ATOMIC_SEQ_CST) +/** + * Explicit atomic in-place bitwise \c NAND. + * Type is deduced from \c obj. + * + * @param obj Pointer to object. + * @param val Value to bitwise \c OR with contents of object. + * @param mode Memory ordering. \see memory_order. + * @return Contents of \c obj before bitwise \c NAND. + */ #define atomic_fetch_nand_explicit(obj, val, mode) \ C11_ATOMIC(fetch_nand)(obj, val, mode) +/** + * Atomic in-place bitwise \c NAND with implicit strongest memory ordering. + * Type is deduced from \c obj. + * + * @param obj Pointer to object. + * @param val Value to bitwise \c NAND with contents of object. + * @return Contents of \c obj before bitwise \c NAND. + */ #define atomic_fetch_nand(obj, val) \ atomic_fetch_nand_explicit(obj, val, __ATOMIC_SEQ_CST) diff --git a/include/arch/cpu.h b/include/arch/cpu.h index 23b2911..763ebba 100644 --- a/include/arch/cpu.h +++ b/include/arch/cpu.h @@ -15,7 +15,15 @@ #include "../../arch/riscv32/include/cpu.h" #endif +/** + * Get current CPU ID. + * ID must be in range \c 0 .. \c num_cpus, where \c num_cpus is the number of + * cpus on this system. + * + * @return Current CPU ID. + */ id_t cpu_id(); + /* TODO: add more cpu handling functions */ #endif /* APOS_CPU_H */ diff --git a/include/arch/irq.h b/include/arch/irq.h index 5526b18..7c6a365 100644 --- a/include/arch/irq.h +++ b/include/arch/irq.h @@ -5,6 +5,8 @@ * @file irq.h * Arch-specific interrupt handling, generally implemented in * arch/whatever/kernel/irq.c + * + * @todo These should probably also be stat_t... */ #if defined(riscv64) @@ -13,9 +15,17 @@ #include "../../arch/riscv32/include/irq.h" #endif +/** + * Initialize IRQ subsystem. + * + * @param fdt Global FDT pointer. + */ void init_irq(void *fdt); -void handle_irq(); + +/** Enable IRQs. */ void enable_irq(); + +/** Disable IRQs. */ void disable_irq(); #endif /* APOS_IRQ_H */ diff --git a/include/arch/pmem.h b/include/arch/pmem.h index c9423b2..21a721a 100644 --- a/include/arch/pmem.h +++ b/include/arch/pmem.h @@ -16,6 +16,47 @@ #include "../../arch/riscv32/include/pmem.h" #endif +/** + * Get physical memory parameters. + * + * The kernel assumes all virtual addresses can be represented approximately as + * follows: + * + * @code + * Content ... 0 1 1 0 0 1 0 1 0 + * ----------------------------- + * Index ... 9 8 7 6 5 4 3 2 1 + * --- --- --- +++++++ + * O2 O1 O0 Base + * @endcode + * + * Where \c Base is a portion of the address that is directly passed through + * without any lookups, and each \c O0, \c O1, \c O2 are increasingly higher + * order pages, where each order is an index into the higher order. + * + * For example, in the diagram above: + * The base page is four bits, and each page order consists of four pages of + * one order lower (two bits), and there are three orders, so + * @code + * max_order = 2 + * base_bits = 4 + * bits[0] = 2 + * bits[1] = 2 + * bits[2] = 2 + * bits[3] = 0 + * ... + * @endcode + * + * @todo Move documentation into its own .md + * + * @param fdt Global FDT pointer. + * @param max_order Highest order pages the arch supports. + * @param base_bits Size of base page as number of bits in bitmask. + * Eg. 12bits -> 4k page. + * @param bits Size in bits as bitmask of corresponding page order. Zeroed out + * beforehand. + * @return \ref OK when query succesful, arch specific otherwise. + */ stat_t stat_pmem_conf(void *fdt, size_t *max_order, size_t *base_bits, size_t bits[NUM_ORDERS]); diff --git a/uncrustify.conf b/uncrustify.conf index 8649f3e..7221de0 100644 --- a/uncrustify.conf +++ b/uncrustify.conf @@ -1,5 +1,8 @@ # Uncrustify-0.72.0_f +# TODO: add slightly more strict rules, there are a few too many 'ignore' +# directives for my liking. + # # General options # |
