/* * \brief Memory subsystem * \author Thomas Friebel * \author Christian Helmuth * \date 2006-11-03 * * The memory subsystem provides the backing store for DMA-able memory via * large malloc and slabs. * * FIXME check thread-safety and add locks where appropriate */ #include "ddekit/memory.h" #include "ddekit/panic.h" extern void * linux_kmalloc (unsigned int size, int priority); extern void linux_kfree (void *p); /**************** ** Page cache ** ****************/ /* FIXME revisit two-linked-lists approach - we could get rid of the * pcache_free lists, because these descriptors can also be allocated * whenever the need arises. (XXX: Check how this hurts performance.) */ /***************************************************************************** DDEKit maintains a list of free pages that can be used for growing existing DDEKit slabs. We distinguish between 2 types of pages: the ones that have been allocated from physically contiguous dataspaces and the the ones that have not. For each type of cache, we maintain two lists: a list of free pages that can be used to grow a cache (pcache_used) and a list of free pcache entries that can be used to store pages when they get freed (pcache_free). The reason for this is that by using these two lists, cache operations can be done atomically using cmpxchg. The function ddekit_slab_setup_page_cache() is used to tune the number of cached pages. ******************************************************************************/ /* page cache to minimize allocations from external servers */ struct ddekit_pcache { struct ddekit_pcache *next; void *page; int contig; }; /** * Setup page cache for all slabs * * \param pages maximal number of memory pages * * If the maximal number of unused pages is exceeded, subsequent deallocation * will be freed at the memory server. This page cache caches pages from all * slabs. */ void ddekit_slab_setup_page_cache(unsigned pages) { } /******************************* ** Slab cache implementation ** *******************************/ /* ddekit slab facilitates l4slabs */ struct ddekit_slab { int size; int contiguous; }; /** * Allocate object in slab */ void *ddekit_slab_alloc(struct ddekit_slab * slab) { if (slab->contiguous) return linux_kmalloc (slab->size, 0); else return ddekit_simple_malloc (slab->size); } /** * Free object in slab */ void ddekit_slab_free(struct ddekit_slab * slab, void *objp) { if (slab->contiguous) linux_kfree (objp); else ddekit_simple_free (objp); } /** * Store user pointer in slab cache */ void ddekit_slab_set_data(struct ddekit_slab * slab, void *data) { #if 0 l4slab_set_data(&slab->cache, data); #endif } /** * Read user pointer from slab cache */ void *ddekit_slab_get_data(struct ddekit_slab * slab) { #if 0 return l4slab_get_data(&slab->cache); #endif return NULL; } /** * Destroy slab cache * * \param slab pointer to slab cache structure */ void ddekit_slab_destroy (struct ddekit_slab * slab) { ddekit_simple_free(slab); } /** * Initialize slab cache * * \param size size of cache objects * \param contiguous make this slab use physically contiguous memory * * \return pointer to new slab cache or 0 on error */ struct ddekit_slab * ddekit_slab_init(unsigned size, int contiguous) { struct ddekit_slab * slab; slab = (struct ddekit_slab *) ddekit_simple_malloc(sizeof(*slab)); slab->size = size; slab->contiguous = contiguous; return slab; } /********************************** ** Large block memory allocator ** **********************************/ /** * Free large block of memory * * This is no useful for allocation < page size. * * TODO The freed memory can be cached and will be still accessible ( * no page fault when accessed). I hope it won't caused any troubles. */ void ddekit_large_free(void *objp) { linux_kfree (objp); } /** * Allocate large block of memory * * This is no useful for allocation < page size. */ void *ddekit_large_malloc(int size) { return linux_kmalloc (size, 0); } /** * Allocate large block of memory (special interface) * * This is no useful for allocation < page size. * * FIXME implementation missing... */ void *ddekit_contig_malloc(unsigned long size, unsigned long low, unsigned long high, unsigned long alignment, unsigned long boundary) { #if 0 void *res; int err; int pages; l4_size_t tmp; l4dm_mem_addr_t dm_paddr; size = l4_round_page(size); pages = size >> L4_PAGESHIFT; res = l4dm_mem_allocate_named(size, L4DM_CONTIGUOUS | L4DM_PINNED | L4RM_MAP | L4RM_LOG2_ALIGNED); if (res) { /* check if res meets low/high/alignment/boundary * and panic if it is not the case * XXXY */ /* get physical address */ err = l4dm_mem_phys_addr(res, 1, &dm_paddr, 1, &tmp); if (err != 1) ddekit_debug("contigmalloc: error getting physical address of new page!\n"); /* set PTE */ ddekit_set_ptes(res, dm_paddr.addr, pages, PTE_TYPE_CONTIG); } return res; #else ddekit_debug("%s: not implemented\n", __func__); return 0; #endif }