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