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 "opt_compat.h" 36 37 #include <sys/param.h> 38 #include <sys/capsicum.h> 39 #include <sys/cdio.h> 40 #include <sys/fcntl.h> 41 #include <sys/filio.h> 42 #include <sys/file.h> 43 #include <sys/ioccom.h> 44 #include <sys/malloc.h> 45 #include <sys/memrange.h> 46 #include <sys/pciio.h> 47 #include <sys/proc.h> 48 #include <sys/syscall.h> 49 #include <sys/syscallsubr.h> 50 #include <sys/sysctl.h> 51 #include <sys/sysent.h> 52 #include <sys/sysproto.h> 53 #include <sys/systm.h> 54 #include <sys/uio.h> 55 56 #include <compat/freebsd32/freebsd32.h> 57 #include <compat/freebsd32/freebsd32_ioctl.h> 58 #include <compat/freebsd32/freebsd32_proto.h> 59 60 CTASSERT(sizeof(struct ioc_read_toc_entry32) == 8); 61 CTASSERT(sizeof(struct mem_range_op32) == 12); 62 CTASSERT(sizeof(struct pci_conf_io32) == 36); 63 CTASSERT(sizeof(struct pci_match_conf32) == 44); 64 CTASSERT(sizeof(struct pci_conf32) == 44); 65 66 static int 67 freebsd32_ioctl_ioc_read_toc(struct thread *td, 68 struct freebsd32_ioctl_args *uap, struct file *fp) 69 { 70 struct ioc_read_toc_entry toce; 71 struct ioc_read_toc_entry32 toce32; 72 int error; 73 74 if ((error = copyin(uap->data, &toce32, sizeof(toce32)))) 75 return (error); 76 CP(toce32, toce, address_format); 77 CP(toce32, toce, starting_track); 78 CP(toce32, toce, data_len); 79 PTRIN_CP(toce32, toce, data); 80 81 if ((error = fo_ioctl(fp, CDIOREADTOCENTRYS, (caddr_t)&toce, 82 td->td_ucred, td))) { 83 CP(toce, toce32, address_format); 84 CP(toce, toce32, starting_track); 85 CP(toce, toce32, data_len); 86 PTROUT_CP(toce, toce32, data); 87 error = copyout(&toce32, uap->data, sizeof(toce32)); 88 } 89 return error; 90 } 91 92 static int 93 freebsd32_ioctl_fiodgname(struct thread *td, 94 struct freebsd32_ioctl_args *uap, struct file *fp) 95 { 96 struct fiodgname_arg fgn; 97 struct fiodgname_arg32 fgn32; 98 int error; 99 100 if ((error = copyin(uap->data, &fgn32, sizeof fgn32)) != 0) 101 return (error); 102 CP(fgn32, fgn, len); 103 PTRIN_CP(fgn32, fgn, buf); 104 error = fo_ioctl(fp, FIODGNAME, (caddr_t)&fgn, td->td_ucred, td); 105 return (error); 106 } 107 108 static int 109 freebsd32_ioctl_memrange(struct thread *td, 110 struct freebsd32_ioctl_args *uap, struct file *fp) 111 { 112 struct mem_range_op mro; 113 struct mem_range_op32 mro32; 114 int error; 115 u_long com; 116 117 if ((error = copyin(uap->data, &mro32, sizeof(mro32))) != 0) 118 return (error); 119 120 PTRIN_CP(mro32, mro, mo_desc); 121 CP(mro32, mro, mo_arg[0]); 122 CP(mro32, mro, mo_arg[1]); 123 124 com = 0; 125 switch (uap->com) { 126 case MEMRANGE_GET32: 127 com = MEMRANGE_GET; 128 break; 129 130 case MEMRANGE_SET32: 131 com = MEMRANGE_SET; 132 break; 133 134 default: 135 panic("%s: unknown MEMRANGE %#x", __func__, uap->com); 136 } 137 138 if ((error = fo_ioctl(fp, com, (caddr_t)&mro, td->td_ucred, td)) != 0) 139 return (error); 140 141 if ( (com & IOC_OUT) ) { 142 CP(mro, mro32, mo_arg[0]); 143 CP(mro, mro32, mo_arg[1]); 144 145 error = copyout(&mro32, uap->data, sizeof(mro32)); 146 } 147 148 return (error); 149 } 150 151 static int 152 freebsd32_ioctl_pciocgetconf(struct thread *td, 153 struct freebsd32_ioctl_args *uap, struct file *fp) 154 { 155 struct pci_conf_io pci; 156 struct pci_conf_io32 pci32; 157 struct pci_match_conf32 pmc32; 158 struct pci_match_conf32 *pmc32p; 159 struct pci_match_conf pmc; 160 struct pci_match_conf *pmcp; 161 struct pci_conf32 pc32; 162 struct pci_conf32 *pc32p; 163 struct pci_conf pc; 164 struct pci_conf *pcp; 165 u_int32_t i; 166 u_int32_t npat_to_convert; 167 u_int32_t nmatch_to_convert; 168 vm_offset_t addr; 169 int error; 170 171 if ((error = copyin(uap->data, &pci32, sizeof(pci32))) != 0) 172 return (error); 173 174 CP(pci32, pci, num_patterns); 175 CP(pci32, pci, offset); 176 CP(pci32, pci, generation); 177 178 npat_to_convert = pci32.pat_buf_len / sizeof(struct pci_match_conf32); 179 pci.pat_buf_len = npat_to_convert * sizeof(struct pci_match_conf); 180 pci.patterns = NULL; 181 nmatch_to_convert = pci32.match_buf_len / sizeof(struct pci_conf32); 182 pci.match_buf_len = nmatch_to_convert * sizeof(struct pci_conf); 183 pci.matches = NULL; 184 185 if ((error = copyout_map(td, &addr, pci.pat_buf_len)) != 0) 186 goto cleanup; 187 pci.patterns = (struct pci_match_conf *)addr; 188 if ((error = copyout_map(td, &addr, pci.match_buf_len)) != 0) 189 goto cleanup; 190 pci.matches = (struct pci_conf *)addr; 191 192 npat_to_convert = min(npat_to_convert, pci.num_patterns); 193 194 for (i = 0, pmc32p = (struct pci_match_conf32 *)PTRIN(pci32.patterns), 195 pmcp = pci.patterns; 196 i < npat_to_convert; i++, pmc32p++, pmcp++) { 197 if ((error = copyin(pmc32p, &pmc32, sizeof(pmc32))) != 0) 198 goto cleanup; 199 CP(pmc32,pmc,pc_sel); 200 strlcpy(pmc.pd_name, pmc32.pd_name, sizeof(pmc.pd_name)); 201 CP(pmc32,pmc,pd_unit); 202 CP(pmc32,pmc,pc_vendor); 203 CP(pmc32,pmc,pc_device); 204 CP(pmc32,pmc,pc_class); 205 CP(pmc32,pmc,flags); 206 if ((error = copyout(&pmc, pmcp, sizeof(pmc))) != 0) 207 goto cleanup; 208 } 209 210 if ((error = fo_ioctl(fp, PCIOCGETCONF, (caddr_t)&pci, 211 td->td_ucred, td)) != 0) 212 goto cleanup; 213 214 nmatch_to_convert = min(nmatch_to_convert, pci.num_matches); 215 216 for (i = 0, pcp = pci.matches, 217 pc32p = (struct pci_conf32 *)PTRIN(pci32.matches); 218 i < nmatch_to_convert; i++, pcp++, pc32p++) { 219 if ((error = copyin(pcp, &pc, sizeof(pc))) != 0) 220 goto cleanup; 221 CP(pc,pc32,pc_sel); 222 CP(pc,pc32,pc_hdr); 223 CP(pc,pc32,pc_subvendor); 224 CP(pc,pc32,pc_subdevice); 225 CP(pc,pc32,pc_vendor); 226 CP(pc,pc32,pc_device); 227 CP(pc,pc32,pc_class); 228 CP(pc,pc32,pc_subclass); 229 CP(pc,pc32,pc_progif); 230 CP(pc,pc32,pc_revid); 231 strlcpy(pc32.pd_name, pc.pd_name, sizeof(pc32.pd_name)); 232 CP(pc,pc32,pd_unit); 233 if ((error = copyout(&pc32, pc32p, sizeof(pc32))) != 0) 234 goto cleanup; 235 } 236 237 CP(pci, pci32, num_matches); 238 CP(pci, pci32, offset); 239 CP(pci, pci32, generation); 240 CP(pci, pci32, status); 241 242 error = copyout(&pci32, uap->data, sizeof(pci32)); 243 244 cleanup: 245 if (pci.patterns) 246 copyout_unmap(td, (vm_offset_t)pci.patterns, pci.pat_buf_len); 247 if (pci.matches) 248 copyout_unmap(td, (vm_offset_t)pci.matches, pci.match_buf_len); 249 250 return (error); 251 } 252 253 static int 254 freebsd32_ioctl_sg(struct thread *td, 255 struct freebsd32_ioctl_args *uap, struct file *fp) 256 { 257 struct sg_io_hdr io; 258 struct sg_io_hdr32 io32; 259 int error; 260 261 if ((error = copyin(uap->data, &io32, sizeof(io32))) != 0) 262 return (error); 263 264 CP(io32, io, interface_id); 265 CP(io32, io, dxfer_direction); 266 CP(io32, io, cmd_len); 267 CP(io32, io, mx_sb_len); 268 CP(io32, io, iovec_count); 269 CP(io32, io, dxfer_len); 270 PTRIN_CP(io32, io, dxferp); 271 PTRIN_CP(io32, io, cmdp); 272 PTRIN_CP(io32, io, sbp); 273 CP(io32, io, timeout); 274 CP(io32, io, flags); 275 CP(io32, io, pack_id); 276 PTRIN_CP(io32, io, usr_ptr); 277 CP(io32, io, status); 278 CP(io32, io, masked_status); 279 CP(io32, io, msg_status); 280 CP(io32, io, sb_len_wr); 281 CP(io32, io, host_status); 282 CP(io32, io, driver_status); 283 CP(io32, io, resid); 284 CP(io32, io, duration); 285 CP(io32, io, info); 286 287 if ((error = fo_ioctl(fp, SG_IO, (caddr_t)&io, td->td_ucred, td)) != 0) 288 return (error); 289 290 CP(io, io32, interface_id); 291 CP(io, io32, dxfer_direction); 292 CP(io, io32, cmd_len); 293 CP(io, io32, mx_sb_len); 294 CP(io, io32, iovec_count); 295 CP(io, io32, dxfer_len); 296 PTROUT_CP(io, io32, dxferp); 297 PTROUT_CP(io, io32, cmdp); 298 PTROUT_CP(io, io32, sbp); 299 CP(io, io32, timeout); 300 CP(io, io32, flags); 301 CP(io, io32, pack_id); 302 PTROUT_CP(io, io32, usr_ptr); 303 CP(io, io32, status); 304 CP(io, io32, masked_status); 305 CP(io, io32, msg_status); 306 CP(io, io32, sb_len_wr); 307 CP(io, io32, host_status); 308 CP(io, io32, driver_status); 309 CP(io, io32, resid); 310 CP(io, io32, duration); 311 CP(io, io32, info); 312 313 error = copyout(&io32, uap->data, sizeof(io32)); 314 315 return (error); 316 } 317 318 int 319 freebsd32_ioctl(struct thread *td, struct freebsd32_ioctl_args *uap) 320 { 321 struct ioctl_args ap /*{ 322 int fd; 323 u_long com; 324 caddr_t data; 325 }*/ ; 326 struct file *fp; 327 cap_rights_t rights; 328 int error; 329 330 error = fget(td, uap->fd, cap_rights_init(&rights, CAP_IOCTL), &fp); 331 if (error != 0) 332 return (error); 333 if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 334 fdrop(fp, td); 335 return (EBADF); 336 } 337 338 switch (uap->com) { 339 case CDIOREADTOCENTRYS_32: 340 error = freebsd32_ioctl_ioc_read_toc(td, uap, fp); 341 break; 342 343 case FIODGNAME_32: 344 error = freebsd32_ioctl_fiodgname(td, uap, fp); 345 break; 346 347 case MEMRANGE_GET32: /* FALLTHROUGH */ 348 case MEMRANGE_SET32: 349 error = freebsd32_ioctl_memrange(td, uap, fp); 350 break; 351 352 case PCIOCGETCONF_32: 353 error = freebsd32_ioctl_pciocgetconf(td, uap, fp); 354 break; 355 356 case SG_IO_32: 357 error = freebsd32_ioctl_sg(td, uap, fp); 358 break; 359 360 default: 361 fdrop(fp, td); 362 ap.fd = uap->fd; 363 ap.com = uap->com; 364 PTRIN_CP(*uap, ap, data); 365 return sys_ioctl(td, &ap); 366 } 367 368 fdrop(fp, td); 369 return error; 370 } 371