Fix insufficient rect width value in resource file.
[wine] / misc / cpu.c
1 /*
2  * What processor?
3  *
4  * Copyright 1995,1997 Morten Welinder
5  * Copyright 1997-1998 Marcus Meissner
6  */
7
8 #include <ctype.h>
9 #include <string.h>
10 #include <stdio.h>
11 #include "winbase.h"
12 #include "wine/winestring.h"
13 #include "winreg.h"
14 #include "global.h"
15 #include "winnt.h"
16 #include "winerror.h"
17 #include "debugtools.h"
18
19 DEFAULT_DEBUG_CHANNEL(reg);
20
21 static BYTE PF[64] = {0,};
22
23 /***********************************************************************
24  *                      GetSystemInfo                   [KERNELL32.404]
25  *
26  * Gets the current system information.
27  *
28  * On the first call it reads cached values, so it doesn't have to determine
29  * them repeatedly. On Linux, the /proc/cpuinfo special file is used.
30  *
31  * It creates a registry subhierarchy, looking like:
32  * \HARDWARE\DESCRIPTION\System\CentralProcessor\<processornumber>\
33  *                                                      Identifier (CPU x86)
34  * Note that there is a hierarchy for every processor installed, so this
35  * supports multiprocessor systems. This is done like Win95 does it, I think.
36  *                                                      
37  * It also creates a cached flag array for IsProcessorFeaturePresent().
38  *
39  * RETURNS
40  *      nothing, really
41  */
42 VOID WINAPI GetSystemInfo(
43         LPSYSTEM_INFO si        /* [out] system information */
44 ) {
45         static int cache = 0;
46         static SYSTEM_INFO cachedsi;
47         HKEY    xhkey=0,hkey;
48
49         if (cache) {
50                 memcpy(si,&cachedsi,sizeof(*si));
51                 return;
52         }
53         memset(PF,0,sizeof(PF));
54
55         /* choose sensible defaults ...
56          * FIXME: perhaps overrideable with precompiler flags?
57          */
58         cachedsi.u.s.wProcessorArchitecture     = PROCESSOR_ARCHITECTURE_INTEL;
59         cachedsi.dwPageSize                     = VIRTUAL_GetPageSize();
60
61         /* FIXME: the two entries below should be computed somehow... */
62         cachedsi.lpMinimumApplicationAddress    = (void *)0x00010000;
63         cachedsi.lpMaximumApplicationAddress    = (void *)0x7FFFFFFF;
64         cachedsi.dwActiveProcessorMask          = 1;
65         cachedsi.dwNumberOfProcessors           = 1;
66         cachedsi.dwProcessorType                = PROCESSOR_INTEL_386;
67         cachedsi.dwAllocationGranularity        = 0x10000;
68         cachedsi.wProcessorLevel                = 3; /* 386 */
69         cachedsi.wProcessorRevision             = 0;
70
71         cache = 1; /* even if there is no more info, we now have a cacheentry */
72         memcpy(si,&cachedsi,sizeof(*si));
73
74         /* Hmm, reasonable processor feature defaults? */
75
76         /* Create this registry key for all systems */
77         if (RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey)!=ERROR_SUCCESS) {
78             WARN("Unable to register CPU information\n");
79         }
80
81 #ifdef linux
82         {
83         char buf[20];
84         char line[200];
85         FILE *f = fopen ("/proc/cpuinfo", "r");
86
87         if (!f)
88                 return;
89         xhkey = 0;
90         while (fgets(line,200,f)!=NULL) {
91                 char    *s,*value;
92
93                 /* NOTE: the ':' is the only character we can rely on */
94                 if (!(value = strchr(line,':')))
95                         continue;
96                 /* terminate the valuename */
97                 *value++ = '\0';
98                 /* skip any leading spaces */
99                 while (*value==' ') value++;
100                 if ((s=strchr(value,'\n')))
101                         *s='\0';
102
103                 /* 2.1 method */
104                 if (!strncasecmp(line, "cpu family",strlen("cpu family"))) {
105                         if (isdigit (value[0])) {
106                                 switch (value[0] - '0') {
107                                 case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
108                                         cachedsi.wProcessorLevel= 3;
109                                         break;
110                                 case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
111                                         cachedsi.wProcessorLevel= 4;
112                                         break;
113                                 case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
114                                         cachedsi.wProcessorLevel= 5;
115                                         break;
116                                 case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
117                                         cachedsi.wProcessorLevel= 5;
118                                         break;
119                                 default:
120                                         break;
121                                 }
122                         }
123                         /* set the CPU type of the current processor */
124                         sprintf(buf,"CPU %ld",cachedsi.dwProcessorType);
125                         if (xhkey)
126                                 RegSetValueExA(xhkey,"Identifier",0,REG_SZ,buf,strlen(buf));
127                         continue;
128                 }
129                 /* old 2.0 method */
130                 if (!strncasecmp(line, "cpu",strlen("cpu"))) {
131                         if (    isdigit (value[0]) && value[1] == '8' && 
132                                 value[2] == '6' && value[3] == 0
133                         ) {
134                                 switch (value[0] - '0') {
135                                 case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
136                                         cachedsi.wProcessorLevel= 3;
137                                         break;
138                                 case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
139                                         cachedsi.wProcessorLevel= 4;
140                                         break;
141                                 case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
142                                         cachedsi.wProcessorLevel= 5;
143                                         break;
144                                 case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
145                                         cachedsi.wProcessorLevel= 5;
146                                         break;
147                                 default:
148                                         break;
149                                 }
150                         }
151                         /* set the CPU type of the current processor */
152                         sprintf(buf,"CPU %ld",cachedsi.dwProcessorType);
153                         if (xhkey)
154                                 RegSetValueExA(xhkey,"Identifier",0,REG_SZ,buf,strlen(buf));
155                         continue;
156                 }
157                 if (!strncasecmp(line,"fdiv_bug",strlen("fdiv_bug"))) {
158                         if (!strncasecmp(value,"yes",3))
159                                 PF[PF_FLOATING_POINT_PRECISION_ERRATA] = TRUE;
160
161                         continue;
162                 }
163                 if (!strncasecmp(line,"fpu",strlen("fpu"))) {
164                         if (!strncasecmp(value,"no",2))
165                                 PF[PF_FLOATING_POINT_EMULATED] = TRUE;
166
167                         continue;
168                 }
169                 if (!strncasecmp(line,"processor",strlen("processor"))) {
170                         /* processor number counts up...*/
171                         int     x;
172
173                         if (sscanf(value,"%d",&x))
174                                 if (x+1>cachedsi.dwNumberOfProcessors)
175                                         cachedsi.dwNumberOfProcessors=x+1;
176
177                         /* Create a new processor subkey on a multiprocessor
178                          * system
179                          */
180                         sprintf(buf,"%d",x);
181                         if (xhkey)
182                                 RegCloseKey(xhkey);
183                         RegCreateKeyA(hkey,buf,&xhkey);
184                 }
185                 if (!strncasecmp(line,"stepping",strlen("stepping"))) {
186                         int     x;
187
188                         if (sscanf(value,"%d",&x))
189                                 cachedsi.wProcessorRevision = x;
190                 }
191                 if (!strncasecmp(line,"flags",strlen("flags"))) {
192                         if (strstr(value,"cx8"))
193                                 PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
194                         if (strstr(value,"mmx"))
195                                 PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
196
197                 }
198         }
199         fclose (f);
200         }
201         memcpy(si,&cachedsi,sizeof(*si));
202 #else  /* linux */
203         /* FIXME: how do we do this on other systems? */
204
205         RegCreateKeyA(hkey,"0",&xhkey);
206         RegSetValueExA(xhkey,"Identifier",0,REG_SZ,"CPU 386",strlen("CPU 386"));
207 #endif  /* !linux */
208         if (xhkey)
209                 RegCloseKey(xhkey);
210         if (hkey)
211                 RegCloseKey(hkey);
212 }
213
214
215 /***********************************************************************
216  *                      IsProcessorFeaturePresent       [KERNELL32.880]
217  * RETURNS:
218  *      TRUE if processorfeature present
219  *      FALSE otherwise
220  */
221 BOOL WINAPI IsProcessorFeaturePresent (
222         DWORD feature   /* [in] feature number, see PF_ defines */
223 ) {
224   SYSTEM_INFO si;
225   GetSystemInfo (&si); /* To ensure the information is loaded and cached */
226
227   if (feature < 64)
228     return PF[feature];
229   else
230     return FALSE;
231 }