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