Fix COM_ExternalLockFreeList to do not fail with an empty list.
[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 "debug.h"
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         char    buf[20];
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.x.wProcessorArchitecture     = PROCESSOR_ARCHITECTURE_INTEL;
59         cachedsi.dwPageSize                     = VIRTUAL_GetPageSize();
60
61         /* FIXME: better values for the two entries below... */
62         cachedsi.lpMinimumApplicationAddress    = (void *)0x40000000;
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 (RegCreateKey16(HKEY_LOCAL_MACHINE,"HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey)!=ERROR_SUCCESS) {
78             WARN(reg,"Unable to register CPU information\n");
79         }
80
81 #ifdef linux
82         {
83         char line[200];
84         FILE *f = fopen ("/proc/cpuinfo", "r");
85
86         if (!f)
87                 return;
88         xhkey = 0;
89         while (fgets(line,200,f)!=NULL) {
90                 char    *s,*value;
91
92                 /* NOTE: the ':' is the only character we can rely on */
93                 if (!(value = strchr(line,':')))
94                         continue;
95                 /* terminate the valuename */
96                 *value++ = '\0';
97                 /* skip any leading spaces */
98                 while (*value==' ') value++;
99                 if ((s=strchr(value,'\n')))
100                         *s='\0';
101
102                 /* 2.1 method */
103                 if (!lstrncmpi32A(line, "cpu family",strlen("cpu family"))) {
104                         if (isdigit (value[0])) {
105                                 switch (value[0] - '0') {
106                                 case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
107                                         cachedsi.wProcessorLevel= 3;
108                                         break;
109                                 case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
110                                         cachedsi.wProcessorLevel= 4;
111                                         break;
112                                 case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
113                                         cachedsi.wProcessorLevel= 5;
114                                         break;
115                                 case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
116                                         cachedsi.wProcessorLevel= 5;
117                                         break;
118                                 default:
119                                         break;
120                                 }
121                         }
122                         /* set the CPU type of the current processor */
123                         sprintf(buf,"CPU %ld",cachedsi.dwProcessorType);
124                         if (xhkey)
125                                 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,buf,strlen(buf));
126                         continue;
127                 }
128                 /* old 2.0 method */
129                 if (!lstrncmpi32A(line, "cpu",strlen("cpu"))) {
130                         if (    isdigit (value[0]) && value[1] == '8' && 
131                                 value[2] == '6' && value[3] == 0
132                         ) {
133                                 switch (value[0] - '0') {
134                                 case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
135                                         cachedsi.wProcessorLevel= 3;
136                                         break;
137                                 case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
138                                         cachedsi.wProcessorLevel= 4;
139                                         break;
140                                 case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
141                                         cachedsi.wProcessorLevel= 5;
142                                         break;
143                                 case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
144                                         cachedsi.wProcessorLevel= 5;
145                                         break;
146                                 default:
147                                         break;
148                                 }
149                         }
150                         /* set the CPU type of the current processor */
151                         sprintf(buf,"CPU %ld",cachedsi.dwProcessorType);
152                         if (xhkey)
153                                 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,buf,strlen(buf));
154                         continue;
155                 }
156                 if (!lstrncmpi32A(line,"fdiv_bug",strlen("fdiv_bug"))) {
157                         if (!lstrncmpi32A(value,"yes",3))
158                                 PF[PF_FLOATING_POINT_PRECISION_ERRATA] = TRUE;
159
160                         continue;
161                 }
162                 if (!lstrncmpi32A(line,"fpu",strlen("fpu"))) {
163                         if (!lstrncmpi32A(value,"no",2))
164                                 PF[PF_FLOATING_POINT_EMULATED] = TRUE;
165
166                         continue;
167                 }
168                 if (!lstrncmpi32A(line,"processor",strlen("processor"))) {
169                         /* processor number counts up...*/
170                         int     x;
171
172                         if (sscanf(value,"%d",&x))
173                                 if (x+1>cachedsi.dwNumberOfProcessors)
174                                         cachedsi.dwNumberOfProcessors=x+1;
175
176                         /* Create a new processor subkey on a multiprocessor
177                          * system
178                          */
179                         sprintf(buf,"%d",x);
180                         if (xhkey)
181                                 RegCloseKey(xhkey);
182                         RegCreateKey16(hkey,buf,&xhkey);
183                 }
184                 if (!lstrncmpi32A(line,"stepping",strlen("stepping"))) {
185                         int     x;
186
187                         if (sscanf(value,"%d",&x))
188                                 cachedsi.wProcessorRevision = x;
189                 }
190                 if (!lstrncmpi32A(line,"flags",strlen("flags"))) {
191                         if (strstr(value,"cx8"))
192                                 PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
193                         if (strstr(value,"mmx"))
194                                 PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
195
196                 }
197         }
198         fclose (f);
199         }
200         memcpy(si,&cachedsi,sizeof(*si));
201 #else  /* linux */
202         /* FIXME: how do we do this on other systems? */
203
204         RegCreateKey16(hkey,"0",&xhkey);
205         RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,"CPU 386",strlen("CPU 386"));
206 #endif  /* !linux */
207         if (xhkey)
208                 RegCloseKey(xhkey);
209         if (hkey)
210                 RegCloseKey(hkey);
211 }
212
213
214 /***********************************************************************
215  *                      IsProcessorFeaturePresent       [KERNELL32.880]
216  * RETURNS:
217  *      TRUE if processorfeature present
218  *      FALSE otherwise
219  */
220 BOOL32 WINAPI IsProcessorFeaturePresent (
221         DWORD feature   /* [in] feature number, see PF_ defines */
222 ) {
223   SYSTEM_INFO si;
224   GetSystemInfo (&si); /* To ensure the information is loaded and cached */
225
226   if (feature < 64)
227     return PF[feature];
228   else
229     return FALSE;
230 }