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