290 lines
10 KiB
C#
290 lines
10 KiB
C#
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// File: PciBus.cs
|
|
//
|
|
// Note:
|
|
//
|
|
|
|
#define VERBOSE
|
|
//#define DEBUG_PCI_BUS
|
|
//#define DONT_USE_PNP_FOR_PCI
|
|
|
|
using Microsoft.Singularity.Channels;
|
|
using Microsoft.Singularity.Io;
|
|
using Microsoft.Singularity.Configuration;
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Text;
|
|
using System.Configuration.Assemblies;
|
|
using System.Runtime.Remoting;
|
|
using System.Runtime.InteropServices;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace Microsoft.Singularity.Drivers
|
|
{
|
|
// create the resource object for CTR to fill in
|
|
[DriverCategory]
|
|
[Signature("/pnp/PNP0A03")]
|
|
[Signature("/pnp/PNP0A08")]
|
|
[EnumeratesDevice("pci/...")]
|
|
internal class PciBusResources : DriverCategoryDeclaration
|
|
{
|
|
[IoFixedPortRange(Base = 0x0cf8, Length = 0x08, Shared = true)]
|
|
IoPortRange configPort;
|
|
|
|
// Provide to unify creation.
|
|
public static IDevice! DeviceCreate(IoConfig! config, String! instanceName)
|
|
{
|
|
Tracing.Log(Tracing.Debug, "Creating PCI Bus");
|
|
PciBus pciBus = new PciBus(PciEnumerator.GetEnumerator(config));
|
|
#if VERBOSE
|
|
DebugStub.WriteLine("Displaying PCI Enumeration:");
|
|
pciBus.Display();
|
|
DebugStub.WriteLine("PCI Enumeration End.");
|
|
#endif
|
|
return pciBus;
|
|
}
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
public class PciBus : IBusDevice
|
|
{
|
|
private PciEnumerator! enumerator;
|
|
|
|
static ushort IdentifierFromUnits(uint nBus, uint nDevice, uint nFunction)
|
|
{
|
|
return (ushort)(nFunction | (nDevice << 3) | (nBus << 8));
|
|
}
|
|
|
|
public PciBus(PciEnumerator! enumerator)
|
|
{
|
|
this.enumerator = enumerator;
|
|
}
|
|
|
|
public void Initialize()
|
|
{
|
|
Tracing.Log(Tracing.Debug, "Initializing PciBus.");
|
|
}
|
|
|
|
public void Finalize()
|
|
{
|
|
}
|
|
|
|
public SortedList Enumerate()
|
|
{
|
|
return enumerator.Enumerate();
|
|
}
|
|
|
|
public void Display()
|
|
{
|
|
SortedList sl = enumerator.Enumerate();
|
|
for ( int i = 0; i < sl.Count; i++ ) {
|
|
object o = sl.GetByIndex(i);
|
|
PciConfig config = o as PciConfig;
|
|
if (config == null) {
|
|
DebugStub.Break();
|
|
}
|
|
else {
|
|
string str = sl.GetKey(i) as string;
|
|
DebugStub.Write("{0}: ",__arglist(str));
|
|
config.Print();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[CLSCompliant(false)]
|
|
public class PciEnumerator
|
|
{
|
|
public const uint MAX_BUSES = 256;
|
|
public const uint MAX_DEVICES = 32;
|
|
public const uint MAX_FUNCTIONS = 8;
|
|
public const uint MAX_IDENTIFIER = (MAX_BUSES * MAX_DEVICES * MAX_FUNCTIONS) - 1;
|
|
|
|
private const ushort PCI_ADDRESS_PORT = 0xcf8;
|
|
private const ushort PCI_DATA_PORT = 0xcfc;
|
|
|
|
private IoPort! addressPort;
|
|
private IoPort! dataPort;
|
|
|
|
static ushort IdentifierFromUnits(uint nBus, uint nDevice, uint nFunction)
|
|
{
|
|
return (ushort)(nFunction | (nDevice << 3) | (nBus << 8));
|
|
}
|
|
|
|
public static PciEnumerator GetEnumerator(IoConfig config)
|
|
{
|
|
#if DONT_USE_PNP_FOR_PCI
|
|
if (config != null && config.FixedRanges != null &&
|
|
config.FixedRanges.Length >= 1 && config.FixedRanges[0] != null &&
|
|
config.FixedRanges[0] is IoPortRange) {
|
|
IoPortRange ports = (IoPortRange)config.FixedRanges[0];
|
|
if(ports != null) {
|
|
IoPort addrPort = ports.PortAtOffset(0, 4, Access.Write);
|
|
IoPort dataPort = ports.PortAtOffset(4, 4, Access.ReadWrite);
|
|
return new PciEnumerator(addrPort, dataPort);
|
|
}
|
|
else {
|
|
DebugStub.WriteLine("PciBus: config != null but ports == null\n");
|
|
DebugStub.Break();
|
|
}
|
|
}
|
|
else {
|
|
#endif
|
|
IoPortRange dev = new IoPortRange(PCI_ADDRESS_PORT, 8, Access.ReadWrite);
|
|
|
|
return new PciEnumerator(dev.PortAtOffset(0, 4, Access.Write),
|
|
dev.PortAtOffset(4, 4, Access.ReadWrite));
|
|
#if DONT_USE_PNP_FOR_PCI
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
private PciEnumerator(IoPort! addressPort, IoPort! dataPort)
|
|
{
|
|
this.addressPort = addressPort;
|
|
this.dataPort = dataPort;
|
|
}
|
|
|
|
private uint Read32(uint identifier, uint offset)
|
|
{
|
|
if (identifier < 0 || identifier > MAX_IDENTIFIER) {
|
|
throw new OverflowException("BAD_IDENTIFIER");
|
|
}
|
|
if ((offset & 0x3) != 0) {
|
|
throw new Exception("BAD_OFFSET");
|
|
}
|
|
|
|
uint config = (((uint)offset & 0xfc) |
|
|
((uint)identifier << 8) |
|
|
((uint)1 << 31));
|
|
|
|
addressPort.Write32(config);
|
|
return dataPort.Read32();
|
|
}
|
|
|
|
private void Write32(uint identifier, uint offset, uint value)
|
|
{
|
|
if (identifier < 0 || identifier > MAX_IDENTIFIER) {
|
|
throw new OverflowException("BAD_IDENTIFIER");
|
|
}
|
|
if ((offset & 0x3) != 0) {
|
|
throw new Exception("BAD_OFFSET");
|
|
}
|
|
|
|
uint config = (((uint)offset & 0xfc) |
|
|
((uint)identifier << 8) |
|
|
((uint)1 << 31));
|
|
|
|
addressPort.Write32(config);
|
|
dataPort.Write32(value);
|
|
}
|
|
|
|
private PciPort PortForIdentifier(uint identifier)
|
|
{
|
|
if (identifier < 0 || identifier > MAX_IDENTIFIER) {
|
|
throw new OverflowException("BAD_IDENTIFIER");
|
|
}
|
|
return new PciPort(addressPort, dataPort, (ushort)identifier);
|
|
}
|
|
|
|
public SortedList! Enumerate()
|
|
{
|
|
Tracing.Log(Tracing.Debug, "PCI Bus Enumerate");
|
|
|
|
SortedList found = new SortedList();
|
|
for (uint bus = 0; bus < MAX_BUSES; bus++) {
|
|
bool hadDevices = false;
|
|
|
|
for (uint device = 0; device < MAX_DEVICES; device++) {
|
|
PciConfig config;
|
|
uint identifier = IdentifierFromUnits(bus, device, 0);
|
|
uint u = Read32(identifier, 0);
|
|
|
|
if (u == ~0u || u == 0) {
|
|
continue;
|
|
}
|
|
|
|
u = Read32(identifier, 0x0c);
|
|
|
|
uint max_functions = (u & PciConfig.PCI_MULTIFUNCTION) == 0
|
|
? (uint)1 : MAX_FUNCTIONS;
|
|
#if DEBUG_PCI_BUS
|
|
Tracing.Log(Tracing.Debug, " {0}.{1}:C => max={2} [{3:x8}]",
|
|
bus, device, max_functions, u);
|
|
#endif
|
|
|
|
for (uint function = 0; function < max_functions; function++) {
|
|
identifier = IdentifierFromUnits(bus, device, function);
|
|
u = Read32(identifier, 0);
|
|
#if DEBUG_PCI_BUS
|
|
Tracing.Log(Tracing.Debug, " {0}.{1}.{2}:0 => {3:x8}",
|
|
bus, device, function, u);
|
|
#endif
|
|
|
|
if (u == ~0u || u == 0) {
|
|
continue;
|
|
}
|
|
|
|
u = Read32(identifier, 0x0c);
|
|
#if DEBUG_PCI_BUS
|
|
Tracing.Log(Tracing.Debug, " {0}.{1}.{2}:C => {3:x8}",
|
|
bus, device, function, u);
|
|
#endif
|
|
|
|
switch (u & PciConfig.PCI_TYPE_MASK) {
|
|
case PciConfig.PCI_DEVICE_TYPE:
|
|
config = new PciDeviceConfig(PortForIdentifier(identifier));
|
|
break;
|
|
case PciConfig.PCI_BRIDGE_TYPE:
|
|
config = new PciBridgeConfig(PortForIdentifier(identifier));
|
|
break;
|
|
case PciConfig.PCI_CARDBUS_TYPE:
|
|
config = new PciCardbusConfig(PortForIdentifier(identifier));
|
|
break;
|
|
default:
|
|
config = null;
|
|
break;
|
|
}
|
|
|
|
if (config != null) {
|
|
|
|
if (((config.VendorId == 0x8086) && (config.DeviceId == 0x269E)) ||
|
|
((config.VendorId == 0x8086) && (config.DeviceId == 0x2681))) {
|
|
//
|
|
// TEMP: Do not enumerate Intel SATA controllers on the Dell Precision 490.
|
|
// This needs to be removed when we have real drivers for them.
|
|
//
|
|
}
|
|
else if ((config.VendorId == 0x8086) &&
|
|
(config.DeviceId >= 0x27C0) &&
|
|
(config.DeviceId <= 0x27C6)) {
|
|
//
|
|
// TEMP: Do not enumerate Intel SATA controllers on the Dell Precision 380.
|
|
// This needs to be removed when we have real drivers for them.
|
|
//
|
|
}
|
|
else {
|
|
found.Add(String.Format("/bus{0,4:x4}/dev{1,4:x4}/func{2,4:x4}",
|
|
bus, device, function),
|
|
config);
|
|
hadDevices = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!hadDevices) {
|
|
break;
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
}
|
|
}
|