diff --git a/hermit/include/hermit/stdlib.h b/hermit/include/hermit/stdlib.h index 634d30376..9468133bd 100644 --- a/hermit/include/hermit/stdlib.h +++ b/hermit/include/hermit/stdlib.h @@ -96,6 +96,27 @@ int destroy_stack(void* addr, size_t sz); */ void kfree(void* addr); +/** @brief Kernel's more general memory allocator function. + * + * This function lets you choose flags for the newly allocated memory. + * The new region is always page aligned. + * + * @param sz Desired size of the new memory + * @param flags Flags to specify + * + * @return Pointer to the new memory range + */ +void* page_alloc(size_t sz, uint32_t flags); + +/** @brief Kernel's more general release function. + * + * This function is the complement of page_allocation. + * + * @param addr Pointer to the memory range + * @param sz Desired size of the new memory + */ +void page_free(void* addr, size_t sz); + /** @brief String to long * * @return Long value of the parsed numerical string diff --git a/hermit/mm/memory.c b/hermit/mm/memory.c index 5fc7df2fc..0c054285f 100644 --- a/hermit/mm/memory.c +++ b/hermit/mm/memory.c @@ -152,6 +152,60 @@ out_err: return -ENOMEM; } +void* page_alloc(size_t sz, uint32_t flags) +{ + size_t viraddr = 0; + size_t phyaddr; + uint32_t npages = PAGE_FLOOR(sz) >> PAGE_BITS; + size_t pflags = PG_PRESENT|PG_GLOBAL|PG_XD; + + if (BUILTIN_EXPECT(!npages, 0)) + goto oom; + + viraddr = vma_alloc(PAGE_FLOOR(sz), flags); + if (BUILTIN_EXPECT(!viraddr, 0)) + goto oom; + + phyaddr = get_pages(npages); + if (BUILTIN_EXPECT(!phyaddr, 0)) + { + vma_free(viraddr, viraddr+npages*PAGE_SIZE); + viraddr = 0; + goto oom; + } + + if (flags & VMA_WRITE) + pflags |= PG_RW; + if (!(flags & VMA_CACHEABLE)) + pflags |= PG_PCD; + + int ret = page_map(viraddr, phyaddr, npages, pflags); + if (BUILTIN_EXPECT(ret, 0)) + { + vma_free(viraddr, viraddr+npages*PAGE_SIZE); + put_pages(phyaddr, npages); + viraddr = 0; + } + +oom: + return (void*) viraddr; +} + +void page_free(void* viraddr, size_t sz) +{ + size_t phyaddr; + + if (BUILTIN_EXPECT(!viraddr || !sz, 0)) + return; + + phyaddr = virt_to_phys((size_t)viraddr); + + vma_free((size_t) viraddr, (size_t) viraddr + PAGE_FLOOR(sz)); + + if (phyaddr) + put_pages(phyaddr, PAGE_FLOOR(sz) >> PAGE_BITS); +} + int memory_init(void) { size_t addr, image_size = (size_t) &kernel_end - (size_t) &kernel_start;