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