/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) Microsoft Corporation. All rights reserved. // // Microsoft Research Singularity // using System; using System.Collections; using System.Diagnostics; using Microsoft.Singularity.Hal.Acpi.AcpiObject; using Microsoft.Singularity.Hal.Acpi.AmlParserUnions; using Node = Microsoft.Singularity.Hal.Acpi.AcpiNamespace.Node; using NodePath = Microsoft.Singularity.Hal.Acpi.AcpiNamespace.NodePath; using AbsoluteNodePath = Microsoft.Singularity.Hal.Acpi.AcpiNamespace.AbsoluteNodePath; namespace Microsoft.Singularity.Hal.Acpi { public class AmlTypeException : Exception { public AmlTypeException() : base("AML type error") { } public AmlTypeException(string s) : base("AML type error: " + s) { } } public class LoadException : Exception { public LoadException() : base("Error loading AML") { } public LoadException(string s) : base("Error loading AML: " + s) { } } public class AmlLoader { AcpiNamespace acpiNamespace; AcpiObject.IOperationRegionAccessor operationRegionAccessor; public AmlLoader(AcpiNamespace acpiNamespace, AcpiObject.IOperationRegionAccessor operationRegionAccessor) { this.acpiNamespace = acpiNamespace; this.operationRegionAccessor = operationRegionAccessor; } public void Load(AmlParser.AMLCode code) { // Because of arbitrary forward-references to names in the AML, we // have to do this in three phases: // 1. Populate the namespace with all the names; // 2. Fill in the details of all the object values. // This allows us to verify that references only reference real // existing names. NamesVisitor namesVisitor = new NamesVisitor(acpiNamespace); foreach (TermObj termObj in code.termList) { termObj.Accept(namesVisitor); } ValuesVisitor valuesVisitor = new ValuesVisitor(this, acpiNamespace); foreach (TermObj termObj in code.termList) { termObj.Accept(valuesVisitor); } } internal AcpiObject.IOperationRegionAccessor OperationRegionAccessor { get { return operationRegionAccessor; } } public class NamesVisitor : AmlParserNodeVisitor { AcpiNamespace acpiNamespace; AbsoluteNodePath currentPath; public NamesVisitor(AcpiNamespace acpiNamespace) { this.acpiNamespace = acpiNamespace; this.currentPath = AbsoluteNodePath.CreateRoot(); } public override void UnhandledNodeType(string nodeTypeName) { throw new LoadException("Encountered unexpected node type " + nodeTypeName + " at load-time (names phase)"); } public override void Visit(AmlParser.DefAlias defAlias) { acpiNamespace.CreateNodeAt(defAlias.aliasName.nodePath, currentPath); } public override void Visit(AmlParser.DefName defName) { acpiNamespace.CreateNodeAt(defName.nameString.nodePath, currentPath); } public override void Visit(AmlParser.DefScope defScope) { AbsoluteNodePath oldPath = currentPath; currentPath = acpiNamespace.LookupNode(defScope.nameString.nodePath, currentPath).Path; foreach (TermObj termObj in defScope.termList) { termObj.Accept(this); } currentPath = oldPath; } public override void Visit(AmlParser.DefBankField defBankField) { foreach (FieldElement fieldElement in defBankField.fieldList) { switch (fieldElement.Tag) { case FieldElement.TagValue.NamedField: AmlParser.NamedField namedField = fieldElement.GetAsNamedField(); Node node = acpiNamespace.CreateNodeAt( new NodePath(false/*isAbsolute*/, 0, new string[] { namedField.nameSeg.data }), currentPath); break; default: break; } } } public override void Visit(AmlParser.DefCreateBitField defCreateBitField) { acpiNamespace.CreateNodeAt(defCreateBitField.nameString.nodePath, currentPath); } public override void Visit(AmlParser.DefCreateByteField defCreateByteField) { acpiNamespace.CreateNodeAt(defCreateByteField.nameString.nodePath, currentPath); } public override void Visit(AmlParser.DefCreateDWordField defCreateDWordField) { acpiNamespace.CreateNodeAt(defCreateDWordField.nameString.nodePath, currentPath); } public override void Visit(AmlParser.DefCreateField defCreateField) { acpiNamespace.CreateNodeAt(defCreateField.nameString.nodePath, currentPath); } public override void Visit(AmlParser.DefCreateQWordField defCreateQWordField) { acpiNamespace.CreateNodeAt(defCreateQWordField.nameString.nodePath, currentPath); } public override void Visit(AmlParser.DefCreateWordField defCreateWordField) { acpiNamespace.CreateNodeAt(defCreateWordField.nameString.nodePath, currentPath); } public override void Visit(AmlParser.DefDataRegion defDataRegion) { acpiNamespace.CreateNodeAt(defDataRegion.nameString.nodePath, currentPath); } public override void Visit(AmlParser.DefDevice defDevice) { AbsoluteNodePath oldPath = currentPath; Node node = acpiNamespace.CreateNodeAt(defDevice.nameString.nodePath, currentPath); currentPath = node.Path; foreach (AmlObject amlObject in defDevice.amlObjectList) { amlObject.Accept(this); } currentPath = oldPath; } public override void Visit(AmlParser.DefEvent defEvent) { acpiNamespace.CreateNodeAt(defEvent.nameString.nodePath, currentPath); } public override void Visit(AmlParser.DefField defField) { foreach (FieldElement fieldElement in defField.fieldList) { switch (fieldElement.Tag) { case FieldElement.TagValue.NamedField: AmlParser.NamedField namedField = fieldElement.GetAsNamedField(); Node node = acpiNamespace.CreateNodeAt( new NodePath(false/*isAbsolute*/, 0, new string[] { namedField.nameSeg.data }), currentPath); break; default: break; } } } public override void Visit(AmlParser.DefIndexField defIndexField) { foreach (FieldElement fieldElement in defIndexField.fieldList) { switch (fieldElement.Tag) { case FieldElement.TagValue.NamedField: AmlParser.NamedField namedField = fieldElement.GetAsNamedField(); Node node = acpiNamespace.CreateNodeAt( new NodePath(false/*isAbsolute*/, 0, new string[] { namedField.nameSeg.data }), currentPath); break; default: break; } } } public override void Visit(AmlParser.DefMethod defMethod) { acpiNamespace.CreateNodeAt(defMethod.nameString.nodePath, currentPath); } public override void Visit(AmlParser.DefMutex defMutex) { acpiNamespace.CreateNodeAt(defMutex.nameString.nodePath, currentPath); } public override void Visit(AmlParser.DefOpRegion defOpRegion) { acpiNamespace.CreateNodeAt(defOpRegion.nameString.nodePath, currentPath); } public override void Visit(AmlParser.DefPowerRes defPowerRes) { AbsoluteNodePath oldPath = currentPath; Node node = acpiNamespace.CreateNodeAt(defPowerRes.nameString.nodePath, currentPath); currentPath = node.Path; foreach (AmlObject amlObject in defPowerRes.amlObjectList) { amlObject.Accept(this); } currentPath = oldPath; } public override void Visit(AmlParser.DefProcessor defProcessor) { AbsoluteNodePath oldPath = currentPath; Node node = acpiNamespace.CreateNodeAt(defProcessor.nameString.nodePath, currentPath); currentPath = node.Path; foreach (AmlObject amlObject in defProcessor.amlObjectList) { amlObject.Accept(this); } currentPath = oldPath; } public override void Visit(AmlParser.DefThermalZone defThermalZone) { AbsoluteNodePath oldPath = currentPath; Node node = acpiNamespace.CreateNodeAt(defThermalZone.nameString.nodePath, currentPath); currentPath = node.Path; foreach (AmlObject amlObject in defThermalZone.amlObjectList) { amlObject.Accept(this); } currentPath = oldPath; } public override void Visit(AmlParser.DefIfElse defIfElse) { // // Load-time Ifs are both rare and tricky, because it makes the // two-phase model here unworkable: we can't let the NamesVisitor // visit the if body before the truth value of its predicate is // known, but this may depend on values filled in by the ValuesVisitor. // Being an exceptional case, we just have the NamesVisitor always // visit both branches, which works for the examples I've come across // like the AMD with Infineon TPM. // foreach (TermObj termObj in defIfElse.termList) { termObj.Accept(this); } if (defIfElse.defElse.termList != null) { foreach (TermObj termObj in defIfElse.defElse.termList) { termObj.Accept(this); } } } } public class ValuesVisitor : AmlParserNodeVisitor { AcpiNamespace acpiNamespace; AmlLoader loader; AbsoluteNodePath currentPath; public ValuesVisitor(AmlLoader loader, AcpiNamespace acpiNamespace) { this.acpiNamespace = acpiNamespace; this.currentPath = AbsoluteNodePath.CreateRoot(); this.loader = loader; } public override void UnhandledNodeType(string nodeTypeName) { throw new LoadException("Encountered unexpected node type " + nodeTypeName + " at load-time (values phase)"); } public override void Visit(AmlParser.DefAlias defAlias) { Node sourceNode = acpiNamespace.LookupNode(defAlias.sourceName.nodePath, currentPath); Node aliasNode = acpiNamespace.LookupNode(defAlias.aliasName.nodePath, currentPath); aliasNode.AliasTo(sourceNode); } public override void Visit(AmlParser.DefName defName) { Node node = acpiNamespace.LookupNode(defName.nameString.nodePath, currentPath); node.Value = LoadTimeEvaluate(defName.dataRefObject); } public override void Visit(AmlParser.DefScope defScope) { AbsoluteNodePath oldPath = currentPath; currentPath = acpiNamespace.LookupNode(defScope.nameString.nodePath, currentPath).Path; foreach (TermObj termObj in defScope.termList) { termObj.Accept(this); } currentPath = oldPath; } public override void Visit(AmlParser.DefBankField defBankField) { Node operationRegionNode = acpiNamespace.LookupNode(defBankField.regionName.nodePath, currentPath); CheckObjectType(operationRegionNode.Value, AcpiObjectType.OperationRegion); // TODO: BankFields are not used in the test files and appear to involve some kind of // "bank selection register". Need to understand this properly to implement it, but for // leaving unimplemented. Commented out below is some code to use as a starting point. throw new LoadException("BankField unimplemented"); #if false AccessType accessType = defBankField.fieldFlags.accessType; AccessAttrib accessAttrib = AccessAttrib.SMBNone; int bitIndex = 0; foreach (FieldElement fieldElement in defBankField.fieldList) { switch (fieldElement.Tag) { case FieldElement.TagValue.NamedField: AmlParser.NamedField namedField = fieldElement.GetAsNamedField(); Node node = acpiNamespace.LookupNode( new NodePath(false/*isAbsolute*/, 0, new string[] { namedField.nameSeg.data }), currentPath); node.Value = new FieldUnit((AcpiObject.OperationRegion)operationRegionNode.Value, bitIndex, namedField.bitWidth, accessType, accessAttrib, defBankField.fieldFlags.lockRule, defBankField.fieldFlags.updateRule); bitIndex += namedField.bitWidth; break; case FieldElement.TagValue.ReservedField: AmlParser.ReservedField reservedField = fieldElement.GetAsReservedField(); bitIndex += reservedField.bitWidth; break; case FieldElement.TagValue.AccessField: AmlParser.AccessField accessField = fieldElement.GetAsAccessField(); accessType = accessField.accessType; accessAttrib = accessField.accessAttrib; break; default: throw new LoadException("Unhandled alternative in switch over 'FieldElement'"); } } #endif } public override void Visit(AmlParser.DefCreateBitField defCreateBitField) { VisitField(defCreateBitField.sourceBuff, defCreateBitField.bitIndex.integer, 1, 1/*numBits*/, defCreateBitField.nameString.nodePath); } public override void Visit(AmlParser.DefCreateByteField defCreateByteField) { VisitField(defCreateByteField.sourceBuff, defCreateByteField.byteIndex.integer, 8, 8/*numBits*/, defCreateByteField.nameString.nodePath); } public override void Visit(AmlParser.DefCreateDWordField defCreateDWordField) { VisitField(defCreateDWordField.sourceBuff, defCreateDWordField.byteIndex.integer, 8, 32/*numBits*/, defCreateDWordField.nameString.nodePath); } public override void Visit(AmlParser.DefCreateField defCreateField) { AcpiObject.AcpiObject sizeObj = LoadTimeEvaluate(defCreateField.numBits.integer); CheckObjectType(sizeObj, AcpiObjectType.Integer); VisitField(defCreateField.sourceBuff, defCreateField.bitIndex.integer, 1, ((AcpiObject.Integer)(sizeObj.GetTarget())).Value, defCreateField.nameString.nodePath); } public override void Visit(AmlParser.DefCreateQWordField defCreateQWordField) { VisitField(defCreateQWordField.sourceBuff, defCreateQWordField.byteIndex.integer, 8, 64/*numBits*/, defCreateQWordField.nameString.nodePath); } public override void Visit(AmlParser.DefCreateWordField defCreateWordField) { VisitField(defCreateWordField.sourceBuff, defCreateWordField.byteIndex.integer, 8, 16/*numBits*/, defCreateWordField.nameString.nodePath); } public void VisitField(AmlParser.SourceBuff sourceBuff, TermArg indexTermArg, ulong bitIndexMultiplier, ulong bitSize, NodePath fieldName) { AcpiObject.AcpiObject indexObj = LoadTimeEvaluate(indexTermArg); CheckObjectType(indexObj, AcpiObjectType.Integer); ulong index = ((AcpiObject.Integer)(indexObj.GetTarget())).Value; ulong bitIndex = index * bitIndexMultiplier; AcpiObject.AcpiObject bufferObj = LoadTimeEvaluate(sourceBuff.buffer); CheckObjectType(bufferObj, AcpiObjectType.Buffer); Node node = acpiNamespace.LookupNode(fieldName, currentPath); node.Value = new BufferField((AcpiObject.Buffer)(bufferObj.GetTarget()), bitIndex, bitSize); } public override void Visit(AmlParser.DefDataRegion defDataRegion) { // TODO: This method will have to go back to the XSDT table // to look up the designated table and its location so that // it can produce a corresponding AcpiObject.OperationRegion. // It is not used in the three test DDBs. throw new LoadException("TODO Not yet implemented"); } public override void Visit(AmlParser.DefDevice defDevice) { AbsoluteNodePath oldPath = currentPath; Node node = acpiNamespace.LookupNode(defDevice.nameString.nodePath, currentPath); string[] segments = new string[currentPath.NameSegments.Length + defDevice.nameString.nodePath.NameSegments.Length]; int index = 0; foreach (string segment in currentPath.NameSegments) { segments[index++] = segment; } foreach (string segment in defDevice.nameString.nodePath.NameSegments) { segments[index++] = segment; } AbsoluteNodePath devPath = new AbsoluteNodePath(segments); node.Value = new AcpiObject.Device(devPath); currentPath = node.Path; foreach (AmlObject amlObject in defDevice.amlObjectList) { amlObject.Accept(this); } currentPath = oldPath; } public override void Visit(AmlParser.DefEvent defEvent) { Node node = acpiNamespace.LookupNode(defEvent.nameString.nodePath, currentPath); node.Value = new AcpiObject.Event(); } public override void Visit(AmlParser.DefField defField) { Node operationRegionNode = acpiNamespace.LookupNode(defField.nameString.nodePath, currentPath); CheckObjectType(operationRegionNode.Value, AcpiObjectType.OperationRegion); SortedList fields = FieldUnit.CreateFromFieldList((AcpiObject.OperationRegion)(operationRegionNode.Value.GetTarget()), defField.fieldList, defField.fieldFlags.accessType, AccessAttrib.SMBNone, defField.fieldFlags.lockRule, defField.fieldFlags.updateRule); foreach (DictionaryEntry entry in fields) { Node node = acpiNamespace.LookupNode( new NodePath(false/*isAbsolute*/, 0, new string[] { (string)entry.Key }), currentPath); node.Value = (FieldUnit)entry.Value; } } public override void Visit(AmlParser.DefIndexField defIndexField) { Node indexNode = acpiNamespace.LookupNode(defIndexField.indexName.nodePath, currentPath); CheckObjectType(indexNode.Value, AcpiObjectType.FieldUnit); AcpiObject.FieldUnit indexField = (AcpiObject.FieldUnit)(indexNode.Value.GetTarget()); Node dataNode = acpiNamespace.LookupNode(defIndexField.dataName.nodePath, currentPath); CheckObjectType(dataNode.Value, AcpiObjectType.FieldUnit); AcpiObject.FieldUnit dataField = (AcpiObject.FieldUnit)(dataNode.Value.GetTarget()); OperationRegion indexFieldRegion = new OperationRegion(new IndexFieldOperationRegionAccessor(indexField, dataField), RegionSpace.SystemIO/*unused*/, 0, 256/*index field never exceeds 8 bits*/); AccessType accessType = defIndexField.fieldFlags.accessType; AccessAttrib accessAttrib = AccessAttrib.SMBNone; int bitIndex = 0; foreach (FieldElement fieldElement in defIndexField.fieldList) { switch (fieldElement.Tag) { case FieldElement.TagValue.NamedField: AmlParser.NamedField namedField = fieldElement.GetAsNamedField(); Node node = acpiNamespace.LookupNode( new NodePath(false/*isAbsolute*/, 0, new string[] { namedField.nameSeg.data }), currentPath); node.Value = new FieldUnit(indexFieldRegion, bitIndex, namedField.bitWidth, accessType, accessAttrib, defIndexField.fieldFlags.lockRule, defIndexField.fieldFlags.updateRule); bitIndex += namedField.bitWidth; break; case FieldElement.TagValue.ReservedField: AmlParser.ReservedField reservedField = fieldElement.GetAsReservedField(); bitIndex += reservedField.bitWidth; break; case FieldElement.TagValue.AccessField: AmlParser.AccessField accessField = fieldElement.GetAsAccessField(); accessType = accessField.accessType; accessAttrib = accessField.accessAttrib; break; default: throw new LoadException("Unhandled alternative in switch over 'FieldElement'"); } } } public override void Visit(AmlParser.DefMethod defMethod) { Node node = acpiNamespace.LookupNode(defMethod.nameString.nodePath, currentPath); node.Value = new AcpiObject.BytecodeMethod(defMethod.methodFlags.argCount, defMethod.methodFlags.serializeFlag, defMethod.methodFlags.syncLevel, defMethod.unparsedTermList); } public override void Visit(AmlParser.DefMutex defMutex) { Node node = acpiNamespace.LookupNode(defMutex.nameString.nodePath, currentPath); node.Value = new AcpiObject.Mutex(defMutex.syncFlags.syncLevel); } public override void Visit(AmlParser.DefOpRegion defOpRegion) { AcpiObject.AcpiObject startIndexObj = LoadTimeEvaluate(defOpRegion.regionOffset.integer); AcpiObject.AcpiObject lengthObj = LoadTimeEvaluate(defOpRegion.regionLen.integer); CheckObjectType(lengthObj, AcpiObjectType.Integer); Node node = acpiNamespace.LookupNode(defOpRegion.nameString.nodePath, currentPath); node.Value = new AcpiObject.OperationRegion(loader.OperationRegionAccessor, (RegionSpace)defOpRegion.regionSpace.byteData, startIndexObj.GetAsInt().Value, ((AcpiObject.Integer)(lengthObj.GetTarget())).Value); } public override void Visit(AmlParser.DefPowerRes defPowerRes) { AbsoluteNodePath oldPath = currentPath; Node node = acpiNamespace.LookupNode(defPowerRes.nameString.nodePath, currentPath); node.Value = new AcpiObject.PowerResource(defPowerRes.systemLevel.byteData, defPowerRes.resourceOrder.wordData); currentPath = node.Path; foreach (AmlObject amlObject in defPowerRes.amlObjectList) { amlObject.Accept(this); } currentPath = oldPath; } public override void Visit(AmlParser.DefProcessor defProcessor) { AbsoluteNodePath oldPath = currentPath; Node node = acpiNamespace.LookupNode(defProcessor.nameString.nodePath, currentPath); node.Value = new AcpiObject.Processor(defProcessor.procID.byteData, defProcessor.pblkAddr.dWordData, defProcessor.pblkLen.byteData); currentPath = node.Path; foreach (AmlObject amlObject in defProcessor.amlObjectList) { amlObject.Accept(this); } currentPath = oldPath; } public override void Visit(AmlParser.DefThermalZone defThermalZone) { AbsoluteNodePath oldPath = currentPath; Node node = acpiNamespace.LookupNode(defThermalZone.nameString.nodePath, currentPath); node.Value = new AcpiObject.ThermalZone(); currentPath = node.Path; foreach (AmlObject amlObject in defThermalZone.amlObjectList) { amlObject.Accept(this); } currentPath = oldPath; } private AcpiObject.AcpiObject LoadTimeEvaluate(AmlParserNode parserNode) { LoadTimeEvaluateVisitor visitor = new LoadTimeEvaluateVisitor(acpiNamespace, currentPath); parserNode.Accept(visitor); return visitor.Result; } public override void Visit(AmlParser.DefIfElse defIfElse) { LoadTimeEvaluateVisitor visitor = new LoadTimeEvaluateVisitor(acpiNamespace, currentPath); defIfElse.predicate.integer.Accept(visitor); if (visitor.Result.GetAsInt().Value != 0) { foreach (TermObj termObj in defIfElse.termList) { termObj.Accept(this); } } else if (defIfElse.defElse.termList != null) { foreach (TermObj termObj in defIfElse.defElse.termList) { termObj.Accept(this); } } } } public class LoadTimeEvaluateVisitor : AmlParserNodeVisitor { AcpiNamespace acpiNamespace; AbsoluteNodePath currentPath; public LoadTimeEvaluateVisitor(AcpiNamespace acpiNamespace, AbsoluteNodePath currentPath) { this.acpiNamespace = acpiNamespace; this.currentPath = currentPath; } public override void UnhandledNodeType(string nodeTypeName) { throw new LoadException("Encountered unexpected node type " + nodeTypeName + " at load-time (during evaluation)"); } private AcpiObject.AcpiObject result; public AcpiObject.AcpiObject Result { get { return result; } } public override void Visit(AmlParser.DefPackage defPackage) { VisitPackage(defPackage.numElements.byteData, defPackage.packageElementList); } public override void Visit(AmlParser.DefVarPackage defVarPackage) { defVarPackage.varNumElements.integer.Accept(this); AcpiObject.AcpiObject numElementsObj = result; CheckObjectType(numElementsObj, AcpiObjectType.Integer); VisitPackage((byte)(((AcpiObject.Integer)(numElementsObj.GetTarget())).Value), defVarPackage.packageElementList); } private void VisitPackage(byte numElements, PackageElement[] packageElementList) { AcpiObjectCell[] elements = new AcpiObjectCell[numElements]; for(int i = 0; i < elements.Length; i++) { if (i < packageElementList.Length) { packageElementList[i].Accept(this); elements[i] = new AcpiObjectCell(result); } else { elements[i] = new AcpiObjectCell(new AcpiObject.UninitializedObject()); } } result = new AcpiObject.Package(elements); } public override void Visit(ComputationalData computationalData) { switch (computationalData.Tag) { case ComputationalData.TagValue.ByteConst: result = new AcpiObject.Integer(computationalData.GetAsByteConst()); break; case ComputationalData.TagValue.WordConst: result = new AcpiObject.Integer(computationalData.GetAsWordConst()); break; case ComputationalData.TagValue.DWordConst: result = new AcpiObject.Integer(computationalData.GetAsDWordConst()); break; case ComputationalData.TagValue.QWordConst: result = new AcpiObject.Integer(computationalData.GetAsQWordConst()); break; case ComputationalData.TagValue.StringConst: result = new AcpiObject.String(computationalData.GetAsStringConst()); break; case ComputationalData.TagValue.RevisionOp: result = AcpiObject.IntegerConstant.Revision.GetAsInt(); break; default: base.Visit(computationalData); break; } } public override void Visit(AmlParser.ConstObj constObj) { if (constObj.op == AmlParser.ZeroOp) { result = AcpiObject.IntegerConstant.Zero.GetAsInt(); } else if (constObj.op == AmlParser.OneOp) { result = AcpiObject.IntegerConstant.One.GetAsInt(); } else if (constObj.op == AmlParser.OnesOp) { result = AcpiObject.IntegerConstant.Ones.GetAsInt(); } } public override void Visit(AmlParser.DefBuffer defBuffer) { defBuffer.bufferSize.integer.Accept(this); AcpiObject.AcpiObject bufferSizeObj = result; CheckObjectType(bufferSizeObj, AcpiObjectType.Integer); byte[] contents = new byte[((AcpiObject.Integer)(bufferSizeObj.GetTarget())).Value]; Array.Copy(defBuffer.byteList, contents, defBuffer.byteList.Length); result = new AcpiObject.Buffer(contents); } public override void Visit(AmlParser.UserTermObj userTermObj) { // At load time, it can't have any args, so just look it up in the namespace. // Note that we can't simply copy the value from the given node, for two reasons: // // 1. UserTermObj references can be forwards or backwards, or even circular, as shown // in this example: // Name (BAR0, Package (0x1) { BAR1 }) // Name (BAR1, Package (0x1) { BAR0 }) // 2. Although the spec doesn't clarify this, I believe a UserTermObj is intended to be // aliased to the named node so that later changes to it are reflected in the object // containing the reference. // // To deal with we have a special "fake" object type containing an absolute NodePath that // acts as a direct reference to an object (not the sort handled by AcpiObject.ObjectReference, // which are different). An alternative would be to attempt to use the same aliasing of nodes // used by DefAlias, but this would be painful and make it later indistinguishable who is the // alias and who the original definition, which might be important. result = new AcpiObject.NodePathReference(acpiNamespace, acpiNamespace.LookupNode(userTermObj.nameString.nodePath, currentPath).Path); } public override void Visit(AmlParser.ObjReference objReference) { objReference.termArg.Accept(this); } } private static void CheckObjectType(AcpiObject.AcpiObject obj, AcpiObjectType type) { if (obj.ObjectType().Value != (ulong)type) { throw new AmlTypeException(); } } } }