CPU TUT



#Start Contents

Rozpoznawanie typu procesora

(przeskocz wykrywanie procesora)
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 danym
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
(przeskocz 8088)
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:
(przeskocz kod dla 8088)
mov ax, sp
push sp
pop cx
xor ax, cx ; lub cmp ax, cx
jz nie_8088
2. 8086
(przeskocz 8086)
Na tym procesorze w rejestrze flag bity 12-15 zawsze maja wartosc
1.
(przeskocz kod dla 8086)
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
(przeskocz 80186)
Test polega na probie wykonania instrukcji "smsw dx",
nieprawidlowej na procesorach wczesniejszych niz 80286.
Przerwanie nieprawidlowej instrukcji przejmujemy tak:
(przeskocz kod dla 80186)
xor ax, ax
mov es, ax

les bx, [es:6 << 2] ; FASM: les bx, [es:(6 shl 2)]

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

mov es, ax
mov word [es:(6 << 2)], moje06
; FASM: mov word [es:(6 shl 2)], moje06
mov word [es:(6 << 2) + 2], seg moje06
; FASM: mov word [es:(6 shl 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
; FASM: mov [ds:(6 shl 2)], cx
mov [ds:(6 << 2) + 2], es
; FASM: mov [ds:(6 shl 2) + 2], es
4. 80286
(przeskocz 80286)
Na tym procesorze bity 12-15 flag zawsze maja wartosc 0.
Przykladowy kod wyglada wiec tak:
(przeskocz kod dla 80286)
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
(przeskocz 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.
(przeskocz kod dla 80386)
mov dx, sp
and sp, ~3 ; aby uniknac AC fault.
; FASM: and sp, not 3
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
(przeskocz 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:
(przeskocz kod dla 80486)
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

(przeskocz wykrywanie koprocesora)
Tutaj mozliwosci sa tylko 4: brak koprocesora, 8087, 80287, 80387. No
to do roboty.
1. czy w ogole jest jakis koprocesor?
(przeskocz test na istnienie FPU)
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:
(przeskocz test na istnienie FPU)
fninit ; inicjalizacja zeruje rejestry

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

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

jz jest_FPU
2. 8087
(przeskocz 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.
(przeskocz kod dla 8087)
; zachowaj slowo kontrolne do pamieci:
fnstcw [_fpu_status]

; wylaczamy wszystkie
; przerwania (poprzez slowo kontrolne):
and word [_fpu_status], 0ff7fh

; zaladuj slowo kontrolne z pamieci:
fldcw [_fpu_status]

fdisi ; wylaczamy wszystkie przerwania
; (jako instrukcja)

; zachowaj slowo kontrolne do pamieci:
fstcw [_fpu_status]
test byte [_fpu_status], 80h ; bit 7 ustawiony?

jz nie_8087 ; jesli nie, to nie jest to 8087
3. 80287
(przeskocz 80287)
Koprocesor ten nie odroznia minus nieskonczonosci od plus
nieskonczonosci. Kod na sprawdzenie tego wyglada tak:
(przeskocz kod dla 80287)
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
(przeskocz 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
(przeskocz 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 (co znaczy "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: procesor 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)

Spis tresci off-line (Alt+1)
Spis tresci on-line (Alt+2)
Ulatwienia dla niepelnosprawnych (Alt+0)


Wyszukiwarka

Podobne podstrony:
CPU TUT
DOS 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