singrdk/base/Kernel/Singularity.Io/IoSystem.sg

2021 lines
85 KiB
Plaintext
Raw Permalink Normal View History

2008-03-05 09:52:00 -05:00
///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: IoSystem.sg
//
// Note:
//
//#define DEBUG_DISPATCH_IO
//#define VERBOSE
2008-11-17 18:29:00 -05:00
// This will be removed as I complete testing on the SIP based nameserver
#define TYAN_MOTHERBOARD_HACK
2008-03-05 09:52:00 -05:00
using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Threading;
2008-11-17 18:29:00 -05:00
using System.Text;
2008-03-05 09:52:00 -05:00
using Microsoft.SingSharp;
using Microsoft.Singularity;
using Microsoft.Singularity.Channels;
2008-11-17 18:29:00 -05:00
using Microsoft.Singularity.Directory;
2008-03-05 09:52:00 -05:00
using Microsoft.Singularity.Extending;
using Microsoft.Singularity.FileSystem;
2008-11-17 18:29:00 -05:00
using Microsoft.Singularity.Hal;
using Microsoft.Singularity.Loader;
using Microsoft.Singularity.Memory;
2008-03-05 09:52:00 -05:00
using Microsoft.Singularity.Memory;
using Microsoft.Singularity.Xml;
namespace Microsoft.Singularity.Io
{
internal sealed class VerboseOut
{
2008-11-17 18:29:00 -05:00
[System.Diagnostics.Conditional("VERBOSE")]
internal static void WriteLine(string format, __arglist)
2008-03-05 09:52:00 -05:00
{
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine(format, new ArgIterator(__arglist));
2008-03-05 09:52:00 -05:00
}
2008-11-17 18:29:00 -05:00
[System.Diagnostics.Conditional("VERBOSE")]
internal static void WriteLine(string message)
2008-03-05 09:52:00 -05:00
{
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine(message);
2008-03-05 09:52:00 -05:00
}
2008-11-17 18:29:00 -05:00
[System.Diagnostics.Conditional("VERBOSE")]
internal static void Write(string format, __arglist)
2008-03-05 09:52:00 -05:00
{
2008-11-17 18:29:00 -05:00
DebugStub.Write(format, new ArgIterator(__arglist));
2008-03-05 09:52:00 -05:00
}
2008-11-17 18:29:00 -05:00
[System.Diagnostics.Conditional("VERBOSE")]
internal static void Write(string message)
2008-03-05 09:52:00 -05:00
{
2008-11-17 18:29:00 -05:00
DebugStub.Write(message);
2008-03-05 09:52:00 -05:00
}
}
[CLSCompliant(false)]
public delegate IDevice! IoDeviceCreate(IoConfig! config,
String! instanceName);
internal class ExtensionDevice
{
// endpoint tags:
public const string EndpointSetXmlTag = "endpoints";
public const string ServiceEndpointXmlTag = "serviceProvider";
public const string ExtensionEndpointXmlTag = "extension";
public const string GenericEndpointXmlTag = "endpoint";
public const string ContractXmlAttribute = "contractName";
public const string EndpointEndXmlAttribute = "endpointEnd";
public const string IndexXmlAttribute = "id";
private readonly Driver! driver;
private readonly DeviceNode! device;
private String instance;
private Process process;
private TRef<ExtensionContract.Imp:Ready> channel;
// invariant driver.imagePath != null;
public ExtensionDevice(Driver! driver, DeviceNode! device)
requires driver.imagePath != null;
{
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine(" ExtensionDevice({0})", __arglist(driver.name));
2008-03-05 09:52:00 -05:00
this.driver = driver;
this.device = device;
this.instance = null;
base();
}
public void Finalize()
{
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine("Finalizing {0} (channel = {1})",
__arglist(driver.name, channel != null));
2008-03-05 09:52:00 -05:00
if (channel == null) {
return;
}
ExtensionContract.Imp imp = channel.Acquire();
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine("Requesting shutdown...");
2008-03-05 09:52:00 -05:00
imp.SendShutdown();
switch receive {
case imp.RecvAckShutdown():
Tracing.Log(Tracing.Audit, "Driver shutdown!");
break;
case imp.RecvNakShutdown():
Tracing.Log(Tracing.Audit, "Driver won't shutdown!");
break;
case unsatisfiable:
Tracing.Log(Tracing.Audit, "Child aborted!");
break;
case timeout(TimeSpan.FromSeconds(5)):
DebugStub.Break();
break;
}
delete imp;
VerboseOut.WriteLine("done");
channel = null;
}
// Activate a device driver
// NB: this method assumes that the device has already been checked, and
// its dependencies are all satisfied/satisfiable
public bool Activate()
{
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine("IoSystem.Activate executing\n");
2008-03-05 09:52:00 -05:00
// Update the /hardware namespace
if (driver.directoryRoot == null || device.directoryRoot == null) {
// The /hardware tree is incomplete for this device
DebugStub.Break();
return false;
}
// Create an instance name for this driver
for (int i = 0;; i++) {
string inst = driver.directoryRoot + "/instance" + i;
if (DirectoryService.FindDirectory(inst, false) == null) {
instance = inst;
break;
}
}
// Create the child process.
Manifest manifest;
2008-11-17 18:29:00 -05:00
2008-03-05 09:52:00 -05:00
// from invariant
assume driver.imagePath != null;
IoMemory memory = Binder.LoadImage(Process.KernelProcess,
driver.imagePath,
out manifest);
if (null == memory && manifest == null) {
2008-11-17 18:29:00 -05:00
DebugStub.Break();
2008-03-05 09:52:00 -05:00
return false;
}
// The instance argument in the
// process arguments gets replaced by the service
// endpoint path if present in the manifest before
// we call process.Start(). This is a little ugly,
// but some services need to be able to pass their
// endpoint name to other services (e.g. disk driver
// to volume manager).
string [] processArgs = new String[] {
driver.imagePath,
"-instance",
instance, // Value overwritten below (do not reorder)
"-signature",
2008-11-17 18:29:00 -05:00
device.MatchingDeviceId,
"-class",
driver.configClass
2008-03-05 09:52:00 -05:00
};
process = new Process(Process.KernelProcess, memory, null,
processArgs, manifest);
if (null == process) {
return false;
}
2008-11-17 18:29:00 -05:00
//
// Allow device drivers to enable / disable interrupts.
// This should however be further restricted only to the drivers
// that need this. This should be added to the manifest somehow.
//
process.SetPrivileges(new ProcessPrivileges(
ProcessPrivileges.Operations.DisableInterrupts));
2008-03-05 09:52:00 -05:00
process.IoConfig = device.config;
// the order here is a little bit funny; we need to create the
// endpoints before we start the driver. We must also build the
// pieces of the /hardware tree that store the real endpoints.
// However, we cannot create the public names (i.e. those in the
// /dev namespace) until after the driver is started.
2008-11-17 18:29:00 -05:00
// TODO: If the activation fails, there is no rollback,
2008-03-05 09:52:00 -05:00
// and so we'll end up with a polluted namespace
// since we can't create the public names until after driver
// activation, we need a place to store the string names as we
// generate them
SortedList publicServiceProviderNames = new SortedList();
// do the accounting, NS bindings, and endpoint creation:
// get the image node and device node, create the instance node
DirNode devImageNode = DirectoryService.FindDirectory(
driver.directoryRoot + "/image", false);
DirNode driverNode = DirectoryService.FindDirectory(instance, true);
DirNode! deviceNode = (!)DirectoryService.FindDirectory(
device.directoryRoot, false);
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine("DriverName: {0}", __arglist(driver.directoryRoot));
VerboseOut.WriteLine("DeviceName: {0}", __arglist(device.directoryRoot));
2008-03-05 09:52:00 -05:00
// build the symlinks:
2008-11-17 18:29:00 -05:00
DirectoryService.CreateSymbolicLink(driverNode, "device", device.directoryRoot);
DirectoryService.CreateSymbolicLink(deviceNode, "driver", instance);
2008-03-05 09:52:00 -05:00
if (devImageNode != null) {
DirectoryService.CreateSymbolicLink(driverNode, "image",
driver.directoryRoot);
}
// Now create and link all of the ServiceProvider endpoints
// that this driver provides:
XmlNode! endpoints
= (!)driver.metadata.GetChild(EndpointSetXmlTag);
2008-11-17 18:29:00 -05:00
// TODO: this will not work correctly if there
2008-03-05 09:52:00 -05:00
// are non-endpoint declarations in the <endpoints> set
int endpointCount = endpoints.GetAttribute("length", 0);
process.SetEndpointCount(endpointCount);
int extensionIndex = -1; // we only support one extension
// Make all endpoints
foreach (XmlNode! endpoint in endpoints.Children) {
string! contract = (!)endpoint.GetAttribute(
ContractXmlAttribute, "");
bool created = false;
int index = endpoint.GetAttribute(IndexXmlAttribute, -1);
if (endpoint.Name == ExtensionEndpointXmlTag &&
extensionIndex == -1) {
extensionIndex = index;
created = true;
}
else if (endpoint.Name == ServiceEndpointXmlTag) {
// create the /hardware name (private name)
string privateName = instance + "/endpoint" + index;
string! publicName;
// now tell the ResourceTracker to connect this private
// name and use the policy to create a public name
Binder.SetEndpoint(process, index,
Binder.BindServiceProvider(
contract, privateName,
out created, out publicName));
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine("privateName: {0}", __arglist(privateName));
VerboseOut.WriteLine("publicName : {0}", __arglist(publicName));
2008-03-05 09:52:00 -05:00
processArgs[2] = privateName;
publicServiceProviderNames.Add(privateName, publicName);
}
else if (endpoint.Name == GenericEndpointXmlTag) {
// get a pre-bound generic endpoint to a service from the
// resource tracker
created = Binder.BindServiceUser(process, index, contract, endpoint);
}
else {
DebugStub.WriteLine("Invalid tag {0} in Metadata",
__arglist(endpoint.Name));
DebugStub.Break();
}
2008-11-17 18:29:00 -05:00
// TODO: how should we handle errors? Can we do
2008-03-05 09:52:00 -05:00
// a roll-back?
if (!created) {
DebugStub.Break();
// we might have dangling endpoints and a polluted
// /hardware namespace
return false;
}
}
if (extensionIndex == -1) {
DebugStub.WriteLine("Driver is missing extension endpoint.");
DebugStub.Break();
}
// Add all endpoints that we created.
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine("Activate Device {0} {1} [{2}]",
__arglist(device.location, driver.name, instance));
2008-03-05 09:52:00 -05:00
ExtensionContract.Imp! imp;
ExtensionContract.Exp! exp;
ExtensionContract.NewChannel(out imp, out exp);
Binder.SetEndpoint(process, extensionIndex, exp);
process.Start();
Tracing.Log(Tracing.Audit, "Waiting for driver {0:x8} to init.",
Kernel.AddressOf(process));
bool success = false;
switch receive {
case imp.RecvSuccess():
Tracing.Log(Tracing.Audit, "Driver initialized!");
success = true;
break;
case unsatisfiable:
Tracing.Log(Tracing.Audit, "Driver failed to initialize!");
break;
}
if (success) {
channel = new TRef<ExtensionContract.Imp:Ready>(imp);
}
else {
delete imp;
}
// update the public namespace
foreach (DictionaryEntry de in publicServiceProviderNames) {
string! privateName = (!)(de.Key as string);
string! publicName = (!)(de.Value as string);
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("{0} symlink {1}", __arglist(privateName, publicName));
2008-03-05 09:52:00 -05:00
Binder.CreatePublicSymlink(publicName, privateName);
}
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("Driver Initialized\n");
2008-03-05 09:52:00 -05:00
return true;
}
}
// Driver encapsulates known device drivers.
internal class Driver
{
// Instance fields:
/// <summary>
/// Friendly name used in debugging.
/// This comes from the Name property of the System.Type instance.
/// </summary>
public readonly String! name;
/// <summary>
/// The PNP device ID (hardware, model, class, etc.) that this device driver definition binds to.
/// </summary>
public readonly String! pnpSignature;
2008-11-17 18:29:00 -05:00
/// <summary>
/// The PNP config class defined in metadata (class with SignatureAttribute).
/// </summary>
public readonly String! configClass;
2008-03-05 09:52:00 -05:00
/// <summary>
/// root node in directory.
/// </summary>
public readonly String! directoryRoot;
/// <summary>
/// The XML metadata for this driver. -XXX- Which element?
/// </summary>
public readonly XmlNode! metadata;
/// <summary>
/// Creation delegate for internal (in-kernel) drivers.
/// </summary>
public readonly IoDeviceCreate factory;
/// <summary>
/// The binary / image path for the executable.
/// This field is only non-null for process drivers (not in-kernel drivers).
/// </summary>
public readonly String imagePath;
public override string! ToString()
{
2008-11-17 18:29:00 -05:00
if (factory != null) {
2008-03-05 09:52:00 -05:00
return "<kernel driver '" + this.name + "'>";
2008-11-17 18:29:00 -05:00
}
if (imagePath != null) {
2008-03-05 09:52:00 -05:00
return "<process driver '" + this.name + "' image=" + this.imagePath + "'>";
2008-11-17 18:29:00 -05:00
}
2008-03-05 09:52:00 -05:00
return "<hal driver '" + this.name + "'>";
}
/// <summary>
/// The number of instances of this device driver.
/// </summary>
private int instanceCount;
// Static fields:
/// <summary>
/// Key: string! PNP device ID
/// Value: Driver! driver
///
/// List of registered drivers. A given driver can be in this list more than once,
/// if that driver can match more than one device ID.
/// </summary>
private static SortedList DriversTable;
// Constructor for external drivers.
2008-11-17 18:29:00 -05:00
private Driver(String! name,
String! pnpSignature,
String! configClass,
2008-03-05 09:52:00 -05:00
String! directoryRoot,
String! imagePath,
XmlNode! metadata)
{
2008-11-17 18:29:00 -05:00
this.name = name;
2008-03-05 09:52:00 -05:00
this.pnpSignature = pnpSignature;
2008-11-17 18:29:00 -05:00
this.configClass = configClass;
2008-03-05 09:52:00 -05:00
this.directoryRoot = directoryRoot;
this.metadata = metadata;
this.imagePath = imagePath;
this.factory = null;
base();
}
// Constructor for internal drivers.
private Driver(String! pnpSignature,
2008-11-17 18:29:00 -05:00
String! configClass,
2008-03-05 09:52:00 -05:00
String! directoryRoot,
Type! type,
IoDeviceCreate! factory,
XmlNode! metadata)
{
this.name = (!)type.Name;
this.pnpSignature = pnpSignature;
2008-11-17 18:29:00 -05:00
this.configClass = configClass;
2008-03-05 09:52:00 -05:00
this.directoryRoot = directoryRoot;
this.metadata = metadata;
this.imagePath = null;
this.factory = factory;
base();
}
// Constructor for HAL drivers.
private Driver(String! pnpSignature,
2008-11-17 18:29:00 -05:00
String! configClass,
2008-03-05 09:52:00 -05:00
String! directoryRoot,
Type! type,
XmlNode! metadata)
{
this.name = (!)type.Name;
this.pnpSignature = pnpSignature;
2008-11-17 18:29:00 -05:00
this.configClass = configClass;
2008-03-05 09:52:00 -05:00
this.directoryRoot = directoryRoot;
this.metadata = metadata;
this.imagePath = null;
this.factory = null;
base();
}
// Generic helper function for driver registration.
private static void Add(Driver! driver)
{
if (DriversTable == null) {
DriversTable = new SortedList();
}
string canonical_device_id = GetCanonicalDeviceId(driver.pnpSignature);
Driver existingDriver = (Driver)DriversTable[canonical_device_id];
if (existingDriver != null) {
DebugStub.WriteLine("WARNING: Two drivers match the same PNP signature!");
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine(" PNP signature: {0}", __arglist(canonical_device_id));
DebugStub.WriteLine(" Existing driver: {0}", __arglist(existingDriver.imagePath));
DebugStub.WriteLine(" Second driver: {0}", __arglist(driver.imagePath));
2008-03-05 09:52:00 -05:00
DebugStub.WriteLine(" The second driver will be IGNORED.");
return;
}
DriversTable.Add(canonical_device_id, driver);
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine("Adding driver map: device id {0,-25} -> {1}",
__arglist(driver.pnpSignature, driver.ToString()));
2008-03-05 09:52:00 -05:00
}
static Driver FindDriverByDeviceId(string! deviceId)
{
2008-11-17 18:29:00 -05:00
if (DriversTable == null) {
2008-03-05 09:52:00 -05:00
return null;
2008-11-17 18:29:00 -05:00
}
2008-03-05 09:52:00 -05:00
deviceId = GetCanonicalDeviceId(deviceId);
Driver driver = (Driver)DriversTable[deviceId];
return driver;
}
static string! GetCanonicalDeviceId(string! id)
{
return id.ToLower();
}
// Register an external driver.
2008-11-17 18:29:00 -05:00
public static Driver! Register(String! name,
String! pnpSignature,
String! configClass,
2008-03-05 09:52:00 -05:00
String! directoryRoot,
String! imagePath,
XmlNode! metadata)
{
Driver! driver
2008-11-17 18:29:00 -05:00
= new Driver(name, pnpSignature, configClass, directoryRoot, imagePath, metadata);
2008-03-05 09:52:00 -05:00
Add(driver);
return driver;
}
// Register an internal driver.
public static Driver! Register(String! pnpSignature,
2008-11-17 18:29:00 -05:00
String! configClass,
2008-03-05 09:52:00 -05:00
String! directoryRoot,
Type! type,
IoDeviceCreate! factory,
XmlNode! metadata)
{
Driver! driver
2008-11-17 18:29:00 -05:00
= new Driver(pnpSignature, configClass, directoryRoot, type, factory, metadata);
2008-03-05 09:52:00 -05:00
Add(driver);
return driver;
}
// Register a HAL driver.
public static Driver! Register(String! pnpSignature,
2008-11-17 18:29:00 -05:00
String! configClass,
2008-03-05 09:52:00 -05:00
String! directoryRoot,
Type! type,
XmlNode! metadata)
{
Driver! driver
2008-11-17 18:29:00 -05:00
= new Driver(pnpSignature, configClass, directoryRoot, type, metadata);
2008-03-05 09:52:00 -05:00
Add(driver);
return driver;
2008-11-17 18:29:00 -05:00
}
2008-03-05 09:52:00 -05:00
// Searches a list of PNP signatures for the best driver (closest match).
public static Driver FindBest(string[]! deviceIds, out string! matchingDeviceId)
{
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine("Driver.FindBest: checking these signatures: {0}",
__arglist(String.Join(", ", deviceIds)));
2008-03-05 09:52:00 -05:00
2008-11-17 18:29:00 -05:00
foreach (string deviceId in deviceIds) {
2008-03-05 09:52:00 -05:00
assert deviceId != null;
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine(" Checking signature: {0}", __arglist(deviceId));
2008-03-05 09:52:00 -05:00
Driver driver = FindBest(deviceId);
if (driver != null) {
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine(" Found match: {0}", __arglist(driver));
2008-03-05 09:52:00 -05:00
matchingDeviceId = deviceId;
return driver;
}
}
matchingDeviceId = "";
return null;
}
// Find the best driver for this PNP signature via prefix match.
public static Driver FindBest(string! deviceId)
{
Driver driver = FindDriverByDeviceId(deviceId);
return driver;
}
// Dump the list of know drivers.
public static void DumpAll()
{
2008-11-17 18:29:00 -05:00
if (DriversTable == null) {
return;
}
2008-03-05 09:52:00 -05:00
#if false
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("Drivers:");
2008-03-05 09:52:00 -05:00
foreach (Driver driver in DriversTable.Values) {
2008-11-17 18:29:00 -05:00
if (driver == null) {
2008-03-05 09:52:00 -05:00
continue;
2008-11-17 18:29:00 -05:00
}
DebugStub.WriteLine(" {0}", __arglist(driver));
2008-03-05 09:52:00 -05:00
}
#endif
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("Device ID mappings:");
2008-03-05 09:52:00 -05:00
foreach (DictionaryEntry entry in DriversTable) {
string! deviceId = (string)entry.Key;
Driver! driver = (!)(Driver)entry.Value;
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine(" {0} -> {1}", __arglist(deviceId, driver.name));
2008-03-05 09:52:00 -05:00
}
DebugStub.WriteLine("");
Tracing.Log(Tracing.Audit, "Drivers:");
foreach (Driver driver in DriversTable.Values) {
2008-11-17 18:29:00 -05:00
if (driver == null) {
2008-03-05 09:52:00 -05:00
continue;
2008-11-17 18:29:00 -05:00
}
2008-03-05 09:52:00 -05:00
Tracing.Log(Tracing.Audit, "{0}:{1}", driver.pnpSignature, driver.name);
}
}
}
// DeviceNodes are the single mechanism for initializing device drivers.
// DeviceNodes will never be fully populated, but once certain fields are
// populated correctly, the DeviceNode can move into a new list, signifying
// that it has moved into a new state of execution
internal class DeviceNode
{
public readonly String! location; // location on a bus
// This is the hardware ID (PNP signature) that we actually matched when
// locating a device driver. This value is null if we have not associated
// a function driver.
public string MatchingDeviceId;
2008-11-17 18:29:00 -05:00
public string MatchingClassName;
2008-03-05 09:52:00 -05:00
public readonly IoConfig! config; // Io resource container
public Driver driver; // associated device driver
public ExtensionDevice extdev; // external device.
public IDevice intdev; // internal device.
public String directoryRoot; // in the /Hardware namespace
public int startOrder; // > zero when activated
public static int lastStartOrder;
public DeviceNode(String! location, String! matchingDeviceId, IoConfig! config)
{
this.location = location;
this.MatchingDeviceId = matchingDeviceId;
this.config = config;
this.startOrder = -1;
base();
}
public override string! ToString()
{
if (MatchingDeviceId != null) {
return "[Device: location='" + this.location + "' MatchingDeviceId='" + this.MatchingDeviceId + "']";
2008-11-17 18:29:00 -05:00
}
else {
2008-03-05 09:52:00 -05:00
return "[Device: location='" + this.location + " (not associated)]";
}
}
}
[CLSCompliant(false)]
public class IoSystem
{
//
// consts for accessing Xml tags and attributes
//
// tags describing the IoSystem config xml tree
public const string DriverRegistrationXmlTag = "driver";
public const string DriverNameXmlAttribute = "name";
public const string DeviceSignatureXmlAttribute = "signature";
public const string DriverPathXmlAttribute = "path";
public const string DriverClassXmlAttribute = "class";
// endpoint tags:
public const string EndpointSetXmlTag = "endpoints";
public const string ServiceEndpointXmlTag = "serviceProvider";
public const string ExtensionEndpointXmlTag = "extension";
public const string GenericEndpointXmlTag = "endpoint";
public const string ContractXmlAttribute = "contractName";
public const string EndpointEndXmlAttribute = "endpointEnd";
// Io resource tags
public const string FixedHardwareSetXmlTag = "fixedHardware";
public const string DynamicHardwareSetXmlTag = "dynamicHardware";
public const string PortRangeXmlTag = "ioPortRange";
public const string DmaRangeXmlTag = "ioDmaRange";
public const string IrqRangeXmlTag = "ioIrqRange";
public const string MemoryRangeXmlTag = "ioMemoryRange";
public const string AddressBitsXmlAttribute = "addressBits";
public const string AlignmentXmlAttribute = "alignment";
public const string BaseAddressXmlAttribute = "baseAddress";
public const string RangeLengthXmlAttribute = "rangeLength";
public const string ReadableXmlAttribute = "allowRead";
public const string WritableXmlAttribute = "allowWrite";
public const string SharedXmlAttribute = "shared";
public const string IndexXmlAttribute = "id";
// follows/provides tags
public const string FollowsXmlTag = "follows";
public const string ProvidesXmlTag = "provides";
public const string FollowsNameXmlAttribute = "name";
// xml config for the IoSystem
private static XmlNode! config;
// a device instance consists (full signature, Dynamic IoConfig,
// location) and is created only during device enumeration.
private static SortedList! instances;
// when a device instance is matched to a driver, we have an
// association. This is an activatable object, if its dependencies
// are met.
private static SortedList! associations;
// an instance that is successfully paired with a driver becomes
// an activatable entity. Upon activation, it moves into this list.
private static SortedList! activations;
// the entire "follows" tracking can be handled with one SortedList
private static SortedList! followsList;
// to speed up LoadImage we need to cache a ref to the directory service root
// this is initialized in InitializeDirectoryService and used in FindFileImage
// and FindManifest
2008-11-17 18:29:00 -05:00
//Is this needed? I don't see it used anywhere, and binder has its own
//private cached copy.
2008-03-05 09:52:00 -05:00
private static TRef<DirectoryServiceContract.Imp:Start> nsRootRef;
// In order to have unified accounting even for devices who do not have
// a Pnp signature (such as the hal console), we need a private,
// concrete IoConfig object
private class FixedIoConfig : IoConfig
{
public FixedIoConfig (string[] ids)
{
this.Ids = ids;
this.DynamicRanges = new IoRange[0];
this.FixedRanges = new IoRange[0];
}
public override string ToPrint()
{
return String.Join(",", this.Ids);
}
}
private static void StartProcess(string! name,
string! executable)
{
Process process = null;
Manifest manifest;
IoMemory memory = Binder.LoadImage(Thread.CurrentProcess,
executable,
out manifest);
if (memory != null && memory.Length > 0 && manifest != null) {
process = new Process(Thread.CurrentProcess,
memory,
null,
new string[1] {name},
manifest);
if (process != null) {
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine("I/O: Starting {0} process", __arglist(name));
2008-03-05 09:52:00 -05:00
process.Start();
}
}
else {
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("I/O: unable to find {0}", __arglist(executable));
2008-03-05 09:52:00 -05:00
}
}
// VolumeManager initialization should be managed just
// like drivers, but currently isn't
public static void InitializeVolumeManager()
{
2008-11-17 18:29:00 -05:00
StartProcess("volmgr", "volmgr");
2008-03-05 09:52:00 -05:00
}
// This configuration should move to DirectoryService.Initialize() and should
// involve xml
public static void InitializeDirectoryService()
{
// initialize IoMemory FileSystem
IoMemoryFS ioFS = new IoMemoryFS();
IoMemFSContract.Imp fsImp = ioFS.Start();
if (fsImp != null) {
Directory.DirectoryService.SetIoFS(fsImp);
}
2008-11-17 18:29:00 -05:00
2008-03-05 09:52:00 -05:00
// create "/dev" namespace and link it into the root
DirectoryServiceContract.Imp! rootNS = DirectoryService.NewClientEndpoint();
DirectoryServiceContract.Imp! dirImp;
DirectoryServiceContract.Exp! dirExp;
DirectoryServiceContract.NewChannel(out dirImp, out dirExp);
rootNS.SendBind((!)Bitter.FromString("/"), dirExp);
switch receive {
case rootNS.NakBind(rejected, error):
delete rejected;
DebugStub.Break();
break;
case rootNS.AckBind():
break;
}
dirImp.RecvSuccess();
dirImp.SendCreateDirectory((!)Bitter.FromString("dev"));
switch receive {
case dirImp.AckCreateDirectory() :
break;
case dirImp.NakCreateDirectory(error) :
2008-11-17 18:29:00 -05:00
if (error != ErrorCode.AlreadyExists) {
DebugStub.WriteLine("Error = {0}\n", __arglist(error));
DebugStub.Break();
}
2008-03-05 09:52:00 -05:00
break;
}
delete dirImp;
2008-11-17 18:29:00 -05:00
nsRootRef = new TRef<DirectoryServiceContract.Imp:Start> (rootNS);
2008-03-05 09:52:00 -05:00
}
2008-11-17 18:29:00 -05:00
///
//<summary>
// This method starts the Service Manager, which is a system process that manages
// service processes. The kernel searches for 'service' elements in the system
// (kernel) manifest, and forwards information about these services to the Service
// Manager process by building the argv list passed to the Service Manager's Main()
// entry point. The service entries are constructed during the build process, by
// a combination of DistroBuilder.exe and Targets\Distro.targets.
//</summary>
//
2008-03-05 09:52:00 -05:00
public static unsafe void InitializeServiceManager(XmlNode !config)
{
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("Initializing Service Manager...");
2008-03-05 09:52:00 -05:00
2008-11-17 18:29:00 -05:00
const string Name = "sms";
const string Executable = "sms";
2008-03-05 09:52:00 -05:00
ArrayList args = new ArrayList();
args.Add(Name);
if (config != null) {
foreach (XmlNode! service in config.Children) {
if (service.Name != "service") {
continue;
}
// Should be separated to avoid type ambiguity.
string name = service.GetAttribute("name", "");
string binary = service.GetAttribute("binary", "");
2008-11-17 18:29:00 -05:00
string activationMode = service.GetAttribute("activationMode", "");
if (name == null || name.Length == 0) {
DebugStub.WriteLine("Warning: System manifest contains a " +
" <service> node without a 'name' attribute.");
continue;
}
if (binary == null || binary.Length == 0) {
DebugStub.WriteLine("Warning: System manifest contains a <service>" +
" node (name={0}) without a 'binary' attribute.",
__arglist(name));
continue;
}
if (activationMode == null || activationMode.Length == 0) {
DebugStub.WriteLine(String.Format("Warning: System manifest contains" +
" a <service> node (name={0}) without" +
" an 'activationMode' attribute.", name));
continue;
}
2008-03-05 09:52:00 -05:00
args.Add(name);
args.Add(binary);
2008-11-17 18:29:00 -05:00
args.Add(activationMode);
2008-03-05 09:52:00 -05:00
}
}
else {
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("Warning: No services were defined in system manifest. " +
"Starting Service Manager anyway.");
2008-03-05 09:52:00 -05:00
}
String [] stringArgs = (string []) args.ToArray(typeof(string));
Process process = null;
Manifest manifest = null;
IoMemory memory = Binder.LoadImage(Thread.CurrentProcess,
Executable,
out manifest);
2008-11-17 18:29:00 -05:00
if (memory == null || memory.Length == 0) {
DebugStub.WriteLine("The Binder failed to load image '{0}' for the Service Manager.", __arglist(Executable));
return;
}
2008-03-05 09:52:00 -05:00
2008-11-17 18:29:00 -05:00
if (manifest == null) {
DebugStub.WriteLine("The Binder loaded the image '{0}', but could not load its manifest.", __arglist(Executable));
return;
}
2008-03-05 09:52:00 -05:00
2008-11-17 18:29:00 -05:00
DirectoryServiceContract.Imp! ds = DirectoryService.NewClientEndpoint();
if (ds == null) {
DebugStub.WriteLine("Failed to create new client endpoint to Directory service.");
DebugStub.WriteLine("The Service Manager cannot be started.");
return;
2008-03-05 09:52:00 -05:00
}
2008-11-17 18:29:00 -05:00
// Next, register the '/service/services' namespace provider with the Directory.
string! services_name = "/service/services";
// DebugStub.WriteLine("Registering '{0}' namespace", __arglist(services_name));
ServiceProviderContract.Imp! services_provider_imp;
ServiceProviderContract.Exp! services_provider_exp;
ServiceProviderContract.NewChannel(out services_provider_imp, out services_provider_exp);
char[]! in ExHeap exname = Bitter.FromString2(services_name);
ds.SendRegister(exname, services_provider_imp);
switch receive {
case ds.AckRegister():
break;
case ds.NakRegister(ServiceProviderContract.Imp:Start rejected_imp, ErrorCode error):
DebugStub.WriteLine("FAILED to register '{0}', error code = {1}.", __arglist(services_name, (int)error));
delete rejected_imp;
delete ds;
delete services_provider_exp;
return;
case ds.NakRegisterReparse(char[]! in ExHeap path, char[]! in ExHeap rest, bool linkFound,
ServiceProviderContract.Imp:Start! rejected_imp):
DebugStub.WriteLine("Encountered reparse point when attempting to register '{0}'?!", __arglist(services_name));
DebugStub.WriteLine("The Service Manager could not be started.");
delete path;
delete rest;
delete rejected_imp;
delete services_provider_exp;
delete ds;
return;
case ds.ChannelClosed():
DebugStub.WriteLine("Directory closed channel!");
DebugStub.WriteLine("The Service Manager could not be started.");
delete services_provider_exp;
delete ds;
return;
}
process = new Process(Thread.CurrentProcess,
memory,
null,
stringArgs,
manifest);
if (process == null) {
DebugStub.WriteLine("Failed to allocate process for Service Manager.");
delete ds;
delete services_provider_exp;
return;
2008-03-05 09:52:00 -05:00
}
2008-11-17 18:29:00 -05:00
process.SetEndpointCount(2);
SharedHeap.Allocation* ep0 = (SharedHeap.Allocation*)ds;
process.SetEndpoint(0, ref ep0);
SharedHeap.Allocation* ep1 = (SharedHeap.Allocation*)services_provider_exp;
process.SetEndpoint(1, ref ep1);
process.Start();
DebugStub.WriteLine("Successfully initialized Service Manager.");
2008-03-05 09:52:00 -05:00
}
2008-11-17 18:29:00 -05:00
2008-03-05 09:52:00 -05:00
// initialize all variables
static public void Initialize(XmlNode! _config)
{
Tracing.Log(Tracing.Debug, "IoSystem.Initialize()");
// store the xml config:
// don't store the nsConfig, since we don't use it locally
config = _config;
// create all lists
instances = new SortedList();
activations = new SortedList();
associations = new SortedList();
followsList = new SortedList();
// initialize the resource tracker.
ResourceTracker.Initialize();
Tracing.Log(Tracing.Debug, "IoSystem.Initialized");
}
public static void Finalize()
{
Tracing.Log(Tracing.Debug, "IoSystem.Finalize()");
FinalizeOldDevices();
}
public static byte GetMaximumIrq()
{
2008-11-17 18:29:00 -05:00
return Platform.GetMaximumIrq();
2008-03-05 09:52:00 -05:00
}
// all sorted tracking is handled here:
// check if a follows name has been provided yet
public static bool CheckFollows(string followName)
{
return followsList.ContainsKey(followName);
}
// mark a follows name as being provided
public static void SetFollows(string! followName)
{
if (!followsList.ContainsKey(followName)) {
followsList.Add(followName, followName);
}
}
2008-11-17 18:29:00 -05:00
2008-03-05 09:52:00 -05:00
////////////////////////////////////////////////////////////////////////
//
// Device Management Code: The kernel has 2 stages of device management.
//
// Stage 1: there are no interrupts, and the Hal isn't even started.
//
// In this stage, we use Drivers\register.cs to create a pnpbus,
// and then we pass it to a custom method in IoSystem which
// associates and activates the bus (the bus is not a process).
// Then we start the Hal, and we use another custom method to
// simulate association and activation of the hal devices (in this
// case, we don't actually activate, we just mark the devices as
// activated and give their resources to the Hal)
//
// Stage 2: we can run any process whose dependencies are satisfied.
//
// In this stage, we can start any driver, and so we use general
// mechanisms. We also pre-bind endpoints and generally do our
// best to make everything nice and clean. There is a hack in here
// to let us register the drivers who haven't migrated to separate
// processes.
// Parse the driverRegistry metadata to register drivers.
public static void RegisterDrivers()
{
2008-11-17 18:29:00 -05:00
ErrorCode error;
VerboseOut.WriteLine("IoSystem.RegisterDrivers executing\n");
2008-03-05 09:52:00 -05:00
foreach (XmlNode! driver in config.Children) {
if (driver.Name != DriverRegistrationXmlTag) {
continue;
}
string! drivername
= (!)driver.GetAttribute(DriverNameXmlAttribute, "");
string! image
= (!)driver.GetAttribute(DriverPathXmlAttribute, "");
string! signature
= (!)driver.GetAttribute(DeviceSignatureXmlAttribute, "");
2008-11-17 18:29:00 -05:00
string! mclass
= (!)driver.GetAttribute(DriverClassXmlAttribute, "");
if (image != "" &&
!image.EndsWith(DirectoryService.ExecutableExtension)) {
// A driver but not for our architecture.
continue;
}
2008-03-05 09:52:00 -05:00
// add the driver to /hardware/drivers
drivername = "/hardware/drivers/" + drivername;
2008-11-17 18:29:00 -05:00
DirNode! driverNode = (!)DirectoryService.FindDirectory(drivername, true);
2008-03-05 09:52:00 -05:00
// if this is an external driver, create a symlink for the
// executable image of the driver. Since this is at boot
// time, we know the image should go to /init
if (image != "") {
2008-11-17 18:29:00 -05:00
// we only work with DirectoryService.ExecutableExtension images for now:
if (image.EndsWith(DirectoryService.ExecutableExtension)) {
const int extensionLength = DirectoryService.ExecutableExtensionLength;
image = "/init/" + image.Remove(image.Length-extensionLength,
extensionLength);
DirectoryService.CreateSymbolicLink(driverNode, "image", image);
2008-03-05 09:52:00 -05:00
}
}
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("image = {0} drivername = {1}", __arglist(image, drivername));
// TODO: if there is no device signature, what
2008-03-05 09:52:00 -05:00
// should we do? We need some way to register the volume
// manager.
if (signature != "") {
if (image != "") {
2008-11-17 18:29:00 -05:00
Driver.Register(image, signature, mclass, drivername, image, driver);
2008-03-05 09:52:00 -05:00
}
// add the device to /hardware/registrations
string! registration_path;
2008-11-17 18:29:00 -05:00
if (signature.StartsWith("/")) {
2008-03-05 09:52:00 -05:00
registration_path = "/hardware/registrations" + signature;
2008-11-17 18:29:00 -05:00
} else {
2008-03-05 09:52:00 -05:00
registration_path = "/hardware/registrations/" + signature;
2008-11-17 18:29:00 -05:00
}
2008-03-05 09:52:00 -05:00
DirNode! deviceNode =
(!)DirectoryService.FindDirectory(registration_path, true);
// create a symlink to the driver
DirectoryService.CreateSymbolicLink(deviceNode, "driver",
2008-11-17 18:29:00 -05:00
drivername);
2008-03-05 09:52:00 -05:00
}
}
}
// There are a few devices that aren't processes but who don't start
// until after interrupts are up. Once all drivers become processes,
// this should go away.
// The key problem is that we haven't figured out, yet, how
// to move bus drivers out of the kernel.
public static bool RegisterKernelDriver(Type type,
IoDeviceCreate creator)
{
string iclass = ((!)type).FullName;
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine(" Registering class: {0}", __arglist(iclass));
2008-03-05 09:52:00 -05:00
// Find any signatures in the metadata for this class.
bool match = false;
foreach (XmlNode! driver in config.Children) {
if (driver.Name != DriverRegistrationXmlTag) {
continue;
}
string mclass = driver.GetAttribute(DriverClassXmlAttribute, "");
if (mclass != iclass) {
continue;
}
match = true;
string! signature = (!)driver.GetAttribute(DeviceSignatureXmlAttribute, "");
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine(" Registering signature: {0}", __arglist(signature));
2008-03-05 09:52:00 -05:00
string! drivername = "/hardware/drivers/" +
driver.GetAttribute(DriverNameXmlAttribute, "");
// Caution: we already added this to /hardware during the general
// registration process, but we need to give this node its name in
// /hardware
2008-11-17 18:29:00 -05:00
Driver.Register(signature, (!)mclass, drivername, type, (!)creator, driver);
2008-03-05 09:52:00 -05:00
}
if (!match) {
DebugStub.WriteLine("Error: No metadata for class {0}",
__arglist(iclass));
DebugStub.Break();
}
return match;
}
// given a piece of metadata, generate an IoRange array
// the input is the <fixedHardware> or <dynamicHardware> node of a
// registered device's metadata
private static IoRange[] CreateIoRangesFromMetadata(XmlNode resources)
{
if (resources == null) {
return new IoRange[0];
}
// see if there are any resources in the metadata
int numitems = resources.GetAttribute("length", 0);
// Create all of the fixed resources in one IoRange array
IoRange[] ranges = new IoRange[numitems];
int i = 0;
foreach (XmlNode! res in resources.Children) {
if (res.Name == PortRangeXmlTag) {
ushort fixedBase
= (ushort)res.GetAttribute(BaseAddressXmlAttribute, 0);
ushort fixedSize
= (ushort)res.GetAttribute(RangeLengthXmlAttribute, 0);
bool read = res.GetAttribute(ReadableXmlAttribute, true);
bool write = res.GetAttribute(WritableXmlAttribute, true);
ranges[i++] = new IoPortRange(fixedBase, fixedSize,
read, write);
}
else if (res.Name == IrqRangeXmlTag) {
byte fixedBase
= (byte)res.GetAttribute(BaseAddressXmlAttribute, 0);
byte fixedSize
= (byte)res.GetAttribute(RangeLengthXmlAttribute, 1);
ranges[i++] = new IoIrqRange(fixedBase, fixedSize);
}
else if (res.Name == DmaRangeXmlTag) {
byte fixedBase
= (byte)res.GetAttribute(BaseAddressXmlAttribute, 0);
byte fixedSize
= (byte)res.GetAttribute(RangeLengthXmlAttribute, 1);
ranges[i++] = new IoDmaRange(fixedBase, fixedSize);
}
else if (res.Name == MemoryRangeXmlTag) {
UIntPtr fixedBase
= res.GetAttributeAsUIntPtr(BaseAddressXmlAttribute, 0);
UIntPtr fixedSize
= res.GetAttributeAsUIntPtr(RangeLengthXmlAttribute, 0);
byte addressBits
= (byte)res.GetAttribute(AddressBitsXmlAttribute, 24);
UIntPtr alignment
= res.GetAttributeAsUIntPtr(AlignmentXmlAttribute, 4);
bool read = res.GetAttribute(ReadableXmlAttribute, true);
bool write = res.GetAttribute(WritableXmlAttribute, true);
if (fixedBase == 0) {
IoMemory mem = null;
2008-11-17 18:29:00 -05:00
// TODO: This only supports 24-bit addressing right
2008-03-05 09:52:00 -05:00
// now. We need support for the rest of the possible regions
// eventually
if (addressBits == 24) {
mem = IoMemory.AllocatePhysBelow16MB(fixedSize, alignment);
}
if (mem == null) {
DebugStub.WriteLine("Failed for addressBits={0}",
__arglist(addressBits));
DebugStub.Break();
continue;
}
DebugStub.Assert(mem.PhysicalAddress.Value != 0);
ranges[i++] = new IoMemoryRange((UIntPtr)mem.PhysicalAddress.Value,
(UIntPtr)mem.Length,
read, write);
}
else {
ranges[i++] = new IoMemoryRange(fixedBase, fixedSize,
read, write);
}
}
else {
// this should never happen
i++;
DebugStub.Break();
}
}
return ranges;
}
// The root device does not have a Pnp configuration via enumeration,
// which is why we require the devConfig parameter. Also, we need to
// enumerate the root before we can start the Hal, but we don't want to
// let anything else start running yet (since there is no threading yet)
public static void AddRootDevice(String! path,
IBusDevice! bus,
IoConfig! config)
{
String! signature = "/root" + path;
// Simulate association: we don't have a true registered driver.
XmlNode metadata = GetMetaData(signature);
if (metadata == null) {
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("No configuration found for root device {0}",
2008-03-05 09:52:00 -05:00
__arglist(path));
DebugStub.Break();
return;
}
if (!ResourceTracker.AreResourcesValid(config, metadata)) {
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("Invalid configuration for root device {0}",
2008-03-05 09:52:00 -05:00
__arglist(path));
DebugStub.Break();
return;
}
Driver! driver = Driver.Register(signature,
2008-11-17 18:29:00 -05:00
(!)bus.GetType().FullName,
2008-03-05 09:52:00 -05:00
path,
bus.GetType(),
metadata);
// create a device instance of the root:
DeviceNode! device = new DeviceNode(path, signature, config);
// Simulate activation: we don't need to make an
// IDevice because we already have one
device.driver = driver;
device.intdev = bus;
// make sure the resources are available, and claim them.
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine("AddRootDevice Device: {0}", __arglist(path));
2008-03-05 09:52:00 -05:00
if (ResourceTracker.FindResourceConflicts(device) == null) {
ResourceTracker.AddResources(device);
}
else {
// somehow the needed root resources are unavailable.
DebugStub.Break();
return;
}
// Manually initialize the root bus, but don't
// associate devices we find
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine("Activate root device {0} {1}",
__arglist(device.location, device.driver.name));
2008-03-05 09:52:00 -05:00
bus.Initialize();
EnumerateDevice(bus, device.location, false);
}
static DeviceNode FindSingletonDeviceBySignature(string! signature)
{
DeviceNode device;
if (signature == "") {
string[]! ids = { "" };
FixedIoConfig! config = new FixedIoConfig(ids);
device = new DeviceNode("/hal0", signature, config);
return device;
2008-11-17 18:29:00 -05:00
}
else {
2008-03-05 09:52:00 -05:00
device = null;
foreach (DictionaryEntry de in instances) {
DeviceNode! node = (DeviceNode!) de.Value;
foreach (string sig in node.config.Ids) {
if (sig == signature) {
if (device != null) {
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("WARNING! Found more than one device with signature '{0}' for singleton device!", __arglist(signature));
DebugStub.WriteLine(" Ignoring device {0}", __arglist(node.config.ToString()));
2008-03-05 09:52:00 -05:00
continue;
}
device = node;
// break;
}
}
// Keep looping so we can find duplicates.
// This is just for debugging / paranoia.
//if (device != null)
// break;
}
return device;
}
}
bool PnpSignaturesAreEqual(string! sig1, string! sig2)
{
return String.Compare(sig1, sig2, true) == 0;
}
// The Hal activates its own devices, but we need to do the accounting
// for them and move them from instances to activations.
// NB - for the hal screen resources, the signature will be ""
public static IoConfig YieldResources(string! signature, Type! type)
{
// do pseudo-registration by getting metadata directly
XmlNode metadata = GetMetaData(signature);
if (metadata == null) {
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("IoSystem.YieldResources: Failed to find driver metadata for signature: {0}", __arglist(signature));
2008-03-05 09:52:00 -05:00
DebugStub.Break(); // Couldn't find info in manifest!
return null;
}
string path = (signature == "") ? "/hal0" : ("/hardware/drivers" + signature);
Driver! driver = Driver.Register(signature,
2008-11-17 18:29:00 -05:00
(!)type.FullName,
2008-03-05 09:52:00 -05:00
path,
type,
metadata);
// first get a device instance (or if signature=="", create an
// instance with an empty IoConfig)
DeviceNode device = FindSingletonDeviceBySignature(signature);
if (device == null) {
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("IoSystem.YieldResources: Failed to find singleton device node for PNP signature: {0}", __arglist(signature));
2008-03-05 09:52:00 -05:00
DebugStub.Break();
for (;;) {
FindSingletonDeviceBySignature(signature);
}
return null; // Couldn't find hardware.
}
device.driver = driver;
// use the XML to get fixed resources
XmlNode fixedResNode
= driver.metadata.GetChild(FixedHardwareSetXmlTag);
device.config.FixedRanges
= CreateIoRangesFromMetadata(fixedResNode);
// This device is now associated. Now do all of the
// accounting, but don't activate it
VerboseOut.WriteLine("YieldResources Signature: {0}",
__arglist(signature));
if (ResourceTracker.AreResourcesValid(device.config, metadata) &&
ResourceTracker.FindResourceConflicts(device) == null) {
ResourceTracker.AddResources(device);
}
else {
// somehow the resources the Hal needs have already been taken!
DebugStub.Break();
return null;
}
// now move the device from instances to activations and return the
// dynamic config
VerboseOut.WriteLine("YieldResources Remove({0})",
__arglist(device.location));
instances.Remove(device.location);
activations.Add(device.location, device);
return device.config;
}
//
// Irq Rerouting code - this lets us keep our accounting clean when
// kernel-only devices reroute IRQs
//
2008-11-17 18:29:00 -05:00
// TODO: if multiple devices exist, all of whom have the same
2008-03-05 09:52:00 -05:00
// Id, this is going to break. How can we fix it? The caller doesn't
// understand hardware locations, so the problem is his, but this code
// suffers from his lack of information
// Public hook for well-behaved devices that reroute IRQs to request
// permission before doing the rerouting. This has the side effect of
// updating the ResourceTracker with the new IoIrqRange values
public static bool RequestRerouteIrq(string name, int irqNum,
byte irqVal)
{
// In order to allow a rerouting, two conditions must be met
// 1 - the device "name" must not be in activations
// 2 - there must be an irqNum'th IoIrq object
foreach (DictionaryEntry de in instances) {
DeviceNode! device = (DeviceNode!) de.Value;
if (device.MatchingDeviceId == name) {
return RerouteIrq(device, irqNum, irqVal);
}
}
foreach (DictionaryEntry de in associations) {
DeviceNode! device = (DeviceNode!) de.Value;
if (device.MatchingDeviceId == name) {
return RerouteIrq(device, irqNum, irqVal);
}
}
return false;
}
// private code that actually changes the IoConfig object
private static bool RerouteIrq(DeviceNode! device, int irqNum,
byte irqVal)
{
int irqCounter = 0;
int targetPosition = -1;
2008-11-17 18:29:00 -05:00
IoRange[]! ranges = device.config.DynamicRanges;
2008-03-05 09:52:00 -05:00
for (int i = 0; i < ranges.Length; i++) {
if (device.config.DynamicRanges[i] is IoIrqRange) {
irqCounter++;
}
if (irqCounter == irqNum) {
targetPosition = i;
break;
}
}
if (targetPosition == -1) {
return false;
}
ranges[targetPosition] = new IoIrqRange(irqVal, 1);
return true;
}
// Enumerate an IBusDevice (create instances):
// - Find devices and add them to the devices list
2008-11-17 18:29:00 -05:00
public static bool EnumerateDevice(IBusDevice! bus, string busLocation, bool associate)
{
Tracing.Log(Tracing.Debug, "Enumerating Bus");
return AddDevicesToTree(bus.Enumerate(), busLocation, associate);
}
// Add a sorted list of devices to the device tree:
2008-03-05 09:52:00 -05:00
// - Add each device to the /hardware namespace
//
// NB: When we get rid of non-process drivers, then this will only be
// used by the root device; all other buses will be separate processes
// who will announce new config to the IoSystem over a channel
2008-11-17 18:29:00 -05:00
public static bool AddDevicesToTree(SortedList found, string busLocation, bool associate)
2008-03-05 09:52:00 -05:00
{
if (found != null) {
foreach (DictionaryEntry n in found) {
// get the IoConfig for this device
IoConfig! config = (IoConfig!)n.Value;
// set the IoConfig's FixedRange to an empty list
config.FixedRanges = new IoRange[0];
assume config.Ids != null;
// now set up the /hardware namespace
string! location = busLocation + n.Key;
string! device = (!)config.Ids[0];
// -XXX- Need to do something smarter, now that we support lists of IDs.
// create a DeviceNode for this device
DeviceNode! node = new DeviceNode(location, device, config);
2008-11-17 18:29:00 -05:00
string! instname;
2008-03-05 09:52:00 -05:00
2008-11-17 18:29:00 -05:00
//so we need the device namespace but we have no DirectoryService....
// add this location and device to the /hardware tree
location = JoinForwardSlashPath("/hardware/locations", location);
DirNode locationNode = DirectoryService.FindDirectory(location, true);
// This needs to be reconsidered. What's the point of registering the
// device ID, now that doing so is ambiguous? We'll register the first
// device ID, anyway, until we figure this out.
string! path = JoinForwardSlashPath("/hardware/devices", device);
DirNode deviceNode = DirectoryService.FindDirectory(path, true);
2008-03-05 09:52:00 -05:00
2008-11-17 18:29:00 -05:00
// create a device instance in the namespace:
for (int i = 0;; i++) { // find next available instance num
instname = path + "/instance" + i.ToString();
if (DirectoryService.FindDirectory(instname, false) == null) {
break;
}
}
deviceNode = DirectoryService.FindDirectory(instname, true);
// symlink the instance and location
DirectoryService.CreateSymbolicLink(locationNode, "device", instname);
DirectoryService.CreateSymbolicLink(deviceNode, "location", location);
2008-03-05 09:52:00 -05:00
node.directoryRoot = instname;
// try to associate the instance, and if we can't, then put
// it in the instance list:
if (!associate || !Associate(node)) {
instances.Add(node.location, node);
}
}
2008-11-17 18:29:00 -05:00
return true;
2008-03-05 09:52:00 -05:00
}
2008-11-17 18:29:00 -05:00
return false;
2008-03-05 09:52:00 -05:00
}
static string! JoinForwardSlashPath(string! container, string! path)
{
bool container_ends_with_slash = container.EndsWith("/");
bool path_starts_with_slash = path.StartsWith("/");
if (container_ends_with_slash && path_starts_with_slash)
return container + path.Substring(1, path.Length - 1);
if (!container_ends_with_slash && !path_starts_with_slash)
return container + "/" + path;
return container + path;
}
// the association step does not care about dependencies and does not
// touch the namespace. All it does is resolve an instance of a device
// with the appropriate registration of a driver for that device, and
// creates the fixed Io resources:
private static bool Associate(DeviceNode! device)
{
string! matchingDeviceId;
Driver driver = Driver.FindBest(device.config.Ids, out matchingDeviceId);
if (driver == null) {
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine("{0}: no driver found for this device. Configuration information:",
2008-03-05 09:52:00 -05:00
__arglist(device.location));
2008-11-17 18:29:00 -05:00
VerboseOut.Write(device.config.ToPrint() + "\n \n\n");
2008-03-05 09:52:00 -05:00
return false;
}
2008-11-17 18:29:00 -05:00
#if TYAN_MOTHERBOARD_HACK
else if (device.location == "/acpi0/123/bus0000/dev0005/func0000" ||
device.location == "/acpi0/123/bus0000/dev0005/func0000/controller0" ||
device.location == "/acpi0/123/bus0000/dev0005/func0000/controller1" ||
device.location == "/acpi0/123/bus0000/dev0005/func0001" ||
device.location == "/acpi0/123/bus0000/dev0005/func0001/controller0" ||
device.location == "/acpi0/123/bus0000/dev0005/func0001/controller1" ||
device.location == "/acpi0/123/bus0000/dev0005/func0002" ||
device.location == "/acpi0/123/bus0000/dev0005/func0002/controller0" ||
device.location == "/acpi0/123/bus0000/dev0005/func0002/controller1") {
//This is a hack to handle machines with more than one storage controller.
VerboseOut.Write("Ignoring secondary device {0} \n", __arglist(device.location));
VerboseOut.Write(device.config.ToPrint() + "\n \n\n");
return false;
}
else if (device.location == "/acpi0/101/bus0000/dev0005/func0000/controller1" ||
device.location == "/acpi0/101/bus0000/dev0004/func0000" ||
device.location == "/acpi0/101/bus0000/dev0004/func0000/controller0" ||
device.location == "/acpi0/101/bus0000/dev0004/func0000/controller1" ||
device.location == "/acpi0/101/bus0000/dev0005/func0000/controller1" ||
device.location == "/acpi0/101/bus0000/dev0005/func0001" ||
device.location == "/acpi0/101/bus0000/dev0005/func0001/controller0" ||
device.location == "/acpi0/101/bus0000/dev0005/func0001/controller1" ||
device.location == "/acpi0/101/bus0000/dev0005/func0002" ||
device.location == "/acpi0/101/bus0000/dev0005/func0002/controller0" ||
device.location == "/acpi0/101/bus0000/dev0005/func0002/controller1") {
//This is a hack to handle machines with more than one storage controller.
VerboseOut.Write("Ignoring secondary device {0} \n", __arglist(device.location));
VerboseOut.Write(device.config.ToPrint() + "\n \n\n");
return false;
}
else if (device.location == "/acpi0/123/bus0000/dev0004/func0000" ||
device.location == "/acpi0/123/bus0000/dev0004/func0000/controller0" ||
device.location == "/acpi0/123/bus0000/dev0004/func0000/controller1" ||
device.location == "/acpi0/123/bus0001/dev0004/func0000" ||
device.location == "/acpi0/123/bus0004/dev0009/func0000") {
//This is a hack to handle machines with more than one storage controller.
VerboseOut.Write("Ignoring secondary device {0} \n", __arglist(device.location));
VerboseOut.Write(device.config.ToPrint() + "\n \n\n");
return false;
}
#endif
2008-03-05 09:52:00 -05:00
if (driver.factory == null && driver.imagePath == null) {
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("Warning: Attempt to associate HAL driver {0} with {1} ",
2008-03-05 09:52:00 -05:00
__arglist(driver.name,
device.location));
2008-11-17 18:29:00 -05:00
//DebugStub.Break();
2008-03-05 09:52:00 -05:00
return false;
}
VerboseOut.WriteLine(
2008-11-17 18:29:00 -05:00
"{0}: now associated with driver {1}, on device id {2}. Configuration information:",
2008-03-05 09:52:00 -05:00
__arglist(device.location, driver.name, matchingDeviceId)
);
2008-11-17 18:29:00 -05:00
VerboseOut.Write(device.config.ToPrint());
2008-03-05 09:52:00 -05:00
// now attached the driver.
device.driver = driver;
device.MatchingDeviceId = matchingDeviceId;
// create the fixed config.
XmlNode fixedResNode
= driver.metadata.GetChild(FixedHardwareSetXmlTag);
device.config.FixedRanges
= CreateIoRangesFromMetadata(fixedResNode);
// if the hardware resources are available, copy the device to associations
if (!ResourceTracker.AreResourcesValid(device.config, driver.metadata)) {
DebugStub.WriteLine("Error: Can't associate a device without resources.");
DebugStub.Break();
return false;
}
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine("{0}: Device associated -> driver {1} using signature {2}",
__arglist(device.location, driver.name, matchingDeviceId));
2008-03-05 09:52:00 -05:00
associations.Add(device.location, device);
return true;
}
// The root bus and hal need to be associated before the registration
// list is ready. Use this method to associate directly from Xml.
private static XmlNode GetMetaData(String! pnpSignature)
{
// a matched driver must not have an image (that is, it shouldn't be
// an external driver). Otherwise, anything that matches is good:
int bestlength = 0;
XmlNode bestNode = null;
// check each driver
foreach (XmlNode! driver in config.Children) {
if (driver.Name != DriverRegistrationXmlTag) {
continue;
}
string! devicename =
(!)driver.GetAttribute(DeviceSignatureXmlAttribute, "");
string! image =
(!)driver.GetAttribute(DriverPathXmlAttribute, "");
if (image == "" &&
pnpSignature.StartsWith(devicename) &&
devicename.Length > bestlength) {
bestNode = driver;
bestlength = devicename.Length;
}
// special code for the Hal console, which has no signature
2008-11-17 18:29:00 -05:00
// Note: This causes a console initialization failure if any driver is registered
// without a signature
2008-03-05 09:52:00 -05:00
else if (image == "" &&
pnpSignature == "" &&
devicename == "" &&
bestlength == 0) {
bestNode = driver;
bestlength = 1;
}
}
return bestNode;
}
// check if we can start a driver
// RequireFollows--> treat "follows" tags as firm requirements
private static bool CheckDependencies(Driver! driver,
bool RequireFollows)
{
// Check all <follows> rules
if (RequireFollows) {
foreach (XmlNode! follows in driver.metadata.Children) {
if (follows.Name != FollowsXmlTag) {
continue;
}
string tagName =
follows.GetAttribute(FollowsNameXmlAttribute, "");
if (!CheckFollows(tagName)) {
return false;
}
}
}
// Make sure that ServiceProvider endpoint names aren't exhausted,
// and that the ServiceContracts are satisfiable
XmlNode! endpointset
= (!)driver.metadata.GetChild(EndpointSetXmlTag);
foreach (XmlNode! endpoint in endpointset.Children) {
string contract = endpoint.GetAttribute(
ContractXmlAttribute, "");
if (endpoint.Name == ServiceEndpointXmlTag) {
if (!Binder.IsServiceContractStartable(contract)) {
return false;
}
}
else if (endpoint.Name == GenericEndpointXmlTag) {
if (!Binder.IsServiceContractAvailable(contract)) {
return false;
}
}
}
return true;
}
// Return the next device that should be activated, according to the
// following priority:
// 1 - if all dependencies of an bus device are satisfied, return it
// 2 - else return the first device with all dependencies satisfied
// 3 - else return the first bus device who only lacks "follows"
// 4 - else return the first device who only lacks "follows"
// 5 - else return null
private static DeviceNode GetActivatableDriver()
{
DeviceNode device = null;
DeviceNode busWithoutFollows = null;
DeviceNode deviceWithoutFollows = null;
2008-11-17 18:29:00 -05:00
VerboseOut.Write("GetActivatableDriver:[");
2008-03-05 09:52:00 -05:00
foreach (DictionaryEntry de in associations) {
DeviceNode! dev = (DeviceNode!)de.Value;
2008-11-17 18:29:00 -05:00
VerboseOut.Write(dev.ToString());
VerboseOut.Write(" ");
2008-03-05 09:52:00 -05:00
}
2008-11-17 18:29:00 -05:00
VerboseOut.WriteLine("] ");
2008-03-05 09:52:00 -05:00
// we need only look in the associations list, as it holds the only
// device instances that are matched to drivers:
foreach (DictionaryEntry de in associations) {
DeviceNode! dev = (DeviceNode!) de.Value;
// device has already been associated
assert dev.driver != null;
assert dev.MatchingDeviceId != null;
Driver! driver = dev.driver;
// First do the hard test - all <follows> must be satisfied
if (CheckDependencies(driver, true)) {
// prioritize buses - if we find one, return it immediately
if (dev.intdev is IBusDevice) {
VerboseOut.WriteLine("-> {0} [bus]",
__arglist(dev.MatchingDeviceId));
return dev;
}
else {
if (device == null) {
device = dev;
}
}
}
// then try without the <follows>
else if (CheckDependencies(driver, false)) {
if (dev.intdev is IBusDevice) {
if (busWithoutFollows == null) {
busWithoutFollows = dev;
}
}
else {
if (deviceWithoutFollows == null) {
deviceWithoutFollows = dev;
}
}
}
}
if (device != null) {
VerboseOut.WriteLine("-> {0}",
__arglist(device.MatchingDeviceId));
return device;
}
else if (busWithoutFollows != null) {
VerboseOut.WriteLine(
"-> {0} [bus w/o]",
__arglist(busWithoutFollows.MatchingDeviceId)
);
return busWithoutFollows;
}
else {
if (deviceWithoutFollows == null) {
VerboseOut.WriteLine("-> null");
}
else {
VerboseOut.WriteLine(
"-> {0} [w/o]",
__arglist(deviceWithoutFollows.MatchingDeviceId)
);
}
return deviceWithoutFollows; // may be null, but that's ok...
}
}
2008-11-17 18:29:00 -05:00
// TODO: non-device services (i.e. volmgr) should start
2008-03-05 09:52:00 -05:00
// through this mechanism, but don't yet
// Activate any drivers whose needs can be fully satisfied:
public static void ActivateDrivers()
{
2008-11-17 18:29:00 -05:00
2008-03-05 09:52:00 -05:00
// since enumeration now associates whatever it can, we can pull
// the association step out of the loop.
foreach (DictionaryEntry d in instances) {
Associate((DeviceNode!) d.Value);
}
// we can't remove items from the instances list during the previous
// step, so we need a second loop to remove instances that have been
// associated:
foreach (DictionaryEntry d in associations) {
String key = (String) d.Key;
if (instances.ContainsKey(key)) {
instances.Remove(key);
}
}
2008-11-17 18:29:00 -05:00
// TODO: once VolMgr is started through this method,
2008-03-05 09:52:00 -05:00
// remove the following line (we need it in order for the DiskDrive
// to run, as it depends on having a volmgr):
Binder.ClaimServiceContract(
"Microsoft.Singularity.Io.VolumeManagerContract");
// now activate devices whose dependencies are satisfied:
for (DeviceNode device; (device = GetActivatableDriver()) != null;) {
// first, check that the device's resources are valid.
Driver! driver = device.driver;
2008-11-17 18:29:00 -05:00
DebugStub.Print("Looping to activate new driver device {0} {1}\n",
__arglist(device.location, device.driver.name));
2008-03-05 09:52:00 -05:00
// Do the accounting for all Io Resources
if (ResourceTracker.AreResourcesValid(device.config, driver.metadata) &&
ResourceTracker.FindResourceConflicts(device) == null) {
ResourceTracker.AddResources(device);
}
else {
// somehow the resources the device needs are unavailable
DebugStub.Break();
2008-11-17 18:29:00 -05:00
DebugStub.Break();
2008-03-05 09:52:00 -05:00
continue;
}
// Next activate it by factory if needed.
bool activated = false;
if (driver.factory != null) {
device.intdev = driver.factory(device.config, device.location);
// initialize the device, conditional on whether it is a bus or not.
// If it is a bus, be sure to enumerate it.
if (device.intdev is IBusDevice) {
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine(
2008-03-05 09:52:00 -05:00
"Activate Device {0} {1} [w/ Enumerate]",
__arglist(device.location, device.driver.name)
);
IBusDevice bus = (IBusDevice)device.intdev;
bus.Initialize();
activated = true;
EnumerateDevice(bus, device.location, true);
}
else if (device.intdev is IDevice) {
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("Activate Device {0} {1}",
2008-03-05 09:52:00 -05:00
__arglist(device.location,
device.driver.name));
device.intdev.Initialize();
activated = true;
}
}
else if (driver.imagePath != null) {
device.extdev = new ExtensionDevice(driver, device);
activated = device.extdev.Activate();
}
else {
DebugStub.WriteLine("Driver appears to be incorrectly initialized.");
DebugStub.Break();
}
if (activated) {
// mark the device as loaded
device.startOrder = ++DeviceNode.lastStartOrder;
activations.Add(device.location, device);
associations.Remove(device.location);
// update the follows listing:
foreach (XmlNode! follows in driver.metadata.Children) {
if (follows.Name != ProvidesXmlTag) {
continue;
}
string tagName =
(!)follows.GetAttribute(FollowsNameXmlAttribute, "");
SetFollows(tagName);
}
}
else {
DebugStub.WriteLine("Driver failed to activate.");
DebugStub.Break();
}
}
}
// Finalize only deals with drivers that have been activated
private static void FinalizeOldDevices()
{
bool removed;
// Disable all of the devices in the order initialized.
do {
removed = false;
int highest = 0;
string highestDevice = null;
foreach (DictionaryEntry d in activations) {
DeviceNode! dev = (DeviceNode!)d.Value;
if (highest < dev.startOrder) {
highest = dev.startOrder;
highestDevice = (string)d.Key;
}
}
if (highest != 0 && highestDevice != null) {
DeviceNode! dev = (DeviceNode!)activations[highestDevice];
Tracing.Log(Tracing.Audit, "Finalizing {0}\n", dev.location);
if (dev.intdev != null) {
dev.intdev.Finalize();
}
else if (dev.extdev != null) {
dev.extdev.Finalize();
}
activations.Remove(highestDevice);
removed = true;
}
} while (removed);
}
// Print device config to debug console and to the log
public static void Dump(bool detailed)
{
Driver.DumpAll();
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("Devices found but not associated:");
2008-03-05 09:52:00 -05:00
Tracing.Log(Tracing.Audit, "Devices found but not associated:");
foreach (DictionaryEntry de in instances) {
DeviceNode! dev = (DeviceNode!)de.Value;
DumpDeviceNode(dev, detailed);
}
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("Devices associated but not initialized:");
Tracing.Log(Tracing.Audit, "Devices associated but not initialized:");
2008-03-05 09:52:00 -05:00
foreach (DictionaryEntry de in associations) {
DeviceNode! dev = (DeviceNode!)de.Value;
DumpDeviceNode(dev, detailed);
}
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("Devices initialized:");
2008-03-05 09:52:00 -05:00
Tracing.Log(Tracing.Audit, "Devices initialized:");
foreach (DictionaryEntry de in activations) {
DeviceNode! dev = (DeviceNode!)de.Value;
if ((dev.intdev != null || dev.extdev != null) && dev.startOrder != 0) {
DumpDeviceNode(dev, detailed);
}
}
}
static void DumpDeviceNode(DeviceNode! device, bool detailed)
{
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine(" {0}:", __arglist(device.location));
Tracing.Log(Tracing.Audit, " device at " + device.location);
2008-03-05 09:52:00 -05:00
if (device.driver != null) {
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine(" driver: {0}", __arglist(device.driver.name));
Tracing.Log(Tracing.Audit, " driver: " + device.driver.name);
2008-03-05 09:52:00 -05:00
}
if (device.MatchingDeviceId != null) {
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine(" dev-id: {0}", __arglist(device.MatchingDeviceId));
Tracing.Log(Tracing.Audit, " dev-id: " + device.MatchingDeviceId);
2008-03-05 09:52:00 -05:00
}
if (detailed) {
if (device.config != null) {
DebugStub.WriteLine(device.config.ToPrint());
}
}
DebugStub.WriteLine("");
}
}
} // namespace Microsoft.Singularity.Io