1*7c478bd9Sstevel@tonic-gate/* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate/* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate#pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate/* 30*7c478bd9Sstevel@tonic-gate * Process switching routines. 31*7c478bd9Sstevel@tonic-gate */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate#if !defined(lint) 34*7c478bd9Sstevel@tonic-gate#include "assym.h" 35*7c478bd9Sstevel@tonic-gate#else /* lint */ 36*7c478bd9Sstevel@tonic-gate#include <sys/thread.h> 37*7c478bd9Sstevel@tonic-gate#endif /* lint */ 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate#include <sys/param.h> 40*7c478bd9Sstevel@tonic-gate#include <sys/asm_linkage.h> 41*7c478bd9Sstevel@tonic-gate#include <sys/mmu.h> 42*7c478bd9Sstevel@tonic-gate#include <sys/pcb.h> 43*7c478bd9Sstevel@tonic-gate#include <sys/machthread.h> 44*7c478bd9Sstevel@tonic-gate#include <sys/privregs.h> 45*7c478bd9Sstevel@tonic-gate#include <sys/vtrace.h> 46*7c478bd9Sstevel@tonic-gate#include <vm/hat_sfmmu.h> 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate/* 49*7c478bd9Sstevel@tonic-gate * resume(kthread_id_t) 50*7c478bd9Sstevel@tonic-gate * 51*7c478bd9Sstevel@tonic-gate * a thread can only run on one processor at a time. there 52*7c478bd9Sstevel@tonic-gate * exists a window on MPs where the current thread on one 53*7c478bd9Sstevel@tonic-gate * processor is capable of being dispatched by another processor. 54*7c478bd9Sstevel@tonic-gate * some overlap between outgoing and incoming threads can happen 55*7c478bd9Sstevel@tonic-gate * when they are the same thread. in this case where the threads 56*7c478bd9Sstevel@tonic-gate * are the same, resume() on one processor will spin on the incoming 57*7c478bd9Sstevel@tonic-gate * thread until resume() on the other processor has finished with 58*7c478bd9Sstevel@tonic-gate * the outgoing thread. 59*7c478bd9Sstevel@tonic-gate * 60*7c478bd9Sstevel@tonic-gate * The MMU context changes when the resuming thread resides in a different 61*7c478bd9Sstevel@tonic-gate * process. Kernel threads are known by resume to reside in process 0. 62*7c478bd9Sstevel@tonic-gate * The MMU context, therefore, only changes when resuming a thread in 63*7c478bd9Sstevel@tonic-gate * a process different from curproc. 64*7c478bd9Sstevel@tonic-gate * 65*7c478bd9Sstevel@tonic-gate * resume_from_intr() is called when the thread being resumed was not 66*7c478bd9Sstevel@tonic-gate * passivated by resume (e.g. was interrupted). This means that the 67*7c478bd9Sstevel@tonic-gate * resume lock is already held and that a restore context is not needed. 68*7c478bd9Sstevel@tonic-gate * Also, the MMU context is not changed on the resume in this case. 69*7c478bd9Sstevel@tonic-gate * 70*7c478bd9Sstevel@tonic-gate * resume_from_zombie() is the same as resume except the calling thread 71*7c478bd9Sstevel@tonic-gate * is a zombie and must be put on the deathrow list after the CPU is 72*7c478bd9Sstevel@tonic-gate * off the stack. 73*7c478bd9Sstevel@tonic-gate */ 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate#if defined(lint) 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate/* ARGSUSED */ 78*7c478bd9Sstevel@tonic-gatevoid 79*7c478bd9Sstevel@tonic-gateresume(kthread_id_t t) 80*7c478bd9Sstevel@tonic-gate{} 81*7c478bd9Sstevel@tonic-gate 82*7c478bd9Sstevel@tonic-gate#else /* lint */ 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate ENTRY(resume) 85*7c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! save ins and locals 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate call __dtrace_probe___sched_off__cpu ! DTrace probe 88*7c478bd9Sstevel@tonic-gate mov %i0, %o0 ! arg for DTrace probe 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate membar #Sync ! flush writebuffers 91*7c478bd9Sstevel@tonic-gate flushw ! flushes all but this window 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate stn %i7, [THREAD_REG + T_PC] ! save return address 94*7c478bd9Sstevel@tonic-gate stn %fp, [THREAD_REG + T_SP] ! save sp 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate ! 97*7c478bd9Sstevel@tonic-gate ! Save GSR (Graphics Status Register). 98*7c478bd9Sstevel@tonic-gate ! 99*7c478bd9Sstevel@tonic-gate ! Read fprs, call fp_save if FPRS_FEF set. 100*7c478bd9Sstevel@tonic-gate ! This handles floating-point state saving. 101*7c478bd9Sstevel@tonic-gate ! The fprs could be turned on by hw bcopy software, 102*7c478bd9Sstevel@tonic-gate ! *or* by fp_disabled. Handle it either way. 103*7c478bd9Sstevel@tonic-gate ! 104*7c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_LWP], %o4 ! get lwp pointer 105*7c478bd9Sstevel@tonic-gate rd %fprs, %g4 ! read fprs 106*7c478bd9Sstevel@tonic-gate brnz,pt %o4, 0f ! if user thread skip 107*7c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %i1 ! get CPU pointer 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate ! 110*7c478bd9Sstevel@tonic-gate ! kernel thread 111*7c478bd9Sstevel@tonic-gate ! 112*7c478bd9Sstevel@tonic-gate ! we save fprs at the beginning the stack so we know 113*7c478bd9Sstevel@tonic-gate ! where to check at resume time 114*7c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_STACK], %i2 115*7c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CTX], %g3 ! get ctx pointer 116*7c478bd9Sstevel@tonic-gate andcc %g4, FPRS_FEF, %g0 ! is FPRS_FEF set 117*7c478bd9Sstevel@tonic-gate bz,pt %icc, 1f ! nope, skip 118*7c478bd9Sstevel@tonic-gate st %g4, [%i2 + SA(MINFRAME) + FPU_FPRS] ! save fprs 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate ! save kernel fp state in stack 121*7c478bd9Sstevel@tonic-gate add %i2, SA(MINFRAME), %o0 ! o0 = kfpu_t ptr 122*7c478bd9Sstevel@tonic-gate rd %gsr, %g5 123*7c478bd9Sstevel@tonic-gate call fp_save 124*7c478bd9Sstevel@tonic-gate stx %g5, [%o0 + FPU_GSR] ! store GSR 125*7c478bd9Sstevel@tonic-gate ba,a,pt %icc, 1f 126*7c478bd9Sstevel@tonic-gate nop 127*7c478bd9Sstevel@tonic-gate 128*7c478bd9Sstevel@tonic-gate0: 129*7c478bd9Sstevel@tonic-gate ! user thread 130*7c478bd9Sstevel@tonic-gate ! o4 = lwp ptr 131*7c478bd9Sstevel@tonic-gate ! g4 = fprs 132*7c478bd9Sstevel@tonic-gate ! i1 = CPU ptr 133*7c478bd9Sstevel@tonic-gate ldn [%o4 + LWP_FPU], %o0 ! fp pointer 134*7c478bd9Sstevel@tonic-gate stn %fp, [THREAD_REG + T_SP] ! save sp 135*7c478bd9Sstevel@tonic-gate andcc %g4, FPRS_FEF, %g0 ! is FPRS_FEF set 136*7c478bd9Sstevel@tonic-gate st %g4, [%o0 + FPU_FPRS] ! store FPRS 137*7c478bd9Sstevel@tonic-gate#if defined(DEBUG) || defined(NEED_FPU_EXISTS) 138*7c478bd9Sstevel@tonic-gate sethi %hi(fpu_exists), %g5 139*7c478bd9Sstevel@tonic-gate ld [%g5 + %lo(fpu_exists)], %g5 140*7c478bd9Sstevel@tonic-gate brz,pn %g5, 1f 141*7c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CTX], %g3 ! get ctx pointer 142*7c478bd9Sstevel@tonic-gate#endif 143*7c478bd9Sstevel@tonic-gate bz,pt %icc, 1f ! most apps don't use fp 144*7c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CTX], %g3 ! get ctx pointer 145*7c478bd9Sstevel@tonic-gate ldn [%o4 + LWP_FPU], %o0 ! fp pointer 146*7c478bd9Sstevel@tonic-gate rd %gsr, %g5 147*7c478bd9Sstevel@tonic-gate call fp_save ! doesn't touch globals 148*7c478bd9Sstevel@tonic-gate stx %g5, [%o0 + FPU_GSR] ! store GSR 149*7c478bd9Sstevel@tonic-gate1: 150*7c478bd9Sstevel@tonic-gate ! 151*7c478bd9Sstevel@tonic-gate ! Perform context switch callback if set. 152*7c478bd9Sstevel@tonic-gate ! This handles coprocessor state saving. 153*7c478bd9Sstevel@tonic-gate ! i1 = cpu ptr 154*7c478bd9Sstevel@tonic-gate ! g3 = ctx pointer 155*7c478bd9Sstevel@tonic-gate ! 156*7c478bd9Sstevel@tonic-gate wr %g0, %g0, %fprs ! disable fpu and clear fprs 157*7c478bd9Sstevel@tonic-gate brz,pt %g3, 2f ! skip call when zero 158*7c478bd9Sstevel@tonic-gate ldn [%i0 + T_PROCP], %i3 ! delay slot - get proc pointer 159*7c478bd9Sstevel@tonic-gate call savectx 160*7c478bd9Sstevel@tonic-gate mov THREAD_REG, %o0 ! delay - arg = thread pointer 161*7c478bd9Sstevel@tonic-gate2: 162*7c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_PROCP], %i2 ! load old curproc - for mmu 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate ! 165*7c478bd9Sstevel@tonic-gate ! Temporarily switch to idle thread's stack 166*7c478bd9Sstevel@tonic-gate ! 167*7c478bd9Sstevel@tonic-gate ldn [%i1 + CPU_IDLE_THREAD], %o0 ! idle thread pointer 168*7c478bd9Sstevel@tonic-gate ldn [%o0 + T_SP], %o1 ! get onto idle thread stack 169*7c478bd9Sstevel@tonic-gate sub %o1, SA(MINFRAME), %sp ! save room for ins and locals 170*7c478bd9Sstevel@tonic-gate clr %fp 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate ! 173*7c478bd9Sstevel@tonic-gate ! Set the idle thread as the current thread 174*7c478bd9Sstevel@tonic-gate ! 175*7c478bd9Sstevel@tonic-gate mov THREAD_REG, %l3 ! save %g7 (current thread) 176*7c478bd9Sstevel@tonic-gate mov %o0, THREAD_REG ! set %g7 to idle 177*7c478bd9Sstevel@tonic-gate stn %o0, [%i1 + CPU_THREAD] ! set CPU's thread to idle 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate ! 180*7c478bd9Sstevel@tonic-gate ! Clear and unlock previous thread's t_lock 181*7c478bd9Sstevel@tonic-gate ! to allow it to be dispatched by another processor. 182*7c478bd9Sstevel@tonic-gate ! 183*7c478bd9Sstevel@tonic-gate clrb [%l3 + T_LOCK] ! clear tp->t_lock 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate ! 186*7c478bd9Sstevel@tonic-gate ! IMPORTANT: Registers at this point must be: 187*7c478bd9Sstevel@tonic-gate ! %i0 = new thread 188*7c478bd9Sstevel@tonic-gate ! %i1 = flag (non-zero if unpinning from an interrupt thread) 189*7c478bd9Sstevel@tonic-gate ! %i1 = cpu pointer 190*7c478bd9Sstevel@tonic-gate ! %i2 = old proc pointer 191*7c478bd9Sstevel@tonic-gate ! %i3 = new proc pointer 192*7c478bd9Sstevel@tonic-gate ! 193*7c478bd9Sstevel@tonic-gate ! Here we are in the idle thread, have dropped the old thread. 194*7c478bd9Sstevel@tonic-gate ! 195*7c478bd9Sstevel@tonic-gate ALTENTRY(_resume_from_idle) 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate ! SET_KCONTEXTREG(reg0, reg1, reg2, reg3, reg4, label1, label2, label3) 198*7c478bd9Sstevel@tonic-gate SET_KCONTEXTREG(%o0, %g1, %g2, %g3, %o3, l1, l2, l3) 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate cmp %i2, %i3 ! resuming the same process? 201*7c478bd9Sstevel@tonic-gate be,pt %xcc, 5f ! yes. 202*7c478bd9Sstevel@tonic-gate nop 203*7c478bd9Sstevel@tonic-gate ldx [%i3 + P_AS], %o0 ! load p->p_as 204*7c478bd9Sstevel@tonic-gate ldx [%o0 + A_HAT], %o3 ! load (p->p_as)->a_hat 205*7c478bd9Sstevel@tonic-gate ! %o3 is live until the call to sfmmu_setctx_sec below 206*7c478bd9Sstevel@tonic-gate 207*7c478bd9Sstevel@tonic-gate ! 208*7c478bd9Sstevel@tonic-gate ! update cpusran field 209*7c478bd9Sstevel@tonic-gate ! 210*7c478bd9Sstevel@tonic-gate ld [%i1 + CPU_ID], %o4 211*7c478bd9Sstevel@tonic-gate add %o3, SFMMU_CPUSRAN, %o5 212*7c478bd9Sstevel@tonic-gate CPU_INDEXTOSET(%o5, %o4, %g1) 213*7c478bd9Sstevel@tonic-gate ldx [%o5], %o2 ! o2 = cpusran field 214*7c478bd9Sstevel@tonic-gate mov 1, %g2 215*7c478bd9Sstevel@tonic-gate sllx %g2, %o4, %o4 ! o4 = bit for this cpu 216*7c478bd9Sstevel@tonic-gate andcc %o4, %o2, %g0 217*7c478bd9Sstevel@tonic-gate bnz,pn %xcc, 4f 218*7c478bd9Sstevel@tonic-gate nop 219*7c478bd9Sstevel@tonic-gate3: 220*7c478bd9Sstevel@tonic-gate or %o2, %o4, %o1 ! or in this cpu's bit mask 221*7c478bd9Sstevel@tonic-gate casx [%o5], %o2, %o1 222*7c478bd9Sstevel@tonic-gate cmp %o2, %o1 223*7c478bd9Sstevel@tonic-gate bne,a,pn %xcc, 3b 224*7c478bd9Sstevel@tonic-gate ldx [%o5], %o2 ! o2 = cpusran field 225*7c478bd9Sstevel@tonic-gate membar #LoadLoad|#StoreLoad 226*7c478bd9Sstevel@tonic-gate 227*7c478bd9Sstevel@tonic-gate ! 228*7c478bd9Sstevel@tonic-gate ! Switch to different address space. 229*7c478bd9Sstevel@tonic-gate ! 230*7c478bd9Sstevel@tonic-gate4: 231*7c478bd9Sstevel@tonic-gate rdpr %pstate, %i4 232*7c478bd9Sstevel@tonic-gate wrpr %i4, PSTATE_IE, %pstate ! disable interrupts 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate call sfmmu_setctx_sec ! switch to other ctx (maybe 0) 235*7c478bd9Sstevel@tonic-gate lduh [%o3 + SFMMU_CNUM], %o0 236*7c478bd9Sstevel@tonic-gate call sfmmu_load_mmustate ! program MMU registers 237*7c478bd9Sstevel@tonic-gate mov %o3, %o0 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate wrpr %g0, %i4, %pstate ! enable interrupts 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate5: 242*7c478bd9Sstevel@tonic-gate ! 243*7c478bd9Sstevel@tonic-gate ! spin until dispatched thread's mutex has 244*7c478bd9Sstevel@tonic-gate ! been unlocked. this mutex is unlocked when 245*7c478bd9Sstevel@tonic-gate ! it becomes safe for the thread to run. 246*7c478bd9Sstevel@tonic-gate ! 247*7c478bd9Sstevel@tonic-gate ldstub [%i0 + T_LOCK], %o0 ! lock curthread's t_lock 248*7c478bd9Sstevel@tonic-gate6: 249*7c478bd9Sstevel@tonic-gate brnz,pn %o0, 7f ! lock failed 250*7c478bd9Sstevel@tonic-gate ldx [%i0 + T_PC], %i7 ! delay - restore resuming thread's pc 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate ! 253*7c478bd9Sstevel@tonic-gate ! Fix CPU structure to indicate new running thread. 254*7c478bd9Sstevel@tonic-gate ! Set pointer in new thread to the CPU structure. 255*7c478bd9Sstevel@tonic-gate ! XXX - Move migration statistic out of here 256*7c478bd9Sstevel@tonic-gate ! 257*7c478bd9Sstevel@tonic-gate ldx [%i0 + T_CPU], %g2 ! last CPU to run the new thread 258*7c478bd9Sstevel@tonic-gate cmp %g2, %i1 ! test for migration 259*7c478bd9Sstevel@tonic-gate be,pt %xcc, 4f ! no migration 260*7c478bd9Sstevel@tonic-gate ldn [%i0 + T_LWP], %o1 ! delay - get associated lwp (if any) 261*7c478bd9Sstevel@tonic-gate ldx [%i1 + CPU_STATS_SYS_CPUMIGRATE], %g2 262*7c478bd9Sstevel@tonic-gate inc %g2 263*7c478bd9Sstevel@tonic-gate stx %g2, [%i1 + CPU_STATS_SYS_CPUMIGRATE] 264*7c478bd9Sstevel@tonic-gate stx %i1, [%i0 + T_CPU] ! set new thread's CPU pointer 265*7c478bd9Sstevel@tonic-gate4: 266*7c478bd9Sstevel@tonic-gate stx %i0, [%i1 + CPU_THREAD] ! set CPU's thread pointer 267*7c478bd9Sstevel@tonic-gate membar #StoreLoad ! synchronize with mutex_exit() 268*7c478bd9Sstevel@tonic-gate mov %i0, THREAD_REG ! update global thread register 269*7c478bd9Sstevel@tonic-gate stx %o1, [%i1 + CPU_LWP] ! set CPU's lwp ptr 270*7c478bd9Sstevel@tonic-gate brz,a,pn %o1, 1f ! if no lwp, branch and clr mpcb 271*7c478bd9Sstevel@tonic-gate stx %g0, [%i1 + CPU_MPCB] 272*7c478bd9Sstevel@tonic-gate ! 273*7c478bd9Sstevel@tonic-gate ! user thread 274*7c478bd9Sstevel@tonic-gate ! o1 = lwp 275*7c478bd9Sstevel@tonic-gate ! i0 = new thread 276*7c478bd9Sstevel@tonic-gate ! 277*7c478bd9Sstevel@tonic-gate ldx [%i0 + T_STACK], %o0 278*7c478bd9Sstevel@tonic-gate stx %o0, [%i1 + CPU_MPCB] ! set CPU's mpcb pointer 279*7c478bd9Sstevel@tonic-gate#ifdef CPU_MPCB_PA 280*7c478bd9Sstevel@tonic-gate ldx [%o0 + MPCB_PA], %o0 281*7c478bd9Sstevel@tonic-gate stx %o0, [%i1 + CPU_MPCB_PA] 282*7c478bd9Sstevel@tonic-gate#endif 283*7c478bd9Sstevel@tonic-gate ! Switch to new thread's stack 284*7c478bd9Sstevel@tonic-gate ldx [%i0 + T_SP], %o0 ! restore resuming thread's sp 285*7c478bd9Sstevel@tonic-gate sub %o0, SA(MINFRAME), %sp ! in case of intr or trap before restore 286*7c478bd9Sstevel@tonic-gate mov %o0, %fp 287*7c478bd9Sstevel@tonic-gate ! 288*7c478bd9Sstevel@tonic-gate ! Restore resuming thread's GSR reg and floating-point regs 289*7c478bd9Sstevel@tonic-gate ! Note that the ld to the gsr register ensures that the loading of 290*7c478bd9Sstevel@tonic-gate ! the floating point saved state has completed without necessity 291*7c478bd9Sstevel@tonic-gate ! of a membar #Sync. 292*7c478bd9Sstevel@tonic-gate ! 293*7c478bd9Sstevel@tonic-gate#if defined(DEBUG) || defined(NEED_FPU_EXISTS) 294*7c478bd9Sstevel@tonic-gate sethi %hi(fpu_exists), %g3 295*7c478bd9Sstevel@tonic-gate ld [%g3 + %lo(fpu_exists)], %g3 296*7c478bd9Sstevel@tonic-gate brz,pn %g3, 2f 297*7c478bd9Sstevel@tonic-gate ldx [%i0 + T_CTX], %i5 ! should resumed thread restorectx? 298*7c478bd9Sstevel@tonic-gate#endif 299*7c478bd9Sstevel@tonic-gate ldx [%o1 + LWP_FPU], %o0 ! fp pointer 300*7c478bd9Sstevel@tonic-gate ld [%o0 + FPU_FPRS], %g5 ! get fpu_fprs 301*7c478bd9Sstevel@tonic-gate andcc %g5, FPRS_FEF, %g0 ! is FPRS_FEF set? 302*7c478bd9Sstevel@tonic-gate bz,a,pt %icc, 9f ! no, skip fp_restore 303*7c478bd9Sstevel@tonic-gate wr %g0, FPRS_FEF, %fprs ! enable fprs so fp_zero works 304*7c478bd9Sstevel@tonic-gate 305*7c478bd9Sstevel@tonic-gate ldx [THREAD_REG + T_CPU], %o4 ! cpu pointer 306*7c478bd9Sstevel@tonic-gate call fp_restore 307*7c478bd9Sstevel@tonic-gate wr %g5, %g0, %fprs ! enable fpu and restore fprs 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate ldx [%o0 + FPU_GSR], %g5 ! load saved GSR data 310*7c478bd9Sstevel@tonic-gate wr %g5, %g0, %gsr ! restore %gsr data 311*7c478bd9Sstevel@tonic-gate ba,pt %icc,2f 312*7c478bd9Sstevel@tonic-gate ldx [%i0 + T_CTX], %i5 ! should resumed thread restorectx? 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate9: 315*7c478bd9Sstevel@tonic-gate ! 316*7c478bd9Sstevel@tonic-gate ! Zero resuming thread's fp registers, for *all* non-fp program 317*7c478bd9Sstevel@tonic-gate ! Remove all possibility of using the fp regs as a "covert channel". 318*7c478bd9Sstevel@tonic-gate ! 319*7c478bd9Sstevel@tonic-gate call fp_zero 320*7c478bd9Sstevel@tonic-gate wr %g0, %g0, %gsr 321*7c478bd9Sstevel@tonic-gate ldx [%i0 + T_CTX], %i5 ! should resumed thread restorectx? 322*7c478bd9Sstevel@tonic-gate ba,pt %icc, 2f 323*7c478bd9Sstevel@tonic-gate wr %g0, %g0, %fprs ! disable fprs 324*7c478bd9Sstevel@tonic-gate 325*7c478bd9Sstevel@tonic-gate1: 326*7c478bd9Sstevel@tonic-gate#ifdef CPU_MPCB_PA 327*7c478bd9Sstevel@tonic-gate mov -1, %o1 328*7c478bd9Sstevel@tonic-gate stx %o1, [%i1 + CPU_MPCB_PA] 329*7c478bd9Sstevel@tonic-gate#endif 330*7c478bd9Sstevel@tonic-gate ! 331*7c478bd9Sstevel@tonic-gate ! kernel thread 332*7c478bd9Sstevel@tonic-gate ! i0 = new thread 333*7c478bd9Sstevel@tonic-gate ! 334*7c478bd9Sstevel@tonic-gate ! Switch to new thread's stack 335*7c478bd9Sstevel@tonic-gate ! 336*7c478bd9Sstevel@tonic-gate ldx [%i0 + T_SP], %o0 ! restore resuming thread's sp 337*7c478bd9Sstevel@tonic-gate sub %o0, SA(MINFRAME), %sp ! in case of intr or trap before restore 338*7c478bd9Sstevel@tonic-gate mov %o0, %fp 339*7c478bd9Sstevel@tonic-gate ! 340*7c478bd9Sstevel@tonic-gate ! Restore resuming thread's GSR reg and floating-point regs 341*7c478bd9Sstevel@tonic-gate ! Note that the ld to the gsr register ensures that the loading of 342*7c478bd9Sstevel@tonic-gate ! the floating point saved state has completed without necessity 343*7c478bd9Sstevel@tonic-gate ! of a membar #Sync. 344*7c478bd9Sstevel@tonic-gate ! 345*7c478bd9Sstevel@tonic-gate ldx [%i0 + T_STACK], %o0 346*7c478bd9Sstevel@tonic-gate ld [%o0 + SA(MINFRAME) + FPU_FPRS], %g5 ! load fprs 347*7c478bd9Sstevel@tonic-gate ldx [%i0 + T_CTX], %i5 ! should thread restorectx? 348*7c478bd9Sstevel@tonic-gate andcc %g5, FPRS_FEF, %g0 ! did we save fp in stack? 349*7c478bd9Sstevel@tonic-gate bz,a,pt %icc, 2f 350*7c478bd9Sstevel@tonic-gate wr %g0, %g0, %fprs ! clr fprs 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate wr %g5, %g0, %fprs ! enable fpu and restore fprs 353*7c478bd9Sstevel@tonic-gate call fp_restore 354*7c478bd9Sstevel@tonic-gate add %o0, SA(MINFRAME), %o0 ! o0 = kpu_t ptr 355*7c478bd9Sstevel@tonic-gate ldx [%o0 + FPU_GSR], %g5 ! load saved GSR data 356*7c478bd9Sstevel@tonic-gate wr %g5, %g0, %gsr ! restore %gsr data 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate2: 359*7c478bd9Sstevel@tonic-gate ! 360*7c478bd9Sstevel@tonic-gate ! Restore resuming thread's context 361*7c478bd9Sstevel@tonic-gate ! i5 = ctx ptr 362*7c478bd9Sstevel@tonic-gate ! 363*7c478bd9Sstevel@tonic-gate brz,a,pt %i5, 8f ! skip restorectx() when zero 364*7c478bd9Sstevel@tonic-gate ld [%i1 + CPU_BASE_SPL], %o0 365*7c478bd9Sstevel@tonic-gate call restorectx ! thread can not sleep on temp stack 366*7c478bd9Sstevel@tonic-gate mov THREAD_REG, %o0 ! delay slot - arg = thread pointer 367*7c478bd9Sstevel@tonic-gate ! 368*7c478bd9Sstevel@tonic-gate ! Set priority as low as possible, blocking all interrupt threads 369*7c478bd9Sstevel@tonic-gate ! that may be active. 370*7c478bd9Sstevel@tonic-gate ! 371*7c478bd9Sstevel@tonic-gate ld [%i1 + CPU_BASE_SPL], %o0 372*7c478bd9Sstevel@tonic-gate8: 373*7c478bd9Sstevel@tonic-gate wrpr %o0, 0, %pil 374*7c478bd9Sstevel@tonic-gate wrpr %g0, WSTATE_KERN, %wstate 375*7c478bd9Sstevel@tonic-gate ! 376*7c478bd9Sstevel@tonic-gate ! If we are resuming an interrupt thread, store a starting timestamp 377*7c478bd9Sstevel@tonic-gate ! in the thread structure. 378*7c478bd9Sstevel@tonic-gate ! 379*7c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o0 380*7c478bd9Sstevel@tonic-gate andcc %o0, T_INTR_THREAD, %g0 381*7c478bd9Sstevel@tonic-gate bnz,pn %xcc, 0f 382*7c478bd9Sstevel@tonic-gate nop 383*7c478bd9Sstevel@tonic-gate5: 384*7c478bd9Sstevel@tonic-gate call __dtrace_probe___sched_on__cpu ! DTrace probe 385*7c478bd9Sstevel@tonic-gate nop 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate ret ! resume curthread 388*7c478bd9Sstevel@tonic-gate restore 389*7c478bd9Sstevel@tonic-gate0: 390*7c478bd9Sstevel@tonic-gate add THREAD_REG, T_INTR_START, %o2 391*7c478bd9Sstevel@tonic-gate1: 392*7c478bd9Sstevel@tonic-gate ldx [%o2], %o1 393*7c478bd9Sstevel@tonic-gate rdpr %tick, %o0 394*7c478bd9Sstevel@tonic-gate sllx %o0, 1, %o0 395*7c478bd9Sstevel@tonic-gate srlx %o0, 1, %o0 ! shift off NPT bit 396*7c478bd9Sstevel@tonic-gate casx [%o2], %o1, %o0 397*7c478bd9Sstevel@tonic-gate cmp %o0, %o1 398*7c478bd9Sstevel@tonic-gate be,pt %xcc, 5b 399*7c478bd9Sstevel@tonic-gate nop 400*7c478bd9Sstevel@tonic-gate ! If an interrupt occurred while we were attempting to store 401*7c478bd9Sstevel@tonic-gate ! the timestamp, try again. 402*7c478bd9Sstevel@tonic-gate ba,pt %xcc, 1b 403*7c478bd9Sstevel@tonic-gate nop 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate ! 406*7c478bd9Sstevel@tonic-gate ! lock failed - spin with regular load to avoid cache-thrashing. 407*7c478bd9Sstevel@tonic-gate ! 408*7c478bd9Sstevel@tonic-gate7: 409*7c478bd9Sstevel@tonic-gate brnz,a,pt %o0, 7b ! spin while locked 410*7c478bd9Sstevel@tonic-gate ldub [%i0 + T_LOCK], %o0 411*7c478bd9Sstevel@tonic-gate ba %xcc, 6b 412*7c478bd9Sstevel@tonic-gate ldstub [%i0 + T_LOCK], %o0 ! delay - lock curthread's mutex 413*7c478bd9Sstevel@tonic-gate SET_SIZE(_resume_from_idle) 414*7c478bd9Sstevel@tonic-gate SET_SIZE(resume) 415*7c478bd9Sstevel@tonic-gate 416*7c478bd9Sstevel@tonic-gate#endif /* lint */ 417*7c478bd9Sstevel@tonic-gate 418*7c478bd9Sstevel@tonic-gate#if defined(lint) 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate/* ARGSUSED */ 421*7c478bd9Sstevel@tonic-gatevoid 422*7c478bd9Sstevel@tonic-gateresume_from_zombie(kthread_id_t t) 423*7c478bd9Sstevel@tonic-gate{} 424*7c478bd9Sstevel@tonic-gate 425*7c478bd9Sstevel@tonic-gate#else /* lint */ 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate ENTRY(resume_from_zombie) 428*7c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! save ins and locals 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate call __dtrace_probe___sched_off__cpu ! DTrace probe 431*7c478bd9Sstevel@tonic-gate mov %i0, %o0 ! arg for DTrace probe 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %i1 ! cpu pointer 434*7c478bd9Sstevel@tonic-gate 435*7c478bd9Sstevel@tonic-gate flushw ! flushes all but this window 436*7c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_PROCP], %i2 ! old procp for mmu ctx 437*7c478bd9Sstevel@tonic-gate 438*7c478bd9Sstevel@tonic-gate ! 439*7c478bd9Sstevel@tonic-gate ! Temporarily switch to the idle thread's stack so that 440*7c478bd9Sstevel@tonic-gate ! the zombie thread's stack can be reclaimed by the reaper. 441*7c478bd9Sstevel@tonic-gate ! 442*7c478bd9Sstevel@tonic-gate ldn [%i1 + CPU_IDLE_THREAD], %o2 ! idle thread pointer 443*7c478bd9Sstevel@tonic-gate ldn [%o2 + T_SP], %o1 ! get onto idle thread stack 444*7c478bd9Sstevel@tonic-gate sub %o1, SA(MINFRAME), %sp ! save room for ins and locals 445*7c478bd9Sstevel@tonic-gate clr %fp 446*7c478bd9Sstevel@tonic-gate ! 447*7c478bd9Sstevel@tonic-gate ! Set the idle thread as the current thread. 448*7c478bd9Sstevel@tonic-gate ! Put the zombie on death-row. 449*7c478bd9Sstevel@tonic-gate ! 450*7c478bd9Sstevel@tonic-gate mov THREAD_REG, %o0 ! save %g7 = curthread for arg 451*7c478bd9Sstevel@tonic-gate mov %o2, THREAD_REG ! set %g7 to idle 452*7c478bd9Sstevel@tonic-gate stn %g0, [%i1 + CPU_MPCB] ! clear mpcb 453*7c478bd9Sstevel@tonic-gate#ifdef CPU_MPCB_PA 454*7c478bd9Sstevel@tonic-gate mov -1, %o1 455*7c478bd9Sstevel@tonic-gate stx %o1, [%i1 + CPU_MPCB_PA] 456*7c478bd9Sstevel@tonic-gate#endif 457*7c478bd9Sstevel@tonic-gate call reapq_add ! reapq_add(old_thread); 458*7c478bd9Sstevel@tonic-gate stn %o2, [%i1 + CPU_THREAD] ! delay - CPU's thread = idle 459*7c478bd9Sstevel@tonic-gate 460*7c478bd9Sstevel@tonic-gate ! 461*7c478bd9Sstevel@tonic-gate ! resume_from_idle args: 462*7c478bd9Sstevel@tonic-gate ! %i0 = new thread 463*7c478bd9Sstevel@tonic-gate ! %i1 = cpu 464*7c478bd9Sstevel@tonic-gate ! %i2 = old proc 465*7c478bd9Sstevel@tonic-gate ! %i3 = new proc 466*7c478bd9Sstevel@tonic-gate ! 467*7c478bd9Sstevel@tonic-gate b _resume_from_idle ! finish job of resume 468*7c478bd9Sstevel@tonic-gate ldn [%i0 + T_PROCP], %i3 ! new process 469*7c478bd9Sstevel@tonic-gate SET_SIZE(resume_from_zombie) 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate#endif /* lint */ 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate#if defined(lint) 474*7c478bd9Sstevel@tonic-gate 475*7c478bd9Sstevel@tonic-gate/* ARGSUSED */ 476*7c478bd9Sstevel@tonic-gatevoid 477*7c478bd9Sstevel@tonic-gateresume_from_intr(kthread_id_t t) 478*7c478bd9Sstevel@tonic-gate{} 479*7c478bd9Sstevel@tonic-gate 480*7c478bd9Sstevel@tonic-gate#else /* lint */ 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate ENTRY(resume_from_intr) 483*7c478bd9Sstevel@tonic-gate save %sp, -SA(MINFRAME), %sp ! save ins and locals 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate flushw ! flushes all but this window 486*7c478bd9Sstevel@tonic-gate stn %fp, [THREAD_REG + T_SP] ! delay - save sp 487*7c478bd9Sstevel@tonic-gate stn %i7, [THREAD_REG + T_PC] ! save return address 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate ldn [%i0 + T_PC], %i7 ! restore resuming thread's pc 490*7c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_CPU], %i1 ! cpu pointer 491*7c478bd9Sstevel@tonic-gate 492*7c478bd9Sstevel@tonic-gate ! 493*7c478bd9Sstevel@tonic-gate ! Fix CPU structure to indicate new running thread. 494*7c478bd9Sstevel@tonic-gate ! The pinned thread we're resuming already has the CPU pointer set. 495*7c478bd9Sstevel@tonic-gate ! 496*7c478bd9Sstevel@tonic-gate mov THREAD_REG, %l3 ! save old thread 497*7c478bd9Sstevel@tonic-gate stn %i0, [%i1 + CPU_THREAD] ! set CPU's thread pointer 498*7c478bd9Sstevel@tonic-gate membar #StoreLoad ! synchronize with mutex_exit() 499*7c478bd9Sstevel@tonic-gate mov %i0, THREAD_REG ! update global thread register 500*7c478bd9Sstevel@tonic-gate 501*7c478bd9Sstevel@tonic-gate ! 502*7c478bd9Sstevel@tonic-gate ! Switch to new thread's stack 503*7c478bd9Sstevel@tonic-gate ! 504*7c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_SP], %o0 ! restore resuming thread's sp 505*7c478bd9Sstevel@tonic-gate sub %o0, SA(MINFRAME), %sp ! in case of intr or trap before restore 506*7c478bd9Sstevel@tonic-gate mov %o0, %fp 507*7c478bd9Sstevel@tonic-gate clrb [%l3 + T_LOCK] ! clear intr thread's tp->t_lock 508*7c478bd9Sstevel@tonic-gate 509*7c478bd9Sstevel@tonic-gate ! 510*7c478bd9Sstevel@tonic-gate ! If we are resuming an interrupt thread, store a timestamp in the 511*7c478bd9Sstevel@tonic-gate ! thread structure. 512*7c478bd9Sstevel@tonic-gate ! 513*7c478bd9Sstevel@tonic-gate lduh [THREAD_REG + T_FLAGS], %o0 514*7c478bd9Sstevel@tonic-gate andcc %o0, T_INTR_THREAD, %g0 515*7c478bd9Sstevel@tonic-gate bnz,pn %xcc, 0f 516*7c478bd9Sstevel@tonic-gate ! 517*7c478bd9Sstevel@tonic-gate ! We're resuming a non-interrupt thread. 518*7c478bd9Sstevel@tonic-gate ! Clear CPU_INTRCNT and check if cpu_kprunrun set? 519*7c478bd9Sstevel@tonic-gate ! 520*7c478bd9Sstevel@tonic-gate ldub [%i1 + CPU_KPRUNRUN], %o5 ! delay 521*7c478bd9Sstevel@tonic-gate brnz,pn %o5, 3f ! call kpreempt(KPREEMPT_SYNC); 522*7c478bd9Sstevel@tonic-gate stub %g0, [%i1 + CPU_INTRCNT] 523*7c478bd9Sstevel@tonic-gate1: 524*7c478bd9Sstevel@tonic-gate ret ! resume curthread 525*7c478bd9Sstevel@tonic-gate restore 526*7c478bd9Sstevel@tonic-gate0: 527*7c478bd9Sstevel@tonic-gate ! 528*7c478bd9Sstevel@tonic-gate ! We're an interrupt thread. Update t_intr_start and cpu_intrcnt 529*7c478bd9Sstevel@tonic-gate ! 530*7c478bd9Sstevel@tonic-gate add THREAD_REG, T_INTR_START, %o2 531*7c478bd9Sstevel@tonic-gate2: 532*7c478bd9Sstevel@tonic-gate ldx [%o2], %o1 533*7c478bd9Sstevel@tonic-gate rdpr %tick, %o0 534*7c478bd9Sstevel@tonic-gate sllx %o0, 1, %o0 535*7c478bd9Sstevel@tonic-gate srlx %o0, 1, %o0 ! shift off NPT bit 536*7c478bd9Sstevel@tonic-gate casx [%o2], %o1, %o0 537*7c478bd9Sstevel@tonic-gate cmp %o0, %o1 538*7c478bd9Sstevel@tonic-gate bne,pn %xcc, 2b 539*7c478bd9Sstevel@tonic-gate ldn [THREAD_REG + T_INTR], %l1 ! delay 540*7c478bd9Sstevel@tonic-gate ! Reset cpu_intrcnt if we aren't pinning anyone 541*7c478bd9Sstevel@tonic-gate brz,a,pt %l1, 2f 542*7c478bd9Sstevel@tonic-gate stub %g0, [%i1 + CPU_INTRCNT] 543*7c478bd9Sstevel@tonic-gate2: 544*7c478bd9Sstevel@tonic-gate ba,pt %xcc, 1b 545*7c478bd9Sstevel@tonic-gate nop 546*7c478bd9Sstevel@tonic-gate3: 547*7c478bd9Sstevel@tonic-gate ! 548*7c478bd9Sstevel@tonic-gate ! We're a non-interrupt thread and cpu_kprunrun is set. call kpreempt. 549*7c478bd9Sstevel@tonic-gate ! 550*7c478bd9Sstevel@tonic-gate call kpreempt 551*7c478bd9Sstevel@tonic-gate mov KPREEMPT_SYNC, %o0 552*7c478bd9Sstevel@tonic-gate ba,pt %xcc, 1b 553*7c478bd9Sstevel@tonic-gate nop 554*7c478bd9Sstevel@tonic-gate SET_SIZE(resume_from_intr) 555*7c478bd9Sstevel@tonic-gate 556*7c478bd9Sstevel@tonic-gate#endif /* lint */ 557*7c478bd9Sstevel@tonic-gate 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate/* 560*7c478bd9Sstevel@tonic-gate * thread_start() 561*7c478bd9Sstevel@tonic-gate * 562*7c478bd9Sstevel@tonic-gate * the current register window was crafted by thread_run() to contain 563*7c478bd9Sstevel@tonic-gate * an address of a procedure (in register %i7), and its args in registers 564*7c478bd9Sstevel@tonic-gate * %i0 through %i5. a stack trace of this thread will show the procedure 565*7c478bd9Sstevel@tonic-gate * that thread_start() invoked at the bottom of the stack. an exit routine 566*7c478bd9Sstevel@tonic-gate * is stored in %l0 and called when started thread returns from its called 567*7c478bd9Sstevel@tonic-gate * procedure. 568*7c478bd9Sstevel@tonic-gate */ 569*7c478bd9Sstevel@tonic-gate 570*7c478bd9Sstevel@tonic-gate#if defined(lint) 571*7c478bd9Sstevel@tonic-gate 572*7c478bd9Sstevel@tonic-gatevoid 573*7c478bd9Sstevel@tonic-gatethread_start(void) 574*7c478bd9Sstevel@tonic-gate{} 575*7c478bd9Sstevel@tonic-gate 576*7c478bd9Sstevel@tonic-gate#else /* lint */ 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate ENTRY(thread_start) 579*7c478bd9Sstevel@tonic-gate mov %i0, %o0 580*7c478bd9Sstevel@tonic-gate jmpl %i7, %o7 ! call thread_run()'s start() procedure. 581*7c478bd9Sstevel@tonic-gate mov %i1, %o1 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate call thread_exit ! destroy thread if it returns. 584*7c478bd9Sstevel@tonic-gate nop 585*7c478bd9Sstevel@tonic-gate unimp 0 586*7c478bd9Sstevel@tonic-gate SET_SIZE(thread_start) 587*7c478bd9Sstevel@tonic-gate 588*7c478bd9Sstevel@tonic-gate#endif /* lint */ 589