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