/////////////////////////////////////////////////////////////////////////////// // // 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. // /// /// Values returned by ObjectType operator as described in section /// 17.5.86 of the ACPI specification 3.0b. /// 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); /// /// Get the value referred to by this value, for creating indirection. /// Returns self for concrete types. /// 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(); } } /// /// Contains a reference to an AcpiObject - this added level of indirection /// is necessary to permit AcpiObject objects to be modified through /// ObjectReference objects. /// 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); } } } } /// /// An uninitialized ACPI object. /// /// 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. 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"); } } /// /// An ACPI buffer object representing an array of bytes. /// /// From Table 17-6: An array of bytes. Uninitialized elements /// are zero by default. 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"); } } /// /// An ACPI buffer field object representing a portion of a buffer. /// /// From Table 17-6: Portion of a buffer created using /// CreateBitField, CreateByteField, CreateWordField, CreateQWordField, /// CreateField, or returned by the Index operator. 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; } } } /// /// An ACPI DDB handle object referring to a Differentiated Definition Block. /// /// From Table 17-6: Definition block handle returned /// by the Load operator [and passed to the Unload operator]. 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"); } } /// /// An ACPI debug object used for formatting and printing debug output. /// /// 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’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. 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 } } /// /// An ACPI device object representing a device or bus. /// /// From Table 17-6: Device or bus object 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; } } /// /// An ACPI event synchronization object /// /// From Table 17-6: Event synchronization object 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 } /// /// An ACPI field unit object referring to a portion of an address space. /// /// 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. 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; } } /// /// This is currently just used by IndexField, will probably become accessible /// from AML when implementing stores. /// 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 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(); 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; } } /// /// 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. /// 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"); } } /// /// An ACPI integer object /// /// 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. 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(); } } /// /// Wrapper class for some static methods referring to ACPI integer /// constant built-in integer constants. /// /// 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. 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 } /// /// An ACPI method object referring to an invokable method. /// /// From Table 17-6: Control Method (Executable AML function) 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"); } } /// /// A method whose body is represented using AML bytecode which can be parsed /// and interpreted. /// 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)); } } /// /// A reserved method implemented directly by the operating system. /// 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))); } } /// /// An ACPI mutex synchronization object /// /// From Table 17-6: Mutex synchronization object 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"); } } /// /// See AmlLoader.LoadTimeEvaluate(AmlParser.UserTermObj userTermObj) /// for an explanation of the existence of this object type, which is /// not defined in the specification. /// 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); } } /// /// An ACPI object reference object referring to some other AcpiObject /// /// From Table 17-6: Reference to an object created using the /// RefOf, Index, or CondRefOf operators 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); } } /// /// From 17.5.89, describes the built-in region spaces in which an /// operation region can be created. /// public enum RegionSpace { SystemMemory = 0, SystemIO = 1, PCI_Config = 2, EmbeddedControl = 3, SMBus = 4, CMOS = 5, PCIBARTarget = 6 } /// /// Abstracts away reading of operation regions such as arbitrary /// memory read/writes, I/O, and PCI configuration space access. /// 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); } /// /// An ACPI operation region object, representing a region within an /// address space. /// /// From Table 17-6: Reference to an object created using the /// RefOf, Index, or CondRefOf operators 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"); } } /// /// An ACPI package object, a fixed-length list of other AcpiObject objects /// /// From Table 17-6: Collection of ASL objects with a fixed /// number of elements (up to 255). 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"); } } /// /// An ACPI power resource description object. /// /// From Table 17-6: Power Resource description object 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"); } } /// /// An ACPI processor description object. /// /// From Table 17-6: Processor description object. See /// section 17.5.93. 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"); } } /// /// An ACPI string object. /// /// From Table 17-6: Null-terminated ASCII string. 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; } } /// /// An ACPI thermal zone description object. /// /// From Table 17-6: Thermal Zone description object 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; } } }