make kernel includes standard
[unix-history] / usr / src / sys / pmax / pmax / locore.s
CommitLineData
dea92547
KM
1/*
2 * Copyright (c) 1992 Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Digital Equipment Corporation and Ralph Campbell.
7 *
8 * %sccs.include.redist.c%
9 *
10 * Copyright (C) 1989 Digital Equipment Corporation.
11 * Permission to use, copy, modify, and distribute this software and
12 * its documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appears in all copies.
14 * Digital Equipment Corporation makes no representations about the
15 * suitability of this software for any purpose. It is provided "as is"
16 * without express or implied warranty.
17 *
18 * from: $Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s,
19 * v 1.1 89/07/11 17:55:04 nelson Exp $ SPRITE (DECWRL)
20 * from: $Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s,
21 * v 9.2 90/01/29 18:00:39 shirriff Exp $ SPRITE (DECWRL)
22 * from: $Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s,
23 * v 1.1 89/07/10 14:27:41 nelson Exp $ SPRITE (DECWRL)
24 *
38a01dbe 25 * @(#)locore.s 7.9 (Berkeley) %G%
dea92547
KM
26 */
27
28/*
29 * Contains code that is the first executed at boot time plus
30 * assembly language support routines.
31 */
32
38a01dbe
KB
33#include <sys/errno.h>
34
35#include <machine/param.h>
36#include <machine/vmparam.h>
37#include <machine/psl.h>
38#include <machine/reg.h>
39#include <machine/machAsmDefs.h>
40#include <machine/pte.h>
dea92547 41
dea92547
KM
42#include "assym.h"
43
44/*
45 * Amount to take off of the stack for the benefit of the debugger.
46 */
47#define START_FRAME ((4 * 4) + 4 + 4)
48
49 .globl start
50start:
51 .set noreorder
52 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts
53 li t1, MACH_RESERVED_ADDR # invalid address
54 mtc0 t1, MACH_COP_0_TLB_HI # Mark entry high as invalid
55 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry.
56/*
57 * Clear the TLB (just to be safe).
58 * Align the starting value (t1), the increment (t2) and the upper bound (t3).
59 */
60 move t1, zero
61 li t2, 1 << VMMACH_TLB_INDEX_SHIFT
62 li t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
631:
64 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register.
65 addu t1, t1, t2 # Increment index.
66 bne t1, t3, 1b # NB: always executes next
67 tlbwi # Write the TLB entry.
68
69 li sp, MACH_CODE_START - START_FRAME
70 la gp, _gp
71 sw zero, START_FRAME - 4(sp) # Zero out old ra for debugger
72 jal mach_init # mach_init(argc, argv, envp)
73 sw zero, START_FRAME - 8(sp) # Zero out old fp for debugger
74
75 li t0, MACH_SR_COP_1_BIT # Disable interrupts and
76 mtc0 t0, MACH_COP_0_STATUS_REG # enable the coprocessor
77 li sp, KERNELSTACK - START_FRAME # switch to standard stack
78 mfc0 t0, MACH_COP_0_PRID # read processor ID register
79 cfc1 t1, MACH_FPC_ID # read FPU ID register
80 sw t0, cpu # save PRID register
81 sw t1, fpu # save FPU ID register
82 jal main # main()
83 nop
84
85/* proc[1] == /etc/init now running here; run icode */
86 li v0, PSL_USERSET
87 mtc0 v0, MACH_COP_0_STATUS_REG # switch to user mode
88 j zero # icode is at address zero
89 rfe
90 .set reorder
91
524dd2a1
RC
92/*
93 * GCC2 seems to want to call __main in main() for some reason.
94 */
95LEAF(__main)
96 j ra
97END(__main)
98
dea92547
KM
99/*
100 * This code is copied to user data space as the first program to run.
101 * Basically, it just calls execve();
102 */
103 .globl icode
104icode:
105 .set noreorder
106 li a1, (9 * 4) # address of 'icode_argv'
107 addu a0, a1, (3 * 4) # address of 'icode_fname'
108 move a2, zero # no environment
109 li v0, 59 # code for execve system call
110 syscall
111 li v0, 1 # code for exit system call
112 syscall # execve failed: call exit()
1131: b 1b # loop if exit returns
114 nop
115 .set reorder
116icode_argv:
117 .word (12 * 4) # address of 'icode_fname'
118 .word (15 * 4) # address of 'icodeEnd'
119 .word 0
120icode_fname:
121 .asciiz "/sbin/init" # occupies 3 words
122 .align 2
123 .globl icodeEnd
124icodeEnd:
125
126 .sdata
127 .align 2
128 .globl szicode
129szicode:
130 .word (9 + 3 + 3) * 4 # compute icodeEnd - icode
131 .text
132
133/*
134 * Primitives
135 */
136
137/*
138 * This table is indexed by u.u_pcb.pcb_onfault in trap().
139 * The reason for using this table rather than storing an address in
140 * u.u_pcb.pcb_onfault is simply to make the code faster.
141 */
142 .globl onfault_table
143 .data
144 .align 2
145onfault_table:
146 .word 0 # invalid index number
147#define BADERR 1
148 .word baderr
524dd2a1 149#define COPYERR 2
dea92547 150 .word copyerr
524dd2a1 151#define FSWBERR 3
dea92547 152 .word fswberr
524dd2a1
RC
153#define FSWINTRBERR 4
154 .word fswintrberr
8d50a649
RC
155#ifdef KADB
156#define KADBERR 5
157 .word kadberr
158#endif
dea92547
KM
159 .text
160
161/*
162 * See if access to addr with a len type instruction causes a machine check.
163 * len is length of access (1=byte, 2=short, 4=long)
164 *
165 * badaddr(addr, len)
166 * char *addr;
167 * int len;
168 */
169LEAF(badaddr)
170 li v0, BADERR
171 sw v0, UADDR+U_PCB_ONFAULT
172 bne a1, 1, 2f
173 lbu v0, (a0)
174 b 5f
1752:
176 bne a1, 2, 4f
177 lhu v0, (a0)
178 b 5f
1794:
180 lw v0, (a0)
1815:
182 sw zero, UADDR+U_PCB_ONFAULT
183 move v0, zero # made it w/o errors
184 j ra
185baderr:
186 li v0, 1 # trap sends us here
187 j ra
188END(badaddr)
189
dea92547
KM
190/*
191 * netorder = htonl(hostorder)
192 * hostorder = ntohl(netorder)
193 */
194LEAF(htonl) # a0 = 0x11223344, return 0x44332211
195ALEAF(ntohl)
196 srl v1, a0, 24 # v1 = 0x00000011
197 sll v0, a0, 24 # v0 = 0x44000000
198 or v0, v0, v1
199 and v1, a0, 0xff00
200 sll v1, v1, 8 # v1 = 0x00330000
201 or v0, v0, v1
202 srl v1, a0, 8
203 and v1, v1, 0xff00 # v1 = 0x00002200
204 or v0, v0, v1
205 j ra
206END(htonl)
207
208/*
209 * netorder = htons(hostorder)
210 * hostorder = ntohs(netorder)
211 */
212LEAF(htons)
213ALEAF(ntohs)
214 srl v0, a0, 8
215 and v0, v0, 0xff
216 sll v1, a0, 8
217 and v1, v1, 0xff00
218 or v0, v0, v1
219 j ra
220END(htons)
221
222/*
223 * bit = ffs(value)
224 */
225LEAF(ffs)
226 move v0, zero
227 beq a0, zero, 2f
2281:
229 and v1, a0, 1 # bit set?
230 addu v0, v0, 1
231 srl a0, a0, 1
232 beq v1, zero, 1b # no, continue
2332:
234 j ra
235END(ffs)
236
237/*
238 * strlen(str)
239 */
240LEAF(strlen)
241 addu v1, a0, 1
2421:
243 lb v0, 0(a0) # get byte from string
244 addu a0, a0, 1 # increment pointer
245 bne v0, zero, 1b # continue if not end
246 subu v0, a0, v1 # compute length - 1 for '\0' char
247 j ra
248END(strlen)
249
8d50a649
RC
250/*
251 * NOTE: this version assumes unsigned chars in order to be "8 bit clean".
252 */
253LEAF(strcmp)
2541:
255 lbu t0, 0(a0) # get two bytes and compare them
256 lbu t1, 0(a1)
257 beq t0, zero, LessOrEq # end of first string?
258 bne t0, t1, NotEq
259 lbu t0, 1(a0) # unroll loop
260 lbu t1, 1(a1)
261 add a0, a0, 2
262 beq t0, zero, LessOrEq # end of first string?
263 add a1, a1, 2
264 beq t0, t1, 1b
265NotEq:
266 subu v0, t0, t1
267 j ra
268LessOrEq:
269 subu v0, zero, t1
270 j ra
271END(strcmp)
272
dea92547
KM
273/*
274 * bzero(s1, n)
275 */
276LEAF(bzero)
277ALEAF(blkclr)
278 .set noreorder
279 blt a1, 12, smallclr # small amount to clear?
280 subu a3, zero, a0 # compute # bytes to word align address
281 and a3, a3, 3
282 beq a3, zero, 1f # skip if word aligned
283 subu a1, a1, a3 # subtract from remaining count
284 swr zero, 0(a0) # clear 1, 2, or 3 bytes to align
285 addu a0, a0, a3
2861:
287 and v0, a1, 3 # compute number of words left
288 subu a3, a1, v0
289 move a1, v0
290 addu a3, a3, a0 # compute ending address
2912:
292 addu a0, a0, 4 # clear words
293 bne a0, a3, 2b # unrolling loop doesn't help
294 sw zero, -4(a0) # since we're limited by memory speed
295smallclr:
296 ble a1, zero, 2f
297 addu a3, a1, a0 # compute ending address
2981:
299 addu a0, a0, 1 # clear bytes
300 bne a0, a3, 1b
301 sb zero, -1(a0)
3022:
303 j ra
304 nop
305 .set reorder
306END(bzero)
307
308/*
309 * bcmp(s1, s2, n)
310 */
311LEAF(bcmp)
312 .set noreorder
313 blt a2, 16, smallcmp # is it worth any trouble?
314 xor v0, a0, a1 # compare low two bits of addresses
315 and v0, v0, 3
316 subu a3, zero, a1 # compute # bytes to word align address
317 bne v0, zero, unalignedcmp # not possible to align addresses
318 and a3, a3, 3
319
320 beq a3, zero, 1f
321 subu a2, a2, a3 # subtract from remaining count
322 move v0, v1 # init v0,v1 so unmodified bytes match
323 lwr v0, 0(a0) # read 1, 2, or 3 bytes
324 lwr v1, 0(a1)
325 addu a1, a1, a3
326 bne v0, v1, nomatch
327 addu a0, a0, a3
3281:
329 and a3, a2, ~3 # compute number of whole words left
330 subu a2, a2, a3 # which has to be >= (16-3) & ~3
331 addu a3, a3, a0 # compute ending address
3322:
333 lw v0, 0(a0) # compare words
334 lw v1, 0(a1)
335 addu a0, a0, 4
336 bne v0, v1, nomatch
337 addu a1, a1, 4
338 bne a0, a3, 2b
339 nop
340 b smallcmp # finish remainder
341 nop
342unalignedcmp:
343 beq a3, zero, 2f
344 subu a2, a2, a3 # subtract from remaining count
345 addu a3, a3, a0 # compute ending address
3461:
347 lbu v0, 0(a0) # compare bytes until a1 word aligned
348 lbu v1, 0(a1)
349 addu a0, a0, 1
350 bne v0, v1, nomatch
351 addu a1, a1, 1
352 bne a0, a3, 1b
353 nop
3542:
355 and a3, a2, ~3 # compute number of whole words left
356 subu a2, a2, a3 # which has to be >= (16-3) & ~3
357 addu a3, a3, a0 # compute ending address
3583:
359 lwr v0, 0(a0) # compare words a0 unaligned, a1 aligned
360 lwl v0, 3(a0)
361 lw v1, 0(a1)
362 addu a0, a0, 4
363 bne v0, v1, nomatch
364 addu a1, a1, 4
365 bne a0, a3, 3b
366 nop
367smallcmp:
368 ble a2, zero, match
369 addu a3, a2, a0 # compute ending address
3701:
371 lbu v0, 0(a0)
372 lbu v1, 0(a1)
373 addu a0, a0, 1
374 bne v0, v1, nomatch
375 addu a1, a1, 1
376 bne a0, a3, 1b
377 nop
378match:
379 j ra
380 move v0, zero
381nomatch:
382 j ra
383 li v0, 1
384 .set reorder
385END(bcmp)
386
387/*
388 * {ov}bcopy(from, to, len)
389 */
390LEAF(bcopy)
391ALEAF(ovbcopy)
392 .set noreorder
393 addu t0, a0, a2 # t0 = end of s1 region
394 sltu t1, a1, t0
395 sltu t2, a0, a1
396 and t1, t1, t2 # t1 = true if from < to < (from+len)
397 beq t1, zero, forward # non overlapping, do forward copy
398 slt t2, a2, 12 # check for small copy
399
400 ble a2, zero, 2f
401 addu t1, a1, a2 # t1 = end of to region
4021:
403 lb v0, -1(t0) # copy bytes backwards,
404 subu t0, t0, 1 # doesn't happen often so do slow way
405 subu t1, t1, 1
406 bne t0, a0, 1b
407 sb v0, 0(t1)
4082:
409 j ra
410 nop
411forward:
412 bne t2, zero, smallcpy # do a small bcopy
413 xor v0, a0, a1 # compare low two bits of addresses
414 and v0, v0, 3
415 subu a3, zero, a1 # compute # bytes to word align address
416 beq v0, zero, aligned # addresses can be word aligned
417 and a3, a3, 3
418
419 beq a3, zero, 1f
420 subu a2, a2, a3 # subtract from remaining count
421 lwr v0, 0(a0) # get next 4 bytes (unaligned)
422 lwl v0, 3(a0)
423 addu a0, a0, a3
424 swr v0, 0(a1) # store 1, 2, or 3 bytes to align a1
425 addu a1, a1, a3
4261:
427 and v0, a2, 3 # compute number of words left
428 subu a3, a2, v0
429 move a2, v0
430 addu a3, a3, a0 # compute ending address
4312:
432 lwr v0, 0(a0) # copy words a0 unaligned, a1 aligned
433 lwl v0, 3(a0)
434 addu a0, a0, 4
435 addu a1, a1, 4
436 bne a0, a3, 2b
437 sw v0, -4(a1)
438 b smallcpy
439 nop
440aligned:
441 beq a3, zero, 1f
442 subu a2, a2, a3 # subtract from remaining count
443 lwr v0, 0(a0) # copy 1, 2, or 3 bytes to align
444 addu a0, a0, a3
445 swr v0, 0(a1)
446 addu a1, a1, a3
4471:
448 and v0, a2, 3 # compute number of whole words left
449 subu a3, a2, v0
450 move a2, v0
451 addu a3, a3, a0 # compute ending address
4522:
453 lw v0, 0(a0) # copy words
454 addu a0, a0, 4
455 addu a1, a1, 4
456 bne a0, a3, 2b
457 sw v0, -4(a1)
458smallcpy:
459 ble a2, zero, 2f
460 addu a3, a2, a0 # compute ending address
4611:
462 lbu v0, 0(a0) # copy bytes
463 addu a0, a0, 1
464 addu a1, a1, 1
465 bne a0, a3, 1b
466 sb v0, -1(a1)
4672:
468 sw zero, UADDR+U_PCB_ONFAULT # for copyin, copyout
469 j ra
470 move v0, zero
471 .set reorder
472END(bcopy)
473
474/*
475 * Copy a null terminated string within the kernel address space.
476 * Maxlength may be null if count not wanted.
477 * copystr(fromaddr, toaddr, maxlength, &lencopied)
478 * caddr_t fromaddr;
479 * caddr_t toaddr;
480 * u_int maxlength;
481 * u_int *lencopied;
482 */
483LEAF(copystr)
484 move t2, a2 # Save the number of bytes
4851:
486 lb t0, 0(a0)
487 sb t0, 0(a1)
488 sub a2, a2, 1
489 beq t0, zero, 2f
490 add a0, a0, 1
491 add a1, a1, 1
492 bne a2, zero, 1b
4932:
494 beq a3, zero, 3f
495 sub a2, t2, a2 # compute length copied
496 sw a2, 0(a3)
4973:
498 sw zero, UADDR+U_PCB_ONFAULT # for copyinstr, copyoutstr
499 move v0, zero
500 j ra
501END(copystr)
502
503/*
504 * Copy a null terminated string from the user address space into
505 * the kernel address space.
506 *
507 * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
508 * caddr_t fromaddr;
509 * caddr_t toaddr;
510 * u_int maxlength;
511 * u_int *lencopied;
512 */
513LEAF(copyinstr)
514 li v0, COPYERR
515 blt a0, zero, copyerr # make sure address is in user space
516 sw v0, UADDR+U_PCB_ONFAULT
517 b copystr
518END(copyinstr)
519
520/*
521 * Copy a null terminated string from the kernel address space into
522 * the user address space.
523 *
524 * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
525 * caddr_t fromaddr;
526 * caddr_t toaddr;
527 * u_int maxlength;
528 * u_int *lencopied;
529 */
530LEAF(copyoutstr)
531 li v0, COPYERR
532 blt a1, zero, copyerr # make sure address is in user space
533 sw v0, UADDR+U_PCB_ONFAULT
534 b copystr
535END(copyoutstr)
536
537/*
538 * Copy specified amount of data from user space into the kernel
539 * copyin(from, to, len)
540 * caddr_t *from; (user source address)
541 * caddr_t *to; (kernel destination address)
542 * unsigned len;
543 */
544LEAF(copyin)
545 li v0, COPYERR
546 blt a0, zero, copyerr # make sure address is in user space
547 sw v0, UADDR+U_PCB_ONFAULT
548 b bcopy
549END(copyin)
550
551/*
552 * Copy specified amount of data from kernel to the user space
553 * copyout(from, to, len)
554 * caddr_t *from; (kernel source address)
555 * caddr_t *to; (user destination address)
556 * unsigned len;
557 */
558LEAF(copyout)
559 li v0, COPYERR
560 blt a1, zero, copyerr # make sure address is in user space
561 sw v0, UADDR+U_PCB_ONFAULT
562 b bcopy
563END(copyout)
564
565LEAF(copyerr)
566 li v0, EFAULT # return error
567 j ra
568END(copyerr)
569
570/*
571 * Copy data to the DMA buffer.
572 * The DMA bufffer can only be written one short at a time
573 * (and takes ~14 cycles).
574 *
575 * CopyToBuffer(src, dst, length)
576 * u_short *src; NOTE: must be short aligned
577 * u_short *dst;
578 * int length;
579 */
580LEAF(CopyToBuffer)
581 blez a2, 2f
5821:
583 lhu t0, 0(a0) # read 2 bytes of data
584 subu a2, a2, 2
585 addu a0, a0, 2
586 addu a1, a1, 4
587 sh t0, -4(a1) # write 2 bytes of data to buffer
588 bgtz a2, 1b
5892:
590 j ra
591END(CopyToBuffer)
592
593/*
594 * Copy data from the DMA buffer.
595 * The DMA bufffer can only be read one short at a time
596 * (and takes ~12 cycles).
597 *
598 * CopyFromBuffer(src, dst, length)
599 * u_short *src;
600 * char *dst;
601 * int length;
602 */
603LEAF(CopyFromBuffer)
604 and t0, a1, 1 # test for aligned dst
605 beq t0, zero, 3f
606 blt a2, 2, 7f # at least 2 bytes to copy?
6071:
608 lhu t0, 0(a0) # read 2 bytes of data from buffer
609 addu a0, a0, 4 # keep buffer pointer word aligned
610 addu a1, a1, 2
611 subu a2, a2, 2
612 sb t0, -2(a1)
613 srl t0, t0, 8
614 sb t0, -1(a1)
615 bge a2, 2, 1b
6163:
617 blt a2, 2, 7f # at least 2 bytes to copy?
6186:
619 lhu t0, 0(a0) # read 2 bytes of data from buffer
620 addu a0, a0, 4 # keep buffer pointer word aligned
621 addu a1, a1, 2
622 subu a2, a2, 2
623 sh t0, -2(a1)
624 bge a2, 2, 6b
6257:
626 ble a2, zero, 9f # done?
627 lhu t0, 0(a0) # copy one more byte
628 sb t0, 0(a1)
6299:
630 j ra
631END(CopyFromBuffer)
632
633/*
634 * Copy the kernel stack to the new process and save the current context so
524dd2a1 635 * the new process will return nonzero when it is resumed by cpu_swtch().
dea92547
KM
636 *
637 * copykstack(up)
638 * struct user *up;
639 */
640LEAF(copykstack)
641 subu v0, sp, UADDR # compute offset into stack
642 addu v0, v0, a0 # v0 = new stack address
643 move v1, sp # v1 = old stack address
644 li t1, KERNELSTACK
6451:
646 lw t0, 0(v1) # copy stack data
647 addu v1, v1, 4
648 sw t0, 0(v0)
649 addu v0, v0, 4
650 bne v1, t1, 1b
651 /* FALLTHROUGH */
652/*
653 * Save registers and state so we can do a longjmp later.
654 * Note: this only works if p != curproc since
524dd2a1 655 * cpu_swtch() will copy over pcb_context.
dea92547
KM
656 *
657 * savectx(up)
658 * struct user *up;
659 */
660ALEAF(savectx)
661 .set noreorder
662 sw s0, U_PCB_CONTEXT+0(a0)
663 sw s1, U_PCB_CONTEXT+4(a0)
664 sw s2, U_PCB_CONTEXT+8(a0)
665 sw s3, U_PCB_CONTEXT+12(a0)
666 mfc0 v0, MACH_COP_0_STATUS_REG
667 sw s4, U_PCB_CONTEXT+16(a0)
668 sw s5, U_PCB_CONTEXT+20(a0)
669 sw s6, U_PCB_CONTEXT+24(a0)
670 sw s7, U_PCB_CONTEXT+28(a0)
671 sw sp, U_PCB_CONTEXT+32(a0)
672 sw s8, U_PCB_CONTEXT+36(a0)
673 sw ra, U_PCB_CONTEXT+40(a0)
674 sw v0, U_PCB_CONTEXT+44(a0)
675 j ra
676 move v0, zero
677 .set reorder
678END(copykstack)
679
680/*
681 * _whichqs tells which of the 32 queues _qs
682 * have processes in them. Setrq puts processes into queues, Remrq
683 * removes them from queues. The running process is on no queue,
684 * other processes are on a queue related to p->p_pri, divided by 4
685 * actually to shrink the 0-127 range of priorities into the 32 available
686 * queues.
687 */
688
689/*
690 * setrq(p)
691 * proc *p;
692 *
693 * Call should be made at splclock(), and p->p_stat should be SRUN.
694 */
695NON_LEAF(setrq, STAND_FRAME_SIZE, ra)
696 subu sp, sp, STAND_FRAME_SIZE
697 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
698 lw t0, P_RLINK(a0) ## firewall: p->p_rlink must be 0
dea92547 699 sw ra, STAND_RA_OFFSET(sp) ##
8d50a649 700 beq t0, zero, 1f ##
dea92547
KM
701 PANIC("setrq") ##
7021:
703 lbu t0, P_PRI(a0) # put on queue which is p->p_pri / 4
704 srl t0, t0, 2 # compute index into 'whichqs'
705 li t1, 1 # compute corresponding bit
706 sll t1, t1, t0
707 lw t2, whichqs # set corresponding bit
708 or t2, t2, t1
709 sw t2, whichqs
710 sll t0, t0, 3 # compute index into 'qs'
711 la t1, qs
712 addu t0, t0, t1 # t0 = qp = &qs[pri >> 2]
713 lw t1, P_RLINK(t0) # t1 = qp->ph_rlink
714 sw t0, P_LINK(a0) # p->p_link = qp
715 sw t1, P_RLINK(a0) # p->p_rlink = qp->ph_rlink
716 sw a0, P_LINK(t1) # p->p_rlink->p_link = p;
717 sw a0, P_RLINK(t0) # qp->ph_rlink = p
718 addu sp, sp, STAND_FRAME_SIZE
719 j ra
720END(setrq)
721
722/*
723 * Remrq(p)
724 *
725 * Call should be made at splclock().
726 */
727NON_LEAF(remrq, STAND_FRAME_SIZE, ra)
728 subu sp, sp, STAND_FRAME_SIZE
729 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
730 lbu t0, P_PRI(a0) # get from queue which is p->p_pri / 4
731 srl t0, t0, 2 # compute index into 'whichqs'
732 li t1, 1 # compute corresponding bit
733 sll t1, t1, t0
734 lw t2, whichqs # check corresponding bit
735 and v0, t2, t1
dea92547 736 sw ra, STAND_RA_OFFSET(sp) ##
8d50a649 737 bne v0, zero, 1f ##
dea92547
KM
738 PANIC("remrq") ## it wasn't recorded to be on its q
7391:
740 lw v0, P_RLINK(a0) # v0 = p->p_rlink
741 lw v1, P_LINK(a0) # v1 = p->p_link
742 sw v1, P_LINK(v0) # p->p_rlink->p_link = p->p_link;
743 sw v0, P_RLINK(v1) # p->p_link->p_rlink = p->r_rlink
744 sll t0, t0, 3 # compute index into 'qs'
745 la v0, qs
746 addu t0, t0, v0 # t0 = qp = &qs[pri >> 2]
747 lw v0, P_LINK(t0) # check if queue empty
748 bne v0, t0, 2f # No. qp->ph_link != qp
749 xor t2, t2, t1 # clear corresponding bit in 'whichqs'
750 sw t2, whichqs
7512:
752 sw zero, P_RLINK(a0) ## for firewall checking
753 addu sp, sp, STAND_FRAME_SIZE
754 j ra
755END(remrq)
756
757/*
758 * swtch_exit()
759 *
524dd2a1 760 * At exit of a process, do a cpu_swtch for the last time.
dea92547
KM
761 * The mapping of the pcb at p->p_addr has already been deleted,
762 * and the memory for the pcb+stack has been freed.
763 * All interrupts should be blocked at this point.
764 */
765LEAF(swtch_exit)
766 .set noreorder
767 la v0, nullproc # save state into garbage proc
768 lw t0, P_UPTE+0(v0) # t0 = first u. pte
769 lw t1, P_UPTE+4(v0) # t1 = 2nd u. pte
770 li v0, UADDR # v0 = first HI entry
771 mtc0 zero, MACH_COP_0_TLB_INDEX # set the index register
772 mtc0 v0, MACH_COP_0_TLB_HI # init high entry
773 mtc0 t0, MACH_COP_0_TLB_LOW # init low entry
774 li t0, 1 << VMMACH_TLB_INDEX_SHIFT
775 tlbwi # Write the TLB entry.
776 addu v0, v0, NBPG # 2nd HI entry
777 mtc0 t0, MACH_COP_0_TLB_INDEX # set the index register
778 mtc0 v0, MACH_COP_0_TLB_HI # init high entry
779 mtc0 t1, MACH_COP_0_TLB_LOW # init low entry
780 nop
781 tlbwi # Write the TLB entry.
782 .set reorder
783 li sp, KERNELSTACK - START_FRAME # switch to standard stack
524dd2a1 784 b cpu_swtch
dea92547
KM
785END(swtch_exit)
786
787/*
524dd2a1 788 * When no processes are on the runq, cpu_swtch branches to idle
dea92547 789 * to wait for something to come ready.
524dd2a1
RC
790 * Note: this is really a part of cpu_swtch() but defined here for kernel
791 * profiling.
dea92547
KM
792 */
793LEAF(idle)
794 .set noreorder
795 li t0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
796 mtc0 t0, MACH_COP_0_STATUS_REG # enable all interrupts
acb64c59 797 sw zero, curproc # set curproc NULL for stats
dea92547
KM
7981:
799 lw t0, whichqs # look for non-empty queue
8d50a649 800 nop
dea92547 801 beq t0, zero, 1b
8d50a649 802 nop
dea92547 803 b sw1
8d50a649
RC
804 mtc0 zero, MACH_COP_0_STATUS_REG # Disable all interrupts
805 .set reorder
dea92547
KM
806END(idle)
807
808/*
524dd2a1 809 * cpu_swtch()
dea92547
KM
810 * Find the highest priority process and resume it.
811 */
524dd2a1 812NON_LEAF(cpu_swtch, STAND_FRAME_SIZE, ra)
dea92547
KM
813 .set noreorder
814 sw sp, UADDR+U_PCB_CONTEXT+32 # save old sp
815 subu sp, sp, STAND_FRAME_SIZE
816 sw ra, STAND_RA_OFFSET(sp)
817 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
818 lw t2, cnt+V_SWTCH # for statistics
819 lw t1, whichqs # look for non-empty queue
820 mfc0 t0, MACH_COP_0_STATUS_REG # t0 = saved status register
821 sw ra, UADDR+U_PCB_CONTEXT+40 # save return address
822 sw t0, UADDR+U_PCB_CONTEXT+44 # save status register
823 addu t2, t2, 1
824 beq t1, zero, idle # if none, idle
825 sw t2, cnt+V_SWTCH
dea92547 826 mtc0 zero, MACH_COP_0_STATUS_REG # Disable all interrupts
8d50a649
RC
827sw1:
828 nop # wait for intrs disabled
dea92547
KM
829 nop
830 lw t0, whichqs # look for non-empty queue
831 li t2, -1 # t2 = lowest bit set
832 beq t0, zero, idle # if none, idle
833 move t3, t0 # t3 = saved whichqs
8341:
835 add t2, t2, 1
836 and t1, t0, 1 # bit set?
837 beq t1, zero, 1b
838 srl t0, t0, 1 # try next bit
839/*
840 * Remove process from queue.
841 */
842 sll t0, t2, 3
843 la t1, qs
844 addu t0, t0, t1 # t0 = qp = &qs[highbit]
845 lw a0, P_LINK(t0) # a0 = p = highest pri process
846 nop
847 lw v0, P_LINK(a0) # v0 = p->p_link
848 bne t0, a0, 2f # make sure something in queue
849 sw v0, P_LINK(t0) # qp->ph_link = p->p_link;
524dd2a1 850 PANIC("cpu_swtch") # nothing in queue
dea92547
KM
8512:
852 sw t0, P_RLINK(v0) # p->p_link->p_rlink = qp
853 bne v0, t0, 3f # queue still not empty
854 sw zero, P_RLINK(a0) ## for firewall checking
855 li v1, 1 # compute bit in 'whichqs'
856 sll v1, v1, t2
857 xor t3, t3, v1 # clear bit in 'whichqs'
858 sw t3, whichqs
8593:
860/*
861 * Save old context and switch to new one.
862 */
863 sw a0, curproc # set curproc
864 sw zero, want_resched
865 jal pmap_alloc_tlbpid # v0 = TLB PID
866 sw a0, STAND_FRAME_SIZE(sp) # save p
867 lw a0, STAND_FRAME_SIZE(sp) # restore p
868 sll v0, v0, VMMACH_TLB_PID_SHIFT # v0 = aligned PID
dea92547
KM
869 lw t0, P_UPTE+0(a0) # t0 = first u. pte
870 lw t1, P_UPTE+4(a0) # t1 = 2nd u. pte
871 sw s0, UADDR+U_PCB_CONTEXT+0 # do a 'savectx()'
872 sw s1, UADDR+U_PCB_CONTEXT+4 # We save s0 to s8 here because
873 sw s2, UADDR+U_PCB_CONTEXT+8 # the TLB trap code uses
874 sw s3, UADDR+U_PCB_CONTEXT+12 # CONTEXT and there should be
875 sw s4, UADDR+U_PCB_CONTEXT+16 # no faults at this point.
876 sw s5, UADDR+U_PCB_CONTEXT+20
877 sw s6, UADDR+U_PCB_CONTEXT+24
878 sw s7, UADDR+U_PCB_CONTEXT+28
879 sw s8, UADDR+U_PCB_CONTEXT+36
8d50a649 880 or v0, v0, UADDR # v0 = first HI entry
dea92547
KM
881/*
882 * Resume process indicated by the pte's for its u struct
883 * NOTE: This is hard coded to UPAGES == 2.
884 * Also, there should be no TLB faults at this point.
885 */
886 mtc0 zero, MACH_COP_0_TLB_INDEX # set the index register
887 mtc0 v0, MACH_COP_0_TLB_HI # init high entry
888 mtc0 t0, MACH_COP_0_TLB_LOW # init low entry
889 li t0, 1 << VMMACH_TLB_INDEX_SHIFT
890 tlbwi # Write the TLB entry.
891 addu v0, v0, NBPG # 2nd HI entry
892 mtc0 t0, MACH_COP_0_TLB_INDEX # set the index register
893 mtc0 v0, MACH_COP_0_TLB_HI # init high entry
894 mtc0 t1, MACH_COP_0_TLB_LOW # init low entry
895 nop
896 tlbwi # Write the TLB entry.
897/*
898 * Now running on new u struct.
899 * Restore registers and return.
900 */
901 lw v0, UADDR+U_PCB_CONTEXT+44 # restore kernel context
902 lw ra, UADDR+U_PCB_CONTEXT+40
903 lw s0, UADDR+U_PCB_CONTEXT+0
904 lw s1, UADDR+U_PCB_CONTEXT+4
905 lw s2, UADDR+U_PCB_CONTEXT+8
906 lw s3, UADDR+U_PCB_CONTEXT+12
907 lw s4, UADDR+U_PCB_CONTEXT+16
908 lw s5, UADDR+U_PCB_CONTEXT+20
909 lw s6, UADDR+U_PCB_CONTEXT+24
910 lw s7, UADDR+U_PCB_CONTEXT+28
911 lw sp, UADDR+U_PCB_CONTEXT+32
912 lw s8, UADDR+U_PCB_CONTEXT+36
913 mtc0 v0, MACH_COP_0_STATUS_REG
914 j ra
915 li v0, 1 # possible return to 'savectx()'
916 .set reorder
524dd2a1 917END(cpu_swtch)
dea92547
KM
918
919/*
524dd2a1
RC
920 * {fu,su},{ibyte,isword,iword}, fetch or store a byte, short or word to
921 * user text space.
922 * {fu,su},{byte,sword,word}, fetch or store a byte, short or word to
923 * user data space.
dea92547
KM
924 */
925LEAF(fuword)
926ALEAF(fuiword)
927 li v0, FSWBERR
928 blt a0, zero, fswberr # make sure address is in user space
929 sw v0, UADDR+U_PCB_ONFAULT
930 lw v0, 0(a0) # fetch word
931 sw zero, UADDR+U_PCB_ONFAULT
932 j ra
933END(fuword)
934
524dd2a1
RC
935LEAF(fusword)
936ALEAF(fuisword)
937 li v0, FSWBERR
938 blt a0, zero, fswberr # make sure address is in user space
939 sw v0, UADDR+U_PCB_ONFAULT
940 lhu v0, 0(a0) # fetch short
941 sw zero, UADDR+U_PCB_ONFAULT
942 j ra
943END(fusword)
944
dea92547
KM
945LEAF(fubyte)
946ALEAF(fuibyte)
947 li v0, FSWBERR
948 blt a0, zero, fswberr # make sure address is in user space
949 sw v0, UADDR+U_PCB_ONFAULT
950 lbu v0, 0(a0) # fetch byte
951 sw zero, UADDR+U_PCB_ONFAULT
952 j ra
953END(fubyte)
954
955LEAF(suword)
dea92547
KM
956 li v0, FSWBERR
957 blt a0, zero, fswberr # make sure address is in user space
958 sw v0, UADDR+U_PCB_ONFAULT
959 sw a1, 0(a0) # store word
960 sw zero, UADDR+U_PCB_ONFAULT
961 move v0, zero
962 j ra
963END(suword)
964
8d50a649
RC
965/*
966 * Have to flush instruction cache afterwards.
967 */
968LEAF(suiword)
969 li v0, FSWBERR
970 blt a0, zero, fswberr # make sure address is in user space
971 sw v0, UADDR+U_PCB_ONFAULT
972 sw a1, 0(a0) # store word
973 sw zero, UADDR+U_PCB_ONFAULT
974 move v0, zero
975 li a1, 4 # size of word
976 b MachFlushICache # NOTE: this should not clobber v0!
977END(suiword)
978
979/*
980 * Will have to flush the instruction cache if byte merging is done in hardware.
981 */
524dd2a1
RC
982LEAF(susword)
983ALEAF(suisword)
984 li v0, FSWBERR
985 blt a0, zero, fswberr # make sure address is in user space
986 sw v0, UADDR+U_PCB_ONFAULT
987 sh a1, 0(a0) # store short
988 sw zero, UADDR+U_PCB_ONFAULT
989 move v0, zero
990 j ra
991END(susword)
992
dea92547
KM
993LEAF(subyte)
994ALEAF(suibyte)
995 li v0, FSWBERR
996 blt a0, zero, fswberr # make sure address is in user space
997 sw v0, UADDR+U_PCB_ONFAULT
998 sb a1, 0(a0) # store byte
999 sw zero, UADDR+U_PCB_ONFAULT
1000 move v0, zero
1001 j ra
1002END(subyte)
1003
1004LEAF(fswberr)
1005 li v0, -1
1006 j ra
1007END(fswberr)
1008
524dd2a1
RC
1009/*
1010 * fuswintr and suswintr are just like fusword and susword except that if
1011 * the page is not in memory or would cause a trap, then we return an error.
1012 * The important thing is to prevent sleep() and swtch().
1013 */
1014LEAF(fuswintr)
1015 li v0, FSWINTRBERR
1016 blt a0, zero, fswintrberr # make sure address is in user space
1017 sw v0, UADDR+U_PCB_ONFAULT
1018 lhu v0, 0(a0) # fetch short
1019 sw zero, UADDR+U_PCB_ONFAULT
1020 j ra
1021END(fuswintr)
1022
1023LEAF(suswintr)
1024 li v0, FSWINTRBERR
1025 blt a0, zero, fswintrberr # make sure address is in user space
1026 sw v0, UADDR+U_PCB_ONFAULT
1027 sh a1, 0(a0) # store short
1028 sw zero, UADDR+U_PCB_ONFAULT
1029 move v0, zero
1030 j ra
1031END(suswintr)
1032
1033LEAF(fswintrberr)
1034 li v0, -1
1035 j ra
1036END(fswintrberr)
1037
dea92547
KM
1038/*
1039 * Insert 'p' after 'q'.
1040 * _insque(p, q)
1041 * caddr_t p, q;
1042 */
1043LEAF(_insque)
1044 lw v0, 0(a1) # v0 = q->next
1045 sw a1, 4(a0) # p->prev = q
1046 sw v0, 0(a0) # p->next = q->next
1047 sw a0, 4(v0) # q->next->prev = p
1048 sw a0, 0(a1) # q->next = p
1049 j ra
1050END(_insque)
1051
1052/*
1053 * Remove item 'p' from queue.
1054 * _remque(p)
1055 * caddr_t p;
1056 */
1057LEAF(_remque)
1058 lw v0, 0(a0) # v0 = p->next
1059 lw v1, 4(a0) # v1 = p->prev
1060 sw v0, 0(v1) # p->prev->next = p->next
1061 sw v1, 4(v0) # p->next->prev = p->prev
1062 j ra
1063END(_remque)
1064
1065/*
1066 * This code is copied to the UTLB exception vector address to
1067 * handle user level TLB translation misses.
1068 * NOTE: This code must be relocatable!!!
1069 */
1070 .globl MachUTLBMiss
1071MachUTLBMiss:
1072 .set noat
1073 .set noreorder
1074 mfc0 k0, MACH_COP_0_BAD_VADDR # get the virtual address
1075 nop
1076 srl k0, k0, PMAP_HASH_SHIFT1 # get page in low bits
1077 srl k1, k0, PMAP_HASH_SHIFT2 - PMAP_HASH_SHIFT1
1078 and k0, k0, PMAP_HASH_MASK1
1079 and k1, k1, PMAP_HASH_MASK2
1080 or k1, k1, k0
1081 sll k1, k1, PMAP_HASH_SIZE_SHIFT # compute index
1082 lw k0, PMAP_HASH_LOW_OFFSET(k1) # get cached low PTE entry
1083 lw k1, PMAP_HASH_HIGH_OFFSET(k1) # get cached high PTE entry
1084 mtc0 k0, MACH_COP_0_TLB_LOW
1085 mfc0 k0, MACH_COP_0_TLB_HI # get actual high PTE entry
1086 nop
1087 bne k0, k1, 1f # non-matching PTE
1088 mfc0 k0, MACH_COP_0_EXC_PC # get return address
1089 tlbwr # update TLB
1090 j k0
1091 rfe
10921:
c1b0ae6e 1093 j UtlbFault # handle the rest
dea92547
KM
1094 nop
1095 .set reorder
1096 .set at
1097 .globl MachUTLBMissEnd
1098MachUTLBMissEnd:
1099
1100/*
1101 * This code is copied to the general exception vector address to
1102 * handle all execptions except RESET and UTLBMiss.
1103 * NOTE: This code must be relocatable!!!
1104 */
1105 .globl MachException
1106MachException:
1107/*
1108 * Find out what mode we came from and jump to the proper handler.
1109 */
1110 .set noat
1111 .set noreorder
1112 mfc0 k0, MACH_COP_0_STATUS_REG # Get the status register
1113 mfc0 k1, MACH_COP_0_CAUSE_REG # Get the cause register value.
1114 and k0, k0, MACH_SR_KU_PREV # test for user mode
e52a96a4 1115 sll k0, k0, 3 # shift user bit for cause index
dea92547 1116 and k1, k1, MACH_CR_EXC_CODE # Mask out the cause bits.
e52a96a4 1117 or k1, k1, k0 # change index to user table
dea92547
KM
11181:
1119 la k0, machExceptionTable # get base of the jump table
e52a96a4 1120 addu k0, k0, k1 # Get the address of the
dea92547
KM
1121 # function entry. Note that
1122 # the cause is already
1123 # shifted left by 2 bits so
1124 # we don't have to shift.
1125 lw k0, 0(k0) # Get the function address
1126 nop
1127 j k0 # Jump to the function.
1128 nop
1129 .set reorder
1130 .set at
1131 .globl MachExceptionEnd
1132MachExceptionEnd:
1133
c1b0ae6e
KM
1134/*
1135 * Handle the rest of the UTLB miss.
1136 */
1137UtlbFault:
1138 .set noreorder
1139 .set noat
1140 mfc0 k0, MACH_COP_0_BAD_VADDR # get the virtual address
1141 nop
1142 srl k0, k0, PMAP_HASH_SHIFT1 # get page in low bits
1143 srl k1, k0, PMAP_HASH_SHIFT2 - PMAP_HASH_SHIFT1
1144 and k0, k0, PMAP_HASH_MASK1
1145 and k1, k1, PMAP_HASH_MASK2
1146 or k1, k1, k0
1147 sll k1, k1, PMAP_HASH_SIZE_SHIFT # compute index
1148 lw k0, PMAP_HASH_LOW_OFFSET+8(k1) # get cached low PTE entry
1149 lw k1, PMAP_HASH_HIGH_OFFSET+8(k1) # get cached high PTE entry
1150 mtc0 k0, MACH_COP_0_TLB_LOW
1151 mfc0 k0, MACH_COP_0_TLB_HI # get actual high PTE entry
1152 nop
1153 bne k0, k1, SlowFault # non-matching PTE
1154 mfc0 k0, MACH_COP_0_EXC_PC # get return address
1155 tlbwr # update TLB
1156 j k0
1157 rfe
dea92547
KM
1158/*
1159 * We couldn't find a TLB entry.
1160 * Find out what mode we came from and call the appropriate handler.
1161 */
1162SlowFault:
dea92547
KM
1163 mfc0 k0, MACH_COP_0_STATUS_REG
1164 nop
1165 and k0, k0, MACH_SR_KU_PREV
1166 bne k0, zero, MachUserGenException
1167 nop
1168 .set reorder
1169 .set at
1170/*
1171 * Fall though ...
1172 */
1173
1174/*----------------------------------------------------------------------------
1175 *
1176 * MachKernGenException --
1177 *
1178 * Handle an exception from kernel mode.
1179 *
1180 * Results:
1181 * None.
1182 *
1183 * Side effects:
1184 * None.
1185 *
1186 *----------------------------------------------------------------------------
1187 */
1188
1189/*
1190 * The kernel exception stack contains 18 saved general registers,
1191 * the status register and the multiply lo and high registers.
1192 * In addition, we set this up for linkage conventions.
1193 */
1194#define KERN_REG_SIZE (18 * 4)
1195#define KERN_REG_OFFSET (STAND_FRAME_SIZE)
1196#define KERN_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE)
1197#define KERN_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4)
1198#define KERN_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8)
1199#define KERN_EXC_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 12)
1200
1201NON_LEAF(MachKernGenException, KERN_EXC_FRAME_SIZE, ra)
1202 .set noreorder
1203 .set noat
8d50a649
RC
1204#ifdef KADB
1205 la k0, kdbpcb # save registers for kadb
1206 sw s0, (S0 * 4)(k0)
1207 sw s1, (S1 * 4)(k0)
1208 sw s2, (S2 * 4)(k0)
1209 sw s3, (S3 * 4)(k0)
1210 sw s4, (S4 * 4)(k0)
1211 sw s5, (S5 * 4)(k0)
1212 sw s6, (S6 * 4)(k0)
1213 sw s7, (S7 * 4)(k0)
1214 sw s8, (S8 * 4)(k0)
1215 sw gp, (GP * 4)(k0)
1216 sw sp, (SP * 4)(k0)
1217#endif
dea92547
KM
1218 subu sp, sp, KERN_EXC_FRAME_SIZE
1219 .mask 0x80000000, (STAND_RA_OFFSET - KERN_EXC_FRAME_SIZE)
1220/*
1221 * Save the relevant kernel registers onto the stack.
1222 * We don't need to save s0 - s8, sp and gp because
1223 * the compiler does it for us.
1224 */
1225 sw AT, KERN_REG_OFFSET + 0(sp)
1226 sw v0, KERN_REG_OFFSET + 4(sp)
1227 sw v1, KERN_REG_OFFSET + 8(sp)
1228 sw a0, KERN_REG_OFFSET + 12(sp)
1229 mflo v0
1230 mfhi v1
1231 sw a1, KERN_REG_OFFSET + 16(sp)
1232 sw a2, KERN_REG_OFFSET + 20(sp)
1233 sw a3, KERN_REG_OFFSET + 24(sp)
1234 sw t0, KERN_REG_OFFSET + 28(sp)
1235 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg.
1236 sw t1, KERN_REG_OFFSET + 32(sp)
1237 sw t2, KERN_REG_OFFSET + 36(sp)
1238 sw t3, KERN_REG_OFFSET + 40(sp)
1239 sw t4, KERN_REG_OFFSET + 44(sp)
1240 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg.
1241 sw t5, KERN_REG_OFFSET + 48(sp)
1242 sw t6, KERN_REG_OFFSET + 52(sp)
1243 sw t7, KERN_REG_OFFSET + 56(sp)
1244 sw t8, KERN_REG_OFFSET + 60(sp)
1245 mfc0 a2, MACH_COP_0_BAD_VADDR # Third arg is the fault addr.
1246 sw t9, KERN_REG_OFFSET + 64(sp)
1247 sw ra, KERN_REG_OFFSET + 68(sp)
1248 sw v0, KERN_MULT_LO_OFFSET(sp)
1249 sw v1, KERN_MULT_HI_OFFSET(sp)
1250 mfc0 a3, MACH_COP_0_EXC_PC # Fourth arg is the pc.
1251 sw a0, KERN_SR_OFFSET(sp)
1252/*
1253 * Call the exception handler.
1254 */
1255 jal trap
1256 sw a3, STAND_RA_OFFSET(sp) # for debugging
1257/*
1258 * Restore registers and return from the exception.
1259 * v0 contains the return address.
1260 */
1261 lw a0, KERN_SR_OFFSET(sp)
1262 lw t0, KERN_MULT_LO_OFFSET(sp)
1263 lw t1, KERN_MULT_HI_OFFSET(sp)
1264 mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs
1265 mtlo t0
1266 mthi t1
1267 move k0, v0
1268 lw AT, KERN_REG_OFFSET + 0(sp)
1269 lw v0, KERN_REG_OFFSET + 4(sp)
1270 lw v1, KERN_REG_OFFSET + 8(sp)
1271 lw a0, KERN_REG_OFFSET + 12(sp)
1272 lw a1, KERN_REG_OFFSET + 16(sp)
1273 lw a2, KERN_REG_OFFSET + 20(sp)
1274 lw a3, KERN_REG_OFFSET + 24(sp)
1275 lw t0, KERN_REG_OFFSET + 28(sp)
1276 lw t1, KERN_REG_OFFSET + 32(sp)
1277 lw t2, KERN_REG_OFFSET + 36(sp)
1278 lw t3, KERN_REG_OFFSET + 40(sp)
1279 lw t4, KERN_REG_OFFSET + 44(sp)
1280 lw t5, KERN_REG_OFFSET + 48(sp)
1281 lw t6, KERN_REG_OFFSET + 52(sp)
1282 lw t7, KERN_REG_OFFSET + 56(sp)
1283 lw t8, KERN_REG_OFFSET + 60(sp)
1284 lw t9, KERN_REG_OFFSET + 64(sp)
1285 lw ra, KERN_REG_OFFSET + 68(sp)
1286 addu sp, sp, KERN_EXC_FRAME_SIZE
1287 j k0 # Now return from the
1288 rfe # exception.
1289 .set at
1290 .set reorder
1291END(MachKernGenException)
1292
1293/*----------------------------------------------------------------------------
1294 *
1295 * MachUserGenException --
1296 *
1297 * Handle an exception from user mode.
1298 *
1299 * Results:
1300 * None.
1301 *
1302 * Side effects:
1303 * None.
1304 *
1305 *----------------------------------------------------------------------------
1306 */
1307NON_LEAF(MachUserGenException, STAND_FRAME_SIZE, ra)
1308 .set noreorder
1309 .set noat
1310 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
1311/*
1312 * Save all of the registers except for the kernel temporaries in u.u_pcb.
1313 */
1314 sw AT, UADDR+U_PCB_REGS+(AST * 4)
1315 sw v0, UADDR+U_PCB_REGS+(V0 * 4)
1316 sw v1, UADDR+U_PCB_REGS+(V1 * 4)
1317 sw a0, UADDR+U_PCB_REGS+(A0 * 4)
1318 mflo v0
1319 sw a1, UADDR+U_PCB_REGS+(A1 * 4)
1320 sw a2, UADDR+U_PCB_REGS+(A2 * 4)
1321 sw a3, UADDR+U_PCB_REGS+(A3 * 4)
1322 sw t0, UADDR+U_PCB_REGS+(T0 * 4)
1323 mfhi v1
1324 sw t1, UADDR+U_PCB_REGS+(T1 * 4)
1325 sw t2, UADDR+U_PCB_REGS+(T2 * 4)
1326 sw t3, UADDR+U_PCB_REGS+(T3 * 4)
1327 sw t4, UADDR+U_PCB_REGS+(T4 * 4)
1328 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg.
1329 sw t5, UADDR+U_PCB_REGS+(T5 * 4)
1330 sw t6, UADDR+U_PCB_REGS+(T6 * 4)
1331 sw t7, UADDR+U_PCB_REGS+(T7 * 4)
1332 sw s0, UADDR+U_PCB_REGS+(S0 * 4)
1333 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg.
1334 sw s1, UADDR+U_PCB_REGS+(S1 * 4)
1335 sw s2, UADDR+U_PCB_REGS+(S2 * 4)
1336 sw s3, UADDR+U_PCB_REGS+(S3 * 4)
1337 sw s4, UADDR+U_PCB_REGS+(S4 * 4)
1338 mfc0 a2, MACH_COP_0_BAD_VADDR # Third arg is the fault addr
1339 sw s5, UADDR+U_PCB_REGS+(S5 * 4)
1340 sw s6, UADDR+U_PCB_REGS+(S6 * 4)
1341 sw s7, UADDR+U_PCB_REGS+(S7 * 4)
1342 sw t8, UADDR+U_PCB_REGS+(T8 * 4)
1343 mfc0 a3, MACH_COP_0_EXC_PC # Fourth arg is the pc.
1344 sw t9, UADDR+U_PCB_REGS+(T9 * 4)
1345 sw gp, UADDR+U_PCB_REGS+(GP * 4)
1346 sw sp, UADDR+U_PCB_REGS+(SP * 4)
1347 sw s8, UADDR+U_PCB_REGS+(S8 * 4)
1348 li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP
1349 sw ra, UADDR+U_PCB_REGS+(RA * 4)
1350 sw v0, UADDR+U_PCB_REGS+(MULLO * 4)
1351 sw v1, UADDR+U_PCB_REGS+(MULHI * 4)
1352 sw a0, UADDR+U_PCB_REGS+(SR * 4)
1353 la gp, _gp # switch to kernel GP
1354 sw a3, UADDR+U_PCB_REGS+(PC * 4)
1355 sw a3, STAND_RA_OFFSET(sp) # for debugging
1356 and t0, a0, ~MACH_SR_COP_1_BIT # Turn off the FPU.
1357/*
1358 * Call the exception handler.
1359 */
1360 jal trap
1361 mtc0 t0, MACH_COP_0_STATUS_REG
1362/*
1363 * Restore user registers and return. NOTE: interrupts are enabled.
1364 */
1365 lw a0, UADDR+U_PCB_REGS+(SR * 4)
1366 lw t0, UADDR+U_PCB_REGS+(MULLO * 4)
1367 lw t1, UADDR+U_PCB_REGS+(MULHI * 4)
1368 mtc0 a0, MACH_COP_0_STATUS_REG # this should disable interrupts
1369 mtlo t0
1370 mthi t1
1371 lw k0, UADDR+U_PCB_REGS+(PC * 4)
1372 lw AT, UADDR+U_PCB_REGS+(AST * 4)
1373 lw v0, UADDR+U_PCB_REGS+(V0 * 4)
1374 lw v1, UADDR+U_PCB_REGS+(V1 * 4)
1375 lw a0, UADDR+U_PCB_REGS+(A0 * 4)
1376 lw a1, UADDR+U_PCB_REGS+(A1 * 4)
1377 lw a2, UADDR+U_PCB_REGS+(A2 * 4)
1378 lw a3, UADDR+U_PCB_REGS+(A3 * 4)
1379 lw t0, UADDR+U_PCB_REGS+(T0 * 4)
1380 lw t1, UADDR+U_PCB_REGS+(T1 * 4)
1381 lw t2, UADDR+U_PCB_REGS+(T2 * 4)
1382 lw t3, UADDR+U_PCB_REGS+(T3 * 4)
1383 lw t4, UADDR+U_PCB_REGS+(T4 * 4)
1384 lw t5, UADDR+U_PCB_REGS+(T5 * 4)
1385 lw t6, UADDR+U_PCB_REGS+(T6 * 4)
1386 lw t7, UADDR+U_PCB_REGS+(T7 * 4)
1387 lw s0, UADDR+U_PCB_REGS+(S0 * 4)
1388 lw s1, UADDR+U_PCB_REGS+(S1 * 4)
1389 lw s2, UADDR+U_PCB_REGS+(S2 * 4)
1390 lw s3, UADDR+U_PCB_REGS+(S3 * 4)
1391 lw s4, UADDR+U_PCB_REGS+(S4 * 4)
1392 lw s5, UADDR+U_PCB_REGS+(S5 * 4)
1393 lw s6, UADDR+U_PCB_REGS+(S6 * 4)
1394 lw s7, UADDR+U_PCB_REGS+(S7 * 4)
1395 lw t8, UADDR+U_PCB_REGS+(T8 * 4)
1396 lw t9, UADDR+U_PCB_REGS+(T9 * 4)
1397 lw gp, UADDR+U_PCB_REGS+(GP * 4)
1398 lw sp, UADDR+U_PCB_REGS+(SP * 4)
1399 lw s8, UADDR+U_PCB_REGS+(S8 * 4)
1400 lw ra, UADDR+U_PCB_REGS+(RA * 4)
1401 j k0
1402 rfe
1403 .set at
1404 .set reorder
1405END(MachUserGenException)
1406
1407/*----------------------------------------------------------------------------
1408 *
1409 * MachKernIntr --
1410 *
1411 * Handle an interrupt from kernel mode.
1412 * Interrupts must use a separate stack since during exit()
1413 * there is a window of time when there is no kernel stack.
1414 *
1415 * Results:
1416 * None.
1417 *
1418 * Side effects:
1419 * None.
1420 *
1421 *----------------------------------------------------------------------------
1422 */
1423#define KINTR_REG_OFFSET (STAND_FRAME_SIZE)
1424#define KINTR_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE)
1425#define KINTR_SP_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4)
1426#define KINTR_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8)
1427#define KINTR_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 12)
1428#define KINTR_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 16)
1429
1430NON_LEAF(MachKernIntr, KINTR_FRAME_SIZE, ra)
1431 .set noreorder
1432 .set noat
1433 .mask 0x80000000, (STAND_RA_OFFSET - KINTR_FRAME_SIZE)
1434/*
1435 * Check to see if we are already on the interrupt stack.
1436 */
1437 li k0, MACH_CODE_START # interrupt stack below code
1438 sltu k1, sp, k0
1439 beq k1, zero, 1f # no, init sp
1440 nop
1441 sw sp, KINTR_SP_OFFSET - KINTR_FRAME_SIZE(sp) # save old sp
1442 b 2f
1443 subu sp, sp, KINTR_FRAME_SIZE # allocate stack frame
14441:
1445 sw sp, KINTR_SP_OFFSET - KINTR_FRAME_SIZE(k0) # save old sp
1446 subu sp, k0, KINTR_FRAME_SIZE # switch to interrupt stack
14472:
1448/*
1449 * Save the relevant kernel registers onto the stack.
1450 * We don't need to save s0 - s8, sp and gp because
1451 * the compiler does it for us.
1452 */
1453 sw AT, KINTR_REG_OFFSET + 0(sp)
1454 sw v0, KINTR_REG_OFFSET + 4(sp)
1455 sw v1, KINTR_REG_OFFSET + 8(sp)
1456 sw a0, KINTR_REG_OFFSET + 12(sp)
1457 mflo v0
1458 mfhi v1
1459 sw a1, KINTR_REG_OFFSET + 16(sp)
1460 sw a2, KINTR_REG_OFFSET + 20(sp)
1461 sw a3, KINTR_REG_OFFSET + 24(sp)
1462 sw t0, KINTR_REG_OFFSET + 28(sp)
1463 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg.
1464 sw t1, KINTR_REG_OFFSET + 32(sp)
1465 sw t2, KINTR_REG_OFFSET + 36(sp)
1466 sw t3, KINTR_REG_OFFSET + 40(sp)
1467 sw t4, KINTR_REG_OFFSET + 44(sp)
1468 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg.
1469 sw t5, KINTR_REG_OFFSET + 48(sp)
1470 sw t6, KINTR_REG_OFFSET + 52(sp)
1471 sw t7, KINTR_REG_OFFSET + 56(sp)
1472 sw t8, KINTR_REG_OFFSET + 60(sp)
1473 mfc0 a2, MACH_COP_0_EXC_PC # Third arg is the pc.
1474 sw t9, KINTR_REG_OFFSET + 64(sp)
1475 sw ra, KINTR_REG_OFFSET + 68(sp)
1476 sw v0, KINTR_MULT_LO_OFFSET(sp)
1477 sw v1, KINTR_MULT_HI_OFFSET(sp)
1478 sw a0, KINTR_SR_OFFSET(sp)
1479/*
1480 * Call the interrupt handler.
1481 */
1482 jal interrupt
1483 sw a2, STAND_RA_OFFSET(sp) # for debugging
1484/*
1485 * Restore registers and return from the interrupt.
1486 */
1487 lw a0, KINTR_SR_OFFSET(sp)
1488 lw t0, KINTR_MULT_LO_OFFSET(sp)
1489 lw t1, KINTR_MULT_HI_OFFSET(sp)
1490 mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs
1491 mtlo t0
1492 mthi t1
1493 lw k0, STAND_RA_OFFSET(sp)
1494 lw AT, KINTR_REG_OFFSET + 0(sp)
1495 lw v0, KINTR_REG_OFFSET + 4(sp)
1496 lw v1, KINTR_REG_OFFSET + 8(sp)
1497 lw a0, KINTR_REG_OFFSET + 12(sp)
1498 lw a1, KINTR_REG_OFFSET + 16(sp)
1499 lw a2, KINTR_REG_OFFSET + 20(sp)
1500 lw a3, KINTR_REG_OFFSET + 24(sp)
1501 lw t0, KINTR_REG_OFFSET + 28(sp)
1502 lw t1, KINTR_REG_OFFSET + 32(sp)
1503 lw t2, KINTR_REG_OFFSET + 36(sp)
1504 lw t3, KINTR_REG_OFFSET + 40(sp)
1505 lw t4, KINTR_REG_OFFSET + 44(sp)
1506 lw t5, KINTR_REG_OFFSET + 48(sp)
1507 lw t6, KINTR_REG_OFFSET + 52(sp)
1508 lw t7, KINTR_REG_OFFSET + 56(sp)
1509 lw t8, KINTR_REG_OFFSET + 60(sp)
1510 lw t9, KINTR_REG_OFFSET + 64(sp)
1511 lw ra, KINTR_REG_OFFSET + 68(sp)
1512 lw sp, KINTR_SP_OFFSET(sp) # restore orig sp
1513 j k0 # Now return from the
1514 rfe # interrupt.
1515 .set at
1516 .set reorder
1517END(MachKernIntr)
1518
1519/*----------------------------------------------------------------------------
1520 *
1521 * MachUserIntr --
1522 *
1523 * Handle an interrupt from user mode.
1524 * Note: we save minimal state in the u.u_pcb struct and use the standard
1525 * kernel stack since there has to be a u page if we came from user mode.
1526 * If there is a pending software interrupt, then save the remaining state
1527 * and call softintr(). This is all because if we call swtch() inside
1528 * interrupt(), not all the user registers have been saved in u.u_pcb.
1529 *
1530 * Results:
1531 * None.
1532 *
1533 * Side effects:
1534 * None.
1535 *
1536 *----------------------------------------------------------------------------
1537 */
1538NON_LEAF(MachUserIntr, STAND_FRAME_SIZE, ra)
1539 .set noreorder
1540 .set noat
1541 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
1542/*
1543 * Save the relevant user registers into the u.u_pcb struct.
1544 * We don't need to save s0 - s8 because
1545 * the compiler does it for us.
1546 */
1547 sw AT, UADDR+U_PCB_REGS+(AST * 4)
1548 sw v0, UADDR+U_PCB_REGS+(V0 * 4)
1549 sw v1, UADDR+U_PCB_REGS+(V1 * 4)
1550 sw a0, UADDR+U_PCB_REGS+(A0 * 4)
1551 mflo v0
1552 mfhi v1
1553 sw a1, UADDR+U_PCB_REGS+(A1 * 4)
1554 sw a2, UADDR+U_PCB_REGS+(A2 * 4)
1555 sw a3, UADDR+U_PCB_REGS+(A3 * 4)
1556 sw t0, UADDR+U_PCB_REGS+(T0 * 4)
1557 mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg.
1558 sw t1, UADDR+U_PCB_REGS+(T1 * 4)
1559 sw t2, UADDR+U_PCB_REGS+(T2 * 4)
1560 sw t3, UADDR+U_PCB_REGS+(T3 * 4)
1561 sw t4, UADDR+U_PCB_REGS+(T4 * 4)
1562 mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg.
1563 sw t5, UADDR+U_PCB_REGS+(T5 * 4)
1564 sw t6, UADDR+U_PCB_REGS+(T6 * 4)
1565 sw t7, UADDR+U_PCB_REGS+(T7 * 4)
1566 sw t8, UADDR+U_PCB_REGS+(T8 * 4)
1567 mfc0 a2, MACH_COP_0_EXC_PC # Third arg is the pc.
1568 sw t9, UADDR+U_PCB_REGS+(T9 * 4)
1569 sw gp, UADDR+U_PCB_REGS+(GP * 4)
1570 sw sp, UADDR+U_PCB_REGS+(SP * 4)
1571 sw ra, UADDR+U_PCB_REGS+(RA * 4)
1572 li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP
1573 sw v0, UADDR+U_PCB_REGS+(MULLO * 4)
1574 sw v1, UADDR+U_PCB_REGS+(MULHI * 4)
1575 sw a0, UADDR+U_PCB_REGS+(SR * 4)
1576 sw a2, UADDR+U_PCB_REGS+(PC * 4)
1577 la gp, _gp # switch to kernel GP
1578 and t0, a0, ~MACH_SR_COP_1_BIT # Turn off the FPU.
1579 mtc0 t0, MACH_COP_0_STATUS_REG
1580/*
1581 * Call the interrupt handler.
1582 */
1583 jal interrupt
1584 sw a2, STAND_RA_OFFSET(sp) # for debugging
1585/*
1586 * Restore registers and return from the interrupt.
1587 */
1588 lw a0, UADDR+U_PCB_REGS+(SR * 4)
1589 lw v0, astpending # any pending interrupts?
1590 mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs
1591 bne v0, zero, 1f # don't restore, call softintr
1592 lw t0, UADDR+U_PCB_REGS+(MULLO * 4)
1593 lw t1, UADDR+U_PCB_REGS+(MULHI * 4)
1594 lw k0, UADDR+U_PCB_REGS+(PC * 4)
1595 lw AT, UADDR+U_PCB_REGS+(AST * 4)
1596 lw v0, UADDR+U_PCB_REGS+(V0 * 4)
1597 lw v1, UADDR+U_PCB_REGS+(V1 * 4)
1598 lw a0, UADDR+U_PCB_REGS+(A0 * 4)
1599 lw a1, UADDR+U_PCB_REGS+(A1 * 4)
1600 lw a2, UADDR+U_PCB_REGS+(A2 * 4)
1601 lw a3, UADDR+U_PCB_REGS+(A3 * 4)
1602 mtlo t0
1603 mthi t1
1604 lw t0, UADDR+U_PCB_REGS+(T0 * 4)
1605 lw t1, UADDR+U_PCB_REGS+(T1 * 4)
1606 lw t2, UADDR+U_PCB_REGS+(T2 * 4)
1607 lw t3, UADDR+U_PCB_REGS+(T3 * 4)
1608 lw t4, UADDR+U_PCB_REGS+(T4 * 4)
1609 lw t5, UADDR+U_PCB_REGS+(T5 * 4)
1610 lw t6, UADDR+U_PCB_REGS+(T6 * 4)
1611 lw t7, UADDR+U_PCB_REGS+(T7 * 4)
1612 lw t8, UADDR+U_PCB_REGS+(T8 * 4)
1613 lw t9, UADDR+U_PCB_REGS+(T9 * 4)
1614 lw gp, UADDR+U_PCB_REGS+(GP * 4)
1615 lw sp, UADDR+U_PCB_REGS+(SP * 4)
1616 lw ra, UADDR+U_PCB_REGS+(RA * 4)
1617 j k0 # Now return from the
1618 rfe # interrupt.
1619
16201:
1621/*
1622 * We have pending software interrupts; save remaining user state in u.u_pcb.
1623 */
1624 sw s0, UADDR+U_PCB_REGS+(S0 * 4)
1625 sw s1, UADDR+U_PCB_REGS+(S1 * 4)
1626 sw s2, UADDR+U_PCB_REGS+(S2 * 4)
1627 sw s3, UADDR+U_PCB_REGS+(S3 * 4)
1628 sw s4, UADDR+U_PCB_REGS+(S4 * 4)
1629 sw s5, UADDR+U_PCB_REGS+(S5 * 4)
1630 sw s6, UADDR+U_PCB_REGS+(S6 * 4)
1631 sw s7, UADDR+U_PCB_REGS+(S7 * 4)
1632 sw s8, UADDR+U_PCB_REGS+(S8 * 4)
1633 li t0, MACH_HARD_INT_MASK | MACH_SR_INT_ENA_CUR
1634/*
1635 * Call the software interrupt handler.
1636 */
1637 jal softintr
1638 mtc0 t0, MACH_COP_0_STATUS_REG # enable interrupts (spl0)
1639/*
1640 * Restore user registers and return. NOTE: interrupts are enabled.
1641 */
1642 lw a0, UADDR+U_PCB_REGS+(SR * 4)
1643 lw t0, UADDR+U_PCB_REGS+(MULLO * 4)
1644 lw t1, UADDR+U_PCB_REGS+(MULHI * 4)
1645 mtc0 a0, MACH_COP_0_STATUS_REG # this should disable interrupts
1646 mtlo t0
1647 mthi t1
1648 lw k0, UADDR+U_PCB_REGS+(PC * 4)
1649 lw AT, UADDR+U_PCB_REGS+(AST * 4)
1650 lw v0, UADDR+U_PCB_REGS+(V0 * 4)
1651 lw v1, UADDR+U_PCB_REGS+(V1 * 4)
1652 lw a0, UADDR+U_PCB_REGS+(A0 * 4)
1653 lw a1, UADDR+U_PCB_REGS+(A1 * 4)
1654 lw a2, UADDR+U_PCB_REGS+(A2 * 4)
1655 lw a3, UADDR+U_PCB_REGS+(A3 * 4)
1656 lw t0, UADDR+U_PCB_REGS+(T0 * 4)
1657 lw t1, UADDR+U_PCB_REGS+(T1 * 4)
1658 lw t2, UADDR+U_PCB_REGS+(T2 * 4)
1659 lw t3, UADDR+U_PCB_REGS+(T3 * 4)
1660 lw t4, UADDR+U_PCB_REGS+(T4 * 4)
1661 lw t5, UADDR+U_PCB_REGS+(T5 * 4)
1662 lw t6, UADDR+U_PCB_REGS+(T6 * 4)
1663 lw t7, UADDR+U_PCB_REGS+(T7 * 4)
1664 lw s0, UADDR+U_PCB_REGS+(S0 * 4)
1665 lw s1, UADDR+U_PCB_REGS+(S1 * 4)
1666 lw s2, UADDR+U_PCB_REGS+(S2 * 4)
1667 lw s3, UADDR+U_PCB_REGS+(S3 * 4)
1668 lw s4, UADDR+U_PCB_REGS+(S4 * 4)
1669 lw s5, UADDR+U_PCB_REGS+(S5 * 4)
1670 lw s6, UADDR+U_PCB_REGS+(S6 * 4)
1671 lw s7, UADDR+U_PCB_REGS+(S7 * 4)
1672 lw t8, UADDR+U_PCB_REGS+(T8 * 4)
1673 lw t9, UADDR+U_PCB_REGS+(T9 * 4)
1674 lw gp, UADDR+U_PCB_REGS+(GP * 4)
1675 lw sp, UADDR+U_PCB_REGS+(SP * 4)
1676 lw s8, UADDR+U_PCB_REGS+(S8 * 4)
1677 lw ra, UADDR+U_PCB_REGS+(RA * 4)
1678 j k0
1679 rfe
1680 .set at
1681 .set reorder
1682END(MachUserIntr)
1683
8d50a649 1684#if 0
dea92547
KM
1685/*----------------------------------------------------------------------------
1686 *
1687 * MachTLBModException --
1688 *
1689 * Handle a TLB modified exception.
1690 * The BaddVAddr, Context, and EntryHi registers contain the failed
1691 * virtual address.
1692 *
1693 * Results:
1694 * None.
1695 *
1696 * Side effects:
1697 * None.
1698 *
1699 *----------------------------------------------------------------------------
1700 */
1701LEAF(MachTLBModException)
dea92547
KM
1702 .set noreorder
1703 .set noat
1704 tlbp # find the TLB entry
1705 mfc0 k0, MACH_COP_0_TLB_LOW # get the physical address
1706 mfc0 k1, MACH_COP_0_TLB_INDEX # check to be sure its valid
1707 or k0, k0, VMMACH_TLB_MOD_BIT # update TLB
1708 blt k1, zero, 4f # not found!!!
1709 mtc0 k0, MACH_COP_0_TLB_LOW
1710 li k1, MACH_CACHED_MEMORY_ADDR
1711 subu k0, k0, k1
1712 srl k0, k0, VMMACH_TLB_PHYS_PAGE_SHIFT
1713 la k1, pmap_attributes
1714 add k0, k0, k1
1715 lbu k1, 0(k0) # fetch old value
1716 nop
1717 or k1, k1, 1 # set modified bit
1718 sb k1, 0(k0) # save new value
1719 mfc0 k0, MACH_COP_0_EXC_PC # get return address
1720 nop
1721 j k0
1722 rfe
17234:
1724 break 0 # panic
1725 .set reorder
1726 .set at
dea92547 1727END(MachTLBModException)
8d50a649 1728#endif
dea92547
KM
1729
1730/*----------------------------------------------------------------------------
1731 *
1732 * MachTLBMissException --
1733 *
1734 * Handle a TLB miss exception from kernel mode.
1735 * The BaddVAddr, Context, and EntryHi registers contain the failed
1736 * virtual address.
1737 *
1738 * Results:
1739 * None.
1740 *
1741 * Side effects:
1742 * None.
1743 *
1744 *----------------------------------------------------------------------------
1745 */
1746LEAF(MachTLBMissException)
1747 .set noreorder
1748 .set noat
1749 mfc0 k0, MACH_COP_0_BAD_VADDR # get the fault address
1750 li k1, MACH_KSEG2_ADDR # compute index
1751 subu k0, k0, k1
1752 srl k0, k0, PGSHIFT
1753 li k1, PMAP_HASH_KPAGES * NPTEPG # index within range?
1754 sltu k1, k0, k1
1755 beq k1, zero, SlowFault # No. do it the long way
1756 sll k0, k0, 2 # compute offset from index
1757 lw k0, PMAP_HASH_KADDR(k0) # get PTE entry
1758 mfc0 k1, MACH_COP_0_EXC_PC # get return address
1759 mtc0 k0, MACH_COP_0_TLB_LOW # save PTE entry
1760 and k0, k0, PG_V # make sure it's valid
1761 beq k0, zero, SlowFault # No. do it the long way
1762 nop
1763 tlbwr # update TLB
1764 j k1
1765 rfe
1766 .set reorder
1767 .set at
1768END(MachTLBMissException)
1769
1770/*
1771 * Set/clear software interrupt routines.
1772 */
1773
1774LEAF(setsoftclock)
1775 .set noreorder
1776 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register
1777 nop
1778 or v0, v0, MACH_SOFT_INT_MASK_0 # set soft clock interrupt
1779 mtc0 v0, MACH_COP_0_CAUSE_REG # save it
1780 j ra
1781 nop
1782 .set reorder
1783END(setsoftclock)
1784
1785LEAF(clearsoftclock)
1786 .set noreorder
1787 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register
1788 nop
1789 and v0, v0, ~MACH_SOFT_INT_MASK_0 # clear soft clock interrupt
1790 mtc0 v0, MACH_COP_0_CAUSE_REG # save it
1791 j ra
1792 nop
1793 .set reorder
1794END(clearsoftclock)
1795
1796LEAF(setsoftnet)
1797 .set noreorder
1798 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register
1799 nop
1800 or v0, v0, MACH_SOFT_INT_MASK_1 # set soft net interrupt
1801 mtc0 v0, MACH_COP_0_CAUSE_REG # save it
1802 j ra
1803 nop
1804 .set reorder
1805END(setsoftnet)
1806
1807LEAF(clearsoftnet)
1808 .set noreorder
1809 mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register
1810 nop
1811 and v0, v0, ~MACH_SOFT_INT_MASK_1 # clear soft net interrupt
1812 mtc0 v0, MACH_COP_0_CAUSE_REG # save it
1813 j ra
1814 nop
1815 .set reorder
1816END(clearsoftnet)
1817
1818/*
1819 * Set/change interrupt priority routines.
1820 */
1821
1822LEAF(MachEnableIntr)
1823 .set noreorder
1824 mfc0 v0, MACH_COP_0_STATUS_REG # read status register
1825 nop
1826 or v0, v0, MACH_SR_INT_ENA_CUR
1827 mtc0 v0, MACH_COP_0_STATUS_REG # enable all interrupts
1828 j ra
1829 nop
1830 .set reorder
1831END(MachEnableIntr)
1832
1833LEAF(spl0)
1834 .set noreorder
1835 mfc0 v0, MACH_COP_0_STATUS_REG # read status register
1836 nop
1837 or t0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1838 mtc0 t0, MACH_COP_0_STATUS_REG # enable all interrupts
1839 j ra
1840 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1841 .set reorder
1842END(spl0)
1843
1844LEAF(splsoftclock)
1845 .set noreorder
1846 mfc0 v0, MACH_COP_0_STATUS_REG # read status register
897d8278 1847 li t0, ~MACH_SOFT_INT_MASK_0 # disable soft clock
dea92547
KM
1848 and t0, t0, v0
1849 mtc0 t0, MACH_COP_0_STATUS_REG # save it
1850 j ra
1851 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1852 .set reorder
1853END(splsoftclock)
1854
8d50a649 1855LEAF(Mach_spl0)
897d8278
KM
1856 .set noreorder
1857 mfc0 v0, MACH_COP_0_STATUS_REG # read status register
8d50a649 1858 li t0, ~(MACH_INT_MASK_0|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0)
897d8278
KM
1859 and t0, t0, v0
1860 mtc0 t0, MACH_COP_0_STATUS_REG # save it
1861 j ra
1862 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1863 .set reorder
8d50a649 1864END(Mach_spl0)
897d8278 1865
8d50a649 1866LEAF(Mach_spl1)
dea92547
KM
1867 .set noreorder
1868 mfc0 v0, MACH_COP_0_STATUS_REG # read status register
8d50a649 1869 li t0, ~(MACH_INT_MASK_1|MACH_SOFT_INT_MASK_0|MACH_SOFT_INT_MASK_1)
dea92547
KM
1870 and t0, t0, v0
1871 mtc0 t0, MACH_COP_0_STATUS_REG # save it
1872 j ra
1873 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1874 .set reorder
8d50a649 1875END(Mach_spl1)
dea92547 1876
8d50a649 1877LEAF(Mach_spl2)
dea92547
KM
1878 .set noreorder
1879 mfc0 v0, MACH_COP_0_STATUS_REG # read status register
8d50a649 1880 li t0, ~(MACH_INT_MASK_2|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0)
dea92547
KM
1881 and t0, t0, v0
1882 mtc0 t0, MACH_COP_0_STATUS_REG # save it
1883 j ra
1884 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1885 .set reorder
8d50a649 1886END(Mach_spl2)
dea92547 1887
8d50a649 1888LEAF(Mach_spl3)
dea92547
KM
1889 .set noreorder
1890 mfc0 v0, MACH_COP_0_STATUS_REG # read status register
8d50a649 1891 li t0, ~(MACH_INT_MASK_3|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0)
dea92547
KM
1892 and t0, t0, v0
1893 mtc0 t0, MACH_COP_0_STATUS_REG # save it
1894 j ra
1895 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1896 .set reorder
8d50a649 1897END(Mach_spl3)
dea92547
KM
1898
1899LEAF(splhigh)
1900 .set noreorder
1901 mfc0 v0, MACH_COP_0_STATUS_REG # read status register
1902 li t0, ~MACH_SR_INT_ENA_CUR # disable all interrupts
1903 and t0, t0, v0
1904 mtc0 t0, MACH_COP_0_STATUS_REG # save it
1905 j ra
1906 and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1907 .set reorder
1908END(splhigh)
1909
1910/*
1911 * Restore saved interrupt mask.
1912 */
1913LEAF(splx)
1914 .set noreorder
1915 mfc0 v0, MACH_COP_0_STATUS_REG
1916 li t0, ~(MACH_INT_MASK | MACH_SR_INT_ENA_CUR)
1917 and t0, t0, v0
1918 or t0, t0, a0
1919 mtc0 t0, MACH_COP_0_STATUS_REG
1920 j ra
1921 nop
1922 .set reorder
1923END(splx)
1924
1925/*----------------------------------------------------------------------------
1926 *
1927 * MachEmptyWriteBuffer --
1928 *
1929 * Return when the write buffer is empty.
1930 *
1931 * MachEmptyWriteBuffer()
1932 *
1933 * Results:
1934 * None.
1935 *
1936 * Side effects:
1937 * None.
1938 *
1939 *----------------------------------------------------------------------------
1940 */
1941LEAF(MachEmptyWriteBuffer)
1942 .set noreorder
1943 nop
1944 nop
1945 nop
1946 nop
19471: bc0f 1b
1948 nop
1949 j ra
1950 nop
1951 .set reorder
1952END(MachEmptyWriteBuffer)
1953
1954/*--------------------------------------------------------------------------
1955 *
1956 * MachTLBWriteIndexed --
1957 *
1958 * Write the given entry into the TLB at the given index.
1959 *
1960 * MachTLBWriteIndexed(index, highEntry, lowEntry)
1961 * int index;
1962 * int highEntry;
1963 * int lowEntry;
1964 *
1965 * Results:
1966 * None.
1967 *
1968 * Side effects:
1969 * TLB entry set.
1970 *
1971 *--------------------------------------------------------------------------
1972 */
1973LEAF(MachTLBWriteIndexed)
1974 .set noreorder
1975 mfc0 t1, MACH_COP_0_STATUS_REG # Save the status register.
dea92547 1976 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts
8d50a649 1977 mfc0 t0, MACH_COP_0_TLB_HI # Save the current PID.
dea92547
KM
1978
1979 sll a0, a0, VMMACH_TLB_INDEX_SHIFT
1980 mtc0 a0, MACH_COP_0_TLB_INDEX # Set the index.
1981 mtc0 a1, MACH_COP_0_TLB_HI # Set up entry high.
1982 mtc0 a2, MACH_COP_0_TLB_LOW # Set up entry low.
1983 nop
1984 tlbwi # Write the TLB
1985
1986 mtc0 t0, MACH_COP_0_TLB_HI # Restore the PID.
1987 j ra
1988 mtc0 t1, MACH_COP_0_STATUS_REG # Restore the status register
1989 .set reorder
1990END(MachTLBWriteIndexed)
1991
1992/*--------------------------------------------------------------------------
1993 *
1994 * MachTLBWriteRandom --
1995 *
1996 * Write the given entry into the TLB at a random location.
1997 *
1998 * MachTLBWriteRandom(highEntry, lowEntry)
1999 * unsigned highEntry;
2000 * unsigned lowEntry;
2001 *
2002 * Results:
2003 * None.
2004 *
2005 * Side effects:
2006 * TLB entry set.
2007 *
2008 *--------------------------------------------------------------------------
2009 */
2010LEAF(MachTLBWriteRandom)
2011 .set noreorder
2012 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register.
dea92547 2013 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts
8d50a649 2014 mfc0 v0, MACH_COP_0_TLB_HI # Save the current PID.
dea92547
KM
2015
2016 mtc0 a0, MACH_COP_0_TLB_HI # Set up entry high.
2017 mtc0 a1, MACH_COP_0_TLB_LOW # Set up entry low.
2018 nop
2019 tlbwr # Write the TLB
2020
2021 mtc0 v0, MACH_COP_0_TLB_HI # Restore the PID.
2022 j ra
2023 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register
2024 .set reorder
2025END(MachTLBWriteRandom)
2026
2027/*--------------------------------------------------------------------------
2028 *
2029 * MachSetPID --
2030 *
2031 * Write the given pid into the TLB pid reg.
2032 *
2033 * MachSetPID(pid)
2034 * int pid;
2035 *
2036 * Results:
2037 * None.
2038 *
2039 * Side effects:
2040 * PID set in the entry hi register.
2041 *
2042 *--------------------------------------------------------------------------
2043 */
2044LEAF(MachSetPID)
2045 .set noreorder
2046 sll a0, a0, VMMACH_TLB_PID_SHIFT # put PID in right spot
2047 mtc0 a0, MACH_COP_0_TLB_HI # Write the hi reg value
2048 j ra
2049 nop
2050 .set reorder
2051END(MachSetPID)
2052
2053/*--------------------------------------------------------------------------
2054 *
2055 * MachTLBFlush --
2056 *
2057 * Flush the "random" entries from the TLB.
2058 *
2059 * MachTLBFlush()
2060 *
2061 * Results:
2062 * None.
2063 *
2064 * Side effects:
2065 * The TLB is flushed.
2066 *
2067 *--------------------------------------------------------------------------
2068 */
2069LEAF(MachTLBFlush)
2070 .set noreorder
2071 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register.
dea92547 2072 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts
8d50a649 2073 mfc0 t0, MACH_COP_0_TLB_HI # Save the PID
dea92547
KM
2074 li t1, MACH_RESERVED_ADDR # invalid address
2075 mtc0 t1, MACH_COP_0_TLB_HI # Mark entry high as invalid
2076 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry.
2077/*
8d50a649 2078 * Align the starting value (t1) and the upper bound (t2).
dea92547
KM
2079 */
2080 li t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT
8d50a649 2081 li t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
dea92547
KM
20821:
2083 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register.
8d50a649
RC
2084 addu t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT # Increment index.
2085 bne t1, t2, 1b # NB: always executes next
dea92547
KM
2086 tlbwi # Write the TLB entry.
2087
2088 mtc0 t0, MACH_COP_0_TLB_HI # Restore the PID
2089 j ra
2090 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register
2091 .set reorder
2092END(MachTLBFlush)
2093
2094/*--------------------------------------------------------------------------
2095 *
2096 * MachTLBFlushPID --
2097 *
2098 * Flush all entries with the given PID from the TLB.
2099 *
2100 * MachTLBFlushPID(pid)
2101 * int pid;
2102 *
2103 * Results:
2104 * None.
2105 *
2106 * Side effects:
2107 * All entries corresponding to this PID are flushed.
2108 *
2109 *--------------------------------------------------------------------------
2110 */
2111LEAF(MachTLBFlushPID)
2112 .set noreorder
2113 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register.
dea92547 2114 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts
8d50a649 2115 mfc0 t0, MACH_COP_0_TLB_HI # Save the current PID
dea92547
KM
2116 sll a0, a0, VMMACH_TLB_PID_SHIFT # Align the pid to flush.
2117/*
8d50a649 2118 * Align the starting value (t1) and the upper bound (t2).
dea92547
KM
2119 */
2120 li t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT
8d50a649 2121 li t2, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
dea92547
KM
2122 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register
21231:
8d50a649 2124 addu t1, t1, 1 << VMMACH_TLB_INDEX_SHIFT # Increment index.
dea92547
KM
2125 tlbr # Read from the TLB
2126 mfc0 t4, MACH_COP_0_TLB_HI # Fetch the hi register.
2127 nop
2128 and t4, t4, VMMACH_TLB_PID # compare PID's
2129 bne t4, a0, 2f
2130 li v0, MACH_RESERVED_ADDR # invalid address
2131 mtc0 v0, MACH_COP_0_TLB_HI # Mark entry high as invalid
2132 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry.
2133 nop
2134 tlbwi # Write the entry.
21352:
8d50a649 2136 bne t1, t2, 1b
dea92547
KM
2137 mtc0 t1, MACH_COP_0_TLB_INDEX # Set the index register
2138
2139 mtc0 t0, MACH_COP_0_TLB_HI # restore PID
2140 j ra
2141 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register
2142 .set reorder
2143END(MachTLBFlushPID)
2144
2145/*--------------------------------------------------------------------------
2146 *
2147 * MachTLBFlushAddr --
2148 *
8d50a649 2149 * Flush any TLB entries for the given address and TLB PID.
dea92547 2150 *
8d50a649
RC
2151 * MachTLBFlushAddr(highreg)
2152 * unsigned highreg;
dea92547
KM
2153 *
2154 * Results:
2155 * None.
2156 *
2157 * Side effects:
2158 * The process's page is flushed from the TLB.
2159 *
2160 *--------------------------------------------------------------------------
2161 */
2162LEAF(MachTLBFlushAddr)
2163 .set noreorder
2164 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register.
dea92547 2165 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts
8d50a649
RC
2166 mfc0 t0, MACH_COP_0_TLB_HI # Get current PID
2167
dea92547 2168 mtc0 a0, MACH_COP_0_TLB_HI # look for addr & PID
dea92547
KM
2169 nop
2170 tlbp # Probe for the entry.
2171 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got
2172 li t1, MACH_RESERVED_ADDR # Load invalid entry.
2173 bltz v0, 1f # index < 0 => !found
8d50a649
RC
2174 mtc0 t1, MACH_COP_0_TLB_HI # Mark entry high as invalid
2175 mtc0 zero, MACH_COP_0_TLB_LOW # Zero out low entry.
dea92547
KM
2176 nop
2177 tlbwi
21781:
2179 mtc0 t0, MACH_COP_0_TLB_HI # restore PID
2180 j ra
2181 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register
2182 .set reorder
2183END(MachTLBFlushAddr)
2184
2185/*--------------------------------------------------------------------------
2186 *
2187 * MachTLBUpdate --
2188 *
2189 * Update the TLB if highreg is found.
2190 *
2191 * MachTLBUpdate(highreg, lowreg)
2192 * unsigned highreg, lowreg;
2193 *
2194 * Results:
2195 * None.
2196 *
2197 * Side effects:
2198 * None.
2199 *
2200 *--------------------------------------------------------------------------
2201 */
2202LEAF(MachTLBUpdate)
2203 .set noreorder
2204 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register.
dea92547 2205 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts
8d50a649
RC
2206 mfc0 t0, MACH_COP_0_TLB_HI # Save current PID
2207
dea92547
KM
2208 mtc0 a0, MACH_COP_0_TLB_HI # init high reg.
2209 mtc0 a1, MACH_COP_0_TLB_LOW # init low reg.
2210 nop
2211 tlbp # Probe for the entry.
2212 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got
2213 nop
2214 bltz v0, 1f # index < 0 => !found
2215 nop
2216 tlbwi
22171:
2218 mtc0 t0, MACH_COP_0_TLB_HI # restore PID
2219 j ra
2220 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register
2221 .set reorder
2222END(MachTLBUpdate)
2223
8d50a649 2224#if defined(DEBUG) || defined(KADB)
dea92547
KM
2225/*--------------------------------------------------------------------------
2226 *
8d50a649 2227 * MachTLBFind --
dea92547 2228 *
8d50a649 2229 * Search the TLB for the given entry.
dea92547 2230 *
8d50a649
RC
2231 * MachTLBFind(hi)
2232 * unsigned hi;
dea92547
KM
2233 *
2234 * Results:
8d50a649
RC
2235 * Returns a value >= 0 if the entry was found (the index).
2236 * Returns a value < 0 if the entry was not found.
dea92547
KM
2237 *
2238 * Side effects:
8d50a649 2239 * tlbhi and tlblo will contain the TLB entry found.
dea92547
KM
2240 *
2241 *--------------------------------------------------------------------------
2242 */
dea92547
KM
2243 .comm tlbhi, 4
2244 .comm tlblo, 4
2245LEAF(MachTLBFind)
2246 .set noreorder
2247 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register.
dea92547 2248 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts
8d50a649
RC
2249 mfc0 t0, MACH_COP_0_TLB_HI # Get current PID
2250 nop
dea92547 2251 mtc0 a0, MACH_COP_0_TLB_HI # Set up entry high.
dea92547
KM
2252 nop
2253 tlbp # Probe for the entry.
2254 mfc0 v0, MACH_COP_0_TLB_INDEX # See what we got
8d50a649
RC
2255 nop
2256 bltz v0, 1f # not found
2257 nop
2258 tlbr # read TLB
dea92547
KM
2259 mfc0 t1, MACH_COP_0_TLB_HI # See what we got
2260 mfc0 t2, MACH_COP_0_TLB_LOW # See what we got
2261 sw t1, tlbhi
2262 sw t2, tlblo
8d50a649
RC
22631:
2264 mtc0 t0, MACH_COP_0_TLB_HI # Restore current PID
dea92547
KM
2265 j ra
2266 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register
2267 .set reorder
2268END(MachTLBFind)
2269
2270/*--------------------------------------------------------------------------
2271 *
8d50a649
RC
2272 * MachTLBRead --
2273 *
2274 * Read the TLB entry.
2275 *
2276 * MachTLBRead(entry)
2277 * unsigned entry;
2278 *
2279 * Results:
2280 * None.
2281 *
2282 * Side effects:
2283 * tlbhi and tlblo will contain the TLB entry found.
2284 *
2285 *--------------------------------------------------------------------------
2286 */
2287LEAF(MachTLBRead)
2288 .set noreorder
2289 mfc0 v1, MACH_COP_0_STATUS_REG # Save the status register.
2290 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts
2291 mfc0 t0, MACH_COP_0_TLB_HI # Get current PID
2292
2293 sll a0, a0, VMMACH_TLB_INDEX_SHIFT
2294 mtc0 a0, MACH_COP_0_TLB_INDEX # Set the index register
2295 nop
2296 tlbr # Read from the TLB
2297 mfc0 t3, MACH_COP_0_TLB_HI # fetch the hi entry
2298 mfc0 t4, MACH_COP_0_TLB_LOW # fetch the low entry
2299 sw t3, tlbhi
2300 sw t4, tlblo
2301
2302 mtc0 t0, MACH_COP_0_TLB_HI # restore PID
2303 j ra
2304 mtc0 v1, MACH_COP_0_STATUS_REG # Restore the status register
2305 .set reorder
2306END(MachTLBRead)
2307
2308/*--------------------------------------------------------------------------
2309 *
2310 * MachTLBGetPID --
dea92547 2311 *
8d50a649 2312 * MachTLBGetPID()
dea92547
KM
2313 *
2314 * Results:
2315 * Returns the current TLB pid reg.
2316 *
2317 * Side effects:
2318 * None.
2319 *
2320 *--------------------------------------------------------------------------
2321 */
8d50a649 2322LEAF(MachTLBGetPID)
dea92547
KM
2323 .set noreorder
2324 mfc0 v0, MACH_COP_0_TLB_HI # get PID
2325 nop
2326 and v0, v0, VMMACH_TLB_PID # mask off PID
2327 j ra
2328 srl v0, v0, VMMACH_TLB_PID_SHIFT # put PID in right spot
2329 .set reorder
8d50a649
RC
2330END(MachTLBGetPID)
2331
2332/*
2333 * Return the current value of the cause register.
2334 */
2335LEAF(MachGetCauseReg)
2336 .set noreorder
2337 mfc0 v0, MACH_COP_0_CAUSE_REG
2338 j ra
2339 nop
2340 .set reorder
2341END(MachGetCauseReg)
dea92547
KM
2342#endif /* DEBUG */
2343
2344/*----------------------------------------------------------------------------
2345 *
2346 * MachSwitchFPState --
2347 *
2348 * Save the current state into 'from' and restore it from 'to'.
2349 *
2350 * MachSwitchFPState(from, to)
2351 * struct proc *from;
2352 * struct user *to;
2353 *
2354 * Results:
2355 * None.
2356 *
2357 * Side effects:
2358 * None.
2359 *
2360 *----------------------------------------------------------------------------
2361 */
2362LEAF(MachSwitchFPState)
2363 .set noreorder
2364 mfc0 t1, MACH_COP_0_STATUS_REG # Save old SR
e52a96a4 2365 li t0, MACH_SR_COP_1_BIT # enable the coprocessor
e52a96a4 2366 mtc0 t0, MACH_COP_0_STATUS_REG
dea92547
KM
2367
2368 beq a0, zero, 1f # skip save if NULL pointer
2369 nop
2370/*
2371 * First read out the status register to make sure that all FP operations
2372 * have completed.
2373 */
2374 lw a0, P_ADDR(a0) # get pointer to pcb for proc
8d50a649
RC
2375 cfc1 t0, MACH_FPC_CSR # stall til FP done
2376 cfc1 t0, MACH_FPC_CSR # now get status
dea92547
KM
2377 li t3, ~MACH_SR_COP_1_BIT
2378 lw t2, U_PCB_REGS+(PS * 4)(a0) # get CPU status register
2379 sw t0, U_PCB_FPREGS+(32 * 4)(a0) # save FP status
2380 and t2, t2, t3 # clear COP_1 enable bit
2381 sw t2, U_PCB_REGS+(PS * 4)(a0) # save new status register
2382/*
2383 * Save the floating point registers.
2384 */
2385 swc1 $f0, U_PCB_FPREGS+(0 * 4)(a0)
2386 swc1 $f1, U_PCB_FPREGS+(1 * 4)(a0)
2387 swc1 $f2, U_PCB_FPREGS+(2 * 4)(a0)
2388 swc1 $f3, U_PCB_FPREGS+(3 * 4)(a0)
2389 swc1 $f4, U_PCB_FPREGS+(4 * 4)(a0)
2390 swc1 $f5, U_PCB_FPREGS+(5 * 4)(a0)
2391 swc1 $f6, U_PCB_FPREGS+(6 * 4)(a0)
2392 swc1 $f7, U_PCB_FPREGS+(7 * 4)(a0)
2393 swc1 $f8, U_PCB_FPREGS+(8 * 4)(a0)
2394 swc1 $f9, U_PCB_FPREGS+(9 * 4)(a0)
2395 swc1 $f10, U_PCB_FPREGS+(10 * 4)(a0)
2396 swc1 $f11, U_PCB_FPREGS+(11 * 4)(a0)
2397 swc1 $f12, U_PCB_FPREGS+(12 * 4)(a0)
2398 swc1 $f13, U_PCB_FPREGS+(13 * 4)(a0)
2399 swc1 $f14, U_PCB_FPREGS+(14 * 4)(a0)
2400 swc1 $f15, U_PCB_FPREGS+(15 * 4)(a0)
2401 swc1 $f16, U_PCB_FPREGS+(16 * 4)(a0)
2402 swc1 $f17, U_PCB_FPREGS+(17 * 4)(a0)
2403 swc1 $f18, U_PCB_FPREGS+(18 * 4)(a0)
2404 swc1 $f19, U_PCB_FPREGS+(19 * 4)(a0)
2405 swc1 $f20, U_PCB_FPREGS+(20 * 4)(a0)
2406 swc1 $f21, U_PCB_FPREGS+(21 * 4)(a0)
2407 swc1 $f22, U_PCB_FPREGS+(22 * 4)(a0)
2408 swc1 $f23, U_PCB_FPREGS+(23 * 4)(a0)
2409 swc1 $f24, U_PCB_FPREGS+(24 * 4)(a0)
2410 swc1 $f25, U_PCB_FPREGS+(25 * 4)(a0)
2411 swc1 $f26, U_PCB_FPREGS+(26 * 4)(a0)
2412 swc1 $f27, U_PCB_FPREGS+(27 * 4)(a0)
2413 swc1 $f28, U_PCB_FPREGS+(28 * 4)(a0)
2414 swc1 $f29, U_PCB_FPREGS+(29 * 4)(a0)
2415 swc1 $f30, U_PCB_FPREGS+(30 * 4)(a0)
2416 swc1 $f31, U_PCB_FPREGS+(31 * 4)(a0)
2417
24181:
2419/*
2420 * Restore the floating point registers.
2421 */
2422 lw t0, U_PCB_FPREGS+(32 * 4)(a1) # get status register
2423 lwc1 $f0, U_PCB_FPREGS+(0 * 4)(a1)
2424 lwc1 $f1, U_PCB_FPREGS+(1 * 4)(a1)
2425 lwc1 $f2, U_PCB_FPREGS+(2 * 4)(a1)
2426 lwc1 $f3, U_PCB_FPREGS+(3 * 4)(a1)
2427 lwc1 $f4, U_PCB_FPREGS+(4 * 4)(a1)
2428 lwc1 $f5, U_PCB_FPREGS+(5 * 4)(a1)
2429 lwc1 $f6, U_PCB_FPREGS+(6 * 4)(a1)
2430 lwc1 $f7, U_PCB_FPREGS+(7 * 4)(a1)
2431 lwc1 $f8, U_PCB_FPREGS+(8 * 4)(a1)
2432 lwc1 $f9, U_PCB_FPREGS+(9 * 4)(a1)
2433 lwc1 $f10, U_PCB_FPREGS+(10 * 4)(a1)
2434 lwc1 $f11, U_PCB_FPREGS+(11 * 4)(a1)
2435 lwc1 $f12, U_PCB_FPREGS+(12 * 4)(a1)
2436 lwc1 $f13, U_PCB_FPREGS+(13 * 4)(a1)
2437 lwc1 $f14, U_PCB_FPREGS+(14 * 4)(a1)
2438 lwc1 $f15, U_PCB_FPREGS+(15 * 4)(a1)
2439 lwc1 $f16, U_PCB_FPREGS+(16 * 4)(a1)
2440 lwc1 $f17, U_PCB_FPREGS+(17 * 4)(a1)
2441 lwc1 $f18, U_PCB_FPREGS+(18 * 4)(a1)
2442 lwc1 $f19, U_PCB_FPREGS+(19 * 4)(a1)
2443 lwc1 $f20, U_PCB_FPREGS+(20 * 4)(a1)
2444 lwc1 $f21, U_PCB_FPREGS+(21 * 4)(a1)
2445 lwc1 $f22, U_PCB_FPREGS+(22 * 4)(a1)
2446 lwc1 $f23, U_PCB_FPREGS+(23 * 4)(a1)
2447 lwc1 $f24, U_PCB_FPREGS+(24 * 4)(a1)
2448 lwc1 $f25, U_PCB_FPREGS+(25 * 4)(a1)
2449 lwc1 $f26, U_PCB_FPREGS+(26 * 4)(a1)
2450 lwc1 $f27, U_PCB_FPREGS+(27 * 4)(a1)
2451 lwc1 $f28, U_PCB_FPREGS+(28 * 4)(a1)
2452 lwc1 $f29, U_PCB_FPREGS+(29 * 4)(a1)
2453 lwc1 $f30, U_PCB_FPREGS+(30 * 4)(a1)
2454 lwc1 $f31, U_PCB_FPREGS+(31 * 4)(a1)
2455
2456 and t0, t0, ~MACH_FPC_EXCEPTION_BITS
2457 ctc1 t0, MACH_FPC_CSR
2458 nop
2459
2460 mtc0 t1, MACH_COP_0_STATUS_REG # Restore the status register.
2461 j ra
2462 nop
2463 .set reorder
2464END(MachSwitchFPState)
2465
2466/*----------------------------------------------------------------------------
2467 *
2468 * MachSaveCurFPState --
2469 *
2470 * Save the current floating point coprocessor state.
2471 *
2472 * MachSaveCurFPState(p)
2473 * struct proc *p;
2474 *
2475 * Results:
2476 * None.
2477 *
2478 * Side effects:
2fc367c2 2479 * machFPCurProcPtr is cleared.
dea92547
KM
2480 *
2481 *----------------------------------------------------------------------------
2482 */
2483LEAF(MachSaveCurFPState)
2484 .set noreorder
2485 lw a0, P_ADDR(a0) # get pointer to pcb for proc
2486 mfc0 t1, MACH_COP_0_STATUS_REG # Disable interrupts and
2487 li t0, MACH_SR_COP_1_BIT # enable the coprocessor
2488 mtc0 t0, MACH_COP_0_STATUS_REG
2fc367c2 2489 sw zero, machFPCurProcPtr # indicate state has been saved
dea92547
KM
2490/*
2491 * First read out the status register to make sure that all FP operations
2492 * have completed.
2493 */
2494 lw t2, U_PCB_REGS+(PS * 4)(a0) # get CPU status register
2495 li t3, ~MACH_SR_COP_1_BIT
2496 and t2, t2, t3 # clear COP_1 enable bit
8d50a649
RC
2497 cfc1 t0, MACH_FPC_CSR # stall til FP done
2498 cfc1 t0, MACH_FPC_CSR # now get status
dea92547
KM
2499 sw t2, U_PCB_REGS+(PS * 4)(a0) # save new status register
2500 sw t0, U_PCB_FPREGS+(32 * 4)(a0) # save FP status
2501/*
2502 * Save the floating point registers.
2503 */
2504 swc1 $f0, U_PCB_FPREGS+(0 * 4)(a0)
2505 swc1 $f1, U_PCB_FPREGS+(1 * 4)(a0)
2506 swc1 $f2, U_PCB_FPREGS+(2 * 4)(a0)
2507 swc1 $f3, U_PCB_FPREGS+(3 * 4)(a0)
2508 swc1 $f4, U_PCB_FPREGS+(4 * 4)(a0)
2509 swc1 $f5, U_PCB_FPREGS+(5 * 4)(a0)
2510 swc1 $f6, U_PCB_FPREGS+(6 * 4)(a0)
2511 swc1 $f7, U_PCB_FPREGS+(7 * 4)(a0)
2512 swc1 $f8, U_PCB_FPREGS+(8 * 4)(a0)
2513 swc1 $f9, U_PCB_FPREGS+(9 * 4)(a0)
2514 swc1 $f10, U_PCB_FPREGS+(10 * 4)(a0)
2515 swc1 $f11, U_PCB_FPREGS+(11 * 4)(a0)
2516 swc1 $f12, U_PCB_FPREGS+(12 * 4)(a0)
2517 swc1 $f13, U_PCB_FPREGS+(13 * 4)(a0)
2518 swc1 $f14, U_PCB_FPREGS+(14 * 4)(a0)
2519 swc1 $f15, U_PCB_FPREGS+(15 * 4)(a0)
2520 swc1 $f16, U_PCB_FPREGS+(16 * 4)(a0)
2521 swc1 $f17, U_PCB_FPREGS+(17 * 4)(a0)
2522 swc1 $f18, U_PCB_FPREGS+(18 * 4)(a0)
2523 swc1 $f19, U_PCB_FPREGS+(19 * 4)(a0)
2524 swc1 $f20, U_PCB_FPREGS+(20 * 4)(a0)
2525 swc1 $f21, U_PCB_FPREGS+(21 * 4)(a0)
2526 swc1 $f22, U_PCB_FPREGS+(22 * 4)(a0)
2527 swc1 $f23, U_PCB_FPREGS+(23 * 4)(a0)
2528 swc1 $f24, U_PCB_FPREGS+(24 * 4)(a0)
2529 swc1 $f25, U_PCB_FPREGS+(25 * 4)(a0)
2530 swc1 $f26, U_PCB_FPREGS+(26 * 4)(a0)
2531 swc1 $f27, U_PCB_FPREGS+(27 * 4)(a0)
2532 swc1 $f28, U_PCB_FPREGS+(28 * 4)(a0)
2533 swc1 $f29, U_PCB_FPREGS+(29 * 4)(a0)
2534 swc1 $f30, U_PCB_FPREGS+(30 * 4)(a0)
2535 swc1 $f31, U_PCB_FPREGS+(31 * 4)(a0)
2536
2537 mtc0 t1, MACH_COP_0_STATUS_REG # Restore the status register.
2538 j ra
2539 nop
2540 .set reorder
2541END(MachSaveCurFPState)
2542
2543/*----------------------------------------------------------------------------
2544 *
2545 * MachFPInterrupt --
2546 *
2547 * Handle a floating point interrupt.
2548 *
2549 * MachFPInterrupt(statusReg, causeReg, pc)
2550 * unsigned statusReg;
2551 * unsigned causeReg;
2552 * unsigned pc;
2553 *
2554 * Results:
2555 * None.
2556 *
2557 * Side effects:
2558 * None.
2559 *
2560 *----------------------------------------------------------------------------
2561 */
2562NON_LEAF(MachFPInterrupt, STAND_FRAME_SIZE, ra)
2563 .set noreorder
2564 subu sp, sp, STAND_FRAME_SIZE
2565 mfc0 t0, MACH_COP_0_STATUS_REG
2566 sw ra, STAND_RA_OFFSET(sp)
2567 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
2568
2569 or t1, t0, MACH_SR_COP_1_BIT
2570 mtc0 t1, MACH_COP_0_STATUS_REG
2571 nop
2572 nop
8d50a649
RC
2573 cfc1 t1, MACH_FPC_CSR # stall til FP done
2574 cfc1 t1, MACH_FPC_CSR # now get status
dea92547
KM
2575 nop
2576 .set reorder
2577 sll t2, t1, (31 - 17) # unimplemented operation?
2578 bgez t2, 3f # no, normal trap
2579/*
2580 * We got an unimplemented operation trap so
2581 * fetch the instruction, compute the next PC and emulate the instruction.
2582 */
2583 bgez a1, 1f # Check the branch delay bit.
2584/*
2585 * The instruction is in the branch delay slot so the branch will have to
2586 * be emulated to get the resulting PC.
2587 */
2588 sw a2, STAND_FRAME_SIZE + 8(sp)
2589 li a0, UADDR+U_PCB_REGS # first arg is ptr to CPU registers
2590 move a1, a2 # second arg is instruction PC
2591 move a2, t1 # third arg is floating point CSR
2592 move a3, zero # fourth arg is FALSE
2593 jal MachEmulateBranch # compute PC after branch
2594/*
2595 * Now load the floating-point instruction in the branch delay slot
2596 * to be emulated.
2597 */
2598 lw a2, STAND_FRAME_SIZE + 8(sp) # restore EXC pc
2599 lw a0, 4(a2) # a0 = coproc instruction
2600 b 2f
2601/*
2602 * This is not in the branch delay slot so calculate the resulting
2603 * PC (epc + 4) into v0 and continue to MachEmulateFP().
2604 */
26051:
2606 lw a0, 0(a2) # a0 = coproc instruction
2607 addu v0, a2, 4 # v0 = next pc
26082:
2609 sw v0, UADDR+U_PCB_REGS+(PC * 4) # save new pc
2610/*
2611 * Check to see if the instruction to be emulated is a floating-point
2612 * instruction.
2613 */
2614 srl a3, a0, MACH_OPCODE_SHIFT
2615 beq a3, MACH_OPCODE_C1, 4f # this should never fail
2616/*
2617 * Send a floating point exception signal to the current process.
2618 */
26193:
2620 lw a0, curproc # get current process
2621 cfc1 a2, MACH_FPC_CSR # code = FP execptions
2622 li a1, SIGFPE
2623 ctc1 zero, MACH_FPC_CSR # Clear exceptions
2624 jal trapsignal
2625 b FPReturn
2626
2627/*
2628 * Finally, we can call MachEmulateFP() where a0 is the instruction to emulate.
2629 */
26304:
2631 jal MachEmulateFP
2632
2633/*
2634 * Turn off the floating point coprocessor and return.
2635 */
2636FPReturn:
2637 .set noreorder
2638 mfc0 t0, MACH_COP_0_STATUS_REG
2639 lw ra, STAND_RA_OFFSET(sp)
2640 and t0, t0, ~MACH_SR_COP_1_BIT
2641 mtc0 t0, MACH_COP_0_STATUS_REG
2642 j ra
2643 addu sp, sp, STAND_FRAME_SIZE
2644 .set reorder
2645END(MachFPInterrupt)
2646
2647/*----------------------------------------------------------------------------
2648 *
2649 * MachConfigCache --
2650 *
2651 * Size the caches.
2652 * NOTE: should only be called from mach_init().
2653 *
2654 * Results:
2655 * None.
2656 *
2657 * Side effects:
2658 * The size of the data cache is stored into machDataCacheSize and the
2659 * size of instruction cache is stored into machInstCacheSize.
2660 *
2661 *----------------------------------------------------------------------------
2662 */
2663NON_LEAF(MachConfigCache, STAND_FRAME_SIZE, ra)
2664 .set noreorder
2665 subu sp, sp, STAND_FRAME_SIZE
2666 sw ra, STAND_RA_OFFSET(sp) # Save return address.
2667 .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
2668 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts.
2669 la v0, 1f
2670 or v0, MACH_UNCACHED_MEMORY_ADDR # Run uncached.
2671 j v0
2672 nop
26731:
2674/*
2675 * This works because jal doesn't change pc[31..28] and the
2676 * linker still thinks SizeCache is in the cached region so it computes
2677 * the correct address without complaining.
2678 */
2679 jal SizeCache # Get the size of the d-cache.
2680 nop
2681 sw v0, machDataCacheSize
2682 nop # Make sure sw out of pipe
2683 nop
2684 nop
2685 nop
2686 li v0, MACH_SR_SWAP_CACHES # Swap caches
2687 mtc0 v0, MACH_COP_0_STATUS_REG
2688 nop # Insure caches stable
2689 nop
2690 nop
2691 nop
2692 jal SizeCache # Get the size of the i-cache.
2693 nop
2694 sw v0, machInstCacheSize
2695 nop # Make sure sw out of pipe
2696 nop
2697 nop
2698 nop
2699 mtc0 zero, MACH_COP_0_STATUS_REG # Swap back caches.
2700 nop
2701 nop
2702 nop
2703 nop
2704 la t0, 1f
2705 j t0 # Back to cached mode
2706 nop
27071:
2708 lw ra, STAND_RA_OFFSET(sp) # Restore return addr
2709 addu sp, sp, STAND_FRAME_SIZE # Restore sp.
2710 j ra
2711 nop
2712 .set reorder
2713END(MachConfigCache)
2714
2715/*----------------------------------------------------------------------------
2716 *
2717 * SizeCache --
2718 *
2719 * Get the size of the cache.
2720 *
2721 * Results:
2722 * The size of the cache.
2723 *
2724 * Side effects:
2725 * None.
2726 *
2727 *----------------------------------------------------------------------------
2728 */
2729LEAF(SizeCache)
2730 .set noreorder
2731 mfc0 t0, MACH_COP_0_STATUS_REG # Save the current status reg.
2732 nop
2733 or v0, t0, MACH_SR_ISOL_CACHES # Isolate the caches.
2734 nop # Make sure no stores in pipe
2735 mtc0 v0, MACH_COP_0_STATUS_REG
2736 nop # Make sure isolated
2737 nop
2738 nop
2739/*
2740 * Clear cache size boundaries.
2741 */
2742 li v0, MACH_MIN_CACHE_SIZE
27431:
2744 sw zero, MACH_CACHED_MEMORY_ADDR(v0) # Clear cache memory
2745 sll v0, v0, 1
2746 bleu v0, +MACH_MAX_CACHE_SIZE, 1b
2747 nop
2748 li v0, -1
2749 sw v0, MACH_CACHED_MEMORY_ADDR(zero) # Store marker in cache
2750 li v0, MACH_MIN_CACHE_SIZE
27512:
2752 lw v1, MACH_CACHED_MEMORY_ADDR(v0) # Look for marker
2753 nop
2754 bne v1, zero, 3f # Found marker.
2755 nop
2756 sll v0, v0, 1 # cache size * 2
2757 bleu v0, +MACH_MAX_CACHE_SIZE, 2b # keep looking
2758 nop
2759 move v0, zero # must be no cache
27603:
2761 mtc0 t0, MACH_COP_0_STATUS_REG
2762 nop # Make sure unisolated
2763 nop
2764 nop
2765 nop
2766 j ra
2767 nop
2768 .set reorder
2769END(SizeCache)
2770
2771/*----------------------------------------------------------------------------
2772 *
2773 * MachFlushCache --
2774 *
2775 * Flush the caches.
2776 *
2777 * Results:
2778 * None.
2779 *
2780 * Side effects:
2781 * The contents of the caches is flushed.
2782 *
2783 *----------------------------------------------------------------------------
2784 */
2785LEAF(MachFlushCache)
2786 .set noreorder
2787 lw t1, machInstCacheSize # Must load before isolating
2788 lw t2, machDataCacheSize # Must load before isolating
2789 mfc0 t3, MACH_COP_0_STATUS_REG # Save the status register.
2790 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts.
2791 la v0, 1f
2792 or v0, MACH_UNCACHED_MEMORY_ADDR # Run uncached.
2793 j v0
2794 nop
2795/*
2796 * Flush the instruction cache.
2797 */
27981:
2799 li v0, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES
2800 mtc0 v0, MACH_COP_0_STATUS_REG # Isolate and swap caches.
2801 li t0, MACH_UNCACHED_MEMORY_ADDR
2802 subu t0, t0, t1
2803 li t1, MACH_UNCACHED_MEMORY_ADDR
2804 la v0, 1f # Run cached
2805 j v0
2806 nop
28071:
8d50a649 2808 addu t0, t0, 4
dea92547
KM
2809 bne t0, t1, 1b
2810 sb zero, -4(t0)
2811
2812 la v0, 1f
2813 or v0, MACH_UNCACHED_MEMORY_ADDR
2814 j v0 # Run uncached
2815 nop
2816/*
2817 * Flush the data cache.
2818 */
28191:
2820 li v0, MACH_SR_ISOL_CACHES
2821 mtc0 v0, MACH_COP_0_STATUS_REG # Isolate and swap back caches
2822 li t0, MACH_UNCACHED_MEMORY_ADDR
2823 subu t0, t0, t2
2824 la v0, 1f
2825 j v0 # Back to cached mode
2826 nop
28271:
8d50a649 2828 addu t0, t0, 4
dea92547
KM
2829 bne t0, t1, 1b
2830 sb zero, -4(t0)
2831
2832 nop # Insure isolated stores
2833 nop # out of pipe.
2834 nop
2835 nop
2836 mtc0 t3, MACH_COP_0_STATUS_REG # Restore status reg.
2837 nop # Insure cache unisolated.
2838 nop
2839 nop
2840 nop
2841 j ra
2842 nop
2843 .set reorder
2844END(MachFlushCache)
2845
2846/*----------------------------------------------------------------------------
2847 *
2848 * MachFlushICache --
2849 *
8d50a649
RC
2850 * void MachFlushICache(addr, len)
2851 * vm_offset_t addr, len;
dea92547
KM
2852 *
2853 * Flush instruction cache for range of addr to addr + len - 1.
8d50a649 2854 * The address can be any valid address so long as no TLB misses occur.
dea92547
KM
2855 *
2856 * Results:
2857 * None.
2858 *
2859 * Side effects:
2860 * The contents of the cache is flushed.
2861 *
2862 *----------------------------------------------------------------------------
2863 */
2864LEAF(MachFlushICache)
2865 .set noreorder
8d50a649 2866 mfc0 t0, MACH_COP_0_STATUS_REG # Save SR
dea92547
KM
2867 mtc0 zero, MACH_COP_0_STATUS_REG # Disable interrupts.
2868
8d50a649
RC
2869 la v1, 1f
2870 or v1, MACH_UNCACHED_MEMORY_ADDR # Run uncached.
2871 j v1
dea92547 2872 nop
dea92547 28731:
8d50a649
RC
2874 bc0f 1b # make sure stores are complete
2875 li v1, MACH_SR_ISOL_CACHES | MACH_SR_SWAP_CACHES
2876 mtc0 v1, MACH_COP_0_STATUS_REG
dea92547 2877 nop
8d50a649 2878 addu a1, a1, a0 # compute ending address
dea92547 28791:
8d50a649
RC
2880 addu a0, a0, 4
2881 bne a0, a1, 1b
2882 sb zero, -4(a0)
dea92547 2883
8d50a649 2884 mtc0 t0, MACH_COP_0_STATUS_REG # enable interrupts
dea92547
KM
2885 j ra # return and run cached
2886 nop
2887 .set reorder
2888END(MachFlushICache)
8d50a649
RC
2889
2890#ifdef KADB
2891/*
2892 * Read a long and return it.
2893 * Note: addresses can be unaligned!
2894 *
2895 * long
2896L* kdbpeek(addr)
2897L* caddt_t addr;
2898L* {
2899L* return (*(long *)addr);
2900L* }
2901 */
2902LEAF(kdbpeek)
2903 li v0, KADBERR
2904 sw v0, UADDR+U_PCB_ONFAULT
2905 and v0, a0, 3 # unaligned address?
2906 bne v0, zero, 1f
2907 lw v0, (a0) # aligned access
2908 b 2f
29091:
2910 lwr v0, 0(a0) # get next 4 bytes (unaligned)
2911 lwl v0, 3(a0)
29122:
2913 sw zero, UADDR+U_PCB_ONFAULT
2914 j ra # made it w/o errors
2915kadberr:
2916 li v0, 1 # trap sends us here
2917 sw v0, kdbmkfault
2918 j ra
2919END(kdbpeek)
2920
2921/*
2922 * Write a long to 'addr'.
2923 * Note: addresses can be unaligned!
2924 *
2925L* void
2926L* kdbpoke(addr, value)
2927L* caddt_t addr;
2928L* long value;
2929L* {
2930L* *(long *)addr = value;
2931L* }
2932 */
2933LEAF(kdbpoke)
2934 li v0, KADBERR
2935 sw v0, UADDR+U_PCB_ONFAULT
2936 and v0, a0, 3 # unaligned address?
2937 bne v0, zero, 1f
2938 sw a1, (a0) # aligned access
2939 b 2f
29401:
2941 swr a1, 0(a0) # store next 4 bytes (unaligned)
2942 swl a1, 3(a0)
2943 and a0, a0, ~3 # align address for cache flush
29442:
2945 sw zero, UADDR+U_PCB_ONFAULT
2946 li a1, 8
2947 b MachFlushICache # flush instruction cache
2948END(kdbpoke)
2949
2950/*
2951 * Save registers and state so we can do a 'kdbreset' (like longjmp) later.
2952 * Always returns zero.
2953 *
2954L* int kdb_savearea[11];
2955L*
2956L* int
2957L* kdbsetexit()
2958L* {
2959L* kdb_savearea[0] = 0;
2960L* return (0);
2961L* }
2962 */
2963 .comm kdb_savearea, (11 * 4)
2964
2965LEAF(kdbsetexit)
2966 .set noreorder
2967 la a0, kdb_savearea
2968 sw s0, 0(a0)
2969 sw s1, 4(a0)
2970 sw s2, 8(a0)
2971 sw s3, 12(a0)
2972 sw s4, 16(a0)
2973 sw s5, 20(a0)
2974 sw s6, 24(a0)
2975 sw s7, 28(a0)
2976 sw sp, 32(a0)
2977 sw s8, 36(a0)
2978 sw ra, 40(a0)
2979 j ra
2980 move v0, zero
2981 .set reorder
2982END(kdbsetexit)
2983
2984/*
2985 * Restore registers and state (like longjmp) and return x.
2986 *
2987L* int
2988L* kdbreset(x)
2989L* {
2990L* return (x);
2991L* }
2992 */
2993LEAF(kdbreset)
2994 .set noreorder
2995 la v0, kdb_savearea
2996 lw ra, 40(v0)
2997 lw s0, 0(v0)
2998 lw s1, 4(v0)
2999 lw s2, 8(v0)
3000 lw s3, 12(v0)
3001 lw s4, 16(v0)
3002 lw s5, 20(v0)
3003 lw s6, 24(v0)
3004 lw s7, 28(v0)
3005 lw sp, 32(v0)
3006 lw s8, 36(v0)
3007 j ra
3008 move v0, a0
3009 .set reorder
3010END(kdbreset)
3011
3012/*
3013 * Trap into the debugger.
3014 *
3015L* void
3016L* kdbpanic()
3017L* {
3018L* }
3019 */
3020LEAF(kdbpanic)
3021 break MACH_BREAK_KDB_VAL
3022 j ra
3023END(kdbpanic)
3024#endif /* KADB */