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