Monday, June 1, 2009

Calling CPUID from PowerShell for Intel VT

I was trying to work out whether the Intel VT (VMX) extensions had been enabled on a server and whether the server support the SSE4.1 and SSE4.2 processor instructions - without having to reboot the server to check the BIOS. I ended up 'writing' a PowerShell script that compiles some C# to call a DLL written in assembler which has run the CPUID instruction and returned the results. Note that I didn't really write any of this, the PowerShell script compiling and running the C# is from the reference below, as is the actual C$ and asm dll.

Does this seem like a lot of effort? Sure does, but unfortunately the simple method - using Win32_Processor.ProcessorID was useless in this example, as for some reason MS chose to only return the EAX and EDX registers, whereas the bits I was after were returned in ECX. There may also be other ways to achieve this through PowerShell/.Net framework, rather than compiling c# to call unmanaged code.

Below is the PowerShell script, which contains the inline C# that is compiled and executed, which in turn requires the dll, using the EFLAGS register to confirm support and the CPUID instruction with eax=1 (if further supported) to query feature information from the CPU.

The original c# and asm dll: (see below for the hex text stream)
http://devpinoy.org/blogs/cvega/archive/2006/04/07/2658.aspx

The compile-csharp function: (adding the -unsafe parameter to allow pointer use)
http://monadblog.blogspot.com/2005/12/calling-win32-api-functions-through.html



#
# Description:
#  Call the CPUID function from an external DLL through C# inline code.
#  Report whether Intel VT (VMX) is supported, bit 5 of the ECX register returned from CPUID eax=1 call.
#  Note that WMI Win32_Processor:ProcessID contains the results of a call to CPUID - except that it only contains EAX and EDX, Intel VT (what I was after) is in ECX
#
# Author:
#  Wayne Martin, note that I didn't write any of this code, the inline C# was from the monad reference below, and the CPUID DLL and C# was from the first reference

#References:
# cpuid.dll and the namespace from: http://devpinoy.org/blogs/cvega/archive/2006/04/07/2658.aspx
# Intel cpuid: http://www.intel.com/Assets/PDF/appnote/241618.pdf
# http://monadblog.blogspot.com/2005/12/calling-win32-api-functions-through.html
# http://msdn.microsoft.com/en-us/library/aa394373.aspx


function Compile-Csharp ([string] $code, $FrameworkVersion="v2.0.50727",
[Array]$References)
{
    $cp = new-object Microsoft.CSharp.CSharpCodeProvider
    $cpar = New-Object System.CodeDom.Compiler.CompilerParameters
    $cpar.CompilerOptions = "-unsafe"      # unsafe to compile the code which uses pointers in the DLL call
    $cpar.GenerateInMemory = $true
    $cpar.GenerateExecutable = $false
    $cpar.OutputAssembly = "custom"
    # $cpar.ReferencedAssemblies.AddRange($refs)
    $cr = $cp.CompileAssemblyFromSource($cpar, $code)

    if ( $cr.Errors.Count)
    {
        $codeLines = $code.Split("`n");
        foreach ($ce in $cr.Errors)
        {
            write-host "Error: $($codeLines[$($ce.Line - 1)])"
            write-host $ce
           # $ce out-default
        }
        Throw "INVALID DATA: Errors encountered while compiling code"
    }
}



$code = @'
namespace CPUID
{
 using System;
 using System.Runtime.InteropServices;
 using System.Text;

 public class cpuid
 {
  private cpuid()
  {
  }

  [DllImport("cpuid.dll")]
     public static extern bool CPUIDIsSupported();

  [DllImport("cpuid.dll")]
     private unsafe static extern bool __cpuid
            (uint function, 
             int* eax, 
             int* ebx, 
             int* ecx, 
             int* edx);

  // Invoke __cpuid function
  public unsafe static bool Invoke
      (uint level, 
       out int eax, 
       out int ebx, 
       out int ecx, 
       out int edx)
  {
   int __eax = 0;
   int __ebx = 0;
   int __ecx = 0;
   int __edx = 0;

   if (__cpuid(level, &__eax, &__ebx, &__ecx, &__edx))
   {
    eax = __eax;
    ebx = __ebx;
    ecx = __ecx;
    edx = __edx;

    return true;
   }
   else
   {
    eax = 0;
    ebx = 0;
    ecx = 0;
    edx = 0;

    return false;
   }
  }
 }
}


'@


compile-CSharp $code
$eax = ""
$ebx = ""
$ecx = ""
$edx = ""
[CPUID.CPUID]::Invoke(1, [ref]$eax, [ref]$ebx, [ref]$ecx, [ref]$edx) 

$INTEL_CPUID_VT_FLAG = 0x0020                                                           # bit 5 of ECX returned from CPUID EAX=1
$INTEL_CPUID_SSE41 = 0x80000                                                            # bit 19 of ECX returned from CPUID EAX=1
$INTEL_CPUID_SSE42 = 0x100000                                                           # bit 20 of ECX returned from CPUID EAX=1
$INTEL_CPUID_XD = 0x00100000

write-output ("Intel VT: " + ($ecx -band $INTEL_CPUID_VT_FLAG) )                        # Does this processor support Intel VT / VMX?
write-output ("SSE 4.1: " + ($ecx -band $INTEL_CPUID_SSE41) )                           # Does this processor support SSE 4.1?
write-output ("SSE 4.2: " + ($ecx -band $INTEL_CPUID_SSE42) )                           # Does this processor support SSE 4.2?
write-output ("eXecute Disable: " + ($edx -band $INTEL_CPUID_XD) )                      # Does this processor support XD?




Note that in a previous post, I have written two powershell scripts, one to convert binary to a hex string, and vice versa. The following stream is the cpuid.dll file, if you write it to cpuid.txt and run the following command it will create the dll:



Powershell . .\HexStringToBinary.ps1 cpuid.txt cpuid.dll

4d5a90000300000004000000ffff0000b800000000000000400000000000000000000000000000000000000000000000000000000000000000000000c00000000e1fba0e00b409cd21b8014ccd21546869732070726f6772616d2063616e6e6f742062652072756e20696e20444f53206d6f64652e0d0d0a240000000000000071d4f7db35b5998835b5998835b59988c9958b8834b59988bbaa8a8834b599885269636835b59988000000000000000000000000000000000000000000000000504500004c0103006a793a440000000000000000e0000e210b01050c00020000000400000000000000100000001000000020000000000010001000000002000004000000040000000400000000000000004000000004000070fa000002000000000010000010000000001000001000000000000010000000002000005f0000000000000000000000000000000000000000000000000000000000000000000000003000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e746578740000006c000000001000000002000000040000000000000000000000000000200000602e726461746100005f000000002000000002000000060000000000000000000000000000400000402e72656c6f6300000c000000003000000002000000080000000000000000000000000000400000420000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000558becb801000000c9c20c005352b8000000009c588bc83500002000509d9c5b33c325000020007507b801000000eb0233c0519d5a5bc3558bec5357e8cbffffff48740433c0eb1e8b45080fa28b7d0c89078b7d14890f8b7d1889178b7d10891fb8010000005f5bc9c214000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006a793a44000000003c2000000100000002000000020000002820000030200000382000000c1000003710000046200000572000000000010063707569642e646c6c0043505549444973537570706f72746564005f5f6370756964000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000


Wayne's World of IT (WWoIT), Copyright 2009 Wayne Martin. 

No comments:

Post a Comment