1/** 2 * \file 3 * \brief Capability system user code 4 */ 5 6/* 7 * Copyright (c) 2007-2010, 2012, 2016, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <stdint.h> 16#include <stdbool.h> 17#include <barrelfish/barrelfish.h> 18#include <barrelfish/cspace.h> 19#include <barrelfish/caddr.h> 20#include <barrelfish/lmp_endpoints.h> 21#include <if/monitor_defs.h> 22#include <if/monitor_blocking_defs.h> 23#include <barrelfish/monitor_client.h> 24#include <trace/trace.h> 25#include <stdio.h> 26 27/// Root CNode 28#define ROOT_CNODE_INIT { \ 29 .croot = CPTR_ROOTCN, \ 30 .cnode = 0, \ 31 .level = CNODE_TYPE_ROOT, } 32 33struct cnoderef cnode_root = ROOT_CNODE_INIT; 34 35#define TASK_CNODE_INIT { \ 36 .croot = CPTR_ROOTCN, \ 37 .cnode = CPTR_TASKCN_BASE, \ 38 .level = CNODE_TYPE_OTHER, } 39 40#define PAGE_CNODE_INIT { \ 41 .croot = CPTR_ROOTCN, \ 42 .cnode = CPTR_PAGECN_BASE, \ 43 .level = CNODE_TYPE_OTHER, } 44 45/// Task CNode 46struct cnoderef cnode_task = TASK_CNODE_INIT; 47 48/// Base CNode 49struct cnoderef cnode_base = { 50 .cnode = CPTR_BASE_PAGE_CN_BASE, 51 .level = CNODE_TYPE_OTHER, 52 .croot = CPTR_ROOTCN, 53}; 54 55/// Super CNode 56struct cnoderef cnode_super = { 57 .cnode = CPTR_SUPERCN_BASE, 58 .level = CNODE_TYPE_OTHER, 59 .croot = CPTR_ROOTCN, 60}; 61 62/// Page CNode 63struct cnoderef cnode_page = PAGE_CNODE_INIT; 64 65/// Module CNode 66struct cnoderef cnode_module = { 67 .cnode = CPTR_MODULECN_BASE, 68 .level = CNODE_TYPE_OTHER, 69 .croot = CPTR_ROOTCN, 70}; 71 72/// Capability to Root CNode 73struct capref cap_root = { 74 .cnode = TASK_CNODE_INIT, 75 .slot = TASKCN_SLOT_ROOTCN 76}; 77 78/// Capability for IRQ table 79struct capref cap_irq = { 80 .cnode = TASK_CNODE_INIT, 81 .slot = TASKCN_SLOT_IRQ 82}; 83 84/// Capability for legacy IO 85struct capref cap_io = { 86 .cnode = TASK_CNODE_INIT, 87 .slot = TASKCN_SLOT_IO 88}; 89 90/// Capability for endpoint to self 91struct capref cap_selfep = { 92 .cnode = TASK_CNODE_INIT, 93 .slot = TASKCN_SLOT_SELFEP 94}; 95 96/// Capability for dispatcher 97struct capref cap_dispatcher = { 98 .cnode = TASK_CNODE_INIT, 99 .slot = TASKCN_SLOT_DISPATCHER 100}; 101 102/// Capability for dispatcher 103struct capref cap_dispframe = { 104 .cnode = TASK_CNODE_INIT, 105 .slot = TASKCN_SLOT_DISPFRAME 106}; 107 108/// Capability for ArgSpace 109struct capref cap_argcn = { 110 .cnode = ROOT_CNODE_INIT, 111 .slot = ROOTCN_SLOT_ARGCN 112}; 113 114/// Capability for monitor endpoint 115struct capref cap_monitorep = { 116 .cnode = TASK_CNODE_INIT, 117 .slot = TASKCN_SLOT_MONITOREP 118}; 119 120/// Capability for kernel (only in monitor) 121struct capref cap_kernel = { 122 .cnode = TASK_CNODE_INIT, 123 .slot = TASKCN_SLOT_KERNELCAP 124}; 125 126/// Capability for IPI sending (only in monitor) 127struct capref cap_ipi = { 128 .cnode = TASK_CNODE_INIT, 129 .slot = TASKCN_SLOT_IPI 130}; 131 132/// PerfMon CNode 133struct capref cap_perfmon = { 134 .cnode = TASK_CNODE_INIT, 135 .slot = TASKCN_SLOT_PERF_MON 136}; 137 138/// Capability for endpoint to init (only in monitor/mem_serv) 139struct capref cap_initep = { 140 .cnode = TASK_CNODE_INIT, 141 .slot = TASKCN_SLOT_INITEP 142}; 143 144/// Session ID 145struct capref cap_sessionid = { 146 .cnode = TASK_CNODE_INIT, 147 .slot = TASKCN_SLOT_SESSIONID 148}; 149 150/// Process manager cap, allows creating domains. 151struct capref cap_procmng = { 152 .cnode = TASK_CNODE_INIT, 153 .slot = TASKCN_SLOT_PROC_MNG 154}; 155 156/// Domain ID cap. 157struct capref cap_domainid = { 158 .cnode = TASK_CNODE_INIT, 159 .slot = TASKCN_SLOT_DOMAINID 160}; 161 162/// Root PML4 VNode 163struct capref cap_vroot = { 164 .cnode = PAGE_CNODE_INIT, 165 .slot = PAGECN_SLOT_VROOT, 166}; 167 168static inline bool backoff(int count) 169{ 170 // very crude exponential backoff based upon core id 171 int yieldcnt = 2^count * disp_get_core_id(); 172 for (int i=0; i<yieldcnt; i++) { 173 thread_yield(); 174 } 175 return true; 176} 177 178/** 179 * \brief Retype a capability into one or more new capabilities, going through 180 * the monitor to ensure consistancy with other cores. Only necessary for 181 * caps that have been sent remotely. 182 */ 183static errval_t cap_retype_remote(struct capref src_root, struct capref dest_root, 184 capaddr_t src, gensize_t offset, enum objtype new_type, 185 gensize_t objsize, size_t count, capaddr_t to, 186 capaddr_t slot, int to_level) 187{ 188 errval_t err, remote_cap_err; 189 struct monitor_blocking_binding *mrc = get_monitor_blocking_binding(); 190 if (!mrc) { 191 err = monitor_client_blocking_rpc_init(); 192 mrc = get_monitor_blocking_binding(); 193 if (err_is_fail(err) || !mrc) { 194 return LIB_ERR_MONITOR_RPC_NULL; 195 } 196 } 197 198 int send_count = 0; 199 do { 200 if (capcmp(src_root, dest_root)) { 201 dest_root = NULL_CAP; 202 } 203 err = mrc->rpc_tx_vtbl.remote_cap_retype(mrc, src_root, dest_root, src, 204 offset, (uint64_t)new_type, objsize, 205 count, to, slot, to_level, &remote_cap_err); 206 if (err_is_fail(err)){ 207 DEBUG_ERR(err, "remote cap retype\n"); 208 } 209 } while (err_no(remote_cap_err) == MON_ERR_REMOTE_CAP_RETRY && backoff(++send_count)); 210 211 return remote_cap_err; 212 213} 214 215 216/** 217 * \brief Delete the given capability, going through the monitor to ensure 218 * consistancy with other cores. Only necessary for caps that have been sent 219 * remotely. 220 * 221 * \param cap Capability to be deleted 222 * 223 * Deletes (but does not revoke) the given capability, allowing the CNode slot 224 * to be reused. 225 */ 226static errval_t cap_delete_remote(struct capref root, capaddr_t src, uint8_t level) 227{ 228 errval_t err, remote_cap_err; 229 struct monitor_blocking_binding *mrc = get_monitor_blocking_binding(); 230 if (!mrc) { 231 err = monitor_client_blocking_rpc_init(); 232 mrc = get_monitor_blocking_binding(); 233 if (err_is_fail(err) || !mrc) { 234 return LIB_ERR_MONITOR_RPC_NULL; 235 } 236 } 237 238 int count = 0; 239 do { 240 err = mrc->rpc_tx_vtbl.remote_cap_delete(mrc, root, src, level, 241 &remote_cap_err); 242 if (err_is_fail(err)){ 243 DEBUG_ERR(err, "remote cap delete\n"); 244 } 245 } while (err_no(remote_cap_err) == MON_ERR_REMOTE_CAP_RETRY && backoff(++count)); 246 247 return remote_cap_err; 248} 249 250/** 251 * \brief Revoke (delete all copies and descendants of) the given capability, 252 * going through the monitor to ensure consistancy with other cores. Only 253 * necessary for caps that have been sent remotely. 254 * 255 * \param cap Capability to be revoked 256 * 257 * Deletes all copies and descendants of the given capability, but not the 258 * capability itself. If this succeeds, the capability is guaranteed to be 259 * the only copy in the system. 260 */ 261static errval_t cap_revoke_remote(struct capref root, capaddr_t src, uint8_t level) 262{ 263 errval_t err, remote_cap_err; 264 struct monitor_blocking_binding *mrc = get_monitor_blocking_binding(); 265 if (!mrc) { 266 err = monitor_client_blocking_rpc_init(); 267 mrc = get_monitor_blocking_binding(); 268 if (err_is_fail(err) || !mrc) { 269 return LIB_ERR_MONITOR_RPC_NULL; 270 } 271 } 272 273 int count = 0; 274 do { 275 err = mrc->rpc_tx_vtbl.remote_cap_revoke(mrc, root, src, level, 276 &remote_cap_err); 277 if (err_is_fail(err)){ 278 DEBUG_ERR(err, "remote cap delete\n"); 279 } 280 } while (err_no(remote_cap_err) == MON_ERR_REMOTE_CAP_RETRY && backoff(++count)); 281 282 return remote_cap_err; 283} 284 285/** 286 * \brief Retype (part of) a capability into one or more new capabilities 287 * 288 * \param dest_start Location of first destination slot, which must be empty 289 * \param src Source capability to retype 290 * \param offset Offset into source capability 291 * \param new_type Kernel object type to retype to. 292 * \param objsize Size of created objects in bytes 293 * (ignored for fixed-size objects) 294 * \param count The number of new objects to create 295 * 296 * When retyping IRQSrc capabilities, offset and objsize represent the start 297 * and end of the to be created interrupt range. Count must be 1 for IRQSrc. 298 * 299 * Retypes (part of) the given source capability into a number of new 300 * capabilities, which may be of the same or of different type. The new 301 * capabilities are created in the slots starting from dest_start, which must 302 * all be empty and lie in the same CNode. The number of objects created is 303 * determined by the argument `count`. 304 */ 305errval_t cap_retype(struct capref dest_start, struct capref src, gensize_t offset, 306 enum objtype new_type, gensize_t objsize, size_t count) 307{ 308 errval_t err; 309 310 // Address of destination cspace 311 capaddr_t dcs_addr = get_croot_addr(dest_start); 312 // Address of the cap to the destination CNode 313 capaddr_t dcn_addr = get_cnode_addr(dest_start); 314 // Depth/Level of destination cnode 315 enum cnode_type dcn_level = get_cnode_level(dest_start); 316 // Address of source cspace 317 capaddr_t scp_root = get_croot_addr(src); 318 // Address of source capability 319 capaddr_t scp_addr = get_cap_addr(src); 320 321 err = invoke_cnode_retype(cap_root, scp_root, scp_addr, offset, new_type, 322 objsize, count, dcs_addr, dcn_addr, dcn_level, 323 dest_start.slot); 324 325 if (err_no(err) == SYS_ERR_RETRY_THROUGH_MONITOR) { 326 struct capref src_root = get_croot_capref(src); 327 struct capref dest_root = get_croot_capref(dest_start); 328 return cap_retype_remote(src_root, dest_root, scp_addr, offset, new_type, 329 objsize, count, dcn_addr, dest_start.slot, 330 dcn_level); 331 } else { 332 return err; 333 } 334} 335 336 337/** 338 * \brief Create a capability 339 * 340 * \param dest Location where to create the cap, which must be empty. 341 * \param type Kernel object type to create. 342 * \param size Size of the created capability in bytes. 343 * (ignored for fixed-size objects) 344 * 345 * Only certain types of capabilities can be created this way. If invoked on 346 * a capability type, that is not creatable at runtime the error 347 * SYS_ERR_TYPE_NOT_CREATABLE is returned. Most capabilities have to be retyped 348 * from other capabilities with cap_retype(). 349 */ 350errval_t cap_create(struct capref dest, enum objtype type, size_t size) 351{ 352 errval_t err; 353 354 // Address of the cap to the destination CNode 355 capaddr_t dest_cnode_cptr = get_cnode_addr(dest); 356 enum cnode_type dest_cnode_level = get_cnode_level(dest); 357 358 err = invoke_cnode_create(cap_root, type, size, dest_cnode_cptr, 359 dest_cnode_level, dest.slot); 360 361 return err; 362} 363 364/** 365 * \brief Delete the given capability 366 * 367 * \param cap Capability to be deleted 368 * 369 * Deletes (but does not revoke) the given capability, allowing the CNode slot 370 * to be reused. 371 */ 372errval_t cap_delete(struct capref cap) 373{ 374 errval_t err; 375 struct capref croot = get_croot_capref(cap); 376 capaddr_t caddr = get_cap_addr(cap); 377 enum cnode_type level = get_cap_level(cap); 378 379 err = invoke_cnode_delete(croot, caddr, level); 380 381 if (err_no(err) == SYS_ERR_RETRY_THROUGH_MONITOR) { 382 return cap_delete_remote(croot, caddr, level); 383 } else { 384 return err; 385 } 386} 387 388/** 389 * \brief Revoke (delete all copies and descendants of) the given capability 390 * 391 * \param cap Capability to be revoked 392 * 393 * Deletes all copies and descendants of the given capability, but not the 394 * capability itself. If this succeeds, the capability is guaranteed to be 395 * the only copy in the system. 396 */ 397errval_t cap_revoke(struct capref cap) 398{ 399 errval_t err; 400 struct capref croot = get_croot_capref(cap); 401 capaddr_t caddr = get_cap_addr(cap); 402 enum cnode_type level = get_cap_level(cap); 403 404 err = invoke_cnode_revoke(croot, caddr, level); 405 406 if (err_no(err) == SYS_ERR_RETRY_THROUGH_MONITOR) { 407 return cap_revoke_remote(croot, caddr, level); 408 } else { 409 return err; 410 } 411} 412 413/** 414 * \brief Destroy a capability, i.e. delete it and free the slot. 415 * 416 * \param cap Capability to be destroyed 417 */ 418errval_t cap_destroy(struct capref cap) 419{ 420 errval_t err; 421 err = cap_delete(cap); 422 if (err_is_fail(err)) { 423 return err; 424 } 425 426 err = slot_free(cap); 427 if (err_is_fail(err)) { 428 return err_push(err, LIB_ERR_WHILE_FREEING_SLOT); 429 } 430 431 return SYS_ERR_OK; 432} 433 434/** 435 * \brief Replace own L1 CNode 436 * 437 * \param new the replacement L1 CNode 438 * \param ret the slot to put the old L1 CNode 439 */ 440errval_t root_cnode_resize(struct capref new, struct capref ret) 441{ 442 assert(get_croot_addr(new) == CPTR_ROOTCN); 443 assert(get_cap_level(new) == CNODE_TYPE_COUNT); 444 capaddr_t new_cptr = get_cap_addr(new); 445 446 assert(get_croot_addr(ret) == CPTR_ROOTCN); 447 assert(get_cap_level(ret) == CNODE_TYPE_COUNT); 448 capaddr_t retcn_ptr= get_cnode_addr(ret); 449 450 return invoke_cnode_resize(cap_root, new_cptr, retcn_ptr, ret.slot); 451} 452 453/** 454 * \brief Create a CNode from a given RAM capability in a specific slot 455 * 456 * \param dest location in which to place newly-created CNode cap 457 * \param src location of RAM capability to be retyped to new CNode 458 * \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info 459 * \param slots number of slots in created CNode 460 * must match size of RAM capability. 461 * 462 * This function requires that dest refer to an existing but empty slot. It 463 * retypes the given memory to a new CNode. 464 */ 465errval_t cnode_create_from_mem(struct capref dest, struct capref src, 466 enum objtype cntype, struct cnoderef *cnoderef, 467 size_t slots) 468{ 469 errval_t err; 470 471 if (cntype != ObjType_L1CNode && 472 cntype != ObjType_L2CNode) 473 { 474 return LIB_ERR_CNODE_TYPE; 475 } 476 477 478 // Retype it to the destination 479 err = cap_retype(dest, src, 0, cntype, slots * (1UL << OBJBITS_CTE), 1); 480 if (err_is_fail(err)) { 481 return err_push(err, LIB_ERR_CAP_RETYPE); 482 } 483 484 // Construct the cnoderef to return 485 if (cnoderef != NULL) { 486 enum cnode_type ref_cntype = cntype == ObjType_L1CNode ? CNODE_TYPE_ROOT : CNODE_TYPE_OTHER; 487 *cnoderef = build_cnoderef(dest, ref_cntype); 488 } 489 490 return SYS_ERR_OK; 491} 492 493/** 494 * \brief Create a CNode from newly-allocated RAM in a newly-allocated slot 495 * 496 * \param ret_dest capref struct to be filled-in with location of CNode 497 * \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info 498 * \param slots Minimum number of slots in created CNode 499 * \param retslots If non-NULL, filled in with the number of slots in created CNode 500 */ 501errval_t cnode_create(struct capref *ret_dest, struct cnoderef *cnoderef, 502 cslot_t slots, cslot_t *retslots) 503{ 504 USER_PANIC("cnode_create deprecated; use cnode_create_l1, cnode_create_l2, or cnode_create_foreign_l2: %p %p %p %p\n", 505 __builtin_return_address(0), 506#ifdef __x86_64__ 507 __builtin_return_address(1), 508 __builtin_return_address(2), 509 __builtin_return_address(3) 510#else 511 NULL, NULL, NULL 512#endif 513 ); 514 return LIB_ERR_NOT_IMPLEMENTED; 515} 516 517/** 518 * \brief Create a L2 CNode from newly-allocated RAM in a newly-allocated slot 519 * 520 * \param ret_dest capref struct to be filled-in with location of CNode 521 * \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info 522 * 523 * This function always creates a L2 CNode which contains 256 capabilities 524 */ 525errval_t cnode_create_l2(struct capref *ret_dest, struct cnoderef *cnoderef) 526{ 527 errval_t err; 528 529 // Allocate a slot in root cn for destination 530 assert(ret_dest != NULL); 531 err = slot_alloc_root(ret_dest); 532 if (err_is_fail(err)) { 533 return err_push(err, LIB_ERR_SLOT_ALLOC); 534 } 535 536 cslot_t retslots; 537 err = cnode_create_raw(*ret_dest, cnoderef, ObjType_L2CNode, 538 L2_CNODE_SLOTS, &retslots); 539 if (retslots != L2_CNODE_SLOTS) { 540 debug_printf("Unable to create properly sized L2 CNode: got %"PRIuCSLOT" slots instead of %"PRIuCSLOT"\n", 541 retslots, (cslot_t)L2_CNODE_SLOTS); 542 } 543 return err; 544} 545 546errval_t cnode_create_l1(struct capref *ret_dest, struct cnoderef *cnoderef) 547{ 548 errval_t err; 549 550 // Allocate a slot in root cn for destination 551 assert(ret_dest != NULL); 552 err = slot_alloc(ret_dest); 553 if (err_is_fail(err)) { 554 return err_push(err, LIB_ERR_SLOT_ALLOC); 555 } 556 557 cslot_t retslots; 558 err = cnode_create_raw(*ret_dest, cnoderef, ObjType_L1CNode, 559 L2_CNODE_SLOTS, &retslots); 560 if (retslots != L2_CNODE_SLOTS) { 561 debug_printf("Unable to create initial L1 CNode: got %"PRIuCSLOT" slots instead of %"PRIuCSLOT"\n", 562 retslots, (cslot_t)L2_CNODE_SLOTS); 563 } 564 return err; 565} 566 567/** 568 * \brief Create a CNode for another cspace from newly-allocated RAM in a 569 * newly-allocated slot 570 * 571 * \param dest_l1 capref to L1 (root) cnode of destination cspace 572 * \param dest_slot slot to fill with new cnode in destination L1 cnode 573 * \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info 574 * 575 * This function creates a CNode which contains 256 capabilities initially 576 * and puts it in a slot in our cspace. 577 */ 578errval_t cnode_create_foreign_l2(struct capref dest_l1, cslot_t dest_slot, 579 struct cnoderef *cnoderef) 580{ 581 errval_t err; 582 583 if (capref_is_null(dest_l1)) { 584 return LIB_ERR_CROOT_NULL; 585 } 586 assert(!capref_is_null(dest_l1)); 587 588 struct capref dest; 589 dest.cnode = build_cnoderef(dest_l1, CNODE_TYPE_ROOT); 590 dest.slot = dest_slot; 591 592 cslot_t retslots; 593 err = cnode_create_raw(dest, NULL, ObjType_L2CNode, L2_CNODE_SLOTS, &retslots); 594 if (retslots != L2_CNODE_SLOTS) { 595 debug_printf("Unable to create properly sized foreign CNode: " 596 "got %"PRIuCSLOT" slots instead of %"PRIuCSLOT"\n", 597 retslots, (cslot_t)L2_CNODE_SLOTS); 598 } 599 600 // Create proper cnoderef for foreign L2 601 if (cnoderef) { 602 cnoderef->croot = get_cap_addr(dest_l1); 603 cnoderef->cnode = ROOTCN_SLOT_ADDR(dest_slot); 604 cnoderef->level = CNODE_TYPE_OTHER; 605 } 606 return err; 607} 608 609/** 610 * \brief Create a CNode from newly-allocated RAM in the given slot 611 * 612 * \param dest location in which to place CNode cap 613 * \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info 614 * \param cntype, type of new cnode 615 * \param slots Minimum number of slots in created CNode 616 * \param retslots If non-NULL, filled in with the number of slots in created CNode 617 * 618 * This function requires that dest refer to an existing but empty slot. It 619 * allocates memory (using #ram_alloc), and retypes that memory to a new CNode. 620 * The intermediate ram cap is destroyed. 621 */ 622errval_t cnode_create_raw(struct capref dest, struct cnoderef *cnoderef, 623 enum objtype cntype, cslot_t slots, cslot_t *retslots) 624{ 625 errval_t err; 626 struct capref ram; 627 628 assert(slots > 0); 629 630 if (cntype != ObjType_L1CNode && 631 cntype != ObjType_L2CNode) 632 { 633 return LIB_ERR_CNODE_TYPE; 634 } 635 636 if (slots < L2_CNODE_SLOTS || 637 (cntype == ObjType_L2CNode && slots != L2_CNODE_SLOTS)) 638 { 639 return LIB_ERR_CNODE_SLOTS; 640 } 641 642 if (retslots != NULL) { 643 *retslots = slots; 644 } 645 646 // XXX: mem_serv should serve non-power-of-two requests 647 uint8_t bits = log2ceil(slots); 648 assert(slots >= (1UL << bits)); 649 650 // Allocate some memory 651 err = ram_alloc(&ram, bits + OBJBITS_CTE); 652 if (err_is_fail(err)) { 653 return err_push(err, LIB_ERR_RAM_ALLOC); 654 } 655 656 err = cnode_create_from_mem(dest, ram, cntype, cnoderef, slots); 657 if (err_is_fail(err)) { 658 return err_push(err, LIB_ERR_CNODE_CREATE_FROM_MEM); 659 } 660 661 err = cap_destroy(ram); 662 if (err_is_fail(err)) { 663 return err_push(err, LIB_ERR_CAP_DESTROY); 664 } 665 666 return SYS_ERR_OK; 667} 668 669/** 670 * \brief Create CNode with a given guard 671 * 672 * \param dest Location where to place the cnode 673 * \param cnoderef Filled in cnoderef struct if non-NULL 674 * \param slots Minimum number of slots in created CNode 675 * \param retslots If non-NULL, filled in with the number of slots in created CNode 676 * \param guard The guard value to set 677 * \param guard_size The length of the guard in bits 678 * 679 * This function requires that dest refer to an existing but empty slot. It 680 * allocates memory (using #ram_alloc), and retypes that memory to a new CNode 681 * with the given guard value and size. An intermediate slot is used in order to 682 * set the guard value. 683 */ 684errval_t cnode_create_with_guard(struct capref dest, struct cnoderef *cnoderef, 685 cslot_t slots, cslot_t *retslots, 686 uint64_t guard, uint8_t guard_size) 687{ 688 USER_PANIC("%s: GPT CNodes are deprecated\n", __FUNCTION__); 689} 690 691/** 692 * \brief Create a VNode in newly-allocated memory 693 * 694 * \param dest location to place new VNode cap 695 * \param type VNode type to create 696 * 697 * This function requires that dest refer to an existing but empty slot. 698 * The intermidiate ram cap is destroyed. 699 */ 700errval_t vnode_create(struct capref dest, enum objtype type) 701{ 702 errval_t err; 703 704 struct capref ram; 705 706 size_t objbits_vnode = vnode_objbits(type); 707 err = ram_alloc(&ram, objbits_vnode); 708 if (err_no(err) == LIB_ERR_RAM_ALLOC_WRONG_SIZE && type != ObjType_VNode_ARM_l1) { 709 // can only get 4kB pages, cannot create ARM_l1, and waste 3kB for 710 // ARM_l2 711 err = ram_alloc(&ram, BASE_PAGE_BITS); 712 } 713 if (err_is_fail(err)) { 714 return err_push(err, LIB_ERR_RAM_ALLOC); 715 } 716 717 assert(type_is_vnode(type)); 718 err = cap_retype(dest, ram, 0, type, vnode_objsize(type), 1); 719 if (err_is_fail(err)) { 720 return err_push(err, LIB_ERR_CAP_RETYPE); 721 } 722 723 err = cap_destroy(ram); 724 if (err_is_fail(err)) { 725 return err_push(err, LIB_ERR_CAP_DESTROY); 726 } 727 728 return SYS_ERR_OK; 729} 730 731/** 732 * \brief Create a Frame cap referring to newly-allocated RAM in a given slot 733 * 734 * \param dest Location to place new frame cap 735 * \param bytes Minimum size of frame to create 736 * \param retbytes If non-NULL, filled in with size of created frame 737 * 738 * This function requires that dest refer to an existing but empty slot. 739 * #ram_alloc is used to allocate memory. After retyping the intermediate 740 * ram cap is destroyed. 741 * 742 * This function will returns a special error code if ram_alloc fails 743 * due to the constrains on the memory server (size of cap or region 744 * of memory). This is to facilitate retrying with different 745 * constraints. 746 */ 747errval_t frame_create(struct capref dest, size_t bytes, size_t *retbytes) 748{ 749 assert(bytes > 0); 750 uint8_t bits = log2ceil(bytes); 751 assert((1UL << bits) >= bytes); 752 errval_t err; 753 754 if (bits < BASE_PAGE_BITS) { 755 bits = BASE_PAGE_BITS; 756 } 757 758 struct capref ram; 759 err = ram_alloc(&ram, bits); 760 if (err_is_fail(err)) { 761 if (err_no(err) == MM_ERR_NOT_FOUND || 762 err_no(err) == LIB_ERR_RAM_ALLOC_WRONG_SIZE) { 763 return err_push(err, LIB_ERR_RAM_ALLOC_MS_CONSTRAINTS); 764 } 765 return err_push(err, LIB_ERR_RAM_ALLOC); 766 } 767 768 err = cap_retype(dest, ram, 0, ObjType_Frame, (1UL << bits), 1); 769 if (err_is_fail(err)) { 770 return err_push(err, LIB_ERR_CAP_RETYPE); 771 } 772 773 err = cap_destroy(ram); 774 if (err_is_fail(err)) { 775 return err_push(err, LIB_ERR_CAP_DESTROY); 776 } 777 778 if (retbytes != NULL) { 779 *retbytes = 1UL << bits; 780 } 781 782 return SYS_ERR_OK; 783} 784 785/** 786 * \brief Create a Dispatcher in newly-allocated memory 787 * 788 * \param dest location to place new dispatcher cap 789 * 790 * This function requires that dest refer to an existing but empty slot. It does 791 * not map in nor initialise the Dispatcher. 792 * The intermediate ram cap is destroyed. 793 */ 794errval_t dispatcher_create(struct capref dest) 795{ 796 errval_t err; 797 798 struct capref ram; 799 assert(1 << log2ceil(OBJSIZE_DISPATCHER) == OBJSIZE_DISPATCHER); 800 err = ram_alloc(&ram, log2ceil(OBJSIZE_DISPATCHER)); 801 if (err_is_fail(err)) { 802 return err_push(err, LIB_ERR_RAM_ALLOC); 803 } 804 805 err = cap_retype(dest, ram, 0, ObjType_Dispatcher, 0, 1); 806 if (err_is_fail(err)) { 807 return err_push(err, LIB_ERR_CAP_RETYPE); 808 } 809 810 err = cap_destroy(ram); 811 if (err_is_fail(err)) { 812 return err_push(err, LIB_ERR_CAP_DESTROY); 813 } 814 return SYS_ERR_OK; 815} 816 817/** 818 * \brief Create endpoint to caller on current dispatcher. 819 * 820 * \param buflen Length of incoming LMP buffer, in words 821 * \param retcap Pointer to capref struct, filled-in with location of cap 822 * \param retep Double pointer to LMP endpoint, filled-in with allocated EP 823 */ 824errval_t endpoint_create(size_t buflen, struct capref *retcap, 825 struct lmp_endpoint **retep) 826{ 827 errval_t err = slot_alloc(retcap); 828 if (err_is_fail(err)) { 829 return err_push(err, LIB_ERR_SLOT_ALLOC); 830 } 831 832 return lmp_endpoint_create_in_slot(buflen, *retcap, retep); 833} 834 835/** 836 * \brief Create a Frame cap referring to newly-allocated RAM in an allocated slot 837 * 838 * \param dest Pointer to capref struct, filled-in with location of new cap 839 * \param bytes Minimum size of frame to create 840 * \param retbytes If non-NULL, filled in with size of created frame 841 */ 842errval_t frame_alloc(struct capref *dest, size_t bytes, size_t *retbytes) 843{ 844 errval_t err = slot_alloc(dest); 845 if (err_is_fail(err)) { 846 return err_push(err, LIB_ERR_SLOT_ALLOC); 847 } 848 849 return frame_create(*dest, bytes, retbytes); 850} 851 852/** 853 * \brief Create a DevFrame cap by retyping out of given source PhysAddr cap 854 * 855 * \param dest Pointer to capref struct, filled-in with location of new cap 856 * \param src Cap_info struct for the source PhysAddr cap 857 * \param size_bits Size of created objects as a power of two 858 * (ignored for fixed-size objects) 859 */ 860errval_t devframe_type(struct capref *dest, struct capref src, uint8_t bits) 861{ 862 errval_t err = slot_alloc(dest); 863 if (err_is_fail(err)) { 864 return err_push(err, LIB_ERR_SLOT_ALLOC); 865 } 866 867 return cap_retype(*dest, src, 0, ObjType_DevFrame, 1UL << bits, 1); 868} 869 870/** 871 * \brief Create an ID cap in a newly allocated slot. 872 * 873 * \param dest Pointer to capref struct, filld-in with location of new cap. 874 * 875 * The caller is responsible for revoking the cap after using it. 876 */ 877errval_t idcap_alloc(struct capref *dest) 878{ 879 errval_t err = slot_alloc(dest); 880 881 if (err_is_fail(err)) { 882 return err_push(err, LIB_ERR_SLOT_ALLOC); 883 } 884 885 return idcap_create(*dest); 886} 887 888/** 889 * \brief Create an ID cap in the specified slot. 890 * 891 * \param dest Capref, where ID cap should be created. 892 * 893 * The caller is responsible for revoking the cap after using it. 894 */ 895errval_t idcap_create(struct capref dest) 896{ 897 return cap_create(dest, ObjType_ID, 0); 898} 899 900/** 901 * \brief Builds a #cnoderef struct from a #capref struct using cap 902 * identification. 903 * 904 * \param cnoder Pointer to a cnoderef struct, fill-in by function. 905 * \param capr Capref to a CNode capability. 906 */ 907errval_t cnode_build_cnoderef(struct cnoderef *cnoder, struct capref capr) 908{ 909 struct capability cap; 910 errval_t err = debug_cap_identify(capr, &cap); 911 if (err_is_fail(err)) { 912 return err; 913 } 914 915 if (cap.type != ObjType_L1CNode && 916 cap.type != ObjType_L2CNode) { 917 return LIB_ERR_NOT_CNODE; 918 } 919 920 if (!cnodecmp(capr.cnode, cnode_root)) { 921 USER_PANIC("cnode_build_cnoderef NYI for non rootcn caprefs"); 922 } 923 924 cnoder->croot = get_croot_addr(capr); 925 cnoder->cnode = capr.slot << L2_CNODE_BITS; 926 cnoder->level = CNODE_TYPE_OTHER; 927 928 return SYS_ERR_OK; 929} 930