1/**
2 * \file
3 * \brief Low-level capability invocations
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 2010, 2012, 2013, 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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#ifndef INCLUDEBARRELFISH_INVOCATIONS_ARCH_H
16#define INCLUDEBARRELFISH_INVOCATIONS_ARCH_H
17
18#include <barrelfish/syscall_arch.h> // for sys_invoke and cap_invoke
19#include <barrelfish_kpi/dispatcher_shared.h>
20#include <barrelfish_kpi/distcaps.h>            // for distcap_state_t
21#include <barrelfish_kpi/syscalls.h>
22#include <barrelfish_kpi/lmp.h> // invoking lmp endpoint requires flags
23#include <barrelfish/caddr.h>
24#include <barrelfish_kpi/paging_arch.h>
25
26/**
27 * capability invocation syscall wrapper, copied from x86_32 version
28 */
29static inline struct sysret cap_invoke(struct capref to, uintptr_t argc, uintptr_t cmd,
30                                       uintptr_t arg2, uintptr_t arg3,
31                                       uintptr_t arg4, uintptr_t arg5,
32                                       uintptr_t arg6, uintptr_t arg7,
33                                       uintptr_t arg8, uintptr_t arg9,
34                                       uintptr_t arg10, uintptr_t arg11)
35{
36    capaddr_t invoke_cptr = get_cap_addr(to);
37    enum cnode_type invoke_level = get_cap_level(to);
38
39    assert(cmd <= 0xFF);
40    assert(invoke_level <= 0xF);
41    // flags << 24 | invoke_bits << 16 | cmd << 8 | syscall_invoke
42    // ^ used for LMP
43    uint32_t invocation = ((LMP_FLAG_IDENTIFY << 24) |
44                           (invoke_level << 16) | (cmd << 8) |
45                           SYSCALL_INVOKE );
46
47    switch (argc) {
48        case 0:
49        return syscall2(invocation, invoke_cptr);
50        case 1:
51        return syscall3(invocation, invoke_cptr, arg2);
52        case 2:
53        return syscall4(invocation, invoke_cptr, arg2, arg3);
54        case 3:
55        return syscall5(invocation, invoke_cptr, arg2, arg3, arg4);
56        case 4:
57        return syscall6(invocation, invoke_cptr, arg2, arg3, arg4, arg5);
58        case 5:
59        return syscall7(invocation, invoke_cptr, arg2, arg3, arg4, arg5, arg6);
60        case 6:
61        return syscall8(invocation, invoke_cptr, arg2, arg3, arg4, arg5, arg6,
62                        arg7);
63        case 7:
64        return syscall9(invocation, invoke_cptr, arg2, arg3, arg4, arg5, arg6,
65                        arg7, arg8);
66        case 8:
67        return syscall10(invocation, invoke_cptr, arg2, arg3, arg4, arg5, arg6,
68                        arg7, arg8, arg9);
69        case 9:
70        return syscall11(invocation, invoke_cptr, arg2, arg3, arg4, arg5, arg6,
71                         arg7, arg8, arg9, arg10);
72        case 10:
73        return syscall12(invocation, invoke_cptr, arg2, arg3, arg4, arg5, arg6,
74                         arg7, arg8, arg9, arg10, arg11);
75        default:
76        return SYSRET(SYS_ERR_ILLEGAL_INVOCATION);
77    }
78    assert(!"reached");
79}
80
81#define cap_invoke11(to, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k)   \
82    cap_invoke(to, 10, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k)
83#define cap_invoke10(to, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j)   \
84    cap_invoke(to, 9, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, 0)
85#define cap_invoke9(to, _a, _b, _c, _d, _e, _f, _g, _h, _i)        \
86    cap_invoke(to, 8, _a, _b, _c, _d, _e, _f, _g, _h, _i, 0, 0)
87#define cap_invoke8(to, _a, _b, _c, _d, _e, _f, _g, _h)    \
88    cap_invoke(to, 7, _a, _b, _c, _d, _e, _f, _g, _h, 0, 0, 0)
89#define cap_invoke7(to, _a, _b, _c, _d, _e, _f, _g)    \
90    cap_invoke(to, 6, _a, _b, _c, _d, _e, _f, _g, 0, 0, 0, 0)
91#define cap_invoke6(to, _a, _b, _c, _d, _e, _f)        \
92    cap_invoke(to, 5, _a, _b, _c, _d, _e, _f, 0, 0, 0, 0, 0)
93#define cap_invoke5(to, _a, _b, _c, _d, _e)            \
94    cap_invoke(to, 4, _a, _b, _c, _d, _e, 0, 0, 0, 0, 0, 0)
95#define cap_invoke4(to, _a, _b, _c, _d)                \
96    cap_invoke(to, 3, _a, _b, _c, _d, 0, 0, 0, 0, 0, 0, 0)
97#define cap_invoke3(to, _a, _b, _c)                    \
98    cap_invoke(to, 2, _a, _b, _c, 0, 0, 0, 0, 0, 0, 0, 0)
99#define cap_invoke2(to, _a, _b)                        \
100    cap_invoke(to, 1, _a, _b, 0, 0, 0, 0, 0, 0, 0, 0, 0)
101#define cap_invoke1(to, _a)                            \
102    cap_invoke(to, 0, _a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
103
104/**
105 * \brief Retype (part of) a capability.
106 *
107 * Retypes (part of) CPtr 'cap' into 'objsize'd caps of type 'newtype' and places them
108 * into slots starting at slot 'slot' in the CNode, addressed by 'to', with
109 * 'bits' address bits of 'to' valid.
110 *
111 * See also cap_retype(), which wraps this.
112 *
113 * \param root          Capability of the Root CNode to invoke
114 * \param cap           Address of cap to retype.
115 * \param offset        Offset into cap to retype
116 * \param newtype       Kernel object type to retype to.
117 * \param objsize       Size of created objects, for variable-sized types
118 * \param count         Number of objects to create
119 * \param to            Address of CNode cap to place retyped caps into.
120 * \param slot          Slot in CNode cap to start placement.
121 * \param bits          Number of valid address bits in 'to'.
122 *
123 * \return Error code
124 */
125STATIC_ASSERT(ObjType_Num < 0xFFFF, "retype invocation argument packing does not truncate enum objtype");
126static inline errval_t
127invoke_cnode_retype(struct capref root, capaddr_t src_cspace, capaddr_t cap,
128                    gensize_t offset, enum objtype newtype, gensize_t objsize,
129                    size_t count, capaddr_t to_cspace, capaddr_t to,
130                    enum cnode_type to_level, capaddr_t slot)
131{
132    assert(cap != CPTR_NULL);
133
134    assert(newtype < ObjType_Num);
135    assert(offset <= 0xFFFFFFFF);
136    assert(objsize <= 0xFFFFFFFF);
137    assert(count <= 0xFFFFFFFF);
138    assert(to_level <= 0xF);
139
140    return cap_invoke10(root, CNodeCmd_Retype, src_cspace, cap, offset,
141                        ((uint32_t)to_level << 16) | newtype,
142                        objsize, count, to_cspace, to, slot).error;
143}
144
145static inline errval_t
146invoke_vnode_map(struct capref ptable, capaddr_t slot,
147                 capaddr_t src_root, capaddr_t src,
148                 enum cnode_type srclevel, size_t
149                 flags, size_t offset, size_t pte_count,
150                 capaddr_t mcnroot, capaddr_t mcnaddr,
151                 enum cnode_type mcnlevel, cslot_t mapping_slot)
152{
153    assert(slot <= 0xffff);
154    assert(srclevel <= 0xf);
155    assert(mcnlevel <= 0xf);
156    assert(offset <= 0xffffffff);
157    assert(flags <= 0xffffffff);
158    assert(pte_count <= 0xffff);
159    assert(mapping_slot <= L2_CNODE_SLOTS);
160
161    uintptr_t small_values = srclevel |
162                             (mcnlevel << 4) |
163                             (mapping_slot << 8) |
164                             (slot << 16);
165
166    return cap_invoke9(ptable, VNodeCmd_Map, src_root, src, flags, offset,
167                       pte_count, mcnroot, mcnaddr, small_values).error;
168}
169
170/**
171 * \brief Duplicate ARMv7 core_data into the supplied frame.
172 *
173 * \param frame    CSpace address of frame capability
174 *
175 * \return Error code
176 */
177
178static inline errval_t
179invoke_kcb_clone(struct capref kcb, struct capref frame)
180{
181    capaddr_t frame_cptr = get_cap_addr(frame);
182    enum cnode_type frame_level = get_cap_level(frame);
183
184    return cap_invoke3(kcb, KCBCmd_Clone, frame_cptr, frame_level).error;
185}
186
187static inline errval_t invoke_iocap_in(struct capref iocap, enum io_cmd cmd,
188                                       uint16_t port, uint32_t *data)
189{
190    // Not strictly applicable on ARM
191    return LIB_ERR_NOT_IMPLEMENTED;
192}
193
194static inline errval_t invoke_iocap_out(struct capref iocap, enum io_cmd cmd,
195                                        uint16_t port, uint32_t data)
196{
197    // Not strictly applicable on ARM
198    return LIB_ERR_NOT_IMPLEMENTED;
199}
200
201
202/**
203 * \brief Setup a VM guest DCB
204 *
205 * \param dcb       Dispatcher capability
206 */
207static inline errval_t invoke_dispatcher_setup_guest(struct capref dispatcher,
208                                                     capaddr_t ep_cap,
209                                                     capaddr_t vnode,
210                                                     capaddr_t vmkit_guest,
211                                                     capaddr_t guest_control_cap)
212{
213    return LIB_ERR_NOT_IMPLEMENTED;
214}
215
216/**
217 * \brief Return the system-wide unique ID of the passed ID capability.
218 *
219 * \param idcap ID capability to invoke.
220 * \param id    Filled-in with system-wide unique ID of ID cap.
221 *
222 * \return      Error code
223 */
224static inline errval_t invoke_idcap_identify(struct capref idcap,
225                                             idcap_id_t *id)
226{
227    assert(id != NULL);
228    assert(get_croot_addr(idcap) == CPTR_ROOTCN);
229
230    return cap_invoke2(idcap, IDCmd_Identify, (uintptr_t)id).error;
231}
232
233static inline errval_t invoke_get_global_paddr(struct capref kernel_cap, genpaddr_t* global)
234{
235    assert(global != NULL);
236    return cap_invoke2(kernel_cap, KernelCmd_GetGlobalPhys, (uintptr_t)global).error;
237}
238
239/*
240 * MVA extensions
241 */
242
243/**
244 * \brief clone vnode
245 *
246 * \arg mcn capaddr array of cnodes holding mapping caps for vnode slots
247 * \arg newflags new flags for cloned table entries. Ignored if 0.
248 */
249static inline errval_t invoke_vnode_inherit(struct capref dest, capaddr_t src,
250                                            enum cnode_type slevel,
251                                            cslot_t start, cslot_t end,
252                                            uintptr_t newflags,
253                                            capaddr_t *mcn)
254{
255    assert(ARM_L2_MAX_ENTRIES / L2_CNODE_SLOTS == 1);
256    assert(mcn[1] == CPTR_NULL);
257    assert(mcn[2] == CPTR_NULL);
258    assert(mcn[3] == CPTR_NULL);
259    assert(mcn[5] == CPTR_NULL);
260    assert(mcn[6] == CPTR_NULL);
261    assert(mcn[7] == CPTR_NULL);
262    // mcn[0] is source mcn, mcn[4] is dest mcn.
263    return cap_invoke8(dest, VNodeCmd_Inherit, src, slevel, start, end,
264                       newflags, mcn[0], mcn[4]).error;
265}
266
267#endif
268