1/* $OpenBSD: process.S,v 1.15 2006/11/22 22:49:02 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 * Disable interrupts since we are about to change the kernel 73 * stack. 74 */ 75 ldcr r3, PSR 76 set r3, r3, 1<PSR_INTERRUPT_DISABLE_BIT> 77 stcr r3, PSR 78 FLUSH_PIPELINE 79 80 /* 81 * Change pcb to idle u. area, i.e., set r31 to top of stack 82 * and set curpcb to point to the cpu's idle stack. 83 * r2 contains proc *p. 84 */ 85 ldcr r10, CPU 86 ld r30, r10, CI_IDLE_PCB 87 addu r31, r30, USIZE /* now on idle stack */ 88 st r30, r10, CI_CURPCB /* curpcb = idle_pcb */ 89 90 /* Schedule the vmspace and stack to be freed. */ 91 bsr.n _C_LABEL(exit2) 92 st r0, r10, CI_CURPROC /* curproc = NULL */ 93 94 /* 95 * exit2() has acquired the scheduler lock for us. Jump into 96 * cpu_switch(), after the context save since we do not need 97 * to save anything. 98 */ 99 br _ASM_LABEL(cpu_switch_search) 100 101/* 102 * void cpu_switch(struct proc *p) 103 * 104 * Find a runnable process and switch to it. On entry, the scheduler lock is 105 * held; it has to be released before returning to the process. 106 * 107 * Note that this code ignores its proc parameter and assumes it has the 108 * same value as curproc. This may change in mi_switch() in the future, 109 * be careful. 110 */ 111ENTRY(cpu_switch) 112 /* 113 * Disable interrupts, we do not want to be disturbed while 114 * saving context. 115 */ 116 ldcr r2, PSR 117 set r2, r2, 1<PSR_INTERRUPT_DISABLE_BIT> 118 stcr r2, PSR 119 FLUSH_PIPELINE 120 121 /* 122 * Save state of previous process in its pcb, and pmap_deactivate() 123 * the process. 124 */ 125 ldcr r2, CPU 126 ld r2, r2, CI_CURPCB 127 st r1, r2, PCB_PC /* save return address */ 128 bsr _ASM_LABEL(__savectx) 129 /* note that we don't need to recover r1 at this point */ 130 131 ldcr r11, CPU 132 ld r2, r11, CI_CURPROC 133 134 /* 135 * Note that we can still use curpcb as our stack after 136 * pmap_deactivate() has been called, as it does not affect the u 137 * area mappings. 138 */ 139 bsr.n _C_LABEL(pmap_deactivate) 140 st r0, r11, CI_CURPROC /* curproc = NULL */ 141 142#ifdef MULTIPROCESSOR 143 /* 144 * We need to switch to the processor's idle stack now (in case the 145 * process we are using the stack of gets scheduled on another 146 * processor). 147 */ 148 ldcr r10, CPU 149 ld r30, r10, CI_IDLE_PCB 150 addu r31, r30, USIZE /* now on idle stack */ 151 st r30, r10, CI_CURPCB /* curpcb = idle_pcb */ 152#endif 153 154ASLOCAL(cpu_switch_search) 155 /* 156 * This is the start of the idle loop. Find the highest-priority 157 * queue that isn't empty, then take the first proc from that queue. 158 */ 159 or.u r7, r0, hi16(_C_LABEL(whichqs)) 160 ld r7, r7, lo16(_C_LABEL(whichqs)) 161 bcnd ne0, r7, _ASM_LABEL(cpu_switch_found) 162 163#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 164 bsr _C_LABEL(sched_unlock_idle) 165#endif 166 167#ifdef MULTIPROCESSOR 168ASGLOBAL(cpu_switch_idle) 169#else 170ASLOCAL(cpu_switch_idle) 171#endif 172 /* 173 * There were no runnable processes. Enable all interrupts and 174 * busy-wait for this to change. 175 * Note that, besides doing setipl(IPL_NONE), this will actually enable 176 * interrupts in the psr. Bootstrap of secondary processors 177 * relies upon this. 178 */ 179 ldcr r2, PSR 180 clr r2, r2, 1<PSR_INTERRUPT_DISABLE_BIT> 181 stcr r2, PSR 182 FLUSH_PIPELINE 183 184 bsr.n _C_LABEL(setipl) 185 or r2, r0, IPL_NONE 186 187 or.u r7, r0, hi16(_C_LABEL(whichqs)) 188 ld r7, r7, lo16(_C_LABEL(whichqs)) 189 bcnd eq0, r7, _ASM_LABEL(cpu_switch_idle) 190 /* XXX run fancy things here, such as page zeroing... */ 191 192#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 193 bsr _C_LABEL(sched_lock_idle) 194#endif 195 196ASLOCAL(cpu_switch_found) 197 /* 198 * Disable interrupts. 199 */ 200 ldcr r2, PSR 201 set r2, r2, 1<PSR_INTERRUPT_DISABLE_BIT> 202 stcr r2, PSR 203 FLUSH_PIPELINE 204 205 /* 206 * An interrupt could have occured between the last whichqs check 207 * and the call to setipl(). Check again that whichqs is nonzero. 208 */ 209 or.u r7, r0, hi16(_C_LABEL(whichqs)) /* reload whichqs */ 210 ld r7, r7, lo16(_C_LABEL(whichqs)) 211 bcnd eq0, r7, _ASM_LABEL(cpu_switch_search) 212 213 /* XXX use ff1, like powerpc... needs *runqueue() adjustments */ 214 xor r6, r6, r6 /* set r6 to 0 */ 2151: bb1 0, r7, 2f /* if rightmost bit set, done */ 216 extu r7, r7, 0<1> /* else, right shift whichqs, */ 217 br.n 1b /* increment r6, and repeat */ 218 addu r6, r6, 1 2192: 220 or.u r7, r0, hi16(_C_LABEL(qs)) 221 or r7, r7, lo16(_C_LABEL(qs)) 222 223 /* 224 * Need to make 225 * p->p_forw->p_back = p->p_back and 226 * p->p_back->p_forw = p->p_forw where 227 * p is q->p_forw. 228 * Remember that q->p_forw == p and p->p_back == q. 229 */ 230 231 lda.d r8, r7[r6] /* r8 = &qs[ff1(whichqs)] */ 232 ld r9, r8, P_FORW /* r8 is q, r9 is p */ 233 234 ld r12, r9, P_FORW /* r12 = p->p_forw */ 235 st r8, r12, P_BACK /* p->p_forw->p_back = q (p->p_back) */ 236 st r12, r8, P_FORW /* q->p_forw = p->p_forw */ 237 lda.d r8, r7[r6] /* reload r8 with qs[ff1(whichqs)] */ 238 ld r12, r8, P_FORW /* q->p_forw */ 239 cmp r12, r12, r8 /* q == q->p_forw; anyone left on queue? */ 240 bb1 ne, r12, 3f /* yes, skip clearing bit in whichqs */ 241 242 or r12, r0, 1 243 mak r12, r12, r6 244 or.u r7, r0, hi16(_C_LABEL(whichqs)) 245 ld r8, r7, lo16(_C_LABEL(whichqs)) 246 and.c r8, r8, r12 /* whichqs &= ~the bit */ 247 st r8, r7, lo16(_C_LABEL(whichqs)) 2483: 249#ifdef DIAGNOSTIC 250 ld r2, r9, P_WCHAN 251 bcnd ne0, r2, _ASM_LABEL(Lswchanpanic) 252 ld.b r2, r9, P_STAT 253 cmp r2, r2, SRUN 254 bb1 ne, r2, _ASM_LABEL(Lswsrunpanic) 255#endif 256 257 ldcr r11, CPU 258 st r0, r11, CI_WANT_RESCHED /* clear want_resched */ 259 260 st r9, r11, CI_CURPROC /* curproc = p */ 261 or r2, r0, SONPROC 262 st.b r2, r9, P_STAT 263 264 ld r3, r9, P_ADDR 265 st r0, r9, P_BACK /* p->p_back = 0 */ 266 st r3, r11, CI_CURPCB /* curpcb = p->p_addr */ 267 268 /* pmap_activate() the process' pmap */ 269 bsr.n _C_LABEL(pmap_activate) 270 or r2, r0, r9 271 272 ldcr r10, CPU 273 ld r10, r10, CI_CURPCB 274 275 /* restore from the current context */ 276 ld r2, r10, PCB_FCR62 277 ld r3, r10, PCB_FCR63 278 fstcr r2, fcr62 279 fstcr r3, fcr63 280 ld r15, r10, PCB_R15 281 ld r16, r10, PCB_R16 282 ld r17, r10, PCB_R17 283 ld r18, r10, PCB_R18 284 ld r19, r10, PCB_R19 285 ld r20, r10, PCB_R20 286 ld r21, r10, PCB_R21 287 ld r22, r10, PCB_R22 288 ld r23, r10, PCB_R23 289 ld r24, r10, PCB_R24 290 ld r25, r10, PCB_R25 291 ld r26, r10, PCB_R26 292 ld r27, r10, PCB_R27 293 ld r28, r10, PCB_R28 294 ld r29, r10, PCB_R29 295 ld r30, r10, PCB_R30 /* restore frame pointer & stack */ 296 ld r31, r10, PCB_SP 297#if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) 298 bsr.n _C_LABEL(sched_unlock_idle) 299 or r14, r10, r0 300 ld r1, r14, PCB_PC 301 ld r14, r14, PCB_R14 302#else 303 ld r1, r10, PCB_PC 304 ld r14, r10, PCB_R14 305#endif 306 307 /* 308 * Enable interrupts again. 309 */ 310 ldcr r2, PSR 311 clr r2, r2, 1<PSR_INTERRUPT_DISABLE_BIT> 312 stcr r2, PSR 313 FLUSH_PIPELINE 314 315 jmp r1 316 317/* 318 * savectx(pcb) 319 * Update pcb, saving current processor state. 320 */ 321ENTRY(savectx) 322 /* 323 * Save preserved general register set. 324 */ 325 st r1, r2, PCB_PC /* save return address */ 326ASLOCAL(__savectx) 327 st r14, r2, PCB_R14 328 st r15, r2, PCB_R15 329 st r16, r2, PCB_R16 330 st r17, r2, PCB_R17 331 st r18, r2, PCB_R18 332 st r19, r2, PCB_R19 333 st r20, r2, PCB_R20 334 st r21, r2, PCB_R21 335 st r22, r2, PCB_R22 336 st r23, r2, PCB_R23 337 st r24, r2, PCB_R24 338 st r25, r2, PCB_R25 339 st r26, r2, PCB_R26 340 st r27, r2, PCB_R27 341 st r28, r2, PCB_R28 342 st r29, r2, PCB_R29 343 st r30, r2, PCB_R30 /* save frame pointer & stack pointer */ 344 st r31, r2, PCB_SP 345 346 /* 347 * Save FP state. 348 */ 349 fldcr r4, fcr62 350 fldcr r5, fcr63 351 st r4, r2, PCB_FCR62 352 jmp.n r1 353 st r5, r2, PCB_FCR63 354