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_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
33struct 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
46struct cnoderef cnode_task = TASK_CNODE_INIT;
47
48/// Base CNode
49struct cnoderef cnode_base = {
50    .cnode = CPTR_BASE_PAGE_CN_BASE,
51    .level = CNODE_TYPE_OTHER,
52    .croot = CPTR_ROOTCN,
53};
54
55/// Super CNode
56struct cnoderef cnode_super = {
57    .cnode = CPTR_SUPERCN_BASE,
58    .level = CNODE_TYPE_OTHER,
59    .croot = CPTR_ROOTCN,
60};
61
62/// Page CNode
63struct cnoderef cnode_page = PAGE_CNODE_INIT;
64
65/// Module CNode
66struct cnoderef cnode_module = {
67    .cnode = CPTR_MODULECN_BASE,
68    .level = CNODE_TYPE_OTHER,
69    .croot = CPTR_ROOTCN,
70};
71
72/// Capability to Root CNode
73struct capref cap_root = {
74    .cnode = TASK_CNODE_INIT,
75    .slot  = TASKCN_SLOT_ROOTCN
76};
77
78/// Capability for IRQ table
79struct capref cap_irq = {
80    .cnode = TASK_CNODE_INIT,
81    .slot  = TASKCN_SLOT_IRQ
82};
83
84/// Capability for legacy IO
85struct capref cap_io = {
86    .cnode = TASK_CNODE_INIT,
87    .slot  = TASKCN_SLOT_IO
88};
89
90/// Capability for endpoint to self
91struct capref cap_selfep = {
92    .cnode = TASK_CNODE_INIT,
93    .slot = TASKCN_SLOT_SELFEP
94};
95
96/// Capability for dispatcher
97struct capref cap_dispatcher = {
98    .cnode = TASK_CNODE_INIT,
99    .slot  = TASKCN_SLOT_DISPATCHER
100};
101
102/// Capability for dispatcher
103struct capref cap_dispframe = {
104    .cnode = TASK_CNODE_INIT,
105    .slot  = TASKCN_SLOT_DISPFRAME
106};
107
108/// Capability for ArgSpace
109struct capref cap_argcn = {
110    .cnode = ROOT_CNODE_INIT,
111    .slot  = ROOTCN_SLOT_ARGCN
112};
113
114/// Capability for monitor endpoint
115struct capref cap_monitorep = {
116    .cnode = TASK_CNODE_INIT,
117    .slot  = TASKCN_SLOT_MONITOREP
118};
119
120/// Capability for kernel (only in monitor)
121struct capref cap_kernel = {
122    .cnode = TASK_CNODE_INIT,
123    .slot  = TASKCN_SLOT_KERNELCAP
124};
125
126/// Capability for IPI sending (only in monitor)
127struct capref cap_ipi = {
128    .cnode = TASK_CNODE_INIT,
129    .slot  = TASKCN_SLOT_IPI
130};
131
132/// PerfMon CNode
133struct 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)
139struct capref cap_initep = {
140    .cnode = TASK_CNODE_INIT,
141    .slot  = TASKCN_SLOT_INITEP
142};
143
144/// Session ID
145struct capref cap_sessionid = {
146    .cnode = TASK_CNODE_INIT,
147    .slot = TASKCN_SLOT_SESSIONID
148};
149
150/// Process manager cap, allows creating domains.
151struct capref cap_procmng = {
152    .cnode = TASK_CNODE_INIT,
153    .slot = TASKCN_SLOT_PROC_MNG
154};
155
156/// Domain ID cap.
157struct capref cap_domainid = {
158    .cnode = TASK_CNODE_INIT,
159    .slot = TASKCN_SLOT_DOMAINID
160};
161
162/// Root PML4 VNode
163struct capref cap_vroot = {
164    .cnode = PAGE_CNODE_INIT,
165    .slot = PAGECN_SLOT_VROOT,
166};
167
168static inline bool backoff(int count)
169{
170    // very crude exponential backoff based upon core id
171    int yieldcnt = 2^count * disp_get_core_id();
172    for (int i=0; i<yieldcnt; i++) {
173        thread_yield();
174    }
175    return true;
176}
177
178/**
179 * \brief Retype a capability into one or more new capabilities, going through
180 * the monitor to ensure consistancy with other cores.  Only necessary for
181 * caps that have been sent remotely.
182 */
183static errval_t cap_retype_remote(struct capref src_root, struct capref dest_root,
184                                  capaddr_t src, gensize_t offset, enum objtype new_type,
185                                  gensize_t objsize, size_t count, capaddr_t to,
186                                  capaddr_t slot, int to_level)
187{
188    errval_t err, remote_cap_err;
189    struct monitor_blocking_binding *mrc = get_monitor_blocking_binding();
190    if (!mrc) {
191        err = monitor_client_blocking_rpc_init();
192        mrc = get_monitor_blocking_binding();
193        if (err_is_fail(err) || !mrc) {
194            return LIB_ERR_MONITOR_RPC_NULL;
195        }
196    }
197
198    int send_count = 0;
199    do {
200        if (capcmp(src_root, dest_root)) {
201            dest_root = NULL_CAP;
202        }
203        err = mrc->rpc_tx_vtbl.remote_cap_retype(mrc, src_root, dest_root, src,
204                                          offset, (uint64_t)new_type, objsize,
205                                          count, to, slot, to_level, &remote_cap_err);
206        if (err_is_fail(err)){
207            DEBUG_ERR(err, "remote cap retype\n");
208        }
209    } while (err_no(remote_cap_err) == MON_ERR_REMOTE_CAP_RETRY && backoff(++send_count));
210
211    return remote_cap_err;
212
213}
214
215
216/**
217 * \brief Delete the given capability, going through  the monitor to ensure
218 * consistancy with other cores.  Only necessary for caps that have been sent
219 * remotely.
220 *
221 * \param cap Capability to be deleted
222 *
223 * Deletes (but does not revoke) the given capability, allowing the CNode slot
224 * to be reused.
225 */
226static errval_t cap_delete_remote(struct capref root, capaddr_t src, uint8_t level)
227{
228    errval_t err, remote_cap_err;
229    struct monitor_blocking_binding *mrc = get_monitor_blocking_binding();
230    if (!mrc) {
231        err = monitor_client_blocking_rpc_init();
232        mrc = get_monitor_blocking_binding();
233        if (err_is_fail(err) || !mrc) {
234            return LIB_ERR_MONITOR_RPC_NULL;
235        }
236    }
237
238    int count = 0;
239    do {
240        err = mrc->rpc_tx_vtbl.remote_cap_delete(mrc, root, src, level,
241                                          &remote_cap_err);
242        if (err_is_fail(err)){
243            DEBUG_ERR(err, "remote cap delete\n");
244        }
245    } while (err_no(remote_cap_err) == MON_ERR_REMOTE_CAP_RETRY && backoff(++count));
246
247    return remote_cap_err;
248}
249
250/**
251 * \brief Revoke (delete all copies and descendants of) the given capability,
252 * going through the monitor to ensure consistancy with other cores.  Only
253 * necessary for caps that have been sent remotely.
254 *
255 * \param cap Capability to be revoked
256 *
257 * Deletes all copies and descendants of the given capability, but not the
258 * capability itself. If this succeeds, the capability is guaranteed to be
259 * the only copy in the system.
260 */
261static errval_t cap_revoke_remote(struct capref root, capaddr_t src, uint8_t level)
262{
263    errval_t err, remote_cap_err;
264    struct monitor_blocking_binding *mrc = get_monitor_blocking_binding();
265    if (!mrc) {
266        err = monitor_client_blocking_rpc_init();
267        mrc = get_monitor_blocking_binding();
268        if (err_is_fail(err) || !mrc) {
269            return LIB_ERR_MONITOR_RPC_NULL;
270        }
271    }
272
273    int count = 0;
274    do {
275        err = mrc->rpc_tx_vtbl.remote_cap_revoke(mrc, root, src, level,
276                                          &remote_cap_err);
277        if (err_is_fail(err)){
278            DEBUG_ERR(err, "remote cap delete\n");
279        }
280    } while (err_no(remote_cap_err) == MON_ERR_REMOTE_CAP_RETRY && backoff(++count));
281
282    return remote_cap_err;
283}
284
285/**
286 * \brief Retype (part of) a capability into one or more new capabilities
287 *
288 * \param dest_start    Location of first destination slot, which must be empty
289 * \param src           Source capability to retype
290 * \param offset        Offset into source capability
291 * \param new_type      Kernel object type to retype to.
292 * \param objsize       Size of created objects in bytes
293 *                      (ignored for fixed-size objects)
294 * \param count         The number of new objects to create
295 *
296 * When retyping IRQSrc capabilities, offset and objsize represent the start
297 * and end of the to be created interrupt range. Count must be 1 for IRQSrc.
298 *
299 * Retypes (part of) the given source capability into a number of new
300 * capabilities, which may be of the same or of different type. The new
301 * capabilities are created in the slots starting from dest_start, which must
302 * all be empty and lie in the same CNode. The number of objects created is
303 * determined by the argument `count`.
304 */
305errval_t cap_retype(struct capref dest_start, struct capref src, gensize_t offset,
306                    enum objtype new_type, gensize_t objsize, size_t count)
307{
308    errval_t err;
309
310    // Address of destination cspace
311    capaddr_t dcs_addr = get_croot_addr(dest_start);
312    // Address of the cap to the destination CNode
313    capaddr_t dcn_addr = get_cnode_addr(dest_start);
314    // Depth/Level of destination cnode
315    enum cnode_type dcn_level = get_cnode_level(dest_start);
316    // Address of source cspace
317    capaddr_t scp_root = get_croot_addr(src);
318    // Address of source capability
319    capaddr_t scp_addr = get_cap_addr(src);
320
321    err = invoke_cnode_retype(cap_root, scp_root, scp_addr, offset, new_type,
322                              objsize, count, dcs_addr, dcn_addr, dcn_level,
323                              dest_start.slot);
324
325    if (err_no(err) == SYS_ERR_RETRY_THROUGH_MONITOR) {
326        struct capref src_root = get_croot_capref(src);
327        struct capref dest_root = get_croot_capref(dest_start);
328        return cap_retype_remote(src_root, dest_root, scp_addr, offset, new_type,
329                                 objsize, count, dcn_addr, dest_start.slot,
330                                 dcn_level);
331    } else {
332        return err;
333    }
334}
335
336
337/**
338 * \brief Create a capability
339 *
340 * \param dest      Location where to create the cap, which must be empty.
341 * \param type      Kernel object type to create.
342 * \param size      Size of the created capability in bytes.
343 *                  (ignored for fixed-size objects)
344 *
345 * Only certain types of capabilities can be created this way. If invoked on
346 * a capability type, that is not creatable at runtime the error
347 * SYS_ERR_TYPE_NOT_CREATABLE is returned. Most capabilities have to be retyped
348 * from other capabilities with cap_retype().
349 */
350errval_t cap_create(struct capref dest, enum objtype type, size_t size)
351{
352    errval_t err;
353
354    // Address of the cap to the destination CNode
355    capaddr_t dest_cnode_cptr = get_cnode_addr(dest);
356    enum cnode_type dest_cnode_level = get_cnode_level(dest);
357
358    err = invoke_cnode_create(cap_root, type, size, dest_cnode_cptr,
359                              dest_cnode_level, dest.slot);
360
361    return err;
362}
363
364/**
365 * \brief Delete the given capability
366 *
367 * \param cap Capability to be deleted
368 *
369 * Deletes (but does not revoke) the given capability, allowing the CNode slot
370 * to be reused.
371 */
372errval_t cap_delete(struct capref cap)
373{
374    errval_t err;
375    struct capref croot = get_croot_capref(cap);
376    capaddr_t caddr = get_cap_addr(cap);
377    enum cnode_type level = get_cap_level(cap);
378
379    err = invoke_cnode_delete(croot, caddr, level);
380
381    if (err_no(err) == SYS_ERR_RETRY_THROUGH_MONITOR) {
382        return cap_delete_remote(croot, caddr, level);
383    } else {
384        return err;
385    }
386}
387
388/**
389 * \brief Revoke (delete all copies and descendants of) the given capability
390 *
391 * \param cap Capability to be revoked
392 *
393 * Deletes all copies and descendants of the given capability, but not the
394 * capability itself. If this succeeds, the capability is guaranteed to be
395 * the only copy in the system.
396 */
397errval_t cap_revoke(struct capref cap)
398{
399    errval_t err;
400    struct capref croot = get_croot_capref(cap);
401    capaddr_t caddr = get_cap_addr(cap);
402    enum cnode_type level = get_cap_level(cap);
403
404    err = invoke_cnode_revoke(croot, caddr, level);
405
406    if (err_no(err) == SYS_ERR_RETRY_THROUGH_MONITOR) {
407        return cap_revoke_remote(croot, caddr, level);
408    } else {
409        return err;
410    }
411}
412
413/**
414 * \brief Destroy a capability, i.e. delete it and free the slot.
415 *
416 * \param cap           Capability to be destroyed
417 */
418errval_t cap_destroy(struct capref cap)
419{
420    errval_t err;
421    err = cap_delete(cap);
422    if (err_is_fail(err)) {
423        return err;
424    }
425
426    err = slot_free(cap);
427    if (err_is_fail(err)) {
428        return err_push(err, LIB_ERR_WHILE_FREEING_SLOT);
429    }
430
431    return SYS_ERR_OK;
432}
433
434/**
435 * \brief Replace own L1 CNode
436 *
437 * \param new the replacement L1 CNode
438 * \param ret the slot to put the old L1 CNode
439 */
440errval_t root_cnode_resize(struct capref new, struct capref ret)
441{
442    assert(get_croot_addr(new) == CPTR_ROOTCN);
443    assert(get_cap_level(new) == CNODE_TYPE_COUNT);
444    capaddr_t new_cptr = get_cap_addr(new);
445
446    assert(get_croot_addr(ret) == CPTR_ROOTCN);
447    assert(get_cap_level(ret) == CNODE_TYPE_COUNT);
448    capaddr_t retcn_ptr= get_cnode_addr(ret);
449
450    return invoke_cnode_resize(cap_root, new_cptr, retcn_ptr, ret.slot);
451}
452
453/**
454 * \brief Create a CNode from a given RAM capability in a specific slot
455 *
456 * \param dest location in which to place newly-created CNode cap
457 * \param src  location of RAM capability to be retyped to new CNode
458 * \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info
459 * \param slots number of slots in created CNode
460 *                  must match size of RAM capability.
461 *
462 * This function requires that dest refer to an existing but empty slot. It
463 * retypes the given memory to a new CNode.
464 */
465errval_t cnode_create_from_mem(struct capref dest, struct capref src,
466                               enum objtype cntype, struct cnoderef *cnoderef,
467                               size_t slots)
468{
469    errval_t err;
470
471    if (cntype != ObjType_L1CNode &&
472        cntype != ObjType_L2CNode)
473    {
474        return LIB_ERR_CNODE_TYPE;
475    }
476
477
478    // Retype it to the destination
479    err = cap_retype(dest, src, 0, cntype, slots * (1UL << OBJBITS_CTE), 1);
480    if (err_is_fail(err)) {
481        return err_push(err, LIB_ERR_CAP_RETYPE);
482    }
483
484    // Construct the cnoderef to return
485    if (cnoderef != NULL) {
486        enum cnode_type ref_cntype = cntype == ObjType_L1CNode ? CNODE_TYPE_ROOT : CNODE_TYPE_OTHER;
487        *cnoderef = build_cnoderef(dest, ref_cntype);
488    }
489
490    return SYS_ERR_OK;
491}
492
493/**
494 * \brief Create a CNode from newly-allocated RAM in a newly-allocated slot
495 *
496 * \param ret_dest capref struct to be filled-in with location of CNode
497 * \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info
498 * \param slots Minimum number of slots in created CNode
499 * \param retslots If non-NULL, filled in with the  number of slots in created CNode
500 */
501errval_t cnode_create(struct capref *ret_dest, struct cnoderef *cnoderef,
502                      cslot_t slots, cslot_t *retslots)
503{
504    USER_PANIC("cnode_create deprecated; use cnode_create_l1, cnode_create_l2, or cnode_create_foreign_l2: %p %p %p %p\n",
505            __builtin_return_address(0),
506#ifdef __x86_64__
507            __builtin_return_address(1),
508            __builtin_return_address(2),
509            __builtin_return_address(3)
510#else
511            NULL, NULL, NULL
512#endif
513            );
514    return LIB_ERR_NOT_IMPLEMENTED;
515}
516
517/**
518 * \brief Create a L2 CNode from newly-allocated RAM in a newly-allocated slot
519 *
520 * \param ret_dest capref struct to be filled-in with location of CNode
521 * \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info
522 *
523 * This function always creates a L2 CNode which contains 256 capabilities
524 */
525errval_t cnode_create_l2(struct capref *ret_dest, struct cnoderef *cnoderef)
526{
527    errval_t err;
528
529    // Allocate a slot in root cn for destination
530    assert(ret_dest != NULL);
531    err = slot_alloc_root(ret_dest);
532    if (err_is_fail(err)) {
533        return err_push(err, LIB_ERR_SLOT_ALLOC);
534    }
535
536    cslot_t retslots;
537    err = cnode_create_raw(*ret_dest, cnoderef, ObjType_L2CNode,
538                           L2_CNODE_SLOTS, &retslots);
539    if (retslots != L2_CNODE_SLOTS) {
540        debug_printf("Unable to create properly sized L2 CNode: got %"PRIuCSLOT" slots instead of %"PRIuCSLOT"\n",
541                retslots, (cslot_t)L2_CNODE_SLOTS);
542    }
543    return err;
544}
545
546errval_t cnode_create_l1(struct capref *ret_dest, struct cnoderef *cnoderef)
547{
548    errval_t err;
549
550    // Allocate a slot in root cn for destination
551    assert(ret_dest != NULL);
552    err = slot_alloc(ret_dest);
553    if (err_is_fail(err)) {
554        return err_push(err, LIB_ERR_SLOT_ALLOC);
555    }
556
557    cslot_t retslots;
558    err = cnode_create_raw(*ret_dest, cnoderef, ObjType_L1CNode,
559                           L2_CNODE_SLOTS, &retslots);
560    if (retslots != L2_CNODE_SLOTS) {
561        debug_printf("Unable to create initial L1 CNode: got %"PRIuCSLOT" slots instead of %"PRIuCSLOT"\n",
562                     retslots, (cslot_t)L2_CNODE_SLOTS);
563    }
564    return err;
565}
566
567/**
568 * \brief Create a CNode for another cspace from newly-allocated RAM in a
569 *        newly-allocated slot
570 *
571 * \param dest_l1   capref to L1 (root) cnode of destination cspace
572 * \param dest_slot slot to fill with new cnode in destination L1 cnode
573 * \param cnoderef  cnoderef struct, filled-in if non-NULL with relevant info
574 *
575 * This function creates a CNode which contains 256 capabilities initially
576 * and puts it in a slot in our cspace.
577 */
578errval_t cnode_create_foreign_l2(struct capref dest_l1, cslot_t dest_slot,
579                                 struct cnoderef *cnoderef)
580{
581    errval_t err;
582
583    if (capref_is_null(dest_l1)) {
584        return LIB_ERR_CROOT_NULL;
585    }
586    assert(!capref_is_null(dest_l1));
587
588    struct capref dest;
589    dest.cnode = build_cnoderef(dest_l1, CNODE_TYPE_ROOT);
590    dest.slot = dest_slot;
591
592    cslot_t retslots;
593    err = cnode_create_raw(dest, NULL, ObjType_L2CNode, L2_CNODE_SLOTS, &retslots);
594    if (retslots != L2_CNODE_SLOTS) {
595        debug_printf("Unable to create properly sized foreign CNode: "
596                     "got %"PRIuCSLOT" slots instead of %"PRIuCSLOT"\n",
597                     retslots, (cslot_t)L2_CNODE_SLOTS);
598    }
599
600    // Create proper cnoderef for foreign L2
601    if (cnoderef) {
602        cnoderef->croot = get_cap_addr(dest_l1);
603        cnoderef->cnode = ROOTCN_SLOT_ADDR(dest_slot);
604        cnoderef->level = CNODE_TYPE_OTHER;
605    }
606    return err;
607}
608
609/**
610 * \brief Create a CNode from newly-allocated RAM in the given slot
611 *
612 * \param dest location in which to place CNode cap
613 * \param cnoderef cnoderef struct, filled-in if non-NULL with relevant info
614 * \param cntype, type of new cnode
615 * \param slots Minimum number of slots in created CNode
616 * \param retslots If non-NULL, filled in with the  number of slots in created CNode
617 *
618 * This function requires that dest refer to an existing but empty slot. It
619 * allocates memory (using #ram_alloc), and retypes that memory to a new CNode.
620 * The intermediate ram cap is destroyed.
621 */
622errval_t cnode_create_raw(struct capref dest, struct cnoderef *cnoderef,
623                          enum objtype cntype, cslot_t slots, cslot_t *retslots)
624{
625    errval_t err;
626    struct capref ram;
627
628    assert(slots > 0);
629
630    if (cntype != ObjType_L1CNode &&
631        cntype != ObjType_L2CNode)
632    {
633        return LIB_ERR_CNODE_TYPE;
634    }
635
636    if (slots < L2_CNODE_SLOTS ||
637        (cntype == ObjType_L2CNode && slots != L2_CNODE_SLOTS))
638    {
639        return LIB_ERR_CNODE_SLOTS;
640    }
641
642    if (retslots != NULL) {
643        *retslots = slots;
644    }
645
646    // XXX: mem_serv should serve non-power-of-two requests
647    uint8_t bits = log2ceil(slots);
648    assert(slots >= (1UL << bits));
649
650    // Allocate some memory
651    err = ram_alloc(&ram, bits + OBJBITS_CTE);
652    if (err_is_fail(err)) {
653        return err_push(err, LIB_ERR_RAM_ALLOC);
654    }
655
656    err = cnode_create_from_mem(dest, ram, cntype, cnoderef, slots);
657    if (err_is_fail(err)) {
658        return err_push(err, LIB_ERR_CNODE_CREATE_FROM_MEM);
659    }
660
661    err = cap_destroy(ram);
662    if (err_is_fail(err)) {
663        return err_push(err, LIB_ERR_CAP_DESTROY);
664    }
665
666    return SYS_ERR_OK;
667}
668
669/**
670 * \brief Create CNode with a given guard
671 *
672 * \param dest         Location where to place the cnode
673 * \param cnoderef   Filled in cnoderef struct if non-NULL
674 * \param slots Minimum number of slots in created CNode
675 * \param retslots If non-NULL, filled in with the  number of slots in created CNode
676 * \param guard        The guard value to set
677 * \param guard_size   The length of the guard in bits
678 *
679 * This function requires that dest refer to an existing but empty slot. It
680 * allocates memory (using #ram_alloc), and retypes that memory to a new CNode
681 * with the given guard value and size. An intermediate slot is used in order to
682 * set the guard value.
683 */
684errval_t cnode_create_with_guard(struct capref dest, struct cnoderef *cnoderef,
685                                 cslot_t slots, cslot_t *retslots,
686                                 uint64_t guard, uint8_t guard_size)
687{
688    USER_PANIC("%s: GPT CNodes are deprecated\n", __FUNCTION__);
689}
690
691/**
692 * \brief Create a VNode in newly-allocated memory
693 *
694 * \param dest location to place new VNode cap
695 * \param type VNode type to create
696 *
697 * This function requires that dest refer to an existing but empty slot.
698 * The intermidiate ram cap is destroyed.
699 */
700errval_t vnode_create(struct capref dest, enum objtype type)
701{
702    errval_t err;
703
704    struct capref ram;
705
706    size_t objbits_vnode = vnode_objbits(type);
707    err = ram_alloc(&ram, objbits_vnode);
708    if (err_no(err) == LIB_ERR_RAM_ALLOC_WRONG_SIZE && type != ObjType_VNode_ARM_l1) {
709        // can only get 4kB pages, cannot create ARM_l1, and waste 3kB for
710        // ARM_l2
711        err = ram_alloc(&ram, BASE_PAGE_BITS);
712    }
713    if (err_is_fail(err)) {
714        return err_push(err, LIB_ERR_RAM_ALLOC);
715    }
716
717    assert(type_is_vnode(type));
718    err = cap_retype(dest, ram, 0, type, vnode_objsize(type), 1);
719    if (err_is_fail(err)) {
720        return err_push(err, LIB_ERR_CAP_RETYPE);
721    }
722
723    err = cap_destroy(ram);
724    if (err_is_fail(err)) {
725        return err_push(err, LIB_ERR_CAP_DESTROY);
726    }
727
728    return SYS_ERR_OK;
729}
730
731/**
732 * \brief Create a Frame cap referring to newly-allocated RAM in a given slot
733 *
734 * \param dest  Location to place new frame cap
735 * \param bytes Minimum size of frame to create
736 * \param retbytes If non-NULL, filled in with size of created frame
737 *
738 * This function requires that dest refer to an existing but empty slot.
739 * #ram_alloc is used to allocate memory. After retyping the intermediate
740 * ram cap is destroyed.
741 *
742 * This function will returns a special error code if ram_alloc fails
743 * due to the constrains on the memory server (size of cap or region
744 * of memory). This is to facilitate retrying with different
745 * constraints.
746 */
747errval_t frame_create(struct capref dest, size_t bytes, size_t *retbytes)
748{
749    assert(bytes > 0);
750    uint8_t bits = log2ceil(bytes);
751    assert((1UL << bits) >= bytes);
752    errval_t err;
753
754    if (bits < BASE_PAGE_BITS) {
755        bits = BASE_PAGE_BITS;
756    }
757
758    struct capref ram;
759    err = ram_alloc(&ram, bits);
760    if (err_is_fail(err)) {
761        if (err_no(err) == MM_ERR_NOT_FOUND ||
762            err_no(err) == LIB_ERR_RAM_ALLOC_WRONG_SIZE) {
763            return err_push(err, LIB_ERR_RAM_ALLOC_MS_CONSTRAINTS);
764        }
765        return err_push(err, LIB_ERR_RAM_ALLOC);
766    }
767
768    err = cap_retype(dest, ram, 0, ObjType_Frame, (1UL << bits), 1);
769    if (err_is_fail(err)) {
770        return err_push(err, LIB_ERR_CAP_RETYPE);
771    }
772
773    err = cap_destroy(ram);
774    if (err_is_fail(err)) {
775        return err_push(err, LIB_ERR_CAP_DESTROY);
776    }
777
778    if (retbytes != NULL) {
779        *retbytes = 1UL << bits;
780    }
781
782    return SYS_ERR_OK;
783}
784
785/**
786 * \brief Create a Dispatcher in newly-allocated memory
787 *
788 * \param dest location to place new dispatcher cap
789 *
790 * This function requires that dest refer to an existing but empty slot. It does
791 * not map in nor initialise the Dispatcher.
792 * The intermediate ram cap is destroyed.
793 */
794errval_t dispatcher_create(struct capref dest)
795{
796    errval_t err;
797
798    struct capref ram;
799    assert(1 << log2ceil(OBJSIZE_DISPATCHER) == OBJSIZE_DISPATCHER);
800    err = ram_alloc(&ram, log2ceil(OBJSIZE_DISPATCHER));
801    if (err_is_fail(err)) {
802        return err_push(err, LIB_ERR_RAM_ALLOC);
803    }
804
805    err = cap_retype(dest, ram, 0, ObjType_Dispatcher, 0, 1);
806    if (err_is_fail(err)) {
807        return err_push(err, LIB_ERR_CAP_RETYPE);
808    }
809
810    err = cap_destroy(ram);
811    if (err_is_fail(err)) {
812        return err_push(err, LIB_ERR_CAP_DESTROY);
813    }
814    return SYS_ERR_OK;
815}
816
817/**
818 * \brief Create endpoint to caller on current dispatcher.
819 *
820 * \param buflen  Length of incoming LMP buffer, in words
821 * \param retcap  Pointer to capref struct, filled-in with location of cap
822 * \param retep   Double pointer to LMP endpoint, filled-in with allocated EP
823 */
824errval_t endpoint_create(size_t buflen, struct capref *retcap,
825                         struct lmp_endpoint **retep)
826{
827    errval_t err = slot_alloc(retcap);
828    if (err_is_fail(err)) {
829        return err_push(err, LIB_ERR_SLOT_ALLOC);
830    }
831
832    return lmp_endpoint_create_in_slot(buflen, *retcap, retep);
833}
834
835/**
836 * \brief Create a Frame cap referring to newly-allocated RAM in an allocated slot
837 *
838 * \param dest  Pointer to capref struct, filled-in with location of new cap
839 * \param bytes Minimum size of frame to create
840 * \param retbytes If non-NULL, filled in with size of created frame
841 */
842errval_t frame_alloc(struct capref *dest, size_t bytes, size_t *retbytes)
843{
844    errval_t err = slot_alloc(dest);
845    if (err_is_fail(err)) {
846        return err_push(err, LIB_ERR_SLOT_ALLOC);
847    }
848
849    return frame_create(*dest, bytes, retbytes);
850}
851
852/**
853 * \brief Create a DevFrame cap by retyping out of given source PhysAddr cap
854 *
855 * \param dest          Pointer to capref struct, filled-in with location of new cap
856 * \param src           Cap_info struct for the source PhysAddr cap
857 * \param size_bits     Size of created objects as a power of two
858 *                      (ignored for fixed-size objects)
859 */
860errval_t devframe_type(struct capref *dest, struct capref src, uint8_t bits)
861{
862    errval_t err = slot_alloc(dest);
863    if (err_is_fail(err)) {
864        return err_push(err, LIB_ERR_SLOT_ALLOC);
865    }
866
867    return cap_retype(*dest, src, 0, ObjType_DevFrame, 1UL << bits, 1);
868}
869
870/**
871 * \brief Create an ID cap in a newly allocated slot.
872 *
873 * \param dest  Pointer to capref struct, filld-in with location of new cap.
874 *
875 * The caller is responsible for revoking the cap after using it.
876 */
877errval_t idcap_alloc(struct capref *dest)
878{
879    errval_t err = slot_alloc(dest);
880
881    if (err_is_fail(err)) {
882        return err_push(err, LIB_ERR_SLOT_ALLOC);
883    }
884
885    return idcap_create(*dest);
886}
887
888/**
889 * \brief Create an ID cap in the specified slot.
890 *
891 * \param dest  Capref, where ID cap should be created.
892 *
893 * The caller is responsible for revoking the cap after using it.
894 */
895errval_t idcap_create(struct capref dest)
896{
897    return cap_create(dest, ObjType_ID, 0);
898}
899
900/**
901 * \brief Builds a #cnoderef struct from a #capref struct using cap
902 *        identification.
903 *
904 * \param cnoder Pointer to a cnoderef struct, fill-in by function.
905 * \param capr   Capref to a CNode capability.
906 */
907errval_t cnode_build_cnoderef(struct cnoderef *cnoder, struct capref capr)
908{
909    struct capability cap;
910    errval_t err = debug_cap_identify(capr, &cap);
911    if (err_is_fail(err)) {
912        return err;
913    }
914
915    if (cap.type != ObjType_L1CNode &&
916        cap.type != ObjType_L2CNode) {
917        return LIB_ERR_NOT_CNODE;
918    }
919
920    if (!cnodecmp(capr.cnode, cnode_root)) {
921        USER_PANIC("cnode_build_cnoderef NYI for non rootcn caprefs");
922    }
923
924    cnoder->croot = get_croot_addr(capr);
925    cnoder->cnode = capr.slot << L2_CNODE_BITS;
926    cnoder->level = CNODE_TYPE_OTHER;
927
928    return SYS_ERR_OK;
929}
930