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