pci.h revision e64031e20c39650a7bc902a3e1aba613b9415dee
/** @file
* PCI - The PCI Controller And Devices. (DEV)
*/
/*
* Copyright (C) 2006-2007 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
#ifndef ___VBox_pci_h
#define ___VBox_pci_h
#include <VBox/cdefs.h>
#include <VBox/types.h>
#include <iprt/assert.h>
/** @defgroup grp_pci PCI - The PCI Controller.
* @{
*/
/** Pointer to a PCI device. */
typedef struct PCIDevice *PPCIDEVICE;
/**
* PCI configuration word 4 (command) and word 6 (status).
*/
typedef enum PCICONFIGCOMMAND
{
/** Supports/uses memory accesses. */
PCI_COMMAND_IOACCESS = 0x0001,
PCI_COMMAND_MEMACCESS = 0x0002,
PCI_COMMAND_BUSMASTER = 0x0004
} PCICONFIGCOMMAND;
/**
* PCI Address space specification.
* This is used when registering a I/O region.
*/
/** Note: There are all sorts of dirty dependencies on the values in the
* pci device. Be careful when changing this.
* @todo we should introduce 32 & 64 bits physical address types
*/
typedef enum PCIADDRESSSPACE
{
/** Memory. */
PCI_ADDRESS_SPACE_MEM = 0x00,
/** I/O space. */
PCI_ADDRESS_SPACE_IO = 0x01,
/** Prefetch memory. */
PCI_ADDRESS_SPACE_MEM_PREFETCH = 0x08
} PCIADDRESSSPACE;
/**
* Callback function for mapping an PCI I/O region.
*
* @return VBox status code.
* @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
* @param iRegion The region number.
* @param GCPhysAddress Physical address of the region. If enmType is PCI_ADDRESS_SPACE_IO, this
* is an I/O port, otherwise it's a physical address.
*
* NIL_RTGCPHYS indicates that a MMIO2 mapping is about to be unmapped and
* that the device deregister access handlers for it and update its internal
* state to reflect this.
*
* @param enmType One of the PCI_ADDRESS_SPACE_* values.
*
* @remarks The address is *NOT* relative to pci_mem_base.
*/
typedef DECLCALLBACK(int) FNPCIIOREGIONMAP(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType);
/** Pointer to a FNPCIIOREGIONMAP() function. */
typedef FNPCIIOREGIONMAP *PFNPCIIOREGIONMAP;
/** @name PCI Configuration Space Registers
* @{ */
#define VBOX_PCI_VENDOR_ID 0x00 /**< 16-bit RO */
#define VBOX_PCI_DEVICE_ID 0x02 /**< 16-bit RO */
#define VBOX_PCI_COMMAND 0x04 /**< 16-bit RW */
#define VBOX_PCI_STATUS 0x06 /**< 16-bit RW */
#define VBOX_PCI_REVISION_ID 0x08 /**< 8-bit RO */
#define VBOX_PCI_CLASS_PROG 0x09 /**< 8-bit RO - - register-level programming class code (device specific). */
#define VBOX_PCI_CLASS_SUB 0x0a /**< 8-bit RO - - sub-class code. */
#define VBOX_PCI_CLASS_DEVICE VBOX_PCI_CLASS_SUB
#define VBOX_PCI_CLASS_BASE 0x0b /**< 8-bit RO - - base class code. */
#define VBOX_PCI_CACHE_LINE_SIZE 0x0c /**< 8-bit ?? */
#define VBOX_PCI_LATENCY_TIMER 0x0d /**< 8-bit ?? */
#define VBOX_PCI_HEADER_TYPE 0x0e /**< 8-bit ?? */
#define VBOX_PCI_BIST 0x0f /**< 8-bit ?? */
#define VBOX_PCI_BASE_ADDRESS_0 0x10 /**< 32-bit RW */
#define VBOX_PCI_BASE_ADDRESS_1 0x14 /**< 32-bit RW */
#define VBOX_PCI_BASE_ADDRESS_2 0x18 /**< 32-bit RW */
#define VBOX_PCI_PRIMARY_BUS 0x18 /**< 8-bit ?? - bridge - primary bus number. */
#define VBOX_PCI_SECONDARY_BUS 0x19 /**< 8-bit ?? - bridge - secondary bus number. */
#define VBOX_PCI_SUBORDINATE_BUS 0x1a /**< 8-bit ?? - bridge - highest subordinate bus number. (behind the bridge) */
#define VBOX_PCI_SEC_LATENCY_TIMER 0x1b /**< 8-bit ?? - bridge - secondary latency timer. */
#define VBOX_PCI_BASE_ADDRESS_3 0x1c /**< 32-bit RW */
#define VBOX_PCI_IO_BASE 0x1c /**< 8-bit ?? - bridge - I/O range base. */
#define VBOX_PCI_IO_LIMIT 0x1d /**< 8-bit ?? - bridge - I/O range limit. */
#define VBOX_PCI_SEC_STATUS 0x1e /**< 16-bit ?? - bridge - secondary status register. */
#define VBOX_PCI_BASE_ADDRESS_4 0x20 /**< 32-bit RW */
#define VBOX_PCI_MEMORY_BASE 0x20 /**< 16-bit ?? - bridge - memory range base. */
#define VBOX_PCI_MEMORY_LIMIT 0x22 /**< 16-bit ?? - bridge - memory range limit. */
#define VBOX_PCI_BASE_ADDRESS_5 0x24 /**< 32-bit RW */
#define VBOX_PCI_PREF_MEMORY_BASE 0x24 /**< 16-bit ?? - bridge - Prefetchable memory range base. */
#define VBOX_PCI_PREF_MEMORY_LIMIT 0x26 /**< 16-bit ?? - bridge - Prefetchable memory range limit. */
#define VBOX_PCI_CARDBUS_CIS 0x28 /**< 32-bit ?? */
#define VBOX_PCI_PREF_BASE_UPPER32 0x28 /**< 32-bit ?? - bridge - Prefetchable memory range high base.*/
#define VBOX_PCI_PREF_LIMIT_UPPER32 0x2c /**< 32-bit ?? - bridge - Prefetchable memory range high limit. */
#define VBOX_PCI_SUBSYSTEM_VENDOR_ID 0x2c /**< 16-bit ?? */
#define VBOX_PCI_SUBSYSTEM_ID 0x2e /**< 16-bit ?? */
#define VBOX_PCI_ROM_ADDRESS 0x30 /**< 32-bit ?? */
#define VBOX_PCI_IO_BASE_UPPER16 0x30 /**< 16-bit ?? - bridge - memory range high base. */
#define VBOX_PCI_IO_LIMIT_UPPER16 0x32 /**< 16-bit ?? - bridge - memory range high limit. */
#define VBOX_PCI_CAPABILITY_LIST 0x34 /**< 8-bit? ?? */
#define VBOX_PCI_ROM_ADDRESS_BR 0x38 /**< 32-bit ?? - bridge */
#define VBOX_PCI_INTERRUPT_LINE 0x3c /**< 8-bit RW - Interrupt line. */
#define VBOX_PCI_INTERRUPT_PIN 0x3d /**< 8-bit RO - Interrupt pin. */
#define VBOX_PCI_MIN_GNT 0x3e /**< 8-bit ?? */
#define VBOX_PCI_BRIDGE_CONTROL 0x3e /**< 8-bit? ?? - bridge */
#define VBOX_PCI_MAX_LAT 0x3f /**< 8-bit ?? */
/** @} */
/**
* Callback function for reading from the PCI configuration space.
*
* @returns The register value.
* @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
* @param Address The configuration space register address. [0..255]
* @param cb The register size. [1,2,4]
*/
typedef DECLCALLBACK(uint32_t) FNPCICONFIGREAD(PPCIDEVICE pPciDev, uint32_t Address, unsigned cb);
/** Pointer to a FNPCICONFIGREAD() function. */
typedef FNPCICONFIGREAD *PFNPCICONFIGREAD;
/** Pointer to a PFNPCICONFIGREAD. */
typedef PFNPCICONFIGREAD *PPFNPCICONFIGREAD;
/**
* Callback function for writing to the PCI configuration space.
*
* @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
* @param Address The configuration space register address. [0..255]
* @param u32Value The value that's being written. The number of bits actually used from
* this value is determined by the cb parameter.
* @param cb The register size. [1,2,4]
*/
typedef DECLCALLBACK(void) FNPCICONFIGWRITE(PPCIDEVICE pPciDev, uint32_t Address, uint32_t u32Value, unsigned cb);
/** Pointer to a FNPCICONFIGWRITE() function. */
typedef FNPCICONFIGWRITE *PFNPCICONFIGWRITE;
/** Pointer to a PFNPCICONFIGWRITE. */
typedef PFNPCICONFIGWRITE *PPFNPCICONFIGWRITE;
/** Fixed I/O region number for ROM. */
#define PCI_ROM_SLOT 6
/** Max number of I/O regions. */
#define PCI_NUM_REGIONS 7
/*
* Hack to include the PCIDEVICEINT structure at the right place
* to avoid duplications of FNPCIIOREGIONMAP and PCI_NUM_REGIONS.
*/
#ifdef PCI_INCLUDE_PRIVATE
# include "PCIInternal.h"
#endif
/**
* PCI Device structure.
*/
typedef struct PCIDevice
{
/** PCI config space. */
uint8_t config[256];
/** Internal data. */
union
{
#ifdef PCIDEVICEINT_DECLARED
PCIDEVICEINT s;
#endif
char padding[256];
} Int;
/** Read only data.
* @{
*/
/** PCI device number on the pci bus. */
int32_t devfn;
uint32_t Alignment0; /**< Alignment. */
/** Device name. */
R3PTRTYPE(const char *) name;
/** Pointer to the device instance which registered the device. */
PPDMDEVINSR3 pDevIns;
/** @} */
} PCIDEVICE;
/**
* Sets the vendor id config register.
* @param pPciDev The PCI device.
* @param u16VendorId The vendor id.
*/
DECLINLINE(void) PCIDevSetVendorId(PPCIDEVICE pPciDev, uint16_t u16VendorId)
{
u16VendorId = RT_H2LE_U16(u16VendorId);
pPciDev->config[VBOX_PCI_VENDOR_ID] = u16VendorId & 0xff;
pPciDev->config[VBOX_PCI_VENDOR_ID + 1] = u16VendorId >> 8;
}
/**
* Gets the vendor id config register.
* @returns the vendor id.
* @param pPciDev The PCI device.
*/
DECLINLINE(uint16_t) PCIDevGetVendorId(PPCIDEVICE pPciDev)
{
return RT_LE2H_U16(RT_MAKE_U16(pPciDev->config[VBOX_PCI_VENDOR_ID], pPciDev->config[VBOX_PCI_VENDOR_ID + 1]));
}
/**
* Sets the device id config register.
* @param pPciDev The PCI device.
* @param u16DeviceId The device id.
*/
DECLINLINE(void) PCIDevSetDeviceId(PPCIDEVICE pPciDev, uint16_t u16DeviceId)
{
u16DeviceId = RT_H2LE_U16(u16DeviceId);
pPciDev->config[VBOX_PCI_DEVICE_ID] = u16DeviceId & 0xff;
pPciDev->config[VBOX_PCI_DEVICE_ID + 1] = u16DeviceId >> 8;
}
/**
* Gets the device id config register.
* @returns the device id.
* @param pPciDev The PCI device.
*/
DECLINLINE(uint16_t) PCIDevGetDeviceId(PPCIDEVICE pPciDev)
{
return RT_LE2H_U16(RT_MAKE_U16(pPciDev->config[VBOX_PCI_DEVICE_ID], pPciDev->config[VBOX_PCI_DEVICE_ID + 1]));
}
/**
* Sets the command config register.
*
* @param pPciDev The PCI device.
* @param u16Command The command register value.
*/
DECLINLINE(void) PCIDevSetCommand(PPCIDEVICE pPciDev, uint16_t u16Command)
{
u16Command = RT_H2LE_U16(u16Command);
pPciDev->config[VBOX_PCI_COMMAND] = u16Command & 0xff;
pPciDev->config[VBOX_PCI_COMMAND + 1] = u16Command >> 8;
}
/**
* Gets the command config register.
* @returns The command register value.
* @param pPciDev The PCI device.
*/
DECLINLINE(uint16_t) PCIDevGetCommand(PPCIDEVICE pPciDev)
{
return RT_LE2H_U16(RT_MAKE_U16(pPciDev->config[VBOX_PCI_COMMAND], pPciDev->config[VBOX_PCI_COMMAND + 1]));
}
/**
* Sets the status config register.
*
* @param pPciDev The PCI device.
* @param u16Status The status register value.
*/
DECLINLINE(void) PCIDevSetStatus(PPCIDEVICE pPciDev, uint16_t u16Status)
{
u16Status = RT_H2LE_U16(u16Status);
pPciDev->config[VBOX_PCI_STATUS] = u16Status & 0xff;
pPciDev->config[VBOX_PCI_STATUS + 1] = u16Status >> 8;
}
/**
* Sets the revision id config register.
*
* @param pPciDev The PCI device.
* @param u8RevisionId The revision id.
*/
DECLINLINE(void) PCIDevSetRevisionId(PPCIDEVICE pPciDev, uint8_t u8RevisionId)
{
pPciDev->config[VBOX_PCI_REVISION_ID] = u8RevisionId;
}
/**
* Sets the register level programming class config register.
*
* @param pPciDev The PCI device.
* @param u8ClassProg The new value.
*/
DECLINLINE(void) PCIDevSetClassProg(PPCIDEVICE pPciDev, uint8_t u8ClassProg)
{
pPciDev->config[VBOX_PCI_CLASS_PROG] = u8ClassProg;
}
/**
* Sets the sub-class (aka device class) config register.
*
* @param pPciDev The PCI device.
* @param u8SubClass The sub-class.
*/
DECLINLINE(void) PCIDevSetClassSub(PPCIDEVICE pPciDev, uint8_t u8SubClass)
{
pPciDev->config[VBOX_PCI_CLASS_SUB] = u8SubClass;
}
/**
* Sets the base class config register.
*
* @param pPciDev The PCI device.
* @param u8BaseClass The base class.
*/
DECLINLINE(void) PCIDevSetClassBase(PPCIDEVICE pPciDev, uint8_t u8BaseClass)
{
pPciDev->config[VBOX_PCI_CLASS_BASE] = u8BaseClass;
}
/**
* Sets the header type config register.
*
* @param pPciDev The PCI device.
* @param u8HdrType The header type.
*/
DECLINLINE(void) PCIDevSetHeaderType(PPCIDEVICE pPciDev, uint8_t u8HdrType)
{
pPciDev->config[VBOX_PCI_HEADER_TYPE] = u8HdrType;
}
/**
* Sets a base address config register.
*
* @param pPciDev The PCI device.
* @param fIOSpace Whether it's I/O (true) or memory (false) space.
* @param fPrefetchable Whether the memory is prefetachable. Must be false if fIOSpace == true.
* @param f64Bit Whether the memory can be mapped anywhere in the 64-bit address space. Otherwise restrict to 32-bit.
* @param u32Addr The address value.
*/
DECLINLINE(void) PCIDevSetBaseAddress(PPCIDEVICE pPciDev, uint8_t iReg, bool fIOSpace, bool fPrefetchable, bool f64Bit, uint32_t u32Addr)
{
if (fIOSpace)
{
Assert(!(u32Addr & 0x3)); Assert(!fPrefetchable); Assert(!f64Bit);
u32Addr |= RT_BIT_32(0);
}
else
{
Assert(!(u32Addr & 0xf));
if (fPrefetchable)
u32Addr |= RT_BIT_32(3);
if (f64Bit)
u32Addr |= 0x2 << 1;
}
switch (iReg)
{
case 0: iReg = VBOX_PCI_BASE_ADDRESS_0; break;
case 1: iReg = VBOX_PCI_BASE_ADDRESS_1; break;
case 2: iReg = VBOX_PCI_BASE_ADDRESS_2; break;
case 3: iReg = VBOX_PCI_BASE_ADDRESS_3; break;
case 4: iReg = VBOX_PCI_BASE_ADDRESS_4; break;
case 5: iReg = VBOX_PCI_BASE_ADDRESS_5; break;
default: AssertFailedReturnVoid();
}
u32Addr = RT_H2LE_U32(u32Addr);
pPciDev->config[iReg] = u32Addr & 0xff;
pPciDev->config[iReg + 1] = (u32Addr >> 8) & 0xff;
pPciDev->config[iReg + 2] = (u32Addr >> 16) & 0xff;
pPciDev->config[iReg + 3] = (u32Addr >> 24) & 0xff;
}
/**
* Sets the sub-system vendor id config register.
*
* @param pPciDev The PCI device.
* @param u16SubSysVendorId The sub-system vendor id.
*/
DECLINLINE(void) PCIDevSetSubSystemVendorId(PPCIDEVICE pPciDev, uint16_t u16SubSysVendorId)
{
u16SubSysVendorId = RT_H2LE_U16(u16SubSysVendorId);
pPciDev->config[VBOX_PCI_SUBSYSTEM_VENDOR_ID] = u16SubSysVendorId & 0xff;
pPciDev->config[VBOX_PCI_SUBSYSTEM_VENDOR_ID + 1] = u16SubSysVendorId >> 8;
}
/**
* Gets the sub-system vendor id config register.
* @returns the sub-system vendor id.
* @param pPciDev The PCI device.
*/
DECLINLINE(uint16_t) PCIDevGetSubSystemVendorId(PPCIDEVICE pPciDev)
{
return RT_LE2H_U16(RT_MAKE_U16(pPciDev->config[VBOX_PCI_SUBSYSTEM_VENDOR_ID], pPciDev->config[VBOX_PCI_SUBSYSTEM_VENDOR_ID + 1]));
}
/**
* Sets the sub-system id config register.
*
* @param pPciDev The PCI device.
* @param u16SubSystemId The sub-system id.
*/
DECLINLINE(void) PCIDevSetSubSystemId(PPCIDEVICE pPciDev, uint16_t u16SubSystemId)
{
u16SubSystemId = RT_H2LE_U16(u16SubSystemId);
pPciDev->config[VBOX_PCI_SUBSYSTEM_ID] = u16SubSystemId & 0xff;
pPciDev->config[VBOX_PCI_SUBSYSTEM_ID + 1] = u16SubSystemId >> 8;
}
/**
* Gets the sub-system id config register.
* @returns the sub-system id.
* @param pPciDev The PCI device.
*/
DECLINLINE(uint16_t) PCIDevGetSubSystemId(PPCIDEVICE pPciDev)
{
return RT_LE2H_U16(RT_MAKE_U16(pPciDev->config[VBOX_PCI_SUBSYSTEM_ID], pPciDev->config[VBOX_PCI_SUBSYSTEM_ID + 1]));
}
/**
* Sets the interrupt line config register.
*
* @param pPciDev The PCI device.
* @param u8Line The interrupt line.
*/
DECLINLINE(void) PCIDevSetInterruptLine(PPCIDEVICE pPciDev, uint8_t u8Line)
{
pPciDev->config[VBOX_PCI_INTERRUPT_LINE] = u8Line;
}
/**
* Sets the interrupt pin config register.
*
* @param pPciDev The PCI device.
* @param u8Pin The interrupt pin.
*/
DECLINLINE(void) PCIDevSetInterruptPin(PPCIDEVICE pPciDev, uint8_t u8Pin)
{
pPciDev->config[VBOX_PCI_INTERRUPT_PIN] = u8Pin;
}
/** @} */
#endif