CPU TUT




Rozpoznawanie typu procesora










Rozpoznawanie typu procesora

Jak zapewne wiecie, wiele programów (systemy operacyjne, gry, ...) potrafi jakoś
"dowiedzieć się", na jakim procesorze zostały uruchomione. Rozpoznanie typu procesora
umożliwia np. uruchomienie dodatkowych optymalizacji w programie lub odmowę dalszego
działania, jeśli program musi korzystać z instrukcji niedostępnych na adanym procesorze.
Wykrywanie rodzaju CPU i FPU nie jest trudne i pokażę teraz, jak po kolei sprawdzać
typ procesora (nie można przecież zacząć sprawdzania od najwyższych).
Informacje, które tutaj podam, są oczywiście słuszne dla wszystkich procesorów
rodziny x86 (AMD, Cyrix, ...), a nie tylko Intela.
Generalnie sposoby wykrywania są dwa: poprzez rejestr FLAG lub poprzez zakodowanie w kodzie
instrukcji, które wykonają się tylko na danym modelu (i późniejszych). Drugi sposób jest trochę trudniejszy:
należy przejąć przerwanie INT6 (nieprawidłowa instrukcja) i sprawdzać, kiedy zostało wywołane.


odróżnienie 8088 od reszty
Procesor 8088 od pozostałych odróżnia to, że zmniejsza on rejestr SP przed umieszczeniem
go na stosie. Reszta robi to po umieszczeniu SP na stosie. Kod wyglądałby więc na przykład tak:

mov ax, sp
push sp
pop cx
xor ax, cx ; lub cmp ax, cx
jz nie_8088


8086
Na tym procesorze w rejestrze flag bity 12-15 zawsze mają wartość 1.

pushf ; flagi na stos
pop ax ; AX = flagi
and ax, 0fffh ; czyscimy bity 12-15
push ax ; AX na stos
popf ; flagi = AX
pushf ; z powrotem na stos
pop ax ; AX = flagi
and ax, 0f000h ; zerujemy bity poza bitami 12-15
cmp ax, 0f000h ; jesli ustawione, to 8086
jz jest_8086


80186
Test polega na próbie wykonania instrukcji "smsw dx", nieprawidłowej na procesorach wcześniejszych
niż 80286. Przerwanie nieprawidłowej instrukcji przejmujemy tak:

xor ax, ax
mov es, ax

les bx, [es:6 << 2]

mov [_stare06+2], es
mov [_stare06], bx

mov es, ax
mov word [es:(6 << 2)], moje06
mov word [es:(6 << 2) + 2], seg moje06
Sama procedura obsługi przerwania wyglądać będzie tak:

moje06:
pop ax
add ax, 3
push ax
xor ax, ax
iret
Proste: zwiększamy adres powrotny o 3 (długość instrukcji "smsw dx") i zerujemy AX
(potem w kodzie sprawdzimy jego wartość). Sam kod sprawdzający wygląda tak:

mov ax, 1
db 0fh, 1, 0e2h ; smsw dx
or ax, ax
jz jest_286

Przywrócenie oryginalnej procedury wygląda tak:

xor ax, ax
les cx, [_stare06]
mov ds, ax
mov [ds:(6 << 2)], cx
mov [ds:(6 << 2) + 2], es

80286
Na tym procesorze bity 12-15 flag zawsze mają wartość 0. Przykładowy kod wygląda więc tak:

pushf ; flagi na stos
pop ax ; AX = flagi
or ax, 0f000h ; ustawiamy bity 12-15
push ax ; AX na stos
popf ; flagi = AX
pushf ; flagi na stos
pop ax ; AX = flagi
and ax, 0f000h ; jesli wyczyszczone, to 286
jnz nie_286


80386
Na tym procesorze nie można zmienić bitu numer 18 we flagach (wiemy, że rejestr flag ma 32 bity).
Bit ten odpowiada za Alignment Check i spowoduje przerwanie m.in wtedy, gdy SP nie będzie podzielne przez 4.
Dlatego, zanim będziemy testować ten bit, musimy zachować SP i wyzerować jego najmłodsze 2 bity.

mov dx, sp
and sp, ~3 ; aby uniknac AC fault
pushfd ; flagi na stos
pop eax ; EAX = E-flagi
mov ecx, eax ; zachowanie EAX
xor eax, 40000h ; zmiana bitu 18
push eax ; EAX na stos
popfd ; E-flagi = EAX
pushfd ; flagi na stos
pop eax ; EAX = flagi
xor eax, ecx ; czy takie same? jesli tak, to 386
mov sp, dx ; przywrocenie SP
jz jest_386


80486
Na tym procesorze nie można zmienić bitu 21 we flagach. Jeśli ten bit można zmienić, to
procesor obsługuje instrukcję CPUID, której będziemy używać do dalszego rozpoznania. Kod:

pushfd ; flagi na stos
pop eax ; EAX = E-flagi
mov ecx, eax ; zachowanie EAX
xor eax, 200000h ; zmiana bitu 21
push eax ; EAX na stos
popfd ; E-flagi = EAX
pushfd ; flagi na stos
pop eax ; EAX = flagi
xor eax, ecx ; czy takie same? jesli tak, to 486
jz jest_486
jmp jest_586


Zanim omówię sposób korzystania z instrukcji CPUID, zajmijmy się sposobem rozpoznania typu koprocesora.





Koprocesor
Tutaj możliwości są tylko 4: brak, 8087, 80287, 80387. No to do roboty.


czy w ogóle jest jakiś koprocesor?
To sprawdzamy bardzo łatwo. Jeśli nie ma koprocesora, to w chwili wykonania instrukcji FPU może wystąpić przerwanie INT6
(nieprawidłowa instrukcja), ale nie o tym sposobie chciałem powiedzieć. Koprocesor można wykryć,
jeśli słowo stanu zostanie zapisane prawidłowo. Oto kod:

fninit ; inicjalizacja zeruje rejestry

mov word [_fpu_status], 5a5ah ; jakas niezerowa wartosc

fnstsw [_fpu_status] ; zapisz slowo statusowe do pamieci
mov ax, [_fpu_status]
or al, al ; jesli zapisalo dobrze (zera oznaczaja puste rejestry), to jest FPU

jz jest_FPU


8087
Sztuczka polega na wykorzystaniu instrukcji FDISI (wyłączenie przerwań), która rzeczywiście coś robi tylko na 8087.
Po wyłączeniu przerwań w słowie kontrolnym zostaje włączony bit numer 7.

fnstcw [_fpu_status] ; zachowaj slowo kontrolne do pamieci
and word [_fpu_status], 0ff7fh ; wylaczamy wszystkie przerwania (poprzez slowo kontrolne)
fldcw [_fpu_status] ; zaladuj slowo kontrolne z pamieci
fdisi ; wylaczamy wszystkie przerwania (jako instrukcja)
fstcw [_fpu_status] ; zachowaj slowo kontrolne do pamieci
test byte [_fpu_status], 80h ; bit 7 ustawiony? jesli nie, to nie jest to 8087
jz nie_8087


80287
Koprocesor ten nie odróżnia minus nieskończoności od plus nieskończoności. Kod na sprawdzenie tego wygląda tak:

finit

fld1 ; st(0)=1
fldz ; st(0)=0,st(1)=1
fdivp st1 ; tworzymy nieskonczonosc, dzielac przez 0
fld st0 ; st(1):=st(0)=niesk.
fchs ; st(0)= -niesk.

; porownanie st0 z st1 i zdjecie obu ze stosu
fcompp ; 8087/287: -niesk. = +niesk.,
; 387: -niesk. != +niesk.

fstsw [_fpu_status] ; zapisz status do pamieci
mov ax, [_fpu_status] ; AX = status
sahf ; zapisz AH we flagach. tak sie sklada, ze tutaj rowniez
; flaga ZF wskazuje na rownosc argumentow.
jz jest_287
jmp jest_387












Dalsze informacje o procesorze - instrukcja CPUID

Od procesorów 586 (choć niektóre 486 też podobno ją obsługiwały), Intel i inni wprowadzili
instrukcję CPUID. Pozwala ona odczytać wiele różnych informacji o procesorze (konkretny typ,
rozmiary pamięci podręcznych, dodatkowe rozszerzenia, ...).
Korzystanie z tej instrukcji jest bardzo proste: do EAX wpisujemy numer (0-3) i wywołujemy instrukcję, np.

mov eax, 1
cpuid

Teraz omówię, co można dostać przy różnych wartościach EAX.

EAX=0
EAX = maksymalny numer funkcji dla CPUID.
EBX:EDX:ECX = marka procesora (12 znaków ASCII).
Intel - "GenuineIntel"
AMD - "AuthenticAMD"
NexGen - "NexGenDriven"
Cyrix, VIA - "CyrixInstead"
RISE - "RiseRiseRise",
Centaur Technology/IDT - "CentaurHauls" (programowalne, może być inne)
United Microelectronics Corporation - "UMC UMC UMC "
Transmeta Corporation - "GenuineTMx86"
SiS - "SiS SiS SiS "
National Semiconductor - "Geode by NSC".


EAX=1
EAX = informacje o wersji:

bity 0-3: stepping ID
bity 4-7: model
bity 8-11: rodzina. Wartości mogą być od 4 (80486) do 7 (Itanium) oraz 15 ("sprawdź rozszerzone informacje o rodzinie")
bity 12-13: typ procesora (0=Original OEM Processor, 1=Intel Overdrive, 2=Dual)
bity 16-19 (jeśli jest taka możliwość): rozszerzona informacja o modelu.
bity 20-27 (jeśli jest taka możliwość): rozszerzona informacja o rodzinie.

EDX = cechy procesora (tutaj akurat z procesorów Intela; najpierw numery bitów):

0: procesor zawiera FPU
1: Virtual 8086 Mode Enchancements
2: Debugging Extensions
3: Page Size Extension
4: Time Stamp Counter
5: Model Specific Registers
6: Physical Address Extensions
7: Machine Check Exception
8: instrukcja CMPXCHG8B
9: procesor zawiera Zaawansowany Programowalny Kontroler Przerwań (APIC)
11: instrukcje SYSENTER i SYSEXIT
12: Memory Type Range Registers
13: Page Table Entries Global Bit
14: Machine Check Architecture
15: instrukcje CMOV*
16: Page Attribute Table
17: 32-bit Page Size Extensions
18: numer seryjny procesora
19: instrukcja CLFLUSH
21: Debug Store
22: monitorowanie temperatury i możliwość modyfikacji wydajności procesora
23: technologia MMX
24: instrukcje FXSAVE i FXRSTOR
25: technologia SSE
26: technologia SSE2
27: Self-Snoop
28: technologia Hyper-Threading
29: monitorowanie temperatury, układy kontroli temperatury
31: Pending Break Enable


EAX=2
EBX, ECX, EDX = informacje o pamięci podręcznej cache i TLB


Nawet te informacje, które tu przedstawiłem są już bardzo szczegółowe i z pewnością nie będą
takie same na wszystkich procesorach. To jest tylko wstęp. Dalsze informacje można znaleźć na stronach producentów procesorów, np.
AMD
Intel,
ale także tutaj:
Sandpile
Lista przerwań Ralfa Brown'a
(plik opcodes.lst)





Wyszukiwarka

Podobne podstrony:
DOS CPU TUT
CPU TUT
CPU TUT
cpu
do pomiary temperatury cpu ReadMe!
ART121 tut 2
phys tut 08
czujnik obrotow went CPU
phys tut 12
DOS DIOD TUT
epox cpu support
SYS TUT
ART121 tut 3
MYSZ TUT
PWR TUT

więcej podobnych podstron