1/* 2 * Copyright 2016, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(D61_BSD) 11 */ 12 13#include <autoconf.h> 14#include <stdio.h> 15#include <stdint.h> 16#include <stdarg.h> 17#include <assert.h> 18#include <sys/mman.h> 19#include <utils/arith.h> 20 21#include <refos/vmlayout.h> 22#include <refos-io/internal_state.h> 23#include <refos-io/ipc_state.h> 24#include <refos-util/dprintf.h> 25#include <refos-util/init.h> 26 27#define _ENOMEM 12 28 29/*! How many pages of memory to expand the heap every increment. 30 Too small and this leads to many many expensive resizing operations, too large and we allocate 31 all this uneccessary memory and never use it. 32*/ 33#define REFOSIO_HEAP_EXPAND_INCREMENT_NPAGES 2 34 35int refosio_morecore_expand(sl_dataspace_t *region, size_t sizeAdd); 36 37long 38sys_brk(va_list ap) 39{ 40 uintptr_t newbrk = va_arg(ap, uintptr_t); 41 42 /* Static more-core override mode. */ 43 if (refosIOState.staticMoreCoreOverride != NULL) { 44 uintptr_t ret = (uintptr_t) 0; 45 if (!newbrk) { 46 /* If the newbrk is 0, we return the bottom of the static heap */ 47 ret = refosIOState.staticMoreCoreOverrideBase; 48 } else if (newbrk < refosIOState.staticMoreCoreOverrideTop && 49 newbrk > (uintptr_t)&refosIOState.staticMoreCoreOverride[0]) { 50 ret = refosIOState.staticMoreCoreOverrideBase = newbrk; 51 } else { 52 seL4_DebugPrintf("ERROR: refos static sbrk out of memory.\n"); 53 assert(!"ERROR: refos static sbrk out of memory."); 54 ret = -_ENOMEM; 55 } 56 57 return ret; 58 } 59 60 /* Dynamic more-core sbrk mode. */ 61 if (!refosIOState.dynamicHeap) { 62 seL4_DebugPrintf("Morecore not available. Please call refosio_setup_morecore_override.\n"); 63 assert(!"Morecore not available. Please call refosio_setup_morecore_override."); 64 return -_ENOMEM; 65 } 66 assert(refosIOState.procInfo); 67 assert(refosIOState.procInfo->magic == SELFLOADER_PROCINFO_MAGIC); 68 69 if (!newbrk) { 70 /* Assign to bottom of dynamic heap address. */ 71 assert(refosIOState.procInfo->heapRegion.vaddr); 72 return refosIOState.procInfo->heapRegion.vaddr; 73 } else if (newbrk < refosIOState.procInfo->heapRegion.vaddr) { 74 /* Invalid brk location. */ 75 return -ENOMEM; 76 } else if (newbrk < refosIOState.procInfo->heapRegion.vaddr + 77 refosIOState.procInfo->heapRegion.size) { 78 /* Our current heap region is large enough. */ 79 return newbrk; 80 } 81 82 /* Our current heap region is too small expand the window and dataspace. */ 83 /* First work out the increase in size. */ 84 uint32_t increaseSize = (newbrk + 1) - 85 (refosIOState.procInfo->heapRegion.vaddr + refosIOState.procInfo->heapRegion.size); 86 assert(increaseSize > 0); 87 uint32_t increaseSizePages = refos_round_up_npages(increaseSize); 88 increaseSizePages = MAX(increaseSizePages, REFOSIO_HEAP_EXPAND_INCREMENT_NPAGES); 89 90 /* Then expand the region and dataspace. */ 91 refosio_internal_save_IPC_buffer(); 92 int error = refosio_morecore_expand(&refosIOState.procInfo->heapRegion, 93 increaseSizePages * REFOS_PAGE_SIZE); 94 if (error != ESUCCESS) { 95 seL4_DebugPrintf("ERROR: refos dynamic sbrk out of memory.\n"); 96 assert(!"ERROR: refos dynamic sbrk out of memory."); 97 return -_ENOMEM; 98 } 99 refosio_internal_restore_IPC_buffer(); 100 101 /* New size should now be lower. */ 102 if (newbrk < refosIOState.procInfo->heapRegion.vaddr + refosIOState.procInfo->heapRegion.size) { 103 return newbrk; 104 } 105 106 seL4_DebugPrintf("ERROR: corruption detected, this should never happen.\n"); 107 assert(!"ERROR: corruption detected, this should never happen."); 108 return -_ENOMEM; 109} 110 111long 112sys_mmap2(va_list ap) 113{ 114 char *addr = va_arg(ap, char*); 115 unsigned int length = va_arg(ap, unsigned int); 116 int prot = va_arg(ap, int); 117 int flags = va_arg(ap, int); 118 int fd = va_arg(ap, int); 119 off_t offset = va_arg(ap, int); 120 121 (void) prot; 122 (void) offset; 123 (void) fd; 124 (void) addr; 125 126 /* Static more-core override mode. */ 127 if (refosIOState.staticMoreCoreOverride != NULL) { 128 if (flags & MAP_ANONYMOUS) { 129 /* Steal from the top of the static region. */ 130 uintptr_t base = refosIOState.staticMoreCoreOverrideTop - length; 131 if (base < refosIOState.staticMoreCoreOverrideBase) { 132 assert(!"ERROR: refos static mmap out of memory."); 133 return -_ENOMEM; 134 } 135 refosIOState.staticMoreCoreOverrideTop = base; 136 return base; 137 } 138 assert(!"File mapping not implemented."); 139 return -_ENOMEM; 140 } 141 142 if (!refosIOState.dynamicMMap) { 143 seL4_DebugPrintf("MMap not available. Please call refosio_setup_morecore_override.\n"); 144 assert(!"MMap not available. Please call refosio_setup_morecore_override."); 145 return -_ENOMEM; 146 } 147 148 /* Dynamic more-core mmap mode. */ 149 if (flags & MAP_ANONYMOUS) { 150 uint32_t vaddr = 0; 151 uint32_t sizeNPages = refos_round_up_npages(length); 152 153 /* Allocate pages and map window. */ 154 refosio_internal_save_IPC_buffer(); 155 int error = refosio_mmap_anon(&refosIOState.mmapState, sizeNPages, &vaddr); 156 if (error != ESUCCESS || !vaddr) { 157 seL4_DebugPrintf("refosio_mmap_anon mapping failed.\n"); 158 return -_ENOMEM; 159 } 160 refosio_internal_restore_IPC_buffer(); 161 162 return vaddr; 163 } 164 165 seL4_DebugPrintf("File mapping not implemented.\n"); 166 assert(!"File mapping not implemented."); 167 return -_ENOMEM; 168} 169 170long 171sys_munmap(va_list ap) 172{ 173 char *addr = va_arg(ap, char*); 174 unsigned int length = va_arg(ap, unsigned int); 175 176 if (!length) { 177 return 0; 178 } 179 180 /* Static more-core override mode. */ 181 if (refosIOState.staticMoreCoreOverride != NULL) { 182 /* Do nothing here. Don't unmap static morecore. */ 183 return 0; 184 } 185 186 if (!refosIOState.dynamicMMap) { 187 /* No mmap. How can we possibly have munmap? This is madness. */ 188 return -1; 189 } 190 191 if ((uint32_t)addr >= PROCESS_MMAP_BOT && (uint32_t)addr < PROCESS_MMAP_TOP) { 192 uint32_t sizeNPages = refos_round_up_npages(length); 193 int error = refosio_munmap_anon(&refosIOState.mmapState, (uint32_t) addr, sizeNPages); 194 if (error != ESUCCESS) { 195 seL4_DebugPrintf("refosio_munmap_anon mapping failed. Ignoring unmap.\n"); 196 return -1; 197 } 198 return 0; 199 } 200 201 return 0; 202} 203