1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 2008 David E. O'Brien 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the author nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include <sys/param.h> 36 #include <sys/capsicum.h> 37 #include <sys/cdio.h> 38 #include <sys/fcntl.h> 39 #include <sys/filio.h> 40 #include <sys/file.h> 41 #include <sys/ioccom.h> 42 #include <sys/malloc.h> 43 #include <sys/memrange.h> 44 #include <sys/pciio.h> 45 #include <sys/proc.h> 46 #include <sys/syscall.h> 47 #include <sys/syscallsubr.h> 48 #include <sys/sysctl.h> 49 #include <sys/sysent.h> 50 #include <sys/sysproto.h> 51 #include <sys/systm.h> 52 #include <sys/uio.h> 53 54 #include <compat/freebsd32/freebsd32.h> 55 #include <compat/freebsd32/freebsd32_ioctl.h> 56 #include <compat/freebsd32/freebsd32_misc.h> 57 #include <compat/freebsd32/freebsd32_proto.h> 58 59 CTASSERT(sizeof(struct mem_range_op32) == 12); 60 61 static int 62 freebsd32_ioctl_fiodgname(struct thread *td, 63 struct freebsd32_ioctl_args *uap, struct file *fp) 64 { 65 struct fiodgname_arg fgn; 66 struct fiodgname_arg32 fgn32; 67 int error; 68 69 if ((error = copyin(uap->data, &fgn32, sizeof fgn32)) != 0) 70 return (error); 71 CP(fgn32, fgn, len); 72 PTRIN_CP(fgn32, fgn, buf); 73 error = fo_ioctl(fp, FIODGNAME, (caddr_t)&fgn, td->td_ucred, td); 74 return (error); 75 } 76 77 static int 78 freebsd32_ioctl_memrange(struct thread *td, 79 struct freebsd32_ioctl_args *uap, struct file *fp) 80 { 81 struct mem_range_op mro; 82 struct mem_range_op32 mro32; 83 int error; 84 u_long com; 85 86 if ((error = copyin(uap->data, &mro32, sizeof(mro32))) != 0) 87 return (error); 88 89 PTRIN_CP(mro32, mro, mo_desc); 90 CP(mro32, mro, mo_arg[0]); 91 CP(mro32, mro, mo_arg[1]); 92 93 com = 0; 94 switch (uap->com) { 95 case MEMRANGE_GET32: 96 com = MEMRANGE_GET; 97 break; 98 99 case MEMRANGE_SET32: 100 com = MEMRANGE_SET; 101 break; 102 103 default: 104 panic("%s: unknown MEMRANGE %#x", __func__, uap->com); 105 } 106 107 if ((error = fo_ioctl(fp, com, (caddr_t)&mro, td->td_ucred, td)) != 0) 108 return (error); 109 110 if ( (com & IOC_OUT) ) { 111 CP(mro, mro32, mo_arg[0]); 112 CP(mro, mro32, mo_arg[1]); 113 114 error = copyout(&mro32, uap->data, sizeof(mro32)); 115 } 116 117 return (error); 118 } 119 120 static int 121 freebsd32_ioctl_barmmap(struct thread *td, 122 struct freebsd32_ioctl_args *uap, struct file *fp) 123 { 124 struct pci_bar_mmap32 pbm32; 125 struct pci_bar_mmap pbm; 126 int error; 127 128 error = copyin(uap->data, &pbm32, sizeof(pbm32)); 129 if (error != 0) 130 return (error); 131 PTRIN_CP(pbm32, pbm, pbm_map_base); 132 CP(pbm32, pbm, pbm_sel); 133 CP(pbm32, pbm, pbm_reg); 134 CP(pbm32, pbm, pbm_flags); 135 CP(pbm32, pbm, pbm_memattr); 136 pbm.pbm_bar_length = PAIR32TO64(uint64_t, pbm32.pbm_bar_length); 137 error = fo_ioctl(fp, PCIOCBARMMAP, (caddr_t)&pbm, td->td_ucred, td); 138 if (error == 0) { 139 PTROUT_CP(pbm, pbm32, pbm_map_base); 140 CP(pbm, pbm32, pbm_map_length); 141 #if BYTE_ORDER == LITTLE_ENDIAN 142 pbm32.pbm_bar_length1 = pbm.pbm_bar_length; 143 pbm32.pbm_bar_length2 = pbm.pbm_bar_length >> 32; 144 #else 145 pbm32.pbm_bar_length1 = pbm.pbm_bar_length >> 32; 146 pbm32.pbm_bar_length2 = pbm.pbm_bar_length; 147 #endif 148 CP(pbm, pbm32, pbm_bar_off); 149 error = copyout(&pbm32, uap->data, sizeof(pbm32)); 150 } 151 return (error); 152 } 153 154 static int 155 freebsd32_ioctl_sg(struct thread *td, 156 struct freebsd32_ioctl_args *uap, struct file *fp) 157 { 158 struct sg_io_hdr io; 159 struct sg_io_hdr32 io32; 160 int error; 161 162 if ((error = copyin(uap->data, &io32, sizeof(io32))) != 0) 163 return (error); 164 165 CP(io32, io, interface_id); 166 CP(io32, io, dxfer_direction); 167 CP(io32, io, cmd_len); 168 CP(io32, io, mx_sb_len); 169 CP(io32, io, iovec_count); 170 CP(io32, io, dxfer_len); 171 PTRIN_CP(io32, io, dxferp); 172 PTRIN_CP(io32, io, cmdp); 173 PTRIN_CP(io32, io, sbp); 174 CP(io32, io, timeout); 175 CP(io32, io, flags); 176 CP(io32, io, pack_id); 177 PTRIN_CP(io32, io, usr_ptr); 178 CP(io32, io, status); 179 CP(io32, io, masked_status); 180 CP(io32, io, msg_status); 181 CP(io32, io, sb_len_wr); 182 CP(io32, io, host_status); 183 CP(io32, io, driver_status); 184 CP(io32, io, resid); 185 CP(io32, io, duration); 186 CP(io32, io, info); 187 188 if ((error = fo_ioctl(fp, SG_IO, (caddr_t)&io, td->td_ucred, td)) != 0) 189 return (error); 190 191 CP(io, io32, interface_id); 192 CP(io, io32, dxfer_direction); 193 CP(io, io32, cmd_len); 194 CP(io, io32, mx_sb_len); 195 CP(io, io32, iovec_count); 196 CP(io, io32, dxfer_len); 197 PTROUT_CP(io, io32, dxferp); 198 PTROUT_CP(io, io32, cmdp); 199 PTROUT_CP(io, io32, sbp); 200 CP(io, io32, timeout); 201 CP(io, io32, flags); 202 CP(io, io32, pack_id); 203 PTROUT_CP(io, io32, usr_ptr); 204 CP(io, io32, status); 205 CP(io, io32, masked_status); 206 CP(io, io32, msg_status); 207 CP(io, io32, sb_len_wr); 208 CP(io, io32, host_status); 209 CP(io, io32, driver_status); 210 CP(io, io32, resid); 211 CP(io, io32, duration); 212 CP(io, io32, info); 213 214 error = copyout(&io32, uap->data, sizeof(io32)); 215 216 return (error); 217 } 218 219 int 220 freebsd32_ioctl(struct thread *td, struct freebsd32_ioctl_args *uap) 221 { 222 struct ioctl_args ap /*{ 223 int fd; 224 u_long com; 225 caddr_t data; 226 }*/ ; 227 struct file *fp; 228 cap_rights_t rights; 229 int error; 230 231 error = fget(td, uap->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); 232 if (error != 0) 233 return (error); 234 if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 235 fdrop(fp, td); 236 return (EBADF); 237 } 238 239 switch (uap->com) { 240 case FIODGNAME_32: 241 error = freebsd32_ioctl_fiodgname(td, uap, fp); 242 break; 243 244 case MEMRANGE_GET32: /* FALLTHROUGH */ 245 case MEMRANGE_SET32: 246 error = freebsd32_ioctl_memrange(td, uap, fp); 247 break; 248 249 case SG_IO_32: 250 error = freebsd32_ioctl_sg(td, uap, fp); 251 break; 252 253 case PCIOCBARMMAP_32: 254 error = freebsd32_ioctl_barmmap(td, uap, fp); 255 break; 256 257 default: 258 fdrop(fp, td); 259 ap.fd = uap->fd; 260 ap.com = uap->com; 261 PTRIN_CP(*uap, ap, data); 262 return sys_ioctl(td, &ap); 263 } 264 265 fdrop(fp, td); 266 return (error); 267 } 268