536 lines
17 KiB
C#
536 lines
17 KiB
C#
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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 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 (BootInfo.GetBootInfo().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();
|
|
}
|
|
}
|
|
}
|