bcopyinout.S revision 137463
1/*	$NetBSD: bcopyinout.S,v 1.11 2003/10/13 21:22:40 scw Exp $	*/
2
3/*
4 * Copyright (c) 2002 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Allen Briggs for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *      This product includes software developed for the NetBSD Project by
20 *      Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 *    or promote products derived from this software without specific prior
23 *    written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38
39#include "assym.s"
40
41#include <machine/asm.h>
42
43__FBSDID("$FreeBSD: head/sys/arm/arm/bcopyinout.S 137463 2004-11-09 16:47:47Z cognet $");
44#ifdef __XSCALE__
45#include <arm/arm/bcopyinout_xscale.S>
46#else
47
48	.text
49	.align	0
50
51#ifdef MULTIPROCESSOR
52.Lcpu_info:
53	.word	_C_LABEL(cpu_info)
54#else
55.Lcurpcb:
56	.word _C_LABEL(__pcpu) + PC_CURPCB
57#endif
58
59#define SAVE_REGS	stmfd	sp!, {r4-r11}
60#define RESTORE_REGS	ldmfd	sp!, {r4-r11}
61
62#if defined(__XSCALE__)
63#define HELLOCPP #
64#define PREFETCH(rx,o)	pld	[ rx , HELLOCPP (o) ]
65#else
66#define PREFETCH(rx,o)
67#endif
68
69/*
70 * r0 = user space address
71 * r1 = kernel space address
72 * r2 = length
73 *
74 * Copies bytes from user space to kernel space
75 *
76 * We save/restore r4-r11:
77 * r4-r11 are scratch
78 */
79ENTRY(copyin)
80	/* Quick exit if length is zero */
81	teq	r2, #0
82	moveq	r0, #0
83	RETEQ
84
85	SAVE_REGS
86#ifdef MULTIPROCESSOR
87	/* XXX Probably not appropriate for non-Hydra SMPs */
88	stmfd	sp!, {r0-r2, r14}
89	bl	_C_LABEL(cpu_number)
90	ldr	r4, .Lcpu_info
91	ldr	r4, [r4, r0, lsl #2]
92	ldr	r4, [r4, #CI_CURPCB]
93	ldmfd	sp!, {r0-r2, r14}
94#else
95	ldr	r4, .Lcurpcb
96	ldr	r4, [r4]
97#endif
98
99	ldr	r5, [r4, #PCB_ONFAULT]
100	adr	r3, .Lcopyfault
101	str	r3, [r4, #PCB_ONFAULT]
102
103	PREFETCH(r0, 0)
104	PREFETCH(r1, 0)
105
106	/*
107	 * If not too many bytes, take the slow path.
108	 */
109	cmp	r2, #0x08
110	blt	.Licleanup
111
112	/*
113	 * Align destination to word boundary.
114	 */
115	and	r6, r1, #0x3
116	ldr	pc, [pc, r6, lsl #2]
117	b	.Lialend
118	.word	.Lialend
119	.word	.Lial3
120	.word	.Lial2
121	.word	.Lial1
122.Lial3:	ldrbt	r6, [r0], #1
123	sub	r2, r2, #1
124	strb	r6, [r1], #1
125.Lial2:	ldrbt	r7, [r0], #1
126	sub	r2, r2, #1
127	strb	r7, [r1], #1
128.Lial1:	ldrbt	r6, [r0], #1
129	sub	r2, r2, #1
130	strb	r6, [r1], #1
131.Lialend:
132
133	/*
134	 * If few bytes left, finish slow.
135	 */
136	cmp	r2, #0x08
137	blt	.Licleanup
138
139	/*
140	 * If source is not aligned, finish slow.
141	 */
142	ands	r3, r0, #0x03
143	bne	.Licleanup
144
145	cmp	r2, #0x60	/* Must be > 0x5f for unrolled cacheline */
146	blt	.Licleanup8
147
148	/*
149	 * Align destination to cacheline boundary.
150	 * If source and destination are nicely aligned, this can be a big
151	 * win.  If not, it's still cheaper to copy in groups of 32 even if
152	 * we don't get the nice cacheline alignment.
153	 */
154	and	r6, r1, #0x1f
155	ldr	pc, [pc, r6]
156	b	.Licaligned
157	.word	.Licaligned
158	.word	.Lical28
159	.word	.Lical24
160	.word	.Lical20
161	.word	.Lical16
162	.word	.Lical12
163	.word	.Lical8
164	.word	.Lical4
165.Lical28:ldrt	r6, [r0], #4
166	sub	r2, r2, #4
167	str	r6, [r1], #4
168.Lical24:ldrt	r7, [r0], #4
169	sub	r2, r2, #4
170	str	r7, [r1], #4
171.Lical20:ldrt	r6, [r0], #4
172	sub	r2, r2, #4
173	str	r6, [r1], #4
174.Lical16:ldrt	r7, [r0], #4
175	sub	r2, r2, #4
176	str	r7, [r1], #4
177.Lical12:ldrt	r6, [r0], #4
178	sub	r2, r2, #4
179	str	r6, [r1], #4
180.Lical8:ldrt	r7, [r0], #4
181	sub	r2, r2, #4
182	str	r7, [r1], #4
183.Lical4:ldrt	r6, [r0], #4
184	sub	r2, r2, #4
185	str	r6, [r1], #4
186
187	/*
188	 * We start with > 0x40 bytes to copy (>= 0x60 got us into this
189	 * part of the code, and we may have knocked that down by as much
190	 * as 0x1c getting aligned).
191	 *
192	 * This loop basically works out to:
193	 * do {
194	 * 	prefetch-next-cacheline(s)
195	 *	bytes -= 0x20;
196	 *	copy cacheline
197	 * } while (bytes >= 0x40);
198	 * bytes -= 0x20;
199	 * copy cacheline
200	 */
201.Licaligned:
202	PREFETCH(r0, 32)
203	PREFETCH(r1, 32)
204
205	sub	r2, r2, #0x20
206
207	/* Copy a cacheline */
208	ldrt	r10, [r0], #4
209	ldrt	r11, [r0], #4
210	ldrt	r6, [r0], #4
211	ldrt	r7, [r0], #4
212	ldrt	r8, [r0], #4
213	ldrt	r9, [r0], #4
214	stmia	r1!, {r10-r11}
215	ldrt	r10, [r0], #4
216	ldrt	r11, [r0], #4
217	stmia	r1!, {r6-r11}
218
219	cmp	r2, #0x40
220	bge	.Licaligned
221
222	sub	r2, r2, #0x20
223
224	/* Copy a cacheline */
225	ldrt	r10, [r0], #4
226	ldrt	r11, [r0], #4
227	ldrt	r6, [r0], #4
228	ldrt	r7, [r0], #4
229	ldrt	r8, [r0], #4
230	ldrt	r9, [r0], #4
231	stmia	r1!, {r10-r11}
232	ldrt	r10, [r0], #4
233	ldrt	r11, [r0], #4
234	stmia	r1!, {r6-r11}
235
236	cmp	r2, #0x08
237	blt	.Liprecleanup
238
239.Licleanup8:
240	ldrt	r8, [r0], #4
241	ldrt	r9, [r0], #4
242	sub	r2, r2, #8
243	stmia	r1!, {r8, r9}
244	cmp	r2, #8
245	bge	.Licleanup8
246
247.Liprecleanup:
248	/*
249	 * If we're done, bail.
250	 */
251	cmp	r2, #0
252	beq	.Lout
253
254.Licleanup:
255	and	r6, r2, #0x3
256	ldr	pc, [pc, r6, lsl #2]
257	b	.Licend
258	.word	.Lic4
259	.word	.Lic1
260	.word	.Lic2
261	.word	.Lic3
262.Lic4:	ldrbt	r6, [r0], #1
263	sub	r2, r2, #1
264	strb	r6, [r1], #1
265.Lic3:	ldrbt	r7, [r0], #1
266	sub	r2, r2, #1
267	strb	r7, [r1], #1
268.Lic2:	ldrbt	r6, [r0], #1
269	sub	r2, r2, #1
270	strb	r6, [r1], #1
271.Lic1:	ldrbt	r7, [r0], #1
272	subs	r2, r2, #1
273	strb	r7, [r1], #1
274.Licend:
275	bne	.Licleanup
276
277.Liout:
278	mov	r0, #0
279
280	str	r5, [r4, #PCB_ONFAULT]
281	RESTORE_REGS
282
283	RET
284
285.Lcopyfault:
286	mov	r0, #14 /* EFAULT */
287	str	r5, [r4, #PCB_ONFAULT]
288	RESTORE_REGS
289
290	RET
291
292/*
293 * r0 = kernel space address
294 * r1 = user space address
295 * r2 = length
296 *
297 * Copies bytes from kernel space to user space
298 *
299 * We save/restore r4-r11:
300 * r4-r11 are scratch
301 */
302
303ENTRY(copyout)
304	/* Quick exit if length is zero */
305	teq	r2, #0
306	moveq	r0, #0
307	RETeq
308
309	SAVE_REGS
310#ifdef MULTIPROCESSOR
311	/* XXX Probably not appropriate for non-Hydra SMPs */
312	stmfd	sp!, {r0-r2, r14}
313	bl	_C_LABEL(cpu_number)
314	ldr	r4, .Lcpu_info
315	ldr	r4, [r4, r0, lsl #2]
316	ldr	r4, [r4, #CI_CURPCB]
317	ldmfd	sp!, {r0-r2, r14}
318#else
319	ldr	r4, .Lcurpcb
320	ldr	r4, [r4]
321#endif
322
323	ldr	r5, [r4, #PCB_ONFAULT]
324	adr	r3, .Lcopyfault
325	str	r3, [r4, #PCB_ONFAULT]
326
327	PREFETCH(r0, 0)
328	PREFETCH(r1, 0)
329
330	/*
331	 * If not too many bytes, take the slow path.
332	 */
333	cmp	r2, #0x08
334	blt	.Lcleanup
335
336	/*
337	 * Align destination to word boundary.
338	 */
339	and	r6, r1, #0x3
340	ldr	pc, [pc, r6, lsl #2]
341	b	.Lalend
342	.word	.Lalend
343	.word	.Lal3
344	.word	.Lal2
345	.word	.Lal1
346.Lal3:	ldrb	r6, [r0], #1
347	sub	r2, r2, #1
348	strbt	r6, [r1], #1
349.Lal2:	ldrb	r7, [r0], #1
350	sub	r2, r2, #1
351	strbt	r7, [r1], #1
352.Lal1:	ldrb	r6, [r0], #1
353	sub	r2, r2, #1
354	strbt	r6, [r1], #1
355.Lalend:
356
357	/*
358	 * If few bytes left, finish slow.
359	 */
360	cmp	r2, #0x08
361	blt	.Lcleanup
362
363	/*
364	 * If source is not aligned, finish slow.
365	 */
366	ands	r3, r0, #0x03
367	bne	.Lcleanup
368
369	cmp	r2, #0x60	/* Must be > 0x5f for unrolled cacheline */
370	blt	.Lcleanup8
371
372	/*
373	 * Align source & destination to cacheline boundary.
374	 */
375	and	r6, r1, #0x1f
376	ldr	pc, [pc, r6]
377	b	.Lcaligned
378	.word	.Lcaligned
379	.word	.Lcal28
380	.word	.Lcal24
381	.word	.Lcal20
382	.word	.Lcal16
383	.word	.Lcal12
384	.word	.Lcal8
385	.word	.Lcal4
386.Lcal28:ldr	r6, [r0], #4
387	sub	r2, r2, #4
388	strt	r6, [r1], #4
389.Lcal24:ldr	r7, [r0], #4
390	sub	r2, r2, #4
391	strt	r7, [r1], #4
392.Lcal20:ldr	r6, [r0], #4
393	sub	r2, r2, #4
394	strt	r6, [r1], #4
395.Lcal16:ldr	r7, [r0], #4
396	sub	r2, r2, #4
397	strt	r7, [r1], #4
398.Lcal12:ldr	r6, [r0], #4
399	sub	r2, r2, #4
400	strt	r6, [r1], #4
401.Lcal8:	ldr	r7, [r0], #4
402	sub	r2, r2, #4
403	strt	r7, [r1], #4
404.Lcal4:	ldr	r6, [r0], #4
405	sub	r2, r2, #4
406	strt	r6, [r1], #4
407
408	/*
409	 * We start with > 0x40 bytes to copy (>= 0x60 got us into this
410	 * part of the code, and we may have knocked that down by as much
411	 * as 0x1c getting aligned).
412	 *
413	 * This loop basically works out to:
414	 * do {
415	 * 	prefetch-next-cacheline(s)
416	 *	bytes -= 0x20;
417	 *	copy cacheline
418	 * } while (bytes >= 0x40);
419	 * bytes -= 0x20;
420	 * copy cacheline
421	 */
422.Lcaligned:
423	PREFETCH(r0, 32)
424	PREFETCH(r1, 32)
425
426	sub	r2, r2, #0x20
427
428	/* Copy a cacheline */
429	ldmia	r0!, {r6-r11}
430	strt	r6, [r1], #4
431	strt	r7, [r1], #4
432	ldmia	r0!, {r6-r7}
433	strt	r8, [r1], #4
434	strt	r9, [r1], #4
435	strt	r10, [r1], #4
436	strt	r11, [r1], #4
437	strt	r6, [r1], #4
438	strt	r7, [r1], #4
439
440	cmp	r2, #0x40
441	bge	.Lcaligned
442
443	sub	r2, r2, #0x20
444
445	/* Copy a cacheline */
446	ldmia	r0!, {r6-r11}
447	strt	r6, [r1], #4
448	strt	r7, [r1], #4
449	ldmia	r0!, {r6-r7}
450	strt	r8, [r1], #4
451	strt	r9, [r1], #4
452	strt	r10, [r1], #4
453	strt	r11, [r1], #4
454	strt	r6, [r1], #4
455	strt	r7, [r1], #4
456
457	cmp	r2, #0x08
458	blt	.Lprecleanup
459
460.Lcleanup8:
461	ldmia	r0!, {r8-r9}
462	sub	r2, r2, #8
463	strt	r8, [r1], #4
464	strt	r9, [r1], #4
465	cmp	r2, #8
466	bge	.Lcleanup8
467
468.Lprecleanup:
469	/*
470	 * If we're done, bail.
471	 */
472	cmp	r2, #0
473	beq	.Lout
474
475.Lcleanup:
476	and	r6, r2, #0x3
477	ldr	pc, [pc, r6, lsl #2]
478	b	.Lcend
479	.word	.Lc4
480	.word	.Lc1
481	.word	.Lc2
482	.word	.Lc3
483.Lc4:	ldrb	r6, [r0], #1
484	sub	r2, r2, #1
485	strbt	r6, [r1], #1
486.Lc3:	ldrb	r7, [r0], #1
487	sub	r2, r2, #1
488	strbt	r7, [r1], #1
489.Lc2:	ldrb	r6, [r0], #1
490	sub	r2, r2, #1
491	strbt	r6, [r1], #1
492.Lc1:	ldrb	r7, [r0], #1
493	subs	r2, r2, #1
494	strbt	r7, [r1], #1
495.Lcend:
496	bne	.Lcleanup
497
498.Lout:
499	mov	r0, #0
500
501	str	r5, [r4, #PCB_ONFAULT]
502	RESTORE_REGS
503
504	RET
505
506/*
507 * r0 = kernel space source address
508 * r1 = kernel space destination address
509 * r2 = length
510 *
511 * Copies bytes from kernel space to kernel space, aborting on page fault
512 *
513 * Copy of copyout, but without the ldrt/strt instructions.
514 */
515
516ENTRY(kcopy)
517	/* Quick exit if length is zero */
518	teq	r2, #0
519	moveq	r0, #0
520	RETeq
521
522	SAVE_REGS
523#ifdef MULTIPROCESSOR
524	/* XXX Probably not appropriate for non-Hydra SMPs */
525	stmfd	sp!, {r0-r2, r14}
526	bl	_C_LABEL(cpu_number)
527	ldr	r4, .Lcpu_info
528	ldr	r4, [r4, r0, lsl #2]
529	ldr	r4, [r4, #CI_CURPCB]
530	ldmfd	sp!, {r0-r2, r14}
531#else
532	ldr	r4, .Lcurpcb
533	ldr	r4, [r4]
534#endif
535
536	ldr	r5, [r4, #PCB_ONFAULT]
537	adr	r3, .Lcopyfault
538	str	r3, [r4, #PCB_ONFAULT]
539
540	PREFETCH(r0, 0)
541	PREFETCH(r1, 0)
542
543	/*
544	 * If not too many bytes, take the slow path.
545	 */
546	cmp	r2, #0x08
547	blt	.Lkcleanup
548
549	/*
550	 * Align destination to word boundary.
551	 */
552	and	r6, r1, #0x3
553	ldr	pc, [pc, r6, lsl #2]
554	b	.Lkalend
555	.word	.Lkalend
556	.word	.Lkal3
557	.word	.Lkal2
558	.word	.Lkal1
559.Lkal3:	ldrb	r6, [r0], #1
560	sub	r2, r2, #1
561	strb	r6, [r1], #1
562.Lkal2:	ldrb	r7, [r0], #1
563	sub	r2, r2, #1
564	strb	r7, [r1], #1
565.Lkal1:	ldrb	r6, [r0], #1
566	sub	r2, r2, #1
567	strb	r6, [r1], #1
568.Lkalend:
569
570	/*
571	 * If few bytes left, finish slow.
572	 */
573	cmp	r2, #0x08
574	blt	.Lkcleanup
575
576	/*
577	 * If source is not aligned, finish slow.
578	 */
579	ands	r3, r0, #0x03
580	bne	.Lkcleanup
581
582	cmp	r2, #0x60	/* Must be > 0x5f for unrolled cacheline */
583	blt	.Lkcleanup8
584
585	/*
586	 * Align source & destination to cacheline boundary.
587	 */
588	and	r6, r1, #0x1f
589	ldr	pc, [pc, r6]
590	b	.Lkcaligned
591	.word	.Lkcaligned
592	.word	.Lkcal28
593	.word	.Lkcal24
594	.word	.Lkcal20
595	.word	.Lkcal16
596	.word	.Lkcal12
597	.word	.Lkcal8
598	.word	.Lkcal4
599.Lkcal28:ldr	r6, [r0], #4
600	sub	r2, r2, #4
601	str	r6, [r1], #4
602.Lkcal24:ldr	r7, [r0], #4
603	sub	r2, r2, #4
604	str	r7, [r1], #4
605.Lkcal20:ldr	r6, [r0], #4
606	sub	r2, r2, #4
607	str	r6, [r1], #4
608.Lkcal16:ldr	r7, [r0], #4
609	sub	r2, r2, #4
610	str	r7, [r1], #4
611.Lkcal12:ldr	r6, [r0], #4
612	sub	r2, r2, #4
613	str	r6, [r1], #4
614.Lkcal8:ldr	r7, [r0], #4
615	sub	r2, r2, #4
616	str	r7, [r1], #4
617.Lkcal4:ldr	r6, [r0], #4
618	sub	r2, r2, #4
619	str	r6, [r1], #4
620
621	/*
622	 * We start with > 0x40 bytes to copy (>= 0x60 got us into this
623	 * part of the code, and we may have knocked that down by as much
624	 * as 0x1c getting aligned).
625	 *
626	 * This loop basically works out to:
627	 * do {
628	 * 	prefetch-next-cacheline(s)
629	 *	bytes -= 0x20;
630	 *	copy cacheline
631	 * } while (bytes >= 0x40);
632	 * bytes -= 0x20;
633	 * copy cacheline
634	 */
635.Lkcaligned:
636	PREFETCH(r0, 32)
637	PREFETCH(r1, 32)
638
639	sub	r2, r2, #0x20
640
641	/* Copy a cacheline */
642	ldmia	r0!, {r6-r11}
643	stmia	r1!, {r6, r7}
644	ldmia	r0!, {r6, r7}
645	stmia	r1!, {r8-r11}
646	stmia	r1!, {r6, r7}
647
648	cmp	r2, #0x40
649	bge	.Lkcaligned
650
651	sub	r2, r2, #0x20
652
653	/* Copy a cacheline */
654	ldmia	r0!, {r6-r11}
655	stmia	r1!, {r6-r7}
656	ldmia	r0!, {r6-r7}
657	stmia	r1!, {r8-r11}
658	stmia	r1!, {r6-r7}
659
660	cmp	r2, #0x08
661	blt	.Lkprecleanup
662
663.Lkcleanup8:
664	ldmia	r0!, {r8-r9}
665	sub	r2, r2, #8
666	stmia	r1!, {r8-r9}
667	cmp	r2, #8
668	bge	.Lkcleanup8
669
670.Lkprecleanup:
671	/*
672	 * If we're done, bail.
673	 */
674	cmp	r2, #0
675	beq	.Lkout
676
677.Lkcleanup:
678	and	r6, r2, #0x3
679	ldr	pc, [pc, r6, lsl #2]
680	b	.Lkcend
681	.word	.Lkc4
682	.word	.Lkc1
683	.word	.Lkc2
684	.word	.Lkc3
685.Lkc4:	ldrb	r6, [r0], #1
686	sub	r2, r2, #1
687	strb	r6, [r1], #1
688.Lkc3:	ldrb	r7, [r0], #1
689	sub	r2, r2, #1
690	strb	r7, [r1], #1
691.Lkc2:	ldrb	r6, [r0], #1
692	sub	r2, r2, #1
693	strb	r6, [r1], #1
694.Lkc1:	ldrb	r7, [r0], #1
695	subs	r2, r2, #1
696	strb	r7, [r1], #1
697.Lkcend:
698	bne	.Lkcleanup
699
700.Lkout:
701	mov	r0, #0
702
703	str	r5, [r4, #PCB_ONFAULT]
704	RESTORE_REGS
705
706	RET
707#endif	/* !__XSCALE__ */
708
709/*
710 * int badaddr_read_1(const uint8_t *src, uint8_t *dest)
711 *
712 * Copies a single 8-bit value from src to dest, returning 0 on success,
713 * else EFAULT if a page fault occurred.
714 */
715ENTRY(badaddr_read_1)
716#ifdef MULTIPROCESSOR
717	/* XXX Probably not appropriate for non-Hydra SMPs */
718	stmfd	sp!, {r0-r1, r14}
719	bl	_C_LABEL(cpu_number)
720	ldr	r2, .Lcpu_info
721	ldr	r2, [r2, r0, lsl #2]
722	ldr	r2, [r2, #CI_CURPCB]
723	ldmfd	sp!, {r0-r1, r14}
724#else
725	ldr	r2, .Lcurpcb
726	ldr	r2, [r2]
727#endif
728	ldr	ip, [r2, #PCB_ONFAULT]
729	adr	r3, 1f
730	str	r3, [r2, #PCB_ONFAULT]
731	nop
732	nop
733	nop
734	ldrb	r3, [r0]
735	nop
736	nop
737	nop
738	strb	r3, [r1]
739	mov	r0, #0		/* No fault */
7401:	str	ip, [r2, #PCB_ONFAULT]
741	RET
742
743/*
744 * int badaddr_read_2(const uint16_t *src, uint16_t *dest)
745 *
746 * Copies a single 16-bit value from src to dest, returning 0 on success,
747 * else EFAULT if a page fault occurred.
748 */
749ENTRY(badaddr_read_2)
750#ifdef MULTIPROCESSOR
751	/* XXX Probably not appropriate for non-Hydra SMPs */
752	stmfd	sp!, {r0-r1, r14}
753	bl	_C_LABEL(cpu_number)
754	ldr	r2, .Lcpu_info
755	ldr	r2, [r2, r0, lsl #2]
756	ldr	r2, [r2, #CI_CURPCB]
757	ldmfd	sp!, {r0-r1, r14}
758#else
759	ldr	r2, .Lcurpcb
760	ldr	r2, [r2]
761#endif
762	ldr	ip, [r2, #PCB_ONFAULT]
763	adr	r3, 1f
764	str	r3, [r2, #PCB_ONFAULT]
765	nop
766	nop
767	nop
768	ldrh	r3, [r0]
769	nop
770	nop
771	nop
772	strh	r3, [r1]
773	mov	r0, #0		/* No fault */
7741:	str	ip, [r2, #PCB_ONFAULT]
775	RET
776
777/*
778 * int badaddr_read_4(const uint32_t *src, uint32_t *dest)
779 *
780 * Copies a single 32-bit value from src to dest, returning 0 on success,
781 * else EFAULT if a page fault occurred.
782 */
783ENTRY(badaddr_read_4)
784#ifdef MULTIPROCESSOR
785	/* XXX Probably not appropriate for non-Hydra SMPs */
786	stmfd	sp!, {r0-r1, r14}
787	bl	_C_LABEL(cpu_number)
788	ldr	r2, .Lcpu_info
789	ldr	r2, [r2, r0, lsl #2]
790	ldr	r2, [r2, #CI_CURPCB]
791	ldmfd	sp!, {r0-r1, r14}
792#else
793	ldr	r2, .Lcurpcb
794	ldr	r2, [r2]
795#endif
796	ldr	ip, [r2, #PCB_ONFAULT]
797	adr	r3, 1f
798	str	r3, [r2, #PCB_ONFAULT]
799	nop
800	nop
801	nop
802	ldr	r3, [r0]
803	nop
804	nop
805	nop
806	str	r3, [r1]
807	mov	r0, #0		/* No fault */
8081:	str	ip, [r2, #PCB_ONFAULT]
809	RET
810
811