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