Delphi下获取CPUID一法

最近忽然有需求获取CPUID。Google后看到些东西,整理出来,防止忘记。由于我惯用Delphi,这里只列出Delphi下用法。

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://my.oschina.net/uian2000/blog/115166

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值