1/* $NetBSD: locore_subr.S,v 1.2 2001/02/28 20:44:41 tsubai 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 0 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 or. 9,9,9 72 beq 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 83#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 84 bl _C_LABEL(sched_lock_idle) 85#endif 86 b _ASM_LABEL(Idle) 87 88/* 89 * switchexit gets called from cpu_exit to complete the exit procedure. 90 */ 91ENTRY(switchexit) 92/* First switch to the idle pcb/kernel stack */ 93#if defined(MULTIPROCESSOR) 94 GET_CPUINFO(7) 95 lwz 6,CI_IDLE_PCB(7) 96 stw 6,CI_CURPCB(7) 97#else 98 lis 6,idle_u@ha 99 lwz 6,idle_u@l(6) 100 lis 7,_C_LABEL(curpcb)@ha 101 stw 6,_C_LABEL(curpcb)@l(7) 102#endif 103 addi 1,6,USPACE-16 /* 16 bytes are reserved at stack top */ 104 /* 105 * Schedule the vmspace and stack to be freed (the proc arg is 106 * already in r3). 107 */ 108 bl _C_LABEL(exit2) 109 110#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 111 bl _C_LABEL(sched_lock_idle) 112#endif 113 114/* Fall through to cpu_switch to actually select another proc */ 115 li 3,0 /* indicate exited process */ 116 117/* 118 * void cpu_switch(struct proc *p) 119 * Find a runnable process and switch to it. 120 */ 121/* XXX noprofile? --thorpej@netbsd.org */ 122ENTRY(cpu_switch) 123 mflr 0 /* save lr */ 124 stw 0,4(1) 125 stwu 1,-16(1) 126 stw 31,12(1) 127 stw 30,8(1) 128 129 mr 30,3 130#if defined(MULTIPROCESSOR) 131 /* Switch to the idle PCB unless we're already running on it. */ 132 GET_CPUINFO(7) 133 cmpwi 30,0 /* old process was exiting? */ 134 beq 1f 135 136 mfsr 10,USER_SR /* save USER_SR for copyin/copyout */ 137 mfcr 11 /* save cr */ 138 mr 12,2 /* save r2 */ 139 stwu 1,-SFRAMELEN(1) /* still running on old stack */ 140 stmw 10,8(1) 141 lwz 3,P_ADDR(30) 142 stw 1,PCB_SP(3) /* save SP */ 143 144 lwz 6,CI_IDLE_PCB(7) 145 addi 1,6,USPACE-16 /* 16 bytes are reserved at stack top */ 146 1471: 148 xor 31,31,31 149 stw 31,CI_CURPROC(7) /* Zero to not accumulate cpu time */ 150 lwz 31,CI_CURPCB(7) 151 152 lwz 3,CI_CPL(7) 153 stw 3,PCB_SPL(31) /* save spl */ 154#else 155 lis 3,_C_LABEL(curproc)@ha 156 xor 31,31,31 157 stw 31,_C_LABEL(curproc)@l(3) /* Zero to not accumulate cpu time */ 158 lis 3,_C_LABEL(curpcb)@ha 159 lwz 31,_C_LABEL(curpcb)@l(3) 160#endif 161 162#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 163/* Release the sched_lock before processing interrupts. */ 164 bl _C_LABEL(sched_unlock_idle) 165#endif 166 167 xor 3,3,3 168 bl _C_LABEL(lcsplx) 169#if !defined(MULTIPROCESSOR) 170 stw 3,PCB_SPL(31) /* save spl */ 171#endif 172 173/* Lock the scheduler. */ 174 mfmsr 3 175 andi. 3,3,~PSL_EE@l /* disable interrupts while 176 manipulating runque */ 177 mtmsr 3 178 isync 179#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 180 bl _C_LABEL(sched_lock_idle) 181#endif 182 183/* Find a new process */ 184 lis 8,_C_LABEL(sched_whichqs)@ha 185 lwz 9,_C_LABEL(sched_whichqs)@l(8) 186 187 or. 9,9,9 188 beq- _ASM_LABEL(Idle) /* all queues empty */ 189.Lsw1: 190 cntlzw 10,9 191 lis 4,_C_LABEL(sched_qs)@ha 192 addi 4,4,_C_LABEL(sched_qs)@l 193 slwi 3,10,3 194 add 3,3,4 /* select queue */ 195 196 lwz 31,P_FORW(3) /* unlink first proc from queue */ 197 lwz 4,P_FORW(31) 198 stw 4,P_FORW(3) 199 stw 3,P_BACK(4) 200 201 cmpl 0,3,4 /* queue empty? */ 202 bne 1f 203 204 lis 3,0x80000000@h 205 srw 3,3,10 206 andc 9,9,3 207 stw 9,_C_LABEL(sched_whichqs)@l(8) /* mark it empty */ 208 2091: 210 /* just did this resched thing */ 211 xor 3,3,3 212#if defined(MULTIPROCESSOR) 213 GET_CPUINFO(4) 214 stw 3,CI_WANT_RESCHED(4) 215#else 216 lis 4,_C_LABEL(want_resched)@ha 217 stw 3,_C_LABEL(want_resched)@l(4) 218#endif 219 220 stw 3,P_BACK(31) /* probably superfluous */ 221 222#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 223 /* Unlock the sched_lock, but leave interrupts off, for now. */ 224 bl _C_LABEL(sched_unlock_idle) 225#endif 226 227#if defined(MULTIPROCESSOR) 228 GET_CPUINFO(4) 229 stw 4,P_CPU(31) /* p->p_cpu = curcpu() */ 230#endif 231 232 /* Process now running on a processor. */ 233 li 3,SONPROC /* p->p_stat = SONPROC */ 234 stb 3,P_STAT(31) 235 236 /* record new process */ 237#if defined(MULTIPROCESSOR) 238 stw 31,CI_CURPROC(4) 239#else 240 lis 4,_C_LABEL(curproc)@ha 241 stw 31,_C_LABEL(curproc)@l(4) 242#endif 243 lwz 4,P_ADDR(31) 244 245 mfmsr 3 246 ori 3,3,PSL_EE@l /* Now we can interrupt again */ 247 mtmsr 3 248 249#if !defined(MULTIPROCESSOR) /* XXX */ 250 cmpl 0,31,30 /* is it the same process? */ 251 beq switch_return 252 253 or. 30,30,30 /* old process was exiting? */ 254 beq switch_exited 255 256 mfsr 10,USER_SR /* save USER_SR for copyin/copyout */ 257 mfcr 11 /* save cr */ 258 mr 12,2 /* save r2 */ 259 stwu 1,-SFRAMELEN(1) /* still running on old stack */ 260 stmw 10,8(1) 261 lwz 3,P_ADDR(30) 262 stw 1,PCB_SP(3) /* save SP */ 263#endif 264 265switch_exited: 266 mfmsr 3 267 andi. 3,3,~PSL_EE@l /* disable interrupts while 268 actually switching */ 269 mtmsr 3 270 271 /* indicate new pcb */ 272#if defined(MULTIPROCESSOR) 273 GET_CPUINFO(6) 274 stw 4,CI_CURPCB(6) 275#else 276 lis 5,_C_LABEL(curpcb)@ha 277 stw 4,_C_LABEL(curpcb)@l(5) 278#endif 279 280 /* save real pmap pointer for spill fill */ 281 lwz 5,PCB_PMR(4) 282#if defined(MULTIPROCESSOR) 283 stwu 5,CI_CURPM(6) 284#else 285 lis 6,_C_LABEL(curpm)@ha 286 stwu 5,_C_LABEL(curpm)@l(6) 287#endif 288 stwcx. 5,0,6 /* clear possible reservation */ 289 290 addic. 5,5,64 291 li 6,0 292 mfsr 8,KERNEL_SR /* save kernel SR */ 2931: 294 addis 6,6,-0x10000000@ha /* set new procs segment registers */ 295 or. 6,6,6 /* This is done from the real 296 address pmap */ 297 lwzu 7,-4(5) /* so we don't have to worry */ 298 mtsrin 7,6 /* about accessibility */ 299 bne 1b 300 mtsr KERNEL_SR,8 /* restore kernel SR */ 301 isync 302 303 lwz 1,PCB_SP(4) /* get new procs SP */ 304 305 ori 3,3,PSL_EE@l /* interrupts are okay again */ 306 mtmsr 3 307 308 lmw 10,8(1) /* get other regs */ 309 lwz 1,0(1) /* get saved SP */ 310 mr 2,12 /* get saved r2 */ 311 mtcr 11 /* get saved cr */ 312 isync 313 mtsr USER_SR,10 /* get saved USER_SR */ 314 isync 315 316switch_return: 317 mr 30,7 /* save proc pointer */ 318 lwz 3,PCB_SPL(4) 319 bl _C_LABEL(lcsplx) 320 321 mr 3,30 /* get curproc for special fork 322 returns */ 323 324 lwz 31,12(1) 325 lwz 30,8(1) 326 addi 1,1,16 327 lwz 0,4(1) 328 mtlr 0 329 blr 330 331/* 332 * Child comes here at the end of a fork. 333 * Return to userspace via the trap return path. 334 */ 335 .globl _C_LABEL(fork_trampoline) 336_C_LABEL(fork_trampoline): 337#if defined(MULTIPROCESSOR) 338 bl _C_LABEL(proc_trampoline_mp) 339#endif 340 xor 3,3,3 341 bl _C_LABEL(lcsplx) 342 mtlr 31 343 mr 3,30 344 blrl /* jump indirect to r31 */ 345 b trapexit 346 347/* 348 * int setfault() 349 * 350 * Similar to setjmp to setup for handling faults on accesses to user memory. 351 * Any routine using this may only call bcopy, either the form below, 352 * or the (currently used) C code optimized, so it doesn't use any non-volatile 353 * registers. 354 */ 355 .globl _C_LABEL(setfault) 356_C_LABEL(setfault): 357 mflr 0 358 mfcr 12 359#if defined(MULTIPROCESSOR) 360 GET_CPUINFO(4) 361 lwz 4,CI_CURPCB(4) 362#else 363 lis 4,_C_LABEL(curpcb)@ha 364 lwz 4,_C_LABEL(curpcb)@l(4) 365#endif 366 stw 3,PCB_FAULT(4) 367 stw 0,0(3) 368 stw 1,4(3) 369 stw 2,8(3) 370 stmw 12,12(3) 371 xor 3,3,3 372 blr 373