Release 980503
[wine] / misc / cpu.c
1 /*
2  * What processor?
3  *
4  * Copyright 1995,1997 Morten Welinder
5  * Copyright 1997 Marcus Meissner
6  */
7
8 #include <stdio.h>
9 #include <ctype.h>
10 #include <string.h>
11 #include "global.h"
12 #include "windows.h"
13 #include "winnt.h"
14 #include "winreg.h"
15
16 static BYTE PF[64] = {0,};
17
18 /***********************************************************************
19  *                      GetSystemInfo                   [KERNELL32.404]
20  */
21 VOID WINAPI GetSystemInfo(LPSYSTEM_INFO si)
22 {
23         static int cache = 0;
24         static SYSTEM_INFO cachedsi;
25         HKEY    xhkey=0,hkey;
26         char    buf[20];
27
28         if (cache) {
29                 memcpy(si,&cachedsi,sizeof(*si));
30                 return;
31         }
32         memset(PF,0,sizeof(PF));
33
34         /* choose sensible defaults ...
35          * FIXME: perhaps overrideable with precompiler flags?
36          */
37         cachedsi.u.x.wProcessorArchitecture     = PROCESSOR_ARCHITECTURE_INTEL;
38         cachedsi.dwPageSize                     = VIRTUAL_GetPageSize();
39
40         /* FIXME: better values for the two entries below... */
41         cachedsi.lpMinimumApplicationAddress    = (void *)0x40000000;
42         cachedsi.lpMaximumApplicationAddress    = (void *)0x7FFFFFFF;
43         cachedsi.dwActiveProcessorMask          = 1;
44         cachedsi.dwNumberOfProcessors           = 1;
45         cachedsi.dwProcessorType                = PROCESSOR_INTEL_386;
46         cachedsi.dwAllocationGranularity        = 0x10000;
47         cachedsi.wProcessorLevel                = 3; /* 386 */
48         cachedsi.wProcessorRevision             = 0;
49
50         cache = 1; /* even if there is no more info, we now have a cacheentry */
51         memcpy(si,&cachedsi,sizeof(*si));
52
53         /* hmm, reasonable processor feature defaults? */
54
55 #ifdef linux
56         {
57         char line[200];
58         FILE *f = fopen ("/proc/cpuinfo", "r");
59
60         if (!f)
61                 return;
62         xhkey = 0;
63         RegCreateKey16(HKEY_LOCAL_MACHINE,"\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor",&hkey);
64         while (fgets(line,200,f)!=NULL) {
65                 char    *s,*value;
66
67                 /* NOTE: the ':' is the only character we can rely on */
68                 if (!(value = strchr(line,':')))
69                         continue;
70                 /* terminate the valuename */
71                 *value++ = '\0';
72                 /* skip any leading spaces */
73                 while (*value==' ') value++;
74                 if ((s=strchr(value,'\n')))
75                         *s='\0';
76
77                 /* 2.1 method */
78                 if (!lstrncmpi32A(line, "cpu family",strlen("cpu family"))) {
79                         if (isdigit (value[0])) {
80                                 switch (value[0] - '0') {
81                                 case 3: cachedsi.dwProcessorType = PROCESSOR_INTEL_386;
82                                         cachedsi.wProcessorLevel= 3;
83                                         break;
84                                 case 4: cachedsi.dwProcessorType = PROCESSOR_INTEL_486;
85                                         cachedsi.wProcessorLevel= 4;
86                                         break;
87                                 case 5: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
88                                         cachedsi.wProcessorLevel= 5;
89                                         break;
90                                 case 6: cachedsi.dwProcessorType = PROCESSOR_INTEL_PENTIUM;
91                                         cachedsi.wProcessorLevel= 5;
92                                         break;
93                                 default:
94                                         break;
95                                 }
96                         }
97                         /* set the CPU type of the current processor */
98                         sprintf(buf,"CPU %ld",cachedsi.dwProcessorType);
99                         if (xhkey)
100                                 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,buf,strlen(buf));
101                         continue;
102                 }
103                 /* old 2.0 method */
104                 if (!lstrncmpi32A(line, "cpu",strlen("cpu"))) {
105                         if (    isdigit (value[0]) && value[1] == '8' && 
106                                 value[2] == '6' && value[3] == 0
107                         ) {
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                                 RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,buf,strlen(buf));
129                         continue;
130                 }
131                 if (!lstrncmpi32A(line,"fdiv_bug",strlen("fdiv_bug"))) {
132                         if (!lstrncmpi32A(value,"yes",3))
133                                 PF[PF_FLOATING_POINT_PRECISION_ERRATA] = TRUE;
134
135                         continue;
136                 }
137                 if (!lstrncmpi32A(line,"fpu",strlen("fpu"))) {
138                         if (!lstrncmpi32A(value,"no",2))
139                                 PF[PF_FLOATING_POINT_EMULATED] = TRUE;
140
141                         continue;
142                 }
143                 if (!lstrncmpi32A(line,"processor",strlen("processor"))) {
144                         /* processor number counts up...*/
145                         int     x;
146
147                         if (sscanf(value,"%d",&x))
148                                 if (x+1>cachedsi.dwNumberOfProcessors)
149                                         cachedsi.dwNumberOfProcessors=x+1;
150
151                         /* create a new processor subkey */
152                         sprintf(buf,"%d",x);
153                         if (xhkey)
154                                 RegCloseKey(xhkey);
155                         RegCreateKey16(hkey,buf,&xhkey);
156                 }
157                 if (!lstrncmpi32A(line,"stepping",strlen("stepping"))) {
158                         int     x;
159
160                         if (sscanf(value,"%d",&x))
161                                 cachedsi.wProcessorRevision = x;
162                 }
163                 if (!lstrncmpi32A(line,"flags",strlen("flags"))) {
164                         if (strstr(value,"cx8"))
165                                 PF[PF_COMPARE_EXCHANGE_DOUBLE] = TRUE;
166                         if (strstr(value,"mmx"))
167                                 PF[PF_MMX_INSTRUCTIONS_AVAILABLE] = TRUE;
168
169                 }
170         }
171         fclose (f);
172         }
173         memcpy(si,&cachedsi,sizeof(*si));
174 #else  /* linux */
175         /* FIXME: how do we do this on other systems? */
176
177         RegCreateKey16(hkey,"0",&xhkey);
178         RegSetValueEx32A(xhkey,"Identifier",0,REG_SZ,"CPU 386",strlen("CPU 386"));
179 #endif  /* !linux */
180         if (xhkey)
181                 RegCloseKey(xhkey);
182         RegCloseKey(hkey);
183 }
184
185 /***********************************************************************
186  *                      IsProcessorFeaturePresent       [KERNELL32.880]
187  */
188 BOOL32 WINAPI IsProcessorFeaturePresent (DWORD feature)
189 {
190   SYSTEM_INFO si;
191   GetSystemInfo (&si); /* to ensure the information is loaded and cached */
192
193   if (feature < 64)
194     return PF[feature];
195   else
196     return FALSE;
197 }