1/**
2 * \file
3 * \brief Architecture independent capability invocations
4 */
5
6/*
7 * Copyright (c) 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_H
16#define INVOCATIONS_H
17
18#include <barrelfish_kpi/dispatcher_shared.h>
19#include <barrelfish_kpi/distcaps.h> // for distcap_state_t
20#include <barrelfish/caddr.h>
21
22#include <barrelfish/invocations_arch.h>
23
24/**
25 * \brief Create a capability.
26 *
27 * Create a new capability of type 'type' and size 'objbits'. The new cap will
28 * be placed in the slot 'dest_slot' of the CNode located at 'dest_cnode_cptr'
29 * in the address space rooted at 'root'.
30 *
31 * See also cap_create(), which wraps this.
32 *
33 * \param root            Capability of the CNode to invoke.
34 * \param type            Kernel object type to create.
35 * \param objsize         Size of created object
36 *                        (ignored for fixed-size objects)
37 * \param dest_cnode_cptr Address of CNode cap, where newly created cap will be
38 *                        placed into.
39 * \param dest_level      Depth/level of destination CNode.
40 * \param dest_slot       Slot in CNode cap to place new cap.
41 *
42 * \return Error code
43 */
44static inline errval_t invoke_cnode_create(struct capref root,
45                                           enum objtype type, size_t objsize,
46                                           capaddr_t dest_cnode_cptr,
47                                           enum cnode_type dest_level,
48                                           capaddr_t dest_slot)
49{
50    assert(dest_cnode_cptr != CPTR_NULL);
51    return cap_invoke6(root, CNodeCmd_Create, type, objsize, dest_cnode_cptr,
52                       dest_level, dest_slot).error;
53}
54
55/**
56 * \brief "Mint" a capability.
57 *
58 * Copies CPtr 'from' into slot 'slot' in the CNode, addressed by 'to', within
59 * the address space, rooted at 'root' and with 'tobits' and 'frombits' address
60 * bits of 'to' and 'from' valid, respectively.
61 *
62 * See also cap_mint(), which wraps this.
63 *
64 * \param root          Capability of the source cspace root CNode to invoke
65 * \param to_cspace     Destination cspace cap address relative to source cspace
66 * \param to            Destination CNode address relative to destination cspace
67 * \param slot          Slot in destination CNode cap to place copy into
68 * \param from          Address of cap to copy.
69 * \param tolevel       Level/depth of 'to'.
70 * \param fromlevel     Level/depth of 'from'.
71 * \param param1        1st cap-dependent parameter.
72 * \param param2        2nd cap-dependent parameter.
73 *
74 * \return Error code
75 */
76static inline errval_t invoke_cnode_mint(struct capref root, capaddr_t to_cspace,
77                                         capaddr_t to, capaddr_t slot,
78                                         capaddr_t from_cspace, capaddr_t from,
79                                         enum cnode_type tolevel,
80                                         enum cnode_type fromlevel,
81                                         uint64_t param1, uint64_t param2)
82{
83    return cap_invoke10(root, CNodeCmd_Mint, to_cspace, to, slot, from_cspace,
84                        from, tolevel, fromlevel, param1, param2).error;
85}
86
87/**
88 * \brief Copy a capability.
89 *
90 * Copies CPtr 'from' into slot 'slot' in the CNode, addressed by 'to', within
91 * the address space, rooted at 'root' and with 'tobits' and 'frombits' address
92 * bits of 'to' and 'from' valid, respectively.
93 *
94 * See also cap_copy(), which wraps this.
95 *
96 * \param root          Capability of the source cspace root CNode to invoke
97 * \param to_cspace     Capability address of destination root cnode relative
98 *                      to our cspace
99 * \param to            CNode address to place copy into relative to
100 *                      destination cspace.
101 * \param slot          Slot in CNode cap to place copy into.
102 * \param from_cspace   Capability address of source root cnode relative
103 *                      to our cspace
104 * \param from          Address of cap to copy.
105 * \param tolevel       Level/depth of 'to'.
106 * \param fromlevel     Level/depth of 'from'.
107 *
108 * \return Error code
109 */
110static inline errval_t invoke_cnode_copy(struct capref root, capaddr_t to_cspace,
111                                         capaddr_t to, capaddr_t slot,
112                                         capaddr_t from_cspace, capaddr_t from,
113                                         enum cnode_type tolevel,
114                                         enum cnode_type fromlevel)
115{
116    return cap_invoke8(root, CNodeCmd_Copy, to_cspace, to, slot, from_cspace,
117                       from, tolevel, fromlevel).error;
118}
119
120/**
121 * \brief Delete a capability.
122 *
123 * Delete the capability pointed to by 'cap', with 'bits' address bits
124 * of it valid, from the address space rooted at 'root'.
125 *
126 * \param root  Capability of the CNode to invoke
127 * \param cap   Address of cap to delete.
128 * \param level Level/depth of 'cap'.
129 *
130 * \return Error code
131 */
132static inline errval_t invoke_cnode_delete(struct capref root, capaddr_t cap,
133                                           enum cnode_type level)
134{
135    return cap_invoke3(root, CNodeCmd_Delete, cap, level).error;
136}
137
138static inline errval_t invoke_cnode_revoke(struct capref root, capaddr_t cap,
139                                           enum cnode_type level)
140{
141    return cap_invoke3(root, CNodeCmd_Revoke, cap, level).error;
142}
143
144static inline errval_t invoke_cnode_get_state(struct capref root, capaddr_t cap,
145                                              enum cnode_type level, distcap_state_t *ret)
146{
147    struct sysret sysret = cap_invoke3(root, CNodeCmd_GetState, cap, level);
148
149    assert(ret != NULL);
150    if (err_is_ok(sysret.error)) {
151        *ret = sysret.value;
152    }
153    else {
154        *ret = 0;
155    }
156    return sysret.error;
157}
158
159
160/**
161 * \brief Get the size of a L1 CNode in bytes.
162 *
163 * \param root Size of this L1 CNode will be returned
164 * \param ret  Result will be stored here in bytes.
165 *
166 * \return Error code
167 */
168static inline errval_t invoke_cnode_get_size(struct capref root, size_t * ret)
169{
170    struct sysret sys_ret =  cap_invoke1(root, CNodeCmd_GetSize);
171    if(err_is_ok(sys_ret.error)){
172        *ret = sys_ret.value;
173    } else {
174        *ret = 0;
175    }
176
177    return sys_ret.error;
178}
179
180static inline errval_t invoke_cnode_resize(struct capref root, capaddr_t new_cptr,
181                                           capaddr_t retcn_ptr, cslot_t retslot)
182{
183    return cap_invoke4(root, CNodeCmd_Resize, new_cptr, retcn_ptr, retslot).error;
184}
185
186static inline errval_t invoke_vnode_unmap(struct capref cap,
187                                          capaddr_t mapping_addr,
188                                          enum cnode_type level)
189{
190    return cap_invoke3(cap, VNodeCmd_Unmap, mapping_addr, level).error;
191}
192
193/**
194 * \brief Return the physical address and size of a frame capability
195 *
196 * \param frame    CSpace address of frame capability
197 * \param ret      frame_identity struct filled in with relevant data
198 *
199 * \return Error code
200 */
201static inline errval_t invoke_frame_identify(struct capref frame,
202                                             struct frame_identity *ret)
203{
204    assert(ret != NULL);
205    assert(get_croot_addr(frame) == CPTR_ROOTCN);
206
207    struct sysret sysret = cap_invoke2(frame, FrameCmd_Identify, (uintptr_t)ret);
208
209    if (err_is_ok(sysret.error)) {
210        return sysret.error;
211    }
212
213    ret->base = 0;
214    ret->bytes = 0;
215    return sysret.error;
216}
217
218static inline errval_t invoke_vnode_identify(struct capref vnode,
219					     struct vnode_identity *ret)
220{
221    assert(get_croot_addr(vnode) == CPTR_ROOTCN);
222    struct sysret sysret = cap_invoke1(vnode, VNodeCmd_Identify);
223
224    assert(ret != NULL);
225    if (err_is_ok(sysret.error)) {
226        ret->base = sysret.value & (~BASE_PAGE_MASK);
227	ret->type = sysret.value & BASE_PAGE_MASK;
228        return sysret.error;
229    }
230
231    ret->base = 0;
232    ret->type = 0;
233    return sysret.error;
234}
235
236/**
237 * \brief Modify mapping flags on parts of a mapping
238 *
239 * \param mapping  CSpace address of mapping capability
240 * \param off      Offset (in #pages) of the first page to get new set of flags
241 *                 from the first page in the mapping identified by `frame`
242 * \param pages    Number of pages that should get new set of flags
243 * \param flags    New set of flags
244 * \param va_hint  Hint for selective TLB flushing
245 *
246 * \return Error code
247 */
248static inline errval_t invoke_mapping_modify_flags(struct capref mapping,
249                                                   size_t offset,
250                                                   size_t pages,
251                                                   size_t flags,
252                                                   genvaddr_t va_hint)
253{
254    return cap_invoke5(mapping, MappingCmd_Modify, offset,
255                       pages, flags, va_hint).error;
256}
257
258/**
259 * \brief Setup a dispatcher, possibly making it runnable
260 *
261 * \param dispatcher    Address of dispatcher capability relative to own
262 *                      cspace
263 * \param domdispatcher Address of existing dispatcher for domain ID relative
264 *                      to own cspace
265 * \param cspace        Root of CSpace for new dispatcher relative to own
266 *                      cspace
267 * \param vspace        Root of VSpace for new dispatcher relative to cspace
268 *                      for new dispatcher.
269 * \param dispframe     Frame capability for dispatcher structure relative to
270 *                      cspace for new dispatcher.
271 * \param run           Make runnable if true
272 *
273 * Need to either supply caprefs for all or none of cspace, vspace, dispframe
274 * and domdispatcher.
275 *
276 * \return Error code
277 */
278static inline errval_t
279invoke_dispatcher(struct capref dispatcher, struct capref domdispatcher,
280                  struct capref cspace, struct capref vspace,
281                  struct capref dispframe, bool run)
282{
283    assert(get_croot_addr(dispatcher) == CPTR_ROOTCN);
284    assert(capref_is_null(cspace) || get_croot_addr(cspace) == CPTR_ROOTCN);
285    assert(capref_is_null(domdispatcher) || get_croot_addr(domdispatcher) == CPTR_ROOTCN);
286    assert(capref_is_null(vspace) || get_croot_addr(vspace) == get_cap_addr(cspace));
287    assert(capref_is_null(dispframe) || get_croot_addr(dispframe) == get_cap_addr(cspace));
288
289    capaddr_t root_caddr = get_cap_addr(cspace);
290    uint8_t   root_level = get_cap_level(cspace);
291    capaddr_t vtree_caddr = get_cap_addr(vspace);
292    capaddr_t disp_caddr = get_cap_addr(dispframe);
293    capaddr_t dd_caddr = get_cap_addr(domdispatcher);
294
295    return cap_invoke7(dispatcher, DispatcherCmd_Setup, root_caddr,
296                       root_level, vtree_caddr, disp_caddr, run,
297                       dd_caddr).error;
298}
299
300static inline errval_t
301invoke_dispatcher_properties(struct capref dispatcher,
302                             enum task_type type, unsigned long deadline,
303                             unsigned long wcet, unsigned long period,
304                             unsigned long release, unsigned short weight)
305{
306    return cap_invoke7(dispatcher, DispatcherCmd_Properties, type, deadline,
307                       wcet, period, release, weight).error;
308}
309
310
311static inline errval_t invoke_dispatcher_dump_ptables(struct capref dispcap)
312{
313    return cap_invoke1(dispcap, DispatcherCmd_DumpPTables).error;
314}
315
316static inline errval_t invoke_dispatcher_dump_capabilities(struct capref dispcap)
317{
318    return cap_invoke1(dispcap, DispatcherCmd_DumpCapabilities).error;
319}
320
321/**
322 * IRQ manipulations
323 */
324static inline errval_t invoke_irqdest_connect(struct capref irqcap, struct capref epcap)
325{
326    struct sysret ret = cap_invoke2(irqcap, IRQDestCmd_Connect, get_cap_addr(epcap));
327    return ret.error;
328}
329
330static inline errval_t invoke_irqdest_get_vector(struct capref irqcap, uint64_t * out_vec)
331{
332    struct sysret ret = cap_invoke1(irqcap, IRQDestCmd_GetVector);
333    *out_vec = ret.value;
334    return ret.error;
335}
336
337static inline errval_t invoke_irqdest_get_cpu(struct capref irqcap, uint64_t * out_cpu)
338{
339    struct sysret ret = cap_invoke1(irqcap, IRQDestCmd_GetCpu);
340    *out_cpu = ret.value;
341    return ret.error;
342}
343
344static inline errval_t invoke_irqsrc_get_vec_start(struct capref irqcap, uint64_t * out_vec)
345{
346    struct sysret ret = cap_invoke1(irqcap, IRQSrcCmd_GetVecStart);
347    *out_vec = ret.value;
348    return ret.error;
349}
350
351static inline errval_t invoke_irqsrc_get_vec_end(struct capref irqcap, uint64_t * out_vec)
352{
353    struct sysret ret = cap_invoke1(irqcap, IRQSrcCmd_GetVecEnd);
354    *out_vec = ret.value;
355    return ret.error;
356}
357
358static inline errval_t invoke_irqtable_alloc_dest_cap(struct capref irqcap, struct capref dest_cap)
359{
360    uint8_t dcn_level = get_cnode_level(dest_cap);
361    capaddr_t dcn_addr = get_cnode_addr(dest_cap);
362    struct sysret ret = cap_invoke4(irqcap, IRQTableCmd_AllocDestCap,
363                                    dcn_level, dcn_addr, dest_cap.slot);
364    return ret.error;
365}
366
367/**
368 * Deprecated. Use invoke_irqtable_alloc_dest_cap
369 */
370static inline errval_t invoke_irqtable_alloc_vector(struct capref irqcap, int *retirq)
371{
372    struct sysret ret = cap_invoke1(irqcap, IRQTableCmd_Alloc);
373    if (err_is_ok(ret.error)) {
374        *retirq = ret.value;
375    } else {
376        *retirq = 0;
377    }
378    return ret.error;
379}
380
381static inline errval_t invoke_irqtable_set(struct capref irqcap, int irq,
382                                           struct capref ep)
383{
384    return cap_invoke3(irqcap, IRQTableCmd_Set, irq, get_cap_addr(ep)).error;
385}
386
387static inline errval_t invoke_irqtable_delete(struct capref irqcap, int irq)
388{
389    return cap_invoke2(irqcap, IRQTableCmd_Delete, irq).error;
390}
391
392/**
393 * \brief do a kernel cap invocation to get the core id
394 */
395static inline errval_t invoke_kernel_get_core_id(struct capref kern_cap,
396                                                 coreid_t *core_id)
397{
398    assert(core_id != NULL);
399
400    struct sysret sysret = cap_invoke1(kern_cap, KernelCmd_Get_core_id);
401    if (sysret.error == SYS_ERR_OK) {
402        *core_id = sysret.value;
403    }
404    return sysret.error;
405}
406
407#endif // INVOCATIONS_H
408