1 /* $NetBSD: linux32_misc.c,v 1.19 2010/07/07 01:30:35 chs Exp $ */ 2 3 /*- 4 * Copyright (c) 1995, 1998, 1999 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Frank van der Linden and Eric Haszlakiewicz; by Jason R. Thorpe 9 * of the Numerical Aerospace Simulation Facility, NASA Ames Research Center; 10 * by Edgar Fu\ss, Mathematisches Institut der Uni Bonn. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: linux32_misc.c,v 1.19 2010/07/07 01:30:35 chs Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/proc.h> 39 #include <sys/time.h> 40 #include <sys/types.h> 41 #include <sys/malloc.h> 42 #include <sys/fstypes.h> 43 #include <sys/vfs_syscalls.h> 44 #include <sys/ptrace.h> 45 #include <sys/syscall.h> 46 47 #include <compat/netbsd32/netbsd32.h> 48 #include <compat/netbsd32/netbsd32_syscallargs.h> 49 50 #include <compat/linux32/common/linux32_types.h> 51 #include <compat/linux32/common/linux32_signal.h> 52 #include <compat/linux32/linux32_syscallargs.h> 53 54 #include <compat/linux/common/linux_ptrace.h> 55 #include <compat/linux/common/linux_types.h> 56 #include <compat/linux/common/linux_emuldata.h> 57 #include <compat/linux/common/linux_signal.h> 58 #include <compat/linux/common/linux_misc.h> 59 #include <compat/linux/common/linux_statfs.h> 60 #include <compat/linux/common/linux_ipc.h> 61 #include <compat/linux/common/linux_sem.h> 62 #include <compat/linux/common/linux_futex.h> 63 #include <compat/linux/linux_syscallargs.h> 64 65 extern const struct linux_mnttypes linux_fstypes[]; 66 extern const int linux_fstypes_cnt; 67 68 void linux32_to_native_timespec(struct timespec *, struct linux32_timespec *); 69 70 /* 71 * Implement the fs stat functions. Straightforward. 72 */ 73 int 74 linux32_sys_statfs(struct lwp *l, const struct linux32_sys_statfs_args *uap, register_t *retval) 75 { 76 /* { 77 syscallarg(const netbsd32_charp char) path; 78 syscallarg(linux32_statfsp) sp; 79 } */ 80 struct statvfs *sb; 81 struct linux_statfs ltmp; 82 int error; 83 84 sb = STATVFSBUF_GET(); 85 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), ST_WAIT, sb); 86 if (error == 0) { 87 bsd_to_linux_statfs(sb, <mp); 88 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); 89 } 90 91 STATVFSBUF_PUT(sb); 92 return error; 93 } 94 95 int 96 linux32_sys_fstatfs(struct lwp *l, const struct linux32_sys_fstatfs_args *uap, register_t *retval) 97 { 98 /* { 99 syscallarg(int) fd; 100 syscallarg(linux32_statfsp) sp; 101 } */ 102 struct statvfs *sb; 103 struct linux_statfs ltmp; 104 int error; 105 106 sb = STATVFSBUF_GET(); 107 error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb); 108 if (error == 0) { 109 bsd_to_linux_statfs(sb, <mp); 110 error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); 111 } 112 STATVFSBUF_PUT(sb); 113 114 return error; 115 } 116 117 extern const int linux_ptrace_request_map[]; 118 119 int 120 linux32_sys_ptrace(struct lwp *l, const struct linux32_sys_ptrace_args *uap, register_t *retval) 121 { 122 /* { 123 i386, m68k, powerpc: T=int 124 alpha, amd64: T=long 125 syscallarg(T) request; 126 syscallarg(T) pid; 127 syscallarg(T) addr; 128 syscallarg(T) data; 129 } */ 130 const int *ptr; 131 int request; 132 int error; 133 134 ptr = linux_ptrace_request_map; 135 request = SCARG(uap, request); 136 while (*ptr != -1) 137 if (*ptr++ == request) { 138 struct sys_ptrace_args pta; 139 140 SCARG(&pta, req) = *ptr; 141 SCARG(&pta, pid) = SCARG(uap, pid); 142 SCARG(&pta, addr) = NETBSD32IPTR64(SCARG(uap, addr)); 143 SCARG(&pta, data) = SCARG(uap, data); 144 145 /* 146 * Linux ptrace(PTRACE_CONT, pid, 0, 0) means actually 147 * to continue where the process left off previously. 148 * The same thing is achieved by addr == (void *) 1 149 * on NetBSD, so rewrite 'addr' appropriately. 150 */ 151 if (request == LINUX_PTRACE_CONT && SCARG(uap, addr)==0) 152 SCARG(&pta, addr) = (void *) 1; 153 154 error = sysent[SYS_ptrace].sy_call(l, &pta, retval); 155 if (error) 156 return error; 157 switch (request) { 158 case LINUX_PTRACE_PEEKTEXT: 159 case LINUX_PTRACE_PEEKDATA: 160 error = copyout (retval, 161 NETBSD32IPTR64(SCARG(uap, data)), 162 sizeof *retval); 163 *retval = SCARG(uap, data); 164 break; 165 default: 166 break; 167 } 168 return error; 169 } 170 else 171 ptr++; 172 173 return EIO; 174 } 175 176 int 177 linux32_sys_personality(struct lwp *l, const struct linux32_sys_personality_args *uap, register_t *retval) 178 { 179 /* { 180 syscallarg(netbsd32_u_long) per; 181 } */ 182 183 switch (SCARG(uap, per)) { 184 case LINUX_PER_LINUX: 185 case LINUX_PER_LINUX32: 186 case LINUX_PER_QUERY: 187 break; 188 default: 189 return EINVAL; 190 } 191 192 retval[0] = LINUX_PER_LINUX; 193 return 0; 194 } 195 196 int 197 linux32_sys_futex(struct lwp *l, 198 const struct linux32_sys_futex_args *uap, register_t *retval) 199 { 200 /* { 201 syscallarg(linux32_intp_t) uaddr; 202 syscallarg(int) op; 203 syscallarg(int) val; 204 syscallarg(linux32_timespecp_t) timeout; 205 syscallarg(linux32_intp_t) uaddr2; 206 syscallarg(int) val3; 207 } */ 208 struct linux_sys_futex_args ua; 209 struct linux32_timespec lts; 210 struct timespec ts = { 0, 0 }; 211 int error; 212 213 NETBSD32TOP_UAP(uaddr, int); 214 NETBSD32TO64_UAP(op); 215 NETBSD32TO64_UAP(val); 216 NETBSD32TOP_UAP(timeout, struct linux_timespec); 217 NETBSD32TOP_UAP(uaddr2, int); 218 NETBSD32TO64_UAP(val3); 219 if ((SCARG(uap, op) & ~LINUX_FUTEX_PRIVATE_FLAG) == LINUX_FUTEX_WAIT && 220 SCARG_P32(uap, timeout) != NULL) { 221 if ((error = copyin((void *)SCARG_P32(uap, timeout), 222 <s, sizeof(lts))) != 0) { 223 return error; 224 } 225 linux32_to_native_timespec(&ts, <s); 226 } 227 return linux_do_futex(l, &ua, retval, &ts); 228 } 229 230 int 231 linux32_sys_set_robust_list(struct lwp *l, 232 const struct linux32_sys_set_robust_list_args *uap, register_t *retval) 233 { 234 /* { 235 syscallarg(linux32_robust_list_headp_t) head; 236 syscallarg(linux32_size_t) len; 237 } */ 238 struct linux_sys_set_robust_list_args ua; 239 struct linux_emuldata *led; 240 241 if (SCARG(uap, len) != 12) 242 return EINVAL; 243 244 NETBSD32TOP_UAP(head, struct robust_list_head); 245 NETBSD32TOX64_UAP(len, size_t); 246 247 led = l->l_emuldata; 248 led->led_robust_head = SCARG(&ua, head); 249 *retval = 0; 250 return 0; 251 } 252 253 int 254 linux32_sys_get_robust_list(struct lwp *l, 255 const struct linux32_sys_get_robust_list_args *uap, register_t *retval) 256 { 257 /* { 258 syscallarg(linux32_robust_list_headpp_t) head; 259 syscallarg(linux32_sizep_t) len; 260 } */ 261 struct linux_sys_get_robust_list_args ua; 262 263 NETBSD32TOP_UAP(head, struct robust_list_head *); 264 NETBSD32TOP_UAP(head, size_t *); 265 return linux_sys_get_robust_list(l, &ua, retval); 266 } 267