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