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