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
26 #include "wine/port.h"
32 #ifdef HAVE_SYS_TIME_H
33 # include <sys/time.h>
36 #ifdef HAVE_SYS_PARAM_H
37 # include <sys/param.h>
39 #ifdef HAVE_SYS_SYSCTL_H
40 # include <sys/sysctl.h>
42 #ifdef HAVE_MACHINE_CPU_H
43 # include <machine/cpu.h>
45 #ifdef HAVE_IOKIT_IOKITLIB_H
46 # include <CoreFoundation/CoreFoundation.h>
47 # include <IOKit/IOKitLib.h>
48 # include <IOKit/pwr_mgt/IOPM.h>
49 # include <IOKit/pwr_mgt/IOPMLib.h>
50 # include <IOKit/ps/IOPowerSources.h>
53 # include <mach/mach.h>
54 # include <mach/machine.h>
55 # include <mach/mach_init.h>
56 # include <mach/mach_host.h>
57 # include <mach/vm_map.h>
60 #define NONAMELESSUNION
62 #define WIN32_NO_STATUS
67 #include "unix_private.h"
68 #include "wine/debug.h"
70 WINE_DEFAULT_DEBUG_CHANNEL(ntdll
);
74 struct smbios_prologue
92 struct smbios_header hdr
;
98 UINT64 characteristics
;
99 BYTE characteristics_ext
[2];
100 BYTE system_bios_major_release
;
101 BYTE system_bios_minor_release
;
102 BYTE ec_firmware_major_release
;
103 BYTE ec_firmware_minor_release
;
108 struct smbios_header hdr
;
121 struct smbios_header hdr
;
128 struct smbios_chassis
130 struct smbios_header hdr
;
137 BYTE power_supply_state
;
139 BYTE security_status
;
144 /* Firmware table providers */
145 #define ACPI 0x41435049
146 #define FIRM 0x4649524D
147 #define RSMB 0x52534D42
149 static SYSTEM_CPU_INFORMATION cpu_info
;
151 /*******************************************************************************
152 * Architecture specific feature detection for CPUs
154 * This a set of mutually exclusive #if define()s each providing its own get_cpuinfo() to be called
155 * from init_cpu_info();
157 #if defined(__i386__) || defined(__x86_64__)
159 #define AUTH 0x68747541 /* "Auth" */
160 #define ENTI 0x69746e65 /* "enti" */
161 #define CAMD 0x444d4163 /* "cAMD" */
163 #define GENU 0x756e6547 /* "Genu" */
164 #define INEI 0x49656e69 /* "ineI" */
165 #define NTEL 0x6c65746e /* "ntel" */
167 extern void do_cpuid(unsigned int ax
, unsigned int *p
);
170 __ASM_GLOBAL_FUNC( do_cpuid
,
173 "movl 12(%esp),%eax\n\t"
174 "movl 16(%esp),%esi\n\t"
176 "movl %eax,(%esi)\n\t"
177 "movl %ebx,4(%esi)\n\t"
178 "movl %ecx,8(%esi)\n\t"
179 "movl %edx,12(%esi)\n\t"
184 __ASM_GLOBAL_FUNC( do_cpuid
,
188 "movl %eax,(%rsi)\n\t"
189 "movl %ebx,4(%rsi)\n\t"
190 "movl %ecx,8(%rsi)\n\t"
191 "movl %edx,12(%rsi)\n\t"
197 extern int have_cpuid(void);
198 __ASM_GLOBAL_FUNC( have_cpuid
,
201 "movl (%esp),%ecx\n\t"
202 "xorl $0x00200000,(%esp)\n\t"
208 "andl $0x00200000,%eax\n\t"
211 static int have_cpuid(void)
217 /* Detect if a SSE2 processor is capable of Denormals Are Zero (DAZ) mode.
219 * This function assumes you have already checked for SSE2/FXSAVE support. */
220 static inline BOOL
have_sse_daz_mode(void)
223 typedef struct DECLSPEC_ALIGN(16) _M128A
{
228 typedef struct _XMM_SAVE_AREA32
{
242 M128A FloatRegisters
[8];
243 M128A XmmRegisters
[16];
247 /* Intel says we need a zeroed 16-byte aligned buffer */
248 char buffer
[512 + 16];
249 XMM_SAVE_AREA32
*state
= (XMM_SAVE_AREA32
*)(((ULONG_PTR
)buffer
+ 15) & ~15);
250 memset(buffer
, 0, sizeof(buffer
));
252 __asm__
__volatile__( "fxsave %0" : "=m" (*state
) : "m" (*state
) );
254 return (state
->MxCsr_Mask
& (1 << 6)) >> 6;
255 #else /* all x86_64 processors include SSE2 with DAZ mode */
260 static void get_cpuinfo( SYSTEM_CPU_INFORMATION
*info
)
262 unsigned int regs
[4], regs2
[4];
264 #if defined(__i386__)
265 info
->Architecture
= PROCESSOR_ARCHITECTURE_INTEL
;
266 #elif defined(__x86_64__)
267 info
->Architecture
= PROCESSOR_ARCHITECTURE_AMD64
;
270 /* We're at least a 386 */
271 info
->FeatureSet
= CPU_FEATURE_VME
| CPU_FEATURE_X86
| CPU_FEATURE_PGE
;
274 if (!have_cpuid()) return;
276 do_cpuid( 0x00000000, regs
); /* get standard cpuid level and vendor name */
277 if (regs
[0]>=0x00000001) /* Check for supported cpuid version */
279 do_cpuid( 0x00000001, regs2
); /* get cpu features */
280 if (regs2
[3] & (1 << 3 )) info
->FeatureSet
|= CPU_FEATURE_PSE
;
281 if (regs2
[3] & (1 << 4 )) info
->FeatureSet
|= CPU_FEATURE_TSC
;
282 if (regs2
[3] & (1 << 6 )) info
->FeatureSet
|= CPU_FEATURE_PAE
;
283 if (regs2
[3] & (1 << 8 )) info
->FeatureSet
|= CPU_FEATURE_CX8
;
284 if (regs2
[3] & (1 << 11)) info
->FeatureSet
|= CPU_FEATURE_SEP
;
285 if (regs2
[3] & (1 << 12)) info
->FeatureSet
|= CPU_FEATURE_MTRR
;
286 if (regs2
[3] & (1 << 15)) info
->FeatureSet
|= CPU_FEATURE_CMOV
;
287 if (regs2
[3] & (1 << 16)) info
->FeatureSet
|= CPU_FEATURE_PAT
;
288 if (regs2
[3] & (1 << 23)) info
->FeatureSet
|= CPU_FEATURE_MMX
;
289 if (regs2
[3] & (1 << 24)) info
->FeatureSet
|= CPU_FEATURE_FXSR
;
290 if (regs2
[3] & (1 << 25)) info
->FeatureSet
|= CPU_FEATURE_SSE
;
291 if (regs2
[3] & (1 << 26)) info
->FeatureSet
|= CPU_FEATURE_SSE2
;
292 if (regs2
[2] & (1 << 0 )) info
->FeatureSet
|= CPU_FEATURE_SSE3
;
293 if (regs2
[2] & (1 << 13)) info
->FeatureSet
|= CPU_FEATURE_CX128
;
294 if (regs2
[2] & (1 << 27)) info
->FeatureSet
|= CPU_FEATURE_XSAVE
;
295 if((regs2
[3] & (1 << 26)) && (regs2
[3] & (1 << 24)) && have_sse_daz_mode()) /* has SSE2 and FXSAVE/FXRSTOR */
296 info
->FeatureSet
|= CPU_FEATURE_DAZ
;
298 if (regs
[1] == AUTH
&& regs
[3] == ENTI
&& regs
[2] == CAMD
)
300 info
->Level
= (regs2
[0] >> 8) & 0xf; /* family */
301 if (info
->Level
== 0xf) /* AMD says to add the extended family to the family if family is 0xf */
302 info
->Level
+= (regs2
[0] >> 20) & 0xff;
304 /* repack model and stepping to make a "revision" */
305 info
->Revision
= ((regs2
[0] >> 16) & 0xf) << 12; /* extended model */
306 info
->Revision
|= ((regs2
[0] >> 4 ) & 0xf) << 8; /* model */
307 info
->Revision
|= regs2
[0] & 0xf; /* stepping */
309 do_cpuid( 0x80000000, regs
); /* get vendor cpuid level */
310 if (regs
[0] >= 0x80000001)
312 do_cpuid( 0x80000001, regs2
); /* get vendor features */
313 if (regs2
[2] & (1 << 2)) info
->FeatureSet
|= CPU_FEATURE_VIRT
;
314 if (regs2
[3] & (1 << 20)) info
->FeatureSet
|= CPU_FEATURE_NX
;
315 if (regs2
[3] & (1 << 27)) info
->FeatureSet
|= CPU_FEATURE_TSC
;
316 if (regs2
[3] & (1u << 31)) info
->FeatureSet
|= CPU_FEATURE_3DNOW
;
319 else if (regs
[1] == GENU
&& regs
[3] == INEI
&& regs
[2] == NTEL
)
321 info
->Level
= ((regs2
[0] >> 8) & 0xf) + ((regs2
[0] >> 20) & 0xff); /* family + extended family */
322 if(info
->Level
== 15) info
->Level
= 6;
324 /* repack model and stepping to make a "revision" */
325 info
->Revision
= ((regs2
[0] >> 16) & 0xf) << 12; /* extended model */
326 info
->Revision
|= ((regs2
[0] >> 4 ) & 0xf) << 8; /* model */
327 info
->Revision
|= regs2
[0] & 0xf; /* stepping */
329 if(regs2
[2] & (1 << 5)) info
->FeatureSet
|= CPU_FEATURE_VIRT
;
330 if(regs2
[3] & (1 << 21)) info
->FeatureSet
|= CPU_FEATURE_DS
;
332 do_cpuid( 0x80000000, regs
); /* get vendor cpuid level */
333 if (regs
[0] >= 0x80000001)
335 do_cpuid( 0x80000001, regs2
); /* get vendor features */
336 if (regs2
[3] & (1 << 20)) info
->FeatureSet
|= CPU_FEATURE_NX
;
337 if (regs2
[3] & (1 << 27)) info
->FeatureSet
|= CPU_FEATURE_TSC
;
342 info
->Level
= (regs2
[0] >> 8) & 0xf; /* family */
344 /* repack model and stepping to make a "revision" */
345 info
->Revision
= ((regs2
[0] >> 4 ) & 0xf) << 8; /* model */
346 info
->Revision
|= regs2
[0] & 0xf; /* stepping */
351 #elif defined(__arm__)
353 static inline void get_cpuinfo( SYSTEM_CPU_INFORMATION
*info
)
358 FILE *f
= fopen("/proc/cpuinfo", "r");
361 while (fgets( line
, sizeof(line
), f
))
363 /* NOTE: the ':' is the only character we can rely on */
364 if (!(value
= strchr(line
,':'))) continue;
365 /* terminate the valuename */
367 while ((s
>= line
) && (*s
== ' ' || *s
== '\t')) s
--;
369 /* and strip leading spaces from value */
371 while (*value
== ' ' || *value
== '\t') value
++;
372 if ((s
= strchr( value
,'\n' ))) *s
= 0;
373 if (!strcmp( line
, "CPU architecture" ))
375 info
->Level
= atoi(value
);
378 if (!strcmp( line
, "CPU revision" ))
380 info
->Revision
= atoi(value
);
383 if (!strcmp( line
, "Features" ))
385 if (strstr(value
, "crc32")) info
->FeatureSet
|= CPU_FEATURE_ARM_V8_CRC32
;
386 if (strstr(value
, "aes")) info
->FeatureSet
|= CPU_FEATURE_ARM_V8_CRYPTO
;
392 #elif defined(__FreeBSD__)
397 valsize
= sizeof(buf
);
398 if (!sysctlbyname("hw.machine_arch", &buf
, &valsize
, NULL
, 0) && sscanf(buf
, "armv%i", &value
) == 1)
401 valsize
= sizeof(value
);
402 if (!sysctlbyname("hw.floatingpoint", &value
, &valsize
, NULL
, 0))
403 info
->FeatureSet
|= CPU_FEATURE_ARM_VFP_32
;
405 FIXME("CPU Feature detection not implemented.\n");
407 info
->Architecture
= PROCESSOR_ARCHITECTURE_ARM
;
410 #elif defined(__aarch64__)
412 static void get_cpuinfo( SYSTEM_CPU_INFORMATION
*info
)
417 FILE *f
= fopen("/proc/cpuinfo", "r");
420 while (fgets( line
, sizeof(line
), f
))
422 /* NOTE: the ':' is the only character we can rely on */
423 if (!(value
= strchr(line
,':'))) continue;
424 /* terminate the valuename */
426 while ((s
>= line
) && (*s
== ' ' || *s
== '\t')) s
--;
428 /* and strip leading spaces from value */
430 while (*value
== ' ' || *value
== '\t') value
++;
431 if ((s
= strchr( value
,'\n' ))) *s
= 0;
432 if (!strcmp( line
, "CPU architecture" ))
434 info
->Level
= atoi(value
);
437 if (!strcmp( line
, "CPU revision" ))
439 info
->Revision
= atoi(value
);
442 if (!strcmp( line
, "Features" ))
444 if (strstr(value
, "crc32")) info
->FeatureSet
|= CPU_FEATURE_ARM_V8_CRC32
;
445 if (strstr(value
, "aes")) info
->FeatureSet
|= CPU_FEATURE_ARM_V8_CRYPTO
;
452 FIXME("CPU Feature detection not implemented.\n");
454 info
->Level
= max(info
->Level
, 8);
455 info
->Architecture
= PROCESSOR_ARCHITECTURE_ARM64
;
458 #endif /* End architecture specific feature detection for CPUs */
460 /******************************************************************
463 * inits a couple of places with CPU related information:
464 * - cpu_info in this file
465 * - Peb->NumberOfProcessors
466 * - SharedUserData->ProcessFeatures[] array
468 void init_cpu_info(void)
472 #ifdef _SC_NPROCESSORS_ONLN
473 num
= sysconf(_SC_NPROCESSORS_ONLN
);
477 WARN("Failed to detect the number of processors.\n");
479 #elif defined(CTL_HW) && defined(HW_NCPU)
481 size_t len
= sizeof(num
);
484 if (sysctl(mib
, 2, &num
, &len
, NULL
, 0) != 0)
487 WARN("Failed to detect the number of processors.\n");
491 FIXME("Detecting the number of processors is not supported.\n");
493 NtCurrentTeb()->Peb
->NumberOfProcessors
= num
;
494 get_cpuinfo( &cpu_info
);
495 TRACE( "<- CPU arch %d, level %d, rev %d, features 0x%x\n",
496 cpu_info
.Architecture
, cpu_info
.Level
, cpu_info
.Revision
, cpu_info
.FeatureSet
);
499 static BOOL
grow_logical_proc_buf( SYSTEM_LOGICAL_PROCESSOR_INFORMATION
**pdata
,
500 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
**pdataex
, DWORD
*max_len
)
504 SYSTEM_LOGICAL_PROCESSOR_INFORMATION
*new_data
;
507 new_data
= RtlReAllocateHeap(GetProcessHeap(), 0, *pdata
, *max_len
*sizeof(*new_data
));
515 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*new_dataex
;
518 new_dataex
= RtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, *pdataex
, *max_len
*sizeof(*new_dataex
));
522 *pdataex
= new_dataex
;
528 static DWORD
log_proc_ex_size_plus(DWORD size
)
530 /* add SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX.Relationship and .Size */
531 return sizeof(LOGICAL_PROCESSOR_RELATIONSHIP
) + sizeof(DWORD
) + size
;
534 static DWORD
count_bits(ULONG_PTR mask
)
545 /* Store package and core information for a logical processor. Parsing of processor
546 * data may happen in multiple passes; the 'id' parameter is then used to locate
547 * previously stored data. The type of data stored in 'id' depends on 'rel':
548 * - RelationProcessorPackage: package id ('CPU socket').
549 * - RelationProcessorCore: physical core number.
551 static BOOL
logical_proc_info_add_by_id( SYSTEM_LOGICAL_PROCESSOR_INFORMATION
**pdata
,
552 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
**pdataex
, DWORD
*len
,
553 DWORD
*pmax_len
, LOGICAL_PROCESSOR_RELATIONSHIP rel
,
554 DWORD id
, ULONG_PTR mask
)
560 for (i
= 0; i
< *len
; i
++)
562 if (rel
== RelationProcessorPackage
&& (*pdata
)[i
].Relationship
== rel
&& (*pdata
)[i
].u
.Reserved
[1] == id
)
564 (*pdata
)[i
].ProcessorMask
|= mask
;
567 else if (rel
== RelationProcessorCore
&& (*pdata
)[i
].Relationship
== rel
&& (*pdata
)[i
].u
.Reserved
[1] == id
)
571 while (*len
== *pmax_len
)
573 if (!grow_logical_proc_buf(pdata
, NULL
, pmax_len
)) return FALSE
;
576 (*pdata
)[i
].Relationship
= rel
;
577 (*pdata
)[i
].ProcessorMask
= mask
;
578 if (rel
== RelationProcessorCore
)
579 (*pdata
)[i
].u
.ProcessorCore
.Flags
= count_bits(mask
) > 1 ? LTP_PC_SMT
: 0;
580 (*pdata
)[i
].u
.Reserved
[0] = 0;
581 (*pdata
)[i
].u
.Reserved
[1] = id
;
586 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*dataex
;
591 dataex
= (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*)(((char *)*pdataex
) + ofs
);
592 if (rel
== RelationProcessorPackage
&& dataex
->Relationship
== rel
&& dataex
->u
.Processor
.Reserved
[1] == id
)
594 dataex
->u
.Processor
.GroupMask
[0].Mask
|= mask
;
597 else if (rel
== RelationProcessorCore
&& dataex
->Relationship
== rel
&& dataex
->u
.Processor
.Reserved
[1] == id
)
604 /* TODO: For now, just one group. If more than 64 processors, then we
605 * need another group. */
607 while (ofs
+ log_proc_ex_size_plus(sizeof(PROCESSOR_RELATIONSHIP
)) > *pmax_len
)
609 if (!grow_logical_proc_buf(NULL
, pdataex
, pmax_len
)) return FALSE
;
612 dataex
= (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*)(((char *)*pdataex
) + ofs
);
614 dataex
->Relationship
= rel
;
615 dataex
->Size
= log_proc_ex_size_plus(sizeof(PROCESSOR_RELATIONSHIP
));
616 if (rel
== RelationProcessorCore
)
617 dataex
->u
.Processor
.Flags
= count_bits(mask
) > 1 ? LTP_PC_SMT
: 0;
619 dataex
->u
.Processor
.Flags
= 0;
620 dataex
->u
.Processor
.EfficiencyClass
= 0;
621 dataex
->u
.Processor
.GroupCount
= 1;
622 dataex
->u
.Processor
.GroupMask
[0].Mask
= mask
;
623 dataex
->u
.Processor
.GroupMask
[0].Group
= 0;
624 /* mark for future lookup */
625 dataex
->u
.Processor
.Reserved
[0] = 0;
626 dataex
->u
.Processor
.Reserved
[1] = id
;
628 *len
+= dataex
->Size
;
634 static BOOL
logical_proc_info_add_cache( SYSTEM_LOGICAL_PROCESSOR_INFORMATION
**pdata
,
635 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
**pdataex
, DWORD
*len
,
636 DWORD
*pmax_len
, ULONG_PTR mask
, CACHE_DESCRIPTOR
*cache
)
642 for (i
= 0; i
< *len
; i
++)
644 if ((*pdata
)[i
].Relationship
==RelationCache
&& (*pdata
)[i
].ProcessorMask
==mask
645 && (*pdata
)[i
].u
.Cache
.Level
==cache
->Level
&& (*pdata
)[i
].u
.Cache
.Type
==cache
->Type
)
649 while (*len
== *pmax_len
)
650 if (!grow_logical_proc_buf(pdata
, NULL
, pmax_len
)) return FALSE
;
652 (*pdata
)[i
].Relationship
= RelationCache
;
653 (*pdata
)[i
].ProcessorMask
= mask
;
654 (*pdata
)[i
].u
.Cache
= *cache
;
659 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*dataex
;
662 for (ofs
= 0; ofs
< *len
; )
664 dataex
= (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*)(((char *)*pdataex
) + ofs
);
665 if (dataex
->Relationship
== RelationCache
&& dataex
->u
.Cache
.GroupMask
.Mask
== mask
&&
666 dataex
->u
.Cache
.Level
== cache
->Level
&& dataex
->u
.Cache
.Type
== cache
->Type
)
671 while (ofs
+ log_proc_ex_size_plus(sizeof(CACHE_RELATIONSHIP
)) > *pmax_len
)
673 if (!grow_logical_proc_buf(NULL
, pdataex
, pmax_len
)) return FALSE
;
676 dataex
= (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*)(((char *)*pdataex
) + ofs
);
678 dataex
->Relationship
= RelationCache
;
679 dataex
->Size
= log_proc_ex_size_plus(sizeof(CACHE_RELATIONSHIP
));
680 dataex
->u
.Cache
.Level
= cache
->Level
;
681 dataex
->u
.Cache
.Associativity
= cache
->Associativity
;
682 dataex
->u
.Cache
.LineSize
= cache
->LineSize
;
683 dataex
->u
.Cache
.CacheSize
= cache
->Size
;
684 dataex
->u
.Cache
.Type
= cache
->Type
;
685 dataex
->u
.Cache
.GroupMask
.Mask
= mask
;
686 dataex
->u
.Cache
.GroupMask
.Group
= 0;
688 *len
+= dataex
->Size
;
694 static BOOL
logical_proc_info_add_numa_node( SYSTEM_LOGICAL_PROCESSOR_INFORMATION
**pdata
,
695 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
**pdataex
, DWORD
*len
,
696 DWORD
*pmax_len
, ULONG_PTR mask
, DWORD node_id
)
700 while (*len
== *pmax_len
)
701 if (!grow_logical_proc_buf(pdata
, NULL
, pmax_len
)) return FALSE
;
703 (*pdata
)[*len
].Relationship
= RelationNumaNode
;
704 (*pdata
)[*len
].ProcessorMask
= mask
;
705 (*pdata
)[*len
].u
.NumaNode
.NodeNumber
= node_id
;
710 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*dataex
;
712 while (*len
+ log_proc_ex_size_plus(sizeof(NUMA_NODE_RELATIONSHIP
)) > *pmax_len
)
714 if (!grow_logical_proc_buf(NULL
, pdataex
, pmax_len
)) return FALSE
;
717 dataex
= (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*)(((char *)*pdataex
) + *len
);
719 dataex
->Relationship
= RelationNumaNode
;
720 dataex
->Size
= log_proc_ex_size_plus(sizeof(NUMA_NODE_RELATIONSHIP
));
721 dataex
->u
.NumaNode
.NodeNumber
= node_id
;
722 dataex
->u
.NumaNode
.GroupMask
.Mask
= mask
;
723 dataex
->u
.NumaNode
.GroupMask
.Group
= 0;
725 *len
+= dataex
->Size
;
731 static BOOL
logical_proc_info_add_group( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
**pdataex
,
732 DWORD
*len
, DWORD
*pmax_len
, DWORD num_cpus
, ULONG_PTR mask
)
734 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*dataex
;
736 while (*len
+ log_proc_ex_size_plus(sizeof(GROUP_RELATIONSHIP
)) > *pmax_len
)
737 if (!grow_logical_proc_buf(NULL
, pdataex
, pmax_len
)) return FALSE
;
739 dataex
= (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*)(((char *)*pdataex
) + *len
);
741 dataex
->Relationship
= RelationGroup
;
742 dataex
->Size
= log_proc_ex_size_plus(sizeof(GROUP_RELATIONSHIP
));
743 dataex
->u
.Group
.MaximumGroupCount
= 1;
744 dataex
->u
.Group
.ActiveGroupCount
= 1;
745 dataex
->u
.Group
.GroupInfo
[0].MaximumProcessorCount
= num_cpus
;
746 dataex
->u
.Group
.GroupInfo
[0].ActiveProcessorCount
= num_cpus
;
747 dataex
->u
.Group
.GroupInfo
[0].ActiveProcessorMask
= mask
;
749 *len
+= dataex
->Size
;
755 /* Helper function for counting bitmap values as commonly used by the Linux kernel
756 * for storing CPU masks in sysfs. The format is comma separated lists of hex values
757 * each max 32-bit e.g. "00ff" or even "00,00000000,0000ffff".
759 * Example files include:
760 * - /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_map
761 * - /sys/devices/system/cpu/cpu0/topology/thread_siblings
763 static BOOL
sysfs_parse_bitmap(const char *filename
, ULONG_PTR
*mask
)
768 f
= fopen(filename
, "r");
769 if (!f
) return FALSE
;
774 if (!fscanf(f
, "%x%c ", &r
, &op
)) break;
775 *mask
= (sizeof(ULONG_PTR
)>sizeof(int) ? *mask
<< (8 * sizeof(DWORD
)) : 0) + r
;
781 /* Helper function for counting number of elements in interval lists as used by
782 * the Linux kernel. The format is comma separated list of intervals of which
783 * each interval has the format of "begin-end" where begin and end are decimal
784 * numbers. E.g. "0-7", "0-7,16-23"
786 * Example files include:
787 * - /sys/devices/system/cpu/online
788 * - /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_list
789 * - /sys/devices/system/cpu/cpu0/topology/thread_siblings_list.
791 static BOOL
sysfs_count_list_elements(const char *filename
, DWORD
*result
)
795 f
= fopen(filename
, "r");
796 if (!f
) return FALSE
;
803 if (!fscanf(f
, "%u%c ", &beg
, &op
)) break;
805 fscanf(f
, "%u%c ", &end
, &op
);
809 *result
+= end
- beg
+ 1;
815 /* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
816 static NTSTATUS
create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION
**data
,
817 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
**dataex
,
818 DWORD
*max_len
, DWORD relation
)
820 static const char core_info
[] = "/sys/devices/system/cpu/cpu%u/topology/%s";
821 static const char cache_info
[] = "/sys/devices/system/cpu/cpu%u/cache/index%u/%s";
822 static const char numa_info
[] = "/sys/devices/system/node/node%u/cpumap";
824 FILE *fcpu_list
, *fnuma_list
, *f
;
825 DWORD len
= 0, beg
, end
, i
, j
, r
, num_cpus
= 0, max_cpus
= 0;
826 char op
, name
[MAX_PATH
];
827 ULONG_PTR all_cpus_mask
= 0;
829 /* On systems with a large number of CPU cores (32 or 64 depending on 32-bit or 64-bit),
830 * we have issues parsing processor information:
831 * - ULONG_PTR masks as used in data structures can't hold all cores. Requires splitting
832 * data appropriately into "processor groups". We are hard coding 1.
833 * - Thread affinity code in wineserver and our CPU parsing code here work independently.
834 * So far the Windows mask applied directly to Linux, but process groups break that.
835 * (NUMA systems you may have multiple non-full groups.)
837 if(sysfs_count_list_elements("/sys/devices/system/cpu/present", &max_cpus
) && max_cpus
> MAXIMUM_PROCESSORS
)
839 FIXME("Improve CPU info reporting: system supports %u logical cores, but only %u supported!\n",
840 max_cpus
, MAXIMUM_PROCESSORS
);
843 fcpu_list
= fopen("/sys/devices/system/cpu/online", "r");
844 if (!fcpu_list
) return STATUS_NOT_IMPLEMENTED
;
846 while (!feof(fcpu_list
))
848 if (!fscanf(fcpu_list
, "%u%c ", &beg
, &op
)) break;
849 if (op
== '-') fscanf(fcpu_list
, "%u%c ", &end
, &op
);
852 for(i
= beg
; i
<= end
; i
++)
855 ULONG_PTR thread_mask
= 0;
857 if (i
> 8*sizeof(ULONG_PTR
))
859 FIXME("skipping logical processor %d\n", i
);
863 if (relation
== RelationAll
|| relation
== RelationProcessorPackage
)
865 sprintf(name
, core_info
, i
, "physical_package_id");
866 f
= fopen(name
, "r");
873 if (!logical_proc_info_add_by_id(data
, dataex
, &len
, max_len
, RelationProcessorPackage
, r
, (ULONG_PTR
)1 << i
))
876 return STATUS_NO_MEMORY
;
880 /* Sysfs enumerates logical cores (and not physical cores), but Windows enumerates
881 * by physical core. Upon enumerating a logical core in sysfs, we register a physical
882 * core and all its logical cores. In order to not report physical cores multiple
883 * times, we pass a unique physical core ID to logical_proc_info_add_by_id and let
884 * that call figure out any duplication.
885 * Obtain a unique physical core ID from the first element of thread_siblings_list.
886 * This list provides logical cores sharing the same physical core. The IDs are based
887 * on kernel cpu core numbering as opposed to a hardware core ID like provided through
888 * 'core_id', so are suitable as a unique ID.
890 if(relation
== RelationAll
|| relation
== RelationProcessorCore
||
891 relation
== RelationNumaNode
|| relation
== RelationGroup
)
893 /* Mask of logical threads sharing same physical core in kernel core numbering. */
894 sprintf(name
, core_info
, i
, "thread_siblings");
895 if(!sysfs_parse_bitmap(name
, &thread_mask
)) thread_mask
= 1<<i
;
897 /* Needed later for NumaNode and Group. */
898 all_cpus_mask
|= thread_mask
;
900 if (relation
== RelationAll
|| relation
== RelationProcessorCore
)
902 sprintf(name
, core_info
, i
, "thread_siblings_list");
903 f
= fopen(name
, "r");
906 fscanf(f
, "%d%c", &phys_core
, &op
);
911 if (!logical_proc_info_add_by_id(data
, dataex
, &len
, max_len
, RelationProcessorCore
, phys_core
, thread_mask
))
914 return STATUS_NO_MEMORY
;
919 if (relation
== RelationAll
|| relation
== RelationCache
)
921 for(j
= 0; j
< 4; j
++)
923 CACHE_DESCRIPTOR cache
;
926 sprintf(name
, cache_info
, i
, j
, "shared_cpu_map");
927 if(!sysfs_parse_bitmap(name
, &mask
)) continue;
929 sprintf(name
, cache_info
, i
, j
, "level");
930 f
= fopen(name
, "r");
936 sprintf(name
, cache_info
, i
, j
, "ways_of_associativity");
937 f
= fopen(name
, "r");
941 cache
.Associativity
= r
;
943 sprintf(name
, cache_info
, i
, j
, "coherency_line_size");
944 f
= fopen(name
, "r");
950 sprintf(name
, cache_info
, i
, j
, "size");
951 f
= fopen(name
, "r");
953 fscanf(f
, "%u%c", &r
, &op
);
956 WARN("unknown cache size %u%c\n", r
, op
);
957 cache
.Size
= (op
=='K' ? r
*1024 : r
);
959 sprintf(name
, cache_info
, i
, j
, "type");
960 f
= fopen(name
, "r");
962 fscanf(f
, "%s", name
);
964 if (!memcmp(name
, "Data", 5))
965 cache
.Type
= CacheData
;
966 else if(!memcmp(name
, "Instruction", 11))
967 cache
.Type
= CacheInstruction
;
969 cache
.Type
= CacheUnified
;
971 if (!logical_proc_info_add_cache(data
, dataex
, &len
, max_len
, mask
, &cache
))
974 return STATUS_NO_MEMORY
;
982 num_cpus
= count_bits(all_cpus_mask
);
984 if(relation
== RelationAll
|| relation
== RelationNumaNode
)
986 fnuma_list
= fopen("/sys/devices/system/node/online", "r");
989 if (!logical_proc_info_add_numa_node(data
, dataex
, &len
, max_len
, all_cpus_mask
, 0))
990 return STATUS_NO_MEMORY
;
994 while (!feof(fnuma_list
))
996 if (!fscanf(fnuma_list
, "%u%c ", &beg
, &op
))
998 if (op
== '-') fscanf(fnuma_list
, "%u%c ", &end
, &op
);
1001 for (i
= beg
; i
<= end
; i
++)
1005 sprintf(name
, numa_info
, i
);
1006 if (!sysfs_parse_bitmap( name
, &mask
)) continue;
1008 if (!logical_proc_info_add_numa_node(data
, dataex
, &len
, max_len
, mask
, i
))
1011 return STATUS_NO_MEMORY
;
1019 if(dataex
&& (relation
== RelationAll
|| relation
== RelationGroup
))
1020 logical_proc_info_add_group(dataex
, &len
, max_len
, num_cpus
, all_cpus_mask
);
1023 *max_len
= len
* sizeof(**data
);
1027 return STATUS_SUCCESS
;
1030 #elif defined(__APPLE__)
1032 /* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
1033 static NTSTATUS
create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION
**data
,
1034 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
**dataex
,
1035 DWORD
*max_len
, DWORD relation
)
1037 DWORD pkgs_no
, cores_no
, lcpu_no
, lcpu_per_core
, cores_per_package
, assoc
, len
= 0;
1038 DWORD cache_ctrs
[10] = {0};
1039 ULONG_PTR all_cpus_mask
= 0;
1040 CACHE_DESCRIPTOR cache
[10];
1041 LONGLONG cache_size
, cache_line_size
, cache_sharing
[10];
1045 if (relation
!= RelationAll
)
1046 FIXME("Relationship filtering not implemented: 0x%x\n", relation
);
1048 lcpu_no
= NtCurrentTeb()->Peb
->NumberOfProcessors
;
1050 size
= sizeof(pkgs_no
);
1051 if (sysctlbyname("hw.packages", &pkgs_no
, &size
, NULL
, 0))
1054 size
= sizeof(cores_no
);
1055 if (sysctlbyname("hw.physicalcpu", &cores_no
, &size
, NULL
, 0))
1058 TRACE("%u logical CPUs from %u physical cores across %u packages\n",
1059 lcpu_no
, cores_no
, pkgs_no
);
1061 lcpu_per_core
= lcpu_no
/ cores_no
;
1062 cores_per_package
= cores_no
/ pkgs_no
;
1064 memset(cache
, 0, sizeof(cache
));
1066 cache
[1].Type
= CacheInstruction
;
1067 cache
[1].Associativity
= 8; /* reasonable default */
1068 cache
[1].LineSize
= 0x40; /* reasonable default */
1070 cache
[2].Type
= CacheData
;
1071 cache
[2].Associativity
= 8;
1072 cache
[2].LineSize
= 0x40;
1074 cache
[3].Type
= CacheUnified
;
1075 cache
[3].Associativity
= 8;
1076 cache
[3].LineSize
= 0x40;
1078 cache
[4].Type
= CacheUnified
;
1079 cache
[4].Associativity
= 12;
1080 cache
[4].LineSize
= 0x40;
1082 size
= sizeof(cache_line_size
);
1083 if (!sysctlbyname("hw.cachelinesize", &cache_line_size
, &size
, NULL
, 0))
1085 for (i
= 1; i
< 5; i
++) cache
[i
].LineSize
= cache_line_size
;
1088 /* TODO: set actual associativity for all caches */
1089 size
= sizeof(assoc
);
1090 if (!sysctlbyname("machdep.cpu.cache.L2_associativity", &assoc
, &size
, NULL
, 0))
1091 cache
[3].Associativity
= assoc
;
1093 size
= sizeof(cache_size
);
1094 if (!sysctlbyname("hw.l1icachesize", &cache_size
, &size
, NULL
, 0))
1095 cache
[1].Size
= cache_size
;
1096 size
= sizeof(cache_size
);
1097 if (!sysctlbyname("hw.l1dcachesize", &cache_size
, &size
, NULL
, 0))
1098 cache
[2].Size
= cache_size
;
1099 size
= sizeof(cache_size
);
1100 if (!sysctlbyname("hw.l2cachesize", &cache_size
, &size
, NULL
, 0))
1101 cache
[3].Size
= cache_size
;
1102 size
= sizeof(cache_size
);
1103 if (!sysctlbyname("hw.l3cachesize", &cache_size
, &size
, NULL
, 0))
1104 cache
[4].Size
= cache_size
;
1106 size
= sizeof(cache_sharing
);
1107 if (sysctlbyname("hw.cacheconfig", cache_sharing
, &size
, NULL
, 0) < 0)
1109 cache_sharing
[1] = lcpu_per_core
;
1110 cache_sharing
[2] = lcpu_per_core
;
1111 cache_sharing
[3] = lcpu_per_core
;
1112 cache_sharing
[4] = lcpu_no
;
1116 /* in cache[], indexes 1 and 2 are l1 caches */
1117 cache_sharing
[4] = cache_sharing
[3];
1118 cache_sharing
[3] = cache_sharing
[2];
1119 cache_sharing
[2] = cache_sharing
[1];
1122 for(p
= 0; p
< pkgs_no
; ++p
)
1124 for(j
= 0; j
< cores_per_package
&& p
* cores_per_package
+ j
< cores_no
; ++j
)
1129 for(k
= 0; k
< lcpu_per_core
; ++k
) mask
|= (ULONG_PTR
)1 << (j
* lcpu_per_core
+ k
);
1131 all_cpus_mask
|= mask
;
1133 /* add to package */
1134 if(!logical_proc_info_add_by_id(data
, dataex
, &len
, max_len
, RelationProcessorPackage
, p
, mask
))
1135 return STATUS_NO_MEMORY
;
1138 phys_core
= p
* cores_per_package
+ j
;
1139 if(!logical_proc_info_add_by_id(data
, dataex
, &len
, max_len
, RelationProcessorCore
, phys_core
, mask
))
1140 return STATUS_NO_MEMORY
;
1142 for(i
= 1; i
< 5; ++i
)
1144 if(cache_ctrs
[i
] == 0 && cache
[i
].Size
> 0)
1147 for(k
= 0; k
< cache_sharing
[i
]; ++k
)
1148 mask
|= (ULONG_PTR
)1 << (j
* lcpu_per_core
+ k
);
1150 if(!logical_proc_info_add_cache(data
, dataex
, &len
, max_len
, mask
, &cache
[i
]))
1151 return STATUS_NO_MEMORY
;
1154 cache_ctrs
[i
] += lcpu_per_core
;
1155 if(cache_ctrs
[i
] == cache_sharing
[i
]) cache_ctrs
[i
] = 0;
1160 /* OSX doesn't support NUMA, so just make one NUMA node for all CPUs */
1161 if(!logical_proc_info_add_numa_node(data
, dataex
, &len
, max_len
, all_cpus_mask
, 0))
1162 return STATUS_NO_MEMORY
;
1164 if(dataex
) logical_proc_info_add_group(dataex
, &len
, max_len
, lcpu_no
, all_cpus_mask
);
1167 *max_len
= len
* sizeof(**data
);
1171 return STATUS_SUCCESS
;
1176 static NTSTATUS
create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION
**data
,
1177 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
**dataex
,
1178 DWORD
*max_len
, DWORD relation
)
1181 return STATUS_NOT_IMPLEMENTED
;
1187 static void copy_smbios_string( char **buffer
, char *s
, size_t len
)
1190 memcpy(*buffer
, s
, len
+ 1);
1194 static size_t get_smbios_string( const char *path
, char *str
, size_t size
)
1199 if (!(file
= fopen(path
, "r"))) return 0;
1201 len
= fread( str
, 1, size
- 1, file
);
1204 if (len
>= 1 && str
[len
- 1] == '\n') len
--;
1209 static void get_system_uuid( GUID
*uuid
)
1211 static const unsigned char hex
[] =
1213 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
1214 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
1215 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
1216 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
1217 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
1218 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
1219 0,10,11,12,13,14,15 /* 0x60 */
1223 memset( uuid
, 0xff, sizeof(*uuid
) );
1224 if ((fd
= open( "/var/lib/dbus/machine-id", O_RDONLY
)) != -1)
1226 unsigned char buf
[32], *p
= buf
;
1227 if (read( fd
, buf
, sizeof(buf
) ) == sizeof(buf
))
1229 uuid
->Data1
= hex
[p
[6]] << 28 | hex
[p
[7]] << 24 | hex
[p
[4]] << 20 | hex
[p
[5]] << 16 |
1230 hex
[p
[2]] << 12 | hex
[p
[3]] << 8 | hex
[p
[0]] << 4 | hex
[p
[1]];
1232 uuid
->Data2
= hex
[p
[10]] << 12 | hex
[p
[11]] << 8 | hex
[p
[8]] << 4 | hex
[p
[9]];
1233 uuid
->Data3
= hex
[p
[14]] << 12 | hex
[p
[15]] << 8 | hex
[p
[12]] << 4 | hex
[p
[13]];
1235 uuid
->Data4
[0] = hex
[p
[16]] << 4 | hex
[p
[17]];
1236 uuid
->Data4
[1] = hex
[p
[18]] << 4 | hex
[p
[19]];
1237 uuid
->Data4
[2] = hex
[p
[20]] << 4 | hex
[p
[21]];
1238 uuid
->Data4
[3] = hex
[p
[22]] << 4 | hex
[p
[23]];
1239 uuid
->Data4
[4] = hex
[p
[24]] << 4 | hex
[p
[25]];
1240 uuid
->Data4
[5] = hex
[p
[26]] << 4 | hex
[p
[27]];
1241 uuid
->Data4
[6] = hex
[p
[28]] << 4 | hex
[p
[29]];
1242 uuid
->Data4
[7] = hex
[p
[30]] << 4 | hex
[p
[31]];
1248 static NTSTATUS
get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION
*sfti
, ULONG available_len
,
1249 ULONG
*required_len
)
1251 switch (sfti
->ProviderSignature
)
1255 char bios_vendor
[128], bios_version
[128], bios_date
[128];
1256 size_t bios_vendor_len
, bios_version_len
, bios_date_len
;
1257 char system_vendor
[128], system_product
[128], system_version
[128], system_serial
[128];
1258 size_t system_vendor_len
, system_product_len
, system_version_len
, system_serial_len
;
1259 char system_sku
[128], system_family
[128];
1260 size_t system_sku_len
, system_family_len
;
1261 char board_vendor
[128], board_product
[128], board_version
[128], board_serial
[128];
1262 size_t board_vendor_len
, board_product_len
, board_version_len
, board_serial_len
;
1263 char chassis_vendor
[128], chassis_version
[128], chassis_serial
[128], chassis_asset_tag
[128];
1264 char chassis_type
[11] = "2"; /* unknown */
1265 size_t chassis_vendor_len
, chassis_version_len
, chassis_serial_len
, chassis_asset_tag_len
;
1266 char *buffer
= (char*)sfti
->TableBuffer
;
1268 struct smbios_prologue
*prologue
;
1269 struct smbios_bios
*bios
;
1270 struct smbios_system
*system
;
1271 struct smbios_board
*board
;
1272 struct smbios_chassis
*chassis
;
1274 #define S(s) s, sizeof(s)
1275 bios_vendor_len
= get_smbios_string("/sys/class/dmi/id/bios_vendor", S(bios_vendor
));
1276 bios_version_len
= get_smbios_string("/sys/class/dmi/id/bios_version", S(bios_version
));
1277 bios_date_len
= get_smbios_string("/sys/class/dmi/id/bios_date", S(bios_date
));
1278 system_vendor_len
= get_smbios_string("/sys/class/dmi/id/sys_vendor", S(system_vendor
));
1279 system_product_len
= get_smbios_string("/sys/class/dmi/id/product_name", S(system_product
));
1280 system_version_len
= get_smbios_string("/sys/class/dmi/id/product_version", S(system_version
));
1281 system_serial_len
= get_smbios_string("/sys/class/dmi/id/product_serial", S(system_serial
));
1282 system_sku_len
= get_smbios_string("/sys/class/dmi/id/product_sku", S(system_sku
));
1283 system_family_len
= get_smbios_string("/sys/class/dmi/id/product_family", S(system_family
));
1284 board_vendor_len
= get_smbios_string("/sys/class/dmi/id/board_vendor", S(board_vendor
));
1285 board_product_len
= get_smbios_string("/sys/class/dmi/id/board_name", S(board_product
));
1286 board_version_len
= get_smbios_string("/sys/class/dmi/id/board_version", S(board_version
));
1287 board_serial_len
= get_smbios_string("/sys/class/dmi/id/board_serial", S(board_serial
));
1288 chassis_vendor_len
= get_smbios_string("/sys/class/dmi/id/chassis_vendor", S(chassis_vendor
));
1289 chassis_version_len
= get_smbios_string("/sys/class/dmi/id/chassis_version", S(chassis_version
));
1290 chassis_serial_len
= get_smbios_string("/sys/class/dmi/id/chassis_serial", S(chassis_serial
));
1291 chassis_asset_tag_len
= get_smbios_string("/sys/class/dmi/id/chassis_tag", S(chassis_asset_tag
));
1292 get_smbios_string("/sys/class/dmi/id/chassis_type", S(chassis_type
));
1295 *required_len
= sizeof(struct smbios_prologue
);
1297 #define L(l) (l + (l ? 1 : 0))
1298 *required_len
+= sizeof(struct smbios_bios
);
1299 *required_len
+= max(L(bios_vendor_len
) + L(bios_version_len
) + L(bios_date_len
) + 1, 2);
1301 *required_len
+= sizeof(struct smbios_system
);
1302 *required_len
+= max(L(system_vendor_len
) + L(system_product_len
) + L(system_version_len
) +
1303 L(system_serial_len
) + L(system_sku_len
) + L(system_family_len
) + 1, 2);
1305 *required_len
+= sizeof(struct smbios_board
);
1306 *required_len
+= max(L(board_vendor_len
) + L(board_product_len
) + L(board_version_len
) + L(board_serial_len
) + 1, 2);
1308 *required_len
+= sizeof(struct smbios_chassis
);
1309 *required_len
+= max(L(chassis_vendor_len
) + L(chassis_version_len
) + L(chassis_serial_len
) +
1310 L(chassis_asset_tag_len
) + 1, 2);
1313 sfti
->TableBufferLength
= *required_len
;
1315 *required_len
+= FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION
, TableBuffer
);
1317 if (available_len
< *required_len
)
1318 return STATUS_BUFFER_TOO_SMALL
;
1320 prologue
= (struct smbios_prologue
*)buffer
;
1321 prologue
->calling_method
= 0;
1322 prologue
->major_version
= 2;
1323 prologue
->minor_version
= 4;
1324 prologue
->revision
= 0;
1325 prologue
->length
= sfti
->TableBufferLength
- sizeof(struct smbios_prologue
);
1326 buffer
+= sizeof(struct smbios_prologue
);
1329 bios
= (struct smbios_bios
*)buffer
;
1331 bios
->hdr
.length
= sizeof(struct smbios_bios
);
1332 bios
->hdr
.handle
= 0;
1333 bios
->vendor
= bios_vendor_len
? ++string_count
: 0;
1334 bios
->version
= bios_version_len
? ++string_count
: 0;
1336 bios
->date
= bios_date_len
? ++string_count
: 0;
1338 bios
->characteristics
= 0x4; /* not supported */
1339 bios
->characteristics_ext
[0] = 0;
1340 bios
->characteristics_ext
[1] = 0;
1341 bios
->system_bios_major_release
= 0xFF; /* not supported */
1342 bios
->system_bios_minor_release
= 0xFF; /* not supported */
1343 bios
->ec_firmware_major_release
= 0xFF; /* not supported */
1344 bios
->ec_firmware_minor_release
= 0xFF; /* not supported */
1345 buffer
+= sizeof(struct smbios_bios
);
1347 copy_smbios_string(&buffer
, bios_vendor
, bios_vendor_len
);
1348 copy_smbios_string(&buffer
, bios_version
, bios_version_len
);
1349 copy_smbios_string(&buffer
, bios_date
, bios_date_len
);
1350 if (!string_count
) *buffer
++ = 0;
1354 system
= (struct smbios_system
*)buffer
;
1355 system
->hdr
.type
= 1;
1356 system
->hdr
.length
= sizeof(struct smbios_system
);
1357 system
->hdr
.handle
= 0;
1358 system
->vendor
= system_vendor_len
? ++string_count
: 0;
1359 system
->product
= system_product_len
? ++string_count
: 0;
1360 system
->version
= system_version_len
? ++string_count
: 0;
1361 system
->serial
= system_serial_len
? ++string_count
: 0;
1362 get_system_uuid( (GUID
*)system
->uuid
);
1363 system
->wake_up_type
= 0x02; /* unknown */
1364 system
->sku_number
= system_sku_len
? ++string_count
: 0;
1365 system
->family
= system_family_len
? ++string_count
: 0;
1366 buffer
+= sizeof(struct smbios_system
);
1368 copy_smbios_string(&buffer
, system_vendor
, system_vendor_len
);
1369 copy_smbios_string(&buffer
, system_product
, system_product_len
);
1370 copy_smbios_string(&buffer
, system_version
, system_version_len
);
1371 copy_smbios_string(&buffer
, system_serial
, system_serial_len
);
1372 copy_smbios_string(&buffer
, system_sku
, system_sku_len
);
1373 copy_smbios_string(&buffer
, system_family
, system_family_len
);
1374 if (!string_count
) *buffer
++ = 0;
1378 board
= (struct smbios_board
*)buffer
;
1379 board
->hdr
.type
= 2;
1380 board
->hdr
.length
= sizeof(struct smbios_board
);
1381 board
->hdr
.handle
= 0;
1382 board
->vendor
= board_vendor_len
? ++string_count
: 0;
1383 board
->product
= board_product_len
? ++string_count
: 0;
1384 board
->version
= board_version_len
? ++string_count
: 0;
1385 board
->serial
= board_serial_len
? ++string_count
: 0;
1386 buffer
+= sizeof(struct smbios_board
);
1388 copy_smbios_string(&buffer
, board_vendor
, board_vendor_len
);
1389 copy_smbios_string(&buffer
, board_product
, board_product_len
);
1390 copy_smbios_string(&buffer
, board_version
, board_version_len
);
1391 copy_smbios_string(&buffer
, board_serial
, board_serial_len
);
1392 if (!string_count
) *buffer
++ = 0;
1396 chassis
= (struct smbios_chassis
*)buffer
;
1397 chassis
->hdr
.type
= 3;
1398 chassis
->hdr
.length
= sizeof(struct smbios_chassis
);
1399 chassis
->hdr
.handle
= 0;
1400 chassis
->vendor
= chassis_vendor_len
? ++string_count
: 0;
1401 chassis
->type
= atoi(chassis_type
);
1402 chassis
->version
= chassis_version_len
? ++string_count
: 0;
1403 chassis
->serial
= chassis_serial_len
? ++string_count
: 0;
1404 chassis
->asset_tag
= chassis_asset_tag_len
? ++string_count
: 0;
1405 chassis
->boot_state
= 0x02; /* unknown */
1406 chassis
->power_supply_state
= 0x02; /* unknown */
1407 chassis
->thermal_state
= 0x02; /* unknown */
1408 chassis
->security_status
= 0x02; /* unknown */
1409 buffer
+= sizeof(struct smbios_chassis
);
1411 copy_smbios_string(&buffer
, chassis_vendor
, chassis_vendor_len
);
1412 copy_smbios_string(&buffer
, chassis_version
, chassis_version_len
);
1413 copy_smbios_string(&buffer
, chassis_serial
, chassis_serial_len
);
1414 copy_smbios_string(&buffer
, chassis_asset_tag
, chassis_asset_tag_len
);
1415 if (!string_count
) *buffer
++ = 0;
1418 return STATUS_SUCCESS
;
1421 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION provider %08x\n", sfti
->ProviderSignature
);
1422 return STATUS_NOT_IMPLEMENTED
;
1426 #elif defined(__APPLE__)
1428 static NTSTATUS
get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION
*sfti
, ULONG available_len
,
1429 ULONG
*required_len
)
1431 switch (sfti
->ProviderSignature
)
1435 io_service_t service
;
1439 struct smbios_prologue
*prologue
;
1440 BYTE major_version
= 2, minor_version
= 0;
1442 if (!(service
= IOServiceGetMatchingService(kIOMasterPortDefault
, IOServiceMatching("AppleSMBIOS"))))
1444 WARN("can't find AppleSMBIOS service\n");
1445 return STATUS_NO_MEMORY
;
1448 if (!(data
= IORegistryEntryCreateCFProperty(service
, CFSTR("SMBIOS-EPS"), kCFAllocatorDefault
, 0)))
1450 WARN("can't find SMBIOS entry point\n");
1451 IOObjectRelease(service
);
1452 return STATUS_NO_MEMORY
;
1455 len
= CFDataGetLength(data
);
1456 ptr
= CFDataGetBytePtr(data
);
1457 if (len
>= 8 && !memcmp(ptr
, "_SM_", 4))
1459 major_version
= ptr
[6];
1460 minor_version
= ptr
[7];
1464 if (!(data
= IORegistryEntryCreateCFProperty(service
, CFSTR("SMBIOS"), kCFAllocatorDefault
, 0)))
1466 WARN("can't find SMBIOS table\n");
1467 IOObjectRelease(service
);
1468 return STATUS_NO_MEMORY
;
1471 len
= CFDataGetLength(data
);
1472 ptr
= CFDataGetBytePtr(data
);
1473 sfti
->TableBufferLength
= sizeof(*prologue
) + len
;
1474 *required_len
= sfti
->TableBufferLength
+ FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION
, TableBuffer
);
1475 if (available_len
< *required_len
)
1478 IOObjectRelease(service
);
1479 return STATUS_BUFFER_TOO_SMALL
;
1482 prologue
= (struct smbios_prologue
*)sfti
->TableBuffer
;
1483 prologue
->calling_method
= 0;
1484 prologue
->major_version
= major_version
;
1485 prologue
->minor_version
= minor_version
;
1486 prologue
->revision
= 0;
1487 prologue
->length
= sfti
->TableBufferLength
- sizeof(*prologue
);
1489 memcpy(sfti
->TableBuffer
+ sizeof(*prologue
), ptr
, len
);
1492 IOObjectRelease(service
);
1493 return STATUS_SUCCESS
;
1496 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION provider %08x\n", sfti
->ProviderSignature
);
1497 return STATUS_NOT_IMPLEMENTED
;
1503 static NTSTATUS
get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION
*sfti
, ULONG available_len
,
1504 ULONG
*required_len
)
1506 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION\n");
1507 sfti
->TableBufferLength
= 0;
1508 return STATUS_NOT_IMPLEMENTED
;
1513 static void get_performance_info( SYSTEM_PERFORMANCE_INFORMATION
*info
)
1515 unsigned long long totalram
= 0, freeram
= 0, totalswap
= 0, freeswap
= 0;
1518 memset( info
, 0, sizeof(*info
) );
1520 if ((fp
= fopen("/proc/uptime", "r")))
1522 double uptime
, idle_time
;
1524 fscanf(fp
, "%lf %lf", &uptime
, &idle_time
);
1526 info
->IdleTime
.QuadPart
= 10000000 * idle_time
;
1530 static ULONGLONG idle
;
1531 /* many programs expect IdleTime to change so fake change */
1532 info
->IdleTime
.QuadPart
= ++idle
;
1536 if ((fp
= fopen("/proc/meminfo", "r")))
1538 unsigned long long value
;
1541 while (fgets(line
, sizeof(line
), fp
))
1543 if(sscanf(line
, "MemTotal: %llu kB", &value
) == 1)
1544 totalram
+= value
* 1024;
1545 else if(sscanf(line
, "MemFree: %llu kB", &value
) == 1)
1546 freeram
+= value
* 1024;
1547 else if(sscanf(line
, "SwapTotal: %llu kB", &value
) == 1)
1548 totalswap
+= value
* 1024;
1549 else if(sscanf(line
, "SwapFree: %llu kB", &value
) == 1)
1550 freeswap
+= value
* 1024;
1551 else if (sscanf(line
, "Buffers: %llu", &value
))
1552 freeram
+= value
* 1024;
1553 else if (sscanf(line
, "Cached: %llu", &value
))
1554 freeram
+= value
* 1024;
1558 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || \
1559 defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
1573 mib
[1] = HW_MEMSIZE
;
1574 size_sys
= sizeof(val64
);
1575 if (!sysctl(mib
, 2, &val64
, &size_sys
, NULL
, 0) && size_sys
== sizeof(val64
)) totalram
= val64
;
1579 #ifdef HAVE_MACH_MACH_H
1581 host_name_port_t host
= mach_host_self();
1582 mach_msg_type_number_t count
;
1583 #ifdef HOST_VM_INFO64_COUNT
1584 vm_statistics64_data_t vm_stat
;
1586 count
= HOST_VM_INFO64_COUNT
;
1587 if (host_statistics64(host
, HOST_VM_INFO64
, (host_info64_t
)&vm_stat
, &count
) == KERN_SUCCESS
)
1588 freeram
= (vm_stat
.free_count
+ vm_stat
.inactive_count
) * (ULONGLONG
)page_size
;
1592 host_basic_info_data_t info
;
1593 count
= HOST_BASIC_INFO_COUNT
;
1594 if (host_info(host
, HOST_BASIC_INFO
, (host_info_t
)&info
, &count
) == KERN_SUCCESS
)
1595 totalram
= info
.max_mem
;
1597 mach_port_deallocate(mach_task_self(), host
);
1603 mib
[1] = HW_PHYSMEM
;
1604 size_sys
= sizeof(val
);
1605 if (!sysctl(mib
, 2, &val
, &size_sys
, NULL
, 0) && size_sys
== sizeof(val
)) totalram
= val
;
1609 mib
[1] = HW_USERMEM
;
1610 size_sys
= sizeof(val
);
1611 if (!sysctl(mib
, 2, &val
, &size_sys
, NULL
, 0) && size_sys
== sizeof(val
)) freeram
= val
;
1615 struct xsw_usage swap
;
1617 mib
[1] = VM_SWAPUSAGE
;
1618 size_sys
= sizeof(swap
);
1619 if (!sysctl(mib
, 2, &swap
, &size_sys
, NULL
, 0) && size_sys
== sizeof(swap
))
1621 totalswap
= swap
.xsu_total
;
1622 freeswap
= swap
.xsu_avail
;
1628 info
->AvailablePages
= freeram
/ page_size
;
1629 info
->TotalCommittedPages
= (totalram
+ totalswap
- freeram
- freeswap
) / page_size
;
1630 info
->TotalCommitLimit
= (totalram
+ totalswap
) / page_size
;
1634 /******************************************************************************
1635 * NtQuerySystemInformation (NTDLL.@)
1637 NTSTATUS WINAPI
NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS
class,
1638 void *info
, ULONG size
, ULONG
*ret_size
)
1640 NTSTATUS ret
= STATUS_SUCCESS
;
1643 TRACE( "(0x%08x,%p,0x%08x,%p)\n", class, info
, size
, ret_size
);
1647 case SystemBasicInformation
:
1649 SYSTEM_BASIC_INFORMATION sbi
;
1651 virtual_get_system_info( &sbi
);
1655 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1656 else memcpy( info
, &sbi
, len
);
1658 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1662 case SystemCpuInformation
:
1663 if (size
>= (len
= sizeof(cpu_info
)))
1665 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1666 else memcpy(info
, &cpu_info
, len
);
1668 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1671 case SystemPerformanceInformation
:
1673 SYSTEM_PERFORMANCE_INFORMATION spi
;
1674 static BOOL fixme_written
= FALSE
;
1676 get_performance_info( &spi
);
1680 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1681 else memcpy( info
, &spi
, len
);
1683 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1684 if(!fixme_written
) {
1685 FIXME("info_class SYSTEM_PERFORMANCE_INFORMATION\n");
1686 fixme_written
= TRUE
;
1691 case SystemTimeOfDayInformation
:
1695 SYSTEM_TIMEOFDAY_INFORMATION sti
= {{{ 0 }}};
1697 sti
.BootTime
.QuadPart
= server_start_time
;
1699 tm
= gmtime( &now
);
1700 sti
.TimeZoneBias
.QuadPart
= mktime( tm
) - now
;
1701 tm
= localtime( &now
);
1702 if (tm
->tm_isdst
) sti
.TimeZoneBias
.QuadPart
-= 3600;
1703 sti
.TimeZoneBias
.QuadPart
*= TICKSPERSEC
;
1704 NtQuerySystemTime( &sti
.SystemTime
);
1706 if (size
<= sizeof(sti
))
1709 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1710 else memcpy( info
, &sti
, size
);
1712 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1716 case SystemProcessInformation
:
1718 SYSTEM_PROCESS_INFORMATION
*spi
= info
;
1719 SYSTEM_PROCESS_INFORMATION
*last
= NULL
;
1721 WCHAR procname
[1024];
1724 DWORD procstructlen
= 0;
1726 SERVER_START_REQ( create_snapshot
)
1728 req
->flags
= SNAP_PROCESS
| SNAP_THREAD
;
1729 if (!(ret
= wine_server_call( req
))) handle
= wine_server_ptr_handle( reply
->handle
);
1734 while (ret
== STATUS_SUCCESS
)
1736 SERVER_START_REQ( next_process
)
1738 req
->handle
= wine_server_obj_handle( handle
);
1739 req
->reset
= (len
== 0);
1740 wine_server_set_reply( req
, procname
, sizeof(procname
) - sizeof(WCHAR
) );
1741 if (!(ret
= wine_server_call( req
)))
1743 /* Make sure procname is 0 terminated */
1744 procname
[wine_server_reply_size(reply
) / sizeof(WCHAR
)] = 0;
1746 /* Get only the executable name, not the path */
1747 if ((exename
= wcsrchr(procname
, '\\')) != NULL
) exename
++;
1748 else exename
= procname
;
1750 wlen
= (wcslen(exename
) + 1) * sizeof(WCHAR
);
1751 procstructlen
= sizeof(*spi
) + wlen
+ ((reply
->threads
- 1) * sizeof(SYSTEM_THREAD_INFORMATION
));
1753 if (size
>= len
+ procstructlen
)
1755 /* ftCreationTime, ftUserTime, ftKernelTime;
1756 * vmCounters, ioCounters
1758 memset(spi
, 0, sizeof(*spi
));
1760 spi
->NextEntryOffset
= procstructlen
- wlen
;
1761 spi
->dwThreadCount
= reply
->threads
;
1763 /* spi->pszProcessName will be set later on */
1765 spi
->dwBasePriority
= reply
->priority
;
1766 spi
->UniqueProcessId
= UlongToHandle(reply
->pid
);
1767 spi
->ParentProcessId
= UlongToHandle(reply
->ppid
);
1768 spi
->HandleCount
= reply
->handles
;
1770 /* spi->ti will be set later on */
1773 len
+= procstructlen
;
1777 if (ret
!= STATUS_SUCCESS
)
1779 if (ret
== STATUS_NO_MORE_FILES
) ret
= STATUS_SUCCESS
;
1787 /* set thread info */
1789 while (ret
== STATUS_SUCCESS
)
1791 SERVER_START_REQ( next_thread
)
1793 req
->handle
= wine_server_obj_handle( handle
);
1794 req
->reset
= (j
== 0);
1795 if (!(ret
= wine_server_call( req
)))
1798 if (UlongToHandle(reply
->pid
) == spi
->UniqueProcessId
)
1800 /* ftKernelTime, ftUserTime, ftCreateTime;
1801 * dwTickCount, dwStartAddress
1804 memset(&spi
->ti
[i
], 0, sizeof(spi
->ti
));
1806 spi
->ti
[i
].CreateTime
.QuadPart
= 0xdeadbeef;
1807 spi
->ti
[i
].ClientId
.UniqueProcess
= UlongToHandle(reply
->pid
);
1808 spi
->ti
[i
].ClientId
.UniqueThread
= UlongToHandle(reply
->tid
);
1809 spi
->ti
[i
].dwCurrentPriority
= reply
->base_pri
+ reply
->delta_pri
;
1810 spi
->ti
[i
].dwBasePriority
= reply
->base_pri
;
1817 if (ret
== STATUS_NO_MORE_FILES
) ret
= STATUS_SUCCESS
;
1819 /* now append process name */
1820 spi
->ProcessName
.Buffer
= (WCHAR
*)((char*)spi
+ spi
->NextEntryOffset
);
1821 spi
->ProcessName
.Length
= wlen
- sizeof(WCHAR
);
1822 spi
->ProcessName
.MaximumLength
= wlen
;
1823 memcpy( spi
->ProcessName
.Buffer
, exename
, wlen
);
1824 spi
->NextEntryOffset
+= wlen
;
1826 spi
= (SYSTEM_PROCESS_INFORMATION
*)((char*)spi
+ spi
->NextEntryOffset
);
1829 if (ret
== STATUS_SUCCESS
&& last
) last
->NextEntryOffset
= 0;
1830 if (len
> size
) ret
= STATUS_INFO_LENGTH_MISMATCH
;
1831 if (handle
) NtClose( handle
);
1835 case SystemProcessorPerformanceInformation
:
1837 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
*sppi
= NULL
;
1838 unsigned int cpus
= 0;
1839 int out_cpus
= size
/ sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
);
1844 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1850 processor_cpu_load_info_data_t
*pinfo
;
1851 mach_msg_type_number_t info_count
;
1853 if (host_processor_info( mach_host_self (),
1854 PROCESSOR_CPU_LOAD_INFO
,
1856 (processor_info_array_t
*)&pinfo
,
1860 cpus
= min(cpus
,out_cpus
);
1861 len
= sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
) * cpus
;
1862 sppi
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
1863 for (i
= 0; i
< cpus
; i
++)
1865 sppi
[i
].IdleTime
.QuadPart
= pinfo
[i
].cpu_ticks
[CPU_STATE_IDLE
];
1866 sppi
[i
].KernelTime
.QuadPart
= pinfo
[i
].cpu_ticks
[CPU_STATE_SYSTEM
];
1867 sppi
[i
].UserTime
.QuadPart
= pinfo
[i
].cpu_ticks
[CPU_STATE_USER
];
1869 vm_deallocate (mach_task_self (), (vm_address_t
) pinfo
, info_count
* sizeof(natural_t
));
1874 FILE *cpuinfo
= fopen("/proc/stat", "r");
1877 unsigned long clk_tck
= sysconf(_SC_CLK_TCK
);
1878 unsigned long usr
,nice
,sys
,idle
,remainder
[8];
1883 /* first line is combined usage */
1884 while (fgets(line
,255,cpuinfo
))
1886 count
= sscanf(line
, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
1887 name
, &usr
, &nice
, &sys
, &idle
,
1888 &remainder
[0], &remainder
[1], &remainder
[2], &remainder
[3],
1889 &remainder
[4], &remainder
[5], &remainder
[6], &remainder
[7]);
1891 if (count
< 5 || strncmp( name
, "cpu", 3 )) break;
1892 for (i
= 0; i
+ 5 < count
; ++i
) sys
+= remainder
[i
];
1895 cpus
= atoi( name
+ 3 ) + 1;
1896 if (cpus
> out_cpus
) break;
1897 len
= sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
) * cpus
;
1899 sppi
= RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, sppi
, len
);
1901 sppi
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
1903 sppi
[cpus
-1].IdleTime
.QuadPart
= (ULONGLONG
)idle
* 10000000 / clk_tck
;
1904 sppi
[cpus
-1].KernelTime
.QuadPart
= (ULONGLONG
)sys
* 10000000 / clk_tck
;
1905 sppi
[cpus
-1].UserTime
.QuadPart
= (ULONGLONG
)usr
* 10000000 / clk_tck
;
1915 cpus
= min(NtCurrentTeb()->Peb
->NumberOfProcessors
, out_cpus
);
1916 len
= sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
) * cpus
;
1917 sppi
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
1918 FIXME("stub info_class SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION\n");
1919 /* many programs expect these values to change so fake change */
1920 for (n
= 0; n
< cpus
; n
++)
1922 sppi
[n
].KernelTime
.QuadPart
= 1 * i
;
1923 sppi
[n
].UserTime
.QuadPart
= 2 * i
;
1924 sppi
[n
].IdleTime
.QuadPart
= 3 * i
;
1931 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1932 else memcpy( info
, sppi
, len
);
1934 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
1936 RtlFreeHeap(GetProcessHeap(),0,sppi
);
1940 case SystemModuleInformation
:
1941 /* FIXME: should be system-wide */
1942 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
1943 else ret
= LdrQueryProcessModuleInformation( info
, size
, &len
);
1946 case SystemHandleInformation
:
1948 struct handle_info
*handle_info
;
1949 DWORD i
, num_handles
;
1951 if (size
< sizeof(SYSTEM_HANDLE_INFORMATION
))
1953 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1959 ret
= STATUS_ACCESS_VIOLATION
;
1963 num_handles
= (size
- FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION
, Handle
)) / sizeof(SYSTEM_HANDLE_ENTRY
);
1964 if (!(handle_info
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*handle_info
) * num_handles
)))
1965 return STATUS_NO_MEMORY
;
1967 SERVER_START_REQ( get_system_handles
)
1969 wine_server_set_reply( req
, handle_info
, sizeof(*handle_info
) * num_handles
);
1970 if (!(ret
= wine_server_call( req
)))
1972 SYSTEM_HANDLE_INFORMATION
*shi
= info
;
1973 shi
->Count
= wine_server_reply_size( req
) / sizeof(*handle_info
);
1974 len
= FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION
, Handle
[shi
->Count
] );
1975 for (i
= 0; i
< shi
->Count
; i
++)
1977 memset( &shi
->Handle
[i
], 0, sizeof(shi
->Handle
[i
]) );
1978 shi
->Handle
[i
].OwnerPid
= handle_info
[i
].owner
;
1979 shi
->Handle
[i
].HandleValue
= handle_info
[i
].handle
;
1980 shi
->Handle
[i
].AccessMask
= handle_info
[i
].access
;
1981 /* FIXME: Fill out ObjectType, HandleFlags, ObjectPointer */
1984 else if (ret
== STATUS_BUFFER_TOO_SMALL
)
1986 len
= FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION
, Handle
[reply
->count
] );
1987 ret
= STATUS_INFO_LENGTH_MISMATCH
;
1992 RtlFreeHeap( GetProcessHeap(), 0, handle_info
);
1996 case SystemCacheInformation
:
1998 SYSTEM_CACHE_INFORMATION sci
= { 0 };
2003 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
2004 else memcpy( info
, &sci
, len
);
2006 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2007 FIXME("info_class SYSTEM_CACHE_INFORMATION\n");
2011 case SystemInterruptInformation
:
2013 SYSTEM_INTERRUPT_INFORMATION sii
= {{ 0 }};
2018 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
2019 else memcpy( info
, &sii
, len
);
2021 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2022 FIXME("info_class SYSTEM_INTERRUPT_INFORMATION\n");
2026 case SystemTimeAdjustmentInformation
:
2028 SYSTEM_TIME_ADJUSTMENT_QUERY query
= { 156250, 156250, TRUE
};
2030 len
= sizeof(query
);
2033 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
2034 else memcpy( info
, &query
, len
);
2036 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2040 case SystemKernelDebuggerInformation
:
2042 SYSTEM_KERNEL_DEBUGGER_INFORMATION skdi
;
2044 skdi
.DebuggerEnabled
= FALSE
;
2045 skdi
.DebuggerNotPresent
= TRUE
;
2049 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
2050 else memcpy( info
, &skdi
, len
);
2052 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2056 case SystemRegistryQuotaInformation
:
2058 /* Something to do with the size of the registry *
2059 * Since we don't have a size limitation, fake it *
2060 * This is almost certainly wrong. *
2061 * This sets each of the three words in the struct to 32 MB, *
2062 * which is enough to make the IE 5 installer happy. */
2063 SYSTEM_REGISTRY_QUOTA_INFORMATION srqi
;
2065 srqi
.RegistryQuotaAllowed
= 0x2000000;
2066 srqi
.RegistryQuotaUsed
= 0x200000;
2067 srqi
.Reserved1
= (void*)0x200000;
2072 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
2075 FIXME("SystemRegistryQuotaInformation: faking max registry size of 32 MB\n");
2076 memcpy( info
, &srqi
, len
);
2079 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2083 case SystemLogicalProcessorInformation
:
2085 SYSTEM_LOGICAL_PROCESSOR_INFORMATION
*buf
;
2087 /* Each logical processor may use up to 7 entries in returned table:
2088 * core, numa node, package, L1i, L1d, L2, L3 */
2089 len
= 7 * NtCurrentTeb()->Peb
->NumberOfProcessors
;
2090 buf
= RtlAllocateHeap(GetProcessHeap(), 0, len
* sizeof(*buf
));
2093 ret
= STATUS_NO_MEMORY
;
2097 ret
= create_logical_proc_info(&buf
, NULL
, &len
, RelationAll
);
2098 if( ret
!= STATUS_SUCCESS
)
2100 RtlFreeHeap(GetProcessHeap(), 0, buf
);
2106 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
2107 else memcpy( info
, buf
, len
);
2109 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2110 RtlFreeHeap(GetProcessHeap(), 0, buf
);
2114 case SystemRecommendedSharedDataAlignment
:
2116 len
= sizeof(DWORD
);
2119 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
2123 *((DWORD
*)info
) = 32;
2125 *((DWORD
*)info
) = 64;
2129 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2133 case SystemFirmwareTableInformation
:
2135 SYSTEM_FIRMWARE_TABLE_INFORMATION
*sfti
= info
;
2136 len
= FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION
, TableBuffer
);
2139 ret
= STATUS_INFO_LENGTH_MISMATCH
;
2143 switch (sfti
->Action
)
2145 case SystemFirmwareTable_Get
:
2146 ret
= get_firmware_info(sfti
, size
, &len
);
2150 ret
= STATUS_NOT_IMPLEMENTED
;
2151 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION action %d\n", sfti
->Action
);
2157 FIXME( "(0x%08x,%p,0x%08x,%p) stub\n", class, info
, size
, ret_size
);
2159 /* Several Information Classes are not implemented on Windows and return 2 different values
2160 * STATUS_NOT_IMPLEMENTED or STATUS_INVALID_INFO_CLASS
2161 * in 95% of the cases it's STATUS_INVALID_INFO_CLASS, so use this as the default
2163 ret
= STATUS_INVALID_INFO_CLASS
;
2166 if (ret_size
) *ret_size
= len
;
2171 /******************************************************************************
2172 * NtQuerySystemInformationEx (NTDLL.@)
2174 NTSTATUS WINAPI
NtQuerySystemInformationEx( SYSTEM_INFORMATION_CLASS
class,
2175 void *query
, ULONG query_len
,
2176 void *info
, ULONG size
, ULONG
*ret_size
)
2179 NTSTATUS ret
= STATUS_NOT_IMPLEMENTED
;
2181 TRACE( "(0x%08x,%p,%u,%p,%u,%p) stub\n", class, query
, query_len
, info
, size
, ret_size
);
2185 case SystemLogicalProcessorInformationEx
:
2187 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*buf
;
2189 if (!query
|| query_len
< sizeof(DWORD
))
2191 ret
= STATUS_INVALID_PARAMETER
;
2195 len
= 3 * sizeof(*buf
);
2196 buf
= RtlAllocateHeap(GetProcessHeap(), 0, len
);
2199 ret
= STATUS_NO_MEMORY
;
2203 ret
= create_logical_proc_info(NULL
, &buf
, &len
, *(DWORD
*)query
);
2204 if (ret
!= STATUS_SUCCESS
)
2206 RtlFreeHeap(GetProcessHeap(), 0, buf
);
2212 if (!info
) ret
= STATUS_ACCESS_VIOLATION
;
2213 else memcpy(info
, buf
, len
);
2216 ret
= STATUS_INFO_LENGTH_MISMATCH
;
2218 RtlFreeHeap(GetProcessHeap(), 0, buf
);
2223 FIXME( "(0x%08x,%p,%u,%p,%u,%p) stub\n", class, query
, query_len
, info
, size
, ret_size
);
2226 if (ret_size
) *ret_size
= len
;
2233 /* Fallback using /proc/cpuinfo for Linux systems without cpufreq. For
2234 * most distributions on recent enough hardware, this is only likely to
2235 * happen while running in virtualized environments such as QEMU. */
2236 static ULONG
mhz_from_cpuinfo(void)
2241 FILE *f
= fopen("/proc/cpuinfo", "r");
2244 while (fgets(line
, sizeof(line
), f
) != NULL
)
2246 if (!(value
= strchr(line
,':'))) continue;
2248 while ((s
>= line
) && (*s
== ' ' || *s
== '\t')) s
--;
2251 if (!strcmp( line
, "cpu MHz" ))
2253 sscanf(value
, " %lf", &cmz
);
2262 static const char * get_sys_str(const char *path
, char *s
)
2264 FILE *f
= fopen(path
, "r");
2265 const char *ret
= NULL
;
2269 if (fgets(s
, 16, f
)) ret
= s
;
2275 static int get_sys_int(const char *path
, int def
)
2278 return get_sys_str(path
, s
) ? atoi(s
) : def
;
2281 static NTSTATUS
fill_battery_state( SYSTEM_BATTERY_STATE
*bs
)
2283 char s
[16], path
[64];
2285 LONG64 voltage
; /* microvolts */
2287 bs
->AcOnLine
= get_sys_int("/sys/class/power_supply/AC/online", 1);
2291 sprintf(path
, "/sys/class/power_supply/BAT%u/status", i
);
2292 if (!get_sys_str(path
, s
)) break;
2293 bs
->Charging
|= (strcmp(s
, "Charging\n") == 0);
2294 bs
->Discharging
|= (strcmp(s
, "Discharging\n") == 0);
2295 bs
->BatteryPresent
= TRUE
;
2299 if (bs
->BatteryPresent
)
2301 voltage
= get_sys_int("/sys/class/power_supply/BAT0/voltage_now", 0);
2302 bs
->MaxCapacity
= get_sys_int("/sys/class/power_supply/BAT0/charge_full", 0) * voltage
/ 1e9
;
2303 bs
->RemainingCapacity
= get_sys_int("/sys/class/power_supply/BAT0/charge_now", 0) * voltage
/ 1e9
;
2304 bs
->Rate
= -get_sys_int("/sys/class/power_supply/BAT0/current_now", 0) * voltage
/ 1e9
;
2305 if (!bs
->Charging
&& (LONG
)bs
->Rate
< 0)
2306 bs
->EstimatedTime
= 3600 * bs
->RemainingCapacity
/ -(LONG
)bs
->Rate
;
2308 bs
->EstimatedTime
= ~0u;
2311 return STATUS_SUCCESS
;
2314 #elif defined(HAVE_IOKIT_IOKITLIB_H)
2316 static NTSTATUS
fill_battery_state( SYSTEM_BATTERY_STATE
*bs
)
2318 CFArrayRef batteries
;
2319 CFDictionaryRef battery
;
2321 uint32_t value
, voltage
;
2322 CFTimeInterval remain
;
2324 if (IOPMCopyBatteryInfo( kIOMasterPortDefault
, &batteries
) != kIOReturnSuccess
)
2325 return STATUS_ACCESS_DENIED
;
2327 if (CFArrayGetCount( batteries
) == 0)
2329 /* Just assume we're on AC with no battery. */
2330 bs
->AcOnLine
= TRUE
;
2331 return STATUS_SUCCESS
;
2333 /* Just use the first battery. */
2334 battery
= CFArrayGetValueAtIndex( batteries
, 0 );
2336 prop
= CFDictionaryGetValue( battery
, CFSTR(kIOBatteryFlagsKey
) );
2337 CFNumberGetValue( prop
, kCFNumberSInt32Type
, &value
);
2339 if (value
& kIOBatteryInstalled
)
2340 bs
->BatteryPresent
= TRUE
;
2342 /* Since we are executing code, we must have AC power. */
2343 bs
->AcOnLine
= TRUE
;
2344 if (value
& kIOBatteryChargerConnect
)
2346 bs
->AcOnLine
= TRUE
;
2347 if (value
& kIOBatteryCharge
)
2348 bs
->Charging
= TRUE
;
2351 bs
->Discharging
= TRUE
;
2353 /* We'll need the voltage to be able to interpret the other values. */
2354 prop
= CFDictionaryGetValue( battery
, CFSTR(kIOBatteryVoltageKey
) );
2355 CFNumberGetValue( prop
, kCFNumberSInt32Type
, &voltage
);
2357 prop
= CFDictionaryGetValue( battery
, CFSTR(kIOBatteryCapacityKey
) );
2358 CFNumberGetValue( prop
, kCFNumberSInt32Type
, &value
);
2359 bs
->MaxCapacity
= value
* voltage
;
2360 /* Apple uses "estimated time < 10:00" and "22%" for these, but we'll follow
2361 * Windows for now (5% and 33%). */
2362 bs
->DefaultAlert1
= bs
->MaxCapacity
/ 20;
2363 bs
->DefaultAlert2
= bs
->MaxCapacity
/ 3;
2365 prop
= CFDictionaryGetValue( battery
, CFSTR(kIOBatteryCurrentChargeKey
) );
2366 CFNumberGetValue( prop
, kCFNumberSInt32Type
, &value
);
2367 bs
->RemainingCapacity
= value
* voltage
;
2369 prop
= CFDictionaryGetValue( battery
, CFSTR(kIOBatteryAmperageKey
) );
2370 CFNumberGetValue( prop
, kCFNumberSInt32Type
, &value
);
2371 bs
->Rate
= value
* voltage
;
2373 remain
= IOPSGetTimeRemainingEstimate();
2374 if (remain
!= kIOPSTimeRemainingUnknown
&& remain
!= kIOPSTimeRemainingUnlimited
)
2375 bs
->EstimatedTime
= (ULONG
)remain
;
2377 CFRelease( batteries
);
2378 return STATUS_SUCCESS
;
2383 static NTSTATUS
fill_battery_state( SYSTEM_BATTERY_STATE
*bs
)
2385 FIXME("SystemBatteryState not implemented on this platform\n");
2386 return STATUS_NOT_IMPLEMENTED
;
2391 /******************************************************************************
2392 * NtPowerInformation (NTDLL.@)
2394 NTSTATUS WINAPI
NtPowerInformation( POWER_INFORMATION_LEVEL level
, void *input
, ULONG in_size
,
2395 void *output
, ULONG out_size
)
2397 TRACE( "(%d,%p,%d,%p,%d)\n", level
, input
, in_size
, output
, out_size
);
2400 case SystemPowerCapabilities
:
2402 PSYSTEM_POWER_CAPABILITIES PowerCaps
= output
;
2403 FIXME("semi-stub: SystemPowerCapabilities\n");
2404 if (out_size
< sizeof(SYSTEM_POWER_CAPABILITIES
)) return STATUS_BUFFER_TOO_SMALL
;
2405 /* FIXME: These values are based off a native XP desktop, should probably use APM/ACPI to get the 'real' values */
2406 PowerCaps
->PowerButtonPresent
= TRUE
;
2407 PowerCaps
->SleepButtonPresent
= FALSE
;
2408 PowerCaps
->LidPresent
= FALSE
;
2409 PowerCaps
->SystemS1
= TRUE
;
2410 PowerCaps
->SystemS2
= FALSE
;
2411 PowerCaps
->SystemS3
= FALSE
;
2412 PowerCaps
->SystemS4
= TRUE
;
2413 PowerCaps
->SystemS5
= TRUE
;
2414 PowerCaps
->HiberFilePresent
= TRUE
;
2415 PowerCaps
->FullWake
= TRUE
;
2416 PowerCaps
->VideoDimPresent
= FALSE
;
2417 PowerCaps
->ApmPresent
= FALSE
;
2418 PowerCaps
->UpsPresent
= FALSE
;
2419 PowerCaps
->ThermalControl
= FALSE
;
2420 PowerCaps
->ProcessorThrottle
= FALSE
;
2421 PowerCaps
->ProcessorMinThrottle
= 100;
2422 PowerCaps
->ProcessorMaxThrottle
= 100;
2423 PowerCaps
->DiskSpinDown
= TRUE
;
2424 PowerCaps
->SystemBatteriesPresent
= FALSE
;
2425 PowerCaps
->BatteriesAreShortTerm
= FALSE
;
2426 PowerCaps
->BatteryScale
[0].Granularity
= 0;
2427 PowerCaps
->BatteryScale
[0].Capacity
= 0;
2428 PowerCaps
->BatteryScale
[1].Granularity
= 0;
2429 PowerCaps
->BatteryScale
[1].Capacity
= 0;
2430 PowerCaps
->BatteryScale
[2].Granularity
= 0;
2431 PowerCaps
->BatteryScale
[2].Capacity
= 0;
2432 PowerCaps
->AcOnLineWake
= PowerSystemUnspecified
;
2433 PowerCaps
->SoftLidWake
= PowerSystemUnspecified
;
2434 PowerCaps
->RtcWake
= PowerSystemSleeping1
;
2435 PowerCaps
->MinDeviceWakeState
= PowerSystemUnspecified
;
2436 PowerCaps
->DefaultLowLatencyWake
= PowerSystemUnspecified
;
2437 return STATUS_SUCCESS
;
2440 case SystemBatteryState
:
2442 if (out_size
< sizeof(SYSTEM_BATTERY_STATE
)) return STATUS_BUFFER_TOO_SMALL
;
2443 memset(output
, 0, sizeof(SYSTEM_BATTERY_STATE
));
2444 return fill_battery_state(output
);
2447 case SystemExecutionState
:
2449 ULONG
*state
= output
;
2450 WARN("semi-stub: SystemExecutionState\n"); /* Needed for .NET Framework, but using a FIXME is really noisy. */
2451 if (input
!= NULL
) return STATUS_INVALID_PARAMETER
;
2452 /* FIXME: The actual state should be the value set by SetThreadExecutionState which is not currently implemented. */
2453 *state
= ES_USER_PRESENT
;
2454 return STATUS_SUCCESS
;
2457 case ProcessorInformation
:
2459 const int cannedMHz
= 1000; /* We fake a 1GHz processor if we can't conjure up real values */
2460 PROCESSOR_POWER_INFORMATION
* cpu_power
= output
;
2463 if ((output
== NULL
) || (out_size
== 0)) return STATUS_INVALID_PARAMETER
;
2464 out_cpus
= NtCurrentTeb()->Peb
->NumberOfProcessors
;
2465 if ((out_size
/ sizeof(PROCESSOR_POWER_INFORMATION
)) < out_cpus
) return STATUS_BUFFER_TOO_SMALL
;
2471 for(i
= 0; i
< out_cpus
; i
++) {
2472 sprintf(filename
, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", i
);
2473 f
= fopen(filename
, "r");
2474 if (f
&& (fscanf(f
, "%d", &cpu_power
[i
].CurrentMhz
) == 1)) {
2475 cpu_power
[i
].CurrentMhz
/= 1000;
2480 cpu_power
[0].CurrentMhz
= mhz_from_cpuinfo();
2481 if(cpu_power
[0].CurrentMhz
== 0)
2482 cpu_power
[0].CurrentMhz
= cannedMHz
;
2485 cpu_power
[i
].CurrentMhz
= cpu_power
[0].CurrentMhz
;
2489 sprintf(filename
, "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", i
);
2490 f
= fopen(filename
, "r");
2491 if (f
&& (fscanf(f
, "%d", &cpu_power
[i
].MaxMhz
) == 1)) {
2492 cpu_power
[i
].MaxMhz
/= 1000;
2496 cpu_power
[i
].MaxMhz
= cpu_power
[i
].CurrentMhz
;
2500 sprintf(filename
, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", i
);
2501 f
= fopen(filename
, "r");
2502 if(f
&& (fscanf(f
, "%d", &cpu_power
[i
].MhzLimit
) == 1)) {
2503 cpu_power
[i
].MhzLimit
/= 1000;
2508 cpu_power
[i
].MhzLimit
= cpu_power
[i
].MaxMhz
;
2512 cpu_power
[i
].Number
= i
;
2513 cpu_power
[i
].MaxIdleState
= 0; /* FIXME */
2514 cpu_power
[i
].CurrentIdleState
= 0; /* FIXME */
2517 #elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__)
2520 size_t valSize
= sizeof(num
);
2521 if (sysctlbyname("hw.clockrate", &num
, &valSize
, NULL
, 0))
2523 for(i
= 0; i
< out_cpus
; i
++) {
2524 cpu_power
[i
].CurrentMhz
= num
;
2525 cpu_power
[i
].MaxMhz
= num
;
2526 cpu_power
[i
].MhzLimit
= num
;
2527 cpu_power
[i
].Number
= i
;
2528 cpu_power
[i
].MaxIdleState
= 0; /* FIXME */
2529 cpu_power
[i
].CurrentIdleState
= 0; /* FIXME */
2532 #elif defined (__APPLE__)
2535 unsigned long long currentMhz
;
2536 unsigned long long maxMhz
;
2538 valSize
= sizeof(currentMhz
);
2539 if (!sysctlbyname("hw.cpufrequency", ¤tMhz
, &valSize
, NULL
, 0))
2540 currentMhz
/= 1000000;
2542 currentMhz
= cannedMHz
;
2544 valSize
= sizeof(maxMhz
);
2545 if (!sysctlbyname("hw.cpufrequency_max", &maxMhz
, &valSize
, NULL
, 0))
2548 maxMhz
= currentMhz
;
2550 for(i
= 0; i
< out_cpus
; i
++) {
2551 cpu_power
[i
].CurrentMhz
= currentMhz
;
2552 cpu_power
[i
].MaxMhz
= maxMhz
;
2553 cpu_power
[i
].MhzLimit
= maxMhz
;
2554 cpu_power
[i
].Number
= i
;
2555 cpu_power
[i
].MaxIdleState
= 0; /* FIXME */
2556 cpu_power
[i
].CurrentIdleState
= 0; /* FIXME */
2560 for(i
= 0; i
< out_cpus
; i
++) {
2561 cpu_power
[i
].CurrentMhz
= cannedMHz
;
2562 cpu_power
[i
].MaxMhz
= cannedMHz
;
2563 cpu_power
[i
].MhzLimit
= cannedMHz
;
2564 cpu_power
[i
].Number
= i
;
2565 cpu_power
[i
].MaxIdleState
= 0; /* FIXME */
2566 cpu_power
[i
].CurrentIdleState
= 0; /* FIXME */
2568 WARN("Unable to detect CPU MHz for this platform. Reporting %d MHz.\n", cannedMHz
);
2570 for(i
= 0; i
< out_cpus
; i
++) {
2571 TRACE("cpu_power[%d] = %u %u %u %u %u %u\n", i
, cpu_power
[i
].Number
,
2572 cpu_power
[i
].MaxMhz
, cpu_power
[i
].CurrentMhz
, cpu_power
[i
].MhzLimit
,
2573 cpu_power
[i
].MaxIdleState
, cpu_power
[i
].CurrentIdleState
);
2575 return STATUS_SUCCESS
;
2579 /* FIXME: Needed by .NET Framework */
2580 WARN( "Unimplemented NtPowerInformation action: %d\n", level
);
2581 return STATUS_NOT_IMPLEMENTED
;