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