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