Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/sun4/brand/common/brand_solaris.s
          +++ new/usr/src/uts/sun4/brand/common/brand_solaris.s
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  23   23   */
  24   24  
  25   25  /*
  26   26   * This is an assembly file that gets #include-ed into the brand-specific
  27   27   * assembly files (e.g. sn1_brand_asm.s) for Solaris-derived brands.
  28   28   * We can't make these into functions since in the trap context there's
  29   29   * no easy place to save the extra parameters that would be required, so
  30   30   * each brand module needs its own copy of this code.  We #include this and
  31   31   * use brand-specific #defines to replace the XXX_brand_... definitions.
  32   32   */ 
  33   33  
  34   34  #ifdef lint
  35   35  
  36   36  #include <sys/systm.h>
  37   37  
  38   38  void
  39   39  XXX_brand_syscall32_callback(void)
  40   40  {
  41   41  }
  42   42  
  43   43  void
  44   44  XXX_brand_syscall_callback(void)
  45   45  {
  46   46  }
  47   47  
  48   48  #else   /* !lint */
  49   49  
  50   50  #include <sys/asm_linkage.h>
  51   51  #include <sys/machthread.h>
  52   52  #include <sys/privregs.h>
  53   53  #include "assym.h"
  54   54  
  55   55  #ifdef _ASM     /* The remainder of this file is only for assembly files */
  56   56  
  57   57  #if defined(sun4v)
  58   58  
  59   59  #define GLOBALS_SWAP(reg)                               \
  60   60          rdpr    %gl, reg;                               \
  61   61          wrpr    reg, 1, %gl
  62   62  
  63   63  /*
  64   64   * The GLOBALS_RESTORE macro can only be one instruction since it's
  65   65   * used in a delay slot.
  66   66   */
  67   67  #define GLOBALS_RESTORE(reg)                            \
  68   68          wrpr    reg, 0, %gl
  69   69  
  70   70  #else /* !sun4v */
  71   71  
  72   72  #define GLOBALS_SWAP(reg)                               \
  73   73          rdpr    %pstate, reg;                           \
  74   74          wrpr    reg, PSTATE_AG, %pstate
  75   75  
  76   76  /*
  77   77   * The GLOBALS_RESTORE macro can only be one instruction since it's
  78   78   * used in a delay slot.
  79   79   */
  80   80  #define GLOBALS_RESTORE(reg)                            \
  81   81          wrpr    reg, %g0, %pstate
  82   82  
  83   83  #endif /* !sun4v */
  84   84  
  85   85  /*
  86   86   * Input parameters:
  87   87   * %g1: return point
  88   88   * %g2: pointer to our cpu structure
  89   89   */
  90   90  ENTRY(XXX_brand_syscall32_callback)
  91   91          /*
  92   92           * If the trapping thread has the address mask bit clear, then it's
  93   93           * a 64-bit process, and has no business calling 32-bit syscalls.
  94   94           */
  95   95          rdpr    %tstate, %g3;           /* %tstate.am is the trapping */
  96   96          andcc   %g3, TSTATE_AM, %g3;    /*   threads address mask bit */
  97   97          bne,pt  %xcc, _entry;
  98   98          nop;
  99   99          jmp     %g1;                    /* 64 bit process, bail out */
 100  100          nop;
 101  101  SET_SIZE(XXX_brand_syscall32_callback)
 102  102  
 103  103  /*
 104  104   * Input parameters:
 105  105   * %g1: return point
 106  106   * %g2: pointer to our cpu structure
 107  107   */
 108  108  ENTRY(XXX_brand_syscall_callback)
 109  109          /*
 110  110           * If the trapping thread has the address mask bit set, then it's
 111  111           * a 32-bit process, and has no business calling 64-bit syscalls.
 112  112           */
 113  113          rdpr    %tstate, %g3;           /* %tstate.am is the trapping */
 114  114          andcc   %g3, TSTATE_AM, %g3;    /*   threads address mask bit */
 115  115          be,pt   %xcc, _entry;
 116  116          nop;
 117  117          jmp     %g1;                    /* 32 bit process, bail out */
 118  118          nop;
 119  119  SET_SIZE(XXX_brand_syscall_callback)
 120  120  
 121  121  ENTRY(XXX_brand_syscall_callback_common)
 122  122  _entry:
 123  123          /*
 124  124           * Input parameters:
 125  125           * %g1: return point
 126  126           * %g2: pointer to our cpu structure
 127  127           *
 128  128           * Note that we're free to use any %g? registers as long as
 129  129           * we are are executing with alternate globals.  If we're
 130  130           * executing with user globals we need to backup any registers
 131  131           * that we want to use so that we can restore them when we're
 132  132           * done.
 133  133           *
 134  134           * Save some locals in the CPU tmp area to give us a little
 135  135           * room to work.
 136  136           */
 137  137          stn     %l0, [%g2 + CPU_TMP1];
 138  138          stn     %l1, [%g2 + CPU_TMP2];
 139  139  
 140  140  #if defined(sun4v)
 141  141          /*
 142  142           * On sun4v save our input parameters (which are stored in the
 143  143           * alternate globals) since we'll need to switch between alternate
 144  144           * globals and normal globals, and on sun4v the alternate globals
 145  145           * are not preserved across these types of switches.
 146  146           */
 147  147          stn     %l2, [%g2 + CPU_TMP3];
 148  148          stn     %l3, [%g2 + CPU_TMP4];
 149  149  
 150  150          mov     %g1, %l2;               /* save %g1 in %l2 */
 151  151          mov     %g2, %l3;               /* save %g2 in %l3 */
 152  152  #endif /* sun4v */
 153  153  
 154  154          /*
 155  155           * Switch from the alternate to user globals to grab the syscall
 156  156           * number.
 157  157           */
 158  158          GLOBALS_SWAP(%l0);              /* switch to normal globals */
 159  159  
 160  160          /*
 161  161           * If the system call number is >= 1024, then it is a native
 162  162           * syscall that doesn't need emulation.
 163  163           */
 164  164          cmp     %g1, 1024;              /* is this a native syscall? */
 165  165          bl,a    _indirect_check;        /* probably not, continue checking */
 166  166          mov     %g1, %l1;               /* delay slot - grab syscall number */
 167  167  
 168  168          /*
 169  169           * This is a native syscall, probably from the emulation library.
 170  170           * Subtract 1024 from the syscall number and let it go through.
 171  171           */
 172  172          sub     %g1, 1024, %g1;         /* convert magic num to real syscall */
 173  173          ba      _exit;                  /* jump back into syscall path */
 174  174          GLOBALS_RESTORE(%l0);           /* delay slot - */
 175  175                                          /* switch back to alternate globals */
 176  176  
 177  177  _indirect_check:
 178  178          /*
 179  179           * If the system call number is 0 (SYS_syscall), then this might be
 180  180           * an indirect syscall, in which case the actual syscall number
 181  181           * would be stored in %o0, in which case we need to redo the
 182  182           * the whole >= 1024 check.
 183  183           */
 184  184          brnz,pt %g1, _emulation_check;  /* is this an indirect syscall? */
 185  185          nop;                            /* if not, goto the emulation check */
 186  186  
 187  187          /*
 188  188           * Indirect syscalls are only supported for 32 bit processes so
 189  189           * consult the tstate address mask again.
 190  190           */
 191  191          rdpr    %tstate, %l1;           /* %tstate.am is the trapping */
 192  192          andcc   %l1, TSTATE_AM, %l1;    /*   threads address mask bit */
 193  193          be,a,pn %xcc, _exit;
 194  194          GLOBALS_RESTORE(%l0);           /* delay slot - */
 195  195                                          /* switch back to alternate globals */
 196  196  
 197  197          /*
 198  198           * The caller is 32 bit and this an indirect system call.
 199  199           */
 200  200          cmp     %o0, 1024;              /* is this a native syscall? */
 201  201          bl,a    _emulation_check;       /* no, goto the emulation check */
 202  202          mov     %o0, %l1;               /* delay slot - grab syscall number */
 203  203  
 204  204          /*
 205  205           * This is native indirect syscall, probably from the emulation
 206  206           * library.  Subtract 1024 from the syscall number and let it go
 207  207           * through.
 208  208           */
 209  209          sub     %o0, 1024, %o0;         /* convert magic num to real syscall */
 210  210          ba      _exit;                  /* jump back into syscall path */
 211  211          GLOBALS_RESTORE(%l0);           /* delay slot - */
 212  212                                          /* switch back to alternate globals */
 213  213  
 214  214  _emulation_check:
 215  215          GLOBALS_RESTORE(%l0);           /* switch back to alternate globals */
 216  216  
 217  217          /*
 218  218           * Check to see if we want to interpose on this system call.  If
 219  219           * not, we jump back into the normal syscall path and pretend
 220  220           * nothing happened.  %l1 contains the syscall we're invoking.
 221  221           */
 222  222          set     XXX_emulation_table, %g3;
 223  223          ldn     [%g3], %g3;
 224  224          add     %g3, %l1, %g3;
 225  225          ldub    [%g3], %g3;
 226  226          brz     %g3, _exit;
 227  227          nop;
 228  228  
 229  229          /*
 230  230           * Find the address of the userspace handler.
 231  231           * cpu->cpu_thread->t_procp->p_brand_data->spd_handler.
 232  232           */
 233  233  #if defined(sun4v)
 234  234          /* restore the alternate global registers after incrementing %gl */
 235  235          mov     %l3, %g2;
 236  236  #endif /* sun4v */
 237  237          ldn     [%g2 + CPU_THREAD], %g3;        /* get thread ptr */
 238  238          ldn     [%g3 + T_PROCP], %g4;           /* get proc ptr */
 239  239          ldn     [%g4 + __P_BRAND_DATA], %g5;    /* get brand data ptr */
 240  240          ldn     [%g5 + SPD_HANDLER], %g5;       /* get userland brnd hdlr ptr */
 241  241          brz     %g5, _exit;                     /* has it been set? */
 242  242          nop;
 243  243  
 244  244          /*
 245  245           * Make sure this isn't an agent lwp.  We can't do syscall
 246  246           * interposition for system calls made by a agent lwp.  See
 247  247           * the block comments in the top of the brand emulation library
 248  248           * for more information.
 249  249           */
 250  250          ldn     [%g4 + P_AGENTTP], %g4;         /* get agent thread ptr */
 251  251          cmp     %g3, %g4;                       /* is this an agent thread? */
 252  252          be,pn   %xcc, _exit;                    /* if so don't emulate */
 253  253          nop;
 254  254  
 255  255          /*
 256  256           * Now the magic happens.  Grab the trap return address and then
 257  257           * reset it to point to the user space handler.  When we execute
 258  258           * the 'done' instruction, we will jump into our handler instead of
 259  259           * the user's code.  We also stick the old return address in %g5,
 260  260           * so we can return to the proper instruction in the user's code.
 261  261           * Note: we also pass back the base address of the syscall
 262  262           * emulation table.  This is a performance hack to avoid having to
 263  263           * look it up on every call.
 264  264           */
 265  265          rdpr    %tnpc, %l1;             /* save old tnpc */
 266  266          wrpr    %g0, %g5, %tnpc;        /* setup tnpc */
 267  267          GLOBALS_SWAP(%l0);              /* switch to normal globals */
 268  268          mov     %l1, %g5;               /* pass tnpc to user code in %g5 */
 269  269          GLOBALS_RESTORE(%l0);           /* switch back to alternate globals */
 270  270  
 271  271          /* Update the address we're going to return to */
 272  272  #if defined(sun4v)
 273  273          set     fast_trap_done_chk_intr, %l2;
 274  274  #else /* !sun4v */
 275  275          set     fast_trap_done_chk_intr, %g1;
 276  276  #endif /* !sun4v */
 277  277  
 278  278  _exit:
 279  279          /*
 280  280           * Restore registers before returning.
 281  281           *
 282  282           * Note that %g2 should be loaded with the CPU struct addr and
 283  283           * %g1 should be loaded the address we're going to return to.
 284  284           */
 285  285  #if defined(sun4v)
 286  286          /* restore the alternate global registers after incrementing %gl */
 287  287          mov     %l2, %g1;               /* restore %g1 from %l2 */
 288  288          mov     %l3, %g2;               /* restore %g2 from %l3 */
 289  289  
 290  290          ldn     [%g2 + CPU_TMP4], %l3;  /* restore locals */
 291  291          ldn     [%g2 + CPU_TMP3], %l2;
 292  292  #endif /* sun4v */
 293  293  
 294  294          ldn     [%g2 + CPU_TMP2], %l1;  /* restore locals */
 295  295          ldn     [%g2 + CPU_TMP1], %l0;
 296  296  
 297  297          jmp     %g1;
 298  298          nop;
 299  299  SET_SIZE(XXX_brand_syscall_callback_common)
 300  300  
 301  301  #endif  /* _ASM */
 302  302  #endif  /* !lint */
  
    | 
      ↓ open down ↓ | 
    302 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX