//////////////////////////////////////////////////////////////////////////////// // // 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 Stdin; [Endpoint] public readonly TRef Stdout; [Endpoint] public readonly TRef 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; } /// /// Use this method to write output to both the screen and the /// debugger if toDebugger is true. /// 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