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