start service tasks separately in-case platforms need to perform additional set-up...
[AROS.git] / workbench / c / CPUInfo / x86.c
blob0fde7f580423895e283d1d4e4dff55362751cbdf
1 /*
2 Copyright © 2000, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Probe installed x86 compatable CPUs and display relevant information
6 Lang: english
7 */
9 /* BIG TO DO - SEPERATE THE INDIVIDUAL PROCESSOR FAMILY "PROBES" INTO RUNTIME SHARED LIBS OR SIMILAR */
11 /****************************************************************************************************
12 Currently Supports:
14 i386 compatable families...
15 AMD 486/5x86/K5/K6/K6-II/K6-III/Athlon/Duron/Opteron/Athlon64
16 Intel P5/P54C/P55C/P24T/P6/P2/P3/PM/Itanium(IA-64)
17 Cyrix 5x86/M1/MediaGX/M2
18 UMC
19 NexGen Nx586
20 Centaur C6/C2/C3
21 Rise Technology mP6
22 SiS 55x
23 Transmeta Crusoe TM3x00 and TM5x00
24 National Semiconductor Geode
26 Soon....
28 PPC?
30 *****************************************************************************************************/
32 #include "x86.h"
34 /********************************************
35 Variables
36 ********************************************/
38 ULONG st_low, st_high, end_low, end_high;
40 /********************************************/
42 void i386_getregs ( char *out, int eax,int ebx,int ecx,int edx )
44 int loop;
46 out[16] = '\0';
47 for( loop = 0 ; loop < 4 ; loop++ )
49 out[loop] = eax >> (8*loop);
50 out[loop+4] = ebx >> (8*loop);
51 out[loop+8] = ecx >> (8*loop);
52 out[loop+12] = edx >> (8*loop);
56 /********************************************/
58 void i386_printregs ( int eax,int ebx,int ecx,int edx )
60 char out[17];
61 i386_getregs( out, eax, ebx, ecx, edx );
62 printf( out );
65 /********************************************/
67 int i386_sprintregs ( int buffpos, char *buffer, int eax,int ebx,int ecx,int edx) /* returns buffer position */
69 char out[17];
70 ULONG size;
72 i386_getregs( out, eax, ebx, ecx, edx );
73 size = strlen( out );
74 AddBufferLine( buffpos, buffer, out );
76 return ( buffpos += size );
79 /********************************************/
81 void Convert32 (unsigned long value)
83 int loop;
85 for( loop=0 ; loop<32 ; loop++, value <<= 1 )
87 putchar( ( 1 << 31 & value ) ? '1' : '0' );
89 if ( loop == 23 || loop == 15 || loop == 7 ) putchar(' ');
91 putchar('\n');
94 /********************************************/
96 void Convert64(unsigned long long value)
98 Convert32 ( value >> 32 );
99 printf (" ");
100 Convert32 ( value );
103 /********************************************/
105 void i386_Parse_MSR ( unsigned int msr, int size)
107 unsigned long msrvala=0,msrvalb=0;
108 unsigned long long msrres;
110 i386_rdmsr( msr, msrvala, msrvalb );
111 msrres = ( ( (unsigned long long)msrvalb << 32 ) | msrvala );
113 if ( msrres == 1 )
115 printf ( "MSR: 0x%08x=0x%08llx : ", msr, msrres );
116 if ( size == 32 ) Convert32( msrres );
117 if ( size == 64 ) Convert64( msrres );
118 return;
120 printf (" Couldn't read MSR 0x%x\n", msr );
123 /********************************************/
125 #define TICKS (65536 - 8271)
127 /* Returns CPU clock in khz */
129 int i386_cpuspeed ( void )
131 int loops;
133 Forbid();
135 /* Setup timer */
136 outb((inb(0x61) & ~0x02) | 0x01, 0x61);
137 outb(0xb0, 0x43);
138 outb(TICKS & 0xff, 0x42);
139 outb(TICKS >> 8, 0x42);
141 asm("rdtsc":"=a" (st_low),"=d" (st_high));
143 loops = 0;
145 do loops++;
146 while ((inb(0x61) & 0x20) == 0);
148 asm( "rdtsc\n\t" "subl st_low,%%eax\n\t" "subl st_high,%%edx\n\t" :"=a" (end_low), "=d" (end_high) );
150 Permit();
152 if (loops < 4 || end_low < 50000) return(-1); /* Make sure we have a credible result */
154 return( end_low/48 );
157 /********************************************/
159 ULONG i386_approx_mhz ( void )
161 ULONG speed;
163 printf(" Approximate Clock Frequency = ");
165 if ((speed = i386_cpuspeed()) > 0)
167 speed += i386_cpuspeed();
168 speed += i386_cpuspeed();
170 speed /= 3; /* get an average for better results */
172 if (speed < 1000000)
174 speed += 50; /* for rounding */
176 printf("%d.%02d Mhz\n",speed/1000,(speed/100)%10);
178 else
180 speed += 500; /* for rounding */
181 printf("%d Mhz\n",speed/1000);
184 return speed;
187 /********************************************
188 PARSE INTEL 386 COMPATABLEs
189 ********************************************/
191 void parse_i386 ( struct i386_compat_intern * CPUi386, ULONG CPU_ID )
193 unsigned long li,maxi,maxei,ebx,ecx,edx,unused;
194 char *strVendor;
195 int i;
197 /* . Display what we know from the CPUs i386 private structure .. */
198 printf("\nProcessor internal (private) for i386 compatable\n");
199 printf("(stored @ %p)\n\n",CPUi386);
201 /* printf(" intern.x86 : %p\n",CPUi386->x86);
202 printf(" intern.x86_vendor : %p\n",CPUi386->x86_vendor);
203 printf(" intern.x86_model : %p\n",CPUi386->x86_model);
204 printf(" intern.x86_mask : %08x\n",CPUi386->x86_mask);
205 printf(" intern.x86_hard_math : %p\n",CPUi386->x86_hard_math);
206 printf(" intern.x86_cpuid : %08x\n",CPUi386->x86_cpuid);
207 printf(" intern.x86_capability : %08x\n",CPUi386->x86_capability); */
209 strVendor = (char *)&CPUi386->x86_vendor_id;
211 /* TODO: Insert code to verify CPUID instruction availability */
212 (void)strVendor;
214 i386_cpuid(0,maxi,unused,unused,unused);
215 maxi &= 0xffff; /* The high-order word is non-zero on some Cyrix CPUs */
217 /* Max CPUID level supported & Vendor Name */
218 i386_cpuid(0,unused,ebx,ecx,edx);
220 printf(" Vendor ID: \"");
221 for(i=0;i<4;i++) putchar(ebx >> (8*i));
222 for(i=0;i<4;i++) putchar(edx >> (8*i));
223 for(i=0;i<4;i++) putchar(ecx >> (8*i));
224 printf("\"; CPUID level %ld\n\n",maxi);
226 /* Use the first 4 letters of the vender string to ID our processor.. */
230 EBX-EDX-ECX Vendor
232 "AuthenticAMD" AMD processor
233 "GenuineIntel" Intel processor
234 "CyrixInstead" Cyrix processor
235 "UMC UMC UMC " UMC processor
236 "NexGenDriven" NexGen processor
237 "CentaurHauls" Centaur processor
238 "RiseRiseRise" Rise Technology processor
239 "SiS SiS SiS " SiS processor
240 "GenuineTMx86" Transmeta processor
241 "Geode by NSC" National Semiconductor processor
244 switch(ebx)
246 case 0x68747541: /* AMD processor */
247 parse_i386_AMD(maxi, CPUi386);
248 break;
250 case 0x756e6547:
251 switch(ecx)
253 case 0x6c65746e:
254 parse_i386_Intel(maxi, CPUi386); /* Intel processor */
255 break;
256 case 0x756e6547:
257 parse_i386_Transmeta(maxi, CPUi386); /* Transmeta processor */
258 break;
261 case 0x69727943: /* Cyrix processor */
262 parse_i386_Cyrix(maxi, CPUi386);
263 break;
265 //case 0x68747541: /* UMC processor */
266 // parse_i386_UMC(maxi, CPUi386);
267 // break;
269 //case 0x756e6547: /* NexGen processor */
270 // parse_i386_NexGen(maxi, CPUi386);
271 // break;
273 //case 0x69727943: /* Centaur processor */
274 // parse_i386_Centaur(maxi, CPUi386);
275 // break;
277 //case 0x68747541: /* Rise Technology processor */
278 // parse_i386_Rise(maxi, CPUi386);
279 // break;
281 //case 0x756e6547: /* SiS processor */
282 // parse_i386_SiS(maxi, CPUi386);
283 // break;
285 //case 0x69727943: /* National Semiconductor processor */
286 // parse_i386_NSC(maxi, CPUi386);
287 // break;
289 default:
290 printf("Unknown vendor\n");
291 break;
294 /* Dump all the CPUID results in raw hex */
295 printf("\n Raw CPUID Dump:\n ---------------\n\n");
296 printf(" eax in eax ebx ecx edx\n");
298 for(i=0;i<=maxi;i++)
300 unsigned long eax,ebx,ecx,edx;
302 i386_cpuid(i,eax,ebx,ecx,edx);
303 printf(" %08x %08lx %08lx %08lx %08lx\n",i,eax,ebx,ecx,edx);
306 i386_cpuid(0x80000000,maxei,unused,unused,unused);
308 for(li=0x80000000;li<=maxei;li++)
310 unsigned long eax,ebx,ecx,edx;
312 i386_cpuid(li,eax,ebx,ecx,edx);
313 printf(" %08lx %08lx %08lx %08lx %08lx\n",li,eax,ebx,ecx,edx);
315 printf("\n");
318 /********************************************
319 Transmeta specific information
320 ********************************************/
322 void parse_i386_Transmeta( int maxi, struct i386_compat_intern * CPUi386 )
325 struct CPU_INTERN_DATA *global;
326 ULONG speed;
327 //ULONG maxei,unused;
328 //int family = 0;
329 //char *BUFF_STR;
331 if ((global = AllocMem(sizeof(struct CPU_INTERN_DATA),MEMF_PUBLIC|MEMF_CLEAR)))
333 //if ( maxi >= 3 ) /* Crusoe CPU serial number */
335 // unsigned long signature,unused,ebx;
337 // i386_cpuid(3,unused,ebx,unused,unused);
339 // Intel_CPU_NAME_cnt = AddBufferLine(Intel_CPU_NAME_cnt, Intel_CPU_NAME, " Processor serial: ");
341 // sprintf( BUFF_STR,"-%04lX",ebx >> 16);
342 // Intel_CPU_NAME_cnt = AddBufferLine(Intel_CPU_NAME_cnt, Intel_CPU_NAME, BUFF_STR);
343 // sprintf( BUFF_STR,"-%04lX",ebx & 0xffff);
344 // Intel_CPU_NAME_cnt = AddBufferLine(Intel_CPU_NAME_cnt, Intel_CPU_NAME, BUFF_STR);
347 speed = i386_approx_mhz();
348 (void)speed;
350 else
352 printf( "ERROR: Couldn't allocate memory to parse CPU information .." );
353 return;
355 FreeMem(global,sizeof(struct CPU_INTERN_DATA));
359 /********************************************
360 UMC specific information
361 ********************************************/
363 void parse_i386_UMC( int maxi, struct i386_compat_intern * CPUi386 )
366 struct CPU_INTERN_DATA *global;
367 ULONG speed;
369 if ((global = AllocMem(sizeof(struct CPU_INTERN_DATA),MEMF_PUBLIC|MEMF_CLEAR)))
371 speed = i386_approx_mhz();
372 (void)speed;
374 else
376 printf( "ERROR: Couldn't allocate memory to parse CPU information .." );
377 return;
379 FreeMem(global,sizeof(struct CPU_INTERN_DATA));
383 /********************************************
384 NexGen specific information
385 ********************************************/
387 void parse_i386_NexGen( int maxi, struct i386_compat_intern * CPUi386 )
390 struct CPU_INTERN_DATA *global;
391 //ULONG speed;
393 if ((global = AllocMem(sizeof(struct CPU_INTERN_DATA),MEMF_PUBLIC|MEMF_CLEAR)))
395 //speed = i386_approx_mhz();
397 else
399 printf( "ERROR: Couldn't allocate memory to parse CPU information .." );
400 return;
402 FreeMem(global,sizeof(struct CPU_INTERN_DATA));
406 /********************************************
407 Centaur specific information
408 ********************************************/
410 void parse_i386_Centaur( int maxi, struct i386_compat_intern * CPUi386 )
413 struct CPU_INTERN_DATA *global;
414 //ULONG speed;
416 if ((global = AllocMem(sizeof(struct CPU_INTERN_DATA),MEMF_PUBLIC|MEMF_CLEAR)))
418 //speed = i386_approx_mhz();
420 else
422 printf( "ERROR: Couldn't allocate memory to parse CPU information .." );
423 return;
425 FreeMem(global,sizeof(struct CPU_INTERN_DATA));
429 /********************************************
430 SiS specific information
431 ********************************************/
433 void parse_i386_SiS( int maxi, struct i386_compat_intern * CPUi386 )
436 struct CPU_INTERN_DATA *global;
437 ULONG speed;
439 if ((global = AllocMem(sizeof(struct CPU_INTERN_DATA),MEMF_PUBLIC|MEMF_CLEAR)))
441 speed = i386_approx_mhz();
442 (void)speed;
444 else
446 printf( "ERROR: Couldn't allocate memory to parse CPU information .." );
447 return;
449 FreeMem(global,sizeof(struct CPU_INTERN_DATA));