1/* $OpenBSD: process.S,v 1.13 2005/12/11 21:45:30 miod Exp $ */ 2/* 3 * Copyright (c) 1996 Nivas Madhur 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Nivas Madhur. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 */ 32 33#include "assym.h" 34#include <machine/asm.h> 35#include <machine/psl.h> 36#include <machine/intr.h> 37 38#ifdef DIAGNOSTIC 39 data 40 align 4 41ASLOCAL(swchanpanic) 42 string "switch wchan %x\0" 43 align 4 44ASLOCAL(swsrunpanic) 45 string "switch SRUN %x\0" 46 47 text 48 align 8 49ASLOCAL(Lswchanpanic) 50 or.u r2, r0, hi16(_ASM_LABEL(swchanpanic)) 51 or r2, r2, lo16(_ASM_LABEL(swchanpanic)) 52 bsr.n _C_LABEL(panic) 53 or r3, r0, r9 54 55ASLOCAL(Lswsrunpanic) 56 or.u r2, r0, hi16(_ASM_LABEL(swsrunpanic)) 57 or r2, r2, lo16(_ASM_LABEL(swsrunpanic)) 58 bsr.n _C_LABEL(panic) 59 or r3, r0, r9 60#endif 61 62/* 63 * void switch_exit(struct proc *p) 64 * 65 * Do the final work to exit from a process. After switching to the 66 * idle stack and pcb, invoke exit2() on behalf of the exiting process, 67 * then continue into cpu_switch() to select another process to run. 68 */ 69 70ENTRY(switch_exit) 71 /* 72 * Change pcb to idle u. area, i.e., set r31 to top of stack 73 * and set curpcb to point to the cpu's idle stack. 74 * r2 contains proc *p. 75 */ 76 ldcr r10, CPU 77 ld r30, r10, CI_IDLE_PCB 78 addu r31, r30, USIZE /* now on idle stack */ 79 st r30, r10, CI_CURPCB /* curpcb = idle_pcb */ 80 81 /* Schedule the vmspace and stack to be freed. */ 82 bsr.n _C_LABEL(exit2) 83 st r0, r10, CI_CURPROC /* curproc = NULL */ 84 85 /* 86 * exit2() has acquired the scheduler lock for us. Jump into 87 * cpu_switch(), after the context save since we do not need 88 * to save anything. 89 */ 90 bsr _ASM_LABEL(cpu_switch_search) 91 92/* 93 * void cpu_switch(struct proc *p) 94 * 95 * Find a runnable process and switch to it. On entry, the scheduler lock is 96 * held; it has to be released before returning to the process. 97 * 98 * Note that this code ignores its proc parameter and assumes it has the 99 * same value as curproc. This may change in mi_switch() in the future, 100 * be careful. 101 */ 102ENTRY(cpu_switch) 103 /* 104 * Save state of previous process in its pcb, and pmap_deactivate() 105 * the process. 106 */ 107 ldcr r2, CPU 108 ld r2, r2, CI_CURPCB 109 st r1, r2, PCB_PC /* save return address */ 110 bsr _ASM_LABEL(__savectx) 111 /* note that we don't need to recover r1 at this point */ 112 113 ldcr r11, CPU 114 ld r2, r11, CI_CURPROC 115 116 /* 117 * Note that we can still use curpcb as our stack after 118 * pmap_deactivate() has been called, as it does not affect the u 119 * area mappings. 120 */ 121 bsr.n _C_LABEL(pmap_deactivate) 122 st r0, r11, CI_CURPROC /* curproc = NULL */ 123 124ASLOCAL(cpu_switch_search) 125 /* 126 * This is the start of the idle loop. Find the highest-priority 127 * queue that isn't empty, then take the first proc from that queue. 128 */ 129 or.u r7, r0, hi16(_C_LABEL(whichqs)) 130 ld r7, r7, lo16(_C_LABEL(whichqs)) 131 bcnd ne0, r7, _ASM_LABEL(cpu_switch_found) 132 133#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 134 bsr _C_LABEL(sched_unlock_idle) 135#endif 136 137#ifdef MULTIPROCESSOR 138ASGLOBAL(cpu_switch_idle) 139#endif 140 /* 141 * There were no runnable processes. Enable all interrupts and 142 * busy-wait for this to change. 143 * Note that, besides doing setipl(IPL_NONE), this will actually enable 144 * interrupts in the psr. Bootstrap of secondary processors 145 * relies upon this. 146 */ 147 ldcr r2, PSR 148 bb0 PSR_INTERRUPT_DISABLE_BIT, r2, 2f 149 clr r2, r2, 1<PSR_INTERRUPT_DISABLE_BIT> 150 stcr r2, PSR 151 FLUSH_PIPELINE 1522: 153 bsr.n _C_LABEL(setipl) 154 or r2, r0, IPL_NONE 155 156 or.u r7, r0, hi16(_C_LABEL(whichqs)) 157 ld r7, r7, lo16(_C_LABEL(whichqs)) 158 bcnd eq0, r7, 2b 159 /* XXX run fancy things here, such as page zeroing... */ 160 161#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 162 bsr _C_LABEL(sched_lock_idle) 163#endif 164 165ASLOCAL(cpu_switch_found) 166 bsr.n _C_LABEL(setipl) /* disable interrupts */ 167 or r2, r0, IPL_HIGH 168 169 /* 170 * An interrupt could have occured between the last whichqs check 171 * and the call to setipl(). Check again that whichqs is nonzero. 172 */ 173 or.u r7, r0, hi16(_C_LABEL(whichqs)) /* reload whichqs */ 174 ld r7, r7, lo16(_C_LABEL(whichqs)) 175 bcnd eq0, r7, _ASM_LABEL(cpu_switch_search) 176 177 /* XXX use ff1, like powerpc... needs *runqueue() adjustments */ 178 xor r6, r6, r6 /* set r6 to 0 */ 1791: bb1 0, r7, 2f /* if rightmost bit set, done */ 180 extu r7, r7, 0<1> /* else, right shift whichqs, */ 181 br.n 1b /* increment r6, and repeat */ 182 addu r6, r6, 1 1832: 184 or.u r7, r0, hi16(_C_LABEL(qs)) 185 or r7, r7, lo16(_C_LABEL(qs)) 186 187 /* 188 * Need to make 189 * p->p_forw->p_back = p->p_back and 190 * p->p_back->p_forw = p->p_forw where 191 * p is q->p_forw. 192 * Remember that q->p_forw == p and p->p_back == q. 193 */ 194 195 lda.d r8, r7[r6] /* r8 = &qs[ff1(whichqs)] */ 196 ld r9, r8, P_FORW /* r8 is q, r9 is p */ 197 198 ld r12, r9, P_FORW /* r12 = p->p_forw */ 199 st r8, r12, P_BACK /* p->p_forw->p_back = q (p->p_back) */ 200 st r12, r8, P_FORW /* q->p_forw = p->p_forw */ 201 lda.d r8, r7[r6] /* reload r8 with qs[ff1(whichqs)] */ 202 ld r12, r8, P_FORW /* q->p_forw */ 203 cmp r12, r12, r8 /* q == q->p_forw; anyone left on queue? */ 204 bb1 ne, r12, 3f /* yes, skip clearing bit in whichqs */ 205 206 or r12, r0, 1 207 mak r12, r12, r6 208 or.u r7, r0, hi16(_C_LABEL(whichqs)) 209 ld r8, r7, lo16(_C_LABEL(whichqs)) 210 and.c r8, r8, r12 /* whichqs &= ~the bit */ 211 st r8, r7, lo16(_C_LABEL(whichqs)) 2123: 213#ifdef DIAGNOSTIC 214 ld r2, r9, P_WCHAN 215 bcnd ne0, r2, _ASM_LABEL(Lswchanpanic) 216 ld.b r2, r9, P_STAT 217 cmp r2, r2, SRUN 218 bb1 ne, r2, _ASM_LABEL(Lswsrunpanic) 219#endif 220 221 ldcr r11, CPU 222 st r0, r11, CI_WANT_RESCHED /* clear want_resched */ 223 224 st r9, r11, CI_CURPROC /* curproc = p */ 225 or r2, r0, SONPROC 226 st.b r2, r9, P_STAT 227 228 ld r3, r9, P_ADDR 229 st r0, r9, P_BACK /* p->p_back = 0 */ 230 st r3, r11, CI_CURPCB /* curpcb = p->p_addr */ 231 232 /* pmap_activate() the process' pmap */ 233 bsr.n _C_LABEL(pmap_activate) 234 or r2, r0, r9 235 236 ldcr r10, CPU 237 ld r10, r10, CI_CURPCB 238 239 /* restore from the current context */ 240 ld r2, r10, PCB_FCR62 241 ld r3, r10, PCB_FCR63 242 fstcr r2, fcr62 243 fstcr r3, fcr63 244 ld r15, r10, PCB_R15 245 ld r16, r10, PCB_R16 246 ld r17, r10, PCB_R17 247 ld r18, r10, PCB_R18 248 ld r19, r10, PCB_R19 249 ld r20, r10, PCB_R20 250 ld r21, r10, PCB_R21 251 ld r22, r10, PCB_R22 252 ld r23, r10, PCB_R23 253 ld r24, r10, PCB_R24 254 ld r25, r10, PCB_R25 255 ld r26, r10, PCB_R26 256 ld r27, r10, PCB_R27 257 ld r28, r10, PCB_R28 258 ld r29, r10, PCB_R29 259 or r14, r10, r0 /* preserve curpcb in a register... */ 260 bsr.n _C_LABEL(setipl) 261 ld r2, r10, PCB_IPL /* restore interrupt mask */ 262 ld r1, r14, PCB_PC 263 ld r30, r14, PCB_R30 /* restore frame pointer & stack */ 264 ld r31, r14, PCB_SP 265#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 266 br.n _C_LABEL(sched_unlock_idle) 267#else 268 jmp.n r1 269#endif 270 ld r14, r14, PCB_R14 271 272/* 273 * savectx(pcb) 274 * Update pcb, saving current processor state. 275 */ 276ENTRY(savectx) 277 /* 278 * Save preserved general register set. 279 */ 280 st r1, r2, PCB_PC /* save return address */ 281ASLOCAL(__savectx) 282 st r14, r2, PCB_R14 283 st r15, r2, PCB_R15 284 st r16, r2, PCB_R16 285 st r17, r2, PCB_R17 286 st r18, r2, PCB_R18 287 st r19, r2, PCB_R19 288 st r20, r2, PCB_R20 289 st r21, r2, PCB_R21 290 st r22, r2, PCB_R22 291 st r23, r2, PCB_R23 292 st r24, r2, PCB_R24 293 st r25, r2, PCB_R25 294 st r26, r2, PCB_R26 295 st r27, r2, PCB_R27 296 st r28, r2, PCB_R28 297 st r29, r2, PCB_R29 298 st r30, r2, PCB_R30 /* save frame pointer & stack pointer */ 299 st r31, r2, PCB_SP 300 301 /* 302 * Get the current spl. 303 * We need to save r1 on the stack because we don't know if we were 304 * called as savectx or __savectx. 305 */ 306 subu r31, r31, 16 /* allocate stack for r1 and args */ 307 st r1, r31, 0 308 bsr.n _C_LABEL(getipl) /* get the current interrupt mask */ 309 or r14, r0, r2 310 st r2, r14, PCB_IPL /* save interrupt mask */ 311 ld r1, r31, 0 /* recover return address */ 312 addu r31, r31, 16 /* put stack pointer back */ 313 314 /* 315 * Save FP state. 316 */ 317 fldcr r2, fcr62 318 fldcr r3, fcr63 319 st r2, r14, PCB_FCR62 320 st r3, r14, PCB_FCR63 321 jmp.n r1 322 ld r14, r14, PCB_R14 /* preserve r14 */ 323