318 lines
13 KiB
C#
318 lines
13 KiB
C#
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Microsoft Research Singularity
|
||
|
//
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
//
|
||
|
// File: IoConfig.cs
|
||
|
//
|
||
|
|
||
|
using System;
|
||
|
using StringBuilder = System.Text.StringBuilder;
|
||
|
using ArrayList = System.Collections.ArrayList;
|
||
|
|
||
|
#if SINGULARITY_PROCESS
|
||
|
using Microsoft.Singularity;
|
||
|
using Microsoft.Singularity.V1.Services;
|
||
|
#endif // SINGULARITY_PROCESS
|
||
|
|
||
|
namespace Microsoft.Singularity.Io
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Instances of this class represent a set of I/O resources that have been assigned
|
||
|
/// to a specific device driver instance.
|
||
|
/// </summary>
|
||
|
[CLSCompliant(false)]
|
||
|
public abstract class IoConfig
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Contains the list of device IDs for this device. These IDs are created (assigned)
|
||
|
/// by the bus driver that enumerated this device. The bus driver may assign any
|
||
|
/// number of IDs. The first ID should always be the Singularity-compatible ID,
|
||
|
/// which uses a path-like syntax, e.g. /pnp/PNP0303 for devices enumerated by the
|
||
|
/// PNP BIOS / ISAPNP bus device, or /pci/02/00/8086/... for devices enumerated by
|
||
|
/// the PCI bus enumerator.
|
||
|
/// </summary>
|
||
|
public String[] Ids;
|
||
|
|
||
|
public IoRange[] DynamicRanges;
|
||
|
public IoRange[] FixedRanges;
|
||
|
|
||
|
/// <summary>
|
||
|
/// This property exists for compatibility with drivers that assume a single device ID.
|
||
|
/// It returns the first device ID in the list.
|
||
|
/// </summary>
|
||
|
// [Obsolete("Fix code to use Ids (list of ids)")]
|
||
|
public String Id
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (Ids == null || Ids.Length == 0 || Ids[0] == null)
|
||
|
return "";
|
||
|
else
|
||
|
return Ids[0];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Builds a description of this IoConfig instance.
|
||
|
/// </summary>
|
||
|
/// <returns>The description text.</returns>
|
||
|
public virtual string ToPrint()
|
||
|
{
|
||
|
StringBuilder text = new StringBuilder();
|
||
|
ToPrint(text);
|
||
|
return text.ToString();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Builds a description of this IoConfig instance.
|
||
|
/// </summary>
|
||
|
/// <param name="text">The text buffer in which to write the description.</param>
|
||
|
protected void ToPrint(StringBuilder text)
|
||
|
{
|
||
|
text.Append("IoConfig: type=");
|
||
|
text.Append(this.GetType().Name);
|
||
|
text.Append("\n");
|
||
|
DumpIds(text);
|
||
|
DumpRanges(text);
|
||
|
}
|
||
|
|
||
|
public void DumpIds(StringBuilder text)
|
||
|
{
|
||
|
foreach (string id in this.Ids)
|
||
|
{
|
||
|
text.Append(" device id: ");
|
||
|
text.Append(id);
|
||
|
text.Append("\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void DumpRanges(StringBuilder text)
|
||
|
{
|
||
|
for (int i = 0; i < DynamicRanges.Length; i++)
|
||
|
{
|
||
|
if (DynamicRanges[i] != null)
|
||
|
{
|
||
|
text.Append(" range[");
|
||
|
text.Append(i);
|
||
|
text.Append("]: ");
|
||
|
text.Append(DynamicRanges[i]);
|
||
|
text.Append("\n");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Prints a description of this I/O configuration to the debug port.
|
||
|
/// </summary>
|
||
|
public void Print()
|
||
|
{
|
||
|
DebugStub.WriteLine(ToPrint());
|
||
|
}
|
||
|
|
||
|
#if SINGULARITY_PROCESS
|
||
|
public static unsafe IoConfig GetConfig()
|
||
|
{
|
||
|
// first get the device signature
|
||
|
ArrayList idlist = new ArrayList();
|
||
|
char[] idbuffer = new char[0x80];
|
||
|
for (int i = 0;; i++) {
|
||
|
int len = (int)DeviceService.GetPnpSignature(i, null, 0);
|
||
|
if (len == 0)
|
||
|
break;
|
||
|
if (len > idbuffer.Length)
|
||
|
idbuffer = new char[len];
|
||
|
fixed (char* idbuffer_pinned = &idbuffer[0]) {
|
||
|
len = (int)DeviceService.GetPnpSignature(i, idbuffer_pinned, (uint)idbuffer.Length);
|
||
|
}
|
||
|
if (len == 0)
|
||
|
break;
|
||
|
string id = new String(idbuffer, 0, len);
|
||
|
idlist.Add(id);
|
||
|
Tracing.Log(Tracing.Debug, "PNP Signature: [{0}]", id);
|
||
|
}
|
||
|
string[] ids = (string[])idlist.ToArray(typeof(string));
|
||
|
#if false
|
||
|
string id = null;
|
||
|
char[] sigArray = new char[DeviceService.GetPnpSignature(null, 0)];
|
||
|
fixed (char *sigPtr = &sigArray[0]) {
|
||
|
int len = (int)DeviceService.GetPnpSignature(
|
||
|
sigPtr, (uint)sigArray.Length);
|
||
|
|
||
|
id = String.StringCTOR(sigPtr, 0, len);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// now get the fixed resources
|
||
|
IoRange[] fixedRanges = GetFixedIoResources();
|
||
|
|
||
|
// now determine if this is a PCI bus, and if so, configure it as
|
||
|
// such
|
||
|
ushort pciAddressPort;
|
||
|
ushort pciDataPort;
|
||
|
ushort pciIdentifier;
|
||
|
|
||
|
if (DeviceService.GetPciConfig(out pciAddressPort,
|
||
|
out pciDataPort,
|
||
|
out pciIdentifier))
|
||
|
{
|
||
|
Tracing.Log(Tracing.Debug, "PCI Config: addr={0:x4} port=" +
|
||
|
"{1:x4} id={2:x4}", pciAddressPort, pciDataPort,
|
||
|
pciIdentifier);
|
||
|
|
||
|
IoPort addrPort = new IoPort(pciAddressPort, 4,
|
||
|
Access.ReadWrite);
|
||
|
IoPort dataPort = new IoPort(pciDataPort, 4, Access.ReadWrite);
|
||
|
PciPort port = new PciPort(addrPort, dataPort, pciIdentifier);
|
||
|
|
||
|
return PciConfig.Create(ids, port, fixedRanges);
|
||
|
}
|
||
|
else {
|
||
|
Tracing.Log(Tracing.Debug, "PCI Config: None.");
|
||
|
}
|
||
|
|
||
|
// it isn't a PCI device, so create a PnpConfig object
|
||
|
|
||
|
// We should really copy all of the ranges, so that
|
||
|
// we can augment even PCI devices (like VGA cards).
|
||
|
|
||
|
uint rangeCount = DeviceService.GetDynamicIoRangeCount();
|
||
|
Tracing.Log(Tracing.Debug, "I/O Ranges: {0}", rangeCount);
|
||
|
|
||
|
IoRange[] dynamicRanges = new IoRange[rangeCount];
|
||
|
|
||
|
for (uint range = 0; range < rangeCount; range++) {
|
||
|
ushort port;
|
||
|
ushort size;
|
||
|
bool readable;
|
||
|
bool writable;
|
||
|
byte * dataAddr;
|
||
|
uint dataSize;
|
||
|
byte irq;
|
||
|
byte irqSize;
|
||
|
byte dma;
|
||
|
byte dmaSize;
|
||
|
|
||
|
if (DeviceService.GetDynamicIoPortRange(range, out port,
|
||
|
out size, out readable,
|
||
|
out writable))
|
||
|
{
|
||
|
Tracing.Log(Tracing.Debug, "{0:d4}. I/O Port: port={1:x4}" +
|
||
|
"[{2:x}] read={3} write={4}",
|
||
|
range, port, size,
|
||
|
(UIntPtr)(readable ? 1 : 0),
|
||
|
(UIntPtr)(writable ? 1 : 0));
|
||
|
dynamicRanges[range] = new IoPortRange(port, size, readable,
|
||
|
writable);
|
||
|
}
|
||
|
else if (DeviceService.GetDynamicIoMemoryRange(range,
|
||
|
out dataAddr,
|
||
|
out dataSize,
|
||
|
out readable,
|
||
|
out writable))
|
||
|
{
|
||
|
|
||
|
UIntPtr addr = (UIntPtr)dataAddr;
|
||
|
Tracing.Log(Tracing.Debug, "{0:d4}. Memory: addr={1:x8}" +
|
||
|
"[2:x] read={3} write={4}",
|
||
|
range, addr, dataSize,
|
||
|
(UIntPtr)(readable ? 1 : 0),
|
||
|
(UIntPtr)(writable ? 1 : 0));
|
||
|
dynamicRanges[range] = new IoMemoryRange(addr, dataSize,
|
||
|
readable,
|
||
|
writable);
|
||
|
}
|
||
|
else if (DeviceService.GetDynamicIoIrqRange(range, out irq,
|
||
|
out irqSize))
|
||
|
{
|
||
|
Tracing.Log(Tracing.Debug, "{0:d4}. Irq: irq={1:x2}" +
|
||
|
"[{2:x}]", range, irq, irqSize);
|
||
|
dynamicRanges[range] = new IoIrqRange(irq, irqSize);
|
||
|
}
|
||
|
else if (DeviceService.GetDynamicIoDmaRange(range, out dma,
|
||
|
out dmaSize))
|
||
|
{
|
||
|
Tracing.Log(Tracing.Debug, "{0:d4}. Dma: dma={1:x2}" +
|
||
|
"[{2:x}]", range, dma, dmaSize);
|
||
|
dynamicRanges[range] = new IoDmaRange(dma, dmaSize);
|
||
|
}
|
||
|
else {
|
||
|
Tracing.Log(Tracing.Debug, "{0:d4}. Empty", range);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return new PnpConfig(ids, dynamicRanges, fixedRanges);
|
||
|
}
|
||
|
|
||
|
// return an IoRange array filled with all of the fixed resources that
|
||
|
// this assembly requested in its manifest
|
||
|
private unsafe static IoRange[] GetFixedIoResources()
|
||
|
{
|
||
|
uint rangeCount = DeviceService.GetFixedIoRangeCount();
|
||
|
Tracing.Log(Tracing.Debug, "I/O Ranges: {0}", rangeCount);
|
||
|
|
||
|
IoRange[] ranges = new IoRange[rangeCount];
|
||
|
|
||
|
for (uint range = 0; range < rangeCount; range++) {
|
||
|
ushort port, size;
|
||
|
bool readable, writable;
|
||
|
byte * dataAddr;
|
||
|
uint dataSize;
|
||
|
byte irq, irqSize;
|
||
|
byte dma, dmaSize;
|
||
|
|
||
|
if (DeviceService.GetFixedIoPortRange(range, out port,
|
||
|
out size, out readable,
|
||
|
out writable))
|
||
|
{
|
||
|
Tracing.Log(Tracing.Debug, "{0:d4}. I/O Port: port={1:x4}" +
|
||
|
"[{2:x}] read={3} write={4}",
|
||
|
range, port, size,
|
||
|
(UIntPtr)(readable ? 1 : 0),
|
||
|
(UIntPtr)(writable ? 1 : 0));
|
||
|
ranges[range] = new IoPortRange(port, size, readable,
|
||
|
writable);
|
||
|
}
|
||
|
else if (DeviceService.GetFixedIoMemoryRange(range,
|
||
|
out dataAddr,
|
||
|
out dataSize,
|
||
|
out readable,
|
||
|
out writable))
|
||
|
{
|
||
|
UIntPtr addr = (UIntPtr)dataAddr;
|
||
|
Tracing.Log(Tracing.Debug, "{0:d4}. Memory: addr={1:x8}" +
|
||
|
"[2:x] read={3} write={4}",
|
||
|
range, addr, dataSize,
|
||
|
(UIntPtr)(readable ? 1 : 0),
|
||
|
(UIntPtr)(writable ? 1 : 0));
|
||
|
ranges[range] = new IoMemoryRange(addr, dataSize, readable,
|
||
|
writable);
|
||
|
}
|
||
|
else if (DeviceService.GetFixedIoIrqRange(range, out irq,
|
||
|
out irqSize))
|
||
|
{
|
||
|
Tracing.Log(Tracing.Debug,
|
||
|
"{0:d4}. Irq: irq={1:x2}[{2:x}]",
|
||
|
range, irq, irqSize);
|
||
|
ranges[range] = new IoIrqRange(irq, irqSize);
|
||
|
}
|
||
|
else if (DeviceService.GetFixedIoDmaRange(range, out dma,
|
||
|
out dmaSize))
|
||
|
{
|
||
|
Tracing.Log(Tracing.Debug,
|
||
|
"{0:d4}. Dma: dma={1:x2}[{2:x}]",
|
||
|
range, dma, dmaSize);
|
||
|
ranges[range] = new IoDmaRange(dma, dmaSize);
|
||
|
}
|
||
|
else {
|
||
|
Tracing.Log(Tracing.Debug, "{0:d4}. Empty", range);
|
||
|
}
|
||
|
}
|
||
|
return ranges;
|
||
|
}
|
||
|
#endif // SINGULARITY_PROCESS
|
||
|
}
|
||
|
}
|