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/** 30 * \brief Map the memory object into a region 31 * 32 * \param memobj The memory object 33 * \param region The region to add 34 */ 35static errval_t map_region(struct memobj *memobj, struct vregion *vregion) 36{ 37 struct memobj_append *append = (struct memobj_append*) memobj; 38 39 /* make sure we are not overshooting the end */ 40 assert(memobj->size >= (vregion->offset + vregion->size)); 41 42 /* the vregion must start at the beginning of the memobj */ 43 if (vregion->offset != 0) { 44 return LIB_ERR_MEMOBJ_MAP_REGION; 45 } 46 47 if (append->vregion) { 48 return LIB_ERR_MEMOBJ_VREGION_ALREADY_MAPPED; 49 } 50 51 append->vregion = vregion; 52 53 return SYS_ERR_OK; 54} 55 56/** 57 * \brief Unmap the memory object from a region 58 * 59 * \param memobj The memory object 60 * \param region The region to remove 61 */ 62static errval_t unmap_region(struct memobj *memobj, struct vregion *vregion) 63{ 64 struct memobj_append *append = (struct memobj_append*) memobj; 65 errval_t err; 66 67 if (append->vregion != vregion) { 68 return LIB_ERR_VSPACE_VREGION_NOT_FOUND; 69 } 70 71 struct vspace *vspace = vregion_get_vspace(vregion); 72 struct pmap *pmap = vspace_get_pmap(vspace); 73 74 genvaddr_t vregion_base = vregion_get_base_addr(vregion); 75 genvaddr_t vregion_offset = vregion_get_offset(vregion); 76 77 err = pmap->f.unmap(pmap, vregion_base + vregion_offset, vregion->size, 78 NULL); 79 if (err_is_fail(err)) { 80 return err_push(err, LIB_ERR_PMAP_UNMAP); 81 } 82 83 append->vregion = NULL; 84 85 return SYS_ERR_OK; 86} 87 88/** 89 * \brief Set the protection on a range 90 * 91 * \param memobj The memory object 92 * \param region The vregion to modify the mappings on 93 * \param offset Offset into the memory object 94 * \param range The range of space to set the protection for 95 * \param flags The protection flags 96 */ 97static errval_t protect(struct memobj *memobj, 98 struct vregion *vregion, 99 genvaddr_t offset, 100 size_t range, 101 vs_prot_flags_t flags) 102{ 103 struct memobj_append *append = (struct memobj_append *) memobj; 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 assert(vregion_get_offset(vregion) == 0); 109 errval_t err; 110 size_t ret_size; 111 112 // short-circuit small requests 113 if (range <= BASE_PAGE_SIZE) { 114 err = pmap->f.modify_flags(pmap, base + offset, range, 115 flags, &ret_size); 116 if (err_is_fail(err)) { 117 return err_push(err, LIB_ERR_PMAP_MODIFY_FLAGS); 118 } 119 return SYS_ERR_OK; 120 } else if (offset == 0 && range > append->offsets[append->first_free_frame-1]) { 121 // need to call modify_flags on every frame 122 for (int i = 0; i < append->first_free_frame && range; i++) { 123 size_t fsize = append->frame_sizes[i]; 124 size_t to_protect = fsize < range ? fsize : range; 125 126 assert(to_protect > 0); 127 err = pmap->f.modify_flags(pmap, base + offset, to_protect, 128 flags, &ret_size); 129 /* 130 err = invoke_frame_modify_flags(append->frames[i], 0, 131 to_protect / BASE_PAGE_SIZE, flags, base + offset); 132 */ 133 if (err_is_fail(err)) { 134 return err_push(err, LIB_ERR_PMAP_MODIFY_FLAGS); 135 } 136 range -= ret_size; 137 offset += ret_size; 138 } 139 return SYS_ERR_OK; 140 } else { 141 142#if 1 143 // binary search 144 int imin = 0; 145 int imax = append->first_free_frame - 1; 146 int first_idx = -1; 147 int found = 0; 148 while (!found && (imin <= imax)) { 149 int imid = (imin + imax) / 2; 150// debug_printf("imin=%d, imid=%d, imax=%d\n", imin, imid, imax); 151 genvaddr_t mid_offset = append->offsets[imid]; 152 if (mid_offset < offset) { 153 imin = imid + 1; 154 } else if (mid_offset > offset) { 155 imax = imid - 1; 156 } else { 157 first_idx = imid; 158 found = 1; 159 } 160 } 161 if (!found) { 162 first_idx = imax; 163 } 164 165#else 166 // linear search 167 int first_idx = -1; 168 for (first_idx = 0; 169 first_idx < append->first_free_frame && append->offsets[first_idx] < offset; 170 first_idx++); 171 // XXX Bug: Do not adjust if we find last frame 172 first_idx -= 1; 173#endif 174 175#if 0 176 debug_printf("offset -> %zx range -> %zx flags -> %zu\n", offset, range, (size_t) flags); 177 for (int i = 0; i < append->first_free_frame; i++) { 178 debug_printf("offsets[%d] = %"PRIxGENVADDR"\n", i, append->offsets[i]); 179 } 180 debug_printf("offset = %zx --> index = %d -> %zx, %zx\n", offset, first_idx, 181 append->offsets[first_idx], first_idx < append->first_free_frame-1 ? append->offsets[first_idx+1] : 0x0); 182#endif 183 184 while(range) { 185 size_t fsize = append->frame_sizes[first_idx] - (offset - append->offsets[first_idx]); 186 size_t to_protect = fsize < range ? fsize : range; 187 188 /// XXX: offset % BASE_PAGE_SIZE != 0? 189 err = pmap->f.modify_flags(pmap, base + offset, to_protect, 190 flags, &ret_size); 191 /* 192 err = invoke_frame_modify_flags(append->frames[i], 0, 193 to_protect / BASE_PAGE_SIZE, flags, base + offset); 194 */ 195 if (err_is_fail(err)) { 196 return err_push(err, LIB_ERR_PMAP_MODIFY_FLAGS); 197 } 198 range -= ret_size; 199 offset += ret_size; 200 first_idx++; 201 } 202 //USER_PANIC("memobj_append: protect: searching for frame NYI\n"); 203 } 204 205 return SYS_ERR_OK; 206} 207 208/** 209 * \brief Pin a range 210 * 211 * \param memobj The memory object 212 * \param region The vregion to modify the state on 213 * \param offset Offset into the memory object 214 * \param range The range of space to pin 215 */ 216static errval_t pin(struct memobj *memobj, 217 struct vregion *vregion, 218 genvaddr_t offset, 219 size_t range) 220{ 221 USER_PANIC("NYI"); 222} 223 224/** 225 * \brief Unpin a range 226 * 227 * \param memobj The memory object 228 * \param region The vregion to modify the state on 229 * \param offset Offset into the memory object 230 * \param range The range of space to unpin 231 */ 232static errval_t unpin(struct memobj *memobj, 233 struct vregion *vregion, 234 genvaddr_t offset, 235 size_t range) 236{ 237 USER_PANIC("NYI"); 238} 239 240/** 241 * \brief Set a frame for an offset into the memobj 242 * 243 * \param memobj The memory object 244 * \param offset Offset into the memory object 245 * \param frame The frame cap for the offset 246 * \param frame_offset The offset into the frame cap 247 * 248 * Pagefault relies on frames inserted in order 249 */ 250static errval_t fill(struct memobj *memobj, 251 genvaddr_t offset, 252 struct capref frame, 253 size_t frame_offset) 254{ 255 struct memobj_append *append = (struct memobj_append*) memobj; 256 257 size_t slot = append->first_free_frame; 258 assert(slot <= append->frame_count); 259 260 // XXX: better error checking 261 if (offset > 0 && offset < append->offsets[slot-1]) { 262 return LIB_ERR_MEMOBJ_FILL; 263 } 264 265 if (slot == append->frame_count) { 266 // grow arrays 267 size_t new_count = append->frame_count * 2; 268 void *f = realloc(append->frames, new_count * sizeof(struct capref)); 269 void *o = realloc(append->offsets, new_count * sizeof(genvaddr_t)); 270 void *s = realloc(append->frame_sizes, new_count * sizeof(size_t)); 271 void *fo = realloc(append->frame_offsets, new_count * sizeof(size_t)); 272 if (!f || !o || !s || !fo) { 273 return LIB_ERR_MALLOC_FAIL; 274 } 275 append->frames = f; 276 append->offsets = o; 277 append->frame_sizes = s; 278 append->frame_offsets = fo; 279 memset(&append->frames[append->first_free_frame], 280 0, append->frame_count * sizeof(struct capref)); 281 memset(&append->offsets[append->first_free_frame], 282 0, append->frame_count * sizeof(genvaddr_t)); 283 memset(&append->frame_sizes[append->first_free_frame], 284 0, append->frame_count * sizeof(size_t)); 285 memset(&append->frame_offsets[append->first_free_frame], 286 0, append->frame_count * sizeof(size_t)); 287 append->frame_count = new_count; 288 } 289 290 if (!capref_is_null((append->frames[slot]))) { 291 return LIB_ERR_MEMOBJ_DUPLICATE_FILL; 292 } 293 294 struct frame_identity fi; 295 errval_t err = frame_identify(frame, &fi); 296 assert(err_is_ok(err)); 297 298 append->frames[slot] = frame; 299 append->offsets[slot] = offset; 300 append->frame_sizes[slot] = fi.bytes; 301 append->frame_offsets[slot] = frame_offset; 302 append->first_free_frame++; 303 304 return SYS_ERR_OK; 305} 306 307/** 308 * \brief Unmap/remove one frame from the end of the memobj 309 * 310 * \param memobj The memory object 311 * \param offset The offset from which to remove a frame from 312 * \param ret_frame Pointer to return the removed frame 313 * 314 */ 315static errval_t unfill(struct memobj *memobj, 316 genvaddr_t offset, 317 struct capref *ret_frame, 318 genvaddr_t *ret_offset) 319{ 320 USER_PANIC("NYI\n"); 321 // this might be implemented as removing the last frame in the obj 322} 323 324/** 325 * \brief Page fault handler 326 * 327 * \param memobj The memory object 328 * \param region The associated vregion 329 * \param offset Offset into memory object of the page fault 330 * \param type The fault type 331 * 332 * Locates the frame for the offset and maps it in. 333 * Relies on fill inserting frames in order. 334 */ 335static errval_t pagefault(struct memobj *memobj, 336 struct vregion *vregion, 337 genvaddr_t offset, 338 vm_fault_type_t type) 339{ 340 errval_t err; 341 struct memobj_append *append = (struct memobj_append*) memobj; 342 343 assert(!(offset % BASE_PAGE_SIZE)); 344 assert(offset == append->already_faulted); 345 346 size_t first_unfaulted = append->first_unfaulted; 347 348 if (capref_is_null(append->frames[first_unfaulted])) { 349 return LIB_ERR_MEMOBJ_PAGEFAULT_HANDLER; 350 } 351 352 struct vspace *vspace = vregion_get_vspace(vregion); 353 struct pmap *pmap = vspace_get_pmap(vspace); 354 355 genvaddr_t base = vregion_get_base_addr(vregion); 356 assert(vregion_get_offset(vregion) == 0); 357 vregion_flags_t flags = vregion_get_flags(vregion); 358 359 size_t retsize; 360 err = pmap->f.map(pmap, base + offset, append->frames[first_unfaulted], 361 append->frame_offsets[first_unfaulted], 362 append->frame_sizes[first_unfaulted], flags, 363 NULL, &retsize); 364 if (err_is_fail(err)) { 365 return err_push(err, LIB_ERR_PMAP_MAP); 366 } 367 // update metadata 368 append->first_unfaulted++; 369 append->already_faulted += retsize; 370 371 return SYS_ERR_OK; 372} 373 374/** 375 * \brief Free up some pages by placing them in the backing storage 376 * 377 * \param memobj The memory object 378 * \param size The amount of space to free up 379 * \param frames An array of capref frames to return the freed pages 380 * \param num_frames The number of frames returned 381 * 382 * This will affect all the vregions that are associated with the object 383 */ 384static errval_t pager_free(struct memobj *memobj, 385 size_t size, 386 struct capref *frames, 387 size_t num_frames) 388{ 389 USER_PANIC("NYI"); 390} 391 392/** 393 * \brief Initialize 394 * 395 * \param memobj The memory object 396 * \param size Size of the memory region 397 * \param flags Memory object specific flags 398 * 399 * This object handles multiple frames. 400 * The frames are mapped in on demand. 401 */ 402errval_t memobj_create_append(struct memobj_append *append, 403 size_t size, 404 memobj_flags_t flags) 405{ 406 struct memobj *memobj = &append->m; 407 408 /* Generic portion */ 409 memobj->f.map_region = map_region; 410 memobj->f.unmap_region = unmap_region; 411 memobj->f.protect = protect; 412 memobj->f.pin = pin; 413 memobj->f.unpin = unpin; 414 memobj->f.fill = fill; 415 memobj->f.unfill = unfill; 416 memobj->f.pagefault = pagefault; 417 memobj->f.pager_free = pager_free; 418 419 memobj->size = size; 420 memobj->flags = flags; 421 422 memobj->type = MEMOBJ_APPEND; 423 424 /* specific portion */ 425 append->vregion = NULL; 426 427#define INIT_FRAME_COUNT 8 428 size_t count = append->frame_count = INIT_FRAME_COUNT; 429 append->first_free_frame = 0; 430 append->first_unfaulted = 0; 431 432 append->frames = malloc(count * sizeof(struct capref)); 433 if (!append->frames) { 434 return LIB_ERR_MALLOC_FAIL; 435 } 436 memset(append->frames, 0, count * sizeof(struct capref)); 437 438 append->offsets = malloc(count * sizeof(genvaddr_t)); 439 if (!append->offsets) { 440 free(append->frames); 441 return LIB_ERR_MALLOC_FAIL; 442 } 443 memset(append->offsets, 0, count * sizeof(genvaddr_t)); 444 445 append->frame_sizes = malloc(count * sizeof(size_t)); 446 if (!append->frame_sizes) { 447 free(append->frames); 448 free(append->offsets); 449 return LIB_ERR_MALLOC_FAIL; 450 } 451 memset(append->frame_sizes, 0, count * sizeof(size_t)); 452 453 append->frame_offsets = malloc(count * sizeof(size_t)); 454 if (!append->frame_offsets) { 455 free(append->frames); 456 free(append->offsets); 457 free(append->frame_sizes); 458 return LIB_ERR_MALLOC_FAIL; 459 } 460 memset(append->frame_offsets, 0, count * sizeof(size_t)); 461 462 return SYS_ERR_OK; 463} 464 465/** 466 * \brief Destroy the object 467 * 468 */ 469errval_t memobj_destroy_append(struct memobj *memobj) 470{ 471 struct memobj_append *m = (struct memobj_append *) memobj; 472 473 errval_t err = SYS_ERR_OK; 474 475 err = vregion_destroy(m->vregion); 476 free(m->frames); 477 free(m->offsets); 478 free(m->frame_sizes); 479 return err; 480} 481