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