最近忽然有需求获取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支持的指令不同,具体编码最好参考厂商提供的相关手册。