254 lines
8.4 KiB
C#
254 lines
8.4 KiB
C#
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// File: PciBus.cs
|
||
|
//
|
||
|
// Note:
|
||
|
//
|
||
|
|
||
|
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")]
|
||
|
[EnumeratesDevice("pci/...")]
|
||
|
internal class PciBusResources : DriverCategoryDeclaration
|
||
|
{
|
||
|
[IoFixedPortRange(Base = 0x0cf8, Length = 0x08)]
|
||
|
IoPortRange configPort;
|
||
|
|
||
|
// Provide to unify creation.
|
||
|
public static IDevice! DeviceCreate(IoConfig! config, String! instanceName)
|
||
|
{
|
||
|
Tracing.Log(Tracing.Debug, "Creating PCI Bus");
|
||
|
|
||
|
return new PciBus(PciEnumerator.GetEnumerator(config));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
[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()
|
||
|
{
|
||
|
foreach (PciConfig! config in enumerator.Enumerate()) {
|
||
|
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 uint numberOfBuses = 0;
|
||
|
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)
|
||
|
{
|
||
|
uint buses = Resources.GetPciNumberOfBuses();
|
||
|
|
||
|
#if DONT_USE_PNP_FOR_PCI
|
||
|
if (config != null &&
|
||
|
config.Ranges.Length >= 1 && config.Ranges[0] != null &&
|
||
|
config.Ranges[0] is IoPortRange) {
|
||
|
IoPortRange ports = (IoPortRange)config.Ranges[0];
|
||
|
|
||
|
IoPort addrPort = ports.PortAtOffset(0, 4, Access.Write);
|
||
|
IoPort dataPort = ports.PortAtOffset(4, 4, Access.ReadWrite);
|
||
|
return new PciEnumerator(addrPort, dataPort, buses);
|
||
|
}
|
||
|
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),
|
||
|
buses);
|
||
|
#if DONT_USE_PNP_FOR_PCI
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
private PciEnumerator(IoPort! addressPort, IoPort! dataPort, uint buses)
|
||
|
{
|
||
|
this.addressPort = addressPort;
|
||
|
this.dataPort = dataPort;
|
||
|
this.numberOfBuses = buses;
|
||
|
}
|
||
|
|
||
|
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();
|
||
|
unchecked {
|
||
|
Tracing.Log(Tracing.Debug, " buses: {0}",
|
||
|
(UIntPtr)(uint)numberOfBuses);
|
||
|
}
|
||
|
|
||
|
for (uint bus = 0; bus < numberOfBuses; bus++) {
|
||
|
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) {
|
||
|
found.Add(String.Format("/bus{0,4:x4}/dev{1,4:x4}/func{2,4:x4}",
|
||
|
bus, device, function),
|
||
|
config);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return found;
|
||
|
}
|
||
|
}
|
||
|
}
|