diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2022-05-29 21:48:00 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2022-05-29 21:48:00 +0300 |
| commit | 6295648f04d1d5d7e8b99d3fdaa8d497406eadf9 (patch) | |
| tree | d2bbe97ae40213356f9e2611285a78f7bac04bca | |
| parent | 1f7f2251faaef84cd441088f02a66440fa7b59cc (diff) | |
| download | kmi-6295648f04d1d5d7e8b99d3fdaa8d497406eadf9.tar.gz kmi-6295648f04d1d5d7e8b99d3fdaa8d497406eadf9.zip | |
continue documentation
| -rw-r--r-- | include/apos/mem.h | 6 | ||||
| -rw-r--r-- | include/apos/mem_regions.h | 208 | ||||
| -rw-r--r-- | include/apos/nodes.h | 53 |
3 files changed, 262 insertions, 5 deletions
diff --git a/include/apos/mem.h b/include/apos/mem.h index a0f32f5..20293db 100644 --- a/include/apos/mem.h +++ b/include/apos/mem.h @@ -159,6 +159,8 @@ */ #define order_bit(idx) ((idx) & (MM_OINFO_WIDTH - 1)) +/** @todo Get rid of slightly ugly __* syntax, as these aren't static. */ + /** * Convert physical address to virtual address in direct mapping. * @@ -178,7 +180,7 @@ /** * Get page number of physical address. * - * @todo Isn't this the same as \ref pnum_to_pm()? + * @todo Isn't this the same as \ref pm_to_pnum()? * * @param x Physical address. * @return Corresponding page number. @@ -214,7 +216,7 @@ #define MR_OWNED (1 << 10) /** Copy on write. */ #define MR_COW (1 << 11) -/** Don't free memory on flush. */ +/** Don't free memory on clear. */ #define MR_KEEP (1 << 12) /** @} */ diff --git a/include/apos/mem_regions.h b/include/apos/mem_regions.h index 38629f2..2eaef8c 100644 --- a/include/apos/mem_regions.h +++ b/include/apos/mem_regions.h @@ -8,47 +8,200 @@ */ #include <apos/mem.h> +#include <arch/vmem.h> #include <apos/types.h> #include <apos/sp_tree.h> -#include <arch/vmem.h> +/** + * 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 is owned. + * + * @param r Memory region to check. + * @return \c 0 if not owned, non-zero otherwise. + */ #define is_region_owned(r) is_set(r->flags, MR_OWNED) + +/** + * Check if region is shared. + * + * @param r Memory region to check. + * @return \c 0 if not shared, non-zero otherwise. + */ #define is_region_shared(r) is_set(r->flags, MR_SHARED) + +/** + * 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; + /** Memory region flags, both access as well as metadata. \see MR_USED, + * MR_SHARED, MR_OWNED, MR_COW, MR_KEEP. */ vmflags_t flags; + /** End address of memory region. */ vm_t end; + + /** Start address of memory region. */ vm_t start; }; +/** + * 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 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); @@ -71,10 +224,61 @@ 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); -vm_t map_fill_region(struct vmem *b, region_callback_t *mem_handler, +/** + * 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); diff --git a/include/apos/nodes.h b/include/apos/nodes.h index 3fefc4c..6cec21c 100644 --- a/include/apos/nodes.h +++ b/include/apos/nodes.h @@ -9,32 +9,83 @@ #include <apos/types.h> -enum node_status { FREE = 0, USED = 1 }; +/** Node slot status. */ +enum node_status { + /** Free. */ + FREE = 0, + + /** Used. */ + USED = 1 +}; + +/** Header for a region in memory with node slots. */ struct node_region { + /** Number of used slots in this region. + * \note Total number of slots is calculated on an instance basis. */ size_t used_nodes; + /** Next node region in free list. */ struct node_region *av_next; + + /** Previous node region in free list. */ struct node_region *av_prev; + /** Next node slot region. */ struct node_region *next; + + /** Previous slot node region. */ struct node_region *prev; }; +/** Node subsystem instance. */ struct node_root { + /** Size of each node. */ size_t node_size; + /** Maximum number of node slots in one region. */ size_t max_nodes; + /** Offset of node slot state bitmap from start of region. */ ptrdiff_t bitmap; + + /** Offset of first node from start of region. */ ptrdiff_t first_node; + /** List of all node regions. */ struct node_region *head; + + /** List of node regions with free slots. */ struct node_region *av_head; }; +/** + * Initialize node subsystem instance. + * + * @param r Node region root. + * @param node_size Size of one node. + */ void init_nodes(struct node_root *r, size_t node_size); + +/** + * Destroy node subsystem instance. + * + * @param r Node region root. + */ void destroy_nodes(struct node_root *r); +/** + * Allocate a new node. + * + * @param r Node region root. + * @return Pointer to allocated node when succesful, \c 0 otherwise. + */ void *get_node(struct node_root *r); + +/** + * Free a node. + * + * @param r Node region root. + * @param p Pointer to node to free. + */ void free_node(struct node_root *r, void *p); #endif /* APOS_NODES_H */ |
