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