summaryrefslogtreecommitdiff
path: root/libc/misc/cputype.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/misc/cputype.c')
-rw-r--r--libc/misc/cputype.c344
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