x86_pci.c revision 49310723
1/*
2 * Copyright (c) 2009, 2012 Samuel Thibault
3 * Heavily inspired from the freebsd, netbsd, and openbsd backends
4 * (C) Copyright Eric Anholt 2006
5 * (C) Copyright IBM Corporation 2006
6 * Copyright (c) 2008 Juan Romero Pardines
7 * Copyright (c) 2008 Mark Kettenis
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21#ifdef HAVE_CONFIG_H
22#include "config.h"
23#endif
24
25#include <unistd.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <sys/mman.h>
31#include <string.h>
32#include <strings.h>
33
34#include "pciaccess.h"
35#include "pciaccess_private.h"
36
37#if defined(__GNU__)
38
39#include <sys/io.h>
40
41static int
42x86_enable_io(void)
43{
44    if (!ioperm(0, 0xffff, 1))
45        return 0;
46    return errno;
47}
48
49static int
50x86_disable_io(void)
51{
52    if (!ioperm(0, 0xffff, 0))
53        return 0;
54    return errno;
55}
56
57#elif defined(__GLIBC__)
58
59#include <sys/io.h>
60
61static int
62x86_enable_io(void)
63{
64    if (!iopl(3))
65        return 0;
66    return errno;
67}
68
69static int
70x86_disable_io(void)
71{
72    if (!iopl(0))
73        return 0;
74    return errno;
75}
76
77#elif defined(__CYGWIN__)
78
79#include <windows.h>
80
81/* WinIo declarations */
82typedef BYTE bool;
83typedef struct tagPhysStruct {
84    DWORD64 dwPhysMemSizeInBytes;
85    DWORD64 pvPhysAddress;
86    DWORD64 PhysicalMemoryHandle;
87    DWORD64 pvPhysMemLin;
88    DWORD64 pvPhysSection;
89} tagPhysStruct;
90
91typedef bool  (_stdcall* INITIALIZEWINIO)(void);
92typedef void  (_stdcall* SHUTDOWNWINIO)(void);
93typedef bool  (_stdcall* GETPORTVAL)(WORD,PDWORD,BYTE);
94typedef bool  (_stdcall* SETPORTVAL)(WORD,DWORD,BYTE);
95typedef PBYTE (_stdcall* MAPPHYSTOLIN)(tagPhysStruct*);
96typedef bool  (_stdcall* UNMAPPHYSMEM)(tagPhysStruct*);
97
98SHUTDOWNWINIO ShutdownWinIo;
99GETPORTVAL GetPortVal;
100SETPORTVAL SetPortVal;
101INITIALIZEWINIO InitializeWinIo;
102MAPPHYSTOLIN MapPhysToLin;
103UNMAPPHYSMEM UnmapPhysicalMemory;
104
105static int
106x86_enable_io(void)
107{
108    HMODULE lib = NULL;
109
110    if ((GetVersion() & 0x80000000) == 0) {
111      /* running on NT, try WinIo version 3 (32 or 64 bits) */
112#ifdef WIN64
113      lib = LoadLibrary("WinIo64.dll");
114#else
115      lib = LoadLibrary("WinIo32.dll");
116#endif
117    }
118
119    if (!lib) {
120      fprintf(stderr, "Failed to load WinIo library.\n");
121      return 1;
122    }
123
124#define GETPROC(n, d) 						\
125    n = (d) GetProcAddress(lib, #n); 				\
126    if (!n) { 							\
127      fprintf(stderr, "Failed to load " #n " function.\n");	\
128      return 1; 						\
129    }
130
131    GETPROC(InitializeWinIo, INITIALIZEWINIO);
132    GETPROC(ShutdownWinIo, SHUTDOWNWINIO);
133    GETPROC(GetPortVal, GETPORTVAL);
134    GETPROC(SetPortVal, SETPORTVAL);
135    GETPROC(MapPhysToLin, MAPPHYSTOLIN);
136    GETPROC(UnmapPhysicalMemory, UNMAPPHYSMEM);
137
138#undef GETPROC
139
140    if (!InitializeWinIo()) {
141      fprintf(stderr, "Failed to initialize WinIo.\n"
142		      "NOTE: WinIo.dll and WinIo.sys must be in the same directory as the executable!\n");
143      return 0;
144    }
145
146    return 0;
147}
148
149static int
150x86_disable_io(void)
151{
152    ShutdownWinIo();
153    return 1;
154}
155
156static inline uint8_t
157inb(uint16_t port)
158{
159    DWORD pv;
160
161    if (GetPortVal(port, &pv, 1))
162      return (uint8_t)pv;
163    return 0;
164}
165
166static inline uint16_t
167inw(uint16_t port)
168{
169    DWORD pv;
170
171    if (GetPortVal(port, &pv, 2))
172      return (uint16_t)pv;
173    return 0;
174}
175
176static inline uint32_t
177inl(uint16_t port)
178{
179    DWORD pv;
180
181    if (GetPortVal(port, &pv, 4))
182        return (uint32_t)pv;
183    return 0;
184}
185
186static inline void
187outb(uint8_t value, uint16_t port)
188{
189    SetPortVal(port, value, 1);
190}
191
192static inline void
193outw(uint16_t value, uint16_t port)
194{
195    SetPortVal(port, value, 2);
196}
197
198static inline void
199outl(uint32_t value, uint16_t port)
200{
201    SetPortVal(port, value, 4);
202}
203
204#else
205
206#error How to enable IO ports on this system?
207
208#endif
209
210#define PCI_VENDOR(reg)		((reg) & 0xFFFF)
211#define PCI_VENDOR_INVALID	0xFFFF
212
213#define PCI_VENDOR_ID		0x00
214#define PCI_SUB_VENDOR_ID	0x2c
215#define PCI_VENDOR_ID_COMPAQ		0x0e11
216#define PCI_VENDOR_ID_INTEL		0x8086
217
218#define PCI_DEVICE(reg)		(((reg) >> 16) & 0xFFFF)
219#define PCI_DEVICE_INVALID	0xFFFF
220
221#define PCI_CLASS		0x08
222#define PCI_CLASS_DEVICE	0x0a
223#define PCI_CLASS_DISPLAY_VGA		0x0300
224#define PCI_CLASS_BRIDGE_HOST		0x0600
225
226#define	PCIC_DISPLAY	0x03
227#define	PCIS_DISPLAY_VGA	0x00
228
229#define PCI_HDRTYPE	0x0E
230#define PCI_IRQ		0x3C
231
232struct pci_system_x86 {
233    struct pci_system system;
234    int (*read)(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size);
235    int (*write)(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size);
236};
237
238static int
239pci_system_x86_conf1_probe(void)
240{
241    unsigned long sav;
242    int res = ENODEV;
243
244    outb(0x01, 0xCFB);
245    sav = inl(0xCF8);
246    outl(0x80000000, 0xCF8);
247    if (inl(0xCF8) == 0x80000000)
248	res = 0;
249    outl(sav, 0xCF8);
250
251    return res;
252}
253
254static int
255pci_system_x86_conf1_read(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size)
256{
257    unsigned addr = 0xCFC + (reg & 3);
258    unsigned long sav;
259    int ret = 0;
260
261    if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 || size == 3)
262	return EIO;
263
264    sav = inl(0xCF8);
265    outl(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), 0xCF8);
266    /* NOTE: x86 is already LE */
267    switch (size) {
268	case 1: {
269	    uint8_t *val = data;
270	    *val = inb(addr);
271	    break;
272	}
273	case 2: {
274	    uint16_t *val = data;
275	    *val = inw(addr);
276	    break;
277	}
278	case 4: {
279	    uint32_t *val = data;
280	    *val = inl(addr);
281	    break;
282	}
283    }
284    outl(sav, 0xCF8);
285
286    return ret;
287}
288
289static int
290pci_system_x86_conf1_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size)
291{
292    unsigned addr = 0xCFC + (reg & 3);
293    unsigned long sav;
294    int ret = 0;
295
296    if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 || size == 3)
297	return EIO;
298
299    sav = inl(0xCF8);
300    outl(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), 0xCF8);
301    /* NOTE: x86 is already LE */
302    switch (size) {
303	case 1: {
304	    const uint8_t *val = data;
305	    outb(*val, addr);
306	    break;
307	}
308	case 2: {
309	    const uint16_t *val = data;
310	    outw(*val, addr);
311	    break;
312	}
313	case 4: {
314	    const uint32_t *val = data;
315	    outl(*val, addr);
316	    break;
317	}
318    }
319    outl(sav, 0xCF8);
320
321    return ret;
322}
323
324static int
325pci_system_x86_conf2_probe(void)
326{
327    outb(0, 0xCFB);
328    outb(0, 0xCF8);
329    outb(0, 0xCFA);
330    if (inb(0xCF8) == 0 && inb(0xCFA) == 0)
331	return 0;
332
333    return ENODEV;
334}
335
336static int
337pci_system_x86_conf2_read(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size)
338{
339    unsigned addr = 0xC000 | dev << 8 | reg;
340    int ret = 0;
341
342    if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100)
343	return EIO;
344
345    outb((func << 1) | 0xF0, 0xCF8);
346    outb(bus, 0xCFA);
347    /* NOTE: x86 is already LE */
348    switch (size) {
349	case 1: {
350	    uint8_t *val = data;
351	    *val = inb(addr);
352	    break;
353	}
354	case 2: {
355	    uint16_t *val = data;
356	    *val = inw(addr);
357	    break;
358	}
359	case 4: {
360	    uint32_t *val = data;
361	    *val = inl(addr);
362	    break;
363	}
364	default:
365	    ret = EIO;
366	    break;
367    }
368    outb(0, 0xCF8);
369
370    return ret;
371}
372
373static int
374pci_system_x86_conf2_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size)
375{
376    unsigned addr = 0xC000 | dev << 8 | reg;
377    int ret = 0;
378
379    if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100)
380	return EIO;
381
382    outb((func << 1) | 0xF0, 0xCF8);
383    outb(bus, 0xCFA);
384    /* NOTE: x86 is already LE */
385    switch (size) {
386	case 1: {
387	    const uint8_t *val = data;
388	    outb(*val, addr);
389	    break;
390	}
391	case 2: {
392	    const uint16_t *val = data;
393	    outw(*val, addr);
394	    break;
395	}
396	case 4: {
397	    const uint32_t *val = data;
398	    outl(*val, addr);
399	    break;
400	}
401	default:
402	    ret = EIO;
403	    break;
404    }
405    outb(0, 0xCF8);
406
407    return ret;
408}
409
410/* Check that this really looks like a PCI configuration. */
411static int
412pci_system_x86_check(struct pci_system_x86 *pci_sys_x86)
413{
414    int dev;
415    uint16_t class, vendor;
416
417    /* Look on bus 0 for a device that is a host bridge, a VGA card,
418     * or an intel or compaq device.  */
419
420    for (dev = 0; dev < 32; dev++) {
421	if (pci_sys_x86->read(0, dev, 0, PCI_CLASS_DEVICE, &class, sizeof(class)))
422	    continue;
423	if (class == PCI_CLASS_BRIDGE_HOST || class == PCI_CLASS_DISPLAY_VGA)
424	    return 0;
425	if (pci_sys_x86->read(0, dev, 0, PCI_VENDOR_ID, &vendor, sizeof(vendor)))
426	    continue;
427	if (vendor == PCI_VENDOR_ID_INTEL || class == PCI_VENDOR_ID_COMPAQ)
428	    return 0;
429    }
430
431    return ENODEV;
432}
433
434static int
435pci_nfuncs(struct pci_system_x86 *pci_sys_x86, int bus, int dev)
436{
437    uint8_t hdr;
438    int err;
439
440    err = pci_sys_x86->read(bus, dev, 0, PCI_HDRTYPE, &hdr, sizeof(hdr));
441
442    if (err)
443	return err;
444
445    return hdr & 0x80 ? 8 : 1;
446}
447
448/**
449 * Read a VGA rom using the 0xc0000 mapping.
450 */
451static int
452pci_device_x86_read_rom(struct pci_device *dev, void *buffer)
453{
454    void *bios;
455    int memfd;
456
457    if ((dev->device_class & 0x00ffff00) !=
458	 ((PCIC_DISPLAY << 16) | ( PCIS_DISPLAY_VGA << 8))) {
459	return ENOSYS;
460    }
461
462    memfd = open("/dev/mem", O_RDONLY | O_CLOEXEC);
463    if (memfd == -1)
464	return errno;
465
466    bios = mmap(NULL, dev->rom_size, PROT_READ, 0, memfd, 0xc0000);
467    if (bios == MAP_FAILED) {
468	close(memfd);
469	return errno;
470    }
471
472    memcpy(buffer, bios, dev->rom_size);
473
474    munmap(bios, dev->rom_size);
475    close(memfd);
476
477    return 0;
478}
479
480/** Returns the number of regions (base address registers) the device has */
481static int
482pci_device_x86_get_num_regions(uint8_t header_type)
483{
484    switch (header_type & 0x7f) {
485	case 0:
486	    return 6;
487	case 1:
488	    return 2;
489	case 2:
490	    return 1;
491	default:
492	    fprintf(stderr,"unknown header type %02x\n", header_type);
493	    return 0;
494    }
495}
496
497/** Masks out the flag bigs of the base address register value */
498static uint32_t
499get_map_base( uint32_t val )
500{
501    if (val & 0x01)
502	return val & ~0x03;
503    else
504	return val & ~0x0f;
505}
506
507/** Returns the size of a region based on the all-ones test value */
508static unsigned
509get_test_val_size( uint32_t testval )
510{
511    unsigned size = 1;
512
513    if (testval == 0)
514	return 0;
515
516    /* Mask out the flag bits */
517    testval = get_map_base( testval );
518    if (!testval)
519	return 0;
520
521    while ((testval & 1) == 0) {
522	size <<= 1;
523	testval >>= 1;
524    }
525
526    return size;
527}
528
529static int
530pci_device_x86_probe(struct pci_device *dev)
531{
532    uint8_t irq, hdrtype;
533    int err, i, bar;
534
535    /* Many of the fields were filled in during initial device enumeration.
536     * At this point, we need to fill in regions, rom_size, and irq.
537     */
538
539    err = pci_device_cfg_read_u8(dev, &irq, PCI_IRQ);
540    if (err)
541	return err;
542    dev->irq = irq;
543
544    err = pci_device_cfg_read_u8(dev, &hdrtype, PCI_HDRTYPE);
545    if (err)
546	return err;
547
548    bar = 0x10;
549    for (i = 0; i < pci_device_x86_get_num_regions(hdrtype); i++, bar += 4) {
550	uint32_t addr, testval;
551
552	/* Get the base address */
553	err = pci_device_cfg_read_u32(dev, &addr, bar);
554	if (err != 0)
555	    continue;
556
557	/* Test write all ones to the register, then restore it. */
558	err = pci_device_cfg_write_u32(dev, 0xffffffff, bar);
559	if (err != 0)
560	    continue;
561	pci_device_cfg_read_u32(dev, &testval, bar);
562	err = pci_device_cfg_write_u32(dev, addr, bar);
563
564	if (addr & 0x01)
565	    dev->regions[i].is_IO = 1;
566	if (addr & 0x04)
567	    dev->regions[i].is_64 = 1;
568	if (addr & 0x08)
569	    dev->regions[i].is_prefetchable = 1;
570
571	/* Set the size */
572	dev->regions[i].size = get_test_val_size(testval);
573
574	/* Set the base address value */
575	if (dev->regions[i].is_64) {
576	    uint32_t top;
577
578	    err = pci_device_cfg_read_u32(dev, &top, bar + 4);
579	    if (err != 0)
580		continue;
581
582	    dev->regions[i].base_addr = ((uint64_t)top << 32) |
583					get_map_base(addr);
584	    bar += 4;
585	    i++;
586	} else {
587	    dev->regions[i].base_addr = get_map_base(addr);
588	}
589    }
590
591    /* If it's a VGA device, set up the rom size for read_rom using the
592     * 0xc0000 mapping.
593     */
594    if ((dev->device_class & 0x00ffff00) ==
595	((PCIC_DISPLAY << 16) | (PCIS_DISPLAY_VGA << 8)))
596    {
597	dev->rom_size = 64 * 1024;
598    }
599
600    return 0;
601}
602
603#if defined(__CYGWIN__)
604
605static int
606pci_device_x86_map_range(struct pci_device *dev,
607    struct pci_device_mapping *map)
608{
609    tagPhysStruct phys;
610
611    phys.pvPhysAddress        = (DWORD64)(DWORD32)map->base;
612    phys.dwPhysMemSizeInBytes = map->size;
613
614    map->memory = (PDWORD)MapPhysToLin(&phys);
615    if (map->memory == NULL)
616        return EFAULT;
617
618    return 0;
619}
620
621static int
622pci_device_x86_unmap_range(struct pci_device *dev,
623    struct pci_device_mapping *map)
624{
625    tagPhysStruct phys;
626
627    phys.pvPhysAddress        = (DWORD64)(DWORD32)map->base;
628    phys.dwPhysMemSizeInBytes = map->size;
629
630    if (!UnmapPhysicalMemory(&phys))
631        return EFAULT;
632
633    return 0;
634}
635
636#else
637
638static int
639pci_device_x86_map_range(struct pci_device *dev,
640    struct pci_device_mapping *map)
641{
642    int memfd = open("/dev/mem", O_RDWR | O_CLOEXEC);
643    int prot = PROT_READ;
644
645    if (memfd == -1)
646	return errno;
647
648    if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE)
649	prot |= PROT_WRITE;
650
651    map->memory = mmap(NULL, map->size, prot, MAP_SHARED, memfd, map->base);
652    close(memfd);
653    if (map->memory == MAP_FAILED)
654	return errno;
655
656    return 0;
657}
658
659static int
660pci_device_x86_unmap_range(struct pci_device *dev,
661    struct pci_device_mapping *map)
662{
663    return pci_device_generic_unmap_range(dev, map);
664}
665
666#endif
667
668static int
669pci_device_x86_read(struct pci_device *dev, void *data,
670    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read)
671{
672    struct pci_system_x86 *pci_sys_x86 = (struct pci_system_x86 *) pci_sys;
673    int err;
674
675    *bytes_read = 0;
676    while (size > 0) {
677	int toread = 1 << (ffs(0x4 + (offset & 0x03)) - 1);
678	if (toread > size)
679	    toread = size;
680
681	err = pci_sys_x86->read(dev->bus, dev->dev, dev->func, offset, data, toread);
682	if (err)
683	    return err;
684
685	offset += toread;
686	data = (char*)data + toread;
687	size -= toread;
688	*bytes_read += toread;
689    }
690    return 0;
691}
692
693static int
694pci_device_x86_write(struct pci_device *dev, const void *data,
695    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written)
696{
697    struct pci_system_x86 *pci_sys_x86 = (struct pci_system_x86 *) pci_sys;
698    int err;
699
700    *bytes_written = 0;
701    while (size > 0) {
702	int towrite = 4;
703	if (towrite > size)
704	    towrite = size;
705	if (towrite > 4 - (offset & 0x3))
706	    towrite = 4 - (offset & 0x3);
707
708	err = pci_sys_x86->write(dev->bus, dev->dev, dev->func, offset, data, towrite);
709	if (err)
710	    return err;
711
712	offset += towrite;
713	data = (const char*)data + towrite;
714	size -= towrite;
715	*bytes_written += towrite;
716    }
717    return 0;
718}
719
720static void
721pci_system_x86_destroy(void)
722{
723    x86_disable_io();
724}
725
726static struct pci_io_handle *
727pci_device_x86_open_legacy_io(struct pci_io_handle *ret,
728    struct pci_device *dev, pciaddr_t base, pciaddr_t size)
729{
730    x86_enable_io();
731
732    ret->base = base;
733    ret->size = size;
734    ret->is_legacy = 1;
735
736    return ret;
737}
738
739static void
740pci_device_x86_close_io(struct pci_device *dev, struct pci_io_handle *handle)
741{
742    /* Like in the Linux case, do not disable I/O, as it may be opened several
743     * times, and closed fewer times. */
744    /* x86_disable_io(); */
745}
746
747static uint32_t
748pci_device_x86_read32(struct pci_io_handle *handle, uint32_t reg)
749{
750    return inl(reg + handle->base);
751}
752
753static uint16_t
754pci_device_x86_read16(struct pci_io_handle *handle, uint32_t reg)
755{
756    return inw(reg + handle->base);
757}
758
759static uint8_t
760pci_device_x86_read8(struct pci_io_handle *handle, uint32_t reg)
761{
762    return inb(reg + handle->base);
763}
764
765static void
766pci_device_x86_write32(struct pci_io_handle *handle, uint32_t reg,
767		       uint32_t data)
768{
769    outl(data, reg + handle->base);
770}
771
772static void
773pci_device_x86_write16(struct pci_io_handle *handle, uint32_t reg,
774		       uint16_t data)
775{
776    outw(data, reg + handle->base);
777}
778
779static void
780pci_device_x86_write8(struct pci_io_handle *handle, uint32_t reg,
781		      uint8_t data)
782{
783    outb(data, reg + handle->base);
784}
785
786static int
787pci_device_x86_map_legacy(struct pci_device *dev, pciaddr_t base,
788    pciaddr_t size, unsigned map_flags, void **addr)
789{
790    struct pci_device_mapping map;
791    int err;
792
793    map.base = base;
794    map.size = size;
795    map.flags = map_flags;
796    err = pci_device_x86_map_range(dev, &map);
797    *addr = map.memory;
798
799    return err;
800}
801
802static int
803pci_device_x86_unmap_legacy(struct pci_device *dev, void *addr,
804    pciaddr_t size)
805{
806    struct pci_device_mapping map;
807
808    map.size = size;
809    map.flags = 0;
810    map.memory = addr;
811
812    return pci_device_x86_unmap_range(dev, &map);
813}
814
815static const struct pci_system_methods x86_pci_methods = {
816    .destroy = pci_system_x86_destroy,
817    .read_rom = pci_device_x86_read_rom,
818    .probe = pci_device_x86_probe,
819    .map_range = pci_device_x86_map_range,
820    .unmap_range = pci_device_x86_unmap_range,
821    .read = pci_device_x86_read,
822    .write = pci_device_x86_write,
823    .fill_capabilities = pci_fill_capabilities_generic,
824    .open_legacy_io = pci_device_x86_open_legacy_io,
825    .close_io = pci_device_x86_close_io,
826    .read32 = pci_device_x86_read32,
827    .read16 = pci_device_x86_read16,
828    .read8 = pci_device_x86_read8,
829    .write32 = pci_device_x86_write32,
830    .write16 = pci_device_x86_write16,
831    .write8 = pci_device_x86_write8,
832    .map_legacy = pci_device_x86_map_legacy,
833    .unmap_legacy = pci_device_x86_unmap_legacy,
834};
835
836static int pci_probe(struct pci_system_x86 *pci_sys_x86)
837{
838    if (pci_system_x86_conf1_probe() == 0) {
839	pci_sys_x86->read = pci_system_x86_conf1_read;
840	pci_sys_x86->write = pci_system_x86_conf1_write;
841	if (pci_system_x86_check(pci_sys_x86) == 0)
842	    return 0;
843    }
844
845    if (pci_system_x86_conf2_probe() == 0) {
846	pci_sys_x86->read = pci_system_x86_conf2_read;
847	pci_sys_x86->write = pci_system_x86_conf2_write;
848	if (pci_system_x86_check(pci_sys_x86) == 0)
849	    return 0;
850    }
851
852    return ENODEV;
853}
854
855_pci_hidden int
856pci_system_x86_create(void)
857{
858    struct pci_device_private *device;
859    int ret, bus, dev, ndevs, func, nfuncs;
860    struct pci_system_x86 *pci_sys_x86;
861    uint32_t reg;
862
863    ret = x86_enable_io();
864    if (ret)
865	return ret;
866
867    pci_sys_x86 = calloc(1, sizeof(struct pci_system_x86));
868    if (pci_sys_x86 == NULL) {
869	x86_disable_io();
870	return ENOMEM;
871    }
872    pci_sys = &pci_sys_x86->system;
873
874    ret = pci_probe(pci_sys_x86);
875    if (ret) {
876	x86_disable_io();
877	free(pci_sys_x86);
878	pci_sys = NULL;
879	return ret;
880    }
881
882    pci_sys->methods = &x86_pci_methods;
883
884    ndevs = 0;
885    for (bus = 0; bus < 256; bus++) {
886	for (dev = 0; dev < 32; dev++) {
887	    nfuncs = pci_nfuncs(pci_sys_x86, bus, dev);
888	    for (func = 0; func < nfuncs; func++) {
889		if (pci_sys_x86->read(bus, dev, func, PCI_VENDOR_ID, &reg, sizeof(reg)) != 0)
890		    continue;
891		if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
892		    PCI_VENDOR(reg) == 0)
893		    continue;
894		ndevs++;
895	    }
896	}
897    }
898
899    pci_sys->num_devices = ndevs;
900    pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private));
901    if (pci_sys->devices == NULL) {
902	x86_disable_io();
903	free(pci_sys_x86);
904	pci_sys = NULL;
905	return ENOMEM;
906    }
907
908    device = pci_sys->devices;
909    for (bus = 0; bus < 256; bus++) {
910	for (dev = 0; dev < 32; dev++) {
911	    nfuncs = pci_nfuncs(pci_sys_x86, bus, dev);
912	    for (func = 0; func < nfuncs; func++) {
913		if (pci_sys_x86->read(bus, dev, func, PCI_VENDOR_ID, &reg, sizeof(reg)) != 0)
914		    continue;
915		if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
916		    PCI_VENDOR(reg) == 0)
917		    continue;
918		device->base.domain = 0;
919		device->base.bus = bus;
920		device->base.dev = dev;
921		device->base.func = func;
922		device->base.vendor_id = PCI_VENDOR(reg);
923		device->base.device_id = PCI_DEVICE(reg);
924
925		if (pci_sys_x86->read(bus, dev, func, PCI_CLASS, &reg, sizeof(reg)) != 0)
926		    continue;
927		device->base.device_class = reg >> 8;
928		device->base.revision = reg & 0xFF;
929
930		if (pci_sys_x86->read(bus, dev, func, PCI_SUB_VENDOR_ID, &reg, sizeof(reg)) != 0)
931		    continue;
932		device->base.subvendor_id = PCI_VENDOR(reg);
933		device->base.subdevice_id = PCI_DEVICE(reg);
934
935		device++;
936	    }
937	}
938    }
939
940    return 0;
941}
942