Annotation of sys/arch/mips64/mips64/context.S, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: context.S,v 1.13 2007/07/16 20:22:18 miod Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2002-2003 Opsycon AB (www.opsycon.se / www.opsycon.com)
! 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: *
! 15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
! 16: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
! 17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 18: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
! 19: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 21: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 25: * SUCH DAMAGE.
! 26: *
! 27: */
! 28: #include <sys/errno.h>
! 29: #include <sys/syscall.h>
! 30:
! 31: #include <machine/param.h>
! 32: #include <machine/psl.h>
! 33: #include <machine/asm.h>
! 34: #include <machine/cpu.h>
! 35: #include <machine/regnum.h>
! 36: #include <machine/cpustate.h>
! 37: #include <machine/pte.h>
! 38:
! 39: #include "assym.h"
! 40:
! 41: #define curproc (cpu_info_primary + CI_CURPROC)
! 42:
! 43: .set mips3
! 44:
! 45: .set noreorder # Noreorder is default style!
! 46:
! 47: /*
! 48: * Save registers and state used by reboot to take snapshot.
! 49: */
! 50: LEAF(savectx, 0)
! 51: REG_S s0, PCB_CONTEXT+0*REGSZ(a0)
! 52: REG_S s1, PCB_CONTEXT+1*REGSZ(a0)
! 53: REG_S s2, PCB_CONTEXT+2*REGSZ(a0)
! 54: REG_S s3, PCB_CONTEXT+3*REGSZ(a0)
! 55: mfc0 v0, COP_0_STATUS_REG
! 56: REG_S s4, PCB_CONTEXT+4*REGSZ(a0)
! 57: REG_S s5, PCB_CONTEXT+5*REGSZ(a0)
! 58: REG_S s6, PCB_CONTEXT+6*REGSZ(a0)
! 59: REG_S s7, PCB_CONTEXT+7*REGSZ(a0)
! 60: REG_S sp, PCB_CONTEXT+8*REGSZ(a0)
! 61: REG_S s8, PCB_CONTEXT+9*REGSZ(a0)
! 62: REG_S ra, PCB_CONTEXT+10*REGSZ(a0)
! 63: REG_S v0, PCB_CONTEXT+11*REGSZ(a0)
! 64: cfc0 t1, COP_0_ICR
! 65: lw t0, cpl
! 66: REG_S t1, PCB_CONTEXT+12*REGSZ(a0) # save status register
! 67: REG_S t0, PCB_CONTEXT+13*REGSZ(a0)
! 68: j ra
! 69: move v0, zero
! 70: END(savectx)
! 71:
! 72: /*
! 73: * The following primitives manipulate the run queues. _whichqs tells which
! 74: * of the 32 queues _qs have processes in them. Setrunqueue puts processes
! 75: * into queues, Remrq removes them from queues. The running process is on
! 76: * no queue, other processes are on a queue related to p->p_priority, divided
! 77: * by 4 actually to shrink the 0-127 range of priorities into the 32 available
! 78: * queues.
! 79: */
! 80: /*
! 81: * setrunqueue(p)
! 82: * proc *p;
! 83: *
! 84: * Call should be made at splclock(), and p->p_stat should be SRUN.
! 85: */
! 86: NON_LEAF(setrunqueue, FRAMESZ(CF_SZ), ra)
! 87: .mask 0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ))
! 88: PTR_L t0, P_BACK(a0) ## firewall: p->p_back must be 0
! 89: bne t0, zero, 1f ##
! 90: lbu t0, P_PRIORITY(a0) # put on p->p_priority / 4 queue
! 91: li t1, 1 # compute corresponding bit
! 92: srl t0, t0, 2 # compute index into 'whichqs'
! 93: sll t1, t1, t0
! 94: lw t2, whichqs # set corresponding bit
! 95: sll t0, t0, LOGREGSZ+1 # compute index into 'qs'
! 96: or t2, t2, t1
! 97: sw t2, whichqs
! 98: LA t1, qs
! 99: PTR_ADDU t0, t0, t1 # t0 = qp = &qs[pri >> 2]
! 100: PTR_L t1, P_BACK(t0) # t1 = qp->ph_rlink
! 101: PTR_S t0, P_FORW(a0) # p->p_forw = qp
! 102: PTR_S t1, P_BACK(a0) # p->p_back = qp->ph_rlink
! 103: PTR_S a0, P_FORW(t1) # p->p_back->p_forw = p;
! 104: j ra
! 105: PTR_S a0, P_BACK(t0) # qp->ph_rlink = p
! 106:
! 107: 1:
! 108: PTR_SUBU sp, sp, FRAMESZ(CF_SZ)
! 109: PTR_S ra, CF_RA_OFFS(sp)
! 110: PANIC("setrunqueue")
! 111: jr ra
! 112: nop
! 113: END(setrunqueue)
! 114:
! 115: /*
! 116: * Remrq(p)
! 117: *
! 118: * Call should be made at splclock().
! 119: */
! 120: NON_LEAF(remrunqueue, FRAMESZ(CF_SZ), ra)
! 121: .mask 0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ))
! 122: lbu t0, P_PRIORITY(a0) # get from p->p_priority / 4 queue
! 123: li t1, 1 # compute corresponding bit
! 124: srl t0, t0, 2 # compute index into 'whichqs'
! 125: lw t2, whichqs # check corresponding bit
! 126: sll t1, t1, t0
! 127: and v0, t2, t1
! 128: beqz v0, 2f # oops! queue is empty!
! 129: PTR_L v0, P_BACK(a0) # v0 = p->p_back
! 130:
! 131: PTR_L v1, P_FORW(a0) # v1 = p->p_forw
! 132: PTR_SLL t0, t0, LOGREGSZ+1 # compute index into 'qs'
! 133: PTR_S v1, P_FORW(v0) # p->p_back->p_forw = p->p_forw;
! 134: PTR_S v0, P_BACK(v1) # p->p_forw->p_back = p->r_rlink
! 135: LA v0, qs
! 136: PTR_ADDU t0, t0, v0 # t0 = qp = &qs[pri >> 2]
! 137: PTR_L v0, P_FORW(t0) # check if queue empty
! 138: bne v0, t0, 1f # No. qp->ph_link != qp
! 139: xor t2, t2, t1 # clear corresponding bit in 'whichqs'
! 140: sw t2, whichqs
! 141: 1:
! 142: j ra
! 143: PTR_S zero, P_BACK(a0) # for firewall checking
! 144:
! 145: 2:
! 146: PTR_SUBU sp, sp, FRAMESZ(CF_SZ)
! 147: PTR_S ra, CF_RA_OFFS(sp)
! 148: PANIC("remrunqueue empty")
! 149: jr ra
! 150: nop
! 151: END(remrunqueue)
! 152:
! 153: /*
! 154: * Idle, this is where we spend time when nothing to do.
! 155: */
! 156: LEAF(idle, 0)
! 157: _idle:
! 158: sw zero, cpl # lower to spl0
! 159: lw t0, ipending
! 160: beqz t0, 1f
! 161: nop
! 162: jal setsoftintr0
! 163: nop
! 164: 1:
! 165: mfc0 a0, COP_0_STATUS_REG # ... and enable interrupts
! 166: li a1, SR_INT_ENAB
! 167: or a0, a0, a1
! 168: mtc0 a0, COP_0_STATUS_REG
! 169: ITLBNOPFIX
! 170:
! 171: #ifdef IMASK_EXTERNAL
! 172: jal hw_setintrmask
! 173: xor a0, a0
! 174: #endif
! 175: jal updateimask # Make sure SR imask is updated
! 176: xor a0, a0
! 177:
! 178: li t1,1
! 179: #if defined(TGT_CP7000) || defined(TGT_CP7000G)
! 180: PTR_L t2, misc_h # if non zero, do Ocelot LEDs.
! 181: beqz t2, 1f
! 182: li t0, 0x40
! 183: sb t0, 0x0d(t2)
! 184: #endif
! 185: 1:
! 186: lw t0, whichqs # look for non-empty queue
! 187: beq t0, zero, 1b
! 188: nop
! 189: #if defined(TGT_CP7000) || defined(TGT_CP7000G)
! 190: beqz t2, sw1
! 191: li t0, 0x40
! 192: sb t0, 0x0c(t2)
! 193: #endif
! 194: b sw1 # Hey, time to do some work!
! 195: nop
! 196: jr ra # DDB trace
! 197: nop
! 198: .globl e_idle
! 199: e_idle:
! 200: END(idle)
! 201:
! 202: /*
! 203: * switch_exit(p)
! 204: *
! 205: * At exit of a process, do a cpu_switch for the last time.
! 206: * All interrupts should be blocked at this point.
! 207: */
! 208: LEAF(switch_exit, 0)
! 209: mfc0 v0, COP_0_STATUS_REG
! 210: li v1, ~SR_INT_ENAB
! 211: and v0, v0, v1
! 212: mtc0 v0, COP_0_STATUS_REG
! 213: ITLBNOPFIX
! 214: LA sp, idle_stack - FRAMESZ(CF_SZ)
! 215: jal exit2
! 216: nop
! 217:
! 218: PTR_S zero, curproc
! 219: b sw0
! 220: nop
! 221: jr ra # DDB trace
! 222: nop
! 223: END(switch_exit)
! 224:
! 225: /*
! 226: * cpu_switch()
! 227: * Find the highest priority process and resume it.
! 228: */
! 229: NON_LEAF(cpu_switch, FRAMESZ(CF_SZ), ra)
! 230: PTR_L t3, curprocpaddr
! 231: REG_S sp, PCB_CONTEXT+8*REGSZ(t3) # save old sp
! 232: PTR_SUBU sp, sp, FRAMESZ(CF_SZ)
! 233: REG_S ra, CF_RA_OFFS(sp)
! 234: .mask 0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ))
! 235: lw t0, cpl
! 236: REG_S t0, PCB_CONTEXT+13*REGSZ(t3)
! 237: REG_S s0, PCB_CONTEXT+0*REGSZ(t3) # do a 'savectx()'
! 238: REG_S s1, PCB_CONTEXT+1*REGSZ(t3)
! 239: REG_S s2, PCB_CONTEXT+2*REGSZ(t3)
! 240: REG_S s3, PCB_CONTEXT+3*REGSZ(t3)
! 241: REG_S s4, PCB_CONTEXT+4*REGSZ(t3)
! 242: REG_S s5, PCB_CONTEXT+5*REGSZ(t3)
! 243: REG_S s6, PCB_CONTEXT+6*REGSZ(t3)
! 244: REG_S s7, PCB_CONTEXT+7*REGSZ(t3)
! 245: REG_S s8, PCB_CONTEXT+9*REGSZ(t3)
! 246: REG_S ra, PCB_CONTEXT+10*REGSZ(t3)
! 247: mfc0 t0, COP_0_STATUS_REG
! 248: cfc0 t1, COP_0_ICR
! 249: REG_S t0, PCB_CONTEXT+11*REGSZ(t3)
! 250: REG_S t1, PCB_CONTEXT+12*REGSZ(t3)
! 251:
! 252: sw0:
! 253: # lw t2, cnt+V_SWTCH # for statistics
! 254: lw t1, whichqs # look for non-empty queue
! 255: # addu t2, t2, 1
! 256: # sw t2, cnt+V_SWTCH
! 257: beq t1, zero, _idle # if none, idle
! 258: nop
! 259: sw1:
! 260: mfc0 v0, COP_0_STATUS_REG
! 261: li v1, ~SR_INT_ENAB
! 262: and v0, v0, v1
! 263: mtc0 v0, COP_0_STATUS_REG
! 264: ITLBNOPFIX
! 265: lw t0, whichqs # look for non-empty queue
! 266: li t2, -1 # t2 = lowest bit set
! 267: beq t0, zero, _idle # if none, idle
! 268: move t3, t0 # t3 = saved whichqs
! 269: 1:
! 270: addu t2, t2, 1
! 271: and t1, t0, 1 # bit set?
! 272: beq t1, zero, 1b
! 273: srl t0, t0, 1 # try next bit
! 274: /*
! 275: * Remove process from queue.
! 276: */
! 277: PTR_SLL t0, t2, LOGREGSZ+1
! 278: LA t1, qs
! 279: PTR_ADDU t0, t0, t1 # t0 = qp = &qs[highbit]
! 280: PTR_L a0, P_FORW(t0) # a0 = p = highest pri process
! 281: PTR_L v0, P_FORW(a0) # v0 = p->p_forw
! 282: beq t0, a0, 4f # make sure something in queue
! 283: PTR_S v0, P_FORW(t0) # qp->ph_link = p->p_forw;
! 284: PTR_S t0, P_BACK(v0) # p->p_forw->p_back = qp
! 285: bne v0, t0, 2f # queue still not empty
! 286: PTR_S zero, P_BACK(a0) ## for firewall checking
! 287: li v1, 1 # compute bit in 'whichqs'
! 288: sll v1, v1, t2
! 289: xor t3, t3, v1 # clear bit in 'whichqs'
! 290: sw t3, whichqs
! 291: 2:
! 292: /*
! 293: * Switch to new context.
! 294: */
! 295: sw zero, want_resched
! 296: jal pmap_activate # v0 = TLB PID
! 297: move s0, a0 # BDSLOT: save p
! 298:
! 299: /*
! 300: * We need to wire the process kernel stack mapping so there
! 301: * will be no tlb misses in exception handlers. This is done
! 302: * by invalidating any tlb entries mapping the U-area and
! 303: * put valid mappings in tlb entries 0 and 1.
! 304: */
! 305:
! 306: PTR_L t3, P_ADDR(s0) # get uarea pointer.
! 307: PTR_S s0, curproc # set curproc
! 308: PTR_S t3, curprocpaddr
! 309:
! 310: li t1, SONPROC
! 311: sb t1, P_STAT(s0) # set to onproc.
! 312:
! 313: or v0, t3
! 314: dmtc0 v0, COP_0_TLB_HI # init high entry (tlbid)
! 315: LA t1, (VM_MIN_KERNEL_ADDRESS)
! 316: PTR_SUBU t2, t3, t1
! 317: bltz t2, ctx3 # not mapped.
! 318: PTR_SRL t2, PGSHIFT+1
! 319: PTR_L t1, Sysmap
! 320: tlbp
! 321: PTR_SLL t2, 3
! 322: PTR_ADDU t1, t2 # t1 now points at ptes.
! 323: mfc0 t0, COP_0_TLB_INDEX
! 324: nop
! 325: bltz t0, ctx1 # not in tlb
! 326: LA t2, KSEG0_BASE # NOTE: if > 1 ins, does not matter
! 327:
! 328: dmtc0 t2, COP_0_TLB_HI # invalidate it.
! 329: dmtc0 zero, COP_0_TLB_LO0
! 330: dmtc0 zero, COP_0_TLB_LO1
! 331: nop
! 332: nop
! 333: nop
! 334: nop
! 335: tlbwi
! 336: nop
! 337: nop
! 338: nop
! 339:
! 340: ctx1:
! 341: mtc0 zero, COP_0_TLB_INDEX
! 342: dmtc0 v0, COP_0_TLB_HI
! 343: lw ta0, 0(t1)
! 344: lw ta1, 4(t1)
! 345: dsll ta0, ta0, 34
! 346: dsrl ta0, ta0, 34
! 347: dsll ta1, ta1, 34
! 348: dsrl ta1, ta1, 34
! 349: dmtc0 ta0, COP_0_TLB_LO0
! 350: dmtc0 ta1, COP_0_TLB_LO1
! 351: nop
! 352: PTR_ADDU v0, 2*NBPG
! 353: nop
! 354: nop
! 355: tlbwi
! 356:
! 357: #if (UPAGES != 2)
! 358: dmtc0 v0, COP_0_TLB_HI # init high entry (tlbid)
! 359: lw ta0, 8(t1)
! 360: lw ta1, 12(t1)
! 361: dsll ta0, ta0, 34
! 362: dsrl ta0, ta0, 34
! 363: tlbp
! 364: nop
! 365: dsll ta1, ta1, 34
! 366: dsrl ta1, ta1, 34
! 367: mfc0 t0, COP_0_TLB_INDEX
! 368: nop
! 369: bltz t0, ctx2 # not in tlb
! 370: li t2, 1
! 371:
! 372: dmtc0 t2, COP_0_TLB_HI # invalidate it.
! 373: dmtc0 zero, COP_0_TLB_LO0
! 374: dmtc0 zero, COP_0_TLB_LO1
! 375: nop
! 376: nop
! 377: nop
! 378: nop
! 379: tlbwi
! 380: nop
! 381: nop
! 382: nop
! 383:
! 384: ctx2:
! 385: mtc0 t2, COP_0_TLB_INDEX
! 386: dmtc0 v0, COP_0_TLB_HI
! 387: dmtc0 ta0, COP_0_TLB_LO0
! 388: dmtc0 ta1, COP_0_TLB_LO1
! 389: nop
! 390: nop
! 391: nop
! 392: nop
! 393: tlbwi
! 394: #endif
! 395: nop
! 396: nop
! 397: nop
! 398: nop
! 399:
! 400: ctx3:
! 401:
! 402: /*
! 403: * Restore registers and return.
! 404: */
! 405: REG_L a0, PCB_CONTEXT+13*REGSZ(t3)
! 406: REG_L s0, PCB_CONTEXT+0*REGSZ(t3)
! 407: REG_L s1, PCB_CONTEXT+1*REGSZ(t3)
! 408: REG_L s2, PCB_CONTEXT+2*REGSZ(t3)
! 409: REG_L s3, PCB_CONTEXT+3*REGSZ(t3)
! 410: REG_L s4, PCB_CONTEXT+4*REGSZ(t3)
! 411: REG_L s5, PCB_CONTEXT+5*REGSZ(t3)
! 412: REG_L s6, PCB_CONTEXT+6*REGSZ(t3)
! 413: REG_L s7, PCB_CONTEXT+7*REGSZ(t3)
! 414: REG_L sp, PCB_CONTEXT+8*REGSZ(t3)
! 415: REG_L s8, PCB_CONTEXT+9*REGSZ(t3)
! 416: sw a0, cpl
! 417: #ifdef IMASK_EXTERNAL
! 418: jal hw_setintrmask
! 419: nop
! 420: #endif
! 421: REG_L ra, PCB_CONTEXT+10*REGSZ(t3)
! 422: REG_L v0, PCB_CONTEXT+11*REGSZ(t3)
! 423: REG_L v1, PCB_CONTEXT+12*REGSZ(t3)
! 424: #ifndef IMASK_EXTERNAL
! 425: ctc0 v1, COP_0_ICR # XXX RM7000
! 426: #endif
! 427: mtc0 v0, COP_0_STATUS_REG
! 428: ITLBNOPFIX
! 429: j ra
! 430: nop
! 431: 4:
! 432: PANIC("cpu_switch") # nothing in queue
! 433: END(cpu_switch)
CVSweb