/* $NetBSD: locore.s,v 1.84 2008/06/23 08:33:38 isaki Exp $ */ /* * Copyright (c) 1980, 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer * Science Department. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: Utah $Hdr: locore.s 1.66 92/12/22$ * * @(#)locore.s 8.6 (Berkeley) 5/27/94 */ /* * Copyright (c) 1988 University of Utah. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer * Science Department. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * from: Utah $Hdr: locore.s 1.66 92/12/22$ * * @(#)locore.s 8.6 (Berkeley) 5/27/94 */ #include "opt_compat_netbsd.h" #include "opt_compat_svr4.h" #include "opt_compat_sunos.h" #include "opt_ddb.h" #include "opt_fpsp.h" #include "opt_kgdb.h" #include "opt_lockdebug.h" #include "ite.h" #include "fd.h" #include "par.h" #include "assym.h" #include "ksyms.h" #include <machine/asm.h> | This is for kvm_mkdb, and should be the address of the beginning | of the kernel text segment (not necessarily the same as kernbase). .text GLOBAL(kernel_text) /* * Temporary stack for a variety of purposes. * Try and make this the first thing is the data segment so it * is page aligned. Note that if we overflow here, we run into * our text segment. */ .data .space PAGE_SIZE ASLOCAL(tmpstk) #include <x68k/x68k/vectors.s> .text /* * This is where we wind up if the kernel jumps to location 0. * (i.e. a bogus PC) This is known to immediately follow the vector * table and is hence at 0x400 (see reset vector in vectors.s). */ PANIC("kernel jump to zero") /* NOTREACHED */ /* * Trap/interrupt vector routines */ #include <m68k/m68k/trap_subr.s> ENTRY_NOPROFILE(buserr) ENTRY_NOPROFILE(buserr60) | XXX tstl _C_LABEL(nofault) | device probe? jeq Lberr | no, handle as usual movl _C_LABEL(nofault),%sp@- | yes, jbsr _C_LABEL(longjmp) | longjmp(nofault) Lberr: #if defined(M68040) || defined(M68060) cmpl #MMU_68040,_C_LABEL(mmutype) | 68040/060? jne _C_LABEL(addrerr) | no, skip clrl %sp@- | stack adjust count moveml #0xFFFF,%sp@- | save user registers movl %usp,%a0 | save the user SP movl %a0,%sp@(FR_SP) | in the savearea lea %sp@(FR_HW),%a1 | grab base of HW berr frame #if defined(M68060) cmpl #CPU_68060,_C_LABEL(cputype) | 68060? jne Lbenot060 movel %a1@(12),%d0 | grap FSLW btst #2,%d0 | branch prediction error? jeq Lnobpe | no, skip movc %cacr,%d1 orl #IC60_CABC,%d1 | clear all branch cache entries movc %d1,%cacr movl %d0,%d1 andl #0x7ffd,%d1 | check other faults jeq _ASM_LABEL(faultstkadjnotrap2) Lnobpe: | XXX this is not needed. | movl %d0,%sp@ | code is FSLW now. | we need to adjust for misaligned addresses movl %a1@(8),%d1 | grab VA btst #27,%d0 | check for mis-aligned access jeq Lberr3 | no, skip addl #28,%d1 | yes, get into next page | operand case: 3, | instruction case: 4+12+12 | XXX instr. case not done yet andl #PG_FRAME,%d1 | and truncate Lberr3: movl %d1,%sp@- | push fault VA movl %d0,%sp@- | and FSLW andw #0x1f80,%d0 jeq Lisberr jra Lismerr Lbenot060: #endif moveq #0,%d0 movw %a1@(12),%d0 | grab SSW movl %a1@(20),%d1 | and fault VA btst #11,%d0 | check for mis-aligned access jeq Lberr2 | no, skip addl #3,%d1 | yes, get into next page andl #PG_FRAME,%d1 | and truncate Lberr2: movl %d1,%sp@- | push fault VA movl %d0,%sp@- | and padded SSW btst #10,%d0 | ATC bit set? jeq Lisberr | no, must be a real bus error movc %dfc,%d1 | yes, get MMU fault movc %d0,%dfc | store faulting function code movl %sp@(4),%a0 | get faulting address .word 0xf568 | ptestr a0@ movc %d1,%dfc .long 0x4e7a0805 | movc mmusr,d0 movw %d0,%sp@ | save (ONLY LOW 16 BITS!) jra Lismerr #endif ENTRY_NOPROFILE(addrerr) clrl %sp@- | stack adjust count moveml #0xFFFF,%sp@- | save user registers movl %usp,%a0 | save the user SP movl %a0,%sp@(FR_SP) | in the savearea lea %sp@(FR_HW),%a1 | grab base of HW berr frame #if defined(M68040) || defined(M68060) cmpl #MMU_68040,_C_LABEL(mmutype) | 68040? jne Lbenot040 | no, skip movl %a1@(8),%sp@- | yes, push fault address clrl %sp@- | no SSW for address fault jra Lisaerr | go deal with it Lbenot040: #endif moveq #0,%d0 movw %a1@(10),%d0 | grab SSW for fault processing btst #12,%d0 | RB set? jeq LbeX0 | no, test RC bset #14,%d0 | yes, must set FB movw %d0,%a1@(10) | for hardware too LbeX0: btst #13,%d0 | RC set? jeq LbeX1 | no, skip bset #15,%d0 | yes, must set FC movw %d0,%a1@(10) | for hardware too LbeX1: btst #8,%d0 | data fault? jeq Lbe0 | no, check for hard cases movl %a1@(16),%d1 | fault address is as given in frame jra Lbe10 | thats it Lbe0: btst #4,%a1@(6) | long (type B) stack frame? jne Lbe4 | yes, go handle movl %a1@(2),%d1 | no, can use save PC btst #14,%d0 | FB set? jeq Lbe3 | no, try FC addql #4,%d1 | yes, adjust address jra Lbe10 | done Lbe3: btst #15,%d0 | FC set? jeq Lbe10 | no, done addql #2,%d1 | yes, adjust address jra Lbe10 | done Lbe4: movl %a1@(36),%d1 | long format, use stage B address btst #15,%d0 | FC set? jeq Lbe10 | no, all done subql #2,%d1 | yes, adjust address Lbe10: movl %d1,%sp@- | push fault VA movl %d0,%sp@- | and padded SSW movw %a1@(6),%d0 | get frame format/vector offset andw #0x0FFF,%d0 | clear out frame format cmpw #12,%d0 | address error vector? jeq Lisaerr | yes, go to it movl %d1,%a0 | fault address movl %sp@,%d0 | function code from ssw btst #8,%d0 | data fault? jne Lbe10a movql #1,%d0 | user program access FC | (we dont separate data/program) btst #5,%a1@ | supervisor mode? jeq Lbe10a | if no, done movql #5,%d0 | else supervisor program access Lbe10a: ptestr %d0,%a0@,#7 | do a table search pmove %psr,%sp@ | save result movb %sp@,%d1 btst #2,%d1 | invalid? (incl. limit viol and berr) jeq Lmightnotbemerr | no -> wp check btst #7,%d1 | is it MMU table berr? jeq Lismerr | no, must be fast jra Lisberr1 | real bus err needs not be fast Lmightnotbemerr: btst #3,%d1 | write protect bit set? jeq Lisberr1 | no, must be bus error movl %sp@,%d0 | ssw into low word of d0 andw #0xc0,%d0 | write protect is set on page: cmpw #0x40,%d0 | was it read cycle? jeq Lisberr1 | yes, was not WPE, must be bus err Lismerr: movl #T_MMUFLT,%sp@- | show that we are an MMU fault jra _ASM_LABEL(faultstkadj) | and deal with it Lisaerr: movl #T_ADDRERR,%sp@- | mark address error jra _ASM_LABEL(faultstkadj) | and deal with it Lisberr1: clrw %sp@ | re-clear pad word Lisberr: movl #T_BUSERR,%sp@- | mark bus error jra _ASM_LABEL(faultstkadj) | and deal with it /* * FP exceptions. */ #include "opt_fpu_emulate.h" ENTRY_NOPROFILE(fpfline) #if defined(M68040) cmpl #FPU_68040,_C_LABEL(fputype) | 64040 FPU? jne Lfp_unimp | no, skip FPSP cmpw #0x202c,%sp@(6) | format type 2? jne _C_LABEL(illinst) | no, not an FP emulation #ifdef FPSP jmp _ASM_LABEL(fpsp_unimp) | yes, go handle it #else clrl %sp@- | stack adjust count moveml #0xFFFF,%sp@- | save registers moveq #T_FPEMULI,%d0 | denote as FP emulation trap jra _ASM_LABEL(fault) | do it #endif Lfp_unimp: #endif #ifdef FPU_EMULATE clrl %sp@- | stack adjust count moveml #0xFFFF,%sp@- | save registers moveq #T_FPEMULD,%d0 | denote as FP emulation trap jra _ASM_LABEL(fault) | do it #else jra _C_LABEL(illinst) #endif ENTRY_NOPROFILE(fpunsupp) #if defined(M68040) cmpl #FPU_68040,_C_LABEL(fputype) | 68040? jne Lfp_unsupp | no, skip FPSP #ifdef FPSP jmp _ASM_LABEL(fpsp_unsupp) | yes, go handle it #else clrl %sp@- | stack adjust count moveml #0xFFFF,%sp@- | save registers moveq #T_FPEMULD,%d0 | denote as FP emulation trap jra _ASM_LABEL(fault) | do it #endif Lfp_unsupp: #endif #ifdef FPU_EMULATE clrl %sp@- | stack adjust count moveml #0xFFFF,%sp@- | save registers moveq #T_FPEMULD,%d0 | denote as FP emulation trap jra _ASM_LABEL(fault) | do it #else jra _C_LABEL(illinst) #endif /* * Handles all other FP coprocessor exceptions. * Note that since some FP exceptions generate mid-instruction frames * and may cause signal delivery, we need to test for stack adjustment * after the trap call. */ ENTRY_NOPROFILE(fpfault) clrl %sp@- | stack adjust count moveml #0xFFFF,%sp@- | save user registers movl %usp,%a0 | and save movl %a0,%sp@(FR_SP) | the user stack pointer clrl %sp@- | no VA arg movl _C_LABEL(curpcb),%a0 | current pcb lea %a0@(PCB_FPCTX),%a0 | address of FP savearea fsave %a0@ | save state #if defined(M68040) || defined(M68060) /* always null state frame on 68040, 68060 */ cmpl #FPU_68040,_C_LABEL(fputype) jle Lfptnull #endif tstb %a0@ | null state frame? jeq Lfptnull | yes, safe clrw %d0 | no, need to tweak BIU movb %a0@(1),%d0 | get frame size bset #3,%a0@(0,%d0:w) | set exc_pend bit of BIU Lfptnull: fmovem %fpsr,%sp@- | push fpsr as code argument frestore %a0@ | restore state movl #T_FPERR,%sp@- | push type arg jra _ASM_LABEL(faultstkadj) | call trap and deal with stack cleanup /* * Other exceptions only cause four and six word stack frame and require * no post-trap stack adjustment. */ ENTRY_NOPROFILE(badtrap) moveml #0xC0C0,%sp@- | save scratch regs movw %sp@(22),%sp@- | push exception vector info clrw %sp@- movl %sp@(22),%sp@- | and PC jbsr _C_LABEL(straytrap) | report addql #8,%sp | pop args moveml %sp@+,#0x0303 | restore regs jra _ASM_LABEL(rei) | all done ENTRY_NOPROFILE(trap0) clrl %sp@- | stack adjust count moveml #0xFFFF,%sp@- | save user registers movl %usp,%a0 | save the user SP movl %a0,%sp@(FR_SP) | in the savearea movl %d0,%sp@- | push syscall number jbsr _C_LABEL(syscall) | handle it addql #4,%sp | pop syscall arg tstl _C_LABEL(astpending) jne Lrei2 tstb _C_LABEL(ssir) jeq Ltrap1 movw #SPL1,%sr tstb _C_LABEL(ssir) jne Lsir1 Ltrap1: movl %sp@(FR_SP),%a0 | grab and restore movl %a0,%usp | user SP moveml %sp@+,#0x7FFF | restore most registers addql #8,%sp | pop SP and stack adjust rte /* * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD) * cachectl(command, addr, length) * command in d0, addr in a1, length in d1 */ ENTRY_NOPROFILE(trap12) movl _C_LABEL(curlwp),%a0 movl %a0@(L_PROC),%sp@- | push curproc pointer movl %d1,%sp@- | push length movl %a1,%sp@- | push addr movl %d0,%sp@- | push command jbsr _C_LABEL(cachectl1) | do it lea %sp@(16),%sp | pop args jra _ASM_LABEL(rei) | all done /* * Trace (single-step) trap. Kernel-mode is special. * User mode traps are simply passed on to trap(). */ ENTRY_NOPROFILE(trace) clrl %sp@- | stack adjust count moveml #0xFFFF,%sp@- moveq #T_TRACE,%d0 | Check PSW and see what happen. | T=0 S=0 (should not happen) | T=1 S=0 trace trap from user mode | T=0 S=1 trace trap on a trap instruction | T=1 S=1 trace trap from system mode (kernel breakpoint) movw %sp@(FR_HW),%d1 | get PSW notw %d1 | XXX no support for T0 on 680[234]0 andw #PSL_TS,%d1 | from system mode (T=1, S=1)? jeq Lkbrkpt | yes, kernel breakpoint jra _ASM_LABEL(fault) | no, user-mode fault /* * Trap 15 is used for: * - GDB breakpoints (in user programs) * - KGDB breakpoints (in the kernel) * - trace traps for SUN binaries (not fully supported yet) * User mode traps are simply passed to trap(). */ ENTRY_NOPROFILE(trap15) clrl %sp@- | stack adjust count moveml #0xFFFF,%sp@- moveq #T_TRAP15,%d0 movw %sp@(FR_HW),%d1 | get PSW andw #PSL_S,%d1 | from system mode? jne Lkbrkpt | yes, kernel breakpoint jra _ASM_LABEL(fault) | no, user-mode fault Lkbrkpt: | Kernel-mode breakpoint or trace trap. (d0=trap_type) | Save the system sp rather than the user sp. movw #PSL_HIGHIPL,%sr | lock out interrupts lea %sp@(FR_SIZE),%a6 | Save stack pointer movl %a6,%sp@(FR_SP) | from before trap | If were are not on tmpstk switch to it. | (so debugger can change the stack pointer) movl %a6,%d1 cmpl #_ASM_LABEL(tmpstk),%d1 jls Lbrkpt2 | already on tmpstk | Copy frame to the temporary stack movl %sp,%a0 | a0=src lea _ASM_LABEL(tmpstk)-96,%a1 | a1=dst movl %a1,%sp | sp=new frame moveq #FR_SIZE,%d1 Lbrkpt1: movl %a0@+,%a1@+ subql #4,%d1 jgt Lbrkpt1 Lbrkpt2: | Call the trap handler for the kernel debugger. | Do not call trap() to do it, so that we can | set breakpoints in trap() if we want. We know | the trap type is either T_TRACE or T_BREAKPOINT. | If we have both DDB and KGDB, let KGDB see it first, | because KGDB will just return 0 if not connected. | Save args in d2, a2 movl %d0,%d2 | trap type movl %sp,%a2 | frame ptr #ifdef KGDB | Let KGDB handle it (if connected) movl %a2,%sp@- | push frame ptr movl %d2,%sp@- | push trap type jbsr _C_LABEL(kgdb_trap) | handle the trap addql #8,%sp | pop args cmpl #0,%d0 | did kgdb handle it? jne Lbrkpt3 | yes, done #endif #ifdef DDB | Let DDB handle it movl %a2,%sp@- | push frame ptr movl %d2,%sp@- | push trap type jbsr _C_LABEL(kdb_trap) | handle the trap addql #8,%sp | pop args #if 0 /* not needed on hp300 */ cmpl #0,%d0 | did ddb handle it? jne Lbrkpt3 | yes, done #endif #endif /* Sun 3 drops into PROM here. */ Lbrkpt3: | The stack pointer may have been modified, or | data below it modified (by kgdb push call), | so push the hardware frame at the current sp | before restoring registers and returning. movl %sp@(FR_SP),%a0 | modified sp lea %sp@(FR_SIZE),%a1 | end of our frame movl %a1@-,%a0@- | copy 2 longs with movl %a1@-,%a0@- | ... predecrement movl %a0,%sp@(FR_SP) | sp = h/w frame moveml %sp@+,#0x7FFF | restore all but sp movl %sp@,%sp | ... and sp rte | all done /* Use common m68k sigreturn */ #include <m68k/m68k/sigreturn.s> /* * Interrupt handlers. (auto vector.... not used) * original(amiga) routines: * Level 0: Spurious: ignored. * Level 1: builtin-RS232 TBE, softint (not used yet) * Level 2: keyboard (CIA-A) + DMA + SCSI * Level 3: VBL * Level 4: not used * Level 5: builtin-RS232 RBF * Level 6: Clock (CIA-B-Timers) * Level 7: Non-maskable: shouldn't be possible. ignore. */ /* Provide a generic interrupt dispatcher, only handle hardclock (int6) * specially, to improve performance */ #define INTERRUPT_SAVEREG moveml #0xC0C0,%sp@- ; addql #1,_C_LABEL(idepth) #define INTERRUPT_RESTOREREG subql #1,_C_LABEL(idepth) ; moveml %sp@+,#0x0303 ENTRY_NOPROFILE(spurintr) /* level 0 */ addql #1,_C_LABEL(intrcnt)+0 rte | XXX mfpcure (x680x0 hardware bug) ENTRY_NOPROFILE(kbdtimer) rte ENTRY_NOPROFILE(powtrap) #include "pow.h" #if NPOW > 0 INTERRUPT_SAVEREG jbsr _C_LABEL(powintr) INTERRUPT_RESTOREREG #endif addql #1,_C_LABEL(intrcnt)+36 addql #1,_C_LABEL(uvmexp)+UVMEXP_INTRS jra rei ENTRY_NOPROFILE(com0trap) #include "com.h" #if NXCOM > 0 INTERRUPT_SAVEREG movel #0,%sp@- jbsr _C_LABEL(comintr) addql #4,%sp INTERRUPT_RESTOREREG #endif addql #1,_C_LABEL(intrcnt)+40 addql #1,_C_LABEL(uvmexp)+UVMEXP_INTRS jra rei ENTRY_NOPROFILE(com1trap) #if NXCOM > 1 INTERRUPT_SAVEREG movel #1,%sp@- jbsr _C_LABEL(comintr) addql #4,%sp INTERRUPT_RESTOREREG #endif addql #1,_C_LABEL(intrcnt)+40 addql #1,_C_LABEL(uvmexp)+UVMEXP_INTRS jra rei ENTRY_NOPROFILE(intiotrap) INTERRUPT_SAVEREG #if 0 movw #PSL_HIGHIPL,%sr | XXX #endif pea %sp@(16-(FR_HW)) | XXX jbsr _C_LABEL(intio_intr) addql #4,%sp INTERRUPT_RESTOREREG addql #1,_C_LABEL(uvmexp)+UVMEXP_INTRS jra rei ENTRY_NOPROFILE(lev1intr) ENTRY_NOPROFILE(lev2intr) ENTRY_NOPROFILE(lev3intr) ENTRY_NOPROFILE(lev4intr) ENTRY_NOPROFILE(lev5intr) ENTRY_NOPROFILE(lev6intr) INTERRUPT_SAVEREG Lnotdma: lea _C_LABEL(intrcnt),%a0 movw %sp@(22),%d0 | use vector offset andw #0xfff,%d0 | sans frame type addql #1,%a0@(-0x60,%d0:w) | to increment apropos counter movw %sr,%sp@- | push current SR value clrw %sp@- | padded to longword jbsr _C_LABEL(intrhand) | handle interrupt addql #4,%sp | pop SR INTERRUPT_RESTOREREG addql #1,_C_LABEL(uvmexp)+UVMEXP_INTRS jra _ASM_LABEL(rei) ENTRY_NOPROFILE(timertrap) moveml #0xC0C0,%sp@- | save scratch registers addql #1,_C_LABEL(intrcnt)+32 | count hardclock interrupts lea %sp@(16),%a1 | a1 = &clockframe movl %a1,%sp@- jbsr _C_LABEL(hardclock) | hardclock(&frame) addql #4,%sp addql #1,_C_LABEL(uvmexp)+UVMEXP_INTRS | chalk up another interrupt moveml %sp@+,#0x0303 | restore scratch registers jra _ASM_LABEL(rei) | all done ENTRY_NOPROFILE(lev7intr) addql #1,_C_LABEL(intrcnt)+28 clrl %sp@- moveml #0xFFFF,%sp@- | save registers movl %usp,%a0 | and save movl %a0,%sp@(FR_SP) | the user stack pointer jbsr _C_LABEL(nmihand) | call handler movl %sp@(FR_SP),%a0 | restore movl %a0,%usp | user SP moveml %sp@+,#0x7FFF | and remaining registers addql #8,%sp | pop SP and stack adjust jra _ASM_LABEL(rei) | all done /* * floppy ejection trap */ ENTRY_NOPROFILE(fdeject) jra _ASM_LABEL(rei) /* * Emulation of VAX REI instruction. * * This code deals with checking for and servicing ASTs * (profiling, scheduling) and software interrupts (network, softclock). * We check for ASTs first, just like the VAX. To avoid excess overhead * the T_ASTFLT handling code will also check for software interrupts so we * do not have to do it here. After identifing that we need an AST we * drop the IPL to allow device interrupts. * * This code is complicated by the fact that sendsig may have been called * necessitating a stack cleanup. */ ASENTRY_NOPROFILE(rei) tstl _C_LABEL(astpending) | AST pending? jeq Lchksir | no, go check for SIR Lrei1: btst #5,%sp@ | yes, are we returning to user mode? jne Lchksir | no, go check for SIR movw #PSL_LOWIPL,%sr | lower SPL clrl %sp@- | stack adjust moveml #0xFFFF,%sp@- | save all registers movl %usp,%a1 | including movl %a1,%sp@(FR_SP) | the users SP Lrei2: clrl %sp@- | VA == none clrl %sp@- | code == none movl #T_ASTFLT,%sp@- | type == async system trap pea %sp@(12) | fp = trap frame address jbsr _C_LABEL(trap) | go handle it lea %sp@(16),%sp | pop value args movl %sp@(FR_SP),%a0 | restore user SP movl %a0,%usp | from save area movw %sp@(FR_ADJ),%d0 | need to adjust stack? jne Laststkadj | yes, go to it moveml %sp@+,#0x7FFF | no, restore most user regs addql #8,%sp | toss SP and stack adjust rte | and do real RTE Laststkadj: lea %sp@(FR_HW),%a1 | pointer to HW frame addql #8,%a1 | source pointer movl %a1,%a0 | source addw %d0,%a0 | + hole size = dest pointer movl %a1@-,%a0@- | copy movl %a1@-,%a0@- | 8 bytes movl %a0,%sp@(FR_SP) | new SSP moveml %sp@+,#0x7FFF | restore user registers movl %sp@,%sp | and our SP rte | and do real RTE Lchksir: tstb _C_LABEL(ssir) | SIR pending? jeq Ldorte | no, all done movl %d0,%sp@- | need a scratch register movw %sp@(4),%d0 | get SR andw #PSL_IPL7,%d0 | mask all but IPL jne Lnosir | came from interrupt, no can do movl %sp@+,%d0 | restore scratch register Lgotsir: movw #SPL1,%sr | prevent others from servicing int tstb _C_LABEL(ssir) | too late? jeq Ldorte | yes, oh well... clrl %sp@- | stack adjust moveml #0xFFFF,%sp@- | save all registers movl %usp,%a1 | including movl %a1,%sp@(FR_SP) | the users SP Lsir1: clrl %sp@- | VA == none clrl %sp@- | code == none movl #T_SSIR,%sp@- | type == software interrupt pea %sp@(12) | fp = trap frame address jbsr _C_LABEL(trap) | go handle it lea %sp@(16),%sp | pop value args movl %sp@(FR_SP),%a0 | restore movl %a0,%usp | user SP moveml %sp@+,#0x7FFF | and all remaining registers addql #8,%sp | pop SP and stack adjust rte Lnosir: movl %sp@+,%d0 | restore scratch register Ldorte: rte | real return /* * Macro to relocate a symbol, used before MMU is enabled. */ #define _RELOC(var, ar) \ lea var,ar; \ addl %a5,ar #define RELOC(var, ar) _RELOC(_C_LABEL(var), ar) #define ASRELOC(var, ar) _RELOC(_ASM_LABEL(var), ar) /* * Initialization * * A4 contains the address of the end of the symtab * A5 contains physical load point from boot * VBR contains zero from ROM. Exceptions will continue to vector * through ROM until MMU is turned on at which time they will vector * through our table (vectors.s). */ BSS(lowram,4) BSS(esym,4) GLOBAL(_verspad) .word 0 GLOBAL(boot_version) .word X68K_BOOTIF_VERS ASENTRY_NOPROFILE(start) movw #PSL_HIGHIPL,%sr | no interrupts addql #4,%sp movel %sp@+,%a5 | firstpa movel %sp@+,%d5 | fphysize -- last page movel %sp@,%a4 | esym RELOC(vectab,%a0) | set Vector Base Register temporaly movc %a0,%vbr #if 0 /* XXX this should be done by the boot loader */ RELOC(edata, %a0) | clear out BSS movl #_C_LABEL(end)-4,%d0 | (must be <= 256 kB) subl #_C_LABEL(edata),%d0 lsrl #2,%d0 1: clrl %a0@+ dbra %d0,1b #endif ASRELOC(tmpstk, %a0) movl %a0,%sp | give ourselves a temporary stack RELOC(esym, %a0) #if 1 movl %a4,%a0@ | store end of symbol table #else clrl %a0@ | no symbol table, yet #endif RELOC(lowram, %a0) movl %a5,%a0@ | store start of physical memory RELOC(intr_reset, %a0) jbsr %a0@ | XXX movl #CACHE_OFF,%d0 movc %d0,%cacr | clear and disable on-chip cache(s) /* determine our CPU/MMU combo - check for all regardless of kernel config */ movl #0x200,%d0 | data freeze bit movc %d0,%cacr | only exists on 68030 movc %cacr,%d0 | read it back tstl %d0 | zero? jeq Lnot68030 | yes, we have 68020/68040/68060 jra Lstart1 | no, we have 68030 Lnot68030: bset #31,%d0 | data cache enable bit movc %d0,%cacr | only exists on 68040/68060 movc %cacr,%d0 | read it back tstl %d0 | zero? jeq Lis68020 | yes, we have 68020 moveq #0,%d0 | now turn it back off movec %d0,%cacr | before we access any data .word 0xf4d8 | cinva bc - invalidate caches XXX bset #30,%d0 | data cache no allocate mode bit movc %d0,%cacr | only exists on 68060 movc %cacr,%d0 | read it back tstl %d0 | zero? jeq Lis68040 | yes, we have 68040 RELOC(mmutype, %a0) | no, we have 68060 movl #MMU_68040,%a0@ | with a 68040 compatible MMU RELOC(cputype, %a0) movl #CPU_68060,%a0@ | and a 68060 CPU jra Lstart1 Lis68040: RELOC(mmutype, %a0) movl #MMU_68040,%a0@ | with a 68040 MMU RELOC(cputype, %a0) movl #CPU_68040,%a0@ | and a 68040 CPU jra Lstart1 Lis68020: RELOC(mmutype, %a0) movl #MMU_68851,%a0@ | we have PMMU RELOC(cputype, %a0) movl #CPU_68020,%a0@ | and a 68020 CPU Lstart1: /* initialize source/destination control registers for movs */ moveq #FC_USERD,%d0 | user space movc %d0,%sfc | as source movc %d0,%dfc | and destination of transfers /* initialize memory sizes (for pmap_bootstrap) */ movl %d5,%d1 | last page moveq #PGSHIFT,%d2 lsrl %d2,%d1 | convert to page (click) number RELOC(maxmem, %a0) movl %d1,%a0@ | save as maxmem movl %a5,%d0 | lowram value from ROM via boot lsrl %d2,%d0 | convert to page number subl %d0,%d1 | compute amount of RAM present RELOC(physmem, %a0) movl %d1,%a0@ | and physmem /* configure kernel and lwp0 VA space so we can get going */ #if NKSYMS || defined(DDB) || defined(LKM) RELOC(esym,%a0) | end of static kernel test/data/syms movl %a0@,%d5 jne Lstart2 #endif movl #_C_LABEL(end),%d5 | end of static kernel text/data Lstart2: addl #PAGE_SIZE-1,%d5 andl #PG_FRAME,%d5 | round to a page movl %d5,%a4 addl %a5,%a4 | convert to PA pea %a5@ | firstpa pea %a4@ | nextpa RELOC(pmap_bootstrap,%a0) jbsr %a0@ | pmap_bootstrap(firstpa, nextpa) addql #8,%sp /* * Prepare to enable MMU. * Since the kernel is not mapped logical == physical we must insure * that when the MMU is turned on, all prefetched addresses (including * the PC) are valid. In order guarantee that, we use the last physical * page (which is conveniently mapped == VA) and load it up with enough * code to defeat the prefetch, then we execute the jump back to here. * * Is this all really necessary, or am I paranoid?? */ RELOC(Sysseg, %a0) | system segment table addr movl %a0@,%d1 | read value (a KVA) addl %a5,%d1 | convert to PA RELOC(mmutype, %a0) cmpl #MMU_68040,%a0@ | 68040? jne Lmotommu1 | no, skip .long 0x4e7b1807 | movc d1,srp jra Lstploaddone Lmotommu1: RELOC(protorp, %a0) movl #0x80000202,%a0@ | nolimit + share global + 4 byte PTEs movl %d1,%a0@(4) | + segtable address pmove %a0@,%srp | load the supervisor root pointer movl #0x80000002,%a0@ | reinit upper half for CRP loads Lstploaddone: RELOC(mmutype, %a0) cmpl #MMU_68040,%a0@ | 68040? jne Lmotommu2 | no, skip #include "opt_jupiter.h" #ifdef JUPITER /* JUPITER-X: set system register "SUPER" bit */ movl #0x0200a240,%d0 | translate DRAM area transparently .long 0x4e7b0006 | movc d0,dtt0 lea 0x00c00000,%a0 | a0: graphic VRAM lea 0x02c00000,%a1 | a1: graphic VRAM ( not JUPITER-X ) | DRAM ( JUPITER-X ) movw %a0@,%d0 movw %d0,%d1 notw %d1 movw %d1,%a1@ movw %d0,%a0@ cmpw %a1@,%d1 | JUPITER-X? jne Ljupiterdone | no, skip movl #0x0100a240,%d0 | to access system register .long 0x4e7b0006 | movc d0,dtt0 movb #0x01,0x01800003 | set "SUPER" bit Ljupiterdone: #endif /* JUPITER */ moveq #0,%d0 | ensure TT regs are disabled .long 0x4e7b0004 | movc d0,itt0 .long 0x4e7b0005 | movc d0,itt1 .long 0x4e7b0006 | movc d0,dtt0 .long 0x4e7b0007 | movc d0,dtt1 .word 0xf4d8 | cinva bc .word 0xf518 | pflusha movl #0x8000,%d0 .long 0x4e7b0003 | movc d0,tc #ifdef M68060 RELOC(cputype, %a0) cmpl #CPU_68060,%a0@ | 68060? jne Lnot060cache movl #1,%d0 .long 0x4e7b0808 | movcl d0,pcr movl #0xa0808000,%d0 movc %d0,%cacr | enable store buffer, both caches jmp Lenab1 Lnot060cache: #endif movl #0x80008000,%d0 movc %d0,%cacr | turn on both caches jmp Lenab1 Lmotommu2: movl #0x82c0aa00,%sp@- | value to load TC with pmove %sp@,%tc | load it /* * Should be running mapped from this point on */ Lenab1: /* set vector base in virtual address */ movl #_C_LABEL(vectab),%d0 | set Vector Base Register movc %d0,%vbr /* select the software page size now */ lea _ASM_LABEL(tmpstk),%sp | temporary stack jbsr _C_LABEL(uvm_setpagesize) | select software page size /* detect FPU type */ jbsr _C_LABEL(fpu_probe) movl %d0,_C_LABEL(fputype) /* set kernel stack, user SP, and initial pcb */ movl _C_LABEL(proc0paddr),%a1 | get lwp0 pcb addr lea %a1@(USPACE-4),%sp | set kernel stack to end of area lea _C_LABEL(lwp0),%a2 | initialize lwp0.l_addr movl %a2,_C_LABEL(curlwp) | and curlwp so that movl %a1,%a2@(L_ADDR) | we don't deref NULL in trap() movl #USRSTACK-4,%a2 movl %a2,%usp | init user SP movl %a1,_C_LABEL(curpcb) | lwp0 is running tstl _C_LABEL(fputype) | Have an FPU? jeq Lenab2 | No, skip. clrl %a1@(PCB_FPCTX) | ensure null FP context movl %a1,%sp@- jbsr _C_LABEL(m68881_restore) | restore it (does not kill a1) addql #4,%sp Lenab2: cmpl #MMU_68040,_C_LABEL(mmutype) | 68040? jeq Ltbia040 | yes, cache already on pflusha tstl _C_LABEL(mmutype) jpl Lenab3 | 68851 implies no d-cache movl #CACHE_ON,%d0 movc %d0,%cacr | clear cache(s) jra Lenab3 Ltbia040: .word 0xf518 Lenab3: /* final setup for C code */ movl %d7,_C_LABEL(boothowto) | save reboot flags movl %d6,_C_LABEL(bootdev) | and boot device /* * Create a fake exception frame so that cpu_fork() can copy it. * main() nevers returns; we exit to user mode from a forked process * later on. */ clrw %sp@- | vector offset/frame type clrl %sp@- | PC - filled in by "execve" movw #PSL_USER,%sp@- | in user mode clrl %sp@- | stack adjust count and padding lea %sp@(-64),%sp | construct space for D0-D7/A0-A7 lea _C_LABEL(lwp0),%a0 | save pointer to frame movl %sp,%a0@(L_MD_REGS) | in lwp0.p_md.md_regs jra _C_LABEL(main) | main() PANIC("main() returned") | Yow! Main returned! /* NOTREACHED */ /* * Use common m68k sigcode. */ #include <m68k/m68k/sigcode.s> #ifdef COMPAT_SUNOS #include <m68k/m68k/sunos_sigcode.s> #endif #ifdef COMPAT_SVR4 #include <m68k/m68k/svr4_sigcode.s> #endif /* * Primitives */ /* * Use common m68k support routines. */ #include <m68k/m68k/support.s> /* * Use common m68k process/lwp switch and context save subroutines. */ #define FPCOPROC /* XXX: Temp. Reqd. */ #include <m68k/m68k/switch_subr.s> #if defined(M68040) || defined(M68060) ENTRY(suline) movl %sp@(4),%a0 | address to write movl _C_LABEL(curpcb),%a1 | current pcb movl #Lslerr,%a1@(PCB_ONFAULT) | where to return to on a fault movl %sp@(8),%a1 | address of line movl %a1@+,%d0 | get lword movsl %d0,%a0@+ | put lword nop | sync movl %a1@+,%d0 | get lword movsl %d0,%a0@+ | put lword nop | sync movl %a1@+,%d0 | get lword movsl %d0,%a0@+ | put lword nop | sync movl %a1@+,%d0 | get lword movsl %d0,%a0@+ | put lword nop | sync moveq #0,%d0 | indicate no fault jra Lsldone Lslerr: moveq #-1,%d0 Lsldone: movl _C_LABEL(curpcb),%a1 | current pcb clrl %a1@(PCB_ONFAULT) | clear fault address rts #endif ENTRY(ecacheon) rts ENTRY(ecacheoff) rts ENTRY_NOPROFILE(getsfc) movc %sfc,%d0 rts ENTRY_NOPROFILE(getdfc) movc %dfc,%d0 rts /* * Load a new user segment table pointer. */ ENTRY(loadustp) movl %sp@(4),%d0 | new USTP moveq #PGSHIFT,%d1 lsll %d1,%d0 | convert to addr #if defined(M68040) || defined(M68060) cmpl #MMU_68040,_C_LABEL(mmutype) | 68040? jne LmotommuC | no, skip .word 0xf518 | pflusha .long 0x4e7b0806 | movc d0,urp #ifdef M68060 cmpl #CPU_68060,_C_LABEL(cputype) jne Lldno60 movc %cacr,%d0 orl #IC60_CUBC,%d0 | clear user branch cache entries movc %d0,%cacr Lldno60: #endif rts LmotommuC: #endif pflusha | flush entire TLB lea _C_LABEL(protorp),%a0 | CRP prototype movl %d0,%a0@(4) | stash USTP pmove %a0@,%crp | load root pointer movl #CACHE_CLR,%d0 movc %d0,%cacr | invalidate cache(s) rts ENTRY(ploadw) #if defined(M68030) movl %sp@(4),%a0 | address to load #if defined(M68040) || defined(M68060) cmpl #MMU_68040,_C_LABEL(mmutype) | 68040? jeq Lploadwskp | yes, skip #endif ploadw #1,%a0@ | pre-load translation Lploadwskp: #endif rts /* * Set processor priority level calls. Most are implemented with * inline asm expansions. However, spl0 requires special handling * as we need to check for our emulated software interrupts. */ ENTRY(spl0) moveq #0,%d0 movw %sr,%d0 | get old SR for return movw #PSL_LOWIPL,%sr | restore new SR tstb _C_LABEL(ssir) | software interrupt pending? jeq Lspldone | no, all done subql #4,%sp | make room for RTE frame movl %sp@(4),%sp@(2) | position return address clrw %sp@(6) | set frame type 0 movw #PSL_LOWIPL,%sp@ | and new SR jra Lgotsir | go handle it Lspldone: rts /* * _delay(u_int N) * * Delay for at least (N/256) microsecends. * This routine depends on the variable: delay_divisor * which should be set based on the CPU clock rate. */ ENTRY_NOPROFILE(_delay) | d0 = arg = (usecs << 8) movl %sp@(4),%d0 | d1 = delay_divisor movl _C_LABEL(delay_divisor),%d1 L_delay: subl %d1,%d0 jgt L_delay rts /* * Save and restore 68881 state. */ ENTRY(m68881_save) movl %sp@(4),%a0 | save area pointer fsave %a0@ | save state #if defined(M68020) || defined(M68030) || defined(M68040) #if defined(M68060) cmpl #FPU_68060,_C_LABEL(fputype) jeq Lm68060fpsave #endif Lm68881fpsave: tstb %a0@ | null state frame? jeq Lm68881sdone | yes, all done fmovem %fp0-%fp7,%a0@(FPF_REGS) | save FP general registers fmovem %fpcr/%fpsr/%fpi,%a0@(FPF_FPCR) | save FP control registers Lm68881sdone: rts #endif #if defined(M68060) Lm68060fpsave: tstb %a0@(2) | null state frame? jeq Lm68060sdone | yes, all done fmovem %fp0-%fp7,%a0@(FPF_REGS) | save FP general registers fmovem %fpcr,%a0@(FPF_FPCR) | save FP control registers fmovem %fpsr,%a0@(FPF_FPSR) fmovem %fpi,%a0@(FPF_FPI) Lm68060sdone: rts #endif ENTRY(m68881_restore) movl %sp@(4),%a0 | save area pointer #if defined(M68020) || defined(M68030) || defined(M68040) #if defined(M68060) cmpl #FPU_68060,_C_LABEL(fputype) jeq Lm68060fprestore #endif Lm68881fprestore: tstb %a0@ | null state frame? jeq Lm68881rdone | yes, easy fmovem %a0@(FPF_FPCR),%fpcr/%fpsr/%fpi | restore FP control registers fmovem %a0@(FPF_REGS),%fp0-%fp7 | restore FP general registers Lm68881rdone: frestore %a0@ | restore state rts #endif #if defined(M68060) Lm68060fprestore: tstb %a0@(2) | null state frame? jeq Lm68060fprdone | yes, easy fmovem %a0@(FPF_FPCR),%fpcr | restore FP control registers fmovem %a0@(FPF_FPSR),%fpsr fmovem %a0@(FPF_FPI),%fpi fmovem %a0@(FPF_REGS),%fp0-%fp7 | restore FP general registers Lm68060fprdone: frestore %a0@ | restore state rts #endif /* * Handle the nitty-gritty of rebooting the machine. * Basically we just turn off the MMU and jump to the appropriate ROM routine. * Note that we must be running in an address range that is mapped one-to-one * logical to physical so that the PC is still valid immediately after the MMU * is turned off. We have conveniently mapped the last page of physical * memory this way. */ ENTRY_NOPROFILE(doboot) movw #PSL_HIGHIPL,%sr | cut off any interrupts subal %a1,%a1 | a1 = 0 movl #CACHE_OFF,%d0 #if defined(M68040) || defined(M68060) movl _C_LABEL(mmutype),%d2 | d2 = mmutype addl #(-1 * MMU_68040),%d2 | 68040? jne Ldoboot0 | no, skip .word 0xf4f8 | cpusha bc - push and invalidate caches nop movl #CACHE40_OFF,%d0 Ldoboot0: #endif movc %d0,%cacr | disable on-chip cache(s) | ok, turn off MMU.. Ldoreboot: #if defined(M68040) || defined(M68060) tstl %d2 | 68040? jne LmotommuF | no, skip movc %a1,%cacr | caches off .long 0x4e7b9003 | movc a1(=0),tc ; disable MMU jra Ldoreboot1 LmotommuF: #endif clrl %sp@ pmove %sp@,%tc | disable MMU Ldoreboot1: moveml 0x00ff0000,#0x0101 | get RESET vectors in ROM | (d0: ssp, a0: pc) moveml #0x0101,%a1@ | put them at 0x0000 (for Xellent30) movc %a1,%vbr | reset Vector Base Register jmp %a0@ | reboot X680x0 Lebootcode: /* * Misc. global variables. */ .data GLOBAL(machineid) .long 0 | default to X68030 GLOBAL(mmutype) .long MMU_68030 | default to 030 internal MMU GLOBAL(cputype) .long CPU_68030 | default to 68030 CPU #ifdef M68K_MMU_HP GLOBAL(ectype) .long EC_NONE | external cache type, default to none #endif GLOBAL(fputype) .long FPU_NONE GLOBAL(protorp) .long 0,0 | prototype root pointer GLOBAL(proc0paddr) .long 0 | KVA of lwp0 u-area GLOBAL(intiolimit) .long 0 | KVA of end of internal IO space GLOBAL(extiobase) .long 0 | KVA of base of external IO space #ifdef DEBUG ASGLOBAL(fulltflush) .long 0 ASGLOBAL(fullcflush) .long 0 #endif /* interrupt counters */ GLOBAL(intrnames) .asciz "spur" .asciz "lev1" .asciz "lev2" .asciz "lev3" .asciz "lev4" .asciz "lev5" .asciz "lev6" .asciz "nmi" .asciz "clock" .asciz "pow" .asciz "com" GLOBAL(eintrnames) .even GLOBAL(intrcnt) .long 0,0,0,0,0,0,0,0,0,0,0 GLOBAL(eintrcnt)