1/*        $NetBSD: locore.s,v 1.134 2024/09/07 06:17:37 andvar 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. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * from: Utah $Hdr: locore.s 1.66 92/12/22$
37 *
38 *        @(#)locore.s        8.6 (Berkeley) 5/27/94
39 */
40
41#include "opt_compat_netbsd.h"
42#include "opt_compat_sunos.h"
43#include "opt_ddb.h"
44#include "opt_fpsp.h"
45#include "opt_kgdb.h"
46#include "opt_lockdebug.h"
47#include "opt_fpu_emulate.h"
48#include "opt_m68k_arch.h"
49
50#include "ite.h"
51#include "fd.h"
52#include "par.h"
53#include "assym.h"
54#include "ksyms.h"
55
56#include <machine/asm.h>
57
58/*
59 * This is for kvm_mkdb, and should be the address of the beginning
60 * of the kernel text segment (not necessarily the same as kernbase).
61 */
62          .text
63GLOBAL(kernel_text)
64
65/*
66 * Temporary stack for a variety of purposes.
67 * Try and make this the first thing is the data segment so it
68 * is page aligned.  Note that if we overflow here, we run into
69 * our text segment.
70 */
71          .data
72          .space    PAGE_SIZE
73ASLOCAL(tmpstk)
74
75#include <x68k/x68k/vectors.s>
76
77          .text
78/*
79 * This is where we wind up if the kernel jumps to location 0.
80 * (i.e. a bogus PC)  This is known to immediately follow the vector
81 * table and is hence at 0x400 (see reset vector in vectors.s).
82 */
83          PANIC("kernel jump to zero")
84          /* NOTREACHED */
85
86/*
87 * Macro to relocate a symbol, used before MMU is enabled.
88 */
89#define   _RELOC(var, ar)                         \
90          lea       var,ar;                       \
91          addl      %a5,ar
92
93#define   RELOC(var, ar)                _RELOC(_C_LABEL(var), ar)
94#define   ASRELOC(var, ar)    _RELOC(_ASM_LABEL(var), ar)
95
96/*
97 * Initialization
98 *
99 * A4 contains the address of the end of the symtab
100 * A5 contains physical load point from boot
101 * VBR contains zero from ROM.  Exceptions will continue to vector
102 * through ROM until MMU is turned on at which time they will vector
103 * through our table (vectors.s).
104 */
105
106BSS(lowram,4)
107BSS(esym,4)
108
109GLOBAL(_verspad)
110          .word     0
111GLOBAL(boot_version)
112          .word     X68K_BOOTIF_VERS
113
114ASENTRY_NOPROFILE(start)
115          movw      #PSL_HIGHIPL,%sr    | no interrupts
116
117          addql     #4,%sp
118          movel     %sp@+,%a5           | firstpa
119          movel     %sp@+,%d5           | fphysize -- last page
120          movel     %sp@,%a4            | esym
121
122          RELOC(vectab,%a0)             | set Vector Base Register temporarily
123          movc      %a0,%vbr
124
125#if 0     /* XXX this should be done by the boot loader */
126          RELOC(edata, %a0)             | clear out BSS
127          movl      #_C_LABEL(end)-4,%d0          | (must be <= 256 kB)
128          subl      #_C_LABEL(edata),%d0
129          lsrl      #2,%d0
1301:        clrl      %a0@+
131          dbra      %d0,1b
132#endif
133
134          ASRELOC(tmpstk, %a0)
135          movl      %a0,%sp                       | give ourselves a temporary stack
136          RELOC(esym, %a0)
137#if 1
138          movl      %a4,%a0@            | store end of symbol table
139#else
140          clrl      %a0@                          | no symbol table, yet
141#endif
142          RELOC(lowram, %a0)
143          movl      %a5,%a0@            | store start of physical memory
144
145          movl      #CACHE_OFF,%d0
146          movc      %d0,%cacr           | clear and disable on-chip cache(s)
147
148/* determine our CPU/MMU combo - check for all regardless of kernel config */
149          movl      #DC_FREEZE,%d0                | data freeze bit
150          movc      %d0,%cacr           |   only exists on 68030
151          movc      %cacr,%d0           | read it back
152          tstl      %d0                           | zero?
153          jeq       Lnot68030           | yes, we have 68020/68040/68060
154          jra       Lstart1                       | no, we have 68030
155Lnot68030:
156          bset      #31,%d0                       | data cache enable bit
157          movc      %d0,%cacr           |   only exists on 68040/68060
158          movc      %cacr,%d0           | read it back
159          tstl      %d0                           | zero?
160          jeq       Lis68020            | yes, we have 68020
161          moveq     #0,%d0                        | now turn it back off
162          movec     %d0,%cacr           |   before we access any data
163          .word     0xf4d8                        | cinva bc - invalidate caches XXX
164          bset      #30,%d0                       | data cache no allocate mode bit
165          movc      %d0,%cacr           |   only exists on 68060
166          movc      %cacr,%d0           | read it back
167          tstl      %d0                           | zero?
168          jeq       Lis68040            | yes, we have 68040
169          RELOC(mmutype, %a0)           | no, we have 68060
170          movl      #MMU_68040,%a0@               | with a 68040 compatible MMU
171          RELOC(cputype, %a0)
172          movl      #CPU_68060,%a0@               | and a 68060 CPU
173          jra       Lstart1
174Lis68040:
175          RELOC(mmutype, %a0)
176          movl      #MMU_68040,%a0@               | with a 68040 MMU
177          RELOC(cputype, %a0)
178          movl      #CPU_68040,%a0@               | and a 68040 CPU
179          jra       Lstart1
180Lis68020:
181          RELOC(mmutype, %a0)
182          movl      #MMU_68851,%a0@               | we have PMMU
183          RELOC(cputype, %a0)
184          movl      #CPU_68020,%a0@               | and a 68020 CPU
185
186Lstart1:
187          /*
188           * Now that we know what CPU we have, initialize the address error
189           * and bus error handlers in the vector table:
190           *
191           *      vectab+8        bus error
192           *      vectab+12       address error
193           */
194          RELOC(cputype,%a0)
195          RELOC(vectab,%a2)
196#if defined(M68060)
197          cmpl      #CPU_68060,%a0@               | 68060?
198          jne       1f
199          movl      #_C_LABEL(buserr60),%a2@(8)
200          movl      #_C_LABEL(addrerr4060),%a2@(12)
201          jra       Lstart2
2021:
203#endif
204#if defined(M68040)
205          cmpl      #CPU_68040,%a0@               | 68040?
206          jne       1f
207          movl      #_C_LABEL(buserr40),%a2@(8)
208          movl      #_C_LABEL(addrerr4060),%a2@(12)
209          jra       Lstart2
2101:
211#endif
212#if defined(M68030)
213          movl      #_C_LABEL(busaddrerr2030),%a2@(8)
214          movl      #_C_LABEL(busaddrerr2030),%a2@(12)
215#endif
216
217Lstart2:
218/* initialize source/destination control registers for movs */
219          moveq     #FC_USERD,%d0                 | user space
220          movc      %d0,%sfc            |   as source
221          movc      %d0,%dfc            |   and destination of transfers
222/* initialize memory sizes (for pmap_bootstrap) */
223          movl      %d5,%d1                       | last page
224          moveq     #PGSHIFT,%d2
225          lsrl      %d2,%d1                       | convert to page (click) number
226          RELOC(maxmem, %a0)
227          movl      %d1,%a0@            | save as maxmem
228          movl      %a5,%d0                       | lowram value from ROM via boot
229          lsrl      %d2,%d0                       | convert to page number
230          subl      %d0,%d1                       | compute amount of RAM present
231          RELOC(physmem, %a0)
232          movl      %d1,%a0@            | and physmem
233
234/* configure kernel and lwp0 VA space so we can get going */
235#if NKSYMS || defined(DDB) || defined(MODULAR)
236          RELOC(esym,%a0)                         | end of static kernel test/data/syms
237          movl      %a0@,%d5
238          jne       Lstart3
239#endif
240          movl      #_C_LABEL(end),%d5  | end of static kernel text/data
241Lstart3:
242          RELOC(setmemrange,%a0)                  | call setmemrange()
243          jbsr      %a0@                          |  to probe all memory regions
244          addl      #PAGE_SIZE-1,%d5
245          andl      #PG_FRAME,%d5                 | round to a page
246          movl      %d5,%a4
247          addl      %a5,%a4                       | convert to PA
248          pea       %a5@                          | firstpa
249          pea       %a4@                          | nextpa
250          RELOC(pmap_bootstrap,%a0)
251          jbsr      %a0@                          | pmap_bootstrap(firstpa, nextpa)
252          addql     #8,%sp
253
254/*
255 * Prepare to enable MMU.
256 * Since the kernel is mapped logical == physical, we just turn it on.
257 */
258          RELOC(Sysseg_pa, %a0)                   | system segment table addr
259          movl      %a0@,%d1            | read value (a PA)
260          RELOC(mmutype, %a0)
261          cmpl      #MMU_68040,%a0@               | 68040?
262          jne       Lmotommu1           | no, skip
263          .long     0x4e7b1807                    | movc %d1,%srp
264          jra       Lstploaddone
265Lmotommu1:
266          RELOC(protorp, %a0)
267          movl      %d1,%a0@(4)                   | segtable address
268          pmove     %a0@,%srp           | load the supervisor root pointer
269Lstploaddone:
270          RELOC(mmutype, %a0)
271          cmpl      #MMU_68040,%a0@               | 68040?
272          jne       Lmotommu2           | no, skip
273#include "opt_jupiter.h"
274#ifdef JUPITER
275          /* JUPITER-X: set system register "SUPER" bit */
276          movl      #0x0200a240,%d0               | translate DRAM area transparently
277          .long     0x4e7b0006                    | movc d0,dtt0
278          lea       0x00c00000,%a0                | %a0: graphic VRAM
279          lea       0x02c00000,%a1                | %a1: graphic VRAM ( not JUPITER-X )
280                                                  |      DRAM ( JUPITER-X )
281          movw      %a0@,%d0
282          movw      %d0,%d1
283          notw      %d1
284          movw      %d1,%a1@
285          movw      %d0,%a0@
286          cmpw      %a1@,%d1            | JUPITER-X?
287          jne       Ljupiterdone                  | no, skip
288          movl      #0x0100a240,%d0               | to access system register
289          .long     0x4e7b0006                    | movc %d0,%dtt0
290          movb      #0x01,0x01800003    | set "SUPER" bit
291Ljupiterdone:
292#endif /* JUPITER */
293          moveq     #0,%d0                        | ensure TT regs are disabled
294          .long     0x4e7b0004                    | movc %d0,%itt0
295          .long     0x4e7b0005                    | movc %d0,%itt1
296          .long     0x4e7b0006                    | movc %d0,%dtt0
297          .long     0x4e7b0007                    | movc %d0,%dtt1
298          .word     0xf4d8                        | cinva bc
299          .word     0xf518                        | pflusha
300          movl      #MMU40_TCR_BITS,%d0
301          .long     0x4e7b0003                    | movc %d0,%tc
302#ifdef M68060
303          RELOC(cputype, %a0)
304          cmpl      #CPU_68060,%a0@               | 68060?
305          jne       Lnot060cache
306          movl      #1,%d0
307          .long     0x4e7b0808                    | movcl %d0,%pcr
308          movl      #0xa0808000,%d0
309          movc      %d0,%cacr           | enable store buffer, both caches
310          jmp       Lenab1
311Lnot060cache:
312#endif
313          movl      #CACHE40_ON,%d0
314          movc      %d0,%cacr           | turn on both caches
315          jmp       Lenab1
316Lmotommu2:
317          pflusha
318          movl      #MMU51_TCR_BITS,%sp@-         | value to load TC with
319          pmove     %sp@,%tc            | load it
320
321/*
322 * Should be running mapped from this point on
323 */
324Lenab1:
325/* set vector base in virtual address */
326          movl      #_C_LABEL(vectab),%d0         | set Vector Base Register
327          movc      %d0,%vbr
328          lea       _ASM_LABEL(tmpstk),%sp        | temporary stack
329/* call final pmap setup */
330          jbsr      _C_LABEL(pmap_bootstrap_finalize)
331/* set kernel stack, user SP */
332          movl      _C_LABEL(lwp0uarea),%a1       | get lwp0 uarea
333          lea       %a1@(USPACE-4),%sp  | set kernel stack to end of area
334          movl      #USRSTACK-4,%a2
335          movl      %a2,%usp            | init user SP
336
337/* detect FPU type */
338          jbsr      _C_LABEL(fpu_probe)
339          movl      %d0,_C_LABEL(fputype)
340          tstl      _C_LABEL(fputype)   | Have an FPU?
341          jeq       Lenab2                        | No, skip.
342          clrl      %a1@(PCB_FPCTX)               | ensure null FP context
343          movl      %a1,%sp@-
344          jbsr      _C_LABEL(m68881_restore) | restore it (does not kill %a1)
345          addql     #4,%sp
346Lenab2:
347          cmpl      #MMU_68040,_C_LABEL(mmutype)  | 68040?
348          jeq       Ltbia040            | yes, cache already on
349          pflusha
350          tstl      _C_LABEL(mmutype)
351          jpl       Lenab3                        | 68851 implies no d-cache
352          movl      #CACHE_ON,%d0
353          movc      %d0,%cacr           | clear cache(s)
354          jra       Lenab3
355Ltbia040:
356          .word     0xf518                        | pflusha
357Lenab3:
358/* final setup for C code */
359          movl      %d7,_C_LABEL(boothowto)       | save reboot flags
360          movl      %d6,_C_LABEL(bootdev)         |   and boot device
361          jbsr      _C_LABEL(x68k_init) | additional pre-main initialization
362
363/*
364 * Create a fake exception frame so that cpu_lwp_fork() can copy it.
365 * main() nevers returns; we exit to user mode from a forked process
366 * later on.
367 */
368          clrw      %sp@-                         | vector offset/frame type
369          clrl      %sp@-                         | PC - filled in by "execve"
370          movw      #PSL_USER,%sp@-               | in user mode
371          clrl      %sp@-                         | stack adjust count and padding
372          lea       %sp@(-64),%sp                 | construct space for D0-D7/A0-A7
373          lea       _C_LABEL(lwp0),%a0  | save pointer to frame
374          movl      %sp,%a0@(L_MD_REGS) |   in lwp0.l_md.md_regs
375
376          jra       _C_LABEL(main)                | main()
377
378          PANIC("main() returned")      | Yow!  Main returned!
379          /* NOTREACHED */
380
381/*
382 * Trap/interrupt vector routines
383 */
384#include <m68k/m68k/trap_subr.s>
385
386/*
387 * Use common m68k bus error and address error handlers.
388 */
389#include <m68k/m68k/busaddrerr.s>
390
391/*
392 * FP exceptions.
393 */
394ENTRY_NOPROFILE(fpfline)
395#if defined(M68040)
396          cmpl      #FPU_68040,_C_LABEL(fputype) | 68040 FPU?
397          jne       Lfp_unimp           | no, skip FPSP
398          cmpw      #0x202c,%sp@(6)               | format type 2?
399          jne       _C_LABEL(illinst)   | no, not an FP emulation
400#ifdef FPSP
401          jmp       _ASM_LABEL(fpsp_unimp)        | yes, go handle it
402#else
403          clrl      %sp@-                         | stack adjust count
404          moveml    #0xFFFF,%sp@-                 | save registers
405          moveq     #T_FPEMULI,%d0                | denote as FP emulation trap
406          jra       _ASM_LABEL(fault)   | do it
407#endif
408Lfp_unimp:
409#endif /* M68040 */
410#ifdef FPU_EMULATE
411          clrl      %sp@-                         | stack adjust count
412          moveml    #0xFFFF,%sp@-                 | save registers
413          moveq     #T_FPEMULD,%d0                | denote as FP emulation trap
414          jra       _ASM_LABEL(fault)   | do it
415#else
416          jra       _C_LABEL(illinst)
417#endif
418
419ENTRY_NOPROFILE(fpunsupp)
420#if defined(M68040)
421          cmpl      #FPU_68040,_C_LABEL(fputype) | 68040 FPU?
422          jne       Lfp_unsupp                    | no, skip FPSP
423#ifdef FPSP
424          jmp       _ASM_LABEL(fpsp_unsupp)       | yes, go handle it
425#else
426          clrl      %sp@-                         | stack adjust count
427          moveml    #0xFFFF,%sp@-                 | save registers
428          moveq     #T_FPEMULD,%d0                | denote as FP emulation trap
429          jra       _ASM_LABEL(fault)   | do it
430#endif /* M68040 */
431Lfp_unsupp:
432#endif
433#ifdef FPU_EMULATE
434          clrl      %sp@-                         | stack adjust count
435          moveml    #0xFFFF,%sp@-                 | save registers
436          moveq     #T_FPEMULD,%d0                | denote as FP emulation trap
437          jra       _ASM_LABEL(fault)   | do it
438#else
439          jra       _C_LABEL(illinst)
440#endif
441
442/*
443 * Handles all other FP coprocessor exceptions.
444 * Note that since some FP exceptions generate mid-instruction frames
445 * and may cause signal delivery, we need to test for stack adjustment
446 * after the trap call.
447 */
448ENTRY_NOPROFILE(fpfault)
449          clrl      %sp@-                         | stack adjust count
450          moveml    #0xFFFF,%sp@-                 | save user registers
451          movl      %usp,%a0            | and save
452          movl      %a0,%sp@(FR_SP)               |   the user stack pointer
453          clrl      %sp@-                         | no VA arg
454          movl      _C_LABEL(curpcb),%a0          | current pcb
455          lea       %a0@(PCB_FPCTX),%a0 | address of FP savearea
456          fsave     %a0@                          | save state
457#if defined(M68040) || defined(M68060)
458          /* always null state frame on 68040, 68060 */
459          cmpl      #FPU_68040,_C_LABEL(fputype)
460          jge       Lfptnull
461#endif
462          tstb      %a0@                          | null state frame?
463          jeq       Lfptnull            | yes, safe
464          clrw      %d0                           | no, need to tweak BIU
465          movb      %a0@(1),%d0                   | get frame size
466          bset      #3,%a0@(0,%d0:w)    | set exc_pend bit of BIU
467Lfptnull:
468          fmovem    %fpsr,%sp@-                   | push fpsr as code argument
469          frestore %a0@                           | restore state
470          movl      #T_FPERR,%sp@-                | push type arg
471          jra       _ASM_LABEL(faultstkadj)       | call trap and deal with stack cleanup
472
473/*
474 * Other exceptions only cause four and six word stack frame and require
475 * no post-trap stack adjustment.
476 */
477
478ENTRY_NOPROFILE(badtrap)
479          moveml    #0xC0C0,%sp@-                 | save scratch regs
480          movw      %sp@(22),%sp@-                | push exception vector info
481          clrw      %sp@-
482          movl      %sp@(22),%sp@-                | and PC
483          jbsr      _C_LABEL(straytrap) | report
484          addql     #8,%sp                        | pop args
485          moveml    %sp@+,#0x0303                 | restore regs
486          jra       _ASM_LABEL(rei)               | all done
487
488ENTRY_NOPROFILE(trap0)
489          clrl      %sp@-                         | stack adjust count
490          moveml    #0xFFFF,%sp@-                 | save user registers
491          movl      %usp,%a0            | save the user SP
492          movl      %a0,%sp@(FR_SP)               |   in the savearea
493          movl      %d0,%sp@-           | push syscall number
494          jbsr      _C_LABEL(syscall)   | handle it
495          addql     #4,%sp                        | pop syscall arg
496          tstl      _C_LABEL(astpending)          | AST pending?
497          jne       Lrei                          | yes, handle it via trap
498          movl      %sp@(FR_SP),%a0               | grab and restore
499          movl      %a0,%usp            |   user SP
500          moveml    %sp@+,#0x7FFF                 | restore most registers
501          addql     #8,%sp                        | pop SP and stack adjust
502          rte
503
504/*
505 * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD)
506 *        cachectl(command, addr, length)
507 * command in %d0, addr in %a1, length in %d1
508 */
509ENTRY_NOPROFILE(trap12)
510          movl      _C_LABEL(curlwp),%a0
511          movl      %a0@(L_PROC),%sp@-  | push current proc pointer
512          movl      %d1,%sp@-           | push length
513          movl      %a1,%sp@-           | push addr
514          movl      %d0,%sp@-           | push command
515          jbsr      _C_LABEL(cachectl1) | do it
516          lea       %sp@(16),%sp                  | pop args
517          jra       _ASM_LABEL(rei)               | all done
518
519/*
520 * Trace (single-step) trap.  Kernel-mode is special.
521 * User mode traps are simply passed on to trap().
522 */
523ENTRY_NOPROFILE(trace)
524          clrl      %sp@-                         | stack adjust count
525          moveml    #0xFFFF,%sp@-
526          moveq     #T_TRACE,%d0
527
528          | Check PSW and see what happen.
529          |   T=0 S=0         (should not happen)
530          |   T=1 S=0         trace trap from user mode
531          |   T=0 S=1         trace trap on a trap instruction
532          |   T=1 S=1         trace trap from system mode (kernel breakpoint)
533
534          movw      %sp@(FR_HW),%d1               | get PSW
535          notw      %d1                           | XXX no support for T0 on 680[234]0
536          andw      #PSL_TS,%d1                   | from system mode (T=1, S=1)?
537          jeq       Lkbrkpt                       | yes, kernel breakpoint
538          jra       _ASM_LABEL(fault)   | no, user-mode fault
539
540/*
541 * Trap 15 is used for:
542 *        - GDB breakpoints (in user programs)
543 *        - KGDB breakpoints (in the kernel)
544 *        - trace traps for SUN binaries (not fully supported yet)
545 * User mode traps are simply passed to trap().
546 */
547ENTRY_NOPROFILE(trap15)
548          clrl      %sp@-                         | stack adjust count
549          moveml    #0xFFFF,%sp@-
550          moveq     #T_TRAP15,%d0
551          movw      %sp@(FR_HW),%d1               | get PSW
552          andw      #PSL_S,%d1                    | from system mode?
553          jne       Lkbrkpt                       | yes, kernel breakpoint
554          jra       _ASM_LABEL(fault)   | no, user-mode fault
555
556Lkbrkpt: | Kernel-mode breakpoint or trace trap. (%d0=trap_type)
557          | Save the system sp rather than the user sp.
558          movw      #PSL_HIGHIPL,%sr    | lock out interrupts
559          lea       %sp@(FR_SIZE),%a6   | Save stack pointer
560          movl      %a6,%sp@(FR_SP)               |  from before trap
561
562          | If were are not on tmpstk switch to it.
563          | (so debugger can change the stack pointer)
564          movl      %a6,%d1
565          cmpl      #_ASM_LABEL(tmpstk),%d1
566          jls       Lbrkpt2                       | already on tmpstk
567          | Copy frame to the temporary stack
568          movl      %sp,%a0                       | %a0=src
569          lea       _ASM_LABEL(tmpstk)-96,%a1 | %a1=dst
570          movl      %a1,%sp                       | %sp=new frame
571          moveq     #FR_SIZE,%d1
572Lbrkpt1:
573          movl      %a0@+,%a1@+
574          subql     #4,%d1
575          jgt       Lbrkpt1
576
577Lbrkpt2:
578          | Call the trap handler for the kernel debugger.
579          | Do not call trap() to do it, so that we can
580          | set breakpoints in trap() if we want.  We know
581          | the trap type is either T_TRACE or T_BREAKPOINT.
582          | If we have both DDB and KGDB, let KGDB see it first,
583          | because KGDB will just return 0 if not connected.
584          | Save args in %d2, %a2
585          movl      %d0,%d2                       | trap type
586          movl      %sp,%a2                       | frame ptr
587#ifdef KGDB
588          | Let KGDB handle it (if connected)
589          movl      %a2,%sp@-           | push frame ptr
590          movl      %d2,%sp@-           | push trap type
591          jbsr      _C_LABEL(kgdb_trap) | handle the trap
592          addql     #8,%sp                        | pop args
593          cmpl      #0,%d0                        | did kgdb handle it?
594          jne       Lbrkpt3                       | yes, done
595#endif
596#ifdef DDB
597          | Let DDB handle it
598          movl      %a2,%sp@-           | push frame ptr
599          movl      %d2,%sp@-           | push trap type
600          jbsr      _C_LABEL(kdb_trap)  | handle the trap
601          addql     #8,%sp                        | pop args
602#if 0     /* not needed on hp300 */
603          cmpl      #0,%d0                        | did ddb handle it?
604          jne       Lbrkpt3                       | yes, done
605#endif
606#endif
607          /* Sun 3 drops into PROM here. */
608Lbrkpt3:
609          | The stack pointer may have been modified, or
610          | data below it modified (by kgdb push call),
611          | so push the hardware frame at the current sp
612          | before restoring registers and returning.
613
614          movl      %sp@(FR_SP),%a0               | modified %sp
615          lea       %sp@(FR_SIZE),%a1   | end of our frame
616          movl      %a1@-,%a0@-                   | copy 2 longs with
617          movl      %a1@-,%a0@-                   | ... predecrement
618          movl      %a0,%sp@(FR_SP)               | %sp = h/w frame
619          moveml    %sp@+,#0x7FFF                 | restore all but %sp
620          movl      %sp@,%sp            | ... and %sp
621          rte                                     | all done
622
623/*
624 * Provide a generic interrupt dispatcher, only handle hardclock (int6)
625 * specially, to improve performance
626 */
627
628ENTRY_NOPROFILE(spurintr)     /* level 0 */
629          addql     #1,_C_LABEL(intrcnt)+0
630          INTERRUPT_SAVEREG
631          CPUINFO_INCREMENT(CI_NINTR)
632          INTERRUPT_RESTOREREG
633          rte                                     | XXX mfpcure (x680x0 hardware bug)
634
635ENTRY_NOPROFILE(kbdtimer)
636          rte
637
638ENTRY_NOPROFILE(intiotrap)
639          addql     #1,_C_LABEL(intr_depth)
640          INTERRUPT_SAVEREG
641          pea       %sp@(16-(FR_HW))    | XXX
642          jbsr      _C_LABEL(intio_intr)
643          addql     #4,%sp
644          CPUINFO_INCREMENT(CI_NINTR)
645          INTERRUPT_RESTOREREG
646          subql     #1,_C_LABEL(intr_depth)
647          jra       rei
648
649ENTRY_NOPROFILE(lev1intr)
650ENTRY_NOPROFILE(lev2intr)
651ENTRY_NOPROFILE(lev3intr)
652ENTRY_NOPROFILE(lev4intr)
653ENTRY_NOPROFILE(lev5intr)
654ENTRY_NOPROFILE(lev6intr)
655          addql     #1,_C_LABEL(intr_depth)
656          INTERRUPT_SAVEREG
657Lnotdma:
658          lea       _C_LABEL(intrcnt),%a0
659          movw      %sp@(22),%d0                  | use vector offset
660          andw      #0xfff,%d0                    |   sans frame type
661          addql     #1,%a0@(-0x60,%d0:w)          |     to increment apropos counter
662          movw      %sr,%sp@-           | push current SR value
663          clrw      %sp@-                         |    padded to longword
664          jbsr      _C_LABEL(intrhand)  | handle interrupt
665          addql     #4,%sp                        | pop SR
666          CPUINFO_INCREMENT(CI_NINTR)
667          INTERRUPT_RESTOREREG
668          subql     #1,_C_LABEL(intr_depth)
669          jra       _ASM_LABEL(rei)
670
671ENTRY_NOPROFILE(timertrap)
672          addql     #1,_C_LABEL(intr_depth)
673          INTERRUPT_SAVEREG             | save scratch registers
674          addql     #1,_C_LABEL(intrcnt)+32       | count hardclock interrupts
675          movl      %sp,%sp@-           | push pointer to clockframe
676          jbsr      _C_LABEL(hardclock) | hardclock(&frame)
677          addql     #4,%sp
678          CPUINFO_INCREMENT(CI_NINTR)   | chalk up another interrupt
679          INTERRUPT_RESTOREREG                    | restore scratch registers
680          subql     #1,_C_LABEL(intr_depth)
681          jra       _ASM_LABEL(rei)               | all done
682
683ENTRY_NOPROFILE(lev7intr)
684          addql     #1,_C_LABEL(intr_depth)
685          addql     #1,_C_LABEL(intrcnt)+28
686          clrl      %sp@-
687          moveml    #0xFFFF,%sp@-                 | save registers
688          movl      %usp,%a0            | and save
689          movl      %a0,%sp@(FR_SP)               |   the user stack pointer
690          jbsr      _C_LABEL(nmihand)   | call handler
691          movl      %sp@(FR_SP),%a0               | restore
692          movl      %a0,%usp            |   user SP
693          moveml    %sp@+,#0x7FFF                 | and remaining registers
694          addql     #8,%sp                        | pop SP and stack adjust
695          subql     #1,_C_LABEL(intr_depth)
696          jra       _ASM_LABEL(rei)               | all done
697
698/*
699 * floppy ejection trap
700 */
701
702ENTRY_NOPROFILE(fdeject)
703          jra       _ASM_LABEL(rei)
704
705/*
706 * Emulation of VAX REI instruction.
707 *
708 * This code deals with checking for and servicing ASTs
709 * (profiling, scheduling) and software interrupts (network, softclock).
710 * We check for ASTs first, just like the VAX.  To avoid excess overhead
711 * the T_ASTFLT handling code will also check for software interrupts so we
712 * do not have to do it here.  After identifying that we need an AST we
713 * drop the IPL to allow device interrupts.
714 *
715 * This code is complicated by the fact that sendsig may have been called
716 * necessitating a stack cleanup.
717 */
718
719ASENTRY_NOPROFILE(rei)
720          tstl      _C_LABEL(astpending)          | AST pending?
721          jne       1f                            | no, done
722          rte
7231:
724          btst      #5,%sp@                       | yes, are we returning to user mode?
725          beq       2f                            | no, done
726          rte
7272:
728          movw      #PSL_LOWIPL,%sr               | lower SPL
729          clrl      %sp@-                         | stack adjust
730          moveml    #0xFFFF,%sp@-                 | save all registers
731          movl      %usp,%a1            | including
732          movl      %a1,%sp@(FR_SP)               |    the users SP
733Lrei:
734          clrl      %sp@-                         | VA == none
735          clrl      %sp@-                         | code == none
736          movl      #T_ASTFLT,%sp@-               | type == async system trap
737          pea       %sp@(12)            | fp == trap frame address
738          jbsr      _C_LABEL(trap)                | go handle it
739          lea       %sp@(16),%sp                  | pop value args
740          movl      %sp@(FR_SP),%a0               | restore user SP
741          movl      %a0,%usp            |   from save area
742          movw      %sp@(FR_ADJ),%d0    | need to adjust stack?
743          jne       Laststkadj                    | yes, go to it
744          moveml    %sp@+,#0x7FFF                 | no, restore most user regs
745          addql     #8,%sp                        | toss SP and stack adjust
746          rte                                     | and do real RTE
747Laststkadj:
748          lea       %sp@(FR_HW),%a1               | pointer to HW frame
749          addql     #8,%a1                        | source pointer
750          movl      %a1,%a0                       | source
751          addw      %d0,%a0                       |  + hole size = dest pointer
752          movl      %a1@-,%a0@-                   | copy
753          movl      %a1@-,%a0@-                   |  8 bytes
754          movl      %a0,%sp@(FR_SP)               | new SSP
755          moveml    %sp@+,#0x7FFF                 | restore user registers
756          movl      %sp@,%sp            | and our SP
757          rte                                     | and do real RTE
758
759/*
760 * Primitives
761 */
762
763/*
764 * Use common m68k process/lwp switch and context save subroutines.
765 */
766#define FPCOPROC    /* XXX: Temp. reqd. */
767#include <m68k/m68k/switch_subr.s>
768
769
770#if defined(M68040) || defined(M68060)
771ENTRY(suline)
772          movl      %sp@(4),%a0                   | address to write
773          movl      _C_LABEL(curpcb),%a1          | current pcb
774          movl      #Lslerr,%a1@(PCB_ONFAULT) | where to return to on a fault
775          movl      %sp@(8),%a1                   | address of line
776          movl      %a1@+,%d0           | get lword
777          movsl     %d0,%a0@+           | put lword
778          nop                                     | sync
779          movl      %a1@+,%d0           | get lword
780          movsl     %d0,%a0@+           | put lword
781          nop                                     | sync
782          movl      %a1@+,%d0           | get lword
783          movsl     %d0,%a0@+           | put lword
784          nop                                     | sync
785          movl      %a1@+,%d0           | get lword
786          movsl     %d0,%a0@+           | put lword
787          nop                                     | sync
788          moveq     #0,%d0                        | indicate no fault
789          jra       Lsldone
790Lslerr:
791          moveq     #-1,%d0
792Lsldone:
793          movl      _C_LABEL(curpcb),%a1          | current pcb
794          clrl      %a1@(PCB_ONFAULT)   | clear fault address
795          rts
796#endif
797
798ENTRY(ecacheon)
799          rts
800
801ENTRY(ecacheoff)
802          rts
803
804/*
805 * _delay(u_int N)
806 *
807 * Delay for at least N microseconds.
808 * This routine depends on the variable:  delay_divisor
809 * which should be set based on the CPU clock rate.
810 */
811ENTRY_NOPROFILE(_delay)
812          | %d0 = (usecs * a certain magnification factor)
813          movl      %sp@(4),%d0
814          lsll      #8,%d0
815          | %d1 = delay_divisor
816          movl      _C_LABEL(delay_divisor),%d1
817L_delay:
818          subl      %d1,%d0
819          jgt       L_delay
820          rts
821
822/*
823 * Handle the nitty-gritty of rebooting the machine.
824 * Basically we just turn off the MMU and jump to the appropriate ROM routine.
825 * Note that we must be running in an address range that is mapped one-to-one
826 * logical to physical so that the PC is still valid immediately after the MMU
827 * is turned off.  We have conveniently mapped the last page of physical
828 * memory this way.
829 */
830ENTRY_NOPROFILE(doboot)
831          movw      #PSL_HIGHIPL,%sr    | cut off any interrupts
832          subal     %a1,%a1                       | a1 = 0
833
834          movl      #CACHE_OFF,%d0
835#if defined(M68040) || defined(M68060)
836          movl      _C_LABEL(mmutype),%d2         | d2 = mmutype
837          addl      #(-1 * MMU_68040),%d2                   | 68040?
838          jne       Ldoboot0            | no, skip
839          .word     0xf4f8                        | cpusha bc - push and invalidate caches
840          nop
841          movl      #CACHE40_OFF,%d0
842Ldoboot0:
843#endif
844          movc      %d0,%cacr           | disable on-chip cache(s)
845
846          | ok, turn off MMU..
847Ldoreboot:
848#if defined(M68040) || defined(M68060)
849          tstl      %d2                           | 68040?
850          jne       LmotommuF           | no, skip
851          movc      %a1,%cacr           | caches off
852          .long     0x4e7b9003                    | movc a1(=0),tc ; disable MMU
853          jra       Ldoreboot1
854LmotommuF:
855#endif
856          clrl      %sp@
857          pmove     %sp@,%tc            | disable MMU
858Ldoreboot1:
859          moveml    0x00ff0000,#0x0101  | get RESET vectors in ROM
860                                                  |         (d0: ssp, a0: pc)
861          moveml    #0x0101,%a1@                  | put them at 0x0000 (for Xellent30)
862          movc      %a1,%vbr            | reset Vector Base Register
863          jmp       %a0@                          | reboot X680x0
864Lebootcode:
865
866/*
867 * Misc. global variables.
868 */
869          .data
870GLOBAL(mmutype)
871          .long     MMU_68030           | default to 030 internal MMU
872
873GLOBAL(cputype)
874          .long     CPU_68030           | default to 68030 CPU
875
876#ifdef M68K_MMU_HP
877GLOBAL(ectype)
878          .long     EC_NONE                       | external cache type, default to none
879#endif
880
881GLOBAL(fputype)
882          .long     FPU_NONE
883
884GLOBAL(intiobase)
885          .long     0                             | KVA of base of internal IO space
886
887GLOBAL(intiolimit)
888          .long     0                             | KVA of end of internal IO space
889
890#ifdef DEBUG
891ASGLOBAL(fulltflush)
892          .long     0
893
894ASGLOBAL(fullcflush)
895          .long     0
896#endif
897
898/* interrupt counters */
899
900GLOBAL(intrnames)
901          .asciz    "spur"
902          .asciz    "lev1"
903          .asciz    "lev2"
904          .asciz    "lev3"
905          .asciz    "lev4"
906          .asciz    "lev5"
907          .asciz    "lev6"
908          .asciz    "nmi"
909          .asciz    "clock"
910          .asciz    "com"
911GLOBAL(eintrnames)
912          .even
913
914GLOBAL(intrcnt)
915          .long     0,0,0,0,0,0,0,0,0,0
916GLOBAL(eintrcnt)
917