xref: /freebsd/sys/i386/linux/linux_copyout.c (revision 3460fab5fced39c7ea597cc7de0ebc3e4c88989a)
10cde66afSKonstantin Belousov /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
30cde66afSKonstantin Belousov  *
40cde66afSKonstantin Belousov  * Copyright (c) 2018 The FreeBSD Foundation
50cde66afSKonstantin Belousov  *
60cde66afSKonstantin Belousov  * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
70cde66afSKonstantin Belousov  * under sponsorship from the FreeBSD Foundation.
80cde66afSKonstantin Belousov  *
90cde66afSKonstantin Belousov  * Redistribution and use in source and binary forms, with or without
100cde66afSKonstantin Belousov  * modification, are permitted provided that the following conditions
110cde66afSKonstantin Belousov  * are met:
120cde66afSKonstantin Belousov  * 1. Redistributions of source code must retain the above copyright
130cde66afSKonstantin Belousov  *    notice, this list of conditions and the following disclaimer.
140cde66afSKonstantin Belousov  * 2. Redistributions in binary form must reproduce the above copyright
150cde66afSKonstantin Belousov  *    notice, this list of conditions and the following disclaimer in the
160cde66afSKonstantin Belousov  *    documentation and/or other materials provided with the distribution.
170cde66afSKonstantin Belousov  *
180cde66afSKonstantin Belousov  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
190cde66afSKonstantin Belousov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
200cde66afSKonstantin Belousov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
210cde66afSKonstantin Belousov  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
220cde66afSKonstantin Belousov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
230cde66afSKonstantin Belousov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
240cde66afSKonstantin Belousov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
250cde66afSKonstantin Belousov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
260cde66afSKonstantin Belousov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
270cde66afSKonstantin Belousov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
280cde66afSKonstantin Belousov  * SUCH DAMAGE.
290cde66afSKonstantin Belousov  */
300cde66afSKonstantin Belousov 
310cde66afSKonstantin Belousov #include <sys/param.h>
320cde66afSKonstantin Belousov #include <sys/imgact.h>
330cde66afSKonstantin Belousov #include <sys/lock.h>
340cde66afSKonstantin Belousov #include <sys/sx.h>
35f4a512a5SDmitry Chagin 
360cde66afSKonstantin Belousov #include <vm/vm.h>
370cde66afSKonstantin Belousov #include <vm/vm_param.h>
380cde66afSKonstantin Belousov #include <vm/vm_extern.h>
390cde66afSKonstantin Belousov #include <vm/pmap.h>
400cde66afSKonstantin Belousov 
410cde66afSKonstantin Belousov #include <machine/atomic.h>
420cde66afSKonstantin Belousov #include <machine/md_var.h>
430cde66afSKonstantin Belousov 
44575e48f1SDmitry Chagin #include <i386/linux/linux.h>
450cde66afSKonstantin Belousov #include <compat/linux/linux_emul.h>
460cde66afSKonstantin Belousov #include <compat/linux/linux_futex.h>
470cde66afSKonstantin Belousov 
480cde66afSKonstantin Belousov struct futex_st0 {
490cde66afSKonstantin Belousov 	int oparg;
500cde66afSKonstantin Belousov 	int *oldval;
510cde66afSKonstantin Belousov };
520cde66afSKonstantin Belousov 
530cde66afSKonstantin Belousov static void
futex_xchgl_slow0(vm_offset_t kva,void * arg)540cde66afSKonstantin Belousov futex_xchgl_slow0(vm_offset_t kva, void *arg)
550cde66afSKonstantin Belousov {
560cde66afSKonstantin Belousov 	struct futex_st0 *st;
570cde66afSKonstantin Belousov 
580cde66afSKonstantin Belousov 	st = arg;
590cde66afSKonstantin Belousov 	*st->oldval = atomic_swap_int((int *)kva, st->oparg);
600cde66afSKonstantin Belousov }
610cde66afSKonstantin Belousov 
620cde66afSKonstantin Belousov int
futex_xchgl(int oparg,uint32_t * uaddr,int * oldval)630cde66afSKonstantin Belousov futex_xchgl(int oparg, uint32_t *uaddr, int *oldval)
640cde66afSKonstantin Belousov {
650cde66afSKonstantin Belousov 	struct futex_st0 st;
660cde66afSKonstantin Belousov 
670cde66afSKonstantin Belousov 	st.oparg = oparg;
680cde66afSKonstantin Belousov 	st.oldval = oldval;
690cde66afSKonstantin Belousov 	if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true,
700cde66afSKonstantin Belousov 	    futex_xchgl_slow0, &st) != 0)
7107d10893SDmitry Chagin 		return (EFAULT);
720cde66afSKonstantin Belousov 	return (0);
730cde66afSKonstantin Belousov }
740cde66afSKonstantin Belousov 
750cde66afSKonstantin Belousov static void
futex_addl_slow0(vm_offset_t kva,void * arg)760cde66afSKonstantin Belousov futex_addl_slow0(vm_offset_t kva, void *arg)
770cde66afSKonstantin Belousov {
780cde66afSKonstantin Belousov 	struct futex_st0 *st;
790cde66afSKonstantin Belousov 
800cde66afSKonstantin Belousov 	st = arg;
810cde66afSKonstantin Belousov 	*st->oldval = atomic_fetchadd_int((int *)kva, st->oparg);
820cde66afSKonstantin Belousov }
830cde66afSKonstantin Belousov 
840cde66afSKonstantin Belousov int
futex_addl(int oparg,uint32_t * uaddr,int * oldval)850cde66afSKonstantin Belousov futex_addl(int oparg, uint32_t *uaddr, int *oldval)
860cde66afSKonstantin Belousov {
870cde66afSKonstantin Belousov 	struct futex_st0 st;
880cde66afSKonstantin Belousov 
890cde66afSKonstantin Belousov 	st.oparg = oparg;
900cde66afSKonstantin Belousov 	st.oldval = oldval;
910cde66afSKonstantin Belousov 	if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true,
920cde66afSKonstantin Belousov 	    futex_addl_slow0, &st) != 0)
9307d10893SDmitry Chagin 		return (EFAULT);
940cde66afSKonstantin Belousov 	return (0);
950cde66afSKonstantin Belousov }
960cde66afSKonstantin Belousov 
970cde66afSKonstantin Belousov static void
futex_orl_slow0(vm_offset_t kva,void * arg)980cde66afSKonstantin Belousov futex_orl_slow0(vm_offset_t kva, void *arg)
990cde66afSKonstantin Belousov {
1000cde66afSKonstantin Belousov 	struct futex_st0 *st;
1010cde66afSKonstantin Belousov 	int old;
1020cde66afSKonstantin Belousov 
1030cde66afSKonstantin Belousov 	st = arg;
1040cde66afSKonstantin Belousov 	old = *(int *)kva;
1050cde66afSKonstantin Belousov 	while (!atomic_fcmpset_int((int *)kva, &old, old | st->oparg))
1060cde66afSKonstantin Belousov 		;
1070cde66afSKonstantin Belousov 	*st->oldval = old;
1080cde66afSKonstantin Belousov }
1090cde66afSKonstantin Belousov 
1100cde66afSKonstantin Belousov int
futex_orl(int oparg,uint32_t * uaddr,int * oldval)1110cde66afSKonstantin Belousov futex_orl(int oparg, uint32_t *uaddr, int *oldval)
1120cde66afSKonstantin Belousov {
1130cde66afSKonstantin Belousov 	struct futex_st0 st;
1140cde66afSKonstantin Belousov 
1150cde66afSKonstantin Belousov 	st.oparg = oparg;
1160cde66afSKonstantin Belousov 	st.oldval = oldval;
1170cde66afSKonstantin Belousov 	if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true,
1180cde66afSKonstantin Belousov 	    futex_orl_slow0, &st) != 0)
11907d10893SDmitry Chagin 		return (EFAULT);
1200cde66afSKonstantin Belousov 	return (0);
1210cde66afSKonstantin Belousov }
1220cde66afSKonstantin Belousov 
1230cde66afSKonstantin Belousov static void
futex_andl_slow0(vm_offset_t kva,void * arg)1240cde66afSKonstantin Belousov futex_andl_slow0(vm_offset_t kva, void *arg)
1250cde66afSKonstantin Belousov {
1260cde66afSKonstantin Belousov 	struct futex_st0 *st;
1270cde66afSKonstantin Belousov 	int old;
1280cde66afSKonstantin Belousov 
1290cde66afSKonstantin Belousov 	st = arg;
1300cde66afSKonstantin Belousov 	old = *(int *)kva;
1310cde66afSKonstantin Belousov 	while (!atomic_fcmpset_int((int *)kva, &old, old & st->oparg))
1320cde66afSKonstantin Belousov 		;
1330cde66afSKonstantin Belousov 	*st->oldval = old;
1340cde66afSKonstantin Belousov }
1350cde66afSKonstantin Belousov 
1360cde66afSKonstantin Belousov int
futex_andl(int oparg,uint32_t * uaddr,int * oldval)1370cde66afSKonstantin Belousov futex_andl(int oparg, uint32_t *uaddr, int *oldval)
1380cde66afSKonstantin Belousov {
1390cde66afSKonstantin Belousov 	struct futex_st0 st;
1400cde66afSKonstantin Belousov 
1410cde66afSKonstantin Belousov 	st.oparg = oparg;
1420cde66afSKonstantin Belousov 	st.oldval = oldval;
1430cde66afSKonstantin Belousov 	if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true,
1440cde66afSKonstantin Belousov 	    futex_andl_slow0, &st) != 0)
14507d10893SDmitry Chagin 		return (EFAULT);
1460cde66afSKonstantin Belousov 	return (0);
1470cde66afSKonstantin Belousov }
1480cde66afSKonstantin Belousov 
1490cde66afSKonstantin Belousov static void
futex_xorl_slow0(vm_offset_t kva,void * arg)1500cde66afSKonstantin Belousov futex_xorl_slow0(vm_offset_t kva, void *arg)
1510cde66afSKonstantin Belousov {
1520cde66afSKonstantin Belousov 	struct futex_st0 *st;
1530cde66afSKonstantin Belousov 	int old;
1540cde66afSKonstantin Belousov 
1550cde66afSKonstantin Belousov 	st = arg;
1560cde66afSKonstantin Belousov 	old = *(int *)kva;
1570cde66afSKonstantin Belousov 	while (!atomic_fcmpset_int((int *)kva, &old, old ^ st->oparg))
1580cde66afSKonstantin Belousov 		;
1590cde66afSKonstantin Belousov 	*st->oldval = old;
1600cde66afSKonstantin Belousov }
1610cde66afSKonstantin Belousov 
1620cde66afSKonstantin Belousov int
futex_xorl(int oparg,uint32_t * uaddr,int * oldval)1630cde66afSKonstantin Belousov futex_xorl(int oparg, uint32_t *uaddr, int *oldval)
1640cde66afSKonstantin Belousov {
1650cde66afSKonstantin Belousov 	struct futex_st0 st;
1660cde66afSKonstantin Belousov 
1670cde66afSKonstantin Belousov 	st.oparg = oparg;
1680cde66afSKonstantin Belousov 	st.oldval = oldval;
1690cde66afSKonstantin Belousov 	if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true,
1700cde66afSKonstantin Belousov 	    futex_xorl_slow0, &st) != 0)
17107d10893SDmitry Chagin 		return (EFAULT);
1720cde66afSKonstantin Belousov 	return (0);
1730cde66afSKonstantin Belousov }
174