1183270Sobrien/*- 2183270Sobrien * Copyright (c) 2008 David E. O'Brien 3183270Sobrien * All rights reserved. 4183270Sobrien * 5183270Sobrien * Redistribution and use in source and binary forms, with or without 6183270Sobrien * modification, are permitted provided that the following conditions 7183270Sobrien * are met: 8183270Sobrien * 1. Redistributions of source code must retain the above copyright 9183270Sobrien * notice, this list of conditions and the following disclaimer. 10183270Sobrien * 2. Redistributions in binary form must reproduce the above copyright 11183270Sobrien * notice, this list of conditions and the following disclaimer in the 12183270Sobrien * documentation and/or other materials provided with the distribution. 13183270Sobrien * 3. Neither the name of the author nor the names of its contributors 14183270Sobrien * may be used to endorse or promote products derived from this software 15183270Sobrien * without specific prior written permission. 16183270Sobrien * 17183270Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18183270Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19183270Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20183270Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21183270Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22183270Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23183270Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24183270Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25183270Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26183270Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27183270Sobrien * SUCH DAMAGE. 28183270Sobrien */ 29183270Sobrien 30183270Sobrien#include <sys/cdefs.h> 31183270Sobrien__FBSDID("$FreeBSD$"); 32183270Sobrien 33183270Sobrien#include "opt_compat.h" 34183270Sobrien 35183270Sobrien#include <sys/param.h> 36224778Srwatson#include <sys/capability.h> 37183270Sobrien#include <sys/cdio.h> 38183270Sobrien#include <sys/fcntl.h> 39190529Sed#include <sys/filio.h> 40183270Sobrien#include <sys/file.h> 41183270Sobrien#include <sys/ioccom.h> 42219989Skib#include <sys/malloc.h> 43183270Sobrien#include <sys/mdioctl.h> 44219989Skib#include <sys/memrange.h> 45220280Skib#include <sys/pciio.h> 46183270Sobrien#include <sys/proc.h> 47183270Sobrien#include <sys/syscall.h> 48183270Sobrien#include <sys/syscallsubr.h> 49183270Sobrien#include <sys/sysctl.h> 50183270Sobrien#include <sys/sysent.h> 51183270Sobrien#include <sys/sysproto.h> 52183270Sobrien#include <sys/systm.h> 53183270Sobrien 54183270Sobrien#include <compat/freebsd32/freebsd32.h> 55183270Sobrien#include <compat/freebsd32/freebsd32_ioctl.h> 56183270Sobrien#include <compat/freebsd32/freebsd32_proto.h> 57183270Sobrien 58183270Sobrien/* Cannot get exact size in 64-bit due to alignment issue of entire struct. */ 59183270SobrienCTASSERT((sizeof(struct md_ioctl32)+4) == 436); 60183273SobrienCTASSERT(sizeof(struct ioc_read_toc_entry32) == 8); 61183273SobrienCTASSERT(sizeof(struct ioc_toc_header32) == 4); 62219989SkibCTASSERT(sizeof(struct mem_range_op32) == 12); 63220280SkibCTASSERT(sizeof(struct pci_conf_io32) == 36); 64220280SkibCTASSERT(sizeof(struct pci_match_conf32) == 44); 65220280SkibCTASSERT(sizeof(struct pci_conf32) == 44); 66183270Sobrien 67183270Sobrien 68183270Sobrienstatic int 69183270Sobrienfreebsd32_ioctl_md(struct thread *td, struct freebsd32_ioctl_args *uap, 70183270Sobrien struct file *fp) 71183270Sobrien{ 72183270Sobrien struct md_ioctl mdv; 73183270Sobrien struct md_ioctl32 md32; 74183270Sobrien u_long com = 0; 75219988Skib int i, error; 76183270Sobrien 77183270Sobrien if (uap->com & IOC_IN) { 78183270Sobrien if ((error = copyin(uap->data, &md32, sizeof(md32)))) { 79183270Sobrien return (error); 80183270Sobrien } 81183270Sobrien CP(md32, mdv, md_version); 82183270Sobrien CP(md32, mdv, md_unit); 83183270Sobrien CP(md32, mdv, md_type); 84183270Sobrien PTRIN_CP(md32, mdv, md_file); 85183270Sobrien CP(md32, mdv, md_mediasize); 86183270Sobrien CP(md32, mdv, md_sectorsize); 87183270Sobrien CP(md32, mdv, md_options); 88183270Sobrien CP(md32, mdv, md_base); 89183270Sobrien CP(md32, mdv, md_fwheads); 90183270Sobrien CP(md32, mdv, md_fwsectors); 91183270Sobrien } else if (uap->com & IOC_OUT) { 92183270Sobrien /* 93183270Sobrien * Zero the buffer so the user always 94183270Sobrien * gets back something deterministic. 95183270Sobrien */ 96183270Sobrien bzero(&mdv, sizeof mdv); 97183270Sobrien } 98183270Sobrien 99183270Sobrien switch (uap->com) { 100183270Sobrien case MDIOCATTACH_32: 101183270Sobrien com = MDIOCATTACH; 102183270Sobrien break; 103183270Sobrien case MDIOCDETACH_32: 104183270Sobrien com = MDIOCDETACH; 105183270Sobrien break; 106183270Sobrien case MDIOCQUERY_32: 107183270Sobrien com = MDIOCQUERY; 108183270Sobrien break; 109183270Sobrien case MDIOCLIST_32: 110183270Sobrien com = MDIOCLIST; 111183270Sobrien break; 112183270Sobrien default: 113183270Sobrien panic("%s: unknown MDIOC %#x", __func__, uap->com); 114183270Sobrien } 115183270Sobrien error = fo_ioctl(fp, com, (caddr_t)&mdv, td->td_ucred, td); 116183270Sobrien if (error == 0 && (com & IOC_OUT)) { 117183270Sobrien CP(mdv, md32, md_version); 118183270Sobrien CP(mdv, md32, md_unit); 119183270Sobrien CP(mdv, md32, md_type); 120183270Sobrien PTROUT_CP(mdv, md32, md_file); 121183270Sobrien CP(mdv, md32, md_mediasize); 122183270Sobrien CP(mdv, md32, md_sectorsize); 123183270Sobrien CP(mdv, md32, md_options); 124183270Sobrien CP(mdv, md32, md_base); 125183270Sobrien CP(mdv, md32, md_fwheads); 126183270Sobrien CP(mdv, md32, md_fwsectors); 127219988Skib if (com == MDIOCLIST) { 128219988Skib /* 129219988Skib * Use MDNPAD, and not MDNPAD32. Padding is 130219988Skib * allocated and used by compat32 ABI. 131219988Skib */ 132219988Skib for (i = 0; i < MDNPAD; i++) 133219988Skib CP(mdv, md32, md_pad[i]); 134219988Skib } 135183270Sobrien error = copyout(&md32, uap->data, sizeof(md32)); 136183270Sobrien } 137183270Sobrien return error; 138183270Sobrien} 139183270Sobrien 140183270Sobrien 141183273Sobrienstatic int 142183273Sobrienfreebsd32_ioctl_ioc_toc_header(struct thread *td, 143183273Sobrien struct freebsd32_ioctl_args *uap, struct file *fp) 144183273Sobrien{ 145183273Sobrien struct ioc_toc_header toch; 146183273Sobrien struct ioc_toc_header32 toch32; 147183273Sobrien int error; 148183273Sobrien 149183273Sobrien if ((error = copyin(uap->data, &toch32, sizeof(toch32)))) 150183273Sobrien return (error); 151183273Sobrien CP(toch32, toch, len); 152183273Sobrien CP(toch32, toch, starting_track); 153183273Sobrien CP(toch32, toch, ending_track); 154183273Sobrien error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&toch, 155183273Sobrien td->td_ucred, td); 156183273Sobrien return (error); 157183273Sobrien} 158183273Sobrien 159183273Sobrien 160183273Sobrienstatic int 161183273Sobrienfreebsd32_ioctl_ioc_read_toc(struct thread *td, 162183273Sobrien struct freebsd32_ioctl_args *uap, struct file *fp) 163183273Sobrien{ 164183273Sobrien struct ioc_read_toc_entry toce; 165183273Sobrien struct ioc_read_toc_entry32 toce32; 166183273Sobrien int error; 167183273Sobrien 168183273Sobrien if ((error = copyin(uap->data, &toce32, sizeof(toce32)))) 169183273Sobrien return (error); 170183273Sobrien CP(toce32, toce, address_format); 171183273Sobrien CP(toce32, toce, starting_track); 172183273Sobrien CP(toce32, toce, data_len); 173183273Sobrien PTRIN_CP(toce32, toce, data); 174183273Sobrien 175183273Sobrien if ((error = fo_ioctl(fp, CDIOREADTOCENTRYS, (caddr_t)&toce, 176183273Sobrien td->td_ucred, td))) { 177183273Sobrien CP(toce, toce32, address_format); 178183273Sobrien CP(toce, toce32, starting_track); 179183273Sobrien CP(toce, toce32, data_len); 180183273Sobrien PTROUT_CP(toce, toce32, data); 181183273Sobrien error = copyout(&toce32, uap->data, sizeof(toce32)); 182183273Sobrien } 183183273Sobrien return error; 184183273Sobrien} 185183273Sobrien 186190529Sedstatic int 187190529Sedfreebsd32_ioctl_fiodgname(struct thread *td, 188190529Sed struct freebsd32_ioctl_args *uap, struct file *fp) 189190529Sed{ 190190529Sed struct fiodgname_arg fgn; 191190529Sed struct fiodgname_arg32 fgn32; 192190529Sed int error; 193183273Sobrien 194190529Sed if ((error = copyin(uap->data, &fgn32, sizeof fgn32)) != 0) 195190529Sed return (error); 196190529Sed CP(fgn32, fgn, len); 197190529Sed PTRIN_CP(fgn32, fgn, buf); 198190529Sed error = fo_ioctl(fp, FIODGNAME, (caddr_t)&fgn, td->td_ucred, td); 199190529Sed return (error); 200190529Sed} 201190529Sed 202219989Skibstatic int 203219989Skibfreebsd32_ioctl_memrange(struct thread *td, 204219989Skib struct freebsd32_ioctl_args *uap, struct file *fp) 205219989Skib{ 206219989Skib struct mem_range_op mro; 207219989Skib struct mem_range_op32 mro32; 208219989Skib int error; 209219989Skib u_long com; 210219989Skib 211219989Skib if ((error = copyin(uap->data, &mro32, sizeof(mro32))) != 0) 212219989Skib return (error); 213219989Skib 214219989Skib PTRIN_CP(mro32, mro, mo_desc); 215219989Skib CP(mro32, mro, mo_arg[0]); 216219989Skib CP(mro32, mro, mo_arg[1]); 217219989Skib 218219989Skib com = 0; 219219989Skib switch (uap->com) { 220219989Skib case MEMRANGE_GET32: 221219989Skib com = MEMRANGE_GET; 222219989Skib break; 223219989Skib 224219989Skib case MEMRANGE_SET32: 225219989Skib com = MEMRANGE_SET; 226219989Skib break; 227219989Skib 228219989Skib default: 229219989Skib panic("%s: unknown MEMRANGE %#x", __func__, uap->com); 230219989Skib } 231219989Skib 232219989Skib if ((error = fo_ioctl(fp, com, (caddr_t)&mro, td->td_ucred, td)) != 0) 233219989Skib return (error); 234219989Skib 235219989Skib if ( (com & IOC_OUT) ) { 236219989Skib CP(mro, mro32, mo_arg[0]); 237219989Skib CP(mro, mro32, mo_arg[1]); 238219989Skib 239219989Skib error = copyout(&mro32, uap->data, sizeof(mro32)); 240219989Skib } 241219989Skib 242219989Skib return (error); 243219989Skib} 244219989Skib 245220281Skibstatic int 246220281Skibfreebsd32_ioctl_pciocgetconf(struct thread *td, 247220281Skib struct freebsd32_ioctl_args *uap, struct file *fp) 248220281Skib{ 249220281Skib struct pci_conf_io pci; 250220281Skib struct pci_conf_io32 pci32; 251220281Skib struct pci_match_conf32 pmc32; 252220281Skib struct pci_match_conf32 *pmc32p; 253220281Skib struct pci_match_conf pmc; 254220281Skib struct pci_match_conf *pmcp; 255220281Skib struct pci_conf32 pc32; 256220281Skib struct pci_conf32 *pc32p; 257220281Skib struct pci_conf pc; 258220281Skib struct pci_conf *pcp; 259220281Skib u_int32_t i; 260220281Skib u_int32_t npat_to_convert; 261220281Skib u_int32_t nmatch_to_convert; 262220281Skib vm_offset_t addr; 263220281Skib int error; 264220281Skib 265220281Skib if ((error = copyin(uap->data, &pci32, sizeof(pci32))) != 0) 266220281Skib return (error); 267220281Skib 268220281Skib CP(pci32, pci, num_patterns); 269220281Skib CP(pci32, pci, offset); 270220281Skib CP(pci32, pci, generation); 271220281Skib 272220281Skib npat_to_convert = pci32.pat_buf_len / sizeof(struct pci_match_conf32); 273220281Skib pci.pat_buf_len = npat_to_convert * sizeof(struct pci_match_conf); 274220281Skib pci.patterns = NULL; 275220281Skib nmatch_to_convert = pci32.match_buf_len / sizeof(struct pci_conf32); 276220281Skib pci.match_buf_len = nmatch_to_convert * sizeof(struct pci_conf); 277220281Skib pci.matches = NULL; 278220281Skib 279220281Skib if ((error = copyout_map(td, &addr, pci.pat_buf_len)) != 0) 280220281Skib goto cleanup; 281220281Skib pci.patterns = (struct pci_match_conf *)addr; 282220281Skib if ((error = copyout_map(td, &addr, pci.match_buf_len)) != 0) 283220281Skib goto cleanup; 284220281Skib pci.matches = (struct pci_conf *)addr; 285220281Skib 286220281Skib npat_to_convert = min(npat_to_convert, pci.num_patterns); 287220281Skib 288220281Skib for (i = 0, pmc32p = (struct pci_match_conf32 *)PTRIN(pci32.patterns), 289220281Skib pmcp = pci.patterns; 290220281Skib i < npat_to_convert; i++, pmc32p++, pmcp++) { 291220281Skib if ((error = copyin(pmc32p, &pmc32, sizeof(pmc32))) != 0) 292220281Skib goto cleanup; 293220281Skib CP(pmc32,pmc,pc_sel); 294220281Skib strlcpy(pmc.pd_name, pmc32.pd_name, sizeof(pmc.pd_name)); 295220281Skib CP(pmc32,pmc,pd_unit); 296220281Skib CP(pmc32,pmc,pc_vendor); 297220281Skib CP(pmc32,pmc,pc_device); 298220281Skib CP(pmc32,pmc,pc_class); 299220281Skib CP(pmc32,pmc,flags); 300220281Skib if ((error = copyout(&pmc, pmcp, sizeof(pmc))) != 0) 301220281Skib goto cleanup; 302220281Skib } 303220281Skib 304220281Skib if ((error = fo_ioctl(fp, PCIOCGETCONF, (caddr_t)&pci, 305220281Skib td->td_ucred, td)) != 0) 306220281Skib goto cleanup; 307220281Skib 308220281Skib nmatch_to_convert = min(nmatch_to_convert, pci.num_matches); 309220281Skib 310220281Skib for (i = 0, pcp = pci.matches, 311220281Skib pc32p = (struct pci_conf32 *)PTRIN(pci32.matches); 312220281Skib i < nmatch_to_convert; i++, pcp++, pc32p++) { 313220281Skib if ((error = copyin(pcp, &pc, sizeof(pc))) != 0) 314220281Skib goto cleanup; 315220281Skib CP(pc,pc32,pc_sel); 316220281Skib CP(pc,pc32,pc_hdr); 317220281Skib CP(pc,pc32,pc_subvendor); 318220281Skib CP(pc,pc32,pc_subdevice); 319220281Skib CP(pc,pc32,pc_vendor); 320220281Skib CP(pc,pc32,pc_device); 321220281Skib CP(pc,pc32,pc_class); 322220281Skib CP(pc,pc32,pc_subclass); 323220281Skib CP(pc,pc32,pc_progif); 324220281Skib CP(pc,pc32,pc_revid); 325220281Skib strlcpy(pc32.pd_name, pc.pd_name, sizeof(pc32.pd_name)); 326220281Skib CP(pc,pc32,pd_unit); 327220281Skib if ((error = copyout(&pc32, pc32p, sizeof(pc32))) != 0) 328220281Skib goto cleanup; 329220281Skib } 330220281Skib 331220281Skib CP(pci, pci32, num_matches); 332220281Skib CP(pci, pci32, offset); 333220281Skib CP(pci, pci32, generation); 334220281Skib CP(pci, pci32, status); 335220281Skib 336220281Skib error = copyout(&pci32, uap->data, sizeof(pci32)); 337220281Skib 338220281Skibcleanup: 339220281Skib if (pci.patterns) 340220281Skib copyout_unmap(td, (vm_offset_t)pci.patterns, pci.pat_buf_len); 341220281Skib if (pci.matches) 342220281Skib copyout_unmap(td, (vm_offset_t)pci.matches, pci.match_buf_len); 343220281Skib 344220281Skib return (error); 345220281Skib} 346220281Skib 347183270Sobrienint 348183270Sobrienfreebsd32_ioctl(struct thread *td, struct freebsd32_ioctl_args *uap) 349183270Sobrien{ 350183270Sobrien struct ioctl_args ap /*{ 351183270Sobrien int fd; 352183270Sobrien u_long com; 353183270Sobrien caddr_t data; 354183270Sobrien }*/ ; 355183270Sobrien struct file *fp; 356183270Sobrien int error; 357183270Sobrien 358224778Srwatson if ((error = fget(td, uap->fd, CAP_IOCTL, &fp)) != 0) 359183270Sobrien return (error); 360183270Sobrien if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 361183270Sobrien fdrop(fp, td); 362183270Sobrien return (EBADF); 363183270Sobrien } 364183270Sobrien 365183270Sobrien switch (uap->com) { 366183270Sobrien case MDIOCATTACH_32: /* FALLTHROUGH */ 367183270Sobrien case MDIOCDETACH_32: /* FALLTHROUGH */ 368183270Sobrien case MDIOCQUERY_32: /* FALLTHROUGH */ 369183270Sobrien case MDIOCLIST_32: 370219986Skib error = freebsd32_ioctl_md(td, uap, fp); 371219986Skib break; 372183270Sobrien 373183273Sobrien case CDIOREADTOCENTRYS_32: 374219986Skib error = freebsd32_ioctl_ioc_read_toc(td, uap, fp); 375219986Skib break; 376183273Sobrien 377183273Sobrien case CDIOREADTOCHEADER_32: 378219986Skib error = freebsd32_ioctl_ioc_toc_header(td, uap, fp); 379219986Skib break; 380183273Sobrien 381190529Sed case FIODGNAME_32: 382219986Skib error = freebsd32_ioctl_fiodgname(td, uap, fp); 383219986Skib break; 384190529Sed 385219989Skib case MEMRANGE_GET32: /* FALLTHROUGH */ 386219989Skib case MEMRANGE_SET32: 387219989Skib error = freebsd32_ioctl_memrange(td, uap, fp); 388219989Skib break; 389219989Skib 390220281Skib case PCIOCGETCONF_32: 391220281Skib error = freebsd32_ioctl_pciocgetconf(td, uap, fp); 392220281Skib break; 393220281Skib 394183270Sobrien default: 395183270Sobrien fdrop(fp, td); 396183270Sobrien ap.fd = uap->fd; 397183270Sobrien ap.com = uap->com; 398183270Sobrien PTRIN_CP(*uap, ap, data); 399225617Skmacy return sys_ioctl(td, &ap); 400183270Sobrien } 401219986Skib 402219986Skib fdrop(fp, td); 403219986Skib return error; 404183270Sobrien} 405