812 lines
36 KiB
C#
812 lines
36 KiB
C#
|
///////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// 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();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|