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