官术网_书友最值得收藏!

第4章 處理器的身份

我需要了解處理器的型號(hào)、廠商、有什么具體的特性等這些關(guān)于處理器的參數(shù),應(yīng)該怎么辦?x86/x64處理器上提供了CPUID指令用來查看和識(shí)別身份。

4.1 測試是否支持CPUID指令

eflags寄存器的bit 21是ID(Processor Feature Identification)標(biāo)志位,在286處理器中flags是16位的,在386處理器中eflags擴(kuò)展為32位,bit 21是reserved。CPUID指令從Intel 486處理器上開始加入,因此除非你在古老的機(jī)器上運(yùn)行,否則沒必要檢測處理器是否支持CPUID指令。

實(shí)驗(yàn)4-1:測試是否支持CPUID指令

test_CPUID()在源文件lib\lib16.asm里,在topic04\ex4-1\目錄有實(shí)驗(yàn)代碼:

代碼清單4-1(lib\lib16.asm):

;---------------------------------------------------
; test_CPUID():測試是否支持 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ù)語及表達(dá)

Intel64手冊里對(duì)CPUID指令廣泛使用了如下一些表達(dá)形式和術(shù)語。

leaf(葉)

功能號(hào)使用leaf術(shù)語,例如: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手冊中使用了下面的描述形式。

上面是判斷處理器是否支持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指令被使用來查詢處理器所支持的特性,因此CPUID所支持的leaf數(shù)量是與處理器相關(guān)的。很多時(shí)候,在使用某個(gè)leaf查詢之前,必須判斷處理器是否支持該leaf。

典型地,在使用0BH號(hào)功能時(shí),應(yīng)先查詢處理器是否支持0BH號(hào)功能。

基本最大功能號(hào)

使用CPUID的00H leaf來查詢,最大的基本功能號(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”,組合起來是“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手冊中指示Core i7處理器(Westmere架構(gòu))最大的basic功能號(hào)是0BH,最大的extended功能號(hào)是80000008H。

如果在eax中輸入的功能號(hào)超過了最大的功能號(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來運(yùn)行獲得信息

由于在目前的Intel上0Dh是最大basic功能號(hào),80000008h是最大的擴(kuò)展功能號(hào),因此本實(shí)驗(yàn)的目的是驗(yàn)證Intel所說的話。

代碼清單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                    ; 打印寄存器的值
; 測試輸入功能號(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)在測試 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。

請注意:當(dāng)輸入的功能號(hào)<=最大功能號(hào)時(shí),如果CPU并不支持該功能號(hào),則所有寄存器返回0值,eax=ebx=ecx=edx=0。

由于在Bochs上所支持的最大basic功能號(hào)是0Dh,如果以0Ch去訪問CPUID指令(0Ch功能號(hào)CPU不支持),返回的寄存器將全是0值(eax<=maxinum number)。

當(dāng)輸入功能號(hào)>最大功能號(hào)時(shí),訪問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的配合來描述處理器的特性,例如下面的這個(gè)描述。

DisplayFamily值的計(jì)算方法如下。

if (Family == 0FH)
{
        DisplayFamily=ExtendedFamily + Family;
}
else
        DisplayFamily=Family;

可見,只有在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()過程來獲得DisplayFamily和DisplayModel值,下面是運(yùn)行結(jié)果。

在筆者實(shí)驗(yàn)的機(jī)器上的處理器DispalyFamily是06H,DisplayModel是25H,根據(jù)Intel的說明這個(gè)Model是屬于32nm制程的Core i3/i5/i7 Mobile處理器(屬于Westmere微架構(gòu))。

它的ExtendedModel值是0010B,Model值是0101B,組合起來是:25H。那么這個(gè)處理器模型將被描述為:06_25H。這種DisplayFamily_DisplayModel的模型相當(dāng)重要,在Intel手冊的描述中使用這種方式來區(qū)別處理器的模型。

在Intel的機(jī)器上,06H家族和0FH家族是兩大派系,0FH家族典型地是指Pentium4處理器系列。而06H家族很龐大,從早期的Pentium Pro、PentiumII到今天的Westmere/SandyBridge微架構(gòu)的i7/i5/i3處理器都屬于06H家族。在如此龐大的06H家族,要靠它的DisplayModel來識(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ù)語來表示最大的物理地址。80000008H leaf返回的EAX[7:0]被稱為MAXPHYADDR。

當(dāng)處理器不支持80000008H leaf(功能)時(shí),如果檢測到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)中得到了支持,也就是說CPU支持AVX指令集。因此,在這種處理器以上才返回YMM狀態(tài)位為1值。

圖中的陰影部分為reserved(保留位),未來的處理器可能會(huì)使用這些位來支持更多的處理器狀態(tài)信息。保留位的值全部為0。

看看前面在Bochs里運(yùn)行的結(jié)果。

得到的結(jié)果表明:CPU支持x87 FPU和SSE狀態(tài)而不支持YMM狀態(tài),也就是說不支持AVX指令。值得注意的是,由于Bochs模擬實(shí)現(xiàn)了CPUID 0DH號(hào)功能,因此可以使用0DH leaf進(jìn)行查詢。實(shí)際上,在不支持AVX指令的處理器上,并不支持CPUID 0DH leaf。

4.6.1 探測Processor Extended State子葉

由于eax返回的是處理器對(duì)Processor Extended State的enable位,在未來的處理器中可能加入更多的支持,因此在使用前應(yīng)該探測處理器到底支持了哪些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 開始探測
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ù)探測
      cpuid                                       ; 探測
      mov ecx,[detect_value]
      mov [state + ecx * 4],eax           ; 保存子葉 size
      mov [state + ecx * 4 + 4],ebx      ; 保存子葉 offset
next_detect:
      inc dword [detect_value]                ; 繼續(xù)探測下一個(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位開始探測,假如Bit 3是支持的,繼續(xù)探測Bit 3,以此類推……

記錄下來:在上面的64位Processor Extended State值中每1位代表一個(gè)子葉,從Bit 2(YMM狀態(tài))開始。

在Processor Extended State中X87 FPU state是必須要支持的,它必定為1,而 SSE state也就是XMM寄存器狀態(tài),也是支持的,這時(shí)Bit 1位是保留。所以從Bit 2開始探測直至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è)置了開啟某個(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è)功能開關(guān),用來開啟或關(guān)閉某些state的保存。而CPUID(eax=0Dh,ecx=00h)返回的Processor Extended State值將決定處理器保存哪些state信息的能力。

OS可以通過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是否開啟相應(yīng)的位)。

如果CPUID(eax=0Dh,ecx=0h)返回的eax寄存器為07H值,那么說明它支持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通過使用XSAVE指令來保存處理器的狀態(tài),在內(nèi)存中處理器的state映像看起來如下。

實(shí)際情況還要更復(fù)雜些,SSE和YMM狀態(tài)的保存,還取決于XSAVE指令提供的64位MASK碼和XCR0上面所述的相應(yīng)位的enable(開啟),如果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í),用來記錄部分狀態(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ù)原來保存的state信息。

header結(jié)構(gòu)是64字節(jié),首8字節(jié)是一個(gè)64位的MASK值,用來記錄在state映像中哪些區(qū)域是被保存過的(被更新過),相應(yīng)的位為1時(shí)表示image中的相應(yīng)的區(qū)域被更新,如:YMM state區(qū)域中被保存過,那么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指令可以檢測處理器所支持的特性。

可是CPUID.EAX=01H在ECX和EDX返回的某些特性是由軟件設(shè)置的。還有部分特性受到MSR(Model Specific Register)的設(shè)置影響。

例如:ECX寄存器的bit 27是OSXSAVE標(biāo)志位,這個(gè)標(biāo)志位并不是硬件特性,是由軟件設(shè)置而來的,在OS里為了開啟AVX指令使用環(huán)境,OS最終會(huì)設(shè)置CR4的Bit 18位CR4.OSXSAVE=1,處理器會(huì)根據(jù)這個(gè)位來置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)境。

檢測CPU是否支持AVX指令的是Bit 28 AVX標(biāo)志位,而Bit 26位是XSAVE標(biāo)志位,它用于檢測CPU是否支持XSAVE/XRSTOR、XSETBV/XGETBV指令和XCR0。

4.8 處理器的Cache與TLB信息

CPUID.EAX=02H用來獲得關(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指示無效。

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下打印出來的,從這個(gè)結(jié)果,我們可以看出來以下信息。

處理器的Cache和TLB情況也可以從CPUID.EAX=04H里獲得,04H功能號(hào)是一個(gè)集,以ECX輸入一個(gè)子葉號(hào),枚舉出處理器Cache的所有信息。

首先以ECX=0H子葉開始查詢,在eax寄存器返回,我們所關(guān)心的是以下幾個(gè)位域。

EAX[4:0]返回cache的類型,分別是:1=Data cache,2=Instruction cache,3=Unified cache,0值是終止標(biāo)志,表示已經(jīng)沒有子葉可以枚舉了,其他值是保留的。

EAX[7:5]返回cache的level,EAX[31:26]域里也可以查詢得到處理器的core數(shù),這個(gè)查詢結(jié)果值需要加上1才是真正的值。

接下來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來查看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                                       ; 探測 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開始進(jìn)行探測,直至EAX[4:0]為0(表示沒有下一個(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ì)算的過程在print_cache_info()過程里,讀者可以在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è)例子里沒有完整打印詳細(xì)的信息,讀者朋友可以自行加入更完整的顯示。這個(gè)例子探測到子葉號(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指令用來監(jiān)控某個(gè)線性地址范圍內(nèi)沒發(fā)生store操作進(jìn)入一個(gè)被優(yōu)化的狀態(tài)。

下面是一個(gè)典型的MONITOR/MWAIT指令使用序列。

@Loop:
      bt dword [WorkQueue],0                   ; 測試 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                   ;  測試 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))中用來提高處理器的性能和減少能耗。pause常用于OS的自旋鎖,monitor/mwait對(duì)某個(gè)地址范圍做監(jiān)控,這個(gè)地址范圍內(nè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)志位,用來查詢處理器是否支持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                                ; 測試是否支持 long mode
jnc no_support
... ...

上面是典型的測試處理器是否支持long mode的代碼。

主站蜘蛛池模板: 团风县| 南乐县| 唐山市| 延长县| 化州市| 革吉县| 虞城县| 贡山| 贵阳市| 宁波市| 丹凤县| 德庆县| 体育| 信阳市| 六盘水市| 金昌市| 察雅县| 通河县| 大足县| 金山区| 陵水| 门头沟区| 收藏| 定远县| 广饶县| 呼玛县| 台东市| 湖口县| 延庆县| 观塘区| 邹平县| 磐石市| 四平市| 汝城县| 定襄县| 鄱阳县| 石楼县| 斗六市| 南华县| 观塘区| 安顺市|