public static ACPIObject ReadField(ACPIObject.FieldUnitData fd, IMachineInterface mi) { ACPIObject.OpRegionData oprd = fd.OpRegion.Data as ACPIObject.OpRegionData; ulong addr = oprd.Offset; if ((fd.BitOffset % 8) != 0) { throw new NotImplementedException(); } addr += (ulong)(fd.BitOffset / 8); ulong res = 0; ulong mask = 0xffffffffffffffff; int alength = 0; switch (fd.Access) { case ACPIObject.FieldUnitData.AccessType.ByteAcc: alength = 8; break; case ACPIObject.FieldUnitData.AccessType.WordAcc: alength = 16; break; case ACPIObject.FieldUnitData.AccessType.DWordAcc: alength = 32; break; case ACPIObject.FieldUnitData.AccessType.QWordAcc: alength = 64; break; case ACPIObject.FieldUnitData.AccessType.AnyAcc: alength = fd.BitLength; break; } if (alength <= 8) { alength = 8; } else if (alength <= 16) { alength = 16; } else if (alength <= 32) { alength = 32; } else if (alength <= 64) { alength = 64; } else { throw new Exception("Unsupported access length: " + alength.ToString()); } switch (oprd.RegionSpace) { case 0: // SystemMemory switch (alength) { case 8: res = (ulong)mi.ReadMemoryByte(addr); break; case 16: res = (ulong)mi.ReadMemoryWord(addr); break; case 32: res = (ulong)mi.ReadMemoryDWord(addr); break; case 64: res = (ulong)mi.ReadMemoryQWord(addr); break; } break; case 1: // SystemIO switch (alength) { case 8: res = (ulong)mi.ReadIOByte(addr); break; case 16: res = (ulong)mi.ReadIOWord(addr); break; case 32: res = (ulong)mi.ReadIODWord(addr); break; case 64: res = (ulong)mi.ReadIOQWord(addr); break; } break; case 2: // PCI Conf space { /* ACPI divides the index into 4x 16-bit words: * - highest is reserved (0) * - next is PCI device number * - next is PCI function number * - lowest is offset in configuration space * * ACPI enforces that only bus 0 is used */ ulong bus = 0; ulong idx = (ulong)fd.BitOffset / 8UL; ulong device = (idx >> 32) & 0x1f; // 5 bits for a PCI Device ulong func = (idx >> 16) & 0x7; // 3 bits for function number ulong offset = idx & 0xff; // 8 bits for register number ulong act_offset = offset & 0xfc; // enforce 32-bit access ulong pci_addr = act_offset | (func << 8) | (device << 11); mi.WriteIODWord(0xcf8, (uint)pci_addr); uint v = mi.ReadIODWord(0xcfc); res = (ulong)(v >> (int)(offset - act_offset)); } break; default: throw new NotImplementedException(); } mask >>= (64 - fd.BitLength); res &= mask; return(new ACPIObject(ACPIObject.DataType.Integer, res)); }
public static void WriteField(ACPIObject val, ACPIObject.FieldUnitData fd, IMachineInterface mi) { ACPIObject.OpRegionData oprd = fd.OpRegion.Data as ACPIObject.OpRegionData; ulong addr = oprd.Offset; if ((fd.BitOffset % 8) != 0) { throw new NotImplementedException(); } addr += (ulong)(fd.BitOffset / 8); ulong mask = 0xffffffffffffffff; int alength = 0; switch (fd.Access) { case ACPIObject.FieldUnitData.AccessType.ByteAcc: alength = 8; break; case ACPIObject.FieldUnitData.AccessType.WordAcc: alength = 16; break; case ACPIObject.FieldUnitData.AccessType.DWordAcc: alength = 32; break; case ACPIObject.FieldUnitData.AccessType.QWordAcc: alength = 64; break; case ACPIObject.FieldUnitData.AccessType.AnyAcc: alength = fd.BitLength; break; } if (alength <= 8) { alength = 8; } else if (alength <= 16) { alength = 16; } else if (alength <= 32) { alength = 32; } else if (alength <= 64) { alength = 64; } else { throw new Exception("Unsupported access length: " + alength.ToString()); } switch (oprd.RegionSpace) { case 0: // SystemMemory switch (alength) { case 8: mi.WriteMemoryByte(addr, (byte)val); break; case 16: mi.WriteMemoryWord(addr, (ushort)val); break; case 32: mi.WriteMemoryDWord(addr, (uint)val); break; case 64: mi.WriteMemoryQWord(addr, val); break; } break; case 1: // SystemIO switch (alength) { case 8: mi.WriteIOByte(addr, (byte)val); break; case 16: mi.WriteIOWord(addr, (ushort)val); break; case 32: mi.WriteIODWord(addr, (uint)val); break; case 64: mi.WriteIOQWord(addr, val); break; } break; default: throw new NotImplementedException(); } }
internal void Write(ACPIObject d, int Offset, IMachineInterface mi, Namespace.State s, Namespace n) { if (Type == DataType.Uninitialized || (Type == DataType.ObjectReference && ((ObjRefData)Data).Object == null) || (Type == DataType.Integer && (ulong)Data == 0UL)) { return; } //System.Diagnostics.Debugger.Log(0, "acpipc", "Write: " + d.Type.ToString() + " to " + Type.ToString()); switch (Type) { case DataType.Local: s.Locals[(int)Data] = d; return; case DataType.Arg: s.Args[(int)Data] = d; return; case DataType.Buffer: { ACPIObject new_buf = d.EvaluateTo(DataType.Buffer, mi, s, n); byte[] dst = (byte[])Data; byte[] src = (byte[])new_buf.Data; for (int i = Offset; i < Offset + dst.Length; i++) { if (i < src.Length) { dst[i] = src[i]; } else { dst[i] = 0; } } return; } case DataType.ObjectReference: { ObjRefData ord = Data as ObjRefData; ACPIObject dst = ord.Object; switch (dst.Type) { case DataType.Buffer: dst.Write(d, ord.Index, mi, s, n); return; case DataType.BufferField: dst.Write(d, mi, s, n); return; case DataType.FieldUnit: dst.Write(d, mi, s, n); return; case DataType.Integer: dst.Data = d.EvaluateTo(DataType.Integer, mi, s, n).IntegerData; return; default: throw new NotSupportedException("Write: " + d.Type + " to ObjectReference(" + dst.Type + ")"); } } case DataType.BufferField: { BufferFieldData bfd = Data as BufferFieldData; ACPIObject new_buf_src = d.EvaluateTo(DataType.Buffer, mi, s, n); ACPIObject new_buf_dst = bfd.Buffer.EvaluateTo(DataType.Buffer, mi, s, n); if (bfd.BitOffset % 8 != 0) { throw new NotImplementedException("BitOffset not divisible by 8"); } if (bfd.BitLength % 8 != 0) { throw new NotImplementedException("BitLength not divisible by 8"); } int byte_offset = bfd.BitOffset / 8; int byte_length = bfd.BitLength / 8; byte[] src = (byte[])new_buf_src.Data; byte[] dst = (byte[])new_buf_dst.Data; for (int i = 0; i < byte_length; i++) { dst[byte_offset + i] = src[i]; } return; } case DataType.FieldUnit: if (Data is FieldUnitData) { FieldUnitData fud = Data as FieldUnitData; ACPIObject op_region = fud.OpRegion; if (op_region.Type != DataType.OpRegion) { throw new Exception("Write to FieldUnit with invalid OpRegion type (" + op_region.Type.ToString() + ")"); } OpRegionData ord = op_region.Data as OpRegionData; /* Ensure the requested field index is within the opregion */ int byte_offset = fud.BitOffset / 8; int byte_length = fud.BitLength / 8; if ((ulong)byte_offset + (ulong)byte_length > ord.Length) { throw new Exception("Write: attempt to write to field beyond length of opregion (offset: " + byte_offset.ToString() + ", length: " + byte_length.ToString() + ", OpRegion.Length: " + ord.Length + ")"); } if (fud.BitOffset % 8 != 0) { throw new NotImplementedException("Write: non-byte aligned offset (" + fud.BitOffset.ToString() + ")"); } if (fud.BitLength % 8 != 0) { throw new NotImplementedException("Write: non-byte aligned length (" + fud.BitLength.ToString() + ")"); } /* Get the data */ ulong int_val = d.EvaluateTo(DataType.Integer, mi, s, n).IntegerData; /* Do the write depending on the op region type */ switch (ord.RegionSpace) { case 0: // Memory switch (byte_length) { case 1: mi.WriteMemoryByte(ord.Offset + (ulong)byte_offset, (byte)(int_val & 0xff)); return; case 2: mi.WriteMemoryWord(ord.Offset + (ulong)byte_offset, (ushort)(int_val & 0xffff)); return; case 4: mi.WriteMemoryDWord(ord.Offset + (ulong)byte_offset, (uint)(int_val & 0xffffff)); return; case 8: mi.WriteMemoryQWord(ord.Offset + (ulong)byte_offset, int_val); return; default: throw new NotImplementedException("Write: unsupported byte length: " + byte_length.ToString()); } case 1: // IO switch (byte_length) { case 1: mi.WriteIOByte(ord.Offset + (ulong)byte_offset, (byte)(int_val & 0xff)); return; case 2: mi.WriteIOWord(ord.Offset + (ulong)byte_offset, (ushort)(int_val & 0xffff)); return; case 4: mi.WriteIODWord(ord.Offset + (ulong)byte_offset, (uint)(int_val & 0xffffff)); return; case 8: mi.WriteIOQWord(ord.Offset + (ulong)byte_offset, int_val); return; default: throw new NotImplementedException("Write: unsupported byte length: " + byte_length.ToString()); } case 2: // PCI Configuration space { // try and get the _ADR object for the current device ACPIObject adr = n.Evaluate(ord.Device.ToString() + "._ADR", mi).EvaluateTo(DataType.Integer, mi, s, n); if (adr == null) { throw new Exception(ord.Device.ToString() + "._ADR failed"); } uint bus = 0; uint device = ((uint)adr.IntegerData >> 16) & 0xffffU; uint func = (uint)adr.IntegerData & 0xffffU; uint offset = (uint)ord.Offset + (uint)byte_offset; switch (byte_length) { case 1: mi.WritePCIByte(bus, device, func, offset, (byte)int_val); return; case 2: mi.WritePCIWord(bus, device, func, offset, (ushort)int_val); return; case 4: mi.WritePCIDWord(bus, device, func, offset, (uint)int_val); return; default: throw new NotImplementedException("Write: unsupported byte length: " + byte_length.ToString()); } } default: throw new NotImplementedException("Write: unsupported OpRegion type: " + ord.ToString()); } } else if (Data is IndexFieldUnitData) { var ifud = Data as IndexFieldUnitData; /* Ensure the requested field index is byte aligned */ int byte_offset = ifud.BitOffset / 8; int byte_length = ifud.BitLength / 8; if (ifud.BitOffset % 8 != 0) { throw new NotImplementedException("Read: non-byte aligned offset (" + ifud.BitOffset.ToString() + ")"); } if (ifud.BitLength % 8 != 0) { throw new NotImplementedException("Read: non-byte aligned length (" + ifud.BitLength.ToString() + ")"); } /* Get the data */ ulong int_val = d.EvaluateTo(DataType.Integer, mi, s, n).IntegerData; /* Write to index port, write to data port */ ifud.Index.Write((ulong)byte_offset, mi, s, n); ifud.Data.Write(int_val, mi, s, n); return; } else { throw new NotSupportedException("Invalid FieldUnit data type: " + Data.ToString()); } default: throw new NotImplementedException("Write: " + Type.ToString()); } throw new NotImplementedException(); }