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