- fix perl syntax error in my own patch
[wine] / misc / cpu.c
1 /*
2  * What processor?
3  *
4  * Copyright 1995,1997 Morten Welinder
5  * Copyright 1997-1998 Marcus Meissner
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <ctype.h>
26 #include <string.h>
27 #include <stdio.h>
28
29 #include "winbase.h"
30 #include "winreg.h"
31 #include "winnt.h"
32 #include "winerror.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(reg);
36
37 static BYTE PF[64] = {0,};
38
39 /***********************************************************************
40  *                      GetSystemInfo                   [KERNEL32.@]
41  *
42  * Gets the current system information.
43  *
44  * On the first call it creates cached values, so it doesn't have to determine
45  * them repeatedly. On Linux, the /proc/cpuinfo special file is used.
46  *
47  * It creates a registry subhierarchy, looking like:
48  * \HARDWARE\DESCRIPTION\System\CentralProcessor\<processornumber>\
49  *                                                      Identifier (CPU x86)
50  * Note that there is a hierarchy for every processor installed, so this
51  * supports multiprocessor systems. This is done like Win95 does it, I think.
52  *
53  * It also creates a cached flag array for IsProcessorFeaturePresent().
54  *
55  * No NULL ptr check for LPSYSTEM_INFO in Win9x.
56  *
57  * RETURNS
58  *      nothing, really
59  */
60 VOID WINAPI GetSystemInfo(
61         LPSYSTEM_INFO si        /* [out] system information */
62 ) {
63         static int cache = 0;
64         static SYSTEM_INFO cachedsi;
65         HKEY    xhkey=0,hkey;
66
67         if (cache) {
68                 memcpy(si,&cachedsi,sizeof(*si));
69                 return;
70         }
71         memset(PF,0,sizeof(PF));
72
73         /* choose sensible defaults ...
74          * FIXME: perhaps overrideable with precompiler flags?
75          */
76         cachedsi.u.s.wProcessorArchitecture     = PROCESSOR_ARCHITECTURE_INTEL;
77         cachedsi.dwPageSize                     = getpagesize();
78
79         /* FIXME: the two entries below should be computed somehow... */
80         cachedsi.lpMinimumApplicationAddress    = (void *)0x00010000;
81         cachedsi.lpMaximumApplicationAddress    = (void *)0x7FFFFFFF;
82         cachedsi.dwActiveProcessorMask          = 1;
83         cachedsi.dwNumberOfProcessors           = 1;
84         cachedsi.dwProcessorType                = PROCESSOR_INTEL_PENTIUM;
85         cachedsi.dwAllocationGranularity        = 0x10000;
86         cachedsi.wProcessorLevel                = 5; /* 586 */
87         cachedsi.wProcessorRevision             = 0;
88
89         cache = 1; /* even if there is no more info, we now have a cacheentry */
90         memcpy(si,&cachedsi,sizeof(*si));
91
92         /* Hmm, reasonable processor feature defaults? */
93
94         /* Create these registry keys for all systems
95          * FPU entry is often empty on Windows, so we don't care either */
96         if ( (RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System\\FloatingPointProcessor",&hkey)!=ERROR_SUCCESS)
97           || (RegCreateKeyA(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey)!=ERROR_SUCCESS) )
98         {
99             WARN("Unable to write FPU/CPU info to registry\n");
100         }
101
102 #ifdef linux
103         {
104         char buf[20];
105         char line[200];
106         FILE *f = fopen ("/proc/cpuinfo", "r");
107
108         if (!f)
109                 return;
110         xhkey = 0;
111         while (fgets(line,200,f)!=NULL) {
112                 char    *s,*value;
113
114                 /* NOTE: the ':' is the only character we can rely on */
115                 if (!(value = strchr(line,':')))
116                         continue;
117                 /* terminate the valuename */
118                 *value++ = '\0';
119                 /* skip any leading spaces */
120                 while (*value==' ') value++;
121                 if ((s=strchr(value,'\n')))
122                         *s='\0';
123
124                 /* 2.1 method */
125                 if (!strncasecmp(line, "cpu family",strlen("cpu family"))) {
126                         if (isdigit (value[0])) {
127                                 switch (value[0] - '0') {
128                                 case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
129                                         cachedsi.wProcessorLevel= 3;
130                                         break;
131                                 case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
132                                         cachedsi.wProcessorLevel= 4;
133                                         break;
134                                 case 5:
135                                 case 6: /* PPro/2/3 has same info as P1 */
136                                         cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
137                                         cachedsi.wProcessorLevel= 5;
138                                         break;
139                                 case 1: /* two-figure levels */
140                                     if (value[1] == '5')
141                                     {
142                                         cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
143                                         cachedsi.wProcessorLevel= 5;
144                                         break;
145                                     }
146                                     /* fall through */
147                                 default:
148                                         FIXME("unknown cpu family '%s', please report ! (-> setting to 386)\n", value);
149                                         break;
150                                 }
151                         }
152                         /* set the CPU type of the current processor */
153                         sprintf(buf,"CPU %ld",cachedsi.dwProcessorType);
154                         if (xhkey)
155                                 RegSetValueExA(xhkey,"Identifier",0,REG_SZ,buf,strlen(buf));
156                         continue;
157                 }
158                 /* old 2.0 method */
159                 if (!strncasecmp(line, "cpu",strlen("cpu"))) {
160                         if (    isdigit (value[0]) && value[1] == '8' &&
161                                 value[2] == '6' && value[3] == 0
162                         ) {
163                                 switch (value[0] - '0') {
164                                 case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
165                                         cachedsi.wProcessorLevel= 3;
166                                         break;
167                                 case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
168                                         cachedsi.wProcessorLevel= 4;
169                                         break;
170                                 case 5:
171                                 case 6: /* PPro/2/3 has same info as P1 */
172                                         cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
173                                         cachedsi.wProcessorLevel= 5;
174                                         break;
175                                 default:
176                                         FIXME("unknown Linux 2.0 cpu family '%s', please report ! (-> setting to 386)\n", value);
177                                         break;
178                                 }
179                         }
180                         /* set the CPU type of the current processor
181                          * FIXME: someone reported P4 as being set to
182                          * "              Intel(R) Pentium(R) 4 CPU 1500MHz"
183                          * Do we need to do the same ?
184                          * */
185                         sprintf(buf,"CPU %ld",cachedsi.dwProcessorType);
186                         if (xhkey)
187                                 RegSetValueExA(xhkey,"Identifier",0,REG_SZ,buf,strlen(buf));
188                         continue;
189                 }
190                 if (!strncasecmp(line,"fdiv_bug",strlen("fdiv_bug"))) {
191                         if (!strncasecmp(value,"yes",3))
192                                 PF[PF_FLOATING_POINT_PRECISION_ERRATA] = TRUE;
193
194                         continue;
195                 }
196                 if (!strncasecmp(line,"fpu",strlen("fpu"))) {
197                         if (!strncasecmp(value,"no",2))
198                                 PF[PF_FLOATING_POINT_EMULATED] = TRUE;
199
200                         continue;
201                 }
202                 if (!strncasecmp(line,"processor",strlen("processor"))) {
203                         /* processor number counts up... */
204                         unsigned int x;
205
206                         if (sscanf(value,"%d",&x))
207                                 if (x+1>cachedsi.dwNumberOfProcessors)
208                                         cachedsi.dwNumberOfProcessors=x+1;
209
210                         /* Create a new processor subkey on a multiprocessor
211                          * system
212                          */
213                         sprintf(buf,"%d",x);
214                         if (xhkey)
215                                 RegCloseKey(xhkey);
216                         RegCreateKeyA(hkey,buf,&xhkey);
217                 }
218                 if (!strncasecmp(line,"stepping",strlen("stepping"))) {
219                         int     x;
220
221                         if (sscanf(value,"%d",&x))
222                                 cachedsi.wProcessorRevision = x;
223                 }
224                 if (    !strncasecmp(line,"flags",strlen("flags"))      ||
225                         !strncasecmp(line,"features",strlen("features"))
226                 ) {
227                         if (strstr(value,"cx8"))
228                                 PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
229                         if (strstr(value,"mmx"))
230                                 PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
231                         if (strstr(value,"tsc"))
232                                 PF[PF_RDTSC_INSTRUCTION_AVAILABLE] = TRUE;
233
234                 }
235         }
236         fclose (f);
237         }
238         memcpy(si,&cachedsi,sizeof(*si));
239 #else  /* linux */
240         FIXME("not yet supported on this system\n");
241         RegCreateKeyA(hkey,"0",&xhkey);
242         RegSetValueExA(xhkey,"Identifier",0,REG_SZ,"CPU 386",strlen("CPU 386"));
243 #endif  /* !linux */
244         if (xhkey)
245                 RegCloseKey(xhkey);
246         if (hkey)
247                 RegCloseKey(hkey);
248         TRACE("<- CPU arch %d, res'd %d, pagesize %ld, minappaddr %p, maxappaddr %p,"
249               " act.cpumask %08lx, numcpus %ld, CPU type %ld, allocgran. %ld, CPU level %d, CPU rev %d\n",
250               si->u.s.wProcessorArchitecture, si->u.s.wReserved, si->dwPageSize,
251               si->lpMinimumApplicationAddress, si->lpMaximumApplicationAddress,
252               si->dwActiveProcessorMask, si->dwNumberOfProcessors, si->dwProcessorType,
253               si->dwAllocationGranularity, si->wProcessorLevel, si->wProcessorRevision);
254 }
255
256
257 /***********************************************************************
258  *                      IsProcessorFeaturePresent       [KERNEL32.@]
259  * RETURNS:
260  *      TRUE if processor feature present
261  *      FALSE otherwise
262  */
263 BOOL WINAPI IsProcessorFeaturePresent (
264         DWORD feature   /* [in] feature number, see PF_ defines */
265 ) {
266   SYSTEM_INFO si;
267   GetSystemInfo (&si); /* To ensure the information is loaded and cached */
268
269   if (feature < 64)
270     return PF[feature];
271   else
272     return FALSE;
273 }