singrdk/base/Kernel/Singularity.Hal.Acpi/AmlInterpreter/AcpiObject.cs

1366 lines
42 KiB
C#
Raw Permalink Normal View History

2008-11-17 18:29:00 -05:00
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Microsoft Research Singularity
//
using System;
using System.Collections;
using System.Diagnostics;
using System.Text;
using TermObj = Microsoft.Singularity.Hal.Acpi.AmlParserUnions.TermObj;
using Microsoft.Singularity.Hal.Acpi.StackIR;
using Microsoft.Singularity.Hal.Acpi.AmlParserUnions;
namespace Microsoft.Singularity.Hal.Acpi.AcpiObject
{
//
// Based roughly on Table 17-6 from the ACPI Specification 3.0b, the
// following class hierarchy describes ACPI objects, which constitute
// the values assigned to each named node in the ACPI namespace as well
// as all values assigned to temporary objects, local objects, and so on.
// They are created and used at both load time and run time.
//
/// <summary>
/// Values returned by ObjectType operator as described in section
/// 17.5.86 of the ACPI specification 3.0b.
/// </summary>
public enum AcpiObjectType
{
Uninitialized = 0,
Integer = 1,
String = 2,
Buffer = 3,
Package = 4,
FieldUnit = 5,
Device = 6,
Event = 7,
Method = 8,
Mutex = 9,
OperationRegion = 10,
PowerResource = 11,
Processor = 12,
ThermalZone = 13,
BufferField = 14,
DdbHandle = 15,
DebugObject = 16
}
public abstract class AcpiObject
{
public abstract Integer ObjectType();
public abstract void Write(AcpiObject value);
/// <summary>
/// Get the value referred to by this value, for creating indirection.
/// Returns self for concrete types.
/// </summary>
public virtual AcpiObject GetTarget()
{
return this;
}
public virtual Integer GetAsInt()
{
throw new AmlTypeException();
}
public virtual String GetAsString()
{
throw new AmlTypeException();
}
public virtual Buffer GetAsBuffer()
{
throw new AmlTypeException();
}
public virtual Method GetAsMethod()
{
throw new AmlTypeException();
}
public virtual Mutex GetAsMutex()
{
throw new AmlTypeException();
}
public virtual Device GetAsDevice()
{
throw new AmlTypeException();
}
public virtual ulong Size
{
get
{
throw new AmlTypeException();
}
}
public virtual AcpiObject Dereference()
{
throw new AmlTypeException();
}
public virtual AcpiObject Index(ulong index)
{
throw new AmlTypeException();
}
public virtual AcpiObject[] GetObjects()
{
throw new AmlTypeException();
}
public virtual void SetIndex(ulong index, AcpiObject value)
{
throw new AmlTypeException();
}
}
/// <summary>
/// Contains a reference to an AcpiObject - this added level of indirection
/// is necessary to permit AcpiObject objects to be modified through
/// ObjectReference objects.
/// </summary>
public class AcpiObjectCell
{
AcpiObject containedValue;
public AcpiObjectCell(AcpiObject containedValue)
{
this.containedValue = containedValue;
}
public AcpiObject Value
{
get
{
return containedValue;
}
set
{
if (containedValue is UninitializedObject) {
containedValue = value;
}
else {
containedValue.Write(value);
}
}
}
}
/// <summary>
/// An uninitialized ACPI object.
/// </summary>
/// <remarks>From Table 17-6: No assigned type or value. This is the type
/// of all control method LocalX variables and unused ArgX variables at
/// the beginning of method execution, as well as all uninitialized
/// Package elements. Uninitialized objects must be initialized (via
/// Store or CopyObject) before they may be used as source operands in
/// ASL expressions.</remarks>
public class UninitializedObject : AcpiObject
{
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.Uninitialized);
}
public override void Write(AcpiObject value)
{
throw new AmlTypeException("Cannot write to uninitialized object");
}
}
/// <summary>
/// An ACPI buffer object representing an array of bytes.
/// </summary>
/// <remarks>From Table 17-6: An array of bytes. Uninitialized elements
/// are zero by default.</remarks>
public class Buffer : AcpiObject
{
byte[] contents;
public Buffer(byte[] contents)
{
this.contents = contents;
}
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.Buffer);
}
public override AcpiObject Index(ulong index)
{
return new Integer(contents[index]);
}
public override void SetIndex(ulong index, AcpiObject value)
{
contents[index] = (byte)value.GetAsInt().Value;
}
public byte[] Contents
{
get
{
return (byte[])contents.Clone();
}
}
public override Buffer GetAsBuffer()
{
return this;
}
public override string ToString()
{
StringBuilder result = new StringBuilder();
result.Append("{");
bool first = true;
foreach (byte b in contents) {
if (first) {
first = false;
}
else {
result.Append(", ");
}
result.Append(b.ToString("x"));
}
result.Append("}");
return result.ToString();
}
public override void Write(AcpiObject value)
{
throw new AmlTypeException("TODO");
}
}
/// <summary>
/// An ACPI buffer field object representing a portion of a buffer.
/// </summary>
/// <remarks>From Table 17-6: Portion of a buffer created using
/// CreateBitField, CreateByteField, CreateWordField, CreateQWordField,
/// CreateField, or returned by the Index operator.</remarks>
public class BufferField : AcpiObject
{
AcpiObject sourceBuffer = null;
ulong startBitIndex;
ulong numBits;
public BufferField(AcpiObject sourceBuffer, ulong startBitIndex, ulong numBits)
{
if (numBits > sizeof(ulong) * 8) {
throw new AmlTypeException("Tried to create field with more than maximum number of bits");
}
this.sourceBuffer = sourceBuffer;
this.startBitIndex = startBitIndex;
this.numBits = numBits;
}
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.BufferField);
}
public override Integer GetAsInt()
{
return (Integer)Dereference();
}
public override AcpiObject Dereference()
{
if ((startBitIndex % 8) != 0 || (numBits % 8) != 0) {
throw new AmlTypeException("TODO: Non-byte-aligned buffer fields");
}
ulong result = 0;
// Loop from first byte to last
for(ulong idx = startBitIndex/8u; idx < startBitIndex/8u + numBits/8u; idx++) {
result = (result << 8) | sourceBuffer.Index(idx).GetAsInt().Value;
}
return new Integer(result);
}
public override void Write(AcpiObject valueObj)
{
if ((startBitIndex % 8) != 0 || (numBits % 8) != 0) {
throw new AmlTypeException("TODO: Non-byte-aligned buffer fields");
}
ulong value = valueObj.GetAsInt().Value;
// We ignore high bits above the number of bits fitting in the field.
// Used to check this, but some code actually depends on the behavior of
// truncating high bits, like this from VPC:
// Method (_CRS, 0, NotSerialized)
// {
// CreateDWordField (CRS, \_SB.SYSM._Y10._BAS, BAS4)
// CreateDWordField (CRS, \_SB.SYSM._Y10._LEN, LEN4)
// Subtract (0x00, BAS4, LEN4)
// }
// NB write in little endian byte-order
ulong end = startBitIndex/8u + numBits/8u;
for (ulong idx = startBitIndex / 8u; idx < end; idx++) {
sourceBuffer.SetIndex(idx, new Integer(value & 0xFF));
value >>= 8;
}
}
}
/// <summary>
/// An ACPI DDB handle object referring to a Differentiated Definition Block.
/// </summary>
/// <remarks>From Table 17-6: Definition block handle returned
/// by the Load operator [and passed to the Unload operator].</remarks>
public class DdbHandle : AcpiObject
{
// TODO: The representation of this will come from the table loading code
// and depend on the implementation of Load and Unload.
private DdbHandle() { } // Prevent construction until completed
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.DdbHandle);
}
public override void Write(AcpiObject value)
{
throw new AmlTypeException("TODO");
}
}
/// <summary>
/// An ACPI debug object used for formatting and printing debug output.
/// </summary>
/// <remarks>From Table 17-6: Debug output object. Formats an object
/// and prints it to the system debug port. Has no effect if debugging
/// is not active. Section 17.5.23: The debug data object is a virtual
/// data object. Writes to this object provide debugging information.
/// On at least debug versions of the interpreter, any writes into this
/// object are appropriately displayed on the system<65>s native kernel
/// debugger. All writes to the debug object are otherwise benign. If
/// the system is in use without a kernel debugger, then writes to the
/// debug object are ignored.</remarks>
public class DebugObject : AcpiObject
{
private DebugObject() { }
public readonly DebugObject Instance = new DebugObject();
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.DebugObject);
}
public override void Write(AcpiObject value)
{
#if SINGULARITY_KERNEL
DebugStub.Write(value.ToString());
#else
Console.Write(value.ToString());
#endif
}
}
/// <summary>
/// An ACPI device object representing a device or bus.
/// </summary>
/// <remarks>From Table 17-6: Device or bus object</remarks>
public class Device : AcpiObject
{
AcpiNamespace.AbsoluteNodePath path;
public Device(AcpiNamespace.AbsoluteNodePath path)
{
this.path = path;
}
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.Device);
}
public override void Write(AcpiObject value)
{
throw new AmlTypeException("TODO");
}
public AcpiNamespace.AbsoluteNodePath Path
{
get
{
return path;
}
}
public override Device GetAsDevice()
{
return this;
}
}
/// <summary>
/// An ACPI event synchronization object
/// </summary>
/// <remarks>From Table 17-6: Event synchronization object</remarks>
public class Event : AcpiObject
{
public Event()
{
// No data - an event is described entirely by its name
}
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.Event);
}
public override void Write(AcpiObject value)
{
throw new AmlTypeException("TODO");
}
}
//
// Enums based on FieldFlags rule in AML grammar,
// ACPI specification 3.0b section 18.2.5.2
//
public enum AccessType
{
AnyAcc = 0,
ByteAcc = 1,
WordAcc = 2,
DWordAcc = 3,
QWordAcc = 4,
BufferAcc = 5,
Reserved1 = 6,
Reserved2 = 7,
Reserved3 = 8,
Reserved4 = 9,
Reserved5 = 10,
Reserved6 = 11,
Reserved7 = 12,
Reserved8 = 13,
Reserved9 = 14,
Reserved10 = 15
}
public enum LockRule
{
NoLock = 0,
Lock = 1
}
public enum UpdateRule
{
Preserved = 0,
WriteAsOnes = 1,
WriteAsZeros = 2,
Invalid = 3
}
public enum AccessAttrib
{
SMBNone = 0x00,
SMBQuick = 0x02,
SMBSendReceive = 0x04,
SMBByte = 0x06,
SMBWord = 0x08,
SMBBlock = 0x0A,
SMBProcessCall = 0x0C,
SMBBlockProcessCall = 0x0D
}
/// <summary>
/// An ACPI field unit object referring to a portion of an address space.
/// </summary>
/// <remarks>From Table 17-6: (within an Operation Region) Portion of an
/// address space, bit-aligned and of one-bit granularity. Created using
/// Field, BankField, or IndexField.</remarks>
public class FieldUnit : AcpiObject
{
OperationRegion operationRegion;
int startBitIndex;
int numBits;
AccessType accessType;
AccessAttrib accessAttrib;
LockRule lockRule;
UpdateRule updateRule;
public FieldUnit(OperationRegion operationRegion, int startBitIndex, int numBits,
AccessType accessType, AccessAttrib accessAttrib,
LockRule lockRule, UpdateRule updateRule)
{
if (startBitIndex < 0 || (startBitIndex + numBits + 7)/8 > (int)operationRegion.Length) {
throw new ArgumentException("Field unit not in bounds of operation region");
}
this.operationRegion = operationRegion;
this.startBitIndex = startBitIndex;
this.numBits = numBits;
this.accessType = accessType;
this.accessAttrib = accessAttrib;
this.lockRule = lockRule;
this.updateRule = updateRule;
}
public override Integer GetAsInt()
{
return new Integer(Read());
}
public override Buffer GetAsBuffer()
{
if ((startBitIndex % 8) == 0) {
return new Buffer(operationRegion.ReadBytes((ulong)(startBitIndex / 8),
(ulong)(numBits + 7)/8));
}
else {
throw new Exception("Unimplemented conversion of unaligned field to buffer");
}
}
public ulong Read()
{
if (numBits == 8 && (startBitIndex % 8) == 0) {
return operationRegion.Read8At((ulong)(startBitIndex / 8));
}
else if (numBits == 16 && (startBitIndex % 8) == 0) {
return operationRegion.Read16At((ulong)(startBitIndex / 8));
}
else if (numBits == 32 && (startBitIndex % 8) == 0) {
return operationRegion.Read32At((ulong)(startBitIndex / 8));
}
else {
// Small field or unaligned, do general case
int bitIndex = startBitIndex;
int remainingBits = numBits;
uint result = 0;
while (remainingBits > 0) {
byte b = operationRegion.Read8At((ulong)(bitIndex / 8));
for (int bitInWord = bitIndex % 8;
bitInWord < 8 && remainingBits > 0;
bitInWord++, bitIndex++, remainingBits--) {
result = (result << 1) | (uint)((b >> (7 - bitInWord)) & 1);
}
}
return result;
}
}
/// <summary>
/// This is currently just used by IndexField, will probably become accessible
/// from AML when implementing stores.
/// </summary>
public override void Write(AcpiObject valueObj)
{
ulong value = valueObj.GetAsInt().Value;
Debug.Assert(AcpiObjectUtils.GetNumBits(value) <= (ulong)numBits, "Writing value too large for field");
if (numBits == 8 && (startBitIndex % 8) == 0) {
operationRegion.Write8At((ulong)(startBitIndex / 8), (byte)value);
}
else if (numBits == 16 && (startBitIndex % 8) == 0) {
operationRegion.Write16At((ulong)(startBitIndex / 8), (byte)value);
}
else if (numBits == 32 && (startBitIndex % 8) == 0) {
operationRegion.Write32At((ulong)(startBitIndex / 8), (byte)value);
}
else {
throw new Exception("Unimplemented operation region field size");
}
}
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.FieldUnit);
}
// SortedList will be Dictionary<string, FieldUnit> when generics are available
public static SortedList CreateFromFieldList(OperationRegion operationRegionNode,
FieldElement[] fieldList,
AccessType initialAccessType,
AccessAttrib initialAccessAttrib,
LockRule lockRule,
UpdateRule updateRule
)
{
SortedList result = new SortedList(); // = new Dictionary<string, FieldUnit>();
AccessType accessType = initialAccessType;
AccessAttrib accessAttrib = initialAccessAttrib;
int bitIndex = 0;
foreach (FieldElement fieldElement in fieldList) {
switch (fieldElement.Tag) {
case FieldElement.TagValue.NamedField:
AmlParser.NamedField namedField = fieldElement.GetAsNamedField();
result.Add(namedField.nameSeg.data,
new FieldUnit(operationRegionNode,
bitIndex, namedField.bitWidth,
accessType, accessAttrib, lockRule, 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'");
}
}
return result;
}
}
/// <summary>
/// This operation region accessor accesses internal device registers
/// through an index/data pair (typically a pair of I/O ports inside an
/// I/O operation region). It is used by IndexField definitions, which
/// create FieldUnits inside these internal operation regions. The
/// RegionSpace type is ignored.
/// </summary>
public class IndexFieldOperationRegionAccessor : IOperationRegionAccessor
{
FieldUnit index;
FieldUnit data;
public IndexFieldOperationRegionAccessor(FieldUnit index, FieldUnit data)
{
this.index = index;
this.data = data;
}
public byte Read8(RegionSpace regionSpace, ulong offset)
{
index.Write(new Integer(offset));
return (byte)data.Read();
}
public void Write8(RegionSpace regionSpace, ulong offset, byte value)
{
index.Write(new Integer(offset));
data.Write(new Integer(value));
}
public ushort Read16(RegionSpace regionSpace, ulong offset)
{
index.Write(new Integer(offset));
return (ushort)data.Read();
}
public void Write16(RegionSpace regionSpace, ulong offset, ushort value)
{
index.Write(new Integer(offset));
data.Write(new Integer(value));
}
public uint Read32(RegionSpace regionSpace, ulong offset)
{
index.Write(new Integer(offset));
return (uint)data.Read();
}
public void Write32(RegionSpace regionSpace, ulong offset, uint value)
{
index.Write(new Integer(offset));
data.Write(new Integer(value));
}
public byte[] ReadBytes(RegionSpace regionSpace, ulong offset, ulong length)
{
throw new Exception("Unimplemented ReadBytes() from index field");
}
}
/// <summary>
/// An ACPI integer object
/// </summary>
/// <remarks>From Table 17-6: An n-bit little-endian unsigned integer.
/// In ACPI 1.0 this was at least 32 bits. In ACPI 2.0 and later, this
/// is 64 bits.</remarks>
public class Integer : AcpiObject
{
ulong value;
public Integer(ulong value)
{
this.value = value;
}
public ulong Value
{
get
{
return value;
}
}
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.Integer);
}
public override Integer GetAsInt()
{
if (this == IntegerConstant.Zero ||
this == IntegerConstant.One ||
this == IntegerConstant.Ones) {
// Reading an IntegerConstant does not get the singleton object
// but just the value in it.
return new Integer(value);
}
return this;
}
public override void Write(AcpiObject value)
{
if (this == IntegerConstant.Zero ||
this == IntegerConstant.One ||
this == IntegerConstant.Ones) {
throw new AmlTypeException("Cannot write to reserved integer constant objects");
}
this.value = value.GetAsInt().Value;
}
public override string ToString()
{
return value.ToString();
}
}
/// <summary>
/// Wrapper class for some static methods referring to ACPI integer
/// constant built-in integer constants.
/// </summary>
/// <remarks>From Table 17-6: Created by the ASL terms "Zero", "One",
/// "Ones", and "Revision". We did not create a subclass for these
/// because ObjectType has no "IntegerConstant" type, only Integer.</remarks>
public class IntegerConstant
{
private IntegerConstant() { } // Don't allow construction
public readonly static Integer Zero = new Integer(0UL);
public readonly static Integer One = new Integer(1UL);
public readonly static Integer Ones = new Integer(~(0UL));
public readonly static Integer Revision = new Integer(0); // TODO: What's the right value for this?
}
//
// Enum based on MethodFlags rule in AML grammar,
// ACPI specification 3.0b section 18.2.5.2
//
public enum SerializeFlag
{
NotSerialized = 0,
Serialized = 1
}
/// <summary>
/// An ACPI method object referring to an invokable method.
/// </summary>
/// <remarks>From Table 17-6: Control Method (Executable AML function)</remarks>
public abstract class Method : AcpiObject
{
byte argCount;
SerializeFlag serializeFlag;
byte syncLevel;
public Method(byte argCount, SerializeFlag serializeFlag, byte syncLevel)
{
this.argCount = argCount;
this.serializeFlag = serializeFlag;
this.syncLevel = syncLevel;
}
public byte ArgCount
{
get
{
return argCount;
}
}
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.Method);
}
public override Method GetAsMethod()
{
return this;
}
public abstract void Invoke(AmlInterpreterThread thread, AcpiObject[] parameters, AcpiNamespace acpiNamespace);
public override void Write(AcpiObject value)
{
throw new AmlTypeException("Cannot write to method");
}
}
/// <summary>
/// A method whose body is represented using AML bytecode which can be parsed
/// and interpreted.
/// </summary>
public class BytecodeMethod : Method
{
byte[] unparsedTermList;
StackIRNode[] body;
public BytecodeMethod(byte argCount, SerializeFlag serializeFlag, byte syncLevel, byte[] unparsedTermList)
: base(argCount, serializeFlag, syncLevel)
{
this.unparsedTermList = unparsedTermList;
this.body = null;
}
public AmlParser.ParseSuccess Parse(AcpiNamespace acpiNamespace, AcpiNamespace.AbsoluteNodePath initialNodePath)
{
int offset = 0;
TermObj[] termList;
if (new AmlParser(new ByteBufferAmlStreamAdapter(unparsedTermList), acpiNamespace, initialNodePath).
ParseTermList(out termList, ref offset, unparsedTermList.Length) == AmlParser.ParseSuccess.Failure) {
return AmlParser.ParseSuccess.Failure;
}
Debug.Assert(offset == unparsedTermList.Length, "offset == unparsedTermList.Length");
AmlToStackIRVisitor amlToStackIRVisitor = new AmlToStackIRVisitor();
amlToStackIRVisitor.VisitSequence(termList);
body = amlToStackIRVisitor.Result;
return AmlParser.ParseSuccess.Success;
}
public override void Invoke(AmlInterpreterThread thread, AcpiObject[] parameters, AcpiNamespace acpiNamespace)
{
if (body == null) {
AcpiNamespace.Node node = acpiNamespace.FindValue(this);
if (Parse(acpiNamespace, node.Path) == AmlParser.ParseSuccess.Failure) {
throw new InterpretException("AML parser failure while just-in-time parsing AML method body");
}
}
thread.PushFrame(new AmlStackFrame(body, parameters));
}
}
/// <summary>
/// A reserved method implemented directly by the operating system.
/// </summary>
public class ReservedMethod : Method
{
public delegate AcpiObject AcpiMethodImpl(AcpiObject[] arguments);
private AcpiMethodImpl impl;
public ReservedMethod(byte argCount, SerializeFlag serializeFlag, byte syncLevel, AcpiMethodImpl impl)
: base(argCount, serializeFlag, syncLevel)
{
this.impl = impl;
}
public override void Invoke(AmlInterpreterThread thread, AcpiObject[] parameters, AcpiNamespace acpiNamespace)
{
thread.Push(new ValueIoLocation(impl(parameters)));
}
}
/// <summary>
/// An ACPI mutex synchronization object
/// </summary>
/// <remarks>From Table 17-6: Mutex synchronization object</remarks>
public class Mutex : AcpiObject
{
private class AmlInterpreterThreadSet : IEnumerable
{
ArrayList set = new ArrayList();
public void Add(AmlInterpreterThread thread) {
set.Add(thread);
}
public IEnumerator GetEnumerator() {
return set.GetEnumerator();
}
public void Clear() {
set.Clear();
}
}
byte syncLevel;
AmlInterpreterThread owner = null;
AmlInterpreterThreadSet waitingThreads = new AmlInterpreterThreadSet();
public Mutex(byte syncLevel)
{
this.syncLevel = syncLevel;
}
public void Acquire(AmlInterpreterThread thread) {
if (owner == null) {
owner = thread;
}
else {
waitingThreads.Add(thread);
thread.Block();
}
}
public void Release(AmlInterpreterThread thread) {
if (owner == null) {
throw new InterpretException("Attempt to release unlocked mutex");
}
owner = null;
foreach (AmlInterpreterThread waitingThread in waitingThreads) {
waitingThread.Notify();
}
waitingThreads.Clear();
}
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.Mutex);
}
public override Mutex GetAsMutex()
{
return this;
}
public override void Write(AcpiObject value)
{
throw new AmlTypeException("Cannot write to mutex");
}
}
/// <summary>
/// See AmlLoader.LoadTimeEvaluate(AmlParser.UserTermObj userTermObj)
/// for an explanation of the existence of this object type, which is
/// not defined in the specification.
/// </summary>
public class NodePathReference : AcpiObject
{
private AcpiNamespace acpiNamespace;
private AcpiNamespace.AbsoluteNodePath nodePath;
public NodePathReference(AcpiNamespace acpiNamespace,
AcpiNamespace.AbsoluteNodePath nodePath)
{
this.acpiNamespace = acpiNamespace;
this.nodePath = nodePath;
}
public override Integer ObjectType()
{
return GetTarget().ObjectType();
}
public override AcpiObject GetTarget()
{
return acpiNamespace.LookupNode(nodePath).Value;
}
public override Integer GetAsInt()
{
return GetTarget().GetAsInt();
}
public override Device GetAsDevice()
{
return GetTarget().GetAsDevice();
}
public override void Write(AcpiObject value)
{
GetTarget().Write(value);
}
}
/// <summary>
/// An ACPI object reference object referring to some other AcpiObject
/// </summary>
/// <remarks>From Table 17-6: Reference to an object created using the
/// RefOf, Index, or CondRefOf operators</remarks>
public class ObjectReference : AcpiObject
{
AcpiObjectCell target;
public ObjectReference(AcpiObjectCell target)
{
this.target = target;
}
public override Integer ObjectType()
{
// From 17.5.86: if this operation is performed on an object
// reference [...] the object type of the base object is returned.
return GetTarget().ObjectType();
}
public override AcpiObject GetTarget()
{
return target.Value;
}
public override Integer GetAsInt()
{
return GetTarget().GetAsInt();
}
public override Device GetAsDevice()
{
return GetTarget().GetAsDevice();
}
public override void Write(AcpiObject value)
{
GetTarget().Write(value);
}
}
/// <summary>
/// From 17.5.89, describes the built-in region spaces in which an
/// operation region can be created.
/// </summary>
public enum RegionSpace
{
SystemMemory = 0,
SystemIO = 1,
PCI_Config = 2,
EmbeddedControl = 3,
SMBus = 4,
CMOS = 5,
PCIBARTarget = 6
}
/// <summary>
/// Abstracts away reading of operation regions such as arbitrary
/// memory read/writes, I/O, and PCI configuration space access.
/// </summary>
public interface IOperationRegionAccessor
{
byte[] ReadBytes(RegionSpace regionSpace, ulong offset, ulong length);
byte Read8(RegionSpace regionSpace, ulong offset);
void Write8(RegionSpace regionSpace, ulong offset, byte value);
ushort Read16(RegionSpace regionSpace, ulong offset);
void Write16(RegionSpace regionSpace, ulong offset, ushort value);
uint Read32(RegionSpace regionSpace, ulong offset);
void Write32(RegionSpace regionSpace, ulong offset, uint value);
}
/// <summary>
/// An ACPI operation region object, representing a region within an
/// address space.
/// </summary>
/// <remarks>From Table 17-6: Reference to an object created using the
/// RefOf, Index, or CondRefOf operators</remarks>
public class OperationRegion : AcpiObject
{
IOperationRegionAccessor accessor;
RegionSpace regionSpace;
ulong startByteIndex;
ulong numBytes;
public OperationRegion(IOperationRegionAccessor accessor,
RegionSpace regionSpace, ulong startByteIndex, ulong numBytes)
{
this.accessor = accessor;
this.regionSpace = regionSpace;
this.startByteIndex = startByteIndex;
this.numBytes = numBytes;
}
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.OperationRegion);
}
public ulong Length
{
get
{
return numBytes;
}
}
//
// These should only be used by FieldUnit.
//
public byte[] ReadBytes(ulong offset, ulong length)
{
if (offset < 0 || offset + length > numBytes) {
throw new ArgumentOutOfRangeException();
}
return accessor.ReadBytes(regionSpace, startByteIndex + offset, length);
}
public byte Read8At(ulong offset)
{
if (offset < 0 || offset >= numBytes) {
throw new ArgumentOutOfRangeException();
}
return accessor.Read8(regionSpace, startByteIndex + offset);
}
public uint Read16At(ulong offset)
{
if (offset < 0 || offset >= numBytes) {
throw new ArgumentOutOfRangeException();
}
return accessor.Read16(regionSpace, startByteIndex + offset);
}
public uint Read32At(ulong offset)
{
if (offset < 0 || offset >= numBytes) {
throw new ArgumentOutOfRangeException();
}
return accessor.Read32(regionSpace, startByteIndex + offset);
}
public void Write8At(ulong offset, byte value)
{
if (offset < 0 || offset >= numBytes) {
throw new ArgumentOutOfRangeException();
}
accessor.Write8(regionSpace, startByteIndex + offset, value);
}
public void Write16At(ulong offset, ushort value)
{
if (offset < 0 || offset >= numBytes) {
throw new ArgumentOutOfRangeException();
}
accessor.Write16(regionSpace, startByteIndex + offset, value);
}
public void Write32At(ulong offset, uint value)
{
if (offset < 0 || offset >= numBytes) {
throw new ArgumentOutOfRangeException();
}
accessor.Write32(regionSpace, startByteIndex + offset, value);
}
public override void Write(AcpiObject value)
{
// Must first create fields inside operation region and then write to those
throw new AmlTypeException("Cannot write directly to operation region");
}
}
/// <summary>
/// An ACPI package object, a fixed-length list of other AcpiObject objects
/// </summary>
/// <remarks>From Table 17-6: Collection of ASL objects with a fixed
/// number of elements (up to 255).</remarks>
public class Package : AcpiObject
{
AcpiObjectCell[] objectList;
public Package(AcpiObjectCell[] objectList)
{
this.objectList = objectList;
}
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.Package);
}
public override AcpiObject Index(ulong index)
{
return objectList[index].Value;
}
public override AcpiObject[] GetObjects()
{
AcpiObject[] result = new AcpiObject[objectList.Length];
for (ulong index = 0; index < (ulong) objectList.Length; index++) {
result[index] = this.Index(index);
}
return result;
}
public override void Write(AcpiObject value)
{
throw new AmlTypeException("Cannot write to package object");
}
}
/// <summary>
/// An ACPI power resource description object.
/// </summary>
/// <remarks>From Table 17-6: Power Resource description object</remarks>
public class PowerResource : AcpiObject
{
public byte systemLevel;
public int resourceOrder;
public PowerResource(byte systemLevel, int resourceOrder)
{
this.systemLevel = systemLevel;
this.resourceOrder = resourceOrder;
}
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.PowerResource);
}
public override void Write(AcpiObject value)
{
throw new AmlTypeException("Cannot write to power resource object");
}
}
/// <summary>
/// An ACPI processor description object.
/// </summary>
/// <remarks>From Table 17-6: Processor description object. See
/// section 17.5.93.</remarks>
public class Processor : AcpiObject
{
byte processorId;
uint pblkAddress;
byte pblkLength;
public Processor(byte processorId, uint pblkAddress, byte pblkLength)
{
this.processorId = processorId;
this.pblkAddress = pblkAddress;
this.pblkLength = pblkLength;
}
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.Processor);
}
public override void Write(AcpiObject value)
{
throw new AmlTypeException("Cannot write to processor object");
}
}
/// <summary>
/// An ACPI string object.
/// </summary>
/// <remarks>From Table 17-6: Null-terminated ASCII string.</remarks>
public class String : AcpiObject
{
string contents;
public String(string contents)
{
for (int i = 0; i < contents.Length; i++) {
if (contents[i] == '\0') {
Debug.Assert(false, "ACPI string contains embedded null");
}
}
this.contents = contents;
}
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.String);
}
public override ulong Size
{
get
{
return (ulong)contents.Length;
}
}
public override AcpiObject Index(ulong index)
{
return new Integer(contents[(int)index]);
}
public string Value
{
get
{
return contents;
}
}
public override String GetAsString()
{
return this;
}
public override string ToString()
{
return contents;
}
public override void Write(AcpiObject value)
{
this.contents = value.GetAsString().Value;
}
}
/// <summary>
/// An ACPI thermal zone description object.
/// </summary>
/// <remarks>From Table 17-6: Thermal Zone description object</remarks>
public class ThermalZone : AcpiObject
{
public ThermalZone()
{
// No data - a thermal zone is described entirely by its name and children
}
public override Integer ObjectType()
{
return new Integer((ulong)AcpiObjectType.ThermalZone);
}
public override void Write(AcpiObject value)
{
throw new AmlTypeException("Cannot write to thermal zone object");
}
}
internal class AcpiObjectUtils
{
public static ulong GetNumBits(ulong value)
{
ulong numBits = 0;
while (value != 0) {
value >>= 1;
numBits++;
}
return numBits;
}
}
}