Home | History | Annotate | Line # | Download | only in hp300
      1 /*
      2  * Copyright (c) 1988 University of Utah.
      3  * Copyright (c) 1980, 1990, 1993
      4  *	The Regents of the University of California.  All rights reserved.
      5  *
      6  * This code is derived from software contributed to Berkeley by
      7  * the Systems Programming Group of the University of Utah Computer
      8  * Science Department.
      9  *
     10  * %sccs.include.redist.c%
     11  *
     12  * from: Utah $Hdr: locore.s 1.66 92/12/22$
     13  *
     14  *	@(#)locore.s	8.6 (Berkeley) 05/27/94
     15  */
     16 
     17 /*
     18  * STACKCHECK enables two types of kernel stack checking:
     19  *	1. stack "overflow".  On every clock interrupt we ensure that
     20  *	   the current kernel stack has not grown into the user struct
     21  *	   page, i.e. size exceeded UPAGES-1 pages.
     22  *	2. stack "underflow".  Before every rte to user mode we ensure
     23  *	   that we will be exactly at the base of the stack after the
     24  *	   exception frame has been popped.
     25  * Both checks are performed at splclock since they operate on the
     26  * global temporary stack.
     27  */
     28 /* #define	STACKCHECK */
     29 
     30 #include "assym.s"
     31 #include <hp300/hp300/vectors.s>
     32 
     33 #define MMUADDR(ar)	movl	_MMUbase,ar
     34 #define CLKADDR(ar)	movl	_CLKbase,ar
     35 
     36 /*
     37  * Temporary stack for a variety of purposes.
     38  * Try and make this the first thing is the data segment so it
     39  * is page aligned.  Note that if we overflow here, we run into
     40  * our text segment.
     41  */
     42 	.data
     43 	.space	NBPG
     44 tmpstk:
     45 
     46 	.text
     47 /*
     48  * This is where we wind up if the kernel jumps to location 0.
     49  * (i.e. a bogus PC)  This is known to immediately follow the vector
     50  * table and is hence at 0x400 (see reset vector in vectors.s).
     51  */
     52 	.globl	_panic
     53 	pea	Ljmp0panic
     54 	jbsr	_panic
     55 	/* NOTREACHED */
     56 Ljmp0panic:
     57 	.asciz	"kernel jump to zero"
     58 	.even
     59 
     60 /*
     61  * Do a dump.
     62  * Called by auto-restart.
     63  */
     64 	.globl	_dumpsys
     65 	.globl	_doadump
     66 _doadump:
     67 	jbsr	_dumpsys
     68 	jbsr	_doboot
     69 	/*NOTREACHED*/
     70 
     71 /*
     72  * Trap/interrupt vector routines
     73  */
     74 
     75 	.globl	_trap, _nofault, _longjmp
     76 _buserr:
     77 	tstl	_nofault		| device probe?
     78 	jeq	Lberr			| no, handle as usual
     79 	movl	_nofault,sp@-		| yes,
     80 	jbsr	_longjmp		|  longjmp(nofault)
     81 Lberr:
     82 #if defined(HP380)
     83 	cmpl	#-2,_mmutype		| 68040?
     84 	jne	_addrerr		| no, skip
     85 	clrl	sp@-			| stack adjust count
     86 	moveml	#0xFFFF,sp@-		| save user registers
     87 	movl	usp,a0			| save the user SP
     88 	movl	a0,sp@(FR_SP)		|   in the savearea
     89 	lea	sp@(FR_HW),a1		| grab base of HW berr frame
     90 	moveq	#0,d0
     91 	movw	a1@(12),d0		| grab SSW
     92 	movl	a1@(20),d1		| and fault VA
     93 	btst	#11,d0			| check for mis-aligned access
     94 	jeq	Lberr2			| no, skip
     95 	addl	#3,d1			| yes, get into next page
     96 	andl	#PG_FRAME,d1		| and truncate
     97 Lberr2:
     98 	movl	d1,sp@-			| push fault VA
     99 	movl	d0,sp@-			| and padded SSW
    100 	btst	#10,d0			| ATC bit set?
    101 	jeq	Lisberr			| no, must be a real bus error
    102 	movc	dfc,d1			| yes, get MMU fault
    103 	movc	d0,dfc			| store faulting function code
    104 	movl	sp@(4),a0		| get faulting address
    105 	.word	0xf568			| ptestr a0@
    106 	movc	d1,dfc
    107 	.long	0x4e7a0805		| movc mmusr,d0
    108 	movw	d0,sp@			| save (ONLY LOW 16 BITS!)
    109 	jra	Lismerr
    110 #endif
    111 _addrerr:
    112 	clrl	sp@-			| stack adjust count
    113 	moveml	#0xFFFF,sp@-		| save user registers
    114 	movl	usp,a0			| save the user SP
    115 	movl	a0,sp@(FR_SP)		|   in the savearea
    116 	lea	sp@(FR_HW),a1		| grab base of HW berr frame
    117 #if defined(HP380)
    118 	cmpl	#-2,_mmutype		| 68040?
    119 	jne	Lbenot040		| no, skip
    120 	movl	a1@(8),sp@-		| yes, push fault address
    121 	clrl	sp@-			| no SSW for address fault
    122 	jra	Lisaerr			| go deal with it
    123 Lbenot040:
    124 #endif
    125 	moveq	#0,d0
    126 	movw	a1@(10),d0		| grab SSW for fault processing
    127 	btst	#12,d0			| RB set?
    128 	jeq	LbeX0			| no, test RC
    129 	bset	#14,d0			| yes, must set FB
    130 	movw	d0,a1@(10)		| for hardware too
    131 LbeX0:
    132 	btst	#13,d0			| RC set?
    133 	jeq	LbeX1			| no, skip
    134 	bset	#15,d0			| yes, must set FC
    135 	movw	d0,a1@(10)		| for hardware too
    136 LbeX1:
    137 	btst	#8,d0			| data fault?
    138 	jeq	Lbe0			| no, check for hard cases
    139 	movl	a1@(16),d1		| fault address is as given in frame
    140 	jra	Lbe10			| thats it
    141 Lbe0:
    142 	btst	#4,a1@(6)		| long (type B) stack frame?
    143 	jne	Lbe4			| yes, go handle
    144 	movl	a1@(2),d1		| no, can use save PC
    145 	btst	#14,d0			| FB set?
    146 	jeq	Lbe3			| no, try FC
    147 	addql	#4,d1			| yes, adjust address
    148 	jra	Lbe10			| done
    149 Lbe3:
    150 	btst	#15,d0			| FC set?
    151 	jeq	Lbe10			| no, done
    152 	addql	#2,d1			| yes, adjust address
    153 	jra	Lbe10			| done
    154 Lbe4:
    155 	movl	a1@(36),d1		| long format, use stage B address
    156 	btst	#15,d0			| FC set?
    157 	jeq	Lbe10			| no, all done
    158 	subql	#2,d1			| yes, adjust address
    159 Lbe10:
    160 	movl	d1,sp@-			| push fault VA
    161 	movl	d0,sp@-			| and padded SSW
    162 	movw	a1@(6),d0		| get frame format/vector offset
    163 	andw	#0x0FFF,d0		| clear out frame format
    164 	cmpw	#12,d0			| address error vector?
    165 	jeq	Lisaerr			| yes, go to it
    166 #if defined(HP330) || defined(HP360) || defined(HP370)
    167 	tstl	_mmutype		| HP MMU?
    168 	jeq	Lbehpmmu		| yes, skip
    169 	movl	d1,a0			| fault address
    170 	ptestr	#1,a0@,#7		| do a table search
    171 	pmove	psr,sp@			| save result
    172 	btst	#7,sp@			| bus error bit set?
    173 	jeq	Lismerr			| no, must be MMU fault
    174 	clrw	sp@			| yes, re-clear pad word
    175 	jra	Lisberr			| and process as normal bus error
    176 Lbehpmmu:
    177 #endif
    178 #if defined(HP320) || defined(HP350)
    179 	MMUADDR(a0)
    180 	movl	a0@(MMUSTAT),d0		| read status
    181 	btst	#3,d0			| MMU fault?
    182 	jeq	Lisberr			| no, just a non-MMU bus error so skip
    183 	andl	#~MMU_FAULT,a0@(MMUSTAT)| yes, clear fault bits
    184 	movw	d0,sp@			| pass MMU stat in upper half of code
    185 #endif
    186 Lismerr:
    187 	movl	#T_MMUFLT,sp@-		| show that we are an MMU fault
    188 	jra	Ltrapnstkadj		| and deal with it
    189 Lisaerr:
    190 	movl	#T_ADDRERR,sp@-		| mark address error
    191 	jra	Ltrapnstkadj		| and deal with it
    192 Lisberr:
    193 	movl	#T_BUSERR,sp@-		| mark bus error
    194 Ltrapnstkadj:
    195 	jbsr	_trap			| handle the error
    196 	lea	sp@(12),sp		| pop value args
    197 	movl	sp@(FR_SP),a0		| restore user SP
    198 	movl	a0,usp			|   from save area
    199 	movw	sp@(FR_ADJ),d0		| need to adjust stack?
    200 	jne	Lstkadj			| yes, go to it
    201 	moveml	sp@+,#0x7FFF		| no, restore most user regs
    202 	addql	#8,sp			| toss SSP and stkadj
    203 	jra	rei			| all done
    204 Lstkadj:
    205 	lea	sp@(FR_HW),a1		| pointer to HW frame
    206 	addql	#8,a1			| source pointer
    207 	movl	a1,a0			| source
    208 	addw	d0,a0			|  + hole size = dest pointer
    209 	movl	a1@-,a0@-		| copy
    210 	movl	a1@-,a0@-		|  8 bytes
    211 	movl	a0,sp@(FR_SP)		| new SSP
    212 	moveml	sp@+,#0x7FFF		| restore user registers
    213 	movl	sp@,sp			| and our SP
    214 	jra	rei			| all done
    215 
    216 /*
    217  * FP exceptions.
    218  */
    219 _fpfline:
    220 #if defined(HP380)
    221 	cmpw	#0x202c,sp@(6)		| format type 2?
    222 	jne	_illinst		| no, not an FP emulation
    223 #ifdef HPFPLIB
    224 	.globl fpsp_unimp
    225 	jmp	fpsp_unimp		| yes, go handle it
    226 #else
    227 	clrl	sp@-			| stack adjust count
    228 	moveml	#0xFFFF,sp@-		| save registers
    229 	moveq	#T_FPEMULI,d0		| denote as FP emulation trap
    230 	jra	fault			| do it
    231 #endif
    232 #else
    233 	jra	_illinst
    234 #endif
    235 
    236 _fpunsupp:
    237 #if defined(HP380)
    238 	cmpl	#-2,_mmutype		| 68040?
    239 	jne	_illinst		| no, treat as illinst
    240 #ifdef HPFPLIB
    241 	.globl	fpsp_unsupp
    242 	jmp	fpsp_unsupp		| yes, go handle it
    243 #else
    244 	clrl	sp@-			| stack adjust count
    245 	moveml	#0xFFFF,sp@-		| save registers
    246 	moveq	#T_FPEMULD,d0		| denote as FP emulation trap
    247 	jra	fault			| do it
    248 #endif
    249 #else
    250 	jra	_illinst
    251 #endif
    252 
    253 /*
    254  * Handles all other FP coprocessor exceptions.
    255  * Note that since some FP exceptions generate mid-instruction frames
    256  * and may cause signal delivery, we need to test for stack adjustment
    257  * after the trap call.
    258  */
    259 _fpfault:
    260 #ifdef FPCOPROC
    261 	clrl	sp@-		| stack adjust count
    262 	moveml	#0xFFFF,sp@-	| save user registers
    263 	movl	usp,a0		| and save
    264 	movl	a0,sp@(FR_SP)	|   the user stack pointer
    265 	clrl	sp@-		| no VA arg
    266 	movl	_curpcb,a0	| current pcb
    267 	lea	a0@(PCB_FPCTX),a0 | address of FP savearea
    268 	fsave	a0@		| save state
    269 	tstb	a0@		| null state frame?
    270 	jeq	Lfptnull	| yes, safe
    271 	clrw	d0		| no, need to tweak BIU
    272 	movb	a0@(1),d0	| get frame size
    273 	bset	#3,a0@(0,d0:w)	| set exc_pend bit of BIU
    274 Lfptnull:
    275 	fmovem	fpsr,sp@-	| push fpsr as code argument
    276 	frestore a0@		| restore state
    277 	movl	#T_FPERR,sp@-	| push type arg
    278 	jra	Ltrapnstkadj	| call trap and deal with stack cleanup
    279 #else
    280 	jra	_badtrap	| treat as an unexpected trap
    281 #endif
    282 
    283 #ifdef HPFPLIB
    284 /*
    285  * We wind up here from the 040 FP emulation library after
    286  * the exception has been processed.
    287  */
    288 	.globl	_fault
    289 _fault:
    290 	subql	#4,sp		| space for rts addr
    291 	movl	d0,sp@-		| scratch register
    292 	movw	sp@(14),d0	| get vector offset
    293 	andl	#0xFFF,d0	| mask out frame type and clear high word
    294 	cmpl	#0x100,d0	| HP-UX style reschedule trap?
    295 	jne	Lfault1		| no, skip
    296 	movl	sp@+,d0		| restore scratch register
    297 	addql	#4,sp		| pop space
    298 	jra	Lrei1		| go do AST
    299 Lfault1:
    300 	cmpl	#0xC0,d0	| FP exception?
    301 	jlt	Lfault2		| no, skip
    302 	movl	sp@+,d0		| yes, backoff
    303 	addql	#4,sp		|  and prepare for normal trap frame
    304 	jra	_fpfault	| go to it
    305 Lfault2:
    306 	addl	#Lvectab,d0	| convert to vector table offset
    307 	exg	d0,a0
    308 	movl	a0@,sp@(4) 	| get exception vector and save for rts
    309 	exg	d0,a0
    310 	movl	sp@+,d0		|   scratch registers
    311 	rts			| return to handler from vectab
    312 #endif
    313 
    314 /*
    315  * Coprocessor and format errors can generate mid-instruction stack
    316  * frames and cause signal delivery hence we need to check for potential
    317  * stack adjustment.
    318  */
    319 _coperr:
    320 	clrl	sp@-		| stack adjust count
    321 	moveml	#0xFFFF,sp@-
    322 	movl	usp,a0		| get and save
    323 	movl	a0,sp@(FR_SP)	|   the user stack pointer
    324 	clrl	sp@-		| no VA arg
    325 	clrl	sp@-		| or code arg
    326 	movl	#T_COPERR,sp@-	| push trap type
    327 	jra	Ltrapnstkadj	| call trap and deal with stack adjustments
    328 
    329 _fmterr:
    330 	clrl	sp@-		| stack adjust count
    331 	moveml	#0xFFFF,sp@-
    332 	movl	usp,a0		| get and save
    333 	movl	a0,sp@(FR_SP)	|   the user stack pointer
    334 	clrl	sp@-		| no VA arg
    335 	clrl	sp@-		| or code arg
    336 	movl	#T_FMTERR,sp@-	| push trap type
    337 	jra	Ltrapnstkadj	| call trap and deal with stack adjustments
    338 
    339 /*
    340  * Other exceptions only cause four and six word stack frame and require
    341  * no post-trap stack adjustment.
    342  */
    343 _illinst:
    344 	clrl	sp@-
    345 	moveml	#0xFFFF,sp@-
    346 	moveq	#T_ILLINST,d0
    347 	jra	fault
    348 
    349 _zerodiv:
    350 	clrl	sp@-
    351 	moveml	#0xFFFF,sp@-
    352 	moveq	#T_ZERODIV,d0
    353 	jra	fault
    354 
    355 _chkinst:
    356 	clrl	sp@-
    357 	moveml	#0xFFFF,sp@-
    358 	moveq	#T_CHKINST,d0
    359 	jra	fault
    360 
    361 _trapvinst:
    362 	clrl	sp@-
    363 	moveml	#0xFFFF,sp@-
    364 	moveq	#T_TRAPVINST,d0
    365 	jra	fault
    366 
    367 _privinst:
    368 	clrl	sp@-
    369 	moveml	#0xFFFF,sp@-
    370 	moveq	#T_PRIVINST,d0
    371 	jra	fault
    372 
    373 	.globl	fault
    374 fault:
    375 	movl	usp,a0			| get and save
    376 	movl	a0,sp@(FR_SP)		|   the user stack pointer
    377 	clrl	sp@-			| no VA arg
    378 	clrl	sp@-			| or code arg
    379 	movl	d0,sp@-			| push trap type
    380 	jbsr	_trap			| handle trap
    381 	lea	sp@(12),sp		| pop value args
    382 	movl	sp@(FR_SP),a0		| restore
    383 	movl	a0,usp			|   user SP
    384 	moveml	sp@+,#0x7FFF		| restore most user regs
    385 	addql	#8,sp			| pop SP and stack adjust
    386 	jra	rei			| all done
    387 
    388 	.globl	_straytrap
    389 _badtrap:
    390 	moveml	#0xC0C0,sp@-		| save scratch regs
    391 	movw	sp@(22),sp@-		| push exception vector info
    392 	clrw	sp@-
    393 	movl	sp@(22),sp@-		| and PC
    394 	jbsr	_straytrap		| report
    395 	addql	#8,sp			| pop args
    396 	moveml	sp@+,#0x0303		| restore regs
    397 	jra	rei			| all done
    398 
    399 	.globl	_syscall
    400 _trap0:
    401 	clrl	sp@-			| stack adjust count
    402 	moveml	#0xFFFF,sp@-		| save user registers
    403 	movl	usp,a0			| save the user SP
    404 	movl	a0,sp@(FR_SP)		|   in the savearea
    405 	movl	d0,sp@-			| push syscall number
    406 	jbsr	_syscall		| handle it
    407 	addql	#4,sp			| pop syscall arg
    408 	movl	sp@(FR_SP),a0		| grab and restore
    409 	movl	a0,usp			|   user SP
    410 	moveml	sp@+,#0x7FFF		| restore most registers
    411 	addql	#8,sp			| pop SP and stack adjust
    412 	jra	rei			| all done
    413 
    414 /*
    415  * Routines for traps 1 and 2.  The meaning of the two traps depends
    416  * on whether we are an HPUX compatible process or a native 4.3 process.
    417  * Our native 4.3 implementation uses trap 1 as sigreturn() and trap 2
    418  * as a breakpoint trap.  HPUX uses trap 1 for a breakpoint, so we have
    419  * to make adjustments so that trap 2 is used for sigreturn.
    420  */
    421 _trap1:
    422 	btst	#MDP_TRCB,mdpflag	| being traced by an HPUX process?
    423 	jeq	sigreturn		| no, trap1 is sigreturn
    424 	jra	_trace			| yes, trap1 is breakpoint
    425 
    426 _trap2:
    427 	btst	#MDP_TRCB,mdpflag	| being traced by an HPUX process?
    428 	jeq	_trace			| no, trap2 is breakpoint
    429 	jra	sigreturn		| yes, trap2 is sigreturn
    430 
    431 /*
    432  * Trap 12 is the entry point for the cachectl "syscall" (both HPUX & BSD)
    433  *	cachectl(command, addr, length)
    434  * command in d0, addr in a1, length in d1
    435  */
    436 	.globl	_cachectl
    437 _trap12:
    438 	movl	d1,sp@-			| push length
    439 	movl	a1,sp@-			| push addr
    440 	movl	d0,sp@-			| push command
    441 	jbsr	_cachectl		| do it
    442 	lea	sp@(12),sp		| pop args
    443 	jra	rei			| all done
    444 
    445 /*
    446  * Trap 15 is used for:
    447  *	- KGDB traps
    448  *	- trace traps for SUN binaries (not fully supported yet)
    449  * We just pass it on and let trap() sort it all out
    450  */
    451 _trap15:
    452 	clrl	sp@-
    453 	moveml	#0xFFFF,sp@-
    454 #ifdef KGDB
    455 	moveq	#T_TRAP15,d0
    456 	movw	sp@(FR_HW),d1		| get PSW
    457 	andw	#PSL_S,d1		| from user mode?
    458 	jeq	fault			| yes, just a regular fault
    459 	movl	d0,sp@-
    460 	.globl	_kgdb_trap_glue
    461 	jbsr	_kgdb_trap_glue		| returns if no debugger
    462 	addl	#4,sp
    463 #endif
    464 	moveq	#T_TRAP15,d0
    465 	jra	fault
    466 
    467 /*
    468  * Hit a breakpoint (trap 1 or 2) instruction.
    469  * Push the code and treat as a normal fault.
    470  */
    471 _trace:
    472 	clrl	sp@-
    473 	moveml	#0xFFFF,sp@-
    474 #ifdef KGDB
    475 	moveq	#T_TRACE,d0
    476 	movw	sp@(FR_HW),d1		| get SSW
    477 	andw	#PSL_S,d1		| from user mode?
    478 	jeq	fault			| no, regular fault
    479 	movl	d0,sp@-
    480 	jbsr	_kgdb_trap_glue		| returns if no debugger
    481 	addl	#4,sp
    482 #endif
    483 	moveq	#T_TRACE,d0
    484 	jra	fault
    485 
    486 /*
    487  * The sigreturn() syscall comes here.  It requires special handling
    488  * because we must open a hole in the stack to fill in the (possibly much
    489  * larger) original stack frame.
    490  */
    491 sigreturn:
    492 	lea	sp@(-84),sp		| leave enough space for largest frame
    493 	movl	sp@(84),sp@		| move up current 8 byte frame
    494 	movl	sp@(88),sp@(4)
    495 	movl	#84,sp@-		| default: adjust by 84 bytes
    496 	moveml	#0xFFFF,sp@-		| save user registers
    497 	movl	usp,a0			| save the user SP
    498 	movl	a0,sp@(FR_SP)		|   in the savearea
    499 	movl	#SYS_sigreturn,sp@-	| push syscall number
    500 	jbsr	_syscall		| handle it
    501 	addql	#4,sp			| pop syscall#
    502 	movl	sp@(FR_SP),a0		| grab and restore
    503 	movl	a0,usp			|   user SP
    504 	lea	sp@(FR_HW),a1		| pointer to HW frame
    505 	movw	sp@(FR_ADJ),d0		| do we need to adjust the stack?
    506 	jeq	Lsigr1			| no, just continue
    507 	moveq	#92,d1			| total size
    508 	subw	d0,d1			|  - hole size = frame size
    509 	lea	a1@(92),a0		| destination
    510 	addw	d1,a1			| source
    511 	lsrw	#1,d1			| convert to word count
    512 	subqw	#1,d1			| minus 1 for dbf
    513 Lsigrlp:
    514 	movw	a1@-,a0@-		| copy a word
    515 	dbf	d1,Lsigrlp		| continue
    516 	movl	a0,a1			| new HW frame base
    517 Lsigr1:
    518 	movl	a1,sp@(FR_SP)		| new SP value
    519 	moveml	sp@+,#0x7FFF		| restore user registers
    520 	movl	sp@,sp			| and our SP
    521 	jra	rei			| all done
    522 
    523 /*
    524  * Interrupt handlers.
    525  * All DIO device interrupts are auto-vectored.  Most can be configured
    526  * to interrupt in the range IPL3 to IPL5.  Here are our assignments:
    527  *
    528  *	Level 0:	Spurious: ignored.
    529  *	Level 1:	HIL
    530  *	Level 2:
    531  *	Level 3:	Internal HP-IB, DCM
    532  *	Level 4:	"Fast" HP-IBs, SCSI
    533  *	Level 5:	DMA, Ethernet, Built-in RS232 (DCA)
    534  *	Level 6:	Clock
    535  *	Level 7:	Non-maskable: parity errors, RESET key
    536  */
    537 	.globl	_hilint, _intrhand, _hardclock, _nmihand, _dmaintr
    538 	.globl	_dcafastservice
    539 
    540 _spurintr:
    541 	addql	#1,_intrcnt+0
    542 	addql	#1,_cnt+V_INTR
    543 	jra	rei
    544 
    545 _lev1intr:
    546 	moveml	#0xC0C0,sp@-
    547 	jbsr	_hilint
    548 	moveml	sp@+,#0x0303
    549 	addql	#1,_intrcnt+4
    550 	addql	#1,_cnt+V_INTR
    551 	jra	rei
    552 
    553 /*
    554  * Check for unbuffered serial port (DCA) interrupts first in an attempt
    555  * to minimize received character lossage.  Then we check for DMA activity
    556  * to reduce overhead there.
    557  */
    558 _lev5intr:
    559 	moveml	#0xC0C0,sp@-
    560 	tstl	_dcafastservice		| unbuffered port active?
    561 	jeq	Ltrydma			| no, check DMA
    562 	clrl	sp@-			| yes, check DCA port 0
    563 	jbsr	_dcaintr		|    first to avoid overflow
    564 	addql	#4,sp
    565 	tstl	d0			| did it belong to DCA?
    566 	jeq	Ltrydma			| no, go try DMA
    567 	moveml	sp@+,#0x0303
    568 	addql	#1,_intrcnt+20
    569 	addql	#1,_cnt+V_INTR
    570 	jra	rei
    571 Ltrydma:
    572 	jbsr	_dmaintr		| check DMA channels
    573 	tstl	d0 			| was it ours?
    574 	jeq	Lnotdma			| no, go poll other devices
    575 	moveml	sp@+,#0x0303
    576 	addql	#1,_intrcnt+24
    577 	addql	#1,_cnt+V_INTR
    578 	jra	rei
    579 
    580 _lev2intr:
    581 _lev3intr:
    582 _lev4intr:
    583 	moveml	#0xC0C0,sp@-
    584 Lnotdma:
    585 	lea	_intrcnt,a0
    586 	movw	sp@(22),d0		| use vector offset
    587 	andw	#0xfff,d0		|   sans frame type
    588 	addql	#1,a0@(-0x60,d0:w)	|     to increment apropos counter
    589 	movw	sr,sp@-			| push current SR value
    590 	clrw	sp@-			|    padded to longword
    591 	jbsr	_intrhand		| handle interrupt
    592 	addql	#4,sp			| pop SR
    593 	moveml	sp@+,#0x0303
    594 	addql	#1,_cnt+V_INTR
    595 	jra	rei
    596 
    597 _lev6intr:
    598 #ifdef STACKCHECK
    599 	.globl	_panicstr,_badkstack
    600 	cmpl	#_kstack+NBPG,sp	| are we still in stack page?
    601 	jcc	Lstackok		| yes, continue normally
    602 	tstl	_curproc		| if !curproc could have switch_exited,
    603 	jeq	Lstackok		|     might be on tmpstk
    604 	tstl	_panicstr		| have we paniced?
    605 	jne	Lstackok		| yes, do not re-panic
    606 	movl	sp@(4),tmpstk-4		| no, copy common
    607 	movl	sp@,tmpstk-8		|  frame info
    608 	movl	sp,tmpstk-16		| no, save original SP
    609 	lea	tmpstk-16,sp		| switch to tmpstk
    610 	moveml	#0xFFFE,sp@-		| push remaining registers
    611 	movl	#1,sp@-			| is an overflow
    612 	jbsr	_badkstack		| badkstack(1, frame)
    613 	addql	#4,sp
    614 	moveml	sp@+,#0x7FFF		| restore most registers
    615 	movl	sp@,sp			| and SP
    616 Lstackok:
    617 #endif
    618 	moveml	#0xC0C0,sp@-		| save scratch registers
    619 	CLKADDR(a0)
    620 	movb	a0@(CLKSR),d0		| read clock status
    621 Lclkagain:
    622 	btst	#0,d0			| clear timer1 int immediately to
    623 	jeq	Lnotim1			|  minimize chance of losing another
    624 	movpw	a0@(CLKMSB1),d1		|  due to statintr processing delay
    625 Lnotim1:
    626 	btst	#2,d0			| timer3 interrupt?
    627 	jeq	Lnotim3			| no, skip statclock
    628 	movpw	a0@(CLKMSB3),d1		| clear timer3 interrupt
    629 	addql	#1,_intrcnt+32		| count clock interrupts
    630 	lea	sp@(16),a1		| a1 = &clockframe
    631 	movl	d0,sp@-			| save status
    632 	movl	a1,sp@-
    633 	jbsr	_statintr		| statintr(&frame)
    634 	addql	#4,sp
    635 	movl	sp@+,d0			| restore pre-statintr status
    636 	CLKADDR(a0)
    637 Lnotim3:
    638 	btst	#0,d0			| timer1 interrupt?
    639 	jeq	Lrecheck		| no, skip hardclock
    640 	addql	#1,_intrcnt+28		| count hardclock interrupts
    641 	lea	sp@(16),a1		| a1 = &clockframe
    642 	movl	a1,sp@-
    643 #ifdef USELEDS
    644 	.globl	_ledaddr, _inledcontrol, _ledcontrol, _hz
    645 	tstl	_ledaddr		| using LEDs?
    646 	jeq	Lnoled0			| no, skip this code
    647 	movl	heartbeat,d0		| get tick count
    648 	addql	#1,d0			|  increment
    649 	movl	_hz,d1
    650 	lsrl	#1,d1			| throb twice a second
    651 	cmpl	d0,d1			| are we there yet?
    652 	jne	Lnoled1			| no, nothing to do
    653 	tstl	_inledcontrol		| already updating LEDs?
    654 	jne	Lnoled2			| yes, skip it
    655 	movl	#LED_PULSE,sp@-
    656 	movl	#LED_DISK+LED_LANRCV+LED_LANXMT,sp@-
    657 	clrl	sp@-
    658 	jbsr	_ledcontrol		| toggle pulse, turn all others off
    659 	lea	sp@(12),sp
    660 Lnoled2:
    661 	movql	#0,d0
    662 Lnoled1:
    663 	movl	d0,heartbeat
    664 Lnoled0:
    665 #endif
    666 	jbsr	_hardclock		| hardclock(&frame)
    667 	addql	#4,sp
    668 	CLKADDR(a0)
    669 Lrecheck:
    670 	addql	#1,_cnt+V_INTR		| chalk up another interrupt
    671 	movb	a0@(CLKSR),d0		| see if anything happened
    672 	jmi	Lclkagain		|  while we were in hardclock/statintr
    673 	moveml	sp@+,#0x0303		| restore scratch registers
    674 	jra	rei			| all done
    675 
    676 _lev7intr:
    677 	addql	#1,_intrcnt+36
    678 	clrl	sp@-
    679 	moveml	#0xFFFF,sp@-		| save registers
    680 	movl	usp,a0			| and save
    681 	movl	a0,sp@(FR_SP)		|   the user stack pointer
    682 	jbsr	_nmihand		| call handler
    683 	movl	sp@(FR_SP),a0		| restore
    684 	movl	a0,usp			|   user SP
    685 	moveml	sp@+,#0x7FFF		| and remaining registers
    686 	addql	#8,sp			| pop SP and stack adjust
    687 	jra	rei			| all done
    688 
    689 /*
    690  * Emulation of VAX REI instruction.
    691  *
    692  * This code deals with checking for and servicing ASTs
    693  * (profiling, scheduling) and software interrupts (network, softclock).
    694  * We check for ASTs first, just like the VAX.  To avoid excess overhead
    695  * the T_ASTFLT handling code will also check for software interrupts so we
    696  * do not have to do it here.  After identifing that we need an AST we
    697  * drop the IPL to allow device interrupts.
    698  *
    699  * This code is complicated by the fact that sendsig may have been called
    700  * necessitating a stack cleanup.
    701  */
    702 	.comm	_ssir,1
    703 	.globl	_astpending
    704 rei:
    705 #ifdef STACKCHECK
    706 	tstl	_panicstr		| have we paniced?
    707 	jne	Ldorte1			| yes, do not make matters worse
    708 #endif
    709 	tstl	_astpending		| AST pending?
    710 	jeq	Lchksir			| no, go check for SIR
    711 Lrei1:
    712 	btst	#5,sp@			| yes, are we returning to user mode?
    713 	jne	Lchksir			| no, go check for SIR
    714 	movw	#PSL_LOWIPL,sr		| lower SPL
    715 	clrl	sp@-			| stack adjust
    716 	moveml	#0xFFFF,sp@-		| save all registers
    717 	movl	usp,a1			| including
    718 	movl	a1,sp@(FR_SP)		|    the users SP
    719 	clrl	sp@-			| VA == none
    720 	clrl	sp@-			| code == none
    721 	movl	#T_ASTFLT,sp@-		| type == async system trap
    722 	jbsr	_trap			| go handle it
    723 	lea	sp@(12),sp		| pop value args
    724 	movl	sp@(FR_SP),a0		| restore user SP
    725 	movl	a0,usp			|   from save area
    726 	movw	sp@(FR_ADJ),d0		| need to adjust stack?
    727 	jne	Laststkadj		| yes, go to it
    728 	moveml	sp@+,#0x7FFF		| no, restore most user regs
    729 	addql	#8,sp			| toss SP and stack adjust
    730 #ifdef STACKCHECK
    731 	jra	Ldorte
    732 #else
    733 	rte				| and do real RTE
    734 #endif
    735 Laststkadj:
    736 	lea	sp@(FR_HW),a1		| pointer to HW frame
    737 	addql	#8,a1			| source pointer
    738 	movl	a1,a0			| source
    739 	addw	d0,a0			|  + hole size = dest pointer
    740 	movl	a1@-,a0@-		| copy
    741 	movl	a1@-,a0@-		|  8 bytes
    742 	movl	a0,sp@(FR_SP)		| new SSP
    743 	moveml	sp@+,#0x7FFF		| restore user registers
    744 	movl	sp@,sp			| and our SP
    745 #ifdef STACKCHECK
    746 	jra	Ldorte
    747 #else
    748 	rte				| and do real RTE
    749 #endif
    750 Lchksir:
    751 	tstb	_ssir			| SIR pending?
    752 	jeq	Ldorte			| no, all done
    753 	movl	d0,sp@-			| need a scratch register
    754 	movw	sp@(4),d0		| get SR
    755 	andw	#PSL_IPL7,d0		| mask all but IPL
    756 	jne	Lnosir			| came from interrupt, no can do
    757 	movl	sp@+,d0			| restore scratch register
    758 Lgotsir:
    759 	movw	#SPL1,sr		| prevent others from servicing int
    760 	tstb	_ssir			| too late?
    761 	jeq	Ldorte			| yes, oh well...
    762 	clrl	sp@-			| stack adjust
    763 	moveml	#0xFFFF,sp@-		| save all registers
    764 	movl	usp,a1			| including
    765 	movl	a1,sp@(FR_SP)		|    the users SP
    766 	clrl	sp@-			| VA == none
    767 	clrl	sp@-			| code == none
    768 	movl	#T_SSIR,sp@-		| type == software interrupt
    769 	jbsr	_trap			| go handle it
    770 	lea	sp@(12),sp		| pop value args
    771 	movl	sp@(FR_SP),a0		| restore
    772 	movl	a0,usp			|   user SP
    773 	moveml	sp@+,#0x7FFF		| and all remaining registers
    774 	addql	#8,sp			| pop SP and stack adjust
    775 #ifdef STACKCHECK
    776 	jra	Ldorte
    777 #else
    778 	rte
    779 #endif
    780 Lnosir:
    781 	movl	sp@+,d0			| restore scratch register
    782 Ldorte:
    783 #ifdef STACKCHECK
    784 	movw	#SPL6,sr		| avoid trouble
    785 	btst	#5,sp@			| are we returning to user mode?
    786 	jne	Ldorte1			| no, skip it
    787 	movl	a6,tmpstk-20
    788 	movl	d0,tmpstk-76
    789 	moveq	#0,d0
    790 	movb	sp@(6),d0		| get format/vector
    791 	lsrl	#3,d0			| convert to index
    792 	lea	_exframesize,a6		|  into exframesize
    793 	addl	d0,a6			|  to get pointer to correct entry
    794 	movw	a6@,d0			| get size for this frame
    795 	addql	#8,d0			| adjust for unaccounted for bytes
    796 	lea	_kstackatbase,a6	| desired stack base
    797 	subl	d0,a6			|   - frame size == our stack
    798 	cmpl	a6,sp			| are we where we think?
    799 	jeq	Ldorte2			| yes, skip it
    800 	lea	tmpstk,a6		| will be using tmpstk
    801 	movl	sp@(4),a6@-		| copy common
    802 	movl	sp@,a6@-		|   frame info
    803 	clrl	a6@-
    804 	movl	sp,a6@-			| save sp
    805 	subql	#4,a6			| skip over already saved a6
    806 	moveml	#0x7FFC,a6@-		| push remaining regs (d0/a6/a7 done)
    807 	lea	a6@(-4),sp		| switch to tmpstk (skip saved d0)
    808 	clrl	sp@-			| is an underflow
    809 	jbsr	_badkstack		| badkstack(0, frame)
    810 	addql	#4,sp
    811 	moveml	sp@+,#0x7FFF		| restore most registers
    812 	movl	sp@,sp			| and SP
    813 	rte
    814 Ldorte2:
    815 	movl	tmpstk-76,d0
    816 	movl	tmpstk-20,a6
    817 Ldorte1:
    818 #endif
    819 	rte				| real return
    820 
    821 /*
    822  * Kernel access to the current processes kernel stack is via a fixed
    823  * virtual address.  It is at the same address as in the users VA space.
    824  * Umap contains the KVA of the first of UPAGES PTEs mapping VA _kstack.
    825  */
    826 	.data
    827 	.set	_kstack,USRSTACK
    828 	.set	_kstackatbase,USRSTACK+UPAGES*NBPG-4
    829 	.globl	_kstackatbase
    830 _Umap:	.long	0
    831 	.globl	_kstack, _Umap
    832 
    833 #define	RELOC(var, ar)	\
    834 	lea	var,ar;	\
    835 	addl	a5,ar
    836 
    837 /*
    838  * Initialization
    839  *
    840  * A5 contains physical load point from boot
    841  * VBR contains zero from ROM.  Exceptions will continue to vector
    842  * through ROM until MMU is turned on at which time they will vector
    843  * through our table (vectors.s).
    844  */
    845 	.comm	_lowram,4
    846 
    847 	.text
    848 	.globl	_edata
    849 	.globl	_etext,_end
    850 	.globl	start
    851 start:
    852 	movw	#PSL_HIGHIPL,sr		| no interrupts
    853 	RELOC(tmpstk, a0)
    854 	movl	a0,sp			| give ourselves a temporary stack
    855 	RELOC(_lowram, a0)
    856 	movl	a5,a0@			| store start of physical memory
    857 	movl	#CACHE_OFF,d0
    858 	movc	d0,cacr			| clear and disable on-chip cache(s)
    859 
    860 /* determine our CPU/MMU combo - check for all regardless of kernel config */
    861 	movl	#INTIOBASE+MMUBASE,a1
    862 	movl	#0x200,d0		| data freeze bit
    863 	movc	d0,cacr			|   only exists on 68030
    864 	movc	cacr,d0			| read it back
    865 	tstl	d0			| zero?
    866 	jeq	Lnot68030		| yes, we have 68020/68040
    867 	RELOC(_mmutype, a0)		| no, we have 68030
    868 	movl	#-1,a0@			| set to reflect 68030 PMMU
    869 	RELOC(_machineid, a0)
    870 	movl	#0x80,a1@(MMUCMD)	| set magic cookie
    871 	movl	a1@(MMUCMD),d0		| read it back
    872 	btst	#7,d0			| cookie still on?
    873 	jeq	Lnot370			| no, 360 or 375
    874 	movl	#0,a1@(MMUCMD)		| clear magic cookie
    875 	movl	a1@(MMUCMD),d0		| read it back
    876 	btst	#7,d0			| still on?
    877 	jeq	Lisa370			| no, must be a 370
    878 	movl	#5,a0@			| yes, must be a 340
    879 	jra	Lstart1
    880 Lnot370:
    881 	movl	#3,a0@			| type is at least a 360
    882 	movl	#0,a1@(MMUCMD)		| clear magic cookie2
    883 	movl	a1@(MMUCMD),d0		| read it back
    884 	btst	#16,d0			| still on?
    885 	jeq	Lstart1			| no, must be a 360
    886 	movl	#6,a0@			| yes, must be a 345/375
    887 	jra	Lhaspac
    888 Lisa370:
    889 	movl	#4,a0@			| set to 370
    890 Lhaspac:
    891 	RELOC(_ectype, a0)
    892 	movl	#-1,a0@			| also has a physical address cache
    893 	jra	Lstart1
    894 Lnot68030:
    895 	bset	#31,d0			| data cache enable bit
    896 	movc	d0,cacr			|   only exists on 68040
    897 	movc	cacr,d0			| read it back
    898 	tstl	d0			| zero?
    899 	beq	Lis68020		| yes, we have 68020
    900 	moveq	#0,d0			| now turn it back off
    901 	movec	d0,cacr			|   before we access any data
    902 	RELOC(_mmutype, a0)
    903 	movl	#-2,a0@			| with a 68040 MMU
    904 	RELOC(_ectype, a0)
    905 	movl	#0,a0@			| and no cache (for now XXX)
    906 #ifdef HPFPLIB
    907 	RELOC(_processor, a0)
    908 	movl	#3,a0@			| HP-UX style processor id
    909 #endif
    910 	RELOC(_machineid, a0)
    911 	movl	a1@(MMUCMD),d0		| read MMU register
    912 	lsrl	#8,d0			| get apparent ID
    913 	cmpb	#6,d0			| id == 6?
    914 	jeq	Lis33mhz		| yes, we have a 433s
    915 	movl	#7,a0@			| no, we have a 380/425t
    916 	jra	Lstart1
    917 Lis33mhz:
    918 	movl	#8,a0@			| 433s (XXX 425s returns same ID, ugh!)
    919 	jra	Lstart1
    920 Lis68020:
    921 	movl	#1,a1@(MMUCMD)		| a 68020, write HP MMU location
    922 	movl	a1@(MMUCMD),d0		| read it back
    923 	btst	#0,d0			| non-zero?
    924 	jne	Lishpmmu		| yes, we have HP MMU
    925 	RELOC(_mmutype, a0)
    926 	movl	#1,a0@			| no, we have PMMU
    927 	RELOC(_machineid, a0)
    928 	movl	#1,a0@			| and 330 CPU
    929 	jra	Lstart1
    930 Lishpmmu:
    931 	RELOC(_ectype, a0)		| 320 or 350
    932 	movl	#1,a0@			| both have a virtual address cache
    933 	movl	#0x80,a1@(MMUCMD)	| set magic cookie
    934 	movl	a1@(MMUCMD),d0		| read it back
    935 	btst	#7,d0			| cookie still on?
    936 	jeq	Lstart1			| no, just a 320
    937 	RELOC(_machineid, a0)
    938 	movl	#2,a0@			| yes, a 350
    939 
    940 Lstart1:
    941 	movl	#0,a1@(MMUCMD)		| clear out MMU again
    942 /* initialize source/destination control registers for movs */
    943 	moveq	#FC_USERD,d0		| user space
    944 	movc	d0,sfc			|   as source
    945 	movc	d0,dfc			|   and destination of transfers
    946 /* initialize memory sizes (for pmap_bootstrap) */
    947 	movl	#MAXADDR,d1		| last page
    948 	moveq	#PGSHIFT,d2
    949 	lsrl	d2,d1			| convert to page (click) number
    950 	RELOC(_maxmem, a0)
    951 	movl	d1,a0@			| save as maxmem
    952 	movl	a5,d0			| lowram value from ROM via boot
    953 	lsrl	d2,d0			| convert to page number
    954 	subl	d0,d1			| compute amount of RAM present
    955 	RELOC(_physmem, a0)
    956 	movl	d1,a0@			| and physmem
    957 /* configure kernel and proc0 VA space so we can get going */
    958 	.globl	_Sysseg, _pmap_bootstrap, _avail_start
    959 	movl	#_end,d5		| end of static kernel text/data
    960 	addl	#NBPG-1,d5
    961 	andl	#PG_FRAME,d5		| round to a page
    962 	movl	d5,a4
    963 	addl	a5,a4			| convert to PA
    964 	pea	a5@			| firstpa
    965 	pea	a4@			| nextpa
    966 	RELOC(_pmap_bootstrap,a0)
    967 	jbsr	a0@			| pmap_bootstrap(firstpa, nextpa)
    968 	addql	#8,sp
    969 
    970 /*
    971  * Prepare to enable MMU.
    972  * Since the kernel is not mapped logical == physical we must insure
    973  * that when the MMU is turned on, all prefetched addresses (including
    974  * the PC) are valid.  In order guarentee that, we use the last physical
    975  * page (which is conveniently mapped == VA) and load it up with enough
    976  * code to defeat the prefetch, then we execute the jump back to here.
    977  *
    978  * Is this all really necessary, or am I paranoid??
    979  */
    980 	RELOC(_Sysseg, a0)		| system segment table addr
    981 	movl	a0@,d1			| read value (a KVA)
    982 	addl	a5,d1			| convert to PA
    983 	RELOC(_mmutype, a0)
    984 	tstl	a0@			| HP MMU?
    985 	jeq	Lhpmmu2			| yes, skip
    986 	cmpl	#-2,a0@			| 68040?
    987 	jne	Lmotommu1		| no, skip
    988 	.long	0x4e7b1807		| movc d1,srp
    989 	jra	Lstploaddone
    990 Lmotommu1:
    991 	RELOC(_protorp, a0)
    992 	movl	#0x80000202,a0@		| nolimit + share global + 4 byte PTEs
    993 	movl	d1,a0@(4)		| + segtable address
    994 	pmove	a0@,srp			| load the supervisor root pointer
    995 	movl	#0x80000002,a0@		| reinit upper half for CRP loads
    996 	jra	Lstploaddone		| done
    997 Lhpmmu2:
    998 	moveq	#PGSHIFT,d2
    999 	lsrl	d2,d1			| convert to page frame
   1000 	movl	d1,INTIOBASE+MMUBASE+MMUSSTP | load in sysseg table register
   1001 Lstploaddone:
   1002 	lea	MAXADDR,a2		| PA of last RAM page
   1003 	RELOC(Lhighcode, a1)		| addr of high code
   1004 	RELOC(Lehighcode, a3)		| end addr
   1005 Lcodecopy:
   1006 	movw	a1@+,a2@+		| copy a word
   1007 	cmpl	a3,a1			| done yet?
   1008 	jcs	Lcodecopy		| no, keep going
   1009 	jmp	MAXADDR			| go for it!
   1010 
   1011 Lhighcode:
   1012 	RELOC(_mmutype, a0)
   1013 	tstl	a0@			| HP MMU?
   1014 	jeq	Lhpmmu3			| yes, skip
   1015 	cmpl	#-2,a0@			| 68040?
   1016 	jne	Lmotommu2		| no, skip
   1017 	movw	#0,INTIOBASE+MMUBASE+MMUCMD+2
   1018 	movw	#MMU_IEN+MMU_CEN+MMU_FPE,INTIOBASE+MMUBASE+MMUCMD+2
   1019 					| enable FPU and caches
   1020 	moveq	#0,d0			| ensure TT regs are disabled
   1021 	.long	0x4e7b0004		| movc d0,itt0
   1022 	.long	0x4e7b0005		| movc d0,itt1
   1023 	.long	0x4e7b0006		| movc d0,dtt0
   1024 	.long	0x4e7b0007		| movc d0,dtt1
   1025 	.word	0xf4d8			| cinva bc
   1026 	.word	0xf518			| pflusha
   1027 	movl	#0x8000,d0
   1028 	.long	0x4e7b0003		| movc d0,tc
   1029 	movl	#0x80008000,d0
   1030 	movc	d0,cacr			| turn on both caches
   1031 	jmp	Lenab1
   1032 Lmotommu2:
   1033 	movl	#MMU_IEN+MMU_FPE,INTIOBASE+MMUBASE+MMUCMD
   1034 					| enable 68881 and i-cache
   1035 	movl	#0x82c0aa00,a2@		| value to load TC with
   1036 	pmove	a2@,tc			| load it
   1037 	jmp	Lenab1
   1038 Lhpmmu3:
   1039 	movl	#0,INTIOBASE+MMUBASE+MMUCMD	| clear external cache
   1040 	movl	#MMU_ENAB,INTIOBASE+MMUBASE+MMUCMD | turn on MMU
   1041 	jmp	Lenab1				| jmp to mapped code
   1042 Lehighcode:
   1043 
   1044 /*
   1045  * Should be running mapped from this point on
   1046  */
   1047 Lenab1:
   1048 /* check for internal HP-IB in SYSFLAG */
   1049 	btst	#5,0xfffffed2		| internal HP-IB?
   1050 	jeq	Lfinish			| yes, have HP-IB just continue
   1051 	clrl	_internalhpib		| no, clear associated address
   1052 Lfinish:
   1053 /* select the software page size now */
   1054 	lea	tmpstk,sp		| temporary stack
   1055 	jbsr	_vm_set_page_size	| select software page size
   1056 /* set kernel stack, user SP, and initial pcb */
   1057 	lea	_kstack,a1		| proc0 kernel stack
   1058 	lea	a1@(UPAGES*NBPG-4),sp	| set kernel stack to end of area
   1059 	movl	#USRSTACK-4,a2
   1060 	movl	a2,usp			| init user SP
   1061 	movl	_proc0paddr,a1		| get proc0 pcb addr
   1062 	movl	a1,_curpcb		| proc0 is running
   1063 #ifdef FPCOPROC
   1064 	clrl	a1@(PCB_FPCTX)		| ensure null FP context
   1065 	movl	a1,sp@-
   1066 	jbsr	_m68881_restore		| restore it (does not kill a1)
   1067 	addql	#4,sp
   1068 #endif
   1069 /* flush TLB and turn on caches */
   1070 	jbsr	_TBIA			| invalidate TLB
   1071 	cmpl	#-2,_mmutype		| 68040?
   1072 	jeq	Lnocache0		| yes, cache already on
   1073 	movl	#CACHE_ON,d0
   1074 	movc	d0,cacr			| clear cache(s)
   1075 	tstl	_ectype
   1076 	jeq	Lnocache0
   1077 	MMUADDR(a0)
   1078 	orl	#MMU_CEN,a0@(MMUCMD)	| turn on external cache
   1079 Lnocache0:
   1080 /* final setup for C code */
   1081 	jbsr	_isrinit		| be ready for stray ints
   1082 	movw	#PSL_LOWIPL,sr		| lower SPL
   1083 	movl	d7,_boothowto		| save reboot flags
   1084 	movl	d6,_bootdev		|   and boot device
   1085 /*
   1086  * Create a fake exception frame that returns to user mode,
   1087  * make space for the rest of a fake saved register set, and
   1088  * pass the first available RAM and a pointer to the register
   1089  * set to "main()".  "main()" will call "icode()", which fakes
   1090  * an "execve()" system call, which is why we need to do that
   1091  * ("main()" sets "u.u_ar0" to point to the register set).
   1092  * When "main()" returns, we're running in process 1 and have
   1093  * successfully faked the "execve()".  We load up the registers from
   1094  * that set; the "rte" loads the PC and PSR, which jumps to "init".
   1095  */
   1096   	clrw	sp@-			| vector offset/frame type
   1097 	clrl	sp@-			| PC - filled in by "execve"
   1098   	movw	#PSL_USER,sp@-		| in user mode
   1099 	clrl	sp@-			| pad word
   1100 	lea	sp@(-64),sp		| construct space for D0-D7/A0-A7
   1101 	pea	sp@			| addr of space for D0
   1102 	jbsr	_main			| main(firstaddr, r0)
   1103 	addql	#4,sp			| pop args
   1104 	cmpl	#-2,_mmutype		| 68040?
   1105 	jne	Lnoflush		| no, skip
   1106 	.word	0xf478			| cpusha dc
   1107 	.word	0xf498			| cinva ic
   1108 Lnoflush:
   1109 	movl	sp@(60),a0		| grab and load
   1110 	movl	a0,usp			|   user SP
   1111 	moveml	sp@+,#0x7FFF		| load most registers (all but SSP)
   1112 	addql	#8,sp			| pop SSP and pad word
   1113   	rte
   1114 
   1115 /*
   1116  * Signal "trampoline" code (18 bytes).  Invoked from RTE setup by sendsig().
   1117  *
   1118  * Stack looks like:
   1119  *
   1120  *	sp+0 ->	signal number
   1121  *	sp+4	signal specific code
   1122  *	sp+8	pointer to signal context frame (scp)
   1123  *	sp+12	address of handler
   1124  *	sp+16	saved hardware state
   1125  *			.
   1126  *			.
   1127  *	scp+0->	beginning of signal context frame
   1128  */
   1129 	.globl	_sigcode, _esigcode, _sigcodetrap
   1130 	.data
   1131 _sigcode:
   1132 	movl	sp@(12),a0		| signal handler addr	(4 bytes)
   1133 	jsr	a0@			| call signal handler	(2 bytes)
   1134 	addql	#4,sp			| pop signo		(2 bytes)
   1135 _sigcodetrap:
   1136 	trap	#1			| special syscall entry	(2 bytes)
   1137 	movl	d0,sp@(4)		| save errno		(4 bytes)
   1138 	moveq	#1,d0			| syscall == exit	(2 bytes)
   1139 	trap	#0			| exit(errno)		(2 bytes)
   1140 	.align	2
   1141 _esigcode:
   1142 
   1143 /*
   1144  * Primitives
   1145  */
   1146 
   1147 #ifdef __STDC__
   1148 #define EXPORT(name)		.globl _ ## name; _ ## name:
   1149 #else
   1150 #define EXPORT(name)		.globl _/**/name; _/**/name:
   1151 #endif
   1152 #ifdef GPROF
   1153 #if __GNUC__ >= 2
   1154 #define	ENTRY(name)		EXPORT(name) link a6,\#0; jbsr mcount; unlk a6
   1155 #else
   1156 #define	ENTRY(name)		EXPORT(name) link a6,#0; jbsr mcount; unlk a6
   1157 #endif
   1158 #define ALTENTRY(name, rname)	ENTRY(name); jra rname+12
   1159 #else
   1160 #define	ENTRY(name)		EXPORT(name)
   1161 #define ALTENTRY(name, rname) 	ENTRY(name)
   1162 #endif
   1163 
   1164 /*
   1165  * For gcc2
   1166  */
   1167 ENTRY(__main)
   1168 	rts
   1169 
   1170 /*
   1171  * copypage(fromaddr, toaddr)
   1172  *
   1173  * Optimized version of bcopy for a single page-aligned NBPG byte copy.
   1174  */
   1175 ENTRY(copypage)
   1176 	movl	sp@(4),a0		| source address
   1177 	movl	sp@(8),a1		| destination address
   1178 	movl	#NBPG/32,d0		| number of 32 byte chunks
   1179 #if defined(HP380)
   1180 	cmpl	#-2,_mmutype		| 68040?
   1181 	jne	Lmlloop			| no, use movl
   1182 Lm16loop:
   1183 	.long	0xf6209000		| move16 a0@+,a1@+
   1184 	.long	0xf6209000		| move16 a0@+,a1@+
   1185 	subql	#1,d0
   1186 	jne	Lm16loop
   1187 	rts
   1188 #endif
   1189 Lmlloop:
   1190 	movl	a0@+,a1@+
   1191 	movl	a0@+,a1@+
   1192 	movl	a0@+,a1@+
   1193 	movl	a0@+,a1@+
   1194 	movl	a0@+,a1@+
   1195 	movl	a0@+,a1@+
   1196 	movl	a0@+,a1@+
   1197 	movl	a0@+,a1@+
   1198 	subql	#1,d0
   1199 	jne	Lmlloop
   1200 	rts
   1201 
   1202 /*
   1203  * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
   1204  *
   1205  * Copy a null terminated string from the user address space into
   1206  * the kernel address space.
   1207  *
   1208  * NOTE: maxlength must be < 64K (due to use of DBcc)
   1209  */
   1210 ENTRY(copyinstr)
   1211 	movl	_curpcb,a0		| current pcb
   1212 	movl	#Lcisflt1,a0@(PCB_ONFAULT) | set up to catch faults
   1213 	movl	sp@(4),a0		| a0 = fromaddr
   1214 	movl	sp@(8),a1		| a1 = toaddr
   1215 	moveq	#0,d0
   1216 	movw	sp@(14),d0		| d0 = maxlength
   1217 	jlt	Lcisflt1		| negative count, error
   1218 	jeq	Lcisdone		| zero count, all done
   1219 	subql	#1,d0			| set up for dbeq
   1220 Lcisloop:
   1221 	movsb	a0@+,d1			| grab a byte
   1222 	nop
   1223 	movb	d1,a1@+			| copy it
   1224 	dbeq	d0,Lcisloop		| if !null and more, continue
   1225 	jne	Lcisflt2		| ran out of room, error
   1226 	moveq	#0,d0			| got a null, all done
   1227 Lcisdone:
   1228 	tstl	sp@(16)			| return length desired?
   1229 	jeq	Lcisret			| no, just return
   1230 	subl	sp@(4),a0		| determine how much was copied
   1231 	movl	sp@(16),a1		| return location
   1232 	movl	a0,a1@			| stash it
   1233 Lcisret:
   1234 	movl	_curpcb,a0		| current pcb
   1235 	clrl	a0@(PCB_ONFAULT) 	| clear fault addr
   1236 	rts
   1237 Lcisflt1:
   1238 	moveq	#EFAULT,d0		| copy fault
   1239 	jra	Lcisdone
   1240 Lcisflt2:
   1241 	moveq	#ENAMETOOLONG,d0	| ran out of space
   1242 	jra	Lcisdone
   1243 
   1244 /*
   1245  * copyoutstr(fromaddr, toaddr, maxlength, &lencopied)
   1246  *
   1247  * Copy a null terminated string from the kernel
   1248  * address space to the user address space.
   1249  *
   1250  * NOTE: maxlength must be < 64K (due to use of DBcc)
   1251  */
   1252 ENTRY(copyoutstr)
   1253 	movl	_curpcb,a0		| current pcb
   1254 	movl	#Lcosflt1,a0@(PCB_ONFAULT) | set up to catch faults
   1255 	movl	sp@(4),a0		| a0 = fromaddr
   1256 	movl	sp@(8),a1		| a1 = toaddr
   1257 	moveq	#0,d0
   1258 	movw	sp@(14),d0		| d0 = maxlength
   1259 	jlt	Lcosflt1		| negative count, error
   1260 	jeq	Lcosdone		| zero count, all done
   1261 	subql	#1,d0			| set up for dbeq
   1262 Lcosloop:
   1263 	movb	a0@+,d1			| grab a byte
   1264 	movsb	d1,a1@+			| copy it
   1265 	nop
   1266 	dbeq	d0,Lcosloop		| if !null and more, continue
   1267 	jne	Lcosflt2		| ran out of room, error
   1268 	moveq	#0,d0			| got a null, all done
   1269 Lcosdone:
   1270 	tstl	sp@(16)			| return length desired?
   1271 	jeq	Lcosret			| no, just return
   1272 	subl	sp@(4),a0		| determine how much was copied
   1273 	movl	sp@(16),a1		| return location
   1274 	movl	a0,a1@			| stash it
   1275 Lcosret:
   1276 	movl	_curpcb,a0		| current pcb
   1277 	clrl	a0@(PCB_ONFAULT) 	| clear fault addr
   1278 	rts
   1279 Lcosflt1:
   1280 	moveq	#EFAULT,d0		| copy fault
   1281 	jra	Lcosdone
   1282 Lcosflt2:
   1283 	moveq	#ENAMETOOLONG,d0	| ran out of space
   1284 	jra	Lcosdone
   1285 
   1286 /*
   1287  * copystr(fromaddr, toaddr, maxlength, &lencopied)
   1288  *
   1289  * Copy a null terminated string from one point to another in
   1290  * the kernel address space.
   1291  *
   1292  * NOTE: maxlength must be < 64K (due to use of DBcc)
   1293  */
   1294 ENTRY(copystr)
   1295 	movl	sp@(4),a0		| a0 = fromaddr
   1296 	movl	sp@(8),a1		| a1 = toaddr
   1297 	moveq	#0,d0
   1298 	movw	sp@(14),d0		| d0 = maxlength
   1299 	jlt	Lcsflt1			| negative count, error
   1300 	jeq	Lcsdone			| zero count, all done
   1301 	subql	#1,d0			| set up for dbeq
   1302 Lcsloop:
   1303 	movb	a0@+,a1@+		| copy a byte
   1304 	dbeq	d0,Lcsloop		| if !null and more, continue
   1305 	jne	Lcsflt2			| ran out of room, error
   1306 	moveq	#0,d0			| got a null, all done
   1307 Lcsdone:
   1308 	tstl	sp@(16)			| return length desired?
   1309 	jeq	Lcsret			| no, just return
   1310 	subl	sp@(4),a0		| determine how much was copied
   1311 	movl	sp@(16),a1		| return location
   1312 	movl	a0,a1@			| stash it
   1313 Lcsret:
   1314 	rts
   1315 Lcsflt1:
   1316 	moveq	#EFAULT,d0		| copy fault
   1317 	jra	Lcsdone
   1318 Lcsflt2:
   1319 	moveq	#ENAMETOOLONG,d0	| ran out of space
   1320 	jra	Lcsdone
   1321 
   1322 /*
   1323  * Copyin(from_user, to_kernel, len)
   1324  * Copyout(from_kernel, to_user, len)
   1325  *
   1326  * Copy specified amount of data between kernel and user space.
   1327  *
   1328  * XXX both use the DBcc instruction which has 16-bit limitation so only
   1329  * 64k units can be copied, where "unit" is either a byte or a longword
   1330  * depending on alignment.  To be safe, assume it can copy at most
   1331  * 64k bytes.  Don't make MAXBSIZE or MAXPHYS larger than 64k without
   1332  * fixing this code!
   1333  */
   1334 ENTRY(copyin)
   1335 	movl	sp@(12),d0		| get size
   1336 #ifdef MAPPEDCOPY
   1337 	.globl	_mappedcopysize,_mappedcopyin
   1338 	cmpl	_mappedcopysize,d0	| size >= mappedcopysize
   1339 	jcc	_mappedcopyin		| yes, go do it the new way
   1340 #endif
   1341 	movl	d2,sp@-			| scratch register
   1342 	movl	_curpcb,a0		| current pcb
   1343 	movl	#Lciflt,a0@(PCB_ONFAULT) | set up to catch faults
   1344 	tstl	d0			| check count
   1345 	jlt	Lciflt			| negative, error
   1346 	jeq	Lcidone			| zero, done
   1347 	movl	sp@(8),a0		| src address
   1348 	movl	sp@(12),a1		| dest address
   1349 	movl	a0,d2
   1350 	btst	#0,d2			| src address odd?
   1351 	jeq	Lcieven			| no, go check dest
   1352 	movsb	a0@+,d1			| yes, get a byte
   1353 	nop
   1354 	movb	d1,a1@+			| put a byte
   1355 	subql	#1,d0			| adjust count
   1356 	jeq	Lcidone			| exit if done
   1357 Lcieven:
   1358 	movl	a1,d2
   1359 	btst	#0,d2			| dest address odd?
   1360 	jne	Lcibloop		| yes, must copy by bytes
   1361 	movl	d0,d2			| no, get count
   1362 	lsrl	#2,d2			| convert to longwords
   1363 	jeq	Lcibloop		| no longwords, copy bytes
   1364 Lcilloop:
   1365 	movsl	a0@+,d1			| get a long
   1366 	nop
   1367 	movl	d1,a1@+			| put a long
   1368 	subql	#1,d2
   1369 	jne	Lcilloop		| til done
   1370 	andl	#3,d0			| what remains
   1371 	jeq	Lcidone			| all done
   1372 Lcibloop:
   1373 	movsb	a0@+,d1			| get a byte
   1374 	nop
   1375 	movb	d1,a1@+			| put a byte
   1376 	subql	#1,d0
   1377 	jne	Lcibloop		| til done
   1378 Lcidone:
   1379 	movl	_curpcb,a0		| current pcb
   1380 	clrl	a0@(PCB_ONFAULT) 	| clear fault catcher
   1381 	movl	sp@+,d2			| restore scratch reg
   1382 	rts
   1383 Lciflt:
   1384 	moveq	#EFAULT,d0		| got a fault
   1385 	jra	Lcidone
   1386 
   1387 ENTRY(copyout)
   1388 	movl	sp@(12),d0		| get size
   1389 #ifdef MAPPEDCOPY
   1390 	.globl	_mappedcopysize,_mappedcopyout
   1391 	cmpl	_mappedcopysize,d0	| size >= mappedcopysize
   1392 	jcc	_mappedcopyout		| yes, go do it the new way
   1393 #endif
   1394 	movl	d2,sp@-			| scratch register
   1395 	movl	_curpcb,a0		| current pcb
   1396 	movl	#Lcoflt,a0@(PCB_ONFAULT) | catch faults
   1397 	tstl	d0			| check count
   1398 	jlt	Lcoflt			| negative, error
   1399 	jeq	Lcodone			| zero, done
   1400 	movl	sp@(8),a0		| src address
   1401 	movl	sp@(12),a1		| dest address
   1402 	movl	a0,d2
   1403 	btst	#0,d2			| src address odd?
   1404 	jeq	Lcoeven			| no, go check dest
   1405 	movb	a0@+,d1			| yes, get a byte
   1406 	movsb	d1,a1@+			| put a byte
   1407 	nop
   1408 	subql	#1,d0			| adjust count
   1409 	jeq	Lcodone			| exit if done
   1410 Lcoeven:
   1411 	movl	a1,d2
   1412 	btst	#0,d2			| dest address odd?
   1413 	jne	Lcobloop		| yes, must copy by bytes
   1414 	movl	d0,d2			| no, get count
   1415 	lsrl	#2,d2			| convert to longwords
   1416 	jeq	Lcobloop		| no longwords, copy bytes
   1417 Lcolloop:
   1418 	movl	a0@+,d1			| get a long
   1419 	movsl	d1,a1@+			| put a long
   1420 	nop
   1421 	subql	#1,d2
   1422 	jne	Lcolloop		| til done
   1423 	andl	#3,d0			| what remains
   1424 	jeq	Lcodone			| all done
   1425 Lcobloop:
   1426 	movb	a0@+,d1			| get a byte
   1427 	movsb	d1,a1@+			| put a byte
   1428 	nop
   1429 	subql	#1,d0
   1430 	jne	Lcobloop		| til done
   1431 Lcodone:
   1432 	movl	_curpcb,a0		| current pcb
   1433 	clrl	a0@(PCB_ONFAULT) 	| clear fault catcher
   1434 	movl	sp@+,d2			| restore scratch reg
   1435 	rts
   1436 Lcoflt:
   1437 	moveq	#EFAULT,d0		| got a fault
   1438 	jra	Lcodone
   1439 
   1440 /*
   1441  * non-local gotos
   1442  */
   1443 ENTRY(setjmp)
   1444 	movl	sp@(4),a0	| savearea pointer
   1445 	moveml	#0xFCFC,a0@	| save d2-d7/a2-a7
   1446 	movl	sp@,a0@(48)	| and return address
   1447 	moveq	#0,d0		| return 0
   1448 	rts
   1449 
   1450 ENTRY(longjmp)
   1451 	movl	sp@(4),a0
   1452 	moveml	a0@+,#0xFCFC
   1453 	movl	a0@,sp@
   1454 	moveq	#1,d0
   1455 	rts
   1456 
   1457 /*
   1458  * The following primitives manipulate the run queues.  _whichqs tells which
   1459  * of the 32 queues _qs have processes in them.  Setrunqueue puts processes
   1460  * into queues, Remrq removes them from queues.  The running process is on
   1461  * no queue, other processes are on a queue related to p->p_priority, divided
   1462  * by 4 actually to shrink the 0-127 range of priorities into the 32 available
   1463  * queues.
   1464  */
   1465 
   1466 	.globl	_whichqs,_qs,_cnt,_panic
   1467 	.globl	_curproc,_want_resched
   1468 
   1469 /*
   1470  * Setrunqueue(p)
   1471  *
   1472  * Call should be made at spl6(), and p->p_stat should be SRUN
   1473  */
   1474 ENTRY(setrunqueue)
   1475 	movl	sp@(4),a0
   1476 	tstl	a0@(P_BACK)
   1477 	jeq	Lset1
   1478 	movl	#Lset2,sp@-
   1479 	jbsr	_panic
   1480 Lset1:
   1481 	clrl	d0
   1482 	movb	a0@(P_PRIORITY),d0
   1483 	lsrb	#2,d0
   1484 	movl	_whichqs,d1
   1485 	bset	d0,d1
   1486 	movl	d1,_whichqs
   1487 	lslb	#3,d0
   1488 	addl	#_qs,d0
   1489 	movl	d0,a0@(P_FORW)
   1490 	movl	d0,a1
   1491 	movl	a1@(P_BACK),a0@(P_BACK)
   1492 	movl	a0,a1@(P_BACK)
   1493 	movl	a0@(P_BACK),a1
   1494 	movl	a0,a1@(P_FORW)
   1495 	rts
   1496 
   1497 Lset2:
   1498 	.asciz	"setrunqueue"
   1499 	.even
   1500 
   1501 /*
   1502  * Remrq(p)
   1503  *
   1504  * Call should be made at spl6().
   1505  */
   1506 ENTRY(remrq)
   1507 	movl	sp@(4),a0
   1508 	clrl	d0
   1509 	movb	a0@(P_PRIORITY),d0
   1510 	lsrb	#2,d0
   1511 	movl	_whichqs,d1
   1512 	bclr	d0,d1
   1513 	jne	Lrem1
   1514 	movl	#Lrem3,sp@-
   1515 	jbsr	_panic
   1516 Lrem1:
   1517 	movl	d1,_whichqs
   1518 	movl	a0@(P_FORW),a1
   1519 	movl	a0@(P_BACK),a1@(P_BACK)
   1520 	movl	a0@(P_BACK),a1
   1521 	movl	a0@(P_FORW),a1@(P_FORW)
   1522 	movl	#_qs,a1
   1523 	movl	d0,d1
   1524 	lslb	#3,d1
   1525 	addl	d1,a1
   1526 	cmpl	a1@(P_FORW),a1
   1527 	jeq	Lrem2
   1528 	movl	_whichqs,d1
   1529 	bset	d0,d1
   1530 	movl	d1,_whichqs
   1531 Lrem2:
   1532 	clrl	a0@(P_BACK)
   1533 	rts
   1534 
   1535 Lrem3:
   1536 	.asciz	"remrq"
   1537 Lsw0:
   1538 	.asciz	"switch"
   1539 	.even
   1540 
   1541 	.globl	_curpcb
   1542 	.globl	_masterpaddr	| XXX compatibility (debuggers)
   1543 	.data
   1544 _masterpaddr:			| XXX compatibility (debuggers)
   1545 _curpcb:
   1546 	.long	0
   1547 mdpflag:
   1548 	.byte	0		| copy of proc md_flags low byte
   1549 	.align	2
   1550 	.comm	nullpcb,SIZEOF_PCB
   1551 	.text
   1552 
   1553 /*
   1554  * At exit of a process, do a switch for the last time.
   1555  * The mapping of the pcb at p->p_addr has already been deleted,
   1556  * and the memory for the pcb+stack has been freed.
   1557  * The ipl is high enough to prevent the memory from being reallocated.
   1558  */
   1559 ENTRY(switch_exit)
   1560 	movl	#nullpcb,_curpcb	| save state into garbage pcb
   1561 	lea	tmpstk,sp		| goto a tmp stack
   1562 	jra	_cpu_switch
   1563 
   1564 /*
   1565  * When no processes are on the runq, Swtch branches to Idle
   1566  * to wait for something to come ready.
   1567  */
   1568 	.globl	idle
   1569 idle:
   1570 	stop	#PSL_LOWIPL
   1571 Idle:
   1572 	movw	#PSL_HIGHIPL,sr
   1573 	tstl	_whichqs
   1574 	jeq	idle
   1575 	movw	#PSL_LOWIPL,sr
   1576 	jra	Lsw1
   1577 
   1578 Lbadsw:
   1579 	movl	#Lsw0,sp@-
   1580 	jbsr	_panic
   1581 	/*NOTREACHED*/
   1582 
   1583 /*
   1584  * cpu_switch()
   1585  *
   1586  * NOTE: On the mc68851 (318/319/330) we attempt to avoid flushing the
   1587  * entire ATC.  The effort involved in selective flushing may not be
   1588  * worth it, maybe we should just flush the whole thing?
   1589  *
   1590  * NOTE 2: With the new VM layout we now no longer know if an inactive
   1591  * user's PTEs have been changed (formerly denoted by the SPTECHG p_flag
   1592  * bit).  For now, we just always flush the full ATC.
   1593  */
   1594 ENTRY(cpu_switch)
   1595 	movl	_curpcb,a0		| current pcb
   1596 	movw	sr,a0@(PCB_PS)		| save sr before changing ipl
   1597 #ifdef notyet
   1598 	movl	_curproc,sp@-		| remember last proc running
   1599 #endif
   1600 	clrl	_curproc
   1601 	addql	#1,_cnt+V_SWTCH
   1602 
   1603 Lsw1:
   1604 	/*
   1605 	 * Find the highest-priority queue that isn't empty,
   1606 	 * then take the first proc from that queue.
   1607 	 */
   1608 	clrl	d0
   1609 	lea	_whichqs,a0
   1610 	movl	a0@,d1
   1611 Lswchk:
   1612 	btst	d0,d1
   1613 	jne	Lswfnd
   1614 	addqb	#1,d0
   1615 	cmpb	#32,d0
   1616 	jne	Lswchk
   1617 	jra	Idle
   1618 Lswfnd:
   1619 	movw	#PSL_HIGHIPL,sr		| lock out interrupts
   1620 	movl	a0@,d1			| and check again...
   1621 	bclr	d0,d1
   1622 	jeq	Lsw1			| proc moved, rescan
   1623 	movl	d1,a0@			| update whichqs
   1624 	moveq	#1,d1			| double check for higher priority
   1625 	lsll	d0,d1			| process (which may have snuck in
   1626 	subql	#1,d1			| while we were finding this one)
   1627 	andl	a0@,d1
   1628 	jeq	Lswok			| no one got in, continue
   1629 	movl	a0@,d1
   1630 	bset	d0,d1			| otherwise put this one back
   1631 	movl	d1,a0@
   1632 	jra	Lsw1			| and rescan
   1633 Lswok:
   1634 	movl	d0,d1
   1635 	lslb	#3,d1			| convert queue number to index
   1636 	addl	#_qs,d1			| locate queue (q)
   1637 	movl	d1,a1
   1638 	cmpl	a1@(P_FORW),a1		| anyone on queue?
   1639 	jeq	Lbadsw			| no, panic
   1640 	movl	a1@(P_FORW),a0		| p = q->p_forw
   1641 	movl	a0@(P_FORW),a1@(P_FORW)	| q->p_forw = p->p_forw
   1642 	movl	a0@(P_FORW),a1		| q = p->p_forw
   1643 	movl	a0@(P_BACK),a1@(P_BACK)	| q->p_back = p->p_back
   1644 	cmpl	a0@(P_FORW),d1		| anyone left on queue?
   1645 	jeq	Lsw2			| no, skip
   1646 	movl	_whichqs,d1
   1647 	bset	d0,d1			| yes, reset bit
   1648 	movl	d1,_whichqs
   1649 Lsw2:
   1650 	movl	a0,_curproc
   1651 	clrl	_want_resched
   1652 #ifdef notyet
   1653 	movl	sp@+,a1
   1654 	cmpl	a0,a1			| switching to same proc?
   1655 	jeq	Lswdone			| yes, skip save and restore
   1656 #endif
   1657 	/*
   1658 	 * Save state of previous process in its pcb.
   1659 	 */
   1660 	movl	_curpcb,a1
   1661 	moveml	#0xFCFC,a1@(PCB_REGS)	| save non-scratch registers
   1662 	movl	usp,a2			| grab USP (a2 has been saved)
   1663 	movl	a2,a1@(PCB_USP)		| and save it
   1664 #ifdef FPCOPROC
   1665 	lea	a1@(PCB_FPCTX),a2	| pointer to FP save area
   1666 	fsave	a2@			| save FP state
   1667 	tstb	a2@			| null state frame?
   1668 	jeq	Lswnofpsave		| yes, all done
   1669 	fmovem	fp0-fp7,a2@(216)	| save FP general registers
   1670 	fmovem	fpcr/fpsr/fpi,a2@(312)	| save FP control registers
   1671 Lswnofpsave:
   1672 #endif
   1673 
   1674 #ifdef DIAGNOSTIC
   1675 	tstl	a0@(P_WCHAN)
   1676 	jne	Lbadsw
   1677 	cmpb	#SRUN,a0@(P_STAT)
   1678 	jne	Lbadsw
   1679 #endif
   1680 	clrl	a0@(P_BACK)		| clear back link
   1681 	movb	a0@(P_MDFLAG+3),mdpflag	| low byte of p_md.md_flags
   1682 	movl	a0@(P_ADDR),a1		| get p_addr
   1683 	movl	a1,_curpcb
   1684 
   1685 	/* see if pmap_activate needs to be called; should remove this */
   1686 	movl	a0@(P_VMSPACE),a0	| vmspace = p->p_vmspace
   1687 #ifdef DIAGNOSTIC
   1688 	tstl	a0			| map == VM_MAP_NULL?
   1689 	jeq	Lbadsw			| panic
   1690 #endif
   1691 	lea	a0@(VM_PMAP),a0		| pmap = &vmspace.vm_pmap
   1692 	tstl	a0@(PM_STCHG)		| pmap->st_changed?
   1693 	jeq	Lswnochg		| no, skip
   1694 	pea	a1@			| push pcb (at p_addr)
   1695 	pea	a0@			| push pmap
   1696 	jbsr	_pmap_activate		| pmap_activate(pmap, pcb)
   1697 	addql	#8,sp
   1698 	movl	_curpcb,a1		| restore p_addr
   1699 Lswnochg:
   1700 
   1701 	movl	#PGSHIFT,d1
   1702 	movl	a1,d0
   1703 	lsrl	d1,d0			| convert p_addr to page number
   1704 	lsll	#2,d0			| and now to Sysmap offset
   1705 	addl	_Sysmap,d0		| add Sysmap base to get PTE addr
   1706 #ifdef notdef
   1707 	movw	#PSL_HIGHIPL,sr		| go crit while changing PTEs
   1708 #endif
   1709 	lea	tmpstk,sp		| now goto a tmp stack for NMI
   1710 	movl	d0,a0			| address of new context
   1711 	movl	_Umap,a2		| address of PTEs for kstack
   1712 	moveq	#UPAGES-1,d0		| sizeof kstack
   1713 Lres1:
   1714 	movl	a0@+,d1			| get PTE
   1715 	andl	#~PG_PROT,d1		| mask out old protection
   1716 	orl	#PG_RW+PG_V,d1		| ensure valid and writable
   1717 	movl	d1,a2@+			| load it up
   1718 	dbf	d0,Lres1		| til done
   1719 #if defined(HP380)
   1720 	cmpl	#-2,_mmutype		| 68040?
   1721 	jne	Lres1a			| no, skip
   1722 	.word	0xf518			| yes, pflusha
   1723 	movl	a1@(PCB_USTP),d0	| get USTP
   1724 	moveq	#PGSHIFT,d1
   1725 	lsll	d1,d0			| convert to addr
   1726 	.long	0x4e7b0806		| movc d0,urp
   1727 	jra	Lcxswdone
   1728 Lres1a:
   1729 #endif
   1730 	movl	#CACHE_CLR,d0
   1731 	movc	d0,cacr			| invalidate cache(s)
   1732 #if defined(HP330) || defined(HP360) || defined(HP370)
   1733 	tstl	_mmutype		| HP MMU?
   1734 	jeq	Lhpmmu4			| yes, skip
   1735 	pflusha				| flush entire TLB
   1736 	movl	a1@(PCB_USTP),d0	| get USTP
   1737 	moveq	#PGSHIFT,d1
   1738 	lsll	d1,d0			| convert to addr
   1739 	lea	_protorp,a0		| CRP prototype
   1740 	movl	d0,a0@(4)		| stash USTP
   1741 	pmove	a0@,crp			| load new user root pointer
   1742 	jra	Lcxswdone		| thats it
   1743 Lhpmmu4:
   1744 #endif
   1745 #if defined(HP320) || defined(HP350)
   1746 	MMUADDR(a0)
   1747 	movl	a0@(MMUTBINVAL),d1	| invalidate TLB
   1748 	tstl	_ectype			| got external VAC?
   1749 	jle	Lnocache1		| no, skip
   1750 	andl	#~MMU_CEN,a0@(MMUCMD)	| toggle cache enable
   1751 	orl	#MMU_CEN,a0@(MMUCMD)	| to clear data cache
   1752 Lnocache1:
   1753 	movl	a1@(PCB_USTP),a0@(MMUUSTP) | context switch
   1754 #endif
   1755 Lcxswdone:
   1756 	moveml	a1@(PCB_REGS),#0xFCFC	| and registers
   1757 	movl	a1@(PCB_USP),a0
   1758 	movl	a0,usp			| and USP
   1759 #ifdef FPCOPROC
   1760 	lea	a1@(PCB_FPCTX),a0	| pointer to FP save area
   1761 	tstb	a0@			| null state frame?
   1762 	jeq	Lresfprest		| yes, easy
   1763 #if defined(HP380)
   1764 	cmpl	#-2,_mmutype		| 68040?
   1765 	jne	Lresnot040		| no, skip
   1766 	clrl	sp@-			| yes...
   1767 	frestore sp@+			| ...magic!
   1768 Lresnot040:
   1769 #endif
   1770 	fmovem	a0@(312),fpcr/fpsr/fpi	| restore FP control registers
   1771 	fmovem	a0@(216),fp0-fp7	| restore FP general registers
   1772 Lresfprest:
   1773 	frestore a0@			| restore state
   1774 #endif
   1775 	movw	a1@(PCB_PS),sr		| no, restore PS
   1776 	moveq	#1,d0			| return 1 (for alternate returns)
   1777 	rts
   1778 
   1779 /*
   1780  * savectx(pcb, altreturn)
   1781  * Update pcb, saving current processor state and arranging
   1782  * for alternate return ala longjmp in switch if altreturn is true.
   1783  */
   1784 ENTRY(savectx)
   1785 	movl	sp@(4),a1
   1786 	movw	sr,a1@(PCB_PS)
   1787 	movl	usp,a0			| grab USP
   1788 	movl	a0,a1@(PCB_USP)		| and save it
   1789 	moveml	#0xFCFC,a1@(PCB_REGS)	| save non-scratch registers
   1790 #ifdef FPCOPROC
   1791 	lea	a1@(PCB_FPCTX),a0	| pointer to FP save area
   1792 	fsave	a0@			| save FP state
   1793 	tstb	a0@			| null state frame?
   1794 	jeq	Lsvnofpsave		| yes, all done
   1795 	fmovem	fp0-fp7,a0@(216)	| save FP general registers
   1796 	fmovem	fpcr/fpsr/fpi,a0@(312)	| save FP control registers
   1797 Lsvnofpsave:
   1798 #endif
   1799 	tstl	sp@(8)			| altreturn?
   1800 	jeq	Lsavedone
   1801 	movl	sp,d0			| relocate current sp relative to a1
   1802 	subl	#_kstack,d0		|   (sp is relative to kstack):
   1803 	addl	d0,a1			|   a1 += sp - kstack;
   1804 	movl	sp@,a1@			| write return pc at (relocated) sp@
   1805 Lsavedone:
   1806 	moveq	#0,d0			| return 0
   1807 	rts
   1808 
   1809 /*
   1810  * {fu,su},{byte,sword,word}
   1811  */
   1812 ALTENTRY(fuiword, _fuword)
   1813 ENTRY(fuword)
   1814 	movl	sp@(4),a0		| address to read
   1815 	movl	_curpcb,a1		| current pcb
   1816 	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
   1817 	movsl	a0@,d0			| do read from user space
   1818 	nop
   1819 	jra	Lfsdone
   1820 
   1821 ENTRY(fusword)
   1822 	movl	sp@(4),a0
   1823 	movl	_curpcb,a1		| current pcb
   1824 	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
   1825 	moveq	#0,d0
   1826 	movsw	a0@,d0			| do read from user space
   1827 	nop
   1828 	jra	Lfsdone
   1829 
   1830 /* Just like fusword, but tells trap code not to page in. */
   1831 ENTRY(fuswintr)
   1832 	movl	sp@(4),a0
   1833 	movl	_curpcb,a1
   1834 	movl	#_fswintr,a1@(PCB_ONFAULT)
   1835 	moveq	#0,d0
   1836 	movsw	a0@,d0
   1837 	nop
   1838 	jra	Lfsdone
   1839 
   1840 ALTENTRY(fuibyte, _fubyte)
   1841 ENTRY(fubyte)
   1842 	movl	sp@(4),a0		| address to read
   1843 	movl	_curpcb,a1		| current pcb
   1844 	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
   1845 	moveq	#0,d0
   1846 	movsb	a0@,d0			| do read from user space
   1847 	nop
   1848 	jra	Lfsdone
   1849 
   1850 Lfserr:
   1851 	moveq	#-1,d0			| error indicator
   1852 Lfsdone:
   1853 	clrl	a1@(PCB_ONFAULT) 	| clear fault address
   1854 	rts
   1855 
   1856 /* Just like Lfserr, but the address is different (& exported). */
   1857 	.globl	_fswintr
   1858 _fswintr:
   1859 	moveq	#-1,d0
   1860 	jra	Lfsdone
   1861 
   1862 
   1863 /*
   1864  * Write a longword in user instruction space.
   1865  * Largely the same as suword but with a final i-cache purge on those
   1866  * machines with split caches.
   1867  */
   1868 ENTRY(suiword)
   1869 	movl	sp@(4),a0		| address to write
   1870 	movl	sp@(8),d0		| value to put there
   1871 	movl	_curpcb,a1		| current pcb
   1872 	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
   1873 	movsl	d0,a0@			| do write to user space
   1874 	nop
   1875 	moveq	#0,d0			| indicate no fault
   1876 #if defined(HP380)
   1877 	cmpl	#-2,_mmutype		| 68040?
   1878 	jne	Lsuicpurge		| no, skip
   1879 	.word	0xf498			| cinva ic (XXX overkill)
   1880 	jra	Lfsdone
   1881 Lsuicpurge:
   1882 #endif
   1883 	movl	#IC_CLEAR,d1
   1884 	movc	d1,cacr			| invalidate i-cache
   1885 	jra	Lfsdone
   1886 
   1887 ENTRY(suword)
   1888 	movl	sp@(4),a0		| address to write
   1889 	movl	sp@(8),d0		| value to put there
   1890 	movl	_curpcb,a1		| current pcb
   1891 	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
   1892 	movsl	d0,a0@			| do write to user space
   1893 	nop
   1894 	moveq	#0,d0			| indicate no fault
   1895 	jra	Lfsdone
   1896 
   1897 ENTRY(susword)
   1898 	movl	sp@(4),a0		| address to write
   1899 	movw	sp@(10),d0		| value to put there
   1900 	movl	_curpcb,a1		| current pcb
   1901 	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
   1902 	movsw	d0,a0@			| do write to user space
   1903 	nop
   1904 	moveq	#0,d0			| indicate no fault
   1905 	jra	Lfsdone
   1906 
   1907 ENTRY(suswintr)
   1908 	movl	sp@(4),a0
   1909 	movw	sp@(10),d0
   1910 	movl	_curpcb,a1
   1911 	movl	#_fswintr,a1@(PCB_ONFAULT)
   1912 	movsw	d0,a0@
   1913 	nop
   1914 	moveq	#0,d0
   1915 	jra	Lfsdone
   1916 
   1917 ALTENTRY(suibyte, _subyte)
   1918 ENTRY(subyte)
   1919 	movl	sp@(4),a0		| address to write
   1920 	movb	sp@(11),d0		| value to put there
   1921 	movl	_curpcb,a1		| current pcb
   1922 	movl	#Lfserr,a1@(PCB_ONFAULT) | where to return to on a fault
   1923 	movsb	d0,a0@			| do write to user space
   1924 	nop
   1925 	moveq	#0,d0			| indicate no fault
   1926 	jra	Lfsdone
   1927 
   1928 #if defined(HP380)
   1929 ENTRY(suline)
   1930 	movl	sp@(4),a0		| address to write
   1931 	movl	_curpcb,a1		| current pcb
   1932 	movl	#Lslerr,a1@(PCB_ONFAULT) | where to return to on a fault
   1933 	movl	sp@(8),a1		| address of line
   1934 	movl	a1@+,d0			| get lword
   1935 	movsl	d0,a0@+			| put lword
   1936 	nop				| sync
   1937 	movl	a1@+,d0			| get lword
   1938 	movsl	d0,a0@+			| put lword
   1939 	nop				| sync
   1940 	movl	a1@+,d0			| get lword
   1941 	movsl	d0,a0@+			| put lword
   1942 	nop				| sync
   1943 	movl	a1@+,d0			| get lword
   1944 	movsl	d0,a0@+			| put lword
   1945 	nop				| sync
   1946 	moveq	#0,d0			| indicate no fault
   1947 	jra	Lsldone
   1948 Lslerr:
   1949 	moveq	#-1,d0
   1950 Lsldone:
   1951 	movl	_curpcb,a1		| current pcb
   1952 	clrl	a1@(PCB_ONFAULT) 	| clear fault address
   1953 	rts
   1954 #endif
   1955 
   1956 /*
   1957  * Invalidate entire TLB.
   1958  */
   1959 ENTRY(TBIA)
   1960 __TBIA:
   1961 #if defined(HP380)
   1962 	cmpl	#-2,_mmutype		| 68040?
   1963 	jne	Lmotommu3		| no, skip
   1964 	.word	0xf518			| yes, pflusha
   1965 	rts
   1966 Lmotommu3:
   1967 #endif
   1968 #if defined(HP330) || defined(HP360) || defined(HP370)
   1969 	tstl	_mmutype		| HP MMU?
   1970 	jeq	Lhpmmu6			| yes, skip
   1971 	pflusha				| flush entire TLB
   1972 #if defined(HP360) || defined(HP370)
   1973 	jpl	Lmc68851a		| 68851 implies no d-cache
   1974 	movl	#DC_CLEAR,d0
   1975 	movc	d0,cacr			| invalidate on-chip d-cache
   1976 Lmc68851a:
   1977 #endif
   1978 	rts
   1979 Lhpmmu6:
   1980 #endif
   1981 #if defined(HP320) || defined(HP350)
   1982 	MMUADDR(a0)
   1983 	movl	a0@(MMUTBINVAL),sp@-	| do not ask me, this
   1984 	addql	#4,sp			|   is how hpux does it
   1985 #ifdef DEBUG
   1986 	tstl	fullcflush
   1987 	jne	__DCIA			| XXX: invalidate entire cache
   1988 #endif
   1989 #endif
   1990 	rts
   1991 
   1992 /*
   1993  * Invalidate any TLB entry for given VA (TB Invalidate Single)
   1994  */
   1995 ENTRY(TBIS)
   1996 #ifdef DEBUG
   1997 	tstl	fulltflush		| being conservative?
   1998 	jne	__TBIA			| yes, flush entire TLB
   1999 #endif
   2000 #if defined(HP380)
   2001 	cmpl	#-2,_mmutype		| 68040?
   2002 	jne	Lmotommu4		| no, skip
   2003 	movl	sp@(4),a0
   2004 	movc	dfc,d1
   2005 	moveq	#1,d0			| user space
   2006 	movc	d0,dfc
   2007 	.word	0xf508			| pflush a0@
   2008 	moveq	#5,d0			| super space
   2009 	movc	d0,dfc
   2010 	.word	0xf508			| pflush a0@
   2011 	movc	d1,dfc
   2012 	rts
   2013 Lmotommu4:
   2014 #endif
   2015 #if defined(HP330) || defined(HP360) || defined(HP370)
   2016 	tstl	_mmutype		| HP MMU?
   2017 	jeq	Lhpmmu5			| yes, skip
   2018 	movl	sp@(4),a0		| get addr to flush
   2019 #if defined(HP360) || defined(HP370)
   2020 	jpl	Lmc68851b		| is 68851?
   2021 	pflush	#0,#0,a0@		| flush address from both sides
   2022 	movl	#DC_CLEAR,d0
   2023 	movc	d0,cacr			| invalidate on-chip data cache
   2024 	rts
   2025 Lmc68851b:
   2026 #endif
   2027 	pflushs	#0,#0,a0@		| flush address from both sides
   2028 	rts
   2029 Lhpmmu5:
   2030 #endif
   2031 #if defined(HP320) || defined(HP350)
   2032 	movl	sp@(4),d0		| VA to invalidate
   2033 	bclr	#0,d0			| ensure even
   2034 	movl	d0,a0
   2035 	movw	sr,d1			| go critical
   2036 	movw	#PSL_HIGHIPL,sr		|   while in purge space
   2037 	moveq	#FC_PURGE,d0		| change address space
   2038 	movc	d0,dfc			|   for destination
   2039 	moveq	#0,d0			| zero to invalidate?
   2040 	movsl	d0,a0@			| hit it
   2041 	moveq	#FC_USERD,d0		| back to old
   2042 	movc	d0,dfc			|   address space
   2043 	movw	d1,sr			| restore IPL
   2044 #endif
   2045 	rts
   2046 
   2047 /*
   2048  * Invalidate supervisor side of TLB
   2049  */
   2050 ENTRY(TBIAS)
   2051 #ifdef DEBUG
   2052 	tstl	fulltflush		| being conservative?
   2053 	jne	__TBIA			| yes, flush everything
   2054 #endif
   2055 #if defined(HP380)
   2056 	cmpl	#-2,_mmutype		| 68040?
   2057 	jne	Lmotommu5		| no, skip
   2058 	.word	0xf518			| yes, pflusha (for now) XXX
   2059 	rts
   2060 Lmotommu5:
   2061 #endif
   2062 #if defined(HP330) || defined(HP360) || defined(HP370)
   2063 	tstl	_mmutype		| HP MMU?
   2064 	jeq	Lhpmmu7			| yes, skip
   2065 #if defined(HP360) || defined(HP370)
   2066 	jpl	Lmc68851c		| 68851?
   2067 	pflush #4,#4			| flush supervisor TLB entries
   2068 	movl	#DC_CLEAR,d0
   2069 	movc	d0,cacr			| invalidate on-chip d-cache
   2070 	rts
   2071 Lmc68851c:
   2072 #endif
   2073 	pflushs #4,#4			| flush supervisor TLB entries
   2074 	rts
   2075 Lhpmmu7:
   2076 #endif
   2077 #if defined(HP320) || defined(HP350)
   2078 	MMUADDR(a0)
   2079 	movl	#0x8000,d0		| more
   2080 	movl	d0,a0@(MMUTBINVAL)	|   HP magic
   2081 #ifdef DEBUG
   2082 	tstl	fullcflush
   2083 	jne	__DCIS			| XXX: invalidate entire sup. cache
   2084 #endif
   2085 #endif
   2086 	rts
   2087 
   2088 /*
   2089  * Invalidate user side of TLB
   2090  */
   2091 ENTRY(TBIAU)
   2092 #ifdef DEBUG
   2093 	tstl	fulltflush		| being conservative?
   2094 	jne	__TBIA			| yes, flush everything
   2095 #endif
   2096 #if defined(HP380)
   2097 	cmpl	#-2,_mmutype		| 68040?
   2098 	jne	Lmotommu6		| no, skip
   2099 	.word	0xf518			| yes, pflusha (for now) XXX
   2100 	rts
   2101 Lmotommu6:
   2102 #endif
   2103 #if defined(HP330) || defined(HP360) || defined(HP370)
   2104 	tstl	_mmutype		| HP MMU?
   2105 	jeq	Lhpmmu8			| yes, skip
   2106 #if defined(HP360) || defined(HP370)
   2107 	jpl	Lmc68851d		| 68851?
   2108 	pflush	#0,#4			| flush user TLB entries
   2109 	movl	#DC_CLEAR,d0
   2110 	movc	d0,cacr			| invalidate on-chip d-cache
   2111 	rts
   2112 Lmc68851d:
   2113 #endif
   2114 	pflushs	#0,#4			| flush user TLB entries
   2115 	rts
   2116 Lhpmmu8:
   2117 #endif
   2118 #if defined(HP320) || defined(HP350)
   2119 	MMUADDR(a0)
   2120 	moveq	#0,d0			| more
   2121 	movl	d0,a0@(MMUTBINVAL)	|   HP magic
   2122 #ifdef DEBUG
   2123 	tstl	fullcflush
   2124 	jne	__DCIU			| XXX: invalidate entire user cache
   2125 #endif
   2126 #endif
   2127 	rts
   2128 
   2129 /*
   2130  * Invalidate instruction cache
   2131  */
   2132 ENTRY(ICIA)
   2133 #if defined(HP380)
   2134 ENTRY(ICPA)
   2135 	cmpl	#-2,_mmutype		| 68040
   2136 	jne	Lmotommu7		| no, skip
   2137 	.word	0xf498			| cinva ic
   2138 	rts
   2139 Lmotommu7:
   2140 #endif
   2141 	movl	#IC_CLEAR,d0
   2142 	movc	d0,cacr			| invalidate i-cache
   2143 	rts
   2144 
   2145 /*
   2146  * Invalidate data cache.
   2147  * HP external cache allows for invalidation of user/supervisor portions.
   2148  * NOTE: we do not flush 68030 on-chip cache as there are no aliasing
   2149  * problems with DC_WA.  The only cases we have to worry about are context
   2150  * switch and TLB changes, both of which are handled "in-line" in resume
   2151  * and TBI*.
   2152  */
   2153 ENTRY(DCIA)
   2154 __DCIA:
   2155 #if defined(HP380)
   2156 	cmpl	#-2,_mmutype		| 68040
   2157 	jne	Lmotommu8		| no, skip
   2158 	/* XXX implement */
   2159 	rts
   2160 Lmotommu8:
   2161 #endif
   2162 #if defined(HP320) || defined(HP350)
   2163 	tstl	_ectype			| got external VAC?
   2164 	jle	Lnocache2		| no, all done
   2165 	MMUADDR(a0)
   2166 	andl	#~MMU_CEN,a0@(MMUCMD)	| disable cache in MMU control reg
   2167 	orl	#MMU_CEN,a0@(MMUCMD)	| reenable cache in MMU control reg
   2168 Lnocache2:
   2169 #endif
   2170 	rts
   2171 
   2172 ENTRY(DCIS)
   2173 __DCIS:
   2174 #if defined(HP380)
   2175 	cmpl	#-2,_mmutype		| 68040
   2176 	jne	Lmotommu9		| no, skip
   2177 	/* XXX implement */
   2178 	rts
   2179 Lmotommu9:
   2180 #endif
   2181 #if defined(HP320) || defined(HP350)
   2182 	tstl	_ectype			| got external VAC?
   2183 	jle	Lnocache3		| no, all done
   2184 	MMUADDR(a0)
   2185 	movl	a0@(MMUSSTP),d0		| read the supervisor STP
   2186 	movl	d0,a0@(MMUSSTP)		| write it back
   2187 Lnocache3:
   2188 #endif
   2189 	rts
   2190 
   2191 ENTRY(DCIU)
   2192 __DCIU:
   2193 #if defined(HP380)
   2194 	cmpl	#-2,_mmutype		| 68040
   2195 	jne	LmotommuA		| no, skip
   2196 	/* XXX implement */
   2197 	rts
   2198 LmotommuA:
   2199 #endif
   2200 #if defined(HP320) || defined(HP350)
   2201 	tstl	_ectype			| got external VAC?
   2202 	jle	Lnocache4		| no, all done
   2203 	MMUADDR(a0)
   2204 	movl	a0@(MMUUSTP),d0		| read the user STP
   2205 	movl	d0,a0@(MMUUSTP)		| write it back
   2206 Lnocache4:
   2207 #endif
   2208 	rts
   2209 
   2210 #if defined(HP380)
   2211 ENTRY(ICPL)
   2212 	movl	sp@(4),a0		| address
   2213 	.word	0xf488			| cinvl ic,a0@
   2214 	rts
   2215 ENTRY(ICPP)
   2216 	movl	sp@(4),a0		| address
   2217 	.word	0xf490			| cinvp ic,a0@
   2218 	rts
   2219 ENTRY(DCPL)
   2220 	movl	sp@(4),a0		| address
   2221 	.word	0xf448			| cinvl dc,a0@
   2222 	rts
   2223 ENTRY(DCPP)
   2224 	movl	sp@(4),a0		| address
   2225 	.word	0xf450			| cinvp dc,a0@
   2226 	rts
   2227 ENTRY(DCPA)
   2228 	.word	0xf458			| cinva dc
   2229 	rts
   2230 ENTRY(DCFL)
   2231 	movl	sp@(4),a0		| address
   2232 	.word	0xf468			| cpushl dc,a0@
   2233 	rts
   2234 ENTRY(DCFP)
   2235 	movl	sp@(4),a0		| address
   2236 	.word	0xf470			| cpushp dc,a0@
   2237 	rts
   2238 #endif
   2239 
   2240 ENTRY(PCIA)
   2241 #if defined(HP380)
   2242 ENTRY(DCFA)
   2243 	cmpl	#-2,_mmutype		| 68040
   2244 	jne	LmotommuB		| no, skip
   2245 	.word	0xf478			| cpusha dc
   2246 	rts
   2247 LmotommuB:
   2248 #endif
   2249 #if defined(HP360) || defined(HP370)
   2250 	movl	#DC_CLEAR,d0
   2251 	movc	d0,cacr			| invalidate on-chip d-cache
   2252 	tstl	_ectype			| got external PAC?
   2253 	jge	Lnocache6		| no, all done
   2254 	MMUADDR(a0)
   2255 	andl	#~MMU_CEN,a0@(MMUCMD)	| disable cache in MMU control reg
   2256 	orl	#MMU_CEN,a0@(MMUCMD)	| reenable cache in MMU control reg
   2257 Lnocache6:
   2258 #endif
   2259 	rts
   2260 
   2261 ENTRY(ecacheon)
   2262 	tstl	_ectype
   2263 	jeq	Lnocache7
   2264 	MMUADDR(a0)
   2265 	orl	#MMU_CEN,a0@(MMUCMD)
   2266 Lnocache7:
   2267 	rts
   2268 
   2269 ENTRY(ecacheoff)
   2270 	tstl	_ectype
   2271 	jeq	Lnocache8
   2272 	MMUADDR(a0)
   2273 	andl	#~MMU_CEN,a0@(MMUCMD)
   2274 Lnocache8:
   2275 	rts
   2276 
   2277 /*
   2278  * Get callers current SP value.
   2279  * Note that simply taking the address of a local variable in a C function
   2280  * doesn't work because callee saved registers may be outside the stack frame
   2281  * defined by A6 (e.g. GCC generated code).
   2282  */
   2283 	.globl	_getsp
   2284 _getsp:
   2285 	movl	sp,d0			| get current SP
   2286 	addql	#4,d0			| compensate for return address
   2287 	rts
   2288 
   2289 	.globl	_getsfc, _getdfc
   2290 _getsfc:
   2291 	movc	sfc,d0
   2292 	rts
   2293 _getdfc:
   2294 	movc	dfc,d0
   2295 	rts
   2296 
   2297 /*
   2298  * Load a new user segment table pointer.
   2299  */
   2300 ENTRY(loadustp)
   2301 #if defined(HP330) || defined(HP360) || defined(HP370) || defined(HP380)
   2302 	tstl	_mmutype		| HP MMU?
   2303 	jeq	Lhpmmu9			| yes, skip
   2304 	movl	sp@(4),d0		| new USTP
   2305 	moveq	#PGSHIFT,d1
   2306 	lsll	d1,d0			| convert to addr
   2307 #if defined(HP380)
   2308 	cmpl	#-2,_mmutype		| 68040?
   2309 	jne	LmotommuC		| no, skip
   2310 	.long	0x4e7b0806		| movc d0,urp
   2311 	rts
   2312 LmotommuC:
   2313 #endif
   2314 	lea	_protorp,a0		| CRP prototype
   2315 	movl	d0,a0@(4)		| stash USTP
   2316 	pmove	a0@,crp			| load root pointer
   2317 	movl	#DC_CLEAR,d0
   2318 	movc	d0,cacr			| invalidate on-chip d-cache
   2319 	rts				|   since pmove flushes TLB
   2320 Lhpmmu9:
   2321 #endif
   2322 #if defined(HP320) || defined(HP350)
   2323 	MMUADDR(a0)
   2324 	movl	sp@(4),a0@(MMUUSTP)	| load a new USTP
   2325 #endif
   2326 	rts
   2327 
   2328 ENTRY(ploadw)
   2329 #if defined(HP330) || defined(HP360) || defined(HP370)
   2330 	movl	sp@(4),a0		| address to load
   2331 	ploadw	#1,a0@			| pre-load translation
   2332 #endif
   2333 	rts
   2334 
   2335 /*
   2336  * Set processor priority level calls.  Most are implemented with
   2337  * inline asm expansions.  However, spl0 requires special handling
   2338  * as we need to check for our emulated software interrupts.
   2339  */
   2340 
   2341 ENTRY(spl0)
   2342 	moveq	#0,d0
   2343 	movw	sr,d0			| get old SR for return
   2344 	movw	#PSL_LOWIPL,sr		| restore new SR
   2345 	tstb	_ssir			| software interrupt pending?
   2346 	jeq	Lspldone		| no, all done
   2347 	subql	#4,sp			| make room for RTE frame
   2348 	movl	sp@(4),sp@(2)		| position return address
   2349 	clrw	sp@(6)			| set frame type 0
   2350 	movw	#PSL_LOWIPL,sp@		| and new SR
   2351 	jra	Lgotsir			| go handle it
   2352 Lspldone:
   2353 	rts
   2354 
   2355 ENTRY(_insque)
   2356 	movw	sr,d0
   2357 	movw	#PSL_HIGHIPL,sr		| atomic
   2358 	movl	sp@(8),a0		| where to insert (after)
   2359 	movl	sp@(4),a1		| element to insert (e)
   2360 	movl	a0@,a1@			| e->next = after->next
   2361 	movl	a0,a1@(4)		| e->prev = after
   2362 	movl	a1,a0@			| after->next = e
   2363 	movl	a1@,a0
   2364 	movl	a1,a0@(4)		| e->next->prev = e
   2365 	movw	d0,sr
   2366 	rts
   2367 
   2368 ENTRY(_remque)
   2369 	movw	sr,d0
   2370 	movw	#PSL_HIGHIPL,sr		| atomic
   2371 	movl	sp@(4),a0		| element to remove (e)
   2372 	movl	a0@,a1
   2373 	movl	a0@(4),a0
   2374 	movl	a0,a1@(4)		| e->next->prev = e->prev
   2375 	movl	a1,a0@			| e->prev->next = e->next
   2376 	movw	d0,sr
   2377 	rts
   2378 
   2379 /*
   2380  * bzero(addr, count)
   2381  */
   2382 ALTENTRY(blkclr, _bzero)
   2383 ENTRY(bzero)
   2384 	movl	sp@(4),a0	| address
   2385 	movl	sp@(8),d0	| count
   2386 	jeq	Lbzdone		| if zero, nothing to do
   2387 	movl	a0,d1
   2388 	btst	#0,d1		| address odd?
   2389 	jeq	Lbzeven		| no, can copy words
   2390 	clrb	a0@+		| yes, zero byte to get to even boundary
   2391 	subql	#1,d0		| decrement count
   2392 	jeq	Lbzdone		| none left, all done
   2393 Lbzeven:
   2394 	movl	d0,d1
   2395 	andl	#31,d0
   2396 	lsrl	#5,d1		| convert count to 8*longword count
   2397 	jeq	Lbzbyte		| no such blocks, zero byte at a time
   2398 Lbzloop:
   2399 	clrl	a0@+; clrl	a0@+; clrl	a0@+; clrl	a0@+;
   2400 	clrl	a0@+; clrl	a0@+; clrl	a0@+; clrl	a0@+;
   2401 	subql	#1,d1		| one more block zeroed
   2402 	jne	Lbzloop		| more to go, do it
   2403 	tstl	d0		| partial block left?
   2404 	jeq	Lbzdone		| no, all done
   2405 Lbzbyte:
   2406 	clrb	a0@+
   2407 	subql	#1,d0		| one more byte cleared
   2408 	jne	Lbzbyte		| more to go, do it
   2409 Lbzdone:
   2410 	rts
   2411 
   2412 /*
   2413  * strlen(str)
   2414  */
   2415 ENTRY(strlen)
   2416 	moveq	#-1,d0
   2417 	movl	sp@(4),a0	| string
   2418 Lslloop:
   2419 	addql	#1,d0		| increment count
   2420 	tstb	a0@+		| null?
   2421 	jne	Lslloop		| no, keep going
   2422 	rts
   2423 
   2424 /*
   2425  * bcmp(s1, s2, len)
   2426  *
   2427  * WARNING!  This guy only works with counts up to 64K
   2428  */
   2429 ENTRY(bcmp)
   2430 	movl	sp@(4),a0		| string 1
   2431 	movl	sp@(8),a1		| string 2
   2432 	moveq	#0,d0
   2433 	movw	sp@(14),d0		| length
   2434 	jeq	Lcmpdone		| if zero, nothing to do
   2435 	subqw	#1,d0			| set up for DBcc loop
   2436 Lcmploop:
   2437 	cmpmb	a0@+,a1@+		| equal?
   2438 	dbne	d0,Lcmploop		| yes, keep going
   2439 	addqw	#1,d0			| +1 gives zero on match
   2440 Lcmpdone:
   2441 	rts
   2442 
   2443 /*
   2444  * {ov}bcopy(from, to, len)
   2445  *
   2446  * Works for counts up to 128K.
   2447  */
   2448 ALTENTRY(ovbcopy, _bcopy)
   2449 ENTRY(bcopy)
   2450 	movl	sp@(12),d0		| get count
   2451 	jeq	Lcpyexit		| if zero, return
   2452 	movl	sp@(4),a0		| src address
   2453 	movl	sp@(8),a1		| dest address
   2454 	cmpl	a1,a0			| src before dest?
   2455 	jlt	Lcpyback		| yes, copy backwards (avoids overlap)
   2456 	movl	a0,d1
   2457 	btst	#0,d1			| src address odd?
   2458 	jeq	Lcfeven			| no, go check dest
   2459 	movb	a0@+,a1@+		| yes, copy a byte
   2460 	subql	#1,d0			| update count
   2461 	jeq	Lcpyexit		| exit if done
   2462 Lcfeven:
   2463 	movl	a1,d1
   2464 	btst	#0,d1			| dest address odd?
   2465 	jne	Lcfbyte			| yes, must copy by bytes
   2466 	movl	d0,d1			| no, get count
   2467 	lsrl	#2,d1			| convert to longwords
   2468 	jeq	Lcfbyte			| no longwords, copy bytes
   2469 	subql	#1,d1			| set up for dbf
   2470 Lcflloop:
   2471 	movl	a0@+,a1@+		| copy longwords
   2472 	dbf	d1,Lcflloop		| til done
   2473 	andl	#3,d0			| get remaining count
   2474 	jeq	Lcpyexit		| done if none
   2475 Lcfbyte:
   2476 	subql	#1,d0			| set up for dbf
   2477 Lcfbloop:
   2478 	movb	a0@+,a1@+		| copy bytes
   2479 	dbf	d0,Lcfbloop		| til done
   2480 Lcpyexit:
   2481 	rts
   2482 Lcpyback:
   2483 	addl	d0,a0			| add count to src
   2484 	addl	d0,a1			| add count to dest
   2485 	movl	a0,d1
   2486 	btst	#0,d1			| src address odd?
   2487 	jeq	Lcbeven			| no, go check dest
   2488 	movb	a0@-,a1@-		| yes, copy a byte
   2489 	subql	#1,d0			| update count
   2490 	jeq	Lcpyexit		| exit if done
   2491 Lcbeven:
   2492 	movl	a1,d1
   2493 	btst	#0,d1			| dest address odd?
   2494 	jne	Lcbbyte			| yes, must copy by bytes
   2495 	movl	d0,d1			| no, get count
   2496 	lsrl	#2,d1			| convert to longwords
   2497 	jeq	Lcbbyte			| no longwords, copy bytes
   2498 	subql	#1,d1			| set up for dbf
   2499 Lcblloop:
   2500 	movl	a0@-,a1@-		| copy longwords
   2501 	dbf	d1,Lcblloop		| til done
   2502 	andl	#3,d0			| get remaining count
   2503 	jeq	Lcpyexit		| done if none
   2504 Lcbbyte:
   2505 	subql	#1,d0			| set up for dbf
   2506 Lcbbloop:
   2507 	movb	a0@-,a1@-		| copy bytes
   2508 	dbf	d0,Lcbbloop		| til done
   2509 	rts
   2510 
   2511 /*
   2512  * Emulate fancy VAX string operations:
   2513  *	scanc(count, startc, table, mask)
   2514  *	skpc(mask, count, startc)
   2515  *	locc(mask, count, startc)
   2516  */
   2517 ENTRY(scanc)
   2518 	movl	sp@(4),d0	| get length
   2519 	jeq	Lscdone		| nothing to do, return
   2520 	movl	sp@(8),a0	| start of scan
   2521 	movl	sp@(12),a1	| table to compare with
   2522 	movb	sp@(19),d1	| and mask to use
   2523 	movw	d2,sp@-		| need a scratch register
   2524 	clrw	d2		| clear it out
   2525 	subqw	#1,d0		| adjust for dbra
   2526 Lscloop:
   2527 	movb	a0@+,d2		| get character
   2528 	movb	a1@(0,d2:w),d2	| get table entry
   2529 	andb	d1,d2		| mask it
   2530 	dbne	d0,Lscloop	| keep going til no more or non-zero
   2531 	addqw	#1,d0		| overshot by one
   2532 	movw	sp@+,d2		| restore scratch
   2533 Lscdone:
   2534 	rts
   2535 
   2536 ENTRY(skpc)
   2537 	movl	sp@(8),d0	| get length
   2538 	jeq	Lskdone		| nothing to do, return
   2539 	movb	sp@(7),d1	| mask to use
   2540 	movl	sp@(12),a0	| where to start
   2541 	subqw	#1,d0		| adjust for dbcc
   2542 Lskloop:
   2543 	cmpb	a0@+,d1		| compate with mask
   2544 	dbne	d0,Lskloop	| keep going til no more or zero
   2545 	addqw	#1,d0		| overshot by one
   2546 Lskdone:
   2547 	rts
   2548 
   2549 ENTRY(locc)
   2550 	movl	sp@(8),d0	| get length
   2551 	jeq	Llcdone		| nothing to do, return
   2552 	movb	sp@(7),d1	| mask to use
   2553 	movl	sp@(12),a0	| where to start
   2554 	subqw	#1,d0		| adjust for dbcc
   2555 Llcloop:
   2556 	cmpb	a0@+,d1		| compate with mask
   2557 	dbeq	d0,Llcloop	| keep going til no more or non-zero
   2558 	addqw	#1,d0		| overshot by one
   2559 Llcdone:
   2560 	rts
   2561 
   2562 /*
   2563  * Emulate VAX FFS (find first set) instruction.
   2564  */
   2565 ENTRY(ffs)
   2566 	moveq	#-1,d0
   2567 	movl	sp@(4),d1
   2568 	jeq	Lffsdone
   2569 Lffsloop:
   2570 	addql	#1,d0
   2571 	btst	d0,d1
   2572 	jeq	Lffsloop
   2573 Lffsdone:
   2574 	addql	#1,d0
   2575 	rts
   2576 
   2577 #ifdef FPCOPROC
   2578 /*
   2579  * Save and restore 68881 state.
   2580  * Pretty awful looking since our assembler does not
   2581  * recognize FP mnemonics.
   2582  */
   2583 ENTRY(m68881_save)
   2584 	movl	sp@(4),a0		| save area pointer
   2585 	fsave	a0@			| save state
   2586 	tstb	a0@			| null state frame?
   2587 	jeq	Lm68881sdone		| yes, all done
   2588 	fmovem fp0-fp7,a0@(216)		| save FP general registers
   2589 	fmovem fpcr/fpsr/fpi,a0@(312)	| save FP control registers
   2590 Lm68881sdone:
   2591 	rts
   2592 
   2593 ENTRY(m68881_restore)
   2594 	movl	sp@(4),a0		| save area pointer
   2595 	tstb	a0@			| null state frame?
   2596 	jeq	Lm68881rdone		| yes, easy
   2597 	fmovem	a0@(312),fpcr/fpsr/fpi	| restore FP control registers
   2598 	fmovem	a0@(216),fp0-fp7	| restore FP general registers
   2599 Lm68881rdone:
   2600 	frestore a0@			| restore state
   2601 	rts
   2602 #endif
   2603 
   2604 /*
   2605  * Handle the nitty-gritty of rebooting the machine.
   2606  * Basically we just turn off the MMU and jump to the appropriate ROM routine.
   2607  * Note that we must be running in an address range that is mapped one-to-one
   2608  * logical to physical so that the PC is still valid immediately after the MMU
   2609  * is turned off.  We have conveniently mapped the last page of physical
   2610  * memory this way.
   2611  */
   2612 	.globl	_doboot
   2613 _doboot:
   2614 #if defined(HP380)
   2615 	cmpl	#-2,_mmutype		| 68040?
   2616 	jeq	Lnocache5		| yes, skip
   2617 #endif
   2618 	movl	#CACHE_OFF,d0
   2619 	movc	d0,cacr			| disable on-chip cache(s)
   2620 #if defined(HP320) || defined(HP350) || defined(HP370)
   2621 	tstl	_ectype
   2622 	jeq	Lnocache5
   2623 	MMUADDR(a0)
   2624 	andl	#~MMU_CEN,a0@(MMUCMD)	| disable external cache
   2625 #endif
   2626 Lnocache5:
   2627 	lea	MAXADDR,a0		| last page of physical memory
   2628 	movl	_boothowto,a0@+		| store howto
   2629 	movl	_bootdev,a0@+		| and devtype
   2630 	lea	Lbootcode,a1		| start of boot code
   2631 	lea	Lebootcode,a3		| end of boot code
   2632 Lbootcopy:
   2633 	movw	a1@+,a0@+		| copy a word
   2634 	cmpl	a3,a1			| done yet?
   2635 	jcs	Lbootcopy		| no, keep going
   2636 #if defined(HP380)
   2637 	cmpl	#-2,_mmutype		| 68040?
   2638 	jne	LmotommuE		| no, skip
   2639 	.word	0xf4f8			| cpusha bc
   2640 LmotommuE:
   2641 #endif
   2642 	jmp	MAXADDR+8		| jump to last page
   2643 
   2644 Lbootcode:
   2645 	lea	MAXADDR+0x800,sp	| physical SP in case of NMI
   2646 #if defined(HP380)
   2647 	cmpl	#-2,_mmutype		| 68040?
   2648 	jne	LmotommuF		| no, skip
   2649 	movl	#0,d0
   2650 	movc	d0,cacr			| caches off
   2651 	.long	0x4e7b0003		| movc d0,tc
   2652 	movl	d2,MAXADDR+NBPG-4	| restore old high page contents
   2653 	jmp	0x1A4			| goto REQ_REBOOT
   2654 LmotommuF:
   2655 #endif
   2656 #if defined(HP330) || defined(HP360) || defined(HP370)
   2657 	tstl	_mmutype		| HP MMU?
   2658 	jeq	LhpmmuB			| yes, skip
   2659 	movl	#0,a0@			| value for pmove to TC (turn off MMU)
   2660 	pmove	a0@,tc			| disable MMU
   2661 	jmp	0x1A4			| goto REQ_REBOOT
   2662 LhpmmuB:
   2663 #endif
   2664 #if defined(HP320) || defined(HP350)
   2665 	MMUADDR(a0)
   2666 	movl	#0xFFFF0000,a0@(MMUCMD)	| totally disable MMU
   2667 	movl	d2,MAXADDR+NBPG-4	| restore old high page contents
   2668 	jmp	0x1A4			| goto REQ_REBOOT
   2669 #endif
   2670 Lebootcode:
   2671 
   2672 	.data
   2673 	.globl	_machineid
   2674 _machineid:
   2675 	.long	0		| default to 320
   2676 	.globl	_mmutype,_protorp
   2677 _mmutype:
   2678 	.long	0		| default to HP MMU
   2679 _protorp:
   2680 	.long	0,0		| prototype root pointer
   2681 	.globl	_ectype
   2682 _ectype:
   2683 	.long	0		| external cache type, default to none
   2684 	.globl	_internalhpib
   2685 _internalhpib:
   2686 	.long	1		| has internal HP-IB, default to yes
   2687 	.globl	_cold
   2688 _cold:
   2689 	.long	1		| cold start flag
   2690 	.globl	_want_resched
   2691 _want_resched:
   2692 	.long	0
   2693 	.globl	_intiobase, _intiolimit, _extiobase, _CLKbase, _MMUbase
   2694 	.globl	_proc0paddr
   2695 _proc0paddr:
   2696 	.long	0		| KVA of proc0 u-area
   2697 _intiobase:
   2698 	.long	0		| KVA of base of internal IO space
   2699 _intiolimit:
   2700 	.long	0		| KVA of end of internal IO space
   2701 _extiobase:
   2702 	.long	0		| KVA of base of external IO space
   2703 _CLKbase:
   2704 	.long	0		| KVA of base of clock registers
   2705 _MMUbase:
   2706 	.long	0		| KVA of base of HP MMU registers
   2707 #ifdef USELEDS
   2708 heartbeat:
   2709 	.long	0		| clock ticks since last pulse of heartbeat
   2710 #endif
   2711 #ifdef DEBUG
   2712 	.globl	fulltflush, fullcflush
   2713 fulltflush:
   2714 	.long	0
   2715 fullcflush:
   2716 	.long	0
   2717 #endif
   2718 #ifdef HPFPLIB
   2719 /*
   2720  * Undefined symbols from hpux_float.o:
   2721  *
   2722  * kdb_printf:	A kernel debugger print routine, we just use printf instead.
   2723  * processor:	HP-UX equiv. of machineid, set to 3 if it is a 68040.
   2724  * u:		Ye ole u-area.  The code wants to grab the first longword
   2725  *		indirect off of that and clear the 0x40000 bit there.
   2726  *		Oddly enough this was incorrect even in HP-UX!
   2727  * runrun:	Old name for want_resched.
   2728  */
   2729 	.globl	_kdb_printf,_processor,_u,_runrun
   2730 _kdb_printf:
   2731 	.long	_printf
   2732 _processor:
   2733 	.long	0
   2734 _u:
   2735 	.long	.+4
   2736 	.long	0
   2737 	.set	_runrun,_want_resched
   2738 #endif
   2739 /* interrupt counters */
   2740 	.globl	_intrcnt,_eintrcnt,_intrnames,_eintrnames
   2741 _intrnames:
   2742 	.asciz	"spur"
   2743 	.asciz	"hil"
   2744 	.asciz	"lev2"
   2745 	.asciz	"lev3"
   2746 	.asciz	"lev4"
   2747 	.asciz	"lev5"
   2748 	.asciz	"dma"
   2749 	.asciz	"clock"
   2750 	.asciz  "statclock"
   2751 	.asciz	"nmi"
   2752 _eintrnames:
   2753 	.even
   2754 _intrcnt:
   2755 	.long	0,0,0,0,0,0,0,0,0,0
   2756 _eintrcnt:
   2757