484 lines
17 KiB
C#
484 lines
17 KiB
C#
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// Microsoft Research Singularity
|
|
//
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Diagnostics;
|
|
using System.Text;
|
|
|
|
namespace Microsoft.Singularity.Hal.Acpi
|
|
{
|
|
public class AcpiNamespace
|
|
{
|
|
/// <summary>
|
|
/// The absolute or relative location of a node in the ACPI namespace.
|
|
/// </summary>
|
|
public class NodePath
|
|
{
|
|
bool isAbsolute;
|
|
int numParentPrefixes;
|
|
string[] nameSegments;
|
|
|
|
public NodePath(bool isAbsolute, int numParentPrefixes, string[] nameSegments)
|
|
{
|
|
Debug.Assert(numParentPrefixes >= 0, "numParentPrefixes >= 0");
|
|
Debug.Assert(!isAbsolute || numParentPrefixes == 0,
|
|
"Absolute path cannot have parent prefixes");
|
|
Debug.Assert(nameSegments.Length >= 0);
|
|
|
|
foreach (string name in nameSegments) {
|
|
AssertIsValidName(name);
|
|
}
|
|
|
|
this.isAbsolute = isAbsolute;
|
|
this.numParentPrefixes = numParentPrefixes;
|
|
this.nameSegments = nameSegments;
|
|
}
|
|
|
|
public bool IsAbsolute
|
|
{
|
|
get
|
|
{
|
|
return isAbsolute;
|
|
}
|
|
}
|
|
|
|
public int NumParentPrefixes
|
|
{
|
|
get
|
|
{
|
|
return numParentPrefixes;
|
|
}
|
|
}
|
|
|
|
public string[] NameSegments
|
|
{
|
|
get
|
|
{
|
|
return nameSegments;
|
|
}
|
|
}
|
|
|
|
public NodePath AddSegment(string segment)
|
|
{
|
|
string[] resultNameSegments = new string[this.nameSegments.Length + 1];
|
|
for (int i = 0; i < this.nameSegments.Length; i++) {
|
|
resultNameSegments[i] = (string)this.nameSegments[i];
|
|
}
|
|
resultNameSegments[resultNameSegments.Length - 1] = segment;
|
|
return new NodePath(IsAbsolute, NumParentPrefixes, resultNameSegments);
|
|
}
|
|
|
|
public NodePath RemoveSegment()
|
|
{
|
|
string[] resultNameSegments = new string[this.nameSegments.Length - 1];
|
|
for (int i = 0; i < this.nameSegments.Length - 1; i++) {
|
|
resultNameSegments[i] = (string)this.nameSegments[i];
|
|
}
|
|
return new NodePath(IsAbsolute, NumParentPrefixes, resultNameSegments);
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
StringBuilder builder = new StringBuilder();
|
|
for (int i = 0; i < nameSegments.Length - 1; i++) {
|
|
builder.Append(nameSegments[i]);
|
|
builder.Append("\\");
|
|
}
|
|
if (nameSegments.Length > 0) {
|
|
builder.Append(nameSegments[nameSegments.Length - 1]);
|
|
}
|
|
return builder.ToString();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A restricted type of NodePath that must be statically absolute.
|
|
/// </summary>
|
|
/// <remarks>Not every absolute path has this type - some are AbsoluteNodePaths
|
|
/// and some are NodePaths. The purpose of this subclass is to statically enforce
|
|
/// that absolute paths are always used in certain limited contexts.</remarks>
|
|
public class AbsoluteNodePath : NodePath
|
|
{
|
|
public AbsoluteNodePath(string[] nameSegments)
|
|
: base(false, 0, nameSegments) { }
|
|
|
|
public static AbsoluteNodePath CreateRoot()
|
|
{
|
|
return new AbsoluteNodePath(new string[] { });
|
|
}
|
|
|
|
public AbsoluteNodePath AddSegmentAbsolute(string segment)
|
|
{
|
|
return new AbsoluteNodePath(AddSegment(segment).NameSegments);
|
|
}
|
|
|
|
public AbsoluteNodePath RemoveSegmentAbsolute()
|
|
{
|
|
return new AbsoluteNodePath(RemoveSegment().NameSegments);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A node in the ACPI namespace tree.
|
|
/// </summary>
|
|
public class Node
|
|
{
|
|
private string name;
|
|
private Node parentNode;
|
|
private IDictionary childByNameMap = null;
|
|
private AcpiObject.AcpiObjectCell value;
|
|
|
|
/// <summary>
|
|
/// Create a root node.
|
|
/// </summary>
|
|
public Node()
|
|
{
|
|
this.name = "";
|
|
this.parentNode = null;
|
|
this.value = new AcpiObject.AcpiObjectCell(new AcpiObject.UninitializedObject());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a child node with a given name and parent node.
|
|
/// </summary>
|
|
public Node(string name, Node parentNode)
|
|
{
|
|
AssertIsValidName(name);
|
|
Debug.Assert(parentNode != null);
|
|
this.name = name;
|
|
this.parentNode = parentNode;
|
|
this.value = new AcpiObject.AcpiObjectCell(new AcpiObject.UninitializedObject());
|
|
parentNode.AddChild(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes this node refer to the same value as the given node.
|
|
/// </summary>
|
|
/// <remarks>Aliased names refer to not only the same object but
|
|
/// the same object location (cell). Any updates to either node
|
|
/// immediately appear in the other.</remarks>
|
|
public void AliasTo(Node n)
|
|
{
|
|
this.value = n.value;
|
|
}
|
|
|
|
private void AddChild(Node child)
|
|
{
|
|
Debug.Assert(child.parentNode == this);
|
|
if (childByNameMap == null) {
|
|
childByNameMap = new SortedList();
|
|
}
|
|
Debug.Assert(!childByNameMap.Contains(child.name));
|
|
childByNameMap.Add(child.name, child);
|
|
}
|
|
|
|
public Node ParentNode
|
|
{
|
|
get
|
|
{
|
|
return parentNode;
|
|
}
|
|
}
|
|
|
|
public string Name
|
|
{
|
|
get
|
|
{
|
|
return name;
|
|
}
|
|
}
|
|
|
|
public Node GetChildByName(string name)
|
|
{
|
|
if (childByNameMap != null && childByNameMap.Contains(name)) {
|
|
return (Node)childByNameMap[name];
|
|
}
|
|
else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public AcpiObject.AcpiObject Value
|
|
{
|
|
get
|
|
{
|
|
return value.Value;
|
|
}
|
|
set
|
|
{
|
|
this.value.Value = value;
|
|
}
|
|
}
|
|
|
|
public void Remove()
|
|
{
|
|
if (childByNameMap != null) {
|
|
foreach (Node child in childByNameMap.Values) {
|
|
child.Remove();
|
|
}
|
|
}
|
|
if (this.parentNode != null) {
|
|
this.parentNode.childByNameMap.Remove(name);
|
|
}
|
|
}
|
|
|
|
public AbsoluteNodePath Path
|
|
{
|
|
get
|
|
{
|
|
// Measure how deep this node's path is
|
|
int level = 0;
|
|
Node n = parentNode;
|
|
while (n != null) {
|
|
level++;
|
|
n = n.parentNode;
|
|
}
|
|
|
|
// Build the path
|
|
string[] nameSegments = new string[level];
|
|
n = this;
|
|
for(int i = nameSegments.Length - 1; i >= 0; i--) {
|
|
nameSegments[i] = n.name;
|
|
n = n.parentNode;
|
|
}
|
|
|
|
return new AbsoluteNodePath(nameSegments);
|
|
}
|
|
}
|
|
|
|
public int CountSubtreeNodes()
|
|
{
|
|
int count = 1;
|
|
if (childByNameMap != null) {
|
|
foreach (Node child in childByNameMap.Values) {
|
|
count += child.CountSubtreeNodes();
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
public void GetSubtreeNodes(Node[] result, ref int startIndex)
|
|
{
|
|
result[startIndex] = this;
|
|
startIndex++;
|
|
|
|
if (childByNameMap != null) {
|
|
foreach (Node child in childByNameMap.Values) {
|
|
child.GetSubtreeNodes(result, ref startIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
public Node FindValue(AcpiObject.AcpiObject value)
|
|
{
|
|
if (this.Value == value) {
|
|
return this;
|
|
}
|
|
else if (childByNameMap != null) {
|
|
foreach (Node child in childByNameMap.Values) {
|
|
Node result = child.FindValue(value);
|
|
if (result != null) {
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return Path.ToString();
|
|
}
|
|
|
|
public void DumpSubtree()
|
|
{
|
|
#if SINGULARITY_KERNEL
|
|
DebugStub.WriteLine(this.ToString());
|
|
#else
|
|
Console.WriteLine(this.ToString());
|
|
#endif
|
|
if (childByNameMap != null) {
|
|
foreach (Node child in childByNameMap.Values) {
|
|
child.DumpSubtree();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public class NodeAlreadyExistsException : Exception
|
|
{
|
|
public NodeAlreadyExistsException()
|
|
: base("Node already exists")
|
|
{
|
|
}
|
|
|
|
public NodeAlreadyExistsException(string message)
|
|
: base("Node already exists: " + message)
|
|
{
|
|
}
|
|
}
|
|
|
|
private Node rootNode = new Node();
|
|
|
|
public AcpiNamespace()
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Look up the node at a given absolute node path.
|
|
/// </summary>
|
|
/// <returns>The requested node, or null if the node is not found.</returns>
|
|
public Node LookupNode(AbsoluteNodePath nodePath)
|
|
{
|
|
return LookupDescendantNode(rootNode, nodePath.NameSegments);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Look up the node at a given absolute or relative node path.
|
|
/// This may include "single segment name" paths which invoke the
|
|
/// search strategy described in section 5.3 of the ACPI spec 3.0b.
|
|
/// </summary>
|
|
/// <param name="currentPath">Absolute path of the current path
|
|
/// relative to which any relative node path will be determined.</param>
|
|
/// <returns>The requested node, or null if the node is not found.</returns>
|
|
public Node LookupNode(NodePath nodePath, AbsoluteNodePath currentPath)
|
|
{
|
|
if (nodePath.IsAbsolute) {
|
|
return LookupDescendantNode(rootNode, nodePath.NameSegments);
|
|
}
|
|
else {
|
|
Node startNode = LookupNode(currentPath);
|
|
Debug.Assert(startNode != null, "LookupNode: Current path did not resolve");
|
|
|
|
if (nodePath.NumParentPrefixes > 0) {
|
|
for (int i = 0; i < nodePath.NumParentPrefixes; i++) {
|
|
startNode = startNode.ParentNode;
|
|
if (startNode == null) {
|
|
throw new ArgumentException("Relative path attempts to move above root");
|
|
}
|
|
}
|
|
return LookupDescendantNode(startNode, nodePath.NameSegments);
|
|
}
|
|
else {
|
|
// The search rules apply - try successively larger scopes
|
|
while (startNode != null) {
|
|
Node result = LookupDescendantNode(startNode, nodePath.NameSegments);
|
|
if (result != null) {
|
|
return result;
|
|
}
|
|
startNode = startNode.ParentNode;
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A version of LookupNode that does not ever apply the search rules.
|
|
/// </summary>
|
|
private Node LookupNodeNoSearch(NodePath nodePath, AbsoluteNodePath currentPath)
|
|
{
|
|
if (nodePath.IsAbsolute) {
|
|
return LookupDescendantNode(rootNode, nodePath.NameSegments);
|
|
}
|
|
else {
|
|
Node startNode = LookupNode(currentPath);
|
|
Debug.Assert(startNode != null, "LookupNode: Current path did not resolve");
|
|
|
|
for (int i = 0; i < nodePath.NumParentPrefixes; i++) {
|
|
startNode = startNode.ParentNode;
|
|
if (startNode == null) {
|
|
throw new ArgumentException("Relative path attempts to move above root");
|
|
}
|
|
}
|
|
return LookupDescendantNode(startNode, nodePath.NameSegments);
|
|
}
|
|
}
|
|
|
|
private Node LookupDescendantNode(Node node, string[] nameSegments)
|
|
{
|
|
Node n = node;
|
|
foreach (string name in nameSegments) {
|
|
n = n.GetChildByName(name);
|
|
if (n == null) {
|
|
break;
|
|
}
|
|
}
|
|
return n;
|
|
}
|
|
|
|
public Node CreateNodeAt(NodePath nodePath, AbsoluteNodePath currentPath)
|
|
{
|
|
if (LookupNodeNoSearch(nodePath, currentPath) != null) {
|
|
throw new NodeAlreadyExistsException();
|
|
}
|
|
|
|
// Find deepest existing node on the path
|
|
NodePath ancestorNodePath = nodePath;
|
|
Node ancestorNode;
|
|
int stepsUp = 0;
|
|
do {
|
|
ancestorNodePath = ancestorNodePath.RemoveSegment();
|
|
stepsUp++;
|
|
ancestorNode = LookupNodeNoSearch(ancestorNodePath, currentPath);
|
|
} while (ancestorNode == null);
|
|
|
|
// Create remaining names to get a node with the desired path
|
|
Node newNode = null;
|
|
string[] nameSegments = nodePath.NameSegments;
|
|
for (int i = nameSegments.Length - stepsUp; i < nameSegments.Length; i++) {
|
|
newNode = new Node((string)nameSegments[i], ancestorNode);
|
|
ancestorNode = newNode;
|
|
}
|
|
|
|
return newNode;
|
|
}
|
|
|
|
public Node FindValue(AcpiObject.AcpiObject value)
|
|
{
|
|
return rootNode.FindValue(value);
|
|
}
|
|
|
|
public Node[] GetAllNodes()
|
|
{
|
|
Node[] result = new Node[rootNode.CountSubtreeNodes()];
|
|
int startIndex = 0;
|
|
rootNode.GetSubtreeNodes(result, ref startIndex);
|
|
return result;
|
|
}
|
|
|
|
private static void AssertIsValidName(string name)
|
|
{
|
|
Debug.Assert(IsValidName(name), "Invalid name for ACPI namespace node");
|
|
}
|
|
|
|
public void DumpTree()
|
|
{
|
|
rootNode.DumpSubtree();
|
|
}
|
|
|
|
internal static bool IsValidName(byte[] name)
|
|
{
|
|
return name.Length == 4 &&
|
|
(Char.IsUpper((char)name[0]) || (char)name[0] == '_') &&
|
|
(Char.IsUpper((char)name[1]) || (char)name[1] == '_' || Char.IsDigit((char)name[1])) &&
|
|
(Char.IsUpper((char)name[2]) || (char)name[2] == '_' || Char.IsDigit((char)name[2])) &&
|
|
(Char.IsUpper((char)name[3]) || (char)name[3] == '_' || Char.IsDigit((char)name[3]));
|
|
}
|
|
|
|
internal static bool IsValidName(string name)
|
|
{
|
|
return name.Length == 4 &&
|
|
(Char.IsUpper(name[0]) || name[0] == '_') &&
|
|
(Char.IsUpper(name[1]) || name[1] == '_' || Char.IsDigit(name[1])) &&
|
|
(Char.IsUpper(name[2]) || name[2] == '_' || Char.IsDigit(name[2])) &&
|
|
(Char.IsUpper(name[3]) || name[3] == '_' || Char.IsDigit(name[3]));
|
|
}
|
|
}
|
|
}
|