Commit | Line | Data |
---|---|---|
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 | |
50 | start: | |
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 | |
63 | 1: | |
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 | */ | |
95 | LEAF(__main) | |
96 | j ra | |
97 | END(__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 | |
104 | icode: | |
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() | |
113 | 1: b 1b # loop if exit returns | |
114 | nop | |
115 | .set reorder | |
116 | icode_argv: | |
117 | .word (12 * 4) # address of 'icode_fname' | |
118 | .word (15 * 4) # address of 'icodeEnd' | |
119 | .word 0 | |
120 | icode_fname: | |
121 | .asciiz "/sbin/init" # occupies 3 words | |
122 | .align 2 | |
123 | .globl icodeEnd | |
124 | icodeEnd: | |
125 | ||
126 | .sdata | |
127 | .align 2 | |
128 | .globl szicode | |
129 | szicode: | |
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 | |
145 | onfault_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 | */ | |
169 | LEAF(badaddr) | |
170 | li v0, BADERR | |
171 | sw v0, UADDR+U_PCB_ONFAULT | |
172 | bne a1, 1, 2f | |
173 | lbu v0, (a0) | |
174 | b 5f | |
175 | 2: | |
176 | bne a1, 2, 4f | |
177 | lhu v0, (a0) | |
178 | b 5f | |
179 | 4: | |
180 | lw v0, (a0) | |
181 | 5: | |
182 | sw zero, UADDR+U_PCB_ONFAULT | |
183 | move v0, zero # made it w/o errors | |
184 | j ra | |
185 | baderr: | |
186 | li v0, 1 # trap sends us here | |
187 | j ra | |
188 | END(badaddr) | |
189 | ||
dea92547 KM |
190 | /* |
191 | * netorder = htonl(hostorder) | |
192 | * hostorder = ntohl(netorder) | |
193 | */ | |
194 | LEAF(htonl) # a0 = 0x11223344, return 0x44332211 | |
195 | ALEAF(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 | |
206 | END(htonl) | |
207 | ||
208 | /* | |
209 | * netorder = htons(hostorder) | |
210 | * hostorder = ntohs(netorder) | |
211 | */ | |
212 | LEAF(htons) | |
213 | ALEAF(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 | |
220 | END(htons) | |
221 | ||
222 | /* | |
223 | * bit = ffs(value) | |
224 | */ | |
225 | LEAF(ffs) | |
226 | move v0, zero | |
227 | beq a0, zero, 2f | |
228 | 1: | |
229 | and v1, a0, 1 # bit set? | |
230 | addu v0, v0, 1 | |
231 | srl a0, a0, 1 | |
232 | beq v1, zero, 1b # no, continue | |
233 | 2: | |
234 | j ra | |
235 | END(ffs) | |
236 | ||
237 | /* | |
238 | * strlen(str) | |
239 | */ | |
240 | LEAF(strlen) | |
241 | addu v1, a0, 1 | |
242 | 1: | |
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 | |
248 | END(strlen) | |
249 | ||
8d50a649 RC |
250 | /* |
251 | * NOTE: this version assumes unsigned chars in order to be "8 bit clean". | |
252 | */ | |
253 | LEAF(strcmp) | |
254 | 1: | |
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 | |
265 | NotEq: | |
266 | subu v0, t0, t1 | |
267 | j ra | |
268 | LessOrEq: | |
269 | subu v0, zero, t1 | |
270 | j ra | |
271 | END(strcmp) | |
272 | ||
dea92547 KM |
273 | /* |
274 | * bzero(s1, n) | |
275 | */ | |
276 | LEAF(bzero) | |
277 | ALEAF(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 | |
286 | 1: | |
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 | |
291 | 2: | |
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 | |
295 | smallclr: | |
296 | ble a1, zero, 2f | |
297 | addu a3, a1, a0 # compute ending address | |
298 | 1: | |
299 | addu a0, a0, 1 # clear bytes | |
300 | bne a0, a3, 1b | |
301 | sb zero, -1(a0) | |
302 | 2: | |
303 | j ra | |
304 | nop | |
305 | .set reorder | |
306 | END(bzero) | |
307 | ||
308 | /* | |
309 | * bcmp(s1, s2, n) | |
310 | */ | |
311 | LEAF(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 | |
328 | 1: | |
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 | |
332 | 2: | |
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 | |
342 | unalignedcmp: | |
343 | beq a3, zero, 2f | |
344 | subu a2, a2, a3 # subtract from remaining count | |
345 | addu a3, a3, a0 # compute ending address | |
346 | 1: | |
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 | |
354 | 2: | |
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 | |
358 | 3: | |
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 | |
367 | smallcmp: | |
368 | ble a2, zero, match | |
369 | addu a3, a2, a0 # compute ending address | |
370 | 1: | |
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 | |
378 | match: | |
379 | j ra | |
380 | move v0, zero | |
381 | nomatch: | |
382 | j ra | |
383 | li v0, 1 | |
384 | .set reorder | |
385 | END(bcmp) | |
386 | ||
387 | /* | |
388 | * {ov}bcopy(from, to, len) | |
389 | */ | |
390 | LEAF(bcopy) | |
391 | ALEAF(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 | |
402 | 1: | |
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) | |
408 | 2: | |
409 | j ra | |
410 | nop | |
411 | forward: | |
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 | |
426 | 1: | |
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 | |
431 | 2: | |
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 | |
440 | aligned: | |
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 | |
447 | 1: | |
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 | |
452 | 2: | |
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) | |
458 | smallcpy: | |
459 | ble a2, zero, 2f | |
460 | addu a3, a2, a0 # compute ending address | |
461 | 1: | |
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) | |
467 | 2: | |
468 | sw zero, UADDR+U_PCB_ONFAULT # for copyin, copyout | |
469 | j ra | |
470 | move v0, zero | |
471 | .set reorder | |
472 | END(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 | */ | |
483 | LEAF(copystr) | |
484 | move t2, a2 # Save the number of bytes | |
485 | 1: | |
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 | |
493 | 2: | |
494 | beq a3, zero, 3f | |
495 | sub a2, t2, a2 # compute length copied | |
496 | sw a2, 0(a3) | |
497 | 3: | |
498 | sw zero, UADDR+U_PCB_ONFAULT # for copyinstr, copyoutstr | |
499 | move v0, zero | |
500 | j ra | |
501 | END(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 | */ | |
513 | LEAF(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 | |
518 | END(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 | */ | |
530 | LEAF(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 | |
535 | END(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 | */ | |
544 | LEAF(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 | |
549 | END(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 | */ | |
558 | LEAF(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 | |
563 | END(copyout) | |
564 | ||
565 | LEAF(copyerr) | |
566 | li v0, EFAULT # return error | |
567 | j ra | |
568 | END(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 | */ | |
580 | LEAF(CopyToBuffer) | |
581 | blez a2, 2f | |
582 | 1: | |
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 | |
589 | 2: | |
590 | j ra | |
591 | END(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 | */ | |
603 | LEAF(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? | |
607 | 1: | |
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 | |
616 | 3: | |
617 | blt a2, 2, 7f # at least 2 bytes to copy? | |
618 | 6: | |
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 | |
625 | 7: | |
626 | ble a2, zero, 9f # done? | |
627 | lhu t0, 0(a0) # copy one more byte | |
628 | sb t0, 0(a1) | |
629 | 9: | |
630 | j ra | |
631 | END(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 | */ | |
640 | LEAF(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 | |
645 | 1: | |
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 | */ | |
660 | ALEAF(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 | |
678 | END(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 | */ | |
695 | NON_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") ## |
702 | 1: | |
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 | |
720 | END(setrq) | |
721 | ||
722 | /* | |
723 | * Remrq(p) | |
724 | * | |
725 | * Call should be made at splclock(). | |
726 | */ | |
727 | NON_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 |
739 | 1: | |
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 | |
751 | 2: | |
752 | sw zero, P_RLINK(a0) ## for firewall checking | |
753 | addu sp, sp, STAND_FRAME_SIZE | |
754 | j ra | |
755 | END(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 | */ | |
765 | LEAF(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 |
785 | END(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 | */ |
793 | LEAF(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 |
798 | 1: |
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 |
806 | END(idle) |
807 | ||
808 | /* | |
524dd2a1 | 809 | * cpu_swtch() |
dea92547 KM |
810 | * Find the highest priority process and resume it. |
811 | */ | |
524dd2a1 | 812 | NON_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 |
827 | sw1: |
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 | |
834 | 1: | |
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 |
851 | 2: |
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 | |
859 | 3: | |
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 | 917 | END(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 | */ |
925 | LEAF(fuword) | |
926 | ALEAF(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 | |
933 | END(fuword) | |
934 | ||
524dd2a1 RC |
935 | LEAF(fusword) |
936 | ALEAF(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 | |
943 | END(fusword) | |
944 | ||
dea92547 KM |
945 | LEAF(fubyte) |
946 | ALEAF(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 | |
953 | END(fubyte) | |
954 | ||
955 | LEAF(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 | |
963 | END(suword) | |
964 | ||
8d50a649 RC |
965 | /* |
966 | * Have to flush instruction cache afterwards. | |
967 | */ | |
968 | LEAF(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! | |
977 | END(suiword) | |
978 | ||
979 | /* | |
980 | * Will have to flush the instruction cache if byte merging is done in hardware. | |
981 | */ | |
524dd2a1 RC |
982 | LEAF(susword) |
983 | ALEAF(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 | |
991 | END(susword) | |
992 | ||
dea92547 KM |
993 | LEAF(subyte) |
994 | ALEAF(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 | |
1002 | END(subyte) | |
1003 | ||
1004 | LEAF(fswberr) | |
1005 | li v0, -1 | |
1006 | j ra | |
1007 | END(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 | */ | |
1014 | LEAF(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 | |
1021 | END(fuswintr) | |
1022 | ||
1023 | LEAF(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 | |
1031 | END(suswintr) | |
1032 | ||
1033 | LEAF(fswintrberr) | |
1034 | li v0, -1 | |
1035 | j ra | |
1036 | END(fswintrberr) | |
1037 | ||
dea92547 KM |
1038 | /* |
1039 | * Insert 'p' after 'q'. | |
1040 | * _insque(p, q) | |
1041 | * caddr_t p, q; | |
1042 | */ | |
1043 | LEAF(_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 | |
1050 | END(_insque) | |
1051 | ||
1052 | /* | |
1053 | * Remove item 'p' from queue. | |
1054 | * _remque(p) | |
1055 | * caddr_t p; | |
1056 | */ | |
1057 | LEAF(_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 | |
1063 | END(_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 | |
1071 | MachUTLBMiss: | |
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 | |
1092 | 1: | |
c1b0ae6e | 1093 | j UtlbFault # handle the rest |
dea92547 KM |
1094 | nop |
1095 | .set reorder | |
1096 | .set at | |
1097 | .globl MachUTLBMissEnd | |
1098 | MachUTLBMissEnd: | |
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 | |
1106 | MachException: | |
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 |
1118 | 1: |
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 | |
1132 | MachExceptionEnd: | |
1133 | ||
c1b0ae6e KM |
1134 | /* |
1135 | * Handle the rest of the UTLB miss. | |
1136 | */ | |
1137 | UtlbFault: | |
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 | */ | |
1162 | SlowFault: | |
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 | ||
1201 | NON_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 | |
1291 | END(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 | */ | |
1307 | NON_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 | |
1405 | END(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 | ||
1430 | NON_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 | |
1444 | 1: | |
1445 | sw sp, KINTR_SP_OFFSET - KINTR_FRAME_SIZE(k0) # save old sp | |
1446 | subu sp, k0, KINTR_FRAME_SIZE # switch to interrupt stack | |
1447 | 2: | |
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 | |
1517 | END(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 | */ | |
1538 | NON_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 | ||
1620 | 1: | |
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 | |
1682 | END(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 | */ | |
1701 | LEAF(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 | |
1723 | 4: | |
1724 | break 0 # panic | |
1725 | .set reorder | |
1726 | .set at | |
dea92547 | 1727 | END(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 | */ | |
1746 | LEAF(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 | |
1768 | END(MachTLBMissException) | |
1769 | ||
1770 | /* | |
1771 | * Set/clear software interrupt routines. | |
1772 | */ | |
1773 | ||
1774 | LEAF(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 | |
1783 | END(setsoftclock) | |
1784 | ||
1785 | LEAF(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 | |
1794 | END(clearsoftclock) | |
1795 | ||
1796 | LEAF(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 | |
1805 | END(setsoftnet) | |
1806 | ||
1807 | LEAF(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 | |
1816 | END(clearsoftnet) | |
1817 | ||
1818 | /* | |
1819 | * Set/change interrupt priority routines. | |
1820 | */ | |
1821 | ||
1822 | LEAF(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 | |
1831 | END(MachEnableIntr) | |
1832 | ||
1833 | LEAF(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 | |
1842 | END(spl0) | |
1843 | ||
1844 | LEAF(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 | |
1853 | END(splsoftclock) | |
1854 | ||
8d50a649 | 1855 | LEAF(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 | 1864 | END(Mach_spl0) |
897d8278 | 1865 | |
8d50a649 | 1866 | LEAF(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 | 1875 | END(Mach_spl1) |
dea92547 | 1876 | |
8d50a649 | 1877 | LEAF(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 | 1886 | END(Mach_spl2) |
dea92547 | 1887 | |
8d50a649 | 1888 | LEAF(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 | 1897 | END(Mach_spl3) |
dea92547 KM |
1898 | |
1899 | LEAF(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 | |
1908 | END(splhigh) | |
1909 | ||
1910 | /* | |
1911 | * Restore saved interrupt mask. | |
1912 | */ | |
1913 | LEAF(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 | |
1923 | END(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 | */ | |
1941 | LEAF(MachEmptyWriteBuffer) | |
1942 | .set noreorder | |
1943 | nop | |
1944 | nop | |
1945 | nop | |
1946 | nop | |
1947 | 1: bc0f 1b | |
1948 | nop | |
1949 | j ra | |
1950 | nop | |
1951 | .set reorder | |
1952 | END(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 | */ | |
1973 | LEAF(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 | |
1990 | END(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 | */ | |
2010 | LEAF(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 | |
2025 | END(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 | */ | |
2044 | LEAF(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 | |
2051 | END(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 | */ | |
2069 | LEAF(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 |
2082 | 1: |
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 | |
2092 | END(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 | */ | |
2111 | LEAF(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 |
2123 | 1: | |
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. | |
2135 | 2: | |
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 | |
2143 | END(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 | */ | |
2162 | LEAF(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 | |
2178 | 1: | |
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 | |
2183 | END(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 | */ | |
2202 | LEAF(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 | |
2217 | 1: | |
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 | |
2222 | END(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 | |
2245 | LEAF(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 |
2263 | 1: |
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 | |
2268 | END(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 | */ | |
2287 | LEAF(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 | |
2306 | END(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 | 2322 | LEAF(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 |
2330 | END(MachTLBGetPID) |
2331 | ||
2332 | /* | |
2333 | * Return the current value of the cause register. | |
2334 | */ | |
2335 | LEAF(MachGetCauseReg) | |
2336 | .set noreorder | |
2337 | mfc0 v0, MACH_COP_0_CAUSE_REG | |
2338 | j ra | |
2339 | nop | |
2340 | .set reorder | |
2341 | END(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 | */ | |
2362 | LEAF(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 | ||
2418 | 1: | |
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 | |
2464 | END(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 | */ | |
2483 | LEAF(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 | |
2541 | END(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 | */ | |
2562 | NON_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 | */ | |
2605 | 1: | |
2606 | lw a0, 0(a2) # a0 = coproc instruction | |
2607 | addu v0, a2, 4 # v0 = next pc | |
2608 | 2: | |
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 | */ | |
2619 | 3: | |
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 | */ | |
2630 | 4: | |
2631 | jal MachEmulateFP | |
2632 | ||
2633 | /* | |
2634 | * Turn off the floating point coprocessor and return. | |
2635 | */ | |
2636 | FPReturn: | |
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 | |
2645 | END(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 | */ | |
2663 | NON_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 | |
2673 | 1: | |
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 | |
2707 | 1: | |
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 | |
2713 | END(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 | */ | |
2729 | LEAF(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 | |
2743 | 1: | |
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 | |
2751 | 2: | |
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 | |
2760 | 3: | |
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 | |
2769 | END(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 | */ | |
2785 | LEAF(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 | */ | |
2798 | 1: | |
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 | |
2807 | 1: | |
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 | */ | |
2819 | 1: | |
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 | |
2827 | 1: | |
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 | |
2844 | END(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 | */ | |
2864 | LEAF(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 | 2873 | 1: |
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 | 2879 | 1: |
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 | |
2888 | END(MachFlushICache) | |
8d50a649 RC |
2889 | |
2890 | #ifdef KADB | |
2891 | /* | |
2892 | * Read a long and return it. | |
2893 | * Note: addresses can be unaligned! | |
2894 | * | |
2895 | * long | |
2896 | L* kdbpeek(addr) | |
2897 | L* caddt_t addr; | |
2898 | L* { | |
2899 | L* return (*(long *)addr); | |
2900 | L* } | |
2901 | */ | |
2902 | LEAF(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 | |
2909 | 1: | |
2910 | lwr v0, 0(a0) # get next 4 bytes (unaligned) | |
2911 | lwl v0, 3(a0) | |
2912 | 2: | |
2913 | sw zero, UADDR+U_PCB_ONFAULT | |
2914 | j ra # made it w/o errors | |
2915 | kadberr: | |
2916 | li v0, 1 # trap sends us here | |
2917 | sw v0, kdbmkfault | |
2918 | j ra | |
2919 | END(kdbpeek) | |
2920 | ||
2921 | /* | |
2922 | * Write a long to 'addr'. | |
2923 | * Note: addresses can be unaligned! | |
2924 | * | |
2925 | L* void | |
2926 | L* kdbpoke(addr, value) | |
2927 | L* caddt_t addr; | |
2928 | L* long value; | |
2929 | L* { | |
2930 | L* *(long *)addr = value; | |
2931 | L* } | |
2932 | */ | |
2933 | LEAF(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 | |
2940 | 1: | |
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 | |
2944 | 2: | |
2945 | sw zero, UADDR+U_PCB_ONFAULT | |
2946 | li a1, 8 | |
2947 | b MachFlushICache # flush instruction cache | |
2948 | END(kdbpoke) | |
2949 | ||
2950 | /* | |
2951 | * Save registers and state so we can do a 'kdbreset' (like longjmp) later. | |
2952 | * Always returns zero. | |
2953 | * | |
2954 | L* int kdb_savearea[11]; | |
2955 | L* | |
2956 | L* int | |
2957 | L* kdbsetexit() | |
2958 | L* { | |
2959 | L* kdb_savearea[0] = 0; | |
2960 | L* return (0); | |
2961 | L* } | |
2962 | */ | |
2963 | .comm kdb_savearea, (11 * 4) | |
2964 | ||
2965 | LEAF(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 | |
2982 | END(kdbsetexit) | |
2983 | ||
2984 | /* | |
2985 | * Restore registers and state (like longjmp) and return x. | |
2986 | * | |
2987 | L* int | |
2988 | L* kdbreset(x) | |
2989 | L* { | |
2990 | L* return (x); | |
2991 | L* } | |
2992 | */ | |
2993 | LEAF(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 | |
3010 | END(kdbreset) | |
3011 | ||
3012 | /* | |
3013 | * Trap into the debugger. | |
3014 | * | |
3015 | L* void | |
3016 | L* kdbpanic() | |
3017 | L* { | |
3018 | L* } | |
3019 | */ | |
3020 | LEAF(kdbpanic) | |
3021 | break MACH_BREAK_KDB_VAL | |
3022 | j ra | |
3023 | END(kdbpanic) | |
3024 | #endif /* KADB */ |