brand_asm.h revision 11685:95082903303d
1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21/* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26#ifndef _COMMON_BRAND_ASM_H 27#define _COMMON_BRAND_ASM_H 28 29#ifdef __cplusplus 30extern "C" { 31#endif 32 33#ifndef lint 34 35#include <sys/asm_linkage.h> 36#include <sys/privregs.h> 37#include <sys/segments.h> 38#include "assym.h" 39 40#endif /* lint */ 41 42#ifdef _ASM /* The remainder of this file is only for assembly files */ 43 44#if defined(__amd64) 45/* 46 * Common to all 64-bit callbacks: 47 * 48 * We're running on the kernel's %gs. 49 * 50 * We return directly to userland, bypassing the _update_sregs logic, so 51 * the routine must NOT do anything that could cause a context switch. 52 * 53 * %rax - syscall number 54 * 55 * When called, all general registers, except for %r15, are as they were when 56 * the user process made the system call. %r15 is available to the callback as 57 * a scratch register. If the callback returns to the kernel path, %r15 does 58 * not have to be restored to the user value. If the callback returns to the 59 * userlevel emulation code, the callback should restore %r15 if the emulation 60 * depends on the original userlevel value. 61 * 62 * 64-BIT INTERPOSITION STACK 63 * On entry to the callback the stack looks like this: 64 * -------------------------------------- 65 * 32 | callback pointer | 66 * 24 | saved stack pointer | 67 * | 16 | lwp pointer | 68 * v 8 | user return address | 69 * 0 | BRAND_CALLBACK()'s return addr | 70 * -------------------------------------- 71 */ 72 73#define V_COUNT 5 74#define V_END (CLONGSIZE * 5) 75#define V_SSP (CLONGSIZE * 3) 76#define V_LWP (CLONGSIZE * 2) 77#define V_URET_ADDR (CLONGSIZE * 1) 78#define V_CB_ADDR (CLONGSIZE * 0) 79 80#define SP_REG %rsp 81#define SCR_REG %r15 82#define SCR_REGB %r15b 83#define SYSCALL_REG %rax 84 85/* 86 * 64-BIT INT STACK 87 * For int callbacks (e.g. int91) the saved stack pointer (V_SSP) points at 88 * the state saved when we took the interrupt: 89 * -------------------------------------- 90 * | 32 | user's %ss | 91 * | 24 | user's %esp | 92 * | 16 | EFLAGS register | 93 * v 8 | user's %cs | 94 * 0 | user's %eip (user return address) | 95 * -------------------------------------- 96 */ 97#define V_U_EIP (CLONGSIZE * 0) 98 99#else /* !__amd64 */ 100/* 101 * 32-BIT INTERPOSITION STACK 102 * When our syscall interposition callback entry point gets invoked the 103 * stack looks like this: 104 * -------------------------------------- 105 * | 16 | 'scratch space' | 106 * | 12 | user's %ebx | 107 * | 8 | user's %gs selector | 108 * v 4 | lwp pointer | 109 * 0 | callback wrapper return addr | 110 * -------------------------------------- 111 */ 112 113#define V_COUNT 5 114#define V_END (CLONGSIZE * 5) 115#define V_U_EBX (CLONGSIZE * 3) 116#define V_LWP (CLONGSIZE * 1) 117#define V_CB_ADDR (CLONGSIZE * 0) 118 119#define SP_REG %esp 120#define SCR_REG %ebx 121#define SCR_REGB %bl 122#define SYSCALL_REG %eax 123 124/* 125 * 32-BIT INT STACK 126 * For the lcall handler for 32-bit OS (i.e. xxx_brand_syscall_callback) 127 * above the stack contents common to all callbacks is the int/lcall-specific 128 * state: 129 * -------------------------------------- 130 * | 36 | user's %ss | 131 * | 32 | user's %esp | 132 * | 28 | EFLAGS register | 133 * v 24 | user's %cs | 134 * 20 | user's %eip (user return address) | 135 * -------------------------------------- 136 */ 137#define V_U_EIP (V_END + (CLONGSIZE * 0)) 138 139#endif /* !__amd64 */ 140 141/* 142 * The following macros allow us to access to variables/parameters passed 143 * in on the stack. They take the following variables: 144 * sp - a register with the current stack pointer value 145 * pcnt - the number of words currently pushed onto the stack 146 * var - the variable to lookup 147 * reg - a register to read the variable into, or 148 * a register to write to the variable 149 */ 150#define V_OFFSET(pcnt, var) \ 151 (var + (pcnt * CLONGSIZE)) 152 153#define GET_V(sp, pcnt, var, reg) \ 154 mov V_OFFSET(pcnt, var)(sp), reg 155 156#define SET_V(sp, pcnt, var, reg) \ 157 mov reg, V_OFFSET(pcnt, var)(sp) 158 159#define GET_PROCP(sp, pcnt, reg) \ 160 GET_V(sp, pcnt, V_LWP, reg); /* get lwp pointer */ \ 161 mov LWP_PROCP(reg), reg /* get proc pointer */ 162 163#define GET_P_BRAND_DATA(sp, pcnt, reg) \ 164 GET_PROCP(sp, pcnt, reg); \ 165 mov P_BRAND_DATA(reg), reg /* get p_brand_data */ 166 167/* 168 * Each of the following macros returns to the standard syscall codepath if 169 * it detects that this process is not able, or intended, to emulate this 170 * system call. They all assume that the routine provides a 'bail-out' 171 * label of '9'. 172 */ 173 174/* 175 * See if this process has a user-space handler registered for it. For the 176 * brand, the per-process brand data holds the address of the handler. 177 * As shown in the stack diagrams above, the callback code leaves the lwp 178 * pointer at well-defined offsets, so check if proc_data_t->X_handler is 179 * non-NULL. For each brand, the handler parameter refers to the brand's 180 * user-space handler variable name. 181 */ 182#define CHECK_FOR_HANDLER(scr, handler) \ 183 GET_P_BRAND_DATA(SP_REG, 0, scr); /* get p_brand_data */ \ 184 cmp $0, scr; \ 185 je 9f; \ 186 cmp $0, handler(scr); /* check handler */ \ 187 je 9f 188 189/* 190 * If the system call number is >= 1024, then it is coming from the 191 * emulation support library. As such we should handle it natively instead 192 * of sending it back to the emulation library. 193 */ 194#define CHECK_FOR_NATIVE(reg) \ 195 cmp $1024, reg; \ 196 jl 1f; \ 197 sub $1024, reg; \ 198 jmp 9f; \ 1991: 200 201/* 202 * Check to see if we want to interpose on this system call. If not, we 203 * jump back into the normal syscall path and pretend nothing happened. 204 * This macro is usable for brands which have the same number of syscalls 205 * as the base OS. 206 */ 207#define CHECK_FOR_INTERPOSITION(emul_table, call, scr, scr_low) \ 208 cmp $NSYSCALL, call; /* is 0 <= syscall <= MAX? */ \ 209 ja 9f; /* no, take normal ret path */ \ 210 lea emul_table, scr; \ 211 /*CSTYLED*/ \ 212 mov (scr), scr; \ 213 add call, scr; \ 214 /*CSTYLED*/ \ 215 movb (scr), scr_low; \ 216 cmpb $0, scr_low; \ 217 je 9f /* no, take normal ret path */ 218 219#define CALLBACK_PROLOGUE(emul_table, handler, call, scr, scr_low) \ 220 CHECK_FOR_HANDLER(scr, handler); \ 221 CHECK_FOR_NATIVE(call); \ 222 CHECK_FOR_INTERPOSITION(emul_table, call, scr, scr_low) 223 224/* 225 * Rather than returning to the instruction after the syscall, we need to 226 * transfer control into the brand library's handler table at 227 * table_addr + (16 * syscall_num), thus encoding the system call number in the 228 * instruction pointer. The CALC_TABLE_ADDR macro performs that calculation. 229 * 230 * This macro assumes the syscall number is in SYSCALL_REG and it clobbers 231 * that register. It leaves the calculated handler table return address in 232 * the scratch reg. 233 */ 234#define CALC_TABLE_ADDR(scr, handler) \ 235 GET_P_BRAND_DATA(SP_REG, 0, scr); /* get p_brand_data ptr */ \ 236 mov handler(scr), scr; /* get p_brand_data->XX_handler */ \ 237 shl $4, SYSCALL_REG; /* syscall_num * 16 */ \ 238 add SYSCALL_REG, scr /* leave return addr in scr reg. */ 239 240#if defined(__amd64) 241 242/* 243 * To 'return' to our user-space handler, we just need to place its address 244 * into 'retreg'. The original return address is passed back in SYSCALL_REG. 245 */ 246#define SYSCALL_EMUL(emul_table, handler, retreg) \ 247 CALLBACK_PROLOGUE(emul_table, handler, SYSCALL_REG, SCR_REG, SCR_REGB);\ 248 CALC_TABLE_ADDR(SCR_REG, handler); \ 249 mov retreg, SYSCALL_REG; /* save orig return addr in syscall_reg */\ 250 mov SCR_REG, retreg; /* place new return addr in retreg */\ 251 mov %gs:CPU_RTMP_R15, SCR_REG; /* restore scratch register */\ 252 mov V_SSP(SP_REG), SP_REG /* restore user stack pointer */ 253 254/* 255 * To 'return' to our user-space handler we need to update the user's %eip 256 * pointer in the saved interrupt state on the stack. The interrupt state was 257 * pushed onto our stack automatically when the interrupt occured; see the 258 * comments above. The original return address is passed back in SYSCALL_REG. 259 */ 260#define INT_EMUL(emul_table, handler) \ 261 CALLBACK_PROLOGUE(emul_table, handler, SYSCALL_REG, SCR_REG, SCR_REGB);\ 262 CALC_TABLE_ADDR(SCR_REG, handler); /* new return addr is in scratch */ \ 263 mov SCR_REG, SYSCALL_REG; /* place new ret addr in syscallreg */ \ 264 mov %gs:CPU_RTMP_R15, SCR_REG; /* restore scratch register */ \ 265 mov V_SSP(SP_REG), SP_REG; /* restore intr stack pointer */ \ 266 /*CSTYLED*/ \ 267 xchg (SP_REG), SYSCALL_REG /* swap new and orig. return addrs */ 268 269#else /* !__amd64 */ 270 271/* 272 * To 'return' to our user-space handler, we just need to place its address 273 * into 'retreg'. The original return address is passed back in SYSCALL_REG. 274 */ 275#define SYSCALL_EMUL(emul_table, handler, retreg) \ 276 CALLBACK_PROLOGUE(emul_table, handler, SYSCALL_REG, SCR_REG, SCR_REGB);\ 277 mov retreg, SCR_REG; /* save orig return addr in scr reg */ \ 278 CALC_TABLE_ADDR(retreg, handler); /* new return addr is in retreg */ \ 279 mov SCR_REG, SYSCALL_REG; /* save orig return addr in %eax */ \ 280 GET_V(SP_REG, 0, V_U_EBX, SCR_REG) /* restore scratch register */ 281 282/* 283 * To 'return' to our user-space handler, we need to replace the 284 * iret target address. 285 * The original return address is passed back in %eax. 286 */ 287#define INT_EMUL(emul_table, handler) \ 288 CALLBACK_PROLOGUE(emul_table, handler, SYSCALL_REG, SCR_REG, SCR_REGB);\ 289 CALC_TABLE_ADDR(SCR_REG, handler); /* new return addr is in scratch */ \ 290 mov SCR_REG, SYSCALL_REG; /* place new ret addr in syscallreg */ \ 291 GET_V(SP_REG, 0, V_U_EBX, SCR_REG); /* restore scratch register */ \ 292 add $V_END, SP_REG; /* restore intr stack pointer */ \ 293 /*CSTYLED*/ \ 294 xchg (SP_REG), SYSCALL_REG /* swap new and orig. return addrs */ 295 296#endif /* !__amd64 */ 297 298#endif /* _ASM */ 299 300#ifdef __cplusplus 301} 302#endif 303 304#endif /* _COMMON_BRAND_ASM_H */ 305