Rozpoznawanie typu procesora
Autor: Bogdan Drozdowski, bogdandr (at) op.pl
Jak zapewne wiecie, wiele programow (systemy operacyjne, gry, ...) potrafi
jakos "dowiedziec sie", na jakim procesorze zostaly uruchomione. Rozpoznanie
typu procesora umozliwia np. uruchomienie dodatkowych optymalizacji w
programie lub odmowe dalszego dzialania, jesli program musi korzystac z
instrukcji niedostepnych na adanym procesorze.
Wykrywanie rodzaju CPU i FPU nie jest trudne i pokaze teraz, jak po kolei
sprawdzac typ procesora (nie mozna przeciez zaczac sprawdzania od
najwyzszych).
Informacje, ktore tutaj podam, sa oczywiscie sluszne dla wszystkich
procesorow rodziny x86 (AMD, Cyrix, ...), a nie tylko Intela.
Generalnie sposoby wykrywania sa dwa: poprzez rejestr FLAG lub poprzez
zakodowanie w kodzie instrukcji, ktore wykonaja sie tylko na danym modelu
(i pozniejszych). Drugi sposob jest troche trudniejszy: nalezy przejac
przerwanie INT6 (nieprawidlowa instrukcja) i sprawdzac, kiedy zostalo
wywolane.
1. odroznienie 8088 od reszty
Procesor 8088 od pozostalych odroznia to, ze zmniejsza on rejestr SP
przed umieszczeniem go na stosie. Reszta robi to po umieszczeniu SP
na stosie. Kod wygladalby wiec na przyklad tak:
mov ax, sp
push sp
pop cx
xor ax, cx ; lub cmp ax, cx
jz nie_8088
2. 8086
Na tym procesorze w rejestrze flag bity 12-15 zawsze maja wartosc 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
3. 80186
Test polega na probie wykonania instrukcji "smsw dx", nieprawidlowej
na procesorach wczesniejszych niz 80286. Przerwanie nieprawidlowej
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 obslugi przerwania wygladac bedzie tak:
moje06:
pop ax
add ax, 3
push ax
xor ax, ax
iret
Proste: zwiekszamy adres powrotny o 3 (dlugosc instrukcji "smsw dx")
i zerujemy AX (potem w kodzie sprawdzimy jego wartosc). Sam kod
sprawdzajacy wyglada tak:
mov ax, 1
db 0fh, 1, 0e2h ; smsw dx
or ax, ax
jz jest_286
Przywrocenie oryginalnej procedury wyglada tak:
xor ax, ax
les cx, [_stare06]
mov ds, ax
mov [ds:(6 << 2)], cx
mov [ds:(6 << 2) + 2], es
4. 80286
Na tym procesorze bity 12-15 flag zawsze maja wartosc 0. Przykladowy
kod wyglada wiec 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
5. 80386
Na tym procesorze nie mozna zmienic bitu numer 18 we flagach (wiemy, ze
rejestr flag ma 32 bity). Bit ten odpowiada za Alignment Check i
spowoduje przerwanie m.in wtedy, gdy SP nie bedzie podzielne przez 4.
Dlatego, zanim bedziemy testowac ten bit, musimy zachowac SP i
wyzerowac jego najmlodsze 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
6. 80486
Na tym procesorze nie mozna zmienic bitu 21 we flagach. Jesli ten bit
mozna zmienic, to procesor obsluguje instrukcje CPUID, ktorej
bedziemy uzywac 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 omowie sposob korzystania z instrukcji CPUID, zajmijmy sie sposobem
rozpoznania typu koprocesora.
-----------------------------------------------------------------------------
Koprocesor
Tutaj mozliwosci sa tylko 4: brak, 8087, 80287, 80387. No to do roboty.
1. czy w ogole jest jakis koprocesor?
To sprawdzamy bardzo latwo. Jesli nie ma koprocesora, to w chwili
wykonania instrukcji FPU moze wystapic przerwanie INT6 (nieprawidlowa
instrukcja), ale nie o tym sposobie chcialem powiedziec. Koprocesor
mozna wykryc, jesli slowo stanu zostanie zapisane prawidlowo. 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
2. 8087
Sztuczka polega na wykorzystaniu instrukcji FDISI (wylaczenie przerwan),
ktora rzeczywiscie cos robi tylko na 8087. Po wylaczeniu przerwan w
slowie kontrolnym zostaje wlaczony 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
3. 80287
Koprocesor ten nie odroznia minus nieskonczonosci od plus
nieskonczonosci. Kod na sprawdzenie tego wyglada 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 procesorow 586 (choc niektore 486 tez podobno ja obslugiwaly), Intel
i inni wprowadzili instrukcje CPUID. Pozwala ona odczytac wiele roznych
informacji o procesorze (konkretny typ, rozmiary pamieci podrecznych,
dodatkowe rozszerzenia, ...).
Korzystanie z tej instrukcji jest bardzo proste: do EAX wpisujemy numer
(0-3) i wywolujemy instrukcje, np.
mov eax, 1
cpuid
Teraz omowie, co mozna dostac przy roznych wartosciach EAX.
1. EAX=0
EAX = maksymalny numer funkcji dla CPUID.
EBX:EDX:ECX = marka procesora (12 znakow ASCII).
Intel - "GenuineIntel"
AMD - "AuthenticAMD"
NexGen - "NexGenDriven"
Cyrix, VIA - "CyrixInstead"
RISE - "RiseRiseRise",
Centaur Technology/IDT - "CentaurHauls" (programowalne, moze byc inne)
United Microelectronics Corporation - "UMC UMC UMC "
Transmeta Corporation - "GenuineTMx86"
SiS - "SiS SiS SiS "
National Semiconductor - "Geode by NSC".
2. EAX=1
EAX = informacje o wersji:
* bity 0-3: stepping ID
* bity 4-7: model
* bity 8-11: rodzina. Wartosci moga byc od 4 (80486) do 7 (Itanium)
oraz 15 ("sprawdz rozszerzone informacje o rodzinie")
* bity 12-13: typ procesora (0=Original OEM Processor,
1=Intel Overdrive, 2=Dual)
* bity 16-19 (jesli jest taka mozliwosc): rozszerzona informacja
o modelu.
* bity 20-27 (jesli jest taka mozliwosc): rozszerzona informacja
o rodzinie.
EDX = cechy procesora (tutaj akurat z procesorow Intela; najpierw
numery bitow):
* 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: zawiera Zaawansowany Programowalny Kontroler Przerwan (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 mozliwosc modyfikacji
wydajnosci 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, uklady kontroli temperatury
* 31: Pending Break Enable
3. EAX=2
EBX, ECX, EDX = informacje o pamieci podrecznej cache i TLB
Nawet te informacje, ktore tu przedstawilem sa juz bardzo szczegolowe i
z pewnoscia nie beda takie same na wszystkich procesorach. To jest tylko
wstep. Dalsze informacje mozna znalezc na stronach producentow procesorow,
np. AMD Intel, ale takze tutaj: Sandpile Lista przerwan Ralfa Brown'a
(plik opcodes.lst)
Wyszukiwarka
Podobne podstrony:
DOS DIOD TUTDOS PWR TUTCPU TUTDOS MYSZ TUTDOS GRAF TUTDOS SPKR TUTDOS BOOT TUTDOS SYS TUTCPU TUTDOS BIBL TUTCPU TUTDOS TSR TUTDOS BMP TUTcpuFUNFACE DOS OPISdo pomiary temperatury cpu ReadMe!ART121 tut 2więcej podobnych podstron