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 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include "assym.h"
  27 
  28 #include <sys/asm_linkage.h>
  29 #include <sys/privregs.h>
  30 #include <sys/x_call.h>
  31 #include <sys/xc_impl.h>
  32 #include <sys/machthread.h>
  33 #include <sys/hypervisor_api.h>
  34 
  35 #ifdef TRAPTRACE
  36 #include <sys/traptrace.h>
  37 #endif /* TRAPTRACE */
  38 
  39 
  40 /*
  41  * Entered by the software trap (TT=ST_SELFXCALL, TL>0) thru send_self_xcall().
  42  * Emulate the mondo handler - vec_interrupt().
  43  *
  44  * Global registers are the Alternate Globals.
  45  * Arguments:
  46  *      %o0 - CPU
  47  *      ILP32 kernel:
  48  *              %o5 - function to call
  49  *              %o1, %o2, %o3, %o4  - arguments
  50  *      LP64 kernel:
  51  *              %o3 - function to call
  52  *              %o1, %o2 - arguments
  53  */
  54         ENTRY_NP(self_xcall)
  55         !
  56         ! TL>0 handlers are expected to do "retry"
  57         ! prepare their return PC and nPC now
  58         !
  59         rdpr    %tnpc, %g1
  60         wrpr    %g1, %tpc                       !  PC <- TNPC[TL]
  61         add     %g1, 4, %g1
  62         wrpr    %g1, %tnpc                      ! nPC <- TNPC[TL] + 4
  63 
  64 #ifdef TRAPTRACE
  65         TRACE_PTR(%g4, %g6)
  66         GET_TRACE_TICK(%g6, %g3)
  67         stxa    %g6, [%g4 + TRAP_ENT_TICK]%asi
  68         rdpr    %tl, %g6
  69         stha    %g6, [%g4 + TRAP_ENT_TL]%asi
  70         rdpr    %tt, %g6
  71         stha    %g6, [%g4 + TRAP_ENT_TT]%asi
  72         stna    %o3, [%g4 + TRAP_ENT_TR]%asi ! pc of the TL>0 handler
  73         rdpr    %tpc, %g6
  74         stna    %g6, [%g4 + TRAP_ENT_TPC]%asi
  75         rdpr    %tstate, %g6
  76         stxa    %g6, [%g4 + TRAP_ENT_TSTATE]%asi
  77         stna    %sp, [%g4 + TRAP_ENT_SP]%asi
  78         stna    %o1, [%g4 + TRAP_ENT_F1]%asi ! arg 1
  79         stna    %o2, [%g4 + TRAP_ENT_F2]%asi ! arg 2
  80         stna    %g0, [%g4 + TRAP_ENT_F3]%asi
  81         stna    %g0, [%g4 + TRAP_ENT_F4]%asi
  82         TRACE_NEXT(%g4, %g6, %g3)
  83 #endif /* TRAPTRACE */
  84         !
  85         ! Load the arguments for the fast trap handler.
  86         !
  87         mov     %o1, %g1
  88         jmp     %o3                             ! call the fast trap handler
  89         mov     %o2, %g2
  90         /* Not Reached */
  91         SET_SIZE(self_xcall)
  92 
  93 #ifdef  TRAPTRACE
  94         ENTRY(xc_trace)
  95         rdpr    %pstate, %g1
  96         andn    %g1, PSTATE_IE | PSTATE_AM, %g2
  97         wrpr    %g0, %g2, %pstate                       /* disable interrupts */
  98         TRACE_PTR(%g3, %g4)
  99         GET_TRACE_TICK(%g6, %g4)
 100         stxa    %g6, [%g3 + TRAP_ENT_TICK]%asi
 101         stha    %g0, [%g3 + TRAP_ENT_TL]%asi
 102         set     TT_XCALL, %g2
 103         or      %o0, %g2, %g4
 104         stha    %g4, [%g3 + TRAP_ENT_TT]%asi
 105         stna    %o7, [%g3 + TRAP_ENT_TPC]%asi
 106         ldn     [%o1], %g2
 107         stna    %g2, [%g3 + TRAP_ENT_SP]%asi            /* sp = cpuset */
 108         stna    %o2, [%g3 + TRAP_ENT_TR]%asi            /* tr = func */
 109         stna    %o3, [%g3 + TRAP_ENT_F1]%asi            /* f1 = arg1 */
 110         stna    %o4, [%g3 + TRAP_ENT_F2]%asi            /* f2 = arg2 */
 111         stna    %g0, [%g3 + TRAP_ENT_F3]%asi            /* f3 = 0 */
 112         stna    %i7, [%g3 + TRAP_ENT_F4]%asi            /* f4 = xcall caller */
 113         stxa    %g1, [%g3 + TRAP_ENT_TSTATE]%asi        /* tstate = pstate */
 114         TRACE_NEXT(%g2, %g3, %g4)
 115 /*
 116  * In the case of a cpuset of greater size than a long we
 117  * grab extra trace buffers just to store the cpuset.
 118  * Seems like a waste but popular opinion opted for this 
 119  * rather than increase the size of the buffer.
 120  */
 121 #if CPUSET_SIZE > CLONGSIZE
 122         add     %o1, CPUSET_SIZE, %g5                   /* end of cpuset */
 123         clr     %o2
 124 1:
 125         TRACE_PTR(%g3, %g4)
 126         stha    %g0, [%g3 + TRAP_ENT_TL]%asi
 127         set     TT_XCALL_CONT, %g2
 128         or      %g2, %o2, %g2                           /* continuation # */
 129         stha    %g2, [%g3 + TRAP_ENT_TT]%asi
 130         stxa    %g6, [%g3 + TRAP_ENT_TICK]%asi          /* same tick */
 131         stna    %g0, [%g3 + TRAP_ENT_TPC]%asi           /* clr unused fields */
 132         stna    %g0, [%g3 + TRAP_ENT_SP]%asi
 133         stna    %g0, [%g3 + TRAP_ENT_TR]%asi
 134         stxa    %g0, [%g3 + TRAP_ENT_TSTATE]%asi
 135         stna    %g0, [%g3 + TRAP_ENT_F2]%asi
 136         stna    %g0, [%g3 + TRAP_ENT_F3]%asi
 137         stna    %g0, [%g3 + TRAP_ENT_F4]%asi
 138         ldn     [%o1], %g2
 139         stna    %g2, [%g3 + TRAP_ENT_F1]%asi
 140         add     %o1, CLONGSIZE, %o1
 141         cmp     %o1, %g5
 142         bge     2f
 143         ldn     [%o1], %g2
 144         stna    %g2, [%g3 + TRAP_ENT_F2]%asi
 145         add     %o1, CLONGSIZE, %o1
 146         cmp     %o1, %g5
 147         bge     2f
 148         ldn     [%o1], %g2
 149         stna    %g2, [%g3 + TRAP_ENT_F3]%asi
 150         add     %o1, CLONGSIZE, %o1
 151         cmp     %o1, %g5
 152         bge     2f
 153         ldn     [%o1], %g2
 154         stna    %g2, [%g3 + TRAP_ENT_F4]%asi
 155         add     %o1, CLONGSIZE, %o1
 156 2:      
 157         TRACE_NEXT(%g2, %g3, %g4)
 158         cmp     %o1, %g5
 159         bl      1b
 160         inc     %o2
 161 #endif  /* CPUSET_SIZE */
 162         retl
 163         wrpr    %g0, %g1, %pstate                       /* enable interrupts */
 164         SET_SIZE(xc_trace)
 165 
 166 #endif  /* TRAPTRACE */
 167 
 168 /*
 169  * Setup interrupt dispatch data registers
 170  * Entry:
 171  *      %o0 - function or inumber to call
 172  *      %o1, %o2 - arguments (2 uint64_t's)
 173  */
 174         ENTRY(init_mondo)
 175         ALTENTRY(init_mondo_nocheck)
 176         CPU_ADDR(%g1, %g4)                      ! load CPU struct addr
 177         add     %g1, CPU_MCPU, %g1
 178         ldx     [%g1 + MCPU_MONDO_DATA], %g1
 179         stx     %o0, [%g1]
 180         stx     %o1, [%g1+8]
 181         stx     %o2, [%g1+0x10]
 182         stx     %g0, [%g1+0x18]
 183         stx     %g0, [%g1+0x20]
 184         stx     %g0, [%g1+0x28]
 185         stx     %g0, [%g1+0x30]
 186         stx     %g0, [%g1+0x38]
 187         retl
 188         membar  #Sync                   ! allowed to be in the delay slot
 189         SET_SIZE(init_mondo)
 190 
 191 /*
 192  * Ship mondo to cpuid
 193  */
 194         ENTRY_NP(shipit)
 195         /* For now use dummy interface:  cpu# func arg1 arg2 */
 196         CPU_ADDR(%g1, %g4)
 197         add     %g1, CPU_MCPU, %g1
 198         ldx     [%g1 + MCPU_MONDO_DATA_RA],     %o2
 199         mov     HV_INTR_SEND, %o5
 200         ta      FAST_TRAP
 201         retl
 202         membar  #Sync
 203         SET_SIZE(shipit)
 204 
 205 /*
 206  * Get cpu structure
 207  * Entry:
 208  *      %o0 - register for CPU_ADDR macro
 209  *      %o1 - scratch for CPU_ADDR macro
 210  */
 211         ENTRY(get_cpuaddr)
 212         CPU_ADDR(%o0, %o1)      ! %o0 == CPU struct addr
 213         retl
 214         nop
 215         SET_SIZE(get_cpuaddr)
 216 
 217 /*
 218  * This is to ensure that previously called xtrap handlers have executed on
 219  * sun4v. We zero out the byte corresponding to its cpuid in the
 220  * array passed to us from xt_sync(), so the sender knows the previous
 221  * mondo has been executed.
 222  * Register:
 223  *              %g1 - Addr of the cpu_sync array.
 224  */
 225         ENTRY_NP(xt_sync_tl1)
 226         CPU_INDEX(%g3, %g4)             /* %g3 = cpu id */
 227         stb     %g0, [%g1 + %g3] 
 228         retry
 229         SET_SIZE(xt_sync_tl1)
 230