diff options
| -rw-r--r-- | common/dmem.c | 30 | ||||
| -rw-r--r-- | common/elf.c | 40 | ||||
| -rw-r--r-- | common/main.c | 9 | ||||
| -rw-r--r-- | common/mem_nodes.c | 1 | ||||
| -rw-r--r-- | common/mem_regions.c | 77 | ||||
| -rw-r--r-- | common/nodes.c | 35 | ||||
| -rw-r--r-- | common/tcb.c | 64 | ||||
| -rw-r--r-- | common/timer.c | 43 | ||||
| -rw-r--r-- | common/uapi/conf.c | 24 | ||||
| -rw-r--r-- | common/uapi/dispatch.c | 6 | ||||
| -rw-r--r-- | common/uapi/ipc.c | 34 | ||||
| -rw-r--r-- | common/uapi/mem.c | 83 | ||||
| -rw-r--r-- | common/uapi/proc.c | 41 | ||||
| -rw-r--r-- | common/uapi/timers.c | 58 | ||||
| -rw-r--r-- | common/vmem.c | 12 | ||||
| -rw-r--r-- | include/apos/debug.h | 2 | ||||
| -rw-r--r-- | include/apos/uapi.h | 8 | ||||
| -rw-r--r-- | lib/fdt_dbg.c | 28 |
18 files changed, 559 insertions, 36 deletions
diff --git a/common/dmem.c b/common/dmem.c index 88b06fd..98b58fd 100644 --- a/common/dmem.c +++ b/common/dmem.c @@ -11,8 +11,12 @@ #include <apos/assert.h> #include <apos/dmem.h> +/** Region before RAM. */ static struct mem_region_root pre_ram = { 0 }; + +/** Region after RAM. */ static struct mem_region_root post_ram = { 0 }; + pm_t __pre_base = 0; pm_t __pre_top = 0; pm_t __post_base = 0; @@ -37,6 +41,19 @@ stat_t init_devmem(pm_t ram_base, pm_t ram_top) return OK; } +/** + * Device virtual memory worker callback for \ref map_fill_region(). + * + * @param b Virtual memory to work in. + * @param offset Hint for \ref alloc_page(). + * @param vaddr Current virtual address. + * @param flags Flags of region. + * @param order Suggested page order. + * @param data Pointer to \ref stat_t. + * @return \see alloc_uvmem_wrapper(). + * + * \see alloc_uvmem_wrapper(). + */ static stat_t dev_alloc_wrapper(struct vmem *b, pm_t *offset, vm_t vaddr, vmflags_t flags, enum mm_order order, void *data) @@ -48,6 +65,19 @@ static stat_t dev_alloc_wrapper(struct vmem *b, pm_t *offset, vm_t vaddr, return OK; } +/** + * Device virtual memory freeing worker callback for \ref map_fill_region(). + * + * @param b Virtual memory to work in. + * @param offset Hint for \ref alloc_page(). + * @param vaddr Current virtual address. + * @param flags Flags of region. + * @param order Suggested page order. + * @param data Pointer to \ref stat_t. + * @return \see alloc_uvmem_wrapper(). + * + * \see alloc_uvmem_wrapper(). + */ static stat_t dev_free_wrapper(struct vmem *b, pm_t *offset, vm_t vaddr, vmflags_t flags, enum mm_order order, void *data) { diff --git a/common/elf.c b/common/elf.c index 977906f..fcd6e85 100644 --- a/common/elf.c +++ b/common/elf.c @@ -12,6 +12,12 @@ #include <apos/string.h> #include <apos/assert.h> +/** + * Convert ELF flags to page flags. + * + * @param elf_flags ELF flags to convert. + * @return Corresponding page flags. + */ static uint8_t __elf_to_uvflags(uint8_t elf_flags) { uint8_t uvflags = VM_V | VM_U; @@ -27,7 +33,16 @@ static uint8_t __elf_to_uvflags(uint8_t elf_flags) return uvflags; } -/* useful bit of info: all segments are sorted in ascending order of p_vaddr */ +/** + * Map ELF executable. + * + * @param t Thread space to work in. + * @param bin Address of binary to map. + * @param ei_c ELF identity class. + * @param phstart Program header start. + * @param phnum Number of program header entries. + * @param phsize Size of page header entry. + */ static void __map_exec(struct tcb *t, vm_t bin, uint8_t ei_c, vm_t phstart, size_t phnum, size_t phsize) { @@ -40,6 +55,7 @@ static void __map_exec(struct tcb *t, vm_t bin, uint8_t ei_c, vm_t phstart, /** \todo check if p_memsz is larger than p_filesz, the segment should be * filled with zeroes. */ /** \todo in general, make this a low more clean. */ + /* useful bit of info: all segments are sorted in ascending order of p_vaddr */ vm_t runner = phstart; vmflags_t default_flags = VM_V | VM_R | VM_W | VM_X | VM_U; for (size_t i = 0; i < phnum; ++i, runner += phsize) { @@ -74,6 +90,17 @@ static void __map_exec(struct tcb *t, vm_t bin, uint8_t ei_c, vm_t phstart, } } +/** + * Map ELF dynamic object. + * + * @param t Thread space to work in. + * @param bin Address of binary to map. + * @param ei_c ELF identity class. + * @param phstart Program header start. + * @param phnum Number of program header entries. + * @param phsize Size of page header entry. + * @return Base of dynamic mapping. + */ static vm_t __map_dyn(struct tcb *t, vm_t bin, uint8_t ei_c, vm_t phstart, size_t phnum, size_t phsize) { @@ -82,6 +109,17 @@ static vm_t __map_dyn(struct tcb *t, vm_t bin, uint8_t ei_c, vm_t phstart, * hacky, I know.*/ } +/** + * Map binary and optional interpreter. + * + * \todo Implement interpeter handling. + * + * @param t Thread space to work in. + * @param ei_c ELF identity class. (Of binary, should do one for interp?) + * @param elf ELF binary. + * @param interp ELF interpeter. + * @return Entry address. + */ static vm_t __prepare_proc(struct tcb *t, uint8_t ei_c, vm_t elf, vm_t interp) { short e_type = elf_header_prop(ei_c, elf, e_type); diff --git a/common/main.c b/common/main.c index fa5434c..fb5d26e 100644 --- a/common/main.c +++ b/common/main.c @@ -17,6 +17,15 @@ #include <arch/irq.h> #include <libfdt.h> +/** + * Boot entry of kernel actual. + * + * Sets up all kernel subsystems and jumps into \c init program, does not + * return. + * + * @param fdt Global FDT pointer. + * @return Should not. + */ void __main main(void *fdt) { /* dbg uses direct mapping at this point */ diff --git a/common/mem_nodes.c b/common/mem_nodes.c index ffa089f..918ee67 100644 --- a/common/mem_nodes.c +++ b/common/mem_nodes.c @@ -16,6 +16,7 @@ #include <apos/string.h> #include <apos/mem_nodes.h> +/** Memory node subsystem instance. */ static struct node_root root; void init_mem_nodes() diff --git a/common/mem_regions.c b/common/mem_regions.c index 3729caf..0101ac2 100644 --- a/common/mem_regions.c +++ b/common/mem_regions.c @@ -13,7 +13,18 @@ #include <apos/bits.h> #include <apos/mem.h> +/** + * Readability wrapper for marking region used. + * + * @param r Region flags to set. + */ #define mark_region_used(r) set_bit(r, MR_USED) + +/** + * Readability wrapper for marking region unused. + * + * @param r Region flags to clear. + */ #define mark_region_unused(r) clear_bit(r, MR_USED) /* pretty major slowdown when we get to some really massive numbers, not @@ -32,6 +43,14 @@ * maybe not even anything with sp_trees but more a weakness of binary trees in * general? */ + +/** + * Insert free memory region. + * + * @param r Memory region root to insert \c m into. + * @param m Free memory region to insert. + * @return \c m. + */ static struct mem_region *__insert_free_region(struct mem_region_root *r, struct mem_region *m) { @@ -76,6 +95,13 @@ static struct mem_region *__insert_free_region(struct mem_region_root *r, return m; } +/** + * Insert used memory region. + * + * @param r Memory region root to insert \c m into. + * @param m Memory region to insert. + * @return \c m. + */ static struct mem_region *__insert_used_region(struct mem_region_root *r, struct mem_region *m) { @@ -124,6 +150,11 @@ stat_t init_region(struct mem_region_root *r, vm_t start, size_t arena_size) return OK; } +/** + * Destroy memory region and all its children. + * + * @param n \ref sp_node of memory region to destroy. + */ static void __destroy_region(struct sp_node *n) { if (!n) @@ -169,6 +200,15 @@ struct mem_region *find_used_region(struct mem_region_root *r, vm_t start) return 0; } +/** + * Create memory region. + * + * @param start Start of region. + * @param end End of region. + * @param prev Previous region. + * @param next Next region. + * @return Created region. + */ static struct mem_region *__create_region(vm_t start, vm_t end, struct mem_region *prev, struct mem_region *next) @@ -181,8 +221,12 @@ static struct mem_region *__create_region(vm_t start, vm_t end, return m; } -/** \todo should probably check if this actually works :D seems to do, but that's - * just from really quick checking */ +/** + * Get first order size smaller than \c s in bytes. + * + * @param s Size to look for. + * @return Size of first order smaller than \c s. + */ static size_t po_align(size_t s) { for (size_t o = __mm_max_order; o > 0; --o) { @@ -270,6 +314,17 @@ struct mem_region *find_first_region(struct mem_region_root *r) return m; } +/** + * Carve out new used memory region from free memory region. + * + * @param r Memory region root to work in. + * @param m Free memory region to carve used memory region out of. + * @param pages Number of base order pages to give used region. + * @param align Alignment of used region. In this case, start of used region + * from start of free region. + * @param flags Flags of used region. + * @return Start address of used region. + */ static vm_t __partition_region(struct mem_region_root *r, struct mem_region *m, size_t pages, size_t align, vmflags_t flags) { @@ -368,6 +423,12 @@ vm_t alloc_fixed_region(struct mem_region_root *r, vm_t start, size_t size, return __partition_region(r, m, pages, start - m->start, flags); } +/** + * Try to coalesce two adjacent memory regions, iterating left. + * + * @param r Memory region root to work in. + * @param m Memory region to start trying to coalesce. + */ static void __try_coalesce_prev(struct mem_region_root *r, struct mem_region *m) { while (m) { @@ -391,6 +452,12 @@ static void __try_coalesce_prev(struct mem_region_root *r, struct mem_region *m) } } +/** + * Try to coalesce two adjacent memory region, iterating right. + * + * @param r Memory region root to work in. + * @param m Memory region to start trying to coalesce. + */ static void __try_coalesce_next(struct mem_region_root *r, struct mem_region *m) { while (m) { @@ -414,6 +481,12 @@ static void __try_coalesce_next(struct mem_region_root *r, struct mem_region *m) } } +/** + * Try coalescing memory regions. + * + * @param r Memory region root to work in. + * @param m Memory region to start trying to coalesce. + */ static void __try_coalesce_regions(struct mem_region_root *r, struct mem_region *m) { diff --git a/common/nodes.c b/common/nodes.c index ce33547..9cfd2a2 100644 --- a/common/nodes.c +++ b/common/nodes.c @@ -41,9 +41,20 @@ * being free) */ +/** + * Get start of node region from pointer. + * + * @param r Pointer to node inside node region. + * @return Corresponding node region. + */ #define node_region(r) \ ((struct node_region *)((uintptr_t)(r) & ~(BASE_PAGE_SIZE - 1))) +/** + * Create new node region. + * + * @return Pointer to created region. + */ static struct node_region *__create_region() { struct node_region *r = (struct node_region *)alloc_page(BASE_PAGE, 0); @@ -78,6 +89,13 @@ void destroy_nodes(struct node_root *r) } } +/** + * Find free node in node region. + * + * @param r Node root to work in. + * @param nr Node region to look in. + * @return Pointer to free node. + */ static void *__find_free_node(struct node_root *r, struct node_region *nr) { uint8_t *bitmap = r->bitmap + (uint8_t *)nr; @@ -92,6 +110,11 @@ static void *__find_free_node(struct node_root *r, struct node_region *nr) return 0; } +/** + * Pop free list head. + * + * @param r Node region root to work in. + */ static void __pop_av_head(struct node_root *r) { struct node_region *t = r->av_head; @@ -124,6 +147,12 @@ void *get_node(struct node_root *r) return p; } +/** + * Push free list head. + * + * @param r Node region root to work in. + * @param nr Node region to push. + */ static void __push_av_head(struct node_root *r, struct node_region *nr) { nr->av_prev = 0; @@ -134,6 +163,12 @@ static void __push_av_head(struct node_root *r, struct node_region *nr) r->av_head = nr; } +/** + * Free a node region. + * + * @param r Node region root to work in. + * @param nr Node region to free. + */ static void __free_region(struct node_root *r, struct node_region *nr) { struct node_region *av_n = nr->av_next; diff --git a/common/tcb.c b/common/tcb.c index c8260ff..119898f 100644 --- a/common/tcb.c +++ b/common/tcb.c @@ -19,13 +19,21 @@ #include <arch/vmem.h> /* arguably exessively many globals... */ +/** Thread ID to start looking from when allocating new ID. */ static id_t start_tid; + +/** Total number of possible thread IDs. */ static size_t num_tids; +/** Pointer to array of \ref tcb structures. Length of the array is \c num_tids.*/ static struct tcb **tcbs; -/* if we ever support systems with massive amounts of cpus, this should probably - * be allocated at runtime */ +/** + * Array of thread control block associated with each cpu. + * + * \todo If we ever support systems with massive amounts of cpus, this should probably + * be allocated at runtime. + */ static struct tcb *cpu_tcb[MAX_CPUS] = { 0 }; void init_tcbs() @@ -43,6 +51,12 @@ void destroy_tcbs() free_page(MM_O1, (pm_t)tcbs); } +/** + * Allocate a new thread ID. + * + * @param t Thread to allocate new ID to. + * @return Allocated ID. + */ static id_t __alloc_tid(struct tcb *t) { /** \todo this would need some locking or something... */ @@ -58,7 +72,17 @@ static id_t __alloc_tid(struct tcb *t) return ERR_NF; } -/** \todo add error checking */ +/** + * Setup RPC stack. + * + * RPC stack is local to each thread, and should not be visible to other threads + * in the same process. + * + * @param t Thread to setup RPC stack for. + * @param bytes Minimum size of RPC stack. + * @return Base of allocated RPC stack. + * + * \todo add error checking */ static vm_t __setup_rpc_stack(struct tcb *t, size_t bytes) { pm_t offset = 0; @@ -74,6 +98,13 @@ static vm_t __setup_rpc_stack(struct tcb *t, size_t bytes) return RPC_STACK_TOP - BASE_PAGE_SIZE * pages; } +/** + * Setup thread stack. + * + * @param t Thread to setup stack for. + * @param bytes Minimum size of stack. + * @return Base of allocated stack. + */ static vm_t __setup_thread_stack(struct tcb *t, size_t bytes) { return alloc_uvmem(t, bytes, VM_V | VM_R | VM_W | VM_U); @@ -132,6 +163,13 @@ struct tcb *create_thread(struct tcb *p) return t; } +/** + * Copy process, setting up COW. + * + * @param p Parent process. + * @param n New process. + * @return \ref OK. + */ static stat_t __copy_proc(struct tcb *p, struct tcb *n) { /** \todo Copy memory regions, and mark them MR_COW, as well as copy @@ -155,6 +193,12 @@ struct tcb *create_proc(struct tcb *p) return n; } +/** + * Destroy data associated with thread. + * + * @param t Thread whose data to destroy. + * @return \ref OK. + */ static stat_t __destroy_thread_data(struct tcb *t) { /* free rpc vmem */ @@ -195,6 +239,13 @@ stat_t destroy_proc(struct tcb *p) return __destroy_thread_data(p); } +/** + * Convenience marco for defining function to attach a thread to either process + * or RPC context. + * + * @param name name of function to define. + * @param type Field name of type \c tcb_ctx. + */ #define DEFINE_ATTACH(name, type) \ stat_t name(struct tcb *r, struct tcb *t) \ { \ @@ -212,6 +263,13 @@ stat_t destroy_proc(struct tcb *p) DEFINE_ATTACH(attach_rpc, rpc); DEFINE_ATTACH(attach_proc, proc); +/** + * Convenience marco for defining function to detach a thread from either process + * or RPC context. + * + * @param name name of function to define. + * @param type Field name of type \c tcb_ctx. + */ #define DEFINE_DETACH(name, type) \ stat_t name(struct tcb *r, struct tcb *t) \ { \ diff --git a/common/timer.c b/common/timer.c index aaaf62e..6dc1bce 100644 --- a/common/timer.c +++ b/common/timer.c @@ -24,19 +24,45 @@ #include <arch/timer.h> #include <arch/cpu.h> +/** Timer resolution. */ static ticks_t ticks_per_sec = 0; + +/** Array of timer maps for each cpu. */ static struct sp_root cpu_timers[MAX_CPUS] = { 0 }; + +/** Timer node subsystem instance. */ static struct node_root node_root; +/** Node in timer map. */ struct timer_node { + /** Sp tree node. */ struct sp_node sp_n; + + /** Corresponding timer. */ struct timer timer; }; +/** + * Get \ref timer_node from \ref sp_node. + * + * @param ptr \ref sp_node whose parent \ref timer_node to get. + * @return Corresponding \ref timer_node. + */ #define timer_container(ptr) container_of(ptr, struct timer_node, sp_n) +/** + * Get \ref timer_node from \ref timer. + * + * @param ptr \ref timer whose parent \ref timer_node to get. + * @return Corresponding \ref timer_node. + */ #define timer_node_container(ptr) container_of(ptr, struct timer_node, timer) +/** + * Get timer map of current cpu. + * + * @return Root of current cpu's timer map. + */ static struct sp_root *__cpu_timers() { return &cpu_timers[cpu_id()]; @@ -50,6 +76,15 @@ void init_timer(const void *fdt) init_nodes(&node_root, sizeof(struct timer_node)); } +/** + * Insert timer into current cpu's timer map. + * + * \note \c ti.cid might change during the insertion if there already is a node + * with identical \c cid to avoid collisions. Very unlikely though. + * + * @param ti Timer node to insert. + * @return \c cid of timer node. + */ static id_t __insert_timer(struct timer_node *ti) { struct sp_root *root = __cpu_timers(); @@ -88,7 +123,13 @@ static id_t __insert_timer(struct timer_node *ti) return ti->timer.cid; } -/* ticks is absolute */ +/** + * Create timer at absolute timepoint. + * + * @param tid Requesting thread ID. + * @param ticks Absolute timepoint. + * @return \c cid of created timer. + */ static id_t __new_timer(id_t tid, ticks_t ticks) { struct timer_node *ti = (struct timer_node *)get_node(&node_root); diff --git a/common/uapi/conf.c b/common/uapi/conf.c index 47a7a0f..470b81e 100644 --- a/common/uapi/conf.c +++ b/common/uapi/conf.c @@ -15,11 +15,28 @@ size_t __thread_stack_size = SZ_2M; size_t __call_stack_size = SZ_2M; +/** + * Configuration parameter read syscall handler. + * + * \todo Implement parameters. + * + * @param param Parameter to read. + * @return \ref OK and parameter value. + */ SYSCALL_DEFINE1(conf_get)(sys_arg_t param) { return (struct sys_ret){ OK, 0 }; } +/** + * Configuration parameter write syscall handler. + * + * \todo Implement parameters. + * + * @param param Parameter to write. + * @param val Value to set \c param to. + * @return \ref OK and \c 0. + */ SYSCALL_DEFINE2(conf_set)(sys_arg_t param, sys_arg_t val) { UNUSED(param); @@ -29,6 +46,13 @@ SYSCALL_DEFINE2(conf_set)(sys_arg_t param, sys_arg_t val) return (struct sys_ret){ OK, 0 }; } +/** + * Poweroff syscall handler. + * + * @param type Type of poweroff. + * @return \ref ERR_INVAL and \c 0 if incorrect poweroff \c type give, otherwise + * does not return. + */ SYSCALL_DEFINE1(poweroff)(sys_arg_t type) { switch (type) { diff --git a/common/uapi/dispatch.c b/common/uapi/dispatch.c index 52cf8d9..c2ddbcf 100644 --- a/common/uapi/dispatch.c +++ b/common/uapi/dispatch.c @@ -9,6 +9,7 @@ #include <apos/debug.h> #include <apos/uapi.h> +/** Syscall number to syscall handler conversion. */ static const sys_t syscall_table[] = { /* noop */ [SYS_NOOP] = sys_noop, @@ -43,6 +44,11 @@ static const sys_t syscall_table[] = { [SYS_POWEROFF] = sys_poweroff, }; +/** + * Noop syscall handler. + * + * @return \ref OK and \c 0. + */ SYSCALL_DEFINE0(noop)(){ info("sys_noop\n"); return (struct sys_ret){ OK, 0 }; diff --git a/common/uapi/ipc.c b/common/uapi/ipc.c index 8584673..4cdec0c 100644 --- a/common/uapi/ipc.c +++ b/common/uapi/ipc.c @@ -9,6 +9,13 @@ #include <apos/uapi.h> #include <apos/tcb.h> +/** + * IPC server notification syscall handler. + * + * @param callback Address of server callback. + * @return \ref ERR_EXT and \c 0 if process already is a server, + * \ref OK and \c 0 otherwise. + */ SYSCALL_DEFINE1(ipc_server)(sys_arg_t callback) { struct tcb *r = cur_tcb(); @@ -19,6 +26,14 @@ SYSCALL_DEFINE1(ipc_server)(sys_arg_t callback) return (struct sys_ret){ OK, 0 }; } +/** + * IPC request syscall handler. + * + * @param pid Process to request RPC to. + * @param d0 IPC argument 0. + * @param d1 IPC argument 1. + * @return \c d0 and \c d1. + */ SYSCALL_DEFINE3(ipc_req)(sys_arg_t pid, sys_arg_t d0, sys_arg_t d1) { struct tcb *r = get_tcb(pid); @@ -27,13 +42,28 @@ SYSCALL_DEFINE3(ipc_req)(sys_arg_t pid, sys_arg_t d0, sys_arg_t d1) return (struct sys_ret){ d0, d1 }; } -SYSCALL_DEFINE3(ipc_fwd)(sys_arg_t tid, sys_arg_t d0, sys_arg_t d1) +/** + * IPC forwarding syscall handler. + * + * @param pid Process to rquest RPC to. + * @param d0 IPC argument 0. + * @param d1 IPC argument 1. + * @return \c d0 and \c d1. + */ +SYSCALL_DEFINE3(ipc_fwd)(sys_arg_t pid, sys_arg_t d0, sys_arg_t d1) { - struct tcb *t = get_tcb(tid); + struct tcb *t = get_tcb(pid); /* ditto */ return (struct sys_ret){ d0, d1 }; } +/** + * IPC response syscall handler. + * + * @param d0 IPC return value 0. + * @param d1 IPC return value 1. + * @return \c d0 and \c d1. + */ SYSCALL_DEFINE2(ipc_resp)(sys_arg_t d0, sys_arg_t d1) { struct tcb *r = cur_tcb(); diff --git a/common/uapi/mem.c b/common/uapi/mem.c index 374e722..71686d6 100644 --- a/common/uapi/mem.c +++ b/common/uapi/mem.c @@ -4,6 +4,7 @@ /** * @file mem.c * Memory handling syscall implementations. + * \todo Should we return more error information? */ #include <apos/uapi.h> @@ -11,33 +12,76 @@ #include <apos/vmem.h> #include <apos/dmem.h> +/** + * Memory request syscall handler. + * + * @param size Minimum size of allocation. + * @param flags Flags of allocation. + * @return \ref OK and start of allocation when succesful, + * \ref ERR_OOMEM and \c NULL otherwise. + */ SYSCALL_DEFINE2(req_mem)(sys_arg_t size, sys_arg_t flags) { /* get current effective process */ struct tcb *r = cur_proc(); - return (struct sys_ret){ OK, alloc_uvmem(r, size, flags) }; + vm_t start = 0; + if ((start = alloc_uvmem(r, size, flags))) + return (struct sys_ret){ ERR_OOMEM, NULL }; + + return (struct sys_ret){ OK, start }; } +/** + * Fixed memory request syscall handler. + * + * @param start Address which should be included in allocation. + * @param size Minimum size of allocation after \c start. + * @param flags Flags of allocation. + * @return \ref OK and start of allocation when succesful, + * \ref ERR_OOMEM and \c NULL otherwise. + */ SYSCALL_DEFINE3(req_fixmem)(sys_arg_t start, sys_arg_t size, sys_arg_t flags) { struct tcb *r = cur_proc(); - /* should probably check if the allocation succeeded...? \todo */ - return (struct sys_ret){ OK, alloc_fixed_uvmem(r, start, size, flags) }; + vm_t start = 0; + if ((start = alloc_fixed_uvmem(r, start, size, flags))) + return (sys_ret){ ERR_OOMEM, NULL }; + + return (struct sys_ret){ OK, start }; } +/** + * Free memory syscall handler. + * + * @param start Start of allocation to free. + * @return \ref OK and \c 0 when succesful, \ref ERR_NF and \c 0 otherwise. + */ SYSCALL_DEFINE1(free_mem)(sys_arg_t start) { struct tcb *r = cur_proc(); vm_t vm_start = (vm_t)start; + stat_t status = OK; if (vm_start > __pre_top && vm_start < __post_base) - free_uvmem(r, vm_start); + status = free_uvmem(r, vm_start); else - free_devmem(r, vm_start); + status = free_devmem(r, vm_start); + + if (status) + return (struct sys_ret){ ERR_NF, 0 }; return (struct sys_ret){ OK, 0 }; } +/** + * Request physical memory syscall handler. + * + * @param paddr Physical address to map. + * @param size Minimum size of allocation. + * @param flags Flags of allocation. + * @return \ref OK and start of allocation when succesful, + * \ref ERR_OOMEM and \c NULL otherwise. + */ SYSCALL_DEFINE3(req_pmem)(sys_arg_t paddr, sys_arg_t size, sys_arg_t flags) { /* this will require some pondering, but essentially this syscall should @@ -46,29 +90,48 @@ SYSCALL_DEFINE3(req_pmem)(sys_arg_t paddr, sys_arg_t size, sys_arg_t flags) * that keeps track of used regions outside of RAM. We'll see. */ struct tcb *r = cur_proc(); - return (struct sys_ret){ OK, alloc_devmem(r, paddr, size, flags) }; + vm_t start = 0; + if ((start = alloc_devmem(r, paddr, size, flags))) + return (struct sys_ret){ ERR_OOMEM, NULL }; + + return (struct sys_ret){ OK, start }; } +/** + * Request shared memory syscall handler. + * + * @param size Minimum size of allocation. + * @param flags Flags of allocation. + * @return \ref OK and start of allocation when succesful, + * \ref ERR_OOMEM and \c NULL otherwise. + */ SYSCALL_DEFINE2(req_sharedmem)(sys_arg_t size, sys_arg_t flags) { /** \todo check that requester is server */ struct tcb *t = cur_proc(); vm_t start = 0; if ((start = alloc_shared_uvmem(t, size, flags))) - return (struct sys_ret){ ERR_OOMEM, 0 }; + return (struct sys_ret){ ERR_OOMEM, NULL }; return (struct sys_ret){ OK, start }; } -/* add a syscall like ref_sharedmem that adds a reference to an existing shared - * memory region to a new tid? */ +/** + * Reference shared memory syscall handler. + * + * @param tid Thread ID of shared memory owner. + * @param va Start of shared memory in \c tid. + * @param flags Flags of reference. + * @return \ref OK and start of reference when succesful, + * \ref ERR_OOMEM and \c NULL otherwise. + */ SYSCALL_DEFINE3(ref_sharedmem)(sys_arg_t tid, sys_arg_t va, sys_arg_t flags) { struct tcb *t1 = cur_tcb(); struct tcb *t2 = get_tcb(tid); vm_t start = 0; if ((start = ref_shared_uvmem(t1, t2, va, flags))) - return (struct sys_ret){ ERR_OOMEM, 0 }; + return (struct sys_ret){ ERR_OOMEM, NULL }; return (struct sys_ret){ OK, start }; } diff --git a/common/uapi/proc.c b/common/uapi/proc.c index 79d243f..60617b4 100644 --- a/common/uapi/proc.c +++ b/common/uapi/proc.c @@ -12,11 +12,21 @@ #include <apos/bits.h> #include <apos/mem_regions.h> +/** + * Create syscall handler. + * + * \todo Implement. + * + * @return \ref OK and 0. + */ SYSCALL_DEFINE0(create)(){ return (struct sys_ret){ OK, 0 }; } -/* Not entirely sure how I should handle forks/execs etc, mostly whether I +/** + * Fork syscall handler. + * + * \todo Not entirely sure how I should handle forks/execs etc, mostly whether I * should allow forks/execs to be called directly or only though the process * manager. Probably though the process manager, although that will add in a * slight bit of delay. @@ -25,11 +35,20 @@ SYSCALL_DEFINE0(create)(){ * that would allow them to be called directly, and then the process manager * would have to periodically ask the kernel about all threads it is aware of * via sys_sync. Dunno. + * + * @return \ref OK and 0. */ SYSCALL_DEFINE0(fork)(){ return (struct sys_ret){ OK, 0 }; } +/** + * Exec syscall handler. + * + * @param bin Binary to execute. + * @param interp Optional interpreter binary. + * @return \see prepare_proc() and 0. + */ SYSCALL_DEFINE2(exec)(sys_arg_t bin, sys_arg_t interp){ /** \todo execute new process, probably with more sensible argc passing */ struct tcb *r = cur_tcb(); @@ -60,11 +79,29 @@ SYSCALL_DEFINE2(exec)(sys_arg_t bin, sys_arg_t interp){ return (struct sys_ret){ prepare_proc(r, bin, interp), 0 }; } +/** + * Signal syscall handler. + * + * \todo Implement. + * + * @param tid Thread ID to signal. + * @param signal Signal to send to \c tid. + * @return \ref OK and 0. + */ SYSCALL_DEFINE2(signal)(sys_arg_t tid, sys_arg_t signal){ - /** \todo signals? */ return (struct sys_ret){ OK, 0 }; } +/** + * Swap syscall handler. + * + * \todo Implement. + * \todo Should swap return the registers of the new thread that would be used + * for message passing? + * + * @param tid Thread ID to swap to. + * @return \ref OK and 0. + */ SYSCALL_DEFINE1(swap)(sys_arg_t tid){ /** \todo switch to process */ /** \todo should switch return the registers of the new thread that would diff --git a/common/uapi/timers.c b/common/uapi/timers.c index bc3ef59..b6f9b95 100644 --- a/common/uapi/timers.c +++ b/common/uapi/timers.c @@ -9,39 +9,81 @@ #include <apos/timer.h> #include <apos/uapi.h> -static ticks_t scaled_ticks(sys_arg_t ticks, sys_arg_t repeat) +/** + * Convert arch-specific register values \c ticks and \c repeat to \c ticks_t. + * + * If we're on a 32bit system, one register can't contain a tick value, + * so we use two registers and combine them into one value and let the compiler + * handle the rest. + * + * @param ticks Register width tick value. + * @param mult Register width repeat value. + * @return Corresponding \c ticks_t value. + */ +static ticks_t scaled_ticks(sys_arg_t ticks, sys_arg_t mult) { -#if __WORDSIZE == 64 - UNUSED(repeat); +#if defined(_LP64) + UNUSED(mult); return ticks; #else - return ((ticks_t)ticks << 32) + repeat; + return (ticks_t)ticks * (ticks_t)mult; #endif } +/** + * Timebase syscall handler. + * + * @return \ref OK and resolution of system timer in Hz. + */ SYSCALL_DEFINE0(timebase)() { return (struct sys_ret){ OK, secs_to_ticks(1) }; } -SYSCALL_DEFINE2(req_rel_timer)(sys_arg_t ticks, sys_arg_t repeat) +/** + * Relative timer request syscall handler. + * + * \note On 64bit systems, \c repeat is ignored as \c ticks register is large + * enough to contain essentially any timepoint we want. A couple thousand years + * when the clock runs at 5GHz, if I'm not completely mistaken. + * + * @param ticks Number of ticks from now. + * @param mult Multiply \c ticks by this value. + * @return \ref OK and \c cid of created timer. + */ +SYSCALL_DEFINE2(req_rel_timer)(sys_arg_t ticks, sys_arg_t mult) { return (struct sys_ret){ OK, new_rel_timer(cur_tcb()->tid, - scaled_ticks(ticks, repeat)) + scaled_ticks(ticks, mult)) }; } -SYSCALL_DEFINE2(req_abs_timer)(sys_arg_t ticks, sys_arg_t repeat) +/** + * Absolute timer request syscall handler. + * + * @param ticks Absolute timepoint relative to some start point defined at boot. + * @param mult Multiply \c ticks by this value. + * @return \ref OK and \c cid of created timer. + * \see req_rel_timer(). + */ +SYSCALL_DEFINE2(req_abs_timer)(sys_arg_t ticks, sys_arg_t mult) { return (struct sys_ret){ OK, new_abs_timer(cur_tcb()->tid, - scaled_ticks(ticks, repeat)) + scaled_ticks(ticks, mult)) }; } +/** + * Free timer request syscall handler. + * + * @param cid \c cid of timer to free. + * @return \ref ERR_NF and \c 0if no timer could be found with \c cid, \ref OK + * and 0 otherwise. + */ SYSCALL_DEFINE1(free_timer)(sys_arg_t cid) { struct timer *timer = find_timer(cid); diff --git a/common/vmem.c b/common/vmem.c index eb88552..fe0178e 100644 --- a/common/vmem.c +++ b/common/vmem.c @@ -18,6 +18,14 @@ stat_t init_uvmem(struct tcb *t, vm_t base, vm_t top) return init_region(&t->sp_r, base, top); } +/** + * Convenience function for freeing mapped regions. + * + * @param t Thread to work in. + * @param m Memory region to free. + * @return \ref INFO_SEFF if other thread in process should be synced, \ref OK + * otherwise. + */ static stat_t __free_mapped_region(struct tcb *t, struct mem_region *m) { stat_t status = OK; @@ -135,12 +143,12 @@ vm_t ref_shared_uvmem(struct tcb *t1, struct tcb *t2, vm_t va, vmflags_t flags) return v; } -/** \todo assume tcb is root tcb? */ stat_t free_uvmem(struct tcb *r, vm_t va) { + /** \todo assume tcb is root tcb? */ struct mem_region *m = find_used_region(&r->sp_r, va); if (!m) - return -1; + return ERR_NF; free_region(&r->sp_r, va); diff --git a/include/apos/debug.h b/include/apos/debug.h index db0e1b5..6d428fe 100644 --- a/include/apos/debug.h +++ b/include/apos/debug.h @@ -329,7 +329,7 @@ enum serial_dev { * * @param fmt Format string. Integer subset of normal printf formatting. */ -void __printf dbg(const char *fmt, ...); +void dbg(const char *fmt, ...) __printf; /** * Initialize debugging, set up serial driver etc. diff --git a/include/apos/uapi.h b/include/apos/uapi.h index db33abc..6832f79 100644 --- a/include/apos/uapi.h +++ b/include/apos/uapi.h @@ -301,12 +301,12 @@ SYSCALL_DECLARE0(timebase); * Request timer that triggers a number of ticks in the future. * * @param ticks Number of ticks from now. - * @param repeat Number of times to trigger. + * @param mult Number of times to trigger. * @param c Unused. * @param d Unused. * @return \ref OK and ID of timer. */ -SYSCALL_DECLARE2(req_rel_timer, ticks, repeat); +SYSCALL_DECLARE2(req_rel_timer, ticks, mult); /** * Request absolute timer syscall. @@ -314,13 +314,13 @@ SYSCALL_DECLARE2(req_rel_timer, ticks, repeat); * Request timer that triggers at some absolute timepoint. * * @param ticks Timepoint. - * @param repeat Number of times to trigger. (What? Why is this here?). + * @param mult Multiplier. * @param c Unused. * @param d Unused. * @return \ref OK and ID of timer. * \todo Check repeat value. */ -SYSCALL_DECLARE2(req_abs_timer, ticks, repeat); +SYSCALL_DECLARE2(req_abs_timer, ticks, mult); /** * Free timer syscall. diff --git a/lib/fdt_dbg.c b/lib/fdt_dbg.c index 5cfacc5..5fd4219 100644 --- a/lib/fdt_dbg.c +++ b/lib/fdt_dbg.c @@ -10,6 +10,12 @@ #include <libfdt.h> #if defined(DEBUG) +/** + * Print single character \c depth number of times. + * + * @param c Character to print. + * @param depth Number of times to print character. + */ static void __print_char(char c, int depth) { /* lol, ugly but good enough for now */ @@ -17,11 +23,27 @@ static void __print_char(char c, int depth) dbg("%c", c); } +/** + * Check if ASCII character is in printable range. + * + * In this case, printable is anything that isn't a control character, line + * feed, bell, etc. + * + * @param c Character to check. + * @return \ref true if in printable range, \ref false otherwise. + */ static int __printable(char c) { return (c >= 32) && (c <= 126); } +/** + * Check if \c data and \c len bytes from it form a reasonable string. + * + * @param data Pointer to some binary data to check. + * @param len Assumed length of string. + * @return \c true if data is likely some string, \c false otherwise. + */ static int __is_string(const void *data, int len) { const char *s = data; @@ -59,6 +81,12 @@ static int __is_string(const void *data, int len) return 1; } +/** + * Print value of FDT property. + * + * @param data Pointer to FDT property. + * @param len Length of property. + */ static void __print_prop_value(const void *data, int len) { if (len == 0) |
