Pergunta

Eu gostaria de adicionar funcionalidade cpuid ao meu aplicativo C #. Eu encontrei este post interessante online. Eu provavelmente terá MASM para compilar isso, mas:

  1. Como devo começar?
  2. Eu suspeito que vou ter que compilar uma dll tanto para X86 e X64 mas novamente eu não tenho a menor idéia sobre como ir sobre uma coisa dessas (e estou um pouco pressionado pelo tempo).

Assim, qualquer ajuda seria mais do que bem-vindo!

Foi útil?

Solução

CPUID é uma dor gigante e gostaria de aconselhar contra indo por esse caminho se você pode evitá-lo. resultados CPUID são diferentes entre Intel e AMD (pelo menos para as coisas interessantes como hyperthreading e topologia cache) e não são particularmente estáveis ??em diferentes versões do processador. (Mais recentes processadores Intel i7 introduzir um novo valor CPUID (eax = 0xB), que substituem as informações apoiado por CPUID em processadores anteriores).

Se você pode obter afastado com ele, sua melhor aposta seria usar WMI (veja Win32_Processor ) ou GetLogicalProcessorInformation .

Qualquer um destes será uma solução muito mais simples e mais fáceis de gerenciar se forem suportadas em sua plataforma (para obter informações sobre o processador lógico de qualquer forma requer WinXP SP3 ou mais recente no lado do cliente ou no Windows Server 2008 ou mais recente no lado do servidor) .

Se você realmente quiser tentar a sua sorte com CPUID, o que eu recomendaria fazer seria criar um esboço simples, que é capaz de executar CPUID e retornando os resultados para código gerenciado (você vai precisar diferentes versões para 32-bit e 64-bit) e executar aqueles dentro do contexto de seu aplicativo gerenciado. Eu faço isso através da compilação de um aplicativo nativo e, em seguida, extrair a instrução matéria-bytes do meu método CPUID em um array de bytes que pode ser executado a partir do código gerenciado.

Este deve começar para suporte de 32 bits apenas:

using System;
using System.Runtime.InteropServices;

static class Program {
  static void Main() {
    //Allocate the executable buffer on a distinct page 
    // rather than just pinning it in place because we
    // need to mark the page as executable.
    // Failing to do this would cause NX-enabled machines 
    // to have access violations attempting to execute.
    IntPtr pExecutableBuffer = VirtualAlloc(
      IntPtr.Zero,
      new IntPtr(CPUID_32.Length),
      AllocationType.MEM_COMMIT | AllocationType.MEM_RESERVE,
      MemoryProtection.PAGE_EXECUTE_READWRITE
    );

    Marshal.Copy(CPUID_32, 0, pExecutableBuffer, CPUID_32.Length);
    CPUID executeHandler = (CPUID)Marshal.GetDelegateForFunctionPointer(
      pExecutableBuffer, typeof(CPUID));
    CPUID_Args args = new CPUID_Args();
    args.eax = 0;
    executeHandler(ref args);
    Console.WriteLine("eax: {0} ebx: {1} ecx: {2} edx: {3}",
      args.eax,
      args.ebx,
      args.ecx,
      args.edx);
    VirtualFree(
      pExecutableBuffer,
      IntPtr.Zero,
      FreeType.MEM_RELEASE);
  }

  [UnmanagedFunctionPointer(CallingConvention.StdCall)]
  delegate void CPUID(ref CPUID_Args args);

  private static readonly byte[] CPUID_32 = new byte[] {
    0x53,          // push ebx 
    0x57,          // push edi 
    0x8B, 0x7C, 0x24, 0x0C, // mov edi,dword ptr [esp+0Ch] 
    0x8B, 0x07,       // mov eax,dword ptr [edi] 
    0x8B, 0x4F, 0x08,    // mov ecx,dword ptr [edi+8] 
    0x0F, 0xA2,       // cpuid      
    0x89, 0x07,       // mov dword ptr [edi],eax 
    0x89, 0x5F, 0x04,    // mov dword ptr [edi+4],ebx 
    0x89, 0x4F, 0x08 ,    // movdword ptr [edi+8],ecx 
    0x89, 0x57, 0x0C ,    // mov dword ptr [edi+0Ch],edx 
    0x5F,          // pop     edi 
    0x5B,          // pop     ebx 
    0xC2, 0x04, 0x00     // ret
    };

  [Flags]
  enum AllocationType {
    MEM_COMMIT = 0x1000,
    MEM_RESERVE = 0x2000,
  }

  [Flags]
  enum MemoryProtection {
    PAGE_EXECUTE_READWRITE = 0x40,
  }

  [Flags]
  enum FreeType {
    MEM_RELEASE = 0x8000
  }

  [DllImport("kernel32.dll")]
  static extern IntPtr VirtualAlloc(
    IntPtr lpAddress,
    IntPtr dwSize,
    AllocationType flAllocationType,
    MemoryProtection flProtect);

  [DllImport("kernel32.dll")]
  [return: MarshalAs(UnmanagedType.Bool)]
  static extern bool VirtualFree(
    IntPtr lpAddress,
    IntPtr dwSize,
    FreeType dwFreeType);
}

[StructLayout(LayoutKind.Sequential)]
struct CPUID_Args {
  public uint eax;
  public uint ebx;
  public uint ecx;
  public uint edx;
}

Outras dicas

Eu acho que você pode construir um CLR nativo montagem empregando linha assembler sintaxe (__asm) em código C ++.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top