Annotation of sys/arch/mips64/mips64/context.S, Revision 1.1.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