locore.s revision 1.48 1 /* $NetBSD: locore.s,v 1.48 2001/07/22 14:11:05 scw Exp $ */
2
3 /*
4 * Copyright (c) 1988 University of Utah.
5 * Copyright (c) 1980, 1990, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * the Systems Programming Group of the University of Utah Computer
10 * Science Department.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * from: Utah $Hdr: locore.s 1.66 92/12/22$
41 * @(#)locore.s 8.6 (Berkeley) 5/27/94
42 */
43
44 #include "opt_compat_netbsd.h"
45 #include "opt_compat_svr4.h"
46 #include "opt_compat_sunos.h"
47 #include "opt_kgdb.h"
48 #include "opt_lockdebug.h"
49
50 #include "assym.h"
51 #include <machine/asm.h>
52 #include <machine/trap.h>
53
54 | Remember this is a fun project!
55
56 .data
57 GLOBAL(mon_crp)
58 .long 0,0
59
60 | This is for kvm_mkdb, and should be the address of the beginning
61 | of the kernel text segment (not necessarily the same as kernbase).
62 .text
63 GLOBAL(kernel_text)
64
65 | This is the entry point, as well as the end of the temporary stack
66 | used during process switch (one 8K page ending at start)
67 ASGLOBAL(tmpstk)
68 ASGLOBAL(start)
69
70 | The first step, after disabling interrupts, is to map enough of the kernel
71 | into high virtual address space so that we can use position dependent code.
72 | This is a tricky task on the sun3x because the MMU is already enabled and
73 | the ROM monitor provides no indication of where the root MMU table is mapped.
74 | Therefore we must use one of the 68030's 'transparent translation' registers
75 | to define a range in the address space where the MMU translation is
76 | turned off. Once this is complete we can modify the MMU table directly
77 | without the need for it to be mapped into virtual memory.
78 | All code must be position independent until otherwise noted, as the
79 | boot loader has loaded us into low memory but all the symbols in this
80 | code have been linked high.
81 movw #PSL_HIGHIPL,%sr | no interrupts
82 movl #KERNBASE,%a5 | for vtop conversion
83 lea _C_LABEL(mon_crp),%a0 | where to store the CRP
84 subl %a5,%a0
85 | Note: borrowing mon_crp for tt0 setup...
86 movl #0x3F8107,%a0@ | map the low 1GB v=p with the
87 .long 0xf0100800 | transparent translation reg0
88 | [ pmove a0@, tt0 ]
89 | In order to map the kernel into high memory we will copy the root table
90 | entry which maps the 16 megabytes of memory starting at 0x0 into the
91 | entry which maps the 16 megabytes starting at KERNBASE.
92 pmove %crp,%a0@ | Get monitor CPU root pointer
93 movl %a0@(4),%a1 | 2nd word is PA of level A table
94
95 movl %a1,%a0 | compute the descriptor address
96 addl #0x3e0,%a1 | for VA starting at KERNBASE
97 movl %a0@,%a1@ | copy descriptor type
98 movl %a0@(4),%a1@(4) | copy physical address
99
100 | Kernel is now double mapped at zero and KERNBASE.
101 | Force a long jump to the relocated code (high VA).
102 movl #IC_CLEAR,%d0 | Flush the I-cache
103 movc %d0,%cacr
104 jmp L_high_code:l | long jump
105
106 L_high_code:
107 | We are now running in the correctly relocated kernel, so
108 | we are no longer restricted to position-independent code.
109 | It is handy to leave transparent translation enabled while
110 | for the low 1GB while _bootstrap() is doing its thing.
111
112 | Do bootstrap stuff needed before main() gets called.
113 | Our boot loader leaves a copy of the kernel's exec header
114 | just before the start of the kernel text segment, so the
115 | kernel can sanity-check the DDB symbols at [end...esym].
116 | Pass the struct exec at tmpstk-32 to _bootstrap().
117 | Also, make sure the initial frame pointer is zero so that
118 | the backtrace algorithm used by KGDB terminates nicely.
119 lea _ASM_LABEL(tmpstk)-32,%sp
120 movl #0,%a6
121 jsr _C_LABEL(_bootstrap) | See locore2.c
122
123 | Now turn off the transparent translation of the low 1GB.
124 | (this also flushes the ATC)
125 clrl %sp@-
126 .long 0xf0170800 | pmove sp@,tt0
127 addql #4,%sp
128
129 | Now that _bootstrap() is done using the PROM functions,
130 | we can safely set the sfc/dfc to something != FC_CONTROL
131 moveq #FC_USERD,%d0 | make movs access "user data"
132 movc %d0,%sfc | space for copyin/copyout
133 movc %d0,%dfc
134
135 | Setup process zero user/kernel stacks.
136 movl _C_LABEL(proc0paddr),%a1| get proc0 pcb addr
137 lea %a1@(USPACE-4),%sp | set SSP to last word
138 movl #USRSTACK-4,%a2
139 movl %a2,%usp | init user SP
140
141 | Note curpcb was already set in _bootstrap().
142 | Will do fpu initialization during autoconfig (see fpu.c)
143 | The interrupt vector table and stack are now ready.
144 | Interrupts will be enabled later, AFTER autoconfiguration
145 | is finished, to avoid spurrious interrupts.
146
147 /*
148 * Final preparation for calling main.
149 *
150 * Create a fake exception frame that returns to user mode,
151 * and save its address in p->p_md.md_regs for cpu_fork().
152 * The new frames for process 1 and 2 will be adjusted by
153 * cpu_set_kpc() to arrange for a call to a kernel function
154 * before the new process does its rte out to user mode.
155 */
156 clrw %sp@- | tf_format,tf_vector
157 clrl %sp@- | tf_pc (filled in later)
158 movw #PSL_USER,%sp@- | tf_sr for user mode
159 clrl %sp@- | tf_stackadj
160 lea %sp@(-64),%sp | tf_regs[16]
161 movl %sp,%a1 | a1=trapframe
162 lea _C_LABEL(proc0),%a0 | proc0.p_md.md_regs =
163 movl %a1,%a0@(P_MDREGS) | trapframe
164 movl %a2,%a1@(FR_SP) | a2 == usp (from above)
165 pea %a1@ | push &trapframe
166 jbsr _C_LABEL(main) | main(&trapframe)
167 addql #4,%sp | help DDB backtrace
168 trap #15 | should not get here
169
170 | This is used by cpu_fork() to return to user mode.
171 | It is called with SP pointing to a struct trapframe.
172 GLOBAL(proc_do_uret)
173 movl %sp@(FR_SP),%a0 | grab and load
174 movl %a0,%usp | user SP
175 moveml %sp@+,#0x7FFF | load most registers (all but SSP)
176 addql #8,%sp | pop SSP and stack adjust count
177 rte
178
179 /*
180 * proc_trampoline:
181 * This is used by cpu_set_kpc() to "push" a function call onto the
182 * kernel stack of some process, very much like a signal delivery.
183 * When we get here, the stack has:
184 *
185 * SP+8: switchframe from before cpu_set_kpc
186 * SP+4: void *arg;
187 * SP: u_long func;
188 *
189 * On entry, the switchframe pushed by cpu_set_kpc has already been
190 * popped off the stack, so all this needs to do is pop the function
191 * pointer into a register, call it, then pop the arg, and finally
192 * return using the switchframe that remains on the stack.
193 */
194 GLOBAL(proc_trampoline)
195 movl %sp@+,%a0 | function pointer
196 jbsr %a0@ | (*func)(arg)
197 addql #4,%sp | toss the arg
198 rts | as cpu_switch would do
199
200 | That is all the assembly startup code we need on the sun3x!
201 | The rest of this is like the hp300/locore.s where possible.
202
203 /*
204 * Trap/interrupt vector routines
205 */
206 #include <m68k/m68k/trap_subr.s>
207
208 GLOBAL(buserr)
209 tstl _C_LABEL(nofault) | device probe?
210 jeq _C_LABEL(addrerr) | no, handle as usual
211 movl _C_LABEL(nofault),%sp@- | yes,
212 jbsr _C_LABEL(longjmp) | longjmp(nofault)
213 GLOBAL(addrerr)
214 clrl %sp@- | stack adjust count
215 moveml #0xFFFF,%sp@- | save user registers
216 movl %usp,%a0 | save the user SP
217 movl %a0,%sp@(FR_SP) | in the savearea
218 lea %sp@(FR_HW),%a1 | grab base of HW berr frame
219 moveq #0,%d0
220 movw %a1@(10),%d0 | grab SSW for fault processing
221 btst #12,%d0 | RB set?
222 jeq LbeX0 | no, test RC
223 bset #14,%d0 | yes, must set FB
224 movw %d0,%a1@(10) | for hardware too
225 LbeX0:
226 btst #13,%d0 | RC set?
227 jeq LbeX1 | no, skip
228 bset #15,%d0 | yes, must set FC
229 movw %d0,%a1@(10) | for hardware too
230 LbeX1:
231 btst #8,%d0 | data fault?
232 jeq Lbe0 | no, check for hard cases
233 movl %a1@(16),%d1 | fault address is as given in frame
234 jra Lbe10 | thats it
235 Lbe0:
236 btst #4,%a1@(6) | long (type B) stack frame?
237 jne Lbe4 | yes, go handle
238 movl %a1@(2),%d1 | no, can use save PC
239 btst #14,%d0 | FB set?
240 jeq Lbe3 | no, try FC
241 addql #4,%d1 | yes, adjust address
242 jra Lbe10 | done
243 Lbe3:
244 btst #15,%d0 | FC set?
245 jeq Lbe10 | no, done
246 addql #2,%d1 | yes, adjust address
247 jra Lbe10 | done
248 Lbe4:
249 movl %a1@(36),%d1 | long format, use stage B address
250 btst #15,%d0 | FC set?
251 jeq Lbe10 | no, all done
252 subql #2,%d1 | yes, adjust address
253 Lbe10:
254 movl %d1,%sp@- | push fault VA
255 movl %d0,%sp@- | and padded SSW
256 movw %a1@(6),%d0 | get frame format/vector offset
257 andw #0x0FFF,%d0 | clear out frame format
258 cmpw #12,%d0 | address error vector?
259 jeq Lisaerr | yes, go to it
260
261 /* MMU-specific code to determine reason for bus error. */
262 movl %d1,%a0 | fault address
263 movl %sp@,%d0 | function code from ssw
264 btst #8,%d0 | data fault?
265 jne Lbe10a
266 movql #1,%d0 | user program access FC
267 | (we dont separate data/program)
268 btst #5,%a1@ | supervisor mode?
269 jeq Lbe10a | if no, done
270 movql #5,%d0 | else supervisor program access
271 Lbe10a:
272 ptestr %d0,%a0@,#7 | do a table search
273 pmove %psr,%sp@ | save result
274 movb %sp@,%d1
275 btst #2,%d1 | invalid? (incl. limit viol and berr)
276 jeq Lmightnotbemerr | no -> wp check
277 btst #7,%d1 | is it MMU table berr?
278 jeq Lismerr | no, must be fast
279 jra Lisberr1 | real bus err needs not be fast
280 Lmightnotbemerr:
281 btst #3,%d1 | write protect bit set?
282 jeq Lisberr1 | no, must be bus error
283 movl %sp@,%d0 | ssw into low word of d0
284 andw #0xc0,%d0 | write protect is set on page:
285 cmpw #0x40,%d0 | was it read cycle?
286 jeq Lisberr1 | yes, was not WPE, must be bus err
287 /* End of MMU-specific bus error code. */
288
289 Lismerr:
290 movl #T_MMUFLT,%sp@- | show that we are an MMU fault
291 jra _ASM_LABEL(faultstkadj) | and deal with it
292 Lisaerr:
293 movl #T_ADDRERR,%sp@- | mark address error
294 jra _ASM_LABEL(faultstkadj) | and deal with it
295 Lisberr1:
296 clrw %sp@ | re-clear pad word
297 Lisberr:
298 movl #T_BUSERR,%sp@- | mark bus error
299 jra _ASM_LABEL(faultstkadj) | and deal with it
300
301 /*
302 * FP exceptions.
303 */
304 GLOBAL(fpfline)
305 clrl %sp@- | stack adjust count
306 moveml #0xFFFF,%sp@- | save registers
307 moveq #T_FPEMULI,%d0 | denote as FP emulation trap
308 jra _ASM_LABEL(fault) | do it
309
310 GLOBAL(fpunsupp)
311 clrl %sp@- | stack adjust count
312 moveml #0xFFFF,%sp@- | save registers
313 moveq #T_FPEMULD,%d0 | denote as FP emulation trap
314 jra _ASM_LABEL(fault) | do it
315
316 /*
317 * Handles all other FP coprocessor exceptions.
318 * Note that since some FP exceptions generate mid-instruction frames
319 * and may cause signal delivery, we need to test for stack adjustment
320 * after the trap call.
321 */
322 GLOBAL(fpfault)
323 clrl %sp@- | stack adjust count
324 moveml #0xFFFF,%sp@- | save user registers
325 movl %usp,%a0 | and save
326 movl %a0,%sp@(FR_SP) | the user stack pointer
327 clrl %sp@- | no VA arg
328 movl _C_LABEL(curpcb),%a0 | current pcb
329 lea %a0@(PCB_FPCTX),%a0 | address of FP savearea
330 fsave %a0@ | save state
331 tstb %a0@ | null state frame?
332 jeq Lfptnull | yes, safe
333 clrw %d0 | no, need to tweak BIU
334 movb %a0@(1),%d0 | get frame size
335 bset #3,%a0@(0,%d0:w) | set exc_pend bit of BIU
336 Lfptnull:
337 fmovem %fpsr,%sp@- | push fpsr as code argument
338 frestore %a0@ | restore state
339 movl #T_FPERR,%sp@- | push type arg
340 jra _ASM_LABEL(faultstkadj) | call trap and deal with stack cleanup
341
342 /*
343 * Other exceptions only cause four and six word stack frame and require
344 * no post-trap stack adjustment.
345 */
346 GLOBAL(badtrap)
347 clrl %sp@- | stack adjust count
348 moveml #0xFFFF,%sp@- | save std frame regs
349 jbsr _C_LABEL(straytrap) | report
350 moveml %sp@+,#0xFFFF | restore regs
351 addql #4,%sp | stack adjust count
352 jra _ASM_LABEL(rei) | all done
353
354 /*
355 * Trap 0 is for system calls
356 */
357 GLOBAL(trap0)
358 clrl %sp@- | stack adjust count
359 moveml #0xFFFF,%sp@- | save user registers
360 movl %usp,%a0 | save the user SP
361 movl %a0,%sp@(FR_SP) | in the savearea
362 movl %d0,%sp@- | push syscall number
363 jbsr _C_LABEL(syscall) | handle it
364 addql #4,%sp | pop syscall arg
365 movl %sp@(FR_SP),%a0 | grab and restore
366 movl %a0,%usp | user SP
367 moveml %sp@+,#0x7FFF | restore most registers
368 addql #8,%sp | pop SP and stack adjust
369 jra _ASM_LABEL(rei) | all done
370
371 /*
372 * Trap 12 is the entry point for the cachectl "syscall"
373 * cachectl(command, addr, length)
374 * command in d0, addr in a1, length in d1
375 */
376 GLOBAL(trap12)
377 movl _C_LABEL(curproc),%sp@- | push curproc pointer
378 movl %d1,%sp@- | push length
379 movl %a1,%sp@- | push addr
380 movl %d0,%sp@- | push command
381 jbsr _C_LABEL(cachectl1) | do it
382 lea %sp@(16),%sp | pop args
383 jra _ASM_LABEL(rei) | all done
384
385 /*
386 * Trace (single-step) trap. Kernel-mode is special.
387 * User mode traps are simply passed on to trap().
388 */
389 GLOBAL(trace)
390 clrl %sp@- | stack adjust count
391 moveml #0xFFFF,%sp@-
392 moveq #T_TRACE,%d0
393
394 | Check PSW and see what happen.
395 | T=0 S=0 (should not happen)
396 | T=1 S=0 trace trap from user mode
397 | T=0 S=1 trace trap on a trap instruction
398 | T=1 S=1 trace trap from system mode (kernel breakpoint)
399
400 movw %sp@(FR_HW),%d1 | get PSW
401 notw %d1 | XXX no support for T0 on 680[234]0
402 andw #PSL_TS,%d1 | from system mode (T=1, S=1)?
403 jeq _ASM_LABEL(kbrkpt) | yes, kernel brkpt
404 jra _ASM_LABEL(fault) | no, user-mode fault
405
406 /*
407 * Trap 15 is used for:
408 * - GDB breakpoints (in user programs)
409 * - KGDB breakpoints (in the kernel)
410 * - trace traps for SUN binaries (not fully supported yet)
411 * User mode traps are simply passed to trap().
412 */
413 GLOBAL(trap15)
414 clrl %sp@- | stack adjust count
415 moveml #0xFFFF,%sp@-
416 moveq #T_TRAP15,%d0
417 btst #5,%sp@(FR_HW) | was supervisor mode?
418 jne _ASM_LABEL(kbrkpt) | yes, kernel brkpt
419 jra _ASM_LABEL(fault) | no, user-mode fault
420
421 ASLOCAL(kbrkpt)
422 | Kernel-mode breakpoint or trace trap. (%d0=trap_type)
423 | Save the system sp rather than the user sp.
424 movw #PSL_HIGHIPL,%sr | lock out interrupts
425 lea %sp@(FR_SIZE),%a6 | Save stack pointer
426 movl %a6,%sp@(FR_SP) | from before trap
427
428 | If we are not on tmpstk switch to it.
429 | (so debugger can change the stack pointer)
430 movl %a6,%d1
431 cmpl #_ASM_LABEL(tmpstk),%d1
432 jls Lbrkpt2 | already on tmpstk
433 | Copy frame to the temporary stack
434 movl %sp,%a0 | %a0=src
435 lea _ASM_LABEL(tmpstk)-96,%a1 | %a1=dst
436 movl %a1,%sp | sp=new frame
437 moveq #FR_SIZE,%d1
438 Lbrkpt1:
439 movl %a0@+,%a1@+
440 subql #4,%d1
441 bgt Lbrkpt1
442
443 Lbrkpt2:
444 | Call the trap handler for the kernel debugger.
445 | Do not call trap() to handle it, so that we can
446 | set breakpoints in trap() if we want. We know
447 | the trap type is either T_TRACE or T_BREAKPOINT.
448 movl %d0,%sp@- | push trap type
449 jbsr _C_LABEL(trap_kdebug)
450 addql #4,%sp | pop args
451
452 | The stack pointer may have been modified, or
453 | data below it modified (by kgdb push call),
454 | so push the hardware frame at the current sp
455 | before restoring registers and returning.
456 movl %sp@(FR_SP),%a0 | modified sp
457 lea %sp@(FR_SIZE),%a1 | end of our frame
458 movl %a1@-,%a0@- | copy 2 longs with
459 movl %a1@-,%a0@- | ... predecrement
460 movl %a0,%sp@(FR_SP) | sp = h/w frame
461 moveml %sp@+,#0x7FFF | restore all but sp
462 movl %sp@,%sp | ... and sp
463 rte | all done
464
465 /* Use common m68k sigreturn */
466 #include <m68k/m68k/sigreturn.s>
467
468 /*
469 * Interrupt handlers. Most are auto-vectored,
470 * and hard-wired the same way on all sun3 models.
471 * Format in the stack is:
472 * %d0,%d1,%a0,%a1, sr, pc, vo
473 */
474
475 #define INTERRUPT_SAVEREG \
476 moveml #0xC0C0,%sp@-
477
478 #define INTERRUPT_RESTORE \
479 moveml %sp@+,#0x0303
480
481 /*
482 * This is the common auto-vector interrupt handler,
483 * for which the CPU provides the vector=0x18+level.
484 * These are installed in the interrupt vector table.
485 */
486 #ifdef __ELF__
487 .align 4
488 #else
489 .align 2
490 #endif
491 GLOBAL(_isr_autovec)
492 INTERRUPT_SAVEREG
493 jbsr _C_LABEL(isr_autovec)
494 INTERRUPT_RESTORE
495 jra _ASM_LABEL(rei)
496
497 /* clock: see clock.c */
498 #ifdef __ELF__
499 .align 4
500 #else
501 .align 2
502 #endif
503 GLOBAL(_isr_clock)
504 INTERRUPT_SAVEREG
505 jbsr _C_LABEL(clock_intr)
506 INTERRUPT_RESTORE
507 jra _ASM_LABEL(rei)
508
509 | Handler for all vectored interrupts (i.e. VME interrupts)
510 #ifdef __ELF__
511 .align 4
512 #else
513 .align 2
514 #endif
515 GLOBAL(_isr_vectored)
516 INTERRUPT_SAVEREG
517 jbsr _C_LABEL(isr_vectored)
518 INTERRUPT_RESTORE
519 jra _ASM_LABEL(rei)
520
521 #undef INTERRUPT_SAVEREG
522 #undef INTERRUPT_RESTORE
523
524 /* interrupt counters (needed by vmstat) */
525 GLOBAL(intrnames)
526 .asciz "spur" | 0
527 .asciz "lev1" | 1
528 .asciz "lev2" | 2
529 .asciz "lev3" | 3
530 .asciz "lev4" | 4
531 .asciz "clock" | 5
532 .asciz "lev6" | 6
533 .asciz "nmi" | 7
534 GLOBAL(eintrnames)
535
536 .data
537 .even
538 GLOBAL(intrcnt)
539 .long 0,0,0,0,0,0,0,0,0,0
540 GLOBAL(eintrcnt)
541 .text
542
543 /*
544 * Emulation of VAX REI instruction.
545 *
546 * This code is (mostly) un-altered from the hp300 code,
547 * except that sun machines do not need a simulated SIR
548 * because they have a real software interrupt register.
549 *
550 * This code deals with checking for and servicing ASTs
551 * (profiling, scheduling) and software interrupts (network, softclock).
552 * We check for ASTs first, just like the VAX. To avoid excess overhead
553 * the T_ASTFLT handling code will also check for software interrupts so we
554 * do not have to do it here. After identifying that we need an AST we
555 * drop the IPL to allow device interrupts.
556 *
557 * This code is complicated by the fact that sendsig may have been called
558 * necessitating a stack cleanup.
559 */
560
561 ASGLOBAL(rei)
562 #ifdef DIAGNOSTIC
563 tstl _C_LABEL(panicstr) | have we paniced?
564 jne Ldorte | yes, do not make matters worse
565 #endif
566 tstl _C_LABEL(astpending) | AST pending?
567 jeq Ldorte | no, done
568 Lrei1:
569 btst #5,%sp@ | yes, are we returning to user mode?
570 jne Ldorte | no, done
571 movw #PSL_LOWIPL,%sr | lower SPL
572 clrl %sp@- | stack adjust
573 moveml #0xFFFF,%sp@- | save all registers
574 movl %usp,%a1 | including
575 movl %a1,%sp@(FR_SP) | the users SP
576 clrl %sp@- | VA == none
577 clrl %sp@- | code == none
578 movl #T_ASTFLT,%sp@- | type == async system trap
579 jbsr _C_LABEL(trap) | go handle it
580 lea %sp@(12),%sp | pop value args
581 movl %sp@(FR_SP),%a0 | restore user SP
582 movl %a0,%usp | from save area
583 movw %sp@(FR_ADJ),%d0 | need to adjust stack?
584 jne Laststkadj | yes, go to it
585 moveml %sp@+,#0x7FFF | no, restore most user regs
586 addql #8,%sp | toss SP and stack adjust
587 rte | and do real RTE
588 Laststkadj:
589 lea %sp@(FR_HW),%a1 | pointer to HW frame
590 addql #8,%a1 | source pointer
591 movl %a1,%a0 | source
592 addw %d0,%a0 | + hole size = dest pointer
593 movl %a1@-,%a0@- | copy
594 movl %a1@-,%a0@- | 8 bytes
595 movl %a0,%sp@(FR_SP) | new SSP
596 moveml %sp@+,#0x7FFF | restore user registers
597 movl %sp@,%sp | and our SP
598 Ldorte:
599 rte | real return
600
601 /*
602 * Initialization is at the beginning of this file, because the
603 * kernel entry point needs to be at zero for compatibility with
604 * the Sun boot loader. This works on Sun machines because the
605 * interrupt vector table for reset is NOT at address zero.
606 * (The MMU has a "boot" bit that forces access to the PROM)
607 */
608
609 /*
610 * Use common m68k sigcode.
611 */
612 #include <m68k/m68k/sigcode.s>
613 #ifdef COMPAT_SUNOS
614 #include <m68k/m68k/sunos_sigcode.s>
615 #endif
616 #ifdef COMPAT_SVR4
617 #include <m68k/m68k/svr4_sigcode.s>
618 #endif
619
620 .text
621
622 /*
623 * Primitives
624 */
625
626 /*
627 * Use common m68k support routines.
628 */
629 #include <m68k/m68k/support.s>
630
631 BSS(want_resched,4)
632
633 /*
634 * Use common m68k process manipulation routines.
635 */
636 #include <m68k/m68k/proc_subr.s>
637
638 | Message for Lbadsw panic
639 Lsw0:
640 .asciz "cpu_switch"
641 .even
642
643 .data
644 GLOBAL(masterpaddr) | XXX compatibility (debuggers)
645 GLOBAL(curpcb)
646 .long 0
647 ASBSS(nullpcb,SIZEOF_PCB)
648 .text
649
650 /*
651 * At exit of a process, do a cpu_switch for the last time.
652 * Switch to a safe stack and PCB, and select a new process to run. The
653 * old stack and u-area will be freed by the reaper.
654 *
655 * MUST BE CALLED AT SPLHIGH!
656 */
657 ENTRY(switch_exit)
658 movl %sp@(4),%a0 | struct proc *p
659 | save state into garbage pcb
660 movl #_ASM_LABEL(nullpcb),_C_LABEL(curpcb)
661 lea _ASM_LABEL(tmpstk),%sp | goto a tmp stack
662
663 /* Schedule the vmspace and stack to be freed. */
664 movl %a0,%sp@- | exit2(p)
665 jbsr _C_LABEL(exit2)
666 lea %sp@(4),%sp
667
668 #if defined(LOCKDEBUG)
669 /* Acquire sched_lock */
670 jbsr _C_LABEL(sched_lock_idle)
671 #endif
672
673 jra _C_LABEL(cpu_switch)
674
675 /*
676 * When no processes are on the runq, cpu_switch() branches to idle
677 * to wait for something to come ready.
678 */
679 Lidle:
680 #if defined(LOCKDEBUG)
681 /* Release sched_lock */
682 jbsr _C_LABEL(sched_unlock_idle)
683 #endif
684 stop #PSL_LOWIPL
685 GLOBAL(_Idle) | See clock.c
686 movw #PSL_HIGHIPL,%sr
687 #if defined(LOCKDEBUG)
688 /* Acquire sched_lock */
689 jbsr _C_LABEL(sched_lock_idle)
690 #endif
691 movl _C_LABEL(sched_whichqs),%d0
692 jeq Lidle
693 jra Lsw1
694
695 Lbadsw:
696 movl #Lsw0,%sp@-
697 jbsr _C_LABEL(panic)
698 /*NOTREACHED*/
699
700 /*
701 * cpu_switch()
702 * Hacked for sun3
703 */
704 ENTRY(cpu_switch)
705 movl _C_LABEL(curpcb),%a1 | current pcb
706 movw %sr,%a1@(PCB_PS) | save sr before changing ipl
707 #ifdef notyet
708 movl _C_LABEL(curproc),%sp@- | remember last proc running
709 #endif
710 clrl _C_LABEL(curproc)
711
712 /*
713 * Find the highest-priority queue that isn't empty,
714 * then take the first proc from that queue.
715 */
716 movl _C_LABEL(sched_whichqs),%d0
717 jeq Lidle
718 Lsw1:
719 /*
720 * Interrupts are blocked, sched_lock is held. If
721 * we come here via Idle, %d0 contains the contents
722 * of a non-zero sched_whichqs.
723 */
724 movl %d0,%d1
725 negl %d0
726 andl %d1,%d0
727 bfffo %d0{#0:#32},%d1
728 eorib #31,%d1
729
730 movl %d1,%d0
731 lslb #3,%d1 | convert queue number to index
732 addl #_C_LABEL(sched_qs),%d1 | locate queue (q)
733 movl %d1,%a1
734 movl %a1@(P_FORW),%a0 | p = q->p_forw
735 cmpal %d1,%a0 | anyone on queue?
736 jeq Lbadsw | no, panic
737 #ifdef DIAGNOSTIC
738 tstl %a0@(P_WCHAN)
739 jne Lbadsw
740 cmpb #SRUN,%a0@(P_STAT)
741 jne Lbadsw
742 #endif
743 movl %a0@(P_FORW),%a1@(P_FORW) | q->p_forw = p->p_forw
744 movl %a0@(P_FORW),%a1 | n = p->p_forw
745 movl %a0@(P_BACK),%a1@(P_BACK) | n->p_back = q
746 cmpal %d1,%a1 | anyone left on queue?
747 jne Lsw2 | yes, skip
748 movl _C_LABEL(sched_whichqs),%d1
749 bclr %d0,%d1 | no, clear bit
750 movl %d1,_C_LABEL(sched_whichqs)
751 Lsw2:
752 /* p->p_cpu initialized in fork1() for single-processor */
753 movb #SONPROC,%a0@(P_STAT) | p->p_stat = SONPROC
754 movl %a0,_C_LABEL(curproc)
755 clrl _C_LABEL(want_resched)
756 #ifdef notyet
757 movl %sp@+,%a1 | XXX - Make this work!
758 cmpl %a0,%a1 | switching to same proc?
759 jeq Lswdone | yes, skip save and restore
760 #endif
761 /*
762 * Save state of previous process in its pcb.
763 */
764 movl _C_LABEL(curpcb),%a1
765 moveml #0xFCFC,%a1@(PCB_REGS) | save non-scratch registers
766 movl %usp,%a2 | grab USP (a2 has been saved)
767 movl %a2,%a1@(PCB_USP) | and save it
768
769 tstl _C_LABEL(fputype) | Do we have an fpu?
770 jeq Lswnofpsave | No? Then don't try save.
771 lea %a1@(PCB_FPCTX),%a2 | pointer to FP save area
772 fsave %a2@ | save FP state
773 tstb %a2@ | null state frame?
774 jeq Lswnofpsave | yes, all done
775 fmovem %fp0-%fp7,%a2@(FPF_REGS) | save FP general regs
776 fmovem %fpcr/%fpsr/%fpi,%a2@(FPF_FPCR) | save FP control regs
777 Lswnofpsave:
778
779 /*
780 * Now that we have saved all the registers that must be
781 * preserved, we are free to use those registers until
782 * we load the registers for the switched-to process.
783 * In this section, keep: %a0=curproc, %a1=curpcb
784 */
785
786 clrl %a0@(P_BACK) | clear back link
787 movl %a0@(P_ADDR),%a1 | get p_addr
788 movl %a1,_C_LABEL(curpcb)
789
790 #if defined(LOCKDEBUG)
791 /*
792 * Done mucking with the run queues, release the
793 * scheduler lock, but keep interrupts out.
794 */
795 movl %a0,%sp@- | not args...
796 movl %a1,%sp@- | ...just saving
797 jbsr _C_LABEL(sched_unlock_idle)
798 movl %sp@+,%a1
799 movl %sp@+,%a0
800 #endif
801
802 /*
803 * Load the new VM context (new MMU root pointer)
804 */
805 movl %a0@(P_VMSPACE),%a2 | vm = p->p_vmspace
806 #ifdef DIAGNOSTIC
807 tstl %a2 | vm == VM_MAP_NULL?
808 jeq Lbadsw | panic
809 #endif
810 #ifdef PMAP_DEBUG
811 /* When debugging just call _pmap_switch(). */
812 movl %a2@(VM_PMAP),a2 | pmap = vm->vm_map.pmap
813 pea %a2@ | push pmap
814 jbsr _C_LABEL(_pmap_switch) | _pmap_switch(pmap)
815 addql #4,%sp
816 movl _C_LABEL(curpcb),%a1 | restore p_addr
817 #else
818 /* Otherwise, use this inline version. */
819 lea _C_LABEL(kernel_crp),%a3 | our CPU Root Ptr. (CRP)
820 movl %a2@(VM_PMAP),%a2 | pmap = vm->vm_map.pmap
821 movl %a2@(PM_A_PHYS),%d0 | phys = pmap->pm_a_phys
822 cmpl %a3@(4),%d0 | == kernel_crp.rp_addr ?
823 jeq Lsame_mmuctx | skip loadcrp/flush
824 /* OK, it is a new MMU context. Load it up. */
825 movl %d0,%a3@(4)
826 movl #CACHE_CLR,%d0
827 movc %d0,%cacr | invalidate cache(s)
828 pflusha | flush entire TLB
829 pmove %a3@,%crp | load new user root pointer
830 Lsame_mmuctx:
831 #endif
832
833 /*
834 * Reload the registers for the new process.
835 * After this point we can only use %d0,%d1,%a0,%a1
836 */
837 moveml %a1@(PCB_REGS),#0xFCFC | reload registers
838 movl %a1@(PCB_USP),%a0
839 movl %a0,%usp | and USP
840
841 tstl _C_LABEL(fputype) | If we don't have an fpu,
842 jeq Lres_skip | don't try to restore it.
843 lea %a1@(PCB_FPCTX),%a0 | pointer to FP save area
844 tstb %a0@ | null state frame?
845 jeq Lresfprest | yes, easy
846 fmovem %a0@(FPF_FPCR),%fpcr/%fpsr/%fpi | restore FP control regs
847 fmovem %a0@(FPF_REGS),%fp0-%fp7 | restore FP general regs
848 Lresfprest:
849 frestore %a0@ | restore state
850 Lres_skip:
851 movw %a1@(PCB_PS),%d0 | no, restore PS
852 #ifdef DIAGNOSTIC
853 btst #13,%d0 | supervisor mode?
854 jeq Lbadsw | no? panic!
855 #endif
856 movw %d0,%sr | OK, restore PS
857 movl #1,%a0 | return 1 (for alternate returns)
858 rts
859
860 /*
861 * savectx(pcb)
862 * Update pcb, saving current processor state.
863 */
864 ENTRY(savectx)
865 movl %sp@(4),%a1
866 movw %sr,%a1@(PCB_PS)
867 movl %usp,%a0 | grab USP
868 movl %a0,%a1@(PCB_USP) | and save it
869 moveml #0xFCFC,%a1@(PCB_REGS) | save non-scratch registers
870
871 tstl _C_LABEL(fputype) | Do we have FPU?
872 jeq Lsavedone | No? Then don't save state.
873 lea %a1@(PCB_FPCTX),%a0 | pointer to FP save area
874 fsave %a0@ | save FP state
875 tstb %a0@ | null state frame?
876 jeq Lsavedone | yes, all done
877 fmovem %fp0-%fp7,%a0@(FPF_REGS) | save FP general regs
878 fmovem %fpcr/%fpsr/%fpi,%a0@(FPF_FPCR) | save FP control regs
879 Lsavedone:
880 movl #0,%a0 | return 0
881 rts
882
883 /* suline() */
884
885 #ifdef DEBUG
886 .data
887 ASGLOBAL(fulltflush)
888 .long 0
889 ASGLOBAL(fullcflush)
890 .long 0
891 .text
892 #endif
893
894 /*
895 * Invalidate entire TLB.
896 */
897 ENTRY(TBIA)
898 _C_LABEL(_TBIA):
899 pflusha
900 movl #DC_CLEAR,%d0
901 movc %d0,%cacr | invalidate on-chip d-cache
902 rts
903
904 /*
905 * Invalidate any TLB entry for given VA (TB Invalidate Single)
906 */
907 ENTRY(TBIS)
908 #ifdef DEBUG
909 tstl _ASM_LABEL(fulltflush) | being conservative?
910 jne _C_LABEL(_TBIA) | yes, flush entire TLB
911 #endif
912 movl %sp@(4),%a0
913 pflush #0,#0,%a0@ | flush address from both sides
914 movl #DC_CLEAR,%d0
915 movc %d0,%cacr | invalidate on-chip data cache
916 rts
917
918 /*
919 * Invalidate supervisor side of TLB
920 */
921 ENTRY(TBIAS)
922 #ifdef DEBUG
923 tstl _ASM_LABEL(fulltflush) | being conservative?
924 jne _C_LABEL(_TBIA) | yes, flush everything
925 #endif
926 pflush #4,#4 | flush supervisor TLB entries
927 movl #DC_CLEAR,%d0
928 movc %d0,%cacr | invalidate on-chip d-cache
929 rts
930
931 /*
932 * Invalidate user side of TLB
933 */
934 ENTRY(TBIAU)
935 #ifdef DEBUG
936 tstl _ASM_LABEL(fulltflush) | being conservative?
937 jne _C_LABEL(_TBIA) | yes, flush everything
938 #endif
939 pflush #0,#4 | flush user TLB entries
940 movl #DC_CLEAR,%d0
941 movc %d0,%cacr | invalidate on-chip d-cache
942 rts
943
944 /*
945 * Invalidate instruction cache
946 */
947 ENTRY(ICIA)
948 movl #IC_CLEAR,%d0
949 movc %d0,%cacr | invalidate i-cache
950 rts
951
952 /*
953 * Invalidate data cache.
954 * NOTE: we do not flush 68030 on-chip cache as there are no aliasing
955 * problems with DC_WA. The only cases we have to worry about are context
956 * switch and TLB changes, both of which are handled "in-line" in resume
957 * and TBI*.
958 */
959 ENTRY(DCIA)
960 __DCIA:
961 rts
962
963 ENTRY(DCIS)
964 __DCIS:
965 rts
966
967 /*
968 * Invalidate data cache.
969 */
970 ENTRY(DCIU)
971 movl #DC_CLEAR,%d0
972 movc %d0,%cacr | invalidate on-chip d-cache
973 rts
974
975 /* ICPL, ICPP, DCPL, DCPP, DCPA, DCFL, DCFP */
976
977 ENTRY(PCIA)
978 movl #DC_CLEAR,%d0
979 movc %d0,%cacr | invalidate on-chip d-cache
980 rts
981
982 ENTRY(ecacheon)
983 rts
984
985 ENTRY(ecacheoff)
986 rts
987
988 /*
989 * Get callers current SP value.
990 * Note that simply taking the address of a local variable in a C function
991 * doesn't work because callee saved registers may be outside the stack frame
992 * defined by A6 (e.g. GCC generated code).
993 *
994 * [I don't think the ENTRY() macro will do the right thing with this -- glass]
995 */
996 GLOBAL(getsp)
997 movl %sp,%d0 | get current SP
998 addql #4,%d0 | compensate for return address
999 movl %d0,%a0
1000 rts
1001
1002 ENTRY(getsfc)
1003 movc %sfc,%d0
1004 movl %d0,%a0
1005 rts
1006
1007 ENTRY(getdfc)
1008 movc %dfc,%d0
1009 movl %d0,%a0
1010 rts
1011
1012 ENTRY(getvbr)
1013 movc %vbr,%d0
1014 movl %d0,%a0
1015 rts
1016
1017 ENTRY(setvbr)
1018 movl %sp@(4),%d0
1019 movc %d0,%vbr
1020 rts
1021
1022 /*
1023 * Load a new CPU Root Pointer (CRP) into the MMU.
1024 * void loadcrp(struct mmu_rootptr *);
1025 */
1026 ENTRY(loadcrp)
1027 movl %sp@(4),%a0 | arg1: &CRP
1028 movl #CACHE_CLR,%d0
1029 movc %d0,%cacr | invalidate cache(s)
1030 pflusha | flush entire TLB
1031 pmove %a0@,%crp | load new user root pointer
1032 rts
1033
1034 ENTRY(getcrp)
1035 movl %sp@(4),%a0 | arg1: &crp
1036 pmove %crp,%a0@ | *crpp = %crp
1037 rts
1038
1039 /*
1040 * Get the physical address of the PTE for a given VA.
1041 */
1042 ENTRY(ptest_addr)
1043 movl %sp@(4),%a1 | VA
1044 ptestr #5,%a1@,#7,%a0 | %a0 = addr of PTE
1045 movl %a0,%d0 | Result in %d0 (not a pointer return)
1046 rts
1047
1048 /*
1049 * Set processor priority level calls. Most are implemented with
1050 * inline asm expansions. However, we need one instantiation here
1051 * in case some non-optimized code makes external references.
1052 * Most places will use the inlined functions param.h supplies.
1053 */
1054
1055 ENTRY(_getsr)
1056 clrl %d0
1057 movw %sr,%d0
1058 movl %a1,%d0
1059 rts
1060
1061 ENTRY(_spl)
1062 clrl %d0
1063 movw %sr,%d0
1064 movl %sp@(4),%d1
1065 movw %d1,%sr
1066 rts
1067
1068 ENTRY(_splraise)
1069 clrl %d0
1070 movw %sr,%d0
1071 movl %d0,%d1
1072 andl #PSL_HIGHIPL,%d1 | old &= PSL_HIGHIPL
1073 cmpl %sp@(4),%d1 | (old - new)
1074 bge Lsplr
1075 movl %sp@(4),%d1
1076 movw %d1,%sr
1077 Lsplr:
1078 rts
1079
1080 /*
1081 * Save and restore 68881 state.
1082 */
1083 ENTRY(m68881_save)
1084 movl %sp@(4),%a0 | save area pointer
1085 fsave %a0@ | save state
1086 tstb %a0@ | null state frame?
1087 jeq Lm68881sdone | yes, all done
1088 fmovem %fp0-%fp7,%a0@(FPF_REGS) | save FP general regs
1089 fmovem %fpcr/%fpsr/%fpi,%a0@(FPF_FPCR) | save FP control regs
1090 Lm68881sdone:
1091 rts
1092
1093 ENTRY(m68881_restore)
1094 movl %sp@(4),%a0 | save area pointer
1095 tstb %a0@ | null state frame?
1096 jeq Lm68881rdone | yes, easy
1097 fmovem %a0@(FPF_FPCR),%fpcr/%fpsr/%fpi | restore FP control regs
1098 fmovem %a0@(FPF_REGS),%fp0-%fp7 | restore FP general regs
1099 Lm68881rdone:
1100 frestore %a0@ | restore state
1101 rts
1102
1103 /*
1104 * _delay(unsigned N)
1105 * Delay for at least (N/256) microseconds.
1106 * This routine depends on the variable: delay_divisor
1107 * which should be set based on the CPU clock rate.
1108 * XXX: Currently this is set based on the CPU model,
1109 * XXX: but this should be determined at run time...
1110 */
1111 GLOBAL(_delay)
1112 | %d0 = arg = (usecs << 8)
1113 movl %sp@(4),%d0
1114 | %d1 = delay_divisor;
1115 movl _C_LABEL(delay_divisor),%d1
1116 jra L_delay /* Jump into the loop! */
1117
1118 /*
1119 * Align the branch target of the loop to a half-line (8-byte)
1120 * boundary to minimize cache effects. This guarantees both
1121 * that there will be no prefetch stalls due to cache line burst
1122 * operations and that the loop will run from a single cache
1123 * half-line.
1124 */
1125 #ifdef __ELF__
1126 .align 8
1127 #else
1128 .align 3
1129 #endif
1130 L_delay:
1131 subl %d1,%d0
1132 jgt L_delay
1133 rts
1134
1135 | Define some addresses, mostly so DDB can print useful info.
1136 | Not using _C_LABEL() here because these symbols are never
1137 | referenced by any C code, and if the leading underscore
1138 | ever goes away, these lines turn into syntax errors...
1139 .set _KERNBASE,KERNBASE
1140 .set _MONSTART,SUN3X_MONSTART
1141 .set _PROM_BASE,SUN3X_PROM_BASE
1142 .set _MONEND,SUN3X_MONEND
1143
1144 |The end!
1145