windowscodecs: Silence fixme for IID_CMetaBitmapRenderTarget.
[wine.git] / dlls / ntdll / unix / system.c
blob15c4a49e611fe2e2272486bd7107cee6644b2654
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"
27 #include <fcntl.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <sys/time.h>
37 #include <time.h>
38 #include <dirent.h>
39 #ifdef HAVE_SYS_PARAM_H
40 # include <sys/param.h>
41 #endif
42 #ifdef HAVE_SYS_SYSCTL_H
43 # include <sys/sysctl.h>
44 #endif
45 #ifdef HAVE_SYS_UTSNAME_H
46 # include <sys/utsname.h>
47 #endif
48 #ifdef HAVE_MACHINE_CPU_H
49 # include <machine/cpu.h>
50 #endif
51 #ifdef HAVE_SYS_RANDOM_H
52 # include <sys/random.h>
53 #endif
54 #ifdef HAVE_SYS_RESOURCE_H
55 # include <sys/resource.h>
56 #endif
57 #ifdef __APPLE__
58 # include <CoreFoundation/CoreFoundation.h>
59 # include <IOKit/IOKitLib.h>
60 # include <IOKit/ps/IOPSKeys.h>
61 # include <IOKit/ps/IOPowerSources.h>
62 # include <mach/mach.h>
63 # include <mach/machine.h>
64 # include <mach/mach_init.h>
65 # include <mach/mach_host.h>
66 # include <mach/vm_map.h>
67 #endif
69 #include "ntstatus.h"
70 #define WIN32_NO_STATUS
71 #include "windef.h"
72 #include "winternl.h"
73 #include "ddk/wdm.h"
74 #include "wine/asm.h"
75 #include "unix_private.h"
76 #include "wine/debug.h"
78 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
80 #include "pshpack1.h"
82 struct smbios_prologue
84 BYTE calling_method;
85 BYTE major_version;
86 BYTE minor_version;
87 BYTE revision;
88 DWORD length;
91 struct smbios_header
93 BYTE type;
94 BYTE length;
95 WORD handle;
98 struct smbios_bios
100 struct smbios_header hdr;
101 BYTE vendor;
102 BYTE version;
103 WORD start;
104 BYTE date;
105 BYTE size;
106 UINT64 characteristics;
107 BYTE characteristics_ext[2];
108 BYTE system_bios_major_release;
109 BYTE system_bios_minor_release;
110 BYTE ec_firmware_major_release;
111 BYTE ec_firmware_minor_release;
114 struct smbios_system
116 struct smbios_header hdr;
117 BYTE vendor;
118 BYTE product;
119 BYTE version;
120 BYTE serial;
121 BYTE uuid[16];
122 BYTE wake_up_type;
123 BYTE sku_number;
124 BYTE family;
127 struct smbios_board
129 struct smbios_header hdr;
130 BYTE vendor;
131 BYTE product;
132 BYTE version;
133 BYTE serial;
134 BYTE asset_tag;
135 BYTE feature_flags;
136 BYTE location;
137 WORD chassis_handle;
138 BYTE board_type;
139 BYTE num_contained_handles;
142 struct smbios_chassis
144 struct smbios_header hdr;
145 BYTE vendor;
146 BYTE type;
147 BYTE version;
148 BYTE serial;
149 BYTE asset_tag;
150 BYTE boot_state;
151 BYTE power_supply_state;
152 BYTE thermal_state;
153 BYTE security_status;
154 DWORD oem_defined;
155 BYTE height;
156 BYTE num_power_cords;
157 BYTE num_contained_elements;
158 BYTE contained_element_rec_length;
161 struct smbios_boot_info
163 struct smbios_header hdr;
164 BYTE reserved[6];
165 BYTE boot_status[10];
168 #include "poppack.h"
170 struct smbios_bios_args
172 const char *vendor;
173 size_t vendor_len;
174 const char *version;
175 size_t version_len;
176 const char *date;
177 size_t date_len;
180 struct smbios_system_args
182 const char *vendor;
183 size_t vendor_len;
184 const char *product;
185 size_t product_len;
186 const char *version;
187 size_t version_len;
188 const char *serial;
189 size_t serial_len;
190 GUID uuid;
191 const char *sku;
192 size_t sku_len;
193 const char *family;
194 size_t family_len;
197 struct smbios_board_args
199 const char *vendor;
200 size_t vendor_len;
201 const char *product;
202 size_t product_len;
203 const char *version;
204 size_t version_len;
205 const char *serial;
206 size_t serial_len;
207 const char *asset_tag;
208 size_t asset_tag_len;
211 struct smbios_chassis_args
213 const char *vendor;
214 size_t vendor_len;
215 BYTE type;
216 const char *version;
217 size_t version_len;
218 const char *serial;
219 size_t serial_len;
220 const char *asset_tag;
221 size_t asset_tag_len;
224 /* Firmware table providers */
225 #define ACPI 0x41435049
226 #define FIRM 0x4649524D
227 #define RSMB 0x52534D42
229 SYSTEM_CPU_INFORMATION cpu_info = { 0 };
230 static SYSTEM_PROCESSOR_FEATURES_INFORMATION cpu_features;
231 static char cpu_name[49];
232 static ULONG *performance_cores;
233 static unsigned int performance_cores_capacity = 0;
234 static SYSTEM_LOGICAL_PROCESSOR_INFORMATION *logical_proc_info;
235 static unsigned int logical_proc_info_len, logical_proc_info_alloc_len;
236 static SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *logical_proc_info_ex;
237 static unsigned int logical_proc_info_ex_size, logical_proc_info_ex_alloc_size;
239 static pthread_mutex_t timezone_mutex = PTHREAD_MUTEX_INITIALIZER;
241 /*******************************************************************************
242 * Architecture specific feature detection for CPUs
244 * This a set of mutually exclusive #if define()s each providing its own get_cpuinfo() to be called
245 * from init_cpu_info();
247 #if defined(__i386__) || defined(__x86_64__)
249 BOOL xstate_compaction_enabled = FALSE;
250 UINT64 xstate_supported_features_mask;
251 UINT64 xstate_features_size;
253 static int xstate_feature_offset[64];
254 static int xstate_feature_size[64];
255 static UINT64 xstate_aligned_features;
257 static int next_xstate_offset( int off, UINT64 compaction_mask, int feature_idx )
259 const UINT64 feature_mask = (UINT64)1 << feature_idx;
261 if (!compaction_mask) return xstate_feature_offset[feature_idx + 1] - sizeof(XSAVE_FORMAT);
263 if (compaction_mask & feature_mask) off += xstate_feature_size[feature_idx];
264 if (xstate_aligned_features & (feature_mask << 1))
265 off = (off + 63) & ~63;
266 return off;
269 unsigned int xstate_get_size( UINT64 compaction_mask, UINT64 mask )
271 unsigned int i;
272 int off;
274 mask >>= 2;
275 off = sizeof(XSAVE_AREA_HEADER);
276 i = 2;
277 while (mask)
279 if (mask == 1) return off + xstate_feature_size[i];
280 off = next_xstate_offset( off, compaction_mask, i );
281 mask >>= 1;
282 ++i;
284 return off;
287 void copy_xstate( XSAVE_AREA_HEADER *dst, XSAVE_AREA_HEADER *src, UINT64 mask )
289 unsigned int i;
290 int src_off, dst_off;
292 mask &= xstate_extended_features() & src->Mask;
293 if (src->CompactionMask) mask &= src->CompactionMask;
294 if (dst->CompactionMask) mask &= dst->CompactionMask;
295 dst->Mask = (dst->Mask & ~xstate_extended_features()) | mask;
296 mask >>= 2;
297 src_off = dst_off = sizeof(XSAVE_AREA_HEADER);
298 i = 2;
299 while (1)
301 if (mask & 1) memcpy( (char *)dst + dst_off, (char *)src + src_off, xstate_feature_size[i] );
302 if (!(mask >>= 1)) break;
303 src_off = next_xstate_offset( src_off, src->CompactionMask, i );
304 dst_off = next_xstate_offset( dst_off, dst->CompactionMask, i );
305 ++i;
309 #define AUTH 0x68747541 /* "Auth" */
310 #define ENTI 0x69746e65 /* "enti" */
311 #define CAMD 0x444d4163 /* "cAMD" */
313 #define GENU 0x756e6547 /* "Genu" */
314 #define INEI 0x49656e69 /* "ineI" */
315 #define NTEL 0x6c65746e /* "ntel" */
317 extern void do_cpuid( unsigned int ax, unsigned int cx, unsigned int *p );
318 #ifdef __i386__
319 __ASM_GLOBAL_FUNC( do_cpuid,
320 "pushl %esi\n\t"
321 "pushl %ebx\n\t"
322 "movl 12(%esp),%eax\n\t"
323 "movl 16(%esp),%ecx\n\t"
324 "movl 20(%esp),%esi\n\t"
325 "cpuid\n\t"
326 "movl %eax,(%esi)\n\t"
327 "movl %ebx,4(%esi)\n\t"
328 "movl %ecx,8(%esi)\n\t"
329 "movl %edx,12(%esi)\n\t"
330 "popl %ebx\n\t"
331 "popl %esi\n\t"
332 "ret" )
333 #else
334 __ASM_GLOBAL_FUNC( do_cpuid,
335 "pushq %rbx\n\t"
336 "movl %edi,%eax\n\t"
337 "movl %esi,%ecx\n\t"
338 "movq %rdx,%r8\n\t"
339 "cpuid\n\t"
340 "movl %eax,(%r8)\n\t"
341 "movl %ebx,4(%r8)\n\t"
342 "movl %ecx,8(%r8)\n\t"
343 "movl %edx,12(%r8)\n\t"
344 "popq %rbx\n\t"
345 "ret" )
346 #endif
348 extern UINT64 do_xgetbv( unsigned int cx);
349 #ifdef __i386__
350 __ASM_GLOBAL_FUNC( do_xgetbv,
351 "movl 4(%esp),%ecx\n\t"
352 "xgetbv\n\t"
353 "ret" )
354 #else
355 __ASM_GLOBAL_FUNC( do_xgetbv,
356 "movl %edi,%ecx\n\t"
357 "xgetbv\n\t"
358 "shlq $32,%rdx\n\t"
359 "orq %rdx,%rax\n\t"
360 "ret" )
361 #endif
363 #ifdef __i386__
364 extern int have_cpuid(void);
365 __ASM_GLOBAL_FUNC( have_cpuid,
366 "pushfl\n\t"
367 "pushfl\n\t"
368 "movl (%esp),%ecx\n\t"
369 "xorl $0x00200000,(%esp)\n\t"
370 "popfl\n\t"
371 "pushfl\n\t"
372 "popl %eax\n\t"
373 "popfl\n\t"
374 "xorl %ecx,%eax\n\t"
375 "andl $0x00200000,%eax\n\t"
376 "ret" )
377 #else
378 static int have_cpuid(void)
380 return 1;
382 #endif
384 /* Detect if a SSE2 processor is capable of Denormals Are Zero (DAZ) mode.
386 * This function assumes you have already checked for SSE2/FXSAVE support. */
387 static inline BOOL have_sse_daz_mode(void)
389 #ifdef __i386__
390 /* Intel says we need a zeroed 16-byte aligned buffer */
391 char buffer[512 + 16];
392 XSAVE_FORMAT *state = (XSAVE_FORMAT *)(((ULONG_PTR)buffer + 15) & ~15);
393 memset(buffer, 0, sizeof(buffer));
395 __asm__ __volatile__( "fxsave %0" : "=m" (*state) : "m" (*state) );
397 return (state->MxCsr_Mask & (1 << 6)) >> 6;
398 #else /* all x86_64 processors include SSE2 with DAZ mode */
399 return TRUE;
400 #endif
403 static void get_cpuid_name( char *buffer )
405 unsigned int regs[4];
407 do_cpuid( 0x80000002, 0, regs );
408 memcpy( buffer, regs, sizeof(regs) );
409 buffer += sizeof(regs);
410 do_cpuid( 0x80000003, 0, regs );
411 memcpy( buffer, regs, sizeof(regs) );
412 buffer += sizeof(regs);
413 do_cpuid( 0x80000004, 0, regs );
414 memcpy( buffer, regs, sizeof(regs) );
415 buffer += sizeof(regs);
416 *buffer = 0;
419 static void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
421 static const ULONG64 wine_xstate_supported_features = 0xff; /* XSTATE_AVX, XSTATE_MPX_BNDREGS, XSTATE_MPX_BNDCSR,
422 * XSTATE_AVX512_KMASK, XSTATE_AVX512_ZMM_H, XSTATE_AVX512_ZMM */
423 unsigned int regs[4], regs2[4], regs3[4];
424 ULONGLONG features;
425 unsigned int i;
427 #if defined(__i386__)
428 info->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
429 #elif defined(__x86_64__)
430 info->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
431 #endif
433 /* We're at least a 386 */
434 features = CPU_FEATURE_VME | CPU_FEATURE_X86 | CPU_FEATURE_PGE;
435 info->ProcessorLevel = 3;
437 if (!have_cpuid()) return;
439 do_cpuid( 0x00000000, 0, regs ); /* get standard cpuid level and vendor name */
440 if (regs[0]>=0x00000001) /* Check for supported cpuid version */
442 do_cpuid( 0x00000001, 0, regs2 ); /* get cpu features */
443 if (regs2[3] & (1 << 3 )) features |= CPU_FEATURE_PSE;
444 if (regs2[3] & (1 << 4 )) features |= CPU_FEATURE_TSC;
445 if (regs2[3] & (1 << 6 )) features |= CPU_FEATURE_PAE;
446 if (regs2[3] & (1 << 8 )) features |= CPU_FEATURE_CX8;
447 if (regs2[3] & (1 << 11)) features |= CPU_FEATURE_SEP;
448 if (regs2[3] & (1 << 12)) features |= CPU_FEATURE_MTRR;
449 if (regs2[3] & (1 << 15)) features |= CPU_FEATURE_CMOV;
450 if (regs2[3] & (1 << 16)) features |= CPU_FEATURE_PAT;
451 if (regs2[3] & (1 << 23)) features |= CPU_FEATURE_MMX;
452 if (regs2[3] & (1 << 24)) features |= CPU_FEATURE_FXSR;
453 if (regs2[3] & (1 << 25)) features |= CPU_FEATURE_SSE;
454 if (regs2[3] & (1 << 26)) features |= CPU_FEATURE_SSE2;
455 if (regs2[2] & (1 << 0 )) features |= CPU_FEATURE_SSE3;
456 if (regs2[2] & (1 << 9 )) features |= CPU_FEATURE_SSSE3;
457 if (regs2[2] & (1 << 13)) features |= CPU_FEATURE_CX128;
458 if (regs2[2] & (1 << 19)) features |= CPU_FEATURE_SSE41;
459 if (regs2[2] & (1 << 20)) features |= CPU_FEATURE_SSE42;
460 if (regs2[2] & (1 << 27)) features |= CPU_FEATURE_XSAVE;
461 if (regs2[2] & (1 << 28)) features |= CPU_FEATURE_AVX;
462 if((regs2[3] & (1 << 26)) && (regs2[3] & (1 << 24)) && have_sse_daz_mode()) /* has SSE2 and FXSAVE/FXRSTOR */
463 features |= CPU_FEATURE_DAZ;
465 if (regs[0] >= 0x00000007)
467 do_cpuid( 0x00000007, 0, regs3 ); /* get extended features */
468 if (regs3[1] & (1 << 5)) features |= CPU_FEATURE_AVX2;
471 if (features & CPU_FEATURE_XSAVE)
473 do_cpuid( 0x0000000d, 1, regs3 ); /* get XSAVE details */
474 if (regs3[0] & 2) xstate_compaction_enabled = TRUE;
476 do_cpuid( 0x0000000d, 0, regs3 ); /* get user xstate features */
477 xstate_supported_features_mask = ((ULONG64)regs3[3] << 32) | regs3[0];
478 xstate_supported_features_mask &= do_xgetbv( 0 ) & wine_xstate_supported_features;
479 TRACE("xstate_supported_features_mask %#llx.\n", (long long)xstate_supported_features_mask);
480 for (i = 2; i < 64; ++i)
482 if (!(xstate_supported_features_mask & ((ULONG64)1 << i))) continue;
483 do_cpuid( 0x0000000d, i, regs3 ); /* get user xstate features */
484 xstate_feature_offset[i] = regs3[1];
485 xstate_feature_size[i] = regs3[0];
486 if (regs3[2] & 2) xstate_aligned_features |= (ULONG64)1 << i;
487 TRACE("xstate[%d] offset %d, size %d, aligned %d.\n", i, xstate_feature_offset[i], xstate_feature_size[i], !!(regs3[2] & 2));
489 xstate_features_size = xstate_get_size( xstate_compaction_enabled ? 0x8000000000000000
490 | xstate_supported_features_mask : 0, xstate_supported_features_mask )
491 - sizeof(XSAVE_AREA_HEADER);
492 xstate_features_size = (xstate_features_size + 15) & ~15;
493 TRACE("xstate_features_size %lld.\n", (long long)xstate_features_size);
496 if (regs[1] == AUTH && regs[3] == ENTI && regs[2] == CAMD)
498 info->ProcessorLevel = (regs2[0] >> 8) & 0xf; /* family */
499 if (info->ProcessorLevel == 0xf) /* AMD says to add the extended family to the family if family is 0xf */
500 info->ProcessorLevel += (regs2[0] >> 20) & 0xff;
502 /* repack model and stepping to make a "revision" */
503 info->ProcessorRevision = ((regs2[0] >> 16) & 0xf) << 12; /* extended model */
504 info->ProcessorRevision |= ((regs2[0] >> 4 ) & 0xf) << 8; /* model */
505 info->ProcessorRevision |= regs2[0] & 0xf; /* stepping */
507 do_cpuid( 0x80000000, 0, regs ); /* get vendor cpuid level */
508 if (regs[0] >= 0x80000001)
510 do_cpuid( 0x80000001, 0, regs2 ); /* get vendor features */
511 if (regs2[2] & (1 << 2)) features |= CPU_FEATURE_VIRT;
512 if (regs2[3] & (1 << 20)) features |= CPU_FEATURE_NX;
513 if (regs2[3] & (1 << 27)) features |= CPU_FEATURE_TSC;
514 if (regs2[3] & (1u << 31)) features |= CPU_FEATURE_3DNOW;
516 if (regs[0] >= 0x80000004) get_cpuid_name( cpu_name );
518 else if (regs[1] == GENU && regs[3] == INEI && regs[2] == NTEL)
520 info->ProcessorLevel = ((regs2[0] >> 8) & 0xf) + ((regs2[0] >> 20) & 0xff); /* family + extended family */
521 if(info->ProcessorLevel == 15) info->ProcessorLevel = 6;
523 /* repack model and stepping to make a "revision" */
524 info->ProcessorRevision = ((regs2[0] >> 16) & 0xf) << 12; /* extended model */
525 info->ProcessorRevision |= ((regs2[0] >> 4 ) & 0xf) << 8; /* model */
526 info->ProcessorRevision |= regs2[0] & 0xf; /* stepping */
528 if(regs2[2] & (1 << 5)) features |= CPU_FEATURE_VIRT;
529 if(regs2[3] & (1 << 21)) features |= CPU_FEATURE_DS;
531 do_cpuid( 0x80000000, 0, regs ); /* get vendor cpuid level */
532 if (regs[0] >= 0x80000001)
534 do_cpuid( 0x80000001, 0, regs2 ); /* get vendor features */
535 if (regs2[3] & (1 << 20)) features |= CPU_FEATURE_NX;
536 if (regs2[3] & (1 << 27)) features |= CPU_FEATURE_TSC;
538 if (regs[0] >= 0x80000004) get_cpuid_name( cpu_name );
540 else
542 info->ProcessorLevel = (regs2[0] >> 8) & 0xf; /* family */
544 /* repack model and stepping to make a "revision" */
545 info->ProcessorRevision = ((regs2[0] >> 4 ) & 0xf) << 8; /* model */
546 info->ProcessorRevision |= regs2[0] & 0xf; /* stepping */
549 info->ProcessorFeatureBits = cpu_features.ProcessorFeatureBits = features;
552 #elif defined(__arm__)
554 static inline void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
556 ULONGLONG features = 0;
557 #ifdef linux
558 char line[512];
559 char *s, *value;
560 FILE *f = fopen("/proc/cpuinfo", "r");
561 if (f)
563 while (fgets( line, sizeof(line), f ))
565 /* NOTE: the ':' is the only character we can rely on */
566 if (!(value = strchr(line,':'))) continue;
567 /* terminate the valuename */
568 s = value - 1;
569 while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
570 s[1] = 0;
571 /* and strip leading spaces from value */
572 value += 1;
573 while (*value == ' ' || *value == '\t') value++;
574 if ((s = strchr( value,'\n' ))) *s = 0;
575 if (!strcmp( line, "CPU architecture" ))
577 info->ProcessorLevel = atoi(value);
578 continue;
580 if (!strcmp( line, "CPU revision" ))
582 info->ProcessorRevision = atoi(value);
583 continue;
585 if (!strcmp( line, "Features" ))
587 if (strstr(value, "crc32")) features |= CPU_FEATURE_ARM_V8_CRC32;
588 if (strstr(value, "aes")) features |= CPU_FEATURE_ARM_V8_CRYPTO;
589 continue;
592 fclose( f );
594 #elif defined(__FreeBSD__)
595 size_t valsize;
596 char buf[8];
597 int value;
599 valsize = sizeof(buf);
600 if (!sysctlbyname("hw.machine_arch", &buf, &valsize, NULL, 0) && sscanf(buf, "armv%i", &value) == 1)
601 info->ProcessorLevel = value;
603 valsize = sizeof(value);
604 if (!sysctlbyname("hw.floatingpoint", &value, &valsize, NULL, 0)) features |= CPU_FEATURE_ARM_VFP_32;
605 #else
606 FIXME("CPU Feature detection not implemented.\n");
607 #endif
608 info->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_ARM;
609 info->ProcessorFeatureBits = cpu_features.ProcessorFeatureBits = features;
612 #elif defined(__aarch64__)
614 static void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
616 ULONGLONG features = 0;
617 #ifdef linux
618 char line[512];
619 char *s, *value;
620 FILE *f = fopen("/proc/cpuinfo", "r");
621 if (f)
623 while (fgets( line, sizeof(line), f ))
625 /* NOTE: the ':' is the only character we can rely on */
626 if (!(value = strchr(line,':'))) continue;
627 /* terminate the valuename */
628 s = value - 1;
629 while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
630 s[1] = 0;
631 /* and strip leading spaces from value */
632 value += 1;
633 while (*value == ' ' || *value == '\t') value++;
634 if ((s = strchr( value,'\n' ))) *s = 0;
635 if (!strcmp( line, "CPU architecture" ))
637 info->ProcessorLevel = atoi(value);
638 continue;
640 if (!strcmp( line, "CPU revision" ))
642 info->ProcessorRevision = atoi(value);
643 continue;
645 if (!strcmp( line, "Features" ))
647 if (strstr(value, "crc32")) features |= CPU_FEATURE_ARM_V8_CRC32;
648 if (strstr(value, "aes")) features |= CPU_FEATURE_ARM_V8_CRYPTO;
649 if (strstr(value, "atomics")) features |= CPU_FEATURE_ARM_V81_ATOMIC;
650 if (strstr(value, "asimddp")) features |= CPU_FEATURE_ARM_V82_DP;
651 if (strstr(value, "jscvt")) features |= CPU_FEATURE_ARM_V83_JSCVT;
652 if (strstr(value, "lrcpc")) features |= CPU_FEATURE_ARM_V83_LRCPC;
653 continue;
656 fclose( f );
658 #else
659 FIXME("CPU Feature detection not implemented.\n");
660 #endif
661 info->ProcessorLevel = max(info->ProcessorLevel, 8);
662 info->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_ARM64;
663 info->ProcessorFeatureBits = cpu_features.ProcessorFeatureBits = features;
666 #endif /* End architecture specific feature detection for CPUs */
668 static BOOL grow_logical_proc_buf(void)
670 SYSTEM_LOGICAL_PROCESSOR_INFORMATION *new_data;
671 unsigned int new_len;
673 if (logical_proc_info_len < logical_proc_info_alloc_len) return TRUE;
675 new_len = max( logical_proc_info_alloc_len * 2, logical_proc_info_len + 1 );
676 if (!(new_data = realloc( logical_proc_info, new_len * sizeof(*new_data) ))) return FALSE;
677 memset( new_data + logical_proc_info_alloc_len, 0,
678 (new_len - logical_proc_info_alloc_len) * sizeof(*new_data) );
679 logical_proc_info = new_data;
680 logical_proc_info_alloc_len = new_len;
681 return TRUE;
684 static BOOL grow_logical_proc_ex_buf( unsigned int add_size )
686 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *new_dataex;
687 DWORD new_len;
689 if ( logical_proc_info_ex_size + add_size <= logical_proc_info_ex_alloc_size ) return TRUE;
691 new_len = max( logical_proc_info_ex_alloc_size * 2, logical_proc_info_ex_alloc_size + add_size );
692 if (!(new_dataex = realloc( logical_proc_info_ex, new_len ))) return FALSE;
693 memset( (char *)new_dataex + logical_proc_info_ex_alloc_size, 0, new_len - logical_proc_info_ex_alloc_size );
694 logical_proc_info_ex = new_dataex;
695 logical_proc_info_ex_alloc_size = new_len;
696 return TRUE;
699 static DWORD log_proc_ex_size_plus( DWORD size )
701 /* add SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX.Relationship and .Size */
702 return sizeof(LOGICAL_PROCESSOR_RELATIONSHIP) + sizeof(DWORD) + size;
705 static DWORD count_bits( ULONG_PTR mask )
707 DWORD count = 0;
708 while (mask > 0)
710 if (mask & 1) ++count;
711 mask >>= 1;
713 return count;
716 static BOOL logical_proc_info_ex_add_by_id( LOGICAL_PROCESSOR_RELATIONSHIP rel, DWORD id, ULONG_PTR mask )
718 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
719 unsigned int ofs = 0;
721 while (ofs < logical_proc_info_ex_size)
723 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((char *)logical_proc_info_ex + ofs);
724 if (rel == RelationProcessorPackage && dataex->Relationship == rel && dataex->Processor.Reserved[1] == id)
726 dataex->Processor.GroupMask[0].Mask |= mask;
727 return TRUE;
729 else if (rel == RelationProcessorCore && dataex->Relationship == rel && dataex->Processor.Reserved[1] == id)
731 return TRUE;
733 ofs += dataex->Size;
736 /* TODO: For now, just one group. If more than 64 processors, then we
737 * need another group. */
738 if (!grow_logical_proc_ex_buf( log_proc_ex_size_plus( sizeof(PROCESSOR_RELATIONSHIP) ))) return FALSE;
740 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((char *)logical_proc_info_ex + ofs);
742 dataex->Relationship = rel;
743 dataex->Size = log_proc_ex_size_plus( sizeof(PROCESSOR_RELATIONSHIP) );
744 if (rel == RelationProcessorCore)
745 dataex->Processor.Flags = count_bits( mask ) > 1 ? LTP_PC_SMT : 0;
746 else
747 dataex->Processor.Flags = 0;
748 if (rel == RelationProcessorCore && id / 32 < performance_cores_capacity)
749 dataex->Processor.EfficiencyClass = (performance_cores[id / 32] >> (id % 32)) & 1;
750 else
751 dataex->Processor.EfficiencyClass = 0;
752 dataex->Processor.GroupCount = 1;
753 dataex->Processor.GroupMask[0].Mask = mask;
754 dataex->Processor.GroupMask[0].Group = 0;
755 /* mark for future lookup */
756 dataex->Processor.Reserved[0] = 0;
757 dataex->Processor.Reserved[1] = id;
759 logical_proc_info_ex_size += dataex->Size;
760 return TRUE;
763 /* Store package and core information for a logical processor. Parsing of processor
764 * data may happen in multiple passes; the 'id' parameter is then used to locate
765 * previously stored data. The type of data stored in 'id' depends on 'rel':
766 * - RelationProcessorPackage: package id ('CPU socket').
767 * - RelationProcessorCore: physical core number.
769 static BOOL logical_proc_info_add_by_id( LOGICAL_PROCESSOR_RELATIONSHIP rel, DWORD id, ULONG_PTR mask )
771 unsigned int i;
773 for (i = 0; i < logical_proc_info_len; i++)
775 if (rel == RelationProcessorPackage && logical_proc_info[i].Relationship == rel
776 && logical_proc_info[i].Reserved[1] == id)
778 logical_proc_info[i].ProcessorMask |= mask;
779 return logical_proc_info_ex_add_by_id( rel, id, mask );
781 else if (rel == RelationProcessorCore && logical_proc_info[i].Relationship == rel
782 && logical_proc_info[i].Reserved[1] == id)
783 return logical_proc_info_ex_add_by_id( rel, id, mask );
786 if (!grow_logical_proc_buf()) return FALSE;
788 logical_proc_info[i].Relationship = rel;
789 logical_proc_info[i].ProcessorMask = mask;
790 if (rel == RelationProcessorCore)
791 logical_proc_info[i].ProcessorCore.Flags = count_bits( mask ) > 1 ? LTP_PC_SMT : 0;
792 logical_proc_info[i].Reserved[0] = 0;
793 logical_proc_info[i].Reserved[1] = id;
794 logical_proc_info_len = i + 1;
796 return logical_proc_info_ex_add_by_id( rel, id, mask );
799 static BOOL logical_proc_info_add_cache( ULONG_PTR mask, CACHE_DESCRIPTOR *cache )
801 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
802 unsigned int ofs = 0, i;
804 for (i = 0; i < logical_proc_info_len; i++)
806 if (logical_proc_info[i].Relationship==RelationCache && logical_proc_info[i].ProcessorMask==mask
807 && logical_proc_info[i].Cache.Level==cache->Level && logical_proc_info[i].Cache.Type==cache->Type)
808 return TRUE;
811 if (!grow_logical_proc_buf()) return FALSE;
813 logical_proc_info[i].Relationship = RelationCache;
814 logical_proc_info[i].ProcessorMask = mask;
815 logical_proc_info[i].Cache = *cache;
816 logical_proc_info_len = i + 1;
818 for (ofs = 0; ofs < logical_proc_info_ex_size; )
820 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((char *)logical_proc_info_ex + ofs);
821 if (dataex->Relationship == RelationCache && dataex->Cache.GroupMask.Mask == mask
822 && dataex->Cache.Level == cache->Level && dataex->Cache.Type == cache->Type)
823 return TRUE;
824 ofs += dataex->Size;
827 if (!grow_logical_proc_ex_buf( log_proc_ex_size_plus( sizeof(CACHE_RELATIONSHIP) ))) return FALSE;
829 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((char *)logical_proc_info_ex + ofs);
831 dataex->Relationship = RelationCache;
832 dataex->Size = log_proc_ex_size_plus( sizeof(CACHE_RELATIONSHIP) );
833 dataex->Cache.Level = cache->Level;
834 dataex->Cache.Associativity = cache->Associativity;
835 dataex->Cache.LineSize = cache->LineSize;
836 dataex->Cache.CacheSize = cache->Size;
837 dataex->Cache.Type = cache->Type;
838 dataex->Cache.GroupMask.Mask = mask;
839 dataex->Cache.GroupMask.Group = 0;
841 logical_proc_info_ex_size += dataex->Size;
843 return TRUE;
846 static BOOL logical_proc_info_add_numa_node( ULONG_PTR mask, DWORD node_id )
848 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
850 if (!grow_logical_proc_buf()) return FALSE;
852 logical_proc_info[logical_proc_info_len].Relationship = RelationNumaNode;
853 logical_proc_info[logical_proc_info_len].ProcessorMask = mask;
854 logical_proc_info[logical_proc_info_len].NumaNode.NodeNumber = node_id;
855 ++logical_proc_info_len;
857 if (!grow_logical_proc_ex_buf( log_proc_ex_size_plus( sizeof(NUMA_NODE_RELATIONSHIP) ))) return FALSE;
859 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((char *)logical_proc_info_ex + logical_proc_info_ex_size);
861 dataex->Relationship = RelationNumaNode;
862 dataex->Size = log_proc_ex_size_plus( sizeof(NUMA_NODE_RELATIONSHIP) );
863 dataex->NumaNode.NodeNumber = node_id;
864 dataex->NumaNode.GroupMask.Mask = mask;
865 dataex->NumaNode.GroupMask.Group = 0;
867 logical_proc_info_ex_size += dataex->Size;
869 return TRUE;
872 static BOOL logical_proc_info_add_group( DWORD num_cpus, ULONG_PTR mask )
874 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
876 if (!grow_logical_proc_ex_buf( log_proc_ex_size_plus( sizeof(GROUP_RELATIONSHIP) ))) return FALSE;
878 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)logical_proc_info_ex) + logical_proc_info_ex_size);
880 dataex->Relationship = RelationGroup;
881 dataex->Size = log_proc_ex_size_plus( sizeof(GROUP_RELATIONSHIP) );
882 dataex->Group.MaximumGroupCount = 1;
883 dataex->Group.ActiveGroupCount = 1;
884 dataex->Group.GroupInfo[0].MaximumProcessorCount = num_cpus;
885 dataex->Group.GroupInfo[0].ActiveProcessorCount = num_cpus;
886 dataex->Group.GroupInfo[0].ActiveProcessorMask = mask;
888 logical_proc_info_ex_size += dataex->Size;
889 return TRUE;
892 #ifdef linux
894 /* Helper function for counting bitmap values as commonly used by the Linux kernel
895 * for storing CPU masks in sysfs. The format is comma separated lists of hex values
896 * each max 32-bit e.g. "00ff" or even "00,00000000,0000ffff".
898 * Example files include:
899 * - /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_map
900 * - /sys/devices/system/cpu/cpu0/topology/thread_siblings
902 static BOOL sysfs_parse_bitmap(const char *filename, ULONG_PTR *mask)
904 FILE *f;
905 unsigned int r;
907 f = fopen(filename, "r");
908 if (!f) return FALSE;
910 while (!feof(f))
912 char op;
913 if (!fscanf(f, "%x%c ", &r, &op)) break;
914 *mask = (sizeof(ULONG_PTR)>sizeof(int) ? *mask << (8 * sizeof(DWORD)) : 0) + r;
916 fclose( f );
917 return TRUE;
920 /* Helper function for counting number of elements in interval lists as used by
921 * the Linux kernel. The format is comma separated list of intervals of which
922 * each interval has the format of "begin-end" where begin and end are decimal
923 * numbers. E.g. "0-7", "0-7,16-23"
925 * Example files include:
926 * - /sys/devices/system/cpu/online
927 * - /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_list
928 * - /sys/devices/system/cpu/cpu0/topology/thread_siblings_list.
930 static BOOL sysfs_count_list_elements(const char *filename, unsigned int *result)
932 FILE *f;
934 f = fopen(filename, "r");
935 if (!f) return FALSE;
937 while (!feof(f))
939 char op;
940 unsigned int beg, end;
942 if (!fscanf(f, "%u%c ", &beg, &op)) break;
943 if(op == '-')
944 fscanf(f, "%u%c ", &end, &op);
945 else
946 end = beg;
948 *result += end - beg + 1;
950 fclose( f );
951 return TRUE;
954 static void fill_performance_core_info(void)
956 FILE *fpcore_list;
957 unsigned int beg, end, i;
958 char op = ',';
959 ULONG *p;
961 fpcore_list = fopen("/sys/devices/cpu_core/cpus", "r");
962 if (!fpcore_list) return;
964 performance_cores = calloc(16, sizeof(ULONG));
965 if (!performance_cores) goto done;
966 performance_cores_capacity = 16;
968 while (!feof(fpcore_list) && op == ',')
970 if (!fscanf(fpcore_list, "%u %c ", &beg, &op)) break;
971 if (op == '-') fscanf(fpcore_list, "%u %c ", &end, &op);
972 else end = beg;
974 for(i = beg; i <= end; i++)
976 if (i / 32 >= performance_cores_capacity)
978 p = realloc(performance_cores, performance_cores_capacity * 2 * sizeof(ULONG));
979 if (!p) goto done;
980 memset(p + performance_cores_capacity, 0, performance_cores_capacity * sizeof(ULONG));
981 performance_cores = p;
982 performance_cores_capacity *= 2;
984 performance_cores[i / 32] |= 1 << (i % 32);
987 done:
988 fclose(fpcore_list);
991 /* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
992 static NTSTATUS create_logical_proc_info(void)
994 static const char core_info[] = "/sys/devices/system/cpu/cpu%u/topology/%s";
995 static const char cache_info[] = "/sys/devices/system/cpu/cpu%u/cache/index%u/%s";
996 static const char numa_info[] = "/sys/devices/system/node/node%u/cpumap";
998 FILE *fcpu_list, *fnuma_list, *f;
999 unsigned int beg, end, i, j, r, num_cpus = 0, max_cpus = 0;
1000 char op, name[MAX_PATH];
1001 ULONG_PTR all_cpus_mask = 0;
1003 /* On systems with a large number of CPU cores (32 or 64 depending on 32-bit or 64-bit),
1004 * we have issues parsing processor information:
1005 * - ULONG_PTR masks as used in data structures can't hold all cores. Requires splitting
1006 * data appropriately into "processor groups". We are hard coding 1.
1007 * - Thread affinity code in wineserver and our CPU parsing code here work independently.
1008 * So far the Windows mask applied directly to Linux, but process groups break that.
1009 * (NUMA systems you may have multiple non-full groups.)
1011 if(sysfs_count_list_elements("/sys/devices/system/cpu/present", &max_cpus) && max_cpus > MAXIMUM_PROCESSORS)
1013 FIXME("Improve CPU info reporting: system supports %u logical cores, but only %u supported!\n",
1014 max_cpus, MAXIMUM_PROCESSORS);
1017 fill_performance_core_info();
1019 fcpu_list = fopen("/sys/devices/system/cpu/online", "r");
1020 if (!fcpu_list) return STATUS_NOT_IMPLEMENTED;
1022 while (!feof(fcpu_list))
1024 if (!fscanf(fcpu_list, "%u%c ", &beg, &op)) break;
1025 if (op == '-') fscanf(fcpu_list, "%u%c ", &end, &op);
1026 else end = beg;
1028 for(i = beg; i <= end; i++)
1030 unsigned int phys_core = 0;
1031 ULONG_PTR thread_mask = 0;
1033 if (i > 8 * sizeof(ULONG_PTR)) break;
1035 snprintf(name, sizeof(name), core_info, i, "physical_package_id");
1036 f = fopen(name, "r");
1037 if (f)
1039 fscanf(f, "%u", &r);
1040 fclose(f);
1042 else r = 0;
1043 if (!logical_proc_info_add_by_id( RelationProcessorPackage, r, (ULONG_PTR)1 << i ))
1045 fclose(fcpu_list);
1046 return STATUS_NO_MEMORY;
1049 /* Sysfs enumerates logical cores (and not physical cores), but Windows enumerates
1050 * by physical core. Upon enumerating a logical core in sysfs, we register a physical
1051 * core and all its logical cores. In order to not report physical cores multiple
1052 * times, we pass a unique physical core ID to logical_proc_info_add_by_id and let
1053 * that call figure out any duplication.
1054 * Obtain a unique physical core ID from the first element of thread_siblings_list.
1055 * This list provides logical cores sharing the same physical core. The IDs are based
1056 * on kernel cpu core numbering as opposed to a hardware core ID like provided through
1057 * 'core_id', so are suitable as a unique ID.
1060 /* Mask of logical threads sharing same physical core in kernel core numbering. */
1061 snprintf(name, sizeof(name), core_info, i, "thread_siblings");
1062 if(!sysfs_parse_bitmap(name, &thread_mask)) thread_mask = 1<<i;
1064 /* Needed later for NumaNode and Group. */
1065 all_cpus_mask |= thread_mask;
1067 snprintf(name, sizeof(name), core_info, i, "thread_siblings_list");
1068 f = fopen(name, "r");
1069 if (f)
1071 fscanf(f, "%d%c", &phys_core, &op);
1072 fclose(f);
1074 else phys_core = i;
1076 if (!logical_proc_info_add_by_id( RelationProcessorCore, phys_core, thread_mask ))
1078 fclose(fcpu_list);
1079 return STATUS_NO_MEMORY;
1082 for (j = 0; j < 4; j++)
1084 CACHE_DESCRIPTOR cache;
1085 ULONG_PTR mask = 0;
1087 snprintf(name, sizeof(name), cache_info, i, j, "shared_cpu_map");
1088 if(!sysfs_parse_bitmap(name, &mask)) continue;
1090 snprintf(name, sizeof(name), cache_info, i, j, "level");
1091 f = fopen(name, "r");
1092 if(!f) continue;
1093 fscanf(f, "%u", &r);
1094 fclose(f);
1095 cache.Level = r;
1097 snprintf(name, sizeof(name), cache_info, i, j, "ways_of_associativity");
1098 f = fopen(name, "r");
1099 if(!f) continue;
1100 fscanf(f, "%u", &r);
1101 fclose(f);
1102 cache.Associativity = r;
1104 snprintf(name, sizeof(name), cache_info, i, j, "coherency_line_size");
1105 f = fopen(name, "r");
1106 if(!f) continue;
1107 fscanf(f, "%u", &r);
1108 fclose(f);
1109 cache.LineSize = r;
1111 snprintf(name, sizeof(name), cache_info, i, j, "size");
1112 f = fopen(name, "r");
1113 if(!f) continue;
1114 fscanf(f, "%u%c", &r, &op);
1115 fclose(f);
1116 if(op != 'K')
1117 WARN("unknown cache size %u%c\n", r, op);
1118 cache.Size = (op=='K' ? r*1024 : r);
1120 snprintf(name, sizeof(name), cache_info, i, j, "type");
1121 f = fopen(name, "r");
1122 if(!f) continue;
1123 fscanf(f, "%s", name);
1124 fclose(f);
1125 if (!memcmp(name, "Data", 5))
1126 cache.Type = CacheData;
1127 else if(!memcmp(name, "Instruction", 11))
1128 cache.Type = CacheInstruction;
1129 else
1130 cache.Type = CacheUnified;
1132 if (!logical_proc_info_add_cache( mask, &cache ))
1134 fclose(fcpu_list);
1135 return STATUS_NO_MEMORY;
1140 fclose(fcpu_list);
1142 num_cpus = count_bits(all_cpus_mask);
1144 fnuma_list = fopen("/sys/devices/system/node/online", "r");
1145 if (!fnuma_list)
1147 if (!logical_proc_info_add_numa_node( all_cpus_mask, 0 ))
1148 return STATUS_NO_MEMORY;
1150 else
1152 while (!feof(fnuma_list))
1154 if (!fscanf(fnuma_list, "%u%c ", &beg, &op))
1155 break;
1156 if (op == '-') fscanf(fnuma_list, "%u%c ", &end, &op);
1157 else end = beg;
1159 for (i = beg; i <= end; i++)
1161 ULONG_PTR mask = 0;
1163 snprintf(name, sizeof(name), numa_info, i);
1164 if (!sysfs_parse_bitmap( name, &mask )) continue;
1166 if (!logical_proc_info_add_numa_node( mask, i ))
1168 fclose(fnuma_list);
1169 return STATUS_NO_MEMORY;
1173 fclose(fnuma_list);
1176 logical_proc_info_add_group( num_cpus, all_cpus_mask );
1178 performance_cores_capacity = 0;
1179 free(performance_cores);
1180 performance_cores = NULL;
1182 return STATUS_SUCCESS;
1185 #elif defined(__APPLE__)
1187 /* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
1188 static NTSTATUS create_logical_proc_info(void)
1190 unsigned int pkgs_no, cores_no, lcpu_no, lcpu_per_core, cores_per_package, assoc;
1191 unsigned int cache_ctrs[10] = {0};
1192 ULONG_PTR all_cpus_mask = 0;
1193 CACHE_DESCRIPTOR cache[10];
1194 LONGLONG cache_size, cache_line_size, cache_sharing[10];
1195 size_t size;
1196 unsigned int p, i, j, k;
1198 lcpu_no = peb->NumberOfProcessors;
1200 size = sizeof(pkgs_no);
1201 if (sysctlbyname("hw.packages", &pkgs_no, &size, NULL, 0))
1202 pkgs_no = 1;
1204 size = sizeof(cores_no);
1205 if (sysctlbyname("hw.physicalcpu", &cores_no, &size, NULL, 0))
1206 cores_no = lcpu_no;
1208 TRACE("%u logical CPUs from %u physical cores across %u packages\n",
1209 lcpu_no, cores_no, pkgs_no);
1211 lcpu_per_core = lcpu_no / cores_no;
1212 cores_per_package = cores_no / pkgs_no;
1214 memset(cache, 0, sizeof(cache));
1215 cache[1].Level = 1;
1216 cache[1].Type = CacheInstruction;
1217 cache[1].Associativity = 8; /* reasonable default */
1218 cache[1].LineSize = 0x40; /* reasonable default */
1219 cache[2].Level = 1;
1220 cache[2].Type = CacheData;
1221 cache[2].Associativity = 8;
1222 cache[2].LineSize = 0x40;
1223 cache[3].Level = 2;
1224 cache[3].Type = CacheUnified;
1225 cache[3].Associativity = 8;
1226 cache[3].LineSize = 0x40;
1227 cache[4].Level = 3;
1228 cache[4].Type = CacheUnified;
1229 cache[4].Associativity = 12;
1230 cache[4].LineSize = 0x40;
1232 size = sizeof(cache_line_size);
1233 if (!sysctlbyname("hw.cachelinesize", &cache_line_size, &size, NULL, 0))
1235 for (i = 1; i < 5; i++) cache[i].LineSize = cache_line_size;
1238 /* TODO: set actual associativity for all caches */
1239 size = sizeof(assoc);
1240 if (!sysctlbyname("machdep.cpu.cache.L2_associativity", &assoc, &size, NULL, 0))
1241 cache[3].Associativity = assoc;
1243 size = sizeof(cache_size);
1244 if (!sysctlbyname("hw.l1icachesize", &cache_size, &size, NULL, 0))
1245 cache[1].Size = cache_size;
1246 size = sizeof(cache_size);
1247 if (!sysctlbyname("hw.l1dcachesize", &cache_size, &size, NULL, 0))
1248 cache[2].Size = cache_size;
1249 size = sizeof(cache_size);
1250 if (!sysctlbyname("hw.l2cachesize", &cache_size, &size, NULL, 0))
1251 cache[3].Size = cache_size;
1252 size = sizeof(cache_size);
1253 if (!sysctlbyname("hw.l3cachesize", &cache_size, &size, NULL, 0))
1254 cache[4].Size = cache_size;
1256 size = sizeof(cache_sharing);
1257 if (sysctlbyname("hw.cacheconfig", cache_sharing, &size, NULL, 0) < 0)
1259 cache_sharing[1] = lcpu_per_core;
1260 cache_sharing[2] = lcpu_per_core;
1261 cache_sharing[3] = lcpu_per_core;
1262 cache_sharing[4] = lcpu_no;
1264 else
1266 /* in cache[], indexes 1 and 2 are l1 caches */
1267 cache_sharing[4] = cache_sharing[3];
1268 cache_sharing[3] = cache_sharing[2];
1269 cache_sharing[2] = cache_sharing[1];
1272 for(p = 0; p < pkgs_no; ++p)
1274 for(j = 0; j < cores_per_package && p * cores_per_package + j < cores_no; ++j)
1276 ULONG_PTR mask = 0;
1277 DWORD phys_core;
1279 for(k = 0; k < lcpu_per_core; ++k) mask |= (ULONG_PTR)1 << (j * lcpu_per_core + k);
1281 all_cpus_mask |= mask;
1283 /* add to package */
1284 if(!logical_proc_info_add_by_id( RelationProcessorPackage, p, mask ))
1285 return STATUS_NO_MEMORY;
1287 /* add new core */
1288 phys_core = p * cores_per_package + j;
1289 if(!logical_proc_info_add_by_id( RelationProcessorCore, phys_core, mask ))
1290 return STATUS_NO_MEMORY;
1292 for(i = 1; i < 5; ++i)
1294 if(cache_ctrs[i] == 0 && cache[i].Size > 0)
1296 mask = 0;
1297 for(k = 0; k < cache_sharing[i]; ++k)
1298 mask |= (ULONG_PTR)1 << (j * lcpu_per_core + k);
1300 if (!logical_proc_info_add_cache( mask, &cache[i] ))
1301 return STATUS_NO_MEMORY;
1304 cache_ctrs[i] += lcpu_per_core;
1305 if(cache_ctrs[i] == cache_sharing[i]) cache_ctrs[i] = 0;
1310 /* OSX doesn't support NUMA, so just make one NUMA node for all CPUs */
1311 if(!logical_proc_info_add_numa_node( all_cpus_mask, 0 ))
1312 return STATUS_NO_MEMORY;
1314 logical_proc_info_add_group( lcpu_no, all_cpus_mask );
1316 return STATUS_SUCCESS;
1319 #else
1321 static NTSTATUS create_logical_proc_info(void)
1323 FIXME("stub\n");
1324 return STATUS_NOT_IMPLEMENTED;
1326 #endif
1328 /******************************************************************
1329 * init_cpu_info
1331 * inits a couple of places with CPU related information:
1332 * - cpu_info in this file
1333 * - Peb->NumberOfProcessors
1334 * - SharedUserData->ProcessFeatures[] array
1336 void init_cpu_info(void)
1338 unsigned int status;
1339 long num;
1341 #ifdef _SC_NPROCESSORS_ONLN
1342 num = sysconf(_SC_NPROCESSORS_ONLN);
1343 if (num < 1)
1345 num = 1;
1346 WARN("Failed to detect the number of processors.\n");
1348 #elif defined(CTL_HW) && defined(HW_NCPU)
1349 int mib[2];
1350 size_t len = sizeof(num);
1351 mib[0] = CTL_HW;
1352 mib[1] = HW_NCPU;
1353 if (sysctl(mib, 2, &num, &len, NULL, 0) != 0)
1355 num = 1;
1356 WARN("Failed to detect the number of processors.\n");
1358 #else
1359 num = 1;
1360 FIXME("Detecting the number of processors is not supported.\n");
1361 #endif
1362 peb->NumberOfProcessors = num;
1363 get_cpuinfo( &cpu_info );
1364 TRACE( "<- CPU arch %d, level %d, rev %d, features 0x%x\n",
1365 (int)cpu_info.ProcessorArchitecture, (int)cpu_info.ProcessorLevel,
1366 (int)cpu_info.ProcessorRevision, (int)cpu_info.ProcessorFeatureBits );
1368 if ((status = create_logical_proc_info()))
1370 FIXME( "Failed to get logical processor information, status %#x.\n", status );
1371 free( logical_proc_info );
1372 logical_proc_info = NULL;
1373 logical_proc_info_len = 0;
1375 free( logical_proc_info_ex );
1376 logical_proc_info_ex = NULL;
1377 logical_proc_info_ex_size = 0;
1379 else
1381 logical_proc_info = realloc( logical_proc_info, logical_proc_info_len * sizeof(*logical_proc_info) );
1382 logical_proc_info_alloc_len = logical_proc_info_len;
1383 logical_proc_info_ex = realloc( logical_proc_info_ex, logical_proc_info_ex_size );
1384 logical_proc_info_ex_alloc_size = logical_proc_info_ex_size;
1388 static NTSTATUS create_cpuset_info(SYSTEM_CPU_SET_INFORMATION *info)
1390 const SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *proc_info;
1391 const DWORD cpu_info_size = logical_proc_info_ex_size;
1392 BYTE core_index, cache_index, max_cache_level;
1393 unsigned int i, j, count;
1394 ULONG64 cpu_mask;
1396 if (!logical_proc_info_ex) return STATUS_NOT_IMPLEMENTED;
1398 count = peb->NumberOfProcessors;
1400 max_cache_level = 0;
1401 proc_info = logical_proc_info_ex;
1402 for (i = 0; (char *)proc_info != (char *)logical_proc_info_ex + cpu_info_size; ++i)
1404 if (proc_info->Relationship == RelationCache)
1406 if (max_cache_level < proc_info->Cache.Level)
1407 max_cache_level = proc_info->Cache.Level;
1409 proc_info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((BYTE *)proc_info + proc_info->Size);
1412 memset(info, 0, count * sizeof(*info));
1414 core_index = 0;
1415 cache_index = 0;
1416 proc_info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)logical_proc_info_ex;
1417 for (i = 0; i < count; ++i)
1419 info[i].Size = sizeof(*info);
1420 info[i].Type = CpuSetInformation;
1421 info[i].CpuSet.Id = 0x100 + i;
1422 info[i].CpuSet.LogicalProcessorIndex = i;
1425 for (i = 0; (char *)proc_info != (char *)logical_proc_info_ex + cpu_info_size; ++i)
1427 if (proc_info->Relationship == RelationProcessorCore)
1429 if (proc_info->Processor.GroupCount != 1)
1431 FIXME("Unsupported group count %u.\n", proc_info->Processor.GroupCount);
1432 continue;
1434 cpu_mask = proc_info->Processor.GroupMask[0].Mask;
1435 for (j = 0; j < count; ++j)
1436 if (((ULONG64)1 << j) & cpu_mask)
1438 info[j].CpuSet.CoreIndex = core_index;
1439 info[j].CpuSet.EfficiencyClass = proc_info->Processor.EfficiencyClass;
1441 ++core_index;
1443 else if (proc_info->Relationship == RelationCache)
1445 if (proc_info->Cache.Level == max_cache_level)
1447 cpu_mask = proc_info->Cache.GroupMask.Mask;
1448 for (j = 0; j < count; ++j)
1449 if (((ULONG64)1 << j) & cpu_mask)
1450 info[j].CpuSet.LastLevelCacheIndex = cache_index;
1452 ++cache_index;
1454 else if (proc_info->Relationship == RelationNumaNode)
1456 cpu_mask = proc_info->NumaNode.GroupMask.Mask;
1457 for (j = 0; j < count; ++j)
1458 if (((ULONG64)1 << j) & cpu_mask)
1459 info[j].CpuSet.NumaNodeIndex = proc_info->NumaNode.NodeNumber;
1461 proc_info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((char *)proc_info + proc_info->Size);
1464 return STATUS_SUCCESS;
1467 #if defined(linux) || defined(__APPLE__)
1469 static void copy_smbios_string( char **buffer, const char *s, size_t len )
1471 if (!len) return;
1472 memcpy(*buffer, s, len + 1);
1473 *buffer += len + 1;
1476 static NTSTATUS create_smbios_tables( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1477 ULONG *required_len,
1478 const struct smbios_bios_args *bios_args,
1479 const struct smbios_system_args *system_args,
1480 const struct smbios_board_args *board_args,
1481 const struct smbios_chassis_args *chassis_args )
1483 char *buffer = (char*)sfti->TableBuffer;
1484 BYTE string_count;
1485 BYTE handle_count = 0;
1486 struct smbios_prologue *prologue;
1487 struct smbios_bios *bios;
1488 struct smbios_system *system;
1489 struct smbios_board *board;
1490 struct smbios_chassis *chassis;
1491 struct smbios_boot_info *boot_info;
1492 struct smbios_header *end_of_table;
1494 *required_len = sizeof(struct smbios_prologue);
1496 #define L(l) (l + (l ? 1 : 0))
1497 *required_len += sizeof(struct smbios_bios);
1498 *required_len += max(L(bios_args->vendor_len) + L(bios_args->version_len) + L(bios_args->date_len) + 1, 2);
1500 *required_len += sizeof(struct smbios_system);
1501 *required_len += max(L(system_args->vendor_len) + L(system_args->product_len) + L(system_args->version_len) +
1502 L(system_args->serial_len) + L(system_args->sku_len) + L(system_args->family_len) + 1, 2);
1504 *required_len += sizeof(struct smbios_board);
1505 *required_len += max(L(board_args->vendor_len) + L(board_args->product_len) + L(board_args->version_len) +
1506 L(board_args->serial_len) + L(board_args->asset_tag_len) + 1, 2);
1508 *required_len += sizeof(struct smbios_chassis);
1509 *required_len += max(L(chassis_args->vendor_len) + L(chassis_args->version_len) + L(chassis_args->serial_len) +
1510 L(chassis_args->asset_tag_len) + 1, 2);
1512 *required_len += sizeof(struct smbios_boot_info);
1513 *required_len += 2;
1515 *required_len += sizeof(struct smbios_header);
1516 *required_len += 2;
1517 #undef L
1519 sfti->TableBufferLength = *required_len;
1521 *required_len += FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
1523 if (available_len < *required_len)
1524 return STATUS_BUFFER_TOO_SMALL;
1526 prologue = (struct smbios_prologue*)buffer;
1527 prologue->calling_method = 0;
1528 prologue->major_version = 2;
1529 prologue->minor_version = 4;
1530 prologue->revision = 0;
1531 prologue->length = sfti->TableBufferLength - sizeof(struct smbios_prologue);
1532 buffer += sizeof(struct smbios_prologue);
1534 string_count = 0;
1535 bios = (struct smbios_bios*)buffer;
1536 bios->hdr.type = 0;
1537 bios->hdr.length = sizeof(struct smbios_bios);
1538 bios->hdr.handle = handle_count++;
1539 bios->vendor = bios_args->vendor_len ? ++string_count : 0;
1540 bios->version = bios_args->version_len ? ++string_count : 0;
1541 bios->start = 0;
1542 bios->date = bios_args->date_len ? ++string_count : 0;
1543 bios->size = 0;
1544 bios->characteristics = 0x4; /* not supported */
1545 bios->characteristics_ext[0] = 0;
1546 bios->characteristics_ext[1] = 0;
1547 bios->system_bios_major_release = 0xFF; /* not supported */
1548 bios->system_bios_minor_release = 0xFF; /* not supported */
1549 bios->ec_firmware_major_release = 0xFF; /* not supported */
1550 bios->ec_firmware_minor_release = 0xFF; /* not supported */
1551 buffer += sizeof(struct smbios_bios);
1553 copy_smbios_string(&buffer, bios_args->vendor, bios_args->vendor_len);
1554 copy_smbios_string(&buffer, bios_args->version, bios_args->version_len);
1555 copy_smbios_string(&buffer, bios_args->date, bios_args->date_len);
1556 if (!string_count) *buffer++ = 0;
1557 *buffer++ = 0;
1559 string_count = 0;
1560 system = (struct smbios_system*)buffer;
1561 system->hdr.type = 1;
1562 system->hdr.length = sizeof(struct smbios_system);
1563 system->hdr.handle = handle_count++;
1564 system->vendor = system_args->vendor_len ? ++string_count : 0;
1565 system->product = system_args->product_len ? ++string_count : 0;
1566 system->version = system_args->version_len ? ++string_count : 0;
1567 system->serial = system_args->serial_len ? ++string_count : 0;
1568 memcpy( system->uuid, &system_args->uuid, sizeof(GUID) );
1569 system->wake_up_type = 0x02; /* unknown */
1570 system->sku_number = system_args->sku_len ? ++string_count : 0;
1571 system->family = system_args->family_len ? ++string_count : 0;
1572 buffer += sizeof(struct smbios_system);
1574 copy_smbios_string(&buffer, system_args->vendor, system_args->vendor_len);
1575 copy_smbios_string(&buffer, system_args->product, system_args->product_len);
1576 copy_smbios_string(&buffer, system_args->version, system_args->version_len);
1577 copy_smbios_string(&buffer, system_args->serial, system_args->serial_len);
1578 copy_smbios_string(&buffer, system_args->sku, system_args->sku_len);
1579 copy_smbios_string(&buffer, system_args->family, system_args->family_len);
1580 if (!string_count) *buffer++ = 0;
1581 *buffer++ = 0;
1583 string_count = 0;
1584 chassis = (struct smbios_chassis*)buffer;
1585 chassis->hdr.type = 3;
1586 chassis->hdr.length = sizeof(struct smbios_chassis);
1587 chassis->hdr.handle = handle_count++;
1588 chassis->vendor = chassis_args->vendor_len ? ++string_count : 0;
1589 chassis->type = chassis_args->type;
1590 chassis->version = chassis_args->version_len ? ++string_count : 0;
1591 chassis->serial = chassis_args->serial_len ? ++string_count : 0;
1592 chassis->asset_tag = chassis_args->asset_tag_len ? ++string_count : 0;
1593 chassis->boot_state = 0x02; /* unknown */
1594 chassis->power_supply_state = 0x02; /* unknown */
1595 chassis->thermal_state = 0x02; /* unknown */
1596 chassis->security_status = 0x02; /* unknown */
1597 chassis->oem_defined = 0;
1598 chassis->height = 0; /* undefined */
1599 chassis->num_power_cords = 0; /* unspecified */
1600 chassis->num_contained_elements = 0;
1601 chassis->contained_element_rec_length = 3;
1602 buffer += sizeof(struct smbios_chassis);
1604 copy_smbios_string(&buffer, chassis_args->vendor, chassis_args->vendor_len);
1605 copy_smbios_string(&buffer, chassis_args->version, chassis_args->version_len);
1606 copy_smbios_string(&buffer, chassis_args->serial, chassis_args->serial_len);
1607 copy_smbios_string(&buffer, chassis_args->asset_tag, chassis_args->asset_tag_len);
1608 if (!string_count) *buffer++ = 0;
1609 *buffer++ = 0;
1611 string_count = 0;
1612 board = (struct smbios_board*)buffer;
1613 board->hdr.type = 2;
1614 board->hdr.length = sizeof(struct smbios_board);
1615 board->hdr.handle = handle_count++;
1616 board->vendor = board_args->vendor_len ? ++string_count : 0;
1617 board->product = board_args->product_len ? ++string_count : 0;
1618 board->version = board_args->version_len ? ++string_count : 0;
1619 board->serial = board_args->serial_len ? ++string_count : 0;
1620 board->asset_tag = board_args->asset_tag_len ? ++string_count : 0;
1621 board->feature_flags = 0x5; /* hosting board, removable */
1622 board->location = 0;
1623 board->chassis_handle = chassis->hdr.handle;
1624 board->board_type = 0xa; /* motherboard */
1625 board->num_contained_handles = 0;
1626 buffer += sizeof(struct smbios_board);
1628 copy_smbios_string(&buffer, board_args->vendor, board_args->vendor_len);
1629 copy_smbios_string(&buffer, board_args->product, board_args->product_len);
1630 copy_smbios_string(&buffer, board_args->version, board_args->version_len);
1631 copy_smbios_string(&buffer, board_args->serial, board_args->serial_len);
1632 copy_smbios_string(&buffer, board_args->asset_tag, board_args->asset_tag_len);
1633 if (!string_count) *buffer++ = 0;
1634 *buffer++ = 0;
1636 boot_info = (struct smbios_boot_info*)buffer;
1637 boot_info->hdr.type = 32;
1638 boot_info->hdr.length = sizeof(struct smbios_boot_info);
1639 boot_info->hdr.handle = handle_count++;
1640 memset(boot_info->reserved, 0, sizeof(boot_info->reserved));
1641 memset(boot_info->boot_status, 0, sizeof(boot_info->boot_status)); /* no errors detected */
1642 buffer += sizeof(struct smbios_boot_info);
1643 *buffer++ = 0;
1644 *buffer++ = 0;
1646 end_of_table = (struct smbios_header*)buffer;
1647 end_of_table->type = 127;
1648 end_of_table->length = sizeof(struct smbios_header);
1649 end_of_table->handle = handle_count++;
1650 buffer += sizeof(struct smbios_header);
1651 *buffer++ = 0;
1652 *buffer++ = 0;
1654 return STATUS_SUCCESS;
1657 #endif
1659 #ifdef linux
1661 static size_t get_smbios_string( const char *path, char *str, size_t size )
1663 FILE *file;
1664 size_t len;
1666 if (!(file = fopen(path, "r"))) return 0;
1668 len = fread( str, 1, size - 1, file );
1669 fclose( file );
1671 if (len >= 1 && str[len - 1] == '\n') len--;
1672 str[len] = 0;
1673 return len;
1676 static void get_system_uuid( GUID *uuid )
1678 static const unsigned char hex[] =
1680 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
1681 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
1682 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
1683 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
1684 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
1685 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
1686 0,10,11,12,13,14,15 /* 0x60 */
1688 int fd;
1690 memset( uuid, 0xff, sizeof(*uuid) );
1691 if ((fd = open( "/var/lib/dbus/machine-id", O_RDONLY )) != -1)
1693 unsigned char buf[32], *p = buf;
1694 if (read( fd, buf, sizeof(buf) ) == sizeof(buf))
1696 uuid->Data1 = hex[p[6]] << 28 | hex[p[7]] << 24 | hex[p[4]] << 20 | hex[p[5]] << 16 |
1697 hex[p[2]] << 12 | hex[p[3]] << 8 | hex[p[0]] << 4 | hex[p[1]];
1699 uuid->Data2 = hex[p[10]] << 12 | hex[p[11]] << 8 | hex[p[8]] << 4 | hex[p[9]];
1700 uuid->Data3 = hex[p[14]] << 12 | hex[p[15]] << 8 | hex[p[12]] << 4 | hex[p[13]];
1702 uuid->Data4[0] = hex[p[16]] << 4 | hex[p[17]];
1703 uuid->Data4[1] = hex[p[18]] << 4 | hex[p[19]];
1704 uuid->Data4[2] = hex[p[20]] << 4 | hex[p[21]];
1705 uuid->Data4[3] = hex[p[22]] << 4 | hex[p[23]];
1706 uuid->Data4[4] = hex[p[24]] << 4 | hex[p[25]];
1707 uuid->Data4[5] = hex[p[26]] << 4 | hex[p[27]];
1708 uuid->Data4[6] = hex[p[28]] << 4 | hex[p[29]];
1709 uuid->Data4[7] = hex[p[30]] << 4 | hex[p[31]];
1711 close( fd );
1715 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1716 ULONG *required_len )
1718 switch (sfti->ProviderSignature)
1720 case RSMB:
1722 char bios_vendor[128], bios_version[128], bios_date[128];
1723 struct smbios_bios_args bios_args;
1724 char system_vendor[128], system_product[128], system_version[128], system_serial[128];
1725 char system_sku[128], system_family[128];
1726 struct smbios_system_args system_args;
1727 char board_vendor[128], board_product[128], board_version[128], board_serial[128], board_asset_tag[128];
1728 struct smbios_board_args board_args;
1729 char chassis_vendor[128], chassis_version[128], chassis_serial[128], chassis_asset_tag[128];
1730 char chassis_type[11] = "2"; /* unknown */
1731 struct smbios_chassis_args chassis_args;
1733 #define S(s) s, sizeof(s)
1734 bios_args.vendor_len = get_smbios_string("/sys/class/dmi/id/bios_vendor", S(bios_vendor));
1735 bios_args.vendor = bios_vendor;
1736 bios_args.version_len = get_smbios_string("/sys/class/dmi/id/bios_version", S(bios_version));
1737 bios_args.version = bios_version;
1738 bios_args.date_len = get_smbios_string("/sys/class/dmi/id/bios_date", S(bios_date));
1739 bios_args.date = bios_date;
1741 system_args.vendor_len = get_smbios_string("/sys/class/dmi/id/sys_vendor", S(system_vendor));
1742 system_args.vendor = system_vendor;
1743 system_args.product_len = get_smbios_string("/sys/class/dmi/id/product_name", S(system_product));
1744 system_args.product = system_product;
1745 system_args.version_len = get_smbios_string("/sys/class/dmi/id/product_version", S(system_version));
1746 system_args.version = system_version;
1747 system_args.serial_len = get_smbios_string("/sys/class/dmi/id/product_serial", S(system_serial));
1748 system_args.serial = system_serial;
1749 get_system_uuid(&system_args.uuid);
1750 system_args.sku_len = get_smbios_string("/sys/class/dmi/id/product_sku", S(system_sku));
1751 system_args.sku = system_sku;
1752 system_args.family_len = get_smbios_string("/sys/class/dmi/id/product_family", S(system_family));
1753 system_args.family = system_family;
1755 board_args.vendor_len = get_smbios_string("/sys/class/dmi/id/board_vendor", S(board_vendor));
1756 board_args.vendor = board_vendor;
1757 board_args.product_len = get_smbios_string("/sys/class/dmi/id/board_name", S(board_product));
1758 board_args.product = board_product;
1759 board_args.version_len = get_smbios_string("/sys/class/dmi/id/board_version", S(board_version));
1760 board_args.version = board_version;
1761 board_args.serial_len = get_smbios_string("/sys/class/dmi/id/board_serial", S(board_serial));
1762 board_args.serial = board_serial;
1763 board_args.asset_tag_len = get_smbios_string("/sys/class/dmi/id/board_asset_tag", S(board_asset_tag));
1764 board_args.asset_tag = board_asset_tag;
1766 chassis_args.vendor_len = get_smbios_string("/sys/class/dmi/id/chassis_vendor", S(chassis_vendor));
1767 chassis_args.vendor = chassis_vendor;
1768 get_smbios_string("/sys/class/dmi/id/chassis_type", S(chassis_type));
1769 chassis_args.type = atoi(chassis_type);
1770 chassis_args.version_len = get_smbios_string("/sys/class/dmi/id/chassis_version", S(chassis_version));
1771 chassis_args.version = chassis_version;
1772 chassis_args.serial_len = get_smbios_string("/sys/class/dmi/id/chassis_serial", S(chassis_serial));
1773 chassis_args.serial = chassis_serial;
1774 chassis_args.asset_tag_len = get_smbios_string("/sys/class/dmi/id/chassis_tag", S(chassis_asset_tag));
1775 chassis_args.asset_tag = chassis_asset_tag;
1776 #undef S
1778 return create_smbios_tables( sfti, available_len, required_len,
1779 &bios_args, &system_args, &board_args, &chassis_args );
1781 default:
1782 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION provider %08x\n", (int)sfti->ProviderSignature);
1783 return STATUS_NOT_IMPLEMENTED;
1787 #elif defined(__APPLE__)
1789 static NTSTATUS get_smbios_from_iokit( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1790 ULONG *required_len )
1792 io_service_t service;
1793 CFDataRef data;
1794 const UInt8 *ptr;
1795 CFIndex len;
1796 struct smbios_prologue *prologue;
1797 BYTE major_version = 2, minor_version = 0;
1799 if (!(service = IOServiceGetMatchingService(0, IOServiceMatching("AppleSMBIOS"))))
1801 WARN("can't find AppleSMBIOS service\n");
1802 return STATUS_NO_MEMORY;
1805 if (!(data = IORegistryEntryCreateCFProperty(service, CFSTR("SMBIOS-EPS"), kCFAllocatorDefault, 0)))
1807 WARN("can't find SMBIOS entry point\n");
1808 IOObjectRelease(service);
1809 return STATUS_NO_MEMORY;
1812 len = CFDataGetLength(data);
1813 ptr = CFDataGetBytePtr(data);
1814 if (len >= 8 && !memcmp(ptr, "_SM_", 4))
1816 major_version = ptr[6];
1817 minor_version = ptr[7];
1819 CFRelease(data);
1821 if (!(data = IORegistryEntryCreateCFProperty(service, CFSTR("SMBIOS"), kCFAllocatorDefault, 0)))
1823 WARN("can't find SMBIOS table\n");
1824 IOObjectRelease(service);
1825 return STATUS_NO_MEMORY;
1828 len = CFDataGetLength(data);
1829 ptr = CFDataGetBytePtr(data);
1830 sfti->TableBufferLength = sizeof(*prologue) + len;
1831 *required_len = sfti->TableBufferLength + FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
1832 if (available_len < *required_len)
1834 CFRelease(data);
1835 IOObjectRelease(service);
1836 return STATUS_BUFFER_TOO_SMALL;
1839 prologue = (struct smbios_prologue *)sfti->TableBuffer;
1840 prologue->calling_method = 0;
1841 prologue->major_version = major_version;
1842 prologue->minor_version = minor_version;
1843 prologue->revision = 0;
1844 prologue->length = sfti->TableBufferLength - sizeof(*prologue);
1846 memcpy(sfti->TableBuffer + sizeof(*prologue), ptr, len);
1848 CFRelease(data);
1849 IOObjectRelease(service);
1850 return STATUS_SUCCESS;
1853 static size_t cf_to_string( CFTypeRef type_ref, char *buffer, size_t buffer_size )
1855 size_t length = 0;
1857 if (!type_ref)
1858 return 0;
1860 if (CFGetTypeID(type_ref) == CFDataGetTypeID())
1862 length = MIN(CFDataGetLength(type_ref), buffer_size);
1863 CFDataGetBytes(type_ref, CFRangeMake(0, length), (UInt8*)buffer);
1864 buffer[length] = 0;
1865 length = strlen(buffer);
1867 else if (CFGetTypeID(type_ref) == CFStringGetTypeID())
1869 if (CFStringGetCString(type_ref, buffer, buffer_size, kCFStringEncodingASCII))
1870 length = strlen(buffer);
1873 CFRelease(type_ref);
1874 return length;
1877 static NTSTATUS generate_smbios( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1878 ULONG *required_len )
1880 /* Apple Silicon Macs don't have SMBIOS, we need to generate it.
1881 * Use strings and data from IOKit when available.
1883 io_service_t platform_expert;
1884 CFDataRef cf_manufacturer, cf_model;
1885 CFStringRef cf_serial_number, cf_uuid_string;
1886 char manufacturer[128], model[128], serial_number[128];
1887 size_t manufacturer_len = 0, model_len = 0, serial_number_len = 0;
1888 GUID system_uuid = {0};
1889 struct smbios_bios_args bios_args;
1890 struct smbios_system_args system_args;
1891 struct smbios_board_args board_args;
1892 struct smbios_chassis_args chassis_args;
1894 platform_expert = IOServiceGetMatchingService(0, IOServiceMatching("IOPlatformExpertDevice"));
1895 if (!platform_expert)
1896 return STATUS_NO_MEMORY;
1898 cf_manufacturer = IORegistryEntryCreateCFProperty(platform_expert, CFSTR("manufacturer"), kCFAllocatorDefault, 0);
1899 cf_model = IORegistryEntryCreateCFProperty(platform_expert, CFSTR("model"), kCFAllocatorDefault, 0);
1900 cf_serial_number = IORegistryEntryCreateCFProperty(platform_expert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0);
1901 cf_uuid_string = IORegistryEntryCreateCFProperty(platform_expert, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
1903 manufacturer_len = cf_to_string(cf_manufacturer, manufacturer, sizeof(manufacturer));
1904 model_len = cf_to_string(cf_model, model, sizeof(model));
1905 serial_number_len = cf_to_string(cf_serial_number, serial_number, sizeof(serial_number));
1907 if (cf_uuid_string)
1909 CFUUIDRef cf_uuid;
1910 CFUUIDBytes bytes;
1912 cf_uuid = CFUUIDCreateFromString(kCFAllocatorDefault, cf_uuid_string);
1913 bytes = CFUUIDGetUUIDBytes(cf_uuid);
1915 system_uuid.Data1 = (bytes.byte0 << 24) | (bytes.byte1 << 16) | (bytes.byte2 << 8) | bytes.byte3;
1916 system_uuid.Data2 = (bytes.byte4 << 8) | bytes.byte5;
1917 system_uuid.Data3 = (bytes.byte6 << 8) | bytes.byte7;
1918 memcpy(&system_uuid.Data4, &bytes.byte8, sizeof(system_uuid.Data4));
1920 CFRelease(cf_uuid);
1921 CFRelease(cf_uuid_string);
1924 IOObjectRelease(platform_expert);
1926 #define S(s, t) { s ## _len = t ## _len; s = t; }
1927 #define STR(s, t) { s ## _len = sizeof(t)-1; s = t; }
1928 S(bios_args.vendor, manufacturer);
1929 /* BIOS version and date are both required */
1930 STR(bios_args.version, "1.0");
1931 STR(bios_args.date, "01/01/2021");
1933 S(system_args.vendor, manufacturer);
1934 S(system_args.product, model);
1935 STR(system_args.version, "1.0");
1936 S(system_args.serial, serial_number);
1937 system_args.uuid = system_uuid;
1938 system_args.sku_len = 0;
1939 S(system_args.family, model);
1941 S(board_args.vendor, manufacturer);
1942 S(board_args.product, model);
1943 S(board_args.version, model);
1944 S(board_args.serial, serial_number);
1945 board_args.asset_tag_len = 0;
1947 S(chassis_args.vendor, manufacturer);
1948 chassis_args.type = 2; /* unknown */
1949 chassis_args.version_len = 0;
1950 S(chassis_args.serial, serial_number);
1951 chassis_args.asset_tag_len = 0;
1952 #undef STR
1953 #undef S
1955 return create_smbios_tables( sfti, available_len, required_len,
1956 &bios_args, &system_args, &board_args, &chassis_args );
1959 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1960 ULONG *required_len )
1962 switch (sfti->ProviderSignature)
1964 case RSMB:
1966 NTSTATUS ret;
1967 ret = get_smbios_from_iokit(sfti, available_len, required_len);
1968 if (ret == STATUS_NO_MEMORY)
1969 ret = generate_smbios(sfti, available_len, required_len);
1970 return ret;
1972 default:
1973 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION provider %08x\n", (unsigned int)sfti->ProviderSignature);
1974 return STATUS_NOT_IMPLEMENTED;
1978 #else
1980 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1981 ULONG *required_len )
1983 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION\n");
1984 sfti->TableBufferLength = 0;
1985 return STATUS_NOT_IMPLEMENTED;
1988 #endif
1990 static void get_performance_info( SYSTEM_PERFORMANCE_INFORMATION *info )
1992 unsigned long long totalram = 0, freeram = 0, totalswap = 0, freeswap = 0;
1994 memset( info, 0, sizeof(*info) );
1996 #if defined(linux)
1998 FILE *fp;
2000 if ((fp = fopen("/proc/uptime", "r")))
2002 double uptime, idle_time;
2004 fscanf(fp, "%lf %lf", &uptime, &idle_time);
2005 fclose(fp);
2006 info->IdleTime.QuadPart = 10000000 * idle_time;
2009 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
2011 static int clockrate_name[] = { CTL_KERN, KERN_CLOCKRATE };
2012 size_t size = 0;
2013 struct clockinfo clockrate;
2014 long ptimes[CPUSTATES];
2016 size = sizeof(clockrate);
2017 if (!sysctl(clockrate_name, 2, &clockrate, &size, NULL, 0))
2019 size = sizeof(ptimes);
2020 if (!sysctlbyname("kern.cp_time", ptimes, &size, NULL, 0))
2021 info->IdleTime.QuadPart = (ULONGLONG)ptimes[CP_IDLE] * 10000000 / clockrate.stathz;
2024 #elif defined(__APPLE__)
2026 host_name_port_t host = mach_host_self();
2027 struct host_cpu_load_info load_info;
2028 mach_msg_type_number_t count;
2030 count = HOST_CPU_LOAD_INFO_COUNT;
2031 if (host_statistics(host, HOST_CPU_LOAD_INFO, (host_info_t)&load_info, &count) == KERN_SUCCESS)
2033 /* Believe it or not, based on my reading of XNU source, this is
2034 * already in the units we want (100 ns).
2036 info->IdleTime.QuadPart = load_info.cpu_ticks[CPU_STATE_IDLE];
2038 mach_port_deallocate(mach_task_self(), host);
2040 #else
2042 static ULONGLONG idle;
2043 /* many programs expect IdleTime to change so fake change */
2044 info->IdleTime.QuadPart = ++idle;
2046 #endif
2048 #ifdef linux
2050 FILE *fp;
2052 if ((fp = fopen("/proc/meminfo", "r")))
2054 unsigned long long value, mem_available = 0;
2055 char line[64];
2057 while (fgets(line, sizeof(line), fp))
2059 if(sscanf(line, "MemTotal: %llu kB", &value) == 1)
2060 totalram += value * 1024;
2061 else if(sscanf(line, "MemFree: %llu kB", &value) == 1)
2062 freeram += value * 1024;
2063 else if(sscanf(line, "SwapTotal: %llu kB", &value) == 1)
2064 totalswap += value * 1024;
2065 else if(sscanf(line, "SwapFree: %llu kB", &value) == 1)
2066 freeswap += value * 1024;
2067 else if (sscanf(line, "Buffers: %llu", &value))
2068 freeram += value * 1024;
2069 else if (sscanf(line, "Cached: %llu", &value))
2070 freeram += value * 1024;
2071 else if (sscanf(line, "MemAvailable: %llu", &value))
2072 mem_available = value * 1024;
2074 fclose(fp);
2075 if (mem_available) freeram = mem_available;
2078 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || \
2079 defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
2081 #ifdef __APPLE__
2082 unsigned int val;
2083 #else
2084 unsigned long val;
2085 #endif
2086 int mib[2];
2087 size_t size_sys;
2089 mib[0] = CTL_HW;
2090 #ifdef HW_MEMSIZE
2092 uint64_t val64;
2093 mib[1] = HW_MEMSIZE;
2094 size_sys = sizeof(val64);
2095 if (!sysctl(mib, 2, &val64, &size_sys, NULL, 0) && size_sys == sizeof(val64)) totalram = val64;
2097 #endif
2099 #ifdef HAVE_MACH_MACH_H
2101 host_name_port_t host = mach_host_self();
2102 mach_msg_type_number_t count;
2103 #ifdef HOST_VM_INFO64_COUNT
2104 vm_statistics64_data_t vm_stat;
2106 count = HOST_VM_INFO64_COUNT;
2107 if (host_statistics64(host, HOST_VM_INFO64, (host_info64_t)&vm_stat, &count) == KERN_SUCCESS)
2108 freeram = (vm_stat.free_count + vm_stat.inactive_count) * (ULONGLONG)page_size;
2109 #endif
2110 if (!totalram)
2112 host_basic_info_data_t info;
2113 count = HOST_BASIC_INFO_COUNT;
2114 if (host_info(host, HOST_BASIC_INFO, (host_info_t)&info, &count) == KERN_SUCCESS)
2115 totalram = info.max_mem;
2117 mach_port_deallocate(mach_task_self(), host);
2119 #endif
2121 if (!totalram)
2123 mib[1] = HW_PHYSMEM;
2124 size_sys = sizeof(val);
2125 if (!sysctl(mib, 2, &val, &size_sys, NULL, 0) && size_sys == sizeof(val)) totalram = val;
2127 if (!freeram)
2129 mib[1] = HW_USERMEM;
2130 size_sys = sizeof(val);
2131 if (!sysctl(mib, 2, &val, &size_sys, NULL, 0) && size_sys == sizeof(val)) freeram = val;
2133 #ifdef VM_SWAPUSAGE
2135 struct xsw_usage swap;
2136 mib[0] = CTL_VM;
2137 mib[1] = VM_SWAPUSAGE;
2138 size_sys = sizeof(swap);
2139 if (!sysctl(mib, 2, &swap, &size_sys, NULL, 0) && size_sys == sizeof(swap))
2141 totalswap = swap.xsu_total;
2142 freeswap = swap.xsu_avail;
2145 #endif
2147 #endif
2149 /* Titan Quest refuses to run if TotalPageFile <= TotalPhys */
2150 if (!totalswap) totalswap = page_size;
2152 info->AvailablePages = freeram / page_size;
2153 info->TotalCommittedPages = (totalram + totalswap - freeram - freeswap) / page_size;
2154 info->TotalCommitLimit = (totalram + totalswap) / page_size;
2158 /* calculate the mday of dst change date, so that for instance Sun 5 Oct 2007
2159 * (last Sunday in October of 2007) becomes Sun Oct 28 2007
2161 * Note: year, day and month must be in unix format.
2163 static int weekday_to_mday(int year, int day, int mon, int day_of_week)
2165 struct tm date;
2166 time_t tmp;
2167 int wday, mday;
2169 /* find first day in the month matching week day of the date */
2170 memset(&date, 0, sizeof(date));
2171 date.tm_year = year;
2172 date.tm_mon = mon;
2173 date.tm_mday = -1;
2174 date.tm_wday = -1;
2177 date.tm_mday++;
2178 tmp = mktime(&date);
2179 } while (date.tm_wday != day_of_week || date.tm_mon != mon);
2181 mday = date.tm_mday;
2183 /* find number of week days in the month matching week day of the date */
2184 wday = 1; /* 1 - 1st, ...., 5 - last */
2185 while (wday < day)
2187 struct tm *tm;
2189 date.tm_mday += 7;
2190 tmp = mktime(&date);
2191 tm = localtime(&tmp);
2192 if (tm->tm_mon != mon)
2193 break;
2194 mday = tm->tm_mday;
2195 wday++;
2198 return mday;
2201 static BOOL match_tz_date( const RTL_SYSTEM_TIME *st, const RTL_SYSTEM_TIME *reg_st )
2203 WORD wDay;
2205 if (st->wMonth != reg_st->wMonth) return FALSE;
2206 if (!st->wMonth) return TRUE; /* no transition dates */
2207 wDay = reg_st->wDay;
2208 if (!reg_st->wYear) /* date in a day-of-week format */
2209 wDay = weekday_to_mday(st->wYear - 1900, reg_st->wDay, reg_st->wMonth - 1, reg_st->wDayOfWeek);
2211 /* special case for 23:59:59.999, match with 0:00:00.000 on the following day */
2212 if (!reg_st->wYear && reg_st->wHour == 23 && reg_st->wMinute == 59 &&
2213 reg_st->wSecond == 59 && reg_st->wMilliseconds == 999)
2214 return (st->wDay == wDay + 1 && !st->wHour && !st->wMinute && !st->wSecond && !st->wMilliseconds);
2216 return (st->wDay == wDay &&
2217 st->wHour == reg_st->wHour &&
2218 st->wMinute == reg_st->wMinute &&
2219 st->wSecond == reg_st->wSecond &&
2220 st->wMilliseconds == reg_st->wMilliseconds);
2223 static BOOL match_tz_info( const RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi,
2224 const RTL_DYNAMIC_TIME_ZONE_INFORMATION *reg_tzi )
2226 return (tzi->Bias == reg_tzi->Bias &&
2227 match_tz_date(&tzi->StandardDate, &reg_tzi->StandardDate) &&
2228 match_tz_date(&tzi->DaylightDate, &reg_tzi->DaylightDate));
2231 static BOOL match_past_tz_bias( time_t past_time, LONG past_bias )
2233 LONG bias;
2234 struct tm *tm;
2235 if (!past_time) return TRUE;
2237 tm = gmtime( &past_time );
2238 bias = (LONG)(mktime(tm) - past_time) / 60;
2239 return bias == past_bias;
2242 static BOOL match_tz_name( const char *tz_name, const RTL_DYNAMIC_TIME_ZONE_INFORMATION *reg_tzi )
2244 static const struct {
2245 WCHAR key_name[32];
2246 const char *short_name;
2247 time_t past_time;
2248 LONG past_bias;
2250 mapping[] =
2252 { {'N','o','r','t','h',' ','K','o','r','e','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
2253 "KST", 1451606400 /* 2016-01-01 00:00:00 UTC */, -510 },
2254 { {'K','o','r','e','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
2255 "KST", 1451606400 /* 2016-01-01 00:00:00 UTC */, -540 },
2256 { {'T','o','k','y','o',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
2257 "JST" },
2258 { {'Y','a','k','u','t','s','k',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
2259 "+09" }, /* YAKST was used until tzdata 2016f */
2261 unsigned int i;
2263 if (reg_tzi->DaylightDate.wMonth) return TRUE;
2264 for (i = 0; i < ARRAY_SIZE(mapping); i++)
2266 if (!wcscmp( mapping[i].key_name, reg_tzi->TimeZoneKeyName ))
2267 return !strcmp( mapping[i].short_name, tz_name )
2268 && match_past_tz_bias( mapping[i].past_time, mapping[i].past_bias );
2270 return TRUE;
2273 static BOOL reg_query_value( HKEY key, LPCWSTR name, DWORD type, void *data, DWORD count )
2275 char buf[256];
2276 UNICODE_STRING nameW;
2277 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buf;
2279 if (count > sizeof(buf) - offsetof(KEY_VALUE_PARTIAL_INFORMATION, Data)) return FALSE;
2281 nameW.Buffer = (WCHAR *)name;
2282 nameW.Length = wcslen( name ) * sizeof(WCHAR);
2283 if (NtQueryValueKey( key, &nameW, KeyValuePartialInformation, buf, sizeof(buf), &count ))
2284 return FALSE;
2286 if (info->Type != type) return FALSE;
2287 memcpy( data, info->Data, info->DataLength );
2288 return TRUE;
2291 static void find_reg_tz_info(RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi, const char* tz_name, int year)
2293 static const WCHAR stdW[] = { 'S','t','d',0 };
2294 static const WCHAR dltW[] = { 'D','l','t',0 };
2295 static const WCHAR mui_stdW[] = { 'M','U','I','_','S','t','d',0 };
2296 static const WCHAR mui_dltW[] = { 'M','U','I','_','D','l','t',0 };
2297 static const WCHAR tziW[] = { 'T','Z','I',0 };
2298 static const WCHAR Time_ZonesW[] = { '\\','R','e','g','i','s','t','r','y','\\',
2299 'M','a','c','h','i','n','e','\\',
2300 'S','o','f','t','w','a','r','e','\\',
2301 'M','i','c','r','o','s','o','f','t','\\',
2302 'W','i','n','d','o','w','s',' ','N','T','\\',
2303 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2304 'T','i','m','e',' ','Z','o','n','e','s',0 };
2305 static const WCHAR Dynamic_DstW[] = { 'D','y','n','a','m','i','c',' ','D','S','T',0 };
2306 RTL_DYNAMIC_TIME_ZONE_INFORMATION reg_tzi;
2307 HANDLE key, subkey, subkey_dyn = 0;
2308 ULONG idx, len;
2309 OBJECT_ATTRIBUTES attr;
2310 UNICODE_STRING nameW;
2311 WCHAR yearW[16];
2312 char buffer[128];
2313 KEY_BASIC_INFORMATION *info = (KEY_BASIC_INFORMATION *)buffer;
2315 snprintf( buffer, sizeof(buffer), "%u", year );
2316 ascii_to_unicode( yearW, buffer, strlen(buffer) + 1 );
2317 init_unicode_string( &nameW, Time_ZonesW );
2318 InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
2319 if (NtOpenKey( &key, KEY_READ, &attr )) return;
2321 idx = 0;
2322 while (!NtEnumerateKey( key, idx++, KeyBasicInformation, buffer, sizeof(buffer), &len ))
2324 struct tz_reg_data
2326 LONG bias;
2327 LONG std_bias;
2328 LONG dlt_bias;
2329 RTL_SYSTEM_TIME std_date;
2330 RTL_SYSTEM_TIME dlt_date;
2331 } tz_data;
2332 BOOL is_dynamic = FALSE;
2334 nameW.Buffer = info->Name;
2335 nameW.Length = info->NameLength;
2336 attr.RootDirectory = key;
2337 if (NtOpenKey( &subkey, KEY_READ, &attr )) continue;
2339 memset( &reg_tzi, 0, sizeof(reg_tzi) );
2340 memcpy(reg_tzi.TimeZoneKeyName, nameW.Buffer, nameW.Length);
2341 reg_tzi.TimeZoneKeyName[nameW.Length/sizeof(WCHAR)] = 0;
2343 if (!reg_query_value(subkey, mui_stdW, REG_SZ, reg_tzi.StandardName, sizeof(reg_tzi.StandardName)) &&
2344 !reg_query_value(subkey, stdW, REG_SZ, reg_tzi.StandardName, sizeof(reg_tzi.StandardName)))
2345 goto next;
2347 if (!reg_query_value(subkey, mui_dltW, REG_SZ, reg_tzi.DaylightName, sizeof(reg_tzi.DaylightName)) &&
2348 !reg_query_value(subkey, dltW, REG_SZ, reg_tzi.DaylightName, sizeof(reg_tzi.DaylightName)))
2349 goto next;
2351 /* Check for Dynamic DST entry first */
2352 nameW.Buffer = (WCHAR *)Dynamic_DstW;
2353 nameW.Length = sizeof(Dynamic_DstW) - sizeof(WCHAR);
2354 attr.RootDirectory = subkey;
2355 if (!NtOpenKey( &subkey_dyn, KEY_READ, &attr ))
2357 is_dynamic = reg_query_value( subkey_dyn, yearW, REG_BINARY, &tz_data, sizeof(tz_data) );
2358 NtClose( subkey_dyn );
2360 if (!is_dynamic && !reg_query_value( subkey, tziW, REG_BINARY, &tz_data, sizeof(tz_data) ))
2361 goto next;
2363 reg_tzi.Bias = tz_data.bias;
2364 reg_tzi.StandardBias = tz_data.std_bias;
2365 reg_tzi.DaylightBias = tz_data.dlt_bias;
2366 reg_tzi.StandardDate = tz_data.std_date;
2367 reg_tzi.DaylightDate = tz_data.dlt_date;
2369 TRACE("%s: bias %d\n", debugstr_us(&nameW), (int)reg_tzi.Bias);
2370 TRACE("std (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
2371 reg_tzi.StandardDate.wDay, reg_tzi.StandardDate.wMonth,
2372 reg_tzi.StandardDate.wYear, reg_tzi.StandardDate.wDayOfWeek,
2373 reg_tzi.StandardDate.wHour, reg_tzi.StandardDate.wMinute,
2374 reg_tzi.StandardDate.wSecond, reg_tzi.StandardDate.wMilliseconds,
2375 (int)reg_tzi.StandardBias);
2376 TRACE("dst (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
2377 reg_tzi.DaylightDate.wDay, reg_tzi.DaylightDate.wMonth,
2378 reg_tzi.DaylightDate.wYear, reg_tzi.DaylightDate.wDayOfWeek,
2379 reg_tzi.DaylightDate.wHour, reg_tzi.DaylightDate.wMinute,
2380 reg_tzi.DaylightDate.wSecond, reg_tzi.DaylightDate.wMilliseconds,
2381 (int)reg_tzi.DaylightBias);
2383 if (match_tz_info( tzi, &reg_tzi ) && match_tz_name( tz_name, &reg_tzi ))
2385 *tzi = reg_tzi;
2386 NtClose( subkey );
2387 NtClose( key );
2388 return;
2390 next:
2391 NtClose( subkey );
2393 NtClose( key );
2395 if (idx == 1) return; /* registry info not initialized yet */
2397 FIXME("Can't find matching timezone information in the registry for "
2398 "%s, bias %d, std (d/m/y): %u/%02u/%04u, dlt (d/m/y): %u/%02u/%04u\n",
2399 tz_name, (int)tzi->Bias,
2400 tzi->StandardDate.wDay, tzi->StandardDate.wMonth, tzi->StandardDate.wYear,
2401 tzi->DaylightDate.wDay, tzi->DaylightDate.wMonth, tzi->DaylightDate.wYear);
2404 static time_t find_dst_change(time_t start, time_t end, int *is_dst)
2406 struct tm *tm;
2407 ULONGLONG min = (sizeof(time_t) == sizeof(int)) ? (ULONG)start : start;
2408 ULONGLONG max = (sizeof(time_t) == sizeof(int)) ? (ULONG)end : end;
2410 tm = localtime(&start);
2411 *is_dst = !tm->tm_isdst;
2412 TRACE("starting date isdst %d, %s", !*is_dst, ctime(&start));
2414 while (min <= max)
2416 time_t pos = (min + max) / 2;
2417 tm = localtime(&pos);
2419 if (tm->tm_isdst != *is_dst)
2420 min = pos + 1;
2421 else
2422 max = pos - 1;
2424 return min;
2427 static void get_timezone_info( RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi )
2429 static pthread_mutex_t tz_mutex = PTHREAD_MUTEX_INITIALIZER;
2430 static RTL_DYNAMIC_TIME_ZONE_INFORMATION cached_tzi;
2431 static int current_year = -1, current_bias = 65535;
2432 struct tm *tm;
2433 char tz_name[16];
2434 time_t year_start, year_end, tmp, dlt = 0, std = 0;
2435 int is_dst, bias;
2437 mutex_lock( &tz_mutex );
2439 year_start = time(NULL);
2440 tm = gmtime(&year_start);
2441 bias = (LONG)(mktime(tm) - year_start) / 60;
2443 tm = localtime(&year_start);
2444 if (current_year == tm->tm_year && current_bias == bias)
2446 *tzi = cached_tzi;
2447 mutex_unlock( &tz_mutex );
2448 return;
2451 memset(tzi, 0, sizeof(*tzi));
2452 if (!strftime(tz_name, sizeof(tz_name), "%Z", tm)) {
2453 /* not enough room or another error */
2454 tz_name[0] = '\0';
2457 TRACE("tz data will be valid through year %d, bias %d\n", tm->tm_year + 1900, bias);
2458 current_year = tm->tm_year;
2459 current_bias = bias;
2461 tzi->Bias = bias;
2463 tm->tm_isdst = 0;
2464 tm->tm_mday = 1;
2465 tm->tm_mon = tm->tm_hour = tm->tm_min = tm->tm_sec = tm->tm_wday = tm->tm_yday = 0;
2466 year_start = mktime(tm);
2467 TRACE("year_start: %s", ctime(&year_start));
2469 tm->tm_mday = tm->tm_wday = tm->tm_yday = 0;
2470 tm->tm_mon = 12;
2471 tm->tm_hour = 23;
2472 tm->tm_min = tm->tm_sec = 59;
2473 year_end = mktime(tm);
2474 TRACE("year_end: %s", ctime(&year_end));
2476 tmp = find_dst_change(year_start, year_end, &is_dst);
2477 if (is_dst)
2478 dlt = tmp;
2479 else
2480 std = tmp;
2482 tmp = find_dst_change(tmp, year_end, &is_dst);
2483 if (is_dst)
2484 dlt = tmp;
2485 else
2486 std = tmp;
2488 TRACE("std: %s", ctime(&std));
2489 TRACE("dlt: %s", ctime(&dlt));
2491 if (dlt == std || !dlt || !std)
2492 TRACE("there is no daylight saving rules in this time zone\n");
2493 else
2495 tmp = dlt - tzi->Bias * 60;
2496 tm = gmtime(&tmp);
2497 TRACE("dlt gmtime: %s", asctime(tm));
2499 tzi->DaylightBias = -60;
2500 tzi->DaylightDate.wYear = tm->tm_year + 1900;
2501 tzi->DaylightDate.wMonth = tm->tm_mon + 1;
2502 tzi->DaylightDate.wDayOfWeek = tm->tm_wday;
2503 tzi->DaylightDate.wDay = tm->tm_mday;
2504 tzi->DaylightDate.wHour = tm->tm_hour;
2505 tzi->DaylightDate.wMinute = tm->tm_min;
2506 tzi->DaylightDate.wSecond = tm->tm_sec;
2507 tzi->DaylightDate.wMilliseconds = 0;
2509 TRACE("daylight (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
2510 tzi->DaylightDate.wDay, tzi->DaylightDate.wMonth,
2511 tzi->DaylightDate.wYear, tzi->DaylightDate.wDayOfWeek,
2512 tzi->DaylightDate.wHour, tzi->DaylightDate.wMinute,
2513 tzi->DaylightDate.wSecond, tzi->DaylightDate.wMilliseconds,
2514 (int)tzi->DaylightBias);
2516 tmp = std - tzi->Bias * 60 - tzi->DaylightBias * 60;
2517 tm = gmtime(&tmp);
2518 TRACE("std gmtime: %s", asctime(tm));
2520 tzi->StandardBias = 0;
2521 tzi->StandardDate.wYear = tm->tm_year + 1900;
2522 tzi->StandardDate.wMonth = tm->tm_mon + 1;
2523 tzi->StandardDate.wDayOfWeek = tm->tm_wday;
2524 tzi->StandardDate.wDay = tm->tm_mday;
2525 tzi->StandardDate.wHour = tm->tm_hour;
2526 tzi->StandardDate.wMinute = tm->tm_min;
2527 tzi->StandardDate.wSecond = tm->tm_sec;
2528 tzi->StandardDate.wMilliseconds = 0;
2530 TRACE("standard (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
2531 tzi->StandardDate.wDay, tzi->StandardDate.wMonth,
2532 tzi->StandardDate.wYear, tzi->StandardDate.wDayOfWeek,
2533 tzi->StandardDate.wHour, tzi->StandardDate.wMinute,
2534 tzi->StandardDate.wSecond, tzi->StandardDate.wMilliseconds,
2535 (int)tzi->StandardBias);
2538 find_reg_tz_info(tzi, tz_name, current_year + 1900);
2539 cached_tzi = *tzi;
2540 mutex_unlock( &tz_mutex );
2544 static void read_dev_urandom( void *buf, ULONG len )
2546 int fd = open( "/dev/urandom", O_RDONLY );
2547 if (fd != -1)
2549 int ret;
2552 ret = read( fd, buf, len );
2554 while (ret == -1 && errno == EINTR);
2555 close( fd );
2557 else WARN( "can't open /dev/urandom\n" );
2560 static unsigned int get_system_process_info( SYSTEM_INFORMATION_CLASS class, void *info, ULONG size, ULONG *len )
2562 unsigned int process_count, total_thread_count, total_name_len, i, j;
2563 unsigned int thread_info_size;
2564 unsigned int pos = 0;
2565 char *buffer = NULL;
2566 unsigned int ret;
2568 C_ASSERT( sizeof(struct thread_info) <= sizeof(SYSTEM_THREAD_INFORMATION) );
2569 C_ASSERT( sizeof(struct process_info) <= sizeof(SYSTEM_PROCESS_INFORMATION) );
2571 if (class == SystemExtendedProcessInformation)
2572 thread_info_size = sizeof(SYSTEM_EXTENDED_THREAD_INFORMATION);
2573 else
2574 thread_info_size = sizeof(SYSTEM_THREAD_INFORMATION);
2576 *len = 0;
2577 if (size && !(buffer = malloc( size ))) return STATUS_NO_MEMORY;
2579 SERVER_START_REQ( list_processes )
2581 wine_server_set_reply( req, buffer, size );
2582 ret = wine_server_call( req );
2583 total_thread_count = reply->total_thread_count;
2584 total_name_len = reply->total_name_len;
2585 process_count = reply->process_count;
2587 SERVER_END_REQ;
2589 if (ret)
2591 if (ret == STATUS_INFO_LENGTH_MISMATCH)
2592 *len = sizeof(SYSTEM_PROCESS_INFORMATION) * process_count
2593 + (total_name_len + process_count) * sizeof(WCHAR)
2594 + total_thread_count * thread_info_size;
2596 free( buffer );
2597 return ret;
2600 for (i = 0; i < process_count; i++)
2602 SYSTEM_PROCESS_INFORMATION *nt_process = (SYSTEM_PROCESS_INFORMATION *)((char *)info + *len);
2603 const struct process_info *server_process;
2604 const WCHAR *server_name, *file_part;
2605 ULONG proc_len;
2606 ULONG name_len = 0;
2608 pos = (pos + 7) & ~7;
2609 server_process = (const struct process_info *)(buffer + pos);
2610 pos += sizeof(*server_process);
2612 server_name = (const WCHAR *)(buffer + pos);
2613 file_part = server_name + (server_process->name_len / sizeof(WCHAR));
2614 pos += server_process->name_len;
2615 while (file_part > server_name && file_part[-1] != '\\')
2617 file_part--;
2618 name_len++;
2621 proc_len = sizeof(*nt_process) + server_process->thread_count * thread_info_size
2622 + (name_len + 1) * sizeof(WCHAR);
2623 *len += proc_len;
2625 if (*len <= size)
2627 memset(nt_process, 0, proc_len);
2628 if (i < process_count - 1)
2629 nt_process->NextEntryOffset = proc_len;
2630 nt_process->CreationTime.QuadPart = server_process->start_time;
2631 nt_process->dwThreadCount = server_process->thread_count;
2632 nt_process->dwBasePriority = server_process->priority;
2633 nt_process->UniqueProcessId = UlongToHandle(server_process->pid);
2634 nt_process->ParentProcessId = UlongToHandle(server_process->parent_pid);
2635 nt_process->SessionId = server_process->session_id;
2636 nt_process->HandleCount = server_process->handle_count;
2637 get_thread_times( server_process->unix_pid, -1, &nt_process->KernelTime, &nt_process->UserTime );
2638 fill_vm_counters( &nt_process->vmCounters, server_process->unix_pid );
2641 pos = (pos + 7) & ~7;
2642 for (j = 0; j < server_process->thread_count; j++)
2644 const struct thread_info *server_thread = (const struct thread_info *)(buffer + pos);
2645 SYSTEM_EXTENDED_THREAD_INFORMATION *ti;
2647 if (*len <= size)
2649 ti = (SYSTEM_EXTENDED_THREAD_INFORMATION *)((BYTE *)nt_process->ti + j * thread_info_size);
2650 ti->ThreadInfo.CreateTime.QuadPart = server_thread->start_time;
2651 ti->ThreadInfo.ClientId.UniqueProcess = UlongToHandle(server_process->pid);
2652 ti->ThreadInfo.ClientId.UniqueThread = UlongToHandle(server_thread->tid);
2653 ti->ThreadInfo.dwCurrentPriority = server_thread->current_priority;
2654 ti->ThreadInfo.dwBasePriority = server_thread->base_priority;
2655 get_thread_times( server_process->unix_pid, server_thread->unix_tid,
2656 &ti->ThreadInfo.KernelTime, &ti->ThreadInfo.UserTime );
2657 if (class == SystemExtendedProcessInformation)
2659 ti->Win32StartAddress = wine_server_get_ptr( server_thread->entry_point );
2660 ti->TebBase = wine_server_get_ptr( server_thread->teb );
2664 pos += sizeof(*server_thread);
2667 if (*len <= size)
2669 nt_process->ProcessName.Buffer = (WCHAR *)((BYTE *)nt_process->ti
2670 + server_process->thread_count * thread_info_size);
2671 nt_process->ProcessName.Length = name_len * sizeof(WCHAR);
2672 nt_process->ProcessName.MaximumLength = (name_len + 1) * sizeof(WCHAR);
2673 memcpy(nt_process->ProcessName.Buffer, file_part, name_len * sizeof(WCHAR));
2674 nt_process->ProcessName.Buffer[name_len] = 0;
2678 if (*len > size) ret = STATUS_INFO_LENGTH_MISMATCH;
2679 free( buffer );
2680 return ret;
2683 /******************************************************************************
2684 * NtQuerySystemInformation (NTDLL.@)
2686 NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class,
2687 void *info, ULONG size, ULONG *ret_size )
2689 unsigned int ret = STATUS_SUCCESS;
2690 ULONG len = 0;
2692 TRACE( "(0x%08x,%p,0x%08x,%p)\n", class, info, (int)size, ret_size );
2694 switch (class)
2696 case SystemNativeBasicInformation: /* 114 */
2697 if (!is_win64) return STATUS_INVALID_INFO_CLASS;
2698 /* fall through */
2699 case SystemBasicInformation: /* 0 */
2701 SYSTEM_BASIC_INFORMATION sbi;
2703 virtual_get_system_info( &sbi, FALSE );
2704 len = sizeof(sbi);
2705 if (size == len)
2707 if (!info) ret = STATUS_ACCESS_VIOLATION;
2708 else memcpy( info, &sbi, len);
2710 else ret = STATUS_INFO_LENGTH_MISMATCH;
2711 break;
2714 case SystemCpuInformation: /* 1 */
2715 if (size >= (len = sizeof(cpu_info))) memcpy(info, &cpu_info, len);
2716 else ret = STATUS_INFO_LENGTH_MISMATCH;
2717 break;
2719 case SystemPerformanceInformation: /* 2 */
2721 SYSTEM_PERFORMANCE_INFORMATION spi;
2722 static BOOL fixme_written = FALSE;
2724 get_performance_info( &spi );
2725 len = sizeof(spi);
2726 if (size >= len)
2728 if (!info) ret = STATUS_ACCESS_VIOLATION;
2729 else memcpy( info, &spi, len);
2731 else ret = STATUS_INFO_LENGTH_MISMATCH;
2732 if(!fixme_written) {
2733 FIXME("info_class SYSTEM_PERFORMANCE_INFORMATION\n");
2734 fixme_written = TRUE;
2736 break;
2739 case SystemTimeOfDayInformation: /* 3 */
2741 static LONGLONG last_bias;
2742 static time_t last_utc;
2743 struct tm *tm;
2744 time_t utc;
2745 SYSTEM_TIMEOFDAY_INFORMATION sti = {{{ 0 }}};
2747 sti.BootTime.QuadPart = server_start_time;
2749 utc = time( NULL );
2750 pthread_mutex_lock( &timezone_mutex );
2751 if (utc != last_utc)
2753 last_utc = utc;
2754 tm = gmtime( &utc );
2755 last_bias = mktime( tm ) - utc;
2756 tm = localtime( &utc );
2757 if (tm->tm_isdst) last_bias -= 3600;
2758 last_bias *= TICKSPERSEC;
2760 sti.TimeZoneBias.QuadPart = last_bias;
2761 pthread_mutex_unlock( &timezone_mutex );
2763 NtQuerySystemTime( &sti.SystemTime );
2765 if (size <= sizeof(sti))
2767 len = size;
2768 if (!info) ret = STATUS_ACCESS_VIOLATION;
2769 else memcpy( info, &sti, size);
2771 else ret = STATUS_INFO_LENGTH_MISMATCH;
2772 break;
2775 case SystemProcessInformation: /* 5 */
2776 ret = get_system_process_info( class, info, size, &len );
2777 break;
2779 case SystemProcessorPerformanceInformation: /* 8 */
2781 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL;
2782 unsigned int cpus = 0;
2783 int out_cpus = size / sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
2785 if (out_cpus == 0)
2787 len = 0;
2788 ret = STATUS_INFO_LENGTH_MISMATCH;
2789 break;
2791 if (!(sppi = calloc( out_cpus, sizeof(*sppi) )))
2793 ret = STATUS_NO_MEMORY;
2794 break;
2796 else
2797 #ifdef __APPLE__
2799 processor_cpu_load_info_data_t *pinfo;
2800 mach_msg_type_number_t info_count;
2801 host_name_port_t host = mach_host_self ();
2803 if (host_processor_info( host,
2804 PROCESSOR_CPU_LOAD_INFO,
2805 &cpus,
2806 (processor_info_array_t*)&pinfo,
2807 &info_count) == 0)
2809 int i;
2810 cpus = min(cpus,out_cpus);
2811 for (i = 0; i < cpus; i++)
2813 sppi[i].IdleTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_IDLE];
2814 sppi[i].KernelTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_SYSTEM];
2815 sppi[i].UserTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_USER];
2817 vm_deallocate (mach_task_self (), (vm_address_t) pinfo, info_count * sizeof(natural_t));
2820 mach_port_deallocate (mach_task_self (), host);
2822 #elif defined(linux)
2824 FILE *cpuinfo = fopen("/proc/stat", "r");
2825 if (cpuinfo)
2827 unsigned long clk_tck = sysconf(_SC_CLK_TCK);
2828 unsigned long usr,nice,sys,idle,remainder[8];
2829 int i, count, id;
2830 char name[32];
2831 char line[255];
2833 /* first line is combined usage */
2834 while (fgets(line,255,cpuinfo))
2836 count = sscanf(line, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
2837 name, &usr, &nice, &sys, &idle,
2838 &remainder[0], &remainder[1], &remainder[2], &remainder[3],
2839 &remainder[4], &remainder[5], &remainder[6], &remainder[7]);
2841 if (count < 5 || strncmp( name, "cpu", 3 )) break;
2842 for (i = 0; i + 5 < count; ++i) sys += remainder[i];
2843 sys += idle;
2844 usr += nice;
2845 id = atoi( name + 3 ) + 1;
2846 if (id > out_cpus) break;
2847 if (id > cpus) cpus = id;
2848 sppi[id-1].IdleTime.QuadPart = (ULONGLONG)idle * 10000000 / clk_tck;
2849 sppi[id-1].KernelTime.QuadPart = (ULONGLONG)sys * 10000000 / clk_tck;
2850 sppi[id-1].UserTime.QuadPart = (ULONGLONG)usr * 10000000 / clk_tck;
2852 fclose(cpuinfo);
2855 #elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__)
2857 static int clockrate_name[] = { CTL_KERN, KERN_CLOCKRATE };
2858 size_t size = 0;
2859 struct clockinfo clockrate;
2860 int have_clockrate;
2861 long *ptimes;
2863 size = sizeof(clockrate);
2864 have_clockrate = !sysctl(clockrate_name, 2, &clockrate, &size, NULL, 0);
2865 size = out_cpus * CPUSTATES * sizeof(long);
2866 ptimes = malloc(size + 1);
2867 if (ptimes)
2869 if (have_clockrate && (!sysctlbyname("kern.cp_times", ptimes, &size, NULL, 0) || errno == ENOMEM))
2871 for (cpus = 0; cpus < out_cpus; cpus++)
2873 if (cpus * CPUSTATES * sizeof(long) >= size) break;
2874 sppi[cpus].IdleTime.QuadPart = (ULONGLONG)ptimes[cpus*CPUSTATES + CP_IDLE] * 10000000 / clockrate.stathz;
2875 sppi[cpus].KernelTime.QuadPart = (ULONGLONG)ptimes[cpus*CPUSTATES + CP_SYS] * 10000000 / clockrate.stathz;
2876 sppi[cpus].UserTime.QuadPart = (ULONGLONG)ptimes[cpus*CPUSTATES + CP_USER] * 10000000 / clockrate.stathz;
2879 free(ptimes);
2882 #endif
2883 if (cpus == 0)
2885 static int i = 1;
2886 unsigned int n;
2887 cpus = min(peb->NumberOfProcessors, out_cpus);
2888 FIXME("stub info_class SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION\n");
2889 /* many programs expect these values to change so fake change */
2890 for (n = 0; n < cpus; n++)
2892 sppi[n].KernelTime.QuadPart = 1 * i;
2893 sppi[n].UserTime.QuadPart = 2 * i;
2894 sppi[n].IdleTime.QuadPart = 3 * i;
2896 i++;
2899 len = sizeof(*sppi) * cpus;
2900 if (size >= len)
2902 if (!info) ret = STATUS_ACCESS_VIOLATION;
2903 else memcpy( info, sppi, len);
2905 else ret = STATUS_INFO_LENGTH_MISMATCH;
2907 free( sppi );
2908 break;
2911 case SystemModuleInformation: /* 11 */
2913 /* FIXME: return some fake info for now */
2914 static const char *fake_modules[] =
2916 "\\SystemRoot\\system32\\ntoskrnl.exe",
2917 "\\SystemRoot\\system32\\hal.dll",
2918 "\\SystemRoot\\system32\\drivers\\mountmgr.sys"
2921 ULONG i;
2922 RTL_PROCESS_MODULES *smi = info;
2924 len = offsetof( RTL_PROCESS_MODULES, Modules[ARRAY_SIZE(fake_modules)] );
2925 if (len <= size)
2927 memset( smi, 0, len );
2928 for (i = 0; i < ARRAY_SIZE(fake_modules); i++)
2930 RTL_PROCESS_MODULE_INFORMATION *sm = &smi->Modules[i];
2931 sm->ImageBaseAddress = (char *)0x10000000 + 0x200000 * i;
2932 sm->ImageSize = 0x200000;
2933 sm->LoadOrderIndex = i;
2934 sm->LoadCount = 1;
2935 strcpy( (char *)sm->Name, fake_modules[i] );
2936 sm->NameOffset = strrchr( fake_modules[i], '\\' ) - fake_modules[i] + 1;
2938 smi->ModulesCount = i;
2940 else ret = STATUS_INFO_LENGTH_MISMATCH;
2942 break;
2945 case SystemHandleInformation: /* 16 */
2947 struct handle_info *handle_info;
2948 DWORD i, num_handles;
2950 if (size < sizeof(SYSTEM_HANDLE_INFORMATION))
2952 ret = STATUS_INFO_LENGTH_MISMATCH;
2953 break;
2956 if (!info)
2958 ret = STATUS_ACCESS_VIOLATION;
2959 break;
2962 num_handles = (size - FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle )) / sizeof(SYSTEM_HANDLE_ENTRY);
2963 if (!(handle_info = malloc( sizeof(*handle_info) * num_handles ))) return STATUS_NO_MEMORY;
2965 SERVER_START_REQ( get_system_handles )
2967 wine_server_set_reply( req, handle_info, sizeof(*handle_info) * num_handles );
2968 if (!(ret = wine_server_call( req )))
2970 SYSTEM_HANDLE_INFORMATION *shi = info;
2971 shi->Count = wine_server_reply_size( req ) / sizeof(*handle_info);
2972 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle[shi->Count] );
2973 for (i = 0; i < shi->Count; i++)
2975 memset( &shi->Handle[i], 0, sizeof(shi->Handle[i]) );
2976 shi->Handle[i].OwnerPid = handle_info[i].owner;
2977 shi->Handle[i].HandleValue = handle_info[i].handle;
2978 shi->Handle[i].AccessMask = handle_info[i].access;
2979 shi->Handle[i].HandleFlags = handle_info[i].attributes;
2980 shi->Handle[i].ObjectType = handle_info[i].type;
2981 /* FIXME: Fill out ObjectPointer */
2984 else if (ret == STATUS_BUFFER_TOO_SMALL)
2986 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle[reply->count] );
2987 ret = STATUS_INFO_LENGTH_MISMATCH;
2990 SERVER_END_REQ;
2992 free( handle_info );
2993 break;
2996 case SystemFileCacheInformation: /* 21 */
2998 SYSTEM_CACHE_INFORMATION sci = { 0 };
3000 len = sizeof(sci);
3001 if (size >= len)
3003 if (!info) ret = STATUS_ACCESS_VIOLATION;
3004 else memcpy( info, &sci, len);
3006 else ret = STATUS_INFO_LENGTH_MISMATCH;
3007 FIXME("info_class SYSTEM_CACHE_INFORMATION\n");
3008 break;
3011 case SystemInterruptInformation: /* 23 */
3013 len = peb->NumberOfProcessors * sizeof(SYSTEM_INTERRUPT_INFORMATION);
3014 if (size >= len)
3016 if (!info) ret = STATUS_ACCESS_VIOLATION;
3017 else
3019 #ifdef HAVE_GETRANDOM
3020 int ret;
3023 ret = getrandom( info, len, 0 );
3025 while (ret == -1 && errno == EINTR);
3027 if (ret == -1 && errno == ENOSYS) read_dev_urandom( info, len );
3028 #else
3029 read_dev_urandom( info, len );
3030 #endif
3033 else ret = STATUS_INFO_LENGTH_MISMATCH;
3034 break;
3037 case SystemTimeAdjustmentInformation: /* 28 */
3039 SYSTEM_TIME_ADJUSTMENT_QUERY query = { 156250, 156250, TRUE };
3041 len = sizeof(query);
3042 if (size == len)
3044 if (!info) ret = STATUS_ACCESS_VIOLATION;
3045 else memcpy( info, &query, len );
3047 else ret = STATUS_INFO_LENGTH_MISMATCH;
3048 break;
3051 case SystemKernelDebuggerInformation: /* 35 */
3053 SYSTEM_KERNEL_DEBUGGER_INFORMATION skdi;
3055 skdi.DebuggerEnabled = FALSE;
3056 skdi.DebuggerNotPresent = TRUE;
3057 len = sizeof(skdi);
3058 if (size >= len)
3060 if (!info) ret = STATUS_ACCESS_VIOLATION;
3061 else memcpy( info, &skdi, len);
3063 else ret = STATUS_INFO_LENGTH_MISMATCH;
3064 break;
3067 case SystemRegistryQuotaInformation: /* 37 */
3069 /* Something to do with the size of the registry *
3070 * Since we don't have a size limitation, fake it *
3071 * This is almost certainly wrong. *
3072 * This sets each of the three words in the struct to 32 MB, *
3073 * which is enough to make the IE 5 installer happy. */
3074 SYSTEM_REGISTRY_QUOTA_INFORMATION srqi;
3076 srqi.RegistryQuotaAllowed = 0x2000000;
3077 srqi.RegistryQuotaUsed = 0x200000;
3078 srqi.Reserved1 = (void*)0x200000;
3079 len = sizeof(srqi);
3081 if (size >= len)
3083 if (!info) ret = STATUS_ACCESS_VIOLATION;
3084 else
3086 FIXME("SystemRegistryQuotaInformation: faking max registry size of 32 MB\n");
3087 memcpy( info, &srqi, len);
3090 else ret = STATUS_INFO_LENGTH_MISMATCH;
3091 break;
3094 case SystemCurrentTimeZoneInformation: /* 44 */
3096 RTL_DYNAMIC_TIME_ZONE_INFORMATION tz;
3098 get_timezone_info( &tz );
3099 len = sizeof(RTL_TIME_ZONE_INFORMATION);
3100 if (size >= len)
3102 if (!info) ret = STATUS_ACCESS_VIOLATION;
3103 else memcpy( info, &tz, len);
3105 else ret = STATUS_INFO_LENGTH_MISMATCH;
3106 break;
3109 case SystemExtendedProcessInformation: /* 57 */
3110 ret = get_system_process_info( class, info, size, &len );
3111 break;
3113 case SystemRecommendedSharedDataAlignment: /* 58 */
3115 len = sizeof(DWORD);
3116 if (size >= len)
3118 if (!info) ret = STATUS_ACCESS_VIOLATION;
3119 else
3121 #ifdef __arm__
3122 *((DWORD *)info) = 32;
3123 #elif defined __aarch64__
3124 *((DWORD *)info) = 128;
3125 #else
3126 *((DWORD *)info) = 64;
3127 #endif
3130 else ret = STATUS_INFO_LENGTH_MISMATCH;
3131 break;
3134 case SystemEmulationBasicInformation: /* 62 */
3136 SYSTEM_BASIC_INFORMATION sbi;
3138 virtual_get_system_info( &sbi, is_wow64() );
3139 len = sizeof(sbi);
3140 if (size == len)
3142 if (!info) ret = STATUS_ACCESS_VIOLATION;
3143 else memcpy( info, &sbi, len);
3145 else ret = STATUS_INFO_LENGTH_MISMATCH;
3146 break;
3149 case SystemEmulationProcessorInformation: /* 63 */
3150 if (size >= (len = sizeof(cpu_info)))
3152 SYSTEM_CPU_INFORMATION cpu = cpu_info;
3153 if (is_win64)
3155 if (cpu_info.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
3156 cpu.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
3157 else if (cpu_info.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64)
3158 cpu.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_ARM;
3160 memcpy(info, &cpu, len);
3162 else ret = STATUS_INFO_LENGTH_MISMATCH;
3163 break;
3165 case SystemExtendedHandleInformation: /* 64 */
3167 struct handle_info *handle_info;
3168 DWORD i, num_handles;
3170 if (size < sizeof(SYSTEM_HANDLE_INFORMATION_EX))
3172 ret = STATUS_INFO_LENGTH_MISMATCH;
3173 break;
3176 if (!info)
3178 ret = STATUS_ACCESS_VIOLATION;
3179 break;
3182 num_handles = (size - FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handles ))
3183 / sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX);
3184 if (!(handle_info = malloc( sizeof(*handle_info) * num_handles ))) return STATUS_NO_MEMORY;
3186 SERVER_START_REQ( get_system_handles )
3188 wine_server_set_reply( req, handle_info, sizeof(*handle_info) * num_handles );
3189 if (!(ret = wine_server_call( req )))
3191 SYSTEM_HANDLE_INFORMATION_EX *shi = info;
3192 shi->NumberOfHandles = wine_server_reply_size( req ) / sizeof(*handle_info);
3193 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handles[shi->NumberOfHandles] );
3194 for (i = 0; i < shi->NumberOfHandles; i++)
3196 memset( &shi->Handles[i], 0, sizeof(shi->Handles[i]) );
3197 shi->Handles[i].UniqueProcessId = handle_info[i].owner;
3198 shi->Handles[i].HandleValue = handle_info[i].handle;
3199 shi->Handles[i].GrantedAccess = handle_info[i].access;
3200 shi->Handles[i].HandleAttributes = handle_info[i].attributes;
3201 shi->Handles[i].ObjectTypeIndex = handle_info[i].type;
3202 /* FIXME: Fill out Object */
3205 else if (ret == STATUS_BUFFER_TOO_SMALL)
3207 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handles[reply->count] );
3208 ret = STATUS_INFO_LENGTH_MISMATCH;
3211 SERVER_END_REQ;
3213 free( handle_info );
3214 break;
3217 case SystemLogicalProcessorInformation: /* 73 */
3219 if (!logical_proc_info)
3221 ret = STATUS_NOT_IMPLEMENTED;
3222 break;
3224 len = logical_proc_info_len * sizeof(*logical_proc_info);
3225 if (size >= len)
3227 if (!info) ret = STATUS_ACCESS_VIOLATION;
3228 else memcpy( info, logical_proc_info, len);
3230 else ret = STATUS_INFO_LENGTH_MISMATCH;
3231 break;
3234 case SystemFirmwareTableInformation: /* 76 */
3236 SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti = info;
3237 len = FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
3238 if (size < len)
3240 ret = STATUS_INFO_LENGTH_MISMATCH;
3241 break;
3244 switch (sfti->Action)
3246 case SystemFirmwareTable_Get:
3247 ret = get_firmware_info(sfti, size, &len);
3248 break;
3249 default:
3250 len = 0;
3251 ret = STATUS_NOT_IMPLEMENTED;
3252 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION action %d\n", sfti->Action);
3254 break;
3257 case SystemModuleInformationEx: /* 77 */
3259 /* FIXME: return some fake info for now */
3260 static const char *fake_modules[] =
3262 "\\SystemRoot\\system32\\ntoskrnl.exe",
3263 "\\SystemRoot\\system32\\hal.dll",
3264 "\\SystemRoot\\system32\\drivers\\mountmgr.sys"
3267 ULONG i;
3268 RTL_PROCESS_MODULE_INFORMATION_EX *module_info = info;
3270 len = sizeof(*module_info) * ARRAY_SIZE(fake_modules) + sizeof(module_info->NextOffset);
3271 if (len <= size)
3273 memset( info, 0, len );
3274 for (i = 0; i < ARRAY_SIZE(fake_modules); i++)
3276 RTL_PROCESS_MODULE_INFORMATION *sm = &module_info[i].BaseInfo;
3277 sm->ImageBaseAddress = (char *)0x10000000 + 0x200000 * i;
3278 sm->ImageSize = 0x200000;
3279 sm->LoadOrderIndex = i;
3280 sm->LoadCount = 1;
3281 strcpy( (char *)sm->Name, fake_modules[i] );
3282 sm->NameOffset = strrchr( fake_modules[i], '\\' ) - fake_modules[i] + 1;
3283 module_info[i].NextOffset = sizeof(*module_info);
3285 module_info[ARRAY_SIZE(fake_modules)].NextOffset = 0;
3287 else ret = STATUS_INFO_LENGTH_MISMATCH;
3289 break;
3292 case SystemDynamicTimeZoneInformation: /* 102 */
3294 RTL_DYNAMIC_TIME_ZONE_INFORMATION tz;
3296 get_timezone_info( &tz );
3297 len = sizeof(tz);
3298 if (size >= len)
3300 if (!info) ret = STATUS_ACCESS_VIOLATION;
3301 else memcpy( info, &tz, len);
3303 else ret = STATUS_INFO_LENGTH_MISMATCH;
3304 break;
3307 case SystemCodeIntegrityInformation: /* 103 */
3309 SYSTEM_CODEINTEGRITY_INFORMATION *integrity_info = info;
3311 FIXME("SystemCodeIntegrityInformation, size %u, info %p, stub!\n", (int)size, info);
3313 len = sizeof(SYSTEM_CODEINTEGRITY_INFORMATION);
3315 if (size >= len)
3316 integrity_info->CodeIntegrityOptions = CODEINTEGRITY_OPTION_ENABLED;
3317 else
3318 ret = STATUS_INFO_LENGTH_MISMATCH;
3319 break;
3322 case SystemProcessorBrandString: /* 105 */
3323 if (!cpu_name[0]) return STATUS_NOT_SUPPORTED;
3324 if ((ULONG_PTR)info & 3) return STATUS_DATATYPE_MISALIGNMENT;
3325 len = sizeof(cpu_name);
3326 if (size >= len)
3327 memcpy( info, cpu_name, len );
3328 else
3329 ret = STATUS_INFO_LENGTH_MISMATCH;
3330 break;
3332 case SystemKernelDebuggerInformationEx: /* 149 */
3334 SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX skdi;
3336 skdi.DebuggerAllowed = FALSE;
3337 skdi.DebuggerEnabled = FALSE;
3338 skdi.DebuggerPresent = FALSE;
3340 len = sizeof(skdi);
3341 if (size >= len)
3343 if (!info) ret = STATUS_ACCESS_VIOLATION;
3344 else memcpy( info, &skdi, len );
3346 else ret = STATUS_INFO_LENGTH_MISMATCH;
3347 break;
3350 case SystemProcessorFeaturesInformation: /* 154 */
3351 len = sizeof(cpu_features);
3352 if (size >= len) memcpy( info, &cpu_features, len );
3353 else ret = STATUS_INFO_LENGTH_MISMATCH;
3354 break;
3356 case SystemCpuSetInformation: /* 175 */
3357 return NtQuerySystemInformationEx(class, NULL, 0, info, size, ret_size);
3359 /* Wine extensions */
3361 case SystemWineVersionInformation: /* 1000 */
3363 static const char version[] = PACKAGE_VERSION;
3364 struct utsname buf;
3366 uname( &buf );
3367 snprintf( info, size, "%s%c%s%c%s%c%s", version, 0, wine_build, 0, buf.sysname, 0, buf.release );
3368 len = strlen(version) + strlen(wine_build) + strlen(buf.sysname) + strlen(buf.release) + 4;
3369 if (size < len) ret = STATUS_INFO_LENGTH_MISMATCH;
3370 break;
3373 default:
3374 FIXME( "(0x%08x,%p,0x%08x,%p) stub\n", class, info, (int)size, ret_size );
3376 /* Several Information Classes are not implemented on Windows and return 2 different values
3377 * STATUS_NOT_IMPLEMENTED or STATUS_INVALID_INFO_CLASS
3378 * in 95% of the cases it's STATUS_INVALID_INFO_CLASS, so use this as the default
3380 ret = STATUS_INVALID_INFO_CLASS;
3383 if (ret_size) *ret_size = len;
3384 return ret;
3388 /******************************************************************************
3389 * NtQuerySystemInformationEx (NTDLL.@)
3391 NTSTATUS WINAPI NtQuerySystemInformationEx( SYSTEM_INFORMATION_CLASS class,
3392 void *query, ULONG query_len,
3393 void *info, ULONG size, ULONG *ret_size )
3395 ULONG len = 0;
3396 unsigned int ret = STATUS_NOT_IMPLEMENTED;
3398 TRACE( "(0x%08x,%p,%u,%p,%u,%p) stub\n", class, query, (int)query_len, info, (int)size, ret_size );
3400 switch (class)
3402 case SystemLogicalProcessorInformationEx:
3404 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *p;
3405 DWORD relation;
3407 if (!query || query_len < sizeof(DWORD))
3409 ret = STATUS_INVALID_PARAMETER;
3410 break;
3412 if (!logical_proc_info_ex)
3414 ret = STATUS_NOT_IMPLEMENTED;
3415 break;
3418 relation = *(DWORD *)query;
3419 len = 0;
3420 p = logical_proc_info_ex;
3421 while ((char *)p != (char *)logical_proc_info_ex + logical_proc_info_ex_size)
3423 if (relation == RelationAll || p->Relationship == relation)
3425 if (len + p->Size <= size)
3426 memcpy( (char *)info + len, p, p->Size );
3427 len += p->Size;
3429 p = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((char *)p + p->Size);
3431 ret = size >= len ? STATUS_SUCCESS : STATUS_INFO_LENGTH_MISMATCH;
3432 break;
3435 case SystemCpuSetInformation:
3437 unsigned int cpu_count = peb->NumberOfProcessors;
3438 PROCESS_BASIC_INFORMATION pbi;
3439 HANDLE process;
3441 if (!query || query_len < sizeof(HANDLE))
3442 return STATUS_INVALID_PARAMETER;
3444 process = *(HANDLE *)query;
3445 if (process && (ret = NtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL)))
3446 return ret;
3448 if (size < (len = cpu_count * sizeof(SYSTEM_CPU_SET_INFORMATION)))
3450 ret = STATUS_BUFFER_TOO_SMALL;
3451 break;
3453 if (!info)
3454 return STATUS_ACCESS_VIOLATION;
3456 if ((ret = create_cpuset_info(info)))
3457 return ret;
3458 break;
3461 case SystemSupportedProcessorArchitectures:
3463 SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION *machines = info;
3464 HANDLE process;
3465 ULONG i;
3466 USHORT machine = 0;
3468 if (!query || query_len < sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
3469 process = *(HANDLE *)query;
3470 if (process)
3472 SERVER_START_REQ( get_process_info )
3474 req->handle = wine_server_obj_handle( process );
3475 if (!(ret = wine_server_call( req ))) machine = reply->machine;
3477 SERVER_END_REQ;
3478 if (ret) return ret;
3481 len = (supported_machines_count + 1) * sizeof(*machines);
3482 if (size < len)
3484 ret = STATUS_BUFFER_TOO_SMALL;
3485 break;
3487 memset( machines, 0, len );
3489 /* native machine */
3490 machines[0].Machine = supported_machines[0];
3491 machines[0].UserMode = 1;
3492 machines[0].KernelMode = 1;
3493 machines[0].Native = 1;
3494 machines[0].Process = (supported_machines[0] == machine || is_machine_64bit( machine ));
3495 machines[0].WoW64Container = 0;
3496 machines[0].ReservedZero0 = 0;
3497 /* wow64 machines */
3498 for (i = 1; i < supported_machines_count; i++)
3500 machines[i].Machine = supported_machines[i];
3501 machines[i].UserMode = 1;
3502 machines[i].Process = supported_machines[i] == machine;
3503 machines[i].WoW64Container = 1;
3505 ret = STATUS_SUCCESS;
3506 break;
3509 default:
3510 FIXME( "(0x%08x,%p,%u,%p,%u,%p) stub\n", class, query, (int)query_len, info, (int)size, ret_size );
3511 break;
3513 if (ret_size) *ret_size = len;
3514 return ret;
3518 /******************************************************************************
3519 * NtSetSystemInformation (NTDLL.@)
3521 NTSTATUS WINAPI NtSetSystemInformation( SYSTEM_INFORMATION_CLASS class, void *info, ULONG length )
3523 FIXME( "(0x%08x,%p,0x%08x) stub\n", class, info, (int)length );
3524 return STATUS_SUCCESS;
3528 /******************************************************************************
3529 * NtQuerySystemEnvironmentValue (NTDLL.@)
3531 NTSTATUS WINAPI NtQuerySystemEnvironmentValue( UNICODE_STRING *name, WCHAR *buffer, ULONG length,
3532 ULONG *retlen )
3534 FIXME( "(%s, %p, %u, %p), stub\n", debugstr_us(name), buffer, (int)length, retlen );
3535 return STATUS_NOT_IMPLEMENTED;
3539 /******************************************************************************
3540 * NtQuerySystemEnvironmentValueEx (NTDLL.@)
3542 NTSTATUS WINAPI NtQuerySystemEnvironmentValueEx( UNICODE_STRING *name, GUID *vendor, void *buffer,
3543 ULONG *retlen, ULONG *attrib )
3545 FIXME( "(%s, %s, %p, %p, %p), stub\n", debugstr_us(name),
3546 debugstr_guid(vendor), buffer, retlen, attrib );
3547 return STATUS_NOT_IMPLEMENTED;
3551 /******************************************************************************
3552 * NtSystemDebugControl (NTDLL.@)
3554 NTSTATUS WINAPI NtSystemDebugControl( SYSDBG_COMMAND command, void *in_buff, ULONG in_len,
3555 void *out_buff, ULONG out_len, ULONG *retlen )
3557 FIXME( "(%d, %p, %d, %p, %d, %p), stub\n",
3558 command, in_buff, (int)in_len, out_buff, (int)out_len, retlen );
3560 return STATUS_DEBUGGER_INACTIVE;
3564 /******************************************************************************
3565 * NtShutdownSystem (NTDLL.@)
3567 NTSTATUS WINAPI NtShutdownSystem( SHUTDOWN_ACTION action )
3569 FIXME( "%d\n", action );
3570 return STATUS_SUCCESS;
3574 #ifdef linux
3576 /* Fallback using /proc/cpuinfo for Linux systems without cpufreq. For
3577 * most distributions on recent enough hardware, this is only likely to
3578 * happen while running in virtualized environments such as QEMU. */
3579 static ULONG mhz_from_cpuinfo(void)
3581 char line[512];
3582 char *s, *value;
3583 double cmz = 0;
3584 FILE *f = fopen("/proc/cpuinfo", "r");
3585 if(f)
3587 while (fgets(line, sizeof(line), f) != NULL)
3589 if (!(value = strchr(line,':'))) continue;
3590 s = value - 1;
3591 while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
3592 s[1] = 0;
3593 value++;
3594 if (!strcmp( line, "cpu MHz" ))
3596 sscanf(value, " %lf", &cmz);
3597 break;
3600 fclose( f );
3602 return cmz;
3605 static const char * get_sys_str(const char *dirname, const char *basename, char *s)
3607 char path[64];
3608 FILE *f;
3609 const char *ret = NULL;
3611 if (snprintf(path, sizeof(path), "%s/%s", dirname, basename) >= sizeof(path)) return NULL;
3612 if ((f = fopen(path, "r")))
3614 if (fgets(s, 16, f)) ret = s;
3615 fclose(f);
3617 return ret;
3620 static int get_sys_int(const char *dirname, const char *basename)
3622 char s[16];
3623 return get_sys_str(dirname, basename, s) ? atoi(s) : 0;
3626 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
3628 DIR *d = opendir("/sys/class/power_supply");
3629 struct dirent *de;
3630 char s[16], path[64];
3631 BOOL found_ac = FALSE;
3632 LONG64 voltage; /* microvolts */
3634 bs->AcOnLine = TRUE;
3635 if (!d) return STATUS_SUCCESS;
3637 while ((de = readdir(d)))
3639 if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue;
3640 if (snprintf(path, sizeof(path), "/sys/class/power_supply/%s", de->d_name) >= sizeof(path)) continue;
3641 if (get_sys_str(path, "scope", s) && strcmp(s, "Device\n") == 0) continue;
3642 if (!get_sys_str(path, "type", s)) continue;
3644 if (strcmp(s, "Mains\n") == 0)
3646 if (!get_sys_str(path, "online", s)) continue;
3647 if (found_ac)
3649 FIXME("Multiple mains found, only reporting on the first\n");
3651 else
3653 bs->AcOnLine = atoi(s);
3654 found_ac = TRUE;
3657 else if (strcmp(s, "Battery\n") == 0)
3659 if (!get_sys_str(path, "status", s)) continue;
3660 if (bs->BatteryPresent)
3662 FIXME("Multiple batteries found, only reporting on the first\n");
3664 else
3666 bs->Charging = (strcmp(s, "Charging\n") == 0);
3667 bs->Discharging = (strcmp(s, "Discharging\n") == 0);
3668 bs->BatteryPresent = TRUE;
3669 voltage = get_sys_int(path, "voltage_now");
3670 bs->MaxCapacity = get_sys_int(path, "charge_full") * voltage / 1e9;
3671 bs->RemainingCapacity = get_sys_int(path, "charge_now") * voltage / 1e9;
3672 bs->Rate = -get_sys_int(path, "current_now") * voltage / 1e9;
3673 if (!bs->Charging && (LONG)bs->Rate < 0)
3674 bs->EstimatedTime = 3600 * bs->RemainingCapacity / -(LONG)bs->Rate;
3675 else
3676 bs->EstimatedTime = ~0u;
3681 closedir(d);
3682 return STATUS_SUCCESS;
3685 #elif defined(__APPLE__)
3687 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
3689 CFTypeRef blob = IOPSCopyPowerSourcesInfo();
3690 CFArrayRef sources = IOPSCopyPowerSourcesList( blob );
3691 CFIndex count, i;
3692 CFDictionaryRef source = NULL;
3693 CFTypeRef prop;
3694 Boolean is_charging, is_internal, is_present;
3695 int32_t value, voltage;
3697 if (!sources)
3699 if (blob) CFRelease( blob );
3700 return STATUS_ACCESS_DENIED;
3703 count = CFArrayGetCount( sources );
3705 for (i = 0; i < count; i++)
3707 source = IOPSGetPowerSourceDescription( blob, CFArrayGetValueAtIndex( sources, i ) );
3709 if (!source)
3710 continue;
3712 prop = CFDictionaryGetValue( source, CFSTR(kIOPSTransportTypeKey) );
3713 is_internal = !CFStringCompare( prop, CFSTR(kIOPSInternalType), 0 );
3715 prop = CFDictionaryGetValue( source, CFSTR(kIOPSIsPresentKey) );
3716 is_present = CFBooleanGetValue( prop );
3718 if (is_internal && is_present)
3719 break;
3722 CFRelease( blob );
3724 if (!source)
3726 /* Just assume we're on AC with no internal power source. */
3727 bs->AcOnLine = TRUE;
3728 CFRelease( sources );
3729 return STATUS_SUCCESS;
3732 bs->BatteryPresent = TRUE;
3734 prop = CFDictionaryGetValue( source, CFSTR(kIOPSIsChargingKey) );
3735 is_charging = CFBooleanGetValue( prop );
3737 prop = CFDictionaryGetValue( source, CFSTR(kIOPSPowerSourceStateKey) );
3739 if (!CFStringCompare( prop, CFSTR(kIOPSACPowerValue), 0 ))
3741 bs->AcOnLine = TRUE;
3742 if (is_charging)
3743 bs->Charging = TRUE;
3745 else
3746 bs->Discharging = TRUE;
3748 /* We'll need the voltage to be able to interpret the other values. */
3749 prop = CFDictionaryGetValue( source, CFSTR(kIOPSVoltageKey) );
3750 if (prop)
3751 CFNumberGetValue( prop, kCFNumberIntType, &voltage );
3752 else
3753 /* kIOPSVoltageKey is optional and might not be populated.
3754 * Assume 11.4 V then, which is a common value for Apple laptops. */
3755 voltage = 11400;
3757 prop = CFDictionaryGetValue( source, CFSTR(kIOPSMaxCapacityKey) );
3758 CFNumberGetValue( prop, kCFNumberIntType, &value );
3759 bs->MaxCapacity = value * voltage;
3760 /* Apple uses "estimated time < 10:00" and "22%" for these, but we'll follow
3761 * Windows for now (5% and 33%). */
3762 bs->DefaultAlert1 = bs->MaxCapacity / 20;
3763 bs->DefaultAlert2 = bs->MaxCapacity / 3;
3765 prop = CFDictionaryGetValue( source, CFSTR(kIOPSCurrentCapacityKey) );
3766 CFNumberGetValue( prop, kCFNumberIntType, &value );
3767 bs->RemainingCapacity = value * voltage;
3769 prop = CFDictionaryGetValue( source, CFSTR(kIOPSCurrentKey) );
3770 if (prop)
3771 CFNumberGetValue( prop, kCFNumberIntType, &value );
3772 else
3773 /* kIOPSCurrentKey is optional and might not be populated. */
3774 value = 0;
3776 bs->Rate = value * voltage / 1000;
3778 prop = CFDictionaryGetValue( source, CFSTR(kIOPSTimeToEmptyKey) );
3779 if (prop)
3781 CFNumberGetValue( prop, kCFNumberIntType, &value );
3782 if (value > 0)
3783 /* A value of -1 indicates "Still Calculating the Time",
3784 * otherwise estimated minutes left on the battery. */
3785 bs->EstimatedTime = value * 60;
3788 CFRelease( sources );
3789 return STATUS_SUCCESS;
3792 #elif defined(__FreeBSD__)
3794 #include <dev/acpica/acpiio.h>
3796 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
3798 size_t len;
3799 int state = 0;
3800 int rate_mW = 0;
3801 int time_mins = -1;
3802 int life_percent = 0;
3804 bs->BatteryPresent = TRUE;
3805 len = sizeof(state);
3806 bs->BatteryPresent &= !sysctlbyname("hw.acpi.battery.state", &state, &len, NULL, 0);
3807 len = sizeof(rate_mW);
3808 bs->BatteryPresent &= !sysctlbyname("hw.acpi.battery.rate", &rate_mW, &len, NULL, 0);
3809 len = sizeof(time_mins);
3810 bs->BatteryPresent &= !sysctlbyname("hw.acpi.battery.time", &time_mins, &len, NULL, 0);
3811 len = sizeof(life_percent);
3812 bs->BatteryPresent &= !sysctlbyname("hw.acpi.battery.life", &life_percent, &len, NULL, 0);
3814 if (bs->BatteryPresent)
3816 bs->AcOnLine = (time_mins == -1);
3817 bs->Charging = state & ACPI_BATT_STAT_CHARGING;
3818 bs->Discharging = state & ACPI_BATT_STAT_DISCHARG;
3820 bs->Rate = (rate_mW >= 0 ? -rate_mW : 0);
3821 if (time_mins >= 0 && life_percent > 0)
3823 bs->EstimatedTime = 60 * time_mins;
3824 bs->RemainingCapacity = bs->EstimatedTime * rate_mW / 3600;
3825 bs->MaxCapacity = bs->RemainingCapacity * 100 / life_percent;
3827 else
3829 bs->EstimatedTime = ~0u;
3830 bs->RemainingCapacity = life_percent;
3831 bs->MaxCapacity = 100;
3834 return STATUS_SUCCESS;
3837 #else
3839 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
3841 FIXME("SystemBatteryState not implemented on this platform\n");
3842 return STATUS_NOT_IMPLEMENTED;
3845 #endif
3847 /******************************************************************************
3848 * NtPowerInformation (NTDLL.@)
3850 NTSTATUS WINAPI NtPowerInformation( POWER_INFORMATION_LEVEL level, void *input, ULONG in_size,
3851 void *output, ULONG out_size )
3853 TRACE( "(%d,%p,%d,%p,%d)\n", level, input, (int)in_size, output, (int)out_size );
3854 switch (level)
3856 case SystemPowerCapabilities:
3858 PSYSTEM_POWER_CAPABILITIES PowerCaps = output;
3859 FIXME("semi-stub: SystemPowerCapabilities\n");
3860 if (out_size < sizeof(SYSTEM_POWER_CAPABILITIES)) return STATUS_BUFFER_TOO_SMALL;
3861 /* FIXME: These values are based off a native XP desktop, should probably use APM/ACPI to get the 'real' values */
3862 PowerCaps->PowerButtonPresent = TRUE;
3863 PowerCaps->SleepButtonPresent = FALSE;
3864 PowerCaps->LidPresent = FALSE;
3865 PowerCaps->SystemS1 = TRUE;
3866 PowerCaps->SystemS2 = FALSE;
3867 PowerCaps->SystemS3 = FALSE;
3868 PowerCaps->SystemS4 = TRUE;
3869 PowerCaps->SystemS5 = TRUE;
3870 PowerCaps->HiberFilePresent = TRUE;
3871 PowerCaps->FullWake = TRUE;
3872 PowerCaps->VideoDimPresent = FALSE;
3873 PowerCaps->ApmPresent = FALSE;
3874 PowerCaps->UpsPresent = FALSE;
3875 PowerCaps->ThermalControl = FALSE;
3876 PowerCaps->ProcessorThrottle = FALSE;
3877 PowerCaps->ProcessorMinThrottle = 100;
3878 PowerCaps->ProcessorMaxThrottle = 100;
3879 PowerCaps->DiskSpinDown = TRUE;
3880 PowerCaps->SystemBatteriesPresent = FALSE;
3881 PowerCaps->BatteriesAreShortTerm = FALSE;
3882 PowerCaps->BatteryScale[0].Granularity = 0;
3883 PowerCaps->BatteryScale[0].Capacity = 0;
3884 PowerCaps->BatteryScale[1].Granularity = 0;
3885 PowerCaps->BatteryScale[1].Capacity = 0;
3886 PowerCaps->BatteryScale[2].Granularity = 0;
3887 PowerCaps->BatteryScale[2].Capacity = 0;
3888 PowerCaps->AcOnLineWake = PowerSystemUnspecified;
3889 PowerCaps->SoftLidWake = PowerSystemUnspecified;
3890 PowerCaps->RtcWake = PowerSystemSleeping1;
3891 PowerCaps->MinDeviceWakeState = PowerSystemUnspecified;
3892 PowerCaps->DefaultLowLatencyWake = PowerSystemUnspecified;
3893 return STATUS_SUCCESS;
3896 case SystemBatteryState:
3898 if (out_size < sizeof(SYSTEM_BATTERY_STATE)) return STATUS_BUFFER_TOO_SMALL;
3899 memset(output, 0, sizeof(SYSTEM_BATTERY_STATE));
3900 return fill_battery_state(output);
3903 case SystemExecutionState:
3905 ULONG *state = output;
3906 WARN("semi-stub: SystemExecutionState\n"); /* Needed for .NET Framework, but using a FIXME is really noisy. */
3907 if (input != NULL) return STATUS_INVALID_PARAMETER;
3908 /* FIXME: The actual state should be the value set by SetThreadExecutionState which is not currently implemented. */
3909 *state = ES_USER_PRESENT;
3910 return STATUS_SUCCESS;
3913 case ProcessorInformation:
3915 const int cannedMHz = 1000; /* We fake a 1GHz processor if we can't conjure up real values */
3916 PROCESSOR_POWER_INFORMATION* cpu_power = output;
3917 int i, out_cpus;
3919 if ((output == NULL) || (out_size == 0)) return STATUS_INVALID_PARAMETER;
3920 out_cpus = peb->NumberOfProcessors;
3921 if ((out_size / sizeof(PROCESSOR_POWER_INFORMATION)) < out_cpus) return STATUS_BUFFER_TOO_SMALL;
3922 #if defined(linux)
3924 unsigned int val;
3925 char filename[128];
3926 FILE* f;
3928 for(i = 0; i < out_cpus; i++) {
3929 snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", i);
3930 f = fopen(filename, "r");
3931 if (f && (fscanf(f, "%u", &val) == 1)) {
3932 cpu_power[i].MaxMhz = val / 1000;
3933 fclose(f);
3934 cpu_power[i].CurrentMhz = cpu_power[i].MaxMhz;
3936 else {
3937 if(i == 0) {
3938 cpu_power[0].CurrentMhz = mhz_from_cpuinfo();
3939 if(cpu_power[0].CurrentMhz == 0)
3940 cpu_power[0].CurrentMhz = cannedMHz;
3942 else
3943 cpu_power[i].CurrentMhz = cpu_power[0].CurrentMhz;
3944 cpu_power[i].MaxMhz = cpu_power[i].CurrentMhz;
3945 if(f) fclose(f);
3948 snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", i);
3949 f = fopen(filename, "r");
3950 if(f && (fscanf(f, "%u", &val) == 1)) {
3951 cpu_power[i].MhzLimit = val / 1000;
3952 fclose(f);
3954 else
3956 cpu_power[i].MhzLimit = cpu_power[i].MaxMhz;
3957 if(f) fclose(f);
3960 cpu_power[i].Number = i;
3961 cpu_power[i].MaxIdleState = 0; /* FIXME */
3962 cpu_power[i].CurrentIdleState = 0; /* FIXME */
3965 #elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__)
3967 int num;
3968 size_t valSize = sizeof(num);
3969 if (sysctlbyname("hw.clockrate", &num, &valSize, NULL, 0))
3970 num = cannedMHz;
3971 for(i = 0; i < out_cpus; i++) {
3972 cpu_power[i].CurrentMhz = num;
3973 cpu_power[i].MaxMhz = num;
3974 cpu_power[i].MhzLimit = num;
3975 cpu_power[i].Number = i;
3976 cpu_power[i].MaxIdleState = 0; /* FIXME */
3977 cpu_power[i].CurrentIdleState = 0; /* FIXME */
3980 #elif defined (__APPLE__)
3982 size_t valSize;
3983 unsigned long long currentMhz;
3984 unsigned long long maxMhz;
3986 valSize = sizeof(currentMhz);
3987 if (!sysctlbyname("hw.cpufrequency", &currentMhz, &valSize, NULL, 0))
3988 currentMhz /= 1000000;
3989 else
3990 currentMhz = cannedMHz;
3992 valSize = sizeof(maxMhz);
3993 if (!sysctlbyname("hw.cpufrequency_max", &maxMhz, &valSize, NULL, 0))
3994 maxMhz /= 1000000;
3995 else
3996 maxMhz = currentMhz;
3998 for(i = 0; i < out_cpus; i++) {
3999 cpu_power[i].CurrentMhz = currentMhz;
4000 cpu_power[i].MaxMhz = maxMhz;
4001 cpu_power[i].MhzLimit = maxMhz;
4002 cpu_power[i].Number = i;
4003 cpu_power[i].MaxIdleState = 0; /* FIXME */
4004 cpu_power[i].CurrentIdleState = 0; /* FIXME */
4007 #else
4008 for(i = 0; i < out_cpus; i++) {
4009 cpu_power[i].CurrentMhz = cannedMHz;
4010 cpu_power[i].MaxMhz = cannedMHz;
4011 cpu_power[i].MhzLimit = cannedMHz;
4012 cpu_power[i].Number = i;
4013 cpu_power[i].MaxIdleState = 0; /* FIXME */
4014 cpu_power[i].CurrentIdleState = 0; /* FIXME */
4016 WARN("Unable to detect CPU MHz for this platform. Reporting %d MHz.\n", cannedMHz);
4017 #endif
4018 for(i = 0; i < out_cpus; i++) {
4019 TRACE("cpu_power[%d] = %u %u %u %u %u %u\n", i, (int)cpu_power[i].Number,
4020 (int)cpu_power[i].MaxMhz, (int)cpu_power[i].CurrentMhz, (int)cpu_power[i].MhzLimit,
4021 (int)cpu_power[i].MaxIdleState, (int)cpu_power[i].CurrentIdleState);
4023 return STATUS_SUCCESS;
4026 default:
4027 /* FIXME: Needed by .NET Framework */
4028 WARN( "Unimplemented NtPowerInformation action: %d\n", level );
4029 return STATUS_NOT_IMPLEMENTED;
4034 /******************************************************************************
4035 * NtLoadDriver (NTDLL.@)
4037 NTSTATUS WINAPI NtLoadDriver( const UNICODE_STRING *name )
4039 FIXME( "(%s), stub!\n", debugstr_us(name) );
4040 return STATUS_NOT_IMPLEMENTED;
4044 /******************************************************************************
4045 * NtUnloadDriver (NTDLL.@)
4047 NTSTATUS WINAPI NtUnloadDriver( const UNICODE_STRING *name )
4049 FIXME( "(%s), stub!\n", debugstr_us(name) );
4050 return STATUS_NOT_IMPLEMENTED;
4054 /******************************************************************************
4055 * NtDisplayString (NTDLL.@)
4057 NTSTATUS WINAPI NtDisplayString( UNICODE_STRING *string )
4059 ERR( "%s\n", debugstr_us(string) );
4060 return STATUS_SUCCESS;
4064 /******************************************************************************
4065 * NtRaiseHardError (NTDLL.@)
4067 NTSTATUS WINAPI NtRaiseHardError( NTSTATUS status, ULONG count,
4068 UNICODE_STRING *params_mask, void **params,
4069 HARDERROR_RESPONSE_OPTION option, HARDERROR_RESPONSE *response )
4071 FIXME( "%08x stub\n", (int)status );
4072 return STATUS_NOT_IMPLEMENTED;
4076 /******************************************************************************
4077 * NtInitiatePowerAction (NTDLL.@)
4079 NTSTATUS WINAPI NtInitiatePowerAction( POWER_ACTION action, SYSTEM_POWER_STATE state,
4080 ULONG flags, BOOLEAN async )
4082 FIXME( "(%d,%d,0x%08x,%d),stub\n", action, state, (int)flags, async );
4083 return STATUS_NOT_IMPLEMENTED;
4087 /******************************************************************************
4088 * NtSetThreadExecutionState (NTDLL.@)
4090 NTSTATUS WINAPI NtSetThreadExecutionState( EXECUTION_STATE new_state, EXECUTION_STATE *old_state )
4092 static EXECUTION_STATE current = ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED | ES_USER_PRESENT;
4094 WARN( "(0x%x, %p): stub, harmless.\n", (int)new_state, old_state );
4095 *old_state = current;
4096 if (!(current & ES_CONTINUOUS) || (new_state & ES_CONTINUOUS)) current = new_state;
4097 return STATUS_SUCCESS;