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, ®, 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, ®, 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, ®, 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, ®, 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