sn1_brand_asm.s revision 4127:64886a16cf93
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 2007 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/machthread.h> 36#include <sys/privregs.h> 37#include "assym.h" 38 39#endif /* lint */ 40 41#ifdef lint 42 43void 44sn1_brand_syscall_callback(void) 45{ 46} 47 48#else /* lint */ 49 50#ifdef sun4v 51 52#define GLOBALS_SWAP(reg) \ 53 rdpr %gl, reg ;\ 54 wrpr reg, 1, %gl 55 56#define GLOBALS_RESTORE(reg) \ 57 wrpr reg, 0, %gl 58 59#else /* !sun4v */ 60 61#define GLOBALS_SWAP(reg) \ 62 rdpr %pstate, reg ;\ 63 wrpr reg, PSTATE_AG, %pstate 64 65#define GLOBALS_RESTORE(reg) \ 66 wrpr reg, %g0, %pstate 67 68#endif /* !sun4v */ 69 70 /* 71 * Input parameters: 72 * %g1: return point 73 * %g2: pointer to our cpu structure 74 */ 75 ENTRY(sn1_brand_syscall_callback) 76 77 /* 78 * save some locals in the CPU tmp area to give us a little 79 * room to work. 80 */ 81 stn %l0, [%g2 + CPU_TMP1] 82 stn %l1, [%g2 + CPU_TMP2] 83 84#ifdef sun4v 85 /* 86 * On sun4v save our input parameters (which are stored in the 87 * alternate globals) since we'll need to switch between alternate 88 * globals and normal globals, and on sun4v the alternate globals 89 * are not preserved across these types of switches. 90 */ 91 stn %l2, [%g2 + CPU_TMP3] 92 stn %l3, [%g2 + CPU_TMP4] 93 mov %g1, %l2 94 mov %g2, %l3 95#endif /* sun4v */ 96 97 /* 98 * Switch from the alternate to user globals to grab the syscall 99 * number, then switch back to the alternate globals. 100 * 101 * If the system call number is >= 1024, then it is coming from the 102 * emulation support library and should not be emulated. 103 */ 104 GLOBALS_SWAP(%l0) ! switch to normal globals 105 cmp %g1, 1024 ! is this call from the library? 106 bl,a 1f 107 mov %g1, %l1 ! delay slot - grab syscall number 108 sub %g1, 1024, %g1 ! convert magic num to real syscall 109 ba 2f ! jump back into syscall path 1101: 111 GLOBALS_RESTORE(%l0) ! delay slot - 112 ! switch back to alternate globals 113 114 /* 115 * Check to see if we want to interpose on this system call. If 116 * not, we jump back into the normal syscall path and pretend 117 * nothing happened. 118 */ 119 set sn1_emulation_table, %g3 120 ldn [%g3], %g3 121 add %g3, %l1, %g3 122 ldub [%g3], %g3 123 brz %g3, 2f 124 nop 125 126 /* 127 * Find the address of the userspace handler. 128 * cpu->cpu_thread->t_procp->p_brandhdlr. 129 */ 130#ifdef sun4v 131 ! restore the alternate global registers after incrementing %gl 132 mov %l3, %g2 133#endif /* sun4v */ 134 ldn [%g2 + CPU_THREAD], %g3 ! load thread pointer 135 ldn [%g3 + T_PROCP], %g3 ! get proc pointer 136 ldn [%g3 + P_BRAND_DATA], %g3 ! get brand handler 137 brz %g3, 2f ! has it been set? 138 nop 139 140 /* 141 * Now the magic happens. Grab the trap return address and then 142 * reset it to point to the user space handler. When we execute 143 * the 'done' instruction, we will jump into our handler instead of 144 * the user's code. We also stick the old return address in %g6, 145 * so we can return to the proper instruction in the user's code. 146 * Note: we also pass back the base address of the syscall 147 * emulation table. This is a performance hack to avoid having to 148 * look it up on every call. 149 */ 150 rdpr %tnpc, %l1 ! save old tnpc 151 wrpr %g0, %g3, %tnpc ! setup tnpc 152 GLOBALS_SWAP(%l0) ! switch to normal globals 153 mov %l1, %g6 ! pass tnpc to user code in %g6 154 GLOBALS_RESTORE(%l0) ! switch back to alternate globals 155 156 /* Update the address we're going to return to */ 157#ifdef sun4v 158 set fast_trap_done_chk_intr, %l2 159#else /* !sun4v */ 160 set fast_trap_done_chk_intr, %g1 161#endif /* !sun4v */ 162 1632: 164 /* 165 * Restore registers before returning. 166 * 167 * Note that %g2 should be loaded with the CPU struct addr and 168 * %g1 should be loaded the address we're going to return to. 169 */ 170#ifdef sun4v 171 ! restore the alternate global registers after incrementing %gl 172 mov %l3, %g2 173 mov %l2, %g1 174 175 ldn [%g2 + CPU_TMP4], %l3 ! restore locals 176 ldn [%g2 + CPU_TMP3], %l2 177#endif /* sun4v */ 178 179 ldn [%g2 + CPU_TMP2], %l1 ! restore locals 180 ldn [%g2 + CPU_TMP1], %l0 181 182 jmp %g1 183 nop 184 SET_SIZE(sn1_brand_syscall_callback) 185#endif /* lint */ 186