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 (c) 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25#include <brand_misc.h> 26 27#if defined(lint) 28 29void 30brand_handler(void) 31{ 32} 33 34#else /* !lint */ 35 36#define PIC_SETUP(r) \ 37 mov %o7, %g1; \ 389: call 8f; \ 39 sethi %hi(_GLOBAL_OFFSET_TABLE_ - (9b - .)), r; \ 408: or r, %lo(_GLOBAL_OFFSET_TABLE_ - (9b - .)), r; \ 41 add r, %o7, r; \ 42 mov %g1, %o7 43 44/* 45 * Translate a global symbol into an address. The resulting address 46 * is returned in the first register parameter. The second register 47 * is just for scratch space. 48 */ 49#if defined(__sparcv9) 50#define GET_SYM_ADDR(r1, r2, name) \ 51 PIC_SETUP(r1) ;\ 52 sethi %hi(name), r2 ;\ 53 or r2, %lo(name), r2 ;\ 54 ldn [r2 + r1], r1 55#else /* !__sparcv9 */ 56#define GET_SYM_ADDR(r1, r2, name) \ 57 PIC_SETUP(r1); \ 58 ld [r1 + name], r1 59#endif /* !__sparcv9 */ 60 61 .section ".text" 62 63 /* 64 * When we get here, %g1 should contain the system call and 65 * %g5 should contain the address immediately after the trap 66 * instruction. 67 */ 68 ENTRY_NP(brand_handler) 69 70 /* 71 * 64-bit sparc may need to save 3 parameters on the stack. 72 * 32-bit sparc may need to save 4 parameters on the stack. 73 * 74 * Our stack frame format is documented in brand_misc.h. 75 */ 76 save %sp, -SA(MINFRAME + EH_LOCALS_SIZE), %sp 77 78 /* 79 * Save the current caller state into gregs and gwins. 80 * Note that this state isn't exact, %g1 and %g5 have been 81 * already been lost. Also, we've pushed a stack frame so 82 * the callers output registers are our input registers. 83 */ 84 stn %g0, [%sp + EH_LOCALS_GREG(REG_G1)] /* %g1 is lost */ 85 stn %g2, [%sp + EH_LOCALS_GREG(REG_G2)] 86 stn %g3, [%sp + EH_LOCALS_GREG(REG_G3)] 87 stn %g4, [%sp + EH_LOCALS_GREG(REG_G4)] 88 stn %g0, [%sp + EH_LOCALS_GREG(REG_G5)] /* %g5 is lost */ 89 stn %g6, [%sp + EH_LOCALS_GREG(REG_G6)] 90 stn %g7, [%sp + EH_LOCALS_GREG(REG_G7)] 91 stn %i0, [%sp + EH_LOCALS_GREG(REG_O0)] 92 stn %i1, [%sp + EH_LOCALS_GREG(REG_O1)] 93 stn %i2, [%sp + EH_LOCALS_GREG(REG_O2)] 94 stn %i3, [%sp + EH_LOCALS_GREG(REG_O3)] 95 stn %i4, [%sp + EH_LOCALS_GREG(REG_O4)] 96 stn %i5, [%sp + EH_LOCALS_GREG(REG_O5)] 97 stn %i6, [%sp + EH_LOCALS_GREG(REG_O6)] 98 stn %i7, [%sp + EH_LOCALS_GREG(REG_O7)] 99 sub %g5, 4, %o0 100 stn %o0, [%sp + EH_LOCALS_GREG(REG_PC)] 101 stn %g5, [%sp + EH_LOCALS_GREG(REG_nPC)] 102 rd %y, %o0 103 stn %o0, [%sp + EH_LOCALS_GREG(REG_Y)] 104#if defined(__sparcv9) 105 stn %g0, [%sp + EH_LOCALS_GREG(REG_ASI)] 106 rd %fprs, %o0 107 stn %o0, [%sp + EH_LOCALS_GREG(REG_FPRS)] 108#endif /* __sparcv9 */ 109 110 /* 111 * Look up the system call's entry in the sysent table 112 * and obtain the address of the proper emulation routine (%l2). 113 */ 114 mov %g1, %l5 /* save syscall number */ 115 GET_SYM_ADDR(%l1, %l2, brand_sysent_table) 116 mov %l5, %g1 /* restore syscall number */ 117 sll %g1, (1 + CLONGSHIFT), %l2 /* Each entry has 2 longs */ 118 add %l2, %l1, %l2 /* index to proper entry */ 119 ldn [%l2], %l2 /* emulation func address */ 120 121 /* 122 * Look up the system call's entry in the sysent table, 123 * taking into account the posibility of indirect system calls, and 124 * obtain the number of arguments (%l4) and return value flag (%l3). 125 */ 126#if defined(__sparcv9) 127 mov %g1, %l3 /* %g1 == syscall number */ 128#else /* !__sparcv9 */ 129 /* 130 * Check for indirect system calls, in which case the real syscall 131 * number is the first parameter to the indirect system call. 132 */ 133 cmp %g1, %g0 /* saved syscall number */ 134 bne,a,pt %icc, no_indir /* indirect syscall? */ 135 mov %g1, %l3 /* %g1 == syscall number */ 136 mov %i0, %l3 /* %i0 == syscall number */ 137no_indir: 138#endif /* !__sparcv9 */ 139 sll %l3, (1 + CLONGSHIFT), %l3 /* Each entry has 2 longs */ 140 add %l3, %l1, %l3 /* index to proper entry */ 141 ldn [%l3 + CPTRSIZE], %l4 /* number of args + rv flag */ 142 sethi %hi(RV_MASK), %l5 143 or %l5, %lo(RV_MASK), %l5 144 andcc %l4, %l5, %l3 /* strip out number of args*/ 145 andcc %l4, NARGS_MASK, %l4 /* strip out rv flag */ 146 147 /* 148 * Setup arguments for our emulation call. Our input arguments, 149 * 0 to N, will become emulation call arguments 1 to N+1. 150 * %l4 == number of arguments. 151 */ 152 mov %i0, %o1 153 mov %i1, %o2 154 mov %i2, %o3 155 mov %i3, %o4 156 mov %i4, %o5 157 158 /* 7th argument and above get passed on the stack */ 159 cmp %l4, 0x6 160 bl,pt %ncc, args_copied 161 nop 162 stn %i5, [%sp + EH_ARGS_OFFSET(0)] /* copy 6th syscall arg */ 163 cmp %l4, 0x7 164 bl,pt %ncc, args_copied 165 nop 166 ldn [%fp + EH_ARGS_OFFSET(0)], %l5 /* copy 7th syscall arg */ 167 stn %l5, [%sp + EH_ARGS_OFFSET(1)] 168 cmp %l4, 0x8 169 bl,pt %ncc, args_copied 170 nop 171 ldn [%fp + EH_ARGS_OFFSET(1)], %l5 172 stn %l5, [%sp + EH_ARGS_OFFSET(2)] /* copy 8th syscall arg */ 173#if !defined(__sparcv9) 174 cmp %l4, 0x9 175 bl,pt %ncc, args_copied 176 nop 177 ldn [%fp + EH_ARGS_OFFSET(2)], %l5 178 stn %l5, [%sp + EH_ARGS_OFFSET(3)] /* copy 9th syscall arg */ 179#endif /* !__sparcv9 */ 180 181args_copied: 182 /* 183 * The first parameter to the emulation callback function is a 184 * pointer to a sysret_t structure. 185 * 186 * invoke the emulation routine. 187 */ 188 ALTENTRY(brand_handler_savepc) 189 call %l2 190 add %sp, EH_LOCALS_SYSRET, %o0 /* arg0 == sysret_t ptr */ 191 192 /* Check for syscall emulation success or failure */ 193 cmp %g0, %o0 194 be success 195 nop 196 subcc %g0, 1, %g0 /* failure, set carry flag */ 197 ba return 198 mov %o0, %i0 /* return, %o0 == errno */ 199 200success: 201 /* There is always at least one return value. */ 202 ldn [%sp + EH_LOCALS_SYSRET1], %i0 /* %i0 == sys_rval1 */ 203 cmp %l3, RV_DEFAULT /* check rv flag */ 204 be,a clear_carry 205 mov %g0, %i1 /* clear second rval */ 206 ldn [%sp + EH_LOCALS_SYSRET2], %i1 /* %i1 == sys_rval2 */ 207clear_carry: 208 addcc %g0, %g0, %g0 /* success, clear carry flag */ 209 210return: 211 /* 212 * Our syscall emulation is complete. Return to the caller that 213 * originally invoked a system which needed emulation. Note that 214 * we have to load the return address that we saved earlier because 215 * it's possible that %g5 was overwritten by a nested call into 216 * this emulation library. 217 */ 218 ldn [%sp + EH_LOCALS_GREG(REG_nPC)], %g5 219 jmp %g5 220 restore /* delay slot */ 221 SET_SIZE(brand_handler) 222 223 224#endif /* !lint */ 225