xref: /netbsd/sys/arch/i386/i386/copy.S (revision d71e829b)
1*d71e829bSmaxv/*	$NetBSD: copy.S,v 1.32 2020/06/30 16:20:01 maxv Exp $	*/
2443e88c5Syamt
3f42d24b1Smaxv/*
452b171caSad * Copyright (c) 1998, 2000, 2004, 2008 The NetBSD Foundation, Inc.
5443e88c5Syamt * All rights reserved.
6443e88c5Syamt *
7443e88c5Syamt * This code is derived from software contributed to The NetBSD Foundation
8443e88c5Syamt * by Charles M. Hannum.
9443e88c5Syamt *
10443e88c5Syamt * Redistribution and use in source and binary forms, with or without
11443e88c5Syamt * modification, are permitted provided that the following conditions
12443e88c5Syamt * are met:
13443e88c5Syamt * 1. Redistributions of source code must retain the above copyright
14443e88c5Syamt *    notice, this list of conditions and the following disclaimer.
15443e88c5Syamt * 2. Redistributions in binary form must reproduce the above copyright
16443e88c5Syamt *    notice, this list of conditions and the following disclaimer in the
17443e88c5Syamt *    documentation and/or other materials provided with the distribution.
18443e88c5Syamt *
19443e88c5Syamt * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20443e88c5Syamt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21443e88c5Syamt * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22443e88c5Syamt * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23443e88c5Syamt * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24443e88c5Syamt * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25443e88c5Syamt * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26443e88c5Syamt * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27443e88c5Syamt * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28443e88c5Syamt * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29443e88c5Syamt * POSSIBILITY OF SUCH DAMAGE.
30443e88c5Syamt */
31443e88c5Syamt
32f42d24b1Smaxv/*
33443e88c5Syamt * Copyright (c) 1990 The Regents of the University of California.
34443e88c5Syamt * All rights reserved.
35443e88c5Syamt *
36443e88c5Syamt * This code is derived from software contributed to Berkeley by
37443e88c5Syamt * William Jolitz.
38443e88c5Syamt *
39443e88c5Syamt * Redistribution and use in source and binary forms, with or without
40443e88c5Syamt * modification, are permitted provided that the following conditions
41443e88c5Syamt * are met:
42443e88c5Syamt * 1. Redistributions of source code must retain the above copyright
43443e88c5Syamt *    notice, this list of conditions and the following disclaimer.
44443e88c5Syamt * 2. Redistributions in binary form must reproduce the above copyright
45443e88c5Syamt *    notice, this list of conditions and the following disclaimer in the
46443e88c5Syamt *    documentation and/or other materials provided with the distribution.
47443e88c5Syamt * 3. Neither the name of the University nor the names of its contributors
48443e88c5Syamt *    may be used to endorse or promote products derived from this software
49443e88c5Syamt *    without specific prior written permission.
50443e88c5Syamt *
51443e88c5Syamt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52443e88c5Syamt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53443e88c5Syamt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54443e88c5Syamt * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55443e88c5Syamt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56443e88c5Syamt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57443e88c5Syamt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58443e88c5Syamt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59443e88c5Syamt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60443e88c5Syamt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61443e88c5Syamt * SUCH DAMAGE.
62443e88c5Syamt *
63443e88c5Syamt *	@(#)locore.s	7.3 (Berkeley) 5/13/91
64443e88c5Syamt */
65443e88c5Syamt
66a4914dc7Slukem#include <machine/asm.h>
67*d71e829bSmaxv__KERNEL_RCSID(0, "$NetBSD: copy.S,v 1.32 2020/06/30 16:20:01 maxv Exp $");
68a4914dc7Slukem
69443e88c5Syamt#include "assym.h"
70443e88c5Syamt
71443e88c5Syamt#include <sys/errno.h>
72443e88c5Syamt
73443e88c5Syamt#include <machine/frameasm.h>
74443e88c5Syamt#include <machine/cputypes.h>
75443e88c5Syamt
76f0301095Syamt#define GET_CURPCB(reg)	\
77f0301095Syamt	movl	CPUVAR(CURLWP),reg; \
783f18fe81Srmind	movl	L_PCB(reg),reg
79443e88c5Syamt
80443e88c5Syamt/*
8164bcc9bdSad * These are arranged so that the abnormal case is a forwards
8264bcc9bdSad * conditional branch - which will be predicted not-taken by
8364bcc9bdSad * both Intel and AMD processors.
8464bcc9bdSad */
8564bcc9bdSad#define DEFERRED_SWITCH_CHECK \
8664bcc9bdSad	CHECK_DEFERRED_SWITCH			; \
8764bcc9bdSad	jnz	99f				; \
8864bcc9bdSad98:
8964bcc9bdSad
9064bcc9bdSad#define DEFERRED_SWITCH_CALL \
9164bcc9bdSad99:						; \
9264bcc9bdSad	call	_C_LABEL(do_pmap_load)		; \
9364bcc9bdSad	jmp	98b
9464bcc9bdSad
9564bcc9bdSad/*
9652b171caSad * The following primitives are to copy regions of memory.
97614719fdSrmind * Label must be before all copy functions.
98443e88c5Syamt */
9964bcc9bdSad	.text
100dd80381cSchsLABEL(x86_copyfunc_start)
10164bcc9bdSad
10264bcc9bdSad/*
10364bcc9bdSad * Handle deferred pmap switch.  We must re-enable preemption without
10464bcc9bdSad * making a function call, so that the program counter is visible to
10564bcc9bdSad * cpu_kpreempt_exit().  It can then know if it needs to restore the
10664bcc9bdSad * pmap on returning, because a preemption occurred within one of the
10764bcc9bdSad * copy functions.
10864bcc9bdSad */
1090c52a5deSmaxvENTRY(do_pmap_load)
11064bcc9bdSad	pushl	%ebp
11164bcc9bdSad	movl	%esp,%ebp
11264bcc9bdSad	pushl	%ebx
11364bcc9bdSad	movl	CPUVAR(CURLWP),%ebx
11464bcc9bdSad1:
11564bcc9bdSad	incl	L_NOPREEMPT(%ebx)
11664bcc9bdSad	call	_C_LABEL(pmap_load)
11764bcc9bdSad	decl	L_NOPREEMPT(%ebx)
11864bcc9bdSad	jnz	2f
11964bcc9bdSad	cmpl	$0,L_DOPREEMPT(%ebx)
12064bcc9bdSad	jz	2f
12164bcc9bdSad	pushl	$0
12264bcc9bdSad	call	_C_LABEL(kpreempt)
12364bcc9bdSad	addl	$4,%esp
12464bcc9bdSad2:
12564bcc9bdSad	cmpl	$0,CPUVAR(WANT_PMAPLOAD)
12664bcc9bdSad	jnz	1b
12764bcc9bdSad	popl	%ebx
12864bcc9bdSad	leave
12964bcc9bdSad	ret
130f42d24b1SmaxvEND(do_pmap_load)
131443e88c5Syamt
132443e88c5Syamt/*
1333d5b001dSdyoung * void *return_address(unsigned int level);
1343d5b001dSdyoung *
1353d5b001dSdyoung * The return address if level == 0, the return address of the caller
1363d5b001dSdyoung * `level' levels down the stack if level > 0.
1373d5b001dSdyoung */
1383d5b001dSdyoungENTRY(return_address)
1393d5b001dSdyoung	movl	%ebp,%eax	/* frame pointer -> %eax */
1403d5b001dSdyoung	movl	4(%esp),%ecx	/* level -> %ecx */
1415df4a900Sdyoung	movl	CPUVAR(CURLWP),%edx
1423f18fe81Srmind	movl	L_PCB(%edx),%edx
1435df4a900Sdyoung	movl	$_C_LABEL(return_address_fault),PCB_ONFAULT(%edx)
1443d5b001dSdyoung	cmpl	$0,%ecx
1453d5b001dSdyoung	je	2f
1463d5b001dSdyoung1:
1473d5b001dSdyoung	movl	(%eax),%eax	/* next frame pointer */
1483d5b001dSdyoung	decl	%ecx
1493d5b001dSdyoung	jnz	1b
1503d5b001dSdyoung2:
1513d5b001dSdyoung	movl	0x4(%eax),%eax
1525df4a900Sdyoung	movl	$0,PCB_ONFAULT(%edx)
1533d5b001dSdyoung	ret
154f42d24b1SmaxvEND(return_address)
1553d5b001dSdyoung
1563d5b001dSdyoung/*
157443e88c5Syamt * int kcopy(const void *from, void *to, size_t len);
158f42d24b1Smaxv * Copy len bytes from and to kernel memory, and abort on fault.
159443e88c5Syamt */
160443e88c5SyamtENTRY(kcopy)
161443e88c5Syamt	pushl	%esi
162443e88c5Syamt	pushl	%edi
163d0f12a6aSyamt	movl	12(%esp),%esi
164d0f12a6aSyamt	movl	16(%esp),%edi
165d0f12a6aSyamt	movl	20(%esp),%ecx
16664bcc9bdSad.Lkcopy_start:
167443e88c5Syamt	movl	%edi,%eax
168443e88c5Syamt	subl	%esi,%eax
16919a4beadSmaxv	cmpl	%ecx,%eax		/* overlapping? */
170d0f12a6aSyamt	movl	%ecx,%edx
171443e88c5Syamt	jb	1f
17219a4beadSmaxv	/* nope, copy forward */
17319a4beadSmaxv	shrl	$2,%ecx			/* copy by 32-bit words */
174443e88c5Syamt	rep
175443e88c5Syamt	movsl
176d0f12a6aSyamt	movl	%edx,%ecx
17719a4beadSmaxv	andl	$3,%ecx			/* any bytes left? */
17833e2fcd0Sad	jz	0f
179443e88c5Syamt	rep
180443e88c5Syamt	movsb
18133e2fcd0Sad0:
182443e88c5Syamt	popl	%edi
183443e88c5Syamt	popl	%esi
184443e88c5Syamt	xorl	%eax,%eax
185443e88c5Syamt	ret
186443e88c5Syamt
187443e88c5Syamt	ALIGN_TEXT
18819a4beadSmaxv1:	addl	%ecx,%edi		/* copy backward */
189443e88c5Syamt	addl	%ecx,%esi
190443e88c5Syamt	std
19119a4beadSmaxv	andl	$3,%ecx			/* any fractional bytes? */
192443e88c5Syamt	decl	%edi
193443e88c5Syamt	decl	%esi
194443e88c5Syamt	rep
195443e88c5Syamt	movsb
19619a4beadSmaxv	movl	%edx,%ecx		/* copy remainder by 32-bit words */
197443e88c5Syamt	shrl	$2,%ecx
198443e88c5Syamt	subl	$3,%esi
199443e88c5Syamt	subl	$3,%edi
200443e88c5Syamt	rep
201443e88c5Syamt	movsl
202443e88c5Syamt	cld
203443e88c5Syamt
204d0f12a6aSyamt.Lkcopy_end:
205443e88c5Syamt	popl	%edi
206443e88c5Syamt	popl	%esi
207443e88c5Syamt	xorl	%eax,%eax
208443e88c5Syamt	ret
209f42d24b1SmaxvEND(kcopy)
210443e88c5Syamt
211443e88c5Syamt/*****************************************************************************/
212443e88c5Syamt
213443e88c5Syamt/*
214443e88c5Syamt * The following primitives are used to copy data in and out of the user's
215443e88c5Syamt * address space.
216443e88c5Syamt */
217443e88c5Syamt
218443e88c5Syamt/*
219443e88c5Syamt * int copyout(const void *from, void *to, size_t len);
220443e88c5Syamt * Copy len bytes into the user's address space.
221443e88c5Syamt * see copyout(9)
222443e88c5Syamt */
223443e88c5SyamtENTRY(copyout)
22464bcc9bdSad	DEFERRED_SWITCH_CHECK
225deae4f32Sad	pushl	%esi
226deae4f32Sad	pushl	%edi
227f42d24b1Smaxv	movl	12(%esp),%esi	/* from */
228f42d24b1Smaxv	movl	16(%esp),%edi	/* to */
229f42d24b1Smaxv	movl	20(%esp),%eax	/* len */
230f42d24b1Smaxv
231443e88c5Syamt	movl	%edi,%edx
232443e88c5Syamt	addl	%eax,%edx
233443e88c5Syamt	jc	_C_LABEL(copy_efault)
234443e88c5Syamt	cmpl	$VM_MAXUSER_ADDRESS,%edx
235443e88c5Syamt	ja	_C_LABEL(copy_efault)
236f42d24b1Smaxv
237ce18565bSmaxv	SMAP_DISABLE
238f42d24b1Smaxv.Lcopyout_start:
239443e88c5Syamt	movl	%eax,%ecx
240443e88c5Syamt	shrl	$2,%ecx
241443e88c5Syamt	rep
242443e88c5Syamt	movsl
24333e2fcd0Sad	andl	$3,%eax
244f42d24b1Smaxv	jz	.Lcopyout_end
245443e88c5Syamt	movl	%eax,%ecx
246443e88c5Syamt	rep
247443e88c5Syamt	movsb
248d0f12a6aSyamt.Lcopyout_end:
249ce18565bSmaxv	SMAP_ENABLE
250f42d24b1Smaxv
251443e88c5Syamt	popl	%edi
252443e88c5Syamt	popl	%esi
253443e88c5Syamt	xorl	%eax,%eax
254443e88c5Syamt	ret
25564bcc9bdSad	DEFERRED_SWITCH_CALL
256f42d24b1SmaxvEND(copyout)
257443e88c5Syamt
258443e88c5Syamt/*
259443e88c5Syamt * int copyin(const void *from, void *to, size_t len);
260443e88c5Syamt * Copy len bytes from the user's address space.
261443e88c5Syamt * see copyin(9)
262443e88c5Syamt */
263443e88c5SyamtENTRY(copyin)
26464bcc9bdSad	DEFERRED_SWITCH_CHECK
265443e88c5Syamt	pushl	%esi
266443e88c5Syamt	pushl	%edi
267f42d24b1Smaxv	movl	12(%esp),%esi	/* from */
268f42d24b1Smaxv	movl	16(%esp),%edi	/* to */
269f42d24b1Smaxv	movl	20(%esp),%eax	/* len */
270f42d24b1Smaxv
271443e88c5Syamt	movl	%esi,%edx
272443e88c5Syamt	addl	%eax,%edx
273443e88c5Syamt	jc	_C_LABEL(copy_efault)
274443e88c5Syamt	cmpl	$VM_MAXUSER_ADDRESS,%edx
275443e88c5Syamt	ja	_C_LABEL(copy_efault)
276f42d24b1Smaxv
277ce18565bSmaxv	SMAP_DISABLE
278f42d24b1Smaxv.Lcopyin_start:
279443e88c5Syamt	movl	%eax,%ecx
280443e88c5Syamt	shrl	$2,%ecx
281443e88c5Syamt	rep
282443e88c5Syamt	movsl
28333e2fcd0Sad	andl	$3,%eax
284f42d24b1Smaxv	jz	.Lcopyin_end
285443e88c5Syamt	movl	%eax,%ecx
286443e88c5Syamt	rep
287443e88c5Syamt	movsb
288d0f12a6aSyamt.Lcopyin_end:
289ce18565bSmaxv	SMAP_ENABLE
290f42d24b1Smaxv
291443e88c5Syamt	popl	%edi
292443e88c5Syamt	popl	%esi
293443e88c5Syamt	xorl	%eax,%eax
294443e88c5Syamt	ret
29564bcc9bdSad	DEFERRED_SWITCH_CALL
296f42d24b1SmaxvEND(copyin)
297443e88c5Syamt
2980c52a5deSmaxvENTRY(copy_efault)
299443e88c5Syamt	movl	$EFAULT,%eax
300f42d24b1Smaxv	popl	%edi
301f42d24b1Smaxv	popl	%esi
302f42d24b1Smaxv	ret
303f42d24b1SmaxvEND(copy_efault)
304443e88c5Syamt
305443e88c5Syamt/*
306443e88c5Syamt * kcopy_fault is used by kcopy and copy_fault is used by copyin/out.
307443e88c5Syamt *
308443e88c5Syamt * they're distinguished for lazy pmap switching.  see trap().
309443e88c5Syamt */
310f42d24b1Smaxv
3110c52a5deSmaxvENTRY(kcopy_fault)
3128f3bea6eSmaxv	cld
313443e88c5Syamt	popl	%edi
314443e88c5Syamt	popl	%esi
315443e88c5Syamt	ret
316f42d24b1SmaxvEND(kcopy_fault)
317443e88c5Syamt
3180c52a5deSmaxvENTRY(copy_fault)
319ce18565bSmaxv	SMAP_ENABLE
320443e88c5Syamt	popl	%edi
321443e88c5Syamt	popl	%esi
322443e88c5Syamt	ret
323f42d24b1SmaxvEND(copy_fault)
324443e88c5Syamt
3250c52a5deSmaxvENTRY(return_address_fault)
3265df4a900Sdyoung	movl	$0,PCB_ONFAULT(%edx)
3273d5b001dSdyoung	movl	$0,%eax
3283d5b001dSdyoung	ret
329f42d24b1SmaxvEND(return_address_fault)
3303d5b001dSdyoung
331443e88c5Syamt/*
332443e88c5Syamt * int copyoutstr(const void *from, void *to, size_t maxlen, size_t *lencopied);
333443e88c5Syamt * Copy a NUL-terminated string, at most maxlen characters long, into the
334443e88c5Syamt * user's address space.  Return the number of characters copied (including the
335443e88c5Syamt * NUL) in *lencopied.  If the string is too long, return ENAMETOOLONG; else
336443e88c5Syamt * return 0 or EFAULT.
337443e88c5Syamt * see copyoutstr(9)
338443e88c5Syamt */
339443e88c5SyamtENTRY(copyoutstr)
34064bcc9bdSad	DEFERRED_SWITCH_CHECK
341443e88c5Syamt	pushl	%esi
342443e88c5Syamt	pushl	%edi
34319a4beadSmaxv	movl	12(%esp),%esi	/* esi = from */
34419a4beadSmaxv	movl	16(%esp),%edi	/* edi = to */
34519a4beadSmaxv	movl	20(%esp),%edx	/* edx = maxlen */
346f42d24b1Smaxv
347443e88c5Syamt	/*
348443e88c5Syamt	 * Get min(%edx, VM_MAXUSER_ADDRESS-%edi).
349443e88c5Syamt	 */
350443e88c5Syamt	movl	$VM_MAXUSER_ADDRESS,%eax
351443e88c5Syamt	subl	%edi,%eax
352443e88c5Syamt	jc	_C_LABEL(copystr_efault)
353443e88c5Syamt	cmpl	%edx,%eax
354443e88c5Syamt	jae	1f
355443e88c5Syamt	movl	%eax,%edx
356443e88c5Syamt	movl	%eax,20(%esp)
357443e88c5Syamt1:	incl	%edx
358443e88c5Syamt
359ce18565bSmaxv	SMAP_DISABLE
360f42d24b1Smaxv.Lcopyoutstr_start:
361443e88c5Syamt1:	decl	%edx
362443e88c5Syamt	jz	2f
363443e88c5Syamt	lodsb
364443e88c5Syamt	stosb
365443e88c5Syamt	testb	%al,%al
366443e88c5Syamt	jnz	1b
367f42d24b1Smaxv.Lcopyoutstr_end:
368ce18565bSmaxv	SMAP_ENABLE
369443e88c5Syamt
370443e88c5Syamt	/* Success -- 0 byte reached. */
371443e88c5Syamt	decl	%edx
372443e88c5Syamt	xorl	%eax,%eax
373443e88c5Syamt	jmp	copystr_return
374443e88c5Syamt
375443e88c5Syamt2:	/* edx is zero -- return EFAULT or ENAMETOOLONG. */
376ce18565bSmaxv	SMAP_ENABLE
377443e88c5Syamt	cmpl	$VM_MAXUSER_ADDRESS,%edi
378443e88c5Syamt	jae	_C_LABEL(copystr_efault)
379443e88c5Syamt	movl	$ENAMETOOLONG,%eax
380443e88c5Syamt	jmp	copystr_return
38164bcc9bdSad	DEFERRED_SWITCH_CALL
382f42d24b1SmaxvEND(copyoutstr)
383443e88c5Syamt
384443e88c5Syamt/*
385443e88c5Syamt * int copyinstr(const void *from, void *to, size_t maxlen, size_t *lencopied);
386443e88c5Syamt * Copy a NUL-terminated string, at most maxlen characters long, from the
387443e88c5Syamt * user's address space.  Return the number of characters copied (including the
388443e88c5Syamt * NUL) in *lencopied.  If the string is too long, return ENAMETOOLONG; else
389443e88c5Syamt * return 0 or EFAULT.
390443e88c5Syamt * see copyinstr(9)
391443e88c5Syamt */
392443e88c5SyamtENTRY(copyinstr)
39364bcc9bdSad	DEFERRED_SWITCH_CHECK
394443e88c5Syamt	pushl	%esi
395443e88c5Syamt	pushl	%edi
39619a4beadSmaxv	movl	12(%esp),%esi		/* %esi = from */
39719a4beadSmaxv	movl	16(%esp),%edi		/* %edi = to */
39819a4beadSmaxv	movl	20(%esp),%edx		/* %edx = maxlen */
399443e88c5Syamt
400443e88c5Syamt	/*
401443e88c5Syamt	 * Get min(%edx, VM_MAXUSER_ADDRESS-%esi).
402443e88c5Syamt	 */
403443e88c5Syamt	movl	$VM_MAXUSER_ADDRESS,%eax
404443e88c5Syamt	subl	%esi,%eax
405443e88c5Syamt	jc	_C_LABEL(copystr_efault)
406443e88c5Syamt	cmpl	%edx,%eax
407443e88c5Syamt	jae	1f
408443e88c5Syamt	movl	%eax,%edx
409443e88c5Syamt	movl	%eax,20(%esp)
410443e88c5Syamt1:	incl	%edx
411443e88c5Syamt
412ce18565bSmaxv	SMAP_DISABLE
413f42d24b1Smaxv.Lcopyinstr_start:
414443e88c5Syamt1:	decl	%edx
415443e88c5Syamt	jz	2f
416443e88c5Syamt	lodsb
417443e88c5Syamt	stosb
418443e88c5Syamt	testb	%al,%al
419443e88c5Syamt	jnz	1b
420f42d24b1Smaxv.Lcopyinstr_end:
421ce18565bSmaxv	SMAP_ENABLE
422443e88c5Syamt
423443e88c5Syamt	/* Success -- 0 byte reached. */
424443e88c5Syamt	decl	%edx
425443e88c5Syamt	xorl	%eax,%eax
426443e88c5Syamt	jmp	copystr_return
427443e88c5Syamt
428443e88c5Syamt2:	/* edx is zero -- return EFAULT or ENAMETOOLONG. */
429ce18565bSmaxv	SMAP_ENABLE
430443e88c5Syamt	cmpl	$VM_MAXUSER_ADDRESS,%esi
431443e88c5Syamt	jae	_C_LABEL(copystr_efault)
432443e88c5Syamt	movl	$ENAMETOOLONG,%eax
433443e88c5Syamt	jmp	copystr_return
43464bcc9bdSad	DEFERRED_SWITCH_CALL
435f42d24b1SmaxvEND(copyinstr)
436443e88c5Syamt
4370c52a5deSmaxvENTRY(copystr_efault)
438443e88c5Syamt	movl	$EFAULT,%eax
439f42d24b1Smaxv	jmp	copystr_return
440f42d24b1SmaxvEND(copystr_efault)
441443e88c5Syamt
4420c52a5deSmaxvENTRY(copystr_fault)
443ce18565bSmaxv	SMAP_ENABLE
444443e88c5Syamtcopystr_return:
445443e88c5Syamt	/* Set *lencopied and return %eax. */
446443e88c5Syamt	movl	20(%esp),%ecx
447443e88c5Syamt	subl	%edx,%ecx
448443e88c5Syamt	movl	24(%esp),%edx
449443e88c5Syamt	testl	%edx,%edx
450443e88c5Syamt	jz	8f
451443e88c5Syamt	movl	%ecx,(%edx)
452443e88c5Syamt
453443e88c5Syamt8:	popl	%edi
454443e88c5Syamt	popl	%esi
455443e88c5Syamt	ret
456f42d24b1SmaxvEND(copystr_fault)
457443e88c5Syamt
458e3f92458Sthorpej/**************************************************************************/
459e3f92458Sthorpej
46015ef08dfSthorpej#define	UFETCHSTORE_PROLOGUE(x)						\
461e3f92458Sthorpej	movl	4(%esp),%edx					;	\
46215ef08dfSthorpej	cmpl	$VM_MAXUSER_ADDRESS-x,%edx			;	\
463e3f92458Sthorpej	ja	_C_LABEL(ufetchstore_efault)
464e3f92458Sthorpej
465e3f92458Sthorpej/* LINTSTUB: int _ufetch_8(const uint8_t *uaddr, uint8_t *valp); */
466e3f92458SthorpejENTRY(_ufetch_8)
46764bcc9bdSad	DEFERRED_SWITCH_CHECK
46815ef08dfSthorpej	UFETCHSTORE_PROLOGUE(1)
469f42d24b1Smaxv
470ce18565bSmaxv	SMAP_DISABLE
471e3f92458Sthorpej.L_ufetch_8_start:
472e3f92458Sthorpej	movb	(%edx),%al
473e3f92458Sthorpej.L_ufetch_8_end:
474ce18565bSmaxv	SMAP_ENABLE
475f42d24b1Smaxv
476e3f92458Sthorpej	movl	8(%esp),%edx
477e3f92458Sthorpej	movb	%al,(%edx)
478443e88c5Syamt	xorl	%eax,%eax
479443e88c5Syamt	ret
480e3f92458Sthorpej	DEFERRED_SWITCH_CALL
481e3f92458SthorpejEND(_ufetch_8)
482443e88c5Syamt
483e3f92458Sthorpej/* LINTSTUB: int _ufetch_16(const uint16_t *uaddr, uint16_t *valp); */
484e3f92458SthorpejENTRY(_ufetch_16)
48564bcc9bdSad	DEFERRED_SWITCH_CHECK
48615ef08dfSthorpej	UFETCHSTORE_PROLOGUE(2)
487e3f92458Sthorpej
488e3f92458Sthorpej	SMAP_DISABLE
489e3f92458Sthorpej.L_ufetch_16_start:
490e3f92458Sthorpej	movw	(%edx),%ax
491e3f92458Sthorpej.L_ufetch_16_end:
492e3f92458Sthorpej	SMAP_ENABLE
493e3f92458Sthorpej
494e3f92458Sthorpej	movl	8(%esp),%edx
495e3f92458Sthorpej	movw	%ax,(%edx)
496e3f92458Sthorpej	xorl	%eax,%eax
497e3f92458Sthorpej	ret
498e3f92458Sthorpej	DEFERRED_SWITCH_CALL
499e3f92458SthorpejEND(_ufetch_16)
500e3f92458Sthorpej
501e3f92458Sthorpej/* LINTSTUB: int _ufetch_32(const uint32_t *uaddr, uint32_t *valp); */
502e3f92458SthorpejENTRY(_ufetch_32)
503e3f92458Sthorpej	DEFERRED_SWITCH_CHECK
50415ef08dfSthorpej	UFETCHSTORE_PROLOGUE(4)
505e3f92458Sthorpej
506e3f92458Sthorpej	SMAP_DISABLE
507e3f92458Sthorpej.L_ufetch_32_start:
508e3f92458Sthorpej	movl	(%edx),%eax
509e3f92458Sthorpej.L_ufetch_32_end:
510e3f92458Sthorpej	SMAP_ENABLE
511e3f92458Sthorpej
512e3f92458Sthorpej	movl	8(%esp),%edx
513e3f92458Sthorpej	movl	%eax,(%edx)
514e3f92458Sthorpej	xorl	%eax,%eax
515e3f92458Sthorpej	ret
516e3f92458Sthorpej	DEFERRED_SWITCH_CALL
517e3f92458SthorpejEND(_ufetch_32)
518e3f92458Sthorpej
519e3f92458Sthorpej/* LINTSTUB: int _ustore_8(uint8_t *uaddr, uint8_t val); */
520e3f92458SthorpejENTRY(_ustore_8)
521e3f92458Sthorpej	DEFERRED_SWITCH_CHECK
52215ef08dfSthorpej	UFETCHSTORE_PROLOGUE(1)
523443e88c5Syamt	movb	8(%esp),%al
524f42d24b1Smaxv
525ce18565bSmaxv	SMAP_DISABLE
526e3f92458Sthorpej.L_ustore_8_start:
527443e88c5Syamt	movb	%al,(%edx)
528e3f92458Sthorpej.L_ustore_8_end:
529ce18565bSmaxv	SMAP_ENABLE
530f42d24b1Smaxv
531443e88c5Syamt	xorl	%eax,%eax
532443e88c5Syamt	ret
53364bcc9bdSad	DEFERRED_SWITCH_CALL
534e3f92458SthorpejEND(_ustore_8)
535e3f92458Sthorpej
536e3f92458Sthorpej/* LINTSTUB: int _ustore_16(uint16_t *uaddr, uint16_t val); */
537e3f92458SthorpejENTRY(_ustore_16)
538e3f92458Sthorpej	DEFERRED_SWITCH_CHECK
53915ef08dfSthorpej	UFETCHSTORE_PROLOGUE(2)
540e3f92458Sthorpej	movw	8(%esp),%ax
541e3f92458Sthorpej
542e3f92458Sthorpej	SMAP_DISABLE
543e3f92458Sthorpej.L_ustore_16_start:
544e3f92458Sthorpej	movw	%ax,(%edx)
545e3f92458Sthorpej.L_ustore_16_end:
546e3f92458Sthorpej	SMAP_ENABLE
547e3f92458Sthorpej
548e3f92458Sthorpej	xorl	%eax,%eax
549e3f92458Sthorpej	ret
550e3f92458Sthorpej	DEFERRED_SWITCH_CALL
551e3f92458SthorpejEND(_ustore_16)
552e3f92458Sthorpej
553e3f92458Sthorpej/* LINTSTUB: int _ustore_32(uint32_t *uaddr, uint32_t val); */
554e3f92458SthorpejENTRY(_ustore_32)
555e3f92458Sthorpej	DEFERRED_SWITCH_CHECK
55615ef08dfSthorpej	UFETCHSTORE_PROLOGUE(4)
557e3f92458Sthorpej	movl	8(%esp),%eax
558e3f92458Sthorpej
559e3f92458Sthorpej	SMAP_DISABLE
560e3f92458Sthorpej.L_ustore_32_start:
561e3f92458Sthorpej	movl	%eax,(%edx)
562e3f92458Sthorpej.L_ustore_32_end:
563e3f92458Sthorpej	SMAP_ENABLE
564e3f92458Sthorpej
565e3f92458Sthorpej	xorl	%eax,%eax
566e3f92458Sthorpej	ret
567e3f92458Sthorpej	DEFERRED_SWITCH_CALL
568e3f92458SthorpejEND(_ustore_32)
569e3f92458Sthorpej
570e3f92458SthorpejENTRY(ufetchstore_efault)
571e3f92458Sthorpej	movl	$EFAULT,%eax
572e3f92458Sthorpej	ret
573e3f92458SthorpejEND(ufetchstore_efault)
574e3f92458Sthorpej
575e3f92458SthorpejENTRY(ufetchstore_fault)
576e3f92458Sthorpej	SMAP_ENABLE
577e3f92458Sthorpej	ret
578e3f92458SthorpejEND(ufetchstore_fault)
579e3f92458Sthorpej
580e3f92458Sthorpej/**************************************************************************/
58117be89c2Sad
58217be89c2Sad/*
583f7d3fa20Srmind * Compare-and-swap the 32-bit integer in the user-space.
584f7d3fa20Srmind *
585e3f92458Sthorpej * int	_ucas_32(volatile uint32_t *uptr, uint32_t old, uint32_t new,
586e3f92458Sthorpej *		 uint32_t *ret);
587f7d3fa20Srmind */
588e3f92458SthorpejENTRY(_ucas_32)
589f7d3fa20Srmind	DEFERRED_SWITCH_CHECK
590f7d3fa20Srmind	movl	4(%esp),%edx
591f7d3fa20Srmind	movl	8(%esp),%eax
592f7d3fa20Srmind	movl	12(%esp),%ecx
593f7d3fa20Srmind	/* Fail if kernel-space */
594f7d3fa20Srmind	cmpl	$VM_MAXUSER_ADDRESS-4,%edx
595dd80381cSchs	ja	_C_LABEL(ucas_efault)
596f42d24b1Smaxv
597ce18565bSmaxv	SMAP_DISABLE
598f7d3fa20Srmind.Lucas32_start:
599f7d3fa20Srmind	/* Perform the CAS */
600f7d3fa20Srmind	lock
601f7d3fa20Srmind	cmpxchgl %ecx,(%edx)
602f7d3fa20Srmind.Lucas32_end:
603ce18565bSmaxv	SMAP_ENABLE
604f42d24b1Smaxv
605f7d3fa20Srmind	/*
606f7d3fa20Srmind	 * Note: %eax is "old" value.
607f7d3fa20Srmind	 * Set the return values.
608f7d3fa20Srmind	 */
609f7d3fa20Srmind	movl	16(%esp),%edx
610f7d3fa20Srmind	movl	%eax,(%edx)
611f7d3fa20Srmind	xorl	%eax,%eax
612f7d3fa20Srmind	ret
613f7d3fa20Srmind	DEFERRED_SWITCH_CALL
614e3f92458SthorpejEND(_ucas_32)
615f7d3fa20Srmind
6160c52a5deSmaxvENTRY(ucas_efault)
617f42d24b1Smaxv	movl	$EFAULT,%eax
618f42d24b1Smaxv	ret
619f42d24b1SmaxvEND(ucas_efault)
620f42d24b1Smaxv
6210c52a5deSmaxvENTRY(ucas_fault)
622ce18565bSmaxv	SMAP_ENABLE
623f7d3fa20Srmind	ret
624f42d24b1SmaxvEND(ucas_fault)
625f7d3fa20Srmind
626f7d3fa20Srmind/*
62717be89c2Sad * copyin() optimised for bringing in syscall arguments.
62817be89c2Sad */
62917be89c2SadENTRY(x86_copyargs)
63064bcc9bdSad	DEFERRED_SWITCH_CHECK
63117be89c2Sad	pushl	%esi
632d0f12a6aSyamt	movl	8(%esp),%esi
633d0f12a6aSyamt	movl	12(%esp),%edx
634d0f12a6aSyamt	movl	16(%esp),%ecx
63517be89c2Sad
63617be89c2Sad	/*
637548506e1Smaxv	 * In this function, we may copy more than the size given in the third
638548506e1Smaxv	 * argument. In order to make sure the real end of the destination
639548506e1Smaxv	 * buffer is not past the end of the user's address space, we don't
640548506e1Smaxv	 * check the third argument but rather the largest possible size, which
641548506e1Smaxv	 * is:
642548506e1Smaxv	 * 	(2 + SYS_MAXSYSARGS) * 4 = 10 * 4
64317be89c2Sad	 */
64417be89c2Sad	movl	%esi,%eax
645548506e1Smaxv	addl	$(10 * 4),%eax
64617be89c2Sad	jc	_C_LABEL(x86_copyargs_efault)
64717be89c2Sad	cmpl	$VM_MAXUSER_ADDRESS,%eax
64817be89c2Sad	ja	_C_LABEL(x86_copyargs_efault)
649f42d24b1Smaxv
650ce18565bSmaxv	SMAP_DISABLE
651f42d24b1Smaxv.Lx86_copyargs_start:
652aa21c280Sdsl	/* There are a maximum of 8 args + 2 for syscall indirect */
653aa21c280Sdsl	cmp	$16,%ecx
65417be89c2Sad	movl	(%esi),%eax
655aa21c280Sdsl	movl	4(%esi),%ecx
65617be89c2Sad	movl	%eax,(%edx)
657aa21c280Sdsl	movl	%ecx,4(%edx)
65817be89c2Sad	movl	8(%esi),%eax
659aa21c280Sdsl	movl	12(%esi),%ecx
66017be89c2Sad	movl	%eax,8(%edx)
661aa21c280Sdsl	movl	%ecx,12(%edx)
662f42d24b1Smaxv
663aa21c280Sdsl	ja	2f		/* Optimise since most sycalls have <= 4 args */
664f42d24b1Smaxv	jmp	.Lx86_copyargs_end
665aa21c280Sdsl2:
666f42d24b1Smaxv
667aa21c280Sdsl	movl	16(%esi),%eax
668aa21c280Sdsl	movl	20(%esi),%ecx
669aa21c280Sdsl	movl	%eax,16(%edx)
670aa21c280Sdsl	movl	%ecx,20(%edx)
671aa21c280Sdsl	movl	24(%esi),%eax
672aa21c280Sdsl	movl	28(%esi),%ecx
673aa21c280Sdsl	movl	%eax,24(%edx)
674aa21c280Sdsl	movl	%ecx,28(%edx)
675aa21c280Sdsl	movl	32(%esi),%eax
676aa21c280Sdsl	movl	36(%esi),%ecx
677aa21c280Sdsl	movl	%eax,32(%edx)
678aa21c280Sdsl	movl	%ecx,36(%edx)
679d0f12a6aSyamt.Lx86_copyargs_end:
680ce18565bSmaxv	SMAP_ENABLE
68117be89c2Sad
682f42d24b1Smaxv	popl	%esi
683f42d24b1Smaxv	xorl	%eax,%eax
684f42d24b1Smaxv	ret
685f42d24b1Smaxv	DEFERRED_SWITCH_CALL
686f42d24b1SmaxvEND(x86_copyargs)
687f42d24b1Smaxv
6880c52a5deSmaxvENTRY(x86_copyargs_efault)
68917be89c2Sad	movl	$EFAULT,%eax
690f42d24b1Smaxv	popl	%esi
691f42d24b1Smaxv	ret
692f42d24b1SmaxvEND(x86_copyargs_efault)
69317be89c2Sad
6940c52a5deSmaxvENTRY(x86_copyargs_fault)
695ce18565bSmaxv	SMAP_ENABLE
69617be89c2Sad	popl	%esi
69717be89c2Sad	ret
698f42d24b1SmaxvEND(x86_copyargs_fault)
69964bcc9bdSad
700614719fdSrmind/*
701614719fdSrmind * Label must be after all copy functions.
702614719fdSrmind */
703dd80381cSchsLABEL(x86_copyfunc_end)
704d0f12a6aSyamt
705614719fdSrmind/*
706614719fdSrmind * Fault table of copy functions for trap().
707614719fdSrmind */
708d0f12a6aSyamt	.section ".rodata"
709d0f12a6aSyamt	.globl _C_LABEL(onfault_table)
710f42d24b1Smaxv
711d0f12a6aSyamt_C_LABEL(onfault_table):
712d0f12a6aSyamt	.long .Lcopyin_start
713d0f12a6aSyamt	.long .Lcopyin_end
714d0f12a6aSyamt	.long _C_LABEL(copy_fault)
715d0f12a6aSyamt
716d0f12a6aSyamt	.long .Lcopyout_start
717d0f12a6aSyamt	.long .Lcopyout_end
718d0f12a6aSyamt	.long _C_LABEL(copy_fault)
719d0f12a6aSyamt
720d0f12a6aSyamt	.long .Lkcopy_start
721d0f12a6aSyamt	.long .Lkcopy_end
722d0f12a6aSyamt	.long _C_LABEL(kcopy_fault)
723d0f12a6aSyamt
724d0f12a6aSyamt	.long .Lcopyoutstr_start
725d0f12a6aSyamt	.long .Lcopyoutstr_end
726d0f12a6aSyamt	.long _C_LABEL(copystr_fault)
727d0f12a6aSyamt
728d0f12a6aSyamt	.long .Lcopyinstr_start
729d0f12a6aSyamt	.long .Lcopyinstr_end
730d0f12a6aSyamt	.long _C_LABEL(copystr_fault)
731d0f12a6aSyamt
732f7d3fa20Srmind	.long .Lucas32_start
733f7d3fa20Srmind	.long .Lucas32_end
734f7d3fa20Srmind	.long _C_LABEL(ucas_fault)
735f7d3fa20Srmind
736e3f92458Sthorpej	.long .L_ufetch_8_start
737e3f92458Sthorpej	.long .L_ufetch_8_end
738e3f92458Sthorpej	.long _C_LABEL(ufetchstore_fault)
739e3f92458Sthorpej
740e3f92458Sthorpej	.long .L_ufetch_16_start
741e3f92458Sthorpej	.long .L_ufetch_16_end
742e3f92458Sthorpej	.long _C_LABEL(ufetchstore_fault)
743e3f92458Sthorpej
744e3f92458Sthorpej	.long .L_ufetch_32_start
745e3f92458Sthorpej	.long .L_ufetch_32_end
746e3f92458Sthorpej	.long _C_LABEL(ufetchstore_fault)
747e3f92458Sthorpej
748e3f92458Sthorpej	.long .L_ustore_8_start
749e3f92458Sthorpej	.long .L_ustore_8_end
750e3f92458Sthorpej	.long _C_LABEL(ufetchstore_fault)
751e3f92458Sthorpej
752e3f92458Sthorpej	.long .L_ustore_16_start
753e3f92458Sthorpej	.long .L_ustore_16_end
754e3f92458Sthorpej	.long _C_LABEL(ufetchstore_fault)
755e3f92458Sthorpej
756e3f92458Sthorpej	.long .L_ustore_32_start
757e3f92458Sthorpej	.long .L_ustore_32_end
758e3f92458Sthorpej	.long _C_LABEL(ufetchstore_fault)
759e3f92458Sthorpej
760d0f12a6aSyamt	.long .Lx86_copyargs_start
761d0f12a6aSyamt	.long .Lx86_copyargs_end
762d0f12a6aSyamt	.long _C_LABEL(x86_copyargs_fault)
763d0f12a6aSyamt
764d0f12a6aSyamt	.long 0	/* terminate */
765d0f12a6aSyamt
766d0f12a6aSyamt	.text
767