1/** 2 * \file 3 * \brief memory object of anonymous type. 4 * The object maintains a list of frames. 5 * 6 * The object maintains a list of frames and a list of vregions. 7 * The lists are backed by slabs. 8 * The slabs may have to be grown, 9 * in which case the object will use #vspace_pinned_alloc. 10 * 11 * morecore uses this memory object so it cannot use malloc for its lists. 12 * Therefore, this uses slabs and grows them using the pinned memory. 13 */ 14 15/* 16 * Copyright (c) 2009, 2010, 2011, ETH Zurich. 17 * All rights reserved. 18 * 19 * This file is distributed under the terms in the attached LICENSE file. 20 * If you do not find this file, copies can be found by writing to: 21 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 22 */ 23 24#include <string.h> 25 26#include <barrelfish/barrelfish.h> 27#include "vspace_internal.h" 28 29#define CHECK_FRAME_SIZE 0 30 31 32/** 33 * \brief Map the memory object into a region 34 * 35 * \param memobj The memory object 36 * \param region The region to add 37 */ 38static errval_t map_region(struct memobj *memobj, struct vregion *vregion) 39{ 40 struct memobj_numa *mo_numa = (struct memobj_numa*) memobj; 41 42 /* make sure we are not overshooting the end */ 43 assert(memobj->size >= (vregion->offset + vregion->size)); 44 45 /* the vregion must start at one of the backed frames */ 46 if (vregion->offset % mo_numa->stride) { 47 return LIB_ERR_MEMOBJ_MAP_REGION; 48 } 49 50 if (mo_numa->vregion) { 51 return LIB_ERR_MEMOBJ_VREGION_ALREADY_MAPPED; 52 } 53 54 mo_numa->vregion = vregion; 55 56 return SYS_ERR_OK; 57} 58 59/** 60 * \brief Unmap the memory object from a region 61 * 62 * \param memobj The memory object 63 * \param region The region to remove 64 */ 65static errval_t unmap_region(struct memobj *memobj, struct vregion *vregion) 66{ 67 struct memobj_numa *mo_numa = (struct memobj_numa*) memobj; 68 errval_t err; 69 70 if (mo_numa->vregion != vregion) { 71 return LIB_ERR_VSPACE_VREGION_NOT_FOUND; 72 } 73 74 struct vspace *vspace = vregion_get_vspace(vregion); 75 struct pmap *pmap = vspace_get_pmap(vspace); 76 77 genvaddr_t vreg_base = vregion_get_base_addr(vregion); 78 genvaddr_t vreg_offset = vregion_get_offset(vregion); 79 80 err = pmap->f.unmap(pmap, vreg_base + vreg_offset, vregion->size, NULL); 81 if (err_is_fail(err)) { 82 return err_push(err, LIB_ERR_PMAP_UNMAP); 83 } 84 85 mo_numa->vregion = NULL; 86 87 return SYS_ERR_OK; 88} 89 90/** 91 * \brief Set the protection on a range 92 * 93 * \param memobj The memory object 94 * \param region The vregion to modify the mappings on 95 * \param offset Offset into the memory object 96 * \param range The range of space to set the protection for 97 * \param flags The protection flags 98 */ 99static errval_t protect(struct memobj *memobj, 100 struct vregion *vregion, 101 genvaddr_t offset, 102 size_t range, 103 vs_prot_flags_t flags) 104{ 105 struct vspace *vspace = vregion_get_vspace(vregion); 106 struct pmap *pmap = vspace_get_pmap(vspace); 107 genvaddr_t base = vregion_get_base_addr(vregion); 108 genvaddr_t vregion_offset = vregion_get_offset(vregion); 109 errval_t err; 110 size_t ret_size; 111 err = pmap->f.modify_flags(pmap, base + offset + vregion_offset, range, 112 flags, &ret_size); 113 if (err_is_fail(err)) { 114 return err_push(err, LIB_ERR_PMAP_MODIFY_FLAGS); 115 } 116 117 return SYS_ERR_OK; 118} 119 120/** 121 * \brief Pin a range 122 * 123 * \param memobj The memory object 124 * \param region The vregion to modify the state on 125 * \param offset Offset into the memory object 126 * \param range The range of space to pin 127 */ 128static errval_t pin(struct memobj *memobj, 129 struct vregion *vregion, 130 genvaddr_t offset, 131 size_t range) 132{ 133 USER_PANIC("NYI"); 134 135 return SYS_ERR_OK; 136} 137 138/** 139 * \brief Unpin a range 140 * 141 * \param memobj The memory object 142 * \param region The vregion to modify the state on 143 * \param offset Offset into the memory object 144 * \param range The range of space to unpin 145 */ 146static errval_t unpin(struct memobj *memobj, 147 struct vregion *vregion, 148 genvaddr_t offset, 149 size_t range) 150{ 151 USER_PANIC("NYI"); 152 153 return SYS_ERR_OK; 154} 155 156/** 157 * \brief Set a frame for an offset into the memobj 158 * 159 * \param memobj The memory object 160 * \param offset Offset into the memory object 161 * \param frame The frame cap for the offset 162 * \param offset The offset into the frame cap 163 * 164 * Pagefault relies on frames inserted in order 165 */ 166static errval_t fill(struct memobj *memobj, 167 genvaddr_t offset, 168 struct capref frame, 169 size_t frame_offset) 170{ 171 struct memobj_numa *mo_numa = (struct memobj_numa*) memobj; 172 173 /* we take a single capability per node using offset as the node ID */ 174 if (offset >= mo_numa->node_count) { 175 return LIB_ERR_MEMOBJ_WRONG_OFFSET; 176 } 177 178 /* check if we already have a capability for that node */ 179 if (!capref_is_null((mo_numa->frames[offset]))) { 180 return LIB_ERR_MEMOBJ_DUPLICATE_FILL; 181 } 182 183#if CHECK_FRAME_SIZE 184 errval_t err; 185 186 /* we must make sure the frame is big enough */ 187 struct frame_identity fid; 188 189 err = frame_identify(frame, &fid); 190 if (err_is_fail(err)) { 191 return err_push(err, LIB_ERR_MEMOBJ_FILL); 192 } 193 194 if (fid.bytes < memobj->size / mo_numa->node_count) {\ 195 return LIB_ERR_MEMOBJ_FILL; 196 } 197 198#endif 199 200 mo_numa->frames[offset] = frame; 201 202 return SYS_ERR_OK; 203} 204 205/** 206 * \brief Unmap/remove one frame from the end of the memobj 207 * 208 * \param memobj The memory object 209 * \param offset The offset from which to remove a frame from 210 * \param ret_frame Pointer to return the removed frame 211 * 212 */ 213static errval_t unfill(struct memobj *memobj, 214 genvaddr_t offset, 215 struct capref *ret_frame, 216 genvaddr_t *ret_offset) 217{ 218 struct memobj_numa *mo_numa = (struct memobj_numa*) memobj; 219 220 /* we take a single capability per node using offset as the node ID */ 221 if (offset >= mo_numa->node_count) { 222 return LIB_ERR_MEMOBJ_WRONG_OFFSET; 223 } 224 225 /* check if we already have a capability for that node */ 226 if (capref_is_null((mo_numa->frames[offset]))) { 227 return LIB_ERR_MEMOBJ_UNFILL_TOO_HIGH_OFFSET; 228 } 229 230 if (ret_frame) { 231 *ret_frame = mo_numa->frames[offset]; 232 } 233 mo_numa->frames[offset] = NULL_CAP; 234 235 return SYS_ERR_OK; 236} 237 238 239/** 240 * \brief Page fault handler 241 * 242 * \param memobj The memory object 243 * \param region The associated vregion 244 * \param offset Offset into memory object of the page fault 245 * \param type The fault type 246 * 247 * Locates the frame for the offset and maps it in. 248 * Relies on fill inserting frames in order. 249 */ 250static errval_t pagefault(struct memobj *memobj, 251 struct vregion *vregion, 252 genvaddr_t offset, 253 vm_fault_type_t type) 254{ 255 errval_t err; 256 257 struct memobj_numa *mo_numa = (struct memobj_numa*) memobj; 258 259 assert(mo_numa->vregion == vregion); 260 261 size_t size = memobj->size; 262 263 for (uint32_t i = 0; i < mo_numa->node_count; ++i) { 264 if (capref_is_null(mo_numa->frames[i])) { 265 return LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER; 266 } 267 } 268 269 uint32_t node = 0; 270 271 struct vspace *vspace = vregion_get_vspace(vregion); 272 struct pmap *pmap = vspace_get_pmap(vspace); 273 genvaddr_t base = vregion_get_base_addr(vregion); 274 genvaddr_t vregion_offset = vregion_get_offset(vregion); 275 vregion_flags_t flags = vregion_get_flags(vregion); 276 277 lvaddr_t map_offset = 0; 278 lvaddr_t map_size = mo_numa->stride; 279 280 while(size) { 281 if (size < map_size) { 282 map_size = size; 283 } 284 285 //debug_printf("mapping: vaddr=%lx, node=%u, frameoffset=%lx\n", 286 // base + vregion_offset + offset, node, map_offset); 287 288 /* 289 * create a copy of the capability to map it as a capability can only 290 * be mapped once 291 */ 292 struct capref copy; 293 err = slot_alloc(©); 294 if (err_is_fail(err)) { 295 return err_push(err, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER); 296 } 297 298 err = cap_copy(copy, mo_numa->frames[node]); 299 if (err_is_fail(err)){ 300 return err_push(err, LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER); 301 } 302 303 /* map the copy */ 304 err = pmap->f.map(pmap, base + vregion_offset + offset, copy, 305 map_offset, map_size, flags, NULL, NULL); 306 if (err_is_fail(err)) { 307 return err_push(err, LIB_ERR_PMAP_MAP); 308 } 309 310 ++node; 311 size -= map_size; 312 offset += map_size; 313 314 if (node == mo_numa->node_count) { 315 node = 0; 316 map_offset += mo_numa->stride; 317 } 318 } 319 320 return SYS_ERR_OK; 321} 322 323/** 324 * \brief Free up some pages by placing them in the backing storage 325 * 326 * \param memobj The memory object 327 * \param size The amount of space to free up 328 * \param frames An array of capref frames to return the freed pages 329 * \param num_frames The number of frames returned 330 * 331 * This will affect all the vregions that are associated with the object 332 */ 333static errval_t pager_free(struct memobj *memobj, 334 size_t size, 335 struct capref *frames, 336 size_t num_frames) 337{ 338 USER_PANIC("NYI"); 339 340 return SYS_ERR_OK; 341} 342 343/** 344 * \brief Initialize 345 * 346 * \param memobj The memory object 347 * \param size Size of the memory region 348 * \param flags Memory object specific flags 349 * 350 * This object handles multiple frames. 351 * The frames are mapped in on demand. 352 */ 353errval_t memobj_create_numa(struct memobj_numa *mo_numa, 354 size_t size, 355 memobj_flags_t flags, 356 size_t node_count, 357 size_t stride) 358{ 359 struct memobj *memobj = &mo_numa->m; 360 361 assert((stride % BASE_PAGE_SIZE)==0); 362 363 /* Generic portion */ 364 memobj->f.map_region = map_region; 365 memobj->f.unmap_region = unmap_region; 366 memobj->f.protect = protect; 367 memobj->f.pin = pin; 368 memobj->f.unpin = unpin; 369 memobj->f.fill = fill; 370 memobj->f.unfill = unfill; 371 memobj->f.pagefault = pagefault; 372 memobj->f.pager_free = pager_free; 373 374 memobj->size = size; 375 memobj->flags = flags; 376 memobj->type = MEMOBJ_NUMA; 377 378 /* specific portion */ 379 mo_numa->node_count = node_count; 380 mo_numa->stride = stride; 381 mo_numa->vregion = NULL; 382 383 mo_numa->frames = calloc(node_count, sizeof(struct capref)); 384 if (mo_numa->frames == NULL) { 385 return LIB_ERR_MALLOC_FAIL; 386 } 387 388 return SYS_ERR_OK; 389} 390 391/** 392 * \brief Destroy the object 393 * 394 */ 395errval_t memobj_destroy_numa(struct memobj *memobj) 396{ 397 struct memobj_numa *mo_numa = (struct memobj_numa *) memobj; 398 399 errval_t err = SYS_ERR_OK; 400 401 struct vregion *vregion = mo_numa->vregion; 402 403 err = vregion_destroy(vregion); 404 if (mo_numa->frames) { 405 free(mo_numa->frames); 406 } 407 408 return err; 409} 410