1/**
2 * \file
3 * \brief Inline functions to allow manipulation of raw capability addresses
4 *
5 * This file is not part of the standard includes, because most user code should
6 * treat #capref as an opaque value.
7 */
8
9/*
10 * Copyright (c) 2007, 2008, 2009, 2010, 2012, ETH Zurich.
11 * All rights reserved.
12 *
13 * This file is distributed under the terms in the attached LICENSE file.
14 * If you do not find this file, copies can be found by writing to:
15 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
16 */
17
18#ifndef INCLUDEBARRELFISH_CADDR_H
19#define INCLUDEBARRELFISH_CADDR_H
20
21#include <stdbool.h>
22#include <sys/cdefs.h>
23
24#include <barrelfish_kpi/types.h>
25#include <barrelfish_kpi/init.h>
26#include <barrelfish_kpi/capabilities.h>
27
28#include <barrelfish/cspace.h>
29
30#include <stdint.h>
31#include <stdbool.h>
32
33#include <bitmacros.h>
34
35__BEGIN_DECLS
36
37/**
38 * \brief extract slot (L2 index) from capability address `addr`
39 * \param addr the capability address
40 * \return The slot number (L2 index) component of the address, i.e. the low
41 *         bits.
42 */
43static inline cslot_t get_capaddr_slot(capaddr_t addr)
44{
45    return (cslot_t)(addr & MASK_T(capaddr_t, L2_CNODE_BITS));
46}
47
48/**
49 * \brief extract CNode address component from capability address `addr`
50 * \param addr the capability address
51 * \return the cnode component of the address, i.e. the address with the slot
52 *         (L2 index) bits set to zero.
53 */
54static inline capaddr_t get_capaddr_cnode_addr(capaddr_t addr)
55{
56    return addr & ~MASK_T(capaddr_t, L2_CNODE_BITS);
57}
58
59enum cnode_type {
60    CNODE_TYPE_ROOT = 0,
61    CNODE_TYPE_OTHER,
62    CNODE_TYPE_COUNT,
63} __attribute__((packed));
64
65/**
66 * \brief User-level representation of a CNode, this is essentially a capref
67 * to a CNode.
68 */
69struct cnoderef {
70    capaddr_t croot;
71    capaddr_t cnode;
72    enum cnode_type level;
73} __attribute__((packed));
74
75#define NULL_CNODE (struct cnoderef){ \
76    /*croot*/ 0, /*cnode*/ 0, \
77    /*level*/ CNODE_TYPE_ROOT  }
78
79/**
80 * \brief User-level representation of a capability and its CSpace address
81 */
82
83struct capref {
84    struct cnoderef cnode;
85    cslot_t slot;
86};
87
88#define NULL_CAP (struct capref){ /*cnode*/ NULL_CNODE, /*slot*/ 0 }
89
90static inline bool cnoderef_is_null(struct cnoderef cnoderef)
91{
92    return cnoderef.croot == 0 && cnoderef.cnode == 0;
93}
94
95static inline bool capref_is_null(struct capref capref)
96{
97    return cnoderef_is_null(capref.cnode) && capref.slot == 0;
98}
99
100/* well-known cnodes */
101extern struct cnoderef cnode_root, cnode_task, cnode_base, cnode_super,
102                       cnode_page, cnode_module;
103
104/* well-known capabilities */
105extern struct capref cap_root, cap_monitorep, cap_irq, cap_io, cap_dispatcher,
106                     cap_selfep, cap_kernel, cap_initep, cap_perfmon, cap_dispframe,
107                     cap_sessionid, cap_ipi, cap_vroot, cap_argcn, cap_procmng,
108                     cap_domainid;
109
110/**
111 * \brief Returns the depth in the CSpace address of a cap
112 */
113static inline uint8_t get_cap_level(struct capref cap)
114{
115    if (capref_is_null(cap)) {
116        return 0;
117    } else {
118        return cap.cnode.level + 1;
119    }
120}
121
122/**
123 * \brief Returns the CSpace address of a cap
124 */
125static inline capaddr_t get_cap_addr(struct capref cap)
126{
127    if (!capref_is_null(cap)) {
128        switch (cap.cnode.level) {
129            case CNODE_TYPE_ROOT:
130                return cap.slot << L2_CNODE_BITS;
131            // capref is in L2 CNode
132            case CNODE_TYPE_OTHER:
133                return cap.cnode.cnode | cap.slot;
134            default:
135                assert(!"invalid level");
136                return 0x0;
137        }
138    }
139    return 0;
140}
141
142/**
143 * \brief Returns the depth in the CSpace address of the CNode
144 *        containing the given cap
145 */
146static inline uint8_t get_cnode_level(struct capref cap)
147{
148    return cap.cnode.level;
149}
150
151/**
152 * \brief Returns the CSpace address of the CNode containing the given cap
153 */
154static inline capaddr_t get_cnode_addr(struct capref cap)
155{
156    switch (cap.cnode.level) {
157        case CNODE_TYPE_ROOT:
158            return cap.cnode.croot;
159        case CNODE_TYPE_OTHER:
160            return cap.cnode.cnode;
161        default:
162            assert(!"unknown cnoderef type");
163            return 0x0;
164    }
165}
166
167
168/**
169 * \brief Returns the CSpace address of the cspace root cap of the given cap
170 */
171static inline capaddr_t get_croot_addr(struct capref cap)
172{
173    return cap.cnode.croot;
174}
175
176static inline struct capref get_croot_capref(struct capref cap)
177{
178    capaddr_t croot = get_croot_addr(cap);
179    struct capref ref = {
180        .cnode = {
181            .croot = CPTR_ROOTCN,
182            .cnode = get_capaddr_cnode_addr(croot),
183            .level = CNODE_TYPE_OTHER,
184        },
185        .slot = get_capaddr_slot(croot),
186    };
187    return ref;
188}
189
190/**
191 * \brief Compare two cnoderefs
192 *
193 * Two cnoderefs are equal if they have the same base address,
194 * same number of valid bits and the same guard_size.
195 */
196static inline bool cnodecmp(struct cnoderef c1, struct cnoderef c2)
197{
198    return (c1.cnode == c2.cnode && c1.croot == c2.croot && c1.level == c2.level);
199}
200
201/**
202 * \brief Compare two caprefs
203 *
204 * Two caprefs are equal if they have the same cnoderef and the same
205 * slot.
206 */
207static inline bool capcmp(struct capref c1, struct capref c2)
208{
209    return c1.slot == c2.slot && cnodecmp(c1.cnode, c2.cnode);
210}
211
212/**
213 * \brief Creates a new #cnoderef struct, performing address calculations.
214 * XXX: TODO remove size_bits from signature
215 */
216static inline struct cnoderef build_cnoderef(struct capref cap,
217                                             enum cnode_type cntype)
218{
219    assert(cntype < CNODE_TYPE_COUNT);
220
221    struct cnoderef cnode = NULL_CNODE;
222    switch(get_cnode_level(cap)) {
223        // L2 cnode in our root cnode
224        case CNODE_TYPE_ROOT:
225            // cannot make cnoderef from non-invokable capref.
226            assert(cap.cnode.croot == CPTR_ROOTCN);
227            cnode.croot = CPTR_ROOTCN;
228            cnode.cnode = get_cap_addr(cap);
229            cnode.level = cntype;
230            break;
231        // CNode for another cspace
232        case CNODE_TYPE_OTHER:
233            cnode.level = cntype;
234            switch (cntype) {
235                // creating a cnoderef to a root cnode for another cspace
236                case CNODE_TYPE_ROOT:
237                    cnode.croot = get_cap_addr(cap);
238                    cnode.cnode = 0;
239                    break;
240                case CNODE_TYPE_OTHER:
241                    cnode.croot = get_croot_addr(cap);
242                    cnode.cnode = get_cap_addr(cap);
243                    break;
244                default:
245                    assert(!"build_cnoderef: provided cntype invalid");
246                    return NULL_CNODE;
247            }
248            break;
249        default:
250            assert(!"cap level not valid");
251            return NULL_CNODE;
252    }
253    return cnode;
254}
255
256__END_DECLS
257
258#endif
259