summaryrefslogtreecommitdiff
path: root/libc/misc/cputype.c
blob: 7dd708830de37b5020404623e44d6316568782cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
/*
 * 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)
 *
 * 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-1996
 */

#ifdef STANDALONE
#define cputype cpu

#include <stdio.h>
#ifndef __MSDOS__
#include <signal.h>
#endif

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
#ifdef STANDALONE
export _cpu
_cpu:
#else
export _cputype
_cputype:
#endif
	; 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		; For 286, ah can only be 0xFF
	inc ah
	jz cpu_prot
	mov bh,#$13	; Major CPU type >= 80386

#ifdef __MSDOS__
	smsw ax		; If we`re in MSDOS and running in real mode
	ror ax,#1	; we can do the int 6 detection.
	jnc try_486
#endif

	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 is_a_286

try_486:
	; This trys to trap undefined instructions
	; it may not work if the CPU is in protected mode
	; Note: This code works for anything 286+
	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

	mov ax,#1		; And again cause of Nasty EMM386s
	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

; This was the old way, didn't always work tho.
;	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