1/**
2 * \file
3 * \brief Arch-specific Low-level capability invocations
4 */
5
6/*
7 * Copyright (c) 2007-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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#ifndef INVOCATIONS_ARCH_H
16#define INVOCATIONS_ARCH_H
17
18#include <barrelfish/syscall_arch.h>
19#include <barrelfish_kpi/dispatcher_shared.h>
20#include <barrelfish/caddr.h>
21#include <barrelfish_kpi/paging_arch.h>
22#include <barrelfish_kpi/lmp.h>
23
24static inline struct sysret cap_invoke(struct capref to, uintptr_t arg1,
25                                       uintptr_t arg2, uintptr_t arg3,
26                                       uintptr_t arg4, uintptr_t arg5,
27                                       uintptr_t arg6, uintptr_t arg7,
28                                       uintptr_t arg8, uintptr_t arg9,
29                                       uintptr_t arg10)
30{
31    capaddr_t invoke_cptr = get_cap_addr(to);
32    enum cnode_type invoke_level = get_cap_level(to);
33
34    return syscall(SYSCALL_INVOKE, (uint64_t)invoke_cptr << 32 |
35                   (uint64_t)invoke_level << 16 | 10 << 8 | LMP_FLAG_IDENTIFY, 0,
36                   arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9,
37                   arg10);
38}
39
40#define cap_invoke10(to, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j)   \
41    cap_invoke(to, _a, _b, _c, _d, _e, _f, _g, _h, _i, _j)
42#define cap_invoke9(to, _a, _b, _c, _d, _e, _f, _g, _h, _i)        \
43    cap_invoke10(to, _a, _b, _c, _d, _e, _f, _g, _h, _i, 0)
44#define cap_invoke8(to, _a, _b, _c, _d, _e, _f, _g, _h)    \
45    cap_invoke9(to, _a, _b, _c, _d, _e, _f, _g, _h, 0)
46#define cap_invoke7(to, _a, _b, _c, _d, _e, _f, _g)    \
47    cap_invoke8(to, _a, _b, _c, _d, _e, _f, _g, 0)
48#define cap_invoke6(to, _a, _b, _c, _d, _e, _f)        \
49    cap_invoke7(to, _a, _b, _c, _d, _e, _f, 0)
50#define cap_invoke5(to, _a, _b, _c, _d, _e)            \
51    cap_invoke6(to, _a, _b, _c, _d, _e, 0)
52#define cap_invoke4(to, _a, _b, _c, _d)                \
53    cap_invoke5(to, _a, _b, _c, _d, 0)
54#define cap_invoke3(to, _a, _b, _c)                    \
55    cap_invoke4(to, _a, _b, _c, 0)
56#define cap_invoke2(to, _a, _b)                        \
57    cap_invoke3(to, _a, _b, 0)
58#define cap_invoke1(to, _a)                            \
59    cap_invoke2(to, _a, 0)
60
61
62/**
63 * \brief Retype (part of) a capability.
64 *
65 * Retypes (part of) CPtr 'cap' into 'objsize'd caps of type 'newtype' and places them
66 * into slots starting at slot 'slot' in the CNode, addressed by 'to', with
67 * 'bits' address bits of 'to' valid.
68 *
69 * See also cap_retype(), which wraps this.
70 *
71 * \param root          Capability of the source cspace root CNode to invoke
72 * \param src_cspace    Source cspace cap address in our cspace.
73 * \param cap           Address of cap to retype in source cspace.
74 * \param offset        Offset into cap to retype
75 * \param newtype       Kernel object type to retype to.
76 * \param objsize       Size of created objects, for variable-sized types
77 * \param count         Number of objects to create
78 * \param to_cspace     Destination cspace cap address in our cspace
79 * \param to            Address of CNode cap in destination cspcae to place
80 *                      retyped caps into.
81 * \param to_level      Level/depth of CNode cap in destination cspace
82 * \param slot          Slot in CNode cap to start placement.
83 *
84 * \return Error code
85 */
86static inline errval_t invoke_cnode_retype(struct capref root, capaddr_t src_cspace,
87                                           capaddr_t cap, gensize_t offset,
88                                           enum objtype newtype, gensize_t objsize,
89                                           size_t count, capaddr_t to_cspace,
90                                           capaddr_t to, enum cnode_type to_level,
91                                           capaddr_t slot)
92{
93    assert(cap != CPTR_NULL);
94    return cap_invoke9(root, CNodeCmd_Retype,
95                       ((uint64_t)src_cspace << 32) | (uint64_t)cap, offset,
96                       newtype, objsize, count,
97                       ((uint64_t)to_cspace << 32) | (uint64_t)to, slot, to_level).error;
98}
99
100static inline errval_t invoke_vnode_map(struct capref ptable, capaddr_t slot,
101                                        capaddr_t src_root, capaddr_t src,
102                                        enum cnode_type srclevel, size_t
103                                        flags, size_t offset, size_t pte_count,
104                                        capaddr_t mcnroot, capaddr_t mcnaddr,
105                                        enum cnode_type mcnlevel, cslot_t mapping_slot)
106{
107    return cap_invoke10(ptable, VNodeCmd_Map, slot,
108                        ((uint64_t)src_root << 32) | (uint64_t)src, srclevel,
109                        flags, offset, pte_count,
110                        ((uint64_t)mcnroot << 32) | (uint64_t)mcnaddr,
111                        mcnlevel, mapping_slot).error;
112}
113
114static inline errval_t invoke_iocap_in(struct capref iocap, enum io_cmd cmd,
115                                       uint16_t port, uint32_t *data)
116{
117    struct sysret sysret = cap_invoke2(iocap, cmd, port);
118
119    if (err_is_ok(sysret.error)) {
120        assert(data != NULL);
121        *data = sysret.value;
122    }
123    return sysret.error;
124}
125
126static inline errval_t invoke_iocap_out(struct capref iocap, enum io_cmd cmd,
127                                        uint16_t port, uint32_t data)
128{
129    return cap_invoke3(iocap, cmd, port, data).error;
130}
131
132/**
133 * \brief Execute vmread on the VMCS of the VM guest DCB
134 *
135 * The VMCS must be current and active.
136 *
137 * \param dcb       Dispatcher capability
138 * \param encoding  Encoding of the field to read from the VMCS
139 * \param addr      The address to write the value of the field to.
140 */
141static inline errval_t invoke_dispatcher_vmread(struct capref dispatcher,
142						uintptr_t encoding,
143						lvaddr_t *addr)
144{
145    return cap_invoke3(dispatcher, DispatcherCmd_Vmread,
146		       encoding, (uintptr_t)addr).error;
147}
148
149/**
150 * \brief Execute vmwrite on the VMCS of the VM guest DCB
151 *
152 * The VMCS must be current and active.
153 *
154 * \param dcb       Dispatcher capability
155 * \param encoding  Encoding of the field to write to the VMCS.
156 * \param value     Value of the field to write.
157 */
158
159static inline errval_t invoke_dispatcher_vmwrite(struct capref dispatcher,
160						 uintptr_t encoding,
161						 uintptr_t value)
162{
163    return cap_invoke3(dispatcher, DispatcherCmd_Vmwrite,
164		       encoding, value).error;
165}
166
167/**
168 * \brief Execute vmptrld on the VMCS of the VM guest DCB
169 *
170 * \param dcb       Dispatcher capability
171 */
172static inline errval_t invoke_dispatcher_vmptrld(struct capref dispatcher)
173{
174    return cap_invoke1(dispatcher, DispatcherCmd_Vmptrld).error;
175}
176
177/**
178 * \brief Execute vmclear on the VMCS of the VM guest DCB
179 *
180 * \param dcb       Dispatcher capability
181 */
182static inline errval_t invoke_dispatcher_vmclear(struct capref dispatcher)
183{
184    return cap_invoke1(dispatcher, DispatcherCmd_Vmclear).error;
185}
186
187/**
188 * \brief Setup a VM guest DCB
189 *
190 * \param dcb       Dispatcher capability
191 */
192static inline errval_t
193invoke_dispatcher_setup_guest(struct capref dispatcher,
194                              struct capref ep_cap,
195                              struct capref vnode,
196                              struct capref vmkit_guest,
197                              struct capref guest_control_cap)
198{
199    return cap_invoke5(dispatcher, DispatcherCmd_SetupGuest,
200                       get_cap_addr(ep_cap), get_cap_addr(vnode),
201                       get_cap_addr(vmkit_guest),
202                       get_cap_addr(guest_control_cap)).error;
203}
204
205static inline errval_t invoke_perfmon_activate(struct capref perfmon_cap,
206                                               uint8_t event, uint8_t perf_umask,
207                                               bool kernel, uint8_t counter_id,
208                                               uint64_t counter_value,
209                                               capaddr_t ep_addr)
210{
211    return cap_invoke7(perfmon_cap, PerfmonCmd_Activate,
212                       event, perf_umask, counter_id, kernel,
213                       counter_value, ep_addr).error;
214}
215
216static inline errval_t invoke_perfmon_write(struct capref perfmon_cap,
217                                                  uint8_t counter_id,
218                                                  uint64_t counter_value)
219{
220    return cap_invoke3(perfmon_cap, PerfmonCmd_Write, counter_id, counter_value).error;
221}
222
223static inline errval_t invoke_perfmon_deactivate(struct capref perfmon_cap)
224{
225    return cap_invoke1(perfmon_cap, PerfmonCmd_Deactivate).error;
226}
227
228static inline errval_t invoke_ipi_notify_send(struct capref notify_cap)
229{
230    return cap_invoke1(notify_cap, NotifyCmd_Send).error;
231}
232
233static inline errval_t invoke_send_init_ipi(struct capref ipi_cap, coreid_t core_id)
234{
235    return cap_invoke2(ipi_cap, IPICmd_Send_Init,
236                       core_id).error;
237}
238
239static inline errval_t invoke_send_start_ipi(struct capref ipi_cap, coreid_t core_id, forvaddr_t entry)
240{
241    return cap_invoke3(ipi_cap, IPICmd_Send_Start,
242                       core_id, entry).error;
243}
244
245/**
246 * \brief Return the system-wide unique ID of the passed ID capability.
247 *
248 * \param idcap ID capability to invoke.
249 * \param id    Filled-in with system-wide unique ID of ID cap.
250 *
251 * \return      Error code
252 */
253static inline errval_t invoke_idcap_identify(struct capref idcap,
254                                             idcap_id_t *id)
255{
256    assert(id != NULL);
257    assert(get_croot_addr(idcap) == CPTR_ROOTCN);
258
259    struct sysret sysret = cap_invoke1(idcap, IDCmd_Identify);
260
261    if (err_is_ok(sysret.error)) {
262        *id = sysret.value;
263    }
264
265    return sysret.error;
266}
267
268// XXX: why is this not in monitor/invocations_arch.h? -SG, 2018-10-19
269static inline errval_t invoke_get_global_paddr(struct capref kernel_cap, genpaddr_t* global)
270{
271    struct sysret sr = cap_invoke1(kernel_cap, KernelCmd_GetGlobalPhys);
272    if (err_is_ok(sr.error)) {
273        *global = sr.value;
274    }
275
276    return sr.error;
277}
278
279/*
280 * MVA extensions
281 */
282
283/**
284 * \brief clone vnode
285 *
286 * \arg mcn capaddr array of cnodes holding mapping caps for vnode slots
287 */
288static inline errval_t invoke_vnode_inherit(struct capref dest, capaddr_t src,
289                                            enum cnode_type slevel,
290                                            cslot_t start, cslot_t end,
291                                            paging_x86_64_flags_t newflags,
292                                            capaddr_t *mcn)
293{
294    assert(PTABLE_SIZE / L2_CNODE_SLOTS == 2);
295    assert(2*CPTR_BITS <= sizeof(uintptr_t) * NBBY);
296    uintptr_t src_mcn = ((uintptr_t)mcn[0]) << CPTR_BITS | mcn[1];
297    uintptr_t dst_mcn = ((uintptr_t)mcn[2]) << CPTR_BITS | mcn[3];
298    return cap_invoke8(dest, VNodeCmd_Inherit, src, slevel, start, end,
299                       newflags, src_mcn, dst_mcn).error;
300}
301
302#endif
303