/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: PciConfig.cs // // Note: // #define VERBOSE //#define DEBUG_PCI using System; using StringBuilder = System.Text.StringBuilder; using System.Collections; using Microsoft.Singularity; namespace Microsoft.Singularity.Io { [CLSCompliant(false)] public class PciConfig : IoConfig { // // Bit encodings for PCI_COMMON_CONFIG.HeaderType // public const uint PCI_MULTIFUNCTION = 0x800000; // full dword public const uint PCI_TYPE_MASK = 0x7f0000; // full dword public const uint PCI_DEVICE_TYPE = 0x000000; // full dword public const uint PCI_BRIDGE_TYPE = 0x010000; // full dword public const uint PCI_CARDBUS_TYPE = 0x020000; // full dword // // Bit encodings for PCI_COMMON_CONFIG.Control // public const uint PCI_CONFIG_Command = 0x0004; public const uint PCI_ENABLE_IO_SPACE = 0x0001; public const uint PCI_ENABLE_MEMORY_SPACE = 0x0002; public const uint PCI_ENABLE_BUS_MASTER = 0x0004; const uint PCI_ENABLE_SPECIAL_CYCLES = 0x0008; const uint PCI_ENABLE_WRITE_AND_INVALIDATE = 0x0010; const uint PCI_ENABLE_VGA_COMPATIBLE_PALETTE = 0x0020; const uint PCI_ENABLE_PARITY = 0x0040; // (ro+) const uint PCI_ENABLE_WAIT_CYCLE = 0x0080; // (ro+) const uint PCI_ENABLE_SERR = 0x0100; // (ro+) const uint PCI_ENABLE_FAST_BACK_TO_BACK = 0x0200; // (ro) const uint PCI_DISABLE_INTERRUPTS = 0x0400; // // Bit encodings for PCI_COMMON_CONFIG.Status // const uint PCI_STATUS_FAST_BACK_TO_BACK = 0x0080; // (ro) const uint PCI_STATUS_DATA_PARITY_DETECTED = 0x0100; const uint PCI_STATUS_DEVSEL = 0x0600; // 2 bits wide const uint PCI_STATUS_SIGNALED_TARGET_ABORT = 0x0800; const uint PCI_STATUS_RECEIVED_TARGET_ABORT = 0x1000; const uint PCI_STATUS_RECEIVED_MASTER_ABORT = 0x2000; const uint PCI_STATUS_SIGNALED_SYSTEM_ERROR = 0x4000; const uint PCI_STATUS_DETECTED_PARITY_ERROR = 0x8000; // Bit encodes for PCI_COMMON_CONFIG.u.type0.BaseAddresses // const uint PCI_ADDRESS_IO_SPACE = 0x00000001; // (ro) const uint PCI_ADDRESS_MEMORY_TYPE_MASK = 0x00000006; // (ro) const uint PCI_ADDRESS_MEMORY_PREFETCHABLE = 0x00000008; // (ro) const uint PCI_TYPE_32BIT = 0; const uint PCI_TYPE_20BIT = 2; const uint PCI_TYPE_64BIT = 4; const uint PCI_ROMADDRESS_ENABLED = 0x00000001; const uint PCI_ENABLE_BRIDGE_PARITY_ERROR = 0x0001; const uint PCI_ENABLE_BRIDGE_SERR = 0x0002; const uint PCI_ENABLE_BRIDGE_ISA = 0x0004; const uint PCI_ENABLE_BRIDGE_VGA = 0x0008; const uint PCI_ENABLE_BRIDGE_MASTER_ABORT_SERR = 0x0020; const uint PCI_ASSERT_BRIDGE_RESET = 0x0040; const uint PCI_ENABLE_BRIDGE_FAST_BACK_TO_BACK = 0x0080; const byte PCI_CLASS_STORAGE = 0x01; const byte PCI_CLASS_NETWORK = 0x02; const byte PCI_CLASS_DISPLAY = 0x03; const byte PCI_CLASS_MULTIMEDIA = 0x04; const byte PCI_CLASS_MEMORY = 0x05; const byte PCI_CLASS_BRIDGE = 0x06; const byte PCI_CLASS_COMMUNICATION = 0x07; const byte PCI_CLASS_SYSTEM = 0x08; const byte PCI_CLASS_INPUT = 0x09; const byte PCI_CLASS_DOCKING = 0x0a; const byte PCI_CLASS_PROCESSOR = 0x0b; const byte PCI_CLASS_SERIAL = 0x0c; const byte PCI_CLASS_WIRELESS = 0x0d; const byte PCI_CLASS_I2O = 0x0e; const byte PCI_CLASS_SATELLITE = 0x0f; const byte PCI_CLASS_ENCRYPTION = 0x10; const byte PCI_CLASS_ACQUISITION = 0x11; const byte PCI_CLASS_OTHERS = 0xff; const byte PCI_CLASS_STORAGE_SCSI = 0x00; const byte PCI_CLASS_STORAGE_IDE = 0x01; // NB: Interface const byte PCI_CLASS_STORAGE_FLOPPY = 0x02; const byte PCI_CLASS_STORAGE_IPI = 0x03; const byte PCI_CLASS_STORAGE_RAID = 0x04; const byte PCI_CLASS_STORAGE_ATA = 0x05; // NB: Interface const byte PCI_CLASS_STORAGE_OTHER = 0x80; const byte PCI_CLASS_NETWORK_ETHERNET = 0x00; const byte PCI_CLASS_NETWORK_RING = 0x01; const byte PCI_CLASS_NETWORK_FDDI = 0x02; const byte PCI_CLASS_NETWORK_ATM = 0x03; const byte PCI_CLASS_NETWORK_ISDN = 0x04; const byte PCI_CLASS_NETWORK_FIP = 0x05; const byte PCI_CLASS_NETWORK_PICMG = 0x06; // NB: Interface const byte PCI_CLASS_NETWORK_OTHER = 0x80; const byte PCI_CLASS_DISPLAY_VGA = 0x00; // NB: Interface const byte PCI_CLASS_DISPLAY_XGA = 0x01; const byte PCI_CLASS_DISPLAY_3D = 0x02; const byte PCI_CLASS_DISPLAY_OTHER = 0x80; const byte PCI_CLASS_MULTIMEDIA_VIDEO = 0x00; const byte PCI_CLASS_MULTIMEDIA_AUDIO = 0x01; const byte PCI_CLASS_MULTIMEDIA_TELEPHONY = 0x02; const byte PCI_CLASS_MULTIMEDIA_OTHER = 0x80; const byte PCI_CLASS_MEMORY_RAM = 0x00; const byte PCI_CLASS_MEMORY_FLASH = 0x01; const byte PCI_CLASS_MEMORY_OTHER = 0x80; const byte PCI_CLASS_BRIDGE_HOST = 0x00; const byte PCI_CLASS_BRIDGE_ISA = 0x01; const byte PCI_CLASS_BRIDGE_EISA = 0x02; const byte PCI_CLASS_BRIDGE_MC = 0x03; const byte PCI_CLASS_BRIDGE_PCI = 0x04; // NB: Interface const byte PCI_CLASS_BRIDGE_PCMCIA = 0x05; const byte PCI_CLASS_BRIDGE_NUBUS = 0x06; const byte PCI_CLASS_BRIDGE_CARDBUS = 0x07; const byte PCI_CLASS_BRIDGE_RACEWAY = 0x08; // NB: Interface const byte PCI_CLASS_BRIDGE_SEMIPCI = 0x09; // NB: Interface const byte PCI_CLASS_BRIDGE_INFINIBAND = 0x0a; const byte PCI_CLASS_BRIDGE_OTHER = 0x80; const byte PCI_CLASS_COMMUNICATION_SERIAL = 0x00; // NB: Interface const byte PCI_CLASS_COMMUNICATION_PARALLEL = 0x01; // NB: Interface const byte PCI_CLASS_COMMUNICATION_MULTIPORT = 0x02; const byte PCI_CLASS_COMMUNICATION_MODEM = 0x03; // NB: Interface const byte PCI_CLASS_COMMUNICATION_GPIB = 0x04; const byte PCI_CLASS_COMMUNICATION_SMARTCARD = 0x05; const byte PCI_CLASS_COMMUNICATION_OTHER = 0x80; const byte PCI_CLASS_SYSTEM_PIC = 0x00; // NB: Interface const byte PCI_CLASS_SYSTEM_DMA = 0x01; // NB: Interface const byte PCI_CLASS_SYSTEM_TIMER = 0x02; // NB: Interface const byte PCI_CLASS_SYSTEM_RTC = 0x03; // NB: Interface const byte PCI_CLASS_SYSTEM_PCIHP = 0x04; const byte PCI_CLASS_SYSTEM_OTHER = 0x80; const byte PCI_CLASS_INPUT_KEYBOARD = 0x00; const byte PCI_CLASS_INPUT_PEN = 0x01; const byte PCI_CLASS_INPUT_MOUSE = 0x02; const byte PCI_CLASS_INPUT_SCANNER = 0x03; const byte PCI_CLASS_INPUT_GAMEPORT = 0x04; // NB: Interface const byte PCI_CLASS_INPUT_OTHER = 0x80; const byte PCI_CLASS_SERIAL_FIREWIRE = 0x00; // NB: Interface const byte PCI_CLASS_SERIAL_ACCESS = 0x01; const byte PCI_CLASS_SERIAL_SSA = 0x02; const byte PCI_CLASS_SERIAL_USB = 0x03; // NB: Interface const byte PCI_CLASS_SERIAL_FIBRE = 0x04; const byte PCI_CLASS_SERIAL_SMBUS = 0x05; const byte PCI_CLASS_SERIAL_INFINIBAND = 0x06; const byte PCI_CLASS_SERIAL_IPMI = 0x07; // NB: Interface const byte PCI_CLASS_SERIAL_SERCOS = 0x08; const byte PCI_CLASS_SERIAL_CANBUS = 0x09; const byte PCI_CLASS_WIRELESS_IRDA = 0x00; const byte PCI_CLASS_WIRELESS_IR = 0x01; const byte PCI_CLASS_WIRELESS_RF = 0x10; const byte PCI_CLASS_WIRELESS_BLUETOOTH = 0x11; const byte PCI_CLASS_WIRELESS_BROADBAND = 0x12; const byte PCI_CLASS_WIRELESS_OTHER = 0x80; const byte PCI_CLASS_I2O_I2O = 0x00; // NB: Interface const byte PCI_CLASS_SATELLITE_TV = 0x01; const byte PCI_CLASS_SATELLITE_AUDIO = 0x02; const byte PCI_CLASS_SATELLITE_VOICE = 0x03; const byte PCI_CLASS_SATELLITE_DATA = 0x04; const byte PCI_CLASS_ENCRYPTION_NETWORK = 0x00; const byte PCI_CLASS_ENCRYPTION_ENTERTAINMENT = 0x10; const byte PCI_CLASS_ENCRYPTION_OTHER = 0x80; const byte PCI_CLASS_ACQUISITION_DPIO = 0x00; const byte PCI_CLASS_ACQUISITION_PERF = 0x01; const byte PCI_CLASS_ACQUISITION_COMM = 0x10; const byte PCI_CLASS_ACQUISITION_MGMT = 0x20; const byte PCI_CLASS_ACQUISITION_OTHER = 0x80; const int PCI_INTERRUPT_LINE = 0x3c; const int PCI_INTERRUPT_PIN = 0x3d; const byte PCI_INTERRUPT_PIN_A = 1; const byte PCI_INTERRUPT_PIN_B = 2; const byte PCI_INTERRUPT_PIN_C = 3; const byte PCI_INTERRUPT_PIN_D = 4; protected PciPort port; public ushort VendorId; // 00..01 (ro) public ushort DeviceId; // 02..03 (ro) public ushort Control; // 04..05 Device control public ushort Status; // 06..07 protected byte RevisionId; // 08..08 (ro) public byte Interface; // 09..09 (ro) protected byte SubClassId; // 0a..0a (ro) protected byte ClassId; // 0b..0b (ro) public byte CacheLineSize; // 0c..0c (ro+) protected byte LatencyTimer; // 0d..0d (ro+) protected byte HeaderType; // 0e..0e (ro) protected byte BIST; // 0f..0f Built in self test protected uint[] BaseAddresses; // 10..17 or ..27 [2 or 6] protected uint[] BaseAddrSizes; protected ushort SubsystemVendorId; // 2c..2d (devices only) protected ushort SubsystemDeviceId; // 2e..2f (devices only) protected uint ROMBaseAddress; // 38..3b or 30.33 protected byte InterruptPin; // 3d..3d public static PciConfig Create(String[] ids, PciPort port, IoRange [] fixedRanges) { uint u = port.Read32(0); if (u == ~0u || u == 0) { return null; } PciConfig config = null; u = port.Read32(0x0c); switch (u & PciConfig.PCI_TYPE_MASK) { case PciConfig.PCI_DEVICE_TYPE: config = new PciDeviceConfig(port); break; case PciConfig.PCI_BRIDGE_TYPE: config = new PciBridgeConfig(port); break; case PciConfig.PCI_CARDBUS_TYPE: config = new PciCardbusConfig(port); break; } if (config != null) { config.FixedRanges = fixedRanges; } return config; } internal PciConfig(String[] ids, PciPort port) { this.port = port; this.Read(); this.Ids = ids; } public PciConfig(PciPort port) { this.port = port; } public ushort AddressPort { get { return port.addressPort.Port; } } public ushort DataPort { get { return port.dataPort.Port; } } public ushort Identifier { get { return port.identifier; } } public IoIrqRange GetIrq() { return new IoIrqRange(InterruptLine, 1); } public void SetInterrupt(byte irq) { Write8(PCI_INTERRUPT_LINE, irq); } public byte InterruptLine { get { return Read8(PCI_INTERRUPT_LINE); } } public void EnableIoSpace(bool Enable) { uint control = Read32(0x04); uint send = (control | PCI_ENABLE_IO_SPACE) & 0xffff; Write32(0x04, send); } public uint Read32(int offset) { return port.Read32(offset); } public void Write32(int offset, uint value) { port.Write32(offset, value); } protected ushort Read16(uint offset) { return port.Read16(offset); } protected void Write16(int offset, ushort value) { port.Write16(offset, value); } public byte Read8(int offset) { return port.Read8(offset); } protected void Write8(int offset, byte value) { port.Write8(offset, value); } protected virtual void Read() { uint u; u = Read32(0x00); VendorId = (ushort)(u & 0xffff); DeviceId = (ushort)((u >> 16) & 0xffff); u = Read32(0x04); Control = (ushort)(u & 0xffff); Status = (ushort)((u >> 16) & 0xffff); u = Read32(0x08); RevisionId = (byte)(u & 0xff); Interface = (byte)((u >> 8) & 0xff); SubClassId = (byte)((u >> 16) & 0xff); ClassId = (byte)((u >> 24) & 0xff); u = Read32(0x0c); CacheLineSize = (byte)(u & 0xff); LatencyTimer = (byte)((u >> 8) & 0xff); HeaderType = (byte)((u >> 16) & 0xff); BIST = (byte)((u >> 24) & 0xff); this.Ids = GetIds(); #if VERBOSE || DEBUG_PCI foreach (string id in Ids) { Tracing.Log(Tracing.Debug, "DeviceId: " + id); } // Tracing.Log(Tracing.Debug, "Read: {0}", Id); #endif } /// /// /// Builds the list of device IDs for this PCI device. We generate the same /// strings that Windows uses for its hardware IDs and compatible IDs. /// The order is significant; the PNP manager will search the device IDs, /// one by one, for a device driver that matches. The list is ordered from /// most specific to least specific. /// /// /// /// WDM "hardware IDs": /// PCI\VEN_xxxy&DEV_yyyy&SUBSYS_zzzzzzzz&REV_rr /// PCI\VEN_xxxy&DEV_yyyy&SUBSYS_zzzzzzzz /// PCI\VEN_xxxy&DEV_yyyy&CC_ccssii /// PCI\VEN_xxxy&DEV_yyyy&CC_ccss /// PCI\VEN_xxxy /// /// /// /// WDM "compatible IDs": /// PCI\VEN_xxxy&DEV_yyyy&REV_rr /// PCI\VEN_xxxy&DEV_yyyy /// PCI\VEN_xxxx&CC_ccssii /// PCI\VEN_xxxx&CC_ccss /// PCI\CC_ccssii /// PCI\CC_ccss /// /// /// /// An array containing the device IDs. The list is ordered from most specific /// to least specific. /// public string[] GetIds() { const string pci_prefix = @"PCI/"; const string and = "&"; string id_classcode = "CC_" + ByteToHex(this.ClassId) + ByteToHex(this.SubClassId); string id_classcode_interface = id_classcode + ByteToHex(this.Interface); string id_vendor = "VEN_" + UInt16ToHex(this.VendorId); string id_device = "DEV_" + UInt16ToHex(this.DeviceId); string id_vendor_device = id_vendor + and + id_device; string id_revision = "REV_" + ByteToHex(this.RevisionId); string id_subsys = "SUBSYS_" + UInt16ToHex(this.SubsystemVendorId) + UInt16ToHex(this.SubsystemDeviceId); #if ENABLE_OLD_SIGNATURE string sing_id = String.Format("/pci/{0,2:x2}/{1,2:x2}/{2,4:x4}/{3,4:x4}/" + "{4,2:x2}", ClassId, SubClassId, VendorId, DeviceId, RevisionId); #endif string[] ids = { #if ENABLE_OLD_SIGNATURE sing_id, #endif // Hardware IDs pci_prefix + id_vendor_device + and + id_subsys + and + id_revision, pci_prefix + id_vendor_device + and + id_subsys, pci_prefix + id_vendor_device + and + id_classcode_interface, pci_prefix + id_vendor_device + and + id_classcode, pci_prefix + id_vendor, // Compatible IDs pci_prefix + id_vendor_device + and + id_revision, pci_prefix + id_vendor_device, pci_prefix + id_vendor + and + id_classcode_interface, pci_prefix + id_vendor + and + id_classcode, pci_prefix + id_classcode_interface, pci_prefix + id_classcode, }; for (int i = 0; i < ids.Length; i++) { string id = ids[i]; id = id.Replace('\\', '/').ToLower(); ids[i] = id; } return ids; } static string ByteToHex(byte value) { StringBuilder sb = new StringBuilder(2); sb.Append(HexDigits[value >> 4]); sb.Append(HexDigits[value & 0xf]); return sb.ToString(); } static string UInt16ToHex(ushort value) { StringBuilder sb = new StringBuilder(4); sb.Append(HexDigits[(value >> 12) & 0xf]); sb.Append(HexDigits[(value >> 8) & 0xf]); sb.Append(HexDigits[(value >> 4) & 0xf]); sb.Append(HexDigits[value & 0xf]); return sb.ToString(); } const string HexDigits = "0123456789ABCDEF"; protected void ReadBaseAddresses(int n) { if (Read8(PCI_INTERRUPT_PIN) != 0) { // Add interrupt resource to list of ranges if present DynamicRanges = new IoRange [n + 1]; DynamicRanges[n] = new IoIrqRange(Read8(PCI_INTERRUPT_LINE), 1); } else { DynamicRanges = new IoRange [n]; } BaseAddresses = new uint [n]; BaseAddrSizes = new uint [n]; #if VERBOSE Tracing.Log(Tracing.Debug, "ReadBaseAddresses()"); #endif #if DEBUG_PCI Tracing.Log(Tracing.Debug, "InterruptsDisabled: {0}", Processor.InterruptsDisabled()); for (int i = 0; i < n; i++) { uint value = Read32(0x10 + i * 4); Tracing.Log(Tracing.Debug, "Read[{0}][{1}] -: {2:x8}", n, i, value); } #endif uint control = Read32(0x04); uint send = (control & (~(PCI_ENABLE_IO_SPACE|PCI_ENABLE_MEMORY_SPACE))) & 0xffff; if (control == 0x02b00003) { send = (control & (~(PCI_ENABLE_IO_SPACE))) & 0xffff; } #if DONT_SKIP_NVIDIA if (control == 0x02b00003) { send = control & 0xffff; send &= ~PCI_ENABLE_IO_SPACE; port.Write32(0x04, send); Tracing.Log(Tracing.Debug, "NVIDIA Read[{0}]: ctrl={1:x8} send={2:x8}", n, control, send); uint x = Read32(0x04); Tracing.Log(Tracing.Debug, "NVIDIA Read[{0}]: finl={1:x8}", n, x); port.Write32(0x04, control & 0xffff); x = Read32(0x04); Tracing.Log(Tracing.Debug, "NVIDIA Read[{0}]: last={1:x8}", n, x); return; } #endif port.Write32(0x04, send); #if DEBUG_PCI Tracing.Log(Tracing.Debug, "Read[{0}]: ctrl={1:x8} send={2:x8}", n, control, send); #endif #if DEBUG_PCI uint x = Read32(0x04); Tracing.Log(Tracing.Debug, "Read[{0}]: finl={1:x8}", n, x); #endif for (int i = 0; i < n; i++) { #if DEBUG_PCI Tracing.Log(Tracing.Debug, "Read[{0}][{1}] A:", n, i); #endif uint addr = Read32(0x10 + i * 4); uint size = 0; // Find the size of the address space by moving to hi memory. if ((addr & PCI_ADDRESS_IO_SPACE) != 0) { #if DEBUG_PCI Tracing.Log(Tracing.Debug, "Read[{0}][{1}] B: {2:x8} ~0", n, i, addr); #endif port.Write32(0x10 + i * 4, ~0u); size = Read32(0x10 + i * 4); port.Write32(0x10 + i * 4, addr); #if DEBUG_PCI Tracing.Log(Tracing.Debug, "Read[{0}][{1}] C: {2:x8}", n, i, size); #endif size &= ~0x3u; size |= 0xffff0000; } else { #if DEBUG_PCI Tracing.Log(Tracing.Debug, "Read[{0}][{1}] B: {2:x8} ~0", n, i, addr); #endif port.Write32(0x10 + i * 4, ~0xfu); size = Read32(0x10 + i * 4); port.Write32(0x10 + i * 4, addr); #if DEBUG_PCI Tracing.Log(Tracing.Debug, "Read[{0}][{1}] C: {2:x8}", n, i, size); #endif size &= ~0xfu; } size = ~size + 1; #if DEBUG_PCI Tracing.Log(Tracing.Debug, "Read[{0}][{1}] D: {2:x8}", n, i, size); #endif if (size >= 2) { if ((addr & PCI_ADDRESS_IO_SPACE) != 0) { DynamicRanges[i] = new IoPortRange((ushort)(addr & ~0xf), (ushort)size, Access.ReadWrite); } else { DynamicRanges[i] = new IoMemoryRange((uint)(addr & ~0xf), size, Access.ReadWrite); } BaseAddresses[i] = addr; BaseAddrSizes[i] = size; } } port.Write32(0x04, control & 0xffff); #if DEBUG_PCI Tracing.Log(Tracing.Debug, "Read[{0}]: done", n); #endif string s = "::"; for (int i = 0; i < DynamicRanges.Length; i++) { if (DynamicRanges[i] != null) { s += String.Format("A{0}={1} ", i, DynamicRanges[i]); } } Tracing.Log(Tracing.Debug, "PCI {0}", s); } public override string ToString() { return String.Format("[PCI: VEN_{0:x4} DEV_{1:x4} CLASS {2:x2}.{3:x2}.{4:x2} BASE {5:x8}]", this.VendorId, this.DeviceId, this.ClassId, this.SubClassId, this.Interface, this.Base); } public override string ToPrint() { StringBuilder text = new StringBuilder(); base.DumpRanges(text); text.AppendFormat(" PCI Vendor/Device: {0:x4}.{1:x4} rev {2:x2} {3} {4}\n", this.VendorId, this.DeviceId, this.RevisionId, this.Vendor, this.Device); text.AppendFormat(" PCI Class/Subclass: {0:x2}.{1:x2}.{2:x2}\n", this.ClassId, this.SubClassId, this.Interface, this.Class); return text.ToString(); } protected string PrintAddresses() { String s; bool print = false; for (int i = 0; i < BaseAddresses.Length; i++) { if (BaseAddresses[i] != 0 || BaseAddrSizes[i] != 0) { print = true; break; } } if (!print && ROMBaseAddress == 0 && InterruptLine == 0 && InterruptPin == 0) { return ""; } s = String.Format(" RM={0:x8} IL={1,2:x2} IP={2,2:x2} ", ROMBaseAddress, InterruptLine, InterruptPin); int printed = 0; for (int i = 0; i < BaseAddresses.Length; i++) { if (DynamicRanges[i] != null) { s += String.Format("A{0}={1} ", i, DynamicRanges[i]); } #if DONT_PRINT_RAW_ADDRESSS_BUT_ONLY_RANGES if (BaseAddresses[i] == 0 && BaseAddrSizes[i] == 0) { continue; } if ((BaseAddresses[i] & PCI_ADDRESS_IO_SPACE) != 0) { s += String.Format("A{0}=IO:{1:x8}[{2:x}] ", i, BaseAddresses[i], BaseAddrSizes[i]); } else { if ((BaseAddresses[i] & PCI_TYPE_64BIT) != 0) { s += String.Format("A{0}=64:{1:x8}[{2:x}] ", i, BaseAddresses[i], BaseAddrSizes[i]); } else if ((BaseAddresses[i] & PCI_TYPE_20BIT) != 0) { s += String.Format("A{0}=20:{1:x8}[{2:x}] ", i, BaseAddresses[i], BaseAddrSizes[i]); } else { s += String.Format("A{0}=32:{1:x8}[{2:x}] ", i, BaseAddresses[i], BaseAddrSizes[i]); } } #endif printed++; } return s; } protected string Vendor { get { switch (VendorId) { case 0x1011: return "DEC"; case 0x104c: return "TI"; case 0x5333: return "S3"; case 0x8086: return "Intel"; case 0x10de: return "nVidia"; case 0x1106: return "VIA Technologies"; default: return String.Format("{0,4:x4}", VendorId); } } } protected string Device { get { switch (VendorId) { case 0x8086: switch (DeviceId) { case 0x0484: return "82379AB"; case 0x1229: return "82559nic"; case 0x122E: return "82371FB"; case 0x1234: return "82371MX"; case 0x2410: return "82801AA"; case 0x7000: return "82371SB"; case 0x7110: return "82371AB"; default: break; } break; case 0x10de: // NVIDIA switch (DeviceId) { case 0x0050: return "PCI-to-ISA bridge"; case 0x0052: return "nForce PCI System Management Module"; case 0x0057: return "nForce Network Interface"; case 0x0059: return "Realtek AC'97 Audio"; case 0x005a: return "USB OHCI"; case 0x005d: return "PCI-to-PCI bridge"; case 0x005e: return "nForce4 HyperTransport Bridge"; default: break; } break; case 0x1106: // VIA switch (DeviceId) { case 0x3044: return "OHCI Compliant IEEE 1394 Host Controller"; default: break; } break; default: break; } return String.Format("{0,4:x4}", DeviceId); } } protected string Class { get { switch (ClassId) { case PCI_CLASS_STORAGE: switch (SubClassId) { case PCI_CLASS_STORAGE_SCSI: return "Scsi"; case PCI_CLASS_STORAGE_IDE: return "Ide"; case PCI_CLASS_STORAGE_FLOPPY: return "Floppy"; case PCI_CLASS_STORAGE_IPI: return "Ipi"; case PCI_CLASS_STORAGE_RAID: return "Raid"; case PCI_CLASS_STORAGE_OTHER: return "Other"; default: return String.Format("{0,2:x2}", SubClassId); } case PCI_CLASS_NETWORK: switch (SubClassId) { case PCI_CLASS_NETWORK_ETHERNET: return "Ethernet"; case PCI_CLASS_NETWORK_RING: return "Ring"; case PCI_CLASS_NETWORK_FDDI: return "Fddi"; case PCI_CLASS_NETWORK_ATM: return "Atm"; case PCI_CLASS_NETWORK_OTHER: return "Other"; case PCI_CLASS_NETWORK_FIP: return "FIP"; case PCI_CLASS_NETWORK_PICMG: return "PICMG"; default: return String.Format("{0,2:x2}", SubClassId); } case PCI_CLASS_DISPLAY: switch (SubClassId) { case PCI_CLASS_DISPLAY_VGA: return "Vga"; case PCI_CLASS_DISPLAY_XGA: return "Xga"; case PCI_CLASS_DISPLAY_3D: return "3D"; case PCI_CLASS_DISPLAY_OTHER: return "Other"; default: return String.Format("{0,2:x2}", SubClassId); } case PCI_CLASS_MULTIMEDIA: switch (SubClassId) { case PCI_CLASS_MULTIMEDIA_VIDEO: return "Video"; case PCI_CLASS_MULTIMEDIA_AUDIO: return "Audio"; case PCI_CLASS_MULTIMEDIA_TELEPHONY: return "Telephony"; case PCI_CLASS_MULTIMEDIA_OTHER: return "Other"; default: return String.Format("{0,2:x2}", SubClassId); } case PCI_CLASS_MEMORY: switch (SubClassId) { case PCI_CLASS_MEMORY_RAM: return "Ram"; case PCI_CLASS_MEMORY_FLASH: return "Flash"; case PCI_CLASS_MEMORY_OTHER: return "Other"; default: return String.Format("{0,2:x2}", SubClassId); } case PCI_CLASS_BRIDGE: switch (SubClassId) { case PCI_CLASS_BRIDGE_HOST: return "Host"; case PCI_CLASS_BRIDGE_ISA: return "Isa"; case PCI_CLASS_BRIDGE_EISA: return "Eisa"; case PCI_CLASS_BRIDGE_MC: return "Mc"; case PCI_CLASS_BRIDGE_PCI: return "Pci"; case PCI_CLASS_BRIDGE_PCMCIA: return "Pcmcia"; case PCI_CLASS_BRIDGE_NUBUS: return "Nubus"; case PCI_CLASS_BRIDGE_CARDBUS: return "Cardbus"; case PCI_CLASS_BRIDGE_RACEWAY: return "Raceway"; case PCI_CLASS_BRIDGE_SEMIPCI: return "Semipci"; case PCI_CLASS_BRIDGE_INFINIBAND: return "Infiniband"; case PCI_CLASS_BRIDGE_OTHER: return "Other"; default: return String.Format("{0,2:x2}", SubClassId); } case PCI_CLASS_COMMUNICATION: switch (SubClassId) { case PCI_CLASS_COMMUNICATION_SERIAL: return "Serial"; case PCI_CLASS_COMMUNICATION_PARALLEL: return "Parallel"; case PCI_CLASS_COMMUNICATION_MULTIPORT: return "Multiport"; case PCI_CLASS_COMMUNICATION_MODEM: return "Modem"; case PCI_CLASS_COMMUNICATION_GPIB: return "Gpib"; case PCI_CLASS_COMMUNICATION_SMARTCARD: return "Smartcard"; case PCI_CLASS_COMMUNICATION_OTHER: return "Other"; default: return String.Format("{0,2:x2}", SubClassId); } case PCI_CLASS_SYSTEM: switch (SubClassId) { case PCI_CLASS_SYSTEM_PIC: return "Pic"; case PCI_CLASS_SYSTEM_DMA: return "Dma"; case PCI_CLASS_SYSTEM_TIMER: return "Timer"; case PCI_CLASS_SYSTEM_RTC: return "Rtc"; case PCI_CLASS_SYSTEM_PCIHP: return "Pcihp"; case PCI_CLASS_SYSTEM_OTHER: return "Other"; default: return String.Format("{0,2:x2}", SubClassId); } case PCI_CLASS_INPUT: switch (SubClassId) { case PCI_CLASS_INPUT_KEYBOARD: return "Keyboard"; case PCI_CLASS_INPUT_PEN: return "Pen"; case PCI_CLASS_INPUT_MOUSE: return "Mouse"; case PCI_CLASS_INPUT_SCANNER: return "Scanner"; case PCI_CLASS_INPUT_GAMEPORT: return "Gameport"; case PCI_CLASS_INPUT_OTHER: return "Other"; default: return String.Format("{0,2:x2}", SubClassId); } case PCI_CLASS_SERIAL: switch (SubClassId) { case PCI_CLASS_SERIAL_FIREWIRE: return "Firewire"; case PCI_CLASS_SERIAL_ACCESS: return "Access"; case PCI_CLASS_SERIAL_SSA: return "Ssa"; case PCI_CLASS_SERIAL_USB: switch (this.Interface) { case 0x00: return "USB1.1 UHCI"; case 0x10: return "USB1.1 OHCI"; case 0x20: return "USB2.0 EHCI"; default: return "Usb"; } case PCI_CLASS_SERIAL_FIBRE: return "Fibre"; case PCI_CLASS_SERIAL_SMBUS: return "Smbus"; case PCI_CLASS_SERIAL_INFINIBAND: return "Infiniband"; case PCI_CLASS_SERIAL_IPMI: return "Ipmi"; case PCI_CLASS_SERIAL_SERCOS: return "Sercos"; case PCI_CLASS_SERIAL_CANBUS: return "Canbus"; default: return String.Format("{0,2:x2}", SubClassId); } case PCI_CLASS_WIRELESS: switch (SubClassId) { case PCI_CLASS_WIRELESS_IRDA: return "Irda"; case PCI_CLASS_WIRELESS_IR: return "Ir"; case PCI_CLASS_WIRELESS_RF: return "Rf"; case PCI_CLASS_WIRELESS_BLUETOOTH: return "Bluetooth"; case PCI_CLASS_WIRELESS_BROADBAND: return "Broadband"; case PCI_CLASS_WIRELESS_OTHER: return "Other"; default: return String.Format("{0,2:x2}", SubClassId); } case PCI_CLASS_I2O: switch (SubClassId) { case PCI_CLASS_I2O_I2O: return "I2O"; default: return String.Format("{0,2:x2}", SubClassId); } case PCI_CLASS_SATELLITE: switch (SubClassId) { case PCI_CLASS_SATELLITE_TV: return "Tv"; case PCI_CLASS_SATELLITE_AUDIO: return "Audio"; case PCI_CLASS_SATELLITE_VOICE: return "Voice"; case PCI_CLASS_SATELLITE_DATA: return "Data"; default: return String.Format("{0,2:x2}", SubClassId); } case PCI_CLASS_ENCRYPTION: switch (SubClassId) { case PCI_CLASS_ENCRYPTION_NETWORK: return "Network"; case PCI_CLASS_ENCRYPTION_ENTERTAINMENT:return "Entertainment"; case PCI_CLASS_ENCRYPTION_OTHER: return "Other"; default: return String.Format("{0,2:x2}", SubClassId); } case PCI_CLASS_ACQUISITION: switch (SubClassId) { case PCI_CLASS_ACQUISITION_DPIO: return "Dpio"; case PCI_CLASS_ACQUISITION_PERF: return "Perf"; case PCI_CLASS_ACQUISITION_COMM: return "Comm"; case PCI_CLASS_ACQUISITION_MGMT: return "Mgmt"; case PCI_CLASS_ACQUISITION_OTHER: return "Other"; default: return String.Format("{0,2:x2}", SubClassId); } default: return String.Format("{0,2:x2}", SubClassId); } } } protected string Base { get { switch (ClassId) { case PCI_CLASS_STORAGE: return "Storage"; case PCI_CLASS_NETWORK: return "Network"; case PCI_CLASS_DISPLAY: return "Display"; case PCI_CLASS_MULTIMEDIA: return "Multimedia"; case PCI_CLASS_MEMORY: return "Memory"; case PCI_CLASS_BRIDGE: return "Bridge"; case PCI_CLASS_COMMUNICATION: return "Communication"; case PCI_CLASS_SYSTEM: return "System"; case PCI_CLASS_INPUT: return "Input"; case PCI_CLASS_DOCKING: return "Docking"; case PCI_CLASS_PROCESSOR: return "Processor"; case PCI_CLASS_SERIAL: return "Serial"; case PCI_CLASS_OTHERS: return "Others"; case PCI_CLASS_WIRELESS: return "Wireless"; case PCI_CLASS_I2O: return "I2O"; case PCI_CLASS_SATELLITE: return "Satellite"; case PCI_CLASS_ENCRYPTION: return "Encryption"; case PCI_CLASS_ACQUISITION: return "Acquisition"; default: return String.Format("{0,2:x2}", ClassId); } } } public bool MemorySpaceEnabled { get { return (Control & PCI_ENABLE_MEMORY_SPACE) != 0; } } public bool IoSpaceEnabled { get { return (Control & PCI_ENABLE_IO_SPACE) != 0; } } public bool InterruptsEnabled { get { return (Control & PCI_DISABLE_INTERRUPTS) == 0; } } } [CLSCompliant(false)] public class PciBridgeConfig : PciConfig { // Bridges: (HeaderType & ~PCI_MULTIFUNCTION) == PCI_BRIDGE_TYPE // public uint BaseAddresses[2]; // 10..17 protected byte PrimaryBus; // 18..18 protected byte SecondaryBus; // 19..19 protected byte SubordinateBus; // 1a..1a protected byte SecondaryLatency; // 1b..1b protected byte IOBase; // 1c..1c protected byte IOLimit; // 1d..1d protected ushort SecondaryStatus; // 1e..1f protected ushort MemoryBase; // 20..21 protected ushort MemoryLimit; // 22..23 protected ushort PrefetchBase; // 24..25 protected ushort PrefetchLimit; // 26..27 protected uint PrefetchBaseUpper32; // 28..2b protected uint PrefetchLimitUpper32; // 2c..2f protected ushort IOBaseUpper16; // 30..31 protected ushort IOLimitUpper16; // 32..33 // protected uint Reserved; // 34..37 // protected uint ROMBaseAddress; // 38..3b #if DISABLED // protected byte InterruptLine; // 3c..3c #endif // protected byte InterruptPin; // 3d..3d protected ushort BridgeControl; // 3e..3f public PciBridgeConfig(PciPort port) : base(port) { Read(); } protected override void Read() { base.Read(); base.ReadBaseAddresses(2); uint u; u = port.Read32(0x18); PrimaryBus = (byte)(u & 0xff); SecondaryBus = (byte)((u >> 8) & 0xff); SubordinateBus = (byte)((u >> 16) & 0xff); SecondaryLatency = (byte)((u >> 24) & 0xff); u = port.Read32(0x1c); IOBase = (byte)(u & 0xff); IOLimit = (byte)((u >> 8) & 0xff); SecondaryStatus = (ushort)((u >> 16) & 0xffff); u = port.Read32(0x20); MemoryBase = (ushort)(u & 0xffff); MemoryLimit = (ushort)((u >> 16) & 0xffff); u = port.Read32(0x24); PrefetchBase = (ushort)(u & 0xffff); PrefetchLimit = (ushort)((u >> 16) & 0xffff); u = port.Read32(0x28); PrefetchBaseUpper32 = u; u = port.Read32(0x2c); PrefetchLimitUpper32 = u; u = port.Read32(0x30); IOBaseUpper16 = (ushort)(u & 0xffff); IOLimitUpper16 = (ushort)((u >> 16) & 0xffff); u = port.Read32(0x38); ROMBaseAddress = u; u = port.Read32(0x3c); #if DISABLED InterruptLine = (byte)(u & 0xff); #endif InterruptPin = (byte)((u >> 8) & 0xff); BridgeControl = (ushort)((u >> 16) & 0xffff); } public override string ToPrint() { return base.ToPrint() + String.Format("BUS={0,2:x2}.{1,2:x2}.{2,2:x2} IO={3,4:x4}..{4,4:x4}", PrimaryBus, SecondaryBus, SubordinateBus, IOBase, IOLimit) + "" + base.PrintAddresses() + ""; } } [CLSCompliant(false)] public class PciDeviceConfig : PciConfig { // Devices: (HeaderType & ~PCI_MULTIFUNCTION) == PCI_DEVICE_TYPE // public uint BaseAddresses[6]; // 10..27 protected uint CardbusCisPtr; // 28..2b // protected ushort SubsystemVendorId; // 2c..2d // protected ushort SubsystemDeviceId; // 2e..2f // protected uint ROMBaseAddress; // 30..33 protected byte Capabilities; // 34..34 // protected byte Reserved[7]; // 35..38 #if DISABLED // protected byte InterruptLine; // 3c..3c #endif // protected byte InterruptPin; // 3d..3d (ro) protected byte MinimumGrant; // 3e..3e (ro) protected byte MaximumLatency; // 3f..3f (ro) public PciDeviceConfig(PciPort port) : base(port) { Read(); } protected override void Read() { base.Read(); base.ReadBaseAddresses(6); uint u; u = port.Read32(0x28); CardbusCisPtr = u; u = port.Read32(0x2c); SubsystemVendorId = (ushort)(u & 0xffff); SubsystemDeviceId = (ushort)((u >> 16) & 0xffff); u = port.Read32(0x30); ROMBaseAddress = u; u = port.Read32(0x34); Capabilities = (byte)(u & 0xff); u = port.Read32(0x3c); if ((u & 0xff) == 0) { port.Write32(0x3c, u | 0x7); u = port.Read32(0x3c); } #if DISABLED InterruptLine = (byte)(u & 0xff); #endif InterruptPin = (byte)((u >> 8) & 0xff); MinimumGrant = (byte)((u >> 16) & 0xff); MaximumLatency = (byte)((u >> 24) & 0xff); Ids = GetIds(); } public override string ToPrint() { String s = base.ToPrint() + "\n " + base.PrintAddresses(); if (CardbusCisPtr != 0 || Capabilities != 0 || MinimumGrant != 0 || MaximumLatency != 0) { s += String.Format(" cis={0:x8} cap={1,2:x2} mg={2,2:x2} ml={3,2:x2}", CardbusCisPtr, Capabilities, MinimumGrant, MaximumLatency); } return s; } } [CLSCompliant(false)] public class PciCardbusConfig : PciConfig { public PciCardbusConfig(PciPort port) : base(port) { BaseAddresses = new uint [0]; Read(); } protected override void Read() { base.Read(); } public override string ToPrint() { return base.ToPrint(); } } [CLSCompliant(false)] public class PciPort { internal readonly IoPort addressPort; internal readonly IoPort dataPort; internal readonly ushort identifier; public PciPort(IoPort addressPort, IoPort dataPort, ushort identifier) { this.addressPort = addressPort; this.dataPort = dataPort; this.identifier = identifier; } public ushort AddressPort { get { return addressPort.Port; } } public ushort DataPort { get { return dataPort.Port; } } public ushort Identifier { get { return identifier; } } public PciConfig ConfigForPort() { uint u = Read32(0); switch (u & PciConfig.PCI_TYPE_MASK) { case PciConfig.PCI_DEVICE_TYPE: return new PciDeviceConfig(this); case PciConfig.PCI_BRIDGE_TYPE: return new PciBridgeConfig(this); case PciConfig.PCI_CARDBUS_TYPE: return new PciCardbusConfig(this); } return null; } public uint Read32(int offset) { #if !DONT_CHECK_IO_BOUNDS if ((offset & 0x3) != 0) { throw new Exception("BAD_OFFSET"); } #endif uint config = (((uint)offset & 0xfc) | ((uint)identifier << 8) | ((uint)1 << 31)); addressPort.Write32(config); return dataPort.Read32(); } public ushort Read16(uint offset) { #if !DONT_CHECK_IO_BOUNDS if ((offset & 0x1) != 0) { throw new Exception("BAD_OFFSET"); } #endif uint config = (((uint)offset & 0xfc) | ((uint)identifier << 8) | ((uint)1 << 31)); addressPort.Write32(config); return dataPort.Read16(offset & 0x1); } public byte Read8(int offset) { uint config = (((uint)offset & 0xfc) | ((uint)identifier << 8) | ((uint)1 << 31)); addressPort.Write32(config); return dataPort.Read8((uint)offset & 0x3); } public void Write32(int offset, uint value) { #if !DONT_CHECK_IO_BOUNDS if ((offset & 0x3) != 0) { throw new Exception("BAD_OFFSET"); } #endif uint config = (((uint)offset & 0xfc) | ((uint)identifier << 8) | ((uint)1 << 31)); addressPort.Write32(config); dataPort.Write32(value); } public void Write16(int offset, ushort value) { #if !DONT_CHECK_IO_BOUNDS if ((offset & 0x1) != 0) { throw new Exception("BAD_OFFSET"); } #endif uint config = (((uint)offset & 0xfc) | ((uint)identifier << 8) | ((uint)1 << 31)); addressPort.Write32(config); dataPort.Write16((uint)(offset & 0x1), value); } public void Write8(int offset, byte value) { uint config = (((uint)offset & 0xff) | ((uint)identifier << 8) | ((uint)1 << 31)); addressPort.Write32(config); dataPort.Write8((uint)(offset & 0x3), value); } } } // end namespace Microsoft.Singularity.Io