a1162b43183da879397f28b06dc7077d5532debb
[barrelfish] / lib / barrelfish / capabilities.c
1 /**
2  * \file
3  * \brief Capability system user code
4  */
5
6 /*
7  * Copyright (c) 2007, 2008, 2009, 2010, 2012, 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, Haldeneggsteig 4, 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
26 /// Root CNode
27 struct cnoderef cnode_root = {
28     .address = CPTR_ROOTCN,
29     .address_bits = CPTR_BITS,
30     .size_bits = DEFAULT_CNODE_BITS,
31     .guard_size = 0
32 };
33
34 #define TASK_CNODE_INIT { \
35     .address = 0, \
36     .address_bits = DEFAULT_CNODE_BITS, \
37     .size_bits = DEFAULT_CNODE_BITS, \
38     .guard_size = GUARD_REMAINDER(2 * DEFAULT_CNODE_BITS) }
39
40 /// Task CNode
41 struct cnoderef cnode_task = TASK_CNODE_INIT;
42
43 /// Base CNode
44 struct cnoderef cnode_base = {
45     .address = CPTR_BASE_PAGE_CN_BASE,
46     .address_bits = DEFAULT_CNODE_BITS,
47     .size_bits = DEFAULT_CNODE_BITS,
48     .guard_size = 0
49 };
50
51 /// Super CNode
52 struct cnoderef cnode_super = {
53     .address = CPTR_SUPERCN_BASE,
54     .address_bits = DEFAULT_CNODE_BITS,
55     .size_bits = DEFAULT_CNODE_BITS,
56     .guard_size = 0
57 };
58
59 /// Page CNode
60 struct cnoderef cnode_page = {
61     .address = ROOTCN_SLOT_PAGECN << DEFAULT_CN_ADDR_BITS,
62     .address_bits = DEFAULT_CNODE_BITS,
63     .size_bits = PAGE_CNODE_BITS,
64     .guard_size = 0
65 };
66
67 /// Module CNode
68 struct cnoderef cnode_module = {
69     .address = CPTR_MODULECN_BASE,
70     .address_bits = DEFAULT_CNODE_BITS,
71     .size_bits = MODULECN_SIZE_BITS,
72     .guard_size = 0
73 };
74
75 /// Capability to Root CNode
76 struct capref cap_root = {
77     .cnode = TASK_CNODE_INIT,
78     .slot  = TASKCN_SLOT_ROOTCN
79 };
80
81 /// Capability for IRQ table
82 struct capref cap_irq = {
83     .cnode = TASK_CNODE_INIT,
84     .slot  = TASKCN_SLOT_IRQ
85 };
86
87 /// Capability for legacy IO
88 struct capref cap_io = {
89     .cnode = TASK_CNODE_INIT,
90     .slot  = TASKCN_SLOT_IO
91 };
92
93 /// Capability for endpoint to self
94 struct capref cap_selfep = {
95     .cnode = TASK_CNODE_INIT,
96     .slot = TASKCN_SLOT_SELFEP
97 };
98
99 /// Capability for dispatcher
100 struct capref cap_dispatcher = {
101     .cnode = TASK_CNODE_INIT,
102     .slot  = TASKCN_SLOT_DISPATCHER
103 };
104
105 /// Capability for dispatcher
106 struct capref cap_dispframe = {
107     .cnode = TASK_CNODE_INIT,
108     .slot  = TASKCN_SLOT_DISPFRAME
109 };
110
111 #define ROOT_CNODE_INIT { \
112     .address = CPTR_ROOTCN, \
113     .address_bits = CPTR_BITS, \
114     .size_bits = DEFAULT_CNODE_BITS, \
115     .guard_size = 0 }
116
117 /// Capability for monitor endpoint
118 struct capref cap_monitorep = {
119     .cnode = ROOT_CNODE_INIT,
120     .slot  = ROOTCN_SLOT_MONITOREP
121 };
122
123 /// Capability for kernel (only in monitor)
124 struct capref cap_kernel = {
125     .cnode = TASK_CNODE_INIT,
126     .slot  = TASKCN_SLOT_KERNELCAP
127 };
128
129 /// PerfMon CNode
130 struct capref cap_perfmon = {
131     .cnode = TASK_CNODE_INIT,
132     .slot  = TASKCN_SLOT_PERF_MON
133 };
134
135 /// Capability for endpoint to init (only in monitor/mem_serv)
136 struct capref cap_initep = {
137     .cnode = TASK_CNODE_INIT,
138     .slot  = TASKCN_SLOT_INITEP
139 };
140
141 /// Session ID
142 struct capref cap_sessionid = {
143     .cnode = TASK_CNODE_INIT,
144     .slot = TASKCN_SLOT_SESSIONID
145 };
146
147 static inline bool backoff(int count)
148 {
149     // very crude exponential backoff based upon core id
150     int yieldcnt = 2^count * disp_get_core_id();
151     for (int i=0; i<yieldcnt; i++) {
152         thread_yield();
153     }
154     return true;
155 }
156
157 /**
158  * \brief Retype a capability into one or more new capabilities, going through
159  * the monitor to ensure consistancy with other cores.  Only necessary for
160  * caps that have been sent remotely.
161  */
162 static errval_t cap_retype_remote(capaddr_t src, enum objtype new_type,
163                                   uint8_t size_bits, capaddr_t to, capaddr_t slot,
164                                   int dcn_vbits)
165 {
166     struct monitor_blocking_rpc_client *mrc = get_monitor_blocking_rpc_client();
167     errval_t err, remote_cap_err;
168     int count = 0;
169     do {
170         err = mrc->vtbl.remote_cap_retype(mrc, cap_root, src,
171                                           (uint64_t)new_type,
172                                           size_bits, to, slot,
173                                           dcn_vbits, &remote_cap_err);
174         if (err_is_fail(err)){
175             DEBUG_ERR(err, "remote cap retype\n");
176         }
177     } while (remote_cap_err == MON_ERR_REMOTE_CAP_RETRY && backoff(++count));
178
179     return remote_cap_err;
180
181 }
182
183
184 /**
185  * \brief Delete the given capability, going through  the monitor to ensure
186  * consistancy with other cores.  Only necessary for caps that have been sent
187  * remotely.
188  *
189  * \param cap Capability to be deleted
190  *
191  * Deletes (but does not revoke) the given capability, allowing the CNode slot
192  * to be reused.
193  */
194 static errval_t cap_delete_remote(capaddr_t src, uint8_t vbits)
195 {
196     struct monitor_blocking_rpc_client *mrc = get_monitor_blocking_rpc_client();
197     errval_t err, remote_cap_err;
198     int count = 0;
199     do {
200         err = mrc->vtbl.remote_cap_delete(mrc, cap_root, src, vbits,
201                                           &remote_cap_err);
202         if (err_is_fail(err)){
203             DEBUG_ERR(err, "remote cap delete\n");
204         }
205     } while (remote_cap_err == MON_ERR_REMOTE_CAP_RETRY && backoff(++count));
206
207     return remote_cap_err;
208 }
209
210 /**
211  * \brief Revoke (delete all copies and descendants of) the given capability,
212  * going through the monitor to ensure consistancy with other cores.  Only
213  * necessary for caps that have been sent remotely.
214  *
215  * \param cap Capability to be revoked
216  *
217  * Deletes all copies and descendants of the given capability, but not the
218  * capability itself. If this succeeds, the capability is guaranteed to be
219  * the only copy in the system.
220  */
221 static errval_t cap_revoke_remote(capaddr_t src, uint8_t vbits)
222 {
223     struct monitor_blocking_rpc_client *mrc = get_monitor_blocking_rpc_client();
224     errval_t err, remote_cap_err;
225     int count = 0;
226     do {
227         err = mrc->vtbl.remote_cap_revoke(mrc, cap_root, src, vbits,
228                                           &remote_cap_err);
229         if (err_is_fail(err)){
230             DEBUG_ERR(err, "remote cap delete\n");
231         }
232     } while (remote_cap_err == MON_ERR_REMOTE_CAP_RETRY && backoff(++count));
233
234     return remote_cap_err;
235 }
236
237 /**
238  * \brief Retype a capability into one or more new capabilities
239  *
240  * \param dest_start    Location of first destination slot, which must be empty
241  * \param src           Source capability to retype
242  * \param new_type      Kernel object type to retype to.
243  * \param size_bits     Size of created objects as a power of two
244  *                      (ignored for fixed-size objects)
245  *
246  * Retypes the given source capability into a number of new capabilities, which
247  * may be of the same or of different type. The new capabilities are created
248  * in the slots starting from dest_start, which must all be empty and lie in the
249  * same CNode. The number of objects created is determined by the size of the
250  * source object divided by the size of the destination objects.
251  */
252 errval_t cap_retype(struct capref dest_start, struct capref src,
253                     enum objtype new_type, uint8_t size_bits)
254 {
255     errval_t err;
256     // Number of valid bits in destination CNode address
257     uint8_t dcn_vbits = get_cnode_valid_bits(dest_start);
258     // Address of the cap to the destination CNode
259     capaddr_t dcn_addr = get_cnode_addr(dest_start);
260     // Address of source capability
261     capaddr_t scp_addr = get_cap_addr(src);
262
263     err = invoke_cnode_retype(cap_root, scp_addr, new_type, size_bits,
264                               dcn_addr, dest_start.slot, dcn_vbits);
265
266     if (err == SYS_ERR_RETRY_THROUGH_MONITOR) {
267         return cap_retype_remote(scp_addr, new_type, size_bits,
268                                  dcn_addr, dest_start.slot, dcn_vbits);
269     } else {
270         return err;
271     }
272 }
273
274
275 /**
276  * \brief Create a capability
277  *
278  * \param dest      Location where to create the cap, which must be empty.
279  * \param type      Kernel object type to create.
280  * \param size_bits Size of the created capability as a power of two.
281  *                  (ignored for fixed-size objects)
282  *
283  * Only certain types of capabilities can be created this way. If invoked on
284  * a capability type, that is not creatable at runtime the error
285  * SYS_ERR_TYPE_NOT_CREATABLE is returned. Most capabilities have to be retyped
286  * from other capabilities with cap_retype().
287  */
288 errval_t cap_create(struct capref dest, enum objtype type, uint8_t size_bits)
289 {
290     errval_t err;
291
292     // Number of valid bits in the destination CNode address
293     uint8_t dest_vbits = get_cnode_valid_bits(dest);
294     // Address of the cap to the destination CNode
295     capaddr_t dest_cnode_cptr = get_cnode_addr(dest);
296
297     err = invoke_cnode_create(cap_root, type, size_bits, dest_cnode_cptr,
298                               dest.slot, dest_vbits);
299
300     return err;
301 }
302
303 /**
304  * \brief Delete the given capability
305  *
306  * \param cap Capability to be deleted
307  *
308  * Deletes (but does not revoke) the given capability, allowing the CNode slot
309  * to be reused.
310  */
311 errval_t cap_delete(struct capref cap)
312 {
313     errval_t err;
314     uint8_t vbits = get_cap_valid_bits(cap);
315     capaddr_t caddr = get_cap_addr(cap) >> (CPTR_BITS - vbits);
316
317     err = invoke_cnode_delete(cap_root, caddr, vbits);
318
319     if (err == SYS_ERR_RETRY_THROUGH_MONITOR) {
320         return cap_delete_remote(caddr, vbits);
321     } else {
322         return err;
323     }
324 }
325
326 /**
327  * \brief Revoke (delete all copies and descendants of) the given capability
328  *
329  * \param cap Capability to be revoked
330  *
331  * Deletes all copies and descendants of the given capability, but not the
332  * capability itself. If this succeeds, the capability is guaranteed to be
333  * the only copy in the system.
334  */
335 errval_t cap_revoke(struct capref cap)
336 {
337     errval_t err;
338     uint8_t vbits = get_cap_valid_bits(cap);
339     capaddr_t caddr = get_cap_addr(cap) >> (CPTR_BITS - vbits);
340
341     err = invoke_cnode_revoke(cap_root, caddr, vbits);
342
343     if (err == SYS_ERR_RETRY_THROUGH_MONITOR) {
344         return cap_revoke_remote(caddr, vbits);
345     } else {
346         return err;
347     }
348 }
349
350 /**
351  * \brief Destroy a capability, i.e. delete it and free the slot.
352  *
353  * \param cap           Capability to be destroyed
354  */
355 errval_t cap_destroy(struct capref cap)
356 {
357     errval_t err;
358     err = cap_delete(cap);
359     if (err_is_fail(err)) {
360         return err;
361     }
362
363     err = slot_free(cap);
364     if (err_is_fail(err)) {
365         return err_push(err, LIB_ERR_WHILE_FREEING_SLOT);
366     }
367
368     return SYS_ERR_OK;
369 }
370
371 /**
372  * \brief Create a CNode from a given RAM capability in a specific slot
373  *
374  * \param dest location in which to place newly-created CNode cap
375  * \param src  location of RAM capability to be retyped to new CNode
376  * \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info
377  * \param slot_bits number of slots in created CNode as a power of two.
378  *                  must match size of RAM capability.
379  *
380  * This function requires that dest refer to an existing but empty slot. It
381  * retypes the given memory to a new CNode.
382  */
383 errval_t cnode_create_from_mem(struct capref dest, struct capref src,
384                                struct cnoderef *cnoderef, uint8_t slot_bits)
385 {
386     errval_t err;
387
388     // Retype it to the destination
389     err = cap_retype(dest, src, ObjType_CNode, slot_bits);
390     if (err_is_fail(err)) {
391         return err_push(err, LIB_ERR_CAP_RETYPE);
392     }
393
394     // Construct the cnoderef to return
395     if (cnoderef != NULL) {
396         *cnoderef = build_cnoderef(dest, slot_bits);
397     }
398
399     return SYS_ERR_OK;
400 }
401
402 /**
403  * \brief Create a CNode from newly-allocated RAM in a newly-allocated slot
404  *
405  * \param ret_dest capref struct to be filled-in with location of CNode
406  * \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info
407  * \param slots Minimum number of slots in created CNode
408  * \param retslots If non-NULL, filled in with the  number of slots in created CNode
409  */
410 errval_t cnode_create(struct capref *ret_dest, struct cnoderef *cnoderef,
411                       cslot_t slots, cslot_t *retslots)
412 {
413     errval_t err;
414
415     // Allocate a slot for destination.
416     assert(ret_dest != NULL);
417     err = slot_alloc(ret_dest);
418     if (err_is_fail(err)) {
419         return err_push(err, LIB_ERR_SLOT_ALLOC);
420     }
421
422     // Use cnode_create_raw
423     return cnode_create_raw(*ret_dest, cnoderef, slots, retslots);
424 }
425
426 /**
427  * \brief Create a CNode from newly-allocated RAM in the given slot
428  *
429  * \param dest location in which to place CNode cap
430  * \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info
431  * \param slots Minimum number of slots in created CNode
432  * \param retslots If non-NULL, filled in with the  number of slots in created CNode
433  *
434  * This function requires that dest refer to an existing but empty slot. It
435  * allocates memory (using #ram_alloc), and retypes that memory to a new CNode.
436  * The intermediate ram cap is destroyed.
437  */
438 errval_t cnode_create_raw(struct capref dest, struct cnoderef *cnoderef,
439                           cslot_t slots, cslot_t *retslots)
440 {
441     errval_t err;
442     struct capref ram;
443
444     assert(slots > 0);
445     uint8_t bits = log2ceil(slots);
446     assert((1UL << bits) >= slots);
447     if (bits < DEFAULT_CNODE_BITS) {
448         bits = DEFAULT_CNODE_BITS;
449     }
450
451     if (retslots != NULL) {
452         *retslots = 1UL << bits;
453     }
454
455     // Allocate some memory
456     err = ram_alloc(&ram, bits + OBJBITS_CTE);
457     if (err_is_fail(err)) {
458         return err_push(err, LIB_ERR_RAM_ALLOC);
459     }
460
461     err = cnode_create_from_mem(dest, ram, cnoderef, bits);
462     if (err_is_fail(err)) {
463         return err_push(err, LIB_ERR_CNODE_CREATE_FROM_MEM);
464     }
465
466     err = cap_destroy(ram);
467     if (err_is_fail(err)) {
468         return err_push(err, LIB_ERR_CAP_DESTROY);
469     }
470
471     return SYS_ERR_OK;
472 }
473
474 /**
475  * \brief Create CNode with a given guard
476  *
477  * \param dest         Location where to place the cnode
478  * \param cnoderef   Filled in cnoderef struct if non-NULL
479  * \param slots Minimum number of slots in created CNode
480  * \param retslots If non-NULL, filled in with the  number of slots in created CNode
481  * \param guard        The guard value to set
482  * \param guard_size   The length of the guard in bits
483  *
484  * This function requires that dest refer to an existing but empty slot. It
485  * allocates memory (using #ram_alloc), and retypes that memory to a new CNode
486  * with the given guard value and size. An intermediate slot is used in order to
487  * set the guard value.
488  */
489 errval_t cnode_create_with_guard(struct capref dest, struct cnoderef *cnoderef,
490                                  cslot_t slots, cslot_t *retslots,
491                                  uint64_t guard, uint8_t guard_size)
492 {
493     errval_t err;
494
495     /* Create an intermediate cnode cap */
496     struct capref inter;
497     err = cnode_create(&inter, NULL, slots, retslots);
498     if (err_is_fail(err)) {
499         return err_push(err, LIB_ERR_CNODE_CREATE);
500     }
501
502     /* Mint it to the new destination setting the guard */
503     err = cap_mint(dest, inter, guard, guard_size);
504     if (err_is_fail(err)) {
505         return err_push(err, LIB_ERR_CAP_MINT);
506     }
507
508     /* Free the intermediate cnode cap and slot */
509     err = cap_delete(inter);
510     if (err_is_fail(err)) {
511         return err_push(err, LIB_ERR_WHILE_DELETING);
512     }
513     err = slot_free(inter);
514     if (err_is_fail(err)) {
515         return err_push(err, LIB_ERR_WHILE_FREEING_SLOT);
516     }
517
518     /* Build the cnoderef */
519     if (cnoderef != NULL) {
520         assert(slots > 0);
521         uint8_t bits = log2ceil(slots);
522         assert((1UL << bits) >= slots);
523         if (bits < DEFAULT_CNODE_BITS) {
524             bits = DEFAULT_CNODE_BITS;
525         }
526         *cnoderef = build_cnoderef(dest, bits);
527         cnoderef->guard_size = guard_size;
528     }
529
530     return SYS_ERR_OK;
531 }
532
533 /**
534  * \brief Create a VNode in newly-allocated memory
535  *
536  * \param dest location to place new VNode cap
537  * \param type VNode type to create
538  *
539  * This function requires that dest refer to an existing but empty slot.
540  * The intermidiate ram cap is destroyed.
541  */
542 errval_t vnode_create(struct capref dest, enum objtype type)
543 {
544     errval_t err;
545
546     struct capref ram;
547
548     size_t objbits_vnode = vnode_objbits(type);
549     err = ram_alloc(&ram, objbits_vnode);
550     if (err_is_fail(err)) {
551         return err_push(err, LIB_ERR_RAM_ALLOC);
552     }
553
554     assert(type_is_vnode(type));
555     err = cap_retype(dest, ram, type, 0);
556     if (err_is_fail(err)) {
557         return err_push(err, LIB_ERR_CAP_RETYPE);
558     }
559
560     err = cap_destroy(ram);
561     if (err_is_fail(err)) {
562         return err_push(err, LIB_ERR_CAP_DESTROY);
563     }
564
565     return SYS_ERR_OK;
566 }
567
568 /**
569  * \brief Create a Frame cap referring to newly-allocated RAM in a given slot
570  *
571  * \param dest  Location to place new frame cap
572  * \param bytes Minimum size of frame to create
573  * \param retbytes If non-NULL, filled in with size of created frame
574  *
575  * This function requires that dest refer to an existing but empty slot.
576  * #ram_alloc is used to allocate memory. After retyping the intermediate
577  * ram cap is destroyed.
578  *
579  * This function will returns a special error code if ram_alloc fails
580  * due to the constrains on the memory server (size of cap or region
581  * of memory). This is to facilitate retrying with different
582  * constraints.
583  */
584 errval_t frame_create(struct capref dest, size_t bytes, size_t *retbytes)
585 {
586     assert(bytes > 0);
587     uint8_t bits = log2ceil(bytes);
588     assert((1UL << bits) >= bytes);
589     errval_t err;
590
591     if (bits < BASE_PAGE_BITS) {
592         bits = BASE_PAGE_BITS;
593     }
594
595     struct capref ram;
596     err = ram_alloc(&ram, bits);
597     if (err_is_fail(err)) {
598         if (err_no(err) == MM_ERR_NOT_FOUND ||
599             err_no(err) == LIB_ERR_RAM_ALLOC_WRONG_SIZE) {
600             return err_push(err, LIB_ERR_RAM_ALLOC_MS_CONSTRAINTS);
601         }
602         return err_push(err, LIB_ERR_RAM_ALLOC);
603     }
604
605     err = cap_retype(dest, ram, ObjType_Frame, bits);
606     if (err_is_fail(err)) {
607         return err_push(err, LIB_ERR_CAP_RETYPE);
608     }
609
610     err = cap_destroy(ram);
611     if (err_is_fail(err)) {
612         return err;
613     }
614
615     if (retbytes != NULL) {
616         *retbytes = 1UL << bits;
617     }
618
619     return SYS_ERR_OK;
620 }
621
622 /**
623  * \brief Create a Dispatcher in newly-allocated memory
624  *
625  * \param dest location to place new dispatcher cap
626  *
627  * This function requires that dest refer to an existing but empty slot. It does
628  * not map in nor initialise the Dispatcher.
629  * The intermediate ram cap is destroyed.
630  */
631 errval_t dispatcher_create(struct capref dest)
632 {
633     errval_t err;
634
635     struct capref ram;
636     err = ram_alloc(&ram, OBJBITS_DISPATCHER);
637     if (err_is_fail(err)) {
638         return err_push(err, LIB_ERR_RAM_ALLOC);
639     }
640
641     err = cap_retype(dest, ram, ObjType_Dispatcher, 0);
642     if (err_is_fail(err)) {
643         return err_push(err, LIB_ERR_CAP_RETYPE);
644     }
645
646     err = cap_destroy(ram);
647     if (err_is_fail(err)) {
648         return err_push(err, LIB_ERR_CAP_DESTROY);
649     }
650     return SYS_ERR_OK;
651 }
652
653 /**
654  * \brief Create endpoint to caller on current dispatcher.
655  *
656  * \param buflen  Length of incoming LMP buffer, in words
657  * \param retcap  Pointer to capref struct, filled-in with location of cap
658  * \param retep   Double pointer to LMP endpoint, filled-in with allocated EP
659  */
660 errval_t endpoint_create(size_t buflen, struct capref *retcap,
661                          struct lmp_endpoint **retep)
662 {
663     errval_t err = slot_alloc(retcap);
664     if (err_is_fail(err)) {
665         return err_push(err, LIB_ERR_SLOT_ALLOC);
666     }
667
668     return lmp_endpoint_create_in_slot(buflen, *retcap, retep);
669 }
670
671 /**
672  * \brief Create a Frame cap referring to newly-allocated RAM in an allocated slot
673  *
674  * \param dest  Pointer to capref struct, filled-in with location of new cap
675  * \param bytes Minimum size of frame to create
676  * \param retbytes If non-NULL, filled in with size of created frame
677  */
678 errval_t frame_alloc(struct capref *dest, size_t bytes, size_t *retbytes)
679 {
680     errval_t err = slot_alloc(dest);
681     if (err_is_fail(err)) {
682         return err_push(err, LIB_ERR_SLOT_ALLOC);
683     }
684
685     return frame_create(*dest, bytes, retbytes);
686 }
687
688 /**
689  * \brief Create a DevFrame cap by retyping out of given source PhysAddr cap
690  *
691  * \param dest          Pointer to capref struct, filled-in with location of new cap
692  * \param src           Cap_info struct for the source PhysAddr cap
693  * \param size_bits     Size of created objects as a power of two
694  *                      (ignored for fixed-size objects)
695  */
696 errval_t devframe_type(struct capref *dest, struct capref src, uint8_t bits)
697 {
698     errval_t err = slot_alloc(dest);
699     if (err_is_fail(err)) {
700         return err_push(err, LIB_ERR_SLOT_ALLOC);
701     }
702
703     return cap_retype(*dest, src, ObjType_DevFrame, bits);
704 }
705
706 /**
707  * \brief Create an ID cap in a newly allocated slot.
708  *
709  * \param dest  Pointer to capref struct, filld-in with location of new cap.
710  *
711  * The caller is responsible for revoking the cap after using it.
712  */
713 errval_t idcap_alloc(struct capref *dest)
714 {
715     errval_t err = slot_alloc(dest);
716
717     if (err_is_fail(err)) {
718         return err_push(err, LIB_ERR_SLOT_ALLOC);
719     }
720
721     return idcap_create(*dest);
722 }
723
724 /**
725  * \brief Create an ID cap in the specified slot.
726  *
727  * \param dest  Capref, where ID cap should be created.
728  *
729  * The caller is responsible for revoking the cap after using it.
730  */
731 errval_t idcap_create(struct capref dest)
732 {
733     return cap_create(dest, ObjType_ID, 0);
734 }
735
736 /**
737  * \brief Builds a #cnoderef struct from a #capref struct using cap
738  *        identification.
739  *
740  * \param cnoder Pointer to a cnoderef struct, fill-in by function.
741  * \param capr   Capref to a CNode capability.
742  */
743 errval_t cnode_build_cnoderef(struct cnoderef *cnoder, struct capref capr)
744 {
745     struct capability cap;
746     errval_t err = debug_cap_identify(capr, &cap);
747     if (err_is_fail(err)) {
748         return err;
749     }
750
751     if (cap.type != ObjType_CNode) {
752         return LIB_ERR_NOT_CNODE;
753     }
754
755     cnoder->address = get_cap_addr(capr);
756     cnoder->address_bits = get_cap_valid_bits(capr);
757     cnoder->size_bits = cap.u.cnode.bits;
758     cnoder->guard_size = cap.u.cnode.guard_size;
759
760     return SYS_ERR_OK;
761 }