singrdk/base/Kernel/Singularity.Hal.Acpi/Madt.cs

461 lines
16 KiB
C#
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: AcpiTables.cs
//
// Note:
// Pages of 111-121 ACPI 3.0 Spec.
namespace Microsoft.Singularity.Hal.Acpi
{
using System;
using System.Collections;
using System.Diagnostics;
using Microsoft.Singularity.Io;
public struct MadtFlags
{
public const uint PCAT_COMPAT_FLAG = 0x01;
}
public class Madt
{
public const string Signature = "APIC";
private IoMemory region;
private SystemTableHeader header;
uint localApicAddress;
uint flags; // Values per MadtFlags
private Madt(IoMemory region, SystemTableHeader header)
{
this.region = region;
this.header = header;
localApicAddress = region.Read32(0);
flags = region.Read32(4);
// XXX Just for debugging
GetLocalApics();
GetIoApics();
GetInterruptSourceOverrides();
GetNmis();
GetApicNmis();
GetLocalApicAddressOverrides();
GetIoSApics();
GetLocalSApics();
GetPlatformInterruptSources();
}
///////////////////////////////////////////////////////////////////////
// Structure and method to get MADT table items generically
private delegate object ItemCreateDelegate(IoMemory mem, int offset);
private ArrayList GetStructures(byte typeId,
ItemCreateDelegate createMethod)
{
ArrayList l = new ArrayList();
int offset = 8;
while (offset < region.Length)
{
if (region.Read8(offset) == typeId)
{
object entry = createMethod(region, offset);
if (entry != null)
{
l.Add(entry);
}
}
offset += region.Read8(offset + 1);
}
return l;
}
///////////////////////////////////////////////////////////////////////
// Methods to get MADT items of particular types
public ArrayList GetLocalApics()
{
return GetStructures(LocalApic.TypeId,
new ItemCreateDelegate(LocalApic.Create));
}
public ArrayList GetIoApics()
{
return GetStructures(IoApic.TypeId,
new ItemCreateDelegate(IoApic.Create));
}
public ArrayList GetInterruptSourceOverrides()
{
return GetStructures(InterruptSourceOverride.TypeId,
new ItemCreateDelegate(InterruptSourceOverride.Create));
}
public ArrayList GetNmis()
{
return GetStructures(Nmi.TypeId,
new ItemCreateDelegate(Nmi.Create));
}
public ArrayList GetApicNmis()
{
return GetStructures(ApicNmi.TypeId,
new ItemCreateDelegate(ApicNmi.Create));
}
public ArrayList GetLocalApicAddressOverrides()
{
return GetStructures(LocalApicAddressOverride.TypeId,
new ItemCreateDelegate(LocalApicAddressOverride.Create));
}
public ArrayList GetIoSApics()
{
return GetStructures(IoSApic.TypeId,
new ItemCreateDelegate(IoSApic.Create));
}
public ArrayList GetLocalSApics()
{
return GetStructures(LocalSApic.TypeId,
new ItemCreateDelegate(LocalSApic.Create));
}
public ArrayList GetPlatformInterruptSources()
{
return GetStructures(PlatformInterruptSource.TypeId,
new ItemCreateDelegate(PlatformInterruptSource.Create));
}
///////////////////////////////////////////////////////////////////////
//
internal static Madt Create(SystemTableHeader header)
{
IoMemory region = IoMemory.MapPhysicalMemory(header.PostHeaderAddress,
header.PostHeaderLength,
true, false);
int sum = (header.Checksum + AcpiChecksum.Compute(region)) & 0xff;
if (sum != 0)
{
return null;
}
return new Madt(region, header);
}
}
///////////////////////////////////////////////////////////////////////////
// MADT APIC Structure Constants
public struct ApicFlags
{
public const uint Enabled = 0x01;
}
public struct MpsIntiFlags
{
public const ushort PolarityBus = 0;
public const ushort PolarityActiveHigh = 1;
public const ushort PolarityActiveLow = 3;
public const ushort PolarityMask = 3;
public const ushort TriggerBus = 0;
public const ushort TriggerEdge = 4;
public const ushort TriggerLevel = 6;
public const ushort TriggerMask = 6;
}
public struct PlatformInterruptType
{
public const uint PMI = 1;
public const uint INIT = 2;
public const uint CorrectedPlatformErrorInterrupt = 3;
}
public struct PlatformInterruptSourceFlags
{
public const uint CpeiProcessorOverride = 1;
}
///////////////////////////////////////////////////////////////////////////
// MADT APIC Structures
public class LocalApic
{
internal const byte TypeId = 0x00;
internal const byte Length = 8;
public byte AcpiProcessorId;
public byte ApicId;
public uint Flags; // Values per ApicFlags
internal LocalApic(IoMemory region, int offset)
{
Debug.Assert(region.Read8(offset + 0) == TypeId);
Debug.Assert(region.Read8(offset + 1) == Length);
AcpiProcessorId = region.Read8(offset + 2);
ApicId = region.Read8(offset + 3);
Flags = region.Read32(offset + 4);
// DebugStub.Print("{0:x4}:{1:x4} type {2:x1} AcpiProcId {3:x2} ApicId {4:x2} Flags {5:x8} (LocalApic)\n", __arglist(offset, offset + Length, TypeId, AcpiProcessorId, ApicId, Flags));
}
internal static object Create(IoMemory region, int offset)
{
LocalApic entry = new LocalApic(region, offset);
// Only return usable entries
return ((entry.Flags & 1) == 1
? entry
: null);
}
}
public class IoApic
{
internal const byte TypeId = 0x01;
internal const byte Length = 12;
public byte Id;
public uint Address;
public uint InterruptBase;
internal IoApic(IoMemory region, int offset)
{
Debug.Assert(region.Read8(offset + 0) == TypeId);
Debug.Assert(region.Read8(offset + 1) == Length);
Id = region.Read8(offset + 2);
// reserved = region.Read8(offset + 3);
Address = region.Read32(offset + 4);
InterruptBase = region.Read32(offset + 8);
// DebugStub.Print("{0:x4}:{1:x4} type {2:x1} Id {3:x2} Address {4:x8} InterruptBase {5:x8} (IoApic)\n", __arglist(offset, offset + Length, TypeId, Id, Address, InterruptBase));
}
internal static object Create(IoMemory region, int offset)
{
return new IoApic(region, offset);
}
}
public class InterruptSourceOverride
{
internal const byte TypeId = 0x02;
internal const byte Length = 10;
public byte Bus;
public byte Source;
public uint GlobalSystemInterrupt;
public ushort Flags; // Values per MpsIntiFlags
internal InterruptSourceOverride(IoMemory region, int offset)
{
Debug.Assert(region.Read8(offset + 0) == TypeId);
Debug.Assert(region.Read8(offset + 1) == Length);
Bus = region.Read8(offset + 2);
Source = region.Read8(offset + 3);
GlobalSystemInterrupt = region.Read32(offset + 4);
Flags = region.Read16(offset + 8);
// DebugStub.Print("{0:x4}:{1:x4} type {2:x1} Bus {3:x2} Source {4:x2} GlobalSystemInterrupt {5:x8} Flags {6:x2} (InterruptSourceOverride)\n", __arglist(offset, offset + Length, TypeId, Bus, Source, GlobalSystemInterrupt, Flags));
}
internal static object Create(IoMemory region, int offset)
{
return new InterruptSourceOverride(region, offset);
}
}
public class Nmi
{
internal const byte TypeId = 0x03;
internal const byte Length = 8;
public ushort Flags; // Values per MpsIntiFlags
public uint GlobalSystemInterrupt;
internal Nmi(IoMemory region, int offset)
{
Debug.Assert(region.Read8(offset + 0) == TypeId);
Debug.Assert(region.Read8(offset + 1) == Length);
Flags = region.Read16(offset + 2);
GlobalSystemInterrupt = region.Read32(offset + 4);
// DebugStub.Print("{0:x4}:{1:x4} type {2:x1} Flags {3:x2} GlobalSystemInterrupt {4:x8} (Nmi)\n", __arglist(offset, offset + Length, TypeId, Flags, GlobalSystemInterrupt));
}
internal static object Create(IoMemory region, int offset)
{
return new Nmi(region, offset);
}
}
public class ApicNmi
{
internal const byte TypeId = 0x04;
internal const byte Length = 6;
public byte AcpiProcessorId;
public ushort Flags; // Values per MpsIntiFlags
public byte LocalApicLint;
internal ApicNmi(IoMemory region, int offset)
{
Debug.Assert(region.Read8(offset + 0) == TypeId);
Debug.Assert(region.Read8(offset + 1) == Length);
AcpiProcessorId = region.Read8(offset + 2);
Flags = region.Read16(offset + 3);
LocalApicLint = region.Read8(offset + 5);
// DebugStub.Print("{0:x4}:{1:x4} type {2:x1} ApicProcessorId {3:x2} Flags {4:x4} LocalApicLint {5:x2} (ApicNmi)\n", __arglist(offset, offset + Length, TypeId, AcpiProcessorId, Flags, LocalApicLint));
}
internal static object Create(IoMemory region, int offset)
{
return new ApicNmi(region, offset);
}
}
public class LocalApicAddressOverride
{
internal const byte TypeId = 0x05;
internal const byte Length = 12;
ulong LocalApicAddress;
internal LocalApicAddressOverride(IoMemory region, int offset)
{
Debug.Assert(region.Read8(offset + 0) == TypeId);
Debug.Assert(region.Read8(offset + 1) == Length);
// reserved = region.Read16(offset + 2);
LocalApicAddress = region.Read64(offset + 4);
// DebugStub.Print("{0:x04}:{1:x04} type {2:x01} LocalApicAddress {3:x016} (LocalApicAddressOverride)\n", __arglist(offset, offset + Length, TypeId, LocalApicAddress));
}
internal static object Create(IoMemory region, int offset)
{
return new LocalApicAddressOverride(region, offset);
}
}
public class IoSApic
{
internal const byte TypeId = 0x6;
internal const byte Length = 16;
internal byte Id;
internal uint InterruptBase;
internal ulong Address;
internal IoSApic(IoMemory region, int offset)
{
Debug.Assert(region.Read8(offset + 0) == TypeId);
Debug.Assert(region.Read8(offset + 1) == Length);
Id = region.Read8(offset + 2);
// reserved = region.Read8(offset + 3);
InterruptBase = region.Read32(offset + 4);
Address = region.Read64(offset + 8);
// DebugStub.Print("{0:x04}:{1:x04} type {2:x01} Id {3:x02} InterruptBase {4:x04} Address {5:x016} (IoSApic)\n", __arglist(offset, offset + Length, TypeId, Id, InterruptBase, Address));
}
internal static object Create(IoMemory region, int offset)
{
return new IoSApic(region, offset);
}
}
public class LocalSApic
{
internal const byte TypeId = 0x07;
internal const byte MinLength = 17;
public byte AcpiProcessorId;
public byte LocalSApicId;
public byte LocalSApicEid;
public uint Flags; // Values per ApicFlags
public uint AcpiProcessorUidValue;
public string AcpiProcessorUidString;
internal LocalSApic(IoMemory region, int offset)
{
Debug.Assert(region.Read8(offset + 0) == TypeId);
byte length = region.Read8(offset + 1);
Debug.Assert(length >= MinLength);
AcpiProcessorId = region.Read8(offset + 2);
LocalSApicId = region.Read8(offset + 3);
LocalSApicEid = region.Read8(offset + 4);
// reserved = region.Read24(offset + 5);
Flags = region.Read32(offset + 8);
AcpiProcessorUidValue = region.Read32(offset + 12) ;
AcpiProcessorUidString = region.ReadString(offset + 16,
(int)length - 17);
// DebugStub.Print("{0:x04}:{1:x04} type {2:x01} AcpiProcId {3:x02} LocalSApicId {4:x02} LocalSApicEid {5:x02} Flags {6:x08} AcpiProcUid {7:x04} AcpiProcUid \"{8}\" (LocalSApic)\n", __arglist(offset, offset + length, TypeId, AcpiProcessorId, LocalSApicId, LocalSApicEid, Flags, AcpiProcessorUidValue, AcpiProcessorUidString));
}
internal static object Create(IoMemory region, int offset)
{
return new LocalSApic(region, offset);
}
}
public class PlatformInterruptSource
{
internal const byte TypeId = 0x8;
internal const byte Length = 16;
public ushort Flags; // Values per MpsIntiFlags
public byte InterruptType; // PlatformInterruptType
public byte ProcessorId;
public byte ProcessorEid;
public byte IoSApicVector;
public uint GlobalSystemInterrupt;
public uint SourceFlags; // PlatformInterruptSourceFlags
internal PlatformInterruptSource(IoMemory region, int offset)
{
Debug.Assert(region.Read8(offset + 0) == TypeId);
Debug.Assert(region.Read8(offset + 1) == Length);
Flags = region.Read16(offset + 2);
InterruptType = region.Read8(offset + 4);
ProcessorId = region.Read8(offset + 5);
ProcessorEid = region.Read8(offset + 6);
IoSApicVector = region.Read8(offset + 7);
GlobalSystemInterrupt = region.Read32(offset + 8);
SourceFlags = region.Read32(offset + 12);
// DebugStub.Print("{0:x04}:{1:x04} type {2:x01} Flags {3:x04} InterruptType {4:x02} ProcessorId {5:x02} ProcessorEid {6:x02} IoSApicVector {7:x02} GlobalSystemInterrupt {8:x04} SourceFlags {9:x04} (PlatformInterruptSource)\n", __arglist(offset, offset + Length, TypeId, Flags, InterruptType, ProcessorId, ProcessorEid, IoSApicVector, GlobalSystemInterrupt, SourceFlags));
}
internal static object Create(IoMemory region, int offset)
{
return new PlatformInterruptSource(region, offset);
}
}
}