ntdll: Use the right cpuid for XSAVEC detection.
[wine/zf.git] / dlls / ntdll / unix / system.c
blob56bdd63c89b133f0c5049a1691b9d1ef733107f7
1 /*
2 * System information APIs
4 * Copyright 1996-1998 Marcus Meissner
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
26 #include "wine/port.h"
28 #include <string.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #ifdef HAVE_SYS_TIME_H
34 # include <sys/time.h>
35 #endif
36 #include <time.h>
37 #ifdef HAVE_SYS_PARAM_H
38 # include <sys/param.h>
39 #endif
40 #ifdef HAVE_SYS_SYSCTL_H
41 # include <sys/sysctl.h>
42 #endif
43 #ifdef HAVE_MACHINE_CPU_H
44 # include <machine/cpu.h>
45 #endif
46 #ifdef HAVE_SYS_RANDOM_H
47 # include <sys/random.h>
48 #endif
49 #ifdef HAVE_IOKIT_IOKITLIB_H
50 # include <CoreFoundation/CoreFoundation.h>
51 # include <IOKit/IOKitLib.h>
52 # include <IOKit/pwr_mgt/IOPM.h>
53 # include <IOKit/pwr_mgt/IOPMLib.h>
54 # include <IOKit/ps/IOPowerSources.h>
55 #endif
56 #ifdef __APPLE__
57 # include <mach/mach.h>
58 # include <mach/machine.h>
59 # include <mach/mach_init.h>
60 # include <mach/mach_host.h>
61 # include <mach/vm_map.h>
62 #endif
64 #define NONAMELESSUNION
65 #include "ntstatus.h"
66 #define WIN32_NO_STATUS
67 #include "windef.h"
68 #include "winternl.h"
69 #include "ddk/wdm.h"
70 #include "wine/asm.h"
71 #include "unix_private.h"
72 #include "wine/debug.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
76 #include "pshpack1.h"
78 struct smbios_prologue
80 BYTE calling_method;
81 BYTE major_version;
82 BYTE minor_version;
83 BYTE revision;
84 DWORD length;
87 struct smbios_header
89 BYTE type;
90 BYTE length;
91 WORD handle;
94 struct smbios_bios
96 struct smbios_header hdr;
97 BYTE vendor;
98 BYTE version;
99 WORD start;
100 BYTE date;
101 BYTE size;
102 UINT64 characteristics;
103 BYTE characteristics_ext[2];
104 BYTE system_bios_major_release;
105 BYTE system_bios_minor_release;
106 BYTE ec_firmware_major_release;
107 BYTE ec_firmware_minor_release;
110 struct smbios_system
112 struct smbios_header hdr;
113 BYTE vendor;
114 BYTE product;
115 BYTE version;
116 BYTE serial;
117 BYTE uuid[16];
118 BYTE wake_up_type;
119 BYTE sku_number;
120 BYTE family;
123 struct smbios_board
125 struct smbios_header hdr;
126 BYTE vendor;
127 BYTE product;
128 BYTE version;
129 BYTE serial;
130 BYTE asset_tag;
131 BYTE feature_flags;
132 BYTE location;
133 WORD chassis_handle;
134 BYTE board_type;
135 BYTE num_contained_handles;
138 struct smbios_chassis
140 struct smbios_header hdr;
141 BYTE vendor;
142 BYTE type;
143 BYTE version;
144 BYTE serial;
145 BYTE asset_tag;
146 BYTE boot_state;
147 BYTE power_supply_state;
148 BYTE thermal_state;
149 BYTE security_status;
150 DWORD oem_defined;
151 BYTE height;
152 BYTE num_power_cords;
153 BYTE num_contained_elements;
154 BYTE contained_element_rec_length;
157 struct smbios_boot_info
159 struct smbios_header hdr;
160 BYTE reserved[6];
161 BYTE boot_status[10];
164 #include "poppack.h"
166 /* Firmware table providers */
167 #define ACPI 0x41435049
168 #define FIRM 0x4649524D
169 #define RSMB 0x52534D42
171 static SYSTEM_CPU_INFORMATION cpu_info;
173 /*******************************************************************************
174 * Architecture specific feature detection for CPUs
176 * This a set of mutually exclusive #if define()s each providing its own get_cpuinfo() to be called
177 * from init_cpu_info();
179 #if defined(__i386__) || defined(__x86_64__)
181 BOOL xstate_compaction_enabled = FALSE;
183 #define AUTH 0x68747541 /* "Auth" */
184 #define ENTI 0x69746e65 /* "enti" */
185 #define CAMD 0x444d4163 /* "cAMD" */
187 #define GENU 0x756e6547 /* "Genu" */
188 #define INEI 0x49656e69 /* "ineI" */
189 #define NTEL 0x6c65746e /* "ntel" */
191 static inline void do_cpuid(unsigned int ax, unsigned int cx, unsigned int *p)
193 __asm__ ("cpuid" : "=a"(p[0]), "=b" (p[1]), "=c"(p[2]), "=d"(p[3]) : "a"(ax), "c"(cx));
196 #ifdef __i386__
197 extern int have_cpuid(void);
198 __ASM_GLOBAL_FUNC( have_cpuid,
199 "pushfl\n\t"
200 "pushfl\n\t"
201 "movl (%esp),%ecx\n\t"
202 "xorl $0x00200000,(%esp)\n\t"
203 "popfl\n\t"
204 "pushfl\n\t"
205 "popl %eax\n\t"
206 "popfl\n\t"
207 "xorl %ecx,%eax\n\t"
208 "andl $0x00200000,%eax\n\t"
209 "ret" )
210 #else
211 static int have_cpuid(void)
213 return 1;
215 #endif
217 /* Detect if a SSE2 processor is capable of Denormals Are Zero (DAZ) mode.
219 * This function assumes you have already checked for SSE2/FXSAVE support. */
220 static inline BOOL have_sse_daz_mode(void)
222 #ifdef __i386__
223 /* Intel says we need a zeroed 16-byte aligned buffer */
224 char buffer[512 + 16];
225 XSAVE_FORMAT *state = (XSAVE_FORMAT *)(((ULONG_PTR)buffer + 15) & ~15);
226 memset(buffer, 0, sizeof(buffer));
228 __asm__ __volatile__( "fxsave %0" : "=m" (*state) : "m" (*state) );
230 return (state->MxCsr_Mask & (1 << 6)) >> 6;
231 #else /* all x86_64 processors include SSE2 with DAZ mode */
232 return TRUE;
233 #endif
236 static void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
238 unsigned int regs[4], regs2[4], regs3[4];
240 #if defined(__i386__)
241 info->Architecture = PROCESSOR_ARCHITECTURE_INTEL;
242 #elif defined(__x86_64__)
243 info->Architecture = PROCESSOR_ARCHITECTURE_AMD64;
244 #endif
246 /* We're at least a 386 */
247 info->FeatureSet = CPU_FEATURE_VME | CPU_FEATURE_X86 | CPU_FEATURE_PGE;
248 info->Level = 3;
250 if (!have_cpuid()) return;
252 do_cpuid( 0x00000000, 0, regs ); /* get standard cpuid level and vendor name */
253 if (regs[0]>=0x00000001) /* Check for supported cpuid version */
255 do_cpuid( 0x00000001, 0, regs2 ); /* get cpu features */
256 if (regs2[3] & (1 << 3 )) info->FeatureSet |= CPU_FEATURE_PSE;
257 if (regs2[3] & (1 << 4 )) info->FeatureSet |= CPU_FEATURE_TSC;
258 if (regs2[3] & (1 << 6 )) info->FeatureSet |= CPU_FEATURE_PAE;
259 if (regs2[3] & (1 << 8 )) info->FeatureSet |= CPU_FEATURE_CX8;
260 if (regs2[3] & (1 << 11)) info->FeatureSet |= CPU_FEATURE_SEP;
261 if (regs2[3] & (1 << 12)) info->FeatureSet |= CPU_FEATURE_MTRR;
262 if (regs2[3] & (1 << 15)) info->FeatureSet |= CPU_FEATURE_CMOV;
263 if (regs2[3] & (1 << 16)) info->FeatureSet |= CPU_FEATURE_PAT;
264 if (regs2[3] & (1 << 23)) info->FeatureSet |= CPU_FEATURE_MMX;
265 if (regs2[3] & (1 << 24)) info->FeatureSet |= CPU_FEATURE_FXSR;
266 if (regs2[3] & (1 << 25)) info->FeatureSet |= CPU_FEATURE_SSE;
267 if (regs2[3] & (1 << 26)) info->FeatureSet |= CPU_FEATURE_SSE2;
268 if (regs2[2] & (1 << 0 )) info->FeatureSet |= CPU_FEATURE_SSE3;
269 if (regs2[2] & (1 << 9 )) info->FeatureSet |= CPU_FEATURE_SSSE3;
270 if (regs2[2] & (1 << 13)) info->FeatureSet |= CPU_FEATURE_CX128;
271 if (regs2[2] & (1 << 19)) info->FeatureSet |= CPU_FEATURE_SSE41;
272 if (regs2[2] & (1 << 20)) info->FeatureSet |= CPU_FEATURE_SSE42;
273 if (regs2[2] & (1 << 27)) info->FeatureSet |= CPU_FEATURE_XSAVE;
274 if (regs2[2] & (1 << 28)) info->FeatureSet |= CPU_FEATURE_AVX;
275 if((regs2[3] & (1 << 26)) && (regs2[3] & (1 << 24)) && have_sse_daz_mode()) /* has SSE2 and FXSAVE/FXRSTOR */
276 info->FeatureSet |= CPU_FEATURE_DAZ;
278 if (regs[0] >= 0x00000007)
280 do_cpuid( 0x00000007, 0, regs3 ); /* get extended features */
281 if (regs3[1] & (1 << 5)) info->FeatureSet |= CPU_FEATURE_AVX2;
284 if (info->FeatureSet & CPU_FEATURE_XSAVE)
286 do_cpuid( 0x0000000d, 1, regs3 ); /* get XSAVE details */
287 if (regs3[0] & 2) xstate_compaction_enabled = TRUE;
290 if (regs[1] == AUTH && regs[3] == ENTI && regs[2] == CAMD)
292 info->Level = (regs2[0] >> 8) & 0xf; /* family */
293 if (info->Level == 0xf) /* AMD says to add the extended family to the family if family is 0xf */
294 info->Level += (regs2[0] >> 20) & 0xff;
296 /* repack model and stepping to make a "revision" */
297 info->Revision = ((regs2[0] >> 16) & 0xf) << 12; /* extended model */
298 info->Revision |= ((regs2[0] >> 4 ) & 0xf) << 8; /* model */
299 info->Revision |= regs2[0] & 0xf; /* stepping */
301 do_cpuid( 0x80000000, 0, regs ); /* get vendor cpuid level */
302 if (regs[0] >= 0x80000001)
304 do_cpuid( 0x80000001, 0, regs2 ); /* get vendor features */
305 if (regs2[2] & (1 << 2)) info->FeatureSet |= CPU_FEATURE_VIRT;
306 if (regs2[3] & (1 << 20)) info->FeatureSet |= CPU_FEATURE_NX;
307 if (regs2[3] & (1 << 27)) info->FeatureSet |= CPU_FEATURE_TSC;
308 if (regs2[3] & (1u << 31)) info->FeatureSet |= CPU_FEATURE_3DNOW;
311 else if (regs[1] == GENU && regs[3] == INEI && regs[2] == NTEL)
313 info->Level = ((regs2[0] >> 8) & 0xf) + ((regs2[0] >> 20) & 0xff); /* family + extended family */
314 if(info->Level == 15) info->Level = 6;
316 /* repack model and stepping to make a "revision" */
317 info->Revision = ((regs2[0] >> 16) & 0xf) << 12; /* extended model */
318 info->Revision |= ((regs2[0] >> 4 ) & 0xf) << 8; /* model */
319 info->Revision |= regs2[0] & 0xf; /* stepping */
321 if(regs2[2] & (1 << 5)) info->FeatureSet |= CPU_FEATURE_VIRT;
322 if(regs2[3] & (1 << 21)) info->FeatureSet |= CPU_FEATURE_DS;
324 do_cpuid( 0x80000000, 0, regs ); /* get vendor cpuid level */
325 if (regs[0] >= 0x80000001)
327 do_cpuid( 0x80000001, 0, regs2 ); /* get vendor features */
328 if (regs2[3] & (1 << 20)) info->FeatureSet |= CPU_FEATURE_NX;
329 if (regs2[3] & (1 << 27)) info->FeatureSet |= CPU_FEATURE_TSC;
332 else
334 info->Level = (regs2[0] >> 8) & 0xf; /* family */
336 /* repack model and stepping to make a "revision" */
337 info->Revision = ((regs2[0] >> 4 ) & 0xf) << 8; /* model */
338 info->Revision |= regs2[0] & 0xf; /* stepping */
343 #elif defined(__arm__)
345 static inline void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
347 #ifdef linux
348 char line[512];
349 char *s, *value;
350 FILE *f = fopen("/proc/cpuinfo", "r");
351 if (f)
353 while (fgets( line, sizeof(line), f ))
355 /* NOTE: the ':' is the only character we can rely on */
356 if (!(value = strchr(line,':'))) continue;
357 /* terminate the valuename */
358 s = value - 1;
359 while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
360 s[1] = 0;
361 /* and strip leading spaces from value */
362 value += 1;
363 while (*value == ' ' || *value == '\t') value++;
364 if ((s = strchr( value,'\n' ))) *s = 0;
365 if (!strcmp( line, "CPU architecture" ))
367 info->Level = atoi(value);
368 continue;
370 if (!strcmp( line, "CPU revision" ))
372 info->Revision = atoi(value);
373 continue;
375 if (!strcmp( line, "Features" ))
377 if (strstr(value, "crc32")) info->FeatureSet |= CPU_FEATURE_ARM_V8_CRC32;
378 if (strstr(value, "aes")) info->FeatureSet |= CPU_FEATURE_ARM_V8_CRYPTO;
379 continue;
382 fclose( f );
384 #elif defined(__FreeBSD__)
385 size_t valsize;
386 char buf[8];
387 int value;
389 valsize = sizeof(buf);
390 if (!sysctlbyname("hw.machine_arch", &buf, &valsize, NULL, 0) && sscanf(buf, "armv%i", &value) == 1)
391 info->Level = value;
393 valsize = sizeof(value);
394 if (!sysctlbyname("hw.floatingpoint", &value, &valsize, NULL, 0))
395 info->FeatureSet |= CPU_FEATURE_ARM_VFP_32;
396 #else
397 FIXME("CPU Feature detection not implemented.\n");
398 #endif
399 info->Architecture = PROCESSOR_ARCHITECTURE_ARM;
402 #elif defined(__aarch64__)
404 static void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
406 #ifdef linux
407 char line[512];
408 char *s, *value;
409 FILE *f = fopen("/proc/cpuinfo", "r");
410 if (f)
412 while (fgets( line, sizeof(line), f ))
414 /* NOTE: the ':' is the only character we can rely on */
415 if (!(value = strchr(line,':'))) continue;
416 /* terminate the valuename */
417 s = value - 1;
418 while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
419 s[1] = 0;
420 /* and strip leading spaces from value */
421 value += 1;
422 while (*value == ' ' || *value == '\t') value++;
423 if ((s = strchr( value,'\n' ))) *s = 0;
424 if (!strcmp( line, "CPU architecture" ))
426 info->Level = atoi(value);
427 continue;
429 if (!strcmp( line, "CPU revision" ))
431 info->Revision = atoi(value);
432 continue;
434 if (!strcmp( line, "Features" ))
436 if (strstr(value, "crc32")) info->FeatureSet |= CPU_FEATURE_ARM_V8_CRC32;
437 if (strstr(value, "aes")) info->FeatureSet |= CPU_FEATURE_ARM_V8_CRYPTO;
438 continue;
441 fclose( f );
443 #else
444 FIXME("CPU Feature detection not implemented.\n");
445 #endif
446 info->Level = max(info->Level, 8);
447 info->Architecture = PROCESSOR_ARCHITECTURE_ARM64;
450 #endif /* End architecture specific feature detection for CPUs */
452 /******************************************************************
453 * init_cpu_info
455 * inits a couple of places with CPU related information:
456 * - cpu_info in this file
457 * - Peb->NumberOfProcessors
458 * - SharedUserData->ProcessFeatures[] array
460 void init_cpu_info(void)
462 long num;
464 #ifdef _SC_NPROCESSORS_ONLN
465 num = sysconf(_SC_NPROCESSORS_ONLN);
466 if (num < 1)
468 num = 1;
469 WARN("Failed to detect the number of processors.\n");
471 #elif defined(CTL_HW) && defined(HW_NCPU)
472 int mib[2];
473 size_t len = sizeof(num);
474 mib[0] = CTL_HW;
475 mib[1] = HW_NCPU;
476 if (sysctl(mib, 2, &num, &len, NULL, 0) != 0)
478 num = 1;
479 WARN("Failed to detect the number of processors.\n");
481 #else
482 num = 1;
483 FIXME("Detecting the number of processors is not supported.\n");
484 #endif
485 NtCurrentTeb()->Peb->NumberOfProcessors = num;
486 get_cpuinfo( &cpu_info );
487 TRACE( "<- CPU arch %d, level %d, rev %d, features 0x%x\n",
488 cpu_info.Architecture, cpu_info.Level, cpu_info.Revision, cpu_info.FeatureSet );
491 static BOOL grow_logical_proc_buf( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata, DWORD *max_len )
493 SYSTEM_LOGICAL_PROCESSOR_INFORMATION *new_data;
495 *max_len *= 2;
496 if (!(new_data = realloc( *pdata, *max_len*sizeof(*new_data) ))) return FALSE;
497 *pdata = new_data;
498 return TRUE;
501 static BOOL grow_logical_proc_ex_buf( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *max_len )
503 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *new_dataex;
504 DWORD new_len = *max_len * 2;
505 if (!(new_dataex = realloc( *pdataex, new_len * sizeof(*new_dataex) ))) return FALSE;
506 memset( new_dataex + *max_len, 0, (new_len - *max_len) * sizeof(*new_dataex) );
507 *pdataex = new_dataex;
508 *max_len = new_len;
509 return TRUE;
512 static DWORD log_proc_ex_size_plus(DWORD size)
514 /* add SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX.Relationship and .Size */
515 return sizeof(LOGICAL_PROCESSOR_RELATIONSHIP) + sizeof(DWORD) + size;
518 static DWORD count_bits(ULONG_PTR mask)
520 DWORD count = 0;
521 while (mask > 0)
523 if (mask & 1) ++count;
524 mask >>= 1;
526 return count;
529 /* Store package and core information for a logical processor. Parsing of processor
530 * data may happen in multiple passes; the 'id' parameter is then used to locate
531 * previously stored data. The type of data stored in 'id' depends on 'rel':
532 * - RelationProcessorPackage: package id ('CPU socket').
533 * - RelationProcessorCore: physical core number.
535 static BOOL logical_proc_info_add_by_id( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
536 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *len,
537 DWORD *pmax_len, LOGICAL_PROCESSOR_RELATIONSHIP rel,
538 DWORD id, ULONG_PTR mask )
540 if (pdata)
542 DWORD i;
544 for (i = 0; i < *len; i++)
546 if (rel == RelationProcessorPackage && (*pdata)[i].Relationship == rel && (*pdata)[i].u.Reserved[1] == id)
548 (*pdata)[i].ProcessorMask |= mask;
549 return TRUE;
551 else if (rel == RelationProcessorCore && (*pdata)[i].Relationship == rel && (*pdata)[i].u.Reserved[1] == id)
552 return TRUE;
555 while (*len == *pmax_len)
557 if (!grow_logical_proc_buf(pdata, pmax_len)) return FALSE;
560 (*pdata)[i].Relationship = rel;
561 (*pdata)[i].ProcessorMask = mask;
562 if (rel == RelationProcessorCore)
563 (*pdata)[i].u.ProcessorCore.Flags = count_bits(mask) > 1 ? LTP_PC_SMT : 0;
564 (*pdata)[i].u.Reserved[0] = 0;
565 (*pdata)[i].u.Reserved[1] = id;
566 *len = i+1;
568 else
570 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
571 DWORD ofs = 0;
573 while (ofs < *len)
575 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
576 if (rel == RelationProcessorPackage && dataex->Relationship == rel && dataex->u.Processor.Reserved[1] == id)
578 dataex->u.Processor.GroupMask[0].Mask |= mask;
579 return TRUE;
581 else if (rel == RelationProcessorCore && dataex->Relationship == rel && dataex->u.Processor.Reserved[1] == id)
583 return TRUE;
585 ofs += dataex->Size;
588 /* TODO: For now, just one group. If more than 64 processors, then we
589 * need another group. */
591 while (ofs + log_proc_ex_size_plus(sizeof(PROCESSOR_RELATIONSHIP)) > *pmax_len)
593 if (!grow_logical_proc_ex_buf(pdataex, pmax_len)) return FALSE;
596 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
598 dataex->Relationship = rel;
599 dataex->Size = log_proc_ex_size_plus(sizeof(PROCESSOR_RELATIONSHIP));
600 if (rel == RelationProcessorCore)
601 dataex->u.Processor.Flags = count_bits(mask) > 1 ? LTP_PC_SMT : 0;
602 else
603 dataex->u.Processor.Flags = 0;
604 dataex->u.Processor.EfficiencyClass = 0;
605 dataex->u.Processor.GroupCount = 1;
606 dataex->u.Processor.GroupMask[0].Mask = mask;
607 dataex->u.Processor.GroupMask[0].Group = 0;
608 /* mark for future lookup */
609 dataex->u.Processor.Reserved[0] = 0;
610 dataex->u.Processor.Reserved[1] = id;
612 *len += dataex->Size;
615 return TRUE;
618 static BOOL logical_proc_info_add_cache( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
619 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *len,
620 DWORD *pmax_len, ULONG_PTR mask, CACHE_DESCRIPTOR *cache )
622 if (pdata)
624 DWORD i;
626 for (i = 0; i < *len; i++)
628 if ((*pdata)[i].Relationship==RelationCache && (*pdata)[i].ProcessorMask==mask
629 && (*pdata)[i].u.Cache.Level==cache->Level && (*pdata)[i].u.Cache.Type==cache->Type)
630 return TRUE;
633 while (*len == *pmax_len)
634 if (!grow_logical_proc_buf(pdata, pmax_len)) return FALSE;
636 (*pdata)[i].Relationship = RelationCache;
637 (*pdata)[i].ProcessorMask = mask;
638 (*pdata)[i].u.Cache = *cache;
639 *len = i+1;
641 else
643 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
644 DWORD ofs;
646 for (ofs = 0; ofs < *len; )
648 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
649 if (dataex->Relationship == RelationCache && dataex->u.Cache.GroupMask.Mask == mask &&
650 dataex->u.Cache.Level == cache->Level && dataex->u.Cache.Type == cache->Type)
651 return TRUE;
652 ofs += dataex->Size;
655 while (ofs + log_proc_ex_size_plus(sizeof(CACHE_RELATIONSHIP)) > *pmax_len)
657 if (!grow_logical_proc_ex_buf(pdataex, pmax_len)) return FALSE;
660 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
662 dataex->Relationship = RelationCache;
663 dataex->Size = log_proc_ex_size_plus(sizeof(CACHE_RELATIONSHIP));
664 dataex->u.Cache.Level = cache->Level;
665 dataex->u.Cache.Associativity = cache->Associativity;
666 dataex->u.Cache.LineSize = cache->LineSize;
667 dataex->u.Cache.CacheSize = cache->Size;
668 dataex->u.Cache.Type = cache->Type;
669 dataex->u.Cache.GroupMask.Mask = mask;
670 dataex->u.Cache.GroupMask.Group = 0;
672 *len += dataex->Size;
675 return TRUE;
678 static BOOL logical_proc_info_add_numa_node( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
679 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *len,
680 DWORD *pmax_len, ULONG_PTR mask, DWORD node_id )
682 if (pdata)
684 while (*len == *pmax_len)
685 if (!grow_logical_proc_buf(pdata, pmax_len)) return FALSE;
687 (*pdata)[*len].Relationship = RelationNumaNode;
688 (*pdata)[*len].ProcessorMask = mask;
689 (*pdata)[*len].u.NumaNode.NodeNumber = node_id;
690 (*len)++;
692 else
694 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
696 while (*len + log_proc_ex_size_plus(sizeof(NUMA_NODE_RELATIONSHIP)) > *pmax_len)
698 if (!grow_logical_proc_ex_buf(pdataex, pmax_len)) return FALSE;
701 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + *len);
703 dataex->Relationship = RelationNumaNode;
704 dataex->Size = log_proc_ex_size_plus(sizeof(NUMA_NODE_RELATIONSHIP));
705 dataex->u.NumaNode.NodeNumber = node_id;
706 dataex->u.NumaNode.GroupMask.Mask = mask;
707 dataex->u.NumaNode.GroupMask.Group = 0;
709 *len += dataex->Size;
712 return TRUE;
715 static BOOL logical_proc_info_add_group( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex,
716 DWORD *len, DWORD *pmax_len, DWORD num_cpus, ULONG_PTR mask )
718 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
720 while (*len + log_proc_ex_size_plus(sizeof(GROUP_RELATIONSHIP)) > *pmax_len)
721 if (!grow_logical_proc_ex_buf(pdataex, pmax_len)) return FALSE;
723 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + *len);
725 dataex->Relationship = RelationGroup;
726 dataex->Size = log_proc_ex_size_plus(sizeof(GROUP_RELATIONSHIP));
727 dataex->u.Group.MaximumGroupCount = 1;
728 dataex->u.Group.ActiveGroupCount = 1;
729 dataex->u.Group.GroupInfo[0].MaximumProcessorCount = num_cpus;
730 dataex->u.Group.GroupInfo[0].ActiveProcessorCount = num_cpus;
731 dataex->u.Group.GroupInfo[0].ActiveProcessorMask = mask;
733 *len += dataex->Size;
734 return TRUE;
737 #ifdef linux
739 /* Helper function for counting bitmap values as commonly used by the Linux kernel
740 * for storing CPU masks in sysfs. The format is comma separated lists of hex values
741 * each max 32-bit e.g. "00ff" or even "00,00000000,0000ffff".
743 * Example files include:
744 * - /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_map
745 * - /sys/devices/system/cpu/cpu0/topology/thread_siblings
747 static BOOL sysfs_parse_bitmap(const char *filename, ULONG_PTR *mask)
749 FILE *f;
750 DWORD r;
752 f = fopen(filename, "r");
753 if (!f) return FALSE;
755 while (!feof(f))
757 char op;
758 if (!fscanf(f, "%x%c ", &r, &op)) break;
759 *mask = (sizeof(ULONG_PTR)>sizeof(int) ? *mask << (8 * sizeof(DWORD)) : 0) + r;
761 fclose( f );
762 return TRUE;
765 /* Helper function for counting number of elements in interval lists as used by
766 * the Linux kernel. The format is comma separated list of intervals of which
767 * each interval has the format of "begin-end" where begin and end are decimal
768 * numbers. E.g. "0-7", "0-7,16-23"
770 * Example files include:
771 * - /sys/devices/system/cpu/online
772 * - /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_list
773 * - /sys/devices/system/cpu/cpu0/topology/thread_siblings_list.
775 static BOOL sysfs_count_list_elements(const char *filename, DWORD *result)
777 FILE *f;
779 f = fopen(filename, "r");
780 if (!f) return FALSE;
782 while (!feof(f))
784 char op;
785 DWORD beg, end;
787 if (!fscanf(f, "%u%c ", &beg, &op)) break;
788 if(op == '-')
789 fscanf(f, "%u%c ", &end, &op);
790 else
791 end = beg;
793 *result += end - beg + 1;
795 fclose( f );
796 return TRUE;
799 /* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
800 static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data,
801 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **dataex,
802 DWORD *max_len, DWORD relation )
804 static const char core_info[] = "/sys/devices/system/cpu/cpu%u/topology/%s";
805 static const char cache_info[] = "/sys/devices/system/cpu/cpu%u/cache/index%u/%s";
806 static const char numa_info[] = "/sys/devices/system/node/node%u/cpumap";
808 FILE *fcpu_list, *fnuma_list, *f;
809 DWORD len = 0, beg, end, i, j, r, num_cpus = 0, max_cpus = 0;
810 char op, name[MAX_PATH];
811 ULONG_PTR all_cpus_mask = 0;
813 /* On systems with a large number of CPU cores (32 or 64 depending on 32-bit or 64-bit),
814 * we have issues parsing processor information:
815 * - ULONG_PTR masks as used in data structures can't hold all cores. Requires splitting
816 * data appropriately into "processor groups". We are hard coding 1.
817 * - Thread affinity code in wineserver and our CPU parsing code here work independently.
818 * So far the Windows mask applied directly to Linux, but process groups break that.
819 * (NUMA systems you may have multiple non-full groups.)
821 if(sysfs_count_list_elements("/sys/devices/system/cpu/present", &max_cpus) && max_cpus > MAXIMUM_PROCESSORS)
823 FIXME("Improve CPU info reporting: system supports %u logical cores, but only %u supported!\n",
824 max_cpus, MAXIMUM_PROCESSORS);
827 fcpu_list = fopen("/sys/devices/system/cpu/online", "r");
828 if (!fcpu_list) return STATUS_NOT_IMPLEMENTED;
830 while (!feof(fcpu_list))
832 if (!fscanf(fcpu_list, "%u%c ", &beg, &op)) break;
833 if (op == '-') fscanf(fcpu_list, "%u%c ", &end, &op);
834 else end = beg;
836 for(i = beg; i <= end; i++)
838 DWORD phys_core = 0;
839 ULONG_PTR thread_mask = 0;
841 if (i > 8*sizeof(ULONG_PTR))
843 FIXME("skipping logical processor %d\n", i);
844 continue;
847 if (relation == RelationAll || relation == RelationProcessorPackage)
849 sprintf(name, core_info, i, "physical_package_id");
850 f = fopen(name, "r");
851 if (f)
853 fscanf(f, "%u", &r);
854 fclose(f);
856 else r = 0;
857 if (!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorPackage, r, (ULONG_PTR)1 << i))
859 fclose(fcpu_list);
860 return STATUS_NO_MEMORY;
864 /* Sysfs enumerates logical cores (and not physical cores), but Windows enumerates
865 * by physical core. Upon enumerating a logical core in sysfs, we register a physical
866 * core and all its logical cores. In order to not report physical cores multiple
867 * times, we pass a unique physical core ID to logical_proc_info_add_by_id and let
868 * that call figure out any duplication.
869 * Obtain a unique physical core ID from the first element of thread_siblings_list.
870 * This list provides logical cores sharing the same physical core. The IDs are based
871 * on kernel cpu core numbering as opposed to a hardware core ID like provided through
872 * 'core_id', so are suitable as a unique ID.
874 if(relation == RelationAll || relation == RelationProcessorCore ||
875 relation == RelationNumaNode || relation == RelationGroup)
877 /* Mask of logical threads sharing same physical core in kernel core numbering. */
878 sprintf(name, core_info, i, "thread_siblings");
879 if(!sysfs_parse_bitmap(name, &thread_mask)) thread_mask = 1<<i;
881 /* Needed later for NumaNode and Group. */
882 all_cpus_mask |= thread_mask;
884 if (relation == RelationAll || relation == RelationProcessorCore)
886 sprintf(name, core_info, i, "thread_siblings_list");
887 f = fopen(name, "r");
888 if (f)
890 fscanf(f, "%d%c", &phys_core, &op);
891 fclose(f);
893 else phys_core = i;
895 if (!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorCore, phys_core, thread_mask))
897 fclose(fcpu_list);
898 return STATUS_NO_MEMORY;
903 if (relation == RelationAll || relation == RelationCache)
905 for(j = 0; j < 4; j++)
907 CACHE_DESCRIPTOR cache;
908 ULONG_PTR mask = 0;
910 sprintf(name, cache_info, i, j, "shared_cpu_map");
911 if(!sysfs_parse_bitmap(name, &mask)) continue;
913 sprintf(name, cache_info, i, j, "level");
914 f = fopen(name, "r");
915 if(!f) continue;
916 fscanf(f, "%u", &r);
917 fclose(f);
918 cache.Level = r;
920 sprintf(name, cache_info, i, j, "ways_of_associativity");
921 f = fopen(name, "r");
922 if(!f) continue;
923 fscanf(f, "%u", &r);
924 fclose(f);
925 cache.Associativity = r;
927 sprintf(name, cache_info, i, j, "coherency_line_size");
928 f = fopen(name, "r");
929 if(!f) continue;
930 fscanf(f, "%u", &r);
931 fclose(f);
932 cache.LineSize = r;
934 sprintf(name, cache_info, i, j, "size");
935 f = fopen(name, "r");
936 if(!f) continue;
937 fscanf(f, "%u%c", &r, &op);
938 fclose(f);
939 if(op != 'K')
940 WARN("unknown cache size %u%c\n", r, op);
941 cache.Size = (op=='K' ? r*1024 : r);
943 sprintf(name, cache_info, i, j, "type");
944 f = fopen(name, "r");
945 if(!f) continue;
946 fscanf(f, "%s", name);
947 fclose(f);
948 if (!memcmp(name, "Data", 5))
949 cache.Type = CacheData;
950 else if(!memcmp(name, "Instruction", 11))
951 cache.Type = CacheInstruction;
952 else
953 cache.Type = CacheUnified;
955 if (!logical_proc_info_add_cache(data, dataex, &len, max_len, mask, &cache))
957 fclose(fcpu_list);
958 return STATUS_NO_MEMORY;
964 fclose(fcpu_list);
966 num_cpus = count_bits(all_cpus_mask);
968 if(relation == RelationAll || relation == RelationNumaNode)
970 fnuma_list = fopen("/sys/devices/system/node/online", "r");
971 if (!fnuma_list)
973 if (!logical_proc_info_add_numa_node(data, dataex, &len, max_len, all_cpus_mask, 0))
974 return STATUS_NO_MEMORY;
976 else
978 while (!feof(fnuma_list))
980 if (!fscanf(fnuma_list, "%u%c ", &beg, &op))
981 break;
982 if (op == '-') fscanf(fnuma_list, "%u%c ", &end, &op);
983 else end = beg;
985 for (i = beg; i <= end; i++)
987 ULONG_PTR mask = 0;
989 sprintf(name, numa_info, i);
990 if (!sysfs_parse_bitmap( name, &mask )) continue;
992 if (!logical_proc_info_add_numa_node(data, dataex, &len, max_len, mask, i))
994 fclose(fnuma_list);
995 return STATUS_NO_MEMORY;
999 fclose(fnuma_list);
1003 if(dataex && (relation == RelationAll || relation == RelationGroup))
1004 logical_proc_info_add_group(dataex, &len, max_len, num_cpus, all_cpus_mask);
1006 if(data)
1007 *max_len = len * sizeof(**data);
1008 else
1009 *max_len = len;
1011 return STATUS_SUCCESS;
1014 #elif defined(__APPLE__)
1016 /* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
1017 static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data,
1018 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **dataex,
1019 DWORD *max_len, DWORD relation)
1021 DWORD pkgs_no, cores_no, lcpu_no, lcpu_per_core, cores_per_package, assoc, len = 0;
1022 DWORD cache_ctrs[10] = {0};
1023 ULONG_PTR all_cpus_mask = 0;
1024 CACHE_DESCRIPTOR cache[10];
1025 LONGLONG cache_size, cache_line_size, cache_sharing[10];
1026 size_t size;
1027 DWORD p,i,j,k;
1029 if (relation != RelationAll)
1030 FIXME("Relationship filtering not implemented: 0x%x\n", relation);
1032 lcpu_no = NtCurrentTeb()->Peb->NumberOfProcessors;
1034 size = sizeof(pkgs_no);
1035 if (sysctlbyname("hw.packages", &pkgs_no, &size, NULL, 0))
1036 pkgs_no = 1;
1038 size = sizeof(cores_no);
1039 if (sysctlbyname("hw.physicalcpu", &cores_no, &size, NULL, 0))
1040 cores_no = lcpu_no;
1042 TRACE("%u logical CPUs from %u physical cores across %u packages\n",
1043 lcpu_no, cores_no, pkgs_no);
1045 lcpu_per_core = lcpu_no / cores_no;
1046 cores_per_package = cores_no / pkgs_no;
1048 memset(cache, 0, sizeof(cache));
1049 cache[1].Level = 1;
1050 cache[1].Type = CacheInstruction;
1051 cache[1].Associativity = 8; /* reasonable default */
1052 cache[1].LineSize = 0x40; /* reasonable default */
1053 cache[2].Level = 1;
1054 cache[2].Type = CacheData;
1055 cache[2].Associativity = 8;
1056 cache[2].LineSize = 0x40;
1057 cache[3].Level = 2;
1058 cache[3].Type = CacheUnified;
1059 cache[3].Associativity = 8;
1060 cache[3].LineSize = 0x40;
1061 cache[4].Level = 3;
1062 cache[4].Type = CacheUnified;
1063 cache[4].Associativity = 12;
1064 cache[4].LineSize = 0x40;
1066 size = sizeof(cache_line_size);
1067 if (!sysctlbyname("hw.cachelinesize", &cache_line_size, &size, NULL, 0))
1069 for (i = 1; i < 5; i++) cache[i].LineSize = cache_line_size;
1072 /* TODO: set actual associativity for all caches */
1073 size = sizeof(assoc);
1074 if (!sysctlbyname("machdep.cpu.cache.L2_associativity", &assoc, &size, NULL, 0))
1075 cache[3].Associativity = assoc;
1077 size = sizeof(cache_size);
1078 if (!sysctlbyname("hw.l1icachesize", &cache_size, &size, NULL, 0))
1079 cache[1].Size = cache_size;
1080 size = sizeof(cache_size);
1081 if (!sysctlbyname("hw.l1dcachesize", &cache_size, &size, NULL, 0))
1082 cache[2].Size = cache_size;
1083 size = sizeof(cache_size);
1084 if (!sysctlbyname("hw.l2cachesize", &cache_size, &size, NULL, 0))
1085 cache[3].Size = cache_size;
1086 size = sizeof(cache_size);
1087 if (!sysctlbyname("hw.l3cachesize", &cache_size, &size, NULL, 0))
1088 cache[4].Size = cache_size;
1090 size = sizeof(cache_sharing);
1091 if (sysctlbyname("hw.cacheconfig", cache_sharing, &size, NULL, 0) < 0)
1093 cache_sharing[1] = lcpu_per_core;
1094 cache_sharing[2] = lcpu_per_core;
1095 cache_sharing[3] = lcpu_per_core;
1096 cache_sharing[4] = lcpu_no;
1098 else
1100 /* in cache[], indexes 1 and 2 are l1 caches */
1101 cache_sharing[4] = cache_sharing[3];
1102 cache_sharing[3] = cache_sharing[2];
1103 cache_sharing[2] = cache_sharing[1];
1106 for(p = 0; p < pkgs_no; ++p)
1108 for(j = 0; j < cores_per_package && p * cores_per_package + j < cores_no; ++j)
1110 ULONG_PTR mask = 0;
1111 DWORD phys_core;
1113 for(k = 0; k < lcpu_per_core; ++k) mask |= (ULONG_PTR)1 << (j * lcpu_per_core + k);
1115 all_cpus_mask |= mask;
1117 /* add to package */
1118 if(!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorPackage, p, mask))
1119 return STATUS_NO_MEMORY;
1121 /* add new core */
1122 phys_core = p * cores_per_package + j;
1123 if(!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorCore, phys_core, mask))
1124 return STATUS_NO_MEMORY;
1126 for(i = 1; i < 5; ++i)
1128 if(cache_ctrs[i] == 0 && cache[i].Size > 0)
1130 mask = 0;
1131 for(k = 0; k < cache_sharing[i]; ++k)
1132 mask |= (ULONG_PTR)1 << (j * lcpu_per_core + k);
1134 if(!logical_proc_info_add_cache(data, dataex, &len, max_len, mask, &cache[i]))
1135 return STATUS_NO_MEMORY;
1138 cache_ctrs[i] += lcpu_per_core;
1139 if(cache_ctrs[i] == cache_sharing[i]) cache_ctrs[i] = 0;
1144 /* OSX doesn't support NUMA, so just make one NUMA node for all CPUs */
1145 if(!logical_proc_info_add_numa_node(data, dataex, &len, max_len, all_cpus_mask, 0))
1146 return STATUS_NO_MEMORY;
1148 if(dataex) logical_proc_info_add_group(dataex, &len, max_len, lcpu_no, all_cpus_mask);
1150 if(data)
1151 *max_len = len * sizeof(**data);
1152 else
1153 *max_len = len;
1155 return STATUS_SUCCESS;
1158 #else
1160 static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data,
1161 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **dataex,
1162 DWORD *max_len, DWORD relation )
1164 FIXME("stub\n");
1165 return STATUS_NOT_IMPLEMENTED;
1167 #endif
1169 #ifdef linux
1171 static void copy_smbios_string( char **buffer, char *s, size_t len )
1173 if (!len) return;
1174 memcpy(*buffer, s, len + 1);
1175 *buffer += len + 1;
1178 static size_t get_smbios_string( const char *path, char *str, size_t size )
1180 FILE *file;
1181 size_t len;
1183 if (!(file = fopen(path, "r"))) return 0;
1185 len = fread( str, 1, size - 1, file );
1186 fclose( file );
1188 if (len >= 1 && str[len - 1] == '\n') len--;
1189 str[len] = 0;
1190 return len;
1193 static void get_system_uuid( GUID *uuid )
1195 static const unsigned char hex[] =
1197 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
1198 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
1199 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
1200 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
1201 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
1202 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
1203 0,10,11,12,13,14,15 /* 0x60 */
1205 int fd;
1207 memset( uuid, 0xff, sizeof(*uuid) );
1208 if ((fd = open( "/var/lib/dbus/machine-id", O_RDONLY )) != -1)
1210 unsigned char buf[32], *p = buf;
1211 if (read( fd, buf, sizeof(buf) ) == sizeof(buf))
1213 uuid->Data1 = hex[p[6]] << 28 | hex[p[7]] << 24 | hex[p[4]] << 20 | hex[p[5]] << 16 |
1214 hex[p[2]] << 12 | hex[p[3]] << 8 | hex[p[0]] << 4 | hex[p[1]];
1216 uuid->Data2 = hex[p[10]] << 12 | hex[p[11]] << 8 | hex[p[8]] << 4 | hex[p[9]];
1217 uuid->Data3 = hex[p[14]] << 12 | hex[p[15]] << 8 | hex[p[12]] << 4 | hex[p[13]];
1219 uuid->Data4[0] = hex[p[16]] << 4 | hex[p[17]];
1220 uuid->Data4[1] = hex[p[18]] << 4 | hex[p[19]];
1221 uuid->Data4[2] = hex[p[20]] << 4 | hex[p[21]];
1222 uuid->Data4[3] = hex[p[22]] << 4 | hex[p[23]];
1223 uuid->Data4[4] = hex[p[24]] << 4 | hex[p[25]];
1224 uuid->Data4[5] = hex[p[26]] << 4 | hex[p[27]];
1225 uuid->Data4[6] = hex[p[28]] << 4 | hex[p[29]];
1226 uuid->Data4[7] = hex[p[30]] << 4 | hex[p[31]];
1228 close( fd );
1232 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1233 ULONG *required_len )
1235 switch (sfti->ProviderSignature)
1237 case RSMB:
1239 char bios_vendor[128], bios_version[128], bios_date[128];
1240 size_t bios_vendor_len, bios_version_len, bios_date_len;
1241 char system_vendor[128], system_product[128], system_version[128], system_serial[128];
1242 size_t system_vendor_len, system_product_len, system_version_len, system_serial_len;
1243 char system_sku[128], system_family[128];
1244 size_t system_sku_len, system_family_len;
1245 char board_vendor[128], board_product[128], board_version[128], board_serial[128], board_asset_tag[128];
1246 size_t board_vendor_len, board_product_len, board_version_len, board_serial_len, board_asset_tag_len;
1247 char chassis_vendor[128], chassis_version[128], chassis_serial[128], chassis_asset_tag[128];
1248 char chassis_type[11] = "2"; /* unknown */
1249 size_t chassis_vendor_len, chassis_version_len, chassis_serial_len, chassis_asset_tag_len;
1250 char *buffer = (char*)sfti->TableBuffer;
1251 BYTE string_count;
1252 BYTE handle_count = 0;
1253 struct smbios_prologue *prologue;
1254 struct smbios_bios *bios;
1255 struct smbios_system *system;
1256 struct smbios_board *board;
1257 struct smbios_chassis *chassis;
1258 struct smbios_boot_info *boot_info;
1259 struct smbios_header *end_of_table;
1261 #define S(s) s, sizeof(s)
1262 bios_vendor_len = get_smbios_string("/sys/class/dmi/id/bios_vendor", S(bios_vendor));
1263 bios_version_len = get_smbios_string("/sys/class/dmi/id/bios_version", S(bios_version));
1264 bios_date_len = get_smbios_string("/sys/class/dmi/id/bios_date", S(bios_date));
1265 system_vendor_len = get_smbios_string("/sys/class/dmi/id/sys_vendor", S(system_vendor));
1266 system_product_len = get_smbios_string("/sys/class/dmi/id/product_name", S(system_product));
1267 system_version_len = get_smbios_string("/sys/class/dmi/id/product_version", S(system_version));
1268 system_serial_len = get_smbios_string("/sys/class/dmi/id/product_serial", S(system_serial));
1269 system_sku_len = get_smbios_string("/sys/class/dmi/id/product_sku", S(system_sku));
1270 system_family_len = get_smbios_string("/sys/class/dmi/id/product_family", S(system_family));
1271 board_vendor_len = get_smbios_string("/sys/class/dmi/id/board_vendor", S(board_vendor));
1272 board_product_len = get_smbios_string("/sys/class/dmi/id/board_name", S(board_product));
1273 board_version_len = get_smbios_string("/sys/class/dmi/id/board_version", S(board_version));
1274 board_serial_len = get_smbios_string("/sys/class/dmi/id/board_serial", S(board_serial));
1275 board_asset_tag_len = get_smbios_string("/sys/class/dmi/id/board_asset_tag", S(board_asset_tag));
1276 chassis_vendor_len = get_smbios_string("/sys/class/dmi/id/chassis_vendor", S(chassis_vendor));
1277 chassis_version_len = get_smbios_string("/sys/class/dmi/id/chassis_version", S(chassis_version));
1278 chassis_serial_len = get_smbios_string("/sys/class/dmi/id/chassis_serial", S(chassis_serial));
1279 chassis_asset_tag_len = get_smbios_string("/sys/class/dmi/id/chassis_tag", S(chassis_asset_tag));
1280 get_smbios_string("/sys/class/dmi/id/chassis_type", S(chassis_type));
1281 #undef S
1283 *required_len = sizeof(struct smbios_prologue);
1285 #define L(l) (l + (l ? 1 : 0))
1286 *required_len += sizeof(struct smbios_bios);
1287 *required_len += max(L(bios_vendor_len) + L(bios_version_len) + L(bios_date_len) + 1, 2);
1289 *required_len += sizeof(struct smbios_system);
1290 *required_len += max(L(system_vendor_len) + L(system_product_len) + L(system_version_len) +
1291 L(system_serial_len) + L(system_sku_len) + L(system_family_len) + 1, 2);
1293 *required_len += sizeof(struct smbios_board);
1294 *required_len += max(L(board_vendor_len) + L(board_product_len) + L(board_version_len) +
1295 L(board_serial_len) + L(board_asset_tag_len) + 1, 2);
1297 *required_len += sizeof(struct smbios_chassis);
1298 *required_len += max(L(chassis_vendor_len) + L(chassis_version_len) + L(chassis_serial_len) +
1299 L(chassis_asset_tag_len) + 1, 2);
1301 *required_len += sizeof(struct smbios_boot_info);
1302 *required_len += 2;
1304 *required_len += sizeof(struct smbios_header);
1305 *required_len += 2;
1306 #undef L
1308 sfti->TableBufferLength = *required_len;
1310 *required_len += FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
1312 if (available_len < *required_len)
1313 return STATUS_BUFFER_TOO_SMALL;
1315 prologue = (struct smbios_prologue*)buffer;
1316 prologue->calling_method = 0;
1317 prologue->major_version = 2;
1318 prologue->minor_version = 4;
1319 prologue->revision = 0;
1320 prologue->length = sfti->TableBufferLength - sizeof(struct smbios_prologue);
1321 buffer += sizeof(struct smbios_prologue);
1323 string_count = 0;
1324 bios = (struct smbios_bios*)buffer;
1325 bios->hdr.type = 0;
1326 bios->hdr.length = sizeof(struct smbios_bios);
1327 bios->hdr.handle = handle_count++;
1328 bios->vendor = bios_vendor_len ? ++string_count : 0;
1329 bios->version = bios_version_len ? ++string_count : 0;
1330 bios->start = 0;
1331 bios->date = bios_date_len ? ++string_count : 0;
1332 bios->size = 0;
1333 bios->characteristics = 0x4; /* not supported */
1334 bios->characteristics_ext[0] = 0;
1335 bios->characteristics_ext[1] = 0;
1336 bios->system_bios_major_release = 0xFF; /* not supported */
1337 bios->system_bios_minor_release = 0xFF; /* not supported */
1338 bios->ec_firmware_major_release = 0xFF; /* not supported */
1339 bios->ec_firmware_minor_release = 0xFF; /* not supported */
1340 buffer += sizeof(struct smbios_bios);
1342 copy_smbios_string(&buffer, bios_vendor, bios_vendor_len);
1343 copy_smbios_string(&buffer, bios_version, bios_version_len);
1344 copy_smbios_string(&buffer, bios_date, bios_date_len);
1345 if (!string_count) *buffer++ = 0;
1346 *buffer++ = 0;
1348 string_count = 0;
1349 system = (struct smbios_system*)buffer;
1350 system->hdr.type = 1;
1351 system->hdr.length = sizeof(struct smbios_system);
1352 system->hdr.handle = handle_count++;
1353 system->vendor = system_vendor_len ? ++string_count : 0;
1354 system->product = system_product_len ? ++string_count : 0;
1355 system->version = system_version_len ? ++string_count : 0;
1356 system->serial = system_serial_len ? ++string_count : 0;
1357 get_system_uuid( (GUID *)system->uuid );
1358 system->wake_up_type = 0x02; /* unknown */
1359 system->sku_number = system_sku_len ? ++string_count : 0;
1360 system->family = system_family_len ? ++string_count : 0;
1361 buffer += sizeof(struct smbios_system);
1363 copy_smbios_string(&buffer, system_vendor, system_vendor_len);
1364 copy_smbios_string(&buffer, system_product, system_product_len);
1365 copy_smbios_string(&buffer, system_version, system_version_len);
1366 copy_smbios_string(&buffer, system_serial, system_serial_len);
1367 copy_smbios_string(&buffer, system_sku, system_sku_len);
1368 copy_smbios_string(&buffer, system_family, system_family_len);
1369 if (!string_count) *buffer++ = 0;
1370 *buffer++ = 0;
1372 string_count = 0;
1373 chassis = (struct smbios_chassis*)buffer;
1374 chassis->hdr.type = 3;
1375 chassis->hdr.length = sizeof(struct smbios_chassis);
1376 chassis->hdr.handle = handle_count++;
1377 chassis->vendor = chassis_vendor_len ? ++string_count : 0;
1378 chassis->type = atoi(chassis_type);
1379 chassis->version = chassis_version_len ? ++string_count : 0;
1380 chassis->serial = chassis_serial_len ? ++string_count : 0;
1381 chassis->asset_tag = chassis_asset_tag_len ? ++string_count : 0;
1382 chassis->boot_state = 0x02; /* unknown */
1383 chassis->power_supply_state = 0x02; /* unknown */
1384 chassis->thermal_state = 0x02; /* unknown */
1385 chassis->security_status = 0x02; /* unknown */
1386 chassis->oem_defined = 0;
1387 chassis->height = 0; /* undefined */
1388 chassis->num_power_cords = 0; /* unspecified */
1389 chassis->num_contained_elements = 0;
1390 chassis->contained_element_rec_length = 3;
1391 buffer += sizeof(struct smbios_chassis);
1393 copy_smbios_string(&buffer, chassis_vendor, chassis_vendor_len);
1394 copy_smbios_string(&buffer, chassis_version, chassis_version_len);
1395 copy_smbios_string(&buffer, chassis_serial, chassis_serial_len);
1396 copy_smbios_string(&buffer, chassis_asset_tag, chassis_asset_tag_len);
1397 if (!string_count) *buffer++ = 0;
1398 *buffer++ = 0;
1400 string_count = 0;
1401 board = (struct smbios_board*)buffer;
1402 board->hdr.type = 2;
1403 board->hdr.length = sizeof(struct smbios_board);
1404 board->hdr.handle = handle_count++;
1405 board->vendor = board_vendor_len ? ++string_count : 0;
1406 board->product = board_product_len ? ++string_count : 0;
1407 board->version = board_version_len ? ++string_count : 0;
1408 board->serial = board_serial_len ? ++string_count : 0;
1409 board->asset_tag = board_asset_tag_len ? ++string_count : 0;
1410 board->feature_flags = 0x5; /* hosting board, removable */
1411 board->location = 0;
1412 board->chassis_handle = chassis->hdr.handle;
1413 board->board_type = 0xa; /* motherboard */
1414 board->num_contained_handles = 0;
1415 buffer += sizeof(struct smbios_board);
1417 copy_smbios_string(&buffer, board_vendor, board_vendor_len);
1418 copy_smbios_string(&buffer, board_product, board_product_len);
1419 copy_smbios_string(&buffer, board_version, board_version_len);
1420 copy_smbios_string(&buffer, board_serial, board_serial_len);
1421 copy_smbios_string(&buffer, board_asset_tag, board_asset_tag_len);
1422 if (!string_count) *buffer++ = 0;
1423 *buffer++ = 0;
1425 boot_info = (struct smbios_boot_info*)buffer;
1426 boot_info->hdr.type = 32;
1427 boot_info->hdr.length = sizeof(struct smbios_boot_info);
1428 boot_info->hdr.handle = handle_count++;
1429 memset(boot_info->reserved, 0, sizeof(boot_info->reserved));
1430 memset(boot_info->boot_status, 0, sizeof(boot_info->boot_status)); /* no errors detected */
1431 buffer += sizeof(struct smbios_boot_info);
1432 *buffer++ = 0;
1433 *buffer++ = 0;
1435 end_of_table = (struct smbios_header*)buffer;
1436 end_of_table->type = 127;
1437 end_of_table->length = sizeof(struct smbios_header);
1438 end_of_table->handle = handle_count++;
1439 buffer += sizeof(struct smbios_header);
1440 *buffer++ = 0;
1441 *buffer++ = 0;
1443 return STATUS_SUCCESS;
1445 default:
1446 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION provider %08x\n", sfti->ProviderSignature);
1447 return STATUS_NOT_IMPLEMENTED;
1451 #elif defined(__APPLE__)
1453 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1454 ULONG *required_len )
1456 switch (sfti->ProviderSignature)
1458 case RSMB:
1460 io_service_t service;
1461 CFDataRef data;
1462 const UInt8 *ptr;
1463 CFIndex len;
1464 struct smbios_prologue *prologue;
1465 BYTE major_version = 2, minor_version = 0;
1467 if (!(service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleSMBIOS"))))
1469 WARN("can't find AppleSMBIOS service\n");
1470 return STATUS_NO_MEMORY;
1473 if (!(data = IORegistryEntryCreateCFProperty(service, CFSTR("SMBIOS-EPS"), kCFAllocatorDefault, 0)))
1475 WARN("can't find SMBIOS entry point\n");
1476 IOObjectRelease(service);
1477 return STATUS_NO_MEMORY;
1480 len = CFDataGetLength(data);
1481 ptr = CFDataGetBytePtr(data);
1482 if (len >= 8 && !memcmp(ptr, "_SM_", 4))
1484 major_version = ptr[6];
1485 minor_version = ptr[7];
1487 CFRelease(data);
1489 if (!(data = IORegistryEntryCreateCFProperty(service, CFSTR("SMBIOS"), kCFAllocatorDefault, 0)))
1491 WARN("can't find SMBIOS table\n");
1492 IOObjectRelease(service);
1493 return STATUS_NO_MEMORY;
1496 len = CFDataGetLength(data);
1497 ptr = CFDataGetBytePtr(data);
1498 sfti->TableBufferLength = sizeof(*prologue) + len;
1499 *required_len = sfti->TableBufferLength + FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
1500 if (available_len < *required_len)
1502 CFRelease(data);
1503 IOObjectRelease(service);
1504 return STATUS_BUFFER_TOO_SMALL;
1507 prologue = (struct smbios_prologue *)sfti->TableBuffer;
1508 prologue->calling_method = 0;
1509 prologue->major_version = major_version;
1510 prologue->minor_version = minor_version;
1511 prologue->revision = 0;
1512 prologue->length = sfti->TableBufferLength - sizeof(*prologue);
1514 memcpy(sfti->TableBuffer + sizeof(*prologue), ptr, len);
1516 CFRelease(data);
1517 IOObjectRelease(service);
1518 return STATUS_SUCCESS;
1520 default:
1521 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION provider %08x\n", sfti->ProviderSignature);
1522 return STATUS_NOT_IMPLEMENTED;
1526 #else
1528 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1529 ULONG *required_len )
1531 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION\n");
1532 sfti->TableBufferLength = 0;
1533 return STATUS_NOT_IMPLEMENTED;
1536 #endif
1538 static void get_performance_info( SYSTEM_PERFORMANCE_INFORMATION *info )
1540 unsigned long long totalram = 0, freeram = 0, totalswap = 0, freeswap = 0;
1541 FILE *fp;
1543 memset( info, 0, sizeof(*info) );
1545 if ((fp = fopen("/proc/uptime", "r")))
1547 double uptime, idle_time;
1549 fscanf(fp, "%lf %lf", &uptime, &idle_time);
1550 fclose(fp);
1551 info->IdleTime.QuadPart = 10000000 * idle_time;
1553 else
1555 static ULONGLONG idle;
1556 /* many programs expect IdleTime to change so fake change */
1557 info->IdleTime.QuadPart = ++idle;
1560 #ifdef linux
1561 if ((fp = fopen("/proc/meminfo", "r")))
1563 unsigned long long value;
1564 char line[64];
1566 while (fgets(line, sizeof(line), fp))
1568 if(sscanf(line, "MemTotal: %llu kB", &value) == 1)
1569 totalram += value * 1024;
1570 else if(sscanf(line, "MemFree: %llu kB", &value) == 1)
1571 freeram += value * 1024;
1572 else if(sscanf(line, "SwapTotal: %llu kB", &value) == 1)
1573 totalswap += value * 1024;
1574 else if(sscanf(line, "SwapFree: %llu kB", &value) == 1)
1575 freeswap += value * 1024;
1576 else if (sscanf(line, "Buffers: %llu", &value))
1577 freeram += value * 1024;
1578 else if (sscanf(line, "Cached: %llu", &value))
1579 freeram += value * 1024;
1581 fclose(fp);
1583 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || \
1584 defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
1586 #ifdef __APPLE__
1587 unsigned int val;
1588 #else
1589 unsigned long val;
1590 #endif
1591 int mib[2];
1592 size_t size_sys;
1594 mib[0] = CTL_HW;
1595 #ifdef HW_MEMSIZE
1597 uint64_t val64;
1598 mib[1] = HW_MEMSIZE;
1599 size_sys = sizeof(val64);
1600 if (!sysctl(mib, 2, &val64, &size_sys, NULL, 0) && size_sys == sizeof(val64)) totalram = val64;
1602 #endif
1604 #ifdef HAVE_MACH_MACH_H
1606 host_name_port_t host = mach_host_self();
1607 mach_msg_type_number_t count;
1608 #ifdef HOST_VM_INFO64_COUNT
1609 vm_statistics64_data_t vm_stat;
1611 count = HOST_VM_INFO64_COUNT;
1612 if (host_statistics64(host, HOST_VM_INFO64, (host_info64_t)&vm_stat, &count) == KERN_SUCCESS)
1613 freeram = (vm_stat.free_count + vm_stat.inactive_count) * (ULONGLONG)page_size;
1614 #endif
1615 if (!totalram)
1617 host_basic_info_data_t info;
1618 count = HOST_BASIC_INFO_COUNT;
1619 if (host_info(host, HOST_BASIC_INFO, (host_info_t)&info, &count) == KERN_SUCCESS)
1620 totalram = info.max_mem;
1622 mach_port_deallocate(mach_task_self(), host);
1624 #endif
1626 if (!totalram)
1628 mib[1] = HW_PHYSMEM;
1629 size_sys = sizeof(val);
1630 if (!sysctl(mib, 2, &val, &size_sys, NULL, 0) && size_sys == sizeof(val)) totalram = val;
1632 if (!freeram)
1634 mib[1] = HW_USERMEM;
1635 size_sys = sizeof(val);
1636 if (!sysctl(mib, 2, &val, &size_sys, NULL, 0) && size_sys == sizeof(val)) freeram = val;
1638 #ifdef VM_SWAPUSAGE
1640 struct xsw_usage swap;
1641 mib[0] = CTL_VM;
1642 mib[1] = VM_SWAPUSAGE;
1643 size_sys = sizeof(swap);
1644 if (!sysctl(mib, 2, &swap, &size_sys, NULL, 0) && size_sys == sizeof(swap))
1646 totalswap = swap.xsu_total;
1647 freeswap = swap.xsu_avail;
1650 #endif
1652 #endif
1653 info->AvailablePages = freeram / page_size;
1654 info->TotalCommittedPages = (totalram + totalswap - freeram - freeswap) / page_size;
1655 info->TotalCommitLimit = (totalram + totalswap) / page_size;
1659 /* calculate the mday of dst change date, so that for instance Sun 5 Oct 2007
1660 * (last Sunday in October of 2007) becomes Sun Oct 28 2007
1662 * Note: year, day and month must be in unix format.
1664 static int weekday_to_mday(int year, int day, int mon, int day_of_week)
1666 struct tm date;
1667 time_t tmp;
1668 int wday, mday;
1670 /* find first day in the month matching week day of the date */
1671 memset(&date, 0, sizeof(date));
1672 date.tm_year = year;
1673 date.tm_mon = mon;
1674 date.tm_mday = -1;
1675 date.tm_wday = -1;
1678 date.tm_mday++;
1679 tmp = mktime(&date);
1680 } while (date.tm_wday != day_of_week || date.tm_mon != mon);
1682 mday = date.tm_mday;
1684 /* find number of week days in the month matching week day of the date */
1685 wday = 1; /* 1 - 1st, ...., 5 - last */
1686 while (wday < day)
1688 struct tm *tm;
1690 date.tm_mday += 7;
1691 tmp = mktime(&date);
1692 tm = localtime(&tmp);
1693 if (tm->tm_mon != mon)
1694 break;
1695 mday = tm->tm_mday;
1696 wday++;
1699 return mday;
1702 static BOOL match_tz_date( const RTL_SYSTEM_TIME *st, const RTL_SYSTEM_TIME *reg_st )
1704 WORD wDay;
1706 if (st->wMonth != reg_st->wMonth) return FALSE;
1707 if (!st->wMonth) return TRUE; /* no transition dates */
1708 wDay = reg_st->wDay;
1709 if (!reg_st->wYear) /* date in a day-of-week format */
1710 wDay = weekday_to_mday(st->wYear - 1900, reg_st->wDay, reg_st->wMonth - 1, reg_st->wDayOfWeek);
1712 return (st->wDay == wDay &&
1713 st->wHour == reg_st->wHour &&
1714 st->wMinute == reg_st->wMinute &&
1715 st->wSecond == reg_st->wSecond &&
1716 st->wMilliseconds == reg_st->wMilliseconds);
1719 static BOOL match_tz_info( const RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi,
1720 const RTL_DYNAMIC_TIME_ZONE_INFORMATION *reg_tzi )
1722 return (tzi->Bias == reg_tzi->Bias &&
1723 match_tz_date(&tzi->StandardDate, &reg_tzi->StandardDate) &&
1724 match_tz_date(&tzi->DaylightDate, &reg_tzi->DaylightDate));
1727 static BOOL match_past_tz_bias( time_t past_time, LONG past_bias )
1729 LONG bias;
1730 struct tm *tm;
1731 if (!past_time) return TRUE;
1733 tm = gmtime( &past_time );
1734 bias = (LONG)(mktime(tm) - past_time) / 60;
1735 return bias == past_bias;
1738 static BOOL match_tz_name( const char *tz_name, const RTL_DYNAMIC_TIME_ZONE_INFORMATION *reg_tzi )
1740 static const struct {
1741 WCHAR key_name[32];
1742 const char *short_name;
1743 time_t past_time;
1744 LONG past_bias;
1746 mapping[] =
1748 { {'N','o','r','t','h',' ','K','o','r','e','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
1749 "KST", 1451606400 /* 2016-01-01 00:00:00 UTC */, -510 },
1750 { {'K','o','r','e','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
1751 "KST", 1451606400 /* 2016-01-01 00:00:00 UTC */, -540 },
1752 { {'T','o','k','y','o',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
1753 "JST" },
1754 { {'Y','a','k','u','t','s','k',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
1755 "+09" }, /* YAKST was used until tzdata 2016f */
1757 unsigned int i;
1759 if (reg_tzi->DaylightDate.wMonth) return TRUE;
1760 for (i = 0; i < ARRAY_SIZE(mapping); i++)
1762 if (!wcscmp( mapping[i].key_name, reg_tzi->TimeZoneKeyName ))
1763 return !strcmp( mapping[i].short_name, tz_name )
1764 && match_past_tz_bias( mapping[i].past_time, mapping[i].past_bias );
1766 return TRUE;
1769 static BOOL reg_query_value( HKEY key, LPCWSTR name, DWORD type, void *data, DWORD count )
1771 char buf[256];
1772 UNICODE_STRING nameW;
1773 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buf;
1775 if (count > sizeof(buf) - sizeof(KEY_VALUE_PARTIAL_INFORMATION)) return FALSE;
1777 nameW.Buffer = (WCHAR *)name;
1778 nameW.Length = wcslen( name ) * sizeof(WCHAR);
1779 if (NtQueryValueKey( key, &nameW, KeyValuePartialInformation, buf, sizeof(buf), &count ))
1780 return FALSE;
1782 if (info->Type != type) return FALSE;
1783 memcpy( data, info->Data, info->DataLength );
1784 return TRUE;
1787 static void find_reg_tz_info(RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi, const char* tz_name, int year)
1789 static const WCHAR stdW[] = { 'S','t','d',0 };
1790 static const WCHAR dltW[] = { 'D','l','t',0 };
1791 static const WCHAR mui_stdW[] = { 'M','U','I','_','S','t','d',0 };
1792 static const WCHAR mui_dltW[] = { 'M','U','I','_','D','l','t',0 };
1793 static const WCHAR tziW[] = { 'T','Z','I',0 };
1794 static const WCHAR Time_ZonesW[] = { 'M','a','c','h','i','n','e','\\',
1795 'S','o','f','t','w','a','r','e','\\',
1796 'M','i','c','r','o','s','o','f','t','\\',
1797 'W','i','n','d','o','w','s',' ','N','T','\\',
1798 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1799 'T','i','m','e',' ','Z','o','n','e','s',0 };
1800 static const WCHAR Dynamic_DstW[] = { 'D','y','n','a','m','i','c',' ','D','S','T',0 };
1801 RTL_DYNAMIC_TIME_ZONE_INFORMATION reg_tzi;
1802 HANDLE key, subkey, subkey_dyn = 0;
1803 ULONG idx, len;
1804 OBJECT_ATTRIBUTES attr;
1805 UNICODE_STRING nameW;
1806 WCHAR yearW[16];
1807 char buffer[128];
1808 KEY_BASIC_INFORMATION *info = (KEY_BASIC_INFORMATION *)buffer;
1810 sprintf( buffer, "%u", year );
1811 ascii_to_unicode( yearW, buffer, strlen(buffer) + 1 );
1813 nameW.Buffer = (WCHAR *)Time_ZonesW;
1814 nameW.Length = sizeof(Time_ZonesW) - sizeof(WCHAR);
1815 InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
1816 if (NtOpenKey( &key, KEY_READ, &attr )) return;
1818 idx = 0;
1819 while (!NtEnumerateKey( key, idx++, KeyBasicInformation, buffer, sizeof(buffer), &len ))
1821 struct tz_reg_data
1823 LONG bias;
1824 LONG std_bias;
1825 LONG dlt_bias;
1826 RTL_SYSTEM_TIME std_date;
1827 RTL_SYSTEM_TIME dlt_date;
1828 } tz_data;
1829 BOOL is_dynamic = FALSE;
1831 nameW.Buffer = info->Name;
1832 nameW.Length = info->NameLength;
1833 attr.RootDirectory = key;
1834 if (NtOpenKey( &subkey, KEY_READ, &attr )) continue;
1836 memset( &reg_tzi, 0, sizeof(reg_tzi) );
1837 memcpy(reg_tzi.TimeZoneKeyName, nameW.Buffer, nameW.Length);
1838 reg_tzi.TimeZoneKeyName[nameW.Length/sizeof(WCHAR)] = 0;
1840 if (!reg_query_value(subkey, mui_stdW, REG_SZ, reg_tzi.StandardName, sizeof(reg_tzi.StandardName)) &&
1841 !reg_query_value(subkey, stdW, REG_SZ, reg_tzi.StandardName, sizeof(reg_tzi.StandardName)))
1842 goto next;
1844 if (!reg_query_value(subkey, mui_dltW, REG_SZ, reg_tzi.DaylightName, sizeof(reg_tzi.DaylightName)) &&
1845 !reg_query_value(subkey, dltW, REG_SZ, reg_tzi.DaylightName, sizeof(reg_tzi.DaylightName)))
1846 goto next;
1848 /* Check for Dynamic DST entry first */
1849 nameW.Buffer = (WCHAR *)Dynamic_DstW;
1850 nameW.Length = sizeof(Dynamic_DstW) - sizeof(WCHAR);
1851 attr.RootDirectory = subkey;
1852 if (!NtOpenKey( &subkey_dyn, KEY_READ, &attr ))
1854 is_dynamic = reg_query_value( subkey_dyn, yearW, REG_BINARY, &tz_data, sizeof(tz_data) );
1855 NtClose( subkey_dyn );
1857 if (!is_dynamic && !reg_query_value( subkey, tziW, REG_BINARY, &tz_data, sizeof(tz_data) ))
1858 goto next;
1860 reg_tzi.Bias = tz_data.bias;
1861 reg_tzi.StandardBias = tz_data.std_bias;
1862 reg_tzi.DaylightBias = tz_data.dlt_bias;
1863 reg_tzi.StandardDate = tz_data.std_date;
1864 reg_tzi.DaylightDate = tz_data.dlt_date;
1866 TRACE("%s: bias %d\n", debugstr_us(&nameW), reg_tzi.Bias);
1867 TRACE("std (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
1868 reg_tzi.StandardDate.wDay, reg_tzi.StandardDate.wMonth,
1869 reg_tzi.StandardDate.wYear, reg_tzi.StandardDate.wDayOfWeek,
1870 reg_tzi.StandardDate.wHour, reg_tzi.StandardDate.wMinute,
1871 reg_tzi.StandardDate.wSecond, reg_tzi.StandardDate.wMilliseconds,
1872 reg_tzi.StandardBias);
1873 TRACE("dst (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
1874 reg_tzi.DaylightDate.wDay, reg_tzi.DaylightDate.wMonth,
1875 reg_tzi.DaylightDate.wYear, reg_tzi.DaylightDate.wDayOfWeek,
1876 reg_tzi.DaylightDate.wHour, reg_tzi.DaylightDate.wMinute,
1877 reg_tzi.DaylightDate.wSecond, reg_tzi.DaylightDate.wMilliseconds,
1878 reg_tzi.DaylightBias);
1880 if (match_tz_info( tzi, &reg_tzi ) && match_tz_name( tz_name, &reg_tzi ))
1882 *tzi = reg_tzi;
1883 NtClose( subkey );
1884 NtClose( key );
1885 return;
1887 next:
1888 NtClose( subkey );
1890 NtClose( key );
1892 if (idx == 1) return; /* registry info not initialized yet */
1894 FIXME("Can't find matching timezone information in the registry for "
1895 "%s, bias %d, std (d/m/y): %u/%02u/%04u, dlt (d/m/y): %u/%02u/%04u\n",
1896 tz_name, tzi->Bias,
1897 tzi->StandardDate.wDay, tzi->StandardDate.wMonth, tzi->StandardDate.wYear,
1898 tzi->DaylightDate.wDay, tzi->DaylightDate.wMonth, tzi->DaylightDate.wYear);
1901 static time_t find_dst_change(unsigned long min, unsigned long max, int *is_dst)
1903 time_t start;
1904 struct tm *tm;
1906 start = min;
1907 tm = localtime(&start);
1908 *is_dst = !tm->tm_isdst;
1909 TRACE("starting date isdst %d, %s", !*is_dst, ctime(&start));
1911 while (min <= max)
1913 time_t pos = (min + max) / 2;
1914 tm = localtime(&pos);
1916 if (tm->tm_isdst != *is_dst)
1917 min = pos + 1;
1918 else
1919 max = pos - 1;
1921 return min;
1924 static void get_timezone_info( RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi )
1926 static pthread_mutex_t tz_mutex = PTHREAD_MUTEX_INITIALIZER;
1927 static RTL_DYNAMIC_TIME_ZONE_INFORMATION cached_tzi;
1928 static int current_year = -1, current_bias = 65535;
1929 struct tm *tm;
1930 char tz_name[16];
1931 time_t year_start, year_end, tmp, dlt = 0, std = 0;
1932 int is_dst, bias;
1934 mutex_lock( &tz_mutex );
1936 year_start = time(NULL);
1937 tm = gmtime(&year_start);
1938 bias = (LONG)(mktime(tm) - year_start) / 60;
1940 tm = localtime(&year_start);
1941 if (current_year == tm->tm_year && current_bias == bias)
1943 *tzi = cached_tzi;
1944 mutex_unlock( &tz_mutex );
1945 return;
1948 memset(tzi, 0, sizeof(*tzi));
1949 if (!strftime(tz_name, sizeof(tz_name), "%Z", tm)) {
1950 /* not enough room or another error */
1951 tz_name[0] = '\0';
1954 TRACE("tz data will be valid through year %d, bias %d\n", tm->tm_year + 1900, bias);
1955 current_year = tm->tm_year;
1956 current_bias = bias;
1958 tzi->Bias = bias;
1960 tm->tm_isdst = 0;
1961 tm->tm_mday = 1;
1962 tm->tm_mon = tm->tm_hour = tm->tm_min = tm->tm_sec = tm->tm_wday = tm->tm_yday = 0;
1963 year_start = mktime(tm);
1964 TRACE("year_start: %s", ctime(&year_start));
1966 tm->tm_mday = tm->tm_wday = tm->tm_yday = 0;
1967 tm->tm_mon = 12;
1968 tm->tm_hour = 23;
1969 tm->tm_min = tm->tm_sec = 59;
1970 year_end = mktime(tm);
1971 TRACE("year_end: %s", ctime(&year_end));
1973 tmp = find_dst_change(year_start, year_end, &is_dst);
1974 if (is_dst)
1975 dlt = tmp;
1976 else
1977 std = tmp;
1979 tmp = find_dst_change(tmp, year_end, &is_dst);
1980 if (is_dst)
1981 dlt = tmp;
1982 else
1983 std = tmp;
1985 TRACE("std: %s", ctime(&std));
1986 TRACE("dlt: %s", ctime(&dlt));
1988 if (dlt == std || !dlt || !std)
1989 TRACE("there is no daylight saving rules in this time zone\n");
1990 else
1992 tmp = dlt - tzi->Bias * 60;
1993 tm = gmtime(&tmp);
1994 TRACE("dlt gmtime: %s", asctime(tm));
1996 tzi->DaylightBias = -60;
1997 tzi->DaylightDate.wYear = tm->tm_year + 1900;
1998 tzi->DaylightDate.wMonth = tm->tm_mon + 1;
1999 tzi->DaylightDate.wDayOfWeek = tm->tm_wday;
2000 tzi->DaylightDate.wDay = tm->tm_mday;
2001 tzi->DaylightDate.wHour = tm->tm_hour;
2002 tzi->DaylightDate.wMinute = tm->tm_min;
2003 tzi->DaylightDate.wSecond = tm->tm_sec;
2004 tzi->DaylightDate.wMilliseconds = 0;
2006 TRACE("daylight (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
2007 tzi->DaylightDate.wDay, tzi->DaylightDate.wMonth,
2008 tzi->DaylightDate.wYear, tzi->DaylightDate.wDayOfWeek,
2009 tzi->DaylightDate.wHour, tzi->DaylightDate.wMinute,
2010 tzi->DaylightDate.wSecond, tzi->DaylightDate.wMilliseconds,
2011 tzi->DaylightBias);
2013 tmp = std - tzi->Bias * 60 - tzi->DaylightBias * 60;
2014 tm = gmtime(&tmp);
2015 TRACE("std gmtime: %s", asctime(tm));
2017 tzi->StandardBias = 0;
2018 tzi->StandardDate.wYear = tm->tm_year + 1900;
2019 tzi->StandardDate.wMonth = tm->tm_mon + 1;
2020 tzi->StandardDate.wDayOfWeek = tm->tm_wday;
2021 tzi->StandardDate.wDay = tm->tm_mday;
2022 tzi->StandardDate.wHour = tm->tm_hour;
2023 tzi->StandardDate.wMinute = tm->tm_min;
2024 tzi->StandardDate.wSecond = tm->tm_sec;
2025 tzi->StandardDate.wMilliseconds = 0;
2027 TRACE("standard (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
2028 tzi->StandardDate.wDay, tzi->StandardDate.wMonth,
2029 tzi->StandardDate.wYear, tzi->StandardDate.wDayOfWeek,
2030 tzi->StandardDate.wHour, tzi->StandardDate.wMinute,
2031 tzi->StandardDate.wSecond, tzi->StandardDate.wMilliseconds,
2032 tzi->StandardBias);
2035 find_reg_tz_info(tzi, tz_name, current_year + 1900);
2036 cached_tzi = *tzi;
2037 mutex_unlock( &tz_mutex );
2041 /******************************************************************************
2042 * NtQuerySystemInformation (NTDLL.@)
2044 NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class,
2045 void *info, ULONG size, ULONG *ret_size )
2047 NTSTATUS ret = STATUS_SUCCESS;
2048 ULONG len = 0;
2050 TRACE( "(0x%08x,%p,0x%08x,%p)\n", class, info, size, ret_size );
2052 switch (class)
2054 case SystemBasicInformation:
2056 SYSTEM_BASIC_INFORMATION sbi;
2058 virtual_get_system_info( &sbi );
2059 len = sizeof(sbi);
2060 if (size == len)
2062 if (!info) ret = STATUS_ACCESS_VIOLATION;
2063 else memcpy( info, &sbi, len);
2065 else ret = STATUS_INFO_LENGTH_MISMATCH;
2066 break;
2069 case SystemCpuInformation:
2070 if (size >= (len = sizeof(cpu_info)))
2072 if (!info) ret = STATUS_ACCESS_VIOLATION;
2073 else memcpy(info, &cpu_info, len);
2075 else ret = STATUS_INFO_LENGTH_MISMATCH;
2076 break;
2078 case SystemPerformanceInformation:
2080 SYSTEM_PERFORMANCE_INFORMATION spi;
2081 static BOOL fixme_written = FALSE;
2083 get_performance_info( &spi );
2084 len = sizeof(spi);
2085 if (size >= len)
2087 if (!info) ret = STATUS_ACCESS_VIOLATION;
2088 else memcpy( info, &spi, len);
2090 else ret = STATUS_INFO_LENGTH_MISMATCH;
2091 if(!fixme_written) {
2092 FIXME("info_class SYSTEM_PERFORMANCE_INFORMATION\n");
2093 fixme_written = TRUE;
2095 break;
2098 case SystemTimeOfDayInformation:
2100 struct tm *tm;
2101 time_t now;
2102 SYSTEM_TIMEOFDAY_INFORMATION sti = {{{ 0 }}};
2104 sti.BootTime.QuadPart = server_start_time;
2105 now = time( NULL );
2106 tm = gmtime( &now );
2107 sti.TimeZoneBias.QuadPart = mktime( tm ) - now;
2108 tm = localtime( &now );
2109 if (tm->tm_isdst) sti.TimeZoneBias.QuadPart -= 3600;
2110 sti.TimeZoneBias.QuadPart *= TICKSPERSEC;
2111 NtQuerySystemTime( &sti.SystemTime );
2113 if (size <= sizeof(sti))
2115 len = size;
2116 if (!info) ret = STATUS_ACCESS_VIOLATION;
2117 else memcpy( info, &sti, size);
2119 else ret = STATUS_INFO_LENGTH_MISMATCH;
2120 break;
2123 case SystemProcessInformation:
2125 unsigned int process_count, i, j;
2126 char *buffer = NULL;
2127 unsigned int pos = 0;
2129 if (size && !(buffer = malloc( size )))
2131 ret = STATUS_NO_MEMORY;
2132 break;
2135 SERVER_START_REQ( list_processes )
2137 wine_server_set_reply( req, buffer, size );
2138 ret = wine_server_call( req );
2139 len = reply->info_size;
2140 process_count = reply->process_count;
2142 SERVER_END_REQ;
2144 if (ret)
2146 free( buffer );
2147 break;
2150 len = 0;
2152 for (i = 0; i < process_count; i++)
2154 SYSTEM_PROCESS_INFORMATION *nt_process = (SYSTEM_PROCESS_INFORMATION *)((char *)info + len);
2155 const struct process_info *server_process;
2156 const WCHAR *server_name, *file_part;
2157 ULONG proc_len;
2158 ULONG name_len = 0;
2160 pos = (pos + 7) & ~7;
2161 server_process = (const struct process_info *)(buffer + pos);
2162 pos += sizeof(*server_process);
2164 server_name = (const WCHAR *)(buffer + pos);
2165 file_part = server_name + (server_process->name_len / sizeof(WCHAR));
2166 pos += server_process->name_len;
2167 while (file_part > server_name && file_part[-1] != '\\')
2169 file_part--;
2170 name_len++;
2173 proc_len = sizeof(*nt_process) + server_process->thread_count * sizeof(SYSTEM_THREAD_INFORMATION)
2174 + (name_len + 1) * sizeof(WCHAR);
2175 len += proc_len;
2177 if (len <= size)
2179 memset(nt_process, 0, sizeof(*nt_process));
2180 if (i < process_count - 1)
2181 nt_process->NextEntryOffset = proc_len;
2182 nt_process->CreationTime.QuadPart = server_process->start_time;
2183 nt_process->dwThreadCount = server_process->thread_count;
2184 nt_process->dwBasePriority = server_process->priority;
2185 nt_process->UniqueProcessId = UlongToHandle(server_process->pid);
2186 nt_process->ParentProcessId = UlongToHandle(server_process->parent_pid);
2187 nt_process->HandleCount = server_process->handle_count;
2188 get_thread_times( server_process->unix_pid, -1, &nt_process->KernelTime, &nt_process->UserTime );
2189 fill_vm_counters( &nt_process->vmCounters, server_process->unix_pid );
2192 pos = (pos + 7) & ~7;
2193 for (j = 0; j < server_process->thread_count; j++)
2195 const struct thread_info *server_thread = (const struct thread_info *)(buffer + pos);
2197 if (len <= size)
2199 nt_process->ti[j].CreateTime.QuadPart = server_thread->start_time;
2200 nt_process->ti[j].ClientId.UniqueProcess = UlongToHandle(server_process->pid);
2201 nt_process->ti[j].ClientId.UniqueThread = UlongToHandle(server_thread->tid);
2202 nt_process->ti[j].dwCurrentPriority = server_thread->current_priority;
2203 nt_process->ti[j].dwBasePriority = server_thread->base_priority;
2204 get_thread_times( server_process->unix_pid, server_thread->unix_tid,
2205 &nt_process->ti[j].KernelTime, &nt_process->ti[j].UserTime );
2208 pos += sizeof(*server_thread);
2211 if (len <= size)
2213 nt_process->ProcessName.Buffer = (WCHAR *)&nt_process->ti[server_process->thread_count];
2214 nt_process->ProcessName.Length = name_len * sizeof(WCHAR);
2215 nt_process->ProcessName.MaximumLength = (name_len + 1) * sizeof(WCHAR);
2216 memcpy(nt_process->ProcessName.Buffer, file_part, name_len * sizeof(WCHAR));
2217 nt_process->ProcessName.Buffer[name_len] = 0;
2221 if (len > size) ret = STATUS_INFO_LENGTH_MISMATCH;
2222 free( buffer );
2223 break;
2226 case SystemProcessorPerformanceInformation:
2228 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL;
2229 unsigned int cpus = 0;
2230 int out_cpus = size / sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
2232 if (out_cpus == 0)
2234 len = 0;
2235 ret = STATUS_INFO_LENGTH_MISMATCH;
2236 break;
2238 if (!(sppi = calloc( out_cpus, sizeof(*sppi) )))
2240 ret = STATUS_NO_MEMORY;
2241 break;
2243 else
2244 #ifdef __APPLE__
2246 processor_cpu_load_info_data_t *pinfo;
2247 mach_msg_type_number_t info_count;
2249 if (host_processor_info( mach_host_self (),
2250 PROCESSOR_CPU_LOAD_INFO,
2251 &cpus,
2252 (processor_info_array_t*)&pinfo,
2253 &info_count) == 0)
2255 int i;
2256 cpus = min(cpus,out_cpus);
2257 for (i = 0; i < cpus; i++)
2259 sppi[i].IdleTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_IDLE];
2260 sppi[i].KernelTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_SYSTEM];
2261 sppi[i].UserTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_USER];
2263 vm_deallocate (mach_task_self (), (vm_address_t) pinfo, info_count * sizeof(natural_t));
2266 #else
2268 FILE *cpuinfo = fopen("/proc/stat", "r");
2269 if (cpuinfo)
2271 unsigned long clk_tck = sysconf(_SC_CLK_TCK);
2272 unsigned long usr,nice,sys,idle,remainder[8];
2273 int i, count, id;
2274 char name[32];
2275 char line[255];
2277 /* first line is combined usage */
2278 while (fgets(line,255,cpuinfo))
2280 count = sscanf(line, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
2281 name, &usr, &nice, &sys, &idle,
2282 &remainder[0], &remainder[1], &remainder[2], &remainder[3],
2283 &remainder[4], &remainder[5], &remainder[6], &remainder[7]);
2285 if (count < 5 || strncmp( name, "cpu", 3 )) break;
2286 for (i = 0; i + 5 < count; ++i) sys += remainder[i];
2287 sys += idle;
2288 usr += nice;
2289 id = atoi( name + 3 ) + 1;
2290 if (id > out_cpus) break;
2291 if (id > cpus) cpus = id;
2292 sppi[id-1].IdleTime.QuadPart = (ULONGLONG)idle * 10000000 / clk_tck;
2293 sppi[id-1].KernelTime.QuadPart = (ULONGLONG)sys * 10000000 / clk_tck;
2294 sppi[id-1].UserTime.QuadPart = (ULONGLONG)usr * 10000000 / clk_tck;
2296 fclose(cpuinfo);
2299 #endif
2300 if (cpus == 0)
2302 static int i = 1;
2303 unsigned int n;
2304 cpus = min(NtCurrentTeb()->Peb->NumberOfProcessors, out_cpus);
2305 FIXME("stub info_class SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION\n");
2306 /* many programs expect these values to change so fake change */
2307 for (n = 0; n < cpus; n++)
2309 sppi[n].KernelTime.QuadPart = 1 * i;
2310 sppi[n].UserTime.QuadPart = 2 * i;
2311 sppi[n].IdleTime.QuadPart = 3 * i;
2313 i++;
2316 len = sizeof(*sppi) * cpus;
2317 if (size >= len)
2319 if (!info) ret = STATUS_ACCESS_VIOLATION;
2320 else memcpy( info, sppi, len);
2322 else ret = STATUS_INFO_LENGTH_MISMATCH;
2324 free( sppi );
2325 break;
2328 case SystemModuleInformation:
2330 /* FIXME: return some fake info for now */
2331 static const char *fake_modules[] =
2333 "\\SystemRoot\\system32\\ntoskrnl.exe",
2334 "\\SystemRoot\\system32\\hal.dll",
2335 "\\SystemRoot\\system32\\drivers\\mountmgr.sys"
2338 ULONG i;
2339 SYSTEM_MODULE_INFORMATION *smi = info;
2341 len = offsetof( SYSTEM_MODULE_INFORMATION, Modules[ARRAY_SIZE(fake_modules)] );
2342 if (len <= size)
2344 memset( smi, 0, len );
2345 for (i = 0; i < ARRAY_SIZE(fake_modules); i++)
2347 SYSTEM_MODULE *sm = &smi->Modules[i];
2348 sm->ImageBaseAddress = (char *)0x10000000 + 0x200000 * i;
2349 sm->ImageSize = 0x200000;
2350 sm->LoadOrderIndex = i;
2351 sm->LoadCount = 1;
2352 strcpy( (char *)sm->Name, fake_modules[i] );
2353 sm->NameOffset = strrchr( fake_modules[i], '\\' ) - fake_modules[i] + 1;
2355 smi->ModulesCount = i;
2357 else ret = STATUS_INFO_LENGTH_MISMATCH;
2359 break;
2362 case SystemModuleInformationEx:
2364 /* FIXME: return some fake info for now */
2365 static const char *fake_modules[] =
2367 "\\SystemRoot\\system32\\ntoskrnl.exe",
2368 "\\SystemRoot\\system32\\hal.dll",
2369 "\\SystemRoot\\system32\\drivers\\mountmgr.sys"
2372 ULONG i;
2373 RTL_PROCESS_MODULE_INFORMATION_EX *module_info = info;
2375 len = sizeof(*module_info) * ARRAY_SIZE(fake_modules) + sizeof(module_info->NextOffset);
2376 if (len <= size)
2378 memset( info, 0, len );
2379 for (i = 0; i < ARRAY_SIZE(fake_modules); i++)
2381 SYSTEM_MODULE *sm = &module_info[i].BaseInfo;
2382 sm->ImageBaseAddress = (char *)0x10000000 + 0x200000 * i;
2383 sm->ImageSize = 0x200000;
2384 sm->LoadOrderIndex = i;
2385 sm->LoadCount = 1;
2386 strcpy( (char *)sm->Name, fake_modules[i] );
2387 sm->NameOffset = strrchr( fake_modules[i], '\\' ) - fake_modules[i] + 1;
2388 module_info[i].NextOffset = sizeof(*module_info);
2390 module_info[ARRAY_SIZE(fake_modules)].NextOffset = 0;
2392 else ret = STATUS_INFO_LENGTH_MISMATCH;
2394 break;
2397 case SystemHandleInformation:
2399 struct handle_info *handle_info;
2400 DWORD i, num_handles;
2402 if (size < sizeof(SYSTEM_HANDLE_INFORMATION))
2404 ret = STATUS_INFO_LENGTH_MISMATCH;
2405 break;
2408 if (!info)
2410 ret = STATUS_ACCESS_VIOLATION;
2411 break;
2414 num_handles = (size - FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle )) / sizeof(SYSTEM_HANDLE_ENTRY);
2415 if (!(handle_info = malloc( sizeof(*handle_info) * num_handles ))) return STATUS_NO_MEMORY;
2417 SERVER_START_REQ( get_system_handles )
2419 wine_server_set_reply( req, handle_info, sizeof(*handle_info) * num_handles );
2420 if (!(ret = wine_server_call( req )))
2422 SYSTEM_HANDLE_INFORMATION *shi = info;
2423 shi->Count = wine_server_reply_size( req ) / sizeof(*handle_info);
2424 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle[shi->Count] );
2425 for (i = 0; i < shi->Count; i++)
2427 memset( &shi->Handle[i], 0, sizeof(shi->Handle[i]) );
2428 shi->Handle[i].OwnerPid = handle_info[i].owner;
2429 shi->Handle[i].HandleValue = handle_info[i].handle;
2430 shi->Handle[i].AccessMask = handle_info[i].access;
2431 shi->Handle[i].HandleFlags = handle_info[i].attributes;
2432 shi->Handle[i].ObjectType = handle_info[i].type;
2433 /* FIXME: Fill out ObjectPointer */
2436 else if (ret == STATUS_BUFFER_TOO_SMALL)
2438 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle[reply->count] );
2439 ret = STATUS_INFO_LENGTH_MISMATCH;
2442 SERVER_END_REQ;
2444 free( handle_info );
2445 break;
2448 case SystemExtendedHandleInformation:
2450 struct handle_info *handle_info;
2451 DWORD i, num_handles;
2453 if (size < sizeof(SYSTEM_HANDLE_INFORMATION_EX))
2455 ret = STATUS_INFO_LENGTH_MISMATCH;
2456 break;
2459 if (!info)
2461 ret = STATUS_ACCESS_VIOLATION;
2462 break;
2465 num_handles = (size - FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handles ))
2466 / sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX);
2467 if (!(handle_info = malloc( sizeof(*handle_info) * num_handles ))) return STATUS_NO_MEMORY;
2469 SERVER_START_REQ( get_system_handles )
2471 wine_server_set_reply( req, handle_info, sizeof(*handle_info) * num_handles );
2472 if (!(ret = wine_server_call( req )))
2474 SYSTEM_HANDLE_INFORMATION_EX *shi = info;
2475 shi->NumberOfHandles = wine_server_reply_size( req ) / sizeof(*handle_info);
2476 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handles[shi->NumberOfHandles] );
2477 for (i = 0; i < shi->NumberOfHandles; i++)
2479 memset( &shi->Handles[i], 0, sizeof(shi->Handles[i]) );
2480 shi->Handles[i].UniqueProcessId = handle_info[i].owner;
2481 shi->Handles[i].HandleValue = handle_info[i].handle;
2482 shi->Handles[i].GrantedAccess = handle_info[i].access;
2483 shi->Handles[i].HandleAttributes = handle_info[i].attributes;
2484 shi->Handles[i].ObjectTypeIndex = handle_info[i].type;
2485 /* FIXME: Fill out Object */
2488 else if (ret == STATUS_BUFFER_TOO_SMALL)
2490 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handles[reply->count] );
2491 ret = STATUS_INFO_LENGTH_MISMATCH;
2494 SERVER_END_REQ;
2496 free( handle_info );
2497 break;
2500 case SystemCacheInformation:
2502 SYSTEM_CACHE_INFORMATION sci = { 0 };
2504 len = sizeof(sci);
2505 if (size >= len)
2507 if (!info) ret = STATUS_ACCESS_VIOLATION;
2508 else memcpy( info, &sci, len);
2510 else ret = STATUS_INFO_LENGTH_MISMATCH;
2511 FIXME("info_class SYSTEM_CACHE_INFORMATION\n");
2512 break;
2515 case SystemInterruptInformation:
2517 len = NtCurrentTeb()->Peb->NumberOfProcessors * sizeof(SYSTEM_INTERRUPT_INFORMATION);
2518 if (size >= len)
2520 if (!info) ret = STATUS_ACCESS_VIOLATION;
2521 else
2523 #ifdef HAVE_GETRANDOM
2524 int ret;
2527 ret = getrandom( info, len, 0 );
2529 while (ret == -1 && errno == EINTR);
2530 #else
2531 int fd = open( "/dev/urandom", O_RDONLY );
2532 if (fd != -1)
2534 int ret;
2537 ret = read( fd, info, len );
2539 while (ret == -1 && errno == EINTR);
2540 close( fd );
2542 else WARN( "can't open /dev/urandom\n" );
2543 #endif
2546 else ret = STATUS_INFO_LENGTH_MISMATCH;
2547 break;
2550 case SystemTimeAdjustmentInformation:
2552 SYSTEM_TIME_ADJUSTMENT_QUERY query = { 156250, 156250, TRUE };
2554 len = sizeof(query);
2555 if (size == len)
2557 if (!info) ret = STATUS_ACCESS_VIOLATION;
2558 else memcpy( info, &query, len );
2560 else ret = STATUS_INFO_LENGTH_MISMATCH;
2561 break;
2564 case SystemKernelDebuggerInformation:
2566 SYSTEM_KERNEL_DEBUGGER_INFORMATION skdi;
2568 skdi.DebuggerEnabled = FALSE;
2569 skdi.DebuggerNotPresent = TRUE;
2570 len = sizeof(skdi);
2571 if (size >= len)
2573 if (!info) ret = STATUS_ACCESS_VIOLATION;
2574 else memcpy( info, &skdi, len);
2576 else ret = STATUS_INFO_LENGTH_MISMATCH;
2577 break;
2580 case SystemRegistryQuotaInformation:
2582 /* Something to do with the size of the registry *
2583 * Since we don't have a size limitation, fake it *
2584 * This is almost certainly wrong. *
2585 * This sets each of the three words in the struct to 32 MB, *
2586 * which is enough to make the IE 5 installer happy. */
2587 SYSTEM_REGISTRY_QUOTA_INFORMATION srqi;
2589 srqi.RegistryQuotaAllowed = 0x2000000;
2590 srqi.RegistryQuotaUsed = 0x200000;
2591 srqi.Reserved1 = (void*)0x200000;
2592 len = sizeof(srqi);
2594 if (size >= len)
2596 if (!info) ret = STATUS_ACCESS_VIOLATION;
2597 else
2599 FIXME("SystemRegistryQuotaInformation: faking max registry size of 32 MB\n");
2600 memcpy( info, &srqi, len);
2603 else ret = STATUS_INFO_LENGTH_MISMATCH;
2604 break;
2607 case SystemTimeZoneInformation:
2609 RTL_DYNAMIC_TIME_ZONE_INFORMATION tz;
2611 get_timezone_info( &tz );
2612 len = sizeof(RTL_TIME_ZONE_INFORMATION);
2613 if (size >= len)
2615 if (!info) ret = STATUS_ACCESS_VIOLATION;
2616 else memcpy( info, &tz, len);
2618 else ret = STATUS_INFO_LENGTH_MISMATCH;
2619 break;
2622 case SystemLogicalProcessorInformation:
2624 SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buf;
2626 /* Each logical processor may use up to 7 entries in returned table:
2627 * core, numa node, package, L1i, L1d, L2, L3 */
2628 len = 7 * NtCurrentTeb()->Peb->NumberOfProcessors;
2629 buf = malloc( len * sizeof(*buf) );
2630 if (!buf)
2632 ret = STATUS_NO_MEMORY;
2633 break;
2635 ret = create_logical_proc_info(&buf, NULL, &len, RelationAll);
2636 if (!ret)
2638 if (size >= len)
2640 if (!info) ret = STATUS_ACCESS_VIOLATION;
2641 else memcpy( info, buf, len);
2643 else ret = STATUS_INFO_LENGTH_MISMATCH;
2645 free( buf );
2646 break;
2649 case SystemRecommendedSharedDataAlignment:
2651 len = sizeof(DWORD);
2652 if (size >= len)
2654 if (!info) ret = STATUS_ACCESS_VIOLATION;
2655 else
2657 #ifdef __arm__
2658 *((DWORD *)info) = 32;
2659 #else
2660 *((DWORD *)info) = 64;
2661 #endif
2664 else ret = STATUS_INFO_LENGTH_MISMATCH;
2665 break;
2668 case SystemFirmwareTableInformation:
2670 SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti = info;
2671 len = FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
2672 if (size < len)
2674 ret = STATUS_INFO_LENGTH_MISMATCH;
2675 break;
2678 switch (sfti->Action)
2680 case SystemFirmwareTable_Get:
2681 ret = get_firmware_info(sfti, size, &len);
2682 break;
2683 default:
2684 len = 0;
2685 ret = STATUS_NOT_IMPLEMENTED;
2686 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION action %d\n", sfti->Action);
2688 break;
2691 case SystemDynamicTimeZoneInformation:
2693 RTL_DYNAMIC_TIME_ZONE_INFORMATION tz;
2695 get_timezone_info( &tz );
2696 len = sizeof(tz);
2697 if (size >= len)
2699 if (!info) ret = STATUS_ACCESS_VIOLATION;
2700 else memcpy( info, &tz, len);
2702 else ret = STATUS_INFO_LENGTH_MISMATCH;
2703 break;
2706 case SystemExtendedProcessInformation:
2707 FIXME("SystemExtendedProcessInformation, size %u, info %p, stub!\n", size, info);
2708 memset( info, 0, size );
2709 ret = STATUS_SUCCESS;
2710 break;
2712 default:
2713 FIXME( "(0x%08x,%p,0x%08x,%p) stub\n", class, info, size, ret_size );
2715 /* Several Information Classes are not implemented on Windows and return 2 different values
2716 * STATUS_NOT_IMPLEMENTED or STATUS_INVALID_INFO_CLASS
2717 * in 95% of the cases it's STATUS_INVALID_INFO_CLASS, so use this as the default
2719 ret = STATUS_INVALID_INFO_CLASS;
2722 if (ret_size) *ret_size = len;
2723 return ret;
2727 /******************************************************************************
2728 * NtQuerySystemInformationEx (NTDLL.@)
2730 NTSTATUS WINAPI NtQuerySystemInformationEx( SYSTEM_INFORMATION_CLASS class,
2731 void *query, ULONG query_len,
2732 void *info, ULONG size, ULONG *ret_size )
2734 ULONG len = 0;
2735 NTSTATUS ret = STATUS_NOT_IMPLEMENTED;
2737 TRACE( "(0x%08x,%p,%u,%p,%u,%p) stub\n", class, query, query_len, info, size, ret_size );
2739 switch (class)
2741 case SystemLogicalProcessorInformationEx:
2743 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buf;
2745 if (!query || query_len < sizeof(DWORD))
2747 ret = STATUS_INVALID_PARAMETER;
2748 break;
2751 len = 3 * sizeof(*buf);
2752 if (!(buf = malloc( len )))
2754 ret = STATUS_NO_MEMORY;
2755 break;
2757 ret = create_logical_proc_info(NULL, &buf, &len, *(DWORD *)query);
2758 if (!ret)
2760 if (size >= len)
2762 if (!info) ret = STATUS_ACCESS_VIOLATION;
2763 else memcpy(info, buf, len);
2765 else ret = STATUS_INFO_LENGTH_MISMATCH;
2767 free( buf );
2768 break;
2771 default:
2772 FIXME( "(0x%08x,%p,%u,%p,%u,%p) stub\n", class, query, query_len, info, size, ret_size );
2773 break;
2775 if (ret_size) *ret_size = len;
2776 return ret;
2780 /******************************************************************************
2781 * NtSetSystemInformation (NTDLL.@)
2783 NTSTATUS WINAPI NtSetSystemInformation( SYSTEM_INFORMATION_CLASS class, void *info, ULONG length )
2785 FIXME( "(0x%08x,%p,0x%08x) stub\n", class, info, length );
2786 return STATUS_SUCCESS;
2790 /******************************************************************************
2791 * NtQuerySystemEnvironmentValue (NTDLL.@)
2793 NTSTATUS WINAPI NtQuerySystemEnvironmentValue( UNICODE_STRING *name, WCHAR *buffer, ULONG length,
2794 ULONG *retlen )
2796 FIXME( "(%s, %p, %u, %p), stub\n", debugstr_us(name), buffer, length, retlen );
2797 return STATUS_NOT_IMPLEMENTED;
2801 /******************************************************************************
2802 * NtQuerySystemEnvironmentValueEx (NTDLL.@)
2804 NTSTATUS WINAPI NtQuerySystemEnvironmentValueEx( UNICODE_STRING *name, GUID *vendor, void *buffer,
2805 ULONG *retlen, ULONG *attrib )
2807 FIXME( "(%s, %s, %p, %p, %p), stub\n", debugstr_us(name),
2808 debugstr_guid(vendor), buffer, retlen, attrib );
2809 return STATUS_NOT_IMPLEMENTED;
2813 /******************************************************************************
2814 * NtSystemDebugControl (NTDLL.@)
2816 NTSTATUS WINAPI NtSystemDebugControl( SYSDBG_COMMAND command, void *in_buff, ULONG in_len,
2817 void *out_buff, ULONG out_len, ULONG *retlen )
2819 FIXME( "(%d, %p, %d, %p, %d, %p), stub\n", command, in_buff, in_len, out_buff, out_len, retlen );
2820 return STATUS_NOT_IMPLEMENTED;
2824 /******************************************************************************
2825 * NtShutdownSystem (NTDLL.@)
2827 NTSTATUS WINAPI NtShutdownSystem( SHUTDOWN_ACTION action )
2829 FIXME( "%d\n", action );
2830 return STATUS_SUCCESS;
2834 #ifdef linux
2836 /* Fallback using /proc/cpuinfo for Linux systems without cpufreq. For
2837 * most distributions on recent enough hardware, this is only likely to
2838 * happen while running in virtualized environments such as QEMU. */
2839 static ULONG mhz_from_cpuinfo(void)
2841 char line[512];
2842 char *s, *value;
2843 double cmz = 0;
2844 FILE *f = fopen("/proc/cpuinfo", "r");
2845 if(f)
2847 while (fgets(line, sizeof(line), f) != NULL)
2849 if (!(value = strchr(line,':'))) continue;
2850 s = value - 1;
2851 while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
2852 s[1] = 0;
2853 value++;
2854 if (!strcmp( line, "cpu MHz" ))
2856 sscanf(value, " %lf", &cmz);
2857 break;
2860 fclose( f );
2862 return cmz;
2865 static const char * get_sys_str(const char *path, char *s)
2867 FILE *f = fopen(path, "r");
2868 const char *ret = NULL;
2870 if (f)
2872 if (fgets(s, 16, f)) ret = s;
2873 fclose(f);
2875 return ret;
2878 static int get_sys_int(const char *path, int def)
2880 char s[16];
2881 return get_sys_str(path, s) ? atoi(s) : def;
2884 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
2886 char s[16], path[64];
2887 unsigned int i = 0;
2888 LONG64 voltage; /* microvolts */
2890 bs->AcOnLine = get_sys_int("/sys/class/power_supply/AC/online", 1);
2892 for (;;)
2894 sprintf(path, "/sys/class/power_supply/BAT%u/status", i);
2895 if (!get_sys_str(path, s)) break;
2896 bs->Charging |= (strcmp(s, "Charging\n") == 0);
2897 bs->Discharging |= (strcmp(s, "Discharging\n") == 0);
2898 bs->BatteryPresent = TRUE;
2899 i++;
2902 if (bs->BatteryPresent)
2904 voltage = get_sys_int("/sys/class/power_supply/BAT0/voltage_now", 0);
2905 bs->MaxCapacity = get_sys_int("/sys/class/power_supply/BAT0/charge_full", 0) * voltage / 1e9;
2906 bs->RemainingCapacity = get_sys_int("/sys/class/power_supply/BAT0/charge_now", 0) * voltage / 1e9;
2907 bs->Rate = -get_sys_int("/sys/class/power_supply/BAT0/current_now", 0) * voltage / 1e9;
2908 if (!bs->Charging && (LONG)bs->Rate < 0)
2909 bs->EstimatedTime = 3600 * bs->RemainingCapacity / -(LONG)bs->Rate;
2910 else
2911 bs->EstimatedTime = ~0u;
2914 return STATUS_SUCCESS;
2917 #elif defined(HAVE_IOKIT_IOKITLIB_H)
2919 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
2921 CFArrayRef batteries;
2922 CFDictionaryRef battery;
2923 CFNumberRef prop;
2924 uint32_t value, voltage;
2925 CFTimeInterval remain;
2927 if (IOPMCopyBatteryInfo( kIOMasterPortDefault, &batteries ) != kIOReturnSuccess)
2928 return STATUS_ACCESS_DENIED;
2930 if (CFArrayGetCount( batteries ) == 0)
2932 /* Just assume we're on AC with no battery. */
2933 bs->AcOnLine = TRUE;
2934 return STATUS_SUCCESS;
2936 /* Just use the first battery. */
2937 battery = CFArrayGetValueAtIndex( batteries, 0 );
2939 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryFlagsKey) );
2940 CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
2942 if (value & kIOBatteryInstalled)
2943 bs->BatteryPresent = TRUE;
2944 else
2945 /* Since we are executing code, we must have AC power. */
2946 bs->AcOnLine = TRUE;
2947 if (value & kIOBatteryChargerConnect)
2949 bs->AcOnLine = TRUE;
2950 if (value & kIOBatteryCharge)
2951 bs->Charging = TRUE;
2953 else
2954 bs->Discharging = TRUE;
2956 /* We'll need the voltage to be able to interpret the other values. */
2957 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryVoltageKey) );
2958 CFNumberGetValue( prop, kCFNumberSInt32Type, &voltage );
2960 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryCapacityKey) );
2961 CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
2962 bs->MaxCapacity = value * voltage;
2963 /* Apple uses "estimated time < 10:00" and "22%" for these, but we'll follow
2964 * Windows for now (5% and 33%). */
2965 bs->DefaultAlert1 = bs->MaxCapacity / 20;
2966 bs->DefaultAlert2 = bs->MaxCapacity / 3;
2968 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryCurrentChargeKey) );
2969 CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
2970 bs->RemainingCapacity = value * voltage;
2972 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryAmperageKey) );
2973 CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
2974 bs->Rate = value * voltage;
2976 remain = IOPSGetTimeRemainingEstimate();
2977 if (remain != kIOPSTimeRemainingUnknown && remain != kIOPSTimeRemainingUnlimited)
2978 bs->EstimatedTime = (ULONG)remain;
2980 CFRelease( batteries );
2981 return STATUS_SUCCESS;
2984 #else
2986 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
2988 FIXME("SystemBatteryState not implemented on this platform\n");
2989 return STATUS_NOT_IMPLEMENTED;
2992 #endif
2994 /******************************************************************************
2995 * NtPowerInformation (NTDLL.@)
2997 NTSTATUS WINAPI NtPowerInformation( POWER_INFORMATION_LEVEL level, void *input, ULONG in_size,
2998 void *output, ULONG out_size )
3000 TRACE( "(%d,%p,%d,%p,%d)\n", level, input, in_size, output, out_size );
3001 switch (level)
3003 case SystemPowerCapabilities:
3005 PSYSTEM_POWER_CAPABILITIES PowerCaps = output;
3006 FIXME("semi-stub: SystemPowerCapabilities\n");
3007 if (out_size < sizeof(SYSTEM_POWER_CAPABILITIES)) return STATUS_BUFFER_TOO_SMALL;
3008 /* FIXME: These values are based off a native XP desktop, should probably use APM/ACPI to get the 'real' values */
3009 PowerCaps->PowerButtonPresent = TRUE;
3010 PowerCaps->SleepButtonPresent = FALSE;
3011 PowerCaps->LidPresent = FALSE;
3012 PowerCaps->SystemS1 = TRUE;
3013 PowerCaps->SystemS2 = FALSE;
3014 PowerCaps->SystemS3 = FALSE;
3015 PowerCaps->SystemS4 = TRUE;
3016 PowerCaps->SystemS5 = TRUE;
3017 PowerCaps->HiberFilePresent = TRUE;
3018 PowerCaps->FullWake = TRUE;
3019 PowerCaps->VideoDimPresent = FALSE;
3020 PowerCaps->ApmPresent = FALSE;
3021 PowerCaps->UpsPresent = FALSE;
3022 PowerCaps->ThermalControl = FALSE;
3023 PowerCaps->ProcessorThrottle = FALSE;
3024 PowerCaps->ProcessorMinThrottle = 100;
3025 PowerCaps->ProcessorMaxThrottle = 100;
3026 PowerCaps->DiskSpinDown = TRUE;
3027 PowerCaps->SystemBatteriesPresent = FALSE;
3028 PowerCaps->BatteriesAreShortTerm = FALSE;
3029 PowerCaps->BatteryScale[0].Granularity = 0;
3030 PowerCaps->BatteryScale[0].Capacity = 0;
3031 PowerCaps->BatteryScale[1].Granularity = 0;
3032 PowerCaps->BatteryScale[1].Capacity = 0;
3033 PowerCaps->BatteryScale[2].Granularity = 0;
3034 PowerCaps->BatteryScale[2].Capacity = 0;
3035 PowerCaps->AcOnLineWake = PowerSystemUnspecified;
3036 PowerCaps->SoftLidWake = PowerSystemUnspecified;
3037 PowerCaps->RtcWake = PowerSystemSleeping1;
3038 PowerCaps->MinDeviceWakeState = PowerSystemUnspecified;
3039 PowerCaps->DefaultLowLatencyWake = PowerSystemUnspecified;
3040 return STATUS_SUCCESS;
3043 case SystemBatteryState:
3045 if (out_size < sizeof(SYSTEM_BATTERY_STATE)) return STATUS_BUFFER_TOO_SMALL;
3046 memset(output, 0, sizeof(SYSTEM_BATTERY_STATE));
3047 return fill_battery_state(output);
3050 case SystemExecutionState:
3052 ULONG *state = output;
3053 WARN("semi-stub: SystemExecutionState\n"); /* Needed for .NET Framework, but using a FIXME is really noisy. */
3054 if (input != NULL) return STATUS_INVALID_PARAMETER;
3055 /* FIXME: The actual state should be the value set by SetThreadExecutionState which is not currently implemented. */
3056 *state = ES_USER_PRESENT;
3057 return STATUS_SUCCESS;
3060 case ProcessorInformation:
3062 const int cannedMHz = 1000; /* We fake a 1GHz processor if we can't conjure up real values */
3063 PROCESSOR_POWER_INFORMATION* cpu_power = output;
3064 int i, out_cpus;
3066 if ((output == NULL) || (out_size == 0)) return STATUS_INVALID_PARAMETER;
3067 out_cpus = NtCurrentTeb()->Peb->NumberOfProcessors;
3068 if ((out_size / sizeof(PROCESSOR_POWER_INFORMATION)) < out_cpus) return STATUS_BUFFER_TOO_SMALL;
3069 #if defined(linux)
3071 char filename[128];
3072 FILE* f;
3074 for(i = 0; i < out_cpus; i++) {
3075 sprintf(filename, "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", i);
3076 f = fopen(filename, "r");
3077 if (f && (fscanf(f, "%d", &cpu_power[i].MaxMhz) == 1)) {
3078 cpu_power[i].MaxMhz /= 1000;
3079 fclose(f);
3080 cpu_power[i].CurrentMhz = cpu_power[i].MaxMhz;
3082 else {
3083 if(i == 0) {
3084 cpu_power[0].CurrentMhz = mhz_from_cpuinfo();
3085 if(cpu_power[0].CurrentMhz == 0)
3086 cpu_power[0].CurrentMhz = cannedMHz;
3088 else
3089 cpu_power[i].CurrentMhz = cpu_power[0].CurrentMhz;
3090 cpu_power[i].MaxMhz = cpu_power[i].CurrentMhz;
3091 if(f) fclose(f);
3094 sprintf(filename, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", i);
3095 f = fopen(filename, "r");
3096 if(f && (fscanf(f, "%d", &cpu_power[i].MhzLimit) == 1)) {
3097 cpu_power[i].MhzLimit /= 1000;
3098 fclose(f);
3100 else
3102 cpu_power[i].MhzLimit = cpu_power[i].MaxMhz;
3103 if(f) fclose(f);
3106 cpu_power[i].Number = i;
3107 cpu_power[i].MaxIdleState = 0; /* FIXME */
3108 cpu_power[i].CurrentIdleState = 0; /* FIXME */
3111 #elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__)
3113 int num;
3114 size_t valSize = sizeof(num);
3115 if (sysctlbyname("hw.clockrate", &num, &valSize, NULL, 0))
3116 num = cannedMHz;
3117 for(i = 0; i < out_cpus; i++) {
3118 cpu_power[i].CurrentMhz = num;
3119 cpu_power[i].MaxMhz = num;
3120 cpu_power[i].MhzLimit = num;
3121 cpu_power[i].Number = i;
3122 cpu_power[i].MaxIdleState = 0; /* FIXME */
3123 cpu_power[i].CurrentIdleState = 0; /* FIXME */
3126 #elif defined (__APPLE__)
3128 size_t valSize;
3129 unsigned long long currentMhz;
3130 unsigned long long maxMhz;
3132 valSize = sizeof(currentMhz);
3133 if (!sysctlbyname("hw.cpufrequency", &currentMhz, &valSize, NULL, 0))
3134 currentMhz /= 1000000;
3135 else
3136 currentMhz = cannedMHz;
3138 valSize = sizeof(maxMhz);
3139 if (!sysctlbyname("hw.cpufrequency_max", &maxMhz, &valSize, NULL, 0))
3140 maxMhz /= 1000000;
3141 else
3142 maxMhz = currentMhz;
3144 for(i = 0; i < out_cpus; i++) {
3145 cpu_power[i].CurrentMhz = currentMhz;
3146 cpu_power[i].MaxMhz = maxMhz;
3147 cpu_power[i].MhzLimit = maxMhz;
3148 cpu_power[i].Number = i;
3149 cpu_power[i].MaxIdleState = 0; /* FIXME */
3150 cpu_power[i].CurrentIdleState = 0; /* FIXME */
3153 #else
3154 for(i = 0; i < out_cpus; i++) {
3155 cpu_power[i].CurrentMhz = cannedMHz;
3156 cpu_power[i].MaxMhz = cannedMHz;
3157 cpu_power[i].MhzLimit = cannedMHz;
3158 cpu_power[i].Number = i;
3159 cpu_power[i].MaxIdleState = 0; /* FIXME */
3160 cpu_power[i].CurrentIdleState = 0; /* FIXME */
3162 WARN("Unable to detect CPU MHz for this platform. Reporting %d MHz.\n", cannedMHz);
3163 #endif
3164 for(i = 0; i < out_cpus; i++) {
3165 TRACE("cpu_power[%d] = %u %u %u %u %u %u\n", i, cpu_power[i].Number,
3166 cpu_power[i].MaxMhz, cpu_power[i].CurrentMhz, cpu_power[i].MhzLimit,
3167 cpu_power[i].MaxIdleState, cpu_power[i].CurrentIdleState);
3169 return STATUS_SUCCESS;
3172 default:
3173 /* FIXME: Needed by .NET Framework */
3174 WARN( "Unimplemented NtPowerInformation action: %d\n", level );
3175 return STATUS_NOT_IMPLEMENTED;
3180 /******************************************************************************
3181 * NtLoadDriver (NTDLL.@)
3183 NTSTATUS WINAPI NtLoadDriver( const UNICODE_STRING *name )
3185 FIXME( "(%s), stub!\n", debugstr_us(name) );
3186 return STATUS_NOT_IMPLEMENTED;
3190 /******************************************************************************
3191 * NtUnloadDriver (NTDLL.@)
3193 NTSTATUS WINAPI NtUnloadDriver( const UNICODE_STRING *name )
3195 FIXME( "(%s), stub!\n", debugstr_us(name) );
3196 return STATUS_NOT_IMPLEMENTED;
3200 /******************************************************************************
3201 * NtDisplayString (NTDLL.@)
3203 NTSTATUS WINAPI NtDisplayString( UNICODE_STRING *string )
3205 ERR( "%s\n", debugstr_us(string) );
3206 return STATUS_SUCCESS;
3210 /******************************************************************************
3211 * NtRaiseHardError (NTDLL.@)
3213 NTSTATUS WINAPI NtRaiseHardError( NTSTATUS status, ULONG count,
3214 UNICODE_STRING *params_mask, void **params,
3215 HARDERROR_RESPONSE_OPTION option, HARDERROR_RESPONSE *response )
3217 FIXME( "%08x stub\n", status );
3218 return STATUS_NOT_IMPLEMENTED;
3222 /******************************************************************************
3223 * NtInitiatePowerAction (NTDLL.@)
3225 NTSTATUS WINAPI NtInitiatePowerAction( POWER_ACTION action, SYSTEM_POWER_STATE state,
3226 ULONG flags, BOOLEAN async )
3228 FIXME( "(%d,%d,0x%08x,%d),stub\n", action, state, flags, async );
3229 return STATUS_NOT_IMPLEMENTED;
3233 /******************************************************************************
3234 * NtCreatePowerRequest (NTDLL.@)
3236 NTSTATUS WINAPI NtCreatePowerRequest( HANDLE *handle, COUNTED_REASON_CONTEXT *context )
3238 FIXME( "(%p, %p): stub\n", handle, context );
3239 return STATUS_NOT_IMPLEMENTED;
3243 /******************************************************************************
3244 * NtSetPowerRequest (NTDLL.@)
3246 NTSTATUS WINAPI NtSetPowerRequest( HANDLE handle, POWER_REQUEST_TYPE type )
3248 FIXME( "(%p, %u): stub\n", handle, type );
3249 return STATUS_NOT_IMPLEMENTED;
3253 /******************************************************************************
3254 * NtClearPowerRequest (NTDLL.@)
3256 NTSTATUS WINAPI NtClearPowerRequest( HANDLE handle, POWER_REQUEST_TYPE type )
3258 FIXME( "(%p, %u): stub\n", handle, type );
3259 return STATUS_NOT_IMPLEMENTED;
3263 /******************************************************************************
3264 * NtSetThreadExecutionState (NTDLL.@)
3266 NTSTATUS WINAPI NtSetThreadExecutionState( EXECUTION_STATE new_state, EXECUTION_STATE *old_state )
3268 static EXECUTION_STATE current = ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED | ES_USER_PRESENT;
3270 WARN( "(0x%x, %p): stub, harmless.\n", new_state, old_state );
3271 *old_state = current;
3272 if (!(current & ES_CONTINUOUS) || (new_state & ES_CONTINUOUS)) current = new_state;
3273 return STATUS_SUCCESS;