Message-ID: <37A6E429.6245A110@softhome.net> Date: Tue, 03 Aug 1999 14:44:25 +0200 From: Laurynas Biveinis X-Mailer: Mozilla 4.61 [en] (Win98; I) X-Accept-Language: lt,en MIME-Version: 1.0 To: DJGPP Workers Subject: CPU identification (Was: Re: uname -m ?) References: Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Reply-To: djgpp-workers AT delorie DOT com Eli Zaretskii wrote: > Because there's no easy way to identify the exact CPU type. If you > know about a safe way to do that without crashing on all supported > platforms, including NT and DOSEmu, please submit a change for the > `uname' library function. I wrote program for this. It uses ways to detect CPU type strictly according to Pentium II documentation. It doesn't use any privileged instructions, so it should (?) work on NT and DOSEMU. However: - It detects any better than 486 clone as "i586" - it won't detect any 386/486 clone which differently uses undefined EFLAGS bits - it has been tested only on one system and correctly reported that original Intel Pentium II 333MHz is a "i686" So anybody is welcome to check it and/or add support for clones Laurynas Biveinis ----------------- /* CPU type under DJGPP checker, v1.0alpha */ /* (C) 1999 Laurynas Biveinis */ #include int main(void) { unsigned is_486_or_better; unsigned is_586_or_better; unsigned vendor_id[3]; unsigned version_info; /* Let's check for 386. Intel says that 386 is unable to set or clear */ /* value of 18 bit in EFLAGS (AC). So we toggle this bit and see if */ /* we succeed */ asm volatile ( "pushf;" /* save EFLAGS */ "popl %%eax;" /* get EFLAGS */ "movl %%eax, %%ebx;" /* temp storage EFLAGS */ "xorl $0x40000, %%eax;" /* change AC bit in EFLAGS */ "pushl %%eax;" /* put new EFLAGS value on stack */ "popf;" /* replace current EFLAGS value */ "pushf;" /* get EFLAGS */ "popl %%eax;" /* save new EFLAGS in EAX */ "cmpl %%ebx, %%eax;" /* compare temp and new EFLAGS */ "jz 0f;" "movl $1, %0;" /* 80486+ present */ "jmp 1f;" "0:" "movl $0, %0;" /* 80386 present */ "1:" "pushl %%ebx;" /* get original EFLAGS */ "popf;" /* restore EFLAGS */ : "=g" (is_486_or_better) : : "eax", "ebx"); if (is_486_or_better) { /* In the same way we checked for 386, we will check for 486 now, */ /* using 21 bit in EFLAGS (ID bit) */ asm volatile ( "pushf;" /* get extended flags */ "popl %%eax;" "movl %%eax, %%ebx;" /* save current flags */ "xorl $0x200000, %%eax;" /* toggle bit 21 */ "pushl %%eax;" /* put new flags on stack */ "popfl;" /* flags updated now in flags */ "pushfl;" /* get extended flags */ "popl %%eax;" "xorl %%ebx, %%eax;" /* if bit 21 r/w then supports cpuid */ "jz 0f;" "movl $1, %0;" "jmp 1f;" "0:" "movl $0, %0;" "1:" : "=g" (is_586_or_better) : : "%eax", "%ebx"); if (is_586_or_better) { /* Now we can use CPUID */ asm volatile ( "movl $0, %%eax;" "cpuid;" : "=b" (vendor_id[0]), "=d" (vendor_id[1]), "=c" (vendor_id[2]) : : "%eax"); /* If we have "GenuineIntel" CPU */ if ((vendor_id[0] == 0x756E6547) && (vendor_id[1] == 0x49656E69) && (vendor_id[2] == 0x6C65746E)) { /* Then we can check, is it Pentium or PentiumPro/PentiumII*/ asm volatile ( "movl $1, %%eax;" "cpuid;" : "=a" (version_info) : : "%ebx", "%ecx", "%edx"); /* What we need is family info in 8-11 bits */ version_info = (version_info & 0x780) >> 8; if (version_info == 0x6) printf("i686\n"); else printf("i586\n"); } else /* TODO: add detection for clones */ printf("i586\n"); } else printf("i486\n"); } else printf("i386\n"); return 0; }