sn1_brand_asm.s revision 2712:f74a135872bc
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 2006 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 38#endif /* lint */ 39 40#ifdef lint 41 42void 43sn1_brand_sysenter_callback(void) 44{ 45} 46 47void 48sn1_brand_syscall_callback(void) 49{ 50} 51 52#if defined(__amd64) 53void 54sn1_brand_syscall32_callback(void) 55{ 56} 57#endif /* amd64 */ 58 59void 60sn1_brand_int91_callback(void) 61{ 62} 63 64#else /* lint */ 65 66/* 67 * Each of the following macros returns to the standard syscall codepath if 68 * it detects that this process is not able, or intended, to emulate this 69 * system call. They all assume that the routine provides a 'bail-out' 70 * label of '9'. 71 */ 72 73/* 74 * See if this process has a user-space handler registered for it. For the 75 * sn1 brand, the per-process brand data holds the address of the handler. 76 * As shown in the stack diagrams below, the callback code leaves that data 77 * at these offsets. 78 */ 79#if defined(__amd64) 80#define CHECK_FOR_HANDLER \ 81 cmpq $0, 24(%rsp) ;\ 82 je 9f 83#else 84#define CHECK_FOR_HANDLER \ 85 cmpl $0, 12(%esp) ;\ 86 je 9f 87#endif /* __amd64 */ 88 89/* 90 * If the system call number is >= 1024, then it is coming from the 91 * emulation support library. As such we should handle it natively instead 92 * of sending it back to the emulation library. 93 */ 94#define CHECK_FOR_NATIVE(reg) \ 95 cmp $1024, reg ;\ 96 jl 1f ;\ 97 sub $1024, reg ;\ 98 jmp 9f ;\ 991: 100 101/* 102 * Check to see if we want to interpose on this system call. If not, we 103 * jump back into the normal syscall path and pretend nothing happened. 104 */ 105#define CHECK_FOR_INTERPOSITION(sysr, scr, scr_low) \ 106 lea sn1_emulation_table, scr ;\ 107 mov (scr), scr ;\ 108 add sysr, scr ;\ 109 movb (scr), scr_low ;\ 110 cmpb $0, scr_low ;\ 111 je 9f ;\ 112 113#define CALLBACK_PROLOGUE(call, scr, scr_low) ;\ 114 push scr /* Save scratch register */ ;\ 115 CHECK_FOR_HANDLER ;\ 116 CHECK_FOR_NATIVE(call) ;\ 117 CHECK_FOR_INTERPOSITION(call, scr, scr_low) 118 119/* 120 * The callback routines: 121 */ 122 123#if defined(__amd64) 124 /* 125 * When we get into any of these callback routines, the stack 126 * looks like this: 127 * -------------------------------------- 128 * 32 | saved stack pointer | 129 * | 24 | lwp brand data | 130 * | 16 | proc brand data | 131 * v 8 | user return address (*) | 132 * 0 | BRAND_CALLBACK()'s return addr | 133 * -------------------------------------- 134 * (*) This is actually just the bottom value from the user's 135 * stack. syscall puts this in %rcx instead of the stack, 136 * so it's just garbage for that entry point. 137 */ 138 139 /* 140 * syscall handler for 32-bit user processes: 141 * 142 * %ecx contains the address of the instruction after the syscall 143 */ 144 ENTRY(sn1_brand_syscall32_callback) 145 146 CALLBACK_PROLOGUE(%rax, %r15, %r15b) 147 148 movq %rsp, %r15 /* save our stack pointer */ 149 150 /* 151 * Adjust the user's stack so that the 'ret' from our userspace 152 * handler takes us to the post-syscall instruction instead of to 153 * the routine that called the system call. 154 */ 155 movq 40(%rsp), %rsp /* restore user's stack pointer */ 156 subq $4, %rsp /* save room for the post-syscall addr */ 157 movl %ecx, (%rsp) /* Save post-syscall addr on stack */ 158 159 /* 160 * To 'return' to our user-space handler, we just need to copy 161 * its address into %ecx. 162 */ 163 movq 24(%r15), %rcx /* user-space handler == proc_data for sn1 */ 164 movq (%r15), %r15 /* Restore scratch register */ 165 sysret 1669: 167 popq %r15 168 retq 169 SET_SIZE(sn1_brand_syscall32_callback) 170 171 /* 172 * syscall handler for 64-bit user processes: 173 * %rax - syscall number 174 * %rcx - user space %rip 175 */ 176 ENTRY(sn1_brand_syscall_callback) 177 178 CALLBACK_PROLOGUE(%rax, %r15, %r15b) 179 180 movq %rsp, %r15 /* save our stack pointer */ 181 182 movq 40(%rsp), %rsp /* restore user's stack pointer */ 183 subq $8, %rsp /* save room for the post-syscall addr */ 184 movq %rcx, (%rsp) /* Save post-syscall addr on stack */ 185 186 /* 187 * To 'return' to our user-space handler, we just need to copy 188 * its address into %ecx. 189 */ 190 movq 24(%r15), %rcx /* user-space handler == proc_data for sn1 */ 191 movq (%r15), %r15 /* Restore scratch register */ 192 sysretq 1939: 194 popq %r15 195 retq 196 197 SET_SIZE(sn1_brand_syscall_callback) 198 199 /* 200 * %rax - syscall number 201 * %rcx - user space %esp 202 * %rdx - user space return address 203 * 204 * XXX: not tested yet. Need a Nocona machine first. 205 */ 206 ENTRY(sn1_brand_sysenter_callback) 207 208 CALLBACK_PROLOGUE(%rax, %r15, %r15b) 209 210 subq $4, %rcx /* Save room for user ret addr */ 211 movq %rdx, (%rcx) /* Save current return addr */ 212 movq 24(%rsp), %rdx /* user-space handler == proc_data for sn1 */ 213 popq %r15 214 sysexit 2159: 216 popq %r15 217 ret 218 SET_SIZE(sn1_brand_sysenter_callback) 219 220 /* 221 * The saved stack pointer points at the state saved when we took 222 * the interrupt: 223 * -------------------------------------- 224 * | 32 | user's %ss | 225 * | 24 | user's %esp | 226 * | 16 | EFLAGS register | 227 * v 8 | user's %cs | 228 * 0 | user's %eip | 229 * -------------------------------------- 230 */ 231 ENTRY(sn1_brand_int91_callback) 232 233 CALLBACK_PROLOGUE(%rax, %r15, %r15b) 234 235 movq 24(%rsp), %r15 /* user-space handler == proc_data for sn1 */ 236 pushq %rax /* Save scratch register */ 237 movq 48(%rsp), %rax /* Get saved %esp */ 238 movq %r15, (%rax) /* replace iret target address with hdlr */ 239 240 /* 241 * Adjust the caller's stack so we return to the instruction after 242 * the syscall on the next 'ret' in userspace - not to the parent 243 * routine. 244 */ 245 movq 24(%rax), %r15 /* Get user's %esp */ 246 subq $4, %r15 /* Make room for new ret addr */ 247 movq %r15, 24(%rax) /* Replace current with updated %esp */ 248 movl 24(%rsp), %eax /* Get post-syscall address */ 249 movl %eax, (%r15) /* Put it on the user's stack */ 250 251 popq %rax /* Restore scratch register */ 252 popq %r15 /* Restore scratch register */ 253 movq 32(%rsp), %rsp /* Remove all callback stuff from stack */ 254 iretq 2559: 256 popq %r15 257 retq 258 SET_SIZE(sn1_brand_int91_callback) 259 260#else /* __amd64 */ 261 262 /* 263 * When we get into any of these callback routines, the stack 264 * looks like this: 265 * -------------------------------------- 266 * | 28 | 'scatch space' | 267 * | 24 | user's %ebx | 268 * | 20 | user's %gs selector | 269 * | 16 | kernel's %gs selector | 270 * | 12 | lwp brand data | 271 * | 8 | proc brand data | 272 * v 4 | user return address | 273 * 0 | callback wrapper return addr | 274 * -------------------------------------- 275 */ 276 277 /* 278 * lcall handler for 32-bit OS 279 * %eax - syscall number 280 * 281 * Above the stack contents common to all callbacks is the 282 * int/lcall-specific state: 283 * -------------------------------------- 284 * | 48 | user's %ss | 285 * | 44 | user's %esp | 286 * | 40 | EFLAGS register | 287 * v 36 | user's %cs | 288 * 32 | user's %eip | 289 * -------------------------------------- 290 */ 291 ENTRY(sn1_brand_syscall_callback) 292 293 CALLBACK_PROLOGUE(%eax, %ebx, %bl) 294 295 movl 12(%esp), %ebx /* user-space handler == proc_data for sn1 */ 296 movl %ebx, 36(%esp) /* replace iret target address with hdlr */ 297 298 /* 299 * Adjust the caller's stack so we return to the instruction after 300 * the syscall on the next 'ret' in userspace - not to the parent 301 * routine. 302 */ 303 pushl %eax /* Save scratch register */ 304 movl 52(%esp), %eax /* Get current %esp */ 305 subl $4, %eax /* Make room for new ret addr */ 306 movl %eax, 52(%esp) /* Replace current with updated %esp */ 307 movl 12(%esp), %ebx /* Get post-syscall address */ 308 movl %ebx, (%eax) /* Put it on the user's stack */ 309 popl %eax /* Restore scratch register */ 310 311 popl %ebx /* Restore scratch register */ 312 addl $32, %esp /* Remove all callback stuff from stack */ 313 iret 3149: 315 popl %ebx 316 ret 317 SET_SIZE(sn1_brand_syscall_callback) 318 319 /* 320 * %eax - syscall number 321 * %ecx - user space %esp 322 * %edx - user space return address 323 */ 324 ENTRY(sn1_brand_sysenter_callback) 325 326 CALLBACK_PROLOGUE(%eax, %ebx, %bl) 327 328 subl $4, %ecx /* Save room for user ret addr */ 329 movl %edx, (%ecx) /* Save current return addr */ 330 movl 12(%esp), %edx /* Return to user-space handler */ 331 popl %ebx /* Restore scratch register */ 332 sysexit 3339: 334 popl %ebx 335 ret 336 SET_SIZE(sn1_brand_sysenter_callback) 337 338#endif /* __amd64 */ 339#endif /* lint */ 340 341