/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #if defined(lint) #include #include #else /*lint */ #include "assym.h" #endif /* lint */ #include #include #include #include #include #include #ifdef TRAPTRACE #include #endif /* TRAPTRACE */ #if defined(lint) /* ARGSUSED */ void self_xcall(struct cpu *cpu, uint64_t arg1, uint64_t arg2, xcfunc_t *func) {} #else /* * Entered by the software trap (TT=ST_SELFXCALL, TL>0) thru send_self_xcall(). * Emulate the mondo handler - vec_interrupt(). * * Global registers are the Alternate Globals. * Arguments: * %o0 - CPU * ILP32 kernel: * %o5 - function to call * %o1, %o2, %o3, %o4 - arguments * LP64 kernel: * %o3 - function to call * %o1, %o2 - arguments */ ENTRY_NP(self_xcall) ! ! TL>0 handlers are expected to do "retry" ! prepare their return PC and nPC now ! rdpr %tnpc, %g1 wrpr %g1, %tpc ! PC <- TNPC[TL] add %g1, 4, %g1 wrpr %g1, %tnpc ! nPC <- TNPC[TL] + 4 #ifdef TRAPTRACE TRACE_PTR(%g4, %g6) GET_TRACE_TICK(%g6) stxa %g6, [%g4 + TRAP_ENT_TICK]%asi rdpr %tl, %g6 stha %g6, [%g4 + TRAP_ENT_TL]%asi rdpr %tt, %g6 stha %g6, [%g4 + TRAP_ENT_TT]%asi stna %o3, [%g4 + TRAP_ENT_TR]%asi ! pc of the TL>0 handler rdpr %tpc, %g6 stna %g6, [%g4 + TRAP_ENT_TPC]%asi rdpr %tstate, %g6 stxa %g6, [%g4 + TRAP_ENT_TSTATE]%asi stna %sp, [%g4 + TRAP_ENT_SP]%asi stna %o1, [%g4 + TRAP_ENT_F1]%asi ! arg 1 stna %o2, [%g4 + TRAP_ENT_F2]%asi ! arg 2 stna %g0, [%g4 + TRAP_ENT_F3]%asi stna %g0, [%g4 + TRAP_ENT_F4]%asi TRACE_NEXT(%g4, %g6, %g3) #endif /* TRAPTRACE */ ! ! Load the arguments for the fast trap handler. ! mov %o1, %g1 jmp %o3 ! call the fast trap handler mov %o2, %g2 /* Not Reached */ SET_SIZE(self_xcall) #endif /* lint */ #ifdef TRAPTRACE #if defined(lint) /* ARGSUSED */ void xc_trace(u_int traptype, cpuset_t *cpu_set, xcfunc_t *func, uint64_t arg1, uint64_t arg2) {} #else /* lint */ ENTRY(xc_trace) rdpr %pstate, %g1 andn %g1, PSTATE_IE | PSTATE_AM, %g2 wrpr %g0, %g2, %pstate /* disable interrupts */ TRACE_PTR(%g3, %g4) GET_TRACE_TICK(%g6) stxa %g6, [%g3 + TRAP_ENT_TICK]%asi stha %g0, [%g3 + TRAP_ENT_TL]%asi set TT_XCALL, %g2 or %o0, %g2, %g4 stha %g4, [%g3 + TRAP_ENT_TT]%asi stna %o7, [%g3 + TRAP_ENT_TPC]%asi ldn [%o1], %g2 stna %g2, [%g3 + TRAP_ENT_SP]%asi /* sp = cpuset */ stna %o2, [%g3 + TRAP_ENT_TR]%asi /* tr = func */ stna %o3, [%g3 + TRAP_ENT_F1]%asi /* f1 = arg1 */ stna %o4, [%g3 + TRAP_ENT_F2]%asi /* f2 = arg2 */ stna %g0, [%g3 + TRAP_ENT_F3]%asi /* f3 = 0 */ stna %i7, [%g3 + TRAP_ENT_F4]%asi /* f4 = xcall caller */ stxa %g1, [%g3 + TRAP_ENT_TSTATE]%asi /* tstate = pstate */ TRACE_NEXT(%g2, %g3, %g4) /* * In the case of a cpuset of greater size than a long we * grab extra trace buffers just to store the cpuset. * Seems like a waste but popular opinion opted for this * rather than increase the size of the buffer. */ #if CPUSET_SIZE > CLONGSIZE add %o1, CPUSET_SIZE, %g5 /* end of cpuset */ clr %o2 1: TRACE_PTR(%g3, %g4) stha %g0, [%g3 + TRAP_ENT_TL]%asi set TT_XCALL_CONT, %g2 or %g2, %o2, %g2 /* continuation # */ stha %g2, [%g3 + TRAP_ENT_TT]%asi stxa %g6, [%g3 + TRAP_ENT_TICK]%asi /* same tick */ stna %g0, [%g3 + TRAP_ENT_TPC]%asi /* clr unused fields */ stna %g0, [%g3 + TRAP_ENT_SP]%asi stna %g0, [%g3 + TRAP_ENT_TR]%asi stxa %g0, [%g3 + TRAP_ENT_TSTATE]%asi stna %g0, [%g3 + TRAP_ENT_F2]%asi stna %g0, [%g3 + TRAP_ENT_F3]%asi stna %g0, [%g3 + TRAP_ENT_F4]%asi ldn [%o1], %g2 stna %g2, [%g3 + TRAP_ENT_F1]%asi add %o1, CLONGSIZE, %o1 cmp %o1, %g5 bge 2f ldn [%o1], %g2 stna %g2, [%g3 + TRAP_ENT_F2]%asi add %o1, CLONGSIZE, %o1 cmp %o1, %g5 bge 2f ldn [%o1], %g2 stna %g2, [%g3 + TRAP_ENT_F3]%asi add %o1, CLONGSIZE, %o1 cmp %o1, %g5 bge 2f ldn [%o1], %g2 stna %g2, [%g3 + TRAP_ENT_F4]%asi add %o1, CLONGSIZE, %o1 2: TRACE_NEXT(%g2, %g3, %g4) cmp %o1, %g5 bl 1b inc %o2 #endif /* CPUSET_SIZE */ retl wrpr %g0, %g1, %pstate /* enable interrupts */ SET_SIZE(xc_trace) #endif /* lint */ #endif /* TRAPTRACE */ #if defined(lint) /*ARGSUSED*/ void init_mondo(xcfunc_t *func, uint64_t arg1, uint64_t arg2) {} /*ARGSUSED*/ int shipit(int n, uint64_t cpuid) { return(0); } #else /* lint */ /* * Setup interrupt dispatch data registers * Entry: * %o0 - function or inumber to call * %o1, %o2 - arguments (2 uint64_t's) */ ENTRY(init_mondo) ALTENTRY(init_mondo_nocheck) CPU_ADDR(%g1, %g4) ! load CPU struct addr add %g1, CPU_MCPU, %g1 ldx [%g1 + MCPU_MONDO_DATA], %g1 stx %o0, [%g1] stx %o1, [%g1+8] stx %o2, [%g1+0x10] stx %g0, [%g1+0x18] stx %g0, [%g1+0x20] stx %g0, [%g1+0x28] stx %g0, [%g1+0x30] stx %g0, [%g1+0x38] retl membar #Sync ! allowed to be in the delay slot SET_SIZE(init_mondo) /* * Ship mondo to cpuid */ ENTRY_NP(shipit) /* For now use dummy interface: cpu# func arg1 arg2 */ CPU_ADDR(%g1, %g4) add %g1, CPU_MCPU, %g1 ldx [%g1 + MCPU_MONDO_DATA_RA], %o2 mov HV_INTR_SEND, %o5 ta FAST_TRAP retl membar #Sync SET_SIZE(shipit) #endif /* lint */ #if defined(lint) /*ARGSUSED*/ uint64_t get_cpuaddr(uint64_t reg, uint64_t scr) { return (0);} #else /* lint */ /* * Get cpu structure * Entry: * %o0 - register for CPU_ADDR macro * %o1 - scratch for CPU_ADDR macro */ ENTRY(get_cpuaddr) CPU_ADDR(%o0, %o1) ! %o0 == CPU struct addr retl nop SET_SIZE(get_cpuaddr) #endif /* lint */ #if defined(lint) /* ARGSUSED */ void xt_sync_tl1(uint64_t *cpu_sync_addr) {} #else /* lint */ /* * This is to ensure that previously called xtrap handlers have executed on * sun4v. We zero out the byte corresponding to its cpuid in the * array passed to us from xt_sync(), so the sender knows the previous * mondo has been executed. * Register: * %g1 - Addr of the cpu_sync array. */ ENTRY_NP(xt_sync_tl1) CPU_INDEX(%g3, %g4) /* %g3 = cpu id */ stb %g0, [%g1 + %g3] retry SET_SIZE(xt_sync_tl1) #endif /* lint */