/////////////////////////////////////////////////////////////////////////////// // // 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 { /// /// The absolute or relative location of a node in the ACPI namespace. /// 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(); } } /// /// A restricted type of NodePath that must be statically absolute. /// /// 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. 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); } } /// /// A node in the ACPI namespace tree. /// public class Node { private string name; private Node parentNode; private IDictionary childByNameMap = null; private AcpiObject.AcpiObjectCell value; /// /// Create a root node. /// public Node() { this.name = ""; this.parentNode = null; this.value = new AcpiObject.AcpiObjectCell(new AcpiObject.UninitializedObject()); } /// /// Create a child node with a given name and parent node. /// 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); } /// /// Makes this node refer to the same value as the given node. /// /// 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. 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() { } /// /// Look up the node at a given absolute node path. /// /// The requested node, or null if the node is not found. public Node LookupNode(AbsoluteNodePath nodePath) { return LookupDescendantNode(rootNode, nodePath.NameSegments); } /// /// 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. /// /// Absolute path of the current path /// relative to which any relative node path will be determined. /// The requested node, or null if the node is not found. 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; } } } /// /// A version of LookupNode that does not ever apply the search rules. /// 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])); } } }