x86_pci.c revision 6a94483f
128d65773Smrg/*
286ea1d58Smrg * Copyright (c) 2009, 2012 Samuel Thibault
328d65773Smrg * Heavily inspired from the freebsd, netbsd, and openbsd backends
428d65773Smrg * (C) Copyright Eric Anholt 2006
528d65773Smrg * (C) Copyright IBM Corporation 2006
628d65773Smrg * Copyright (c) 2008 Juan Romero Pardines
728d65773Smrg * Copyright (c) 2008 Mark Kettenis
828d65773Smrg *
928d65773Smrg * Permission to use, copy, modify, and distribute this software for any
1028d65773Smrg * purpose with or without fee is hereby granted, provided that the above
1128d65773Smrg * copyright notice and this permission notice appear in all copies.
1228d65773Smrg *
1328d65773Smrg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1428d65773Smrg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1528d65773Smrg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1628d65773Smrg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1728d65773Smrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1828d65773Smrg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1928d65773Smrg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2028d65773Smrg */
2128d65773Smrg
2228d65773Smrg#define _GNU_SOURCE
2328d65773Smrg#include <unistd.h>
2428d65773Smrg#include <stdio.h>
2528d65773Smrg#include <stdlib.h>
2628d65773Smrg#include <errno.h>
2728d65773Smrg#include <fcntl.h>
2828d65773Smrg#include <sys/mman.h>
2928d65773Smrg#include <string.h>
3028d65773Smrg#include <strings.h>
3128d65773Smrg
3228d65773Smrg#include "pciaccess.h"
3328d65773Smrg#include "pciaccess_private.h"
3428d65773Smrg
3528d65773Smrg#if defined(__GNU__)
3628d65773Smrg
3728d65773Smrg#include <sys/io.h>
3828d65773Smrg
3928d65773Smrgstatic int
4028d65773Smrgx86_enable_io(void)
4128d65773Smrg{
4228d65773Smrg    if (!ioperm(0, 0xffff, 1))
4328d65773Smrg        return 0;
4428d65773Smrg    return errno;
4528d65773Smrg}
4628d65773Smrg
4728d65773Smrgstatic int
4828d65773Smrgx86_disable_io(void)
4928d65773Smrg{
5028d65773Smrg    if (!ioperm(0, 0xffff, 0))
5128d65773Smrg        return 0;
5228d65773Smrg    return errno;
5328d65773Smrg}
5428d65773Smrg
5528d65773Smrg#elif defined(__GLIBC__)
5628d65773Smrg
5728d65773Smrg#include <sys/io.h>
5828d65773Smrg
5928d65773Smrgstatic int
6028d65773Smrgx86_enable_io(void)
6128d65773Smrg{
6228d65773Smrg    if (!iopl(3))
6328d65773Smrg        return 0;
6428d65773Smrg    return errno;
6528d65773Smrg}
6628d65773Smrg
6728d65773Smrgstatic int
6828d65773Smrgx86_disable_io(void)
6928d65773Smrg{
7028d65773Smrg    if (!iopl(0))
7128d65773Smrg        return 0;
7228d65773Smrg    return errno;
7328d65773Smrg}
7428d65773Smrg
756a94483fSmrg#elif defined(__CYGWIN__)
766a94483fSmrg
776a94483fSmrg#include <windows.h>
786a94483fSmrg
796a94483fSmrg/* WinIo declarations */
806a94483fSmrgtypedef BYTE bool;
816a94483fSmrgtypedef struct tagPhysStruct {
826a94483fSmrg    DWORD64 dwPhysMemSizeInBytes;
836a94483fSmrg    DWORD64 pvPhysAddress;
846a94483fSmrg    DWORD64 PhysicalMemoryHandle;
856a94483fSmrg    DWORD64 pvPhysMemLin;
866a94483fSmrg    DWORD64 pvPhysSection;
876a94483fSmrg} tagPhysStruct;
886a94483fSmrg
896a94483fSmrgtypedef bool  (_stdcall* INITIALIZEWINIO)(void);
906a94483fSmrgtypedef void  (_stdcall* SHUTDOWNWINIO)(void);
916a94483fSmrgtypedef bool  (_stdcall* GETPORTVAL)(WORD,PDWORD,BYTE);
926a94483fSmrgtypedef bool  (_stdcall* SETPORTVAL)(WORD,DWORD,BYTE);
936a94483fSmrgtypedef PBYTE (_stdcall* MAPPHYSTOLIN)(tagPhysStruct*);
946a94483fSmrgtypedef bool  (_stdcall* UNMAPPHYSMEM)(tagPhysStruct*);
956a94483fSmrg
966a94483fSmrgSHUTDOWNWINIO ShutdownWinIo;
976a94483fSmrgGETPORTVAL GetPortVal;
986a94483fSmrgSETPORTVAL SetPortVal;
996a94483fSmrgINITIALIZEWINIO InitializeWinIo;
1006a94483fSmrgMAPPHYSTOLIN MapPhysToLin;
1016a94483fSmrgUNMAPPHYSMEM UnmapPhysicalMemory;
1026a94483fSmrg
1036a94483fSmrgstatic int
1046a94483fSmrgx86_enable_io(void)
1056a94483fSmrg{
1066a94483fSmrg    HMODULE lib = NULL;
1076a94483fSmrg
1086a94483fSmrg    if ((GetVersion() & 0x80000000) == 0) {
1096a94483fSmrg      /* running on NT, try WinIo version 3 (32 or 64 bits) */
1106a94483fSmrg#ifdef WIN64
1116a94483fSmrg      lib = LoadLibrary("WinIo64.dll");
1126a94483fSmrg#else
1136a94483fSmrg      lib = LoadLibrary("WinIo32.dll");
1146a94483fSmrg#endif
1156a94483fSmrg    }
1166a94483fSmrg
1176a94483fSmrg    if (!lib) {
1186a94483fSmrg      fprintf(stderr, "Failed to load WinIo library.\n");
1196a94483fSmrg      return 1;
1206a94483fSmrg    }
1216a94483fSmrg
1226a94483fSmrg#define GETPROC(n, d) 						\
1236a94483fSmrg    n = (d) GetProcAddress(lib, #n); 				\
1246a94483fSmrg    if (!n) { 							\
1256a94483fSmrg      fprintf(stderr, "Failed to load " #n " function.\n");	\
1266a94483fSmrg      return 1; 						\
1276a94483fSmrg    }
1286a94483fSmrg
1296a94483fSmrg    GETPROC(InitializeWinIo, INITIALIZEWINIO);
1306a94483fSmrg    GETPROC(ShutdownWinIo, SHUTDOWNWINIO);
1316a94483fSmrg    GETPROC(GetPortVal, GETPORTVAL);
1326a94483fSmrg    GETPROC(SetPortVal, SETPORTVAL);
1336a94483fSmrg    GETPROC(MapPhysToLin, MAPPHYSTOLIN);
1346a94483fSmrg    GETPROC(UnmapPhysicalMemory, UNMAPPHYSMEM);
1356a94483fSmrg
1366a94483fSmrg#undef GETPROC
1376a94483fSmrg
1386a94483fSmrg    if (!InitializeWinIo()) {
1396a94483fSmrg      fprintf(stderr, "Failed to initialize WinIo.\n"
1406a94483fSmrg		      "NOTE: WinIo.dll and WinIo.sys must be in the same directory as the executable!\n");
1416a94483fSmrg      return 0;
1426a94483fSmrg    }
1436a94483fSmrg
1446a94483fSmrg    return 0;
1456a94483fSmrg}
1466a94483fSmrg
1476a94483fSmrgstatic int
1486a94483fSmrgx86_disable_io(void)
1496a94483fSmrg{
1506a94483fSmrg    ShutdownWinIo();
1516a94483fSmrg    return 1;
1526a94483fSmrg}
1536a94483fSmrg
1546a94483fSmrgstatic inline uint8_t
1556a94483fSmrginb(uint16_t port)
1566a94483fSmrg{
1576a94483fSmrg    DWORD pv;
1586a94483fSmrg
1596a94483fSmrg    if (GetPortVal(port, &pv, 1))
1606a94483fSmrg      return (uint8_t)pv;
1616a94483fSmrg    return 0;
1626a94483fSmrg}
1636a94483fSmrg
1646a94483fSmrgstatic inline uint16_t
1656a94483fSmrginw(uint16_t port)
1666a94483fSmrg{
1676a94483fSmrg    DWORD pv;
1686a94483fSmrg
1696a94483fSmrg    if (GetPortVal(port, &pv, 2))
1706a94483fSmrg      return (uint16_t)pv;
1716a94483fSmrg    return 0;
1726a94483fSmrg}
1736a94483fSmrg
1746a94483fSmrgstatic inline uint32_t
1756a94483fSmrginl(uint16_t port)
1766a94483fSmrg{
1776a94483fSmrg    DWORD pv;
1786a94483fSmrg
1796a94483fSmrg    if (GetPortVal(port, &pv, 4))
1806a94483fSmrg        return (uint32_t)pv;
1816a94483fSmrg    return 0;
1826a94483fSmrg}
1836a94483fSmrg
1846a94483fSmrgstatic inline void
1856a94483fSmrgoutb(uint8_t value, uint16_t port)
1866a94483fSmrg{
1876a94483fSmrg    SetPortVal(port, value, 1);
1886a94483fSmrg}
1896a94483fSmrg
1906a94483fSmrgstatic inline void
1916a94483fSmrgoutw(uint16_t value, uint16_t port)
1926a94483fSmrg{
1936a94483fSmrg    SetPortVal(port, value, 2);
1946a94483fSmrg}
1956a94483fSmrg
1966a94483fSmrgstatic inline void
1976a94483fSmrgoutl(uint32_t value, uint16_t port)
1986a94483fSmrg{
1996a94483fSmrg    SetPortVal(port, value, 4);
2006a94483fSmrg}
2016a94483fSmrg
20228d65773Smrg#else
20328d65773Smrg
20428d65773Smrg#error How to enable IO ports on this system?
20528d65773Smrg
20628d65773Smrg#endif
20728d65773Smrg
20828d65773Smrg#define PCI_VENDOR(reg)		((reg) & 0xFFFF)
20928d65773Smrg#define PCI_VENDOR_INVALID	0xFFFF
21028d65773Smrg
21128d65773Smrg#define PCI_VENDOR_ID		0x00
21228d65773Smrg#define PCI_SUB_VENDOR_ID	0x2c
21328d65773Smrg#define PCI_VENDOR_ID_COMPAQ		0x0e11
21428d65773Smrg#define PCI_VENDOR_ID_INTEL		0x8086
21528d65773Smrg
21628d65773Smrg#define PCI_DEVICE(reg)		(((reg) >> 16) & 0xFFFF)
21728d65773Smrg#define PCI_DEVICE_INVALID	0xFFFF
21828d65773Smrg
21928d65773Smrg#define PCI_CLASS		0x08
22028d65773Smrg#define PCI_CLASS_DEVICE	0x0a
22128d65773Smrg#define PCI_CLASS_DISPLAY_VGA		0x0300
22228d65773Smrg#define PCI_CLASS_BRIDGE_HOST		0x0600
22328d65773Smrg
22428d65773Smrg#define	PCIC_DISPLAY	0x03
22528d65773Smrg#define	PCIS_DISPLAY_VGA	0x00
22628d65773Smrg
22728d65773Smrg#define PCI_HDRTYPE	0x0E
22828d65773Smrg#define PCI_IRQ		0x3C
22928d65773Smrg
23028d65773Smrgstruct pci_system_x86 {
23128d65773Smrg    struct pci_system system;
23228d65773Smrg    int (*read)(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size);
23328d65773Smrg    int (*write)(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size);
23428d65773Smrg};
23528d65773Smrg
23628d65773Smrgstatic int
23728d65773Smrgpci_system_x86_conf1_probe(void)
23828d65773Smrg{
23928d65773Smrg    unsigned long sav;
24028d65773Smrg    int res = ENODEV;
24128d65773Smrg
24228d65773Smrg    outb(0x01, 0xCFB);
24328d65773Smrg    sav = inl(0xCF8);
24428d65773Smrg    outl(0x80000000, 0xCF8);
24528d65773Smrg    if (inl(0xCF8) == 0x80000000)
24628d65773Smrg	res = 0;
24728d65773Smrg    outl(sav, 0xCF8);
24828d65773Smrg
24928d65773Smrg    return res;
25028d65773Smrg}
25128d65773Smrg
25228d65773Smrgstatic int
25328d65773Smrgpci_system_x86_conf1_read(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size)
25428d65773Smrg{
25528d65773Smrg    unsigned addr = 0xCFC + (reg & 3);
25628d65773Smrg    unsigned long sav;
25728d65773Smrg    int ret = 0;
25828d65773Smrg
25928d65773Smrg    if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 || size == 3)
26028d65773Smrg	return EIO;
26128d65773Smrg
26228d65773Smrg    sav = inl(0xCF8);
26328d65773Smrg    outl(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), 0xCF8);
26428d65773Smrg    /* NOTE: x86 is already LE */
26528d65773Smrg    switch (size) {
26628d65773Smrg	case 1: {
26728d65773Smrg	    uint8_t *val = data;
26828d65773Smrg	    *val = inb(addr);
26928d65773Smrg	    break;
27028d65773Smrg	}
27128d65773Smrg	case 2: {
27228d65773Smrg	    uint16_t *val = data;
27328d65773Smrg	    *val = inw(addr);
27428d65773Smrg	    break;
27528d65773Smrg	}
27628d65773Smrg	case 4: {
27728d65773Smrg	    uint32_t *val = data;
27828d65773Smrg	    *val = inl(addr);
27928d65773Smrg	    break;
28028d65773Smrg	}
28128d65773Smrg    }
28228d65773Smrg    outl(sav, 0xCF8);
28328d65773Smrg
28428d65773Smrg    return ret;
28528d65773Smrg}
28628d65773Smrg
28728d65773Smrgstatic int
28828d65773Smrgpci_system_x86_conf1_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size)
28928d65773Smrg{
29028d65773Smrg    unsigned addr = 0xCFC + (reg & 3);
29128d65773Smrg    unsigned long sav;
29228d65773Smrg    int ret = 0;
29328d65773Smrg
29428d65773Smrg    if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 || size == 3)
29528d65773Smrg	return EIO;
29628d65773Smrg
29728d65773Smrg    sav = inl(0xCF8);
29828d65773Smrg    outl(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), 0xCF8);
29928d65773Smrg    /* NOTE: x86 is already LE */
30028d65773Smrg    switch (size) {
30128d65773Smrg	case 1: {
30228d65773Smrg	    const uint8_t *val = data;
30328d65773Smrg	    outb(*val, addr);
30428d65773Smrg	    break;
30528d65773Smrg	}
30628d65773Smrg	case 2: {
30728d65773Smrg	    const uint16_t *val = data;
30828d65773Smrg	    outw(*val, addr);
30928d65773Smrg	    break;
31028d65773Smrg	}
31128d65773Smrg	case 4: {
31228d65773Smrg	    const uint32_t *val = data;
31328d65773Smrg	    outl(*val, addr);
31428d65773Smrg	    break;
31528d65773Smrg	}
31628d65773Smrg    }
31728d65773Smrg    outl(sav, 0xCF8);
31828d65773Smrg
31928d65773Smrg    return ret;
32028d65773Smrg}
32128d65773Smrg
32228d65773Smrgstatic int
32328d65773Smrgpci_system_x86_conf2_probe(void)
32428d65773Smrg{
32528d65773Smrg    outb(0, 0xCFB);
32628d65773Smrg    outb(0, 0xCF8);
32728d65773Smrg    outb(0, 0xCFA);
32828d65773Smrg    if (inb(0xCF8) == 0 && inb(0xCFA) == 0)
32928d65773Smrg	return 0;
33028d65773Smrg
33128d65773Smrg    return ENODEV;
33228d65773Smrg}
33328d65773Smrg
33428d65773Smrgstatic int
33528d65773Smrgpci_system_x86_conf2_read(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size)
33628d65773Smrg{
33728d65773Smrg    unsigned addr = 0xC000 | dev << 8 | reg;
33828d65773Smrg    int ret = 0;
33928d65773Smrg
34028d65773Smrg    if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100)
34128d65773Smrg	return EIO;
34228d65773Smrg
34328d65773Smrg    outb((func << 1) | 0xF0, 0xCF8);
34428d65773Smrg    outb(bus, 0xCFA);
34528d65773Smrg    /* NOTE: x86 is already LE */
34628d65773Smrg    switch (size) {
34728d65773Smrg	case 1: {
34828d65773Smrg	    uint8_t *val = data;
34928d65773Smrg	    *val = inb(addr);
35028d65773Smrg	    break;
35128d65773Smrg	}
35228d65773Smrg	case 2: {
35328d65773Smrg	    uint16_t *val = data;
35428d65773Smrg	    *val = inw(addr);
35528d65773Smrg	    break;
35628d65773Smrg	}
35728d65773Smrg	case 4: {
35828d65773Smrg	    uint32_t *val = data;
35928d65773Smrg	    *val = inl(addr);
36028d65773Smrg	    break;
36128d65773Smrg	}
36228d65773Smrg	default:
36328d65773Smrg	    ret = EIO;
36428d65773Smrg	    break;
36528d65773Smrg    }
36628d65773Smrg    outb(0, 0xCF8);
36728d65773Smrg
36828d65773Smrg    return ret;
36928d65773Smrg}
37028d65773Smrg
37128d65773Smrgstatic int
37228d65773Smrgpci_system_x86_conf2_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size)
37328d65773Smrg{
37428d65773Smrg    unsigned addr = 0xC000 | dev << 8 | reg;
37528d65773Smrg    int ret = 0;
37628d65773Smrg
37728d65773Smrg    if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100)
37828d65773Smrg	return EIO;
37928d65773Smrg
38028d65773Smrg    outb((func << 1) | 0xF0, 0xCF8);
38128d65773Smrg    outb(bus, 0xCFA);
38228d65773Smrg    /* NOTE: x86 is already LE */
38328d65773Smrg    switch (size) {
38428d65773Smrg	case 1: {
38528d65773Smrg	    const uint8_t *val = data;
38628d65773Smrg	    outb(*val, addr);
38728d65773Smrg	    break;
38828d65773Smrg	}
38928d65773Smrg	case 2: {
39028d65773Smrg	    const uint16_t *val = data;
39128d65773Smrg	    outw(*val, addr);
39228d65773Smrg	    break;
39328d65773Smrg	}
39428d65773Smrg	case 4: {
39528d65773Smrg	    const uint32_t *val = data;
39628d65773Smrg	    outl(*val, addr);
39728d65773Smrg	    break;
39828d65773Smrg	}
39928d65773Smrg	default:
40028d65773Smrg	    ret = EIO;
40128d65773Smrg	    break;
40228d65773Smrg    }
40328d65773Smrg    outb(0, 0xCF8);
40428d65773Smrg
40528d65773Smrg    return ret;
40628d65773Smrg}
40728d65773Smrg
40828d65773Smrg/* Check that this really looks like a PCI configuration. */
40928d65773Smrgstatic int
41028d65773Smrgpci_system_x86_check(struct pci_system_x86 *pci_sys_x86)
41128d65773Smrg{
41228d65773Smrg    int dev;
41328d65773Smrg    uint16_t class, vendor;
41428d65773Smrg
41528d65773Smrg    /* Look on bus 0 for a device that is a host bridge, a VGA card,
41628d65773Smrg     * or an intel or compaq device.  */
41728d65773Smrg
41828d65773Smrg    for (dev = 0; dev < 32; dev++) {
41928d65773Smrg	if (pci_sys_x86->read(0, dev, 0, PCI_CLASS_DEVICE, &class, sizeof(class)))
42028d65773Smrg	    continue;
42128d65773Smrg	if (class == PCI_CLASS_BRIDGE_HOST || class == PCI_CLASS_DISPLAY_VGA)
42228d65773Smrg	    return 0;
42328d65773Smrg	if (pci_sys_x86->read(0, dev, 0, PCI_VENDOR_ID, &vendor, sizeof(vendor)))
42428d65773Smrg	    continue;
42528d65773Smrg	if (vendor == PCI_VENDOR_ID_INTEL || class == PCI_VENDOR_ID_COMPAQ)
42628d65773Smrg	    return 0;
42728d65773Smrg    }
42828d65773Smrg
42928d65773Smrg    return ENODEV;
43028d65773Smrg}
43128d65773Smrg
43228d65773Smrgstatic int
43328d65773Smrgpci_nfuncs(struct pci_system_x86 *pci_sys_x86, int bus, int dev)
43428d65773Smrg{
43528d65773Smrg    uint8_t hdr;
43628d65773Smrg    int err;
43728d65773Smrg
43828d65773Smrg    err = pci_sys_x86->read(bus, dev, 0, PCI_HDRTYPE, &hdr, sizeof(hdr));
43928d65773Smrg
44028d65773Smrg    if (err)
44128d65773Smrg	return err;
44228d65773Smrg
44328d65773Smrg    return hdr & 0x80 ? 8 : 1;
44428d65773Smrg}
44528d65773Smrg
44628d65773Smrg/**
44728d65773Smrg * Read a VGA rom using the 0xc0000 mapping.
44828d65773Smrg */
44928d65773Smrgstatic int
45028d65773Smrgpci_device_x86_read_rom(struct pci_device *dev, void *buffer)
45128d65773Smrg{
45228d65773Smrg    void *bios;
45328d65773Smrg    int memfd;
45428d65773Smrg
45528d65773Smrg    if ((dev->device_class & 0x00ffff00) !=
45628d65773Smrg	 ((PCIC_DISPLAY << 16) | ( PCIS_DISPLAY_VGA << 8))) {
45728d65773Smrg	return ENOSYS;
45828d65773Smrg    }
45928d65773Smrg
460cad31331Smrg    memfd = open("/dev/mem", O_RDONLY | O_CLOEXEC);
46128d65773Smrg    if (memfd == -1)
46228d65773Smrg	return errno;
46328d65773Smrg
46428d65773Smrg    bios = mmap(NULL, dev->rom_size, PROT_READ, 0, memfd, 0xc0000);
46528d65773Smrg    if (bios == MAP_FAILED) {
46628d65773Smrg	close(memfd);
46728d65773Smrg	return errno;
46828d65773Smrg    }
46928d65773Smrg
47028d65773Smrg    memcpy(buffer, bios, dev->rom_size);
47128d65773Smrg
47228d65773Smrg    munmap(bios, dev->rom_size);
47328d65773Smrg    close(memfd);
47428d65773Smrg
47528d65773Smrg    return 0;
47628d65773Smrg}
47728d65773Smrg
47828d65773Smrg/** Returns the number of regions (base address registers) the device has */
47928d65773Smrgstatic int
48028d65773Smrgpci_device_x86_get_num_regions(uint8_t header_type)
48128d65773Smrg{
48228d65773Smrg    switch (header_type & 0x7f) {
48328d65773Smrg	case 0:
48428d65773Smrg	    return 6;
48528d65773Smrg	case 1:
48628d65773Smrg	    return 2;
48728d65773Smrg	case 2:
48828d65773Smrg	    return 1;
48928d65773Smrg	default:
49028d65773Smrg	    fprintf(stderr,"unknown header type %02x\n", header_type);
49128d65773Smrg	    return 0;
49228d65773Smrg    }
49328d65773Smrg}
49428d65773Smrg
49528d65773Smrg/** Masks out the flag bigs of the base address register value */
49628d65773Smrgstatic uint32_t
49728d65773Smrgget_map_base( uint32_t val )
49828d65773Smrg{
49928d65773Smrg    if (val & 0x01)
50028d65773Smrg	return val & ~0x03;
50128d65773Smrg    else
50228d65773Smrg	return val & ~0x0f;
50328d65773Smrg}
50428d65773Smrg
50528d65773Smrg/** Returns the size of a region based on the all-ones test value */
50628d65773Smrgstatic unsigned
50728d65773Smrgget_test_val_size( uint32_t testval )
50828d65773Smrg{
50928d65773Smrg    unsigned size = 1;
51028d65773Smrg
51128d65773Smrg    if (testval == 0)
51228d65773Smrg	return 0;
51328d65773Smrg
51428d65773Smrg    /* Mask out the flag bits */
51528d65773Smrg    testval = get_map_base( testval );
51628d65773Smrg    if (!testval)
51728d65773Smrg	return 0;
51828d65773Smrg
51928d65773Smrg    while ((testval & 1) == 0) {
52028d65773Smrg	size <<= 1;
52128d65773Smrg	testval >>= 1;
52228d65773Smrg    }
52328d65773Smrg
52428d65773Smrg    return size;
52528d65773Smrg}
52628d65773Smrg
52728d65773Smrgstatic int
52828d65773Smrgpci_device_x86_probe(struct pci_device *dev)
52928d65773Smrg{
53028d65773Smrg    uint8_t irq, hdrtype;
53128d65773Smrg    int err, i, bar;
53228d65773Smrg
53328d65773Smrg    /* Many of the fields were filled in during initial device enumeration.
53428d65773Smrg     * At this point, we need to fill in regions, rom_size, and irq.
53528d65773Smrg     */
53628d65773Smrg
53728d65773Smrg    err = pci_device_cfg_read_u8(dev, &irq, PCI_IRQ);
53828d65773Smrg    if (err)
53928d65773Smrg	return err;
54028d65773Smrg    dev->irq = irq;
54128d65773Smrg
54228d65773Smrg    err = pci_device_cfg_read_u8(dev, &hdrtype, PCI_HDRTYPE);
54328d65773Smrg    if (err)
54428d65773Smrg	return err;
54528d65773Smrg
54628d65773Smrg    bar = 0x10;
54728d65773Smrg    for (i = 0; i < pci_device_x86_get_num_regions(hdrtype); i++, bar += 4) {
54828d65773Smrg	uint32_t addr, testval;
54928d65773Smrg
55028d65773Smrg	/* Get the base address */
55128d65773Smrg	err = pci_device_cfg_read_u32(dev, &addr, bar);
55228d65773Smrg	if (err != 0)
55328d65773Smrg	    continue;
55428d65773Smrg
55528d65773Smrg	/* Test write all ones to the register, then restore it. */
55628d65773Smrg	err = pci_device_cfg_write_u32(dev, 0xffffffff, bar);
55728d65773Smrg	if (err != 0)
55828d65773Smrg	    continue;
55928d65773Smrg	pci_device_cfg_read_u32(dev, &testval, bar);
56028d65773Smrg	err = pci_device_cfg_write_u32(dev, addr, bar);
56128d65773Smrg
56228d65773Smrg	if (addr & 0x01)
56328d65773Smrg	    dev->regions[i].is_IO = 1;
56428d65773Smrg	if (addr & 0x04)
56528d65773Smrg	    dev->regions[i].is_64 = 1;
56628d65773Smrg	if (addr & 0x08)
56728d65773Smrg	    dev->regions[i].is_prefetchable = 1;
56828d65773Smrg
56928d65773Smrg	/* Set the size */
57028d65773Smrg	dev->regions[i].size = get_test_val_size(testval);
57128d65773Smrg
57228d65773Smrg	/* Set the base address value */
57328d65773Smrg	if (dev->regions[i].is_64) {
57428d65773Smrg	    uint32_t top;
57528d65773Smrg
57628d65773Smrg	    err = pci_device_cfg_read_u32(dev, &top, bar + 4);
57728d65773Smrg	    if (err != 0)
57828d65773Smrg		continue;
57928d65773Smrg
58028d65773Smrg	    dev->regions[i].base_addr = ((uint64_t)top << 32) |
58128d65773Smrg					get_map_base(addr);
58228d65773Smrg	    bar += 4;
58328d65773Smrg	    i++;
58428d65773Smrg	} else {
58528d65773Smrg	    dev->regions[i].base_addr = get_map_base(addr);
58628d65773Smrg	}
58728d65773Smrg    }
58828d65773Smrg
58928d65773Smrg    /* If it's a VGA device, set up the rom size for read_rom using the
59028d65773Smrg     * 0xc0000 mapping.
59128d65773Smrg     */
59228d65773Smrg    if ((dev->device_class & 0x00ffff00) ==
59328d65773Smrg	((PCIC_DISPLAY << 16) | (PCIS_DISPLAY_VGA << 8)))
59428d65773Smrg    {
59528d65773Smrg	dev->rom_size = 64 * 1024;
59628d65773Smrg    }
59728d65773Smrg
59828d65773Smrg    return 0;
59928d65773Smrg}
60028d65773Smrg
6016a94483fSmrg#if defined(__CYGWIN__)
6026a94483fSmrg
6036a94483fSmrgstatic int
6046a94483fSmrgpci_device_x86_map_range(struct pci_device *dev,
6056a94483fSmrg    struct pci_device_mapping *map)
6066a94483fSmrg{
6076a94483fSmrg    tagPhysStruct phys;
6086a94483fSmrg
6096a94483fSmrg    phys.pvPhysAddress        = (DWORD64)(DWORD32)map->base;
6106a94483fSmrg    phys.dwPhysMemSizeInBytes = map->size;
6116a94483fSmrg
6126a94483fSmrg    map->memory = (PDWORD)MapPhysToLin(&phys);
6136a94483fSmrg    if (map->memory == NULL)
6146a94483fSmrg        return EFAULT;
6156a94483fSmrg
6166a94483fSmrg    return 0;
6176a94483fSmrg}
6186a94483fSmrg
6196a94483fSmrgstatic int
6206a94483fSmrgpci_device_x86_unmap_range(struct pci_device *dev,
6216a94483fSmrg    struct pci_device_mapping *map)
6226a94483fSmrg{
6236a94483fSmrg    tagPhysStruct phys;
6246a94483fSmrg
6256a94483fSmrg    phys.pvPhysAddress        = (DWORD64)(DWORD32)map->base;
6266a94483fSmrg    phys.dwPhysMemSizeInBytes = map->size;
6276a94483fSmrg
6286a94483fSmrg    if (!UnmapPhysicalMemory(&phys))
6296a94483fSmrg        return EFAULT;
6306a94483fSmrg
6316a94483fSmrg    return 0;
6326a94483fSmrg}
6336a94483fSmrg
6346a94483fSmrg#else
6356a94483fSmrg
63628d65773Smrgstatic int
63728d65773Smrgpci_device_x86_map_range(struct pci_device *dev,
63828d65773Smrg    struct pci_device_mapping *map)
63928d65773Smrg{
640cad31331Smrg    int memfd = open("/dev/mem", O_RDWR | O_CLOEXEC);
64128d65773Smrg    int prot = PROT_READ;
64228d65773Smrg
64328d65773Smrg    if (memfd == -1)
64428d65773Smrg	return errno;
64528d65773Smrg
64628d65773Smrg    if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE)
64728d65773Smrg	prot |= PROT_WRITE;
64828d65773Smrg
64928d65773Smrg    map->memory = mmap(NULL, map->size, prot, MAP_SHARED, memfd, map->base);
65028d65773Smrg    close(memfd);
65128d65773Smrg    if (map->memory == MAP_FAILED)
65228d65773Smrg	return errno;
65328d65773Smrg
65428d65773Smrg    return 0;
65528d65773Smrg}
65628d65773Smrg
6576a94483fSmrgstatic int
6586a94483fSmrgpci_device_x86_unmap_range(struct pci_device *dev,
6596a94483fSmrg    struct pci_device_mapping *map)
6606a94483fSmrg{
6616a94483fSmrg    return pci_device_generic_unmap_range(dev, map);
6626a94483fSmrg}
6636a94483fSmrg
6646a94483fSmrg#endif
6656a94483fSmrg
66628d65773Smrgstatic int
66728d65773Smrgpci_device_x86_read(struct pci_device *dev, void *data,
66828d65773Smrg    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read)
66928d65773Smrg{
67028d65773Smrg    struct pci_system_x86 *pci_sys_x86 = (struct pci_system_x86 *) pci_sys;
67128d65773Smrg    int err;
67228d65773Smrg
67328d65773Smrg    *bytes_read = 0;
67428d65773Smrg    while (size > 0) {
67528d65773Smrg	int toread = 1 << (ffs(0x4 + (offset & 0x03)) - 1);
67628d65773Smrg	if (toread > size)
67728d65773Smrg	    toread = size;
67828d65773Smrg
67928d65773Smrg	err = pci_sys_x86->read(dev->bus, dev->dev, dev->func, offset, data, toread);
68028d65773Smrg	if (err)
68128d65773Smrg	    return err;
68228d65773Smrg
68328d65773Smrg	offset += toread;
68428d65773Smrg	data = (char*)data + toread;
68528d65773Smrg	size -= toread;
68628d65773Smrg	*bytes_read += toread;
68728d65773Smrg    }
68828d65773Smrg    return 0;
68928d65773Smrg}
69028d65773Smrg
69128d65773Smrgstatic int
69228d65773Smrgpci_device_x86_write(struct pci_device *dev, const void *data,
69328d65773Smrg    pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written)
69428d65773Smrg{
69528d65773Smrg    struct pci_system_x86 *pci_sys_x86 = (struct pci_system_x86 *) pci_sys;
69628d65773Smrg    int err;
69728d65773Smrg
69828d65773Smrg    *bytes_written = 0;
69928d65773Smrg    while (size > 0) {
70028d65773Smrg	int towrite = 4;
70128d65773Smrg	if (towrite > size)
70228d65773Smrg	    towrite = size;
70328d65773Smrg	if (towrite > 4 - (offset & 0x3))
70428d65773Smrg	    towrite = 4 - (offset & 0x3);
70528d65773Smrg
70628d65773Smrg	err = pci_sys_x86->write(dev->bus, dev->dev, dev->func, offset, data, towrite);
70728d65773Smrg	if (err)
70828d65773Smrg	    return err;
70928d65773Smrg
71028d65773Smrg	offset += towrite;
71128d65773Smrg	data = (const char*)data + towrite;
71228d65773Smrg	size -= towrite;
71328d65773Smrg	*bytes_written += towrite;
71428d65773Smrg    }
71528d65773Smrg    return 0;
71628d65773Smrg}
71728d65773Smrg
71828d65773Smrgstatic void
71928d65773Smrgpci_system_x86_destroy(void)
72028d65773Smrg{
72128d65773Smrg    x86_disable_io();
72228d65773Smrg}
72328d65773Smrg
72486ea1d58Smrgstatic struct pci_io_handle *
72586ea1d58Smrgpci_device_x86_open_legacy_io(struct pci_io_handle *ret,
72686ea1d58Smrg    struct pci_device *dev, pciaddr_t base, pciaddr_t size)
72786ea1d58Smrg{
72886ea1d58Smrg    x86_enable_io();
72986ea1d58Smrg
73086ea1d58Smrg    ret->base = base;
73186ea1d58Smrg    ret->size = size;
7326a94483fSmrg    ret->is_legacy = 1;
73386ea1d58Smrg
73486ea1d58Smrg    return ret;
73586ea1d58Smrg}
73686ea1d58Smrg
73786ea1d58Smrgstatic void
73886ea1d58Smrgpci_device_x86_close_io(struct pci_device *dev, struct pci_io_handle *handle)
73986ea1d58Smrg{
74086ea1d58Smrg    /* Like in the Linux case, do not disable I/O, as it may be opened several
74186ea1d58Smrg     * times, and closed fewer times. */
74286ea1d58Smrg    /* x86_disable_io(); */
74386ea1d58Smrg}
74486ea1d58Smrg
74586ea1d58Smrgstatic uint32_t
74686ea1d58Smrgpci_device_x86_read32(struct pci_io_handle *handle, uint32_t reg)
74786ea1d58Smrg{
74886ea1d58Smrg    return inl(reg + handle->base);
74986ea1d58Smrg}
75086ea1d58Smrg
75186ea1d58Smrgstatic uint16_t
75286ea1d58Smrgpci_device_x86_read16(struct pci_io_handle *handle, uint32_t reg)
75386ea1d58Smrg{
75486ea1d58Smrg    return inw(reg + handle->base);
75586ea1d58Smrg}
75686ea1d58Smrg
75786ea1d58Smrgstatic uint8_t
75886ea1d58Smrgpci_device_x86_read8(struct pci_io_handle *handle, uint32_t reg)
75986ea1d58Smrg{
76086ea1d58Smrg    return inb(reg + handle->base);
76186ea1d58Smrg}
76286ea1d58Smrg
76386ea1d58Smrgstatic void
76486ea1d58Smrgpci_device_x86_write32(struct pci_io_handle *handle, uint32_t reg,
76586ea1d58Smrg		       uint32_t data)
76686ea1d58Smrg{
76786ea1d58Smrg    outl(data, reg + handle->base);
76886ea1d58Smrg}
76986ea1d58Smrg
77086ea1d58Smrgstatic void
77186ea1d58Smrgpci_device_x86_write16(struct pci_io_handle *handle, uint32_t reg,
77286ea1d58Smrg		       uint16_t data)
77386ea1d58Smrg{
77486ea1d58Smrg    outw(data, reg + handle->base);
77586ea1d58Smrg}
77686ea1d58Smrg
77786ea1d58Smrgstatic void
77886ea1d58Smrgpci_device_x86_write8(struct pci_io_handle *handle, uint32_t reg,
77986ea1d58Smrg		      uint8_t data)
78086ea1d58Smrg{
78186ea1d58Smrg    outb(data, reg + handle->base);
78286ea1d58Smrg}
78386ea1d58Smrg
78486ea1d58Smrgstatic int
78586ea1d58Smrgpci_device_x86_map_legacy(struct pci_device *dev, pciaddr_t base,
78686ea1d58Smrg    pciaddr_t size, unsigned map_flags, void **addr)
78786ea1d58Smrg{
78886ea1d58Smrg    struct pci_device_mapping map;
78986ea1d58Smrg    int err;
79086ea1d58Smrg
79186ea1d58Smrg    map.base = base;
79286ea1d58Smrg    map.size = size;
79386ea1d58Smrg    map.flags = map_flags;
79486ea1d58Smrg    err = pci_device_x86_map_range(dev, &map);
79586ea1d58Smrg    *addr = map.memory;
79686ea1d58Smrg
79786ea1d58Smrg    return err;
79886ea1d58Smrg}
79986ea1d58Smrg
80086ea1d58Smrgstatic int
80186ea1d58Smrgpci_device_x86_unmap_legacy(struct pci_device *dev, void *addr,
80286ea1d58Smrg    pciaddr_t size)
80386ea1d58Smrg{
80486ea1d58Smrg    struct pci_device_mapping map;
80586ea1d58Smrg
80686ea1d58Smrg    map.size = size;
80786ea1d58Smrg    map.flags = 0;
80886ea1d58Smrg    map.memory = addr;
80986ea1d58Smrg
8106a94483fSmrg    return pci_device_x86_unmap_range(dev, &map);
81186ea1d58Smrg}
81286ea1d58Smrg
81328d65773Smrgstatic const struct pci_system_methods x86_pci_methods = {
81428d65773Smrg    .destroy = pci_system_x86_destroy,
81528d65773Smrg    .read_rom = pci_device_x86_read_rom,
81628d65773Smrg    .probe = pci_device_x86_probe,
81728d65773Smrg    .map_range = pci_device_x86_map_range,
8186a94483fSmrg    .unmap_range = pci_device_x86_unmap_range,
81928d65773Smrg    .read = pci_device_x86_read,
82028d65773Smrg    .write = pci_device_x86_write,
82128d65773Smrg    .fill_capabilities = pci_fill_capabilities_generic,
82286ea1d58Smrg    .open_legacy_io = pci_device_x86_open_legacy_io,
82386ea1d58Smrg    .close_io = pci_device_x86_close_io,
82486ea1d58Smrg    .read32 = pci_device_x86_read32,
82586ea1d58Smrg    .read16 = pci_device_x86_read16,
82686ea1d58Smrg    .read8 = pci_device_x86_read8,
82786ea1d58Smrg    .write32 = pci_device_x86_write32,
82886ea1d58Smrg    .write16 = pci_device_x86_write16,
82986ea1d58Smrg    .write8 = pci_device_x86_write8,
83086ea1d58Smrg    .map_legacy = pci_device_x86_map_legacy,
83186ea1d58Smrg    .unmap_legacy = pci_device_x86_unmap_legacy,
83228d65773Smrg};
83328d65773Smrg
83428d65773Smrgstatic int pci_probe(struct pci_system_x86 *pci_sys_x86)
83528d65773Smrg{
83628d65773Smrg    if (pci_system_x86_conf1_probe() == 0) {
83728d65773Smrg	pci_sys_x86->read = pci_system_x86_conf1_read;
83828d65773Smrg	pci_sys_x86->write = pci_system_x86_conf1_write;
83928d65773Smrg	if (pci_system_x86_check(pci_sys_x86) == 0)
84028d65773Smrg	    return 0;
84128d65773Smrg    }
84228d65773Smrg
84328d65773Smrg    if (pci_system_x86_conf2_probe() == 0) {
84428d65773Smrg	pci_sys_x86->read = pci_system_x86_conf2_read;
84528d65773Smrg	pci_sys_x86->write = pci_system_x86_conf2_write;
84628d65773Smrg	if (pci_system_x86_check(pci_sys_x86) == 0)
84728d65773Smrg	    return 0;
84828d65773Smrg    }
84928d65773Smrg
85028d65773Smrg    return ENODEV;
85128d65773Smrg}
85228d65773Smrg
85328d65773Smrg_pci_hidden int
85428d65773Smrgpci_system_x86_create(void)
85528d65773Smrg{
85628d65773Smrg    struct pci_device_private *device;
85728d65773Smrg    int ret, bus, dev, ndevs, func, nfuncs;
85828d65773Smrg    struct pci_system_x86 *pci_sys_x86;
85928d65773Smrg    uint32_t reg;
86028d65773Smrg
86128d65773Smrg    ret = x86_enable_io();
86228d65773Smrg    if (ret)
86328d65773Smrg	return ret;
86428d65773Smrg
86528d65773Smrg    pci_sys_x86 = calloc(1, sizeof(struct pci_system_x86));
86628d65773Smrg    if (pci_sys_x86 == NULL) {
86728d65773Smrg	x86_disable_io();
86828d65773Smrg	return ENOMEM;
86928d65773Smrg    }
87028d65773Smrg    pci_sys = &pci_sys_x86->system;
87128d65773Smrg
87228d65773Smrg    ret = pci_probe(pci_sys_x86);
87328d65773Smrg    if (ret) {
87428d65773Smrg	x86_disable_io();
87528d65773Smrg	free(pci_sys_x86);
87628d65773Smrg	pci_sys = NULL;
87728d65773Smrg	return ret;
87828d65773Smrg    }
87928d65773Smrg
88028d65773Smrg    pci_sys->methods = &x86_pci_methods;
88128d65773Smrg
88228d65773Smrg    ndevs = 0;
88328d65773Smrg    for (bus = 0; bus < 256; bus++) {
88428d65773Smrg	for (dev = 0; dev < 32; dev++) {
88528d65773Smrg	    nfuncs = pci_nfuncs(pci_sys_x86, bus, dev);
88628d65773Smrg	    for (func = 0; func < nfuncs; func++) {
88728d65773Smrg		if (pci_sys_x86->read(bus, dev, func, PCI_VENDOR_ID, &reg, sizeof(reg)) != 0)
88828d65773Smrg		    continue;
88928d65773Smrg		if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
89028d65773Smrg		    PCI_VENDOR(reg) == 0)
89128d65773Smrg		    continue;
89228d65773Smrg		ndevs++;
89328d65773Smrg	    }
89428d65773Smrg	}
89528d65773Smrg    }
89628d65773Smrg
89728d65773Smrg    pci_sys->num_devices = ndevs;
89828d65773Smrg    pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private));
89928d65773Smrg    if (pci_sys->devices == NULL) {
90028d65773Smrg	x86_disable_io();
90128d65773Smrg	free(pci_sys_x86);
90228d65773Smrg	pci_sys = NULL;
90328d65773Smrg	return ENOMEM;
90428d65773Smrg    }
90528d65773Smrg
90628d65773Smrg    device = pci_sys->devices;
90728d65773Smrg    for (bus = 0; bus < 256; bus++) {
90828d65773Smrg	for (dev = 0; dev < 32; dev++) {
90928d65773Smrg	    nfuncs = pci_nfuncs(pci_sys_x86, bus, dev);
91028d65773Smrg	    for (func = 0; func < nfuncs; func++) {
91128d65773Smrg		if (pci_sys_x86->read(bus, dev, func, PCI_VENDOR_ID, &reg, sizeof(reg)) != 0)
91228d65773Smrg		    continue;
91328d65773Smrg		if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
91428d65773Smrg		    PCI_VENDOR(reg) == 0)
91528d65773Smrg		    continue;
91628d65773Smrg		device->base.domain = 0;
91728d65773Smrg		device->base.bus = bus;
91828d65773Smrg		device->base.dev = dev;
91928d65773Smrg		device->base.func = func;
92028d65773Smrg		device->base.vendor_id = PCI_VENDOR(reg);
92128d65773Smrg		device->base.device_id = PCI_DEVICE(reg);
92228d65773Smrg
92328d65773Smrg		if (pci_sys_x86->read(bus, dev, func, PCI_CLASS, &reg, sizeof(reg)) != 0)
92428d65773Smrg		    continue;
92528d65773Smrg		device->base.device_class = reg >> 8;
92628d65773Smrg		device->base.revision = reg & 0xFF;
92728d65773Smrg
92828d65773Smrg		if (pci_sys_x86->read(bus, dev, func, PCI_SUB_VENDOR_ID, &reg, sizeof(reg)) != 0)
92928d65773Smrg		    continue;
93028d65773Smrg		device->base.subvendor_id = PCI_VENDOR(reg);
93128d65773Smrg		device->base.subdevice_id = PCI_DEVICE(reg);
93228d65773Smrg
93328d65773Smrg		device++;
93428d65773Smrg	    }
93528d65773Smrg	}
93628d65773Smrg    }
93728d65773Smrg
93828d65773Smrg    return 0;
93928d65773Smrg}
940