From ef4d131c1225339cf8797ba16c69bb860a1565fe Mon Sep 17 00:00:00 2001 From: brooks Date: Thu, 27 Sep 2018 21:08:32 +0000 Subject: [PATCH] Centralize compat support for PCIOCGETCONF. The pre-7.x compat for both native and 32-bit code was already in pci_user.c. Use this infrastructure to add implement 32-bit support. This is more correct as ioctl(2) commands only have meaning in the context of a file descriptor. Reviewed by: kib Approved by: re (gjb) Obtained from: CheriBSD Sponsored by: DARPA, AFRL Differential revision: https://reviews.freebsd.org/D17324 --- sys/compat/freebsd32/freebsd32_ioctl.c | 109 ---------------- sys/compat/freebsd32/freebsd32_ioctl.h | 40 ------ sys/dev/pci/pci_user.c | 172 ++++++++++++++++++++++--- 3 files changed, 154 insertions(+), 167 deletions(-) diff --git a/sys/compat/freebsd32/freebsd32_ioctl.c b/sys/compat/freebsd32/freebsd32_ioctl.c index a3226cdcd9a0..b181913b6688 100644 --- a/sys/compat/freebsd32/freebsd32_ioctl.c +++ b/sys/compat/freebsd32/freebsd32_ioctl.c @@ -58,9 +58,6 @@ __FBSDID("$FreeBSD$"); CTASSERT(sizeof(struct ioc_read_toc_entry32) == 8); CTASSERT(sizeof(struct mem_range_op32) == 12); -CTASSERT(sizeof(struct pci_conf_io32) == 36); -CTASSERT(sizeof(struct pci_match_conf32) == 44); -CTASSERT(sizeof(struct pci_conf32) == 44); static int freebsd32_ioctl_ioc_read_toc(struct thread *td, @@ -147,108 +144,6 @@ freebsd32_ioctl_memrange(struct thread *td, return (error); } -static int -freebsd32_ioctl_pciocgetconf(struct thread *td, - struct freebsd32_ioctl_args *uap, struct file *fp) -{ - struct pci_conf_io pci; - struct pci_conf_io32 pci32; - struct pci_match_conf32 pmc32; - struct pci_match_conf32 *pmc32p; - struct pci_match_conf pmc; - struct pci_match_conf *pmcp; - struct pci_conf32 pc32; - struct pci_conf32 *pc32p; - struct pci_conf pc; - struct pci_conf *pcp; - u_int32_t i; - u_int32_t npat_to_convert; - u_int32_t nmatch_to_convert; - vm_offset_t addr; - int error; - - if ((error = copyin(uap->data, &pci32, sizeof(pci32))) != 0) - return (error); - - CP(pci32, pci, num_patterns); - CP(pci32, pci, offset); - CP(pci32, pci, generation); - - npat_to_convert = pci32.pat_buf_len / sizeof(struct pci_match_conf32); - pci.pat_buf_len = npat_to_convert * sizeof(struct pci_match_conf); - pci.patterns = NULL; - nmatch_to_convert = pci32.match_buf_len / sizeof(struct pci_conf32); - pci.match_buf_len = nmatch_to_convert * sizeof(struct pci_conf); - pci.matches = NULL; - - if ((error = copyout_map(td, &addr, pci.pat_buf_len)) != 0) - goto cleanup; - pci.patterns = (struct pci_match_conf *)addr; - if ((error = copyout_map(td, &addr, pci.match_buf_len)) != 0) - goto cleanup; - pci.matches = (struct pci_conf *)addr; - - npat_to_convert = min(npat_to_convert, pci.num_patterns); - - for (i = 0, pmc32p = (struct pci_match_conf32 *)PTRIN(pci32.patterns), - pmcp = pci.patterns; - i < npat_to_convert; i++, pmc32p++, pmcp++) { - if ((error = copyin(pmc32p, &pmc32, sizeof(pmc32))) != 0) - goto cleanup; - CP(pmc32,pmc,pc_sel); - strlcpy(pmc.pd_name, pmc32.pd_name, sizeof(pmc.pd_name)); - CP(pmc32,pmc,pd_unit); - CP(pmc32,pmc,pc_vendor); - CP(pmc32,pmc,pc_device); - CP(pmc32,pmc,pc_class); - CP(pmc32,pmc,flags); - if ((error = copyout(&pmc, pmcp, sizeof(pmc))) != 0) - goto cleanup; - } - - if ((error = fo_ioctl(fp, PCIOCGETCONF, (caddr_t)&pci, - td->td_ucred, td)) != 0) - goto cleanup; - - nmatch_to_convert = min(nmatch_to_convert, pci.num_matches); - - for (i = 0, pcp = pci.matches, - pc32p = (struct pci_conf32 *)PTRIN(pci32.matches); - i < nmatch_to_convert; i++, pcp++, pc32p++) { - if ((error = copyin(pcp, &pc, sizeof(pc))) != 0) - goto cleanup; - CP(pc,pc32,pc_sel); - CP(pc,pc32,pc_hdr); - CP(pc,pc32,pc_subvendor); - CP(pc,pc32,pc_subdevice); - CP(pc,pc32,pc_vendor); - CP(pc,pc32,pc_device); - CP(pc,pc32,pc_class); - CP(pc,pc32,pc_subclass); - CP(pc,pc32,pc_progif); - CP(pc,pc32,pc_revid); - strlcpy(pc32.pd_name, pc.pd_name, sizeof(pc32.pd_name)); - CP(pc,pc32,pd_unit); - if ((error = copyout(&pc32, pc32p, sizeof(pc32))) != 0) - goto cleanup; - } - - CP(pci, pci32, num_matches); - CP(pci, pci32, offset); - CP(pci, pci32, generation); - CP(pci, pci32, status); - - error = copyout(&pci32, uap->data, sizeof(pci32)); - -cleanup: - if (pci.patterns) - copyout_unmap(td, (vm_offset_t)pci.patterns, pci.pat_buf_len); - if (pci.matches) - copyout_unmap(td, (vm_offset_t)pci.matches, pci.match_buf_len); - - return (error); -} - static int freebsd32_ioctl_barmmap(struct thread *td, struct freebsd32_ioctl_args *uap, struct file *fp) @@ -382,10 +277,6 @@ freebsd32_ioctl(struct thread *td, struct freebsd32_ioctl_args *uap) error = freebsd32_ioctl_memrange(td, uap, fp); break; - case PCIOCGETCONF_32: - error = freebsd32_ioctl_pciocgetconf(td, uap, fp); - break; - case SG_IO_32: error = freebsd32_ioctl_sg(td, uap, fp); break; diff --git a/sys/compat/freebsd32/freebsd32_ioctl.h b/sys/compat/freebsd32/freebsd32_ioctl.h index fc9c93a7a29b..c19c27e3618a 100644 --- a/sys/compat/freebsd32/freebsd32_ioctl.h +++ b/sys/compat/freebsd32/freebsd32_ioctl.h @@ -56,45 +56,6 @@ struct mem_range_op32 int mo_arg[2]; }; -struct pci_conf32 { - struct pcisel pc_sel; /* domain+bus+slot+function */ - u_int8_t pc_hdr; /* PCI header type */ - u_int16_t pc_subvendor; /* card vendor ID */ - u_int16_t pc_subdevice; /* card device ID, assigned by - card vendor */ - u_int16_t pc_vendor; /* chip vendor ID */ - u_int16_t pc_device; /* chip device ID, assigned by - chip vendor */ - u_int8_t pc_class; /* chip PCI class */ - u_int8_t pc_subclass; /* chip PCI subclass */ - u_int8_t pc_progif; /* chip PCI programming interface */ - u_int8_t pc_revid; /* chip revision ID */ - char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ - u_int32_t pd_unit; /* device unit number */ -}; - -struct pci_match_conf32 { - struct pcisel pc_sel; /* domain+bus+slot+function */ - char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ - u_int32_t pd_unit; /* Unit number */ - u_int16_t pc_vendor; /* PCI Vendor ID */ - u_int16_t pc_device; /* PCI Device ID */ - u_int8_t pc_class; /* PCI class */ - u_int32_t flags; /* Matching expression */ -}; - -struct pci_conf_io32 { - u_int32_t pat_buf_len; /* pattern buffer length */ - u_int32_t num_patterns; /* number of patterns */ - caddr_t32 patterns; /* struct pci_match_conf ptr */ - u_int32_t match_buf_len; /* match buffer length */ - u_int32_t num_matches; /* number of matches returned */ - caddr_t32 matches; /* struct pci_conf ptr */ - u_int32_t offset; /* offset into device list */ - u_int32_t generation; /* device list generation */ - u_int32_t status; /* request status */ -}; - struct pci_bar_mmap32 { uint32_t pbm_map_base; uint32_t pbm_map_length; @@ -110,7 +71,6 @@ struct pci_bar_mmap32 { #define FIODGNAME_32 _IOW('f', 120, struct fiodgname_arg32) #define MEMRANGE_GET32 _IOWR('m', 50, struct mem_range_op32) #define MEMRANGE_SET32 _IOW('m', 51, struct mem_range_op32) -#define PCIOCGETCONF_32 _IOWR('p', 5, struct pci_conf_io32) #define SG_IO_32 _IOWR(SGIOC, 0x85, struct sg_io_hdr32) #define PCIOCBARMMAP_32 _IOWR('p', 8, struct pci_bar_mmap32) diff --git a/sys/dev/pci/pci_user.c b/sys/dev/pci/pci_user.c index 4e40a8167362..380beff0d310 100644 --- a/sys/dev/pci/pci_user.c +++ b/sys/dev/pci/pci_user.c @@ -66,6 +66,49 @@ __FBSDID("$FreeBSD$"); #include "pcib_if.h" #include "pci_if.h" +#ifdef COMPAT_FREEBSD32 +struct pci_conf32 { + struct pcisel pc_sel; /* domain+bus+slot+function */ + u_int8_t pc_hdr; /* PCI header type */ + u_int16_t pc_subvendor; /* card vendor ID */ + u_int16_t pc_subdevice; /* card device ID, assigned by + card vendor */ + u_int16_t pc_vendor; /* chip vendor ID */ + u_int16_t pc_device; /* chip device ID, assigned by + chip vendor */ + u_int8_t pc_class; /* chip PCI class */ + u_int8_t pc_subclass; /* chip PCI subclass */ + u_int8_t pc_progif; /* chip PCI programming interface */ + u_int8_t pc_revid; /* chip revision ID */ + char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ + u_int32_t pd_unit; /* device unit number */ +}; + +struct pci_match_conf32 { + struct pcisel pc_sel; /* domain+bus+slot+function */ + char pd_name[PCI_MAXNAMELEN + 1]; /* device name */ + u_int32_t pd_unit; /* Unit number */ + u_int16_t pc_vendor; /* PCI Vendor ID */ + u_int16_t pc_device; /* PCI Device ID */ + u_int8_t pc_class; /* PCI class */ + u_int32_t flags; /* Matching expression */ +}; + +struct pci_conf_io32 { + u_int32_t pat_buf_len; /* pattern buffer length */ + u_int32_t num_patterns; /* number of patterns */ + u_int32_t patterns; /* struct pci_match_conf ptr */ + u_int32_t match_buf_len; /* match buffer length */ + u_int32_t num_matches; /* number of matches returned */ + u_int32_t matches; /* struct pci_conf ptr */ + u_int32_t offset; /* offset into device list */ + u_int32_t generation; /* device list generation */ + u_int32_t status; /* request status */ +}; + +#define PCIOCGETCONF32 _IOC_NEWTYPE(PCIOCGETCONF, struct pci_conf_io32) +#endif + /* * This is the user interface to PCI configuration space. */ @@ -175,6 +218,73 @@ pci_conf_match_native(struct pci_match_conf *matches, int num_matches, return(1); } +#ifdef COMPAT_FREEBSD32 +static int +pci_conf_match32(struct pci_match_conf32 *matches, int num_matches, + struct pci_conf *match_buf) +{ + int i; + + if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0)) + return(1); + + for (i = 0; i < num_matches; i++) { + /* + * I'm not sure why someone would do this...but... + */ + if (matches[i].flags == PCI_GETCONF_NO_MATCH) + continue; + + /* + * Look at each of the match flags. If it's set, do the + * comparison. If the comparison fails, we don't have a + * match, go on to the next item if there is one. + */ + if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0) + && (match_buf->pc_sel.pc_domain != + matches[i].pc_sel.pc_domain)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0) + && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0) + && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0) + && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) + && (match_buf->pc_vendor != matches[i].pc_vendor)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0) + && (match_buf->pc_device != matches[i].pc_device)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0) + && (match_buf->pc_class != matches[i].pc_class)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0) + && (match_buf->pd_unit != matches[i].pd_unit)) + continue; + + if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0) + && (strncmp(matches[i].pd_name, match_buf->pd_name, + sizeof(match_buf->pd_name)) != 0)) + continue; + + return(0); + } + + return(1); +} +#endif /* COMPAT_FREEBSD32 */ + #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ defined(COMPAT_FREEBSD6) #define PRE7_COMPAT @@ -259,20 +369,6 @@ struct pci_match_conf_old32 { pci_getconf_flags_old flags; /* Matching expression */ }; -struct pci_conf_io32 { - uint32_t pat_buf_len; /* pattern buffer length */ - uint32_t num_patterns; /* number of patterns */ - uint32_t patterns; /* pattern buffer - (struct pci_match_conf_old32 *) */ - uint32_t match_buf_len; /* match buffer length */ - uint32_t num_matches; /* number of matches returned */ - uint32_t matches; /* match buffer - (struct pci_conf_old32 *) */ - uint32_t offset; /* offset into device list */ - uint32_t generation; /* device list generation */ - pci_getconf_status status; /* request status */ -}; - #define PCIOCGETCONF_OLD32 _IOWR('p', 1, struct pci_conf_io32) #endif /* COMPAT_FREEBSD32 */ @@ -411,6 +507,9 @@ pci_conf_match_old32(struct pci_match_conf_old32 *matches, int num_matches, union pci_conf_union { struct pci_conf pc; +#ifdef COMPAT_FREEBSD32 + struct pci_conf32 pc32; +#endif #ifdef PRE7_COMPAT struct pci_conf_old pco; #ifdef COMPAT_FREEBSD32 @@ -428,6 +527,11 @@ pci_conf_match(u_long cmd, struct pci_match_conf *matches, int num_matches, case PCIOCGETCONF: return (pci_conf_match_native( (struct pci_match_conf *)matches, num_matches, match_buf)); +#ifdef COMPAT_FREEBSD32 + case PCIOCGETCONF32: + return (pci_conf_match32((struct pci_match_conf32 *)matches, + num_matches, match_buf)); +#endif #ifdef PRE7_COMPAT case PCIOCGETCONF_OLD: return (pci_conf_match_old( @@ -544,6 +648,10 @@ pci_match_conf_size(u_long cmd) switch (cmd) { case PCIOCGETCONF: return (sizeof(struct pci_match_conf)); +#ifdef COMPAT_FREEBSD32 + case PCIOCGETCONF32: + return (sizeof(struct pci_match_conf32)); +#endif #ifdef PRE7_COMPAT case PCIOCGETCONF_OLD: return (sizeof(struct pci_match_conf_old)); @@ -565,6 +673,10 @@ pci_conf_size(u_long cmd) switch (cmd) { case PCIOCGETCONF: return (sizeof(struct pci_conf)); +#ifdef COMPAT_FREEBSD32 + case PCIOCGETCONF32: + return (sizeof(struct pci_conf32)); +#endif #ifdef PRE7_COMPAT case PCIOCGETCONF_OLD: return (sizeof(struct pci_conf_old)); @@ -582,7 +694,7 @@ pci_conf_size(u_long cmd) static void pci_conf_io_init(struct pci_conf_io *cio, caddr_t data, u_long cmd) { -#if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32) +#if defined(COMPAT_FREEBSD32) struct pci_conf_io32 *cio32; #endif @@ -594,8 +706,11 @@ pci_conf_io_init(struct pci_conf_io *cio, caddr_t data, u_long cmd) *cio = *(struct pci_conf_io *)data; return; -#if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32) +#ifdef COMPAT_FREEBSD32 + case PCIOCGETCONF32: +#ifdef PRE7_COMPAT case PCIOCGETCONF_OLD32: +#endif cio32 = (struct pci_conf_io32 *)data; cio->pat_buf_len = cio32->pat_buf_len; cio->num_patterns = cio32->num_patterns; @@ -620,7 +735,7 @@ pci_conf_io_update_data(const struct pci_conf_io *cio, caddr_t data, u_long cmd) { struct pci_conf_io *d_cio; -#if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32) +#if defined(COMPAT_FREEBSD32) struct pci_conf_io32 *cio32; #endif @@ -636,8 +751,11 @@ pci_conf_io_update_data(const struct pci_conf_io *cio, caddr_t data, d_cio->num_matches = cio->num_matches; return; -#if defined(PRE7_COMPAT) && defined(COMPAT_FREEBSD32) +#ifdef COMPAT_FREEBSD32 + case PCIOCGETCONF32: +#ifdef PRE7_COMPAT case PCIOCGETCONF_OLD32: +#endif cio32 = (struct pci_conf_io32 *)data; cio32->status = cio->status; @@ -665,6 +783,24 @@ pci_conf_for_copyout(const struct pci_conf *pcp, union pci_conf_union *pcup, pcup->pc = *pcp; return; +#ifdef COMPAT_FREEBSD32 + case PCIOCGETCONF32: + pcup->pc32.pc_sel = pcp->pc_sel; + pcup->pc32.pc_hdr = pcp->pc_hdr; + pcup->pc32.pc_subvendor = pcp->pc_subvendor; + pcup->pc32.pc_subdevice = pcp->pc_subdevice; + pcup->pc32.pc_vendor = pcp->pc_vendor; + pcup->pc32.pc_device = pcp->pc_device; + pcup->pc32.pc_class = pcp->pc_class; + pcup->pc32.pc_subclass = pcp->pc_subclass; + pcup->pc32.pc_progif = pcp->pc_progif; + pcup->pc32.pc_revid = pcp->pc_revid; + strlcpy(pcup->pc32.pd_name, pcp->pd_name, + sizeof(pcup->pc32.pd_name)); + pcup->pc32.pd_unit = (uint32_t)pcp->pd_unit; + return; +#endif + #ifdef PRE7_COMPAT #ifdef COMPAT_FREEBSD32 case PCIOCGETCONF_OLD32: