/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: PciConfig.cs // // Note: // #define DEBUG_PCI using System; using StringBuilder = System.Text.StringBuilder; using System.Collections; using Microsoft.Singularity; #if !SINGULARITY_PROCESS using Microsoft.Singularity.Hal; #endif 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 private const int PCI_CONTROL_OFFSET = 0x0004; private const int PCI_STATUS_OFFSET = 0x0006; // // Bit encodings for PCI_COMMON_CONFIG.Control // public const uint PCI_ENABLE_IO_SPACE = 0x0001; public const uint PCI_ENABLE_MEMORY_SPACE = 0x0002; public const uint PCI_ENABLE_BUS_MASTER = 0x0004; public const uint PCI_ENABLE_SPECIAL_CYCLES = 0x0008; public const uint PCI_ENABLE_WRITE_AND_INVALIDATE = 0x0010; public const uint PCI_ENABLE_VGA_COMPATIBLE_PALETTE = 0x0020; public const uint PCI_ENABLE_PARITY = 0x0040; // (ro+) public const uint PCI_ENABLE_WAIT_CYCLE = 0x0080; // (ro+) public const uint PCI_ENABLE_SERR = 0x0100; // (ro+) public const uint PCI_ENABLE_FAST_BACK_TO_BACK = 0x0200; // (ro) public 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_BAR_TYPE_MASK = 0xf; const uint PCI_BAR_TYPE_IO = 0x1; const uint PCI_BAR_TYPE_MEM20 = 0x2; const uint PCI_BAR_TYPE_MEM32 = 0x0; const uint PCI_BAR_TYPE_MEM64 = 0x4; const uint PCI_BAR_TYPE_MEMMASK = 0x6; const uint PCI_BAR_TYPE_PREFETCH = 0x8; 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) 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 ulong[] BaseAddresses; // 10..17 or ..27 [2 or 6] protected ulong[] 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 PciPort PciPort { get { return this.port; } } 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 ushort Control { get { return Read16(PCI_CONTROL_OFFSET); } set { Write16(PCI_CONTROL_OFFSET, value); } } public ushort Status { get { return Read16(PCI_STATUS_OFFSET); } set { Write16(PCI_STATUS_OFFSET, value); } } public bool IoSpaceEnabled { get { return ((uint)Control & PCI_ENABLE_IO_SPACE) != 0; } set { uint tmp = (uint)Control & ~PCI_ENABLE_IO_SPACE; if (value) { tmp |= PCI_ENABLE_IO_SPACE; } Control = (ushort)(tmp & 0xffff); } } public bool MemorySpaceEnabled { get { return ((uint)Control & PCI_ENABLE_MEMORY_SPACE) != 0; } set { uint tmp = (uint)Control & ~PCI_ENABLE_MEMORY_SPACE; if (value) { tmp |= PCI_ENABLE_MEMORY_SPACE; } Control = (ushort)(tmp & 0xffff); } } public bool InterruptsEnabled { get { return ((uint)Control & PCI_DISABLE_INTERRUPTS) == 0; } set { uint tmp = (uint)Control & ~PCI_DISABLE_INTERRUPTS; if (!value) { tmp |= PCI_ENABLE_MEMORY_SPACE; } Control = (ushort)(tmp & 0xffff); } } /////////////////////////////////////////////////////////////////////// // // Port operations // public ulong Read64(int offset) { ulong hi = Read32(offset + 4); return (hi << 32) | (ulong)Read32(offset); } public void Write64(int offset, ulong value) { Write32(offset + 4, (uint)(value >> 32)); Write32(offset, (uint)(value & 0xffffffff)); } public uint Read32(int offset) { return port.Read32(offset); } public void Write32(int offset, uint value) { port.Write32(offset, value); } public ushort Read16(int offset) { return port.Read16(offset); } public void Write16(int offset, ushort value) { port.Write16(offset, value); } public byte Read8(int offset) { return port.Read8(offset); } public 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(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(); } /// /// /// 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_classcode + and + id_subsys + and + id_revision, 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"; private void ProbeIoRange(int offset, out ushort start, out ushort length) { uint start32 = port.Read32(offset); DebugStub.Assert((start32 & PCI_BAR_TYPE_IO) == PCI_BAR_TYPE_IO); Write32(offset, ~0u); uint length32 = Read32(offset); length32 &= ~PCI_BAR_TYPE_IO; length32 |= 0xffff0000; length32 = ~length32 + 1; Write32(offset, start32); if (start32 <= 0xffff && length32 <= 0xffff) { start = (ushort)start32; length = (ushort)length32; } else { start = 0; length = 0; #if DEBUG_PCI DebugStub.Break(); #endif // DEBUG_PCI } } private void ProbeMemoryRange64(int offset, out ulong start, out ulong length) { start = Read64(offset); DebugStub.Assert((start & PCI_BAR_TYPE_MEMMASK) == PCI_BAR_TYPE_MEM64); Write64(offset, UInt64.MaxValue); length = Read64(offset); length &= ~((ulong)PCI_BAR_TYPE_MASK); length = ~length + 1; Write64(offset, start); if (UIntPtr.Size == 4 && (start > (ulong)UInt32.MaxValue || (start + length) > (ulong)UInt32.MaxValue)) { start = 0; length = 0; #if DEBUG_PCI DebugStub.Break(); #endif // DEBUG_PCI } } private void ProbeMemoryRange32(int offset, out uint start, out uint length) { start = Read32(offset); DebugStub.Assert( (start & PCI_BAR_TYPE_MEMMASK) == PCI_BAR_TYPE_MEM32 || (start & PCI_BAR_TYPE_MEMMASK) == PCI_BAR_TYPE_MEM20 ); Write32(offset, UInt32.MaxValue); length = port.Read32(offset) & ~PCI_BAR_TYPE_MASK; if ((start & PCI_BAR_TYPE_MASK) == PCI_BAR_TYPE_MEM20) { length |= 0xfff00000; } length = ~length + 1; Write32(offset, start); } protected void ReadBaseAddresses(int n) { InterruptPin = Read8(PCI_INTERRUPT_PIN); if (InterruptPin != 0) { // Add interrupt resource to list of ranges if present DynamicRanges = new IoRange [n + 1]; DynamicRanges[n] = new IoIrqRange(Read8(PCI_INTERRUPT_LINE), 1); byte currentInterruptLine = InterruptLine; #if !SINGULARITY_PROCESS byte newInterruptLine = Platform.TranslatePciInterrupt(currentInterruptLine, InterruptPin, port); if (newInterruptLine != currentInterruptLine) { SetInterrupt(newInterruptLine); currentInterruptLine = newInterruptLine; } #endif IoIrqRange range = new IoIrqRange(currentInterruptLine, 1); DynamicRanges[n] = range; } else { DynamicRanges = new IoRange [n]; } BaseAddresses = new ulong [n]; BaseAddrSizes = new ulong [n]; 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); for (int i = 0, bar = 0; i < n; i++, bar++) { int offset = 0x10 + i * 4; uint type = Read32(offset) & PCI_BAR_TYPE_MASK; if ((type & PCI_BAR_TYPE_IO) == PCI_BAR_TYPE_IO) { ushort addr16, size16; ProbeIoRange(offset, out addr16, out size16); if (size16 != 0) { DynamicRanges[bar] = new IoPortRange( (ushort)((uint)addr16 & ~PCI_BAR_TYPE_IO), size16, Access.ReadWrite ); BaseAddresses[bar] = addr16; BaseAddrSizes[bar] = size16; } } else if ((type & PCI_BAR_TYPE_MEMMASK) == PCI_BAR_TYPE_MEM64) { ulong addr64, size64; ProbeMemoryRange64(offset, out addr64, out size64); if (size64 != 0) { DynamicRanges[bar] = new IoMemoryRange( addr64 & ~PCI_BAR_TYPE_MASK, size64, Access.ReadWrite ); BaseAddresses[bar] = addr64; BaseAddrSizes[bar] = size64; i += 1; } } else if ((type & PCI_BAR_TYPE_MEMMASK) == PCI_BAR_TYPE_MEM32 || (type & PCI_BAR_TYPE_MEMMASK) == PCI_BAR_TYPE_MEM20) { uint addr32, size32; ProbeMemoryRange32(offset, out addr32, out size32); if (size32 != 0) { DynamicRanges[bar] = new IoMemoryRange( addr32 & ~PCI_BAR_TYPE_MASK, size32, Access.ReadWrite ); BaseAddresses[bar] = addr32; BaseAddrSizes[bar] = size32; } } } port.Write32(0x04, control & 0xffff); } 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_BAR_TYPE_IO) != 0) { s += String.Format("A{0}=IO:{1:x8}[{2:x}] ", i, BaseAddresses[i], BaseAddrSizes[i]); } else if ((BaseAddresses[i] & PCI_BAR_TYPE_MEM64) != 0) { s += String.Format("A{0}=64:{1:x8}[{2:x}] ", i, BaseAddresses[i], BaseAddrSizes[i]); } else if ((BaseAddresses[i] & PCI_BAR_TYPE_MEM20) != 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); } } } } [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(); } public byte Capabilities { get { return this.capabilities; } } 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); this.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 ulong [0]; Read(); } protected override void Read() { base.Read(); } public override string ToPrint() { return base.ToPrint(); } } } // end namespace Microsoft.Singularity.Io