1/* $NetBSD: locore_subr.S,v 1.5 2002/07/28 07:05:06 chs Exp $ */ 2 3/* 4 * Copyright (C) 1995, 1996 Wolfgang Solfrank. 5 * Copyright (C) 1995, 1996 TooLs GmbH. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by TooLs GmbH. 19 * 4. The name of TooLs GmbH may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34/* 35 * NOTICE: This is not a standalone file. to use it, #include it in 36 * your port's locore.S, like so: 37 * 38 * #include <powerpc/powerpc/locore_subr.S> 39 */ 40 41 .data 42GLOBAL(powersave) 43 .long -1 44 45 .text 46/* 47 * No processes are runnable, so loop waiting for one. 48 * Separate label here for accounting purposes. 49 * When we get here, interrupts are off (MSR[EE]=0) and sched_lock is held. 50 */ 51ASENTRY(Idle) 52 lis 8,_C_LABEL(sched_whichqs)@ha 53 lwz 9,_C_LABEL(sched_whichqs)@l(8) 54 55 or. 9,9,9 56 bne+ .Lsw1 /* at least one queue non-empty */ 57 58#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 59 bl _C_LABEL(sched_unlock_idle) 60#endif 61 62 mfmsr 3 63 ori 3,3,PSL_EE@l /* reenable ints again */ 64 mtmsr 3 65 isync 66 67/* Check if we can use power saving mode */ 68 lis 8,_C_LABEL(powersave)@ha 69 lwz 9,_C_LABEL(powersave)@l(8) 70 71 add. 9,9,9 72 ble 1f 73 74 sync 75 oris 3,3,PSL_POW@h /* enter power saving mode */ 76 mtmsr 3 77 isync 781: 79 andi. 3,3,~PSL_EE@l /* disable interrupts while 80 manipulating runque */ 81 mtmsr 3 82#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 83 bl _C_LABEL(sched_lock_idle) 84#endif 85 b _ASM_LABEL(Idle) 86 87/* 88 * switchexit gets called from cpu_exit to complete the exit procedure. 89 */ 90ENTRY(switchexit) 91/* First switch to the idle pcb/kernel stack */ 92#if defined(MULTIPROCESSOR) 93 GET_CPUINFO(7) 94 lwz 6,CI_IDLE_PCB(7) 95 stw 6,CI_CURPCB(7) 96#else 97 lis 6,idle_u@ha 98 lwz 6,idle_u@l(6) 99 lis 7,_C_LABEL(curpcb)@ha 100 stw 6,_C_LABEL(curpcb)@l(7) 101#endif 102 addi 1,6,USPACE-16 /* 16 bytes are reserved at stack top */ 103 /* 104 * Schedule the vmspace and stack to be freed (the proc arg is 105 * already in r3). 106 */ 107 bl _C_LABEL(exit2) 108 109#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 110 bl _C_LABEL(sched_lock_idle) 111#endif 112 113/* Fall through to cpu_switch to actually select another proc */ 114 li 3,0 /* indicate exited process */ 115 116/* 117 * void cpu_switch(struct proc *p) 118 * Find a runnable process and switch to it. 119 */ 120ENTRY_NOPROFILE(cpu_switch) 121 mflr 0 /* save lr */ 122 stw 0,4(1) 123 stwu 1,-16(1) 124 stw 31,12(1) 125 stw 30,8(1) 126 127 mr 30,3 128#if defined(MULTIPROCESSOR) 129 /* Switch to the idle PCB unless we're already running on it. */ 130 GET_CPUINFO(7) 131 cmpwi 30,0 /* old process was exiting? */ 132 beq 1f 133 134 mfsr 10,USER_SR /* save USER_SR for copyin/copyout */ 135 mfcr 11 /* save cr */ 136 mr 12,2 /* save r2 */ 137 stwu 1,-SFRAMELEN(1) /* still running on old stack */ 138 stmw 10,8(1) 139 lwz 3,P_ADDR(30) 140 stw 1,PCB_SP(3) /* save SP */ 141 142 lwz 6,CI_IDLE_PCB(7) 143 addi 1,6,USPACE-16 /* 16 bytes are reserved at stack top */ 144 1451: 146 xor 31,31,31 147 stw 31,CI_CURPROC(7) /* Zero to not accumulate cpu time */ 148 lwz 31,CI_CURPCB(7) 149 150 lwz 3,CI_CPL(7) 151 stw 3,PCB_SPL(31) /* save spl */ 152#else 153 lis 3,_C_LABEL(curproc)@ha 154 xor 31,31,31 155 stw 31,_C_LABEL(curproc)@l(3) /* Zero to not accumulate cpu time */ 156 lis 3,_C_LABEL(curpcb)@ha 157 lwz 31,_C_LABEL(curpcb)@l(3) 158#endif 159 160#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 161/* Release the sched_lock before processing interrupts. */ 162 bl _C_LABEL(sched_unlock_idle) 163#endif 164 165 xor 3,3,3 /* spl0() */ 166 bl _C_LABEL(lcsplx) 167#if !defined(MULTIPROCESSOR) 168 stw 3,PCB_SPL(31) /* save spl */ 169#endif 170 171/* Lock the scheduler. */ 172 mfmsr 3 173 andi. 3,3,~PSL_EE@l /* disable interrupts while 174 manipulating runque */ 175 mtmsr 3 176 isync 177#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 178 bl _C_LABEL(sched_lock_idle) 179#endif 180 181/* Find a new process */ 182 lis 8,_C_LABEL(sched_whichqs)@ha 183 lwz 9,_C_LABEL(sched_whichqs)@l(8) 184 185 or. 9,9,9 186 beq- _ASM_LABEL(Idle) /* all queues empty */ 187.Lsw1: 188 cntlzw 10,9 189 lis 4,_C_LABEL(sched_qs)@ha 190 addi 4,4,_C_LABEL(sched_qs)@l 191 slwi 3,10,3 192 add 3,3,4 /* select queue */ 193 194 lwz 31,P_FORW(3) /* unlink first proc from queue */ 195 lwz 4,P_FORW(31) 196 stw 4,P_FORW(3) 197 stw 3,P_BACK(4) 198 199 cmpl 0,3,4 /* queue empty? */ 200 bne 1f 201 202 lis 3,0x80000000@h 203 srw 3,3,10 204 andc 9,9,3 205 stw 9,_C_LABEL(sched_whichqs)@l(8) /* mark it empty */ 206 2071: 208 /* just did this resched thing */ 209 xor 3,3,3 210#if defined(MULTIPROCESSOR) 211 GET_CPUINFO(4) 212 stw 3,CI_WANT_RESCHED(4) 213#else 214 lis 4,_C_LABEL(want_resched)@ha 215 stw 3,_C_LABEL(want_resched)@l(4) 216#endif 217 218 stw 3,P_BACK(31) /* probably superfluous */ 219 220#if defined(MULTIPROCESSOR) 221 GET_CPUINFO(4) 222 stw 4,P_CPU(31) /* p->p_cpu = curcpu() */ 223#endif 224 225 /* Process now running on a processor. */ 226 li 3,SONPROC /* p->p_stat = SONPROC */ 227 stb 3,P_STAT(31) 228 229 /* record new process */ 230#if defined(MULTIPROCESSOR) 231 stw 31,CI_CURPROC(4) 232#else 233 lis 4,_C_LABEL(curproc)@ha 234 stw 31,_C_LABEL(curproc)@l(4) 235#endif 236 lwz 4,P_ADDR(31) 237 238#if !defined(MULTIPROCESSOR) /* XXX */ 239 cmpl 0,31,30 /* is it the same process? */ 240 beq switch_return 241 242 or. 30,30,30 /* old process was exiting? */ 243 beq switch_exited 244 245 mfsr 10,USER_SR /* save USER_SR for copyin/copyout */ 246 mfcr 11 /* save cr */ 247 mr 12,2 /* save r2 */ 248 stwu 1,-SFRAMELEN(1) /* still running on old stack */ 249 stmw 10,8(1) 250 lwz 3,P_ADDR(30) 251 stw 1,PCB_SP(3) /* save SP */ 252 253switch_exited: 254#endif 255 256 /* indicate new pcb */ 257#if defined(MULTIPROCESSOR) 258 GET_CPUINFO(6) 259 stw 4,CI_CURPCB(6) 260#else 261 lis 5,_C_LABEL(curpcb)@ha 262 stw 4,_C_LABEL(curpcb)@l(5) 263#endif 264 265 /* save real pmap pointer for spill fill */ 266 lwz 5,PCB_PMR(4) 267#if defined(MULTIPROCESSOR) 268 stwu 5,CI_CURPM(6) 269#else 270 lis 6,_C_LABEL(curpm)@ha 271 stwu 5,_C_LABEL(curpm)@l(6) 272#endif 273 stwcx. 5,0,6 /* clear possible reservation */ 274 isync 275 276 lwz 1,PCB_SP(4) /* get new procs SP */ 277 lmw 10,8(1) /* get other regs */ 278 lwz 1,0(1) /* get saved SP */ 279 mr 2,12 /* get saved r2 */ 280 mtcr 11 /* get saved cr */ 281 isync 282 mtsr USER_SR,10 /* get saved USER_SR */ 283 isync 284 285switch_return: 286#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 287 /* Unlock the sched_lock, but leave interrupts off, for now. */ 288 bl _C_LABEL(sched_unlock_idle) 289#endif 290 291 mfmsr 3 292 ori 3,3,PSL_EE@l /* interrupts are okay again */ 293 mtmsr 3 294 295 mr 30,7 /* save proc pointer */ 296 lwz 3,PCB_SPL(4) 297 bl _C_LABEL(lcsplx) 298 299 mr 3,30 /* get curproc for special fork 300 returns */ 301 302 lwz 31,12(1) 303 lwz 30,8(1) 304 addi 1,1,16 305 lwz 0,4(1) 306 mtlr 0 307 blr 308 309/* 310 * Child comes here at the end of a fork. 311 * Return to userspace via the trap return path. 312 */ 313 .globl _C_LABEL(fork_trampoline) 314_C_LABEL(fork_trampoline): 315#if defined(MULTIPROCESSOR) 316 bl _C_LABEL(proc_trampoline_mp) 317#endif 318 xor 3,3,3 319 bl _C_LABEL(lcsplx) 320 mtlr 31 321 mr 3,30 322 blrl /* jump indirect to r31 */ 323 b trapexit 324 325/* 326 * int setfault() 327 * 328 * Similar to setjmp to setup for handling faults on accesses to user memory. 329 * Any routine using this may only call bcopy, either the form below, 330 * or the (currently used) C code optimized, so it doesn't use any non-volatile 331 * registers. 332 */ 333 .globl _C_LABEL(setfault) 334_C_LABEL(setfault): 335 mflr 0 336 mfcr 12 337#if defined(MULTIPROCESSOR) 338 GET_CPUINFO(4) 339 lwz 4,CI_CURPCB(4) 340#else 341 lis 4,_C_LABEL(curpcb)@ha 342 lwz 4,_C_LABEL(curpcb)@l(4) 343#endif 344 stw 3,PCB_FAULT(4) 345 stw 0,0(3) 346 stw 1,4(3) 347 stw 2,8(3) 348 stmw 12,12(3) 349 xor 3,3,3 350 blr 351