CPU Detection Algorithms

Programming, for all ages and all languages.
Post Reply
User avatar
ChosenOreo
Member
Member
Posts: 25
Joined: Sun May 29, 2011 5:16 pm
Location: Inside A Computer
Contact:

CPU Detection Algorithms

Post by ChosenOreo »

I've added a wiki page at User:ChosenOreo/CPU_Detection detailing different ways I detect various CPUs. I've only just started it, can't really do much on my phone right now but I'll probably add the rest of it tomorrow when I get on my computer. Right now I have detecting things lower than an 80286, (currently only) 8088/8086/80188/80186/V20/V30/V40/V50.

If you happen to know any other algorithms for detecting CPUs it'd be greatly appreciated. Some of the stuff I'm currently looking for include detecting if there is a coprocessor (x87-series, 8089, etc..), and getting the stepping information for the processor. I know you can reset the computer and get the values from the EDX register on 80386+, but I was wondering if there was any way to get the stepping info on 8086 through 80286.

Any feedback on my page and help with the two things listed above would be great!

- Adrian
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: CPU Detection Algorithms

Post by Combuster »

Div tests are good to tell apart brands of CPUs.
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Octocontrabass
Member
Member
Posts: 5513
Joined: Mon Mar 25, 2013 7:01 pm

Re: CPU Detection Algorithms

Post by Octocontrabass »

ChosenOreo wrote:I know you can reset the computer and get the values from the EDX register on 80386+, but I was wondering if there was any way to get the stepping info on 8086 through 80286.
The 386 is the first CPU to provide stepping information in a standard way. For all prior CPUs, you must use bugs or small differences in behavior to tell them apart.

I'm curious to see what information you have about getting the stepping from a 386/486. I know of at least two methods, but neither is 100% reliable.
Nable
Member
Member
Posts: 453
Joined: Tue Nov 08, 2011 11:35 am

Re: CPU Detection Algorithms

Post by Nable »

Code: Select all

xor al, al
mov al, 0x40
mul al
jz Cpu_Is_NEC
0x40 * 0x40 != 0, so other register should be used in lines 2-3, shouldn't it? Another option: you can just remove line 2.
Octocontrabass
Member
Member
Posts: 5513
Joined: Mon Mar 25, 2013 7:01 pm

Re: CPU Detection Algorithms

Post by Octocontrabass »

The zero flag is undefined after mul. That code relies on differences in undefined behavior to detect the CPU.
freecrac
Member
Member
Posts: 69
Joined: Thu Sep 20, 2012 5:11 am
Location: germany hamburg

Re: CPU Detection Algorithms

Post by freecrac »

Code: Select all

                Cpu86    =   0
                Cpu286   =   4
                Cpu386   =   8
                Cpu486   =  12
                Cpu586   =  16
;-------------------------------------
                FpuNone  =   0
                FpuYes   =   10h
                FpuEmul  =   50h
;-------------------------------------

          call GETCPU                 ; AX=CPU
          call GETFPU                 ; DX=FPU

;-------------------------------------
GETCPU:   mov      ax, Cpu86
          xor      bx, bx
          push     bx
          popf
          pushf
          pop      bx
          and      bh, 0F0h
          cmp      bh, 0F0h
          je  short CPUOK
;-------------------------------------
          mov      ax, Cpu286
          push     7000h
          popf
          pushf
          pop      bx
          and      bh, 70h
          jz  short CPUOK
;-------------------------------------
          mov      ax, Cpu386
          mov      edx, esp
          and      esp, 0FFFCh
          pushfd
          pop      ebx
          mov      ecx, ebx
          btc      ebx, 18
          push     ebx
          popfd
          pushfd
          pop      ebx
          push     ecx
          popfd
          mov      esp, edx
          cmp      ecx, ebx
          jz  short CPUOK
;-------------------------------------
          mov      ax, Cpu486
          btc      ecx, 21
          push     ecx
          popfd
          pushfd
          pop      ebx
          cmp      ebx, ecx
          jnz short CPUOK
;-------------------------------------
          mov      ax, Cpu586
;-------------------------------------
CPUOK:    mov      bp, ax
          ret                         ; AX=Cpu
;------------------------------------------------------------------------------
GETFPU:   mov      dx, FpuNone
          mov     BYTE PTR cs:[F1], 90h
          mov     BYTE PTR cs:[F2], 90h
F1:       finit
F2:       fstcw   WORD PTR[FLAGS]
          cmp     BYTE PTR[FLAGS+1], 3
          jnz short FPUOK
;-------------------------------------
          mov      dx, FpuYes
          cmp      ax, Cpu86          ; No emulation for 8086
          jz  short FPUOK
;-------------------------------------
          smsw     bx
          shr      bx, 1
          and      bx, 3
          cmp      bx, 2              ; Bit 2=1 -> Emul
          jnz short FPUOK
;-------------------------------------
          mov      dx, FpuEmul
;-------------------------------------
FPUOK:    ret                         ; DX=FPU

FLAGS  DB 0, 0, 0, 0
User avatar
ChosenOreo
Member
Member
Posts: 25
Joined: Sun May 29, 2011 5:16 pm
Location: Inside A Computer
Contact:

Re: CPU Detection Algorithms

Post by ChosenOreo »

Thanks for all the comments guys!
Combuster wrote:Div tests are good to tell apart brands of CPUs.
I hadn't even heard about that before. Thanks for the link.. will be reading it! :D
Octocontrabass wrote:I'm curious to see what information you have about getting the stepping from a 386/486. I know of at least two methods, but neither is 100% reliable.
I rely on a method I learned about from Robert Collin's great article where you use a (bug?) where you can change the reset vector to point to your code (due to an inconsistency with the A20 line). Immediately after doing that, the computer is reset and you have some stepping information in the EDX register.
However, as stated on his page, there are some times where that code shouldn't be executed as some BIOSes ignore the A20 line, while others have 2 copies of the code at both locations.
Octocontrabass wrote:For all prior CPUs, you must use bugs or small differences in behavior to tell them apart.
I was hoping someone wouldn't say that. :(
I was browsing the internet at one point for algorithms and I came across a few assembly files (sorry, can't seem to find them right now.. will keep looking!) that got stepping on 8086 and 80286, but nothing for the 80186 series. In those files, however, there were still a few steppings missing (from what I've read at least). I'll try to add links to them if I find them.
Nable wrote:

Code: Select all

xor al, al
mov al, 0x40
mul al
jz Cpu_Is_NEC
0x40 * 0x40 != 0, so ther register should be used in lines 2-3, shouldn't it? Another option: you can just remove line 2
On all Intel documentation I've seen, the zero flag is undefined after a mul operation. On NECs (according to Robert Collins again..), however, the zero flag is set to what the result is. In the code, the xor operation sets the zero flag. At the mul operation, Intel CPUs will leave the flag alone while the NEC CPUs will, in this case, clear it. Then we just check the flag to see if we're a NEC or an Intel.

Edit: Through some deeper digging, I found an old NEC documentation that said that a MUL operation leaves the zero flag undefined. But, I did find a pdf with another way to detect it (rep lods bug). I'll be looking at that and incorporating it into the CPU Detection page as well.
freecrac wrote:

Code: Select all

...
Thanks for showing that! However, being a bit paranoid, I read somewhere that a finit can lock up some computers if an x87 coprocessor isn't there. Do you know if there's any truth to that?

Again, thanks everyone for comments!
- Adrian
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: CPU Detection Algorithms

Post by Brendan »

Hi,
ChosenOreo wrote:Any feedback on my page and help with the two things listed above would be great!
I think you're missing the simplest and most powerful technique: install an invalid opcode handler and see which opcodes are invalid. If "smsw" doesn't work then it's older than 80286, if "mov eax,cr3" doesn't work then it's older than 80386, if "invlpg" doesn't work it's older than 80486, if "cpuid" doesn't work then it's older than Pentium, etc.


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
User avatar
ChosenOreo
Member
Member
Posts: 25
Joined: Sun May 29, 2011 5:16 pm
Location: Inside A Computer
Contact:

Re: CPU Detection Algorithms

Post by ChosenOreo »

Brendan wrote:I think you're missing the simplest and most powerful technique: install an invalid opcode handler and see which opcodes are invalid.
I do that for my detection of 286/386/486, I just haven't added it to the page yet. Thanks for the comment though!

- Adrian
Antti
Member
Member
Posts: 923
Joined: Thu Jul 05, 2012 5:12 am
Location: Finland

Re: CPU Detection Algorithms

Post by Antti »

Brendan wrote:install an invalid opcode handler and see which opcodes are invalid. If "smsw" doesn't work then it's older than 80286
I have not found a good manual for 80186 but I guess it is not possible to use an invalid opcode handler if the CPU is older than 80286. For newer CPUs, this is an excellent method.

Just a historical side note, the "smsw instruction starts with "0F" and I we had a really ancient 8086 CPU, this would be "pop cs".
freecrac
Member
Member
Posts: 69
Joined: Thu Sep 20, 2012 5:11 am
Location: germany hamburg

Re: CPU Detection Algorithms

Post by freecrac »

ChosenOreo wrote:Thanks for showing that! However, being a bit paranoid, I read somewhere that a finit can lock up some computers if an x87 coprocessor isn't there. Do you know if there's any truth to that?
No sorry, i do not know that. I used it only together with a 80286 CPU and with the emulator "EM87.COM" (EM87 V1.2 9/08/89 from Ron Kimball).

Dirk
Octocontrabass
Member
Member
Posts: 5513
Joined: Mon Mar 25, 2013 7:01 pm

Re: CPU Detection Algorithms

Post by Octocontrabass »

ChosenOreo wrote:However, as stated on his page, there are some times where that code shouldn't be executed as some BIOSes ignore the A20 line, while others have 2 copies of the code at both locations.
The BIOS has a long-forgotten "fast reset" function that does a far jump to whatever address you'd like. It's intended for 286 operating systems, so it should be supported by all 386 and 486 BIOSes. You can use it to prevent the computer from rebooting in case your attempt to move the reset vector fails. (One BIOS does a near jump instead of a far jump, so you'll need to keep that in mind when you write your code.)

It's also useful for getting the CPU signature, since most BIOSes won't modify EDX before jumping.
Post Reply