最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

DOS下和WINDOWS下用CPUID讀CPU信息

2023-12-18 10:33 作者:失傳技術(shù)  | 我要投稿

DOS下和WINDOWS下用CPUID讀CPU信息

liwu_111

于 2008-04-09 12:10:00 發(fā)布

閱讀量1.9k

?收藏?1

點贊數(shù) 1

文章標簽:?windows?dos?vc++?c

版權(quán)

一 :WINDOWS下,用VC++來編譯。

???????? 格式:?? unsigned long DBase;
char cA[13];
char cB[49];
_asm
? {
??? xor eax, eax
??? cpuid
??? mov DBase????? ,eax
??? mov dword ptr cA??? ,ebx
??? mov dword ptr cA+4? ,edx?
??? mov dword ptr cA+8? ,ecx?


??? mov eax, 0x80000002
??? cpuid
??? mov dword ptr cB??? , eax
??? mov dword ptr cB + 4? , ebx
??? mov dword ptr cB + 8? , ecx
??? mov dword ptr cB + 12? ,edx

??? mov eax, 0x80000003
??? cpuid
??? mov dword ptr cB + 16? , eax
??? mov dword ptr cB + 20? , ebx
??? mov dword ptr cB + 24? , ecx
??? mov dword ptr cB + 28? , edx

??? mov eax, 0x80000004
??? cpuid
??? mov dword ptr cB + 32? , eax
??? mov dword ptr cB + 36? , ebx
??? mov dword ptr cB + 40? , ecx
??? mov dword ptr cB + 44? , edx
? }

二:DOS下,需要用DJGPP來編譯(支持32位)。

????????? 格式:

#define CPUID(op,a,b,c,d)? /
__asm__ __volatile__("cpuid":"=a"(a),"=b"(b),"=c"(c),"=d"(d):"a"(op))

?

?MSN:???twinliwu@hotmail.com??[TurboC++] 如何在DOS下的16位C++編譯器中使用CPUID指令獲取CPU信息

  有時我們需要編寫DOS實模式下的CPU信息診斷程序,但是TurboC++等很多16位C++編譯器不支持CPUID指令和32位匯編。于是本文介紹了一種辦法,靠內(nèi)嵌機器碼實現(xiàn)了獲取CPUID信息。

一、CPUID指令簡介

  CPUID指令是intel IA32架構(gòu)下獲得CPU信息的匯編指令,可以得到CPU類型,型號,廠商信息,商標信息,序列號,緩存等一系列CPU相關(guān)的東西。

  CPUID指令一般使用使用eax作為輸入?yún)?shù)(某些時候會用到ecx),eax、ebx、ecx、edx作為輸出參數(shù)。例如這樣的匯編代碼——

mov ? ?eax, 1cpuid...

?

  以上代碼以1為輸入?yún)?shù),執(zhí)行cpuid后,eax、ebx、ecx、edx的值都被返回值填充。針對不同的輸入?yún)?shù)eax的值,輸出參數(shù)的意義都不相同。具體含義可參考Intel和AMD的手冊——
《Intel? 64 and IA-32 Architectures Software Developer’s Manual Volume 2 (2A, 2B & 2C): Instruction Set Reference, A-Z》. May 2012.?http://developer.intel.com/content/www/us/en/processors/processor-identification-cpuid-instruction-note.html
《Intel? Processor Identification and the CPUID Instruction》. April 2012.?http://developer.intel.com/content/www/us/en/processors/processor-identification-cpuid-instruction-note.html
《AMD CPUID Specification》. September 2010.?http://support.amd.com/us/Embedded_TechDocs/25481.pdf

二、將CPUID封轉(zhuǎn)為函數(shù)

  用匯編語言來做軟件開發(fā)的成本很高,所以一般使用C++等高級語言來做軟件開發(fā),于是我們希望能將CPUID指令封裝為函數(shù)。
  但現(xiàn)在遇到一個難題——雖然TurboC++等16位C++編譯器支持asm語句來實現(xiàn)內(nèi)嵌匯編,但它只支持16位匯編,不支持CPUID指令和32位匯編。該怎么辦呢?

  幸好TurboC++支持在asm語句插入機器碼。比如我們可以將CPUID指令的機器碼插入到asm語句中——

? ?_asm{ ? ? ? ?... ? ? ? ?db 0x0f; db 0xa2; ? ?// cpuid ? ? ? ?... ? ?}

?

  “0f a2”是CPUID指令的機器碼,在Intel手冊上可以查到——

  現(xiàn)在我們又遇到一個難題——CPUID指令使用了eax、ebx、ecx、edx這幾個32位寄存器,但TurboC++中的內(nèi)嵌匯編只支持16位匯編,既只能訪問ax、bc、cx、dx。
  這時,可以使用66h前綴來調(diào)整操作數(shù)的大?。?6H prefix - Operand Size Override)。給一條16位指令加上66H前綴時,它的操作數(shù)——既寄存器寬度變?yōu)榱?2位。比如原16位指令用的是ax,加上66H前綴時變?yōu)閑ax。注意此時的內(nèi)存尋址方式仍是16位的,僅是操作數(shù)變?yōu)?2位,例如——

? ?_asm{ ? ? ? ?db 0x66; mov ax, [di]; ? ?// mov eax, DWORD PTR [di] ? ?}

注:在16位代碼中要想使用32位尋址,得使用67H前綴來調(diào)整地址大小(67H prefix - Address Size Override)。本文沒有用到,讀者可自行學習。

  利用上述知識,我們可以構(gòu)造CPUID函數(shù)了——

// 獲得CPU信息(加強版)//// pdwout4: 返回eax, ebx, ecx, edx這四個寄存器的值。// id: 功能ID。既CPUID指令的eax參數(shù)。// subid: 子功能ID。既CPUID指令的ecx參數(shù)。void getcpuidex(DWORD* pdwout4, DWORD id, DWORD subid) { ? ?if (NULL==pdwout4) ? ?return; ? ?pdwout4[0] = id; ? ?// eax ? ?pdwout4[2] = subid; ? ?// ecx ? ?_asm{ ? ? ? ?// load. 讀取參數(shù)到寄存器 ? ? ? ?mov di, pdwout4; ? ?// 準備用di尋址pdwout4 ? ? ? ?db 0x66; mov cx, [di+8]; ? ?// mov ecx, DWORD PTR [di+8] ? ? ? ?db 0x66; mov ax, [di]; ? ?// mov eax, DWORD PTR [di] ? ? ? ?db 0x66; xor dx, dx; ? ?// xor edx, edx ? ? ? ?db 0x66; xor bx, bx; ? ?// xor ebx, ebx ? ? ? ?// CPUID ? ? ? ?db 0x0f; db 0xa2; ? ?// cpuid ? ? ? ?// save. 將寄存器保存到pdwout4 ? ? ? ?db 0x66; mov [di], ax; ? ?// mov DWORD PTR [di], eax ? ? ? ?db 0x66; mov [di+4], bx; ? ?// mov DWORD PTR [di+4], ebx ? ? ? ?db 0x66; mov [di+8], cx; ? ?// mov DWORD PTR [di+8], ecx ? ? ? ?db 0x66; mov [di+12], dx; ? ?// mov DWORD PTR [di+12], edx ? ?} }

?

  注解——
1. 因為CPUID的返回值會占滿eax、ebx、ecx、edx這四個通用寄存器,所以利用di寄存器來尋址。
2. 為了減少寄存器占用,將輸入?yún)?shù)id、subid寫入pdwout4,然后再在匯編代碼中通過di寄存器尋址來加載參數(shù)。
3. 雖然對于CPUID指令來說,不需要“xor edx, edx”等指令將edx、dbx清零。但考慮某些16位編譯器對內(nèi)嵌匯編的支持性不夠好,手工寫上dx、bx后能讓編譯器知道該內(nèi)嵌匯編代碼用到這2個寄存器,不會將這2個寄存器挪作他用。

  上面我們采用了內(nèi)嵌機器碼的形式實現(xiàn)了getcpuidex函數(shù)。但手工編寫機器碼是很容易出錯的,怎樣才能驗證機器碼是正確的呢?這時可以先將程序編譯為exe,然后利用反匯編器來解析機器碼。例如我用IDA Pro打開編譯后的exe,因為現(xiàn)在程序很短小,能很快的找到調(diào)用cpuid指令的地方——

  反匯編的結(jié)果與我們預想的相同,驗證通過。

三、常用的CPUID功能

3.1 取得CPU廠商(Vendor)

  把eax = 0作為輸入?yún)?shù),可以得到CPU的廠商信息。
  cpuid指令執(zhí)行以后,會返回一個12字符的廠商信息,前四個字符的ASC碼按低位到高位放在ebx,中間四個放在edx,最后四個字符放在ecx。比如說,對于intel的cpu,會返回一個“GenuineIntel”的字符串,返回值的存儲格式為—— ?
??????? 31????? 23????? 15????? 07????? 00
??????? EBX| u (75)| n (6E)| e (65)| G (47)
??????? EDX| I (49)| e (65)| n (6E)| i (69)
??????? ECX| l (6C)| e (65)| t (74)| n (6E)

  代碼為——

// 取得CPU廠商(Vendor)//// result: 成功時返回字符串的長度(一般為12)。失敗時返回0。// pvendor: 接收廠商信息的字符串緩沖區(qū)。至少為13字節(jié)。int cpu_getvendor(char* pvendor) { ? ?DWORD dwBuf[4]; ? ?if (NULL==pvendor) ? ?return 0; ? ?// Function 0: Vendor-ID and Largest Standard Function ? ?getcpuid(dwBuf, 0); ? ?// save. 保存到pvendor ? ?*(DWORD*)&pvendor[0] = dwBuf[1]; ? ?// ebx: 前四個字符 ? ?*(DWORD*)&pvendor[4] = dwBuf[3]; ? ?// edx: 中間四個字符 ? ?*(DWORD*)&pvendor[8] = dwBuf[2]; ? ?// ecx: 最后四個字符 ? ?pvendor[12] = '\0'; ? ?return 12; }

?

3.2 取得CPU商標(Brand)

  在我的電腦上點擊右鍵,選擇屬性,可以在窗口的下面看到一條CPU的信息,這就是CPU的商標字符串。CPU的商標字符串也是通過cpuid得到的。由于商標的字符串很長(48個字符),所以不能在一次cpuid指令執(zhí)行時全部得到,所以intel把它分成了3個操作,eax的輸入?yún)?shù)分別是0x80000002,0x80000003,0x80000004,每次返回的16個字符,按照從低位到高位的順序依次放在eax, ebx, ecx, edx。
  為了穩(wěn)妥,最好事先調(diào)用0x80000000號功能檢查一下擴展功能號的范圍。

  代碼為——

// 取得CPU商標(Brand)//// result: 成功時返回字符串的長度(一般為48)。失敗時返回0。// pbrand: 接收商標信息的字符串緩沖區(qū)。至少為49字節(jié)。int cpu_getbrand(char* pbrand) { ? ?DWORD dwBuf[4]; ? ?if (NULL==pbrand) ? ?return 0; ? ?// Function 0x80000000: Largest Extended Function Number ? ?getcpuid(dwBuf, 0x80000000UL); ? ?if (dwBuf[0] < 0x80000004UL) ? ?return 0; ? ?// Function 80000002h,80000003h,80000004h: Processor Brand String ? ?getcpuid((DWORD*)&pbrand[0], 0x80000002UL); ? ?// 前16個字符 ? ?getcpuid((DWORD*)&pbrand[16], 0x80000003UL); ? ?// 中間16個字符 ? ?getcpuid((DWORD*)&pbrand[32], 0x80000004UL); ? ?// 最后16個字符 ? ?pbrand[48] = '\0'; ? ?return 48; }

?

四、全部代碼

  全部代碼——

#include <stdio.h>typedef unsigned long DWORD;char szBuf[64]; DWORD dwBuf[4];// 獲得CPU信息(加強版)//// pdwout4: 返回eax, ebx, ecx, edx這四個寄存器的值。// id: 功能ID。既CPUID指令的eax參數(shù)。// subid: 子功能ID。既CPUID指令的ecx參數(shù)。void getcpuidex(DWORD* pdwout4, DWORD id, DWORD subid) { ? ?if (NULL==pdwout4) ? ?return; ? ?pdwout4[0] = id; ? ?// eax ? ?pdwout4[2] = subid; ? ?// ecx ? ?_asm{ ? ? ? ?// load. 讀取參數(shù)到寄存器 ? ? ? ?mov di, pdwout4; ? ?// 準備用di尋址pdwout4 ? ? ? ?db 0x66; mov cx, [di+8]; ? ?// mov ecx, DWORD PTR [di+8] ? ? ? ?db 0x66; mov ax, [di]; ? ?// mov eax, DWORD PTR [di] ? ? ? ?db 0x66; xor dx, dx; ? ?// xor edx, edx ? ? ? ?db 0x66; xor bx, bx; ? ?// xor ebx, ebx ? ? ? ?// CPUID ? ? ? ?db 0x0f; db 0xa2; ? ?// cpuid ? ? ? ?// save. 將寄存器保存到pdwout4 ? ? ? ?db 0x66; mov [di], ax; ? ?// mov DWORD PTR [di], eax ? ? ? ?db 0x66; mov [di+4], bx; ? ?// mov DWORD PTR [di+4], ebx ? ? ? ?db 0x66; mov [di+8], cx; ? ?// mov DWORD PTR [di+8], ecx ? ? ? ?db 0x66; mov [di+12], dx; ? ?// mov DWORD PTR [di+12], edx ? ?} }// 獲得CPU信息void getcpuid(DWORD* pdwout4, DWORD id) { ? ?getcpuidex(pdwout4, id, 0); }// 取得CPU廠商(Vendor)//// result: 成功時返回字符串的長度(一般為12)。失敗時返回0。// pvendor: 接收廠商信息的字符串緩沖區(qū)。至少為13字節(jié)。int cpu_getvendor(char* pvendor) { ? ?DWORD dwBuf[4]; ? ?if (NULL==pvendor) ? ?return 0; ? ?// Function 0: Vendor-ID and Largest Standard Function ? ?getcpuid(dwBuf, 0); ? ?// save. 保存到pvendor ? ?*(DWORD*)&pvendor[0] = dwBuf[1]; ? ?// ebx: 前四個字符 ? ?*(DWORD*)&pvendor[4] = dwBuf[3]; ? ?// edx: 中間四個字符 ? ?*(DWORD*)&pvendor[8] = dwBuf[2]; ? ?// ecx: 最后四個字符 ? ?pvendor[12] = '\0'; ? ?return 12; }// 取得CPU商標(Brand)//// result: 成功時返回字符串的長度(一般為48)。失敗時返回0。// pbrand: 接收商標信息的字符串緩沖區(qū)。至少為49字節(jié)。int cpu_getbrand(char* pbrand) { ? ?DWORD dwBuf[4]; ? ?if (NULL==pbrand) ? ?return 0; ? ?// Function 0x80000000: Largest Extended Function Number ? ?getcpuid(dwBuf, 0x80000000UL); ? ?if (dwBuf[0] < 0x80000004UL) ? ?return 0; ? ?// Function 80000002h,80000003h,80000004h: Processor Brand String ? ?getcpuid((DWORD*)&pbrand[0], 0x80000002UL); ? ?// 前16個字符 ? ?getcpuid((DWORD*)&pbrand[16], 0x80000003UL); ? ?// 中間16個字符 ? ?getcpuid((DWORD*)&pbrand[32], 0x80000004UL); ? ?// 最后16個字符 ? ?pbrand[48] = '\0'; ? ?return 48; }int main(void) { ? ?//getcpuidex(dwBuf, 0,0); ? ?//printf("%.8lX\t%.8lX\t%.8lX\t%.8lX\n", dwBuf[0],dwBuf[1],dwBuf[2],dwBuf[3]); ? ?cpu_getvendor(szBuf); ? ?printf("CPU Vendor:\t%s\n", szBuf); ? ?cpu_getbrand(szBuf); ? ?printf("CPU Name:\t%s\n", szBuf); ? ?return 0; }

?

五、編譯和運行

  在Turbo C++ 3.0和Borland C++ 3.1中編譯通過。將編譯后的exe放在C盤根目錄。然后重啟電腦進入DOS實模式,運行成功——

  在Windows的命令提示符中也運行成功——

?

參考文獻——
《Intel? 64 and IA-32 Architectures Software Developer’s Manual Volume 2 (2A, 2B & 2C): Instruction Set Reference, A-Z》. May 2012.?http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.html
《Intel? Processor Identification and the CPUID Instruction》. April 2012.?http://developer.intel.com/content/www/us/en/processors/processor-identification-cpuid-instruction-note.html
《AMD CPUID Specification》. September 2010.?http://support.amd.com/us/Embedded_TechDocs/25481.pdf
《DOS下使用32位寄存器及CPUID》。senvei著。http://hi.baidu.com/senvei/blog/item/4820c11b4ad4e09b6438db64.html
《x86/x64 指令編碼內(nèi)幕(適用于 AMD/Intel)》中的“2. 深入了解 prefix”。mik著。http://www.mouseos.com/x64/doc3.html
《在C++中使用cpuid指令獲得CPU信息》。閑人(freeman)著。http://freeman.cnblogs.com/archive/2005/08/30/226128.html
http://en.wikipedia.org/wiki/CPUID
http://baike.baidu.com/view/1829765.htm

?

源碼下載——
https://files.cnblogs.com/zyl910/getcpuid.rar

作者:zyl910

出處:http://www.cnblogs.com/zyl910/

版權(quán)聲明:自由轉(zhuǎn)載-非商用-非衍生-保持署名 |?Creative Commons BY-NC-ND 3.0.

分類:?--- My_原創(chuàng)?,?--- Program_編程?,?C00 Language_語言?,?C10 C系列?,?C11 C?,?C12 C++?,?D00 Platform_平臺?,?D20 DOS/BIOS?,?H00 Hardware_硬件?,?H10 Architecture_體系結(jié)構(gòu)?,?H11 x86

標簽:?Cpp?,?x86?,?Asm?,?CPUID?,?dos?,?16bit?,?32bit

PC獲取硬件標識(Windows篇)


Lmagic


設(shè)計

2 人贊同了該文章

參考:設(shè)備唯一標識方法(Unique Identifier):如何在Windows系統(tǒng)上獲取設(shè)備的唯一標識


(1)網(wǎng)卡MAC地址

在Windows系統(tǒng)中通過命令行運行“systeminfo"。

(2)CPU ID

在Windows系統(tǒng)中通過命令行運行“wmic cpu get processorid”就可以查看CPU ID。

目前CPU ID也無法唯一標識設(shè)備,Intel現(xiàn)在可能同一批次的CPU ID都一樣,不再提供唯一的ID。而且經(jīng)過實際測試,新購買的同一批次PC的CPU ID很可能一樣。這樣作為設(shè)備的唯一標識就會存在問題。

(3)硬盤序列號

在Windows系統(tǒng)中通過命令行運行“wmic diskdrive get serialnumber”可以查看。

硬盤序列號作為設(shè)備唯一ID存在的問題是,很多機器可能存在多塊硬盤,特別是服務(wù)器,而且機器更換硬盤是很可能發(fā)生的事情,更換硬盤后設(shè)備ID也必須隨之改變,不然也會影響授權(quán)等應用。因此,很多授權(quán)軟件沒有考慮使用硬盤序列號。而且,不一定所有的電腦都能獲取到硬盤序列號。

(4)主板smBIOS UUID

在Windows系統(tǒng)中通過命令行運行“wmic csproduct get UUID”可以查看。

主板UUID是很多授權(quán)方法和微軟官方都比較推崇的方法,即便重裝系統(tǒng)UUID應該也不會變(筆者沒有實測重裝,不過在一臺機器上安裝雙系統(tǒng),獲取的主板UUID是一樣的,雙系統(tǒng)一個windows一個Linux,Linux下用“dmidecode -s system-uuid”命令可以獲取UUID)。

但是這個方法也有缺陷,因為不是所有的廠商都提供一個UUID,當這種情況發(fā)生時,wmic會返回“FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF”,即一個無效的UUID。

補充:

UUID就是Universal Unique IDentifier的縮寫,它是一個128位,16字節(jié)的值,并確保在時間和空間上唯一。

它是把硬件地址、時間以及隨機數(shù)結(jié)合在一起,來確保其唯一性的。

一般情況下,生成算法用計算機網(wǎng)卡的地址和一個60位的timestamp生成,時間是以100ns為時間間隔。

例如,一臺300PL 6862的計算機,主板集成的網(wǎng)卡的MAC地址為00-04-AC-2E-B7-DC,而UUID的最后六個字節(jié)也會是0004AC2EB7DC


DOS下和WINDOWS下用CPUID讀CPU信息的評論 (共 條)

分享到微博請遵守國家法律
信宜市| 拜泉县| 宝丰县| 瑞昌市| 云梦县| 耿马| 固阳县| 德化县| 蓬溪县| 木里| 海盐县| 万盛区| 汶上县| 泌阳县| 治县。| 大邑县| 申扎县| 精河县| 沁水县| 长泰县| 抚松县| 福鼎市| 临城县| 九江市| 阜康市| 鹤山市| 汨罗市| 延安市| 高雄县| 曲周县| 武胜县| 济南市| 溧水县| 马关县| 巴林右旗| 皮山县| 洛浦县| 遵义县| 大埔区| 绥中县| 太湖县|