/* $NetBSD: linux32_misc.c,v 1.34 2021/11/25 03:08:04 ryo Exp $ */ /*- * Copyright (c) 1995, 1998, 1999 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Frank van der Linden and Eric Haszlakiewicz; by Jason R. Thorpe * of the Numerical Aerospace Simulation Facility, NASA Ames Research Center; * by Edgar Fu\ss, Mathematisches Institut der Uni Bonn. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __KERNEL_RCSID(0, "$NetBSD: linux32_misc.c,v 1.34 2021/11/25 03:08:04 ryo Exp $"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern const struct linux_mnttypes linux_fstypes[]; extern const int linux_fstypes_cnt; /* * Implement the fs stat functions. Straightforward. */ int linux32_sys_statfs(struct lwp *l, const struct linux32_sys_statfs_args *uap, register_t *retval) { /* { syscallarg(const netbsd32_charp char) path; syscallarg(linux32_statfsp) sp; } */ struct statvfs *sb; struct linux_statfs ltmp; int error; sb = STATVFSBUF_GET(); error = do_sys_pstatvfs(l, SCARG_P32(uap, path), ST_WAIT, sb); if (error == 0) { bsd_to_linux_statfs(sb, <mp); error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); } STATVFSBUF_PUT(sb); return error; } int linux32_sys_fstatfs(struct lwp *l, const struct linux32_sys_fstatfs_args *uap, register_t *retval) { /* { syscallarg(int) fd; syscallarg(linux32_statfsp) sp; } */ struct statvfs *sb; struct linux_statfs ltmp; int error; sb = STATVFSBUF_GET(); error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb); if (error == 0) { bsd_to_linux_statfs(sb, <mp); error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); } STATVFSBUF_PUT(sb); return error; } int linux32_sys_statfs64(struct lwp *l, const struct linux32_sys_statfs64_args *uap, register_t *retval) { /* { syscallarg(const netbsd32_charp char) path; syscallarg(linux32_statfs64p) sp; } */ struct statvfs *sb; struct linux_statfs64 ltmp; int error; sb = STATVFSBUF_GET(); error = do_sys_pstatvfs(l, SCARG_P32(uap, path), ST_WAIT, sb); if (error == 0) { bsd_to_linux_statfs64(sb, <mp); error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); } STATVFSBUF_PUT(sb); return error; } int linux32_sys_fstatfs64(struct lwp *l, const struct linux32_sys_fstatfs64_args *uap, register_t *retval) { /* { syscallarg(int) fd; syscallarg(linux32_statfs64p) sp; } */ struct statvfs *sb; struct linux_statfs64 ltmp; int error; sb = STATVFSBUF_GET(); error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb); if (error == 0) { bsd_to_linux_statfs64(sb, <mp); error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); } STATVFSBUF_PUT(sb); return error; } extern const int linux_ptrace_request_map[]; int linux32_sys_ptrace(struct lwp *l, const struct linux32_sys_ptrace_args *uap, register_t *retval) { /* { i386, m68k, powerpc: T=int aarch64, alpha, amd64: T=long syscallarg(T) request; syscallarg(T) pid; syscallarg(T) addr; syscallarg(T) data; } */ const int *ptr; int request; int error; ptr = linux_ptrace_request_map; request = SCARG(uap, request); while (*ptr != -1) if (*ptr++ == request) { struct sys_ptrace_args pta; SCARG(&pta, req) = *ptr; SCARG(&pta, pid) = SCARG(uap, pid); SCARG(&pta, addr) = NETBSD32IPTR64(SCARG(uap, addr)); SCARG(&pta, data) = SCARG(uap, data); /* * Linux ptrace(PTRACE_CONT, pid, 0, 0) means actually * to continue where the process left off previously. * The same thing is achieved by addr == (void *) 1 * on NetBSD, so rewrite 'addr' appropriately. */ if (request == LINUX_PTRACE_CONT && SCARG(uap, addr)==0) SCARG(&pta, addr) = (void *) 1; error = sysent[SYS_ptrace].sy_call(l, &pta, retval); if (error) return error; switch (request) { case LINUX_PTRACE_PEEKTEXT: case LINUX_PTRACE_PEEKDATA: error = copyout (retval, NETBSD32IPTR64(SCARG(uap, data)), sizeof *retval); *retval = SCARG(uap, data); break; default: break; } return error; } else ptr++; return EIO; } int linux32_sys_personality(struct lwp *l, const struct linux32_sys_personality_args *uap, register_t *retval) { /* { syscallarg(netbsd32_u_long) per; } */ struct linux_sys_personality_args ua; NETBSD32TOX_UAP(per, long); return linux_sys_personality(l, &ua, retval); } int linux32_sys_futex(struct lwp *l, const struct linux32_sys_futex_args *uap, register_t *retval) { /* { syscallarg(linux32_intp_t) uaddr; syscallarg(int) op; syscallarg(int) val; syscallarg(linux32_timespecp_t) timeout; syscallarg(linux32_intp_t) uaddr2; syscallarg(int) val3; } */ struct linux32_timespec lts; struct timespec ts, *tsp = NULL; int val2 = 0; int error; /* * Linux overlays the "timeout" field and the "val2" field. * "timeout" is only valid for FUTEX_WAIT and FUTEX_WAIT_BITSET * on Linux. */ const int op = (SCARG(uap, op) & FUTEX_CMD_MASK); if ((op == FUTEX_WAIT || op == FUTEX_WAIT_BITSET) && SCARG_P32(uap, timeout) != NULL) { if ((error = copyin(SCARG_P32(uap, timeout), <s, sizeof(lts))) != 0) { return error; } linux32_to_native_timespec(&ts, <s); tsp = &ts; } else { val2 = (int)(uintptr_t)SCARG_P32(uap, timeout); } return linux_do_futex(SCARG_P32(uap, uaddr), SCARG(uap, op), SCARG(uap, val), tsp, SCARG_P32(uap, uaddr2), val2, SCARG(uap, val3), retval); } int linux32_sys_truncate64(struct lwp *l, const struct linux32_sys_truncate64_args *uap, register_t *retval) { /* { syscallarg(netbsd32_charp) path; syscallarg(off_t) length; } */ struct sys_truncate_args ua; /* Linux doesn't have the 'pad' pseudo-parameter */ NETBSD32TOP_UAP(path, const char *); SCARG(&ua, PAD) = 0; SCARG(&ua, length) = ((off_t)SCARG(uap, lenhi) << 32) + SCARG(uap, lenlo); return sys_truncate(l, &ua, retval); } int linux32_sys_ftruncate64(struct lwp *l, const struct linux32_sys_ftruncate64_args *uap, register_t *retval) { /* { syscallarg(unsigned int) fd; syscallarg(off_t) length; } */ struct sys_ftruncate_args ua; /* Linux doesn't have the 'pad' pseudo-parameter */ NETBSD32TO64_UAP(fd); SCARG(&ua, PAD) = 0; SCARG(&ua, length) = ((off_t)SCARG(uap, lenhi) << 32) + SCARG(uap, lenlo); return sys_ftruncate(l, &ua, retval); } int linux32_sys_setdomainname(struct lwp *l, const struct linux32_sys_setdomainname_args *uap, register_t *retval) { /* { syscallarg(netbsd32_charp) domainname; syscallarg(int) len; } */ struct linux_sys_setdomainname_args ua; NETBSD32TOP_UAP(domainname, char); NETBSD32TO64_UAP(len); return linux_sys_setdomainname(l, &ua, retval); } int linux32_sys_ppoll(struct lwp *l, const struct linux32_sys_ppoll_args *uap, register_t *retval) { /* { syscallarg(netbsd32_pollfdp_t) fds; syscallarg(u_int) nfds; syscallarg(linux32_timespecp_t) timeout; syscallarg(linux32_sigsetp_t) sigset; } */ struct linux32_timespec lts0, *lts; struct timespec ts0, *ts = NULL; linux32_sigset_t lsigmask0, *lsigmask; sigset_t sigmask0, *sigmask = NULL; int error; lts = SCARG_P32(uap, timeout); if (lts) { if ((error = copyin(lts, <s0, sizeof(lts0))) != 0) return error; linux32_to_native_timespec(&ts0, <s0); ts = &ts0; } lsigmask = SCARG_P32(uap, sigset); if (lsigmask) { if ((error = copyin(lsigmask, &lsigmask0, sizeof(lsigmask0)))) return error; linux32_to_native_sigset(&sigmask0, &lsigmask0); sigmask = &sigmask0; } return pollcommon(retval, SCARG_P32(uap, fds), SCARG(uap, nfds), ts, sigmask); } int linux32_sys_eventfd(struct lwp *l, const struct linux32_sys_eventfd_args *uap, register_t *retval) { /* { syscallarg(unsigned int) initval; } */ struct linux_sys_eventfd_args ua; NETBSD32TO64_UAP(initval); return linux_sys_eventfd(l, &ua, retval); } int linux32_sys_eventfd2(struct lwp *l, const struct linux32_sys_eventfd2_args *uap, register_t *retval) { /* { syscallarg(unsigned int) initval; syscallarg(int) flags; } */ struct linux_sys_eventfd2_args ua; NETBSD32TO64_UAP(initval); NETBSD32TO64_UAP(flags); return linux_sys_eventfd2(l, &ua, retval); } static inline off_t linux32_hilo_to_off_t(unsigned long hi, unsigned long lo) { return (((off_t)hi) << 32) | lo; } int linux32_sys_preadv(struct lwp *l, const struct linux32_sys_preadv_args *uap, register_t *retval) { /* { syscallarg(int) fd; syscallarg(const netbsd32_iovecp_t) iovp; syscallarg(int) iovcnt; syscallarg(netbsd32_u_long) off_lo; syscallarg(netbsd32_u_long) off_hi; } */ struct netbsd32_preadv_args ua; SCARG(&ua, fd) = SCARG(uap, fd); SCARG(&ua, iovp) = SCARG(uap, iovp); SCARG(&ua, iovcnt) = SCARG(uap, iovcnt); SCARG(&ua, PAD) = 0; SCARG(&ua, offset) = linux32_hilo_to_off_t(SCARG(uap, off_hi), SCARG(uap, off_lo)); return netbsd32_preadv(l, &ua, retval); } int linux32_sys_pwritev(struct lwp *l, const struct linux32_sys_pwritev_args *uap, register_t *retval) { /* { syscallarg(int) fd; syscallarg(const netbsd32_iovecp_t) iovp; syscallarg(int) iovcnt; syscallarg(netbsd32_u_long) off_lo; syscallarg(netbsd32_u_long) off_hi; } */ struct netbsd32_pwritev_args ua; SCARG(&ua, fd) = SCARG(uap, fd); SCARG(&ua, iovp) = SCARG(uap, iovp); SCARG(&ua, iovcnt) = SCARG(uap, iovcnt); SCARG(&ua, PAD) = 0; SCARG(&ua, offset) = linux32_hilo_to_off_t(SCARG(uap, off_hi), SCARG(uap, off_lo)); return netbsd32_pwritev(l, &ua, retval); }