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