1/* $OpenBSD: process.S,v 1.7 2004/08/09 20:52:11 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 data 39 align 4 40ASLOCAL(swchanpanic) 41 string "switch wchan %x\0" 42 align 4 43ASLOCAL(swsrunpanic) 44 string "switch SRUN %x\0" 45#ifdef DEBUG 46 align 4 47ASLOCAL(boguspsr) 48 string "Invalid PSR in idle loop 0x%x\n\0" 49#endif 50 51 text 52 align 8 53ASLOCAL(Lswchanpanic) 54 or.u r2, r0, hi16(_ASM_LABEL(swchanpanic)) 55 or r2, r2, lo16(_ASM_LABEL(swchanpanic)) 56 bsr.n _C_LABEL(panic) 57 or r3, r0, r9 58 59ASLOCAL(Lswsrunpanic) 60 or.u r2, r0, hi16(_ASM_LABEL(swsrunpanic)) 61 or r2, r2, lo16(_ASM_LABEL(swsrunpanic)) 62 bsr.n _C_LABEL(panic) 63 or r3, r0, r9 64 65/* 66 * At exit of a process, do a cpu_switch for the last time. 67 * The mapping of the pcb at p->p_addr has already been deleted, 68 * and the memory for the pcb+stack has been freed. 69 * The ipl is high enough to prevent the memory from being reallocated. 70 * switch_exit(proc * p) 71 */ 72 73ENTRY(switch_exit) 74 /* 75 * Change pcb to idle u. area, i.e., set r31 to top of stack 76 * and set curpcb to point to _idle_u. r2 contains proc *p. 77 */ 78 or.u r30, r0, hi16(_C_LABEL(idle_u)) 79 or r30, r30,lo16(_C_LABEL(idle_u)) 80 addu r31, r30, USIZE /* now on idle_u stack */ 81 or.u r10, r0, hi16(_C_LABEL(curpcb)) 82 st r30, r10,lo16(_C_LABEL(curpcb)) /* curpcb = &idle_u */ 83 84 /* Schedule the vmspace and stack to be freed. */ 85 or.u r10, r0, hi16(_C_LABEL(curproc)) 86 bsr.n _C_LABEL(exit2) 87 st r0, r10, lo16(_C_LABEL(curproc)) /* curproc = NULL */ 88 bsr _C_LABEL(cpu_switch) /* goto final switch */ 89 90/* 91 * cpu_switch() 92 * XXX - Arg 1 is a proc pointer (curproc) but this doesn't use it. 93 * XXX - how about using stack for saving spl and last proc? 94 * XXX rewrite this whole mess in C nivas 95 */ 96ENTRY(cpu_switch) 97 98 /* 99 * Save state of previous process in its pcb. 100 */ 101 or.u r2, r0, hi16(_C_LABEL(curpcb)) 102 ld r2, r2, lo16(_C_LABEL(curpcb)) 103 st r1, r2, PCB_PC /* save return address */ 104 bsr _ASM_LABEL(__savectx) 105 /* note that we don't need to recover r1 at this point */ 106 107 or.u r11, r0, hi16(_C_LABEL(curproc)) 108 ld r2, r11, lo16(_C_LABEL(curproc)) 109 bcnd eq0, r2, 1f 110 111 bsr _C_LABEL(pmap_deactivate) 112 or.u r11, r0, hi16(_C_LABEL(curproc)) 113 1141: 115 st r0, r11, lo16(_C_LABEL(curproc)) /* curproc = NULL */ 116 117ASLOCAL(Lidleloop) 118 119 /* 120 * Find the highest-priority queue that isn't empty, 121 * then take the first proc from that queue. 122 */ 123 124 or.u r7, r0, hi16(_C_LABEL(whichqs)) 125 ld r7, r7, lo16(_C_LABEL(whichqs)) 126 127 bcnd ne0, r7, _ASM_LABEL(Ldoneloop) 128 129ASLOCAL(Lloopchk) /* if whichqs is zero, keep checking */ 130 bsr.n _C_LABEL(setipl) /* unmask all ints... */ 131 or r2, r0, IPL_NONE 132 133 ldcr r2, PSR 134 bb0 PSR_INTERRUPT_DISABLE_BIT, r2, 1f 135#ifdef DEBUG 136 or r3, r2, r0 137 or.u r2, r0, hi16(_ASM_LABEL(boguspsr)) 138 bsr.n _C_LABEL(printf) 139 or r2, r2, lo16(_ASM_LABEL(boguspsr)) 140 ldcr r2, PSR 141#endif 142 clr r2, r2, 1<PSR_INTERRUPT_DISABLE_BIT> /* ...and enable them */ 143 stcr r2, PSR 144 FLUSH_PIPELINE 1451: 146 br _ASM_LABEL(Lidleloop) 147 148ASLOCAL(Ldoneloop) 149 150 bsr.n _C_LABEL(setipl) /* disable ints */ 151 or r2, r0, IPL_HIGH 152 153 or.u r7, r0, hi16(_C_LABEL(whichqs)) /* reload whichqs */ 154 ld r7, r7, lo16(_C_LABEL(whichqs)) 155 156 bcnd eq0, r7, _ASM_LABEL(Lloopchk) /* keep spinning for whichqs to be != 0 */ 157 158 xor r6, r6, r6 /* set r6 to 0 */ 1591: bb1 0, r7, 2f /* if rightmost bit set, done */ 160 extu r7, r7, 0<1> /* else, right shift whichqs, */ 161 br.n 1b /* increment r6, and repeat */ 162 addu r6, r6, 1 1632: 164 or.u r7, r0, hi16(_qs) 165 or r7, r7, lo16(_qs) 166 167 /* 168 * Need to make 169 * p->p_forw->p_back = p->p_back and 170 * p->p_back->p_forw = p->p_forw where 171 * p is q->p_forw. 172 * Remember that q->p_forw == p and p->p_back == q. 173 */ 174 175 lda.d r8, r7[r6] /* r8 = &qs[ff1(whichqs)] */ 176 ld r9, r8, P_FORW /* r8 is q, r9 is p */ 177 178 ld r12, r9, P_FORW /* r12 = p->p_forw */ 179 st r8, r12, P_BACK /* p->p_forw->p_back = q (p->p_back) */ 180 st r12, r8, P_FORW /* q->p_forw = p->p_forw */ 181 lda.d r8, r7[r6] /* reload r8 with qs[ff1(whichqs)] */ 182 ld r12, r8, P_FORW /* q->p_forw */ 183 cmp r12, r12, r8 /* q == q->p_forw; anyone left on queue? */ 184 bb1 ne, r12, 3f /* yes, skip clearing bit in whichqs */ 185 186 or r12, r0, 1 /* r12 is 1 now */ 1871: bcnd eq0, r6, 2f 188 mak r12, r12, 0<1> /* shift left by 1 */ 189 br.n 1b 190 subu r6, r6, 1 /* keep doing this while r6 != 0 */ 1912: 192 /* 193 * NOTE: we could have just used "mak r12, r12, r6" instead of the 194 * loop above. But that will break if NQS is made > 32. I can use 195 * preprocessor to do the right thing, but that means I have to 196 * include sys/proc.h in this file. XXX nivas 197 */ 198 or.u r7, r0, hi16(_C_LABEL(whichqs)) 199 ld r8, r7, lo16(_C_LABEL(whichqs)) 200 and.c r8, r8, r12 /* whichqs &= ~the bit */ 201 st r8, r7, lo16(_C_LABEL(whichqs)) 2023: 203 ld r2, r9, P_WCHAN 204 bcnd ne0, r2, _ASM_LABEL(Lswchanpanic) 205 ld.b r2, r9, P_STAT 206 cmp r2, r2, SRUN 207 bb1 ne, r2, _ASM_LABEL(Lswsrunpanic) 208 209 or.u r11, r0, hi16(_C_LABEL(want_resched)) 210 st r0, r11, lo16(_C_LABEL(want_resched)) /* clear want_resched */ 211 212 or.u r11, r0, hi16(_C_LABEL(curproc)) 213 st r9, r11,lo16(_C_LABEL(curproc)) /* curproc = p */ 214 or r2, r0, SONPROC 215 st.b r2, r9, P_STAT 216 217 /* r9 is curproc */ 218 st r0, r9, P_BACK /* p->p_back = 0 */ 219 ld r3, r9, P_ADDR 220 or.u r10, r0, hi16(_C_LABEL(curpcb)) 221 st r3, r10, lo16(_C_LABEL(curpcb)) /* curpcb = p->p_addr */ 222 223 /* pmap_activate() the process' pmap */ 224 or r14, r0, r9 /* save p in r14 */ 225 bsr.n _C_LABEL(pmap_activate) 226 or r2, r0, r9 227 or r9, r0, r14 /* restore p saved in r14 */ 228 229 or.u r31, r0, hi16(_ASM_LABEL(intstack_end)) 230 or r31,r31, lo16(_ASM_LABEL(intstack_end)) 231 bsr.n _C_LABEL(load_u_area) 232 or r2, r0, r9 233 234 or.u r10, r0, hi16(_C_LABEL(curpcb)) 235 ld r10, r10, lo16(_C_LABEL(curpcb)) 236 /* XXX Is this correct/necessary? */ 237 st r10, r14, P_ADDR /* p->p_addr = curpcb; restore p_addr */ 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 ld r14,r14, PCB_R14 266 jmp.n r1 267 or r2, r0, 1 /* return 1 (for alternate returns) */ 268 269/* 270 * savectx(pcb) 271 * Update pcb, saving current processor state. 272 */ 273ENTRY(savectx) 274 /* 275 * Save preserved general register set. 276 */ 277 st r1, r2, PCB_PC /* save return address */ 278ASLOCAL(__savectx) 279 st r14, r2, PCB_R14 280 st r15, r2, PCB_R15 281 st r16, r2, PCB_R16 282 st r17, r2, PCB_R17 283 st r18, r2, PCB_R18 284 st r19, r2, PCB_R19 285 st r20, r2, PCB_R20 286 st r21, r2, PCB_R21 287 st r22, r2, PCB_R22 288 st r23, r2, PCB_R23 289 st r24, r2, PCB_R24 290 st r25, r2, PCB_R25 291 st r26, r2, PCB_R26 292 st r27, r2, PCB_R27 293 st r28, r2, PCB_R28 294 st r29, r2, PCB_R29 295 st r30, r2, PCB_R30 /* save frame pointer & stack pointer */ 296 st r31, r2, PCB_SP 297 298 /* 299 * Get the current spl. 300 * We need to save r1 on the stack because we don't know if we were 301 * called as savectx or __savectx. 302 */ 303 subu r31, r31, 16 /* allocate stack for r1 and args */ 304 st r1, r31, 0 305 bsr.n _C_LABEL(getipl) /* get the current interrupt mask */ 306 or r14, r0, r2 307 st r2, r14, PCB_IPL /* save interrupt mask */ 308 ld r1, r31, 0 /* recover return address */ 309 addu r31, r31, 16 /* put stack pointer back */ 310 311 /* 312 * Save FP state. 313 */ 314 fldcr r2, fcr62 315 fldcr r3, fcr63 316 st r2, r14, PCB_FCR62 317 st r3, r14, PCB_FCR63 318 jmp.n r1 319 ld r14, r14, PCB_R14 /* preserve r14 */ 320