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 "dataspace.h" 14#include "../../badge.h" 15#include "../../state.h" 16#include "../process/pid.h" 17#include <refos/refos.h> 18 19/*! @file 20 @brief Process Server anon RAM dataspace implementation. */ 21 22extern seL4_MessageInfo_t _dispatcherEmptyReply; 23 24/* --------------------------- RAM dataspace OAT callback functions ----------------------------- */ 25 26/*! @brief Dataspace OAT creation callback function. 27 28 This callback function is called by the OAT allocation helper library in <data_struct/coat.h>, 29 in order to create dataspace objects. Here we malloc some memory for the structure, initialise 30 its data structures, initialise its page array, and mint the dataspace badge capability. 31 32 @param oat The parent dataspace list (struct ram_dspace_list*). 33 @param id The dataspace ID allocated by the OAT table. 34 @param arg Arg[0] is the dataspace size, the rest unused. 35 @return A new dataspace (struct ram_dspace *) on success, NULL on error. (Transfers ownership) 36*/ 37static cvector_item_t 38ram_dspace_oat_create(coat_t *oat, int id, uint32_t arg[COAT_ARGS]) 39{ 40 struct ram_dspace *ndspace = malloc(sizeof(struct ram_dspace)); 41 if (!ndspace) { 42 ROS_ERROR("ram_dspace_oat_create out of memory!"); 43 return NULL; 44 } 45 memset(ndspace, 0, sizeof(struct ram_dspace)); 46 ndspace->magic = RAM_DATASPACE_MAGIC; 47 ndspace->ID = id; 48 ndspace->npages = (arg[0] / REFOS_PAGE_SIZE) + ((arg[0] % REFOS_PAGE_SIZE) ? 1 : 0); 49 ndspace->ref = 1; 50 ndspace->contentInitBitmask = NULL; 51 ndspace->contentInitEP.capPtr = 0; 52 ndspace->contentInitPID = PID_NULL; 53 ndspace->parentList = (struct ram_dspace_list *) oat; 54 assert(ndspace->parentList->magic == RAM_DATASPACE_LIST_MAGIC); 55 56 /* Initialise content init list. */ 57 cvector_init(&ndspace->contentInitWaitingList); 58 59 /* Create the page array. */ 60 ndspace->pages = kmalloc(sizeof(vka_object_t) * ndspace->npages); 61 if (!ndspace->pages) { 62 ROS_ERROR("ram_dspace_oat_create could not allocate page array, procserv out of mem!"); 63 goto exit1; 64 } 65 memset(ndspace->pages, 0, sizeof(vka_object_t) * ndspace->npages); 66 67 /* Mint the badged capability representing this ram dataspace. */ 68 ndspace->capability = procserv_mint_badge(RAM_DATASPACE_BADGE_BASE + id); 69 if (!ndspace->capability.capPtr) { 70 ROS_ERROR("ram_dspace_oat_create could not mint cap!"); 71 goto exit2; 72 } 73 74 return (cvector_item_t) ndspace; 75 76 /* Exit stack. */ 77exit2: 78 assert(ndspace->pages); 79 free(ndspace->pages); 80exit1: 81 free(ndspace); 82 return NULL; 83} 84 85/*! @brief Dataspace OAT deletion callback function. 86 87 This callback function is called by the OAT library defined in <data_struct/coat.h>, in order 88 to delete dataspace objects created by ram_dspace_oat_create(). It unmaps the dataspace from 89 all mapped windows, frees the caps, cslots, frames & frame arrays, and then the structure 90 itself. 91 92 @param oat The parent dataspace list (struct ram_dspace_list*). 93 @param obj The dataspace to delete (struct ram_dspace *) (Takes ownership). 94*/ 95static void 96ram_dspace_oat_delete(coat_t *oat, cvector_item_t *obj) 97{ 98 struct ram_dspace *rds = (struct ram_dspace *) obj; 99 assert(rds); 100 assert(rds->magic == RAM_DATASPACE_MAGIC); 101 102 /* Unmap everywhere where this dataspace has been mapped, by notifying the global procServ 103 window list that this dataspace has been deleted. This will loop through the windowList, 104 find any windows associated with this dspace, and unmap it and set back to EMPTY. 105 This potentially does VSpace mapping operations. 106 */ 107 w_purge_dspace(&procServ.windowList, rds); 108 109 /* We now should be at ref 0. */ 110 if (rds->ref != 0) { 111 ROS_WARNING("WARNING WARNING WARNING: RAM dataspace is being force released with hanging"); 112 ROS_WARNING("strong reference. This is most likely a procserv bug. The most likely cause"); 113 ROS_WARNING("is things such as a ring buffer object that has been attached to a"); 114 ROS_WARNING("dataspace, that belongs to a RDS list which has been freed."); 115 assert(!"RAM dspace hanging reference. Process server bug."); 116 } 117 118 /* Free the content initialised bitmask. */ 119 if (rds->contentInitBitmask) { 120 kfree(rds->contentInitBitmask); 121 rds->contentInitBitmask = NULL; 122 } 123 124 /* Free the content init endpoint & cslot. */ 125 if (rds->contentInitEnabled) { 126 assert(rds->contentInitEP.capPtr); 127 vka_cnode_revoke(&rds->contentInitEP); 128 vka_cnode_delete(&rds->contentInitEP); 129 vka_cspace_free(&procServ.vka, rds->contentInitEP.capPtr); 130 rds->contentInitPID = PID_NULL; 131 } 132 133 /* Clear the content init waiting list. */ 134 int waitingListCount = cvector_count(&rds->contentInitWaitingList); 135 for (int i = 0; i < waitingListCount; i++) { 136 struct ram_dspace_waiter *waiter = (struct ram_dspace_waiter *) 137 cvector_get(&rds->contentInitWaitingList, i); 138 assert(waiter && waiter->magic == RAM_DATASPACE_WAITER_MAGIC); 139 assert(waiter->reply.capPtr); 140 141 vka_cnode_revoke(&waiter->reply); 142 vka_cnode_delete(&waiter->reply); 143 vka_cspace_free(&procServ.vka, waiter->reply.capPtr); 144 kfree(waiter); 145 } 146 cvector_free(&rds->contentInitWaitingList); 147 148 /* Free the pages. */ 149 assert(rds->pages); 150 for (int i = 0; i < rds->npages; i++) { 151 if (rds->pages[i].cptr) { 152 cspacepath_t path; 153 vka_cspace_make_path(&procServ.vka, rds->pages[i].cptr, &path); 154 vka_cnode_revoke(&path); 155 if (rds->physicalAddrEnabled) { 156 /* Frames belong to a device, we do not own this frame. Just delete the cslot. */ 157 vka_cnode_delete(&path); 158 vka_cspace_free(&procServ.vka, path.capPtr); 159 } else { 160 /* We do own this anonymous dataspace frame. */ 161 vka_free_object(&procServ.vka, &rds->pages[i]); 162 } 163 } 164 } 165 kfree(rds->pages); 166 167 /* Free the capability. */ 168 assert(rds->capability.capPtr); 169 vka_cnode_revoke(&rds->capability); 170 vka_cnode_delete(&rds->capability); 171 vka_cspace_free(&procServ.vka, rds->capability.capPtr); 172 173 /* Free the actual window structure. */ 174 free(rds); 175} 176 177/* ------------------------------- RAM dataspace table functions -------------------------------- */ 178 179/*! @brief Calculates the page index into the dataspace based on the nbytes offset. 180 @param nbytes The offset into the ram dataspace. 181 @return The page index into the dataspace. 182 */ 183static inline uint32_t 184ram_dspace_get_index(size_t nbytes) 185{ 186 return (uint32_t)(nbytes / REFOS_PAGE_SIZE); 187} 188 189void 190ram_dspace_init(struct ram_dspace_list *rdslist) 191{ 192 assert(rdslist); 193 dprintf("Initialising RAM dataspace allocation table (max %d dspaces).\n", 194 RAM_DATASPACE_MAX_NUM_DATASPACE); 195 196 /* Configure the object allocation table creation / deletion callback func pointers. */ 197 rdslist->allocTable.oat_expand = NULL; 198 rdslist->allocTable.oat_create = ram_dspace_oat_create; 199 rdslist->allocTable.oat_delete = ram_dspace_oat_delete; 200 rdslist->magic = RAM_DATASPACE_LIST_MAGIC; 201 202 /* Initialise the allocation table. */ 203 coat_init(&rdslist->allocTable, 1, RAM_DATASPACE_MAX_NUM_DATASPACE); 204} 205 206void 207ram_dspace_deinit(struct ram_dspace_list *rdslist) 208{ 209 assert(rdslist); 210 for (int i = 1; i < RAM_DATASPACE_MAX_NUM_DATASPACE; i++) { 211 struct ram_dspace *dspace = ram_dspace_get(rdslist, i); 212 if (dspace) { 213 assert(dspace->magic == RAM_DATASPACE_MAGIC); 214 dspace->ref--; 215 } 216 } 217 coat_release(&rdslist->allocTable); 218} 219 220struct ram_dspace * 221ram_dspace_create(struct ram_dspace_list *rdslist, size_t size) 222{ 223 assert(rdslist); 224 uint32_t arg[COAT_ARGS]; 225 struct ram_dspace *dspace= NULL; 226 227 /* Allocate the dataspace ID and structure. */ 228 arg[0] = (uint32_t) size; 229 int ID = coat_alloc(&rdslist->allocTable, arg, (cvector_item_t *) &dspace); 230 if (ID == RAM_DATASPACE_INVALID_ID) { 231 ROS_ERROR("Could not allocate window."); 232 return NULL; 233 } 234 assert(dspace && dspace->magic == RAM_DATASPACE_MAGIC); 235 return dspace; 236} 237 238void 239ram_dspace_ref(struct ram_dspace_list *rdslist, int ID) 240{ 241 struct ram_dspace *dspace = ram_dspace_get(rdslist, ID); 242 if (!dspace) { 243 ROS_ERROR("ram_dspace_ref no such dataspace!"); 244 assert(!"ram_dspace_ref no such dataspace! Procserv book keeping error."); 245 return; 246 } 247 assert(dspace->ref > 0); 248 dspace->ref++; 249} 250 251void 252ram_dspace_unref(struct ram_dspace_list *rdslist, int ID) 253{ 254 struct ram_dspace *dspace = ram_dspace_get(rdslist, ID); 255 if (!dspace) { 256 ROS_ERROR("ram_dspace_unref no such dataspace!"); 257 assert(!"ram_dspace_unref no such dataspace! Procserv book keeping error."); 258 return; 259 } 260 assert(dspace->ref > 0); 261 dspace->ref--; 262 if (dspace->ref == 0) { 263 /* Last reference, delete the object. */ 264 coat_free(&rdslist->allocTable, ID); 265 } 266} 267 268seL4_CPtr 269ram_dspace_check_page(struct ram_dspace *dataspace, uint32_t offset) 270{ 271 assert(dataspace && dataspace->magic == RAM_DATASPACE_MAGIC); 272 uint32_t idx = ram_dspace_get_index(offset); 273 if (idx >= dataspace->npages) { 274 /* Offset of of range. */ 275 return (seL4_CPtr) 0; 276 } 277 return dataspace->pages[idx].cptr; 278} 279 280seL4_CPtr 281ram_dspace_get_page(struct ram_dspace *dataspace, uint32_t offset) 282{ 283 assert(dataspace && dataspace->magic == RAM_DATASPACE_MAGIC); 284 uint32_t idx = ram_dspace_get_index(offset); 285 if (idx >= dataspace->npages) { 286 /* Offset of of range. */ 287 return (seL4_CPtr) 0; 288 } 289 if (!dataspace->pages[idx].cptr) { 290 if (dataspace->physicalAddrEnabled) { 291 /* Allocate a physical address device memory region frame to fill this page. */ 292 cspacepath_t deviceFrame = procserv_find_device( 293 (void*) dataspace->physicalAddr + idx * REFOS_PAGE_SIZE, REFOS_PAGE_SIZE); 294 if (!deviceFrame.capPtr) { 295 ROS_WARNING("Could not allocate frame object. No such device."); 296 return (seL4_CPtr) 0; 297 } 298 memset(&dataspace->pages[idx], 0, sizeof(vka_object_t)); 299 dataspace->pages[idx].cptr = deviceFrame.capPtr; 300 } else { 301 /* Allocate a normal frame to fill this page. */ 302 int error = vka_alloc_frame(&procServ.vka, seL4_PageBits, &dataspace->pages[idx]); 303 if (error || !dataspace->pages[idx].cptr) { 304 ROS_ERROR("Could not allocate frame object. Procserv out of memory."); 305 return (seL4_CPtr) 0; 306 } 307 } 308 } 309 return dataspace->pages[idx].cptr; 310} 311 312struct ram_dspace * 313ram_dspace_get(struct ram_dspace_list *rdslist, int ID) 314{ 315 if (ID <= RAM_DATASPACE_INVALID_ID || ID >= RAM_DATASPACE_MAX_NUM_DATASPACE) { 316 /* Invalid ID. */ 317 return NULL; 318 } 319 struct ram_dspace* dspace = (struct ram_dspace*) coat_get(&rdslist->allocTable, ID); 320 if (!dspace) { 321 return NULL; 322 } 323 assert(dspace->magic == RAM_DATASPACE_MAGIC); 324 return dspace; 325} 326 327struct ram_dspace * 328ram_dspace_get_badge(struct ram_dspace_list *rdslist, seL4_Word badge) 329{ 330 return ram_dspace_get(rdslist, badge - RAM_DATASPACE_BADGE_BASE); 331} 332 333uint32_t 334ram_dspace_get_size(struct ram_dspace *dataspace) 335{ 336 assert(dataspace && dataspace->magic == RAM_DATASPACE_MAGIC); 337 return dataspace->npages * REFOS_PAGE_SIZE; 338} 339 340int 341ram_dspace_expand(struct ram_dspace *dataspace, uint32_t size) 342{ 343 assert(dataspace && dataspace->magic == RAM_DATASPACE_MAGIC); 344 uint32_t npages = (size / REFOS_PAGE_SIZE) + ((size % REFOS_PAGE_SIZE) ? 1 : 0); 345 346 if (npages < dataspace->npages) { 347 /* Contraction not supported. */ 348 return EINVALIDPARAM; 349 } else if (npages == dataspace->npages) { 350 /* Nothing to do here. */ 351 return ESUCCESS; 352 } 353 uint32_t nbitmaskPrev = (dataspace->npages / 32) + 1; 354 355 /* Expand the dataspace. */ 356 dataspace->pages = krealloc(dataspace->pages, sizeof(vka_object_t) * npages); 357 if (!dataspace->pages) { 358 ROS_ERROR("ram_dspace_expand could not reallocate page array, procserv out of mem!"); 359 return ENOMEM; /* Easier to not clean up, leave extra bit of mem. */ 360 } 361 uint32_t pageDiff = npages - dataspace->npages; 362 assert(pageDiff); 363 memset(&dataspace->pages[dataspace->npages], 0, sizeof(vka_object_t) * pageDiff); 364 365 /* Expand the dataspace content init mask. */ 366 uint32_t nbitmask = (npages / 32) + 1; 367 if (dataspace->contentInitBitmask && nbitmaskPrev < nbitmask) { 368 dataspace->contentInitBitmask = krealloc ( 369 dataspace->contentInitBitmask, nbitmask * sizeof(uint32_t) 370 ); 371 if (!dataspace->contentInitBitmask) { 372 ROS_ERROR("ram_dspace_expand failed to realloc content init bitmask. Procserv OOM."); 373 return ENOMEM; /* Easier to not clean up, leave extra bit of mem. */ 374 } 375 uint32_t bitmaskDiff = nbitmask - nbitmaskPrev; 376 assert(bitmaskDiff > 0); 377 memset(&dataspace->contentInitBitmask[nbitmaskPrev], 0, bitmaskDiff * sizeof(uint32_t)); 378 } 379 380 dataspace->npages = npages; 381 return ESUCCESS; 382} 383 384int 385ram_dspace_set_to_paddr(struct ram_dspace *dataspace, uint32_t paddr) 386{ 387 /* Check that the dataspace isn't already occupied with something. */ 388 if (dataspace->contentInitEnabled) { 389 ROS_WARNING("Dataspace is already content init enabled, cannot set to physaddr mode."); 390 return EINVALID; 391 } 392 if (dataspace->physicalAddrEnabled) { 393 ROS_WARNING("Dataspace is already set to physaddr mode."); 394 return EINVALID; 395 } 396 397 /* Check that the dataspace is empty. */ 398 dprintf("Checking pages...\n"); 399 for (int i = 0; i < dataspace->npages; i++) { 400 if (dataspace->pages[i].cptr) { 401 ROS_WARNING("Dataspace already has mapped anonymous content."); 402 return EINVALID; 403 } 404 } 405 406 /* Quick sanity check that something actually exists at the given paddr. */ 407 dprintf("procserv_find_device...\n"); 408 cspacepath_t deviceFrame = procserv_find_device((void*) paddr, REFOS_PAGE_SIZE); 409 if (!deviceFrame.capPtr) { 410 ROS_WARNING("No such device 0x%x.", paddr); 411 return EFILENOTFOUND; 412 } 413 vka_cnode_delete(&deviceFrame); 414 vka_cspace_free(&procServ.vka, deviceFrame.capPtr); 415 416 dprintf("procserv_find_device OK...\n"); 417 dataspace->physicalAddrEnabled = true; 418 dataspace->physicalAddr = paddr; 419 return ESUCCESS; 420} 421 422/* --------------------------- RAM dataspace read / write functions ----------------------------- */ 423 424/*! @brief Reads data from a single page within a ram dataspace. 425 426 Reads data from a single page within a ram dataspace. Can _NOT_ read across page boundaries. 427 This is an internal helper function to implement the more general dataspace_read which can read 428 across page boundaries. 429 If the offset is not paged aligned, will only read data up to the next boundary. This should be 430 an internal function and not exposed, but is not declared static here to give special access to 431 unit tests. 432 433 @param buf The destination buffer to copy data to. (No ownership) 434 @param len The length of the data to be copied. 435 @param dataspace The source ram dataspace. (No ownership) 436 @param offset The offset into the dataspace to read from. 437 @return ESUCCESS if success, refos_err_t otherwise. 438 */ 439int 440ram_dspace_read_page(char *buf, size_t len, struct ram_dspace *dataspace, uint32_t offset) 441{ 442 vaddr_t skipBytes = offset - REFOS_PAGE_ALIGN(offset); 443 if (len > (REFOS_PAGE_SIZE - skipBytes)) { 444 dvprintf("WARNING: capping at len > PAGE_SIZE - skipBytes.\n"); 445 len = (REFOS_PAGE_SIZE - skipBytes); 446 } 447 seL4_CPtr frame = ram_dspace_get_page(dataspace, offset); 448 if (!frame) { 449 ROS_ERROR("ram_dspace_read_page failed to allocate page. Procserv out of memory."); 450 return ENOMEM; 451 } 452 return procserv_frame_read(frame, buf, len, skipBytes); 453} 454 455/*! @brief Writes data to a page within a ram dataspace. 456 457 Writes data to a page within a ram dataspace. Can _NOT_ write across page boundaries. 458 This is an internal helper function to implement the more general dataspace_write which can write 459 across page boundaries. 460 If the offset is not paged aligned, will only write data up to the next boundary. This should be 461 an internal function and not exposed, but is not declared static here to give special access to 462 unit tests. 463 464 @param buf The source buffer containing the data. (No ownership) 465 @param len The length of the data to be written. 466 @param dataspace The destination dataspace to be written to. (No ownership) 467 @param offset The offset into the dataspace to write to. 468 @return ESUCCESS if success, refos_err_t otherwise. 469 */ 470int 471ram_dspace_write_page(char *buf, size_t len, struct ram_dspace *dataspace, uint32_t offset) 472{ 473 vaddr_t skipBytes = offset - REFOS_PAGE_ALIGN(offset); 474 if (len > (REFOS_PAGE_SIZE - skipBytes)) { 475 dvprintf("WARNING: capping at len > PAGE_SIZE - skipBytes.\n"); 476 len = (REFOS_PAGE_SIZE - skipBytes); 477 } 478 seL4_CPtr frame = ram_dspace_get_page(dataspace, offset); 479 if (!frame) { 480 ROS_ERROR("ram_dataspace_write_page failed to allocate page. Procserv out of memory."); 481 return ENOMEM; 482 } 483 return procserv_frame_write(frame, buf, len, skipBytes); 484} 485 486int 487ram_dspace_read(char *buf, size_t len, struct ram_dspace *dataspace, uint32_t offset) 488{ 489 assert(buf && dataspace && dataspace->magic == RAM_DATASPACE_MAGIC); 490 int start = offset; 491 int bufOffset = 0; 492 493 /* Check if the read length runs off the end of the dataspace. */ 494 if (len > ((dataspace->npages * REFOS_PAGE_SIZE) - offset)) { 495 return EINVALIDPARAM; 496 } 497 498 while (start < offset + len) { 499 int end = MIN(REFOS_PAGE_ALIGN(start) + REFOS_PAGE_SIZE, offset + len); 500 501 /* Read data out of the next page. */ 502 int error = ram_dspace_read_page ( 503 (char*)(buf + bufOffset), end - start, 504 dataspace, start 505 ); 506 if (error) { 507 ROS_ERROR("ram_dspace_read_page failed."); 508 return error; 509 } 510 511 bufOffset += end - start; 512 start = end; 513 } 514 return ESUCCESS; 515} 516 517int 518ram_dspace_write(char *buf, size_t len, struct ram_dspace *dataspace, uint32_t offset) 519{ 520 assert(buf && dataspace && dataspace->magic == RAM_DATASPACE_MAGIC); 521 int start = offset; 522 int bufOffset = 0; 523 524 /* Check if the write length runs off the end of the dataspace. */ 525 if (len > ((dataspace->npages * REFOS_PAGE_SIZE) - offset)) { 526 return EINVALIDPARAM; 527 } 528 529 while (start < offset + len) { 530 int end = MIN(REFOS_PAGE_ALIGN(start) + REFOS_PAGE_SIZE, offset + len); 531 532 /* Write data into the next page. */ 533 int error = ram_dspace_write_page ( 534 (char*)(buf + bufOffset), end - start, 535 dataspace, start 536 ); 537 if (error) { 538 ROS_ERROR("ram_dspace_write_page failed."); 539 return error; 540 } 541 542 bufOffset += end - start; 543 start = end; 544 } 545 546 return ESUCCESS; 547} 548 549/* --------------------------- RAM dataspace content init functions ----------------------------- */ 550 551int 552ram_dspace_content_init(struct ram_dspace *dataspace, cspacepath_t initEP, uint32_t initPID) 553{ 554 assert(dataspace && dataspace->magic == RAM_DATASPACE_MAGIC); 555 556 /* We can't content init a dataspace that is physical address bound. */ 557 if (dataspace->physicalAddrEnabled) { 558 ROS_WARNING("Can't content init a dataspace that is physical address bound."); 559 return EINVALID; 560 } 561 562 /* Free any previous content initialised bitmasks. */ 563 if (dataspace->contentInitBitmask) { 564 kfree(dataspace->contentInitBitmask); 565 dataspace->contentInitBitmask = NULL; 566 } 567 568 /* Free any previous content initialisation endpoints. */ 569 if (dataspace->contentInitEnabled) { 570 assert(dataspace->contentInitEP.capPtr); 571 vka_cnode_revoke(&dataspace->contentInitEP); 572 vka_cnode_delete(&dataspace->contentInitEP); 573 vka_cspace_free(&procServ.vka, dataspace->contentInitEP.capPtr); 574 dataspace->contentInitEP.capPtr = 0; 575 } 576 577 /* Special case, no endpoint, means unset content initialisation. */ 578 if (initEP.capPtr == 0) { 579 dataspace->contentInitEnabled = false; 580 dataspace->contentInitPID = PID_NULL; 581 return ESUCCESS; 582 } 583 584 /* Allocate bitmask. */ 585 uint32_t nbitmask = (dataspace->npages / 32) + 1; 586 dataspace->contentInitBitmask = kmalloc(nbitmask * sizeof(uint32_t)); 587 if (!dataspace->contentInitBitmask) { 588 ROS_ERROR("ram_dspace_content_init failed to malloc content init bitmask. Procserv OOM."); 589 return ENOMEM; 590 } 591 memset(dataspace->contentInitBitmask, 0, nbitmask * sizeof(uint32_t)); 592 593 /* Clear the waiting list. */ 594 int waitingListCount = cvector_count(&dataspace->contentInitWaitingList); 595 for (int i = 0; i < waitingListCount; i++) { 596 struct ram_dspace_waiter *waiter = (struct ram_dspace_waiter *) 597 cvector_get(&dataspace->contentInitWaitingList, i); 598 assert(waiter && waiter->magic == RAM_DATASPACE_WAITER_MAGIC); 599 assert(waiter->reply.capPtr); 600 601 vka_cnode_revoke(&waiter->reply); 602 vka_cnode_delete(&waiter->reply); 603 vka_cspace_free(&procServ.vka, waiter->reply.capPtr); 604 kfree(waiter); 605 } 606 cvector_free(&dataspace->contentInitWaitingList); 607 cvector_init(&dataspace->contentInitWaitingList); 608 609 /* Set the content EP, taking ownership of given endpoint. */ 610 dataspace->contentInitEP = initEP; 611 dataspace->contentInitEnabled = true; 612 dataspace->contentInitPID = initPID; 613 return ESUCCESS; 614} 615 616int 617ram_dspace_need_content_init(struct ram_dspace *dataspace, uint32_t offset) 618{ 619 assert(dataspace && dataspace->magic == RAM_DATASPACE_MAGIC); 620 621 if (!dataspace->contentInitEnabled || !dataspace->contentInitBitmask) { 622 return -EINVALID; 623 } 624 if (offset > ram_dspace_get_size(dataspace)) { 625 return -EINVALIDPARAM; 626 } 627 628 uint32_t npage = (offset / REFOS_PAGE_SIZE); 629 uint32_t idxbitmask = npage / 32; 630 uint32_t idxshift = npage % 32; 631 assert(npage <= dataspace->npages); 632 633 return !((dataspace->contentInitBitmask[idxbitmask] >> idxshift) & 0x1); 634} 635 636int 637ram_dspace_add_content_init_waiter(struct ram_dspace *dataspace, uint32_t offset, 638 cspacepath_t reply) 639{ 640 assert(dataspace && dataspace->magic == RAM_DATASPACE_MAGIC); 641 if (!reply.capPtr) { 642 ROS_WARNING("add_content_init_waiter: null cap given. Nothing to do."); 643 return EINVALIDPARAM; 644 } 645 if (offset > ram_dspace_get_size(dataspace)) { 646 return EINVALIDPARAM; 647 } 648 if (!dataspace->contentInitEnabled) { 649 dvprintf("add_content_init_waiter: content init not enabled."); 650 return EINVALID; 651 } 652 uint32_t npage = (offset / REFOS_PAGE_SIZE); 653 assert(npage < dataspace->npages); 654 655 /* Allocate the waiter structure. */ 656 struct ram_dspace_waiter* waiter = kmalloc(sizeof(struct ram_dspace_waiter)); 657 if (!waiter) { 658 ROS_ERROR("add_content_init_waiter could not malloc waiter struct. Procserv OOM."); 659 return ENOMEM; 660 } 661 662 /* Fill out the waiter structure and add to waiting list. */ 663 waiter->magic = RAM_DATASPACE_WAITER_MAGIC; 664 waiter->pageidx = npage; 665 waiter->reply = reply; 666 cvector_add(&dataspace->contentInitWaitingList, (cvector_item_t) waiter); 667 return ESUCCESS; 668} 669 670int 671ram_dspace_add_content_init_waiter_save_current_caller(struct ram_dspace *dataspace, 672 uint32_t offset) 673{ 674 /* Allocate anew cslot to save the reply cap to. */ 675 cspacepath_t callerReply; 676 int error = vka_cspace_alloc_path(&procServ.vka, &callerReply); 677 if (error != seL4_NoError) { 678 ROS_ERROR("Could not allocate path to save caller. PRocserv outof cslots."); 679 return ENOMEM; 680 } 681 assert(callerReply.capPtr); 682 683 /* Save the caller cap. */ 684 error = vka_cnode_saveCaller(&callerReply); 685 if (error != seL4_NoError) { 686 ROS_ERROR("Could not copy out reply cap."); 687 return EINVALID; 688 } 689 690 /* Add reply cap as waiter (takes ownership of the cap) */ 691 return ram_dspace_add_content_init_waiter(dataspace, offset, callerReply); 692} 693 694 695void 696ram_dspace_content_init_reply_waiters(struct ram_dspace *dataspace, uint32_t offset) 697{ 698 assert(dataspace && dataspace->magic == RAM_DATASPACE_MAGIC); 699 700 /* Calculate (and check) the dspace page number. */ 701 uint32_t npage = (offset / REFOS_PAGE_SIZE); 702 if(npage >= dataspace->npages) { 703 ROS_ERROR("ram_dspace_content_init_reply_waiters: offset out of bounds.") 704 return; 705 } 706 707 /* Loop through the waiting list, find any clients that are currently blocked on the page 708 we have data for, and reply to them. */ 709 int waitingListCount = cvector_count(&dataspace->contentInitWaitingList); 710 for (int i = 0; i < waitingListCount; i++) { 711 struct ram_dspace_waiter *waiter = (struct ram_dspace_waiter *) 712 cvector_get(&dataspace->contentInitWaitingList, i); 713 assert(waiter && waiter->magic == RAM_DATASPACE_WAITER_MAGIC); 714 assert(waiter->reply.capPtr); 715 716 if (waiter->pageidx == npage) { 717 /* Unblock this client. */ 718 seL4_Send(waiter->reply.capPtr, _dispatcherEmptyReply); 719 720 /* Remove this waiter from the waiting list. */ 721 cvector_delete(&dataspace->contentInitWaitingList, i); 722 waitingListCount--; 723 assert(waitingListCount == cvector_count(&dataspace->contentInitWaitingList)); 724 i--; 725 726 /* Delete this waiter. */ 727 vka_cnode_revoke(&waiter->reply); 728 vka_cnode_delete(&waiter->reply); 729 vka_cspace_free(&procServ.vka, waiter->reply.capPtr); 730 kfree(waiter); 731 } 732 } 733} 734 735void 736ram_dspace_set_content_init_provided(struct ram_dspace *dataspace, uint32_t offset) 737{ 738 assert(dataspace && dataspace->magic == RAM_DATASPACE_MAGIC); 739 740 if (!dataspace->contentInitEnabled || !dataspace->contentInitBitmask) { 741 ROS_WARNING("set_content_init_provided called with content init disabled."); 742 return; 743 } 744 if (offset > ram_dspace_get_size(dataspace)) { 745 ROS_WARNING("set_content_init_provided offset out-of-bounds."); 746 return; 747 } 748 749 uint32_t npage = (offset / REFOS_PAGE_SIZE); 750 uint32_t idxbitmask = npage / 32; 751 uint32_t idxshift = npage % 32; 752 assert(npage <= dataspace->npages); 753 754 /* Set the bitmask bit. */ 755 dataspace->contentInitBitmask[idxbitmask] |= (1 << idxshift); 756} 757 758 759