Delphi下获取CPUID一法

CPUID是一个处理器支持的操作指令,用于获取CPU特性信息。详见http://en.wikipedia.org/wiki/CPUID

既然与CPU相关,就有适用范围的问题。判断其是否可用,需要检查EFlags的第21为是否可更改,如是,则表示处理器支持。

Intel 8086/286只有Flags(不E),386的第21位为保留位,无法改写,因此这些CPU均不支持CPUID指令。

测试CPU是否支持CPUID

function TestCPUID: Boolean;
begin
  asm
    mov Result, 0
    pushfd            // 将EFlags压栈
    pop eax           // 取出EFlags
    mov ecx, eax
    xor eax, 200000h  // 修改第21位
    push eax
    popfd             // 将变更后的EFlags存入扩展标志
    pushfd
    pop eax           // 再次取出EFlags
    xor eax, ecx      // 判断是否变化
    jz @end
    mov Result, 1
    @end:
  end;
end;

CPUID指令以EAX为参数,返回值分布于EAX,EBX,ECX,EDX四个寄存器,由此,通用的CPUID过程设计如下

procedure GetCPUID(var AAx, ABx, ACx, ADx: Cardinal);
var
  vAx, vBx, vCx, vDx: Cardinal;
begin
  // 传参与寄存器关联,此处采用内部变量缓存
  vAx := AAx; vBx := ABx; vCx := ACx; vDx := ADx;
  asm
    push ebx       // 寄存器ebx需要保护

    mov eax, vAx
    mov ebx, vBx
    mov ecx, vCx
    mov edx, vDx
    cpuid
    mov vAx, eax
    mov vBx, ebx
    mov vCx, ecx
    mov vDx, edx

    pop ebx
  end;

  AAx := vAx; ABx := vBx; ACx := vCx; ADx := vDx;
end;

然后,就可以根据处理器指令手册获取相关信息了。

如:获取VendorString

type
  TCardinalChar = packed record
    case Integer of
      0: (CharA, CharB, CharC, CharD: AnsiChar;);
      1: (Chars: Cardinal;);
  end;

function GetVendorString: String;
var
  vAx, vBx, vCx, vDx: Cardinal;
  vChars: TCardinalChar;
begin
  Result := '';

  if not TestCPUID then Exit;

  vAx := 0;
  GetCPUID(vAx, vBx, vCx, vDx);

  vChars.Chars := vBx;
  Result := Result + vChars.CharA + vChars.CharB + vChars.CharC + vChars.CharD;
  vChars.Chars := vDx;
  Result := Result + vChars.CharA + vChars.CharB + vChars.CharC + vChars.CharD;
  vChars.Chars := vCx;
  Result := Result + vChars.CharA + vChars.CharB + vChars.CharC + vChars.CharD;
end;

或者:获取BrandString

function GetBrandString: String;
var
  vAx, vBx, vCx, vDx: Cardinal;
  vChars: TCardinalChar;
begin
  Result := '';
  if not TestCPUID then Exit;

  vAx := $80000002;
  GetCPUID(vAx, vBx, vCx, vDx);
  vChars.Chars := vAx;
  Result := Result + vChars.CharA + vChars.CharB + vChars.CharC + vChars.CharD;
  vChars.Chars := vBx;
  Result := Result + vChars.CharA + vChars.CharB + vChars.CharC + vChars.CharD;
  vChars.Chars := vCx;
  Result := Result + vChars.CharA + vChars.CharB + vChars.CharC + vChars.CharD;
  vChars.Chars := vDx;
  Result := Result + vChars.CharA + vChars.CharB + vChars.CharC + vChars.CharD;
  vAx := $80000003;
  GetCPUID(vAx, vBx, vCx, vDx);
  vChars.Chars := vAx;
  Result := Result + vChars.CharA + vChars.CharB + vChars.CharC + vChars.CharD;
  vChars.Chars := vBx;
  Result := Result + vChars.CharA + vChars.CharB + vChars.CharC + vChars.CharD;
  vChars.Chars := vCx;
  Result := Result + vChars.CharA + vChars.CharB + vChars.CharC + vChars.CharD;
  vChars.Chars := vDx;
  Result := Result + vChars.CharA + vChars.CharB + vChars.CharC + vChars.CharD;
  vAx := $80000004;
  GetCPUID(vAx, vBx, vCx, vDx);
  vChars.Chars := vAx;
  Result := Result + vChars.CharA + vChars.CharB + vChars.CharC + vChars.CharD;
  vChars.Chars := vBx;
  Result := Result + vChars.CharA + vChars.CharB + vChars.CharC + vChars.CharD;
  vChars.Chars := vCx;
  Result := Result + vChars.CharA + vChars.CharB + vChars.CharC + vChars.CharD;
  vChars.Chars := vDx;
  Result := Result + vChars.CharA + vChars.CharB + vChars.CharC + vChars.CharD;
end;

以上。

另,不同CPU支持的指令不同,具体编码最好参考厂商提供的相关手册。

https://files.cnblogs.com/files/Thenext/uCPUID.zip

原文地址:https://www.cnblogs.com/Thenext/p/12313321.html