1/**
2 * \file
3 * \brief User-side system call implementation
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 2010, 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 ARCH_X86_64_BARRELFISH_SYSCALL_H
16#define ARCH_X86_64_BARRELFISH_SYSCALL_H
17
18#include <barrelfish_kpi/syscalls.h>  // for struct sysret.
19
20/*
21 * Introduction to the syscall macros, or "what the hell is going on here"?
22 *
23 * The macros here are collectively used to expand the body of the inlined
24 * function syscall() that implements all syscalls except for cap_invoke(),
25 * which is a special case, due to the thread_invoke_cap_and_exit() hack.
26 *
27 * First, BF_SYSCALL_BODY sets up the register arguments to be passed into the
28 * syscall, then BF_SYSCALL_ASM contains the asm code that includes the actual
29 * syscall. This macro has a "label" argument which can be used to emit an
30 * arbitrary bit of assembly code after the syscall instruction. This is used
31 * by cap_invoke() to insert a label immediately following the syscall, so that
32 * the threads package can tell if a thread that was about to do an invocation
33 * actually reached the syscall instruction. Note that this can't be inserted
34 * in the syscall code unconditionally, because we want it to be inlined, and
35 * that would result in multiple definitions of the symbol.
36 *
37 * If you can think of a better way to do this, by all means clean it up! :)
38 */
39
40/* FIXME: the first version of this code is optimal, and works when we are
41 * compiling either with optimisation on (-O) or at any optimisation level
42 * without a frame pointer (-fomit-frame-pointer), however not for the
43 * standard unoptimised GCC, which insists on using RBP.
44 */
45#if 0 /* was if defined(NDEBUG), but gcc is still screwing this up -- AB */
46// XXX: Need to update this to the new syscall ABI before it will work again
47# define BF_SYSCALL_ASM(arg11, label) \
48    register uint64_t a11 __asm("rbp") = arg11;     \
49    __asm volatile("syscall\n\t"                    \
50                   label                            \
51        : "+r" (a10_ret1), "+r" (a2_ret2)           \
52        : "r" (a1), "r" (a3), "r" (a4), "r" (a5), "r" (a6), "r" (a7), \
53          "r" (a8), "r" (a9), "r" (a11), "r" (a12), "r" (syscall_num) \
54        : "r11", "rcx");
55#else /* DEBUG */
56# ifndef ARRAKIS
57#  define BF_SYSCALL_ASM(arg11, label) \
58    __asm volatile("pushq %%rbp             \n\t"   \
59                   "movq %%rcx, %%rbp       \n\t"   \
60                   "syscall                 \n\t"   \
61                   label                            \
62                   "popq %%rbp              \n\t"   \
63        : "+a" (a10_ret1), "+c" (arg11), "+d" (a2_ret2), "+r" (a1), \
64          "+r" (a3), "+r" (a4), "+r" (a5), "+r" (syscall_num)  \
65        : "r" (a6), "r" (a7), "r" (a8), "r" (a9), "r" (a12) \
66        : "r11");
67#else
68#ifdef CONFIG_SVM
69#  define BF_SYSCALL_ASM(arg11, label) \
70    __asm volatile("pushq %%rbp             \n\t"   \
71                   "movq %%rcx, %%rbp       \n\t"   \
72                   "vmmcall                 \n\t"   \
73                   label                            \
74                   "popq %%rbp              \n\t"   \
75        : "+a" (a10_ret1), "+c" (arg11), "+d" (a2_ret2), "+r" (a1), \
76          "+r" (a3), "+r" (a4), "+r" (a5), "+r" (syscall_num)  \
77        : "r" (a6), "r" (a7), "r" (a8), "r" (a9), "r" (a12) \
78        : "r11");
79#else
80#  define BF_SYSCALL_ASM(arg11, label) \
81    __asm volatile("pushq %%rbp             \n\t"   \
82                   "movq %%rcx, %%rbp       \n\t"   \
83                   "vmcall                 \n\t"    \
84                   label                            \
85                   "popq %%rbp              \n\t"   \
86        : "+a" (a10_ret1), "+c" (arg11), "+d" (a2_ret2), "+r" (a1), \
87          "+r" (a3), "+r" (a4), "+r" (a5), "+r" (syscall_num)  \
88        : "r" (a6), "r" (a7), "r" (a8), "r" (a9), "r" (a12) \
89        : "r11");
90#endif
91#endif
92#endif
93
94/* NB: We use a10_ret (in the rax register) as both input and output
95 * register, because some versions of GCC (eg. 4.2.3) fail to use rax as
96 * both an input and separately as an output register
97 */
98#define BF_SYSCALL_BODY(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, \
99                        arg9, arg10, arg11, arg12, label) \
100    register uint64_t syscall_num __asm("rdi") = num;   \
101    register uint64_t a1 __asm("rsi") = arg1;           \
102    register uint64_t a2_ret2 __asm("rdx") = arg2;           \
103    register uint64_t a3 __asm("r10") = arg3;           \
104    register uint64_t a4 __asm("r8") = arg4;            \
105    register uint64_t a5 __asm("r9") = arg5;            \
106    register uint64_t a6 __asm("r12") = arg6;           \
107    register uint64_t a7 __asm("r13") = arg7;           \
108    register uint64_t a8 __asm("r14") = arg8;           \
109    register uint64_t a9 __asm("r15") = arg9;           \
110    register uint64_t a12 __asm("rbx") = arg12;         \
111    register uint64_t a10_ret1 __asm("rax") = arg10;     \
112    BF_SYSCALL_ASM(arg11, label)
113
114
115extern bool debug_notify_syscall;
116
117#include <stdio.h>
118
119static inline struct sysret syscall(uint64_t num, uint64_t arg1, uint64_t arg2,
120                 uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6,
121                 uint64_t arg7, uint64_t arg8, uint64_t arg9, uint64_t arg10,
122                 uint64_t arg11, uint64_t arg12)
123{
124    if(debug_notify_syscall && num == SYSCALL_INVOKE) {
125        char str[256];
126        snprintf(str, 256, "Syscall while forbidden! from %p, %p, %p\n",
127                 __builtin_return_address(0),
128                 __builtin_return_address(1),
129                 __builtin_return_address(2));
130        BF_SYSCALL_BODY(SYSCALL_PRINT, (uint64_t)str, 256, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, "");
131        return (struct sysret){/*error*/ SYS_ERR_ILLEGAL_SYSCALL, /*value*/ 0};
132    }
133
134    BF_SYSCALL_BODY(num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9,
135                    arg10, arg11, arg12, "");
136    return (struct sysret){/*error*/ a10_ret1, /*value*/ a2_ret2};
137}
138
139#define syscall12(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l) \
140	syscall(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, 0)
141#define syscall11(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k) \
142	syscall12(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, 0)
143#define syscall10(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j) \
144	syscall11(_a, _b, _c, _d, _e, _f, _g, _h, _i, _j, 0)
145#define syscall9(_a, _b, _c, _d, _e, _f, _g, _h, _i) \
146	syscall10(_a, _b, _c, _d, _e, _f, _g, _h, _i, 0)
147#define syscall8(_a, _b, _c, _d, _e, _f, _g, _h) \
148	syscall9(_a, _b, _c, _d, _e, _f, _g, _h, 0)
149#define syscall7(_a, _b, _c, _d, _e, _f, _g) \
150	syscall8(_a, _b, _c, _d, _e, _f, _g, 0)
151#define syscall6(_a, _b, _c, _d, _e, _f) \
152	syscall7(_a, _b, _c, _d, _e, _f, 0)
153#define syscall5(_a, _b, _c, _d, _e) \
154	syscall6(_a, _b, _c, _d, _e, 0)
155#define syscall4(_a, _b, _c, _d) \
156	syscall5(_a, _b, _c, _d, 0)
157#define syscall3(_a, _b, _c) \
158	syscall4(_a, _b, _c, 0)
159#define syscall2(_a, _b) \
160	syscall3(_a, _b, 0)
161#define syscall1(_a) \
162	syscall2(_a, 0)
163
164static inline errval_t sys_x86_reload_ldt(void)
165{
166    return syscall1(SYSCALL_X86_RELOAD_LDT).error;
167}
168
169#endif
170