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

posted @   Thenext  阅读(1025)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示