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 #if defined(lint) 27 28 #include <sys/systm.h> 29 30 #else /* lint */ 31 32 #include <sys/asm_linkage.h> 33 #include <sys/privregs.h> 34 #include <sys/segments.h> 35 #include <sn1_offsets.h> 36 #include "assym.h" 37 38 #endif /* lint */ 39 40 #ifdef lint 41 42 void 43 sn1_brand_sysenter_callback(void) 44 { 45 } 46 47 void 48 sn1_brand_syscall_callback(void) 49 { 50 } 51 52 #if defined(__amd64) 53 void 54 sn1_brand_syscall32_callback(void) 55 { 56 } 57 #endif /* amd64 */ 58 59 void 60 sn1_brand_int91_callback(void) 61 { 62 } 63 64 #else /* lint */ 65 66 #if defined(__amd64) 67 /* 68 * When our syscall interposition callback entry point gets invoked the 69 * stack looks like this: 70 * -------------------------------------- 71 * 40 | user %gs | 72 * 32 | callback pointer | 73 * 24 | saved stack pointer | 74 * | 16 | lwp pointer | 75 * v 8 | user return address | 76 * 0 | BRAND_CALLBACK()'s return addr | 77 * -------------------------------------- 78 */ 79 80 #define V_COUNT 6 81 #define V_END (CLONGSIZE * 6) 82 #define V_SSP (CLONGSIZE * 3) 83 #define V_LWP (CLONGSIZE * 2) 84 #define V_URET_ADDR (CLONGSIZE * 1) 85 #define V_CB_ADDR (CLONGSIZE * 0) 86 87 #define SP_REG %rsp 88 #define SYSCALL_REG %rax 89 90 #else /* !__amd64 */ 91 /* 92 * When our syscall interposition callback entry point gets invoked the 93 * stack looks like this: 94 * -------------------------------------- 95 * | 24 | 'scratch space' | 96 * | 20 | user's %ebx | 97 * | 16 | user's %gs selector | 98 * | 12 | kernel's %gs selector | 99 * | 8 | lwp pointer | 100 * v 4 | user return address | 101 * 0 | callback wrapper return addr | 102 * -------------------------------------- 103 */ 104 105 #define V_COUNT 7 106 #define V_END (CLONGSIZE * 7) 107 #define V_U_GS (CLONGSIZE * 4) 108 #define V_K_GS (CLONGSIZE * 3) 109 #define V_LWP (CLONGSIZE * 2) 110 #define V_URET_ADDR (CLONGSIZE * 1) 111 #define V_CB_ADDR (CLONGSIZE * 0) 112 113 #define SP_REG %esp 114 #define SYSCALL_REG %eax 115 116 #endif /* !__amd64 */ 117 118 /* 119 * The following macros allow us to access to variables/parameters passed 120 * in on the stack. They take the following variables: 121 * sp - a register with the current stack pointer value 122 * pcnt - the number of words currently pushed onto the stack 123 * var - the variable to lookup 124 * reg - a register to read the variable into, or 125 * a register to write to the variable 126 */ 127 #define V_OFFSET(pcnt, var) \ 128 (var + (pcnt * CLONGSIZE)) 129 130 #define GET_V(sp, pcnt, var, reg) \ 131 mov V_OFFSET(pcnt, var)(sp), reg 132 133 #define SET_V(sp, pcnt, var, reg) \ 134 mov reg, V_OFFSET(pcnt, var)(sp) 135 136 #define GET_PROCP(sp, pcnt, reg) \ 137 GET_V(sp, pcnt, V_LWP, reg) /* get lwp pointer */ ;\ 138 mov LWP_PROCP(reg), reg /* get proc pointer */ 139 140 #define GET_P_BRAND_DATA(sp, pcnt, reg) \ 141 GET_PROCP(sp, pcnt, reg) ;\ 142 mov P_BRAND_DATA(reg), reg /* get p_brand_data */ 143 144 /* 145 * Each of the following macros returns to the standard syscall codepath if 146 * it detects that this process is not able, or intended, to emulate this 147 * system call. They all assume that the routine provides a 'bail-out' 148 * label of '9'. 149 */ 150 151 /* 152 * See if this process has a user-space hdlr registered for it. For the 153 * sn1 brand, the per-process brand data holds the address of the handler. 154 * As shown in the stack diagrams below, the callback code leaves that data 155 * at these offsets. So check if sn1_proc_data_t->spd_handler is non-NULL. 156 */ 157 #define CHECK_FOR_HANDLER(scr) \ 158 GET_P_BRAND_DATA(SP_REG, 1, scr) /* get p_brand_data */ ;\ 159 cmp $0, scr ;\ 160 je 9f ;\ 161 cmp $0, SPD_HANDLER(scr) /* check spd_handler */ ;\ 162 je 9f 163 164 /* 165 * If the system call number is >= 1024, then it is coming from the 166 * emulation support library. As such we should handle it natively instead 167 * of sending it back to the emulation library. 168 */ 169 #define CHECK_FOR_NATIVE(reg) \ 170 cmp $1024, reg ;\ 171 jl 1f ;\ 172 sub $1024, reg ;\ 173 jmp 9f ;\ 174 1: 175 176 /* 177 * Check to see if we want to interpose on this system call. If not, we 178 * jump back into the normal syscall path and pretend nothing happened. 179 */ 180 #define CHECK_FOR_INTERPOSITION(sysr, scr, scr_low) \ 181 cmp $NSYSCALL, sysr /* is 0 <= syscall <= MAX? */ ;\ 182 ja 9f /* no, take normal err path */ ;\ 183 lea sn1_emulation_table, scr ;\ 184 mov (scr), scr ;\ 185 add sysr, scr ;\ 186 movb (scr), scr_low ;\ 187 cmpb $0, scr_low ;\ 188 je 9f 189 190 #define CALLBACK_PROLOGUE(call, scr, scr_low) \ 191 push scr /* Save scratch register */ ;\ 192 CHECK_FOR_HANDLER(scr) ;\ 193 CHECK_FOR_NATIVE(call) ;\ 194 CHECK_FOR_INTERPOSITION(call, scr, scr_low) 195 196 /* 197 * Rather than returning to the instruction after the syscall, we need to 198 * transfer control into the brand library's handler table at 199 * table_addr + (16 * syscall_num), thus encoding the system call number in the 200 * instruction pointer. The CALC_TABLE_ADDR macro performs that calculation. 201 * 202 * This macro assumes the syscall number is in SYSCALL_REG and it clobbers 203 * that register. It leaves the calculated handler table return address in 204 * the scratch reg. 205 */ 206 #define CALC_TABLE_ADDR(scr) \ 207 GET_P_BRAND_DATA(SP_REG, 1, scr) /* get p_brand_data ptr */ ;\ 208 mov SPD_HANDLER(scr), scr /* get p_brand_data->spd_handler */ ;\ 209 shl $4, SYSCALL_REG /* syscall_num * 16 */ ;\ 210 add SYSCALL_REG, scr /* leave return addr in scr reg. */ 211 212 /* 213 * To 'return' to our user-space handler, we just need to place its address 214 * into 'retreg'. The original return address is passed in SYSCALL_REG. 215 */ 216 #define SETUP_RET_DATA(scr, retreg) \ 217 CALC_TABLE_ADDR(scr) ;\ 218 mov retreg, SYSCALL_REG /* save orig return addr in %rax */ ;\ 219 mov scr, retreg /* save new return addr in ret reg */ ;\ 220 pop scr /* restore scratch register */ 221 222 /* 223 * The callback routines: 224 */ 225 226 #if defined(__amd64) 227 228 /* 229 * syscall handler for 32-bit user processes: 230 * %rax - syscall number 231 * %ecx - the address of the instruction after the syscall 232 */ 233 ENTRY(sn1_brand_syscall32_callback) 234 235 CALLBACK_PROLOGUE(%rax, %r15, %r15b) 236 237 SETUP_RET_DATA(%r15, %rcx) 238 GET_V(%rsp, 0, V_SSP, %rsp) /* restore user's stack pointer */ 239 jmp nopop_sys_syscall32_swapgs_sysretl 240 9: 241 popq %r15 242 retq 243 SET_SIZE(sn1_brand_syscall32_callback) 244 245 /* 246 * syscall handler for 64-bit user processes: 247 * %rax - syscall number 248 * %rcx - user space %rip 249 */ 250 ENTRY(sn1_brand_syscall_callback) 251 252 CALLBACK_PROLOGUE(%rax, %r15, %r15b) 253 254 SETUP_RET_DATA(%r15, %rcx) 255 GET_V(%rsp, 0, V_SSP, %rsp) /* restore user's stack pointer */ 256 jmp nopop_sys_syscall_swapgs_sysretq 257 9: 258 popq %r15 259 retq 260 261 SET_SIZE(sn1_brand_syscall_callback) 262 263 /* 264 * %eax - syscall number 265 * %ecx - user space %esp 266 * %edx - user space return address 267 */ 268 ENTRY(sn1_brand_sysenter_callback) 269 270 CALLBACK_PROLOGUE(%rax, %r15, %r15b) 271 272 SETUP_RET_DATA(%r15, %rdx) 273 jmp sys_sysenter_swapgs_sysexit 274 9: 275 popq %r15 276 ret 277 SET_SIZE(sn1_brand_sysenter_callback) 278 279 /* 280 * The saved stack pointer points at the state saved when we took 281 * the interrupt: 282 * -------------------------------------- 283 * | 32 | user's %ss | 284 * | 24 | user's %esp | 285 * | 16 | EFLAGS register | 286 * v 8 | user's %cs | 287 * 0 | user's %eip | 288 * -------------------------------------- 289 */ 290 #define V_U_EIP (CLONGSIZE * 0) 291 292 ENTRY(sn1_brand_int91_callback) 293 294 CALLBACK_PROLOGUE(%rax, %r15, %r15b) 295 296 /* 297 * To 'return' to our user-space handler we need to update the user's 298 * %eip pointer in the saved interrupt state. The interrupt state was 299 * pushed onto our stack automatically when the interrupt occured; see 300 * the comments above. The original return address is passed in %rax. 301 */ 302 CALC_TABLE_ADDR(%r15) 303 GET_V(%rsp, 1, V_SSP, %rax) /* get saved stack pointer */ 304 SET_V(%rax, 0, V_U_EIP, %r15) /* save new return addr in %eip */ 305 GET_V(%rsp, 1, V_URET_ADDR, %rax) /* %rax has orig. return addr. */ 306 307 popq %r15 /* Restore scratch register */ 308 movq V_SSP(%rsp), %rsp /* Remove callback stuff from stack */ 309 jmp sys_sysint_swapgs_iret 310 9: 311 popq %r15 312 retq 313 SET_SIZE(sn1_brand_int91_callback) 314 315 #else /* !__amd64 */ 316 317 /* 318 * lcall handler for 32-bit OS 319 * %eax - syscall number 320 * 321 * Above the stack contents common to all callbacks is the 322 * int/lcall-specific state: 323 * -------------------------------------- 324 * | 44 | user's %ss | 325 * | 40 | user's %esp | 326 * | 36 | EFLAGS register | 327 * v 32 | user's %cs | 328 * 28 | user's %eip | 329 * -------------------------------------- 330 */ 331 #define V_U_SS (V_END + (CLONGSIZE * 4)) 332 #define V_U_ESP (V_END + (CLONGSIZE * 3)) 333 #define V_EFLAGS (V_END + (CLONGSIZE * 2)) 334 #define V_U_CS (V_END + (CLONGSIZE * 1)) 335 #define V_U_EIP (V_END + (CLONGSIZE * 0)) 336 337 ENTRY(sn1_brand_syscall_callback) 338 339 CALLBACK_PROLOGUE(%eax, %ebx, %bl) 340 341 /* 342 * To 'return' to our user-space handler, we need to replace the 343 * iret target address. 344 * The original return address is passed in %eax. 345 */ 346 CALC_TABLE_ADDR(%ebx) /* new return addr is in %ebx */ 347 SET_V(%esp, 1, V_U_EIP, %ebx) /* set iret target address to hdlr */ 348 GET_V(%esp, 1, V_URET_ADDR, %eax) /* save orig return addr in %eax */ 349 350 GET_V(%esp, 1, V_U_GS, %ebx) /* grab the the user %gs */ 351 movw %bx, %gs /* restore the user %gs */ 352 353 popl %ebx /* Restore scratch register */ 354 addl $V_END, %esp /* Remove all callback stuff from stack */ 355 jmp nopop_sys_rtt_syscall 356 9: 357 popl %ebx 358 ret 359 SET_SIZE(sn1_brand_syscall_callback) 360 361 /* 362 * %eax - syscall number 363 * %ecx - user space %esp 364 * %edx - user space return address 365 */ 366 ENTRY(sn1_brand_sysenter_callback) 367 368 CALLBACK_PROLOGUE(%eax, %ebx, %bl) 369 370 /* 371 * To 'return' to our user-space handler, we just need to place its 372 * address into %edx. 373 * The original return address is passed in %eax. 374 */ 375 movl %edx, %ebx /* save orig return addr in tmp reg */ 376 CALC_TABLE_ADDR(%edx) /* new return addr is in %edx */ 377 movl %ebx, %eax /* save orig return addr in %eax */ 378 379 GET_V(%esp, 1, V_U_GS, %ebx) /* grab the the user %gs */ 380 movw %bx, %gs /* restore the user %gs */ 381 382 popl %ebx /* restore scratch register */ 383 sysexit 384 9: 385 popl %ebx 386 ret 387 SET_SIZE(sn1_brand_sysenter_callback) 388 389 #endif /* !__amd64 */ 390 #endif /* lint */ 391