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