ntdll: Don't hard-code the battery and AC adapter names on Linux.
[wine.git] / dlls / ntdll / unix / system.c
blob0df20aff3d5daf80300e17c735a40d8aac5b140a
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 HAVE_IOKIT_IOKITLIB_H
58 # include <CoreFoundation/CoreFoundation.h>
59 # include <IOKit/IOKitLib.h>
60 # include <IOKit/pwr_mgt/IOPM.h>
61 # include <IOKit/pwr_mgt/IOPMLib.h>
62 # include <IOKit/ps/IOPowerSources.h>
63 #endif
64 #ifdef __APPLE__
65 # include <mach/mach.h>
66 # include <mach/machine.h>
67 # include <mach/mach_init.h>
68 # include <mach/mach_host.h>
69 # include <mach/vm_map.h>
70 #endif
72 #define NONAMELESSUNION
73 #include "ntstatus.h"
74 #define WIN32_NO_STATUS
75 #include "windef.h"
76 #include "winternl.h"
77 #include "ddk/wdm.h"
78 #include "wine/asm.h"
79 #include "unix_private.h"
80 #include "wine/debug.h"
82 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
84 #include "pshpack1.h"
86 struct smbios_prologue
88 BYTE calling_method;
89 BYTE major_version;
90 BYTE minor_version;
91 BYTE revision;
92 DWORD length;
95 struct smbios_header
97 BYTE type;
98 BYTE length;
99 WORD handle;
102 struct smbios_bios
104 struct smbios_header hdr;
105 BYTE vendor;
106 BYTE version;
107 WORD start;
108 BYTE date;
109 BYTE size;
110 UINT64 characteristics;
111 BYTE characteristics_ext[2];
112 BYTE system_bios_major_release;
113 BYTE system_bios_minor_release;
114 BYTE ec_firmware_major_release;
115 BYTE ec_firmware_minor_release;
118 struct smbios_system
120 struct smbios_header hdr;
121 BYTE vendor;
122 BYTE product;
123 BYTE version;
124 BYTE serial;
125 BYTE uuid[16];
126 BYTE wake_up_type;
127 BYTE sku_number;
128 BYTE family;
131 struct smbios_board
133 struct smbios_header hdr;
134 BYTE vendor;
135 BYTE product;
136 BYTE version;
137 BYTE serial;
138 BYTE asset_tag;
139 BYTE feature_flags;
140 BYTE location;
141 WORD chassis_handle;
142 BYTE board_type;
143 BYTE num_contained_handles;
146 struct smbios_chassis
148 struct smbios_header hdr;
149 BYTE vendor;
150 BYTE type;
151 BYTE version;
152 BYTE serial;
153 BYTE asset_tag;
154 BYTE boot_state;
155 BYTE power_supply_state;
156 BYTE thermal_state;
157 BYTE security_status;
158 DWORD oem_defined;
159 BYTE height;
160 BYTE num_power_cords;
161 BYTE num_contained_elements;
162 BYTE contained_element_rec_length;
165 struct smbios_boot_info
167 struct smbios_header hdr;
168 BYTE reserved[6];
169 BYTE boot_status[10];
172 #include "poppack.h"
174 struct smbios_bios_args
176 const char *vendor;
177 size_t vendor_len;
178 const char *version;
179 size_t version_len;
180 const char *date;
181 size_t date_len;
184 struct smbios_system_args
186 const char *vendor;
187 size_t vendor_len;
188 const char *product;
189 size_t product_len;
190 const char *version;
191 size_t version_len;
192 const char *serial;
193 size_t serial_len;
194 GUID uuid;
195 const char *sku;
196 size_t sku_len;
197 const char *family;
198 size_t family_len;
201 struct smbios_board_args
203 const char *vendor;
204 size_t vendor_len;
205 const char *product;
206 size_t product_len;
207 const char *version;
208 size_t version_len;
209 const char *serial;
210 size_t serial_len;
211 const char *asset_tag;
212 size_t asset_tag_len;
215 struct smbios_chassis_args
217 const char *vendor;
218 size_t vendor_len;
219 BYTE type;
220 const char *version;
221 size_t version_len;
222 const char *serial;
223 size_t serial_len;
224 const char *asset_tag;
225 size_t asset_tag_len;
228 /* Firmware table providers */
229 #define ACPI 0x41435049
230 #define FIRM 0x4649524D
231 #define RSMB 0x52534D42
233 SYSTEM_CPU_INFORMATION cpu_info = { 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 /*******************************************************************************
240 * Architecture specific feature detection for CPUs
242 * This a set of mutually exclusive #if define()s each providing its own get_cpuinfo() to be called
243 * from init_cpu_info();
245 #if defined(__i386__) || defined(__x86_64__)
247 BOOL xstate_compaction_enabled = FALSE;
249 #define AUTH 0x68747541 /* "Auth" */
250 #define ENTI 0x69746e65 /* "enti" */
251 #define CAMD 0x444d4163 /* "cAMD" */
253 #define GENU 0x756e6547 /* "Genu" */
254 #define INEI 0x49656e69 /* "ineI" */
255 #define NTEL 0x6c65746e /* "ntel" */
257 extern void do_cpuid( unsigned int ax, unsigned int cx, unsigned int *p ) DECLSPEC_HIDDEN;
258 #ifdef __i386__
259 __ASM_GLOBAL_FUNC( do_cpuid,
260 "pushl %esi\n\t"
261 "pushl %ebx\n\t"
262 "movl 12(%esp),%eax\n\t"
263 "movl 16(%esp),%ecx\n\t"
264 "movl 20(%esp),%esi\n\t"
265 "cpuid\n\t"
266 "movl %eax,(%esi)\n\t"
267 "movl %ebx,4(%esi)\n\t"
268 "movl %ecx,8(%esi)\n\t"
269 "movl %edx,12(%esi)\n\t"
270 "popl %ebx\n\t"
271 "popl %esi\n\t"
272 "ret" )
273 #else
274 __ASM_GLOBAL_FUNC( do_cpuid,
275 "pushq %rbx\n\t"
276 "movl %edi,%eax\n\t"
277 "movl %esi,%ecx\n\t"
278 "movq %rdx,%r8\n\t"
279 "cpuid\n\t"
280 "movl %eax,(%r8)\n\t"
281 "movl %ebx,4(%r8)\n\t"
282 "movl %ecx,8(%r8)\n\t"
283 "movl %edx,12(%r8)\n\t"
284 "popq %rbx\n\t"
285 "ret" )
286 #endif
288 #ifdef __i386__
289 extern int have_cpuid(void) DECLSPEC_HIDDEN;
290 __ASM_GLOBAL_FUNC( have_cpuid,
291 "pushfl\n\t"
292 "pushfl\n\t"
293 "movl (%esp),%ecx\n\t"
294 "xorl $0x00200000,(%esp)\n\t"
295 "popfl\n\t"
296 "pushfl\n\t"
297 "popl %eax\n\t"
298 "popfl\n\t"
299 "xorl %ecx,%eax\n\t"
300 "andl $0x00200000,%eax\n\t"
301 "ret" )
302 #else
303 static int have_cpuid(void)
305 return 1;
307 #endif
309 /* Detect if a SSE2 processor is capable of Denormals Are Zero (DAZ) mode.
311 * This function assumes you have already checked for SSE2/FXSAVE support. */
312 static inline BOOL have_sse_daz_mode(void)
314 #ifdef __i386__
315 /* Intel says we need a zeroed 16-byte aligned buffer */
316 char buffer[512 + 16];
317 XSAVE_FORMAT *state = (XSAVE_FORMAT *)(((ULONG_PTR)buffer + 15) & ~15);
318 memset(buffer, 0, sizeof(buffer));
320 __asm__ __volatile__( "fxsave %0" : "=m" (*state) : "m" (*state) );
322 return (state->MxCsr_Mask & (1 << 6)) >> 6;
323 #else /* all x86_64 processors include SSE2 with DAZ mode */
324 return TRUE;
325 #endif
328 static void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
330 unsigned int regs[4], regs2[4], regs3[4];
332 #if defined(__i386__)
333 info->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
334 #elif defined(__x86_64__)
335 info->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
336 #endif
338 /* We're at least a 386 */
339 info->ProcessorFeatureBits = CPU_FEATURE_VME | CPU_FEATURE_X86 | CPU_FEATURE_PGE;
340 info->ProcessorLevel = 3;
342 if (!have_cpuid()) return;
344 do_cpuid( 0x00000000, 0, regs ); /* get standard cpuid level and vendor name */
345 if (regs[0]>=0x00000001) /* Check for supported cpuid version */
347 do_cpuid( 0x00000001, 0, regs2 ); /* get cpu features */
348 if (regs2[3] & (1 << 3 )) info->ProcessorFeatureBits |= CPU_FEATURE_PSE;
349 if (regs2[3] & (1 << 4 )) info->ProcessorFeatureBits |= CPU_FEATURE_TSC;
350 if (regs2[3] & (1 << 6 )) info->ProcessorFeatureBits |= CPU_FEATURE_PAE;
351 if (regs2[3] & (1 << 8 )) info->ProcessorFeatureBits |= CPU_FEATURE_CX8;
352 if (regs2[3] & (1 << 11)) info->ProcessorFeatureBits |= CPU_FEATURE_SEP;
353 if (regs2[3] & (1 << 12)) info->ProcessorFeatureBits |= CPU_FEATURE_MTRR;
354 if (regs2[3] & (1 << 15)) info->ProcessorFeatureBits |= CPU_FEATURE_CMOV;
355 if (regs2[3] & (1 << 16)) info->ProcessorFeatureBits |= CPU_FEATURE_PAT;
356 if (regs2[3] & (1 << 23)) info->ProcessorFeatureBits |= CPU_FEATURE_MMX;
357 if (regs2[3] & (1 << 24)) info->ProcessorFeatureBits |= CPU_FEATURE_FXSR;
358 if (regs2[3] & (1 << 25)) info->ProcessorFeatureBits |= CPU_FEATURE_SSE;
359 if (regs2[3] & (1 << 26)) info->ProcessorFeatureBits |= CPU_FEATURE_SSE2;
360 if (regs2[2] & (1 << 0 )) info->ProcessorFeatureBits |= CPU_FEATURE_SSE3;
361 if (regs2[2] & (1 << 9 )) info->ProcessorFeatureBits |= CPU_FEATURE_SSSE3;
362 if (regs2[2] & (1 << 13)) info->ProcessorFeatureBits |= CPU_FEATURE_CX128;
363 if (regs2[2] & (1 << 19)) info->ProcessorFeatureBits |= CPU_FEATURE_SSE41;
364 if (regs2[2] & (1 << 20)) info->ProcessorFeatureBits |= CPU_FEATURE_SSE42;
365 if (regs2[2] & (1 << 27)) info->ProcessorFeatureBits |= CPU_FEATURE_XSAVE;
366 if (regs2[2] & (1 << 28)) info->ProcessorFeatureBits |= CPU_FEATURE_AVX;
367 if((regs2[3] & (1 << 26)) && (regs2[3] & (1 << 24)) && have_sse_daz_mode()) /* has SSE2 and FXSAVE/FXRSTOR */
368 info->ProcessorFeatureBits |= CPU_FEATURE_DAZ;
370 if (regs[0] >= 0x00000007)
372 do_cpuid( 0x00000007, 0, regs3 ); /* get extended features */
373 if (regs3[1] & (1 << 5)) info->ProcessorFeatureBits |= CPU_FEATURE_AVX2;
376 if (info->ProcessorFeatureBits & CPU_FEATURE_XSAVE)
378 do_cpuid( 0x0000000d, 1, regs3 ); /* get XSAVE details */
379 if (regs3[0] & 2) xstate_compaction_enabled = TRUE;
382 if (regs[1] == AUTH && regs[3] == ENTI && regs[2] == CAMD)
384 info->ProcessorLevel = (regs2[0] >> 8) & 0xf; /* family */
385 if (info->ProcessorLevel == 0xf) /* AMD says to add the extended family to the family if family is 0xf */
386 info->ProcessorLevel += (regs2[0] >> 20) & 0xff;
388 /* repack model and stepping to make a "revision" */
389 info->ProcessorRevision = ((regs2[0] >> 16) & 0xf) << 12; /* extended model */
390 info->ProcessorRevision |= ((regs2[0] >> 4 ) & 0xf) << 8; /* model */
391 info->ProcessorRevision |= regs2[0] & 0xf; /* stepping */
393 do_cpuid( 0x80000000, 0, regs ); /* get vendor cpuid level */
394 if (regs[0] >= 0x80000001)
396 do_cpuid( 0x80000001, 0, regs2 ); /* get vendor features */
397 if (regs2[2] & (1 << 2)) info->ProcessorFeatureBits |= CPU_FEATURE_VIRT;
398 if (regs2[3] & (1 << 20)) info->ProcessorFeatureBits |= CPU_FEATURE_NX;
399 if (regs2[3] & (1 << 27)) info->ProcessorFeatureBits |= CPU_FEATURE_TSC;
400 if (regs2[3] & (1u << 31)) info->ProcessorFeatureBits |= CPU_FEATURE_3DNOW;
403 else if (regs[1] == GENU && regs[3] == INEI && regs[2] == NTEL)
405 info->ProcessorLevel = ((regs2[0] >> 8) & 0xf) + ((regs2[0] >> 20) & 0xff); /* family + extended family */
406 if(info->ProcessorLevel == 15) info->ProcessorLevel = 6;
408 /* repack model and stepping to make a "revision" */
409 info->ProcessorRevision = ((regs2[0] >> 16) & 0xf) << 12; /* extended model */
410 info->ProcessorRevision |= ((regs2[0] >> 4 ) & 0xf) << 8; /* model */
411 info->ProcessorRevision |= regs2[0] & 0xf; /* stepping */
413 if(regs2[2] & (1 << 5)) info->ProcessorFeatureBits |= CPU_FEATURE_VIRT;
414 if(regs2[3] & (1 << 21)) info->ProcessorFeatureBits |= CPU_FEATURE_DS;
416 do_cpuid( 0x80000000, 0, regs ); /* get vendor cpuid level */
417 if (regs[0] >= 0x80000001)
419 do_cpuid( 0x80000001, 0, regs2 ); /* get vendor features */
420 if (regs2[3] & (1 << 20)) info->ProcessorFeatureBits |= CPU_FEATURE_NX;
421 if (regs2[3] & (1 << 27)) info->ProcessorFeatureBits |= CPU_FEATURE_TSC;
424 else
426 info->ProcessorLevel = (regs2[0] >> 8) & 0xf; /* family */
428 /* repack model and stepping to make a "revision" */
429 info->ProcessorRevision = ((regs2[0] >> 4 ) & 0xf) << 8; /* model */
430 info->ProcessorRevision |= regs2[0] & 0xf; /* stepping */
435 #elif defined(__arm__)
437 static inline void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
439 #ifdef linux
440 char line[512];
441 char *s, *value;
442 FILE *f = fopen("/proc/cpuinfo", "r");
443 if (f)
445 while (fgets( line, sizeof(line), f ))
447 /* NOTE: the ':' is the only character we can rely on */
448 if (!(value = strchr(line,':'))) continue;
449 /* terminate the valuename */
450 s = value - 1;
451 while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
452 s[1] = 0;
453 /* and strip leading spaces from value */
454 value += 1;
455 while (*value == ' ' || *value == '\t') value++;
456 if ((s = strchr( value,'\n' ))) *s = 0;
457 if (!strcmp( line, "CPU architecture" ))
459 info->ProcessorLevel = atoi(value);
460 continue;
462 if (!strcmp( line, "CPU revision" ))
464 info->ProcessorRevision = atoi(value);
465 continue;
467 if (!strcmp( line, "Features" ))
469 if (strstr(value, "crc32")) info->ProcessorFeatureBits |= CPU_FEATURE_ARM_V8_CRC32;
470 if (strstr(value, "aes")) info->ProcessorFeatureBits |= CPU_FEATURE_ARM_V8_CRYPTO;
471 continue;
474 fclose( f );
476 #elif defined(__FreeBSD__)
477 size_t valsize;
478 char buf[8];
479 int value;
481 valsize = sizeof(buf);
482 if (!sysctlbyname("hw.machine_arch", &buf, &valsize, NULL, 0) && sscanf(buf, "armv%i", &value) == 1)
483 info->ProcessorLevel = value;
485 valsize = sizeof(value);
486 if (!sysctlbyname("hw.floatingpoint", &value, &valsize, NULL, 0))
487 info->ProcessorFeatureBits |= CPU_FEATURE_ARM_VFP_32;
488 #else
489 FIXME("CPU Feature detection not implemented.\n");
490 #endif
491 info->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_ARM;
494 #elif defined(__aarch64__)
496 static void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
498 #ifdef linux
499 char line[512];
500 char *s, *value;
501 FILE *f = fopen("/proc/cpuinfo", "r");
502 if (f)
504 while (fgets( line, sizeof(line), f ))
506 /* NOTE: the ':' is the only character we can rely on */
507 if (!(value = strchr(line,':'))) continue;
508 /* terminate the valuename */
509 s = value - 1;
510 while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
511 s[1] = 0;
512 /* and strip leading spaces from value */
513 value += 1;
514 while (*value == ' ' || *value == '\t') value++;
515 if ((s = strchr( value,'\n' ))) *s = 0;
516 if (!strcmp( line, "CPU architecture" ))
518 info->ProcessorLevel = atoi(value);
519 continue;
521 if (!strcmp( line, "CPU revision" ))
523 info->ProcessorRevision = atoi(value);
524 continue;
526 if (!strcmp( line, "Features" ))
528 if (strstr(value, "crc32")) info->ProcessorFeatureBits |= CPU_FEATURE_ARM_V8_CRC32;
529 if (strstr(value, "aes")) info->ProcessorFeatureBits |= CPU_FEATURE_ARM_V8_CRYPTO;
530 continue;
533 fclose( f );
535 #else
536 FIXME("CPU Feature detection not implemented.\n");
537 #endif
538 info->ProcessorLevel = max(info->ProcessorLevel, 8);
539 info->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_ARM64;
542 #endif /* End architecture specific feature detection for CPUs */
544 static BOOL grow_logical_proc_buf(void)
546 SYSTEM_LOGICAL_PROCESSOR_INFORMATION *new_data;
547 unsigned int new_len;
549 if (logical_proc_info_len < logical_proc_info_alloc_len) return TRUE;
551 new_len = max( logical_proc_info_alloc_len * 2, logical_proc_info_len + 1 );
552 if (!(new_data = realloc( logical_proc_info, new_len * sizeof(*new_data) ))) return FALSE;
553 memset( new_data + logical_proc_info_alloc_len, 0,
554 (new_len - logical_proc_info_alloc_len) * sizeof(*new_data) );
555 logical_proc_info = new_data;
556 logical_proc_info_alloc_len = new_len;
557 return TRUE;
560 static BOOL grow_logical_proc_ex_buf( unsigned int add_size )
562 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *new_dataex;
563 DWORD new_len;
565 if ( logical_proc_info_ex_size + add_size <= logical_proc_info_ex_alloc_size ) return TRUE;
567 new_len = max( logical_proc_info_ex_alloc_size * 2, logical_proc_info_ex_alloc_size + add_size );
568 if (!(new_dataex = realloc( logical_proc_info_ex, new_len ))) return FALSE;
569 memset( (char *)new_dataex + logical_proc_info_ex_alloc_size, 0, new_len - logical_proc_info_ex_alloc_size );
570 logical_proc_info_ex = new_dataex;
571 logical_proc_info_ex_alloc_size = new_len;
572 return TRUE;
575 static DWORD log_proc_ex_size_plus( DWORD size )
577 /* add SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX.Relationship and .Size */
578 return sizeof(LOGICAL_PROCESSOR_RELATIONSHIP) + sizeof(DWORD) + size;
581 static DWORD count_bits( ULONG_PTR mask )
583 DWORD count = 0;
584 while (mask > 0)
586 if (mask & 1) ++count;
587 mask >>= 1;
589 return count;
592 /* Store package and core information for a logical processor. Parsing of processor
593 * data may happen in multiple passes; the 'id' parameter is then used to locate
594 * previously stored data. The type of data stored in 'id' depends on 'rel':
595 * - RelationProcessorPackage: package id ('CPU socket').
596 * - RelationProcessorCore: physical core number.
598 static BOOL logical_proc_info_add_by_id( LOGICAL_PROCESSOR_RELATIONSHIP rel, DWORD id, ULONG_PTR mask )
600 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
601 unsigned int ofs = 0, i;
603 for (i = 0; i < logical_proc_info_len; i++)
605 if (rel == RelationProcessorPackage && logical_proc_info[i].Relationship == rel
606 && logical_proc_info[i].u.Reserved[1] == id)
608 logical_proc_info[i].ProcessorMask |= mask;
609 return TRUE;
611 else if (rel == RelationProcessorCore && logical_proc_info[i].Relationship == rel
612 && logical_proc_info[i].u.Reserved[1] == id)
613 return TRUE;
616 if (!grow_logical_proc_buf()) return FALSE;
618 logical_proc_info[i].Relationship = rel;
619 logical_proc_info[i].ProcessorMask = mask;
620 if (rel == RelationProcessorCore)
621 logical_proc_info[i].u.ProcessorCore.Flags = count_bits( mask ) > 1 ? LTP_PC_SMT : 0;
622 logical_proc_info[i].u.Reserved[0] = 0;
623 logical_proc_info[i].u.Reserved[1] = id;
624 logical_proc_info_len = i + 1;
626 while (ofs < logical_proc_info_ex_size)
628 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((char *)logical_proc_info_ex + ofs);
629 if (rel == RelationProcessorPackage && dataex->Relationship == rel && dataex->u.Processor.Reserved[1] == id)
631 dataex->u.Processor.GroupMask[0].Mask |= mask;
632 return TRUE;
634 else if (rel == RelationProcessorCore && dataex->Relationship == rel && dataex->u.Processor.Reserved[1] == id)
636 return TRUE;
638 ofs += dataex->Size;
641 /* TODO: For now, just one group. If more than 64 processors, then we
642 * need another group. */
643 if (!grow_logical_proc_ex_buf( log_proc_ex_size_plus( sizeof(PROCESSOR_RELATIONSHIP) ))) return FALSE;
645 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((char *)logical_proc_info_ex + ofs);
647 dataex->Relationship = rel;
648 dataex->Size = log_proc_ex_size_plus( sizeof(PROCESSOR_RELATIONSHIP) );
649 if (rel == RelationProcessorCore)
650 dataex->u.Processor.Flags = count_bits( mask ) > 1 ? LTP_PC_SMT : 0;
651 else
652 dataex->u.Processor.Flags = 0;
653 dataex->u.Processor.EfficiencyClass = 0;
654 dataex->u.Processor.GroupCount = 1;
655 dataex->u.Processor.GroupMask[0].Mask = mask;
656 dataex->u.Processor.GroupMask[0].Group = 0;
657 /* mark for future lookup */
658 dataex->u.Processor.Reserved[0] = 0;
659 dataex->u.Processor.Reserved[1] = id;
661 logical_proc_info_ex_size += dataex->Size;
663 return TRUE;
666 static BOOL logical_proc_info_add_cache( ULONG_PTR mask, CACHE_DESCRIPTOR *cache )
668 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
669 unsigned int ofs = 0, i;
671 for (i = 0; i < logical_proc_info_len; i++)
673 if (logical_proc_info[i].Relationship==RelationCache && logical_proc_info[i].ProcessorMask==mask
674 && logical_proc_info[i].u.Cache.Level==cache->Level && logical_proc_info[i].u.Cache.Type==cache->Type)
675 return TRUE;
678 if (!grow_logical_proc_buf()) return FALSE;
680 logical_proc_info[i].Relationship = RelationCache;
681 logical_proc_info[i].ProcessorMask = mask;
682 logical_proc_info[i].u.Cache = *cache;
683 logical_proc_info_len = i + 1;
685 for (ofs = 0; ofs < logical_proc_info_ex_size; )
687 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((char *)logical_proc_info_ex + ofs);
688 if (dataex->Relationship == RelationCache && dataex->u.Cache.GroupMask.Mask == mask
689 && dataex->u.Cache.Level == cache->Level && dataex->u.Cache.Type == cache->Type)
690 return TRUE;
691 ofs += dataex->Size;
694 if (!grow_logical_proc_ex_buf( log_proc_ex_size_plus( sizeof(CACHE_RELATIONSHIP) ))) return FALSE;
696 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((char *)logical_proc_info_ex + ofs);
698 dataex->Relationship = RelationCache;
699 dataex->Size = log_proc_ex_size_plus( sizeof(CACHE_RELATIONSHIP) );
700 dataex->u.Cache.Level = cache->Level;
701 dataex->u.Cache.Associativity = cache->Associativity;
702 dataex->u.Cache.LineSize = cache->LineSize;
703 dataex->u.Cache.CacheSize = cache->Size;
704 dataex->u.Cache.Type = cache->Type;
705 dataex->u.Cache.GroupMask.Mask = mask;
706 dataex->u.Cache.GroupMask.Group = 0;
708 logical_proc_info_ex_size += dataex->Size;
710 return TRUE;
713 static BOOL logical_proc_info_add_numa_node( ULONG_PTR mask, DWORD node_id )
715 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
717 if (!grow_logical_proc_buf()) return FALSE;
719 logical_proc_info[logical_proc_info_len].Relationship = RelationNumaNode;
720 logical_proc_info[logical_proc_info_len].ProcessorMask = mask;
721 logical_proc_info[logical_proc_info_len].u.NumaNode.NodeNumber = node_id;
722 ++logical_proc_info_len;
724 if (!grow_logical_proc_ex_buf( log_proc_ex_size_plus( sizeof(NUMA_NODE_RELATIONSHIP) ))) return FALSE;
726 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((char *)logical_proc_info_ex + logical_proc_info_ex_size);
728 dataex->Relationship = RelationNumaNode;
729 dataex->Size = log_proc_ex_size_plus( sizeof(NUMA_NODE_RELATIONSHIP) );
730 dataex->u.NumaNode.NodeNumber = node_id;
731 dataex->u.NumaNode.GroupMask.Mask = mask;
732 dataex->u.NumaNode.GroupMask.Group = 0;
734 logical_proc_info_ex_size += dataex->Size;
736 return TRUE;
739 static BOOL logical_proc_info_add_group( DWORD num_cpus, ULONG_PTR mask )
741 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
743 if (!grow_logical_proc_ex_buf( log_proc_ex_size_plus( sizeof(GROUP_RELATIONSHIP) ))) return FALSE;
745 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)logical_proc_info_ex) + logical_proc_info_ex_size);
747 dataex->Relationship = RelationGroup;
748 dataex->Size = log_proc_ex_size_plus( sizeof(GROUP_RELATIONSHIP) );
749 dataex->u.Group.MaximumGroupCount = 1;
750 dataex->u.Group.ActiveGroupCount = 1;
751 dataex->u.Group.GroupInfo[0].MaximumProcessorCount = num_cpus;
752 dataex->u.Group.GroupInfo[0].ActiveProcessorCount = num_cpus;
753 dataex->u.Group.GroupInfo[0].ActiveProcessorMask = mask;
755 logical_proc_info_ex_size += dataex->Size;
756 return TRUE;
759 #ifdef linux
761 /* Helper function for counting bitmap values as commonly used by the Linux kernel
762 * for storing CPU masks in sysfs. The format is comma separated lists of hex values
763 * each max 32-bit e.g. "00ff" or even "00,00000000,0000ffff".
765 * Example files include:
766 * - /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_map
767 * - /sys/devices/system/cpu/cpu0/topology/thread_siblings
769 static BOOL sysfs_parse_bitmap(const char *filename, ULONG_PTR *mask)
771 FILE *f;
772 DWORD r;
774 f = fopen(filename, "r");
775 if (!f) return FALSE;
777 while (!feof(f))
779 char op;
780 if (!fscanf(f, "%x%c ", &r, &op)) break;
781 *mask = (sizeof(ULONG_PTR)>sizeof(int) ? *mask << (8 * sizeof(DWORD)) : 0) + r;
783 fclose( f );
784 return TRUE;
787 /* Helper function for counting number of elements in interval lists as used by
788 * the Linux kernel. The format is comma separated list of intervals of which
789 * each interval has the format of "begin-end" where begin and end are decimal
790 * numbers. E.g. "0-7", "0-7,16-23"
792 * Example files include:
793 * - /sys/devices/system/cpu/online
794 * - /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_list
795 * - /sys/devices/system/cpu/cpu0/topology/thread_siblings_list.
797 static BOOL sysfs_count_list_elements(const char *filename, DWORD *result)
799 FILE *f;
801 f = fopen(filename, "r");
802 if (!f) return FALSE;
804 while (!feof(f))
806 char op;
807 DWORD beg, end;
809 if (!fscanf(f, "%u%c ", &beg, &op)) break;
810 if(op == '-')
811 fscanf(f, "%u%c ", &end, &op);
812 else
813 end = beg;
815 *result += end - beg + 1;
817 fclose( f );
818 return TRUE;
821 /* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
822 static NTSTATUS create_logical_proc_info(void)
824 static const char core_info[] = "/sys/devices/system/cpu/cpu%u/topology/%s";
825 static const char cache_info[] = "/sys/devices/system/cpu/cpu%u/cache/index%u/%s";
826 static const char numa_info[] = "/sys/devices/system/node/node%u/cpumap";
828 FILE *fcpu_list, *fnuma_list, *f;
829 DWORD beg, end, i, j, r, num_cpus = 0, max_cpus = 0;
830 char op, name[MAX_PATH];
831 ULONG_PTR all_cpus_mask = 0;
833 /* On systems with a large number of CPU cores (32 or 64 depending on 32-bit or 64-bit),
834 * we have issues parsing processor information:
835 * - ULONG_PTR masks as used in data structures can't hold all cores. Requires splitting
836 * data appropriately into "processor groups". We are hard coding 1.
837 * - Thread affinity code in wineserver and our CPU parsing code here work independently.
838 * So far the Windows mask applied directly to Linux, but process groups break that.
839 * (NUMA systems you may have multiple non-full groups.)
841 if(sysfs_count_list_elements("/sys/devices/system/cpu/present", &max_cpus) && max_cpus > MAXIMUM_PROCESSORS)
843 FIXME("Improve CPU info reporting: system supports %u logical cores, but only %u supported!\n",
844 max_cpus, MAXIMUM_PROCESSORS);
847 fcpu_list = fopen("/sys/devices/system/cpu/online", "r");
848 if (!fcpu_list) return STATUS_NOT_IMPLEMENTED;
850 while (!feof(fcpu_list))
852 if (!fscanf(fcpu_list, "%u%c ", &beg, &op)) break;
853 if (op == '-') fscanf(fcpu_list, "%u%c ", &end, &op);
854 else end = beg;
856 for(i = beg; i <= end; i++)
858 DWORD phys_core = 0;
859 ULONG_PTR thread_mask = 0;
861 if (i > 8 * sizeof(ULONG_PTR))
863 FIXME("skipping logical processor %d\n", i);
864 continue;
867 sprintf(name, core_info, i, "physical_package_id");
868 f = fopen(name, "r");
869 if (f)
871 fscanf(f, "%u", &r);
872 fclose(f);
874 else r = 0;
875 if (!logical_proc_info_add_by_id( RelationProcessorPackage, r, (ULONG_PTR)1 << i ))
877 fclose(fcpu_list);
878 return STATUS_NO_MEMORY;
881 /* Sysfs enumerates logical cores (and not physical cores), but Windows enumerates
882 * by physical core. Upon enumerating a logical core in sysfs, we register a physical
883 * core and all its logical cores. In order to not report physical cores multiple
884 * times, we pass a unique physical core ID to logical_proc_info_add_by_id and let
885 * that call figure out any duplication.
886 * Obtain a unique physical core ID from the first element of thread_siblings_list.
887 * This list provides logical cores sharing the same physical core. The IDs are based
888 * on kernel cpu core numbering as opposed to a hardware core ID like provided through
889 * 'core_id', so are suitable as a unique ID.
892 /* Mask of logical threads sharing same physical core in kernel core numbering. */
893 sprintf(name, core_info, i, "thread_siblings");
894 if(!sysfs_parse_bitmap(name, &thread_mask)) thread_mask = 1<<i;
896 /* Needed later for NumaNode and Group. */
897 all_cpus_mask |= thread_mask;
899 sprintf(name, core_info, i, "thread_siblings_list");
900 f = fopen(name, "r");
901 if (f)
903 fscanf(f, "%d%c", &phys_core, &op);
904 fclose(f);
906 else phys_core = i;
908 if (!logical_proc_info_add_by_id( RelationProcessorCore, phys_core, thread_mask ))
910 fclose(fcpu_list);
911 return STATUS_NO_MEMORY;
914 for (j = 0; j < 4; j++)
916 CACHE_DESCRIPTOR cache;
917 ULONG_PTR mask = 0;
919 sprintf(name, cache_info, i, j, "shared_cpu_map");
920 if(!sysfs_parse_bitmap(name, &mask)) continue;
922 sprintf(name, cache_info, i, j, "level");
923 f = fopen(name, "r");
924 if(!f) continue;
925 fscanf(f, "%u", &r);
926 fclose(f);
927 cache.Level = r;
929 sprintf(name, cache_info, i, j, "ways_of_associativity");
930 f = fopen(name, "r");
931 if(!f) continue;
932 fscanf(f, "%u", &r);
933 fclose(f);
934 cache.Associativity = r;
936 sprintf(name, cache_info, i, j, "coherency_line_size");
937 f = fopen(name, "r");
938 if(!f) continue;
939 fscanf(f, "%u", &r);
940 fclose(f);
941 cache.LineSize = r;
943 sprintf(name, cache_info, i, j, "size");
944 f = fopen(name, "r");
945 if(!f) continue;
946 fscanf(f, "%u%c", &r, &op);
947 fclose(f);
948 if(op != 'K')
949 WARN("unknown cache size %u%c\n", r, op);
950 cache.Size = (op=='K' ? r*1024 : r);
952 sprintf(name, cache_info, i, j, "type");
953 f = fopen(name, "r");
954 if(!f) continue;
955 fscanf(f, "%s", name);
956 fclose(f);
957 if (!memcmp(name, "Data", 5))
958 cache.Type = CacheData;
959 else if(!memcmp(name, "Instruction", 11))
960 cache.Type = CacheInstruction;
961 else
962 cache.Type = CacheUnified;
964 if (!logical_proc_info_add_cache( mask, &cache ))
966 fclose(fcpu_list);
967 return STATUS_NO_MEMORY;
972 fclose(fcpu_list);
974 num_cpus = count_bits(all_cpus_mask);
976 fnuma_list = fopen("/sys/devices/system/node/online", "r");
977 if (!fnuma_list)
979 if (!logical_proc_info_add_numa_node( all_cpus_mask, 0 ))
980 return STATUS_NO_MEMORY;
982 else
984 while (!feof(fnuma_list))
986 if (!fscanf(fnuma_list, "%u%c ", &beg, &op))
987 break;
988 if (op == '-') fscanf(fnuma_list, "%u%c ", &end, &op);
989 else end = beg;
991 for (i = beg; i <= end; i++)
993 ULONG_PTR mask = 0;
995 sprintf(name, numa_info, i);
996 if (!sysfs_parse_bitmap( name, &mask )) continue;
998 if (!logical_proc_info_add_numa_node( mask, i ))
1000 fclose(fnuma_list);
1001 return STATUS_NO_MEMORY;
1005 fclose(fnuma_list);
1008 logical_proc_info_add_group( num_cpus, all_cpus_mask );
1010 return STATUS_SUCCESS;
1013 #elif defined(__APPLE__)
1015 /* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
1016 static NTSTATUS create_logical_proc_info(void)
1018 DWORD pkgs_no, cores_no, lcpu_no, lcpu_per_core, cores_per_package, assoc;
1019 DWORD cache_ctrs[10] = {0};
1020 ULONG_PTR all_cpus_mask = 0;
1021 CACHE_DESCRIPTOR cache[10];
1022 LONGLONG cache_size, cache_line_size, cache_sharing[10];
1023 size_t size;
1024 DWORD p,i,j,k;
1026 lcpu_no = peb->NumberOfProcessors;
1028 size = sizeof(pkgs_no);
1029 if (sysctlbyname("hw.packages", &pkgs_no, &size, NULL, 0))
1030 pkgs_no = 1;
1032 size = sizeof(cores_no);
1033 if (sysctlbyname("hw.physicalcpu", &cores_no, &size, NULL, 0))
1034 cores_no = lcpu_no;
1036 TRACE("%u logical CPUs from %u physical cores across %u packages\n",
1037 lcpu_no, cores_no, pkgs_no);
1039 lcpu_per_core = lcpu_no / cores_no;
1040 cores_per_package = cores_no / pkgs_no;
1042 memset(cache, 0, sizeof(cache));
1043 cache[1].Level = 1;
1044 cache[1].Type = CacheInstruction;
1045 cache[1].Associativity = 8; /* reasonable default */
1046 cache[1].LineSize = 0x40; /* reasonable default */
1047 cache[2].Level = 1;
1048 cache[2].Type = CacheData;
1049 cache[2].Associativity = 8;
1050 cache[2].LineSize = 0x40;
1051 cache[3].Level = 2;
1052 cache[3].Type = CacheUnified;
1053 cache[3].Associativity = 8;
1054 cache[3].LineSize = 0x40;
1055 cache[4].Level = 3;
1056 cache[4].Type = CacheUnified;
1057 cache[4].Associativity = 12;
1058 cache[4].LineSize = 0x40;
1060 size = sizeof(cache_line_size);
1061 if (!sysctlbyname("hw.cachelinesize", &cache_line_size, &size, NULL, 0))
1063 for (i = 1; i < 5; i++) cache[i].LineSize = cache_line_size;
1066 /* TODO: set actual associativity for all caches */
1067 size = sizeof(assoc);
1068 if (!sysctlbyname("machdep.cpu.cache.L2_associativity", &assoc, &size, NULL, 0))
1069 cache[3].Associativity = assoc;
1071 size = sizeof(cache_size);
1072 if (!sysctlbyname("hw.l1icachesize", &cache_size, &size, NULL, 0))
1073 cache[1].Size = cache_size;
1074 size = sizeof(cache_size);
1075 if (!sysctlbyname("hw.l1dcachesize", &cache_size, &size, NULL, 0))
1076 cache[2].Size = cache_size;
1077 size = sizeof(cache_size);
1078 if (!sysctlbyname("hw.l2cachesize", &cache_size, &size, NULL, 0))
1079 cache[3].Size = cache_size;
1080 size = sizeof(cache_size);
1081 if (!sysctlbyname("hw.l3cachesize", &cache_size, &size, NULL, 0))
1082 cache[4].Size = cache_size;
1084 size = sizeof(cache_sharing);
1085 if (sysctlbyname("hw.cacheconfig", cache_sharing, &size, NULL, 0) < 0)
1087 cache_sharing[1] = lcpu_per_core;
1088 cache_sharing[2] = lcpu_per_core;
1089 cache_sharing[3] = lcpu_per_core;
1090 cache_sharing[4] = lcpu_no;
1092 else
1094 /* in cache[], indexes 1 and 2 are l1 caches */
1095 cache_sharing[4] = cache_sharing[3];
1096 cache_sharing[3] = cache_sharing[2];
1097 cache_sharing[2] = cache_sharing[1];
1100 for(p = 0; p < pkgs_no; ++p)
1102 for(j = 0; j < cores_per_package && p * cores_per_package + j < cores_no; ++j)
1104 ULONG_PTR mask = 0;
1105 DWORD phys_core;
1107 for(k = 0; k < lcpu_per_core; ++k) mask |= (ULONG_PTR)1 << (j * lcpu_per_core + k);
1109 all_cpus_mask |= mask;
1111 /* add to package */
1112 if(!logical_proc_info_add_by_id( RelationProcessorPackage, p, mask ))
1113 return STATUS_NO_MEMORY;
1115 /* add new core */
1116 phys_core = p * cores_per_package + j;
1117 if(!logical_proc_info_add_by_id( RelationProcessorCore, phys_core, mask ))
1118 return STATUS_NO_MEMORY;
1120 for(i = 1; i < 5; ++i)
1122 if(cache_ctrs[i] == 0 && cache[i].Size > 0)
1124 mask = 0;
1125 for(k = 0; k < cache_sharing[i]; ++k)
1126 mask |= (ULONG_PTR)1 << (j * lcpu_per_core + k);
1128 if (!logical_proc_info_add_cache( mask, &cache[i] ))
1129 return STATUS_NO_MEMORY;
1132 cache_ctrs[i] += lcpu_per_core;
1133 if(cache_ctrs[i] == cache_sharing[i]) cache_ctrs[i] = 0;
1138 /* OSX doesn't support NUMA, so just make one NUMA node for all CPUs */
1139 if(!logical_proc_info_add_numa_node( all_cpus_mask, 0 ))
1140 return STATUS_NO_MEMORY;
1142 logical_proc_info_add_group( lcpu_no, all_cpus_mask );
1144 return STATUS_SUCCESS;
1147 #else
1149 static NTSTATUS create_logical_proc_info(void)
1151 FIXME("stub\n");
1152 return STATUS_NOT_IMPLEMENTED;
1154 #endif
1156 /******************************************************************
1157 * init_cpu_info
1159 * inits a couple of places with CPU related information:
1160 * - cpu_info in this file
1161 * - Peb->NumberOfProcessors
1162 * - SharedUserData->ProcessFeatures[] array
1164 void init_cpu_info(void)
1166 NTSTATUS status;
1167 long num;
1169 #ifdef _SC_NPROCESSORS_ONLN
1170 num = sysconf(_SC_NPROCESSORS_ONLN);
1171 if (num < 1)
1173 num = 1;
1174 WARN("Failed to detect the number of processors.\n");
1176 #elif defined(CTL_HW) && defined(HW_NCPU)
1177 int mib[2];
1178 size_t len = sizeof(num);
1179 mib[0] = CTL_HW;
1180 mib[1] = HW_NCPU;
1181 if (sysctl(mib, 2, &num, &len, NULL, 0) != 0)
1183 num = 1;
1184 WARN("Failed to detect the number of processors.\n");
1186 #else
1187 num = 1;
1188 FIXME("Detecting the number of processors is not supported.\n");
1189 #endif
1190 peb->NumberOfProcessors = num;
1191 get_cpuinfo( &cpu_info );
1192 TRACE( "<- CPU arch %d, level %d, rev %d, features 0x%x\n",
1193 cpu_info.ProcessorArchitecture, cpu_info.ProcessorLevel, cpu_info.ProcessorRevision,
1194 cpu_info.ProcessorFeatureBits );
1196 if ((status = create_logical_proc_info()))
1198 FIXME( "Failed to get logical processor information, status %#x.\n", status );
1199 free( logical_proc_info );
1200 logical_proc_info = NULL;
1201 logical_proc_info_len = 0;
1203 free( logical_proc_info_ex );
1204 logical_proc_info_ex = NULL;
1205 logical_proc_info_ex_size = 0;
1207 else
1209 logical_proc_info = realloc( logical_proc_info, logical_proc_info_len * sizeof(*logical_proc_info) );
1210 logical_proc_info_alloc_len = logical_proc_info_len;
1211 logical_proc_info_ex = realloc( logical_proc_info_ex, logical_proc_info_ex_size );
1212 logical_proc_info_ex_alloc_size = logical_proc_info_ex_size;
1216 static NTSTATUS create_cpuset_info(SYSTEM_CPU_SET_INFORMATION *info)
1218 const SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *proc_info;
1219 const DWORD cpu_info_size = logical_proc_info_ex_size;
1220 BYTE core_index, cache_index, max_cache_level;
1221 unsigned int i, j, count;
1222 ULONG64 cpu_mask;
1224 if (!logical_proc_info_ex) return STATUS_NOT_IMPLEMENTED;
1226 count = peb->NumberOfProcessors;
1228 max_cache_level = 0;
1229 proc_info = logical_proc_info_ex;
1230 for (i = 0; (char *)proc_info != (char *)logical_proc_info_ex + cpu_info_size; ++i)
1232 if (proc_info->Relationship == RelationCache)
1234 if (max_cache_level < proc_info->u.Cache.Level)
1235 max_cache_level = proc_info->u.Cache.Level;
1237 proc_info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((BYTE *)proc_info + proc_info->Size);
1240 memset(info, 0, count * sizeof(*info));
1242 core_index = 0;
1243 cache_index = 0;
1244 proc_info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)logical_proc_info_ex;
1245 for (i = 0; i < count; ++i)
1247 info[i].Size = sizeof(*info);
1248 info[i].Type = CpuSetInformation;
1249 info[i].u.CpuSet.Id = 0x100 + i;
1250 info[i].u.CpuSet.LogicalProcessorIndex = i;
1253 for (i = 0; (char *)proc_info != (char *)logical_proc_info_ex + cpu_info_size; ++i)
1255 if (proc_info->Relationship == RelationProcessorCore)
1257 if (proc_info->u.Processor.GroupCount != 1)
1259 FIXME("Unsupported group count %u.\n", proc_info->u.Processor.GroupCount);
1260 continue;
1262 cpu_mask = proc_info->u.Processor.GroupMask[0].Mask;
1263 for (j = 0; j < count; ++j)
1264 if (((ULONG64)1 << j) & cpu_mask)
1266 info[j].u.CpuSet.CoreIndex = core_index;
1267 info[j].u.CpuSet.EfficiencyClass = proc_info->u.Processor.EfficiencyClass;
1269 ++core_index;
1271 else if (proc_info->Relationship == RelationCache)
1273 if (proc_info->u.Cache.Level == max_cache_level)
1275 cpu_mask = proc_info->u.Cache.GroupMask.Mask;
1276 for (j = 0; j < count; ++j)
1277 if (((ULONG64)1 << j) & cpu_mask)
1278 info[j].u.CpuSet.LastLevelCacheIndex = cache_index;
1280 ++cache_index;
1282 else if (proc_info->Relationship == RelationNumaNode)
1284 cpu_mask = proc_info->u.NumaNode.GroupMask.Mask;
1285 for (j = 0; j < count; ++j)
1286 if (((ULONG64)1 << j) & cpu_mask)
1287 info[j].u.CpuSet.NumaNodeIndex = proc_info->u.NumaNode.NodeNumber;
1289 proc_info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((char *)proc_info + proc_info->Size);
1292 return STATUS_SUCCESS;
1295 #if defined(linux) || defined(__APPLE__)
1297 static void copy_smbios_string( char **buffer, const char *s, size_t len )
1299 if (!len) return;
1300 memcpy(*buffer, s, len + 1);
1301 *buffer += len + 1;
1304 static NTSTATUS create_smbios_tables( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1305 ULONG *required_len,
1306 const struct smbios_bios_args *bios_args,
1307 const struct smbios_system_args *system_args,
1308 const struct smbios_board_args *board_args,
1309 const struct smbios_chassis_args *chassis_args )
1311 char *buffer = (char*)sfti->TableBuffer;
1312 BYTE string_count;
1313 BYTE handle_count = 0;
1314 struct smbios_prologue *prologue;
1315 struct smbios_bios *bios;
1316 struct smbios_system *system;
1317 struct smbios_board *board;
1318 struct smbios_chassis *chassis;
1319 struct smbios_boot_info *boot_info;
1320 struct smbios_header *end_of_table;
1322 *required_len = sizeof(struct smbios_prologue);
1324 #define L(l) (l + (l ? 1 : 0))
1325 *required_len += sizeof(struct smbios_bios);
1326 *required_len += max(L(bios_args->vendor_len) + L(bios_args->version_len) + L(bios_args->date_len) + 1, 2);
1328 *required_len += sizeof(struct smbios_system);
1329 *required_len += max(L(system_args->vendor_len) + L(system_args->product_len) + L(system_args->version_len) +
1330 L(system_args->serial_len) + L(system_args->sku_len) + L(system_args->family_len) + 1, 2);
1332 *required_len += sizeof(struct smbios_board);
1333 *required_len += max(L(board_args->vendor_len) + L(board_args->product_len) + L(board_args->version_len) +
1334 L(board_args->serial_len) + L(board_args->asset_tag_len) + 1, 2);
1336 *required_len += sizeof(struct smbios_chassis);
1337 *required_len += max(L(chassis_args->vendor_len) + L(chassis_args->version_len) + L(chassis_args->serial_len) +
1338 L(chassis_args->asset_tag_len) + 1, 2);
1340 *required_len += sizeof(struct smbios_boot_info);
1341 *required_len += 2;
1343 *required_len += sizeof(struct smbios_header);
1344 *required_len += 2;
1345 #undef L
1347 sfti->TableBufferLength = *required_len;
1349 *required_len += FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
1351 if (available_len < *required_len)
1352 return STATUS_BUFFER_TOO_SMALL;
1354 prologue = (struct smbios_prologue*)buffer;
1355 prologue->calling_method = 0;
1356 prologue->major_version = 2;
1357 prologue->minor_version = 4;
1358 prologue->revision = 0;
1359 prologue->length = sfti->TableBufferLength - sizeof(struct smbios_prologue);
1360 buffer += sizeof(struct smbios_prologue);
1362 string_count = 0;
1363 bios = (struct smbios_bios*)buffer;
1364 bios->hdr.type = 0;
1365 bios->hdr.length = sizeof(struct smbios_bios);
1366 bios->hdr.handle = handle_count++;
1367 bios->vendor = bios_args->vendor_len ? ++string_count : 0;
1368 bios->version = bios_args->version_len ? ++string_count : 0;
1369 bios->start = 0;
1370 bios->date = bios_args->date_len ? ++string_count : 0;
1371 bios->size = 0;
1372 bios->characteristics = 0x4; /* not supported */
1373 bios->characteristics_ext[0] = 0;
1374 bios->characteristics_ext[1] = 0;
1375 bios->system_bios_major_release = 0xFF; /* not supported */
1376 bios->system_bios_minor_release = 0xFF; /* not supported */
1377 bios->ec_firmware_major_release = 0xFF; /* not supported */
1378 bios->ec_firmware_minor_release = 0xFF; /* not supported */
1379 buffer += sizeof(struct smbios_bios);
1381 copy_smbios_string(&buffer, bios_args->vendor, bios_args->vendor_len);
1382 copy_smbios_string(&buffer, bios_args->version, bios_args->version_len);
1383 copy_smbios_string(&buffer, bios_args->date, bios_args->date_len);
1384 if (!string_count) *buffer++ = 0;
1385 *buffer++ = 0;
1387 string_count = 0;
1388 system = (struct smbios_system*)buffer;
1389 system->hdr.type = 1;
1390 system->hdr.length = sizeof(struct smbios_system);
1391 system->hdr.handle = handle_count++;
1392 system->vendor = system_args->vendor_len ? ++string_count : 0;
1393 system->product = system_args->product_len ? ++string_count : 0;
1394 system->version = system_args->version_len ? ++string_count : 0;
1395 system->serial = system_args->serial_len ? ++string_count : 0;
1396 memcpy( system->uuid, &system_args->uuid, sizeof(GUID) );
1397 system->wake_up_type = 0x02; /* unknown */
1398 system->sku_number = system_args->sku_len ? ++string_count : 0;
1399 system->family = system_args->family_len ? ++string_count : 0;
1400 buffer += sizeof(struct smbios_system);
1402 copy_smbios_string(&buffer, system_args->vendor, system_args->vendor_len);
1403 copy_smbios_string(&buffer, system_args->product, system_args->product_len);
1404 copy_smbios_string(&buffer, system_args->version, system_args->version_len);
1405 copy_smbios_string(&buffer, system_args->serial, system_args->serial_len);
1406 copy_smbios_string(&buffer, system_args->sku, system_args->sku_len);
1407 copy_smbios_string(&buffer, system_args->family, system_args->family_len);
1408 if (!string_count) *buffer++ = 0;
1409 *buffer++ = 0;
1411 string_count = 0;
1412 chassis = (struct smbios_chassis*)buffer;
1413 chassis->hdr.type = 3;
1414 chassis->hdr.length = sizeof(struct smbios_chassis);
1415 chassis->hdr.handle = handle_count++;
1416 chassis->vendor = chassis_args->vendor_len ? ++string_count : 0;
1417 chassis->type = chassis_args->type;
1418 chassis->version = chassis_args->version_len ? ++string_count : 0;
1419 chassis->serial = chassis_args->serial_len ? ++string_count : 0;
1420 chassis->asset_tag = chassis_args->asset_tag_len ? ++string_count : 0;
1421 chassis->boot_state = 0x02; /* unknown */
1422 chassis->power_supply_state = 0x02; /* unknown */
1423 chassis->thermal_state = 0x02; /* unknown */
1424 chassis->security_status = 0x02; /* unknown */
1425 chassis->oem_defined = 0;
1426 chassis->height = 0; /* undefined */
1427 chassis->num_power_cords = 0; /* unspecified */
1428 chassis->num_contained_elements = 0;
1429 chassis->contained_element_rec_length = 3;
1430 buffer += sizeof(struct smbios_chassis);
1432 copy_smbios_string(&buffer, chassis_args->vendor, chassis_args->vendor_len);
1433 copy_smbios_string(&buffer, chassis_args->version, chassis_args->version_len);
1434 copy_smbios_string(&buffer, chassis_args->serial, chassis_args->serial_len);
1435 copy_smbios_string(&buffer, chassis_args->asset_tag, chassis_args->asset_tag_len);
1436 if (!string_count) *buffer++ = 0;
1437 *buffer++ = 0;
1439 string_count = 0;
1440 board = (struct smbios_board*)buffer;
1441 board->hdr.type = 2;
1442 board->hdr.length = sizeof(struct smbios_board);
1443 board->hdr.handle = handle_count++;
1444 board->vendor = board_args->vendor_len ? ++string_count : 0;
1445 board->product = board_args->product_len ? ++string_count : 0;
1446 board->version = board_args->version_len ? ++string_count : 0;
1447 board->serial = board_args->serial_len ? ++string_count : 0;
1448 board->asset_tag = board_args->asset_tag_len ? ++string_count : 0;
1449 board->feature_flags = 0x5; /* hosting board, removable */
1450 board->location = 0;
1451 board->chassis_handle = chassis->hdr.handle;
1452 board->board_type = 0xa; /* motherboard */
1453 board->num_contained_handles = 0;
1454 buffer += sizeof(struct smbios_board);
1456 copy_smbios_string(&buffer, board_args->vendor, board_args->vendor_len);
1457 copy_smbios_string(&buffer, board_args->product, board_args->product_len);
1458 copy_smbios_string(&buffer, board_args->version, board_args->version_len);
1459 copy_smbios_string(&buffer, board_args->serial, board_args->serial_len);
1460 copy_smbios_string(&buffer, board_args->asset_tag, board_args->asset_tag_len);
1461 if (!string_count) *buffer++ = 0;
1462 *buffer++ = 0;
1464 boot_info = (struct smbios_boot_info*)buffer;
1465 boot_info->hdr.type = 32;
1466 boot_info->hdr.length = sizeof(struct smbios_boot_info);
1467 boot_info->hdr.handle = handle_count++;
1468 memset(boot_info->reserved, 0, sizeof(boot_info->reserved));
1469 memset(boot_info->boot_status, 0, sizeof(boot_info->boot_status)); /* no errors detected */
1470 buffer += sizeof(struct smbios_boot_info);
1471 *buffer++ = 0;
1472 *buffer++ = 0;
1474 end_of_table = (struct smbios_header*)buffer;
1475 end_of_table->type = 127;
1476 end_of_table->length = sizeof(struct smbios_header);
1477 end_of_table->handle = handle_count++;
1478 buffer += sizeof(struct smbios_header);
1479 *buffer++ = 0;
1480 *buffer++ = 0;
1482 return STATUS_SUCCESS;
1485 #endif
1487 #ifdef linux
1489 static size_t get_smbios_string( const char *path, char *str, size_t size )
1491 FILE *file;
1492 size_t len;
1494 if (!(file = fopen(path, "r"))) return 0;
1496 len = fread( str, 1, size - 1, file );
1497 fclose( file );
1499 if (len >= 1 && str[len - 1] == '\n') len--;
1500 str[len] = 0;
1501 return len;
1504 static void get_system_uuid( GUID *uuid )
1506 static const unsigned char hex[] =
1508 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
1509 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
1510 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
1511 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
1512 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
1513 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
1514 0,10,11,12,13,14,15 /* 0x60 */
1516 int fd;
1518 memset( uuid, 0xff, sizeof(*uuid) );
1519 if ((fd = open( "/var/lib/dbus/machine-id", O_RDONLY )) != -1)
1521 unsigned char buf[32], *p = buf;
1522 if (read( fd, buf, sizeof(buf) ) == sizeof(buf))
1524 uuid->Data1 = hex[p[6]] << 28 | hex[p[7]] << 24 | hex[p[4]] << 20 | hex[p[5]] << 16 |
1525 hex[p[2]] << 12 | hex[p[3]] << 8 | hex[p[0]] << 4 | hex[p[1]];
1527 uuid->Data2 = hex[p[10]] << 12 | hex[p[11]] << 8 | hex[p[8]] << 4 | hex[p[9]];
1528 uuid->Data3 = hex[p[14]] << 12 | hex[p[15]] << 8 | hex[p[12]] << 4 | hex[p[13]];
1530 uuid->Data4[0] = hex[p[16]] << 4 | hex[p[17]];
1531 uuid->Data4[1] = hex[p[18]] << 4 | hex[p[19]];
1532 uuid->Data4[2] = hex[p[20]] << 4 | hex[p[21]];
1533 uuid->Data4[3] = hex[p[22]] << 4 | hex[p[23]];
1534 uuid->Data4[4] = hex[p[24]] << 4 | hex[p[25]];
1535 uuid->Data4[5] = hex[p[26]] << 4 | hex[p[27]];
1536 uuid->Data4[6] = hex[p[28]] << 4 | hex[p[29]];
1537 uuid->Data4[7] = hex[p[30]] << 4 | hex[p[31]];
1539 close( fd );
1543 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1544 ULONG *required_len )
1546 switch (sfti->ProviderSignature)
1548 case RSMB:
1550 char bios_vendor[128], bios_version[128], bios_date[128];
1551 struct smbios_bios_args bios_args;
1552 char system_vendor[128], system_product[128], system_version[128], system_serial[128];
1553 char system_sku[128], system_family[128];
1554 struct smbios_system_args system_args;
1555 char board_vendor[128], board_product[128], board_version[128], board_serial[128], board_asset_tag[128];
1556 struct smbios_board_args board_args;
1557 char chassis_vendor[128], chassis_version[128], chassis_serial[128], chassis_asset_tag[128];
1558 char chassis_type[11] = "2"; /* unknown */
1559 struct smbios_chassis_args chassis_args;
1561 #define S(s) s, sizeof(s)
1562 bios_args.vendor_len = get_smbios_string("/sys/class/dmi/id/bios_vendor", S(bios_vendor));
1563 bios_args.vendor = bios_vendor;
1564 bios_args.version_len = get_smbios_string("/sys/class/dmi/id/bios_version", S(bios_version));
1565 bios_args.version = bios_version;
1566 bios_args.date_len = get_smbios_string("/sys/class/dmi/id/bios_date", S(bios_date));
1567 bios_args.date = bios_date;
1569 system_args.vendor_len = get_smbios_string("/sys/class/dmi/id/sys_vendor", S(system_vendor));
1570 system_args.vendor = system_vendor;
1571 system_args.product_len = get_smbios_string("/sys/class/dmi/id/product_name", S(system_product));
1572 system_args.product = system_product;
1573 system_args.version_len = get_smbios_string("/sys/class/dmi/id/product_version", S(system_version));
1574 system_args.version = system_version;
1575 system_args.serial_len = get_smbios_string("/sys/class/dmi/id/product_serial", S(system_serial));
1576 system_args.serial = system_serial;
1577 get_system_uuid(&system_args.uuid);
1578 system_args.sku_len = get_smbios_string("/sys/class/dmi/id/product_sku", S(system_sku));
1579 system_args.sku = system_sku;
1580 system_args.family_len = get_smbios_string("/sys/class/dmi/id/product_family", S(system_family));
1581 system_args.family = system_family;
1583 board_args.vendor_len = get_smbios_string("/sys/class/dmi/id/board_vendor", S(board_vendor));
1584 board_args.vendor = board_vendor;
1585 board_args.product_len = get_smbios_string("/sys/class/dmi/id/board_name", S(board_product));
1586 board_args.product = board_product;
1587 board_args.version_len = get_smbios_string("/sys/class/dmi/id/board_version", S(board_version));
1588 board_args.version = board_version;
1589 board_args.serial_len = get_smbios_string("/sys/class/dmi/id/board_serial", S(board_serial));
1590 board_args.serial = board_serial;
1591 board_args.asset_tag_len = get_smbios_string("/sys/class/dmi/id/board_asset_tag", S(board_asset_tag));
1592 board_args.asset_tag = board_asset_tag;
1594 chassis_args.vendor_len = get_smbios_string("/sys/class/dmi/id/chassis_vendor", S(chassis_vendor));
1595 chassis_args.vendor = chassis_vendor;
1596 get_smbios_string("/sys/class/dmi/id/chassis_type", S(chassis_type));
1597 chassis_args.type = atoi(chassis_type);
1598 chassis_args.version_len = get_smbios_string("/sys/class/dmi/id/chassis_version", S(chassis_version));
1599 chassis_args.version = chassis_version;
1600 chassis_args.serial_len = get_smbios_string("/sys/class/dmi/id/chassis_serial", S(chassis_serial));
1601 chassis_args.serial = chassis_serial;
1602 chassis_args.asset_tag_len = get_smbios_string("/sys/class/dmi/id/chassis_tag", S(chassis_asset_tag));
1603 chassis_args.asset_tag = chassis_asset_tag;
1604 #undef S
1606 return create_smbios_tables( sfti, available_len, required_len,
1607 &bios_args, &system_args, &board_args, &chassis_args );
1609 default:
1610 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION provider %08x\n", sfti->ProviderSignature);
1611 return STATUS_NOT_IMPLEMENTED;
1615 #elif defined(__APPLE__)
1617 static NTSTATUS get_smbios_from_iokit( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1618 ULONG *required_len )
1620 io_service_t service;
1621 CFDataRef data;
1622 const UInt8 *ptr;
1623 CFIndex len;
1624 struct smbios_prologue *prologue;
1625 BYTE major_version = 2, minor_version = 0;
1627 if (!(service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleSMBIOS"))))
1629 WARN("can't find AppleSMBIOS service\n");
1630 return STATUS_NO_MEMORY;
1633 if (!(data = IORegistryEntryCreateCFProperty(service, CFSTR("SMBIOS-EPS"), kCFAllocatorDefault, 0)))
1635 WARN("can't find SMBIOS entry point\n");
1636 IOObjectRelease(service);
1637 return STATUS_NO_MEMORY;
1640 len = CFDataGetLength(data);
1641 ptr = CFDataGetBytePtr(data);
1642 if (len >= 8 && !memcmp(ptr, "_SM_", 4))
1644 major_version = ptr[6];
1645 minor_version = ptr[7];
1647 CFRelease(data);
1649 if (!(data = IORegistryEntryCreateCFProperty(service, CFSTR("SMBIOS"), kCFAllocatorDefault, 0)))
1651 WARN("can't find SMBIOS table\n");
1652 IOObjectRelease(service);
1653 return STATUS_NO_MEMORY;
1656 len = CFDataGetLength(data);
1657 ptr = CFDataGetBytePtr(data);
1658 sfti->TableBufferLength = sizeof(*prologue) + len;
1659 *required_len = sfti->TableBufferLength + FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
1660 if (available_len < *required_len)
1662 CFRelease(data);
1663 IOObjectRelease(service);
1664 return STATUS_BUFFER_TOO_SMALL;
1667 prologue = (struct smbios_prologue *)sfti->TableBuffer;
1668 prologue->calling_method = 0;
1669 prologue->major_version = major_version;
1670 prologue->minor_version = minor_version;
1671 prologue->revision = 0;
1672 prologue->length = sfti->TableBufferLength - sizeof(*prologue);
1674 memcpy(sfti->TableBuffer + sizeof(*prologue), ptr, len);
1676 CFRelease(data);
1677 IOObjectRelease(service);
1678 return STATUS_SUCCESS;
1681 static size_t cf_to_string( CFTypeRef type_ref, char *buffer, size_t buffer_size )
1683 size_t length = 0;
1685 if (!type_ref)
1686 return 0;
1688 if (CFGetTypeID(type_ref) == CFDataGetTypeID())
1690 length = MIN(CFDataGetLength(type_ref), buffer_size);
1691 CFDataGetBytes(type_ref, CFRangeMake(0, length), (UInt8*)buffer);
1692 buffer[length] = 0;
1693 length = strlen(buffer);
1695 else if (CFGetTypeID(type_ref) == CFStringGetTypeID())
1697 if (CFStringGetCString(type_ref, buffer, buffer_size, kCFStringEncodingASCII))
1698 length = strlen(buffer);
1701 CFRelease(type_ref);
1702 return length;
1705 static NTSTATUS generate_smbios( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1706 ULONG *required_len )
1708 /* Apple Silicon Macs don't have SMBIOS, we need to generate it.
1709 * Use strings and data from IOKit when available.
1711 io_service_t platform_expert;
1712 CFDataRef cf_manufacturer, cf_model;
1713 CFStringRef cf_serial_number, cf_uuid_string;
1714 char manufacturer[128], model[128], serial_number[128];
1715 size_t manufacturer_len = 0, model_len = 0, serial_number_len = 0;
1716 GUID system_uuid = {0};
1717 struct smbios_bios_args bios_args;
1718 struct smbios_system_args system_args;
1719 struct smbios_board_args board_args;
1720 struct smbios_chassis_args chassis_args;
1722 platform_expert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
1723 if (!platform_expert)
1724 return STATUS_NO_MEMORY;
1726 cf_manufacturer = IORegistryEntryCreateCFProperty(platform_expert, CFSTR("manufacturer"), kCFAllocatorDefault, 0);
1727 cf_model = IORegistryEntryCreateCFProperty(platform_expert, CFSTR("model"), kCFAllocatorDefault, 0);
1728 cf_serial_number = IORegistryEntryCreateCFProperty(platform_expert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0);
1729 cf_uuid_string = IORegistryEntryCreateCFProperty(platform_expert, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
1731 manufacturer_len = cf_to_string(cf_manufacturer, manufacturer, sizeof(manufacturer));
1732 model_len = cf_to_string(cf_model, model, sizeof(model));
1733 serial_number_len = cf_to_string(cf_serial_number, serial_number, sizeof(serial_number));
1735 if (cf_uuid_string)
1737 CFUUIDRef cf_uuid;
1738 CFUUIDBytes bytes;
1740 cf_uuid = CFUUIDCreateFromString(kCFAllocatorDefault, cf_uuid_string);
1741 bytes = CFUUIDGetUUIDBytes(cf_uuid);
1743 system_uuid.Data1 = (bytes.byte0 << 24) | (bytes.byte1 << 16) | (bytes.byte2 << 8) | bytes.byte3;
1744 system_uuid.Data2 = (bytes.byte4 << 8) | bytes.byte5;
1745 system_uuid.Data3 = (bytes.byte6 << 8) | bytes.byte7;
1746 memcpy(&system_uuid.Data4, &bytes.byte8, sizeof(system_uuid.Data4));
1748 CFRelease(cf_uuid);
1749 CFRelease(cf_uuid_string);
1752 IOObjectRelease(platform_expert);
1754 #define S(s, t) { s ## _len = t ## _len; s = t; }
1755 #define STR(s, t) { s ## _len = sizeof(t)-1; s = t; }
1756 S(bios_args.vendor, manufacturer);
1757 /* BIOS version and date are both required */
1758 STR(bios_args.version, "1.0");
1759 STR(bios_args.date, "01/01/2021");
1761 S(system_args.vendor, manufacturer);
1762 S(system_args.product, model);
1763 STR(system_args.version, "1.0");
1764 S(system_args.serial, serial_number);
1765 system_args.uuid = system_uuid;
1766 system_args.sku_len = 0;
1767 S(system_args.family, model);
1769 S(board_args.vendor, manufacturer);
1770 S(board_args.product, model);
1771 S(board_args.version, model);
1772 S(board_args.serial, serial_number);
1773 board_args.asset_tag_len = 0;
1775 S(chassis_args.vendor, manufacturer);
1776 chassis_args.type = 2; /* unknown */
1777 chassis_args.version_len = 0;
1778 S(chassis_args.serial, serial_number);
1779 chassis_args.asset_tag_len = 0;
1780 #undef STR
1781 #undef S
1783 return create_smbios_tables( sfti, available_len, required_len,
1784 &bios_args, &system_args, &board_args, &chassis_args );
1787 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1788 ULONG *required_len )
1790 switch (sfti->ProviderSignature)
1792 case RSMB:
1794 NTSTATUS ret;
1795 ret = get_smbios_from_iokit(sfti, available_len, required_len);
1796 if (ret == STATUS_NO_MEMORY)
1797 ret = generate_smbios(sfti, available_len, required_len);
1798 return ret;
1800 default:
1801 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION provider %08x\n", sfti->ProviderSignature);
1802 return STATUS_NOT_IMPLEMENTED;
1806 #else
1808 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1809 ULONG *required_len )
1811 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION\n");
1812 sfti->TableBufferLength = 0;
1813 return STATUS_NOT_IMPLEMENTED;
1816 #endif
1818 static void get_performance_info( SYSTEM_PERFORMANCE_INFORMATION *info )
1820 unsigned long long totalram = 0, freeram = 0, totalswap = 0, freeswap = 0;
1822 memset( info, 0, sizeof(*info) );
1824 #if defined(linux)
1826 FILE *fp;
1828 if ((fp = fopen("/proc/uptime", "r")))
1830 double uptime, idle_time;
1832 fscanf(fp, "%lf %lf", &uptime, &idle_time);
1833 fclose(fp);
1834 info->IdleTime.QuadPart = 10000000 * idle_time;
1837 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1839 static int clockrate_name[] = { CTL_KERN, KERN_CLOCKRATE };
1840 size_t size = 0;
1841 struct clockinfo clockrate;
1842 long ptimes[CPUSTATES];
1844 size = sizeof(clockrate);
1845 if (!sysctl(clockrate_name, 2, &clockrate, &size, NULL, 0))
1847 size = sizeof(ptimes);
1848 if (!sysctlbyname("kern.cp_time", ptimes, &size, NULL, 0))
1849 info->IdleTime.QuadPart = (ULONGLONG)ptimes[CP_IDLE] * 10000000 / clockrate.stathz;
1852 #elif defined(__APPLE__)
1854 host_name_port_t host = mach_host_self();
1855 struct host_cpu_load_info load_info;
1856 mach_msg_type_number_t count;
1858 count = HOST_CPU_LOAD_INFO_COUNT;
1859 if (host_statistics(host, HOST_CPU_LOAD_INFO, (host_info_t)&load_info, &count) == KERN_SUCCESS)
1861 /* Believe it or not, based on my reading of XNU source, this is
1862 * already in the units we want (100 ns).
1864 info->IdleTime.QuadPart = load_info.cpu_ticks[CPU_STATE_IDLE];
1866 mach_port_deallocate(mach_task_self(), host);
1868 #else
1870 static ULONGLONG idle;
1871 /* many programs expect IdleTime to change so fake change */
1872 info->IdleTime.QuadPart = ++idle;
1874 #endif
1876 #ifdef linux
1878 FILE *fp;
1880 if ((fp = fopen("/proc/meminfo", "r")))
1882 unsigned long long value;
1883 char line[64];
1885 while (fgets(line, sizeof(line), fp))
1887 if(sscanf(line, "MemTotal: %llu kB", &value) == 1)
1888 totalram += value * 1024;
1889 else if(sscanf(line, "MemFree: %llu kB", &value) == 1)
1890 freeram += value * 1024;
1891 else if(sscanf(line, "SwapTotal: %llu kB", &value) == 1)
1892 totalswap += value * 1024;
1893 else if(sscanf(line, "SwapFree: %llu kB", &value) == 1)
1894 freeswap += value * 1024;
1895 else if (sscanf(line, "Buffers: %llu", &value))
1896 freeram += value * 1024;
1897 else if (sscanf(line, "Cached: %llu", &value))
1898 freeram += value * 1024;
1900 fclose(fp);
1903 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || \
1904 defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
1906 #ifdef __APPLE__
1907 unsigned int val;
1908 #else
1909 unsigned long val;
1910 #endif
1911 int mib[2];
1912 size_t size_sys;
1914 mib[0] = CTL_HW;
1915 #ifdef HW_MEMSIZE
1917 uint64_t val64;
1918 mib[1] = HW_MEMSIZE;
1919 size_sys = sizeof(val64);
1920 if (!sysctl(mib, 2, &val64, &size_sys, NULL, 0) && size_sys == sizeof(val64)) totalram = val64;
1922 #endif
1924 #ifdef HAVE_MACH_MACH_H
1926 host_name_port_t host = mach_host_self();
1927 mach_msg_type_number_t count;
1928 #ifdef HOST_VM_INFO64_COUNT
1929 vm_statistics64_data_t vm_stat;
1931 count = HOST_VM_INFO64_COUNT;
1932 if (host_statistics64(host, HOST_VM_INFO64, (host_info64_t)&vm_stat, &count) == KERN_SUCCESS)
1933 freeram = (vm_stat.free_count + vm_stat.inactive_count) * (ULONGLONG)page_size;
1934 #endif
1935 if (!totalram)
1937 host_basic_info_data_t info;
1938 count = HOST_BASIC_INFO_COUNT;
1939 if (host_info(host, HOST_BASIC_INFO, (host_info_t)&info, &count) == KERN_SUCCESS)
1940 totalram = info.max_mem;
1942 mach_port_deallocate(mach_task_self(), host);
1944 #endif
1946 if (!totalram)
1948 mib[1] = HW_PHYSMEM;
1949 size_sys = sizeof(val);
1950 if (!sysctl(mib, 2, &val, &size_sys, NULL, 0) && size_sys == sizeof(val)) totalram = val;
1952 if (!freeram)
1954 mib[1] = HW_USERMEM;
1955 size_sys = sizeof(val);
1956 if (!sysctl(mib, 2, &val, &size_sys, NULL, 0) && size_sys == sizeof(val)) freeram = val;
1958 #ifdef VM_SWAPUSAGE
1960 struct xsw_usage swap;
1961 mib[0] = CTL_VM;
1962 mib[1] = VM_SWAPUSAGE;
1963 size_sys = sizeof(swap);
1964 if (!sysctl(mib, 2, &swap, &size_sys, NULL, 0) && size_sys == sizeof(swap))
1966 totalswap = swap.xsu_total;
1967 freeswap = swap.xsu_avail;
1970 #endif
1972 #endif
1974 /* Titan Quest refuses to run if TotalPageFile <= TotalPhys */
1975 if (!totalswap) totalswap = page_size;
1977 info->AvailablePages = freeram / page_size;
1978 info->TotalCommittedPages = (totalram + totalswap - freeram - freeswap) / page_size;
1979 info->TotalCommitLimit = (totalram + totalswap) / page_size;
1983 /* calculate the mday of dst change date, so that for instance Sun 5 Oct 2007
1984 * (last Sunday in October of 2007) becomes Sun Oct 28 2007
1986 * Note: year, day and month must be in unix format.
1988 static int weekday_to_mday(int year, int day, int mon, int day_of_week)
1990 struct tm date;
1991 time_t tmp;
1992 int wday, mday;
1994 /* find first day in the month matching week day of the date */
1995 memset(&date, 0, sizeof(date));
1996 date.tm_year = year;
1997 date.tm_mon = mon;
1998 date.tm_mday = -1;
1999 date.tm_wday = -1;
2002 date.tm_mday++;
2003 tmp = mktime(&date);
2004 } while (date.tm_wday != day_of_week || date.tm_mon != mon);
2006 mday = date.tm_mday;
2008 /* find number of week days in the month matching week day of the date */
2009 wday = 1; /* 1 - 1st, ...., 5 - last */
2010 while (wday < day)
2012 struct tm *tm;
2014 date.tm_mday += 7;
2015 tmp = mktime(&date);
2016 tm = localtime(&tmp);
2017 if (tm->tm_mon != mon)
2018 break;
2019 mday = tm->tm_mday;
2020 wday++;
2023 return mday;
2026 static BOOL match_tz_date( const RTL_SYSTEM_TIME *st, const RTL_SYSTEM_TIME *reg_st )
2028 WORD wDay;
2030 if (st->wMonth != reg_st->wMonth) return FALSE;
2031 if (!st->wMonth) return TRUE; /* no transition dates */
2032 wDay = reg_st->wDay;
2033 if (!reg_st->wYear) /* date in a day-of-week format */
2034 wDay = weekday_to_mday(st->wYear - 1900, reg_st->wDay, reg_st->wMonth - 1, reg_st->wDayOfWeek);
2036 return (st->wDay == wDay &&
2037 st->wHour == reg_st->wHour &&
2038 st->wMinute == reg_st->wMinute &&
2039 st->wSecond == reg_st->wSecond &&
2040 st->wMilliseconds == reg_st->wMilliseconds);
2043 static BOOL match_tz_info( const RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi,
2044 const RTL_DYNAMIC_TIME_ZONE_INFORMATION *reg_tzi )
2046 return (tzi->Bias == reg_tzi->Bias &&
2047 match_tz_date(&tzi->StandardDate, &reg_tzi->StandardDate) &&
2048 match_tz_date(&tzi->DaylightDate, &reg_tzi->DaylightDate));
2051 static BOOL match_past_tz_bias( time_t past_time, LONG past_bias )
2053 LONG bias;
2054 struct tm *tm;
2055 if (!past_time) return TRUE;
2057 tm = gmtime( &past_time );
2058 bias = (LONG)(mktime(tm) - past_time) / 60;
2059 return bias == past_bias;
2062 static BOOL match_tz_name( const char *tz_name, const RTL_DYNAMIC_TIME_ZONE_INFORMATION *reg_tzi )
2064 static const struct {
2065 WCHAR key_name[32];
2066 const char *short_name;
2067 time_t past_time;
2068 LONG past_bias;
2070 mapping[] =
2072 { {'N','o','r','t','h',' ','K','o','r','e','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
2073 "KST", 1451606400 /* 2016-01-01 00:00:00 UTC */, -510 },
2074 { {'K','o','r','e','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
2075 "KST", 1451606400 /* 2016-01-01 00:00:00 UTC */, -540 },
2076 { {'T','o','k','y','o',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
2077 "JST" },
2078 { {'Y','a','k','u','t','s','k',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
2079 "+09" }, /* YAKST was used until tzdata 2016f */
2081 unsigned int i;
2083 if (reg_tzi->DaylightDate.wMonth) return TRUE;
2084 for (i = 0; i < ARRAY_SIZE(mapping); i++)
2086 if (!wcscmp( mapping[i].key_name, reg_tzi->TimeZoneKeyName ))
2087 return !strcmp( mapping[i].short_name, tz_name )
2088 && match_past_tz_bias( mapping[i].past_time, mapping[i].past_bias );
2090 return TRUE;
2093 static BOOL reg_query_value( HKEY key, LPCWSTR name, DWORD type, void *data, DWORD count )
2095 char buf[256];
2096 UNICODE_STRING nameW;
2097 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buf;
2099 if (count > sizeof(buf) - offsetof(KEY_VALUE_PARTIAL_INFORMATION, Data)) return FALSE;
2101 nameW.Buffer = (WCHAR *)name;
2102 nameW.Length = wcslen( name ) * sizeof(WCHAR);
2103 if (NtQueryValueKey( key, &nameW, KeyValuePartialInformation, buf, sizeof(buf), &count ))
2104 return FALSE;
2106 if (info->Type != type) return FALSE;
2107 memcpy( data, info->Data, info->DataLength );
2108 return TRUE;
2111 static void find_reg_tz_info(RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi, const char* tz_name, int year)
2113 static const WCHAR stdW[] = { 'S','t','d',0 };
2114 static const WCHAR dltW[] = { 'D','l','t',0 };
2115 static const WCHAR mui_stdW[] = { 'M','U','I','_','S','t','d',0 };
2116 static const WCHAR mui_dltW[] = { 'M','U','I','_','D','l','t',0 };
2117 static const WCHAR tziW[] = { 'T','Z','I',0 };
2118 static const WCHAR Time_ZonesW[] = { 'M','a','c','h','i','n','e','\\',
2119 'S','o','f','t','w','a','r','e','\\',
2120 'M','i','c','r','o','s','o','f','t','\\',
2121 'W','i','n','d','o','w','s',' ','N','T','\\',
2122 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
2123 'T','i','m','e',' ','Z','o','n','e','s',0 };
2124 static const WCHAR Dynamic_DstW[] = { 'D','y','n','a','m','i','c',' ','D','S','T',0 };
2125 RTL_DYNAMIC_TIME_ZONE_INFORMATION reg_tzi;
2126 HANDLE key, subkey, subkey_dyn = 0;
2127 ULONG idx, len;
2128 OBJECT_ATTRIBUTES attr;
2129 UNICODE_STRING nameW;
2130 WCHAR yearW[16];
2131 char buffer[128];
2132 KEY_BASIC_INFORMATION *info = (KEY_BASIC_INFORMATION *)buffer;
2134 sprintf( buffer, "%u", year );
2135 ascii_to_unicode( yearW, buffer, strlen(buffer) + 1 );
2136 init_unicode_string( &nameW, Time_ZonesW );
2137 InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
2138 if (NtOpenKey( &key, KEY_READ, &attr )) return;
2140 idx = 0;
2141 while (!NtEnumerateKey( key, idx++, KeyBasicInformation, buffer, sizeof(buffer), &len ))
2143 struct tz_reg_data
2145 LONG bias;
2146 LONG std_bias;
2147 LONG dlt_bias;
2148 RTL_SYSTEM_TIME std_date;
2149 RTL_SYSTEM_TIME dlt_date;
2150 } tz_data;
2151 BOOL is_dynamic = FALSE;
2153 nameW.Buffer = info->Name;
2154 nameW.Length = info->NameLength;
2155 attr.RootDirectory = key;
2156 if (NtOpenKey( &subkey, KEY_READ, &attr )) continue;
2158 memset( &reg_tzi, 0, sizeof(reg_tzi) );
2159 memcpy(reg_tzi.TimeZoneKeyName, nameW.Buffer, nameW.Length);
2160 reg_tzi.TimeZoneKeyName[nameW.Length/sizeof(WCHAR)] = 0;
2162 if (!reg_query_value(subkey, mui_stdW, REG_SZ, reg_tzi.StandardName, sizeof(reg_tzi.StandardName)) &&
2163 !reg_query_value(subkey, stdW, REG_SZ, reg_tzi.StandardName, sizeof(reg_tzi.StandardName)))
2164 goto next;
2166 if (!reg_query_value(subkey, mui_dltW, REG_SZ, reg_tzi.DaylightName, sizeof(reg_tzi.DaylightName)) &&
2167 !reg_query_value(subkey, dltW, REG_SZ, reg_tzi.DaylightName, sizeof(reg_tzi.DaylightName)))
2168 goto next;
2170 /* Check for Dynamic DST entry first */
2171 nameW.Buffer = (WCHAR *)Dynamic_DstW;
2172 nameW.Length = sizeof(Dynamic_DstW) - sizeof(WCHAR);
2173 attr.RootDirectory = subkey;
2174 if (!NtOpenKey( &subkey_dyn, KEY_READ, &attr ))
2176 is_dynamic = reg_query_value( subkey_dyn, yearW, REG_BINARY, &tz_data, sizeof(tz_data) );
2177 NtClose( subkey_dyn );
2179 if (!is_dynamic && !reg_query_value( subkey, tziW, REG_BINARY, &tz_data, sizeof(tz_data) ))
2180 goto next;
2182 reg_tzi.Bias = tz_data.bias;
2183 reg_tzi.StandardBias = tz_data.std_bias;
2184 reg_tzi.DaylightBias = tz_data.dlt_bias;
2185 reg_tzi.StandardDate = tz_data.std_date;
2186 reg_tzi.DaylightDate = tz_data.dlt_date;
2188 TRACE("%s: bias %d\n", debugstr_us(&nameW), reg_tzi.Bias);
2189 TRACE("std (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
2190 reg_tzi.StandardDate.wDay, reg_tzi.StandardDate.wMonth,
2191 reg_tzi.StandardDate.wYear, reg_tzi.StandardDate.wDayOfWeek,
2192 reg_tzi.StandardDate.wHour, reg_tzi.StandardDate.wMinute,
2193 reg_tzi.StandardDate.wSecond, reg_tzi.StandardDate.wMilliseconds,
2194 reg_tzi.StandardBias);
2195 TRACE("dst (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
2196 reg_tzi.DaylightDate.wDay, reg_tzi.DaylightDate.wMonth,
2197 reg_tzi.DaylightDate.wYear, reg_tzi.DaylightDate.wDayOfWeek,
2198 reg_tzi.DaylightDate.wHour, reg_tzi.DaylightDate.wMinute,
2199 reg_tzi.DaylightDate.wSecond, reg_tzi.DaylightDate.wMilliseconds,
2200 reg_tzi.DaylightBias);
2202 if (match_tz_info( tzi, &reg_tzi ) && match_tz_name( tz_name, &reg_tzi ))
2204 *tzi = reg_tzi;
2205 NtClose( subkey );
2206 NtClose( key );
2207 return;
2209 next:
2210 NtClose( subkey );
2212 NtClose( key );
2214 if (idx == 1) return; /* registry info not initialized yet */
2216 FIXME("Can't find matching timezone information in the registry for "
2217 "%s, bias %d, std (d/m/y): %u/%02u/%04u, dlt (d/m/y): %u/%02u/%04u\n",
2218 tz_name, tzi->Bias,
2219 tzi->StandardDate.wDay, tzi->StandardDate.wMonth, tzi->StandardDate.wYear,
2220 tzi->DaylightDate.wDay, tzi->DaylightDate.wMonth, tzi->DaylightDate.wYear);
2223 static time_t find_dst_change(time_t start, time_t end, int *is_dst)
2225 struct tm *tm;
2226 ULONGLONG min = (sizeof(time_t) == sizeof(int)) ? (ULONG)start : start;
2227 ULONGLONG max = (sizeof(time_t) == sizeof(int)) ? (ULONG)end : end;
2229 tm = localtime(&start);
2230 *is_dst = !tm->tm_isdst;
2231 TRACE("starting date isdst %d, %s", !*is_dst, ctime(&start));
2233 while (min <= max)
2235 time_t pos = (min + max) / 2;
2236 tm = localtime(&pos);
2238 if (tm->tm_isdst != *is_dst)
2239 min = pos + 1;
2240 else
2241 max = pos - 1;
2243 return min;
2246 static void get_timezone_info( RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi )
2248 static pthread_mutex_t tz_mutex = PTHREAD_MUTEX_INITIALIZER;
2249 static RTL_DYNAMIC_TIME_ZONE_INFORMATION cached_tzi;
2250 static int current_year = -1, current_bias = 65535;
2251 struct tm *tm;
2252 char tz_name[16];
2253 time_t year_start, year_end, tmp, dlt = 0, std = 0;
2254 int is_dst, bias;
2256 mutex_lock( &tz_mutex );
2258 year_start = time(NULL);
2259 tm = gmtime(&year_start);
2260 bias = (LONG)(mktime(tm) - year_start) / 60;
2262 tm = localtime(&year_start);
2263 if (current_year == tm->tm_year && current_bias == bias)
2265 *tzi = cached_tzi;
2266 mutex_unlock( &tz_mutex );
2267 return;
2270 memset(tzi, 0, sizeof(*tzi));
2271 if (!strftime(tz_name, sizeof(tz_name), "%Z", tm)) {
2272 /* not enough room or another error */
2273 tz_name[0] = '\0';
2276 TRACE("tz data will be valid through year %d, bias %d\n", tm->tm_year + 1900, bias);
2277 current_year = tm->tm_year;
2278 current_bias = bias;
2280 tzi->Bias = bias;
2282 tm->tm_isdst = 0;
2283 tm->tm_mday = 1;
2284 tm->tm_mon = tm->tm_hour = tm->tm_min = tm->tm_sec = tm->tm_wday = tm->tm_yday = 0;
2285 year_start = mktime(tm);
2286 TRACE("year_start: %s", ctime(&year_start));
2288 tm->tm_mday = tm->tm_wday = tm->tm_yday = 0;
2289 tm->tm_mon = 12;
2290 tm->tm_hour = 23;
2291 tm->tm_min = tm->tm_sec = 59;
2292 year_end = mktime(tm);
2293 TRACE("year_end: %s", ctime(&year_end));
2295 tmp = find_dst_change(year_start, year_end, &is_dst);
2296 if (is_dst)
2297 dlt = tmp;
2298 else
2299 std = tmp;
2301 tmp = find_dst_change(tmp, year_end, &is_dst);
2302 if (is_dst)
2303 dlt = tmp;
2304 else
2305 std = tmp;
2307 TRACE("std: %s", ctime(&std));
2308 TRACE("dlt: %s", ctime(&dlt));
2310 if (dlt == std || !dlt || !std)
2311 TRACE("there is no daylight saving rules in this time zone\n");
2312 else
2314 tmp = dlt - tzi->Bias * 60;
2315 tm = gmtime(&tmp);
2316 TRACE("dlt gmtime: %s", asctime(tm));
2318 tzi->DaylightBias = -60;
2319 tzi->DaylightDate.wYear = tm->tm_year + 1900;
2320 tzi->DaylightDate.wMonth = tm->tm_mon + 1;
2321 tzi->DaylightDate.wDayOfWeek = tm->tm_wday;
2322 tzi->DaylightDate.wDay = tm->tm_mday;
2323 tzi->DaylightDate.wHour = tm->tm_hour;
2324 tzi->DaylightDate.wMinute = tm->tm_min;
2325 tzi->DaylightDate.wSecond = tm->tm_sec;
2326 tzi->DaylightDate.wMilliseconds = 0;
2328 TRACE("daylight (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
2329 tzi->DaylightDate.wDay, tzi->DaylightDate.wMonth,
2330 tzi->DaylightDate.wYear, tzi->DaylightDate.wDayOfWeek,
2331 tzi->DaylightDate.wHour, tzi->DaylightDate.wMinute,
2332 tzi->DaylightDate.wSecond, tzi->DaylightDate.wMilliseconds,
2333 tzi->DaylightBias);
2335 tmp = std - tzi->Bias * 60 - tzi->DaylightBias * 60;
2336 tm = gmtime(&tmp);
2337 TRACE("std gmtime: %s", asctime(tm));
2339 tzi->StandardBias = 0;
2340 tzi->StandardDate.wYear = tm->tm_year + 1900;
2341 tzi->StandardDate.wMonth = tm->tm_mon + 1;
2342 tzi->StandardDate.wDayOfWeek = tm->tm_wday;
2343 tzi->StandardDate.wDay = tm->tm_mday;
2344 tzi->StandardDate.wHour = tm->tm_hour;
2345 tzi->StandardDate.wMinute = tm->tm_min;
2346 tzi->StandardDate.wSecond = tm->tm_sec;
2347 tzi->StandardDate.wMilliseconds = 0;
2349 TRACE("standard (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
2350 tzi->StandardDate.wDay, tzi->StandardDate.wMonth,
2351 tzi->StandardDate.wYear, tzi->StandardDate.wDayOfWeek,
2352 tzi->StandardDate.wHour, tzi->StandardDate.wMinute,
2353 tzi->StandardDate.wSecond, tzi->StandardDate.wMilliseconds,
2354 tzi->StandardBias);
2357 find_reg_tz_info(tzi, tz_name, current_year + 1900);
2358 cached_tzi = *tzi;
2359 mutex_unlock( &tz_mutex );
2363 static void read_dev_urandom( void *buf, ULONG len )
2365 int fd = open( "/dev/urandom", O_RDONLY );
2366 if (fd != -1)
2368 int ret;
2371 ret = read( fd, buf, len );
2373 while (ret == -1 && errno == EINTR);
2374 close( fd );
2376 else WARN( "can't open /dev/urandom\n" );
2379 static NTSTATUS get_system_process_info( SYSTEM_INFORMATION_CLASS class, void *info, ULONG size, ULONG *len )
2381 unsigned int process_count, total_thread_count, total_name_len, i, j;
2382 unsigned int thread_info_size;
2383 unsigned int pos = 0;
2384 char *buffer = NULL;
2385 NTSTATUS ret;
2387 C_ASSERT( sizeof(struct thread_info) <= sizeof(SYSTEM_THREAD_INFORMATION) );
2388 C_ASSERT( sizeof(struct process_info) <= sizeof(SYSTEM_PROCESS_INFORMATION) );
2390 if (class == SystemExtendedProcessInformation)
2391 thread_info_size = sizeof(SYSTEM_EXTENDED_THREAD_INFORMATION);
2392 else
2393 thread_info_size = sizeof(SYSTEM_THREAD_INFORMATION);
2395 *len = 0;
2396 if (size && !(buffer = malloc( size ))) return STATUS_NO_MEMORY;
2398 SERVER_START_REQ( list_processes )
2400 wine_server_set_reply( req, buffer, size );
2401 ret = wine_server_call( req );
2402 total_thread_count = reply->total_thread_count;
2403 total_name_len = reply->total_name_len;
2404 process_count = reply->process_count;
2406 SERVER_END_REQ;
2408 if (ret)
2410 if (ret == STATUS_INFO_LENGTH_MISMATCH)
2411 *len = sizeof(SYSTEM_PROCESS_INFORMATION) * process_count
2412 + (total_name_len + process_count) * sizeof(WCHAR)
2413 + total_thread_count * thread_info_size;
2415 free( buffer );
2416 return ret;
2419 for (i = 0; i < process_count; i++)
2421 SYSTEM_PROCESS_INFORMATION *nt_process = (SYSTEM_PROCESS_INFORMATION *)((char *)info + *len);
2422 const struct process_info *server_process;
2423 const WCHAR *server_name, *file_part;
2424 ULONG proc_len;
2425 ULONG name_len = 0;
2427 pos = (pos + 7) & ~7;
2428 server_process = (const struct process_info *)(buffer + pos);
2429 pos += sizeof(*server_process);
2431 server_name = (const WCHAR *)(buffer + pos);
2432 file_part = server_name + (server_process->name_len / sizeof(WCHAR));
2433 pos += server_process->name_len;
2434 while (file_part > server_name && file_part[-1] != '\\')
2436 file_part--;
2437 name_len++;
2440 proc_len = sizeof(*nt_process) + server_process->thread_count * thread_info_size
2441 + (name_len + 1) * sizeof(WCHAR);
2442 *len += proc_len;
2444 if (*len <= size)
2446 memset(nt_process, 0, proc_len);
2447 if (i < process_count - 1)
2448 nt_process->NextEntryOffset = proc_len;
2449 nt_process->CreationTime.QuadPart = server_process->start_time;
2450 nt_process->dwThreadCount = server_process->thread_count;
2451 nt_process->dwBasePriority = server_process->priority;
2452 nt_process->UniqueProcessId = UlongToHandle(server_process->pid);
2453 nt_process->ParentProcessId = UlongToHandle(server_process->parent_pid);
2454 nt_process->SessionId = server_process->session_id;
2455 nt_process->HandleCount = server_process->handle_count;
2456 get_thread_times( server_process->unix_pid, -1, &nt_process->KernelTime, &nt_process->UserTime );
2457 fill_vm_counters( &nt_process->vmCounters, server_process->unix_pid );
2460 pos = (pos + 7) & ~7;
2461 for (j = 0; j < server_process->thread_count; j++)
2463 const struct thread_info *server_thread = (const struct thread_info *)(buffer + pos);
2464 SYSTEM_EXTENDED_THREAD_INFORMATION *ti;
2466 if (*len <= size)
2468 ti = (SYSTEM_EXTENDED_THREAD_INFORMATION *)((BYTE *)nt_process->ti + j * thread_info_size);
2469 ti->ThreadInfo.CreateTime.QuadPart = server_thread->start_time;
2470 ti->ThreadInfo.ClientId.UniqueProcess = UlongToHandle(server_process->pid);
2471 ti->ThreadInfo.ClientId.UniqueThread = UlongToHandle(server_thread->tid);
2472 ti->ThreadInfo.dwCurrentPriority = server_thread->current_priority;
2473 ti->ThreadInfo.dwBasePriority = server_thread->base_priority;
2474 get_thread_times( server_process->unix_pid, server_thread->unix_tid,
2475 &ti->ThreadInfo.KernelTime, &ti->ThreadInfo.UserTime );
2476 if (class == SystemExtendedProcessInformation)
2478 ti->Win32StartAddress = wine_server_get_ptr( server_thread->entry_point );
2479 ti->TebBase = wine_server_get_ptr( server_thread->teb );
2483 pos += sizeof(*server_thread);
2486 if (*len <= size)
2488 nt_process->ProcessName.Buffer = (WCHAR *)((BYTE *)nt_process->ti
2489 + server_process->thread_count * thread_info_size);
2490 nt_process->ProcessName.Length = name_len * sizeof(WCHAR);
2491 nt_process->ProcessName.MaximumLength = (name_len + 1) * sizeof(WCHAR);
2492 memcpy(nt_process->ProcessName.Buffer, file_part, name_len * sizeof(WCHAR));
2493 nt_process->ProcessName.Buffer[name_len] = 0;
2497 if (*len > size) ret = STATUS_INFO_LENGTH_MISMATCH;
2498 free( buffer );
2499 return ret;
2502 /******************************************************************************
2503 * NtQuerySystemInformation (NTDLL.@)
2505 NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class,
2506 void *info, ULONG size, ULONG *ret_size )
2508 NTSTATUS ret = STATUS_SUCCESS;
2509 ULONG len = 0;
2511 TRACE( "(0x%08x,%p,0x%08x,%p)\n", class, info, size, ret_size );
2513 switch (class)
2515 case SystemNativeBasicInformation: /* 114 */
2516 if (!is_win64) return STATUS_INVALID_INFO_CLASS;
2517 /* fall through */
2518 case SystemBasicInformation: /* 0 */
2520 SYSTEM_BASIC_INFORMATION sbi;
2522 virtual_get_system_info( &sbi, FALSE );
2523 len = sizeof(sbi);
2524 if (size == len)
2526 if (!info) ret = STATUS_ACCESS_VIOLATION;
2527 else memcpy( info, &sbi, len);
2529 else ret = STATUS_INFO_LENGTH_MISMATCH;
2530 break;
2533 case SystemCpuInformation: /* 1 */
2534 if (size >= (len = sizeof(cpu_info)))
2536 if (!info) ret = STATUS_ACCESS_VIOLATION;
2537 else memcpy(info, &cpu_info, len);
2539 else ret = STATUS_INFO_LENGTH_MISMATCH;
2540 break;
2542 case SystemPerformanceInformation: /* 2 */
2544 SYSTEM_PERFORMANCE_INFORMATION spi;
2545 static BOOL fixme_written = FALSE;
2547 get_performance_info( &spi );
2548 len = sizeof(spi);
2549 if (size >= len)
2551 if (!info) ret = STATUS_ACCESS_VIOLATION;
2552 else memcpy( info, &spi, len);
2554 else ret = STATUS_INFO_LENGTH_MISMATCH;
2555 if(!fixme_written) {
2556 FIXME("info_class SYSTEM_PERFORMANCE_INFORMATION\n");
2557 fixme_written = TRUE;
2559 break;
2562 case SystemTimeOfDayInformation: /* 3 */
2564 struct tm *tm;
2565 time_t now;
2566 SYSTEM_TIMEOFDAY_INFORMATION sti = {{{ 0 }}};
2568 sti.BootTime.QuadPart = server_start_time;
2569 now = time( NULL );
2570 tm = gmtime( &now );
2571 sti.TimeZoneBias.QuadPart = mktime( tm ) - now;
2572 tm = localtime( &now );
2573 if (tm->tm_isdst) sti.TimeZoneBias.QuadPart -= 3600;
2574 sti.TimeZoneBias.QuadPart *= TICKSPERSEC;
2575 NtQuerySystemTime( &sti.SystemTime );
2577 if (size <= sizeof(sti))
2579 len = size;
2580 if (!info) ret = STATUS_ACCESS_VIOLATION;
2581 else memcpy( info, &sti, size);
2583 else ret = STATUS_INFO_LENGTH_MISMATCH;
2584 break;
2587 case SystemProcessInformation: /* 5 */
2588 ret = get_system_process_info( class, info, size, &len );
2589 break;
2591 case SystemProcessorPerformanceInformation: /* 8 */
2593 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL;
2594 unsigned int cpus = 0;
2595 int out_cpus = size / sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
2597 if (out_cpus == 0)
2599 len = 0;
2600 ret = STATUS_INFO_LENGTH_MISMATCH;
2601 break;
2603 if (!(sppi = calloc( out_cpus, sizeof(*sppi) )))
2605 ret = STATUS_NO_MEMORY;
2606 break;
2608 else
2609 #ifdef __APPLE__
2611 processor_cpu_load_info_data_t *pinfo;
2612 mach_msg_type_number_t info_count;
2614 if (host_processor_info( mach_host_self (),
2615 PROCESSOR_CPU_LOAD_INFO,
2616 &cpus,
2617 (processor_info_array_t*)&pinfo,
2618 &info_count) == 0)
2620 int i;
2621 cpus = min(cpus,out_cpus);
2622 for (i = 0; i < cpus; i++)
2624 sppi[i].IdleTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_IDLE];
2625 sppi[i].KernelTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_SYSTEM];
2626 sppi[i].UserTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_USER];
2628 vm_deallocate (mach_task_self (), (vm_address_t) pinfo, info_count * sizeof(natural_t));
2631 #elif defined(linux)
2633 FILE *cpuinfo = fopen("/proc/stat", "r");
2634 if (cpuinfo)
2636 unsigned long clk_tck = sysconf(_SC_CLK_TCK);
2637 unsigned long usr,nice,sys,idle,remainder[8];
2638 int i, count, id;
2639 char name[32];
2640 char line[255];
2642 /* first line is combined usage */
2643 while (fgets(line,255,cpuinfo))
2645 count = sscanf(line, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
2646 name, &usr, &nice, &sys, &idle,
2647 &remainder[0], &remainder[1], &remainder[2], &remainder[3],
2648 &remainder[4], &remainder[5], &remainder[6], &remainder[7]);
2650 if (count < 5 || strncmp( name, "cpu", 3 )) break;
2651 for (i = 0; i + 5 < count; ++i) sys += remainder[i];
2652 sys += idle;
2653 usr += nice;
2654 id = atoi( name + 3 ) + 1;
2655 if (id > out_cpus) break;
2656 if (id > cpus) cpus = id;
2657 sppi[id-1].IdleTime.QuadPart = (ULONGLONG)idle * 10000000 / clk_tck;
2658 sppi[id-1].KernelTime.QuadPart = (ULONGLONG)sys * 10000000 / clk_tck;
2659 sppi[id-1].UserTime.QuadPart = (ULONGLONG)usr * 10000000 / clk_tck;
2661 fclose(cpuinfo);
2664 #elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__)
2666 static int clockrate_name[] = { CTL_KERN, KERN_CLOCKRATE };
2667 size_t size = 0;
2668 struct clockinfo clockrate;
2669 int have_clockrate;
2670 long *ptimes;
2672 size = sizeof(clockrate);
2673 have_clockrate = !sysctl(clockrate_name, 2, &clockrate, &size, NULL, 0);
2674 size = out_cpus * CPUSTATES * sizeof(long);
2675 ptimes = malloc(size + 1);
2676 if (ptimes)
2678 if (have_clockrate && (!sysctlbyname("kern.cp_times", ptimes, &size, NULL, 0) || errno == ENOMEM))
2680 for (cpus = 0; cpus < out_cpus; cpus++)
2682 if (cpus * CPUSTATES * sizeof(long) >= size) break;
2683 sppi[cpus].IdleTime.QuadPart = (ULONGLONG)ptimes[cpus*CPUSTATES + CP_IDLE] * 10000000 / clockrate.stathz;
2684 sppi[cpus].KernelTime.QuadPart = (ULONGLONG)ptimes[cpus*CPUSTATES + CP_SYS] * 10000000 / clockrate.stathz;
2685 sppi[cpus].UserTime.QuadPart = (ULONGLONG)ptimes[cpus*CPUSTATES + CP_USER] * 10000000 / clockrate.stathz;
2688 free(ptimes);
2691 #endif
2692 if (cpus == 0)
2694 static int i = 1;
2695 unsigned int n;
2696 cpus = min(peb->NumberOfProcessors, out_cpus);
2697 FIXME("stub info_class SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION\n");
2698 /* many programs expect these values to change so fake change */
2699 for (n = 0; n < cpus; n++)
2701 sppi[n].KernelTime.QuadPart = 1 * i;
2702 sppi[n].UserTime.QuadPart = 2 * i;
2703 sppi[n].IdleTime.QuadPart = 3 * i;
2705 i++;
2708 len = sizeof(*sppi) * cpus;
2709 if (size >= len)
2711 if (!info) ret = STATUS_ACCESS_VIOLATION;
2712 else memcpy( info, sppi, len);
2714 else ret = STATUS_INFO_LENGTH_MISMATCH;
2716 free( sppi );
2717 break;
2720 case SystemModuleInformation: /* 11 */
2722 /* FIXME: return some fake info for now */
2723 static const char *fake_modules[] =
2725 "\\SystemRoot\\system32\\ntoskrnl.exe",
2726 "\\SystemRoot\\system32\\hal.dll",
2727 "\\SystemRoot\\system32\\drivers\\mountmgr.sys"
2730 ULONG i;
2731 RTL_PROCESS_MODULES *smi = info;
2733 len = offsetof( RTL_PROCESS_MODULES, Modules[ARRAY_SIZE(fake_modules)] );
2734 if (len <= size)
2736 memset( smi, 0, len );
2737 for (i = 0; i < ARRAY_SIZE(fake_modules); i++)
2739 RTL_PROCESS_MODULE_INFORMATION *sm = &smi->Modules[i];
2740 sm->ImageBaseAddress = (char *)0x10000000 + 0x200000 * i;
2741 sm->ImageSize = 0x200000;
2742 sm->LoadOrderIndex = i;
2743 sm->LoadCount = 1;
2744 strcpy( (char *)sm->Name, fake_modules[i] );
2745 sm->NameOffset = strrchr( fake_modules[i], '\\' ) - fake_modules[i] + 1;
2747 smi->ModulesCount = i;
2749 else ret = STATUS_INFO_LENGTH_MISMATCH;
2751 break;
2754 case SystemHandleInformation: /* 16 */
2756 struct handle_info *handle_info;
2757 DWORD i, num_handles;
2759 if (size < sizeof(SYSTEM_HANDLE_INFORMATION))
2761 ret = STATUS_INFO_LENGTH_MISMATCH;
2762 break;
2765 if (!info)
2767 ret = STATUS_ACCESS_VIOLATION;
2768 break;
2771 num_handles = (size - FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle )) / sizeof(SYSTEM_HANDLE_ENTRY);
2772 if (!(handle_info = malloc( sizeof(*handle_info) * num_handles ))) return STATUS_NO_MEMORY;
2774 SERVER_START_REQ( get_system_handles )
2776 wine_server_set_reply( req, handle_info, sizeof(*handle_info) * num_handles );
2777 if (!(ret = wine_server_call( req )))
2779 SYSTEM_HANDLE_INFORMATION *shi = info;
2780 shi->Count = wine_server_reply_size( req ) / sizeof(*handle_info);
2781 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle[shi->Count] );
2782 for (i = 0; i < shi->Count; i++)
2784 memset( &shi->Handle[i], 0, sizeof(shi->Handle[i]) );
2785 shi->Handle[i].OwnerPid = handle_info[i].owner;
2786 shi->Handle[i].HandleValue = handle_info[i].handle;
2787 shi->Handle[i].AccessMask = handle_info[i].access;
2788 shi->Handle[i].HandleFlags = handle_info[i].attributes;
2789 shi->Handle[i].ObjectType = handle_info[i].type;
2790 /* FIXME: Fill out ObjectPointer */
2793 else if (ret == STATUS_BUFFER_TOO_SMALL)
2795 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle[reply->count] );
2796 ret = STATUS_INFO_LENGTH_MISMATCH;
2799 SERVER_END_REQ;
2801 free( handle_info );
2802 break;
2805 case SystemFileCacheInformation: /* 21 */
2807 SYSTEM_CACHE_INFORMATION sci = { 0 };
2809 len = sizeof(sci);
2810 if (size >= len)
2812 if (!info) ret = STATUS_ACCESS_VIOLATION;
2813 else memcpy( info, &sci, len);
2815 else ret = STATUS_INFO_LENGTH_MISMATCH;
2816 FIXME("info_class SYSTEM_CACHE_INFORMATION\n");
2817 break;
2820 case SystemInterruptInformation: /* 23 */
2822 len = peb->NumberOfProcessors * sizeof(SYSTEM_INTERRUPT_INFORMATION);
2823 if (size >= len)
2825 if (!info) ret = STATUS_ACCESS_VIOLATION;
2826 else
2828 #ifdef HAVE_GETRANDOM
2829 int ret;
2832 ret = getrandom( info, len, 0 );
2834 while (ret == -1 && errno == EINTR);
2836 if (ret == -1 && errno == ENOSYS) read_dev_urandom( info, len );
2837 #else
2838 read_dev_urandom( info, len );
2839 #endif
2842 else ret = STATUS_INFO_LENGTH_MISMATCH;
2843 break;
2846 case SystemTimeAdjustmentInformation: /* 28 */
2848 SYSTEM_TIME_ADJUSTMENT_QUERY query = { 156250, 156250, TRUE };
2850 len = sizeof(query);
2851 if (size == len)
2853 if (!info) ret = STATUS_ACCESS_VIOLATION;
2854 else memcpy( info, &query, len );
2856 else ret = STATUS_INFO_LENGTH_MISMATCH;
2857 break;
2860 case SystemKernelDebuggerInformation: /* 35 */
2862 SYSTEM_KERNEL_DEBUGGER_INFORMATION skdi;
2864 skdi.DebuggerEnabled = FALSE;
2865 skdi.DebuggerNotPresent = TRUE;
2866 len = sizeof(skdi);
2867 if (size >= len)
2869 if (!info) ret = STATUS_ACCESS_VIOLATION;
2870 else memcpy( info, &skdi, len);
2872 else ret = STATUS_INFO_LENGTH_MISMATCH;
2873 break;
2876 case SystemRegistryQuotaInformation: /* 37 */
2878 /* Something to do with the size of the registry *
2879 * Since we don't have a size limitation, fake it *
2880 * This is almost certainly wrong. *
2881 * This sets each of the three words in the struct to 32 MB, *
2882 * which is enough to make the IE 5 installer happy. */
2883 SYSTEM_REGISTRY_QUOTA_INFORMATION srqi;
2885 srqi.RegistryQuotaAllowed = 0x2000000;
2886 srqi.RegistryQuotaUsed = 0x200000;
2887 srqi.Reserved1 = (void*)0x200000;
2888 len = sizeof(srqi);
2890 if (size >= len)
2892 if (!info) ret = STATUS_ACCESS_VIOLATION;
2893 else
2895 FIXME("SystemRegistryQuotaInformation: faking max registry size of 32 MB\n");
2896 memcpy( info, &srqi, len);
2899 else ret = STATUS_INFO_LENGTH_MISMATCH;
2900 break;
2903 case SystemCurrentTimeZoneInformation: /* 44 */
2905 RTL_DYNAMIC_TIME_ZONE_INFORMATION tz;
2907 get_timezone_info( &tz );
2908 len = sizeof(RTL_TIME_ZONE_INFORMATION);
2909 if (size >= len)
2911 if (!info) ret = STATUS_ACCESS_VIOLATION;
2912 else memcpy( info, &tz, len);
2914 else ret = STATUS_INFO_LENGTH_MISMATCH;
2915 break;
2918 case SystemExtendedProcessInformation: /* 57 */
2919 ret = get_system_process_info( class, info, size, &len );
2920 break;
2922 case SystemRecommendedSharedDataAlignment: /* 58 */
2924 len = sizeof(DWORD);
2925 if (size >= len)
2927 if (!info) ret = STATUS_ACCESS_VIOLATION;
2928 else
2930 #ifdef __arm__
2931 *((DWORD *)info) = 32;
2932 #else
2933 *((DWORD *)info) = 64;
2934 #endif
2937 else ret = STATUS_INFO_LENGTH_MISMATCH;
2938 break;
2941 case SystemEmulationBasicInformation: /* 62 */
2943 SYSTEM_BASIC_INFORMATION sbi;
2945 virtual_get_system_info( &sbi, !!NtCurrentTeb()->WowTebOffset );
2946 len = sizeof(sbi);
2947 if (size == len)
2949 if (!info) ret = STATUS_ACCESS_VIOLATION;
2950 else memcpy( info, &sbi, len);
2952 else ret = STATUS_INFO_LENGTH_MISMATCH;
2953 break;
2956 case SystemEmulationProcessorInformation: /* 63 */
2957 if (size >= (len = sizeof(cpu_info)))
2959 SYSTEM_CPU_INFORMATION cpu = cpu_info;
2960 if (is_win64)
2962 if (cpu_info.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
2963 cpu.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
2964 else if (cpu_info.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64)
2965 cpu.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_ARM;
2967 memcpy(info, &cpu, len);
2969 else ret = STATUS_INFO_LENGTH_MISMATCH;
2970 break;
2972 case SystemExtendedHandleInformation: /* 64 */
2974 struct handle_info *handle_info;
2975 DWORD i, num_handles;
2977 if (size < sizeof(SYSTEM_HANDLE_INFORMATION_EX))
2979 ret = STATUS_INFO_LENGTH_MISMATCH;
2980 break;
2983 if (!info)
2985 ret = STATUS_ACCESS_VIOLATION;
2986 break;
2989 num_handles = (size - FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handles ))
2990 / sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX);
2991 if (!(handle_info = malloc( sizeof(*handle_info) * num_handles ))) return STATUS_NO_MEMORY;
2993 SERVER_START_REQ( get_system_handles )
2995 wine_server_set_reply( req, handle_info, sizeof(*handle_info) * num_handles );
2996 if (!(ret = wine_server_call( req )))
2998 SYSTEM_HANDLE_INFORMATION_EX *shi = info;
2999 shi->NumberOfHandles = wine_server_reply_size( req ) / sizeof(*handle_info);
3000 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handles[shi->NumberOfHandles] );
3001 for (i = 0; i < shi->NumberOfHandles; i++)
3003 memset( &shi->Handles[i], 0, sizeof(shi->Handles[i]) );
3004 shi->Handles[i].UniqueProcessId = handle_info[i].owner;
3005 shi->Handles[i].HandleValue = handle_info[i].handle;
3006 shi->Handles[i].GrantedAccess = handle_info[i].access;
3007 shi->Handles[i].HandleAttributes = handle_info[i].attributes;
3008 shi->Handles[i].ObjectTypeIndex = handle_info[i].type;
3009 /* FIXME: Fill out Object */
3012 else if (ret == STATUS_BUFFER_TOO_SMALL)
3014 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handles[reply->count] );
3015 ret = STATUS_INFO_LENGTH_MISMATCH;
3018 SERVER_END_REQ;
3020 free( handle_info );
3021 break;
3024 case SystemLogicalProcessorInformation: /* 73 */
3026 if (!logical_proc_info)
3028 ret = STATUS_NOT_IMPLEMENTED;
3029 break;
3031 len = logical_proc_info_len * sizeof(*logical_proc_info);
3032 if (size >= len)
3034 if (!info) ret = STATUS_ACCESS_VIOLATION;
3035 else memcpy( info, logical_proc_info, len);
3037 else ret = STATUS_INFO_LENGTH_MISMATCH;
3038 break;
3041 case SystemFirmwareTableInformation: /* 76 */
3043 SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti = info;
3044 len = FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
3045 if (size < len)
3047 ret = STATUS_INFO_LENGTH_MISMATCH;
3048 break;
3051 switch (sfti->Action)
3053 case SystemFirmwareTable_Get:
3054 ret = get_firmware_info(sfti, size, &len);
3055 break;
3056 default:
3057 len = 0;
3058 ret = STATUS_NOT_IMPLEMENTED;
3059 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION action %d\n", sfti->Action);
3061 break;
3064 case SystemModuleInformationEx: /* 77 */
3066 /* FIXME: return some fake info for now */
3067 static const char *fake_modules[] =
3069 "\\SystemRoot\\system32\\ntoskrnl.exe",
3070 "\\SystemRoot\\system32\\hal.dll",
3071 "\\SystemRoot\\system32\\drivers\\mountmgr.sys"
3074 ULONG i;
3075 RTL_PROCESS_MODULE_INFORMATION_EX *module_info = info;
3077 len = sizeof(*module_info) * ARRAY_SIZE(fake_modules) + sizeof(module_info->NextOffset);
3078 if (len <= size)
3080 memset( info, 0, len );
3081 for (i = 0; i < ARRAY_SIZE(fake_modules); i++)
3083 RTL_PROCESS_MODULE_INFORMATION *sm = &module_info[i].BaseInfo;
3084 sm->ImageBaseAddress = (char *)0x10000000 + 0x200000 * i;
3085 sm->ImageSize = 0x200000;
3086 sm->LoadOrderIndex = i;
3087 sm->LoadCount = 1;
3088 strcpy( (char *)sm->Name, fake_modules[i] );
3089 sm->NameOffset = strrchr( fake_modules[i], '\\' ) - fake_modules[i] + 1;
3090 module_info[i].NextOffset = sizeof(*module_info);
3092 module_info[ARRAY_SIZE(fake_modules)].NextOffset = 0;
3094 else ret = STATUS_INFO_LENGTH_MISMATCH;
3096 break;
3099 case SystemDynamicTimeZoneInformation: /* 102 */
3101 RTL_DYNAMIC_TIME_ZONE_INFORMATION tz;
3103 get_timezone_info( &tz );
3104 len = sizeof(tz);
3105 if (size >= len)
3107 if (!info) ret = STATUS_ACCESS_VIOLATION;
3108 else memcpy( info, &tz, len);
3110 else ret = STATUS_INFO_LENGTH_MISMATCH;
3111 break;
3114 case SystemCodeIntegrityInformation: /* 103 */
3116 SYSTEM_CODEINTEGRITY_INFORMATION *integrity_info = info;
3118 FIXME("SystemCodeIntegrityInformation, size %u, info %p, stub!\n", size, info);
3120 len = sizeof(SYSTEM_CODEINTEGRITY_INFORMATION);
3122 if (size >= len)
3123 integrity_info->CodeIntegrityOptions = CODEINTEGRITY_OPTION_ENABLED;
3124 else
3125 ret = STATUS_INFO_LENGTH_MISMATCH;
3126 break;
3129 case SystemKernelDebuggerInformationEx: /* 149 */
3131 SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX skdi;
3133 skdi.DebuggerAllowed = FALSE;
3134 skdi.DebuggerEnabled = FALSE;
3135 skdi.DebuggerPresent = FALSE;
3137 len = sizeof(skdi);
3138 if (size >= len)
3140 if (!info) ret = STATUS_ACCESS_VIOLATION;
3141 else memcpy( info, &skdi, len );
3143 else ret = STATUS_INFO_LENGTH_MISMATCH;
3144 break;
3147 case SystemCpuSetInformation: /* 175 */
3148 return NtQuerySystemInformationEx(class, NULL, 0, info, size, ret_size);
3150 /* Wine extensions */
3152 case SystemWineVersionInformation: /* 1000 */
3154 static const char version[] = PACKAGE_VERSION;
3155 struct utsname buf;
3157 uname( &buf );
3158 len = strlen(version) + strlen(wine_build) + strlen(buf.sysname) + strlen(buf.release) + 4;
3159 snprintf( info, size, "%s%c%s%c%s%c%s", version, 0, wine_build, 0, buf.sysname, 0, buf.release );
3160 if (size < len) ret = STATUS_INFO_LENGTH_MISMATCH;
3161 break;
3164 default:
3165 FIXME( "(0x%08x,%p,0x%08x,%p) stub\n", class, info, size, ret_size );
3167 /* Several Information Classes are not implemented on Windows and return 2 different values
3168 * STATUS_NOT_IMPLEMENTED or STATUS_INVALID_INFO_CLASS
3169 * in 95% of the cases it's STATUS_INVALID_INFO_CLASS, so use this as the default
3171 ret = STATUS_INVALID_INFO_CLASS;
3174 if (ret_size) *ret_size = len;
3175 return ret;
3179 /******************************************************************************
3180 * NtQuerySystemInformationEx (NTDLL.@)
3182 NTSTATUS WINAPI NtQuerySystemInformationEx( SYSTEM_INFORMATION_CLASS class,
3183 void *query, ULONG query_len,
3184 void *info, ULONG size, ULONG *ret_size )
3186 ULONG len = 0;
3187 NTSTATUS ret = STATUS_NOT_IMPLEMENTED;
3189 TRACE( "(0x%08x,%p,%u,%p,%u,%p) stub\n", class, query, query_len, info, size, ret_size );
3191 switch (class)
3193 case SystemLogicalProcessorInformationEx:
3195 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *p;
3196 DWORD relation;
3198 if (!query || query_len < sizeof(DWORD))
3200 ret = STATUS_INVALID_PARAMETER;
3201 break;
3203 if (!logical_proc_info_ex)
3205 ret = STATUS_NOT_IMPLEMENTED;
3206 break;
3209 relation = *(DWORD *)query;
3210 len = 0;
3211 p = logical_proc_info_ex;
3212 while ((char *)p != (char *)logical_proc_info_ex + logical_proc_info_ex_size)
3214 if (relation == RelationAll || p->Relationship == relation)
3216 if (len + p->Size <= size)
3217 memcpy( (char *)info + len, p, p->Size );
3218 len += p->Size;
3220 p = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((char *)p + p->Size);
3222 ret = size >= len ? STATUS_SUCCESS : STATUS_INFO_LENGTH_MISMATCH;
3223 break;
3226 case SystemCpuSetInformation:
3228 unsigned int cpu_count = peb->NumberOfProcessors;
3229 PROCESS_BASIC_INFORMATION pbi;
3230 HANDLE process;
3232 if (!query || query_len < sizeof(HANDLE))
3233 return STATUS_INVALID_PARAMETER;
3235 process = *(HANDLE *)query;
3236 if (process && (ret = NtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL)))
3237 return ret;
3239 if (size < (len = cpu_count * sizeof(SYSTEM_CPU_SET_INFORMATION)))
3241 ret = STATUS_BUFFER_TOO_SMALL;
3242 break;
3244 if (!info)
3245 return STATUS_ACCESS_VIOLATION;
3247 if ((ret = create_cpuset_info(info)))
3248 return ret;
3249 break;
3252 case SystemSupportedProcessorArchitectures:
3254 HANDLE process;
3255 ULONG i;
3256 USHORT machine = 0;
3258 if (!query || query_len < sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
3259 process = *(HANDLE *)query;
3260 if (process)
3262 SERVER_START_REQ( get_process_info )
3264 req->handle = wine_server_obj_handle( process );
3265 if (!(ret = wine_server_call( req ))) machine = reply->machine;
3267 SERVER_END_REQ;
3268 if (ret) return ret;
3271 len = (supported_machines_count + 1) * sizeof(ULONG);
3272 if (size < len)
3274 ret = STATUS_BUFFER_TOO_SMALL;
3275 break;
3277 for (i = 0; i < supported_machines_count; i++)
3279 USHORT flags = 2; /* supported (?) */
3280 if (!i) flags |= 5; /* native machine (?) */
3281 if (supported_machines[i] == machine) flags |= 8; /* current machine */
3282 ((DWORD *)info)[i] = MAKELONG( supported_machines[i], flags );
3284 ((DWORD *)info)[i] = 0;
3285 ret = STATUS_SUCCESS;
3286 break;
3289 default:
3290 FIXME( "(0x%08x,%p,%u,%p,%u,%p) stub\n", class, query, query_len, info, size, ret_size );
3291 break;
3293 if (ret_size) *ret_size = len;
3294 return ret;
3298 /******************************************************************************
3299 * NtSetSystemInformation (NTDLL.@)
3301 NTSTATUS WINAPI NtSetSystemInformation( SYSTEM_INFORMATION_CLASS class, void *info, ULONG length )
3303 FIXME( "(0x%08x,%p,0x%08x) stub\n", class, info, length );
3304 return STATUS_SUCCESS;
3308 /******************************************************************************
3309 * NtQuerySystemEnvironmentValue (NTDLL.@)
3311 NTSTATUS WINAPI NtQuerySystemEnvironmentValue( UNICODE_STRING *name, WCHAR *buffer, ULONG length,
3312 ULONG *retlen )
3314 FIXME( "(%s, %p, %u, %p), stub\n", debugstr_us(name), buffer, length, retlen );
3315 return STATUS_NOT_IMPLEMENTED;
3319 /******************************************************************************
3320 * NtQuerySystemEnvironmentValueEx (NTDLL.@)
3322 NTSTATUS WINAPI NtQuerySystemEnvironmentValueEx( UNICODE_STRING *name, GUID *vendor, void *buffer,
3323 ULONG *retlen, ULONG *attrib )
3325 FIXME( "(%s, %s, %p, %p, %p), stub\n", debugstr_us(name),
3326 debugstr_guid(vendor), buffer, retlen, attrib );
3327 return STATUS_NOT_IMPLEMENTED;
3331 /******************************************************************************
3332 * NtSystemDebugControl (NTDLL.@)
3334 NTSTATUS WINAPI NtSystemDebugControl( SYSDBG_COMMAND command, void *in_buff, ULONG in_len,
3335 void *out_buff, ULONG out_len, ULONG *retlen )
3337 FIXME( "(%d, %p, %d, %p, %d, %p), stub\n", command, in_buff, in_len, out_buff, out_len, retlen );
3338 return STATUS_NOT_IMPLEMENTED;
3342 /******************************************************************************
3343 * NtShutdownSystem (NTDLL.@)
3345 NTSTATUS WINAPI NtShutdownSystem( SHUTDOWN_ACTION action )
3347 FIXME( "%d\n", action );
3348 return STATUS_SUCCESS;
3352 #ifdef linux
3354 /* Fallback using /proc/cpuinfo for Linux systems without cpufreq. For
3355 * most distributions on recent enough hardware, this is only likely to
3356 * happen while running in virtualized environments such as QEMU. */
3357 static ULONG mhz_from_cpuinfo(void)
3359 char line[512];
3360 char *s, *value;
3361 double cmz = 0;
3362 FILE *f = fopen("/proc/cpuinfo", "r");
3363 if(f)
3365 while (fgets(line, sizeof(line), f) != NULL)
3367 if (!(value = strchr(line,':'))) continue;
3368 s = value - 1;
3369 while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
3370 s[1] = 0;
3371 value++;
3372 if (!strcmp( line, "cpu MHz" ))
3374 sscanf(value, " %lf", &cmz);
3375 break;
3378 fclose( f );
3380 return cmz;
3383 static const char * get_sys_str(const char *dirname, const char *basename, char *s)
3385 char path[64];
3386 FILE *f;
3387 const char *ret = NULL;
3389 if (snprintf(path, sizeof(path), "%s/%s", dirname, basename) >= sizeof(path)) return NULL;
3390 if ((f = fopen(path, "r")))
3392 if (fgets(s, 16, f)) ret = s;
3393 fclose(f);
3395 return ret;
3398 static int get_sys_int(const char *dirname, const char *basename)
3400 char s[16];
3401 return get_sys_str(dirname, basename, s) ? atoi(s) : 0;
3404 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
3406 DIR *d = opendir("/sys/class/power_supply");
3407 struct dirent *de;
3408 char s[16], path[64];
3409 BOOL found_ac = FALSE;
3410 LONG64 voltage; /* microvolts */
3412 bs->AcOnLine = TRUE;
3413 if (!d) return STATUS_SUCCESS;
3415 while ((de = readdir(d)))
3417 if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue;
3418 if (snprintf(path, sizeof(path), "/sys/class/power_supply/%s", de->d_name) >= sizeof(path)) continue;
3419 if (get_sys_str(path, "scope", s) && strcmp(s, "Device\n") == 0) continue;
3420 if (!get_sys_str(path, "type", s)) continue;
3422 if (strcmp(s, "Mains\n") == 0)
3424 if (!get_sys_str(path, "online", s)) continue;
3425 if (found_ac)
3427 FIXME("Multiple mains found, only reporting on the first\n");
3429 else
3431 bs->AcOnLine = atoi(s);
3432 found_ac = TRUE;
3435 else if (strcmp(s, "Battery\n") == 0)
3437 if (!get_sys_str(path, "status", s)) continue;
3438 if (bs->BatteryPresent)
3440 FIXME("Multiple batteries found, only reporting on the first\n");
3442 else
3444 bs->Charging = (strcmp(s, "Charging\n") == 0);
3445 bs->Discharging = (strcmp(s, "Discharging\n") == 0);
3446 bs->BatteryPresent = TRUE;
3447 voltage = get_sys_int(path, "voltage_now");
3448 bs->MaxCapacity = get_sys_int(path, "charge_full") * voltage / 1e9;
3449 bs->RemainingCapacity = get_sys_int(path, "charge_now") * voltage / 1e9;
3450 bs->Rate = -get_sys_int(path, "current_now") * voltage / 1e9;
3451 if (!bs->Charging && (LONG)bs->Rate < 0)
3452 bs->EstimatedTime = 3600 * bs->RemainingCapacity / -(LONG)bs->Rate;
3453 else
3454 bs->EstimatedTime = ~0u;
3459 closedir(d);
3460 return STATUS_SUCCESS;
3463 #elif defined(HAVE_IOKIT_IOKITLIB_H)
3465 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
3467 CFArrayRef batteries;
3468 CFDictionaryRef battery;
3469 CFNumberRef prop;
3470 uint32_t value, voltage;
3471 CFTimeInterval remain;
3473 if (IOPMCopyBatteryInfo( kIOMasterPortDefault, &batteries ) != kIOReturnSuccess)
3474 return STATUS_ACCESS_DENIED;
3476 if (CFArrayGetCount( batteries ) == 0)
3478 /* Just assume we're on AC with no battery. */
3479 bs->AcOnLine = TRUE;
3480 return STATUS_SUCCESS;
3482 /* Just use the first battery. */
3483 battery = CFArrayGetValueAtIndex( batteries, 0 );
3485 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryFlagsKey) );
3486 CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
3488 if (value & kIOBatteryInstalled)
3489 bs->BatteryPresent = TRUE;
3490 else
3491 /* Since we are executing code, we must have AC power. */
3492 bs->AcOnLine = TRUE;
3493 if (value & kIOBatteryChargerConnect)
3495 bs->AcOnLine = TRUE;
3496 if (value & kIOBatteryCharge)
3497 bs->Charging = TRUE;
3499 else
3500 bs->Discharging = TRUE;
3502 /* We'll need the voltage to be able to interpret the other values. */
3503 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryVoltageKey) );
3504 CFNumberGetValue( prop, kCFNumberSInt32Type, &voltage );
3506 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryCapacityKey) );
3507 CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
3508 bs->MaxCapacity = value * voltage;
3509 /* Apple uses "estimated time < 10:00" and "22%" for these, but we'll follow
3510 * Windows for now (5% and 33%). */
3511 bs->DefaultAlert1 = bs->MaxCapacity / 20;
3512 bs->DefaultAlert2 = bs->MaxCapacity / 3;
3514 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryCurrentChargeKey) );
3515 CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
3516 bs->RemainingCapacity = value * voltage;
3518 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryAmperageKey) );
3519 CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
3520 bs->Rate = value * voltage;
3522 remain = IOPSGetTimeRemainingEstimate();
3523 if (remain != kIOPSTimeRemainingUnknown && remain != kIOPSTimeRemainingUnlimited)
3524 bs->EstimatedTime = (ULONG)remain;
3526 CFRelease( batteries );
3527 return STATUS_SUCCESS;
3530 #elif defined(__FreeBSD__)
3532 #include <dev/acpica/acpiio.h>
3534 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
3536 size_t len;
3537 int state = 0;
3538 int rate_mW = 0;
3539 int time_mins = -1;
3540 int life_percent = 0;
3542 bs->BatteryPresent = TRUE;
3543 len = sizeof(state);
3544 bs->BatteryPresent &= !sysctlbyname("hw.acpi.battery.state", &state, &len, NULL, 0);
3545 len = sizeof(rate_mW);
3546 bs->BatteryPresent &= !sysctlbyname("hw.acpi.battery.rate", &rate_mW, &len, NULL, 0);
3547 len = sizeof(time_mins);
3548 bs->BatteryPresent &= !sysctlbyname("hw.acpi.battery.time", &time_mins, &len, NULL, 0);
3549 len = sizeof(life_percent);
3550 bs->BatteryPresent &= !sysctlbyname("hw.acpi.battery.life", &life_percent, &len, NULL, 0);
3552 if (bs->BatteryPresent)
3554 bs->AcOnLine = (time_mins == -1);
3555 bs->Charging = state & ACPI_BATT_STAT_CHARGING;
3556 bs->Discharging = state & ACPI_BATT_STAT_DISCHARG;
3558 bs->Rate = (rate_mW >= 0 ? -rate_mW : 0);
3559 if (time_mins >= 0 && life_percent > 0)
3561 bs->EstimatedTime = 60 * time_mins;
3562 bs->RemainingCapacity = bs->EstimatedTime * rate_mW / 3600;
3563 bs->MaxCapacity = bs->RemainingCapacity * 100 / life_percent;
3565 else
3567 bs->EstimatedTime = ~0u;
3568 bs->RemainingCapacity = life_percent;
3569 bs->MaxCapacity = 100;
3572 return STATUS_SUCCESS;
3575 #else
3577 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
3579 FIXME("SystemBatteryState not implemented on this platform\n");
3580 return STATUS_NOT_IMPLEMENTED;
3583 #endif
3585 /******************************************************************************
3586 * NtPowerInformation (NTDLL.@)
3588 NTSTATUS WINAPI NtPowerInformation( POWER_INFORMATION_LEVEL level, void *input, ULONG in_size,
3589 void *output, ULONG out_size )
3591 TRACE( "(%d,%p,%d,%p,%d)\n", level, input, in_size, output, out_size );
3592 switch (level)
3594 case SystemPowerCapabilities:
3596 PSYSTEM_POWER_CAPABILITIES PowerCaps = output;
3597 FIXME("semi-stub: SystemPowerCapabilities\n");
3598 if (out_size < sizeof(SYSTEM_POWER_CAPABILITIES)) return STATUS_BUFFER_TOO_SMALL;
3599 /* FIXME: These values are based off a native XP desktop, should probably use APM/ACPI to get the 'real' values */
3600 PowerCaps->PowerButtonPresent = TRUE;
3601 PowerCaps->SleepButtonPresent = FALSE;
3602 PowerCaps->LidPresent = FALSE;
3603 PowerCaps->SystemS1 = TRUE;
3604 PowerCaps->SystemS2 = FALSE;
3605 PowerCaps->SystemS3 = FALSE;
3606 PowerCaps->SystemS4 = TRUE;
3607 PowerCaps->SystemS5 = TRUE;
3608 PowerCaps->HiberFilePresent = TRUE;
3609 PowerCaps->FullWake = TRUE;
3610 PowerCaps->VideoDimPresent = FALSE;
3611 PowerCaps->ApmPresent = FALSE;
3612 PowerCaps->UpsPresent = FALSE;
3613 PowerCaps->ThermalControl = FALSE;
3614 PowerCaps->ProcessorThrottle = FALSE;
3615 PowerCaps->ProcessorMinThrottle = 100;
3616 PowerCaps->ProcessorMaxThrottle = 100;
3617 PowerCaps->DiskSpinDown = TRUE;
3618 PowerCaps->SystemBatteriesPresent = FALSE;
3619 PowerCaps->BatteriesAreShortTerm = FALSE;
3620 PowerCaps->BatteryScale[0].Granularity = 0;
3621 PowerCaps->BatteryScale[0].Capacity = 0;
3622 PowerCaps->BatteryScale[1].Granularity = 0;
3623 PowerCaps->BatteryScale[1].Capacity = 0;
3624 PowerCaps->BatteryScale[2].Granularity = 0;
3625 PowerCaps->BatteryScale[2].Capacity = 0;
3626 PowerCaps->AcOnLineWake = PowerSystemUnspecified;
3627 PowerCaps->SoftLidWake = PowerSystemUnspecified;
3628 PowerCaps->RtcWake = PowerSystemSleeping1;
3629 PowerCaps->MinDeviceWakeState = PowerSystemUnspecified;
3630 PowerCaps->DefaultLowLatencyWake = PowerSystemUnspecified;
3631 return STATUS_SUCCESS;
3634 case SystemBatteryState:
3636 if (out_size < sizeof(SYSTEM_BATTERY_STATE)) return STATUS_BUFFER_TOO_SMALL;
3637 memset(output, 0, sizeof(SYSTEM_BATTERY_STATE));
3638 return fill_battery_state(output);
3641 case SystemExecutionState:
3643 ULONG *state = output;
3644 WARN("semi-stub: SystemExecutionState\n"); /* Needed for .NET Framework, but using a FIXME is really noisy. */
3645 if (input != NULL) return STATUS_INVALID_PARAMETER;
3646 /* FIXME: The actual state should be the value set by SetThreadExecutionState which is not currently implemented. */
3647 *state = ES_USER_PRESENT;
3648 return STATUS_SUCCESS;
3651 case ProcessorInformation:
3653 const int cannedMHz = 1000; /* We fake a 1GHz processor if we can't conjure up real values */
3654 PROCESSOR_POWER_INFORMATION* cpu_power = output;
3655 int i, out_cpus;
3657 if ((output == NULL) || (out_size == 0)) return STATUS_INVALID_PARAMETER;
3658 out_cpus = peb->NumberOfProcessors;
3659 if ((out_size / sizeof(PROCESSOR_POWER_INFORMATION)) < out_cpus) return STATUS_BUFFER_TOO_SMALL;
3660 #if defined(linux)
3662 char filename[128];
3663 FILE* f;
3665 for(i = 0; i < out_cpus; i++) {
3666 sprintf(filename, "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", i);
3667 f = fopen(filename, "r");
3668 if (f && (fscanf(f, "%d", &cpu_power[i].MaxMhz) == 1)) {
3669 cpu_power[i].MaxMhz /= 1000;
3670 fclose(f);
3671 cpu_power[i].CurrentMhz = cpu_power[i].MaxMhz;
3673 else {
3674 if(i == 0) {
3675 cpu_power[0].CurrentMhz = mhz_from_cpuinfo();
3676 if(cpu_power[0].CurrentMhz == 0)
3677 cpu_power[0].CurrentMhz = cannedMHz;
3679 else
3680 cpu_power[i].CurrentMhz = cpu_power[0].CurrentMhz;
3681 cpu_power[i].MaxMhz = cpu_power[i].CurrentMhz;
3682 if(f) fclose(f);
3685 sprintf(filename, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", i);
3686 f = fopen(filename, "r");
3687 if(f && (fscanf(f, "%d", &cpu_power[i].MhzLimit) == 1)) {
3688 cpu_power[i].MhzLimit /= 1000;
3689 fclose(f);
3691 else
3693 cpu_power[i].MhzLimit = cpu_power[i].MaxMhz;
3694 if(f) fclose(f);
3697 cpu_power[i].Number = i;
3698 cpu_power[i].MaxIdleState = 0; /* FIXME */
3699 cpu_power[i].CurrentIdleState = 0; /* FIXME */
3702 #elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__)
3704 int num;
3705 size_t valSize = sizeof(num);
3706 if (sysctlbyname("hw.clockrate", &num, &valSize, NULL, 0))
3707 num = cannedMHz;
3708 for(i = 0; i < out_cpus; i++) {
3709 cpu_power[i].CurrentMhz = num;
3710 cpu_power[i].MaxMhz = num;
3711 cpu_power[i].MhzLimit = num;
3712 cpu_power[i].Number = i;
3713 cpu_power[i].MaxIdleState = 0; /* FIXME */
3714 cpu_power[i].CurrentIdleState = 0; /* FIXME */
3717 #elif defined (__APPLE__)
3719 size_t valSize;
3720 unsigned long long currentMhz;
3721 unsigned long long maxMhz;
3723 valSize = sizeof(currentMhz);
3724 if (!sysctlbyname("hw.cpufrequency", &currentMhz, &valSize, NULL, 0))
3725 currentMhz /= 1000000;
3726 else
3727 currentMhz = cannedMHz;
3729 valSize = sizeof(maxMhz);
3730 if (!sysctlbyname("hw.cpufrequency_max", &maxMhz, &valSize, NULL, 0))
3731 maxMhz /= 1000000;
3732 else
3733 maxMhz = currentMhz;
3735 for(i = 0; i < out_cpus; i++) {
3736 cpu_power[i].CurrentMhz = currentMhz;
3737 cpu_power[i].MaxMhz = maxMhz;
3738 cpu_power[i].MhzLimit = maxMhz;
3739 cpu_power[i].Number = i;
3740 cpu_power[i].MaxIdleState = 0; /* FIXME */
3741 cpu_power[i].CurrentIdleState = 0; /* FIXME */
3744 #else
3745 for(i = 0; i < out_cpus; i++) {
3746 cpu_power[i].CurrentMhz = cannedMHz;
3747 cpu_power[i].MaxMhz = cannedMHz;
3748 cpu_power[i].MhzLimit = cannedMHz;
3749 cpu_power[i].Number = i;
3750 cpu_power[i].MaxIdleState = 0; /* FIXME */
3751 cpu_power[i].CurrentIdleState = 0; /* FIXME */
3753 WARN("Unable to detect CPU MHz for this platform. Reporting %d MHz.\n", cannedMHz);
3754 #endif
3755 for(i = 0; i < out_cpus; i++) {
3756 TRACE("cpu_power[%d] = %u %u %u %u %u %u\n", i, cpu_power[i].Number,
3757 cpu_power[i].MaxMhz, cpu_power[i].CurrentMhz, cpu_power[i].MhzLimit,
3758 cpu_power[i].MaxIdleState, cpu_power[i].CurrentIdleState);
3760 return STATUS_SUCCESS;
3763 default:
3764 /* FIXME: Needed by .NET Framework */
3765 WARN( "Unimplemented NtPowerInformation action: %d\n", level );
3766 return STATUS_NOT_IMPLEMENTED;
3771 /******************************************************************************
3772 * NtLoadDriver (NTDLL.@)
3774 NTSTATUS WINAPI NtLoadDriver( const UNICODE_STRING *name )
3776 FIXME( "(%s), stub!\n", debugstr_us(name) );
3777 return STATUS_NOT_IMPLEMENTED;
3781 /******************************************************************************
3782 * NtUnloadDriver (NTDLL.@)
3784 NTSTATUS WINAPI NtUnloadDriver( const UNICODE_STRING *name )
3786 FIXME( "(%s), stub!\n", debugstr_us(name) );
3787 return STATUS_NOT_IMPLEMENTED;
3791 /******************************************************************************
3792 * NtDisplayString (NTDLL.@)
3794 NTSTATUS WINAPI NtDisplayString( UNICODE_STRING *string )
3796 ERR( "%s\n", debugstr_us(string) );
3797 return STATUS_SUCCESS;
3801 /******************************************************************************
3802 * NtRaiseHardError (NTDLL.@)
3804 NTSTATUS WINAPI NtRaiseHardError( NTSTATUS status, ULONG count,
3805 UNICODE_STRING *params_mask, void **params,
3806 HARDERROR_RESPONSE_OPTION option, HARDERROR_RESPONSE *response )
3808 FIXME( "%08x stub\n", status );
3809 return STATUS_NOT_IMPLEMENTED;
3813 /******************************************************************************
3814 * NtInitiatePowerAction (NTDLL.@)
3816 NTSTATUS WINAPI NtInitiatePowerAction( POWER_ACTION action, SYSTEM_POWER_STATE state,
3817 ULONG flags, BOOLEAN async )
3819 FIXME( "(%d,%d,0x%08x,%d),stub\n", action, state, flags, async );
3820 return STATUS_NOT_IMPLEMENTED;
3824 /******************************************************************************
3825 * NtSetThreadExecutionState (NTDLL.@)
3827 NTSTATUS WINAPI NtSetThreadExecutionState( EXECUTION_STATE new_state, EXECUTION_STATE *old_state )
3829 static EXECUTION_STATE current = ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED | ES_USER_PRESENT;
3831 WARN( "(0x%x, %p): stub, harmless.\n", new_state, old_state );
3832 *old_state = current;
3833 if (!(current & ES_CONTINUOUS) || (new_state & ES_CONTINUOUS)) current = new_state;
3834 return STATUS_SUCCESS;