(汇编源代码 )侦测CPU型号

_PROCESSOR DETECTION SCHEMES_
by Richard C. Leinecker
  [LISTING ONE]
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Detect the Processor Type -- by Richard C. Leinecker         ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  _PTEXT   SEGMENT PARA PUBLIC 'CODE'
    ASSUME CS:_PTEXT, DS:_PTEXT
  public _Processor
; This routine returns the processor type as an integer value.
; C Prototype
; int Processor( void );
; Returns: 0 == 8088, 1 == 8086, 2 == 80286, 3 == 80386, 4 == 80486
; Code assumes es, ax, bx, cx, and dx can be altered. If their contents
; must be preserved, then you'll have to push and pop them.
_Processor proc  far
  push  bp     ; Preserve bp
    mov bp,sp      ; bp = sp
  push  ds     ; Preserve ds
    push  di     ; and di
  mov ax,cs      ; Point ds
    mov ds,ax      ; to _PTEXT
  call  IsItAn8088   ; Returns 0 or 2
  cmp al,2      ; 2 = 286 or better
    jge AtLeast286   ; Go to 286 and above code
  call  IsItAn8086   ; Returns 0 or 1
  jmp short ExitProcessor ; Jump to exit code
AtLeast286:
    call  IsItA286    ; See if it's a 286
  cmp al,3      ; 4 and above for 386 and up
    jl short ExitProcessor ; Jump to exit code
AtLeast386:
    call  IsItA386    ; See if it's a 386
ExitProcessor:
    pop di     ; Restore di,
    pop ds     ; ds,
    pop bp     ; and bp
  ret       ; Return to caller
_Processor endp
  ; Is It an 8088?
; Returns ax==0 for 8088/8086, ax==2 for 80286 and above
IsItAn8088 proc
    pushf        ; Preserve the flags
  pushf        ; Push the flags so
    pop bx     ; we can pop them into bx
  and bx,00fffh    ; Mask off bits 12-15
    push  bx     ; and put it back on the stack
  popf        ; Pop value back into the flags
    pushf        ; Push it back. 8088/8086 will
                        ; have bits 12-15 set
    pop bx     ; Get value into bx
    and bx,0f000h    ; Mask all but bits 12-15
  sub ax,ax      ; Set ax to 8088 value
    cmp bx,0f000h    ; See if the bits are still set
    je Not286     ; Jump if not
  mov al,2      ; Set for 286 and above
Not286:
    popf        ; Restore the flags
  ret       ; Return to caller
IsItAn8088 endp
  ; Is It an 8086?
; Returns ax==0 for 8088, ax==1 for 8086
; Code takes advantage of the 8088's 4-byte prefetch queues and 8086's
; 6-byte prefetch queues. By self-modifying the code at a location exactly 5
; bytes away from IP, and determining if the modification took effect,
; you can differentiate between 8088s and 8086s.
IsItAn8086 proc
  mov ax,cs     ; es == code segment
    mov es,ax
  std      ; Cause stosb to count backwards
  mov dx,1      ; dx is flag and we'll start at 1
    mov di,OFFSET EndLabel ; di==offset of code tail to modify
    mov al,090h    ; al==nop instruction opcode
    mov cx,3      ; Set for 3 repetitions
    REP stosb     ; Store the bytes
  cld      ; Clear the direction flag
    nop      ; Three nops in a row
    nop      ; provide dummy instructions
    nop
    dec dx     ; Decrement flag (only with 8088)
    nop      ; dummy instruction--6 bytes
EndLabel:
    nop
  mov ax,dx     ; Store the flag in ax
  ret      ; Back to caller
IsItAn8086 endp
  ; Is It an 80286?
; Determines whether processor is a 286 or higher. Going into subroutine ax = 2
; If the processor is a 386 or higher, ax will be 3 before returning. The
; method is to set ax to 7000h which represent the 386/486 NT and IOPL bits
; This value is pushed onto the stack and popped into the flags (with popf).
; The flags are then pushed back onto the stack (with pushf). Only a 386 or 486
; will keep the 7000h bits set. If it's a 286, those bits aren't defined and
; when the flags are pushed onto stack these bits will be 0. Now, when ax is
; popped these bits can be checked. If they're set, we have a 386 or 486.
IsItA286  proc
    pushf        ; Preserve the flags
    mov ax,7000h    ; Set the NT and IOPL flag
            ; bits only available for
            ; 386 processors and above
    push  ax     ; push ax so we can pop 7000h
            ; into the flag register
    popf        ; pop 7000h off of the stack
    pushf        ; push the flags back on
    pop ax     ; get the pushed flags
            ; into ax
    and ah,70h     ; see if the NT and IOPL
            ; flags are still set
    mov ax,2      ; set ax to the 286 value
    jz YesItIsA286   ; If NT and IOPL not set
            ; it's a 286
    inc ax     ; ax now is 4 to indicate
            ; 386 or higher
YesItIsA286:
    popf        ; Restore the flags
  ret       ; Return to caller
IsItA286  endp
  ; Is It an 80386 or 80486?
; Determines whether processor is a 386 or higher. Going into subroutine ax=3
; If the processor is a 486, ax will be 4 before leaving. The method is to set
; the AC bit of the flags via EAX and the stack. If it stays set, it's a 486.
IsItA386  proc
    mov di,ax      ; Store the processor value
    mov bx,sp      ; Save sp
    and sp,0fffch    ; Prevent alignment fault
.386
    pushfd       ; Preserve the flags
  pushfd       ; Push so we can get flags
    pop eax     ; Get flags into eax
    or eax,40000h   ; Set the AC bit
    push  eax     ; Push back on the stack
    popfd        ; Get the value into flags
    pushfd       ; Put the value back on stack
    pop eax     ; Get value into eax
    test  eax,40000h   ; See if the bit is set
    jz YesItIsA386   ; If not we have a 386
  add di,2      ; Increment to indicate 486
YesItIsA386:
    popfd        ; Restore the flags
.8086
    mov sp,bx      ; Restore sp
    mov ax,di      ; Put processor value into ax
  ret       ; Back to caller
IsItA386  endp
  _PTEXT   ENDS
    END
[LISTING TWO]
  .586
; Pentium detect routine. Call only after verifying processor is an i486 or
; later. Returns 4 if on i486, 5 if Pentium, 6 or greater for future
; Intel processors.
EF_IDequ200000h ; ID bit in EFLAGS register
Pentium proc near
  ; Check for Pentium or later by attempting to toggle the ID bit in EFLAGS reg;
; if we can't, it's an i486.
pushfd ; get current flags
popeax ;
movebx,eax ;
xoreax,EF_ID; attempt to toggle ID bit
pusheax ;
popfd  ;
pushfd ; get new EFLAGS
popeax ;
pushebx ; restore original flags
popfd  ;
andeax,EF_ID; if we couldn't toggle ID, it's an i486
andebx,EF_ID ;
cmpeax,ebx ;
jeshort Is486 ;
  ; It's a Pentium or later. Use CPUID to get processor family.
moveax,1 ; get processor info form of CPUID
cpuid  ;
shrax,8 ; get Family field; 5 means Pentium.
andax,0Fh ;
ret
Is486:
movax,4 ; return 4 for i486
ret
pentium endp
[LISTING THREE]
  #pragma inline
main()
{
  long  start1;
  long end1;
  long  start2;
  long end2;
  start1 = clock();
asm   P386
asm   mov eax,10000000
asm   lea ebx,loop1
asm   loop1: 
asm   dec eax
asm   jz loop1e
asm   jmp ebx
loop1e:
  start2 = end1 = clock();
asm   mov eax,10000000
asm   lea ebx,loop2
asm   nop
asm   loop2:
asm   dec eax
asm   jz loop2e
asm   jmp ebx
loop2e:
  end2 = clock();
   printf("misaligned loop time = %d, aligned loop time =%d
",
  (int)(end1-start1), (int)(end2-start2));
  return;
}
posted @ 2007-12-13 00:01  Max Woods  阅读(485)  评论(0编辑  收藏  举报