singrdk/base/Applications/procmeminfo/ProcMemInfo.sg

651 lines
25 KiB
Plaintext

////////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: ProcMemInfo.cs
//
//
// Note: Simple Windows XP-like ProcMemInfo program.
//
using System;
using System.Collections;
using System.Runtime.CompilerServices;
using System.Threading;
using Microsoft.Singularity;
using Microsoft.Singularity.Channels;
using Microsoft.Singularity.Diagnostics.Contracts;
using Microsoft.Singularity.Configuration;
using Microsoft.Singularity.Io;
using Microsoft.Singularity.Directory;
using Microsoft.Singularity.V1.Services;
using Microsoft.SingSharp;
using Microsoft.Contracts;
using Microsoft.SingSharp.Reflection;
using Microsoft.Singularity.Applications;
[assembly: Transform(typeof(ApplicationResourceTransform))]
namespace Microsoft.Singularity.Applications
{
[ConsoleCategory(HelpMessage=
"ProcMemInfo [options] Display Processor Cache info",
DefaultAction=true)]
internal sealed class Parameters
{
[Endpoint]
public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
[Endpoint]
public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
[Endpoint]
public readonly TRef<ProcMemInfoContract.Imp:Start> pmInfoRef;
[BoolParameter( "d", Default=true , HelpMessage=
"Dumps output and PageTable to Debugger.")]
internal bool dumpTable;
reflective internal Parameters();
internal int AppMain() {
return ProcMemInfo.AppMain(this);
}
}
public class ProcMemInfo
{
// Check if processor is Intel/AMD
internal static bool isIntel(uint ebx, uint ecx, uint edx)
{
if (ebx == 0x756e6547 && ecx == 0x6c65746e && edx == 0x49656e69) {
return true;
}
else {
return false;
}
}
// Check if processor is Intel/AMD
internal static bool isAMD(uint ebx, uint ecx, uint edx)
{
if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65) {
return true;
}
else {
return false;
}
}
// Call CPUID with all possible inputs (EAX=1-5,8000_0001-8000_000A)
internal static void DoTestAllCpuId(Parameters! config)
{
bool dumpTable = config.dumpTable;
uint v0, v1, v2, v3;
WriteLine(dumpTable, "\n");
WriteLine(dumpTable, "----------------------------------------");
WriteLine(dumpTable, "TESTING ALL CPUID ");
WriteLine(dumpTable, "----------------------------------------\n");
for (uint i = 0; i < 6; i++) {
Processor.ReadCpuid(i, out v0, out v1, out v2, out v3);
WriteLine(dumpTable, "{0:x8} : {1:x8}.{2:x8}.{3:x8}.{4:x8}",
i, v0, v1, v2, v3);
}
for (uint i = 0x80000000; i < 0x80000010; i++) {
Processor.ReadCpuid(i, out v0, out v1, out v2, out v3);
WriteLine(dumpTable, "{0:x8} : {1:x8}.{2:x8}.{3:x8}.{4:x8}",
i, v0, v1, v2, v3);
}
WriteLine(dumpTable, "\n");
}
// Get AMD Processor Cache Information
internal static void GetAmdInfo(Parameters! config)
{
bool dumpTable = config.dumpTable;
uint v0, v1, v2, v3;
WriteLine(dumpTable, "\n");
WriteLine(dumpTable, "----------------------------------------");
WriteLine(dumpTable, "PROCESSOR CACHE INFORMATION (from CPUID)");
WriteLine(dumpTable, "----------------------------------------\n");
// Call CPUID with Input EAX=1, 8000_0005H and 8000_0006H
GetAmdInput1(config);
GetAmdInput85(config);
GetAmdInput86(config);
}
// EAX = 1
// a : Processor Signature
// b : Initial APIC ID, CLFLUSH Size, Brand ID
// c : Reserved
// d : Standard Feature support
internal static void GetAmdInput1(Parameters! config)
{
uint a, b, c, d;
uint eax = 1;
bool dumpTable = config.dumpTable;
Processor.ReadCpuid(eax, out a, out b, out c, out d);
// -------------------------------------- output EAX
uint stepping = (a & 0x0000000f);
uint model = (a & 0x000000f0) >> 4;
uint family = (a & 0x00000f00) >> 8;
uint xModel = (a & 0x000f0000) >> 16;
uint xFamily = (a & 0x0ff00000) >> 20;
// from AMD, CPUID manual:
// computing effective family/model computation
uint effFamily = family;
if (family == 0x0f) {
effFamily = (xFamily + family);
}
uint effModel = model;
if (family == 0x0f) {
effModel = (xModel << 4) + model;
}
/// -------------------------------------- output EBX
uint brandId = (b & 0x000000ff);
uint clflush = (b & 0x0000ff00) >> 8;
uint apicId = (b & 0xff000000) >> 24;
Write(dumpTable, "\nInput EAX={0:x8} ", eax);
Write(dumpTable,"output:{1:x8}.{2:x8}.{3:x8}.{4:x8}\n\n",
eax, a, b, c, d);
if (a == 0 && b == 0 && c == 0 && d == 0) {
return;
}
WriteLine(dumpTable, " Output EAX:");
WriteLine(dumpTable, " Stepping {0}", stepping);
WriteLine(dumpTable, " Model {0}", model);
WriteLine(dumpTable, " Family {0}", family);
WriteLine(dumpTable, " xModel {0}", xModel);
WriteLine(dumpTable, " xFamily {0}", xFamily);
WriteLine(dumpTable, " effFamily {0}", effFamily);
WriteLine(dumpTable, " effModel {0}", effModel);
WriteLine(dumpTable, " Output EBX:");
WriteLine(dumpTable, " Brand Id {0}", brandId);
WriteLine(dumpTable, " CLFLUSH Size {0}", clflush);
WriteLine(dumpTable, " APIC ID {0}", apicId);
// -------------------------------------- output EDX
WriteLine(dumpTable, " Output EDX:");
Write(dumpTable, " ");
if ((d & 0x1) > 0) { Write(dumpTable, "x87 "); }
if ((d & 0x2) > 0) { Write(dumpTable, "VME "); }
if ((d & 0x4) > 0) { Write(dumpTable, "DBG "); }
if ((d & 0x8) > 0) { Write(dumpTable, "PSE "); }
if ((d & 0x10) > 0) { Write(dumpTable, "TSC "); }
if ((d & 0x20) > 0) { Write(dumpTable, "MSR "); }
if ((d & 0x40) > 0) { Write(dumpTable, "PAE "); }
if ((d & 0x80) > 0) { Write(dumpTable, "MCE "); }
Write(dumpTable, "\n ");
if ((d & 0x100) > 0) { Write(dumpTable, "CX8 "); }
if ((d & 0x200) > 0) { Write(dumpTable, "APIC "); }
if ((d & 0x200) > 0) { Write(dumpTable, "R0 "); }
if ((d & 0x800) > 0) { Write(dumpTable, "SEP "); }
if ((d & 0x1000) > 0) { Write(dumpTable, "MTRR "); }
if ((d & 0x2000) > 0) { Write(dumpTable, "PGE "); }
if ((d & 0x4000) > 0) { Write(dumpTable, "MCA "); }
if ((d & 0x8000) > 0) { Write(dumpTable, "CMOV "); }
Write(dumpTable, "\n ");
if ((d & 0x10000) > 0) { Write(dumpTable, "PAT "); }
if ((d & 0x20000) > 0) { Write(dumpTable, "P36 "); }
if ((d & 0x40000) > 0) { Write(dumpTable, "R1 "); }
if ((d & 0x80000) > 0) { Write(dumpTable, "CFL "); }
if ((d & 0x100000) > 0) { Write(dumpTable, "R2 "); }
if ((d & 0x200000) > 0) { Write(dumpTable, "R3 "); }
if ((d & 0x400000) > 0) { Write(dumpTable, "R4 "); }
if ((d & 0x800000) > 0) { Write(dumpTable, "MMX "); }
Write(dumpTable, "\n ");
if ((d & 0x1000000) > 0) { Write(dumpTable, "FXSR "); }
if ((d & 0x2000000) > 0) { Write(dumpTable, "SSE "); }
if ((d & 0x4000000) > 0) { Write(dumpTable, "SSE2 "); }
if ((d & 0x8000000) > 0) { Write(dumpTable, "R5 "); }
if ((d & 0x10000000) > 0){ Write(dumpTable, "R6 "); }
if ((d & 0x20000000) > 0){ Write(dumpTable, "R7 "); }
if ((d & 0x40000000) > 0){ Write(dumpTable, "R8 "); }
if ((d & 0x80000000) > 0){ Write(dumpTable, "R9 "); }
Write(dumpTable, "\n");
}
// EAX = 8000_0005
// a : TLB Bits for 2 MB and 4MB
// b : TLB Bits for 4 KB
// c : L1 Data Cache Bits
// d : L1 Instruction Cache Bits
internal static void GetAmdInput85(Parameters! config)
{
uint a, b, c, d;
uint eax = 0x80000005;
bool dumpTable = config.dumpTable;
Processor.ReadCpuid(eax, out a, out b, out c, out d);
Write(dumpTable, "\nInput EAX={0:x8} ", eax);
Write(dumpTable,"output:{1:x8}.{2:x8}.{3:x8}.{4:x8}\n\n",
eax, a, b, c, d);
if (a == 0 && b == 0 && c == 0 && d == 0) {
return;
}
uint a1 = (a & 0x000000ff) >> 0;
uint a2 = (a & 0x0000ff00) >> 8;
uint a3 = (a & 0x00ff0000) >> 16;
uint a4 = (a & 0xff000000) >> 24;
uint b1 = (b & 0x000000ff) >> 0;
uint b2 = (b & 0x0000ff00) >> 8;
uint b3 = (b & 0x00ff0000) >> 16;
uint b4 = (b & 0xff000000) >> 24;
uint c1 = (c & 0x000000ff) >> 0;
uint c2 = (c & 0x0000ff00) >> 8;
uint c3 = (c & 0x00ff0000) >> 16;
uint c4 = (c & 0xff000000) >> 24;
uint d1 = (d & 0x000000ff) >> 0;
uint d2 = (d & 0x0000ff00) >> 8;
uint d3 = (d & 0x00ff0000) >> 16;
uint d4 = (d & 0xff000000) >> 24;
// -------------------------------------- output EAX
WriteLine(dumpTable, " Output EAX:");
WriteLine(dumpTable, " 2MB Inst TLB, Entries {0}", a1);
WriteLine(dumpTable, " 2MB Inst TLB, Assctvy {0}", Assoc(a2));
WriteLine(dumpTable, " 2MB Data TLB, Entries {0}", a3);
WriteLine(dumpTable, " 2MB Data TLB, Assctvy {0}", Assoc(a4));
// -------------------------------------- output EBX
WriteLine(dumpTable, " Output EBX:");
WriteLine(dumpTable, " 4KB Inst TLB, Entries {0}", b1);
WriteLine(dumpTable, " 4KB Inst TLB, Assctvy {0}", Assoc(b2));
WriteLine(dumpTable, " 4KB Data TLB, Entries {0}", b3);
WriteLine(dumpTable, " 4KB Data TLB, Assctvy {0}", Assoc(b4));
// -------------------------------------- output ECX
WriteLine(dumpTable, " Output ECX:");
WriteLine(dumpTable, " L1 Data, Line Size {0}", c1);
WriteLine(dumpTable, " L1 Data, Lines/Tag {0}", c2);
WriteLine(dumpTable, " L1 Data, Assctvy {0}", Assoc(c3));
WriteLine(dumpTable, " L1 Data, Size (KB) {0}", c4);
// -------------------------------------- output EDX
WriteLine(dumpTable, " Output EDX:");
WriteLine(dumpTable, " L1 Inst , Line Size {0}", d1);
WriteLine(dumpTable, " L1 Inst , Lines/Tag {0}", d2);
WriteLine(dumpTable, " L1 Inst , Assctvy {0}", Assoc(d3));
WriteLine(dumpTable, " L1 Inst , Size (KB) {0}", d4);
}
// Convert associativity code to associativity in string
internal static string Assoc(uint associativity)
{
switch (associativity) {
case 0: return "Reserved"; break;
case 1: return "Direct Mapped"; break;
case 0xff: return "Fully Assoc"; break;
default :
return string.Format("{0}-way", associativity);
break;
}
}
// Similar to Assoc() but specific for L2 cache
internal static string AssocL2(uint associativity)
{
switch (associativity) {
case 0: return "Off/Disabled"; break;
case 1: return "Direct Mapped"; break;
case 0x02: return "2-way"; break;
case 0x04: return "4-way"; break;
case 0x06: return "8-way"; break;
case 0x08: return "16-way"; break;
case 0x0f: return "Fully Assoc"; break;
default :
return "Reserved (disabled?)";
break;
}
}
// Check if L2 is reserved according to the associativity code
internal static bool IsL2Reserved(uint associativity)
{
switch (associativity)
{
case 0:
case 1:
case 0x02:
case 0x04:
case 0x06:
case 0x08:
case 0x0f:
return false;
break;
default :
return true;
break;
}
}
// EAX = 8000_0006
// a : L2 TLB Bits for 2 MB / 4 MB pages
// b : L2 TLB Bits for 4 KB
// c : L2 Cache Bits
// d : reserved
internal static void GetAmdInput86(Parameters! config)
{
uint a, b, c, d;
uint eax = 0x80000006;
bool dumpTable = config.dumpTable;
Processor.ReadCpuid(eax, out a, out b, out c, out d);
uint a1 = (a & 0x000000ff) >> 0;
uint a2 = (a & 0x0000ff00) >> 8;
uint a3 = (a & 0x00ff0000) >> 16;
uint a4 = (a & 0xff000000) >> 24;
uint b1 = (b & 0x000000ff) >> 0;
uint b2 = (b & 0x0000ff00) >> 8;
uint b3 = (b & 0x00ff0000) >> 16;
uint b4 = (b & 0xff000000) >> 24;
uint c1 = (c & 0x000000ff) >> 0;
uint c2 = (c & 0x0000ff00) >> 8;
uint c3 = (c & 0x00ff0000) >> 16;
uint c4 = (c & 0xff000000) >> 24;
Write(dumpTable, "\nInput EAX={0:x8} ", eax);
Write(dumpTable,"output:{1:x8}.{2:x8}.{3:x8}.{4:x8}\n\n",
eax, a, b, c, d);
if (a == 0 && b == 0 && c == 0 && d == 0) {
return;
}
// -------------------------------------- output EAX
WriteLine(dumpTable, " Output EAX:");
if (a2 == 0) {
WriteLine(dumpTable, " 2MB L2 Inst TLB is disabled");
}
else if (IsL2Reserved(a2)) {
WriteLine(dumpTable, " 2MB L2 Inst TLB is reserved");
}
else {
WriteLine(dumpTable, " 2MB L2 Inst TLB, Entries {0}", a1);
WriteLine(dumpTable, " 2MB L2 Inst TLB, Assctvy {0}",
AssocL2(a2));
}
if (a4 == 0) {
WriteLine(dumpTable, " 2MB L2 Data TLB is disabled");
}
else if (IsL2Reserved(a4)) {
WriteLine(dumpTable, " 2MB L2 Inst TLB is reserved");
}
else {
WriteLine(dumpTable, " 2MB L2 Data TLB, Entries {0}", a3);
WriteLine(dumpTable, " 2MB L2 Data TLB, Assctvy {0}",
AssocL2(a4));
}
// -------------------------------------- output EBX
WriteLine(dumpTable, " Output EBX:");
if (b2 == 0) {
WriteLine(dumpTable, " 4KB L2 Inst TLB is disabled");
}
else if (IsL2Reserved(b2)) {
WriteLine(dumpTable, " 4KB L2 Inst TLB is reserved");
}
else {
WriteLine(dumpTable, " 4KB L2 Inst TLB, Entries {0}", b1);
WriteLine(dumpTable, " 4KB L2 Inst TLB, Assctvy {0}",
AssocL2(b2));
}
if (b4 == 0) {
WriteLine(dumpTable, " 4KB L2 Data TLB is disabled");
}
else if (IsL2Reserved(b4))
{
WriteLine(dumpTable, " 4KB L2 Data TLB is reserved");
}
else
{
WriteLine(dumpTable, " 4KB L2 Data TLB, Entries {0}", b3);
WriteLine(dumpTable, " 4KB L2 Data TLB, Assctvy {0}",
AssocL2(b4));
}
// -------------------------------------- output ECX
WriteLine(dumpTable, " Output ECX:");
if (c3 == 0)
{
WriteLine(dumpTable, " L2 Cache is disabled");
}
else if (IsL2Reserved(c3))
{
WriteLine(dumpTable, " L2 Cache is reserved");
}
else
{
WriteLine(dumpTable, " L2, Line Size {0}", c1);
WriteLine(dumpTable, " L2, Lines Per Tag {0}", c2);
WriteLine(dumpTable, " L2, Associativity {0}", c3);
WriteLine(dumpTable, " L2, Size (KB) {0}", c4);
}
}
// Call GetCPUID
internal static void DoTestGetCpuId(Parameters! config)
{
bool intel = false, amd = false;
uint a, b, c, d;
Processor.ReadCpuid(0, out a, out b, out c, out d);
intel = isIntel(b, c, d);
amd = isAMD(b, c, d);
if (intel) {
// haryadi: I haven't implemented Intel config yet
// GetIntelInfo(config);
}
else if (amd) {
GetAmdInfo(config);
}
}
// Get Processor and Memory Affinity
internal static void DoTestGetAffinity(Parameters! config)
{
bool dumpTable = config.dumpTable;
ProcMemInfoContract.ProcessorAffinity[] in ExHeap processors;
ProcMemInfoContract.MemoryAffinity[] in ExHeap memories;
ProcMemInfoContract.Imp imp = config.pmInfoRef.Acquire();
if (imp == null) {
throw new ApplicationException("Error: Unable to bind to " +
ProcMemInfoContract.ModuleName);
}
imp.SendGetProcessorAffinity();
imp.RecvResultProcessorAffinity(out processors);
imp.SendGetMemoryAffinity();
imp.RecvResultMemoryAffinity(out memories);
WriteLine(dumpTable, "\n");
WriteLine(dumpTable, "----------------------------------------");
WriteLine(dumpTable, "PROCESSOR AFFINITY INFORMATION");
WriteLine(dumpTable, "----------------------------------------\n");
if (processors == null) {
WriteLine(dumpTable, "There is no Processor Affinity info!");
}
else {
WriteLine(dumpTable, "Found {0} processors\n",
processors.Length);
for (int i = 0; i < processors.Length; i++) {
WriteLine(dumpTable, "Processor #{0}", i);
WriteLine(dumpTable, " domain : {0}",
processors[i].domain);
WriteLine(dumpTable, " apicId : {0}",
processors[i].apicId);
WriteLine(dumpTable, " flagIgnore : {0}\n",
processors[i].flagIgnore);
}
}
WriteLine(dumpTable, "\n");
WriteLine(dumpTable, "----------------------------------------");
WriteLine(dumpTable, "MEMORY AFFINITY INFORMATION");
WriteLine(dumpTable, "----------------------------------------\n");
if (memories == null) {
WriteLine(dumpTable, "There is no Memory Affinity info!");
}
else {
WriteLine(dumpTable, "Found {0} memory\n", memories.Length);
for (int i = 0; i < memories.Length; i++) {
WriteLine(dumpTable, "Memory #{0}", i);
WriteLine(dumpTable, " domain : {0}",
memories[i].domain);
WriteLine(dumpTable, " baseAddress : {0} {1}",
GetBigAddr(memories[i].baseAddress),
GetBigAddrStr(memories[i].baseAddress));
WriteLine(dumpTable, " endAddress : {0} {1}",
GetBigAddr(memories[i].endAddress),
GetBigAddrStr(memories[i].endAddress));
WriteLine(dumpTable, " memorySize : {0} {1}",
GetBigAddr(memories[i].memorySize),
GetBigAddrStr(memories[i].memorySize));
WriteLine(dumpTable, " flagIgnore : {0}",
memories[i].flagIgnore);
WriteLine(dumpTable, " flagHotPlug : {0}",
memories[i].flagHotPluggable);
WriteLine(dumpTable, " flagNonVoltl: {0}\n",
memories[i].flagNonVolatile);
}
}
delete processors;
delete memories;
config.pmInfoRef.Release(imp);
return;
}
internal static ulong GetBigAddr(ulong address)
{
ulong KB = 1024;
ulong MB = KB * KB;
ulong GB = KB * KB * KB;
if (address > GB) {
return address / GB;
}
else if (address > MB) {
return address / MB;
}
else if (address > KB) {
return address / KB;
}
else {
return address;
}
}
internal static string GetBigAddrStr(ulong address)
{
ulong KB = 1024;
ulong MB = KB * KB;
ulong GB = KB * KB * KB;
if (address > GB) {
return "GB";
}
else if (address > MB) {
return "MB";
}
else if (address > KB) {
return "KB";
}
else {
return "B";
}
}
// Main
internal static int AppMain(Parameters! config)
{
// Set the default options
bool dumpTable = config.dumpTable;
WriteLine(dumpTable, "\nWelcome to ProcMemInfo ... \n\n");
// Test if ProcMemInfoContract is okay
ProcMemInfoContract.Imp imp3 = config.pmInfoRef.Acquire();
imp3.RecvReady();
config.pmInfoRef.Release(imp3);
try {
DoTestGetAffinity(config);
DoTestGetCpuId (config);
DoTestAllCpuId (config);
} catch (Exception ex) {
Console.WriteLine("Error .");
Console.WriteLine(ex.ToString());
return 1;
}
return 0;
}
/// <summary>
/// Use this method to write output to both the screen and the
/// debugger if toDebugger is true.
/// </summary>
public static void WriteLine(bool toDebugger, string format,
params object[] args) {
string s = String.Format(format, args);
Console.WriteLine(s);
if (toDebugger) {
DebugStub.WriteLine(s);
}
}
public static void Write(bool toDebugger, string format,
params object[] args) {
string s = String.Format(format, args);
Console.Write(s);
if (toDebugger) {
DebugStub.Write(s);
}
}
public static void WriteLine(bool toDebugger) {
Console.WriteLine();
if (toDebugger) {
DebugStub.WriteLine();
}
}
} // end of ProcMemInfo class
} // end of Singularity.Applications