New bus error/address error trap handlers, code lifted from mac68k

port, which is lifted from amiga port, plus some changes from me:
- Add support for the HP MMU to the 020/030 bus/address error handler
  (mostly lifted wholesale from the old code).
- Rename addrerr and buserr to busaddrerr2030.  The new name reflects that
  these functions are specific to the 68020 and 68030, and that the same
  handler function is used for both vectors.

The vector table is patched once we know our CPU type, before the MMU
is enabled.  In the event that we're running on a CPU that we're not
configured for, simply invoke the PROM's "reboot request"; we have no
hope of running in the event of a config botch, since we need working
a working bus error handler for console initialization.

These new functions optimze for common-case page faults, eliminate
many run-time checks, and are sharable.
This commit is contained in:
thorpej 1997-07-14 19:18:31 +00:00
parent 89c8d10a08
commit e296b3b344
2 changed files with 178 additions and 96 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: locore.s,v 1.74 1997/05/13 18:01:03 gwr Exp $ */
/* $NetBSD: locore.s,v 1.75 1997/07/14 19:18:31 thorpej Exp $ */
/*
* Copyright (c) 1994, 1995 Gordon W. Ross
@ -89,6 +89,17 @@ ASLOCAL(tmpstk)
#define RELOC(var, ar) _RELOC(_C_LABEL(var), ar)
#define ASRELOC(var, ar) _RELOC(_ASM_LABEL(var), ar)
/*
* Final bits of grunt work required to reboot the system. The MMU
* must be disabled when this is invoked.
*/
#define DOREBOOT \
/* Reset Vector Base Register to what PROM expects. */ \
movl #0,d0; \
movc d0,vbr; \
/* Jump to REQ_REBOOT */ \
jmp 0x1A4;
/*
* Initialization
*
@ -279,6 +290,41 @@ Lis320:
*/
Lstart1:
/*
* Now that we know what CPU we have, initialize the address error
* and bus error handlers in the vector table:
*
* vectab+8 bus error
* vectab+12 address error
*/
RELOC(cputype, a0)
#if 0
/* XXX assembler/linker feature/bug */
RELOC(vectab, a2)
#else
movl #_C_LABEL(vectab),a2
addl a5,a2
#endif
#if defined(M68040)
cmpl #CPU_68040,a0@ | 68040?
jne 1f | no, skip
movl #_C_LABEL(buserr40),a2@(8)
movl #_C_LABEL(addrerr4060),a2@(12)
jra Lstart2
1:
#endif
#if defined(M68020) || defined(M68030)
cmpl #CPU_68040,a0@ | 68040?
jeq 1f | yes, skip
movl #_C_LABEL(busaddrerr2030),a2@(8)
movl #_C_LABEL(busaddrerr2030),a2@(12)
jra Lstart2
1:
#endif
/* Config botch; no hope. */
DOREBOOT
Lstart2:
movl #0,a1@(MMUCMD) | clear out MMU again
/* initialize source/destination control registers for movs */
moveq #FC_USERD,d0 | user space
@ -300,10 +346,10 @@ Lstart1:
#ifdef DDB
RELOC(esym,a0) | end of static kernel test/data/syms
movl a0@,d5
jne Lstart2
jne Lstart3
#endif
movl #_C_LABEL(end),d5 | end of static kernel text/data
Lstart2:
Lstart3:
addl #NBPG-1,d5
andl #PG_FRAME,d5 | round to a page
movl d5,a4
@ -477,85 +523,117 @@ GLOBAL(proc_trampoline)
*/
#include <m68k/m68k/trap_subr.s>
ENTRY_NOPROFILE(buserr)
/*
* XXX TODO: look at the mac68k _buserr and generalize
* XXX the saving of the fault address so this routine
* XXX can be shared.
*/
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)
#if defined(M68020) || defined(M68030)
cmpl #MMU_68040,_C_LABEL(mmutype) | 68040?
jne _C_LABEL(addrerr) | no, skip
#endif
.data
GLOBAL(m68k_fault_addr)
.long 0
#if defined(M68040) || defined(M68060)
ENTRY_NOPROFILE(addrerr4060)
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
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
movl sp@(FR_HW+8),sp@-
clrl sp@- | dummy code
movl #T_ADDRERR,sp@- | mark address error
jra _ASM_LABEL(faultstkadj) | and deal with it
#endif
ENTRY_NOPROFILE(addrerr)
#if defined(M68060)
ENTRY_NOPROFILE(buserr60)
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
movel sp@(FR_HW+12),d0 | FSLW
btst #2,d0 | branch prediction error?
jeq Lnobpe
movc cacr,d2
orl #IC60_CABC,d2 | clear all branch cache entries
movc d2,cacr
movl d0,d1
addql #1,L60bpe
andl #0x7ffd,d1
jeq _ASM_LABEL(faultstkadjnotrap2)
Lnobpe:
| we need to adjust for misaligned addresses
movl sp@(FR_HW+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
andl #PG_FRAME,d1 | and truncate
Lberr3:
movl d1,sp@-
movl d0,sp@- | code is FSLW now.
andw #0x1f80,d0
jeq Lberr60 | it is a bus error
movl #T_MMUFLT,sp@- | show that we are an MMU fault
jra _ASM_LABEL(faultstkadj) | and deal with it
Lberr60:
tstl _C_LABEL(nofault) | catch bus error?
jeq Lisberr | no, handle as usual
movl sp@(FR_HW+8+8),_C_LABEL(m68k_fault_addr) | save fault addr
movl _C_LABEL(nofault),sp@- | yes,
jbsr _C_LABEL(longjmp) | longjmp(nofault)
/* NOTREACHED */
#endif
#if defined(M68040)
#if defined(M68020) || defined(M68030)
cmpl #MMU_68040,_C_LABEL(mmutype) | 68040?
jne Lbenot040 | no, skip
#endif
movl a1@(8),sp@- | yes, push fault address
clrl sp@- | no SSW for address fault
jra Lisaerr | go deal with it
Lbenot040:
#endif
ENTRY_NOPROFILE(buserr40)
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 sp@(FR_HW+20),d1 | get fault address
moveq #0,d0
movw a1@(10),d0 | grab SSW for fault processing
movw sp@(FR_HW+12),d0 | get SSW
btst #11,d0 | check for mis-aligned
jeq Lbe1stpg | no skip
addl #3,d1 | get into next page
andl #PG_FRAME,d1 | and truncate
Lbe1stpg:
movl d1,sp@- | pass fault address.
movl d0,sp@- | pass SSW as code
btst #10,d0 | test ATC
jeq Lberr40 | it is a bus error
movl #T_MMUFLT,sp@- | show that we are an MMU fault
jra _ASM_LABEL(faultstkadj) | and deal with it
Lberr40:
tstl _C_LABEL(nofault) | catch bus error?
jeq Lisberr | no, handle as usual
movl sp@(FR_HW+8+16),_C_LABEL(m68k_fault_addr) | save fault addr
movl _C_LABEL(nofault),sp@- | yes,
jbsr _C_LABEL(longjmp) | longjmp(nofault)
/* NOTREACHED */
#endif
#if defined(M68020) || defined(M68030)
ENTRY_NOPROFILE(busaddrerr2030)
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
moveq #0,d0
movw sp@(FR_HW+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
movw d0,sp@(FR_HW+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
movw d0,sp@(FR_HW+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
movl sp@(FR_HW+16),d1 | fault address is as given in frame
jra Lbe10 | thats it
Lbe0:
btst #4,a1@(6) | long (type B) stack frame?
btst #4,sp@(FR_HW+6) | long (type B) stack frame?
jne Lbe4 | yes, go handle
movl a1@(2),d1 | no, can use save PC
movl sp@(FR_HW+2),d1 | no, can use save PC
btst #14,d0 | FB set?
jeq Lbe3 | no, try FC
addql #4,d1 | yes, adjust address
@ -566,67 +644,75 @@ Lbe3:
addql #2,d1 | yes, adjust address
jra Lbe10 | done
Lbe4:
movl a1@(36),d1 | long format, use stage B address
movl sp@(FR_HW+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
movw sp@(FR_HW+8+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
#if defined(M68K_MMU_MOTOROLA)
#if defined(M68K_MMU_HP)
tstl _C_LABEL(mmutype) | HP MMU?
jeq Lbehpmmu | yes, skip
jeq Lbehpmmu | yes, different MMU fault handler
#endif
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?
| (we dont seperate data/program)
btst #5,sp@(FR_HW+8) | 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)
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
jra Lismerr | no, must be mem err
Lbehpmmu:
#endif
#if defined(M68K_MMU_HP)
MMUADDR(a0)
movl a0@(MMUSTAT),d0 | read status
btst #3,d0 | MMU fault?
jeq Lisberr | no, just a non-MMU bus error so skip
andl #~MMU_FAULT,a0@(MMUSTAT)| yes, clear fault bits
movw d0,sp@ | pass MMU stat in upper half of code
#endif
jne Lisberr1 | yes, needs not be fast.
Lismerr:
movl #T_MMUFLT,sp@- | show that we are an MMU fault
jra _ASM_LABEL(faultstkadj) | and deal with it
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?
jne Lismerr | no, was not WPE, must be MMU fault
jra Lisberr1 | real bus err needs not be fast.
#endif /* M68K_MMU_MOTOROLA */
#if defined(M68K_MMU_HP)
Lbehpmmu:
MMUADDR(a0)
movl a0@(MMUSTAT),d0 | read MMU status
btst #3,d0 | MMU fault?
jeq Lisberr1 | no, just a non-MMU bus error
andl #~MMU_FAULT,a0@(MMUSTAT)| yes, clear fault bits
movw d0,sp@ | pass MMU stat in upper half of code
jra Lismerr | and handle it
#endif
Lisaerr:
movl #T_ADDRERR,sp@- | mark address error
jra _ASM_LABEL(faultstkadj) | and deal with it
Lisberr1:
clrw sp@ | re-clear pad word
Lisberr:
tstl _C_LABEL(nofault) | catch bus error?
jeq Lisberr | no, handle as usual
movl sp@(FR_HW+8+16),_C_LABEL(m68k_fault_addr) | save fault addr
movl _C_LABEL(nofault),sp@- | yes,
jbsr _C_LABEL(longjmp) | longjmp(nofault)
/* NOTREACHED */
#endif /* M68020 || M68030 */
Lisberr: | also used by M68040/60
movl #T_BUSERR,sp@- | mark bus error
jra _ASM_LABEL(faultstkadj) | and deal with it
@ -1810,13 +1896,6 @@ LmotommuE:
#endif
jmp MAXADDR+8 | jump to last page
#define DOREBOOT \
/* Reset Vector Base Register to what PROM expects. */ \
movl #0,d0; \
movc d0,vbr; \
/* Jump to REQ_REBOOT */ \
jmp 0x1A4;
Lbootcode:
lea MAXADDR+0x800,sp | physical SP in case of NMI
#if defined(M68040)
@ -1845,8 +1924,6 @@ LhpmmuB:
#endif
Lebootcode:
#undef DOREBOOT
/*
* Misc. global variables.
*/

View File

@ -1,4 +1,4 @@
| $NetBSD: vectors.s,v 1.11 1997/04/25 02:16:38 thorpej Exp $
| $NetBSD: vectors.s,v 1.12 1997/07/14 19:18:32 thorpej Exp $
| Copyright (c) 1997 Jason R. Thorpe. All rights reserved.
| Copyright (c) 1988 University of Utah
@ -46,12 +46,17 @@
VECTOR(badtrap) ; VECTOR(badtrap) ; \
VECTOR(badtrap) ; VECTOR(badtrap)
/*
* bus error and address error vectors are initialized
* in locore.s once we know our CPU type.
*/
.text
GLOBAL(vectab)
VECTOR_UNUSED /* 0: NOT USED (reset SSP) */
VECTOR_UNUSED /* 1: NOT USED (reset PC) */
VECTOR(buserr) /* 2: bus error */
VECTOR(addrerr) /* 3: address error */
VECTOR_UNUSED /* 2: bus error */
VECTOR_UNUSED /* 3: address error */
VECTOR(illinst) /* 4: illegal instruction */
VECTOR(zerodiv) /* 5: zero divide */
VECTOR(chkinst) /* 6: CHK instruction */