]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/pci/pci_user.c
Fix several leaks of kernel stack data through paddings.
[FreeBSD/FreeBSD.git] / sys / dev / pci / pci_user.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
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 unmodified, this list of conditions, and the following
12  *    disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include "opt_bus.h"    /* XXX trim includes */
33 #include "opt_compat.h"
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 #include <sys/module.h>
39 #include <sys/linker.h>
40 #include <sys/fcntl.h>
41 #include <sys/conf.h>
42 #include <sys/kernel.h>
43 #include <sys/proc.h>
44 #include <sys/queue.h>
45 #include <sys/types.h>
46
47 #include <vm/vm.h>
48 #include <vm/pmap.h>
49 #include <vm/vm_extern.h>
50
51 #include <sys/bus.h>
52 #include <machine/bus.h>
53 #include <sys/rman.h>
54 #include <machine/resource.h>
55
56 #include <sys/pciio.h>
57 #include <dev/pci/pcireg.h>
58 #include <dev/pci/pcivar.h>
59
60 #include "pcib_if.h"
61 #include "pci_if.h"
62
63 /*
64  * This is the user interface to PCI configuration space.
65  */
66
67 static d_open_t         pci_open;
68 static d_close_t        pci_close;
69 static int      pci_conf_match(struct pci_match_conf *matches, int num_matches,
70                                struct pci_conf *match_buf);
71 static d_ioctl_t        pci_ioctl;
72
73 struct cdevsw pcicdev = {
74         .d_version =    D_VERSION,
75         .d_flags =      D_NEEDGIANT,
76         .d_open =       pci_open,
77         .d_close =      pci_close,
78         .d_ioctl =      pci_ioctl,
79         .d_name =       "pci",
80 };
81   
82 static int
83 pci_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
84 {
85         int error;
86
87         if (oflags & FWRITE) {
88                 error = securelevel_gt(td->td_ucred, 0);
89                 if (error)
90                         return (error);
91         }
92
93         return (0);
94 }
95
96 static int
97 pci_close(struct cdev *dev, int flag, int devtype, struct thread *td)
98 {
99         return 0;
100 }
101
102 /*
103  * Match a single pci_conf structure against an array of pci_match_conf
104  * structures.  The first argument, 'matches', is an array of num_matches
105  * pci_match_conf structures.  match_buf is a pointer to the pci_conf
106  * structure that will be compared to every entry in the matches array.
107  * This function returns 1 on failure, 0 on success.
108  */
109 static int
110 pci_conf_match(struct pci_match_conf *matches, int num_matches, 
111                struct pci_conf *match_buf)
112 {
113         int i;
114
115         if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
116                 return(1);
117
118         for (i = 0; i < num_matches; i++) {
119                 /*
120                  * I'm not sure why someone would do this...but...
121                  */
122                 if (matches[i].flags == PCI_GETCONF_NO_MATCH)
123                         continue;
124
125                 /*
126                  * Look at each of the match flags.  If it's set, do the
127                  * comparison.  If the comparison fails, we don't have a
128                  * match, go on to the next item if there is one.
129                  */
130                 if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0)
131                  && (match_buf->pc_sel.pc_domain !=
132                  matches[i].pc_sel.pc_domain))
133                         continue;
134
135                 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0)
136                  && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
137                         continue;
138
139                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0)
140                  && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
141                         continue;
142
143                 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0)
144                  && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
145                         continue;
146
147                 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0) 
148                  && (match_buf->pc_vendor != matches[i].pc_vendor))
149                         continue;
150
151                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0)
152                  && (match_buf->pc_device != matches[i].pc_device))
153                         continue;
154
155                 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0)
156                  && (match_buf->pc_class != matches[i].pc_class))
157                         continue;
158
159                 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0)
160                  && (match_buf->pd_unit != matches[i].pd_unit))
161                         continue;
162
163                 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0)
164                  && (strncmp(matches[i].pd_name, match_buf->pd_name,
165                              sizeof(match_buf->pd_name)) != 0))
166                         continue;
167
168                 return(0);
169         }
170
171         return(1);
172 }
173
174 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
175     defined(COMPAT_FREEBSD6)
176 #define PRE7_COMPAT
177
178 typedef enum {
179         PCI_GETCONF_NO_MATCH_OLD        = 0x00,
180         PCI_GETCONF_MATCH_BUS_OLD       = 0x01,
181         PCI_GETCONF_MATCH_DEV_OLD       = 0x02,
182         PCI_GETCONF_MATCH_FUNC_OLD      = 0x04,
183         PCI_GETCONF_MATCH_NAME_OLD      = 0x08,
184         PCI_GETCONF_MATCH_UNIT_OLD      = 0x10,
185         PCI_GETCONF_MATCH_VENDOR_OLD    = 0x20,
186         PCI_GETCONF_MATCH_DEVICE_OLD    = 0x40,
187         PCI_GETCONF_MATCH_CLASS_OLD     = 0x80
188 } pci_getconf_flags_old;
189
190 struct pcisel_old {
191         u_int8_t        pc_bus;         /* bus number */
192         u_int8_t        pc_dev;         /* device on this bus */
193         u_int8_t        pc_func;        /* function on this device */
194 };
195
196 struct pci_conf_old {
197         struct pcisel_old pc_sel;       /* bus+slot+function */
198         u_int8_t        pc_hdr;         /* PCI header type */
199         u_int16_t       pc_subvendor;   /* card vendor ID */
200         u_int16_t       pc_subdevice;   /* card device ID, assigned by
201                                            card vendor */
202         u_int16_t       pc_vendor;      /* chip vendor ID */
203         u_int16_t       pc_device;      /* chip device ID, assigned by
204                                            chip vendor */
205         u_int8_t        pc_class;       /* chip PCI class */
206         u_int8_t        pc_subclass;    /* chip PCI subclass */
207         u_int8_t        pc_progif;      /* chip PCI programming interface */
208         u_int8_t        pc_revid;       /* chip revision ID */
209         char            pd_name[PCI_MAXNAMELEN + 1];  /* device name */
210         u_long          pd_unit;        /* device unit number */
211 };
212
213 struct pci_match_conf_old {
214         struct pcisel_old       pc_sel;         /* bus+slot+function */
215         char                    pd_name[PCI_MAXNAMELEN + 1];  /* device name */
216         u_long                  pd_unit;        /* Unit number */
217         u_int16_t               pc_vendor;      /* PCI Vendor ID */
218         u_int16_t               pc_device;      /* PCI Device ID */
219         u_int8_t                pc_class;       /* PCI class */
220         pci_getconf_flags_old   flags;          /* Matching expression */
221 };
222
223 struct pci_io_old {
224         struct pcisel_old pi_sel;       /* device to operate on */
225         int             pi_reg;         /* configuration register to examine */
226         int             pi_width;       /* width (in bytes) of read or write */
227         u_int32_t       pi_data;        /* data to write or result of read */
228 };
229
230 #ifdef COMPAT_FREEBSD32
231 struct pci_conf_old32 {
232         struct pcisel_old pc_sel;       /* bus+slot+function */
233         uint8_t         pc_hdr;         /* PCI header type */
234         uint16_t        pc_subvendor;   /* card vendor ID */
235         uint16_t        pc_subdevice;   /* card device ID, assigned by
236                                            card vendor */
237         uint16_t        pc_vendor;      /* chip vendor ID */
238         uint16_t        pc_device;      /* chip device ID, assigned by
239                                            chip vendor */
240         uint8_t         pc_class;       /* chip PCI class */
241         uint8_t         pc_subclass;    /* chip PCI subclass */
242         uint8_t         pc_progif;      /* chip PCI programming interface */
243         uint8_t         pc_revid;       /* chip revision ID */
244         char            pd_name[PCI_MAXNAMELEN + 1]; /* device name */
245         uint32_t        pd_unit;        /* device unit number (u_long) */
246 };
247
248 struct pci_match_conf_old32 {
249         struct pcisel_old pc_sel;       /* bus+slot+function */
250         char            pd_name[PCI_MAXNAMELEN + 1]; /* device name */
251         uint32_t        pd_unit;        /* Unit number (u_long) */
252         uint16_t        pc_vendor;      /* PCI Vendor ID */
253         uint16_t        pc_device;      /* PCI Device ID */
254         uint8_t         pc_class;       /* PCI class */
255         pci_getconf_flags_old flags;    /* Matching expression */
256 };
257
258 struct pci_conf_io32 {
259         uint32_t        pat_buf_len;    /* pattern buffer length */
260         uint32_t        num_patterns;   /* number of patterns */
261         uint32_t        patterns;       /* pattern buffer
262                                            (struct pci_match_conf_old32 *) */
263         uint32_t        match_buf_len;  /* match buffer length */
264         uint32_t        num_matches;    /* number of matches returned */
265         uint32_t        matches;        /* match buffer
266                                            (struct pci_conf_old32 *) */
267         uint32_t        offset;         /* offset into device list */
268         uint32_t        generation;     /* device list generation */
269         pci_getconf_status status;      /* request status */
270 };
271
272 #define PCIOCGETCONF_OLD32      _IOWR('p', 1, struct pci_conf_io32)
273 #endif  /* COMPAT_FREEBSD32 */
274
275 #define PCIOCGETCONF_OLD        _IOWR('p', 1, struct pci_conf_io)
276 #define PCIOCREAD_OLD           _IOWR('p', 2, struct pci_io_old)
277 #define PCIOCWRITE_OLD          _IOWR('p', 3, struct pci_io_old)
278
279 static int      pci_conf_match_old(struct pci_match_conf_old *matches,
280                     int num_matches, struct pci_conf *match_buf);
281
282 static int
283 pci_conf_match_old(struct pci_match_conf_old *matches, int num_matches,
284     struct pci_conf *match_buf)
285 {
286         int i;
287
288         if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
289                 return(1);
290
291         for (i = 0; i < num_matches; i++) {
292                 if (match_buf->pc_sel.pc_domain != 0)
293                         continue;
294
295                 /*
296                  * I'm not sure why someone would do this...but...
297                  */
298                 if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD)
299                         continue;
300
301                 /*
302                  * Look at each of the match flags.  If it's set, do the
303                  * comparison.  If the comparison fails, we don't have a
304                  * match, go on to the next item if there is one.
305                  */
306                 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0)
307                  && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
308                         continue;
309
310                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0)
311                  && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
312                         continue;
313
314                 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0)
315                  && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
316                         continue;
317
318                 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0)
319                  && (match_buf->pc_vendor != matches[i].pc_vendor))
320                         continue;
321
322                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0)
323                  && (match_buf->pc_device != matches[i].pc_device))
324                         continue;
325
326                 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0)
327                  && (match_buf->pc_class != matches[i].pc_class))
328                         continue;
329
330                 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0)
331                  && (match_buf->pd_unit != matches[i].pd_unit))
332                         continue;
333
334                 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0)
335                  && (strncmp(matches[i].pd_name, match_buf->pd_name,
336                              sizeof(match_buf->pd_name)) != 0))
337                         continue;
338
339                 return(0);
340         }
341
342         return(1);
343 }
344
345 #ifdef COMPAT_FREEBSD32
346 static int
347 pci_conf_match_old32(struct pci_match_conf_old32 *matches, int num_matches,
348     struct pci_conf *match_buf)
349 {
350         int i;
351
352         if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
353                 return(1);
354
355         for (i = 0; i < num_matches; i++) {
356                 if (match_buf->pc_sel.pc_domain != 0)
357                         continue;
358
359                 /*
360                  * I'm not sure why someone would do this...but...
361                  */
362                 if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD)
363                         continue;
364
365                 /*
366                  * Look at each of the match flags.  If it's set, do the
367                  * comparison.  If the comparison fails, we don't have a
368                  * match, go on to the next item if there is one.
369                  */
370                 if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0) &&
371                     (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
372                         continue;
373
374                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0) &&
375                     (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
376                         continue;
377
378                 if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0) &&
379                     (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
380                         continue;
381
382                 if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0) &&
383                     (match_buf->pc_vendor != matches[i].pc_vendor))
384                         continue;
385
386                 if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0) &&
387                     (match_buf->pc_device != matches[i].pc_device))
388                         continue;
389
390                 if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0) &&
391                     (match_buf->pc_class != matches[i].pc_class))
392                         continue;
393
394                 if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0) &&
395                     ((u_int32_t)match_buf->pd_unit != matches[i].pd_unit))
396                         continue;
397
398                 if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0) &&
399                     (strncmp(matches[i].pd_name, match_buf->pd_name,
400                     sizeof(match_buf->pd_name)) != 0))
401                         continue;
402
403                 return (0);
404         }
405
406         return (1);
407 }
408 #endif  /* COMPAT_FREEBSD32 */
409 #endif  /* PRE7_COMPAT */
410
411 static int
412 pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio)
413 {
414         struct pci_vpd_element vpd_element, *vpd_user;
415         struct pcicfg_vpd *vpd;
416         size_t len;
417         int error, i;
418
419         vpd = pci_fetch_vpd_list(dev);
420         if (vpd->vpd_reg == 0 || vpd->vpd_ident == NULL)
421                 return (ENXIO);
422
423         /*
424          * Calculate the amount of space needed in the data buffer.  An
425          * identifier element is always present followed by the read-only
426          * and read-write keywords.
427          */
428         len = sizeof(struct pci_vpd_element) + strlen(vpd->vpd_ident);
429         for (i = 0; i < vpd->vpd_rocnt; i++)
430                 len += sizeof(struct pci_vpd_element) + vpd->vpd_ros[i].len;
431         for (i = 0; i < vpd->vpd_wcnt; i++)
432                 len += sizeof(struct pci_vpd_element) + vpd->vpd_w[i].len;
433
434         if (lvio->plvi_len == 0) {
435                 lvio->plvi_len = len;
436                 return (0);
437         }
438         if (lvio->plvi_len < len) {
439                 lvio->plvi_len = len;
440                 return (ENOMEM);
441         }
442
443         /*
444          * Copyout the identifier string followed by each keyword and
445          * value.
446          */
447         vpd_user = lvio->plvi_data;
448         vpd_element.pve_keyword[0] = '\0';
449         vpd_element.pve_keyword[1] = '\0';
450         vpd_element.pve_flags = PVE_FLAG_IDENT;
451         vpd_element.pve_datalen = strlen(vpd->vpd_ident);
452         error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
453         if (error)
454                 return (error);
455         error = copyout(vpd->vpd_ident, vpd_user->pve_data,
456             strlen(vpd->vpd_ident));
457         if (error)
458                 return (error);
459         vpd_user = PVE_NEXT(vpd_user);
460         vpd_element.pve_flags = 0;
461         for (i = 0; i < vpd->vpd_rocnt; i++) {
462                 vpd_element.pve_keyword[0] = vpd->vpd_ros[i].keyword[0];
463                 vpd_element.pve_keyword[1] = vpd->vpd_ros[i].keyword[1];
464                 vpd_element.pve_datalen = vpd->vpd_ros[i].len;
465                 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
466                 if (error)
467                         return (error);
468                 error = copyout(vpd->vpd_ros[i].value, vpd_user->pve_data,
469                     vpd->vpd_ros[i].len);
470                 if (error)
471                         return (error);
472                 vpd_user = PVE_NEXT(vpd_user);
473         }
474         vpd_element.pve_flags = PVE_FLAG_RW;
475         for (i = 0; i < vpd->vpd_wcnt; i++) {
476                 vpd_element.pve_keyword[0] = vpd->vpd_w[i].keyword[0];
477                 vpd_element.pve_keyword[1] = vpd->vpd_w[i].keyword[1];
478                 vpd_element.pve_datalen = vpd->vpd_w[i].len;
479                 error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
480                 if (error)
481                         return (error);
482                 error = copyout(vpd->vpd_w[i].value, vpd_user->pve_data,
483                     vpd->vpd_w[i].len);
484                 if (error)
485                         return (error);
486                 vpd_user = PVE_NEXT(vpd_user);
487         }
488         KASSERT((char *)vpd_user - (char *)lvio->plvi_data == len,
489             ("length mismatch"));
490         lvio->plvi_len = len;
491         return (0);
492 }
493
494 static int
495 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
496 {
497         device_t pcidev;
498         void *confdata;
499         const char *name;
500         struct devlist *devlist_head;
501         struct pci_conf_io *cio = NULL;
502         struct pci_devinfo *dinfo;
503         struct pci_io *io;
504         struct pci_bar_io *bio;
505         struct pci_list_vpd_io *lvio;
506         struct pci_match_conf *pattern_buf;
507         struct pci_map *pm;
508         size_t confsz, iolen, pbufsz;
509         int error, ionum, i, num_patterns;
510 #ifdef PRE7_COMPAT
511 #ifdef COMPAT_FREEBSD32
512         struct pci_conf_io32 *cio32 = NULL;
513         struct pci_conf_old32 conf_old32;
514         struct pci_match_conf_old32 *pattern_buf_old32 = NULL;
515 #endif
516         struct pci_conf_old conf_old;
517         struct pci_io iodata;
518         struct pci_io_old *io_old;
519         struct pci_match_conf_old *pattern_buf_old = NULL;
520
521         io_old = NULL;
522 #endif
523
524         if (!(flag & FWRITE)) {
525                 switch (cmd) {
526 #ifdef PRE7_COMPAT
527 #ifdef COMPAT_FREEBSD32
528                 case PCIOCGETCONF_OLD32:
529 #endif
530                 case PCIOCGETCONF_OLD:
531 #endif
532                 case PCIOCGETCONF:
533                 case PCIOCGETBAR:
534                 case PCIOCLISTVPD:
535                         break;
536                 default:
537                         return (EPERM);
538                 }
539         }
540
541         switch (cmd) {
542 #ifdef PRE7_COMPAT
543 #ifdef COMPAT_FREEBSD32
544         case PCIOCGETCONF_OLD32:
545                cio32 = (struct pci_conf_io32 *)data;
546                cio = malloc(sizeof(struct pci_conf_io), M_TEMP, M_WAITOK);
547                cio->pat_buf_len = cio32->pat_buf_len;
548                cio->num_patterns = cio32->num_patterns;
549                cio->patterns = (void *)(uintptr_t)cio32->patterns;
550                cio->match_buf_len = cio32->match_buf_len;
551                cio->num_matches = cio32->num_matches;
552                cio->matches = (void *)(uintptr_t)cio32->matches;
553                cio->offset = cio32->offset;
554                cio->generation = cio32->generation;
555                cio->status = cio32->status;
556                cio32->num_matches = 0;
557                break;
558 #endif
559         case PCIOCGETCONF_OLD:
560 #endif
561         case PCIOCGETCONF:
562                 cio = (struct pci_conf_io *)data;
563         }
564
565         switch (cmd) {
566 #ifdef PRE7_COMPAT
567 #ifdef COMPAT_FREEBSD32
568         case PCIOCGETCONF_OLD32:
569 #endif
570         case PCIOCGETCONF_OLD:
571 #endif
572         case PCIOCGETCONF:
573
574                 pattern_buf = NULL;
575                 num_patterns = 0;
576                 dinfo = NULL;
577
578                 cio->num_matches = 0;
579
580                 /*
581                  * If the user specified an offset into the device list,
582                  * but the list has changed since they last called this
583                  * ioctl, tell them that the list has changed.  They will
584                  * have to get the list from the beginning.
585                  */
586                 if ((cio->offset != 0)
587                  && (cio->generation != pci_generation)){
588                         cio->status = PCI_GETCONF_LIST_CHANGED;
589                         error = 0;
590                         goto getconfexit;
591                 }
592
593                 /*
594                  * Check to see whether the user has asked for an offset
595                  * past the end of our list.
596                  */
597                 if (cio->offset >= pci_numdevs) {
598                         cio->status = PCI_GETCONF_LAST_DEVICE;
599                         error = 0;
600                         goto getconfexit;
601                 }
602
603                 /* get the head of the device queue */
604                 devlist_head = &pci_devq;
605
606                 /*
607                  * Determine how much room we have for pci_conf structures.
608                  * Round the user's buffer size down to the nearest
609                  * multiple of sizeof(struct pci_conf) in case the user
610                  * didn't specify a multiple of that size.
611                  */
612 #ifdef PRE7_COMPAT
613 #ifdef COMPAT_FREEBSD32
614                 if (cmd == PCIOCGETCONF_OLD32)
615                         confsz = sizeof(struct pci_conf_old32);
616                 else
617 #endif
618                 if (cmd == PCIOCGETCONF_OLD)
619                         confsz = sizeof(struct pci_conf_old);
620                 else
621 #endif
622                         confsz = sizeof(struct pci_conf);
623                 iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz),
624                     pci_numdevs * confsz);
625
626                 /*
627                  * Since we know that iolen is a multiple of the size of
628                  * the pciconf union, it's okay to do this.
629                  */
630                 ionum = iolen / confsz;
631
632                 /*
633                  * If this test is true, the user wants the pci_conf
634                  * structures returned to match the supplied entries.
635                  */
636                 if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs)
637                  && (cio->pat_buf_len > 0)) {
638                         /*
639                          * pat_buf_len needs to be:
640                          * num_patterns * sizeof(struct pci_match_conf)
641                          * While it is certainly possible the user just
642                          * allocated a large buffer, but set the number of
643                          * matches correctly, it is far more likely that
644                          * their kernel doesn't match the userland utility
645                          * they're using.  It's also possible that the user
646                          * forgot to initialize some variables.  Yes, this
647                          * may be overly picky, but I hazard to guess that
648                          * it's far more likely to just catch folks that
649                          * updated their kernel but not their userland.
650                          */
651 #ifdef PRE7_COMPAT
652 #ifdef COMPAT_FREEBSD32
653                         if (cmd == PCIOCGETCONF_OLD32)
654                                 pbufsz = sizeof(struct pci_match_conf_old32);
655                         else
656 #endif
657                         if (cmd == PCIOCGETCONF_OLD)
658                                 pbufsz = sizeof(struct pci_match_conf_old);
659                         else
660 #endif
661                                 pbufsz = sizeof(struct pci_match_conf);
662                         if (cio->num_patterns * pbufsz != cio->pat_buf_len) {
663                                 /* The user made a mistake, return an error. */
664                                 cio->status = PCI_GETCONF_ERROR;
665                                 error = EINVAL;
666                                 goto getconfexit;
667                         }
668
669                         /*
670                          * Allocate a buffer to hold the patterns.
671                          */
672 #ifdef PRE7_COMPAT
673 #ifdef COMPAT_FREEBSD32
674                         if (cmd == PCIOCGETCONF_OLD32) {
675                                 pattern_buf_old32 = malloc(cio->pat_buf_len,
676                                     M_TEMP, M_WAITOK);
677                                 error = copyin(cio->patterns,
678                                     pattern_buf_old32, cio->pat_buf_len);
679                         } else
680 #endif /* COMPAT_FREEBSD32 */
681                         if (cmd == PCIOCGETCONF_OLD) {
682                                 pattern_buf_old = malloc(cio->pat_buf_len,
683                                     M_TEMP, M_WAITOK);
684                                 error = copyin(cio->patterns,
685                                     pattern_buf_old, cio->pat_buf_len);
686                         } else
687 #endif /* PRE7_COMPAT */
688                         {
689                                 pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
690                                     M_WAITOK);
691                                 error = copyin(cio->patterns, pattern_buf,
692                                     cio->pat_buf_len);
693                         }
694                         if (error != 0) {
695                                 error = EINVAL;
696                                 goto getconfexit;
697                         }
698                         num_patterns = cio->num_patterns;
699                 } else if ((cio->num_patterns > 0)
700                         || (cio->pat_buf_len > 0)) {
701                         /*
702                          * The user made a mistake, spit out an error.
703                          */
704                         cio->status = PCI_GETCONF_ERROR;
705                         error = EINVAL;
706                        goto getconfexit;
707                 }
708
709                 /*
710                  * Go through the list of devices and copy out the devices
711                  * that match the user's criteria.
712                  */
713                 for (cio->num_matches = 0, i = 0,
714                                  dinfo = STAILQ_FIRST(devlist_head);
715                      dinfo != NULL;
716                      dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
717
718                         if (i < cio->offset)
719                                 continue;
720
721                         /* Populate pd_name and pd_unit */
722                         name = NULL;
723                         if (dinfo->cfg.dev)
724                                 name = device_get_name(dinfo->cfg.dev);
725                         if (name) {
726                                 strncpy(dinfo->conf.pd_name, name,
727                                         sizeof(dinfo->conf.pd_name));
728                                 dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0;
729                                 dinfo->conf.pd_unit =
730                                         device_get_unit(dinfo->cfg.dev);
731                         } else {
732                                 dinfo->conf.pd_name[0] = '\0';
733                                 dinfo->conf.pd_unit = 0;
734                         }
735
736 #ifdef PRE7_COMPAT
737                         if (
738 #ifdef COMPAT_FREEBSD32
739                             (cmd == PCIOCGETCONF_OLD32 &&
740                             (pattern_buf_old32 == NULL ||
741                             pci_conf_match_old32(pattern_buf_old32,
742                             num_patterns, &dinfo->conf) == 0)) ||
743 #endif
744                             (cmd == PCIOCGETCONF_OLD &&
745                             (pattern_buf_old == NULL ||
746                             pci_conf_match_old(pattern_buf_old, num_patterns,
747                             &dinfo->conf) == 0)) ||
748                             (cmd == PCIOCGETCONF &&
749                             (pattern_buf == NULL ||
750                             pci_conf_match(pattern_buf, num_patterns,
751                             &dinfo->conf) == 0))) {
752 #else
753                         if (pattern_buf == NULL ||
754                             pci_conf_match(pattern_buf, num_patterns,
755                             &dinfo->conf) == 0) {
756 #endif
757                                 /*
758                                  * If we've filled up the user's buffer,
759                                  * break out at this point.  Since we've
760                                  * got a match here, we'll pick right back
761                                  * up at the matching entry.  We can also
762                                  * tell the user that there are more matches
763                                  * left.
764                                  */
765                                 if (cio->num_matches >= ionum) {
766                                         error = 0;
767                                         break;
768                                 }
769
770 #ifdef PRE7_COMPAT
771 #ifdef COMPAT_FREEBSD32
772                                 if (cmd == PCIOCGETCONF_OLD32) {
773                                         memset(&conf_old32, 0,
774                                             sizeof(conf_old32));
775                                         conf_old32.pc_sel.pc_bus =
776                                             dinfo->conf.pc_sel.pc_bus;
777                                         conf_old32.pc_sel.pc_dev =
778                                             dinfo->conf.pc_sel.pc_dev;
779                                         conf_old32.pc_sel.pc_func =
780                                             dinfo->conf.pc_sel.pc_func;
781                                         conf_old32.pc_hdr = dinfo->conf.pc_hdr;
782                                         conf_old32.pc_subvendor =
783                                             dinfo->conf.pc_subvendor;
784                                         conf_old32.pc_subdevice =
785                                             dinfo->conf.pc_subdevice;
786                                         conf_old32.pc_vendor =
787                                             dinfo->conf.pc_vendor;
788                                         conf_old32.pc_device =
789                                             dinfo->conf.pc_device;
790                                         conf_old32.pc_class =
791                                             dinfo->conf.pc_class;
792                                         conf_old32.pc_subclass =
793                                             dinfo->conf.pc_subclass;
794                                         conf_old32.pc_progif =
795                                             dinfo->conf.pc_progif;
796                                         conf_old32.pc_revid =
797                                             dinfo->conf.pc_revid;
798                                         strncpy(conf_old32.pd_name,
799                                             dinfo->conf.pd_name,
800                                             sizeof(conf_old32.pd_name));
801                                         conf_old32.pd_name[PCI_MAXNAMELEN] = 0;
802                                         conf_old32.pd_unit =
803                                             (uint32_t)dinfo->conf.pd_unit;
804                                         confdata = &conf_old32;
805                                 } else
806 #endif /* COMPAT_FREEBSD32 */
807                                 if (cmd == PCIOCGETCONF_OLD) {
808                                         memset(&conf_old, 0, sizeof(conf_old));
809                                         conf_old.pc_sel.pc_bus =
810                                             dinfo->conf.pc_sel.pc_bus;
811                                         conf_old.pc_sel.pc_dev =
812                                             dinfo->conf.pc_sel.pc_dev;
813                                         conf_old.pc_sel.pc_func =
814                                             dinfo->conf.pc_sel.pc_func;
815                                         conf_old.pc_hdr = dinfo->conf.pc_hdr;
816                                         conf_old.pc_subvendor =
817                                             dinfo->conf.pc_subvendor;
818                                         conf_old.pc_subdevice =
819                                             dinfo->conf.pc_subdevice;
820                                         conf_old.pc_vendor =
821                                             dinfo->conf.pc_vendor;
822                                         conf_old.pc_device =
823                                             dinfo->conf.pc_device;
824                                         conf_old.pc_class =
825                                             dinfo->conf.pc_class;
826                                         conf_old.pc_subclass =
827                                             dinfo->conf.pc_subclass;
828                                         conf_old.pc_progif =
829                                             dinfo->conf.pc_progif;
830                                         conf_old.pc_revid =
831                                             dinfo->conf.pc_revid;
832                                         strncpy(conf_old.pd_name,
833                                             dinfo->conf.pd_name,
834                                             sizeof(conf_old.pd_name));
835                                         conf_old.pd_name[PCI_MAXNAMELEN] = 0;
836                                         conf_old.pd_unit =
837                                             dinfo->conf.pd_unit;
838                                         confdata = &conf_old;
839                                 } else
840 #endif /* PRE7_COMPAT */
841                                         confdata = &dinfo->conf;
842                                 error = copyout(confdata,
843                                     (caddr_t)cio->matches +
844                                     confsz * cio->num_matches, confsz);
845                                 if (error)
846                                         break;
847                                 cio->num_matches++;
848                         }
849                 }
850
851                 /*
852                  * Set the pointer into the list, so if the user is getting
853                  * n records at a time, where n < pci_numdevs,
854                  */
855                 cio->offset = i;
856
857                 /*
858                  * Set the generation, the user will need this if they make
859                  * another ioctl call with offset != 0.
860                  */
861                 cio->generation = pci_generation;
862
863                 /*
864                  * If this is the last device, inform the user so he won't
865                  * bother asking for more devices.  If dinfo isn't NULL, we
866                  * know that there are more matches in the list because of
867                  * the way the traversal is done.
868                  */
869                 if (dinfo == NULL)
870                         cio->status = PCI_GETCONF_LAST_DEVICE;
871                 else
872                         cio->status = PCI_GETCONF_MORE_DEVS;
873
874 getconfexit:
875 #ifdef PRE7_COMPAT
876 #ifdef COMPAT_FREEBSD32
877                 if (cmd == PCIOCGETCONF_OLD32) {
878                         cio32->status = cio->status;
879                         cio32->generation = cio->generation;
880                         cio32->offset = cio->offset;
881                         cio32->num_matches = cio->num_matches;
882                         free(cio, M_TEMP);
883                 }
884                 if (pattern_buf_old32 != NULL)
885                         free(pattern_buf_old32, M_TEMP);
886 #endif
887                 if (pattern_buf_old != NULL)
888                         free(pattern_buf_old, M_TEMP);
889 #endif
890                 if (pattern_buf != NULL)
891                         free(pattern_buf, M_TEMP);
892
893                 break;
894
895 #ifdef PRE7_COMPAT
896         case PCIOCREAD_OLD:
897         case PCIOCWRITE_OLD:
898                 io_old = (struct pci_io_old *)data;
899                 iodata.pi_sel.pc_domain = 0;
900                 iodata.pi_sel.pc_bus = io_old->pi_sel.pc_bus;
901                 iodata.pi_sel.pc_dev = io_old->pi_sel.pc_dev;
902                 iodata.pi_sel.pc_func = io_old->pi_sel.pc_func;
903                 iodata.pi_reg = io_old->pi_reg;
904                 iodata.pi_width = io_old->pi_width;
905                 iodata.pi_data = io_old->pi_data;
906                 data = (caddr_t)&iodata;
907                 /* FALLTHROUGH */
908 #endif
909         case PCIOCREAD:
910         case PCIOCWRITE:
911                 io = (struct pci_io *)data;
912                 switch(io->pi_width) {
913                 case 4:
914                 case 2:
915                 case 1:
916                         /* Make sure register is not negative and aligned. */
917                         if (io->pi_reg < 0 ||
918                             io->pi_reg & (io->pi_width - 1)) {
919                                 error = EINVAL;
920                                 break;
921                         }
922                         /*
923                          * Assume that the user-level bus number is
924                          * in fact the physical PCI bus number.
925                          * Look up the grandparent, i.e. the bridge device,
926                          * so that we can issue configuration space cycles.
927                          */
928                         pcidev = pci_find_dbsf(io->pi_sel.pc_domain,
929                             io->pi_sel.pc_bus, io->pi_sel.pc_dev,
930                             io->pi_sel.pc_func);
931                         if (pcidev) {
932 #ifdef PRE7_COMPAT
933                                 if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD)
934 #else
935                                 if (cmd == PCIOCWRITE)
936 #endif
937                                         pci_write_config(pcidev,
938                                                           io->pi_reg,
939                                                           io->pi_data,
940                                                           io->pi_width);
941 #ifdef PRE7_COMPAT
942                                 else if (cmd == PCIOCREAD_OLD)
943                                         io_old->pi_data =
944                                                 pci_read_config(pcidev,
945                                                           io->pi_reg,
946                                                           io->pi_width);
947 #endif
948                                 else
949                                         io->pi_data =
950                                                 pci_read_config(pcidev,
951                                                           io->pi_reg,
952                                                           io->pi_width);
953                                 error = 0;
954                         } else {
955 #ifdef COMPAT_FREEBSD4
956                                 if (cmd == PCIOCREAD_OLD) {
957                                         io_old->pi_data = -1;
958                                         error = 0;
959                                 } else
960 #endif
961                                         error = ENODEV;
962                         }
963                         break;
964                 default:
965                         error = EINVAL;
966                         break;
967                 }
968                 break;
969
970         case PCIOCGETBAR:
971                 bio = (struct pci_bar_io *)data;
972
973                 /*
974                  * Assume that the user-level bus number is
975                  * in fact the physical PCI bus number.
976                  */
977                 pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain,
978                     bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev,
979                     bio->pbi_sel.pc_func);
980                 if (pcidev == NULL) {
981                         error = ENODEV;
982                         break;
983                 }
984                 pm = pci_find_bar(pcidev, bio->pbi_reg);
985                 if (pm == NULL) {
986                         error = EINVAL;
987                         break;
988                 }
989                 bio->pbi_base = pm->pm_value;
990                 bio->pbi_length = (pci_addr_t)1 << pm->pm_size;
991                 bio->pbi_enabled = pci_bar_enabled(pcidev, pm);
992                 error = 0;
993                 break;
994         case PCIOCATTACHED:
995                 error = 0;
996                 io = (struct pci_io *)data;
997                 pcidev = pci_find_dbsf(io->pi_sel.pc_domain, io->pi_sel.pc_bus,
998                                        io->pi_sel.pc_dev, io->pi_sel.pc_func);
999                 if (pcidev != NULL)
1000                         io->pi_data = device_is_attached(pcidev);
1001                 else
1002                         error = ENODEV;
1003                 break;
1004         case PCIOCLISTVPD:
1005                 lvio = (struct pci_list_vpd_io *)data;
1006
1007                 /*
1008                  * Assume that the user-level bus number is
1009                  * in fact the physical PCI bus number.
1010                  */
1011                 pcidev = pci_find_dbsf(lvio->plvi_sel.pc_domain,
1012                     lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev,
1013                     lvio->plvi_sel.pc_func);
1014                 if (pcidev == NULL) {
1015                         error = ENODEV;
1016                         break;
1017                 }
1018                 error = pci_list_vpd(pcidev, lvio);
1019                 break;
1020         default:
1021                 error = ENOTTY;
1022                 break;
1023         }
1024
1025         return (error);
1026 }