diff options
Diffstat (limited to 'libc/misc/cputype.c')
-rw-r--r-- | libc/misc/cputype.c | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/libc/misc/cputype.c b/libc/misc/cputype.c new file mode 100644 index 0000000..642edf6 --- /dev/null +++ b/libc/misc/cputype.c @@ -0,0 +1,344 @@ +/* + * This does a determination of the cpu type that is actually being used. + * It can determine the CPU on anything upto and including a 386 accuratly + * whatever mode the CPU is in (This is 16 bit code) + * An MSDOS compiled version is available. + * + * For Post 386 interpretation the argument must be set to 1, if this is done + * an attempt to determine the CPU type will be made using MSDOS calls and + * potentially Illegal instructions. + * + * If STANDALONE is defined this will decode and print the output from cputype + * + * $ cputype # Call cputype(0) and interpret + * $ cputype + # Call cputype(1) get a SIGILL (or perhaps interpret) + * + * NOTE: This code is COPYRIGHT and not under the GNU Lib copyright, this + * may be distributed freely as source or as a standalone binary + * compiled from this unmodified source. + * + * You may use the cputype() function in your own personal code. + * You may distribute a binary version of code containing the + * cputype() function if either you distribute this source with + * the binary version or distribute a clear reference to a freely + * available copy of this source code and the source code to the + * rest of your package with the binary version of the package. + * + * (C) Copyright R de Bath 1989-1995 + */ + +#ifdef STANDALONE + +#include <stdio.h> +#include <signal.h> + +char * name_808x[] = { +"8088", "8086", "80C88", "80C86", "NEC V20", "NEC V30", "808x Clone" +}; + +char * name_8018x[] = { +"80188", "80186", "8018x Clone" +}; + +void +main(argc, argv) +int argc; char **argv; +{ + int c, major, flg, fpu; +#ifdef SIGFPE + signal(SIGFPE, SIG_IGN); +#endif + + printf("Cpu identifier - (C) R de Bath <rdebath@cix.compulink.co.uk>\n"); + + c = cputype(argc!=1); + fpu = (c<0); major = ((c>>8)&0x1F); c &= 0xFF; + + if( major == 0 ) + { + if( c > 6 ) c = 6; + printf("Cpu is an %s\n", name_808x[c]); + } + else if( major == 1 ) + { + if( c > 3 ) c = 3; + printf("Cpu is an %s\n", name_8018x[c]); + } + else + { + printf("Cpu is an 80%x86%s", major&0xF, major>15?"+":""); + if(c&0x01) printf( " in protected mode"); + printf(" MSW= "); + if( c&0x10 ) printf("ET,"); else printf("--,"); + if( c&0x08 ) printf("TS,"); else printf("--,"); + if( c&0x04 ) printf("EM,"); else printf("--,"); + if( c&0x02 ) printf("MP,"); else printf("--,"); + if( c&0x01 ) printf("PE\n"); else printf("--\n"); + + if( !fpu && ( c&0x06) ) + printf("An FPU appears to exist but it is unavailable\n"); + else + { + if( c&0x02 ) printf("Math processor requires WAIT\n"); + if( c&0x04 ) printf("Emulated math present\n"); + if( c&0x08 ) printf("Math processor belongs to a different process\n"); + /* if( c&0x10 ) printf("Humm\n"); */ + } + } + if( fpu ) printf("FPU available for use\n"); + + exit(0); +} +#endif + +/* + * The assembler for CPU determination. + * + * Improvements and additional CPUs are solicited. + */ + +#ifdef __AS386_16__ +#asm + .text +export _cputype +_cputype: + ; First save everything ... + push bp + mov bp,sp + push ds + push es + push bx + push cx + push dx + pushf +#if __FIRST_ARG_IN_AX__ + mov cx, ax ; Collect the flag +#else + mov cx, [bp+4] ; Collect the flag +#endif + + ; Tiny mode code ... + mov ax, cs + mov es, ax + mov ds, ax + mov bx, #0 ; Init to 8086 + + ; First easy check is it a 286 or better ... + push sp + pop ax + cmp ax, sp + jz ge286 + br pre286 + + ; Come here when we`re done (286+) +cpu_prot: + ; .286P + smsw ax ; Fetch 5 LSB of MSW (PE,MP,EP,...) + and al,#31 + mov bl,al + + ; Check for FPU + fninit + xor ax,ax + push ax + mov bp,sp + fnstcw word ptr [bp] + pop ax + cmp ah,#3 + jne cpuend + or bh,#$80 + + ; Another check for FPU *BUT* I think this only get`s 287+ +; finit +; fstsw ax +; or al,al +; jnz cpuend +; or bh,#$80 + + ; .8086 +cpuend: + mov ax, bx + popf + pop dx + pop cx + pop bx + pop es + pop ds + pop bp + ret + +ge286: ; .286P + ; Does the caller want the exact CPU + cmp cx,#0 + jne try_486 + +; Simple test for a 286 ... + + mov bh,#2 ; Major CPU type >= 80286 + ; What`s the contents of the GDT pointer + sub sp,#6 + mov bp,sp + sgdt [bp] + add sp,#4 + pop ax ; 286 == FFFF, 386+ anything else + inc ax + jz cpu_prot + mov bh,#$13 ; Major CPU type >= 80386 + +; smsw ax +; ror ax,#1 +; jnc try_486 ; If in real mode and running MSDOS + + jmp cpu_prot ; Assume 486 test will NOT work in prot mode + + ; This is an alternate way of finding a 386 ... + ; But it *can* be hidden by V86 mode. +; pushf +; mov ax,#$7000 +; push ax +; popf +; pushf +; pop ax +; popf +; and ax,#$7000 +; jz cpu_prot ; It`s id`ed as a 286 we already know + ; different but it`s probably a bad idea + ; to try for a 486. + +try_486: + ; This trys to trap undefined instructions + ; it may not work if the CPU is in protected mode + ; Note: This does actually re-test 286 v 386 + cli + push bp + mov bp, sp + mov ax,#$3506 + int #$21 ; WARNING - DOS DOS DOS DOS DOS !!!!! + mov [vector+2], es + mov [vector], bx + mov ax,#$2506 + lea dx, [int6] + int #$21 + mov bh,#2 ; 286 + + ; .486 +test386: + mov ebx,#$00040300 ; 386 or 486 +test486: + bswap ebx ; Byte twiddle now 486 + + mov ax,#1 +do_cpuid: + db $0F ; CPUID instruction + db $A2 + and ah,#15 ; Select family number + mov bh,ah ; put it where we want it + + ; .286P +fail386: + mov ax, #$2506 + mov dx, [vector] + mov ds, [vector+2] + int #$21 + pop bp + sti + br cpu_prot + + + ; Tests for processors before the 80286 ... + ; .8086 +pre286: + ; Is it an 8018x ? These mask shifts to less that 32 bits + mov cl,#32 + mov ax, #$0100 + shl ax,cl + mov bx, ax + jnz test8 + + ; Try for an NEC V20/30 + mov ax, #$0208 + db $D5 + db 16 ; Only the 8088 actually checks the arg to AAD + cmp al, #$28 ; as intel ran out of microcode space + jz cmos + mov bx,#4 ; NEC V20 + jmp test8 + + ; The CMOS 8088/6 had the bug with rep lods repaired. +cmos: push si + sti + mov cx, #$FFFF + rep + lodsb + pop si + or cx,cx + jne test8 + mov bx,#2 ; Intel 80C88 + + ; This tests the prefetch of the CPU, 8 bit ones have 4 bytes + ; 16 bit cpus have a queue of 6 bytes. +test8: push di + push bx + mov dx,#0 + mov bx,#4 + std + mov al,#$90 + +retest: lea di,[_nop] + cli + mov cx,#3 + rep + stosb + nop + nop + nop + nop +_inc: inc dx + nop +_nop: nop + sti + mov byte ptr [_inc], #$42 + dec bx + jnz retest + pop bx + cmp dx,#0 + jz done8 + inc bx +done8: pop di + cld + + br cpuend + + + ; Function called by the illegal instruction trap +int6: + mov sp, bp + jmp fail386 +;; + push bp + mov bp, sp + push ax + mov ax,cs + cmp 4[bp],ax + pop ax + jnz pass + cmp bh,#2 + je move23 + cmp bh,#3 + je move34 + add [bp+2], #(fail386 - do_cpuid) + jmp return +move34: add [bp+2], #(fail386 - test486) + jmp return +move23: add [bp+2], #(fail386 - test386) +return: pop bp + iret + +pass: pop bp + jmp [vector] + +vector: dd 0 + +#endasm + +#endif |