/* $OpenBSD: process.S,v 1.16 2007/05/12 19:59:52 miod Exp $ */ /* * Copyright (c) 1996 Nivas Madhur * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Nivas Madhur. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "assym.h" #include #include #include #ifdef DIAGNOSTIC data align 4 ASLOCAL(swchanpanic) string "switch wchan %x\0" align 4 ASLOCAL(swsrunpanic) string "switch SRUN %x\0" text align 8 ASLOCAL(Lswchanpanic) or.u r2, r0, hi16(_ASM_LABEL(swchanpanic)) or r2, r2, lo16(_ASM_LABEL(swchanpanic)) bsr.n _C_LABEL(panic) or r3, r0, r9 ASLOCAL(Lswsrunpanic) or.u r2, r0, hi16(_ASM_LABEL(swsrunpanic)) or r2, r2, lo16(_ASM_LABEL(swsrunpanic)) bsr.n _C_LABEL(panic) or r3, r0, r9 #endif /* * void switch_exit(struct proc *p) * * Do the final work to exit from a process. After switching to the * idle stack and pcb, invoke exit2() on behalf of the exiting process, * then continue into cpu_switch() to select another process to run. */ ENTRY(switch_exit) /* * Disable interrupts since we are about to change the kernel * stack. */ ldcr r3, PSR set r3, r3, 1 stcr r3, PSR FLUSH_PIPELINE /* * Change pcb to idle u. area, i.e., set r31 to top of stack * and set curpcb to point to the cpu's idle stack. * r2 contains proc *p. */ ldcr r10, CPU ld r30, r10, CI_IDLE_PCB addu r31, r30, USIZE /* now on idle stack */ st r30, r10, CI_CURPCB /* curpcb = idle_pcb */ /* Schedule the vmspace and stack to be freed. */ bsr.n _C_LABEL(exit2) st r0, r10, CI_CURPROC /* curproc = NULL */ /* * exit2() has acquired the scheduler lock for us. Jump into * cpu_switch(), after the context save since we do not need * to save anything. */ br _ASM_LABEL(cpu_switch_search) /* * void cpu_switch(struct proc *p) * * Find a runnable process and switch to it. On entry, the scheduler lock is * held; it has to be released before returning to the process. * * Note that this code ignores its proc parameter and assumes it has the * same value as curproc. This may change in mi_switch() in the future, * be careful. */ ENTRY(cpu_switch) /* * Disable interrupts, we do not want to be disturbed while * saving context. */ ldcr r2, PSR set r2, r2, 1 stcr r2, PSR FLUSH_PIPELINE /* * Save state of previous process in its pcb, and pmap_deactivate() * the process. */ ldcr r2, CPU ld r2, r2, CI_CURPCB st r1, r2, PCB_PC /* save return address */ bsr _ASM_LABEL(__savectx) /* note that we don't need to recover r1 at this point */ ldcr r11, CPU ld r2, r11, CI_CURPROC /* * Note that we can still use curpcb as our stack after * pmap_deactivate() has been called, as it does not affect the u * area mappings. */ bsr.n _C_LABEL(pmap_deactivate) st r0, r11, CI_CURPROC /* curproc = NULL */ #ifdef MULTIPROCESSOR /* * We need to switch to the processor's idle stack now (in case the * process we are using the stack of gets scheduled on another * processor). */ ldcr r10, CPU ld r30, r10, CI_IDLE_PCB addu r31, r30, USIZE /* now on idle stack */ st r30, r10, CI_CURPCB /* curpcb = idle_pcb */ #endif ASLOCAL(cpu_switch_search) /* * This is the start of the idle loop. Find the highest-priority * queue that isn't empty, then take the first proc from that queue. */ or.u r7, r0, hi16(_C_LABEL(whichqs)) ld r7, r7, lo16(_C_LABEL(whichqs)) bcnd ne0, r7, _ASM_LABEL(cpu_switch_found) #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) bsr _C_LABEL(sched_unlock_idle) #endif #ifdef MULTIPROCESSOR ASGLOBAL(cpu_switch_idle) #else ASLOCAL(cpu_switch_idle) #endif /* * There were no runnable processes. Enable all interrupts and * busy-wait for this to change. * Note that, besides doing setipl(IPL_NONE), this will actually enable * interrupts in the psr. Bootstrap of secondary processors * relies upon this. */ ldcr r2, PSR clr r2, r2, 1 stcr r2, PSR FLUSH_PIPELINE bsr.n _C_LABEL(setipl) or r2, r0, IPL_NONE or.u r7, r0, hi16(_C_LABEL(whichqs)) ld r7, r7, lo16(_C_LABEL(whichqs)) bcnd eq0, r7, _ASM_LABEL(cpu_switch_idle) /* XXX run fancy things here, such as page zeroing... */ #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) bsr _C_LABEL(sched_lock_idle) #endif ASLOCAL(cpu_switch_found) /* * Disable interrupts. */ ldcr r2, PSR set r2, r2, 1 stcr r2, PSR FLUSH_PIPELINE /* * An interrupt could have occured between the last whichqs check * and the call to setipl(). Check again that whichqs is nonzero. */ or.u r7, r0, hi16(_C_LABEL(whichqs)) /* reload whichqs */ ld r7, r7, lo16(_C_LABEL(whichqs)) bcnd eq0, r7, _ASM_LABEL(cpu_switch_search) /* XXX use ff1, like powerpc... needs *runqueue() adjustments */ xor r6, r6, r6 /* set r6 to 0 */ 1: bb1 0, r7, 2f /* if rightmost bit set, done */ extu r7, r7, 0<1> /* else, right shift whichqs, */ br.n 1b /* increment r6, and repeat */ addu r6, r6, 1 2: or.u r7, r0, hi16(_C_LABEL(qs)) or r7, r7, lo16(_C_LABEL(qs)) /* * Need to make * p->p_forw->p_back = p->p_back and * p->p_back->p_forw = p->p_forw where * p is q->p_forw. * Remember that q->p_forw == p and p->p_back == q. */ lda.d r8, r7[r6] /* r8 = &qs[ff1(whichqs)] */ ld r9, r8, P_FORW /* r8 is q, r9 is p */ ld r12, r9, P_FORW /* r12 = p->p_forw */ st r8, r12, P_BACK /* p->p_forw->p_back = q (p->p_back) */ st r12, r8, P_FORW /* q->p_forw = p->p_forw */ lda.d r8, r7[r6] /* reload r8 with qs[ff1(whichqs)] */ ld r12, r8, P_FORW /* q->p_forw */ cmp r12, r12, r8 /* q == q->p_forw; anyone left on queue? */ bb1 ne, r12, 3f /* yes, skip clearing bit in whichqs */ or r12, r0, 1 mak r12, r12, r6 or.u r7, r0, hi16(_C_LABEL(whichqs)) ld r8, r7, lo16(_C_LABEL(whichqs)) and.c r8, r8, r12 /* whichqs &= ~the bit */ st r8, r7, lo16(_C_LABEL(whichqs)) 3: #ifdef DIAGNOSTIC ld r2, r9, P_WCHAN bcnd ne0, r2, _ASM_LABEL(Lswchanpanic) ld.b r2, r9, P_STAT cmp r2, r2, SRUN bb1 ne, r2, _ASM_LABEL(Lswsrunpanic) #endif ldcr r11, CPU st r0, r11, CI_WANT_RESCHED /* clear want_resched */ st r9, r11, CI_CURPROC /* curproc = p */ or r2, r0, SONPROC st.b r2, r9, P_STAT #ifdef MULTIPROCESSOR st r11, r9, P_CPU /* p->p_cpu = curcpu */ #endif ld r3, r9, P_ADDR st r0, r9, P_BACK /* p->p_back = 0 */ st r3, r11, CI_CURPCB /* curpcb = p->p_addr */ /* pmap_activate() the process' pmap */ bsr.n _C_LABEL(pmap_activate) or r2, r0, r9 ldcr r10, CPU ld r10, r10, CI_CURPCB /* restore from the current context */ ld r2, r10, PCB_FCR62 ld r3, r10, PCB_FCR63 fstcr r2, fcr62 fstcr r3, fcr63 ld r15, r10, PCB_R15 ld r16, r10, PCB_R16 ld r17, r10, PCB_R17 ld r18, r10, PCB_R18 ld r19, r10, PCB_R19 ld r20, r10, PCB_R20 ld r21, r10, PCB_R21 ld r22, r10, PCB_R22 ld r23, r10, PCB_R23 ld r24, r10, PCB_R24 ld r25, r10, PCB_R25 ld r26, r10, PCB_R26 ld r27, r10, PCB_R27 ld r28, r10, PCB_R28 ld r29, r10, PCB_R29 ld r30, r10, PCB_R30 /* restore frame pointer & stack */ ld r31, r10, PCB_SP #if defined(MULTIPROCESSOR) || defined(LOCKDEBUG) bsr.n _C_LABEL(sched_unlock_idle) or r14, r10, r0 ld r1, r14, PCB_PC ld r14, r14, PCB_R14 #else ld r1, r10, PCB_PC ld r14, r10, PCB_R14 #endif /* * Enable interrupts again. */ ldcr r2, PSR clr r2, r2, 1 stcr r2, PSR FLUSH_PIPELINE jmp r1 /* * savectx(pcb) * Update pcb, saving current processor state. */ ENTRY(savectx) /* * Save preserved general register set. */ st r1, r2, PCB_PC /* save return address */ ASLOCAL(__savectx) st r14, r2, PCB_R14 st r15, r2, PCB_R15 st r16, r2, PCB_R16 st r17, r2, PCB_R17 st r18, r2, PCB_R18 st r19, r2, PCB_R19 st r20, r2, PCB_R20 st r21, r2, PCB_R21 st r22, r2, PCB_R22 st r23, r2, PCB_R23 st r24, r2, PCB_R24 st r25, r2, PCB_R25 st r26, r2, PCB_R26 st r27, r2, PCB_R27 st r28, r2, PCB_R28 st r29, r2, PCB_R29 st r30, r2, PCB_R30 /* save frame pointer & stack pointer */ st r31, r2, PCB_SP /* * Save FP state. */ fldcr r4, fcr62 fldcr r5, fcr63 st r4, r2, PCB_FCR62 jmp.n r1 st r5, r2, PCB_FCR63