Home | History | Annotate | Download | only in sn1
      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