- x86/x64體系探索及編程
- 鄧志著
- 1389字
- 2019-03-01 11:49:36
第4章 處理器的身份
我需要了解處理器的型號(hào)、廠商、有什么具體的特性等這些關(guān)于處理器的參數(shù),應(yīng)該怎么辦?x86/x64處理器上提供了CPUID指令用來(lái)查看和識(shí)別身份。
4.1 測(cè)試是否支持CPUID指令
eflags寄存器的bit 21是ID(Processor Feature Identification)標(biāo)志位,在286處理器中flags是16位的,在386處理器中eflags擴(kuò)展為32位,bit 21是reserved。CPUID指令從Intel 486處理器上開(kāi)始加入,因此除非你在古老的機(jī)器上運(yùn)行,否則沒(méi)必要檢測(cè)處理器是否支持CPUID指令。
實(shí)驗(yàn)4-1:測(cè)試是否支持CPUID指令
test_CPUID()在源文件lib\lib16.asm里,在topic04\ex4-1\目錄有實(shí)驗(yàn)代碼:
代碼清單4-1(lib\lib16.asm):
;--------------------------------------------------- ; test_CPUID():測(cè)試是否支持 CPUID 指令 ; output: ; 1 - support, 0 - no support ;--------------------------------------------------- __test_CPUID: pushfd ; save eflags DWORD size mov eax,dword [esp] ; get old eflags xor dword [esp],0x200000 ; xor the eflags.ID bit popfd ; set eflags register pushfd ; save eflags again pop ebx ; get new eflags cmp eax,ebx ; test eflags.ID has been modify setnz al ; OK! support CPUID instruction movzx eax,al ret
修改eflags寄存器的bit 21標(biāo)志位,如果能成功修改,就表示支持CPUID指令。
4.2 CPUID指令的術(shù)語(yǔ)及表達(dá)
Intel64手冊(cè)里對(duì)CPUID指令廣泛使用了如下一些表達(dá)形式和術(shù)語(yǔ)。
leaf(葉)
功能號(hào)使用leaf術(shù)語(yǔ),例如:CPUID的01號(hào)功能,你可以稱其為CPUID的01 leaf(葉)。
sub-leaf(子葉)
對(duì)于一些較復(fù)雜的信息查詢,往往需要一個(gè)輔助的子號(hào)。EAX寄存器輸入的是main leaf(主葉號(hào)),ECX寄存器提供的是sub-leaf(子葉號(hào))。
mov eax,0Bh ; main leaf mov ecx,0 ; sub-leaf cpuid
如上所示,0B號(hào)功能就是main leaf(主葉),ECX提供的0號(hào)就是sub-leaf(子葉)。
CPUID指令的描述形式
當(dāng)軟件需要判斷某項(xiàng)功能處理器是否支持時(shí),使用CPUID指令進(jìn)行查詢,在Intel手冊(cè)中使用了下面的描述形式。
上面是判斷處理器是否支持PAE(Physical Address Extensions)功能時(shí)的描述,當(dāng)CPUID.01H:EDX[6]的值為1時(shí),表示支持PAE功能。
4.3 基本信息與擴(kuò)展信息
從CPUID指令獲得的信息有兩大類:basic(基本)和extended(擴(kuò)展),要獲得信息必須要先提供相應(yīng)的leaf(功能號(hào)),每一類信息都有最大的功能號(hào)限制。
某些功能號(hào)下面還有許多sub-leaf(子葉),也就是信息的子集。使用CPUID指令之前在eax寄存器提供要查詢的某個(gè)信息相應(yīng)的功能號(hào)。
mov eax,0 ; 功能號(hào) 0(main leaf) cpuid ; 查詢 0 號(hào)信息
返回的相應(yīng)信息放在eax、ebx、ecx,以及edx寄存器中。這些信息是32位的,因此在64位模式下,rax、rbx、rcx,以及rdx寄存器的高32位被清0。
查詢最大leaf(功能)號(hào)
CPUID指令被使用來(lái)查詢處理器所支持的特性,因此CPUID所支持的leaf數(shù)量是與處理器相關(guān)的。很多時(shí)候,在使用某個(gè)leaf查詢之前,必須判斷處理器是否支持該leaf。
典型地,在使用0BH號(hào)功能時(shí),應(yīng)先查詢處理器是否支持0BH號(hào)功能。
基本最大功能號(hào)
使用CPUID的00H leaf來(lái)查詢,最大的基本功能號(hào)返回在EAX寄存器里。
mov eax,0 ; 功能號(hào) 0(main leaf) cpuid ; 查詢 0 號(hào)信息 cmp eax,0BH ; 判斷是否支持 0B leaf jb no_support ; 假如不支持...
擴(kuò)展最大功能號(hào)
同樣,最大的擴(kuò)展功能號(hào)也可以查詢。
mov eax,80000000 ; 功能號(hào) 80000000(main leaf) cpuid ; 查詢最大擴(kuò)展功能號(hào) cmp eax,80000001H ; 判斷是否支持 80000001 leaf jb no_support ; 假如不支持...
輸入80000000H功能號(hào),從返回的EAX寄存器里可以得到最大的擴(kuò)展功能號(hào)。
功能號(hào)0也返回處理器廠商名,在Intel的機(jī)器上返回的是:ebx寄存器是“Genu”,ecx寄存器是“ntel”,edx寄存器是“ineI”,組合起來(lái)是“GenuineIntel”,在AMD的機(jī)器上是“AuthenticAMD”。
實(shí)驗(yàn)4-2:獲得basic和extended功能號(hào)
實(shí)驗(yàn)的源碼在\topic04\ex4-2\setup.asm文件里。
代碼清單4-2(topic04\ex4-2\setup.asm):
call test_CPUID test ax,ax jz no_support ;; 獲得最大 basic 功能號(hào) mov eax,0 cpuid mov esi,eax mov di,value_address call get_dword_hex_string mov si,basic_message call puts mov si,value_address call puts call println ;; 獲得最大 extended 功能號(hào) mov eax,0x80000000 cpuid mov esi,eax mov di,value_address call get_dword_hex_string mov si,extend_message call puts mov si,value_address call puts call println jmp $ no_support: mov si,[message_table + eax * 2] call puts jmp $ support_message db 'support CPUID instruction',13,10,0 no_support_message db 'no support CPUID instruction',13,10,0 message_table dw no_support_message,support_message,0 basic_message db 'maximun basic function:0x',0 extend_message db 'maximun extended function:0x',0 value_address dd 0,0,0
在Bochs里運(yùn)行的結(jié)果如下所示。
Bochs是模擬Intel系列的CPU,在筆者的AMD真實(shí)機(jī)器上最大basic功能號(hào)是0x00000005,最大extended功能號(hào)是0x8000001A,在另一臺(tái)Intel i5機(jī)器上分別是0Bh和80000008h:
Intel的處理器上目前的最大basic功能號(hào)是0DH,最大extended功能號(hào)是80000008H(依賴于每個(gè)機(jī)器的實(shí)現(xiàn))。Intel手冊(cè)中指示Core i7處理器(Westmere架構(gòu))最大的basic功能號(hào)是0BH,最大的extended功能號(hào)是80000008H。
如果在eax中輸入的功能號(hào)超過(guò)了最大的功能號(hào),那么將返回basic最大功能號(hào)的信息。
當(dāng)eax=0Eh時(shí),返回的信息和eax=0Dh一致,當(dāng)eax=80000009h時(shí)返回的信息也和eax=0Dh一致。
實(shí)驗(yàn)4-3:分別使用0Dh和0Eh,以及80000008h和80000009h來(lái)運(yùn)行獲得信息
由于在目前的Intel上0Dh是最大basic功能號(hào),80000008h是最大的擴(kuò)展功能號(hào),因此本實(shí)驗(yàn)的目的是驗(yàn)證Intel所說(shuō)的話。
代碼清單4-3(topic04\ex4-3\setup.asm):
;; 現(xiàn)在得到最大功能號(hào) 0DH 的信息 mov si,msg1 call puts mov eax,0Dh cpuid mov [eax_value],eax mov [ebx_value],ebx mov [ecx_value],ecx mov [edx_value],edx call print_register_value ; 打印寄存器的值 ; 測(cè)試輸入功能號(hào)為 eax=0Eh mov si,msg2 call puts mov eax,0Eh cpuid mov [eax_value],eax mov [ebx_value],ebx mov [ecx_value],ecx mov [edx_value],edx call print_register_value ; 打印寄存器的值 ;; 現(xiàn)在得到 extended 最大功能號(hào) 80000008h 的信息 mov si,msg3 call puts mov eax,80000008h cpuid mov [eax_value],eax mov [ebx_value],ebx mov [ecx_value],ecx mov [edx_value],edx call print_register_value ; 打印寄存器的值 ;; 現(xiàn)在測(cè)試 extended 最大功能號(hào) 80000009 的信息 mov si,msg4 call puts mov eax,80000009h cpuid mov [eax_value],eax mov [ebx_value],ebx mov [ecx_value],ecx mov [edx_value],edx call print_register_value ; 打印寄存器的值
下面是在Bochs中運(yùn)行的結(jié)果。
可以看出,當(dāng)eax分別等于0Dh、0Eh和80000009h時(shí),所返回的信息是一樣的。在筆者的AMD真實(shí)機(jī)器上運(yùn)行上面的例子,得不到輸出結(jié)果,目前在AMD的機(jī)器上最大的basic功能號(hào)是06H,而extended功能號(hào)則達(dá)到了8000001Bh。
請(qǐng)注意:當(dāng)輸入的功能號(hào)<=最大功能號(hào)時(shí),如果CPU并不支持該功能號(hào),則所有寄存器返回0值,eax=ebx=ecx=edx=0。
由于在Bochs上所支持的最大basic功能號(hào)是0Dh,如果以0Ch去訪問(wèn)CPUID指令(0Ch功能號(hào)CPU不支持),返回的寄存器將全是0值(eax<=maxinum number)。
當(dāng)輸入功能號(hào)>最大功能號(hào)時(shí),訪問(wèn)CPUID,返回的將是最大功能號(hào)的信息,也就是上面做的實(shí)驗(yàn)所證明的。
4.4 處理器的型號(hào)(family,model與stepping)
由CPUID.01H:EAX可返回處理器的家族、模型及步進(jìn)信息。
EAX[11:8]得到family編碼,典型地,P6家族處理器的family編碼是06H,Pentium4家族的family編碼是0FH。EAX[27:20]得到擴(kuò)展的family值。EAX[7:4]得到處理器在家族中的model。EAX[19:16]得到擴(kuò)展的model值。
在這些處理器信息里,最重要的是family與model。由于x86處理器的龐大和混亂,在Intel文檔的相關(guān)描述中,使用了family和model的配合來(lái)描述處理器的特性,例如下面的這個(gè)描述。
DisplayFamily值的計(jì)算方法如下。
if (Family == 0FH) { DisplayFamily=ExtendedFamily + Family; } else DisplayFamily=Family;
可見(jiàn),只有在Pentium4以后的處理器才支持ExtendedFamily編號(hào)。DisplayModel值的計(jì)算方法如下。
if (Family == 06H || Family == 0FH) { DisplayModel=ExtendedModel << 4 + Model; } else DisplayModel=Model;
現(xiàn)在我們可以做個(gè)實(shí)驗(yàn)。
實(shí)驗(yàn)4-4:獲得處理器的DisplayFamily與DisplayModel
實(shí)驗(yàn)的完整源碼在topic04\ex4-4\setup.asm文件里,調(diào)用了lib\lib16.asm文件里面的get_DisplayFamily_DisplayModel()過(guò)程來(lái)獲得DisplayFamily和DisplayModel值,下面是運(yùn)行結(jié)果。
在筆者實(shí)驗(yàn)的機(jī)器上的處理器DispalyFamily是06H,DisplayModel是25H,根據(jù)Intel的說(shuō)明這個(gè)Model是屬于32nm制程的Core i3/i5/i7 Mobile處理器(屬于Westmere微架構(gòu))。
它的ExtendedModel值是0010B,Model值是0101B,組合起來(lái)是:25H。那么這個(gè)處理器模型將被描述為:06_25H。這種DisplayFamily_DisplayModel的模型相當(dāng)重要,在Intel手冊(cè)的描述中使用這種方式來(lái)區(qū)別處理器的模型。
在Intel的機(jī)器上,06H家族和0FH家族是兩大派系,0FH家族典型地是指Pentium4處理器系列。而06H家族很龐大,從早期的Pentium Pro、PentiumII到今天的Westmere/SandyBridge微架構(gòu)的i7/i5/i3處理器都屬于06H家族。在如此龐大的06H家族,要靠它的DisplayModel來(lái)識(shí)別每一代架構(gòu)的處理器。05H家族則屬于Pentium處理器。
4.5 最大的物理地址和線性地址
在CPUID.80000008H葉里,我們可以獲取處理器所支持的最大物理地址和線性地址的寬度。
上面的實(shí)驗(yàn)中80000008h功能號(hào)返回的eax值為0x00003028,低byte是物理地址寬度,值為28h就是40位,接著是線性地址寬度。當(dāng)CPU支持long mode時(shí),這個(gè)值是30h,否則就是20h,這表明long mode下最高支持48位的線性地址,線性地址的高16位被用做sign位,在32位的機(jī)器上這個(gè)值是20h(32位)。
MAXPHYADDR值
在Intel中廣泛使用MAXPHYADDR這個(gè)術(shù)語(yǔ)來(lái)表示最大的物理地址。80000008H leaf返回的EAX[7:0]被稱為MAXPHYADDR。
當(dāng)處理器不支持80000008H leaf(功能)時(shí),如果檢測(cè)到CPUID.01H:EDX[6]=1(即:PAE=1)則支持最高36位物理地址。如果此時(shí)PAE也并不支持,那么MAXPHYADDR就是32位。
4.6 處理器擴(kuò)展?fàn)顟B(tài)信息
實(shí)際上0Dh功能號(hào)是獲得處理器對(duì)Processor Extended State(處理器擴(kuò)展?fàn)顟B(tài))的支持度,這在AVX指令編程里非常重要。在最新的Sandy Bridge架構(gòu)的處理器中,支持度只使用了3位。
Processor Extended State(處理器擴(kuò)展?fàn)顟B(tài))是什么?
0Dh功能號(hào)是一個(gè)功能集,在前面的例子中:
mov eax,0Dh ; 0Dh 功能號(hào) mov ecx,0 ; main leaf(主葉)功能 cpuid ; 得到 0Dh 的 main leaf功能
這個(gè)main leaf功能就可以獲得CPU目前對(duì)處理器狀態(tài)信息的支持度,eax和edx寄存器返回processor extended state的enable/disable位圖。
返回的edx和eax寄存器組成一個(gè)64位的Processor Extended State功能表,高32位在edx寄存器,低32位在eax寄存器。在處理器的規(guī)劃中,每1位對(duì)應(yīng)一個(gè)擴(kuò)展?fàn)顟B(tài)功能enable位。為1時(shí)支持該狀態(tài),為0時(shí)不支持。
這個(gè)Processor Extended State值將影響到XCR0(Extended Control Register)的值。當(dāng)State值的某位為0時(shí),那么XCR0的相應(yīng)位為保留位(此位不能被XSETBV指令設(shè)置)。
目前的x86處理器中(包括Intel和AMD)僅使用了低3位(Bit 0~Bit2)。Bit 0對(duì)應(yīng)X87 FPU狀態(tài),Bit 1對(duì)應(yīng)SSE狀態(tài),這兩位一般都能返回1,表示CPU支持X87 FPU和SSE功能。Bit 2對(duì)應(yīng)YMM狀態(tài)。
YMM狀態(tài)在Intel的Sandy Bridge架構(gòu)和AMD的bulldozer架構(gòu)中得到了支持,也就是說(shuō)CPU支持AVX指令集。因此,在這種處理器以上才返回YMM狀態(tài)位為1值。
圖中的陰影部分為reserved(保留位),未來(lái)的處理器可能會(huì)使用這些位來(lái)支持更多的處理器狀態(tài)信息。保留位的值全部為0。
看看前面在Bochs里運(yùn)行的結(jié)果。
得到的結(jié)果表明:CPU支持x87 FPU和SSE狀態(tài)而不支持YMM狀態(tài),也就是說(shuō)不支持AVX指令。值得注意的是,由于Bochs模擬實(shí)現(xiàn)了CPUID 0DH號(hào)功能,因此可以使用0DH leaf進(jìn)行查詢。實(shí)際上,在不支持AVX指令的處理器上,并不支持CPUID 0DH leaf。
4.6.1 探測(cè)Processor Extended State子葉
由于eax返回的是處理器對(duì)Processor Extended State的enable位,在未來(lái)的處理器中可能加入更多的支持,因此在使用前應(yīng)該探測(cè)處理器到底支持了哪些Prcessor Extended State。
mov eax,0Dh ; 0Dh 功能號(hào) mov ecx,0 ; main leaf(主葉)功能 cpuid ; 得到 0Dh 的 main leaf功能,在edx:eax返回對(duì) ; processor extended state的支持位 mov [extended_state],eax ; 保存 enable 位 mov [extended_size],ebx ; 保存整個(gè)exended state的size值 mov dword [detect_value],2 ; 從Bit2 開(kāi)始探測(cè) detect: mov eax,0Dh ; 0Dh 功能號(hào) mov ecx,[detect_value] ; sub-leaves 子葉號(hào) bt dword [extended_state],ecx ; Bit n == 1 ? jnc next_detect ; 該位不支持,繼續(xù)探測(cè) cpuid ; 探測(cè) mov ecx,[detect_value] mov [state + ecx * 4],eax ; 保存子葉 size mov [state + ecx * 4 + 4],ebx ; 保存子葉 offset next_detect: inc dword [detect_value] ; 繼續(xù)探測(cè)下一個(gè)子葉 cmp dword [detect_value],62 ; 小于等于 62 就繼續(xù) jle detect next: ... ...
假如CPU支持AVX指令,那么CPUID(eax=0Dh,ecx=0h):EAX[YMM]為1,也就是eax的Bit 2為1,因此從第2位開(kāi)始探測(cè),假如Bit 3是支持的,繼續(xù)探測(cè)Bit 3,以此類推……
記錄下來(lái):在上面的64位Processor Extended State值中每1位代表一個(gè)子葉,從Bit 2(YMM狀態(tài))開(kāi)始。
在Processor Extended State中X87 FPU state是必須要支持的,它必定為1,而 SSE state也就是XMM寄存器狀態(tài),也是支持的,這時(shí)Bit 1位是保留。所以從Bit 2開(kāi)始探測(cè)直至Bit 62位,Bit 63位是保留未用。
4.6.2 Processor Extended State子葉所需內(nèi)存size
在main leaf(eax=0Dh,ecx=0h)里,ebx和ecx寄存器都返回一個(gè)內(nèi)存size。
ebx寄存器返回的是在XCR0(Extended Control Register)里設(shè)置了開(kāi)啟某個(gè)位去支持處理器狀態(tài)所需要的內(nèi)存size。
XCR0的結(jié)構(gòu)與上面CPUID(EAX=0Dh,ECX=0H) 返回的64位Processor Extended State值結(jié)構(gòu)是一樣的。XCR0可以設(shè)置SSE狀態(tài)為disable(關(guān)閉),這樣CPU將不會(huì)保存SSE(即:XMM寄存器)的值。
Processor Extended State與XCR0的關(guān)系
XCR0是一個(gè)功能開(kāi)關(guān),用來(lái)開(kāi)啟或關(guān)閉某些state的保存。而CPUID(eax=0Dh,ecx=00h)返回的Processor Extended State值將決定處理器保存哪些state信息的能力。
OS可以通過(guò)XSETBV指令對(duì)XCR0進(jìn)行相應(yīng)的設(shè)置,如果某位被disable掉,這時(shí)候,XCR0與CPU支持的64位Processor Extended State值會(huì)不一致。因此,ebx寄存器返回的是這個(gè)XCR0設(shè)置的保存狀態(tài)所需要的內(nèi)存size。
ecx寄存器返回的是CPU所支持的所有狀態(tài)(即:在main leaf里返回eax的位圖),保存這些狀態(tài)所需要的總內(nèi)存size,因此,ebx不一定等于ecx(取決于XCR0是否開(kāi)啟相應(yīng)的位)。
如果CPUID(eax=0Dh,ecx=0h)返回的eax寄存器為07H值,那么說(shuō)明它支持AVX指令,這樣的話就可以接著使用0Dh的2號(hào)子葉去查看相關(guān)的信息。
在AMD處理器上支持LWP指令,Bit 62位是LWP state位,所以在AMD里就可以查看62號(hào)子葉的信息。
下面是查看子葉號(hào)為62的相關(guān)信息(如果CPU支持)。
mov eax,0Dh ; 0Dh 功能號(hào) mov ecx,62 ; AMD機(jī)器上的62號(hào)子葉功能 cpuid
4.6.3 Processor Extended State的保存
Processor Extended State通過(guò)使用XSAVE指令來(lái)保存處理器的狀態(tài),在內(nèi)存中處理器的state映像看起來(lái)如下。
實(shí)際情況還要更復(fù)雜些,SSE和YMM狀態(tài)的保存,還取決于XSAVE指令提供的64位MASK碼和XCR0上面所述的相應(yīng)位的enable(開(kāi)啟),如果XCR0.YMM=0表明不保存YMM狀態(tài),那么圖中的YMM state區(qū)域是0值(不被更新)。
mov edx,0 mov eax,3 ; 不保存 YMM state xsave [state_image] ; 根據(jù) 64位的 Mask值和XCR0位進(jìn)行保存
同樣,在edx:eax這個(gè)64位的mask碼值中,如果YMM state mask位為0,YMM state區(qū)域也不被更新,必須XCR0和MASK值同時(shí)被置1(AND與關(guān)系)區(qū)域才被更新。
回到上面的例子,由于不支持AVX指令,所以eax返回0x03,表明僅支持X87 FPU和SSE狀態(tài)。而ebx和ecx寄存器的返回值是0x240,這個(gè)值就等于512+64=576(0x240),X87 FPU需要512字節(jié),還要加上一個(gè)header部分。這個(gè)header的首64位(8 bytes)是一個(gè)XSTATE_BV結(jié)構(gòu),當(dāng)XSAVE保存狀態(tài)時(shí),用來(lái)記錄部分狀態(tài)被保存了。若保存X87 FPU和SSE狀態(tài),就設(shè)置Bit 0和Bit 1為1,反之將清0。
4.6.4 Processor Extended State的恢復(fù)
使用XRSTOR指令可以從內(nèi)存的state映像中恢復(fù)原來(lái)保存的state信息。
header結(jié)構(gòu)是64字節(jié),首8字節(jié)是一個(gè)64位的MASK值,用來(lái)記錄在state映像中哪些區(qū)域是被保存過(guò)的(被更新過(guò)),相應(yīng)的位為1時(shí)表示image中的相應(yīng)的區(qū)域被更新,如:YMM state區(qū)域中被保存過(guò),那么XSTATE_BV[2]=1(Bit 2對(duì)應(yīng)于YMM state位)。
XSTATE_BV的位在執(zhí)行XSAVE指令保存state時(shí)被CPU設(shè)置。當(dāng)執(zhí)行xrstor指令時(shí),CPU會(huì)根據(jù)XSTATE_BV中哪一位被置位,而做相應(yīng)的恢復(fù)。
4.7 處理器的特性
EAX=01h號(hào)功能將獲得處理器的基本信息,它是CPUID中一個(gè)重要的功能號(hào),eax寄存器返回處理器的Model、Family、Stepping等信息。在ebx寄存器中:ebx[15:8]返回CLFLUSH line size,這個(gè)值乘8就可以得到Cache line的size,ebx[23:16]返回邏輯處理器最大可尋址的數(shù)目。
實(shí)驗(yàn)4-5:查看CPU的cache line size和Maximum logic processor
實(shí)驗(yàn)的完整源碼在\topic04\ex4-5\setup.asm文件里,下面是在VMware里的運(yùn)行結(jié)果。
在VMware中筆者設(shè)置processor core的數(shù)目為4個(gè),上面顯示的logic processor是4個(gè),ebx[15:8]的值是0x08,所以它的cache line size是64(0x40)字節(jié)。
在ecx和edx寄存器中返回CPU支持的種類繁多的特性,下面分別是ecx和edx寄存器返回值所對(duì)應(yīng)的功能。
這些特性是處理器硬件物理上所支持的功能,利用CPUID指令可以檢測(cè)處理器所支持的特性。
可是CPUID.EAX=01H在ECX和EDX返回的某些特性是由軟件設(shè)置的。還有部分特性受到MSR(Model Specific Register)的設(shè)置影響。
例如:ECX寄存器的bit 27是OSXSAVE標(biāo)志位,這個(gè)標(biāo)志位并不是硬件特性,是由軟件設(shè)置而來(lái)的,在OS里為了開(kāi)啟AVX指令使用環(huán)境,OS最終會(huì)設(shè)置CR4的Bit 18位CR4.OSXSAVE=1,處理器會(huì)根據(jù)這個(gè)位來(lái)置CPUID(EAX=01h):ECX[27]標(biāo)志,也就是上面的ECX[OSXSAVE]標(biāo)志位。軟件使用AVX指令前會(huì)讀取這個(gè)標(biāo)志位,確認(rèn)OS已經(jīng)準(zhǔn)備好AVX指令的執(zhí)行環(huán)境。
檢測(cè)CPU是否支持AVX指令的是Bit 28 AVX標(biāo)志位,而Bit 26位是XSAVE標(biāo)志位,它用于檢測(cè)CPU是否支持XSAVE/XRSTOR、XSETBV/XGETBV指令和XCR0。
4.8 處理器的Cache與TLB信息
CPUID.EAX=02H用來(lái)獲得關(guān)于CPU的Cache與TLB信息。
mov eax,02H ; 02號(hào)功能 cpuid
eax寄存器的最低字節(jié)(byte 0)是需要執(zhí)行CPUID.EAX=02H的次數(shù)。
上面這個(gè)最低字節(jié)的值為01,表明只需要執(zhí)行一次CPUID.EAX=02H就能獲得完整的信息。
寄存器的MSB(Bit31)位是個(gè)標(biāo)志位,為0指示有效,為1指示無(wú)效。
eax、ebx、ecx和edx寄存器中的每個(gè)字節(jié)指示一個(gè)信息(除EAX寄存器的byte 0外)。
如果是FF字節(jié)表示CPUID.EAX=02H不返回cache及TLB信息,需要執(zhí)行CPUID.EAX=04H進(jìn)行查詢。
實(shí)驗(yàn)4-6:使用CPUID.EAX=02H查看cache及TLB信息
實(shí)驗(yàn)的源碼在\topic04\ex4-6\setup.asm中,下面是在VMware中的運(yùn)行結(jié)果。
上面的信息是在VMware下打印出來(lái)的,從這個(gè)結(jié)果,我們可以看出來(lái)以下信息。
處理器的Cache和TLB情況也可以從CPUID.EAX=04H里獲得,04H功能號(hào)是一個(gè)集,以ECX輸入一個(gè)子葉號(hào),枚舉出處理器Cache的所有信息。
首先以ECX=0H子葉開(kāi)始查詢,在eax寄存器返回,我們所關(guān)心的是以下幾個(gè)位域。
EAX[4:0]返回cache的類型,分別是:1=Data cache,2=Instruction cache,3=Unified cache,0值是終止標(biāo)志,表示已經(jīng)沒(méi)有子葉可以枚舉了,其他值是保留的。
EAX[7:5]返回cache的level,EAX[31:26]域里也可以查詢得到處理器的core數(shù),這個(gè)查詢結(jié)果值需要加上1才是真正的值。
接下來(lái)EBX寄存器的返回信息是:EBX[11:00]是line size,EBX[21:12]是physical line partition,EBX[31:22]返回cache的way數(shù)。最后ECX寄存器返回32位的cache set數(shù)量。
實(shí)驗(yàn)4-7:使用CPUID.EAX=04H/ECX=n來(lái)查看cache及TLB信息
下面是部分代碼片斷,完整的源碼在topic04\ex4-7\setup.asm里。
代碼清單4-4:
@@1: mov ecx,[sub_leaves] ; 子葉號(hào) mov esi,ecx mov di,value_address call get_hex_string mov si,msg call puts mov si,value_address call puts mov si,msg2 call puts mov eax,04 ; 探測(cè) ECX=n cpuid mov [eax_value],eax ; 保存各個(gè)寄存器的值 mov [ebx_value],ebx mov [ecx_value],ecx mov [edx_value],edx inc dword [sub_leaves] ; 下一個(gè)子葉號(hào) call print_cache_info ; 打印信息 test eax,eax jnz @@1
從子葉ECX=0H開(kāi)始進(jìn)行探測(cè),直至EAX[4:0]為0(表示沒(méi)有下一個(gè)子葉),每一個(gè)子葉得到的cache size的計(jì)算方法如下。
cache size=line size×line partition×way×set
也就是等于:(EBX[11:00]+1)*(EBX[21:12]+1)*(EBX[31:22]+1)*(ECX+1)。
每一項(xiàng)加上1,是因?yàn)榉祷氐男畔⒓由?才是完整的值。這個(gè)計(jì)算的過(guò)程在print_cache_info()過(guò)程里,讀者可以在topic04\ex4-7\setup.asm源碼里看到。下面是在VMware中的運(yùn)行結(jié)果。
對(duì)比一下上面的運(yùn)行結(jié)果和使用CPUID.EAX=02H查詢到的結(jié)果,看是否一致。上面的結(jié)果是:
1級(jí)Data-cache的size是32KB(值為0x8000),8-way 64 set結(jié)構(gòu)。1級(jí)Instruction-cache的size同樣是32KB(值為0x8000),4-way 128 set結(jié)構(gòu)。2級(jí)cache的size是256KB(值為0x40000),8-way 512 set結(jié)構(gòu)。3級(jí)cache的size是3MB(值為0x300000),屬于12-way 4096 set結(jié)構(gòu)。
對(duì)比結(jié)果cache size和cache結(jié)構(gòu)是一樣的,在這個(gè)例子里沒(méi)有完整打印詳細(xì)的信息,讀者朋友可以自行加入更完整的顯示。這個(gè)例子探測(cè)到子葉號(hào)ECX=03H為止,ECX=04H已經(jīng)不支持了。
讓人感到沮喪的是:在AMD的機(jī)器上并不支持EAX=02H到EAX=04H的功能號(hào)!
是的,這確實(shí)讓人反感,在AMD的機(jī)器上basic功能號(hào)支持EAX=01H、EAX=05H、EAX=06H以及EAX=0DH,這4個(gè)功能號(hào)。可是AMD比Intel支持更多的extended功能號(hào),根據(jù)AMD的CPUID specification指示,最多達(dá)到了8000001EH,而Intel只支持到80000008H。
在AMD機(jī)器上可以使用80000005H、80000006H,以及8000001DH擴(kuò)展功能號(hào)查詢cache和TLB的相關(guān)信息。
4.9 MONITOR/MWAIT信息
在CPUID.EAX=01H功能里返回的ECX[3]可以查詢處理器是否支持MONITOR與MWAIT指令,MONITOR/MWAIT指令用來(lái)監(jiān)控某個(gè)線性地址范圍內(nèi)沒(méi)發(fā)生store操作進(jìn)入一個(gè)被優(yōu)化的狀態(tài)。
下面是一個(gè)典型的MONITOR/MWAIT指令使用序列。
@Loop: bt dword [WorkQueue],0 ; 測(cè)試 WorkQueue == 1 ? jnc no_work ... ... ; 執(zhí)行其他調(diào)度 jmp @Loop ;;; 當(dāng) WorkQueue == 0 時(shí): no_work: mov eax,WorkQueue ; 監(jiān)控地址 mov ecx,0 ; 0 extensions mov edx,0 ; 0 hints MONITOR ; 進(jìn)入監(jiān)控 bt dword [WorkQueue],0 ; 測(cè)試 WorkQueue jc @Loop ; WorkdQueue == 1 時(shí)重新循環(huán) sti ; 允許被中斷事件退出優(yōu)化的狀態(tài) mov eax,0 ; 0 hints mov ecx,0 ; 0 extensions MWAIT ; wait jmp @Loop
monitor/mwait指令的使用情形有些與pause指令類似,在Idle Loop(空閑的循環(huán))中用來(lái)提高處理器的性能和減少能耗。pause常用于OS的自旋鎖,monitor/mwait對(duì)某個(gè)地址范圍做監(jiān)控,這個(gè)地址范圍內(nèi)沒(méi)發(fā)生store操作就進(jìn)入優(yōu)化的狀態(tài),由mwait等待某些事件而退出,因地址store操作而退出或者因某些中斷類的事件發(fā)生。
執(zhí)行CPUID.05H在EAX[15:00]里返回Smallest monitor-line size,在EBX[15:00]里返回Largest monitor-line size。在MSR IA32_MONITOR_FILTER_LINE_SIZE里可以對(duì)這些值進(jìn)行設(shè)置,從而影響CPUID.05H leaf的讀取結(jié)果。
4.10 處理器的long mode
extended功能號(hào)80000001H是一個(gè)很重要的CPUID leaf,里面有最為重要的Long Mode標(biāo)志位,用來(lái)查詢處理器是否支持long mode,在AMD的機(jī)器上80000001H具有很多特性,而Intel的機(jī)器上許多為保留位。
最重要的位是EDX[29]返回long mode標(biāo)志,EDX[11]是SYSCALL/SYSRET指令支持標(biāo)志位,EDX[26]是1G-page支持位。
mov eax,80000000H cpuid cmp eax,80000001H ; < 80000001h ? jb no_support mov eax,80000001H cpuid bt edx,29 ; 測(cè)試是否支持 long mode jnc no_support ... ...
上面是典型的測(cè)試處理器是否支持long mode的代碼。
- Big Data Analytics with Hadoop 3
- Practical Ansible 2
- 計(jì)算機(jī)應(yīng)用基礎(chǔ)·基礎(chǔ)模塊
- 圖解PLC控制系統(tǒng)梯形圖和語(yǔ)句表
- PyTorch深度學(xué)習(xí)實(shí)戰(zhàn)
- MicroPython Projects
- 工業(yè)機(jī)器人入門實(shí)用教程(KUKA機(jī)器人)
- STM32G4入門與電機(jī)控制實(shí)戰(zhàn):基于X-CUBE-MCSDK的無(wú)刷直流電機(jī)與永磁同步電機(jī)控制實(shí)現(xiàn)
- Maya 2012從入門到精通
- Windows內(nèi)核原理與實(shí)現(xiàn)
- Excel 2010函數(shù)與公式速查手冊(cè)
- 21天學(xué)通Linux嵌入式開(kāi)發(fā)
- 生成對(duì)抗網(wǎng)絡(luò)項(xiàng)目實(shí)戰(zhàn)
- Cortex-M3嵌入式處理器原理與應(yīng)用
- Data Analysis with R(Second Edition)