/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: MpResources.cs // // Note: // Intel MP Specification 1.4 namespace Microsoft.Singularity.Hal { using Microsoft.Singularity.Io; using Microsoft.Singularity; using Microsoft.Singularity.Hal; using System; using System.Collections; using System.Diagnostics; [CLSCompliant(false)] internal class MpFloatingPointer { private const uint Signature = 0x5f504d5f; internal uint ConfTableBase; internal byte Revision; internal byte [] Feature; internal byte ConfigurationType { get { return Feature[0]; } } internal bool MpConfTablePresent { get { return Feature[0] == 0; } } internal bool ImcrPresent { get { return (Feature[1] & 0x80) != 0; } } internal bool MultipleClockSources { get { return (Feature[1] & 0x40) != 0; } } internal static MpFloatingPointer Parse(IoMemory region) { uint signature = region.Read32(0); if (signature != Signature) { return null; } int length = region.Read8(8) * 16; if (length != 16) { return null; } byte checksum = 0; for (int i = 0; i < length; i++) { checksum += region.Read8((int) i); } if (checksum != 0) { return null; } MpFloatingPointer m = new MpFloatingPointer(); m.ConfTableBase = region.Read32(4); m.Revision = region.Read8(9); m.Feature = new byte [5]; for (int i = 0; i < m.Feature.Length; i++) { m.Feature[i] = region.Read8(0xb + i); } return m; } } [CLSCompliant(false)] internal class MpConfTable { private const uint Signature = 0x504d4350; private const uint FixedLength = 0x2c; internal ushort BaseTableLength; internal byte Revision; internal uint OemTableBase; internal ushort OemTableSize; internal ushort EntryCount; internal uint LocalApicBase; internal ushort ExtendedTableLength; internal byte ExtendedTableChecksum; internal string OemId; internal string ProductId; internal static MpConfTable Parse(IoMemory region) { if (region.Read32(0) != Signature) { return null; } int length = region.Read16(4); DebugStub.Print("MP Conf Table length {0}\n", __arglist(length)); #if NOTYET byte checksum = 0; for (int i = 0; i < length; i++) { checksum += region.Read8(i); } if (checksum != 0) { return null; } #endif MpConfTable confTable = new MpConfTable(); confTable.BaseTableLength = region.Read16(4); confTable.Revision = region.Read8(7); confTable.OemTableBase = region.Read32(0x1c); confTable.OemTableSize = region.Read16(0x20); confTable.EntryCount = region.Read16(0x22); confTable.LocalApicBase = region.Read32(0x24); confTable.ExtendedTableLength = region.Read16(0x28); confTable.ExtendedTableChecksum = region.Read8(0x2a); confTable.OemId = region.ReadAsciiZeroString(8, 8); confTable.ProductId = region.ReadAsciiZeroString(0x10, 0x0c); return confTable; } } [CLSCompliant(false)] internal class MpProcessorEntry { internal const byte EntryType = 0x00; internal const int Length = 0x14; internal byte LocalApicId; internal byte LocalApicVersion; internal byte CpuFlags; internal uint CpuSignature; internal uint FeatureFlags; internal bool Enabled { get { return (CpuFlags & 0x01) != 0; } } internal bool BootStrapProcessor { get { return (CpuFlags & 0x02) != 0; } } [Conditional("MP_TABLE_DEBUG")] internal void DebugPrint() { DebugStub.Print("CPU Apic Id {0:x2} Version {1:x2} CpuFlags {2:x2} " + "Signature {3:x8} Features {4:x8}\n", __arglist( LocalApicId, LocalApicVersion, CpuFlags, CpuSignature, FeatureFlags)); } internal static MpProcessorEntry Parse(IoMemory region, int length, ref int offset) { Debug.Assert(length >= offset + Length); Debug.Assert(region.Read8(offset + 0) == EntryType); MpProcessorEntry e = new MpProcessorEntry(); e.LocalApicId = region.Read8(offset + 1); e.LocalApicVersion = region.Read8(offset + 2); e.CpuFlags = region.Read8(offset + 3); e.CpuSignature = region.Read32(offset + 4); e.FeatureFlags = region.Read32(offset + 8); e.DebugPrint(); offset += Length; return e; } } internal enum BusType : byte { CBUS = 0, CBUSII = 1, EISA = 2, FUTURE = 3, INTERN = 4, ISA = 5, MBI = 6, MBII = 7, MCA = 8, MPI = 9, MPSA = 10, NUBUS = 11, PCI = 12, PCMCIA = 13, TC = 14, VL = 15, VME = 16, XPRESS = 17, LAST = 17, UNKNOWN = 255, } [CLSCompliant(false)] internal class MpBusEntry { internal const byte EntryType = 0x01; internal const int Length = 0x08; // Bus type names 1-1 correspondence with BusType enum. private static string [] busNames = new string [(int)BusType.LAST + 1] { "CBUS ", "CBUSII", "EISA ", "FUTURE", "INTERN", "ISA ", "MBI ", "MBII ", "MCA ", "MPI ", "MPSA ", "NUBUS ", "PCI ", "PCMCIA", "TC ", "VL ", "VME ", "XPRESS" }; internal byte BusId; internal BusType BusType; [Conditional("MP_TABLE_DEBUG")] internal void DebugPrint() { DebugStub.Print("BusId {0:x2} BusType {1:x2}\n", __arglist(BusId, BusName)); } internal string BusName { get { if (BusType == BusType.UNKNOWN) { return "UNKNOWN"; } return busNames[(int)BusType]; } } internal static MpBusEntry Parse(IoMemory region, int length, ref int offset) { Debug.Assert(length >= offset + Length); Debug.Assert(region.Read8(offset + 0) == EntryType); MpBusEntry e = new MpBusEntry(); e.BusId = region.Read8(offset + 1); e.BusType = BusType.UNKNOWN; string name = region.ReadAsciiZeroString(offset + 2, 6); e.BusType = BusType.UNKNOWN; for (int i = 0; i <= (int)BusType.LAST; i++) { if (name == busNames[i]) { e.BusType = (BusType)i; break; } } e.DebugPrint(); offset += Length; return e; } } [CLSCompliant(false)] internal class MpIoApicEntry { internal const byte EntryType = 0x02; internal const int Length = 0x08; internal byte Id; internal byte Version; internal byte Flags; internal uint BaseAddress; internal bool Enabled { get { return (Flags & 0x01) == 0x01; } } [Conditional("MP_TABLE_DEBUG")] internal void DebugPrint() { DebugStub.Print("Id {0:x2} Version {1:x2} Flags {2:x2} BaseAddress {3:x8}\n", __arglist(Id, Version, Flags, BaseAddress)); } internal static MpIoApicEntry Parse(IoMemory region, int length, ref int offset) { Debug.Assert(length >= offset + Length); Debug.Assert(region.Read8(offset + 0) == EntryType); MpIoApicEntry e = new MpIoApicEntry(); e.Id = region.Read8(offset + 1); e.Version = region.Read8(offset + 2); e.Flags = region.Read8(offset + 3); e.BaseAddress = region.Read32(offset + 4); e.DebugPrint(); offset += Length; return e; } } internal enum InterruptType : byte { INT = 0, NMI = 1, SMI = 2, ExtINT = 3, } internal enum Polarity : ushort { Bus = 0, ActiveHigh = 1, Reserved = 2, ActiveLow = 3, } internal enum Trigger : ushort { Bus = 0, Edge = 4, Reserved = 8, Level = 12, } [CLSCompliant(false)] internal class MpInterruptEntry { internal const byte IoEntryType = 0x03; internal const byte LocalEntryType = 0x04; internal const int Length = 0x08; internal byte EntryType; internal byte Interrupt; internal ushort Flags; internal byte BusId; internal byte BusIrq; internal byte ApicId; internal byte ApicLine; internal bool ApicRedirect { get { return Interrupt == (byte)InterruptType.INT; } } internal Polarity PolarityType { get { return (Polarity) (Flags & 0x3); } } internal Trigger TriggerType { get { return (Trigger) (Flags & 0xc); } } [Conditional("MP_TABLE_DEBUG")] internal void DebugPrint() { DebugStub.Print("{0} Interrupt {1:x2} Flags {2:x4} BusId {3:x2} " + "BusIrq {4:x2} ApicId {5:x2} ApicLine {6:x2}\n", __arglist( EntryType == IoEntryType ? "Io" : "Local", Interrupt, Flags, BusId, BusIrq, ApicId, ApicLine)); } internal static MpInterruptEntry Parse(IoMemory region, int length, ref int offset) { Debug.Assert(length >= offset + Length); byte entry = region.Read8(offset + 0); Debug.Assert(entry == IoEntryType || entry == LocalEntryType); MpInterruptEntry e = new MpInterruptEntry(); e.EntryType = entry; e.Interrupt = region.Read8(offset + 1); e.Flags = region.Read16(offset + 2); e.BusId = region.Read8(offset + 4); e.BusIrq = region.Read8(offset + 5); e.ApicId = region.Read8(offset + 6); e.ApicLine = region.Read8(offset + 7); e.DebugPrint(); offset += Length; return e; } } [CLSCompliant(false)] internal class MpResources { static IoMemory mpFloatRegion; static IoMemory mpConfTableRegion; internal static MpFloatingPointer FloatingPointer; internal static MpConfTable ConfTable; internal static ArrayList ProcessorEntries; internal static ArrayList BusEntries; internal static ArrayList IoApicEntries; internal static ArrayList IoInterruptEntries; internal static ArrayList LocalInterruptEntries; internal static void Parse(IoMemory region, int length, uint entryCount) { int offset = 0; for (int i = 0; i < entryCount; i++) { switch (region.Read8(offset)) { case MpProcessorEntry.EntryType: ProcessorEntries.Add( MpProcessorEntry.Parse(region, length, ref offset) ); break; case MpBusEntry.EntryType: BusEntries.Add( MpBusEntry.Parse(region, length, ref offset) ); break; case MpIoApicEntry.EntryType: IoApicEntries.Add( MpIoApicEntry.Parse(region, length, ref offset) ); break; case MpInterruptEntry.IoEntryType: IoInterruptEntries.Add( MpInterruptEntry.Parse(region, length, ref offset) ); break; case MpInterruptEntry.LocalEntryType: LocalInterruptEntries.Add( MpInterruptEntry.Parse(region, length, ref offset) ); break; } } } private static UIntPtr GetMpFloatBase() { unsafe { return new UIntPtr (Platform.ThePlatform.MpFloat32); } } internal static MpBusEntry GetBusEntryById(byte id) { foreach (MpBusEntry be in BusEntries) { if (be.BusId == id) { return be; } } return null; } internal static void ParseMpTables() { UIntPtr mpFloat = GetMpFloatBase(); if (mpFloat == UIntPtr.Zero) { DebugStub.Print("MP Floating Pointer Structure not found.\n"); return; } mpFloatRegion = IoMemory.MapPhysicalMemory(mpFloat, new UIntPtr(16), true, false); FloatingPointer = MpFloatingPointer.Parse(mpFloatRegion); if (FloatingPointer == null) { DebugStub.Print("Failed to parse MP Floating Pointer " + "Structure.\n"); return; } if (FloatingPointer.MpConfTablePresent) { mpConfTableRegion = IoMemory.MapPhysicalMemory( new UIntPtr(FloatingPointer.ConfTableBase), new UIntPtr(0x2c), true, false); DebugStub.Print("Found MP Conf Table\n"); ConfTable = MpConfTable.Parse(mpConfTableRegion); if (ConfTable == null) { DebugStub.Print("Failed to parse MP Configuration table.\n"); } IoMemory mpResourceRegion = IoMemory.MapPhysicalMemory( new UIntPtr(FloatingPointer.ConfTableBase + 0x2c), new UIntPtr(ConfTable.BaseTableLength - 0x2c), true, false); DebugStub.Print("Parsing MP Conf Table Resources\n"); MpResources.Parse(mpResourceRegion, ConfTable.BaseTableLength - 0x2c, ConfTable.EntryCount); } else { DebugStub.Print("MP Configuration table not present.\n"); DebugStub.Print("MP Floating Pointer features: " + "{0:x8} {1:x8} {2:x8} {3:x8} {4:x8}\n", __arglist( FloatingPointer.Feature[0], FloatingPointer.Feature[1], FloatingPointer.Feature[2], FloatingPointer.Feature[3], FloatingPointer.Feature[4])); } } static MpResources() { ProcessorEntries = new ArrayList(); BusEntries = new ArrayList(); IoApicEntries = new ArrayList(); IoInterruptEntries = new ArrayList(); LocalInterruptEntries = new ArrayList(); } } }