Release 980301
[wine] / misc / cpu.c
1 /*
2  * What processor?
3  *
4  * Copyright 1995,1997 Morten Welinder
5  * Copyright 1997 Marcus Meissner
6  */
7
8 #include <stdio.h>
9 #include <ctype.h>
10 #include <string.h>
11 #include "windows.h"
12 #include "winnt.h"
13 #include "winreg.h"
14
15 static BYTE PF[64] = {0,};
16
17 /***********************************************************************
18  *                      GetSystemInfo                   [KERNELL32.404]
19  */
20 VOID WINAPI GetSystemInfo(LPSYSTEM_INFO si)
21 {
22         static int cache = 0;
23         static SYSTEM_INFO cachedsi;
24         HKEY    xhkey=0,hkey;
25         char    buf[20];
26
27         if (cache) {
28                 memcpy(si,&cachedsi,sizeof(*si));
29                 return;
30         }
31         memset(PF,0,sizeof(PF));
32
33         /* choose sensible defaults ...
34          * FIXME: perhaps overrideable with precompiler flags?
35          */
36         cachedsi.u.x.wProcessorArchitecture     = PROCESSOR_ARCHITECTURE_INTEL;
37         cachedsi.dwPageSize                     = 4096;
38
39         /* FIXME: better values for the two entries below... */
40         cachedsi.lpMinimumApplicationAddress    = (void *)0x40000000;
41         cachedsi.lpMaximumApplicationAddress    = (void *)0x7FFFFFFF;
42         cachedsi.dwActiveProcessorMask          = 1;
43         cachedsi.dwNumberOfProcessors           = 1;
44         cachedsi.dwProcessorType                = PROCESSOR_INTEL_386;
45         cachedsi.dwAllocationGranularity        = 0x10000;
46         cachedsi.wProcessorLevel                = 3; /* 386 */
47         cachedsi.wProcessorRevision             = 0;
48
49         cache = 1; /* even if there is no more info, we now have a cacheentry */
50         memcpy(si,&cachedsi,sizeof(*si));
51
52         /* hmm, reasonable processor feature defaults? */
53
54 #ifdef linux
55         {
56         char line[200];
57         FILE *f = fopen ("/proc/cpuinfo", "r");
58
59         if (!f)
60                 return;
61         xhkey = 0;
62         RegCreateKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey);
63         while (fgets(line,200,f)!=NULL) {
64                 char    *s,*value;
65
66                 /* NOTE: the ':' is the only character we can rely on */
67                 if (!(value = strchr(line,':')))
68                         continue;
69                 /* terminate the valuename */
70                 *value++ = '\0';
71                 /* skip any leading spaces */
72                 while (*value==' ') value++;
73                 if ((s=strchr(value,'\n')))
74                         *s='\0';
75
76                 /* 2.1 method */
77                 if (!lstrncmpi32A(line, "cpu family",strlen("cpu family"))) {
78                         if (isdigit (value[0])) {
79                                 switch (value[0] - '0') {
80                                 case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
81                                         cachedsi.wProcessorLevel= 3;
82                                         break;
83                                 case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
84                                         cachedsi.wProcessorLevel= 4;
85                                         break;
86                                 case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
87                                         cachedsi.wProcessorLevel= 5;
88                                         break;
89                                 case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
90                                         cachedsi.wProcessorLevel= 5;
91                                         break;
92                                 default:
93                                         break;
94                                 }
95                         }
96                         /* set the CPU type of the current processor */
97                         sprintf(buf,"CPU %ld",cachedsi.dwProcessorType);
98                         if (xhkey)
99                                 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,buf,strlen(buf));
100                         continue;
101                 }
102                 /* old 2.0 method */
103                 if (!lstrncmpi32A(line, "cpu",strlen("cpu"))) {
104                         if (    isdigit (value[0]) && value[1] == '8' && 
105                                 value[2] == '6' && value[3] == 0
106                         ) {
107                                 switch (value[0] - '0') {
108                                 case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
109                                         cachedsi.wProcessorLevel= 3;
110                                         break;
111                                 case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
112                                         cachedsi.wProcessorLevel= 4;
113                                         break;
114                                 case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
115                                         cachedsi.wProcessorLevel= 5;
116                                         break;
117                                 case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
118                                         cachedsi.wProcessorLevel= 5;
119                                         break;
120                                 default:
121                                         break;
122                                 }
123                         }
124                         /* set the CPU type of the current processor */
125                         sprintf(buf,"CPU %ld",cachedsi.dwProcessorType);
126                         if (xhkey)
127                                 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,buf,strlen(buf));
128                         continue;
129                 }
130                 if (!lstrncmpi32A(line,"fdiv_bug",strlen("fdiv_bug"))) {
131                         if (!lstrncmpi32A(value,"yes",3))
132                                 PF[PF_FLOATING_POINT_PRECISION_ERRATA] = TRUE;
133
134                         continue;
135                 }
136                 if (!lstrncmpi32A(line,"fpu",strlen("fpu"))) {
137                         if (!lstrncmpi32A(value,"no",2))
138                                 PF[PF_FLOATING_POINT_EMULATED] = TRUE;
139
140                         continue;
141                 }
142                 if (!lstrncmpi32A(line,"processor",strlen("processor"))) {
143                         /* processor number counts up...*/
144                         int     x;
145
146                         if (sscanf(value,"%d",&x))
147                                 if (x+1>cachedsi.dwNumberOfProcessors)
148                                         cachedsi.dwNumberOfProcessors=x+1;
149
150                         /* create a new processor subkey */
151                         sprintf(buf,"%d",x);
152                         if (xhkey)
153                                 RegCloseKey(xhkey);
154                         RegCreateKey16(hkey,buf,&xhkey);
155                 }
156                 if (!lstrncmpi32A(line,"stepping",strlen("stepping"))) {
157                         int     x;
158
159                         if (sscanf(value,"%d",&x))
160                                 cachedsi.wProcessorRevision = x;
161                 }
162                 if (!lstrncmpi32A(line,"flags",strlen("flags"))) {
163                         if (strstr(value,"cx8"))
164                                 PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
165                         if (strstr(value,"mmx"))
166                                 PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
167
168                 }
169         }
170         fclose (f);
171         }
172         memcpy(si,&cachedsi,sizeof(*si));
173 #else  /* linux */
174         /* FIXME: how do we do this on other systems? */
175
176         RegCreateKey16(hkey,"0",&xhkey);
177         RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,"CPU 386",strlen("CPU 386"));
178 #endif  /* !linux */
179         if (xhkey)
180                 RegCloseKey(xhkey);
181         RegCloseKey(hkey);
182 }
183
184 /***********************************************************************
185  *                      IsProcessorFeaturePresent       [KERNELL32.880]
186  */
187 BOOL32 WINAPI IsProcessorFeaturePresent (DWORD feature)
188 {
189   SYSTEM_INFO si;
190   GetSystemInfo (&si); /* to ensure the information is loaded and cached */
191
192   if (feature < 64)
193     return PF[feature];
194   else
195     return FALSE;
196 }