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