ntdll: Make wine_build a hidden symbol.
[wine.git] / dlls / ntdll / unix / system.c
blobcc4b283ffc759f76a8a1c797248a0a133ee72680
1 /*
2 * System information APIs
4 * Copyright 1996-1998 Marcus Meissner
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
26 #include "wine/port.h"
28 #include <string.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #ifdef HAVE_SYS_TIME_H
34 # include <sys/time.h>
35 #endif
36 #include <time.h>
37 #ifdef HAVE_SYS_PARAM_H
38 # include <sys/param.h>
39 #endif
40 #ifdef HAVE_SYS_SYSCTL_H
41 # include <sys/sysctl.h>
42 #endif
43 #ifdef HAVE_SYS_UTSNAME_H
44 # include <sys/utsname.h>
45 #endif
46 #ifdef HAVE_MACHINE_CPU_H
47 # include <machine/cpu.h>
48 #endif
49 #ifdef HAVE_SYS_RANDOM_H
50 # include <sys/random.h>
51 #endif
52 #ifdef HAVE_IOKIT_IOKITLIB_H
53 # include <CoreFoundation/CoreFoundation.h>
54 # include <IOKit/IOKitLib.h>
55 # include <IOKit/pwr_mgt/IOPM.h>
56 # include <IOKit/pwr_mgt/IOPMLib.h>
57 # include <IOKit/ps/IOPowerSources.h>
58 #endif
59 #ifdef __APPLE__
60 # include <mach/mach.h>
61 # include <mach/machine.h>
62 # include <mach/mach_init.h>
63 # include <mach/mach_host.h>
64 # include <mach/vm_map.h>
65 #endif
67 #define NONAMELESSUNION
68 #include "ntstatus.h"
69 #define WIN32_NO_STATUS
70 #include "windef.h"
71 #include "winternl.h"
72 #include "ddk/wdm.h"
73 #include "wine/asm.h"
74 #include "unix_private.h"
75 #include "wine/debug.h"
77 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
79 #include "pshpack1.h"
81 struct smbios_prologue
83 BYTE calling_method;
84 BYTE major_version;
85 BYTE minor_version;
86 BYTE revision;
87 DWORD length;
90 struct smbios_header
92 BYTE type;
93 BYTE length;
94 WORD handle;
97 struct smbios_bios
99 struct smbios_header hdr;
100 BYTE vendor;
101 BYTE version;
102 WORD start;
103 BYTE date;
104 BYTE size;
105 UINT64 characteristics;
106 BYTE characteristics_ext[2];
107 BYTE system_bios_major_release;
108 BYTE system_bios_minor_release;
109 BYTE ec_firmware_major_release;
110 BYTE ec_firmware_minor_release;
113 struct smbios_system
115 struct smbios_header hdr;
116 BYTE vendor;
117 BYTE product;
118 BYTE version;
119 BYTE serial;
120 BYTE uuid[16];
121 BYTE wake_up_type;
122 BYTE sku_number;
123 BYTE family;
126 struct smbios_board
128 struct smbios_header hdr;
129 BYTE vendor;
130 BYTE product;
131 BYTE version;
132 BYTE serial;
133 BYTE asset_tag;
134 BYTE feature_flags;
135 BYTE location;
136 WORD chassis_handle;
137 BYTE board_type;
138 BYTE num_contained_handles;
141 struct smbios_chassis
143 struct smbios_header hdr;
144 BYTE vendor;
145 BYTE type;
146 BYTE version;
147 BYTE serial;
148 BYTE asset_tag;
149 BYTE boot_state;
150 BYTE power_supply_state;
151 BYTE thermal_state;
152 BYTE security_status;
153 DWORD oem_defined;
154 BYTE height;
155 BYTE num_power_cords;
156 BYTE num_contained_elements;
157 BYTE contained_element_rec_length;
160 struct smbios_boot_info
162 struct smbios_header hdr;
163 BYTE reserved[6];
164 BYTE boot_status[10];
167 #include "poppack.h"
169 /* Firmware table providers */
170 #define ACPI 0x41435049
171 #define FIRM 0x4649524D
172 #define RSMB 0x52534D42
174 SYSTEM_CPU_INFORMATION cpu_info = { 0 };
176 /*******************************************************************************
177 * Architecture specific feature detection for CPUs
179 * This a set of mutually exclusive #if define()s each providing its own get_cpuinfo() to be called
180 * from init_cpu_info();
182 #if defined(__i386__) || defined(__x86_64__)
184 BOOL xstate_compaction_enabled = FALSE;
186 #define AUTH 0x68747541 /* "Auth" */
187 #define ENTI 0x69746e65 /* "enti" */
188 #define CAMD 0x444d4163 /* "cAMD" */
190 #define GENU 0x756e6547 /* "Genu" */
191 #define INEI 0x49656e69 /* "ineI" */
192 #define NTEL 0x6c65746e /* "ntel" */
194 static inline void do_cpuid(unsigned int ax, unsigned int cx, unsigned int *p)
196 __asm__ ("cpuid" : "=a"(p[0]), "=b" (p[1]), "=c"(p[2]), "=d"(p[3]) : "a"(ax), "c"(cx));
199 #ifdef __i386__
200 extern int have_cpuid(void) DECLSPEC_HIDDEN;
201 __ASM_GLOBAL_FUNC( have_cpuid,
202 "pushfl\n\t"
203 "pushfl\n\t"
204 "movl (%esp),%ecx\n\t"
205 "xorl $0x00200000,(%esp)\n\t"
206 "popfl\n\t"
207 "pushfl\n\t"
208 "popl %eax\n\t"
209 "popfl\n\t"
210 "xorl %ecx,%eax\n\t"
211 "andl $0x00200000,%eax\n\t"
212 "ret" )
213 #else
214 static int have_cpuid(void)
216 return 1;
218 #endif
220 /* Detect if a SSE2 processor is capable of Denormals Are Zero (DAZ) mode.
222 * This function assumes you have already checked for SSE2/FXSAVE support. */
223 static inline BOOL have_sse_daz_mode(void)
225 #ifdef __i386__
226 /* Intel says we need a zeroed 16-byte aligned buffer */
227 char buffer[512 + 16];
228 XSAVE_FORMAT *state = (XSAVE_FORMAT *)(((ULONG_PTR)buffer + 15) & ~15);
229 memset(buffer, 0, sizeof(buffer));
231 __asm__ __volatile__( "fxsave %0" : "=m" (*state) : "m" (*state) );
233 return (state->MxCsr_Mask & (1 << 6)) >> 6;
234 #else /* all x86_64 processors include SSE2 with DAZ mode */
235 return TRUE;
236 #endif
239 static void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
241 unsigned int regs[4], regs2[4], regs3[4];
243 #if defined(__i386__)
244 info->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
245 #elif defined(__x86_64__)
246 info->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
247 #endif
249 /* We're at least a 386 */
250 info->ProcessorFeatureBits = CPU_FEATURE_VME | CPU_FEATURE_X86 | CPU_FEATURE_PGE;
251 info->ProcessorLevel = 3;
253 if (!have_cpuid()) return;
255 do_cpuid( 0x00000000, 0, regs ); /* get standard cpuid level and vendor name */
256 if (regs[0]>=0x00000001) /* Check for supported cpuid version */
258 do_cpuid( 0x00000001, 0, regs2 ); /* get cpu features */
259 if (regs2[3] & (1 << 3 )) info->ProcessorFeatureBits |= CPU_FEATURE_PSE;
260 if (regs2[3] & (1 << 4 )) info->ProcessorFeatureBits |= CPU_FEATURE_TSC;
261 if (regs2[3] & (1 << 6 )) info->ProcessorFeatureBits |= CPU_FEATURE_PAE;
262 if (regs2[3] & (1 << 8 )) info->ProcessorFeatureBits |= CPU_FEATURE_CX8;
263 if (regs2[3] & (1 << 11)) info->ProcessorFeatureBits |= CPU_FEATURE_SEP;
264 if (regs2[3] & (1 << 12)) info->ProcessorFeatureBits |= CPU_FEATURE_MTRR;
265 if (regs2[3] & (1 << 15)) info->ProcessorFeatureBits |= CPU_FEATURE_CMOV;
266 if (regs2[3] & (1 << 16)) info->ProcessorFeatureBits |= CPU_FEATURE_PAT;
267 if (regs2[3] & (1 << 23)) info->ProcessorFeatureBits |= CPU_FEATURE_MMX;
268 if (regs2[3] & (1 << 24)) info->ProcessorFeatureBits |= CPU_FEATURE_FXSR;
269 if (regs2[3] & (1 << 25)) info->ProcessorFeatureBits |= CPU_FEATURE_SSE;
270 if (regs2[3] & (1 << 26)) info->ProcessorFeatureBits |= CPU_FEATURE_SSE2;
271 if (regs2[2] & (1 << 0 )) info->ProcessorFeatureBits |= CPU_FEATURE_SSE3;
272 if (regs2[2] & (1 << 9 )) info->ProcessorFeatureBits |= CPU_FEATURE_SSSE3;
273 if (regs2[2] & (1 << 13)) info->ProcessorFeatureBits |= CPU_FEATURE_CX128;
274 if (regs2[2] & (1 << 19)) info->ProcessorFeatureBits |= CPU_FEATURE_SSE41;
275 if (regs2[2] & (1 << 20)) info->ProcessorFeatureBits |= CPU_FEATURE_SSE42;
276 if (regs2[2] & (1 << 27)) info->ProcessorFeatureBits |= CPU_FEATURE_XSAVE;
277 if (regs2[2] & (1 << 28)) info->ProcessorFeatureBits |= CPU_FEATURE_AVX;
278 if((regs2[3] & (1 << 26)) && (regs2[3] & (1 << 24)) && have_sse_daz_mode()) /* has SSE2 and FXSAVE/FXRSTOR */
279 info->ProcessorFeatureBits |= CPU_FEATURE_DAZ;
281 if (regs[0] >= 0x00000007)
283 do_cpuid( 0x00000007, 0, regs3 ); /* get extended features */
284 if (regs3[1] & (1 << 5)) info->ProcessorFeatureBits |= CPU_FEATURE_AVX2;
287 if (info->ProcessorFeatureBits & CPU_FEATURE_XSAVE)
289 do_cpuid( 0x0000000d, 1, regs3 ); /* get XSAVE details */
290 if (regs3[0] & 2) xstate_compaction_enabled = TRUE;
293 if (regs[1] == AUTH && regs[3] == ENTI && regs[2] == CAMD)
295 info->ProcessorLevel = (regs2[0] >> 8) & 0xf; /* family */
296 if (info->ProcessorLevel == 0xf) /* AMD says to add the extended family to the family if family is 0xf */
297 info->ProcessorLevel += (regs2[0] >> 20) & 0xff;
299 /* repack model and stepping to make a "revision" */
300 info->ProcessorRevision = ((regs2[0] >> 16) & 0xf) << 12; /* extended model */
301 info->ProcessorRevision |= ((regs2[0] >> 4 ) & 0xf) << 8; /* model */
302 info->ProcessorRevision |= regs2[0] & 0xf; /* stepping */
304 do_cpuid( 0x80000000, 0, regs ); /* get vendor cpuid level */
305 if (regs[0] >= 0x80000001)
307 do_cpuid( 0x80000001, 0, regs2 ); /* get vendor features */
308 if (regs2[2] & (1 << 2)) info->ProcessorFeatureBits |= CPU_FEATURE_VIRT;
309 if (regs2[3] & (1 << 20)) info->ProcessorFeatureBits |= CPU_FEATURE_NX;
310 if (regs2[3] & (1 << 27)) info->ProcessorFeatureBits |= CPU_FEATURE_TSC;
311 if (regs2[3] & (1u << 31)) info->ProcessorFeatureBits |= CPU_FEATURE_3DNOW;
314 else if (regs[1] == GENU && regs[3] == INEI && regs[2] == NTEL)
316 info->ProcessorLevel = ((regs2[0] >> 8) & 0xf) + ((regs2[0] >> 20) & 0xff); /* family + extended family */
317 if(info->ProcessorLevel == 15) info->ProcessorLevel = 6;
319 /* repack model and stepping to make a "revision" */
320 info->ProcessorRevision = ((regs2[0] >> 16) & 0xf) << 12; /* extended model */
321 info->ProcessorRevision |= ((regs2[0] >> 4 ) & 0xf) << 8; /* model */
322 info->ProcessorRevision |= regs2[0] & 0xf; /* stepping */
324 if(regs2[2] & (1 << 5)) info->ProcessorFeatureBits |= CPU_FEATURE_VIRT;
325 if(regs2[3] & (1 << 21)) info->ProcessorFeatureBits |= CPU_FEATURE_DS;
327 do_cpuid( 0x80000000, 0, regs ); /* get vendor cpuid level */
328 if (regs[0] >= 0x80000001)
330 do_cpuid( 0x80000001, 0, regs2 ); /* get vendor features */
331 if (regs2[3] & (1 << 20)) info->ProcessorFeatureBits |= CPU_FEATURE_NX;
332 if (regs2[3] & (1 << 27)) info->ProcessorFeatureBits |= CPU_FEATURE_TSC;
335 else
337 info->ProcessorLevel = (regs2[0] >> 8) & 0xf; /* family */
339 /* repack model and stepping to make a "revision" */
340 info->ProcessorRevision = ((regs2[0] >> 4 ) & 0xf) << 8; /* model */
341 info->ProcessorRevision |= regs2[0] & 0xf; /* stepping */
346 #elif defined(__arm__)
348 static inline void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
350 #ifdef linux
351 char line[512];
352 char *s, *value;
353 FILE *f = fopen("/proc/cpuinfo", "r");
354 if (f)
356 while (fgets( line, sizeof(line), f ))
358 /* NOTE: the ':' is the only character we can rely on */
359 if (!(value = strchr(line,':'))) continue;
360 /* terminate the valuename */
361 s = value - 1;
362 while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
363 s[1] = 0;
364 /* and strip leading spaces from value */
365 value += 1;
366 while (*value == ' ' || *value == '\t') value++;
367 if ((s = strchr( value,'\n' ))) *s = 0;
368 if (!strcmp( line, "CPU architecture" ))
370 info->ProcessorLevel = atoi(value);
371 continue;
373 if (!strcmp( line, "CPU revision" ))
375 info->ProcessorRevision = atoi(value);
376 continue;
378 if (!strcmp( line, "Features" ))
380 if (strstr(value, "crc32")) info->ProcessorFeatureBits |= CPU_FEATURE_ARM_V8_CRC32;
381 if (strstr(value, "aes")) info->ProcessorFeatureBits |= CPU_FEATURE_ARM_V8_CRYPTO;
382 continue;
385 fclose( f );
387 #elif defined(__FreeBSD__)
388 size_t valsize;
389 char buf[8];
390 int value;
392 valsize = sizeof(buf);
393 if (!sysctlbyname("hw.machine_arch", &buf, &valsize, NULL, 0) && sscanf(buf, "armv%i", &value) == 1)
394 info->ProcessorLevel = value;
396 valsize = sizeof(value);
397 if (!sysctlbyname("hw.floatingpoint", &value, &valsize, NULL, 0))
398 info->ProcessorFeatureBits |= CPU_FEATURE_ARM_VFP_32;
399 #else
400 FIXME("CPU Feature detection not implemented.\n");
401 #endif
402 info->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_ARM;
405 #elif defined(__aarch64__)
407 static void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
409 #ifdef linux
410 char line[512];
411 char *s, *value;
412 FILE *f = fopen("/proc/cpuinfo", "r");
413 if (f)
415 while (fgets( line, sizeof(line), f ))
417 /* NOTE: the ':' is the only character we can rely on */
418 if (!(value = strchr(line,':'))) continue;
419 /* terminate the valuename */
420 s = value - 1;
421 while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
422 s[1] = 0;
423 /* and strip leading spaces from value */
424 value += 1;
425 while (*value == ' ' || *value == '\t') value++;
426 if ((s = strchr( value,'\n' ))) *s = 0;
427 if (!strcmp( line, "CPU architecture" ))
429 info->ProcessorLevel = atoi(value);
430 continue;
432 if (!strcmp( line, "CPU revision" ))
434 info->ProcessorRevision = atoi(value);
435 continue;
437 if (!strcmp( line, "Features" ))
439 if (strstr(value, "crc32")) info->ProcessorFeatureBits |= CPU_FEATURE_ARM_V8_CRC32;
440 if (strstr(value, "aes")) info->ProcessorFeatureBits |= CPU_FEATURE_ARM_V8_CRYPTO;
441 continue;
444 fclose( f );
446 #else
447 FIXME("CPU Feature detection not implemented.\n");
448 #endif
449 info->ProcessorLevel = max(info->ProcessorLevel, 8);
450 info->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_ARM64;
453 #endif /* End architecture specific feature detection for CPUs */
455 /******************************************************************
456 * init_cpu_info
458 * inits a couple of places with CPU related information:
459 * - cpu_info in this file
460 * - Peb->NumberOfProcessors
461 * - SharedUserData->ProcessFeatures[] array
463 void init_cpu_info(void)
465 long num;
467 #ifdef _SC_NPROCESSORS_ONLN
468 num = sysconf(_SC_NPROCESSORS_ONLN);
469 if (num < 1)
471 num = 1;
472 WARN("Failed to detect the number of processors.\n");
474 #elif defined(CTL_HW) && defined(HW_NCPU)
475 int mib[2];
476 size_t len = sizeof(num);
477 mib[0] = CTL_HW;
478 mib[1] = HW_NCPU;
479 if (sysctl(mib, 2, &num, &len, NULL, 0) != 0)
481 num = 1;
482 WARN("Failed to detect the number of processors.\n");
484 #else
485 num = 1;
486 FIXME("Detecting the number of processors is not supported.\n");
487 #endif
488 peb->NumberOfProcessors = num;
489 get_cpuinfo( &cpu_info );
490 TRACE( "<- CPU arch %d, level %d, rev %d, features 0x%x\n",
491 cpu_info.ProcessorArchitecture, cpu_info.ProcessorLevel, cpu_info.ProcessorRevision,
492 cpu_info.ProcessorFeatureBits );
495 static BOOL grow_logical_proc_buf( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata, DWORD *max_len )
497 SYSTEM_LOGICAL_PROCESSOR_INFORMATION *new_data;
499 *max_len *= 2;
500 if (!(new_data = realloc( *pdata, *max_len*sizeof(*new_data) ))) return FALSE;
501 *pdata = new_data;
502 return TRUE;
505 static BOOL grow_logical_proc_ex_buf( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *max_len )
507 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *new_dataex;
508 DWORD new_len = *max_len * 2;
509 if (!(new_dataex = realloc( *pdataex, new_len * sizeof(*new_dataex) ))) return FALSE;
510 memset( new_dataex + *max_len, 0, (new_len - *max_len) * sizeof(*new_dataex) );
511 *pdataex = new_dataex;
512 *max_len = new_len;
513 return TRUE;
516 static DWORD log_proc_ex_size_plus(DWORD size)
518 /* add SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX.Relationship and .Size */
519 return sizeof(LOGICAL_PROCESSOR_RELATIONSHIP) + sizeof(DWORD) + size;
522 static DWORD count_bits(ULONG_PTR mask)
524 DWORD count = 0;
525 while (mask > 0)
527 if (mask & 1) ++count;
528 mask >>= 1;
530 return count;
533 /* Store package and core information for a logical processor. Parsing of processor
534 * data may happen in multiple passes; the 'id' parameter is then used to locate
535 * previously stored data. The type of data stored in 'id' depends on 'rel':
536 * - RelationProcessorPackage: package id ('CPU socket').
537 * - RelationProcessorCore: physical core number.
539 static BOOL logical_proc_info_add_by_id( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
540 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *len,
541 DWORD *pmax_len, LOGICAL_PROCESSOR_RELATIONSHIP rel,
542 DWORD id, ULONG_PTR mask )
544 if (pdata)
546 DWORD i;
548 for (i = 0; i < *len; i++)
550 if (rel == RelationProcessorPackage && (*pdata)[i].Relationship == rel && (*pdata)[i].u.Reserved[1] == id)
552 (*pdata)[i].ProcessorMask |= mask;
553 return TRUE;
555 else if (rel == RelationProcessorCore && (*pdata)[i].Relationship == rel && (*pdata)[i].u.Reserved[1] == id)
556 return TRUE;
559 while (*len == *pmax_len)
561 if (!grow_logical_proc_buf(pdata, pmax_len)) return FALSE;
564 (*pdata)[i].Relationship = rel;
565 (*pdata)[i].ProcessorMask = mask;
566 if (rel == RelationProcessorCore)
567 (*pdata)[i].u.ProcessorCore.Flags = count_bits(mask) > 1 ? LTP_PC_SMT : 0;
568 (*pdata)[i].u.Reserved[0] = 0;
569 (*pdata)[i].u.Reserved[1] = id;
570 *len = i+1;
572 else
574 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
575 DWORD ofs = 0;
577 while (ofs < *len)
579 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
580 if (rel == RelationProcessorPackage && dataex->Relationship == rel && dataex->u.Processor.Reserved[1] == id)
582 dataex->u.Processor.GroupMask[0].Mask |= mask;
583 return TRUE;
585 else if (rel == RelationProcessorCore && dataex->Relationship == rel && dataex->u.Processor.Reserved[1] == id)
587 return TRUE;
589 ofs += dataex->Size;
592 /* TODO: For now, just one group. If more than 64 processors, then we
593 * need another group. */
595 while (ofs + log_proc_ex_size_plus(sizeof(PROCESSOR_RELATIONSHIP)) > *pmax_len)
597 if (!grow_logical_proc_ex_buf(pdataex, pmax_len)) return FALSE;
600 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
602 dataex->Relationship = rel;
603 dataex->Size = log_proc_ex_size_plus(sizeof(PROCESSOR_RELATIONSHIP));
604 if (rel == RelationProcessorCore)
605 dataex->u.Processor.Flags = count_bits(mask) > 1 ? LTP_PC_SMT : 0;
606 else
607 dataex->u.Processor.Flags = 0;
608 dataex->u.Processor.EfficiencyClass = 0;
609 dataex->u.Processor.GroupCount = 1;
610 dataex->u.Processor.GroupMask[0].Mask = mask;
611 dataex->u.Processor.GroupMask[0].Group = 0;
612 /* mark for future lookup */
613 dataex->u.Processor.Reserved[0] = 0;
614 dataex->u.Processor.Reserved[1] = id;
616 *len += dataex->Size;
619 return TRUE;
622 static BOOL logical_proc_info_add_cache( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
623 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *len,
624 DWORD *pmax_len, ULONG_PTR mask, CACHE_DESCRIPTOR *cache )
626 if (pdata)
628 DWORD i;
630 for (i = 0; i < *len; i++)
632 if ((*pdata)[i].Relationship==RelationCache && (*pdata)[i].ProcessorMask==mask
633 && (*pdata)[i].u.Cache.Level==cache->Level && (*pdata)[i].u.Cache.Type==cache->Type)
634 return TRUE;
637 while (*len == *pmax_len)
638 if (!grow_logical_proc_buf(pdata, pmax_len)) return FALSE;
640 (*pdata)[i].Relationship = RelationCache;
641 (*pdata)[i].ProcessorMask = mask;
642 (*pdata)[i].u.Cache = *cache;
643 *len = i+1;
645 else
647 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
648 DWORD ofs;
650 for (ofs = 0; ofs < *len; )
652 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
653 if (dataex->Relationship == RelationCache && dataex->u.Cache.GroupMask.Mask == mask &&
654 dataex->u.Cache.Level == cache->Level && dataex->u.Cache.Type == cache->Type)
655 return TRUE;
656 ofs += dataex->Size;
659 while (ofs + log_proc_ex_size_plus(sizeof(CACHE_RELATIONSHIP)) > *pmax_len)
661 if (!grow_logical_proc_ex_buf(pdataex, pmax_len)) return FALSE;
664 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
666 dataex->Relationship = RelationCache;
667 dataex->Size = log_proc_ex_size_plus(sizeof(CACHE_RELATIONSHIP));
668 dataex->u.Cache.Level = cache->Level;
669 dataex->u.Cache.Associativity = cache->Associativity;
670 dataex->u.Cache.LineSize = cache->LineSize;
671 dataex->u.Cache.CacheSize = cache->Size;
672 dataex->u.Cache.Type = cache->Type;
673 dataex->u.Cache.GroupMask.Mask = mask;
674 dataex->u.Cache.GroupMask.Group = 0;
676 *len += dataex->Size;
679 return TRUE;
682 static BOOL logical_proc_info_add_numa_node( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
683 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *len,
684 DWORD *pmax_len, ULONG_PTR mask, DWORD node_id )
686 if (pdata)
688 while (*len == *pmax_len)
689 if (!grow_logical_proc_buf(pdata, pmax_len)) return FALSE;
691 (*pdata)[*len].Relationship = RelationNumaNode;
692 (*pdata)[*len].ProcessorMask = mask;
693 (*pdata)[*len].u.NumaNode.NodeNumber = node_id;
694 (*len)++;
696 else
698 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
700 while (*len + log_proc_ex_size_plus(sizeof(NUMA_NODE_RELATIONSHIP)) > *pmax_len)
702 if (!grow_logical_proc_ex_buf(pdataex, pmax_len)) return FALSE;
705 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + *len);
707 dataex->Relationship = RelationNumaNode;
708 dataex->Size = log_proc_ex_size_plus(sizeof(NUMA_NODE_RELATIONSHIP));
709 dataex->u.NumaNode.NodeNumber = node_id;
710 dataex->u.NumaNode.GroupMask.Mask = mask;
711 dataex->u.NumaNode.GroupMask.Group = 0;
713 *len += dataex->Size;
716 return TRUE;
719 static BOOL logical_proc_info_add_group( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex,
720 DWORD *len, DWORD *pmax_len, DWORD num_cpus, ULONG_PTR mask )
722 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
724 while (*len + log_proc_ex_size_plus(sizeof(GROUP_RELATIONSHIP)) > *pmax_len)
725 if (!grow_logical_proc_ex_buf(pdataex, pmax_len)) return FALSE;
727 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + *len);
729 dataex->Relationship = RelationGroup;
730 dataex->Size = log_proc_ex_size_plus(sizeof(GROUP_RELATIONSHIP));
731 dataex->u.Group.MaximumGroupCount = 1;
732 dataex->u.Group.ActiveGroupCount = 1;
733 dataex->u.Group.GroupInfo[0].MaximumProcessorCount = num_cpus;
734 dataex->u.Group.GroupInfo[0].ActiveProcessorCount = num_cpus;
735 dataex->u.Group.GroupInfo[0].ActiveProcessorMask = mask;
737 *len += dataex->Size;
738 return TRUE;
741 #ifdef linux
743 /* Helper function for counting bitmap values as commonly used by the Linux kernel
744 * for storing CPU masks in sysfs. The format is comma separated lists of hex values
745 * each max 32-bit e.g. "00ff" or even "00,00000000,0000ffff".
747 * Example files include:
748 * - /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_map
749 * - /sys/devices/system/cpu/cpu0/topology/thread_siblings
751 static BOOL sysfs_parse_bitmap(const char *filename, ULONG_PTR *mask)
753 FILE *f;
754 DWORD r;
756 f = fopen(filename, "r");
757 if (!f) return FALSE;
759 while (!feof(f))
761 char op;
762 if (!fscanf(f, "%x%c ", &r, &op)) break;
763 *mask = (sizeof(ULONG_PTR)>sizeof(int) ? *mask << (8 * sizeof(DWORD)) : 0) + r;
765 fclose( f );
766 return TRUE;
769 /* Helper function for counting number of elements in interval lists as used by
770 * the Linux kernel. The format is comma separated list of intervals of which
771 * each interval has the format of "begin-end" where begin and end are decimal
772 * numbers. E.g. "0-7", "0-7,16-23"
774 * Example files include:
775 * - /sys/devices/system/cpu/online
776 * - /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_list
777 * - /sys/devices/system/cpu/cpu0/topology/thread_siblings_list.
779 static BOOL sysfs_count_list_elements(const char *filename, DWORD *result)
781 FILE *f;
783 f = fopen(filename, "r");
784 if (!f) return FALSE;
786 while (!feof(f))
788 char op;
789 DWORD beg, end;
791 if (!fscanf(f, "%u%c ", &beg, &op)) break;
792 if(op == '-')
793 fscanf(f, "%u%c ", &end, &op);
794 else
795 end = beg;
797 *result += end - beg + 1;
799 fclose( f );
800 return TRUE;
803 /* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
804 static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data,
805 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **dataex,
806 DWORD *max_len, DWORD relation )
808 static const char core_info[] = "/sys/devices/system/cpu/cpu%u/topology/%s";
809 static const char cache_info[] = "/sys/devices/system/cpu/cpu%u/cache/index%u/%s";
810 static const char numa_info[] = "/sys/devices/system/node/node%u/cpumap";
812 FILE *fcpu_list, *fnuma_list, *f;
813 DWORD len = 0, beg, end, i, j, r, num_cpus = 0, max_cpus = 0;
814 char op, name[MAX_PATH];
815 ULONG_PTR all_cpus_mask = 0;
817 /* On systems with a large number of CPU cores (32 or 64 depending on 32-bit or 64-bit),
818 * we have issues parsing processor information:
819 * - ULONG_PTR masks as used in data structures can't hold all cores. Requires splitting
820 * data appropriately into "processor groups". We are hard coding 1.
821 * - Thread affinity code in wineserver and our CPU parsing code here work independently.
822 * So far the Windows mask applied directly to Linux, but process groups break that.
823 * (NUMA systems you may have multiple non-full groups.)
825 if(sysfs_count_list_elements("/sys/devices/system/cpu/present", &max_cpus) && max_cpus > MAXIMUM_PROCESSORS)
827 FIXME("Improve CPU info reporting: system supports %u logical cores, but only %u supported!\n",
828 max_cpus, MAXIMUM_PROCESSORS);
831 fcpu_list = fopen("/sys/devices/system/cpu/online", "r");
832 if (!fcpu_list) return STATUS_NOT_IMPLEMENTED;
834 while (!feof(fcpu_list))
836 if (!fscanf(fcpu_list, "%u%c ", &beg, &op)) break;
837 if (op == '-') fscanf(fcpu_list, "%u%c ", &end, &op);
838 else end = beg;
840 for(i = beg; i <= end; i++)
842 DWORD phys_core = 0;
843 ULONG_PTR thread_mask = 0;
845 if (i > 8*sizeof(ULONG_PTR))
847 FIXME("skipping logical processor %d\n", i);
848 continue;
851 if (relation == RelationAll || relation == RelationProcessorPackage)
853 sprintf(name, core_info, i, "physical_package_id");
854 f = fopen(name, "r");
855 if (f)
857 fscanf(f, "%u", &r);
858 fclose(f);
860 else r = 0;
861 if (!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorPackage, r, (ULONG_PTR)1 << i))
863 fclose(fcpu_list);
864 return STATUS_NO_MEMORY;
868 /* Sysfs enumerates logical cores (and not physical cores), but Windows enumerates
869 * by physical core. Upon enumerating a logical core in sysfs, we register a physical
870 * core and all its logical cores. In order to not report physical cores multiple
871 * times, we pass a unique physical core ID to logical_proc_info_add_by_id and let
872 * that call figure out any duplication.
873 * Obtain a unique physical core ID from the first element of thread_siblings_list.
874 * This list provides logical cores sharing the same physical core. The IDs are based
875 * on kernel cpu core numbering as opposed to a hardware core ID like provided through
876 * 'core_id', so are suitable as a unique ID.
878 if(relation == RelationAll || relation == RelationProcessorCore ||
879 relation == RelationNumaNode || relation == RelationGroup)
881 /* Mask of logical threads sharing same physical core in kernel core numbering. */
882 sprintf(name, core_info, i, "thread_siblings");
883 if(!sysfs_parse_bitmap(name, &thread_mask)) thread_mask = 1<<i;
885 /* Needed later for NumaNode and Group. */
886 all_cpus_mask |= thread_mask;
888 if (relation == RelationAll || relation == RelationProcessorCore)
890 sprintf(name, core_info, i, "thread_siblings_list");
891 f = fopen(name, "r");
892 if (f)
894 fscanf(f, "%d%c", &phys_core, &op);
895 fclose(f);
897 else phys_core = i;
899 if (!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorCore, phys_core, thread_mask))
901 fclose(fcpu_list);
902 return STATUS_NO_MEMORY;
907 if (relation == RelationAll || relation == RelationCache)
909 for(j = 0; j < 4; j++)
911 CACHE_DESCRIPTOR cache;
912 ULONG_PTR mask = 0;
914 sprintf(name, cache_info, i, j, "shared_cpu_map");
915 if(!sysfs_parse_bitmap(name, &mask)) continue;
917 sprintf(name, cache_info, i, j, "level");
918 f = fopen(name, "r");
919 if(!f) continue;
920 fscanf(f, "%u", &r);
921 fclose(f);
922 cache.Level = r;
924 sprintf(name, cache_info, i, j, "ways_of_associativity");
925 f = fopen(name, "r");
926 if(!f) continue;
927 fscanf(f, "%u", &r);
928 fclose(f);
929 cache.Associativity = r;
931 sprintf(name, cache_info, i, j, "coherency_line_size");
932 f = fopen(name, "r");
933 if(!f) continue;
934 fscanf(f, "%u", &r);
935 fclose(f);
936 cache.LineSize = r;
938 sprintf(name, cache_info, i, j, "size");
939 f = fopen(name, "r");
940 if(!f) continue;
941 fscanf(f, "%u%c", &r, &op);
942 fclose(f);
943 if(op != 'K')
944 WARN("unknown cache size %u%c\n", r, op);
945 cache.Size = (op=='K' ? r*1024 : r);
947 sprintf(name, cache_info, i, j, "type");
948 f = fopen(name, "r");
949 if(!f) continue;
950 fscanf(f, "%s", name);
951 fclose(f);
952 if (!memcmp(name, "Data", 5))
953 cache.Type = CacheData;
954 else if(!memcmp(name, "Instruction", 11))
955 cache.Type = CacheInstruction;
956 else
957 cache.Type = CacheUnified;
959 if (!logical_proc_info_add_cache(data, dataex, &len, max_len, mask, &cache))
961 fclose(fcpu_list);
962 return STATUS_NO_MEMORY;
968 fclose(fcpu_list);
970 num_cpus = count_bits(all_cpus_mask);
972 if(relation == RelationAll || relation == RelationNumaNode)
974 fnuma_list = fopen("/sys/devices/system/node/online", "r");
975 if (!fnuma_list)
977 if (!logical_proc_info_add_numa_node(data, dataex, &len, max_len, all_cpus_mask, 0))
978 return STATUS_NO_MEMORY;
980 else
982 while (!feof(fnuma_list))
984 if (!fscanf(fnuma_list, "%u%c ", &beg, &op))
985 break;
986 if (op == '-') fscanf(fnuma_list, "%u%c ", &end, &op);
987 else end = beg;
989 for (i = beg; i <= end; i++)
991 ULONG_PTR mask = 0;
993 sprintf(name, numa_info, i);
994 if (!sysfs_parse_bitmap( name, &mask )) continue;
996 if (!logical_proc_info_add_numa_node(data, dataex, &len, max_len, mask, i))
998 fclose(fnuma_list);
999 return STATUS_NO_MEMORY;
1003 fclose(fnuma_list);
1007 if(dataex && (relation == RelationAll || relation == RelationGroup))
1008 logical_proc_info_add_group(dataex, &len, max_len, num_cpus, all_cpus_mask);
1010 if(data)
1011 *max_len = len * sizeof(**data);
1012 else
1013 *max_len = len;
1015 return STATUS_SUCCESS;
1018 #elif defined(__APPLE__)
1020 /* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
1021 static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data,
1022 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **dataex,
1023 DWORD *max_len, DWORD relation)
1025 DWORD pkgs_no, cores_no, lcpu_no, lcpu_per_core, cores_per_package, assoc, len = 0;
1026 DWORD cache_ctrs[10] = {0};
1027 ULONG_PTR all_cpus_mask = 0;
1028 CACHE_DESCRIPTOR cache[10];
1029 LONGLONG cache_size, cache_line_size, cache_sharing[10];
1030 size_t size;
1031 DWORD p,i,j,k;
1033 if (relation != RelationAll)
1034 FIXME("Relationship filtering not implemented: 0x%x\n", relation);
1036 lcpu_no = peb->NumberOfProcessors;
1038 size = sizeof(pkgs_no);
1039 if (sysctlbyname("hw.packages", &pkgs_no, &size, NULL, 0))
1040 pkgs_no = 1;
1042 size = sizeof(cores_no);
1043 if (sysctlbyname("hw.physicalcpu", &cores_no, &size, NULL, 0))
1044 cores_no = lcpu_no;
1046 TRACE("%u logical CPUs from %u physical cores across %u packages\n",
1047 lcpu_no, cores_no, pkgs_no);
1049 lcpu_per_core = lcpu_no / cores_no;
1050 cores_per_package = cores_no / pkgs_no;
1052 memset(cache, 0, sizeof(cache));
1053 cache[1].Level = 1;
1054 cache[1].Type = CacheInstruction;
1055 cache[1].Associativity = 8; /* reasonable default */
1056 cache[1].LineSize = 0x40; /* reasonable default */
1057 cache[2].Level = 1;
1058 cache[2].Type = CacheData;
1059 cache[2].Associativity = 8;
1060 cache[2].LineSize = 0x40;
1061 cache[3].Level = 2;
1062 cache[3].Type = CacheUnified;
1063 cache[3].Associativity = 8;
1064 cache[3].LineSize = 0x40;
1065 cache[4].Level = 3;
1066 cache[4].Type = CacheUnified;
1067 cache[4].Associativity = 12;
1068 cache[4].LineSize = 0x40;
1070 size = sizeof(cache_line_size);
1071 if (!sysctlbyname("hw.cachelinesize", &cache_line_size, &size, NULL, 0))
1073 for (i = 1; i < 5; i++) cache[i].LineSize = cache_line_size;
1076 /* TODO: set actual associativity for all caches */
1077 size = sizeof(assoc);
1078 if (!sysctlbyname("machdep.cpu.cache.L2_associativity", &assoc, &size, NULL, 0))
1079 cache[3].Associativity = assoc;
1081 size = sizeof(cache_size);
1082 if (!sysctlbyname("hw.l1icachesize", &cache_size, &size, NULL, 0))
1083 cache[1].Size = cache_size;
1084 size = sizeof(cache_size);
1085 if (!sysctlbyname("hw.l1dcachesize", &cache_size, &size, NULL, 0))
1086 cache[2].Size = cache_size;
1087 size = sizeof(cache_size);
1088 if (!sysctlbyname("hw.l2cachesize", &cache_size, &size, NULL, 0))
1089 cache[3].Size = cache_size;
1090 size = sizeof(cache_size);
1091 if (!sysctlbyname("hw.l3cachesize", &cache_size, &size, NULL, 0))
1092 cache[4].Size = cache_size;
1094 size = sizeof(cache_sharing);
1095 if (sysctlbyname("hw.cacheconfig", cache_sharing, &size, NULL, 0) < 0)
1097 cache_sharing[1] = lcpu_per_core;
1098 cache_sharing[2] = lcpu_per_core;
1099 cache_sharing[3] = lcpu_per_core;
1100 cache_sharing[4] = lcpu_no;
1102 else
1104 /* in cache[], indexes 1 and 2 are l1 caches */
1105 cache_sharing[4] = cache_sharing[3];
1106 cache_sharing[3] = cache_sharing[2];
1107 cache_sharing[2] = cache_sharing[1];
1110 for(p = 0; p < pkgs_no; ++p)
1112 for(j = 0; j < cores_per_package && p * cores_per_package + j < cores_no; ++j)
1114 ULONG_PTR mask = 0;
1115 DWORD phys_core;
1117 for(k = 0; k < lcpu_per_core; ++k) mask |= (ULONG_PTR)1 << (j * lcpu_per_core + k);
1119 all_cpus_mask |= mask;
1121 /* add to package */
1122 if(!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorPackage, p, mask))
1123 return STATUS_NO_MEMORY;
1125 /* add new core */
1126 phys_core = p * cores_per_package + j;
1127 if(!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorCore, phys_core, mask))
1128 return STATUS_NO_MEMORY;
1130 for(i = 1; i < 5; ++i)
1132 if(cache_ctrs[i] == 0 && cache[i].Size > 0)
1134 mask = 0;
1135 for(k = 0; k < cache_sharing[i]; ++k)
1136 mask |= (ULONG_PTR)1 << (j * lcpu_per_core + k);
1138 if(!logical_proc_info_add_cache(data, dataex, &len, max_len, mask, &cache[i]))
1139 return STATUS_NO_MEMORY;
1142 cache_ctrs[i] += lcpu_per_core;
1143 if(cache_ctrs[i] == cache_sharing[i]) cache_ctrs[i] = 0;
1148 /* OSX doesn't support NUMA, so just make one NUMA node for all CPUs */
1149 if(!logical_proc_info_add_numa_node(data, dataex, &len, max_len, all_cpus_mask, 0))
1150 return STATUS_NO_MEMORY;
1152 if(dataex) logical_proc_info_add_group(dataex, &len, max_len, lcpu_no, all_cpus_mask);
1154 if(data)
1155 *max_len = len * sizeof(**data);
1156 else
1157 *max_len = len;
1159 return STATUS_SUCCESS;
1162 #else
1164 static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data,
1165 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **dataex,
1166 DWORD *max_len, DWORD relation )
1168 FIXME("stub\n");
1169 return STATUS_NOT_IMPLEMENTED;
1171 #endif
1173 static NTSTATUS create_cpuset_info(SYSTEM_CPU_SET_INFORMATION *info)
1175 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *proc_info;
1176 BYTE core_index, cache_index, max_cache_level;
1177 unsigned int i, j, count;
1178 BYTE *proc_info_buffer;
1179 DWORD cpu_info_size;
1180 ULONG64 cpu_mask;
1181 NTSTATUS status;
1183 count = peb->NumberOfProcessors;
1185 cpu_info_size = 3 * sizeof(*proc_info);
1186 if (!(proc_info_buffer = malloc(cpu_info_size)))
1187 return STATUS_NO_MEMORY;
1189 if ((status = create_logical_proc_info(NULL, (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **)&proc_info_buffer,
1190 &cpu_info_size, RelationAll)))
1192 free(proc_info_buffer);
1193 return status;
1196 max_cache_level = 0;
1197 proc_info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)proc_info_buffer;
1198 for (i = 0; (BYTE *)proc_info != proc_info_buffer + cpu_info_size; ++i)
1200 if (proc_info->Relationship == RelationCache)
1202 if (max_cache_level < proc_info->u.Cache.Level)
1203 max_cache_level = proc_info->u.Cache.Level;
1205 proc_info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((BYTE *)proc_info + proc_info->Size);
1208 memset(info, 0, count * sizeof(*info));
1210 core_index = 0;
1211 cache_index = 0;
1212 proc_info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)proc_info_buffer;
1213 for (i = 0; i < count; ++i)
1215 info[i].Size = sizeof(*info);
1216 info[i].Type = CpuSetInformation;
1217 info[i].u.CpuSet.Id = 0x100 + i;
1218 info[i].u.CpuSet.LogicalProcessorIndex = i;
1221 for (i = 0; (BYTE *)proc_info != (BYTE *)proc_info_buffer + cpu_info_size; ++i)
1223 if (proc_info->Relationship == RelationProcessorCore)
1225 if (proc_info->u.Processor.GroupCount != 1)
1227 FIXME("Unsupported group count %u.\n", proc_info->u.Processor.GroupCount);
1228 continue;
1230 cpu_mask = proc_info->u.Processor.GroupMask[0].Mask;
1231 for (j = 0; j < count; ++j)
1232 if (((ULONG64)1 << j) & cpu_mask)
1234 info[j].u.CpuSet.CoreIndex = core_index;
1235 info[j].u.CpuSet.EfficiencyClass = proc_info->u.Processor.EfficiencyClass;
1237 ++core_index;
1239 else if (proc_info->Relationship == RelationCache)
1241 if (proc_info->u.Cache.Level == max_cache_level)
1243 cpu_mask = proc_info->u.Cache.GroupMask.Mask;
1244 for (j = 0; j < count; ++j)
1245 if (((ULONG64)1 << j) & cpu_mask)
1246 info[j].u.CpuSet.LastLevelCacheIndex = cache_index;
1248 ++cache_index;
1250 else if (proc_info->Relationship == RelationNumaNode)
1252 cpu_mask = proc_info->u.NumaNode.GroupMask.Mask;
1253 for (j = 0; j < count; ++j)
1254 if (((ULONG64)1 << j) & cpu_mask)
1255 info[j].u.CpuSet.NumaNodeIndex = proc_info->u.NumaNode.NodeNumber;
1257 proc_info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((BYTE *)proc_info + proc_info->Size);
1260 free(proc_info_buffer);
1262 return STATUS_SUCCESS;
1265 #ifdef linux
1267 static void copy_smbios_string( char **buffer, char *s, size_t len )
1269 if (!len) return;
1270 memcpy(*buffer, s, len + 1);
1271 *buffer += len + 1;
1274 static size_t get_smbios_string( const char *path, char *str, size_t size )
1276 FILE *file;
1277 size_t len;
1279 if (!(file = fopen(path, "r"))) return 0;
1281 len = fread( str, 1, size - 1, file );
1282 fclose( file );
1284 if (len >= 1 && str[len - 1] == '\n') len--;
1285 str[len] = 0;
1286 return len;
1289 static void get_system_uuid( GUID *uuid )
1291 static const unsigned char hex[] =
1293 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
1294 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
1295 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
1296 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
1297 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
1298 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
1299 0,10,11,12,13,14,15 /* 0x60 */
1301 int fd;
1303 memset( uuid, 0xff, sizeof(*uuid) );
1304 if ((fd = open( "/var/lib/dbus/machine-id", O_RDONLY )) != -1)
1306 unsigned char buf[32], *p = buf;
1307 if (read( fd, buf, sizeof(buf) ) == sizeof(buf))
1309 uuid->Data1 = hex[p[6]] << 28 | hex[p[7]] << 24 | hex[p[4]] << 20 | hex[p[5]] << 16 |
1310 hex[p[2]] << 12 | hex[p[3]] << 8 | hex[p[0]] << 4 | hex[p[1]];
1312 uuid->Data2 = hex[p[10]] << 12 | hex[p[11]] << 8 | hex[p[8]] << 4 | hex[p[9]];
1313 uuid->Data3 = hex[p[14]] << 12 | hex[p[15]] << 8 | hex[p[12]] << 4 | hex[p[13]];
1315 uuid->Data4[0] = hex[p[16]] << 4 | hex[p[17]];
1316 uuid->Data4[1] = hex[p[18]] << 4 | hex[p[19]];
1317 uuid->Data4[2] = hex[p[20]] << 4 | hex[p[21]];
1318 uuid->Data4[3] = hex[p[22]] << 4 | hex[p[23]];
1319 uuid->Data4[4] = hex[p[24]] << 4 | hex[p[25]];
1320 uuid->Data4[5] = hex[p[26]] << 4 | hex[p[27]];
1321 uuid->Data4[6] = hex[p[28]] << 4 | hex[p[29]];
1322 uuid->Data4[7] = hex[p[30]] << 4 | hex[p[31]];
1324 close( fd );
1328 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1329 ULONG *required_len )
1331 switch (sfti->ProviderSignature)
1333 case RSMB:
1335 char bios_vendor[128], bios_version[128], bios_date[128];
1336 size_t bios_vendor_len, bios_version_len, bios_date_len;
1337 char system_vendor[128], system_product[128], system_version[128], system_serial[128];
1338 size_t system_vendor_len, system_product_len, system_version_len, system_serial_len;
1339 char system_sku[128], system_family[128];
1340 size_t system_sku_len, system_family_len;
1341 char board_vendor[128], board_product[128], board_version[128], board_serial[128], board_asset_tag[128];
1342 size_t board_vendor_len, board_product_len, board_version_len, board_serial_len, board_asset_tag_len;
1343 char chassis_vendor[128], chassis_version[128], chassis_serial[128], chassis_asset_tag[128];
1344 char chassis_type[11] = "2"; /* unknown */
1345 size_t chassis_vendor_len, chassis_version_len, chassis_serial_len, chassis_asset_tag_len;
1346 char *buffer = (char*)sfti->TableBuffer;
1347 BYTE string_count;
1348 BYTE handle_count = 0;
1349 struct smbios_prologue *prologue;
1350 struct smbios_bios *bios;
1351 struct smbios_system *system;
1352 struct smbios_board *board;
1353 struct smbios_chassis *chassis;
1354 struct smbios_boot_info *boot_info;
1355 struct smbios_header *end_of_table;
1357 #define S(s) s, sizeof(s)
1358 bios_vendor_len = get_smbios_string("/sys/class/dmi/id/bios_vendor", S(bios_vendor));
1359 bios_version_len = get_smbios_string("/sys/class/dmi/id/bios_version", S(bios_version));
1360 bios_date_len = get_smbios_string("/sys/class/dmi/id/bios_date", S(bios_date));
1361 system_vendor_len = get_smbios_string("/sys/class/dmi/id/sys_vendor", S(system_vendor));
1362 system_product_len = get_smbios_string("/sys/class/dmi/id/product_name", S(system_product));
1363 system_version_len = get_smbios_string("/sys/class/dmi/id/product_version", S(system_version));
1364 system_serial_len = get_smbios_string("/sys/class/dmi/id/product_serial", S(system_serial));
1365 system_sku_len = get_smbios_string("/sys/class/dmi/id/product_sku", S(system_sku));
1366 system_family_len = get_smbios_string("/sys/class/dmi/id/product_family", S(system_family));
1367 board_vendor_len = get_smbios_string("/sys/class/dmi/id/board_vendor", S(board_vendor));
1368 board_product_len = get_smbios_string("/sys/class/dmi/id/board_name", S(board_product));
1369 board_version_len = get_smbios_string("/sys/class/dmi/id/board_version", S(board_version));
1370 board_serial_len = get_smbios_string("/sys/class/dmi/id/board_serial", S(board_serial));
1371 board_asset_tag_len = get_smbios_string("/sys/class/dmi/id/board_asset_tag", S(board_asset_tag));
1372 chassis_vendor_len = get_smbios_string("/sys/class/dmi/id/chassis_vendor", S(chassis_vendor));
1373 chassis_version_len = get_smbios_string("/sys/class/dmi/id/chassis_version", S(chassis_version));
1374 chassis_serial_len = get_smbios_string("/sys/class/dmi/id/chassis_serial", S(chassis_serial));
1375 chassis_asset_tag_len = get_smbios_string("/sys/class/dmi/id/chassis_tag", S(chassis_asset_tag));
1376 get_smbios_string("/sys/class/dmi/id/chassis_type", S(chassis_type));
1377 #undef S
1379 *required_len = sizeof(struct smbios_prologue);
1381 #define L(l) (l + (l ? 1 : 0))
1382 *required_len += sizeof(struct smbios_bios);
1383 *required_len += max(L(bios_vendor_len) + L(bios_version_len) + L(bios_date_len) + 1, 2);
1385 *required_len += sizeof(struct smbios_system);
1386 *required_len += max(L(system_vendor_len) + L(system_product_len) + L(system_version_len) +
1387 L(system_serial_len) + L(system_sku_len) + L(system_family_len) + 1, 2);
1389 *required_len += sizeof(struct smbios_board);
1390 *required_len += max(L(board_vendor_len) + L(board_product_len) + L(board_version_len) +
1391 L(board_serial_len) + L(board_asset_tag_len) + 1, 2);
1393 *required_len += sizeof(struct smbios_chassis);
1394 *required_len += max(L(chassis_vendor_len) + L(chassis_version_len) + L(chassis_serial_len) +
1395 L(chassis_asset_tag_len) + 1, 2);
1397 *required_len += sizeof(struct smbios_boot_info);
1398 *required_len += 2;
1400 *required_len += sizeof(struct smbios_header);
1401 *required_len += 2;
1402 #undef L
1404 sfti->TableBufferLength = *required_len;
1406 *required_len += FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
1408 if (available_len < *required_len)
1409 return STATUS_BUFFER_TOO_SMALL;
1411 prologue = (struct smbios_prologue*)buffer;
1412 prologue->calling_method = 0;
1413 prologue->major_version = 2;
1414 prologue->minor_version = 4;
1415 prologue->revision = 0;
1416 prologue->length = sfti->TableBufferLength - sizeof(struct smbios_prologue);
1417 buffer += sizeof(struct smbios_prologue);
1419 string_count = 0;
1420 bios = (struct smbios_bios*)buffer;
1421 bios->hdr.type = 0;
1422 bios->hdr.length = sizeof(struct smbios_bios);
1423 bios->hdr.handle = handle_count++;
1424 bios->vendor = bios_vendor_len ? ++string_count : 0;
1425 bios->version = bios_version_len ? ++string_count : 0;
1426 bios->start = 0;
1427 bios->date = bios_date_len ? ++string_count : 0;
1428 bios->size = 0;
1429 bios->characteristics = 0x4; /* not supported */
1430 bios->characteristics_ext[0] = 0;
1431 bios->characteristics_ext[1] = 0;
1432 bios->system_bios_major_release = 0xFF; /* not supported */
1433 bios->system_bios_minor_release = 0xFF; /* not supported */
1434 bios->ec_firmware_major_release = 0xFF; /* not supported */
1435 bios->ec_firmware_minor_release = 0xFF; /* not supported */
1436 buffer += sizeof(struct smbios_bios);
1438 copy_smbios_string(&buffer, bios_vendor, bios_vendor_len);
1439 copy_smbios_string(&buffer, bios_version, bios_version_len);
1440 copy_smbios_string(&buffer, bios_date, bios_date_len);
1441 if (!string_count) *buffer++ = 0;
1442 *buffer++ = 0;
1444 string_count = 0;
1445 system = (struct smbios_system*)buffer;
1446 system->hdr.type = 1;
1447 system->hdr.length = sizeof(struct smbios_system);
1448 system->hdr.handle = handle_count++;
1449 system->vendor = system_vendor_len ? ++string_count : 0;
1450 system->product = system_product_len ? ++string_count : 0;
1451 system->version = system_version_len ? ++string_count : 0;
1452 system->serial = system_serial_len ? ++string_count : 0;
1453 get_system_uuid( (GUID *)system->uuid );
1454 system->wake_up_type = 0x02; /* unknown */
1455 system->sku_number = system_sku_len ? ++string_count : 0;
1456 system->family = system_family_len ? ++string_count : 0;
1457 buffer += sizeof(struct smbios_system);
1459 copy_smbios_string(&buffer, system_vendor, system_vendor_len);
1460 copy_smbios_string(&buffer, system_product, system_product_len);
1461 copy_smbios_string(&buffer, system_version, system_version_len);
1462 copy_smbios_string(&buffer, system_serial, system_serial_len);
1463 copy_smbios_string(&buffer, system_sku, system_sku_len);
1464 copy_smbios_string(&buffer, system_family, system_family_len);
1465 if (!string_count) *buffer++ = 0;
1466 *buffer++ = 0;
1468 string_count = 0;
1469 chassis = (struct smbios_chassis*)buffer;
1470 chassis->hdr.type = 3;
1471 chassis->hdr.length = sizeof(struct smbios_chassis);
1472 chassis->hdr.handle = handle_count++;
1473 chassis->vendor = chassis_vendor_len ? ++string_count : 0;
1474 chassis->type = atoi(chassis_type);
1475 chassis->version = chassis_version_len ? ++string_count : 0;
1476 chassis->serial = chassis_serial_len ? ++string_count : 0;
1477 chassis->asset_tag = chassis_asset_tag_len ? ++string_count : 0;
1478 chassis->boot_state = 0x02; /* unknown */
1479 chassis->power_supply_state = 0x02; /* unknown */
1480 chassis->thermal_state = 0x02; /* unknown */
1481 chassis->security_status = 0x02; /* unknown */
1482 chassis->oem_defined = 0;
1483 chassis->height = 0; /* undefined */
1484 chassis->num_power_cords = 0; /* unspecified */
1485 chassis->num_contained_elements = 0;
1486 chassis->contained_element_rec_length = 3;
1487 buffer += sizeof(struct smbios_chassis);
1489 copy_smbios_string(&buffer, chassis_vendor, chassis_vendor_len);
1490 copy_smbios_string(&buffer, chassis_version, chassis_version_len);
1491 copy_smbios_string(&buffer, chassis_serial, chassis_serial_len);
1492 copy_smbios_string(&buffer, chassis_asset_tag, chassis_asset_tag_len);
1493 if (!string_count) *buffer++ = 0;
1494 *buffer++ = 0;
1496 string_count = 0;
1497 board = (struct smbios_board*)buffer;
1498 board->hdr.type = 2;
1499 board->hdr.length = sizeof(struct smbios_board);
1500 board->hdr.handle = handle_count++;
1501 board->vendor = board_vendor_len ? ++string_count : 0;
1502 board->product = board_product_len ? ++string_count : 0;
1503 board->version = board_version_len ? ++string_count : 0;
1504 board->serial = board_serial_len ? ++string_count : 0;
1505 board->asset_tag = board_asset_tag_len ? ++string_count : 0;
1506 board->feature_flags = 0x5; /* hosting board, removable */
1507 board->location = 0;
1508 board->chassis_handle = chassis->hdr.handle;
1509 board->board_type = 0xa; /* motherboard */
1510 board->num_contained_handles = 0;
1511 buffer += sizeof(struct smbios_board);
1513 copy_smbios_string(&buffer, board_vendor, board_vendor_len);
1514 copy_smbios_string(&buffer, board_product, board_product_len);
1515 copy_smbios_string(&buffer, board_version, board_version_len);
1516 copy_smbios_string(&buffer, board_serial, board_serial_len);
1517 copy_smbios_string(&buffer, board_asset_tag, board_asset_tag_len);
1518 if (!string_count) *buffer++ = 0;
1519 *buffer++ = 0;
1521 boot_info = (struct smbios_boot_info*)buffer;
1522 boot_info->hdr.type = 32;
1523 boot_info->hdr.length = sizeof(struct smbios_boot_info);
1524 boot_info->hdr.handle = handle_count++;
1525 memset(boot_info->reserved, 0, sizeof(boot_info->reserved));
1526 memset(boot_info->boot_status, 0, sizeof(boot_info->boot_status)); /* no errors detected */
1527 buffer += sizeof(struct smbios_boot_info);
1528 *buffer++ = 0;
1529 *buffer++ = 0;
1531 end_of_table = (struct smbios_header*)buffer;
1532 end_of_table->type = 127;
1533 end_of_table->length = sizeof(struct smbios_header);
1534 end_of_table->handle = handle_count++;
1535 buffer += sizeof(struct smbios_header);
1536 *buffer++ = 0;
1537 *buffer++ = 0;
1539 return STATUS_SUCCESS;
1541 default:
1542 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION provider %08x\n", sfti->ProviderSignature);
1543 return STATUS_NOT_IMPLEMENTED;
1547 #elif defined(__APPLE__)
1549 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1550 ULONG *required_len )
1552 switch (sfti->ProviderSignature)
1554 case RSMB:
1556 io_service_t service;
1557 CFDataRef data;
1558 const UInt8 *ptr;
1559 CFIndex len;
1560 struct smbios_prologue *prologue;
1561 BYTE major_version = 2, minor_version = 0;
1563 if (!(service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleSMBIOS"))))
1565 WARN("can't find AppleSMBIOS service\n");
1566 return STATUS_NO_MEMORY;
1569 if (!(data = IORegistryEntryCreateCFProperty(service, CFSTR("SMBIOS-EPS"), kCFAllocatorDefault, 0)))
1571 WARN("can't find SMBIOS entry point\n");
1572 IOObjectRelease(service);
1573 return STATUS_NO_MEMORY;
1576 len = CFDataGetLength(data);
1577 ptr = CFDataGetBytePtr(data);
1578 if (len >= 8 && !memcmp(ptr, "_SM_", 4))
1580 major_version = ptr[6];
1581 minor_version = ptr[7];
1583 CFRelease(data);
1585 if (!(data = IORegistryEntryCreateCFProperty(service, CFSTR("SMBIOS"), kCFAllocatorDefault, 0)))
1587 WARN("can't find SMBIOS table\n");
1588 IOObjectRelease(service);
1589 return STATUS_NO_MEMORY;
1592 len = CFDataGetLength(data);
1593 ptr = CFDataGetBytePtr(data);
1594 sfti->TableBufferLength = sizeof(*prologue) + len;
1595 *required_len = sfti->TableBufferLength + FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
1596 if (available_len < *required_len)
1598 CFRelease(data);
1599 IOObjectRelease(service);
1600 return STATUS_BUFFER_TOO_SMALL;
1603 prologue = (struct smbios_prologue *)sfti->TableBuffer;
1604 prologue->calling_method = 0;
1605 prologue->major_version = major_version;
1606 prologue->minor_version = minor_version;
1607 prologue->revision = 0;
1608 prologue->length = sfti->TableBufferLength - sizeof(*prologue);
1610 memcpy(sfti->TableBuffer + sizeof(*prologue), ptr, len);
1612 CFRelease(data);
1613 IOObjectRelease(service);
1614 return STATUS_SUCCESS;
1616 default:
1617 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION provider %08x\n", sfti->ProviderSignature);
1618 return STATUS_NOT_IMPLEMENTED;
1622 #else
1624 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1625 ULONG *required_len )
1627 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION\n");
1628 sfti->TableBufferLength = 0;
1629 return STATUS_NOT_IMPLEMENTED;
1632 #endif
1634 static void get_performance_info( SYSTEM_PERFORMANCE_INFORMATION *info )
1636 unsigned long long totalram = 0, freeram = 0, totalswap = 0, freeswap = 0;
1637 FILE *fp;
1639 memset( info, 0, sizeof(*info) );
1641 if ((fp = fopen("/proc/uptime", "r")))
1643 double uptime, idle_time;
1645 fscanf(fp, "%lf %lf", &uptime, &idle_time);
1646 fclose(fp);
1647 info->IdleTime.QuadPart = 10000000 * idle_time;
1649 else
1651 static ULONGLONG idle;
1652 /* many programs expect IdleTime to change so fake change */
1653 info->IdleTime.QuadPart = ++idle;
1656 #ifdef linux
1657 if ((fp = fopen("/proc/meminfo", "r")))
1659 unsigned long long value;
1660 char line[64];
1662 while (fgets(line, sizeof(line), fp))
1664 if(sscanf(line, "MemTotal: %llu kB", &value) == 1)
1665 totalram += value * 1024;
1666 else if(sscanf(line, "MemFree: %llu kB", &value) == 1)
1667 freeram += value * 1024;
1668 else if(sscanf(line, "SwapTotal: %llu kB", &value) == 1)
1669 totalswap += value * 1024;
1670 else if(sscanf(line, "SwapFree: %llu kB", &value) == 1)
1671 freeswap += value * 1024;
1672 else if (sscanf(line, "Buffers: %llu", &value))
1673 freeram += value * 1024;
1674 else if (sscanf(line, "Cached: %llu", &value))
1675 freeram += value * 1024;
1677 fclose(fp);
1679 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || \
1680 defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
1682 #ifdef __APPLE__
1683 unsigned int val;
1684 #else
1685 unsigned long val;
1686 #endif
1687 int mib[2];
1688 size_t size_sys;
1690 mib[0] = CTL_HW;
1691 #ifdef HW_MEMSIZE
1693 uint64_t val64;
1694 mib[1] = HW_MEMSIZE;
1695 size_sys = sizeof(val64);
1696 if (!sysctl(mib, 2, &val64, &size_sys, NULL, 0) && size_sys == sizeof(val64)) totalram = val64;
1698 #endif
1700 #ifdef HAVE_MACH_MACH_H
1702 host_name_port_t host = mach_host_self();
1703 mach_msg_type_number_t count;
1704 #ifdef HOST_VM_INFO64_COUNT
1705 vm_statistics64_data_t vm_stat;
1707 count = HOST_VM_INFO64_COUNT;
1708 if (host_statistics64(host, HOST_VM_INFO64, (host_info64_t)&vm_stat, &count) == KERN_SUCCESS)
1709 freeram = (vm_stat.free_count + vm_stat.inactive_count) * (ULONGLONG)page_size;
1710 #endif
1711 if (!totalram)
1713 host_basic_info_data_t info;
1714 count = HOST_BASIC_INFO_COUNT;
1715 if (host_info(host, HOST_BASIC_INFO, (host_info_t)&info, &count) == KERN_SUCCESS)
1716 totalram = info.max_mem;
1718 mach_port_deallocate(mach_task_self(), host);
1720 #endif
1722 if (!totalram)
1724 mib[1] = HW_PHYSMEM;
1725 size_sys = sizeof(val);
1726 if (!sysctl(mib, 2, &val, &size_sys, NULL, 0) && size_sys == sizeof(val)) totalram = val;
1728 if (!freeram)
1730 mib[1] = HW_USERMEM;
1731 size_sys = sizeof(val);
1732 if (!sysctl(mib, 2, &val, &size_sys, NULL, 0) && size_sys == sizeof(val)) freeram = val;
1734 #ifdef VM_SWAPUSAGE
1736 struct xsw_usage swap;
1737 mib[0] = CTL_VM;
1738 mib[1] = VM_SWAPUSAGE;
1739 size_sys = sizeof(swap);
1740 if (!sysctl(mib, 2, &swap, &size_sys, NULL, 0) && size_sys == sizeof(swap))
1742 totalswap = swap.xsu_total;
1743 freeswap = swap.xsu_avail;
1746 #endif
1748 #endif
1749 info->AvailablePages = freeram / page_size;
1750 info->TotalCommittedPages = (totalram + totalswap - freeram - freeswap) / page_size;
1751 info->TotalCommitLimit = (totalram + totalswap) / page_size;
1755 /* calculate the mday of dst change date, so that for instance Sun 5 Oct 2007
1756 * (last Sunday in October of 2007) becomes Sun Oct 28 2007
1758 * Note: year, day and month must be in unix format.
1760 static int weekday_to_mday(int year, int day, int mon, int day_of_week)
1762 struct tm date;
1763 time_t tmp;
1764 int wday, mday;
1766 /* find first day in the month matching week day of the date */
1767 memset(&date, 0, sizeof(date));
1768 date.tm_year = year;
1769 date.tm_mon = mon;
1770 date.tm_mday = -1;
1771 date.tm_wday = -1;
1774 date.tm_mday++;
1775 tmp = mktime(&date);
1776 } while (date.tm_wday != day_of_week || date.tm_mon != mon);
1778 mday = date.tm_mday;
1780 /* find number of week days in the month matching week day of the date */
1781 wday = 1; /* 1 - 1st, ...., 5 - last */
1782 while (wday < day)
1784 struct tm *tm;
1786 date.tm_mday += 7;
1787 tmp = mktime(&date);
1788 tm = localtime(&tmp);
1789 if (tm->tm_mon != mon)
1790 break;
1791 mday = tm->tm_mday;
1792 wday++;
1795 return mday;
1798 static BOOL match_tz_date( const RTL_SYSTEM_TIME *st, const RTL_SYSTEM_TIME *reg_st )
1800 WORD wDay;
1802 if (st->wMonth != reg_st->wMonth) return FALSE;
1803 if (!st->wMonth) return TRUE; /* no transition dates */
1804 wDay = reg_st->wDay;
1805 if (!reg_st->wYear) /* date in a day-of-week format */
1806 wDay = weekday_to_mday(st->wYear - 1900, reg_st->wDay, reg_st->wMonth - 1, reg_st->wDayOfWeek);
1808 return (st->wDay == wDay &&
1809 st->wHour == reg_st->wHour &&
1810 st->wMinute == reg_st->wMinute &&
1811 st->wSecond == reg_st->wSecond &&
1812 st->wMilliseconds == reg_st->wMilliseconds);
1815 static BOOL match_tz_info( const RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi,
1816 const RTL_DYNAMIC_TIME_ZONE_INFORMATION *reg_tzi )
1818 return (tzi->Bias == reg_tzi->Bias &&
1819 match_tz_date(&tzi->StandardDate, &reg_tzi->StandardDate) &&
1820 match_tz_date(&tzi->DaylightDate, &reg_tzi->DaylightDate));
1823 static BOOL match_past_tz_bias( time_t past_time, LONG past_bias )
1825 LONG bias;
1826 struct tm *tm;
1827 if (!past_time) return TRUE;
1829 tm = gmtime( &past_time );
1830 bias = (LONG)(mktime(tm) - past_time) / 60;
1831 return bias == past_bias;
1834 static BOOL match_tz_name( const char *tz_name, const RTL_DYNAMIC_TIME_ZONE_INFORMATION *reg_tzi )
1836 static const struct {
1837 WCHAR key_name[32];
1838 const char *short_name;
1839 time_t past_time;
1840 LONG past_bias;
1842 mapping[] =
1844 { {'N','o','r','t','h',' ','K','o','r','e','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
1845 "KST", 1451606400 /* 2016-01-01 00:00:00 UTC */, -510 },
1846 { {'K','o','r','e','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
1847 "KST", 1451606400 /* 2016-01-01 00:00:00 UTC */, -540 },
1848 { {'T','o','k','y','o',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
1849 "JST" },
1850 { {'Y','a','k','u','t','s','k',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
1851 "+09" }, /* YAKST was used until tzdata 2016f */
1853 unsigned int i;
1855 if (reg_tzi->DaylightDate.wMonth) return TRUE;
1856 for (i = 0; i < ARRAY_SIZE(mapping); i++)
1858 if (!wcscmp( mapping[i].key_name, reg_tzi->TimeZoneKeyName ))
1859 return !strcmp( mapping[i].short_name, tz_name )
1860 && match_past_tz_bias( mapping[i].past_time, mapping[i].past_bias );
1862 return TRUE;
1865 static BOOL reg_query_value( HKEY key, LPCWSTR name, DWORD type, void *data, DWORD count )
1867 char buf[256];
1868 UNICODE_STRING nameW;
1869 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buf;
1871 if (count > sizeof(buf) - sizeof(KEY_VALUE_PARTIAL_INFORMATION)) return FALSE;
1873 nameW.Buffer = (WCHAR *)name;
1874 nameW.Length = wcslen( name ) * sizeof(WCHAR);
1875 if (NtQueryValueKey( key, &nameW, KeyValuePartialInformation, buf, sizeof(buf), &count ))
1876 return FALSE;
1878 if (info->Type != type) return FALSE;
1879 memcpy( data, info->Data, info->DataLength );
1880 return TRUE;
1883 static void find_reg_tz_info(RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi, const char* tz_name, int year)
1885 static const WCHAR stdW[] = { 'S','t','d',0 };
1886 static const WCHAR dltW[] = { 'D','l','t',0 };
1887 static const WCHAR mui_stdW[] = { 'M','U','I','_','S','t','d',0 };
1888 static const WCHAR mui_dltW[] = { 'M','U','I','_','D','l','t',0 };
1889 static const WCHAR tziW[] = { 'T','Z','I',0 };
1890 static const WCHAR Time_ZonesW[] = { 'M','a','c','h','i','n','e','\\',
1891 'S','o','f','t','w','a','r','e','\\',
1892 'M','i','c','r','o','s','o','f','t','\\',
1893 'W','i','n','d','o','w','s',' ','N','T','\\',
1894 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1895 'T','i','m','e',' ','Z','o','n','e','s',0 };
1896 static const WCHAR Dynamic_DstW[] = { 'D','y','n','a','m','i','c',' ','D','S','T',0 };
1897 RTL_DYNAMIC_TIME_ZONE_INFORMATION reg_tzi;
1898 HANDLE key, subkey, subkey_dyn = 0;
1899 ULONG idx, len;
1900 OBJECT_ATTRIBUTES attr;
1901 UNICODE_STRING nameW;
1902 WCHAR yearW[16];
1903 char buffer[128];
1904 KEY_BASIC_INFORMATION *info = (KEY_BASIC_INFORMATION *)buffer;
1906 sprintf( buffer, "%u", year );
1907 ascii_to_unicode( yearW, buffer, strlen(buffer) + 1 );
1908 init_unicode_string( &nameW, Time_ZonesW );
1909 InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
1910 if (NtOpenKey( &key, KEY_READ, &attr )) return;
1912 idx = 0;
1913 while (!NtEnumerateKey( key, idx++, KeyBasicInformation, buffer, sizeof(buffer), &len ))
1915 struct tz_reg_data
1917 LONG bias;
1918 LONG std_bias;
1919 LONG dlt_bias;
1920 RTL_SYSTEM_TIME std_date;
1921 RTL_SYSTEM_TIME dlt_date;
1922 } tz_data;
1923 BOOL is_dynamic = FALSE;
1925 nameW.Buffer = info->Name;
1926 nameW.Length = info->NameLength;
1927 attr.RootDirectory = key;
1928 if (NtOpenKey( &subkey, KEY_READ, &attr )) continue;
1930 memset( &reg_tzi, 0, sizeof(reg_tzi) );
1931 memcpy(reg_tzi.TimeZoneKeyName, nameW.Buffer, nameW.Length);
1932 reg_tzi.TimeZoneKeyName[nameW.Length/sizeof(WCHAR)] = 0;
1934 if (!reg_query_value(subkey, mui_stdW, REG_SZ, reg_tzi.StandardName, sizeof(reg_tzi.StandardName)) &&
1935 !reg_query_value(subkey, stdW, REG_SZ, reg_tzi.StandardName, sizeof(reg_tzi.StandardName)))
1936 goto next;
1938 if (!reg_query_value(subkey, mui_dltW, REG_SZ, reg_tzi.DaylightName, sizeof(reg_tzi.DaylightName)) &&
1939 !reg_query_value(subkey, dltW, REG_SZ, reg_tzi.DaylightName, sizeof(reg_tzi.DaylightName)))
1940 goto next;
1942 /* Check for Dynamic DST entry first */
1943 nameW.Buffer = (WCHAR *)Dynamic_DstW;
1944 nameW.Length = sizeof(Dynamic_DstW) - sizeof(WCHAR);
1945 attr.RootDirectory = subkey;
1946 if (!NtOpenKey( &subkey_dyn, KEY_READ, &attr ))
1948 is_dynamic = reg_query_value( subkey_dyn, yearW, REG_BINARY, &tz_data, sizeof(tz_data) );
1949 NtClose( subkey_dyn );
1951 if (!is_dynamic && !reg_query_value( subkey, tziW, REG_BINARY, &tz_data, sizeof(tz_data) ))
1952 goto next;
1954 reg_tzi.Bias = tz_data.bias;
1955 reg_tzi.StandardBias = tz_data.std_bias;
1956 reg_tzi.DaylightBias = tz_data.dlt_bias;
1957 reg_tzi.StandardDate = tz_data.std_date;
1958 reg_tzi.DaylightDate = tz_data.dlt_date;
1960 TRACE("%s: bias %d\n", debugstr_us(&nameW), reg_tzi.Bias);
1961 TRACE("std (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
1962 reg_tzi.StandardDate.wDay, reg_tzi.StandardDate.wMonth,
1963 reg_tzi.StandardDate.wYear, reg_tzi.StandardDate.wDayOfWeek,
1964 reg_tzi.StandardDate.wHour, reg_tzi.StandardDate.wMinute,
1965 reg_tzi.StandardDate.wSecond, reg_tzi.StandardDate.wMilliseconds,
1966 reg_tzi.StandardBias);
1967 TRACE("dst (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
1968 reg_tzi.DaylightDate.wDay, reg_tzi.DaylightDate.wMonth,
1969 reg_tzi.DaylightDate.wYear, reg_tzi.DaylightDate.wDayOfWeek,
1970 reg_tzi.DaylightDate.wHour, reg_tzi.DaylightDate.wMinute,
1971 reg_tzi.DaylightDate.wSecond, reg_tzi.DaylightDate.wMilliseconds,
1972 reg_tzi.DaylightBias);
1974 if (match_tz_info( tzi, &reg_tzi ) && match_tz_name( tz_name, &reg_tzi ))
1976 *tzi = reg_tzi;
1977 NtClose( subkey );
1978 NtClose( key );
1979 return;
1981 next:
1982 NtClose( subkey );
1984 NtClose( key );
1986 if (idx == 1) return; /* registry info not initialized yet */
1988 FIXME("Can't find matching timezone information in the registry for "
1989 "%s, bias %d, std (d/m/y): %u/%02u/%04u, dlt (d/m/y): %u/%02u/%04u\n",
1990 tz_name, tzi->Bias,
1991 tzi->StandardDate.wDay, tzi->StandardDate.wMonth, tzi->StandardDate.wYear,
1992 tzi->DaylightDate.wDay, tzi->DaylightDate.wMonth, tzi->DaylightDate.wYear);
1995 static time_t find_dst_change(unsigned long min, unsigned long max, int *is_dst)
1997 time_t start;
1998 struct tm *tm;
2000 start = min;
2001 tm = localtime(&start);
2002 *is_dst = !tm->tm_isdst;
2003 TRACE("starting date isdst %d, %s", !*is_dst, ctime(&start));
2005 while (min <= max)
2007 time_t pos = (min + max) / 2;
2008 tm = localtime(&pos);
2010 if (tm->tm_isdst != *is_dst)
2011 min = pos + 1;
2012 else
2013 max = pos - 1;
2015 return min;
2018 static void get_timezone_info( RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi )
2020 static pthread_mutex_t tz_mutex = PTHREAD_MUTEX_INITIALIZER;
2021 static RTL_DYNAMIC_TIME_ZONE_INFORMATION cached_tzi;
2022 static int current_year = -1, current_bias = 65535;
2023 struct tm *tm;
2024 char tz_name[16];
2025 time_t year_start, year_end, tmp, dlt = 0, std = 0;
2026 int is_dst, bias;
2028 mutex_lock( &tz_mutex );
2030 year_start = time(NULL);
2031 tm = gmtime(&year_start);
2032 bias = (LONG)(mktime(tm) - year_start) / 60;
2034 tm = localtime(&year_start);
2035 if (current_year == tm->tm_year && current_bias == bias)
2037 *tzi = cached_tzi;
2038 mutex_unlock( &tz_mutex );
2039 return;
2042 memset(tzi, 0, sizeof(*tzi));
2043 if (!strftime(tz_name, sizeof(tz_name), "%Z", tm)) {
2044 /* not enough room or another error */
2045 tz_name[0] = '\0';
2048 TRACE("tz data will be valid through year %d, bias %d\n", tm->tm_year + 1900, bias);
2049 current_year = tm->tm_year;
2050 current_bias = bias;
2052 tzi->Bias = bias;
2054 tm->tm_isdst = 0;
2055 tm->tm_mday = 1;
2056 tm->tm_mon = tm->tm_hour = tm->tm_min = tm->tm_sec = tm->tm_wday = tm->tm_yday = 0;
2057 year_start = mktime(tm);
2058 TRACE("year_start: %s", ctime(&year_start));
2060 tm->tm_mday = tm->tm_wday = tm->tm_yday = 0;
2061 tm->tm_mon = 12;
2062 tm->tm_hour = 23;
2063 tm->tm_min = tm->tm_sec = 59;
2064 year_end = mktime(tm);
2065 TRACE("year_end: %s", ctime(&year_end));
2067 tmp = find_dst_change(year_start, year_end, &is_dst);
2068 if (is_dst)
2069 dlt = tmp;
2070 else
2071 std = tmp;
2073 tmp = find_dst_change(tmp, year_end, &is_dst);
2074 if (is_dst)
2075 dlt = tmp;
2076 else
2077 std = tmp;
2079 TRACE("std: %s", ctime(&std));
2080 TRACE("dlt: %s", ctime(&dlt));
2082 if (dlt == std || !dlt || !std)
2083 TRACE("there is no daylight saving rules in this time zone\n");
2084 else
2086 tmp = dlt - tzi->Bias * 60;
2087 tm = gmtime(&tmp);
2088 TRACE("dlt gmtime: %s", asctime(tm));
2090 tzi->DaylightBias = -60;
2091 tzi->DaylightDate.wYear = tm->tm_year + 1900;
2092 tzi->DaylightDate.wMonth = tm->tm_mon + 1;
2093 tzi->DaylightDate.wDayOfWeek = tm->tm_wday;
2094 tzi->DaylightDate.wDay = tm->tm_mday;
2095 tzi->DaylightDate.wHour = tm->tm_hour;
2096 tzi->DaylightDate.wMinute = tm->tm_min;
2097 tzi->DaylightDate.wSecond = tm->tm_sec;
2098 tzi->DaylightDate.wMilliseconds = 0;
2100 TRACE("daylight (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
2101 tzi->DaylightDate.wDay, tzi->DaylightDate.wMonth,
2102 tzi->DaylightDate.wYear, tzi->DaylightDate.wDayOfWeek,
2103 tzi->DaylightDate.wHour, tzi->DaylightDate.wMinute,
2104 tzi->DaylightDate.wSecond, tzi->DaylightDate.wMilliseconds,
2105 tzi->DaylightBias);
2107 tmp = std - tzi->Bias * 60 - tzi->DaylightBias * 60;
2108 tm = gmtime(&tmp);
2109 TRACE("std gmtime: %s", asctime(tm));
2111 tzi->StandardBias = 0;
2112 tzi->StandardDate.wYear = tm->tm_year + 1900;
2113 tzi->StandardDate.wMonth = tm->tm_mon + 1;
2114 tzi->StandardDate.wDayOfWeek = tm->tm_wday;
2115 tzi->StandardDate.wDay = tm->tm_mday;
2116 tzi->StandardDate.wHour = tm->tm_hour;
2117 tzi->StandardDate.wMinute = tm->tm_min;
2118 tzi->StandardDate.wSecond = tm->tm_sec;
2119 tzi->StandardDate.wMilliseconds = 0;
2121 TRACE("standard (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
2122 tzi->StandardDate.wDay, tzi->StandardDate.wMonth,
2123 tzi->StandardDate.wYear, tzi->StandardDate.wDayOfWeek,
2124 tzi->StandardDate.wHour, tzi->StandardDate.wMinute,
2125 tzi->StandardDate.wSecond, tzi->StandardDate.wMilliseconds,
2126 tzi->StandardBias);
2129 find_reg_tz_info(tzi, tz_name, current_year + 1900);
2130 cached_tzi = *tzi;
2131 mutex_unlock( &tz_mutex );
2135 static void read_dev_urandom( void *buf, ULONG len )
2137 int fd = open( "/dev/urandom", O_RDONLY );
2138 if (fd != -1)
2140 int ret;
2143 ret = read( fd, buf, len );
2145 while (ret == -1 && errno == EINTR);
2146 close( fd );
2148 else WARN( "can't open /dev/urandom\n" );
2151 /******************************************************************************
2152 * NtQuerySystemInformation (NTDLL.@)
2154 NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class,
2155 void *info, ULONG size, ULONG *ret_size )
2157 NTSTATUS ret = STATUS_SUCCESS;
2158 ULONG len = 0;
2160 TRACE( "(0x%08x,%p,0x%08x,%p)\n", class, info, size, ret_size );
2162 switch (class)
2164 case SystemNativeBasicInformation: /* 114 */
2165 if (!is_win64) return STATUS_INVALID_INFO_CLASS;
2166 /* fall through */
2167 case SystemBasicInformation: /* 0 */
2169 SYSTEM_BASIC_INFORMATION sbi;
2171 virtual_get_system_info( &sbi, FALSE );
2172 len = sizeof(sbi);
2173 if (size == len)
2175 if (!info) ret = STATUS_ACCESS_VIOLATION;
2176 else memcpy( info, &sbi, len);
2178 else ret = STATUS_INFO_LENGTH_MISMATCH;
2179 break;
2182 case SystemCpuInformation: /* 1 */
2183 if (size >= (len = sizeof(cpu_info)))
2185 if (!info) ret = STATUS_ACCESS_VIOLATION;
2186 else memcpy(info, &cpu_info, len);
2188 else ret = STATUS_INFO_LENGTH_MISMATCH;
2189 break;
2191 case SystemPerformanceInformation: /* 2 */
2193 SYSTEM_PERFORMANCE_INFORMATION spi;
2194 static BOOL fixme_written = FALSE;
2196 get_performance_info( &spi );
2197 len = sizeof(spi);
2198 if (size >= len)
2200 if (!info) ret = STATUS_ACCESS_VIOLATION;
2201 else memcpy( info, &spi, len);
2203 else ret = STATUS_INFO_LENGTH_MISMATCH;
2204 if(!fixme_written) {
2205 FIXME("info_class SYSTEM_PERFORMANCE_INFORMATION\n");
2206 fixme_written = TRUE;
2208 break;
2211 case SystemTimeOfDayInformation: /* 3 */
2213 struct tm *tm;
2214 time_t now;
2215 SYSTEM_TIMEOFDAY_INFORMATION sti = {{{ 0 }}};
2217 sti.BootTime.QuadPart = server_start_time;
2218 now = time( NULL );
2219 tm = gmtime( &now );
2220 sti.TimeZoneBias.QuadPart = mktime( tm ) - now;
2221 tm = localtime( &now );
2222 if (tm->tm_isdst) sti.TimeZoneBias.QuadPart -= 3600;
2223 sti.TimeZoneBias.QuadPart *= TICKSPERSEC;
2224 NtQuerySystemTime( &sti.SystemTime );
2226 if (size <= sizeof(sti))
2228 len = size;
2229 if (!info) ret = STATUS_ACCESS_VIOLATION;
2230 else memcpy( info, &sti, size);
2232 else ret = STATUS_INFO_LENGTH_MISMATCH;
2233 break;
2236 case SystemProcessInformation: /* 5 */
2238 unsigned int process_count, i, j;
2239 char *buffer = NULL;
2240 unsigned int pos = 0;
2242 if (size && !(buffer = malloc( size )))
2244 ret = STATUS_NO_MEMORY;
2245 break;
2248 SERVER_START_REQ( list_processes )
2250 wine_server_set_reply( req, buffer, size );
2251 ret = wine_server_call( req );
2252 len = reply->info_size;
2253 process_count = reply->process_count;
2255 SERVER_END_REQ;
2257 if (ret)
2259 free( buffer );
2260 break;
2263 len = 0;
2265 for (i = 0; i < process_count; i++)
2267 SYSTEM_PROCESS_INFORMATION *nt_process = (SYSTEM_PROCESS_INFORMATION *)((char *)info + len);
2268 const struct process_info *server_process;
2269 const WCHAR *server_name, *file_part;
2270 ULONG proc_len;
2271 ULONG name_len = 0;
2273 pos = (pos + 7) & ~7;
2274 server_process = (const struct process_info *)(buffer + pos);
2275 pos += sizeof(*server_process);
2277 server_name = (const WCHAR *)(buffer + pos);
2278 file_part = server_name + (server_process->name_len / sizeof(WCHAR));
2279 pos += server_process->name_len;
2280 while (file_part > server_name && file_part[-1] != '\\')
2282 file_part--;
2283 name_len++;
2286 proc_len = sizeof(*nt_process) + server_process->thread_count * sizeof(SYSTEM_THREAD_INFORMATION)
2287 + (name_len + 1) * sizeof(WCHAR);
2288 len += proc_len;
2290 if (len <= size)
2292 memset(nt_process, 0, sizeof(*nt_process));
2293 if (i < process_count - 1)
2294 nt_process->NextEntryOffset = proc_len;
2295 nt_process->CreationTime.QuadPart = server_process->start_time;
2296 nt_process->dwThreadCount = server_process->thread_count;
2297 nt_process->dwBasePriority = server_process->priority;
2298 nt_process->UniqueProcessId = UlongToHandle(server_process->pid);
2299 nt_process->ParentProcessId = UlongToHandle(server_process->parent_pid);
2300 nt_process->SessionId = server_process->session_id;
2301 nt_process->HandleCount = server_process->handle_count;
2302 get_thread_times( server_process->unix_pid, -1, &nt_process->KernelTime, &nt_process->UserTime );
2303 fill_vm_counters( &nt_process->vmCounters, server_process->unix_pid );
2306 pos = (pos + 7) & ~7;
2307 for (j = 0; j < server_process->thread_count; j++)
2309 const struct thread_info *server_thread = (const struct thread_info *)(buffer + pos);
2311 if (len <= size)
2313 nt_process->ti[j].CreateTime.QuadPart = server_thread->start_time;
2314 nt_process->ti[j].ClientId.UniqueProcess = UlongToHandle(server_process->pid);
2315 nt_process->ti[j].ClientId.UniqueThread = UlongToHandle(server_thread->tid);
2316 nt_process->ti[j].dwCurrentPriority = server_thread->current_priority;
2317 nt_process->ti[j].dwBasePriority = server_thread->base_priority;
2318 get_thread_times( server_process->unix_pid, server_thread->unix_tid,
2319 &nt_process->ti[j].KernelTime, &nt_process->ti[j].UserTime );
2322 pos += sizeof(*server_thread);
2325 if (len <= size)
2327 nt_process->ProcessName.Buffer = (WCHAR *)&nt_process->ti[server_process->thread_count];
2328 nt_process->ProcessName.Length = name_len * sizeof(WCHAR);
2329 nt_process->ProcessName.MaximumLength = (name_len + 1) * sizeof(WCHAR);
2330 memcpy(nt_process->ProcessName.Buffer, file_part, name_len * sizeof(WCHAR));
2331 nt_process->ProcessName.Buffer[name_len] = 0;
2335 if (len > size) ret = STATUS_INFO_LENGTH_MISMATCH;
2336 free( buffer );
2337 break;
2340 case SystemProcessorPerformanceInformation: /* 8 */
2342 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL;
2343 unsigned int cpus = 0;
2344 int out_cpus = size / sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
2346 if (out_cpus == 0)
2348 len = 0;
2349 ret = STATUS_INFO_LENGTH_MISMATCH;
2350 break;
2352 if (!(sppi = calloc( out_cpus, sizeof(*sppi) )))
2354 ret = STATUS_NO_MEMORY;
2355 break;
2357 else
2358 #ifdef __APPLE__
2360 processor_cpu_load_info_data_t *pinfo;
2361 mach_msg_type_number_t info_count;
2363 if (host_processor_info( mach_host_self (),
2364 PROCESSOR_CPU_LOAD_INFO,
2365 &cpus,
2366 (processor_info_array_t*)&pinfo,
2367 &info_count) == 0)
2369 int i;
2370 cpus = min(cpus,out_cpus);
2371 for (i = 0; i < cpus; i++)
2373 sppi[i].IdleTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_IDLE];
2374 sppi[i].KernelTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_SYSTEM];
2375 sppi[i].UserTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_USER];
2377 vm_deallocate (mach_task_self (), (vm_address_t) pinfo, info_count * sizeof(natural_t));
2380 #else
2382 FILE *cpuinfo = fopen("/proc/stat", "r");
2383 if (cpuinfo)
2385 unsigned long clk_tck = sysconf(_SC_CLK_TCK);
2386 unsigned long usr,nice,sys,idle,remainder[8];
2387 int i, count, id;
2388 char name[32];
2389 char line[255];
2391 /* first line is combined usage */
2392 while (fgets(line,255,cpuinfo))
2394 count = sscanf(line, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
2395 name, &usr, &nice, &sys, &idle,
2396 &remainder[0], &remainder[1], &remainder[2], &remainder[3],
2397 &remainder[4], &remainder[5], &remainder[6], &remainder[7]);
2399 if (count < 5 || strncmp( name, "cpu", 3 )) break;
2400 for (i = 0; i + 5 < count; ++i) sys += remainder[i];
2401 sys += idle;
2402 usr += nice;
2403 id = atoi( name + 3 ) + 1;
2404 if (id > out_cpus) break;
2405 if (id > cpus) cpus = id;
2406 sppi[id-1].IdleTime.QuadPart = (ULONGLONG)idle * 10000000 / clk_tck;
2407 sppi[id-1].KernelTime.QuadPart = (ULONGLONG)sys * 10000000 / clk_tck;
2408 sppi[id-1].UserTime.QuadPart = (ULONGLONG)usr * 10000000 / clk_tck;
2410 fclose(cpuinfo);
2413 #endif
2414 if (cpus == 0)
2416 static int i = 1;
2417 unsigned int n;
2418 cpus = min(peb->NumberOfProcessors, out_cpus);
2419 FIXME("stub info_class SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION\n");
2420 /* many programs expect these values to change so fake change */
2421 for (n = 0; n < cpus; n++)
2423 sppi[n].KernelTime.QuadPart = 1 * i;
2424 sppi[n].UserTime.QuadPart = 2 * i;
2425 sppi[n].IdleTime.QuadPart = 3 * i;
2427 i++;
2430 len = sizeof(*sppi) * cpus;
2431 if (size >= len)
2433 if (!info) ret = STATUS_ACCESS_VIOLATION;
2434 else memcpy( info, sppi, len);
2436 else ret = STATUS_INFO_LENGTH_MISMATCH;
2438 free( sppi );
2439 break;
2442 case SystemModuleInformation: /* 11 */
2444 /* FIXME: return some fake info for now */
2445 static const char *fake_modules[] =
2447 "\\SystemRoot\\system32\\ntoskrnl.exe",
2448 "\\SystemRoot\\system32\\hal.dll",
2449 "\\SystemRoot\\system32\\drivers\\mountmgr.sys"
2452 ULONG i;
2453 RTL_PROCESS_MODULES *smi = info;
2455 len = offsetof( RTL_PROCESS_MODULES, Modules[ARRAY_SIZE(fake_modules)] );
2456 if (len <= size)
2458 memset( smi, 0, len );
2459 for (i = 0; i < ARRAY_SIZE(fake_modules); i++)
2461 RTL_PROCESS_MODULE_INFORMATION *sm = &smi->Modules[i];
2462 sm->ImageBaseAddress = (char *)0x10000000 + 0x200000 * i;
2463 sm->ImageSize = 0x200000;
2464 sm->LoadOrderIndex = i;
2465 sm->LoadCount = 1;
2466 strcpy( (char *)sm->Name, fake_modules[i] );
2467 sm->NameOffset = strrchr( fake_modules[i], '\\' ) - fake_modules[i] + 1;
2469 smi->ModulesCount = i;
2471 else ret = STATUS_INFO_LENGTH_MISMATCH;
2473 break;
2476 case SystemHandleInformation: /* 16 */
2478 struct handle_info *handle_info;
2479 DWORD i, num_handles;
2481 if (size < sizeof(SYSTEM_HANDLE_INFORMATION))
2483 ret = STATUS_INFO_LENGTH_MISMATCH;
2484 break;
2487 if (!info)
2489 ret = STATUS_ACCESS_VIOLATION;
2490 break;
2493 num_handles = (size - FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle )) / sizeof(SYSTEM_HANDLE_ENTRY);
2494 if (!(handle_info = malloc( sizeof(*handle_info) * num_handles ))) return STATUS_NO_MEMORY;
2496 SERVER_START_REQ( get_system_handles )
2498 wine_server_set_reply( req, handle_info, sizeof(*handle_info) * num_handles );
2499 if (!(ret = wine_server_call( req )))
2501 SYSTEM_HANDLE_INFORMATION *shi = info;
2502 shi->Count = wine_server_reply_size( req ) / sizeof(*handle_info);
2503 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle[shi->Count] );
2504 for (i = 0; i < shi->Count; i++)
2506 memset( &shi->Handle[i], 0, sizeof(shi->Handle[i]) );
2507 shi->Handle[i].OwnerPid = handle_info[i].owner;
2508 shi->Handle[i].HandleValue = handle_info[i].handle;
2509 shi->Handle[i].AccessMask = handle_info[i].access;
2510 shi->Handle[i].HandleFlags = handle_info[i].attributes;
2511 shi->Handle[i].ObjectType = handle_info[i].type;
2512 /* FIXME: Fill out ObjectPointer */
2515 else if (ret == STATUS_BUFFER_TOO_SMALL)
2517 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle[reply->count] );
2518 ret = STATUS_INFO_LENGTH_MISMATCH;
2521 SERVER_END_REQ;
2523 free( handle_info );
2524 break;
2527 case SystemFileCacheInformation: /* 21 */
2529 SYSTEM_CACHE_INFORMATION sci = { 0 };
2531 len = sizeof(sci);
2532 if (size >= len)
2534 if (!info) ret = STATUS_ACCESS_VIOLATION;
2535 else memcpy( info, &sci, len);
2537 else ret = STATUS_INFO_LENGTH_MISMATCH;
2538 FIXME("info_class SYSTEM_CACHE_INFORMATION\n");
2539 break;
2542 case SystemInterruptInformation: /* 23 */
2544 len = peb->NumberOfProcessors * sizeof(SYSTEM_INTERRUPT_INFORMATION);
2545 if (size >= len)
2547 if (!info) ret = STATUS_ACCESS_VIOLATION;
2548 else
2550 #ifdef HAVE_GETRANDOM
2551 int ret;
2554 ret = getrandom( info, len, 0 );
2556 while (ret == -1 && errno == EINTR);
2558 if (ret == -1 && errno == ENOSYS) read_dev_urandom( info, len );
2559 #else
2560 read_dev_urandom( info, len );
2561 #endif
2564 else ret = STATUS_INFO_LENGTH_MISMATCH;
2565 break;
2568 case SystemTimeAdjustmentInformation: /* 28 */
2570 SYSTEM_TIME_ADJUSTMENT_QUERY query = { 156250, 156250, TRUE };
2572 len = sizeof(query);
2573 if (size == len)
2575 if (!info) ret = STATUS_ACCESS_VIOLATION;
2576 else memcpy( info, &query, len );
2578 else ret = STATUS_INFO_LENGTH_MISMATCH;
2579 break;
2582 case SystemKernelDebuggerInformation: /* 35 */
2584 SYSTEM_KERNEL_DEBUGGER_INFORMATION skdi;
2586 skdi.DebuggerEnabled = FALSE;
2587 skdi.DebuggerNotPresent = TRUE;
2588 len = sizeof(skdi);
2589 if (size >= len)
2591 if (!info) ret = STATUS_ACCESS_VIOLATION;
2592 else memcpy( info, &skdi, len);
2594 else ret = STATUS_INFO_LENGTH_MISMATCH;
2595 break;
2598 case SystemRegistryQuotaInformation: /* 37 */
2600 /* Something to do with the size of the registry *
2601 * Since we don't have a size limitation, fake it *
2602 * This is almost certainly wrong. *
2603 * This sets each of the three words in the struct to 32 MB, *
2604 * which is enough to make the IE 5 installer happy. */
2605 SYSTEM_REGISTRY_QUOTA_INFORMATION srqi;
2607 srqi.RegistryQuotaAllowed = 0x2000000;
2608 srqi.RegistryQuotaUsed = 0x200000;
2609 srqi.Reserved1 = (void*)0x200000;
2610 len = sizeof(srqi);
2612 if (size >= len)
2614 if (!info) ret = STATUS_ACCESS_VIOLATION;
2615 else
2617 FIXME("SystemRegistryQuotaInformation: faking max registry size of 32 MB\n");
2618 memcpy( info, &srqi, len);
2621 else ret = STATUS_INFO_LENGTH_MISMATCH;
2622 break;
2625 case SystemCurrentTimeZoneInformation: /* 44 */
2627 RTL_DYNAMIC_TIME_ZONE_INFORMATION tz;
2629 get_timezone_info( &tz );
2630 len = sizeof(RTL_TIME_ZONE_INFORMATION);
2631 if (size >= len)
2633 if (!info) ret = STATUS_ACCESS_VIOLATION;
2634 else memcpy( info, &tz, len);
2636 else ret = STATUS_INFO_LENGTH_MISMATCH;
2637 break;
2640 case SystemExtendedProcessInformation: /* 57 */
2641 FIXME("SystemExtendedProcessInformation, size %u, info %p, stub!\n", size, info);
2642 memset( info, 0, size );
2643 ret = STATUS_SUCCESS;
2644 break;
2646 case SystemRecommendedSharedDataAlignment: /* 58 */
2648 len = sizeof(DWORD);
2649 if (size >= len)
2651 if (!info) ret = STATUS_ACCESS_VIOLATION;
2652 else
2654 #ifdef __arm__
2655 *((DWORD *)info) = 32;
2656 #else
2657 *((DWORD *)info) = 64;
2658 #endif
2661 else ret = STATUS_INFO_LENGTH_MISMATCH;
2662 break;
2665 case SystemEmulationBasicInformation: /* 62 */
2667 SYSTEM_BASIC_INFORMATION sbi;
2669 virtual_get_system_info( &sbi, !!NtCurrentTeb()->WowTebOffset );
2670 len = sizeof(sbi);
2671 if (size == len)
2673 if (!info) ret = STATUS_ACCESS_VIOLATION;
2674 else memcpy( info, &sbi, len);
2676 else ret = STATUS_INFO_LENGTH_MISMATCH;
2677 break;
2680 case SystemEmulationProcessorInformation: /* 63 */
2681 if (size >= (len = sizeof(cpu_info)))
2683 SYSTEM_CPU_INFORMATION cpu = cpu_info;
2684 if (is_win64)
2686 if (cpu_info.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
2687 cpu.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
2688 else if (cpu_info.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64)
2689 cpu.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_ARM;
2691 memcpy(info, &cpu, len);
2693 else ret = STATUS_INFO_LENGTH_MISMATCH;
2694 break;
2696 case SystemExtendedHandleInformation: /* 64 */
2698 struct handle_info *handle_info;
2699 DWORD i, num_handles;
2701 if (size < sizeof(SYSTEM_HANDLE_INFORMATION_EX))
2703 ret = STATUS_INFO_LENGTH_MISMATCH;
2704 break;
2707 if (!info)
2709 ret = STATUS_ACCESS_VIOLATION;
2710 break;
2713 num_handles = (size - FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handles ))
2714 / sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX);
2715 if (!(handle_info = malloc( sizeof(*handle_info) * num_handles ))) return STATUS_NO_MEMORY;
2717 SERVER_START_REQ( get_system_handles )
2719 wine_server_set_reply( req, handle_info, sizeof(*handle_info) * num_handles );
2720 if (!(ret = wine_server_call( req )))
2722 SYSTEM_HANDLE_INFORMATION_EX *shi = info;
2723 shi->NumberOfHandles = wine_server_reply_size( req ) / sizeof(*handle_info);
2724 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handles[shi->NumberOfHandles] );
2725 for (i = 0; i < shi->NumberOfHandles; i++)
2727 memset( &shi->Handles[i], 0, sizeof(shi->Handles[i]) );
2728 shi->Handles[i].UniqueProcessId = handle_info[i].owner;
2729 shi->Handles[i].HandleValue = handle_info[i].handle;
2730 shi->Handles[i].GrantedAccess = handle_info[i].access;
2731 shi->Handles[i].HandleAttributes = handle_info[i].attributes;
2732 shi->Handles[i].ObjectTypeIndex = handle_info[i].type;
2733 /* FIXME: Fill out Object */
2736 else if (ret == STATUS_BUFFER_TOO_SMALL)
2738 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handles[reply->count] );
2739 ret = STATUS_INFO_LENGTH_MISMATCH;
2742 SERVER_END_REQ;
2744 free( handle_info );
2745 break;
2748 case SystemLogicalProcessorInformation: /* 73 */
2750 SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buf;
2752 /* Each logical processor may use up to 7 entries in returned table:
2753 * core, numa node, package, L1i, L1d, L2, L3 */
2754 len = 7 * peb->NumberOfProcessors;
2755 buf = malloc( len * sizeof(*buf) );
2756 if (!buf)
2758 ret = STATUS_NO_MEMORY;
2759 break;
2761 ret = create_logical_proc_info(&buf, NULL, &len, RelationAll);
2762 if (!ret)
2764 if (size >= len)
2766 if (!info) ret = STATUS_ACCESS_VIOLATION;
2767 else memcpy( info, buf, len);
2769 else ret = STATUS_INFO_LENGTH_MISMATCH;
2771 free( buf );
2772 break;
2775 case SystemFirmwareTableInformation: /* 76 */
2777 SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti = info;
2778 len = FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
2779 if (size < len)
2781 ret = STATUS_INFO_LENGTH_MISMATCH;
2782 break;
2785 switch (sfti->Action)
2787 case SystemFirmwareTable_Get:
2788 ret = get_firmware_info(sfti, size, &len);
2789 break;
2790 default:
2791 len = 0;
2792 ret = STATUS_NOT_IMPLEMENTED;
2793 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION action %d\n", sfti->Action);
2795 break;
2798 case SystemModuleInformationEx: /* 77 */
2800 /* FIXME: return some fake info for now */
2801 static const char *fake_modules[] =
2803 "\\SystemRoot\\system32\\ntoskrnl.exe",
2804 "\\SystemRoot\\system32\\hal.dll",
2805 "\\SystemRoot\\system32\\drivers\\mountmgr.sys"
2808 ULONG i;
2809 RTL_PROCESS_MODULE_INFORMATION_EX *module_info = info;
2811 len = sizeof(*module_info) * ARRAY_SIZE(fake_modules) + sizeof(module_info->NextOffset);
2812 if (len <= size)
2814 memset( info, 0, len );
2815 for (i = 0; i < ARRAY_SIZE(fake_modules); i++)
2817 RTL_PROCESS_MODULE_INFORMATION *sm = &module_info[i].BaseInfo;
2818 sm->ImageBaseAddress = (char *)0x10000000 + 0x200000 * i;
2819 sm->ImageSize = 0x200000;
2820 sm->LoadOrderIndex = i;
2821 sm->LoadCount = 1;
2822 strcpy( (char *)sm->Name, fake_modules[i] );
2823 sm->NameOffset = strrchr( fake_modules[i], '\\' ) - fake_modules[i] + 1;
2824 module_info[i].NextOffset = sizeof(*module_info);
2826 module_info[ARRAY_SIZE(fake_modules)].NextOffset = 0;
2828 else ret = STATUS_INFO_LENGTH_MISMATCH;
2830 break;
2833 case SystemDynamicTimeZoneInformation: /* 102 */
2835 RTL_DYNAMIC_TIME_ZONE_INFORMATION tz;
2837 get_timezone_info( &tz );
2838 len = sizeof(tz);
2839 if (size >= len)
2841 if (!info) ret = STATUS_ACCESS_VIOLATION;
2842 else memcpy( info, &tz, len);
2844 else ret = STATUS_INFO_LENGTH_MISMATCH;
2845 break;
2848 case SystemCodeIntegrityInformation: /* 103 */
2850 SYSTEM_CODEINTEGRITY_INFORMATION *integrity_info = info;
2852 FIXME("SystemCodeIntegrityInformation, size %u, info %p, stub!\n", size, info);
2854 len = sizeof(SYSTEM_CODEINTEGRITY_INFORMATION);
2856 if (size < len)
2857 integrity_info->CodeIntegrityOptions = CODEINTEGRITY_OPTION_ENABLED;
2858 else
2859 ret = STATUS_INFO_LENGTH_MISMATCH;
2860 break;
2863 case SystemKernelDebuggerInformationEx: /* 149 */
2865 SYSTEM_KERNEL_DEBUGGER_INFORMATION_EX skdi;
2867 skdi.DebuggerAllowed = FALSE;
2868 skdi.DebuggerEnabled = FALSE;
2869 skdi.DebuggerPresent = FALSE;
2871 len = sizeof(skdi);
2872 if (size >= len)
2874 if (!info) ret = STATUS_ACCESS_VIOLATION;
2875 else memcpy( info, &skdi, len );
2877 else ret = STATUS_INFO_LENGTH_MISMATCH;
2878 break;
2881 case SystemCpuSetInformation: /* 175 */
2882 return NtQuerySystemInformationEx(class, NULL, 0, info, size, ret_size);
2884 /* Wine extensions */
2886 case SystemWineVersionInformation: /* 1000 */
2888 static const char version[] = PACKAGE_VERSION;
2889 struct utsname buf;
2891 uname( &buf );
2892 len = strlen(version) + strlen(wine_build) + strlen(buf.sysname) + strlen(buf.release) + 4;
2893 snprintf( info, size, "%s%c%s%c%s%c%s", version, 0, wine_build, 0, buf.sysname, 0, buf.release );
2894 if (size < len) ret = STATUS_INFO_LENGTH_MISMATCH;
2895 break;
2898 default:
2899 FIXME( "(0x%08x,%p,0x%08x,%p) stub\n", class, info, size, ret_size );
2901 /* Several Information Classes are not implemented on Windows and return 2 different values
2902 * STATUS_NOT_IMPLEMENTED or STATUS_INVALID_INFO_CLASS
2903 * in 95% of the cases it's STATUS_INVALID_INFO_CLASS, so use this as the default
2905 ret = STATUS_INVALID_INFO_CLASS;
2908 if (ret_size) *ret_size = len;
2909 return ret;
2913 /******************************************************************************
2914 * NtQuerySystemInformationEx (NTDLL.@)
2916 NTSTATUS WINAPI NtQuerySystemInformationEx( SYSTEM_INFORMATION_CLASS class,
2917 void *query, ULONG query_len,
2918 void *info, ULONG size, ULONG *ret_size )
2920 ULONG len = 0;
2921 NTSTATUS ret = STATUS_NOT_IMPLEMENTED;
2923 TRACE( "(0x%08x,%p,%u,%p,%u,%p) stub\n", class, query, query_len, info, size, ret_size );
2925 switch (class)
2927 case SystemLogicalProcessorInformationEx:
2929 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buf;
2931 if (!query || query_len < sizeof(DWORD))
2933 ret = STATUS_INVALID_PARAMETER;
2934 break;
2937 len = 3 * sizeof(*buf);
2938 if (!(buf = malloc( len )))
2940 ret = STATUS_NO_MEMORY;
2941 break;
2943 ret = create_logical_proc_info(NULL, &buf, &len, *(DWORD *)query);
2944 if (!ret)
2946 if (size >= len)
2948 if (!info) ret = STATUS_ACCESS_VIOLATION;
2949 else memcpy(info, buf, len);
2951 else ret = STATUS_INFO_LENGTH_MISMATCH;
2953 free( buf );
2954 break;
2957 case SystemCpuSetInformation:
2959 unsigned int cpu_count = peb->NumberOfProcessors;
2960 PROCESS_BASIC_INFORMATION pbi;
2961 HANDLE process;
2963 if (!query || query_len < sizeof(HANDLE))
2964 return STATUS_INVALID_PARAMETER;
2966 process = *(HANDLE *)query;
2967 if (process && (ret = NtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL)))
2968 return ret;
2970 if (size < (len = cpu_count * sizeof(SYSTEM_CPU_SET_INFORMATION)))
2972 ret = STATUS_BUFFER_TOO_SMALL;
2973 break;
2975 if (!info)
2976 return STATUS_ACCESS_VIOLATION;
2978 if ((ret = create_cpuset_info(info)))
2979 return ret;
2980 break;
2983 case SystemSupportedProcessorArchitectures:
2985 HANDLE process;
2986 ULONG i;
2987 USHORT machine = 0;
2989 if (!query || query_len < sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
2990 process = *(HANDLE *)query;
2991 if (process)
2993 SERVER_START_REQ( get_process_info )
2995 req->handle = wine_server_obj_handle( process );
2996 if (!(ret = wine_server_call( req ))) machine = reply->machine;
2998 SERVER_END_REQ;
2999 if (ret) return ret;
3002 len = (supported_machines_count + 1) * sizeof(ULONG);
3003 if (size < len)
3005 ret = STATUS_BUFFER_TOO_SMALL;
3006 break;
3008 for (i = 0; i < supported_machines_count; i++)
3010 USHORT flags = 2; /* supported (?) */
3011 if (!i) flags |= 5; /* native machine (?) */
3012 if (supported_machines[i] == machine) flags |= 8; /* current machine */
3013 ((DWORD *)info)[i] = MAKELONG( supported_machines[i], flags );
3015 ((DWORD *)info)[i] = 0;
3016 ret = STATUS_SUCCESS;
3017 break;
3020 default:
3021 FIXME( "(0x%08x,%p,%u,%p,%u,%p) stub\n", class, query, query_len, info, size, ret_size );
3022 break;
3024 if (ret_size) *ret_size = len;
3025 return ret;
3029 /******************************************************************************
3030 * NtSetSystemInformation (NTDLL.@)
3032 NTSTATUS WINAPI NtSetSystemInformation( SYSTEM_INFORMATION_CLASS class, void *info, ULONG length )
3034 FIXME( "(0x%08x,%p,0x%08x) stub\n", class, info, length );
3035 return STATUS_SUCCESS;
3039 /******************************************************************************
3040 * NtQuerySystemEnvironmentValue (NTDLL.@)
3042 NTSTATUS WINAPI NtQuerySystemEnvironmentValue( UNICODE_STRING *name, WCHAR *buffer, ULONG length,
3043 ULONG *retlen )
3045 FIXME( "(%s, %p, %u, %p), stub\n", debugstr_us(name), buffer, length, retlen );
3046 return STATUS_NOT_IMPLEMENTED;
3050 /******************************************************************************
3051 * NtQuerySystemEnvironmentValueEx (NTDLL.@)
3053 NTSTATUS WINAPI NtQuerySystemEnvironmentValueEx( UNICODE_STRING *name, GUID *vendor, void *buffer,
3054 ULONG *retlen, ULONG *attrib )
3056 FIXME( "(%s, %s, %p, %p, %p), stub\n", debugstr_us(name),
3057 debugstr_guid(vendor), buffer, retlen, attrib );
3058 return STATUS_NOT_IMPLEMENTED;
3062 /******************************************************************************
3063 * NtSystemDebugControl (NTDLL.@)
3065 NTSTATUS WINAPI NtSystemDebugControl( SYSDBG_COMMAND command, void *in_buff, ULONG in_len,
3066 void *out_buff, ULONG out_len, ULONG *retlen )
3068 FIXME( "(%d, %p, %d, %p, %d, %p), stub\n", command, in_buff, in_len, out_buff, out_len, retlen );
3069 return STATUS_NOT_IMPLEMENTED;
3073 /******************************************************************************
3074 * NtShutdownSystem (NTDLL.@)
3076 NTSTATUS WINAPI NtShutdownSystem( SHUTDOWN_ACTION action )
3078 FIXME( "%d\n", action );
3079 return STATUS_SUCCESS;
3083 #ifdef linux
3085 /* Fallback using /proc/cpuinfo for Linux systems without cpufreq. For
3086 * most distributions on recent enough hardware, this is only likely to
3087 * happen while running in virtualized environments such as QEMU. */
3088 static ULONG mhz_from_cpuinfo(void)
3090 char line[512];
3091 char *s, *value;
3092 double cmz = 0;
3093 FILE *f = fopen("/proc/cpuinfo", "r");
3094 if(f)
3096 while (fgets(line, sizeof(line), f) != NULL)
3098 if (!(value = strchr(line,':'))) continue;
3099 s = value - 1;
3100 while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
3101 s[1] = 0;
3102 value++;
3103 if (!strcmp( line, "cpu MHz" ))
3105 sscanf(value, " %lf", &cmz);
3106 break;
3109 fclose( f );
3111 return cmz;
3114 static const char * get_sys_str(const char *path, char *s)
3116 FILE *f = fopen(path, "r");
3117 const char *ret = NULL;
3119 if (f)
3121 if (fgets(s, 16, f)) ret = s;
3122 fclose(f);
3124 return ret;
3127 static int get_sys_int(const char *path, int def)
3129 char s[16];
3130 return get_sys_str(path, s) ? atoi(s) : def;
3133 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
3135 char s[16], path[64];
3136 unsigned int i = 0;
3137 LONG64 voltage; /* microvolts */
3139 bs->AcOnLine = get_sys_int("/sys/class/power_supply/AC/online", 1);
3141 for (;;)
3143 sprintf(path, "/sys/class/power_supply/BAT%u/status", i);
3144 if (!get_sys_str(path, s)) break;
3145 bs->Charging |= (strcmp(s, "Charging\n") == 0);
3146 bs->Discharging |= (strcmp(s, "Discharging\n") == 0);
3147 bs->BatteryPresent = TRUE;
3148 i++;
3151 if (bs->BatteryPresent)
3153 voltage = get_sys_int("/sys/class/power_supply/BAT0/voltage_now", 0);
3154 bs->MaxCapacity = get_sys_int("/sys/class/power_supply/BAT0/charge_full", 0) * voltage / 1e9;
3155 bs->RemainingCapacity = get_sys_int("/sys/class/power_supply/BAT0/charge_now", 0) * voltage / 1e9;
3156 bs->Rate = -get_sys_int("/sys/class/power_supply/BAT0/current_now", 0) * voltage / 1e9;
3157 if (!bs->Charging && (LONG)bs->Rate < 0)
3158 bs->EstimatedTime = 3600 * bs->RemainingCapacity / -(LONG)bs->Rate;
3159 else
3160 bs->EstimatedTime = ~0u;
3163 return STATUS_SUCCESS;
3166 #elif defined(HAVE_IOKIT_IOKITLIB_H)
3168 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
3170 CFArrayRef batteries;
3171 CFDictionaryRef battery;
3172 CFNumberRef prop;
3173 uint32_t value, voltage;
3174 CFTimeInterval remain;
3176 if (IOPMCopyBatteryInfo( kIOMasterPortDefault, &batteries ) != kIOReturnSuccess)
3177 return STATUS_ACCESS_DENIED;
3179 if (CFArrayGetCount( batteries ) == 0)
3181 /* Just assume we're on AC with no battery. */
3182 bs->AcOnLine = TRUE;
3183 return STATUS_SUCCESS;
3185 /* Just use the first battery. */
3186 battery = CFArrayGetValueAtIndex( batteries, 0 );
3188 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryFlagsKey) );
3189 CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
3191 if (value & kIOBatteryInstalled)
3192 bs->BatteryPresent = TRUE;
3193 else
3194 /* Since we are executing code, we must have AC power. */
3195 bs->AcOnLine = TRUE;
3196 if (value & kIOBatteryChargerConnect)
3198 bs->AcOnLine = TRUE;
3199 if (value & kIOBatteryCharge)
3200 bs->Charging = TRUE;
3202 else
3203 bs->Discharging = TRUE;
3205 /* We'll need the voltage to be able to interpret the other values. */
3206 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryVoltageKey) );
3207 CFNumberGetValue( prop, kCFNumberSInt32Type, &voltage );
3209 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryCapacityKey) );
3210 CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
3211 bs->MaxCapacity = value * voltage;
3212 /* Apple uses "estimated time < 10:00" and "22%" for these, but we'll follow
3213 * Windows for now (5% and 33%). */
3214 bs->DefaultAlert1 = bs->MaxCapacity / 20;
3215 bs->DefaultAlert2 = bs->MaxCapacity / 3;
3217 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryCurrentChargeKey) );
3218 CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
3219 bs->RemainingCapacity = value * voltage;
3221 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryAmperageKey) );
3222 CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
3223 bs->Rate = value * voltage;
3225 remain = IOPSGetTimeRemainingEstimate();
3226 if (remain != kIOPSTimeRemainingUnknown && remain != kIOPSTimeRemainingUnlimited)
3227 bs->EstimatedTime = (ULONG)remain;
3229 CFRelease( batteries );
3230 return STATUS_SUCCESS;
3233 #else
3235 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
3237 FIXME("SystemBatteryState not implemented on this platform\n");
3238 return STATUS_NOT_IMPLEMENTED;
3241 #endif
3243 /******************************************************************************
3244 * NtPowerInformation (NTDLL.@)
3246 NTSTATUS WINAPI NtPowerInformation( POWER_INFORMATION_LEVEL level, void *input, ULONG in_size,
3247 void *output, ULONG out_size )
3249 TRACE( "(%d,%p,%d,%p,%d)\n", level, input, in_size, output, out_size );
3250 switch (level)
3252 case SystemPowerCapabilities:
3254 PSYSTEM_POWER_CAPABILITIES PowerCaps = output;
3255 FIXME("semi-stub: SystemPowerCapabilities\n");
3256 if (out_size < sizeof(SYSTEM_POWER_CAPABILITIES)) return STATUS_BUFFER_TOO_SMALL;
3257 /* FIXME: These values are based off a native XP desktop, should probably use APM/ACPI to get the 'real' values */
3258 PowerCaps->PowerButtonPresent = TRUE;
3259 PowerCaps->SleepButtonPresent = FALSE;
3260 PowerCaps->LidPresent = FALSE;
3261 PowerCaps->SystemS1 = TRUE;
3262 PowerCaps->SystemS2 = FALSE;
3263 PowerCaps->SystemS3 = FALSE;
3264 PowerCaps->SystemS4 = TRUE;
3265 PowerCaps->SystemS5 = TRUE;
3266 PowerCaps->HiberFilePresent = TRUE;
3267 PowerCaps->FullWake = TRUE;
3268 PowerCaps->VideoDimPresent = FALSE;
3269 PowerCaps->ApmPresent = FALSE;
3270 PowerCaps->UpsPresent = FALSE;
3271 PowerCaps->ThermalControl = FALSE;
3272 PowerCaps->ProcessorThrottle = FALSE;
3273 PowerCaps->ProcessorMinThrottle = 100;
3274 PowerCaps->ProcessorMaxThrottle = 100;
3275 PowerCaps->DiskSpinDown = TRUE;
3276 PowerCaps->SystemBatteriesPresent = FALSE;
3277 PowerCaps->BatteriesAreShortTerm = FALSE;
3278 PowerCaps->BatteryScale[0].Granularity = 0;
3279 PowerCaps->BatteryScale[0].Capacity = 0;
3280 PowerCaps->BatteryScale[1].Granularity = 0;
3281 PowerCaps->BatteryScale[1].Capacity = 0;
3282 PowerCaps->BatteryScale[2].Granularity = 0;
3283 PowerCaps->BatteryScale[2].Capacity = 0;
3284 PowerCaps->AcOnLineWake = PowerSystemUnspecified;
3285 PowerCaps->SoftLidWake = PowerSystemUnspecified;
3286 PowerCaps->RtcWake = PowerSystemSleeping1;
3287 PowerCaps->MinDeviceWakeState = PowerSystemUnspecified;
3288 PowerCaps->DefaultLowLatencyWake = PowerSystemUnspecified;
3289 return STATUS_SUCCESS;
3292 case SystemBatteryState:
3294 if (out_size < sizeof(SYSTEM_BATTERY_STATE)) return STATUS_BUFFER_TOO_SMALL;
3295 memset(output, 0, sizeof(SYSTEM_BATTERY_STATE));
3296 return fill_battery_state(output);
3299 case SystemExecutionState:
3301 ULONG *state = output;
3302 WARN("semi-stub: SystemExecutionState\n"); /* Needed for .NET Framework, but using a FIXME is really noisy. */
3303 if (input != NULL) return STATUS_INVALID_PARAMETER;
3304 /* FIXME: The actual state should be the value set by SetThreadExecutionState which is not currently implemented. */
3305 *state = ES_USER_PRESENT;
3306 return STATUS_SUCCESS;
3309 case ProcessorInformation:
3311 const int cannedMHz = 1000; /* We fake a 1GHz processor if we can't conjure up real values */
3312 PROCESSOR_POWER_INFORMATION* cpu_power = output;
3313 int i, out_cpus;
3315 if ((output == NULL) || (out_size == 0)) return STATUS_INVALID_PARAMETER;
3316 out_cpus = peb->NumberOfProcessors;
3317 if ((out_size / sizeof(PROCESSOR_POWER_INFORMATION)) < out_cpus) return STATUS_BUFFER_TOO_SMALL;
3318 #if defined(linux)
3320 char filename[128];
3321 FILE* f;
3323 for(i = 0; i < out_cpus; i++) {
3324 sprintf(filename, "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", i);
3325 f = fopen(filename, "r");
3326 if (f && (fscanf(f, "%d", &cpu_power[i].MaxMhz) == 1)) {
3327 cpu_power[i].MaxMhz /= 1000;
3328 fclose(f);
3329 cpu_power[i].CurrentMhz = cpu_power[i].MaxMhz;
3331 else {
3332 if(i == 0) {
3333 cpu_power[0].CurrentMhz = mhz_from_cpuinfo();
3334 if(cpu_power[0].CurrentMhz == 0)
3335 cpu_power[0].CurrentMhz = cannedMHz;
3337 else
3338 cpu_power[i].CurrentMhz = cpu_power[0].CurrentMhz;
3339 cpu_power[i].MaxMhz = cpu_power[i].CurrentMhz;
3340 if(f) fclose(f);
3343 sprintf(filename, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", i);
3344 f = fopen(filename, "r");
3345 if(f && (fscanf(f, "%d", &cpu_power[i].MhzLimit) == 1)) {
3346 cpu_power[i].MhzLimit /= 1000;
3347 fclose(f);
3349 else
3351 cpu_power[i].MhzLimit = cpu_power[i].MaxMhz;
3352 if(f) fclose(f);
3355 cpu_power[i].Number = i;
3356 cpu_power[i].MaxIdleState = 0; /* FIXME */
3357 cpu_power[i].CurrentIdleState = 0; /* FIXME */
3360 #elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__)
3362 int num;
3363 size_t valSize = sizeof(num);
3364 if (sysctlbyname("hw.clockrate", &num, &valSize, NULL, 0))
3365 num = cannedMHz;
3366 for(i = 0; i < out_cpus; i++) {
3367 cpu_power[i].CurrentMhz = num;
3368 cpu_power[i].MaxMhz = num;
3369 cpu_power[i].MhzLimit = num;
3370 cpu_power[i].Number = i;
3371 cpu_power[i].MaxIdleState = 0; /* FIXME */
3372 cpu_power[i].CurrentIdleState = 0; /* FIXME */
3375 #elif defined (__APPLE__)
3377 size_t valSize;
3378 unsigned long long currentMhz;
3379 unsigned long long maxMhz;
3381 valSize = sizeof(currentMhz);
3382 if (!sysctlbyname("hw.cpufrequency", &currentMhz, &valSize, NULL, 0))
3383 currentMhz /= 1000000;
3384 else
3385 currentMhz = cannedMHz;
3387 valSize = sizeof(maxMhz);
3388 if (!sysctlbyname("hw.cpufrequency_max", &maxMhz, &valSize, NULL, 0))
3389 maxMhz /= 1000000;
3390 else
3391 maxMhz = currentMhz;
3393 for(i = 0; i < out_cpus; i++) {
3394 cpu_power[i].CurrentMhz = currentMhz;
3395 cpu_power[i].MaxMhz = maxMhz;
3396 cpu_power[i].MhzLimit = maxMhz;
3397 cpu_power[i].Number = i;
3398 cpu_power[i].MaxIdleState = 0; /* FIXME */
3399 cpu_power[i].CurrentIdleState = 0; /* FIXME */
3402 #else
3403 for(i = 0; i < out_cpus; i++) {
3404 cpu_power[i].CurrentMhz = cannedMHz;
3405 cpu_power[i].MaxMhz = cannedMHz;
3406 cpu_power[i].MhzLimit = cannedMHz;
3407 cpu_power[i].Number = i;
3408 cpu_power[i].MaxIdleState = 0; /* FIXME */
3409 cpu_power[i].CurrentIdleState = 0; /* FIXME */
3411 WARN("Unable to detect CPU MHz for this platform. Reporting %d MHz.\n", cannedMHz);
3412 #endif
3413 for(i = 0; i < out_cpus; i++) {
3414 TRACE("cpu_power[%d] = %u %u %u %u %u %u\n", i, cpu_power[i].Number,
3415 cpu_power[i].MaxMhz, cpu_power[i].CurrentMhz, cpu_power[i].MhzLimit,
3416 cpu_power[i].MaxIdleState, cpu_power[i].CurrentIdleState);
3418 return STATUS_SUCCESS;
3421 default:
3422 /* FIXME: Needed by .NET Framework */
3423 WARN( "Unimplemented NtPowerInformation action: %d\n", level );
3424 return STATUS_NOT_IMPLEMENTED;
3429 /******************************************************************************
3430 * NtLoadDriver (NTDLL.@)
3432 NTSTATUS WINAPI NtLoadDriver( const UNICODE_STRING *name )
3434 FIXME( "(%s), stub!\n", debugstr_us(name) );
3435 return STATUS_NOT_IMPLEMENTED;
3439 /******************************************************************************
3440 * NtUnloadDriver (NTDLL.@)
3442 NTSTATUS WINAPI NtUnloadDriver( const UNICODE_STRING *name )
3444 FIXME( "(%s), stub!\n", debugstr_us(name) );
3445 return STATUS_NOT_IMPLEMENTED;
3449 /******************************************************************************
3450 * NtDisplayString (NTDLL.@)
3452 NTSTATUS WINAPI NtDisplayString( UNICODE_STRING *string )
3454 ERR( "%s\n", debugstr_us(string) );
3455 return STATUS_SUCCESS;
3459 /******************************************************************************
3460 * NtRaiseHardError (NTDLL.@)
3462 NTSTATUS WINAPI NtRaiseHardError( NTSTATUS status, ULONG count,
3463 UNICODE_STRING *params_mask, void **params,
3464 HARDERROR_RESPONSE_OPTION option, HARDERROR_RESPONSE *response )
3466 FIXME( "%08x stub\n", status );
3467 return STATUS_NOT_IMPLEMENTED;
3471 /******************************************************************************
3472 * NtInitiatePowerAction (NTDLL.@)
3474 NTSTATUS WINAPI NtInitiatePowerAction( POWER_ACTION action, SYSTEM_POWER_STATE state,
3475 ULONG flags, BOOLEAN async )
3477 FIXME( "(%d,%d,0x%08x,%d),stub\n", action, state, flags, async );
3478 return STATUS_NOT_IMPLEMENTED;
3482 /******************************************************************************
3483 * NtCreatePowerRequest (NTDLL.@)
3485 NTSTATUS WINAPI NtCreatePowerRequest( HANDLE *handle, COUNTED_REASON_CONTEXT *context )
3487 FIXME( "(%p, %p): stub\n", handle, context );
3488 return STATUS_NOT_IMPLEMENTED;
3492 /******************************************************************************
3493 * NtSetPowerRequest (NTDLL.@)
3495 NTSTATUS WINAPI NtSetPowerRequest( HANDLE handle, POWER_REQUEST_TYPE type )
3497 FIXME( "(%p, %u): stub\n", handle, type );
3498 return STATUS_NOT_IMPLEMENTED;
3502 /******************************************************************************
3503 * NtClearPowerRequest (NTDLL.@)
3505 NTSTATUS WINAPI NtClearPowerRequest( HANDLE handle, POWER_REQUEST_TYPE type )
3507 FIXME( "(%p, %u): stub\n", handle, type );
3508 return STATUS_NOT_IMPLEMENTED;
3512 /******************************************************************************
3513 * NtSetThreadExecutionState (NTDLL.@)
3515 NTSTATUS WINAPI NtSetThreadExecutionState( EXECUTION_STATE new_state, EXECUTION_STATE *old_state )
3517 static EXECUTION_STATE current = ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED | ES_USER_PRESENT;
3519 WARN( "(0x%x, %p): stub, harmless.\n", new_state, old_state );
3520 *old_state = current;
3521 if (!(current & ES_CONTINUOUS) || (new_state & ES_CONTINUOUS)) current = new_state;
3522 return STATUS_SUCCESS;