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