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