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