From 76517486919657ecadda9867125dc6730f29a5b7 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Sat, 6 Jul 2024 18:14:04 +0300 Subject: pretty massive virtual memory rewrite + The system is now a bit simpler and hopefully easier to understand, while also extending the shared memory to be 1:N, where there is one owner who may become a zombie while waiting for the N to die. --- include/arch/proc.h | 2 +- include/arch/vmem.h | 7 +- include/kmi/bkl.h | 12 ++ include/kmi/caps.h | 3 + include/kmi/mem.h | 7 +- include/kmi/mem_nodes.h | 42 ------- include/kmi/mem_regions.h | 304 -------------------------------------------- include/kmi/orphanage.h | 2 + include/kmi/regions.h | 311 ++++++++++++++++++++++++++++++++++++++++++++++ include/kmi/syscalls.h | 6 +- include/kmi/tcb.h | 22 +++- include/kmi/uapi.h | 24 +--- include/kmi/vmem.h | 189 +++++----------------------- 13 files changed, 396 insertions(+), 535 deletions(-) delete mode 100644 include/kmi/mem_nodes.h delete mode 100644 include/kmi/mem_regions.h create mode 100644 include/kmi/regions.h (limited to 'include') diff --git a/include/arch/proc.h b/include/arch/proc.h index 429f688..61a30c4 100644 --- a/include/arch/proc.h +++ b/include/arch/proc.h @@ -91,7 +91,7 @@ void load_regs(void *p, struct tcb *t); * @param d Destination. * @param s Source. */ -void clone_regs(struct tcb *d, struct tcb *s); +void copy_regs(struct tcb *d, struct tcb *s); /** * Do modifications to \ref tcb state if necessary for ipis to work. diff --git a/include/arch/vmem.h b/include/arch/vmem.h index 8f94e07..6e761b6 100644 --- a/include/arch/vmem.h +++ b/include/arch/vmem.h @@ -17,6 +17,7 @@ #endif #include +#include /** * Map one virtual page to physical page. @@ -161,17 +162,15 @@ struct vmem *create_vmem(); * Jump into virtual memory context. * * @param b Virtual memory to jump into. - * @return \ref OK. */ -stat_t use_vmem(struct vmem *b); +void use_vmem(struct vmem *b); /** * Destroy virtual memory space. * * @param b Virtual memory to destroy. - * @return \ref OK. */ -stat_t destroy_vmem(struct vmem *b); +void destroy_vmem(struct vmem *b); /** * Raw clone user virtual memory. diff --git a/include/kmi/bkl.h b/include/kmi/bkl.h index 26dfaa8..9ea6ccd 100644 --- a/include/kmi/bkl.h +++ b/include/kmi/bkl.h @@ -1,15 +1,27 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2024, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ + #ifndef KMI_BKL_H #define KMI_BKL_H +/** + * @file bkl.h + * + * Stuff for handling the Big Kernel Lock. + */ + #include +/** Big Kenrel Lock. */ extern spinlock_t bkl; +/** Lock the Big Kernel Lock. */ static inline void bkl_lock() { spin_lock(&bkl); } +/** Unlock the Big Kernel Lock. */ static inline void bkl_unlock() { spin_unlock(&bkl); diff --git a/include/kmi/caps.h b/include/kmi/caps.h index 158845d..02f6b3e 100644 --- a/include/kmi/caps.h +++ b/include/kmi/caps.h @@ -40,6 +40,9 @@ enum { /** Thread is allowed to request notification handler. */ CAP_SIGNAL = (1 << 6), + + /** Thread is allowed to request shared memory */ + CAP_SHARED = (1 << 7) }; /** diff --git a/include/kmi/mem.h b/include/kmi/mem.h index 97a85bf..f2b7b74 100644 --- a/include/kmi/mem.h +++ b/include/kmi/mem.h @@ -132,9 +132,12 @@ /** @{ */ /** Memory region is used. */ -#define MR_USED (1 << 8) +#define MR_USED (1 << (ARCH_VP_FLAGS + 0)) /** Don't free memory on clear. */ -#define MR_KEEP (1 << 9) +#define MR_KEEP (1 << (ARCH_VP_FLAGS + 1)) +/** Memory region in shared, but owned. Note: regions that are shared but no + * owned don't use this flag, they just set the tid field for the region. */ +#define MR_SHARED (1 << (ARCH_VP_FLAGS + 2)) /** @} */ diff --git a/include/kmi/mem_nodes.h b/include/kmi/mem_nodes.h deleted file mode 100644 index 523c087..0000000 --- a/include/kmi/mem_nodes.h +++ /dev/null @@ -1,42 +0,0 @@ -/* SPDX-License-Identifier: copyleft-next-0.3.1 */ -/* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ - -#ifndef KMI_MM_NODES_H -#define KMI_MM_NODES_H - -/** - * @file mem_nodes.h - * Memory node subsystem. Used by the memory region subsystem. - */ - -#include -#include - -/** - * Initialize memory node subsystem. - * - * @pre Physical memory subsystem has been initialized. - */ -void init_mem_nodes(); - -/** - * Destroy memory node subsystem. - * Free all associated allocations. - */ -void destroy_mem_nodes(); - -/** - * Fetch a new memory node. - * - * @return Pointer to \ref mem_region node on success, \c NULL otherwise. - */ -struct mem_region *get_mem_node(); - -/** - * Free a memory node. - * - * @param m Pointer to \ref mem_region node to free. - */ -void free_mem_node(struct mem_region *m); - -#endif /* KMI_MM_NODES_H */ diff --git a/include/kmi/mem_regions.h b/include/kmi/mem_regions.h deleted file mode 100644 index 080a499..0000000 --- a/include/kmi/mem_regions.h +++ /dev/null @@ -1,304 +0,0 @@ -/* SPDX-License-Identifier: copyleft-next-0.3.1 */ -/* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ - -#ifndef KMI_MEM_REGIONS_H -#define KMI_MEM_REGIONS_H - -/** - * @file mem_regions.h - * Memory region subsytem. Mainly used by the virtual memory subsytems, i.e. device and - * user memory. - */ - -#include -#include -#include -#include - -/** - * Get \ref mem_region container of \c ptr. - * - * @param ptr Pointer to \c sp_n member in \ref mem_region. - * @return Parent \ref mem_region. - */ -#define mem_container(ptr) container_of(ptr, struct mem_region, sp_n) - -/** - * Check if memory region is used. - * - * @param r Memory region to check. - * @return \c 0 if not used, non-zero otherwise. - */ -#define is_region_used(r) is_set(r->flags, MR_USED) - -/** - * Check if region should be kept during clear. - * - * @param r Memory region to check. - * @return \c 0 if not kept, non-zero otherwise. - */ -#define is_region_kept(r) is_set(r->flags, MR_KEEP) - -/** Root of memory region. */ -struct mem_region_root { - /** Sp-tree of free regions. */ - struct sp_root free_regions; - - /** Sp-tree of used region. */ - struct sp_root used_regions; -}; - -/** - * Memory region. - * Regions can have two states, used or free. There are two sp-trees, which keep - * track of free and used regions, respectively. All regions are chained - * together with a doubly linked list, so that the next region's start address - * should be the current region's end address. - */ -struct mem_region { - /** Sp-tree node slot. */ - struct sp_node sp_n; - - /** Next memory region by start address. */ - struct mem_region *next; - - /** Previous memory region by end address. */ - struct mem_region *prev; - - /** End address of memory region. */ - vm_t end; - - /** Start address of memory region. */ - vm_t start; - - /** In shared regions, this is the address associated with region in the - * other process. */ - vm_t alt_va; - - /** In shared regions, mark the other pid that shared the region. */ - id_t pid; - - /** Memory region flags, both access as well as metadata. \see MR_USED, - * MR_SHARED, MR_OWNED, MR_COW, MR_KEEP. */ - vmflags_t flags; - -}; - -/** - * Initialize memory region subsystem instance. - * - * @param r Memory region root to initialize. - * @param start Start of memory arena. - * @param arena_size Size of memory arena. - * @return \ref OK on success. - * \todo Document error codes when I actually implement them properly. - */ -stat_t init_region(struct mem_region_root *r, vm_t start, size_t arena_size); - -/** - * Destroy memory region subsystem instance. - * - * @param r Memory region root to destroy. - * @return \ref OK on success. - */ -stat_t destroy_region(struct mem_region_root *r); - -/** - * Allocate memory region. - * Will allocate region of at least \c size bytes, with best possible location. - * - * @param r Memory region root. - * @param size Size of region to allocate. - * @param actual_size Size of region that was allocated. - * @param flags Memory flags. - * @return Address of allocated region on success, otherwise \c NULL. - */ -vm_t alloc_region(struct mem_region_root *r, size_t size, size_t *actual_size, - vmflags_t flags); - -/** - * Allocate memory region and associate it with some other process. - * Will allocate region of at least \c size bytes, with best possible location. - * - * @param r Memory region root. - * @param size Size of region to allocate. - * @param actual_size Size of region that was allocated. - * @param flags Memory flags. - * @param pid Process to associate with region. - * @return Address of allocated region on success, otherwise \c NULL. - */ -vm_t alloc_shared_region(struct mem_region_root *r, size_t size, - size_t *actual_size, - vmflags_t flags, id_t pid); - -/** - * Allocate fixed memory region. - * Will allocate region that is at least \c size bytes, and includes \c start. - * \note The address returned might not be the address requested, and the caller - * must keep track of which address it was given, so it can cleanly give it to - * \ref free_region() when finished with the allocation. - * - * @param r Memory region root. - * @param start Address that must be within region to allocate. - * @param size Size of region to allocate. - * @param actual_size Size of region that was allocated. - * @param flags Memory flags. - * @return Address of allocated region on success, otherwise \c NULL. - */ -vm_t alloc_fixed_region(struct mem_region_root *r, vm_t start, size_t size, - size_t *actual_size, vmflags_t flags); - -/** - * Free memory region. - * - * @param r Memory region root. - * @param start Address of region to free. - * @return \ref OK on success, \ref ERR_ALIGN if \c start is misaligned and \ref - * ERR_NF if the memory region is not found. - */ -stat_t free_region(struct mem_region_root *r, vm_t start); - -/** - * Free memory region through a direct pointer to the memory region. - * Mainly useful if you look up a region beforehand, do something with it and - * then free it. Skips looking up the start address. - * - * @param r Memory region root. - * @param m Memory region to free. - * @return \ref OK. - * \todo Improve error checking. - */ -stat_t free_known_region(struct mem_region_root *r, struct mem_region *m); - -/** - * Find the memory region with lowest starting address. - * This region will also be the first node in the linked list. - * Useful when you need to iterate over all regions. - * - * @param r Memory region root. - * @return First memory region when succesful, otherwise \c NULL. - */ -struct mem_region *find_first_region(struct mem_region_root *r); - -/** - * Find used memory region at address \c start. - * - * @param r Memory region root. - * @param start Address at which a used region should exist. - * @return Pointer to requested memory region when succesful, \c NULL otherwise. - */ -struct mem_region *find_used_region(struct mem_region_root *r, vm_t start); - -/** - * Find used memory region closest to \c start. - * Useful when you don't necessarily need the exact region, just something close - * by. - * - * @param r Memory region root. - * @param start Address region should be closest to. - * @return Pointer to memory region closest to \c start when succesful, \c NULL - * otherwise. - */ -struct mem_region *find_closest_used_region(struct mem_region_root *r, - vm_t start); - -/** - * Find best region that fulfills requested parameters. - * - * @param r Memory region root. - * @param size Size of free region. - * @param align Recommended offset into this region from where the allocation - * should be carved. - * @return Pointer to suitable \c memory_region when succesful, \c NULL - * otherwise. - */ -struct mem_region *find_free_region(struct mem_region_root *r, size_t size, - size_t *align); - -/** - * Helper functions for converting between memory regions and page - * mappings. Called by \ref map_fill_region(). - * \see map_fill_region() for further explanation. - * - * @param vmem Virtual memory space in which the operation is to be done. - * @param offset Offset from where to start looking for next physical page. \see - * alloc_page(). - * @param vaddr Current virtual address. - * @param flags Virtual memory allocation flags. - * @param order Order of physical page. - * @param data Custom data. - * @return \ref OK if succesful, \c INFO_TRGN if page order should be decreased, - * anything else means error. - */ -typedef stat_t region_callback_t(struct vmem *vmem, pm_t *offset, vm_t vaddr, - vmflags_t flags, enum mm_order order, - void *data); - -/** - * Query flags of region that contains \c va. - * - * @param r Memory region root. - * @param va Address that is within memory region. - * @param flags Memory region flags. - * @return \ref OK when succesful. - * \todo Implement. - */ -stat_t stat_region(struct mem_region_root *r, vm_t va, vmflags_t *flags); - -/** - * Modify flags of region that contains \c va. - * - * @param r Memory region root. - * @param va Address that is within memory region. - * @param flags New flags of region. - * @return \ref OK when succesful. - * \todo Implement. - */ -stat_t mod_region(struct mem_region_root *r, vm_t va, vmflags_t flags); - -/** - * Set alternate virtual address associated with shared memory region in other process. - * - * @param r Memory region root. - * @param va Virtual address in \p r. - * @param alt_va Virtual address in other process. - */ -void set_alt_region_addr(struct mem_region_root *r, vm_t va, vm_t alt_va); - -/** - * Conversion function between abstract memory region and actual page mappings. - * Assumes that pages of some order are mappable at multiples of their size, and - * tries to fit as many and as high order pages as it can into the region. - * Heavily utilizes \c mem_handler, to which it gives a suggestion for how to - * map a page. If this suggestion is accepted and succesfully executed, \c mem_handler - * returns \ref OK. If the suggestion is not possible, for example no higher - * order pages are available, \c mem_handler returns \ref INFO_TRGN to tell \c - * map_fill_region() to give it some other suggestion. Any error value stops the - * conversion. - * - * This 'algorithm' also works quite nicely for freeing a region, but in - * reverse, i.e. it is given a suggestion and checks if that suggestion was - * executed when the region was mapped. If the suggestion was executed, then the - * same suggestion is freed, else \ref INFO_TRGN is returned and a new - * suggestion is requested until all pages have been freed. - * - * There are some more technicalities, for example currently \c - * map_fill_region() gives up trying to map higher order pages as soon as its - * first suggestion is rejected, which gives us quick conversion times but - * probably less than ideal mappings. - * - * @param vmem Virtual memory inside which to map the region. - * @param mem_handler Worker handler callback. - * @param offset Offset at which the physical memory availability map should - * start searching. - * @param start Start address of memory region. - * @param bytes Size of memory region. - * @param flags Memory flags. - * @param data User-specified data. - * @return \c start when succesful, \c 0 otherwise. - */ -vm_t map_fill_region(struct vmem *vmem, region_callback_t *mem_handler, - pm_t offset, vm_t start, size_t bytes, vmflags_t flags, - void *data); - -#endif /* KMI_MEM_REGIONS_H */ diff --git a/include/kmi/orphanage.h b/include/kmi/orphanage.h index 09e36b3..db5a617 100644 --- a/include/kmi/orphanage.h +++ b/include/kmi/orphanage.h @@ -14,6 +14,8 @@ * them whenever it gets a chance. */ +#include +#include #include /** diff --git a/include/kmi/regions.h b/include/kmi/regions.h new file mode 100644 index 0000000..1d96f00 --- /dev/null +++ b/include/kmi/regions.h @@ -0,0 +1,311 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ + +#ifndef KMI_REGIONS_H +#define KMI_REGIONS_H + +/** + * @file regions.h + * Memory region subsytem. Mainly used by the virtual memory subsytems, i.e. device and + * user memory. + */ + +#include +#include +#include +#include + +#include + +/** + * Initialize memory region nodes. Must be done after physical memory has been + * initialized. + */ +void init_mem_nodes(); + +/** + * Destroy all nodes allocated by the memory region subsystem. + */ +void destroy_mem_nodes(); + +/** + * Get \ref mem_region container of \c ptr. + * + * @param ptr Pointer to \c sp_n member in \ref mem_region. + * @return Parent \ref mem_region. + */ +#define mem_container(ptr) container_of(ptr, struct mem_region, sp_n) + +/** + * Check if memory region is used. + * + * @param r Memory region to check. + * @return \c 0 if not used, non-zero otherwise. + */ +#define is_region_used(r) is_set(r->flags, MR_USED) + +/** + * Check if region should be kept during clear. + * + * @param r Memory region to check. + * @return \c 0 if not kept, non-zero otherwise. + */ +#define is_region_kept(r) is_set(r->flags, MR_KEEP) + +/** Root of memory region. */ +struct mem_region_root { + /** Sp-tree of free regions. */ + struct sp_root free_regions; + + /** Sp-tree of used region. */ + struct sp_root used_regions; +}; + +/** + * Memory region. + * Regions can have two states, used or free. There are two sp-trees, which keep + * track of free and used regions, respectively. All regions are chained + * together with a doubly linked list, so that the next region's start address + * should be the current region's end address. + */ +struct mem_region { + /** Sp-tree node slot. */ + struct sp_node sp_n; + + /** Next memory region by start address. */ + struct mem_region *next; + + /** Previous memory region by end address. */ + struct mem_region *prev; + + /** End address of memory region. */ + vm_t end; + + /** Start address of memory region. */ + vm_t start; + + /** In shared regions, mark the other pid that shared the region. */ + id_t pid; + + /** Memory region flags, both access as well as metadata. \see MR_USED, + * MR_SHARED, MR_OWNED, MR_COW, MR_KEEP. */ + vmflags_t flags; + +}; + +/** + * Initialize memory region subsystem instance. + * + * @param r Memory region root to initialize. + * @param start Start of memory arena. + * @param arena_size Size of memory arena. + * @return \ref OK on success. + * \todo Document error codes when I actually implement them properly. + */ +stat_t init_region(struct mem_region_root *r, vm_t start, size_t arena_size); + +/** + * Destroy memory region subsystem instance. + * + * @param r Memory region root to destroy. + * @return \ref OK on success. + */ +stat_t destroy_region(struct mem_region_root *r); + +/** + * Allocate memory region. + * Will allocate region of at least \c size bytes, with best possible location. + * + * @param r Memory region root. + * @param size Size of region to allocate. + * @param actual_size Size of region that was allocated. + * @param flags Memory flags. + * @return Address of allocated region on success, otherwise \c NULL. + */ +vm_t alloc_region(struct mem_region_root *r, size_t size, size_t *actual_size, + vmflags_t flags); + +/** + * Allocate memory region and associate it with some other process. + * Will allocate region of at least \c size bytes, with best possible location. + * + * @param r Memory region root. + * @param size Size of region to allocate. + * @param actual_size Size of region that was allocated. + * @param flags Memory flags. + * @param pid Process to associate with region. + * @return Address of allocated region on success, otherwise \c NULL. + */ +vm_t alloc_shared_region(struct mem_region_root *r, size_t size, + size_t *actual_size, + vmflags_t flags, id_t pid); + +/** + * Allocate fixed memory region. + * Will allocate region that is at least \c size bytes, and includes \c start. + * \note The address returned might not be the address requested, and the caller + * must keep track of which address it was given, so it can cleanly give it to + * \ref free_region() when finished with the allocation. + * + * @param r Memory region root. + * @param start Address that must be within region to allocate. + * @param size Size of region to allocate. + * @param actual_size Size of region that was allocated. + * @param flags Memory flags. + * @return Address of allocated region on success, otherwise \c NULL. + */ +vm_t alloc_fixed_region(struct mem_region_root *r, vm_t start, size_t size, + size_t *actual_size, vmflags_t flags); + +/** + * Free memory region. + * + * @param r Memory region root. + * @param start Address of region to free. + * @return \ref OK on success, \ref ERR_ALIGN if \c start is misaligned and \ref + * ERR_NF if the memory region is not found. + */ +stat_t free_region(struct mem_region_root *r, vm_t start); + +/** + * Free memory region through a direct pointer to the memory region. + * Mainly useful if you look up a region beforehand, do something with it and + * then free it. Skips looking up the start address. + * + * @param r Memory region root. + * @param m Memory region to free. + */ +void free_known_region(struct mem_region_root *r, struct mem_region *m); + +/** + * Find the memory region with lowest starting address. + * This region will also be the first node in the linked list. + * Useful when you need to iterate over all regions. + * + * @param r Memory region root. + * @return First memory region when succesful, otherwise \c NULL. + */ +struct mem_region *find_first_region(struct mem_region_root *r); + +/** + * Find used memory region at address \c start. + * + * @param r Memory region root. + * @param start Address at which a used region should exist. + * @return Pointer to requested memory region when succesful, \c NULL otherwise. + */ +struct mem_region *find_used_region(struct mem_region_root *r, vm_t start); + +/** + * Find used memory region closest to \c start. + * Useful when you don't necessarily need the exact region, just something close + * by. + * + * @param r Memory region root. + * @param start Address region should be closest to. + * @return Pointer to memory region closest to \c start when succesful, \c NULL + * otherwise. + */ +struct mem_region *find_closest_used_region(struct mem_region_root *r, + vm_t start); + +/** + * Find best region that fulfills requested parameters. + * + * @param r Memory region root. + * @param size Size of free region. + * @param align Recommended offset into this region from where the allocation + * should be carved. + * @return Pointer to suitable \c memory_region when succesful, \c NULL + * otherwise. + */ +struct mem_region *find_free_region(struct mem_region_root *r, size_t size, + size_t *align); + +/** + * Map a region starting at virtual address \p start, that is \p bytes bytes in size + * to physical memory. Will allocate pages itself. If it fails midway through, + * doesn't clean up after itself, so remember to call \ref unmap_region() in + * such a case. + * + * @param vmem Virtual memory to do allocation in. + * @param start Start of region. + * @param bytes How large the allocation is in bytes. + * @param order What is the maximum order of page the function is allowed to + * use. This is mainly useful for shared memory regions that may want to always + * use base pages to maximize the chance of a clone succeeding. + * @param flags What flags to assign the page. + * @return \ref OK on success, some other error code otherwise. + */ +stat_t map_region(struct vmem *vmem, vm_t start, size_t bytes, + enum mm_order order, vmflags_t flags); + +/** + * Map a virtual memory region starting at \p v to the physical memory region + * starting at \p start, \p bytes long. Same as \ref map_region(), clean up + * after this function if it fails. + * + * @param vmem Virtual memory to do mapping in. + * @param v Start of virtual region. + * @param start Start of physical region. + * @param bytes Size of region in bytes. + * @param flags Flags to use for mapping. + * @return \ref OK on success, some other error code otherwise. + */ +stat_t map_fixed_region(struct vmem *vmem, vm_t v, pm_t start, size_t bytes, + vmflags_t flags); + +/** + * Clone a region starting at \p from in \p g of size \p bytes into \p to in \p + * b. Does not allocate new pages, just makes the virtual region point to the + * same physical pages. Used to implement shared memory, primarily. + * + * @param b Where to create mapping. + * @param g Where current mapping exists. + * @param from Start of region in \p g. + * @param to Start of region in \p b. + * @param bytes Size of region. Must be identical for both \p b and \p g. + * @param flags Flags for the new mapping. The original mapping can be RW while + * the new one just R, for example. + * + * @return \ref OK on success, some other error code otherwise. + */ +stat_t clone_region(struct vmem *b, struct vmem *g, vm_t from, vm_t to, + size_t bytes, vmflags_t flags); + +/** + * Copy region starting at \p from in \p g of size \p bytes to \p to in \p b. + * Allocates new pages, so the regions get copied as well. Used to implement + * \ref fork(). + * + * @param b Where to create mapping. + * @param g Where current mapping exists. + * @param from Start of region in \p g. + * @param to Start of region in \p b. + * @param bytes Size of region. Must be identical for both \p b and \p g. + * + * @return \ref OK on success, some other error code otherwise. + */ +stat_t copy_region(struct vmem *b, struct vmem *g, vm_t from, vm_t to, + size_t bytes); + +/** + * Unmap a region, while at the same time freeing backing pages. + * + * @param b Where to unmap region. + * @param v Start of region to unmap. + * @param bytes Size of region to unmap. + */ +void unmap_region(struct vmem *b, vm_t v, size_t bytes); + +/** + * Unmap a region, without freeing any pages. + * Useful for freeing shared memory or mappings outside RAM. + * + * @param b Where to unmap region. + * @param v Start of region to unmap. + * @param bytes Size of region to unmap. + */ +void unmap_fixed_region(struct vmem *b, vm_t v, size_t bytes); + +#endif /* KMI_REGIONS_H */ diff --git a/include/kmi/syscalls.h b/include/kmi/syscalls.h index 4ae0f0b..42cbcc0 100644 --- a/include/kmi/syscalls.h +++ b/include/kmi/syscalls.h @@ -11,9 +11,9 @@ /* pass VM_X etc. to userspace */ #if defined(riscv64) -#include "../../arch/riscv64/include/vmem.h" +#include "../../arch/riscv64/include/uapi.h" #elif defined(riscv32) -#include "../../arch/riscv32/include/vmem.h" +#include "../../arch/riscv32/include/uapi.h" #endif /** enum for now, possibly macros in the future once I get an approximate idea of @@ -46,7 +46,7 @@ enum sys_code { SYS_REQ_MEM, /** Request physical page from ram. */ - SYS_REQ_PAGE, + SYS_REF_SHAREDMEM, /** Request memory with physical address. */ SYS_REQ_PMEM, diff --git a/include/kmi/tcb.h b/include/kmi/tcb.h index 54f6e82..b7fd3d6 100644 --- a/include/kmi/tcb.h +++ b/include/kmi/tcb.h @@ -12,14 +12,15 @@ /* forward declaration */ struct tcb; -#include #include #include +#include #include #include #include #include -#include /* arch-specific data */ + +#include /** * Check if thread is process thread. @@ -82,6 +83,21 @@ enum tcb_state { TCB_ORPHAN = (1 << 1), }; +/** Wrapper around data for managing userspace virtual memory, defined here to + * avoid loops */ +struct uvmem { + /** ID of owning thread. Zombie threads or orhaned threads may be moved + * to other virtual memories, but they still hold a 'backwards' + * reference to their original virtual memory. */ + id_t owner; + + /** Actual userspace virtual memory address space. */ + struct vmem *vmem; + + /** Region data for allocations within this address space. */ + struct mem_region_root region; +}; + /** Thread control block. Main way to handle threads. */ struct tcb { /** Execution continuation point. Important that it is first. */ @@ -97,7 +113,7 @@ struct tcb { struct arch_tcbd arch; /** Memory mapping data. Only relevant in root thread. */ - struct mem_region_root sp_r; + struct uvmem uvmem; /** Address of callback function in servers. */ vm_t callback; diff --git a/include/kmi/uapi.h b/include/kmi/uapi.h index 42d6e5b..87b1895 100644 --- a/include/kmi/uapi.h +++ b/include/kmi/uapi.h @@ -292,30 +292,18 @@ SYSCALL_DECLARE1(putch, ch); SYSCALL_DECLARE2(req_mem, size, flags); /** - * Request one page of memory. The nearest fitting size is chosen. + * Reference shared memory, i.e. create a mapping for it in \p tid. * - * This might be better implemented as some number of adjacent physical pages, - * but the underlying physical page allocator doesn't really handle it very - * well. This weird design decision is because I don't know if there are devices - * whose drivers need multiple adjacent physical pages, only that at least - * virtio devices need to be able to access the physical address of a single - * page. Basic adjacent physical pages can be made from higher order pages, - * just with a massive overhead. Still, probably good eough for now. - * - * For example, if you need two adjacent 4K pages, you pass size = 8K and you - * get back a 2M page, if one is available. - * - * @param t Current tcb. - * @param size Required size of region. + * @param t Current tcb, owner of \p addr. + * @param tid Thread to create mapping in. + * @param addr Address of shared region in \p t. * @param flags Mapping flags to use. - * @param c Unused. * @param d Unused. * @param e Unused. * - * Returns \ref ERR_OOMEM if no page is available, otherwise \c OK, virtual - * address, actual size, physical size in that order. + * Returns \ref OK, virtual address, size, in that order. */ -SYSCALL_DECLARE2(req_page, size, flags); +SYSCALL_DECLARE3(ref_sharedmem, tid, addr, flags); /** * Request physical memory syscall. diff --git a/include/kmi/vmem.h b/include/kmi/vmem.h index 6335959..3f7ab71 100644 --- a/include/kmi/vmem.h +++ b/include/kmi/vmem.h @@ -12,6 +12,7 @@ #include #include #include +#include #include /** @@ -58,48 +59,30 @@ vm_t alloc_fixed_uvmem(struct tcb *r, vm_t start, size_t size, vmflags_t flags); /** * Allocate shared user virtual memory. + * Initially this region is only visible to whoever allocated it, but calling + * \ref ref_shared_uvmem() with the address of this allocation + * will add mappings to this region into other processes' address spaces. * * @param s First process to allocate memory in. - * @param c Second process to allocate memory in. * @param size Minimum size of allocation. - * @param sflags Flags of allocation for \p s. - * @param cflags Flags of allocation for \p c. - * @param sstart Start of allocation for \p s. - * @param cstart Start of allocation for \p c. - * @return Status of allocation. - */ -stat_t alloc_shared_uvmem(struct tcb *s, struct tcb *c, size_t size, - vmflags_t sflags, vmflags_t cflags, - vm_t *sstart, vm_t *cstart); - -/** - * Reference shared user virtual memory. - * - * Only callable by clients. - * - * @param r1 Process in which shared memory resides. - * @param r2 Process to reference shared memory in. - * @param va Virtual address of shared memory in \c r1. - * @param flags Flags of reference in \c r2. - * @return Start of reference in \c r2 when succesful, \c NULL otherwise. + * @param flags Flags of allocation. + * @return Address of allocation. */ -vm_t ref_shared_uvmem(struct tcb *r1, struct tcb *r2, vm_t va, vmflags_t flags); +vm_t alloc_shared_uvmem(struct tcb *s, size_t size, vmflags_t flags); /** * Free all user virtual memory allocations not marked with \ref MR_KEEP. * * @param r Process in which to clear user virtual memory. - * @return \ref OK. */ -stat_t clear_uvmem(struct tcb *r); +void clear_uvmem(struct tcb *r); /** * Free all user virtual memory allocations, even if marked with \ref MR_KEEP. * * @param r Process in which to clear user virtual memory. - * @return \ref OK. */ -stat_t purge_uvmem(struct tcb *r); +void purge_uvmem(struct tcb *r); /** * Free one user virtual memory allocation. @@ -116,6 +99,8 @@ stat_t free_uvmem(struct tcb *r, vm_t va); * This assumes the user virtual memory is contiguous, with no holes between \c * base and \c top. * + * Requires that \p t already has a vmem allocated. + * * @param r Process in which to initialize user virtual memory. * @param base Start of user virtual memory. * @param top Top of user virtual memory. @@ -127,9 +112,8 @@ stat_t init_uvmem(struct tcb *r, vm_t base, vm_t top); * Destroy user virtual memory instance. * * @param r Process in which to destroy user virtual memory. - * @return \see destroy_region(). */ -stat_t destroy_uvmem(struct tcb *r); +void destroy_uvmem(struct tcb *r); /** * Map a fixed physical region (within kernelspace) to somewhere in virtual @@ -143,7 +127,7 @@ stat_t destroy_uvmem(struct tcb *r); * the start of \p base, not necessarily the start of the allocation. * If this should be freed, remember to align down to the base page size. */ -vm_t map_fixed_mem(struct tcb *r, pm_t base, size_t size, vmflags_t flags); +vm_t map_fixed_uvmem(struct tcb *r, pm_t base, size_t size, vmflags_t flags); /** * Clone process memory. @@ -158,144 +142,33 @@ vm_t map_fixed_mem(struct tcb *r, pm_t base, size_t size, vmflags_t flags); stat_t clone_mem_regions(struct tcb *d, struct tcb *s); /** - * User virtual memory worker callback for \ref map_fill_region(). - * - * \c data is a pointer to \ref stat_t, which is set to \ref INFO_SEFF if all - * threads in process should sync their memory mappings. This occurs when the - * top level page table is modified. - * - * @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 \c OK when suggested order if acceptable, \c INFO_TRGN if suggested - * order not acceptable. Error otherwise. - * again - */ -stat_t alloc_uvmem_wrapper(struct vmem *b, pm_t *offset, vm_t vaddr, - vmflags_t flags, enum mm_order order, void *data); - -/** - * Shared user 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(). - */ -stat_t alloc_shared_wrapper(struct vmem *b, pm_t *offset, vm_t vaddr, - vmflags_t flags, enum mm_order order, void *data); - -/** - * User virtual memory copying worker callback for \ref map_fill_region(). - * - * Currently unused, but intention is to set up copy of some other virtual - * memory region, likely passed through \c data? - * - * @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 vmem to clone from. - * @return \see alloc_uvmem_wrapper(). - * - * \see alloc_uvmem_wraper(). - * \todo Implement. - */ -stat_t copy_allocd_wrapper(struct vmem *b, pm_t *offset, vm_t vaddr, - vmflags_t flags, enum mm_order order, void *data); - -/** - * User 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(). - */ -stat_t free_uvmem_wrapper(struct vmem *b, pm_t *offset, vm_t vaddr, - vmflags_t flags, enum mm_order order, void *data); - -/** - * Convenience wrapper for \ref map_fill_region() when mapping an allocated - * region. - * - * @param b Virtual memory to work in. - * @param start Start of virtual memory region to map. - * @param bytes Size of virtual memory region. - * @param flags Flags of virtual memory region. - * @param data Pointer to \c stat_t. - * @return \see map_fill_region(). - */ -#define map_allocd_region(b, start, bytes, flags, data) \ - map_fill_region(b, &alloc_uvmem_wrapper, 0, start, bytes, flags, data) - -/** - * Convenience wrapper for \ref map_fill_region() when mapping a shared region. - * - * @param b Virtual memory to work in. - * @param start Start of virtual memory region to map. - * @param bytes Size of virtual memory region. - * @param flags Flags of virtual memory region. - * @param data Pointer to \c stat_t. - * @return \see map_fill_region(). - */ -#define map_shared_region(b, start, bytes, flags, data) \ - map_fill_region(b, &alloc_shared_wrapper, 0, start, bytes, flags, data) - -/** - * Convenience wrapper for \ref map_fill_region() when copying a region. - * - * @param b Virtual memory to work in. - * @param start Start of virtual memory region to map. - * @param bytes Size of virtual memory region. - * @param flags Flags of virtual memory region. - * @param data Pointer to \c vmem to clone. - * @return \see map_fill_region(). - */ -#define copy_allocd_region(b, start, bytes, flags, data) \ - map_fill_region(b, ©_allocd_wrapper, 0, start, bytes, flags, data) - -/** - * Convenience wrapper for \ref map_fill_region() when freeing region. + * Reference a shared memory region. + * Adds a mapping in \p d of region \p v in \p s. * - * @param b Virtual memory to work in. - * @param start Start of virtual memory region to unmap. - * @param bytes Size of virtual memory region. - * @param flags Flags of virtual memory region. Technically unused? - * @param data Pointer to \c stat_t. - * @return \see map_fill_region(). + * @param d For which thread to create a new mapping. + * @param s Owner of shared region. + * @param v Address of shared region in \p s. + * @param flags Flags for mapping in \p d. + * @return Address of mapping in \p d. */ -#define unmap_freed_region(b, start, bytes, flags, data) \ - map_fill_region(b, &free_uvmem_wrapper, 0, start, bytes, flags, data) +vm_t ref_shared_uvmem(struct tcb *d, struct tcb *s, vm_t v, vmflags_t flags); /** - * Extract virtual memory flags (MR_XXX). + * Create a copy of \p s in \p d. Used for implementing \ref fork(). * - * @param x Flags to extract virtual memory region flags from. - * @return Virtual memory region flags. + * @param d Destination of copy. + * @param s Source of copy. + * @return \ref OK on success, some error otherwise. */ -#define vm_flags(x) ((x) & ~0xff) +stat_t copy_uvmem(struct tcb *d, struct tcb *s); /** - * Extract physical memory page flags (VM_XXX). + * Clears out all other flags besides VM_W/VM_R/VM_X from user-provided flags + * and adds VM_U and VM_V to make mapping accessible from userspace. * - * @param x Flags to extract physical memory page flags from. - * @return Physical memory page flags. + * @param flags Flags to sanitize. + * @return Sanitized flags. */ -#define vp_flags(x) ((x) & 0xff) +vmflags_t sanitize_uvflags(vmflags_t flags); #endif /* KMI_VMEM_H */ -- cgit v1.3