xref: /openbsd/sys/arch/m88k/m88k/subr.S (revision 0ef4c01d)
1/* $OpenBSD: subr.S,v 1.32 2024/03/08 16:18:53 miod Exp $	*/
2/*
3 * Mach Operating System
4 * Copyright (c) 1993-1992 Carnegie Mellon University
5 * Copyright (c) 1991 OMRON Corporation
6 * Copyright (c) 1996 Nivas Madhur
7 * Copyright (c) 1998 Steve Murphree, Jr.
8 * All Rights Reserved.
9 *
10 * Permission to use, copy, modify and distribute this software and its
11 * documentation is hereby granted, provided that both the copyright
12 * notice and this permission notice appear in all copies of the
13 * software, derivative works or modified versions, and any portions
14 * thereof, and that both notices appear in supporting documentation.
15 *
16 * CARNEGIE MELLON AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17 * CONDITION.  CARNEGIE MELLON AND OMRON DISCLAIM ANY LIABILITY OF ANY KIND
18 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19 *
20 * Carnegie Mellon requests users of this software to return to
21 *
22 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
23 *  School of Computer Science
24 *  Carnegie Mellon University
25 *  Pittsburgh PA 15213-3890
26 *
27 * any improvements or extensions that they make and grant Carnegie the
28 * rights to redistribute these changes.
29 */
30
31#include "assym.h"
32
33#include <sys/errno.h>
34
35#include <machine/param.h>
36#include <machine/asm.h>
37#include <machine/psl.h>
38#include <machine/trap.h>
39
40#ifdef	M88100
41
42/*
43 * DO_LOAD_ADDRESS
44 *
45 * 	unsigned int do_load_word(address, supervisor_mode)
46 *		vaddr_t address;		\\ in r2
47 *		boolean_t supervisor_mode;	\\ in r3
48 *
49 * Return the word at ADDRESS (from user space if SUPERVISOR_MODE is zero,
50 * supervisor space if non-zero).
51 *
52 */
53
54ENTRY(do_load_word)	/* do_load_word(address, supervisor) */
55	bcnd	ne0,%r3,1f
56#ifdef ERRATA__XXX_USR
57	NOP
58	ld.usr	%r2,%r2,%r0
59	NOP
60	NOP
61	NOP
62	jmp	%r1
63#else
64	jmp.n	%r1
65	 ld.usr	%r2,%r2,%r0
66#endif
671:	jmp.n	%r1
68	 ld	%r2,%r2,%r0
69
70ENTRY(do_load_half)	/* do_load_half(address, supervisor) */
71	bcnd	ne0,%r3,1f
72#ifdef ERRATA__XXX_USR
73	NOP
74	ld.h.usr	%r2,%r2,%r0
75	NOP
76	NOP
77	NOP
78	jmp	%r1
79#else
80	jmp.n	%r1
81	 ld.h.usr	%r2,%r2,%r0
82#endif
831:	jmp.n	%r1
84	 ld.h	%r2,%r2,%r0
85
86ENTRY(do_load_byte)	/* do_load_byte(address, supervisor) */
87	bcnd	ne0,%r3,1f
88#ifdef ERRATA__XXX_USR
89	NOP
90	ld.b.usr	%r2,%r2,%r0
91	NOP
92	NOP
93	NOP
94	jmp	%r1
95#else
96	jmp.n	%r1
97	 ld.b.usr	%r2,%r2,%r0
98#endif
991:	jmp.n	%r1
100	 ld.b	%r2,%r2,%r0
101
102ENTRY(do_store_word)	/* do_store_word(address, data, supervisor) */
103	bcnd	ne0,%r4,1f
104#ifdef ERRATA__XXX_USR
105	NOP
106	st.usr	%r3,%r2,%r0
107	NOP
108	NOP
109	NOP
110	jmp	%r1
111#else
112	jmp.n	%r1
113	 st.usr	%r3,%r2,%r0
114#endif
1151:	jmp.n	%r1
116	 st	%r3,%r2,%r0
117
118ENTRY(do_store_half)	/* do_store_half(address, data, supervisor) */
119	bcnd	ne0,%r4,1f
120#ifdef ERRATA__XXX_USR
121	NOP
122	st.h.usr	%r3,%r2,%r0
123	NOP
124	NOP
125	NOP
126	jmp	%r1
127#else
128	jmp.n	%r1
129	 st.h.usr	%r3,%r2,%r0
130#endif
1311:	jmp.n	%r1
132	 st.h	%r3,%r2,%r0
133
134ENTRY(do_store_byte)	/* do_store_byte(address, data, supervisor) */
135	bcnd	ne0,%r4,1f
136#ifdef ERRATA__XXX_USR
137	NOP
138	st.b.usr	%r3,%r2,%r0
139	NOP
140	NOP
141	NOP
142	jmp	%r1
143#else
144	jmp.n	%r1
145	 st.b.usr	%r3,%r2,%r0
146#endif
1471:	jmp.n	%r1
148	 st.b	%r3,%r2,%r0
149
150ENTRY(do_xmem_word)	/* do_xmem_word(address, data, supervisor) */
151	bcnd	ne0,%r4,1f
152#ifdef ERRATA__XXX_USR
153	NOP
154#endif
155	xmem.usr	%r3,%r2,%r0
156#ifdef ERRATA__XXX_USR
157	NOP
158	NOP
159	NOP
160#endif
161	jmp.n	%r1
162	 or	%r2, %r3, %r0
1631:	xmem	%r3,%r2,%r0
164	jmp.n	%r1
165	 or	%r2, %r3, %r0
166
167ENTRY(do_xmem_byte)	/* do_xmem_byte(address, data, supervisor) */
168	bcnd	ne0,%r4,1f
169#ifdef ERRATA__XXX_USR
170	NOP
171#endif
172	xmem.bu.usr	%r3,%r2,%r0
173#ifdef ERRATA__XXX_USR
174	NOP
175	NOP
176	NOP
177#endif
178	jmp.n	%r1
179	 or	%r2,%r3,%r0
1801:	xmem.bu	%r3,%r2,%r0
181	jmp.n	%r1
182	 or	%r2,%r3,%r0
183
184#endif	/* M88100 */
185
186/*
187 * Copy specified amount of data from user space into the kernel
188 * _copyin(from, to, len)
189 *	r2 == from (user source address)
190 *	r3 == to (kernel destination address)
191 *	r4 == length
192 */
193
194#define	SRC	%r2
195#define	DEST	%r3
196#define	LEN	%r4
197
198ENTRY(_copyin)
199	/* set up fault handler */
200	ldcr	%r5,  CPU
201	ld	%r6,  %r5,  CI_CURPCB
202	or.u	%r5,  %r0,  %hi16(Lciflt)
203	or	%r5,  %r5,  %lo16(Lciflt)
204	st	%r5,  %r6,  PCB_ONFAULT	/* pcb_onfault = Lciflt */
205
206	/*
207	 * If it's a small length (less than 8), then do byte-by-byte.
208	 * Despite not being optimal if len is 4, and from and to
209	 * are word-aligned, this is still faster than doing more tests
210	 * to save an hyperthetical fraction of cycle.
211	 */
212	cmp	%r9,  LEN,  8
213	bb1	lt,   %r9,  copyin_byte_only
214
215	/* If they're not aligned similarly, use byte only... */
216	xor	%r9,  SRC,  DEST
217	mask	%r8,  %r9,  0x3
218	bcnd	ne0,  %r8,  copyin_byte_only
219
220	/*
221	 * At this point, we don't know if they're word aligned or not,
222	 * but we know that what needs to be done to one to align
223	 * it is what's needed for the other.
224	 */
225	bb1	0,    SRC,  copyin_left_align_to_halfword
226ASLOCAL(copyin_left_aligned_to_halfword)
227	bb1	1,    SRC,  copyin_left_align_to_word
228ASLOCAL(copyin_left_aligned_to_word)
229	bb1	0,    LEN,  copyin_right_align_to_halfword
230ASLOCAL(copyin_right_aligned_to_halfword)
231	bb1	1,    LEN,  copyin_right_align_to_word
232ASLOCAL(copyin_right_aligned_to_word)
233
234	/*
235	 * At this point, both SRC and DEST are aligned to a word
236	 * boundary, and LEN is a multiple of 4. We want it an even
237	 * multiple of 4.
238	 */
239	bb1.n	2,    LEN,  copyin_right_align_to_doubleword
240	 or	%r7,  %r0,  4
241
242ASLOCAL(copyin_right_aligned_to_doubleword)
243#ifdef ERRATA__XXX_USR
244	NOP
245	ld.usr	%r5,  SRC,  %r0
246	NOP
247	NOP
248	NOP
249	ld.usr	%r6,  SRC,  %r7
250	NOP
251	NOP
252	NOP
253#else
254	ld.usr	%r5,  SRC,  %r0
255	ld.usr	%r6,  SRC,  %r7
256#endif
257	subu	LEN,  LEN,  8
258	st	%r5,  DEST, %r0
259	addu	SRC,  SRC,  8
260	st	%r6,  DEST, %r7
261	bcnd.n	ne0,  LEN,  copyin_right_aligned_to_doubleword
262	 addu	DEST, DEST, 8
263	br.n	Lcidone
264	 or	%r2, %r0, %r0	/* successful return */
265
266ASLOCAL(copyin_left_align_to_halfword)
267#ifdef ERRATA__XXX_USR
268	NOP
269	ld.b.usr	%r5,  SRC, %r0
270	NOP
271	NOP
272	NOP
273#else
274	ld.b.usr	%r5,  SRC, %r0
275#endif
276	subu	LEN,  LEN,  1
277	st.b	%r5,  DEST, %r0
278	addu	SRC,  SRC,  1
279	br.n	copyin_left_aligned_to_halfword
280	 addu	DEST, DEST, 1
281
282ASLOCAL(copyin_left_align_to_word)
283#ifdef ERRATA__XXX_USR
284	NOP
285	ld.h.usr	%r5,   SRC,  %r0
286	NOP
287	NOP
288	NOP
289#else
290	ld.h.usr	%r5,   SRC,  %r0
291#endif
292	subu	LEN,  LEN,  2
293	st.h	%r5,  DEST, %r0
294	addu	SRC,  SRC,  2
295	br.n	copyin_left_aligned_to_word
296	 addu	DEST, DEST, 2
297
298ASLOCAL(copyin_right_align_to_halfword)
299	subu	LEN,  LEN,  1
300#ifdef ERRATA__XXX_USR
301	NOP
302	ld.b.usr	%r5,  SRC, LEN
303	NOP
304	NOP
305	NOP
306#else
307	ld.b.usr	%r5,  SRC, LEN
308#endif
309	br.n	copyin_right_aligned_to_halfword
310	 st.b	%r5,  DEST, LEN
311
312ASLOCAL(copyin_right_align_to_word)
313	subu	LEN,  LEN,  2
314#ifdef ERRATA__XXX_USR
315	NOP
316	ld.h.usr	%r5,  SRC, LEN
317	NOP
318	NOP
319	NOP
320#else
321	ld.h.usr	%r5,  SRC, LEN
322#endif
323	br.n	copyin_right_aligned_to_word
324	 st.h	%r5,  DEST, LEN
325
326ASLOCAL(copyin_right_align_to_doubleword)
327	subu	LEN,  LEN,  4
328#ifdef ERRATA__XXX_USR
329	NOP
330	ld.usr	%r5,  SRC,  LEN
331	NOP
332	NOP
333	NOP
334#else
335	ld.usr	%r5,  SRC,  LEN
336#endif
337	bcnd.n	ne0,  LEN, copyin_right_aligned_to_doubleword
338	 st	%r5,  DEST, LEN
339	br.n	Lcidone
340   	 or	%r2, %r0, %r0	/* successful return */
341
342ASLOCAL(copyin_byte_only)
343	bcnd	eq0, LEN, 2f
3441:
345	subu	LEN, LEN, 1
346#ifdef ERRATA__XXX_USR
347	NOP
348	ld.b.usr	%r5, SRC, LEN
349	NOP
350	NOP
351	NOP
352#else
353	ld.b.usr	%r5, SRC, LEN
354#endif
355	bcnd.n	ne0, LEN, 1b
356	 st.b	%r5, DEST, LEN
3572:
358	or	%r2, %r0, %r0	/* successful return */
359	/* FALLTHROUGH */
360
361ASLOCAL(Lcidone)
362	ldcr	%r5,  CPU
363	ld	%r6,  %r5,  CI_CURPCB
364	jmp.n	%r1
365	 st	%r0,  %r6,  PCB_ONFAULT
366
367ASLOCAL(Lciflt)
368	br.n	Lcidone
369	 or	%r2, %r0, EFAULT	/* return fault */
370
371#undef	SRC
372#undef	DEST
373#undef	LEN
374
375/*
376 * Specific flavour for a single 32-bit word copy.
377 * copyin32(from, to)
378 *	r2 == from (user source address)
379 *	r3 == to (kernel destination address)
380 */
381
382#define	SRC	%r2
383#define	DEST	%r3
384
385ENTRY(copyin32)
386	/* check for source alignment */
387	mask	%r8,  SRC,  0x3
388	bcnd	ne0,  %r8,  copyin32_misaligned
389
390	/* set up fault handler */
391	ldcr	%r5,  CPU
392	ld	%r6,  %r5,  CI_CURPCB
393	or.u	%r5,  %r0,  %hi16(Lciflt)
394	or	%r5,  %r5,  %lo16(Lciflt)
395	st	%r5,  %r6,  PCB_ONFAULT	/* pcb_onfault = Lciflt */
396
397#ifdef ERRATA__XXX_USR
398	NOP
399	ld.usr	%r5,  SRC,  %r0
400	NOP
401	NOP
402	NOP
403#else
404	ld.usr	%r5,  SRC,  %r0
405#endif
406	st	%r5,  DEST, %r0
407	br.n	Lcidone
408   	 or	%r2, %r0, %r0	/* successful return */
409
410ASLOCAL(copyin32_misaligned)
411	jmp.n	%r1
412	 or	%r2, %r0, EFAULT	/* return fault */
413
414#undef	SRC
415#undef	DEST
416
417/*######################################################################*/
418/*######################################################################*/
419
420/*
421 * Copy a null terminated string from the user space to the kernel
422 * address space.
423 *
424 * _copyinstr(from, to, maxlen, &lencopied)
425 * r2 == from
426 * r3 == to
427 * r4 == maxlen
428 * r5 == len actually transferred (includes the terminating NUL!!!)
429 * r6 & r7 - used as temporaries
430 */
431#define	SRC	%r2
432#define	DEST	%r3
433#define	CNT	%r4
434#define	LEN	%r5
435
436ENTRY(_copyinstr)
437
438	/* setup fault handler */
439	ldcr	%r6,  CPU
440	ld	%r7,  %r6,   CI_CURPCB
441	or.u	%r6,  %r0,   %hi16(Lcisflt)
442	or	%r6,  %r6,   %lo16(Lcisflt)
443	st	%r6,  %r7,   PCB_ONFAULT
444	or	%r6,  %r0,   0
445	bcnd	lt0,  CNT,  Lcisflt
446	bcnd	eq0,  CNT,  Lcistoolong
4471:
448#ifdef ERRATA__XXX_USR
449	NOP
450	ld.bu.usr	%r7,  SRC, %r6
451	NOP
452	NOP
453	NOP
454#else
455	ld.bu.usr	%r7,  SRC,  %r6
456#endif
457	st.b	%r7,  DEST, %r6
458	bcnd.n	eq0,  %r7,  2f		/* all done */
459	 addu	%r6,  %r6,  1
460	cmp	%r7,  %r6,  CNT
461	bb1	lt,   %r7,  1b
462
463ASLOCAL(Lcistoolong)
464	or	%r2,   %r0, ENAMETOOLONG	/* overflow */
465
466ASLOCAL(Lcisnull)
467	bcnd	eq0,%r6, Lcisdone		/* do not attempt to clear last byte */
468					/* if we did not write to the string */
469	subu	%r6,  %r6,  1
470	st.b	%r0,  DEST, %r6		/* clear last byte */
471	br.n	Lcisdone
472	 addu	%r6,  %r6,  1
4732:					/* all done */
474	or	%r2,  %r0,  0
475
476ASLOCAL(Lcisdone)
477	bcnd	eq0, LEN, 3f
478	st	%r6, %r0, LEN
4793:
480	ldcr	%r5,  CPU
481	ld	%r6,  %r5,  CI_CURPCB
482	jmp.n	%r1
483	 st	%r0,  %r6,  PCB_ONFAULT	/* clear the handler */
484
485ASLOCAL(Lcisflt)
486	br.n	Lcisnull
487	 or	%r2,  %r0,  EFAULT	/* return fault */
488
489#undef	SRC
490#undef	DEST
491#undef	CNT
492#undef	LEN
493
494/*
495 * Copy specified amount of data from kernel to the user space
496 * Copyout(from, to, len)
497 *	r2 == from (kernel source address)
498 *	r3 == to (user destination address)
499 *	r4 == length
500 */
501
502#define	SRC	%r2
503#define	DEST	%r3
504#define	LEN	%r4
505
506ENTRY(copyout)
507	/* setup fault handler */
508	ldcr	%r5,  CPU
509	ld	%r6,  %r5,  CI_CURPCB
510	or.u	%r5,  %r0,  %hi16(Lcoflt)
511	or	%r5,  %r5,  %lo16(Lcoflt)
512	st	%r5,  %r6,  PCB_ONFAULT	/* pcb_onfault = Lcoflt */
513
514	/*
515	 * If it's a small length (less than 8), then do byte-by-byte.
516	 * Despite not being optimal if len is 4, and from and to
517	 * are word-aligned, this is still faster than doing more tests
518	 * to save an hyperthetical fraction of cycle.
519	 */
520	cmp	%r9,  LEN,  8
521	bb1	lt,   %r9,   copyout_byte_only
522
523	/* If they're not aligned similarly, use byte only... */
524	xor	%r9,  SRC,  DEST
525	mask	%r8,  %r9,  0x3
526	bcnd	ne0,  %r8,  copyout_byte_only
527
528	/*
529	 * At this point, we don't know if they're word aligned or not,
530	 * but we know that what needs to be done to one to align
531	 * it is what's needed for the other.
532	 */
533	bb1	0,    SRC,  copyout_left_align_to_halfword
534ASLOCAL(copyout_left_aligned_to_halfword)
535	bb1	1,    SRC,  copyout_left_align_to_word
536ASLOCAL(copyout_left_aligned_to_word)
537	bb1	0,    LEN,  copyout_right_align_to_halfword
538ASLOCAL(copyout_right_aligned_to_halfword)
539	bb1	1,    LEN,  copyout_right_align_to_word
540ASLOCAL(copyout_right_aligned_to_word)
541
542	/*
543	 * At this point, both SRC and DEST are aligned to a word
544	 * boundary, and LEN is a multiple of 4. We want it an even
545	 * multiple of 4.
546	 */
547	bb1.n	2,    LEN,  copyout_right_align_to_doubleword
548	 or	%r7,  %r0,  4
549
550ASLOCAL(copyout_right_aligned_to_doubleword)
551	ld 	%r5,  SRC,  %r0
552	ld    	%r6,  SRC,  %r7
553	subu	LEN,  LEN,  8
554#ifdef ERRATA__XXX_USR
555	NOP
556	st.usr	%r5,  DEST, %r0
557	NOP
558	NOP
559	NOP
560#else
561	st.usr	%r5,  DEST, %r0
562#endif
563	addu	SRC,  SRC,  8
564#ifdef ERRATA__XXX_USR
565	NOP
566	st.usr	%r6,  DEST, %r7
567	NOP
568	NOP
569	NOP
570#else
571	st.usr	%r6,  DEST, %r7
572#endif
573	bcnd.n	ne0,  LEN,  copyout_right_aligned_to_doubleword
574	 addu	DEST, DEST, 8
575	or	%r2,  %r0,  %r0	/* successful return */
576	br	Lcodone
577
578	/***************************************************/
579ASLOCAL(copyout_left_align_to_halfword)
580	ld.b	%r5,  SRC,  %r0
581	subu	LEN,  LEN,  1
582#ifdef ERRATA__XXX_USR
583	NOP
584	st.b.usr	%r5,  DEST, %r0
585	NOP
586	NOP
587	NOP
588#else
589	st.b.usr	%r5,  DEST, %r0
590#endif
591	addu	SRC,  SRC,  1
592	br.n	copyout_left_aligned_to_halfword
593	 addu	DEST, DEST, 1
594
595ASLOCAL(copyout_left_align_to_word)
596	ld.h	%r5,  SRC,  %r0
597	subu	LEN,  LEN,  2
598#ifdef ERRATA__XXX_USR
599	NOP
600	st.h.usr	%r5,  DEST, %r0
601	NOP
602	NOP
603	NOP
604#else
605	st.h.usr	%r5,  DEST, %r0
606#endif
607	addu	SRC,  SRC,  2
608	br.n	copyout_left_aligned_to_word
609	 addu	DEST, DEST, 2
610
611ASLOCAL(copyout_right_align_to_halfword)
612	subu	LEN,  LEN,  1
613	ld.b	%r5,  SRC,  LEN
614#ifdef ERRATA__XXX_USR
615	NOP
616	st.b.usr	%r5,  DEST, LEN
617	NOP
618	NOP
619	NOP
620	br	copyout_right_aligned_to_halfword
621#else
622	br.n	copyout_right_aligned_to_halfword
623	 st.b.usr	%r5,  DEST, LEN
624#endif
625
626ASLOCAL(copyout_right_align_to_word)
627	subu	LEN,  LEN,  2
628	ld.h	%r5,  SRC,  LEN
629#ifdef ERRATA__XXX_USR
630	NOP
631	st.h.usr	%r5,  DEST, LEN
632	NOP
633	NOP
634	NOP
635	br	copyout_right_aligned_to_word
636#else
637	br.n	copyout_right_aligned_to_word
638	 st.h.usr	%r5,  DEST, LEN
639#endif
640
641ASLOCAL(copyout_right_align_to_doubleword)
642	subu	LEN,  LEN,  4
643	ld	%r5,  SRC,  LEN
644#ifdef ERRATA__XXX_USR
645	NOP
646	st.usr	%r5,  DEST, LEN
647	NOP
648	NOP
649	NOP
650	bcnd	ne0,  LEN, copyout_right_aligned_to_doubleword
651#else
652	bcnd.n	ne0,  LEN, copyout_right_aligned_to_doubleword
653	 st.usr	%r5,  DEST, LEN
654#endif
655	br.n	Lcodone
656	 or	%r2, %r0, %r0	/* successful return */
657
658ASLOCAL(copyout_byte_only)
659	bcnd	eq0, LEN, 2f
6601:
661	subu	LEN, LEN, 1
662	ld.b	%r5, SRC, LEN
663#ifdef ERRATA__XXX_USR
664	NOP
665	st.b.usr	%r5, DEST, LEN
666	NOP
667	NOP
668	NOP
669	bcnd	ne0, LEN, 1b
670#else
671	bcnd.n	ne0, LEN, 1b
672	 st.b.usr	%r5, DEST, LEN
673#endif
674
6752:
676	or	%r2, %r0, %r0	/* successful return */
677	/* FALLTHROUGH */
678
679ASLOCAL(Lcodone)
680	ldcr	%r5,  CPU
681	ld	%r6,  %r5,  CI_CURPCB
682	jmp.n	%r1
683	 st	%r0,  %r6,  PCB_ONFAULT	/* clear the handler */
684
685ASLOCAL(Lcoflt)
686	br.n	Lcodone
687	 or	%r2, %r0, EFAULT	/* return fault */
688
689#undef	SRC
690#undef	DEST
691#undef	LEN
692
693/*
694 * Copy a null terminated string from the kernel space to the user
695 * address space.
696 *
697 * copyoutstr(from, to, maxlen, &lencopied)
698 * r2 == from
699 * r3 == to
700 * r4 == maxlen that can be copied
701 * r5 == len actually copied (including the terminating NUL!!!)
702 */
703
704#define	SRC	%r2
705#define	DEST	%r3
706#define	CNT	%r4
707#define	LEN	%r5
708
709ENTRY(copyoutstr)
710	/* setup fault handler */
711	ldcr	%r6,  CPU
712	ld	%r7,  %r6,  CI_CURPCB
713	or.u	%r6,  %r0,  %hi16(Lcosflt)
714	or	%r6,  %r6,  %lo16(Lcosflt)
715	st	%r6,  %r7,  PCB_ONFAULT
716	bcnd	lt0,  CNT,  Lcosflt
717	bcnd	eq0,  CNT,  2f
718	or	%r6,  %r0,  0
7191:
720	ld.bu	%r7,  SRC,  %r6
721#ifdef ERRATA__XXX_USR
722	NOP
723	st.b.usr	%r7,  DEST,  %r6
724	NOP
725	NOP
726	NOP
727#else
728	st.b.usr	%r7,  DEST,  %r6
729#endif
730	bcnd.n	eq0,  %r7, 3f		/* all done */
731	 addu	%r6,  %r6, 1
732	cmp	%r7,  %r6, CNT
733	bb1	lt,   %r7, 1b
7342:
735	br.n	Lcosdone
736	 or	%r2,  %r0, ENAMETOOLONG
7373:
738	br.n	Lcosdone
739	 or	%r2,  %r0, 0
740
741ASLOCAL(Lcosflt)
742	br.n	Lcosdone
743	 or	%r2, %r0, EFAULT
744
745ASLOCAL(Lcosdone)
746	bcnd	eq0, LEN, 3f
747	st	%r6, %r0, LEN
7483:
749	ldcr	%r5, CPU
750	ld	%r6, %r5, CI_CURPCB
751	jmp.n	%r1
752	 st	%r0, %r6, PCB_ONFAULT	/* clear the handler */
753
754#undef	SRC
755#undef	DEST
756#undef	CNT
757#undef	LEN
758
759/*######################################################################*/
760
761/*
762 * kcopy(const void *src, void *dst, size_t len);
763 *
764 * Copy len bytes from src to dst, aborting if we encounter a page fault.
765 */
766ENTRY(kcopy)
767	subu	%r31, %r31, 16
768	ldcr	%r5,  CPU
769	ld	%r6,  %r5,  CI_CURPCB
770	or.u	%r5,  %r0,  %hi16(kcopy_fault)
771	ld	%r7,  %r6,  PCB_ONFAULT
772	or	%r5,  %r5,  %lo16(kcopy_fault)
773	st	%r7,  %r31, 0			/* save old pcb_onfault */
774	st	%r5,  %r6,  PCB_ONFAULT		/* pcb_onfault = kcopy_fault */
775	bcnd	le0,  %r4,  kcopy_out /* nothing to do if <= 0 */
776/*
777 *	check position of source and destination data
778 */
779	cmp 	%r9,  %r2,  %r3	/* compare source address to destination */
780	bb1	eq,   %r9,  kcopy_out /* nothing to do if equal */
781	bb1	lo,   %r9,  kcopy_reverse /* reverse copy if src < dest */
782/*
783 *	source address is greater than destination address, copy forward
784 */
785	cmp 	%r9,  %r4,  16	/* see if we have at least 16 bytes */
786	bb1	lt,   %r9,  kf_byte_copy		/* copy bytes for small length */
787/*
788 *	determine copy strategy based on alignment of source and destination
789 */
790	mask	%r6,  %r2,  3	/* get 2 low order bits of source address */
791	mask	%r7,  %r3,  3	/* get 2 low order bits of destination addr */
792	mak	%r6,  %r6,  0<4>/* convert source bits to table offset */
793	mak	%r7,  %r7,  0<2>/* convert destination bits to table offset */
794	or.u	%r12, %r0,  %hi16(kf_strat)
795	or	%r12, %r12, %lo16(kf_strat)
796	addu	%r6,  %r6,  %r7	/* compute final table offset for strategy */
797	ld	%r12, %r12, %r6	/* load the strategy routine */
798	jmp	%r12		/* branch to strategy routine */
799
800/*
801 * Copy three bytes from src to destination then copy words
802 */
803ASLOCAL(kf_3byte_word_copy)
804	ld.bu	%r6,  %r2,  0		/* load byte from source */
805	ld.bu	%r7,  %r2,  1		/* load byte from source */
806	ld.bu	%r8,  %r2,  2		/* load byte from source */
807	st.b	%r6,  %r3,  0		/* store byte to destination */
808	st.b	%r7,  %r3,  1		/* store byte to destination */
809	st.b	%r8,  %r3,  2		/* store byte to destination */
810	addu	%r2,  %r2,  3		/* increment source pointer */
811	addu	%r3,  %r3,  3		/* increment destination pointer */
812	br.n	kf_word_copy/* copy full words */
813	 subu	%r4,  %r4,  3		/* decrement length */
814
815/*
816 * Copy 1 halfword from src to destination then copy words
817 */
818ASLOCAL(kf_1half_word_copy)
819	ld.hu	%r6,  %r2,  0		/* load half-word from source */
820	st.h	%r6,  %r3,  0		/* store half-word to destination */
821	addu	%r2,  %r2,  2		/* increment source pointer */
822	addu	%r3,  %r3,  2		/* increment destination pointer */
823	br.n	kf_word_copy/* copy full words */
824	 subu	%r4,  %r4,  2		/* decrement remaining length */
825
826/*
827 * Copy 1 byte from src to destination then copy words
828 */
829ASLOCAL(kf_1byte_word_copy)
830	ld.bu	%r6,  %r2,  0		/* load 1 byte from source */
831	st.b	%r6,  %r3,  0		/* store 1 byte to destination */
832	addu	%r2,  %r2,  1		/* increment source pointer */
833	addu	%r3,  %r3,  1		/* increment destination pointer */
834	subu	%r4,  %r4,  1		/* decrement remaining length */
835	/* fall through to word copy */
836/*
837 * Copy as many full words as possible, 4 words per loop
838 */
839ASLOCAL(kf_word_copy)
840	cmp	%r10, %r4,  16		/* see if we have 16 bytes remaining */
841	bb1	lo,   %r10, kf_byte_copy 		/* not enough left, copy bytes */
842	ld	%r6,  %r2,  0		/* load first word */
843	ld	%r7,  %r2,  4		/* load second word */
844	ld	%r8,  %r2,  8		/* load third word */
845	ld	%r9,  %r2,  12		/* load fourth word */
846	st	%r6,  %r3,  0		/* store first word */
847	st	%r7,  %r3,  4		/* store second word */
848	st 	%r8,  %r3,  8		/* store third word */
849	st 	%r9,  %r3,  12		/* store fourth word */
850	addu	%r2,  %r2,  16		/* increment source pointer */
851	addu	%r3,  %r3,  16		/* increment destination pointer */
852	br.n	kf_word_copy/* copy another block */
853	 subu	%r4,  %r4,  16		/* decrement remaining length */
854
855ASLOCAL(kf_1byte_half_copy)
856	ld.bu	%r6,  %r2,  0		/* load 1 byte from source */
857	st.b	%r6,  %r3,  0		/* store 1 byte to destination */
858	addu	%r2,  %r2,  1		/* increment source pointer */
859	addu	%r3,  %r3,  1		/* increment destination pointer */
860	subu	%r4,  %r4,  1		/* decrement remaining length */
861	/* fall through to half copy */
862
863ASLOCAL(kf_half_copy)
864	cmp	%r10, %r4,  16		/* see if we have 16 bytes remaining */
865	bb1	lo,   %r10, kf_byte_copy		/* not enough left, copy bytes */
866	ld.hu	%r6,  %r2,  0		/* load first half-word */
867	ld.hu	%r7,  %r2,  2		/* load second half-word */
868	ld.hu	%r8,  %r2,  4		/* load third half-word */
869	ld.hu	%r9,  %r2,  6		/* load fourth half-word */
870	ld.hu	%r10, %r2,  8		/* load fifth half-word */
871	ld.hu	%r11, %r2,  10		/* load sixth half-word */
872	ld.hu	%r12, %r2,  12		/* load seventh half-word */
873	ld.hu	%r13, %r2,  14		/* load eighth half-word */
874	st.h	%r6,  %r3,  0		/* store first half-word */
875	st.h	%r7,  %r3,  2		/* store second half-word */
876	st.h 	%r8,  %r3,  4		/* store third half-word */
877	st.h 	%r9,  %r3,  6		/* store fourth half-word */
878	st.h	%r10, %r3,  8		/* store fifth half-word */
879	st.h	%r11, %r3,  10		/* store sixth half-word */
880	st.h 	%r12, %r3,  12		/* store seventh half-word */
881	st.h 	%r13, %r3,  14		/* store eighth half-word */
882	addu	%r2,  %r2,  16		/* increment source pointer */
883	addu	%r3,  %r3,  16		/* increment destination pointer */
884	br.n	kf_half_copy/* copy another block */
885	 subu	%r4,  %r4,  16		/* decrement remaining length */
886
887ASLOCAL(kf_byte_copy)
888	bcnd	eq0,  %r4,  kcopy_out			/* branch if nothing left to copy */
889	ld.bu	%r6,  %r2,  0		/* load byte from source */
890	st.b	%r6,  %r3,  0		/* store byte in destination */
891	addu	%r2,  %r2,  1		/* increment source pointer */
892	addu	%r3,  %r3,  1		/* increment destination pointer */
893	br.n	kf_byte_copy/* branch for next byte */
894	 subu	%r4,  %r4,  1		/* decrement remaining length */
895
896/*
897 *	source address is less than destination address, copy in reverse
898 */
899ASLOCAL(kcopy_reverse)
900/*
901 * start copy pointers at end of data
902 */
903	addu	%r2,  %r2,  %r4		/* start source at end of data */
904	addu	%r3,  %r3,  %r4		/* start destination at end of data */
905/*
906 * check for short data
907 */
908	cmp 	%r9,  %r4,  16		/* see if we have at least 16 bytes */
909	bb1	lt,   %r9,  kr_byte_copy		/* copy bytes for small data length */
910/*
911 *	determine copy strategy based on alignment of source and destination
912 */
913	mask	%r6,  %r2,  3	/* get 2 low order bits of source address */
914	mask	%r7,  %r3,  3	/* get 2 low order bits of destination addr */
915	mak	%r6,  %r6,  0<4>/* convert source bits to table offset */
916	mak	%r7,  %r7,  0<2>/* convert destination bits to table offset */
917	or.u	%r12, %r0,  %hi16(kr_strat)
918	or	%r12, %r12, %lo16(kr_strat)
919	addu	%r6,  %r6,  %r7	/* compute final table offset for strategy */
920	ld	%r12, %r12, %r6	/* load the strategy routine */
921	jmp	%r12		/* branch to strategy routine */
922
923/*
924 * Copy three bytes from src to destination then copy words
925 */
926ASLOCAL(kr_3byte_word_copy)
927	subu	%r2,  %r2,  3		/* decrement source pointer */
928	subu	%r3,  %r3,  3		/* decrement destination pointer */
929	ld.bu	%r6,  %r2,  0		/* load byte from source */
930	ld.bu	%r7,  %r2,  1		/* load byte from source */
931	ld.bu	%r8,  %r2,  2		/* load byte from source */
932	st.b	%r6,  %r3,  0		/* store byte to destination */
933	st.b	%r7,  %r3,  1		/* store byte to destination */
934	st.b	%r8,  %r3,  2		/* store byte to destination */
935	br.n	kr_word_copy/* copy full words */
936	 subu	%r4,  %r4,  3		/* decrement length */
937
938/*
939 * Copy 1 halfword from src to destination then copy words
940 */
941ASLOCAL(kr_1half_word_copy)
942	subu	%r2,  %r2,  2		/* decrement source pointer */
943	subu	%r3,  %r3,  2		/* decrement destination pointer */
944	ld.hu	%r6,  %r2,  0		/* load half-word from source */
945	st.h	%r6,  %r3,  0		/* store half-word to destination */
946	br.n	kr_word_copy/* copy full words */
947	 subu	%r4,  %r4,  2		/* decrement remaining length */
948
949/*
950 * Copy 1 byte from src to destination then copy words
951 */
952ASLOCAL(kr_1byte_word_copy)
953	subu	%r2,  %r2,  1		/* decrement source pointer */
954	subu	%r3,  %r3,  1		/* decrement destination pointer */
955	ld.bu	%r6,  %r2,  0		/* load 1 byte from source */
956	st.b	%r6,  %r3,  0		/* store 1 byte to destination */
957	subu	%r4,  %r4,  1		/* decrement remaining length */
958	/* fall through to word copy */
959/*
960 * Copy as many full words as possible, 4 words per loop
961 */
962ASLOCAL(kr_word_copy)
963	cmp	%r10, %r4,  16		/* see if we have 16 bytes remaining */
964	bb1	lo,   %r10, kr_byte_copy		/* not enough left, copy bytes */
965	subu	%r2,  %r2,  16		/* decrement source pointer */
966	subu	%r3,  %r3,  16		/* decrement destination pointer */
967	ld	%r6,  %r2,  0		/* load first word */
968	ld	%r7,  %r2,  4		/* load second word */
969	ld	%r8,  %r2,  8		/* load third word */
970	ld	%r9,  %r2,  12		/* load fourth word */
971	st	%r6,  %r3,  0		/* store first word */
972	st	%r7,  %r3,  4		/* store second word */
973	st 	%r8,  %r3,  8		/* store third word */
974	st 	%r9,  %r3,  12		/* store fourth word */
975	br.n	kr_word_copy/* copy another block */
976	 subu	%r4,  %r4,  16	/* decrement remaining length */
977
978ASLOCAL(kr_1byte_half_copy)
979	subu	%r2,  %r2,  1		/* decrement source pointer */
980	subu	%r3,  %r3,  1		/* decrement destination pointer */
981	ld.bu	%r6,  %r2,  0		/* load 1 byte from source */
982	st.b	%r6,  %r3,  0		/* store 1 byte to destination */
983	subu	%r4,  %r4,  1		/* decrement remaining length */
984	/* fall through to half copy */
985
986ASLOCAL(kr_half_copy)
987	cmp	%r10, %r4,  16		/* see if we have 16 bytes remaining */
988	bb1	lo,   %r10, kr_byte_copy		/* not enough left, copy bytes */
989	subu	%r2,  %r2,  16		/* decrement source pointer */
990	subu	%r3,  %r3,  16		/* decrement destination pointer */
991	ld.hu	%r6,  %r2,  0		/* load first half-word */
992	ld.hu	%r7,  %r2,  2		/* load second half-word */
993	ld.hu	%r8,  %r2,  4		/* load third half-word */
994	ld.hu	%r9,  %r2,  6		/* load fourth half-word */
995	ld.hu	%r10, %r2,  8		/* load fifth half-word */
996	ld.hu	%r11, %r2,  10		/* load sixth half-word */
997	ld.hu	%r12, %r2,  12		/* load seventh half-word */
998	ld.hu	%r13, %r2,  14		/* load eighth half-word */
999	st.h	%r6,  %r3,  0		/* store first half-word */
1000	st.h	%r7,  %r3,  2		/* store second half-word */
1001	st.h 	%r8,  %r3,  4		/* store third half-word */
1002	st.h 	%r9,  %r3,  6		/* store fourth half-word */
1003	st.h	%r10, %r3,  8		/* store fifth half-word */
1004	st.h	%r11, %r3,  10		/* store sixth half-word */
1005	st.h 	%r12, %r3,  12		/* store seventh half-word */
1006	st.h 	%r13, %r3,  14		/* store eighth half-word */
1007	br.n	kr_half_copy/* copy another block */
1008	 subu	%r4,  %r4,  16		/* decrement remaining length */
1009
1010ASLOCAL(kr_byte_copy)
1011	bcnd	eq0,  %r4,  kcopy_out			/* branch if nothing left to copy */
1012	subu	%r2,  %r2,  1		/* decrement source pointer */
1013	subu	%r3,  %r3,  1		/* decrement destination pointer */
1014	ld.bu	%r6,  %r2,  0		/* load byte from source */
1015	st.b	%r6,  %r3,  0		/* store byte in destination */
1016	br.n	kr_byte_copy/* branch for next byte */
1017	 subu	%r4,  %r4,  1		/* decrement remaining length */
1018
1019ASLOCAL(kcopy_out)
1020	or	%r2,   %r0,  0		/* return success */
1021ASLOCAL(kcopy_out_fault)
1022	ldcr	%r5,  CPU
1023	ld	%r7,  %r31, 0
1024	ld	%r6,  %r5,  CI_CURPCB
1025	add	%r31, %r31, 16
1026	jmp.n	%r1			/* all done, return to caller */
1027	 st	%r7,  %r6,  PCB_ONFAULT	/* restore previous pcb_onfault */
1028
1029ASLOCAL(kcopy_fault)
1030	br.n	kcopy_out_fault
1031	 or	%r2,  %r0,  EFAULT	/* return fault */
1032
1033	.data
1034	.align	2
1035ASLOCAL(kf_strat)
1036	.word	kf_word_copy
1037	.word	kf_byte_copy
1038	.word	kf_half_copy
1039	.word	kf_byte_copy
1040	.word	kf_byte_copy
1041	.word	kf_3byte_word_copy
1042	.word	kf_byte_copy
1043	.word	kf_1byte_half_copy
1044	.word	kf_half_copy
1045	.word	kf_byte_copy
1046	.word	kf_1half_word_copy
1047	.word	kf_byte_copy
1048	.word	kf_byte_copy
1049	.word	kf_1byte_half_copy
1050	.word	kf_byte_copy
1051	.word	kf_1byte_word_copy
1052
1053ASLOCAL(kr_strat)
1054	.word	kr_word_copy
1055	.word	kr_byte_copy
1056	.word	kr_half_copy
1057	.word	kr_byte_copy
1058	.word	kr_byte_copy
1059	.word	kr_1byte_word_copy
1060	.word	kr_byte_copy
1061	.word	kr_1byte_half_copy
1062	.word	kr_half_copy
1063	.word	kr_byte_copy
1064	.word	kr_1half_word_copy
1065	.word	kr_byte_copy
1066	.word	kr_byte_copy
1067	.word	kr_1byte_half_copy
1068	.word	kr_byte_copy
1069	.word	kr_3byte_word_copy
1070
1071#ifdef DDB
1072/*
1073 * non-local goto
1074 *	int setjmp(label_t *);
1075 *	void longjmp(label_t*);
1076 */
1077ENTRY(setjmp)
1078	st	%r1,  %r2, 0
1079	st	%r14, %r2, 4
1080	st	%r15, %r2, 2*4
1081	st	%r16, %r2, 3*4
1082	st	%r17, %r2, 4*4
1083	st	%r18, %r2, 5*4
1084	st	%r19, %r2, 6*4
1085	st	%r20, %r2, 7*4
1086	st	%r21, %r2, 8*4
1087	st	%r22, %r2, 9*4
1088	st	%r23, %r2, 10*4
1089	st	%r24, %r2, 11*4
1090	st	%r25, %r2, 12*4
1091	st	%r26, %r2, 13*4
1092	st	%r27, %r2, 14*4
1093	st	%r28, %r2, 15*4
1094	st	%r29, %r2, 16*4
1095	st	%r30, %r2, 17*4
1096	st	%r31, %r2, 18*4
1097	jmp.n	%r1
1098	 or	%r2,  %r0, %r0
1099
1100ENTRY(longjmp)
1101	ld	%r1,  %r2, 0
1102	ld	%r14, %r2, 4
1103	ld	%r15, %r2, 2*4
1104	ld	%r16, %r2, 3*4
1105	ld	%r17, %r2, 4*4
1106	ld	%r18, %r2, 5*4
1107	ld	%r19, %r2, 6*4
1108	ld	%r20, %r2, 7*4
1109	ld	%r21, %r2, 8*4
1110	ld	%r22, %r2, 9*4
1111	ld	%r23, %r2, 10*4
1112	ld	%r24, %r2, 11*4
1113	ld	%r25, %r2, 12*4
1114	ld	%r26, %r2, 13*4
1115	ld	%r27, %r2, 14*4
1116	ld	%r28, %r2, 15*4
1117	ld	%r29, %r2, 16*4
1118	ld	%r30, %r2, 17*4
1119	ld	%r31, %r2, 18*4
1120	jmp.n	%r1
1121	 or	%r2,  %r0, 1
1122#endif
1123
1124/*
1125 * Signal trampoline code.
1126 * The kernel arranges for the handler to be invoked directly, and return
1127 * here.
1128 */
1129	 .section .rodata
1130	 .align	3
1131	 .type	sigcode,@function
1132GLOBAL(sigcode)			/* r31 points to sigframe */
1133	ld	%r2,  %r31, 0	/* pick sigcontext* */
1134	or	%r13, %r0,  SYS_sigreturn
1135GLOBAL(sigcodecall)
1136GLOBAL(sigcoderet)
1137	tb0	0,    %r0,  450	/* syscall trap, calling sigreturn */
1138	NOP			| failure return
1139#ifdef dontbother		/* sigreturn will not return unless it fails */
1140	NOP			| success return
1141#endif
1142GLOBAL(esigcode)
1143	/* FALLTHROUGH */
1144GLOBAL(sigfill)
1145	tb0	0, %r0, 130	/* breakpoint */
1146GLOBAL(sigfillsiz)
1147	.word	sigfillsiz - sigfill
1148
1149/*
1150 * Helper functions for pmap_copy_page() and pmap_zero_page().
1151 */
1152
1153#ifdef M88100
1154
1155/*
1156 * void copypage(vaddr_t src, vaddr_t dst);
1157 *
1158 * This copies PAGE_SIZE bytes from src to dst in 32 byte chunks.
1159 */
1160ENTRY(m8820x_copypage)
1161	addu	%r12, %r2, PAGE_SIZE
11621:
1163	ld.d	%r4,  %r2, 0x00
1164	ld.d	%r6,  %r2, 0x08
1165	st.d	%r4,  %r3, 0x00
1166	ld.d	%r8,  %r2, 0x10
1167	st.d	%r6,  %r3, 0x08
1168	ld.d	%r10, %r2, 0x18
1169	st.d	%r8,  %r3, 0x10
1170	addu	%r2,  %r2, 0x20
1171	st.d	%r10, %r3, 0x18
1172	cmp	%r4,  %r2, %r12
1173	bb1.n	ne,   %r4, 1b
1174	 addu	%r3,  %r3, 0x20
1175	jmp	%r1
1176
1177/*
1178 * void zeropage(vaddr_t dst);
1179 *
1180 * This zeroes PAGE_SIZE bytes from src to dst in 64 byte chunks.
1181 */
1182ENTRY(m8820x_zeropage)
1183	addu	%r12, %r2, PAGE_SIZE
1184	or	%r3,  %r1, %r0
1185	or	%r1,  %r0, %r0
11861:
1187	st.d	%r0,  %r2, 0x00
1188	st.d	%r0,  %r2, 0x08
1189	st.d	%r0,  %r2, 0x10
1190	st.d	%r0,  %r2, 0x18
1191	st.d	%r0,  %r2, 0x20
1192	st.d	%r0,  %r2, 0x28
1193	st.d	%r0,  %r2, 0x30
1194	st.d	%r0,  %r2, 0x38
1195	addu	%r2,  %r2, 0x40
1196	cmp	%r4,  %r2, %r12
1197	bb1	ne,   %r4, 1b
1198	jmp	%r3
1199
1200#endif	/* M88100 */
1201
1202#ifdef M88110
1203
1204/*
1205 * void copypage(vaddr_t src, vaddr_t dst);
1206 *
1207 * This copies PAGE_SIZE bytes from src to dst in 32 byte chunks (one
1208 * cache line).
1209 */
1210ENTRY(m88110_copypage)
1211	addu	%r12, %r2, PAGE_SIZE
12121:
1213	ld.h	%r0,  %r2, 0x00	| load allocate
1214	ld.d	%r4,  %r2, 0x00
1215	ld.d	%r6,  %r2, 0x08
1216	st.d	%r4,  %r3, 0x00
1217	ld.d	%r8,  %r2, 0x10
1218	st.d	%r6,  %r3, 0x08
1219	ld.d	%r10, %r2, 0x18
1220	st.d	%r8,  %r3, 0x10
1221	addu	%r2,  %r2, 0x20
1222	st.d	%r10, %r3, 0x18
1223	cmp	%r4,  %r2, %r12
1224	addu	%r3,  %r3, 0x20
1225	bb1	ne,   %r4, 1b
1226	jmp	%r1
1227
1228/*
1229 * void zeropage(vaddr_t dst);
1230 *
1231 * This zeroes PAGE_SIZE bytes from src to dst in 32 byte chunks.
1232 */
1233ENTRY(m88110_zeropage)
1234	addu	%r12, %r2, PAGE_SIZE
1235	or	%r3,  %r1, %r0
1236	or	%r1,  %r0, %r0
12371:
1238	ld.h	%r0,  %r2, 0x00	| load allocate
1239	st.d	%r0,  %r2, 0x00
1240	st.d	%r0,  %r2, 0x08
1241	st.d	%r0,  %r2, 0x10
1242	st.d	%r0,  %r2, 0x18
1243	addu	%r2,  %r2, 0x20
1244	cmp	%r4,  %r2, %r12
1245	bb1	ne,   %r4, 1b
1246	jmp	%r3
1247
1248#endif	/* M88110 */
1249
1250/*
1251 * PSR initialization code, invoked from locore on every processor startup.
1252 */
1253ASENTRY(setup_psr)
1254	ldcr	%r2,  PID
1255	extu	%r3,  %r2, 8<8>
1256
1257	/*
1258	 * Ensure that the PSR is as we like:
1259	 *	supervisor mode
1260	 *	big-endian byte ordering
1261	 *	concurrent operation allowed
1262	 *	carry bit clear (I don't think we really care about this)
1263	 *	FPU enabled
1264	 *	misaligned access raises an exception
1265	 *	interrupts disabled
1266	 *	shadow registers frozen
1267	 *
1268	 * The manual says not to disable interrupts and freeze shadowing
1269	 * at the same time because interrupts are not actually disabled
1270	 * until after the next instruction. Well, if an interrupt
1271	 * occurs now, we're in deep trouble anyway, so I'm going to do
1272	 * the two together.
1273	 *
1274	 * Upon a reset (or poweron, I guess), the PSR indicates:
1275	 *   supervisor mode
1276	 *   interrupts, shadowing, FPU, misaligned exception: all disabled
1277	 *
1278	 * We'll just construct our own turning on what we want.
1279	 *
1280	 *	jfriedl@omron.co.jp
1281	 */
1282
1283	cmp	%r4, %r3, CPU_88110
1284	bb1	eq,  %r4, 1f	/* if it's a mc88110, skip SSBR */
1285	stcr	%r0, SSBR	/* clear this for later */
12861:
1287	stcr	%r0, SR1	/* clear the CPU flags */
1288
1289	or.u	%r2, %r0, %hi16(KERNEL_PSR)
1290	or	%r2, %r2, %lo16(KERNEL_PSR)
1291	stcr	%r2, PSR
1292	FLUSH_PIPELINE
1293
1294	jmp	%r1
1295
1296/*
1297 * Update the VBR value.
1298 * This needs to be done with interrupts and shadowing disabled.
1299 */
1300GLOBAL(set_vbr)
1301	ldcr	%r3, PSR
1302	set	%r4, %r3, 1<PSR_INTERRUPT_DISABLE_BIT>
1303	set	%r4, %r4, 1<PSR_SHADOW_FREEZE_BIT>
1304	stcr	%r4, PSR
1305	FLUSH_PIPELINE
1306
1307	stcr	%r2, VBR
1308	FLUSH_PIPELINE
1309
1310#if defined(M88100) && defined(M88110)
1311	ldcr	%r2, PID
1312	extu	%r5, %r2, 8<8>
1313	cmp	%r4, %r5, CPU_88110
1314	bb1	eq,  %r4, 1f
1315#endif
1316#ifdef M88100
1317	/* 88100 */
1318	stcr	%r3, PSR
1319	FLUSH_PIPELINE
1320	jmp	%r1
1321#endif
1322#ifdef M88110
13231:
1324	/* 88110 */
1325	stcr	%r1, EXIP
1326	stcr	%r3, EPSR
1327	RTE
1328#endif
1329