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