wined3d: Correctly destroy the adapter on format initialization failure in no3d mode.
[wine/zf.git] / dlls / ntdll / unix / system.c
blob681d56a869f4a8a806a9ba322654878e9014837f
1 /*
2 * System information APIs
4 * Copyright 1996-1998 Marcus Meissner
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
26 #include "wine/port.h"
28 #include <string.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #ifdef HAVE_SYS_TIME_H
33 # include <sys/time.h>
34 #endif
35 #include <time.h>
36 #ifdef HAVE_SYS_PARAM_H
37 # include <sys/param.h>
38 #endif
39 #ifdef HAVE_SYS_SYSCTL_H
40 # include <sys/sysctl.h>
41 #endif
42 #ifdef HAVE_MACHINE_CPU_H
43 # include <machine/cpu.h>
44 #endif
45 #ifdef HAVE_IOKIT_IOKITLIB_H
46 # include <CoreFoundation/CoreFoundation.h>
47 # include <IOKit/IOKitLib.h>
48 # include <IOKit/pwr_mgt/IOPM.h>
49 # include <IOKit/pwr_mgt/IOPMLib.h>
50 # include <IOKit/ps/IOPowerSources.h>
51 #endif
52 #ifdef __APPLE__
53 # include <mach/mach.h>
54 # include <mach/machine.h>
55 # include <mach/mach_init.h>
56 # include <mach/mach_host.h>
57 # include <mach/vm_map.h>
58 #endif
60 #define NONAMELESSUNION
61 #include "ntstatus.h"
62 #define WIN32_NO_STATUS
63 #include "windef.h"
64 #include "winternl.h"
65 #include "ddk/wdm.h"
66 #include "wine/asm.h"
67 #include "unix_private.h"
68 #include "wine/debug.h"
70 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
72 #include "pshpack1.h"
74 struct smbios_prologue
76 BYTE calling_method;
77 BYTE major_version;
78 BYTE minor_version;
79 BYTE revision;
80 DWORD length;
83 struct smbios_header
85 BYTE type;
86 BYTE length;
87 WORD handle;
90 struct smbios_bios
92 struct smbios_header hdr;
93 BYTE vendor;
94 BYTE version;
95 WORD start;
96 BYTE date;
97 BYTE size;
98 UINT64 characteristics;
99 BYTE characteristics_ext[2];
100 BYTE system_bios_major_release;
101 BYTE system_bios_minor_release;
102 BYTE ec_firmware_major_release;
103 BYTE ec_firmware_minor_release;
106 struct smbios_system
108 struct smbios_header hdr;
109 BYTE vendor;
110 BYTE product;
111 BYTE version;
112 BYTE serial;
113 BYTE uuid[16];
114 BYTE wake_up_type;
115 BYTE sku_number;
116 BYTE family;
119 struct smbios_board
121 struct smbios_header hdr;
122 BYTE vendor;
123 BYTE product;
124 BYTE version;
125 BYTE serial;
128 struct smbios_chassis
130 struct smbios_header hdr;
131 BYTE vendor;
132 BYTE type;
133 BYTE version;
134 BYTE serial;
135 BYTE asset_tag;
136 BYTE boot_state;
137 BYTE power_supply_state;
138 BYTE thermal_state;
139 BYTE security_status;
142 #include "poppack.h"
144 /* Firmware table providers */
145 #define ACPI 0x41435049
146 #define FIRM 0x4649524D
147 #define RSMB 0x52534D42
149 static SYSTEM_CPU_INFORMATION cpu_info;
151 /*******************************************************************************
152 * Architecture specific feature detection for CPUs
154 * This a set of mutually exclusive #if define()s each providing its own get_cpuinfo() to be called
155 * from init_cpu_info();
157 #if defined(__i386__) || defined(__x86_64__)
159 #define AUTH 0x68747541 /* "Auth" */
160 #define ENTI 0x69746e65 /* "enti" */
161 #define CAMD 0x444d4163 /* "cAMD" */
163 #define GENU 0x756e6547 /* "Genu" */
164 #define INEI 0x49656e69 /* "ineI" */
165 #define NTEL 0x6c65746e /* "ntel" */
167 extern void do_cpuid(unsigned int ax, unsigned int *p);
169 #ifdef __i386__
170 __ASM_GLOBAL_FUNC( do_cpuid,
171 "pushl %esi\n\t"
172 "pushl %ebx\n\t"
173 "movl 12(%esp),%eax\n\t"
174 "movl 16(%esp),%esi\n\t"
175 "cpuid\n\t"
176 "movl %eax,(%esi)\n\t"
177 "movl %ebx,4(%esi)\n\t"
178 "movl %ecx,8(%esi)\n\t"
179 "movl %edx,12(%esi)\n\t"
180 "popl %ebx\n\t"
181 "popl %esi\n\t"
182 "ret" )
183 #else
184 __ASM_GLOBAL_FUNC( do_cpuid,
185 "pushq %rbx\n\t"
186 "movl %edi,%eax\n\t"
187 "cpuid\n\t"
188 "movl %eax,(%rsi)\n\t"
189 "movl %ebx,4(%rsi)\n\t"
190 "movl %ecx,8(%rsi)\n\t"
191 "movl %edx,12(%rsi)\n\t"
192 "popq %rbx\n\t"
193 "ret" )
194 #endif
196 #ifdef __i386__
197 extern int have_cpuid(void);
198 __ASM_GLOBAL_FUNC( have_cpuid,
199 "pushfl\n\t"
200 "pushfl\n\t"
201 "movl (%esp),%ecx\n\t"
202 "xorl $0x00200000,(%esp)\n\t"
203 "popfl\n\t"
204 "pushfl\n\t"
205 "popl %eax\n\t"
206 "popfl\n\t"
207 "xorl %ecx,%eax\n\t"
208 "andl $0x00200000,%eax\n\t"
209 "ret" )
210 #else
211 static int have_cpuid(void)
213 return 1;
215 #endif
217 /* Detect if a SSE2 processor is capable of Denormals Are Zero (DAZ) mode.
219 * This function assumes you have already checked for SSE2/FXSAVE support. */
220 static inline BOOL have_sse_daz_mode(void)
222 #ifdef __i386__
223 typedef struct DECLSPEC_ALIGN(16) _M128A {
224 ULONGLONG Low;
225 LONGLONG High;
226 } M128A;
228 typedef struct _XMM_SAVE_AREA32 {
229 WORD ControlWord;
230 WORD StatusWord;
231 BYTE TagWord;
232 BYTE Reserved1;
233 WORD ErrorOpcode;
234 DWORD ErrorOffset;
235 WORD ErrorSelector;
236 WORD Reserved2;
237 DWORD DataOffset;
238 WORD DataSelector;
239 WORD Reserved3;
240 DWORD MxCsr;
241 DWORD MxCsr_Mask;
242 M128A FloatRegisters[8];
243 M128A XmmRegisters[16];
244 BYTE Reserved4[96];
245 } XMM_SAVE_AREA32;
247 /* Intel says we need a zeroed 16-byte aligned buffer */
248 char buffer[512 + 16];
249 XMM_SAVE_AREA32 *state = (XMM_SAVE_AREA32 *)(((ULONG_PTR)buffer + 15) & ~15);
250 memset(buffer, 0, sizeof(buffer));
252 __asm__ __volatile__( "fxsave %0" : "=m" (*state) : "m" (*state) );
254 return (state->MxCsr_Mask & (1 << 6)) >> 6;
255 #else /* all x86_64 processors include SSE2 with DAZ mode */
256 return TRUE;
257 #endif
260 static void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
262 unsigned int regs[4], regs2[4];
264 #if defined(__i386__)
265 info->Architecture = PROCESSOR_ARCHITECTURE_INTEL;
266 #elif defined(__x86_64__)
267 info->Architecture = PROCESSOR_ARCHITECTURE_AMD64;
268 #endif
270 /* We're at least a 386 */
271 info->FeatureSet = CPU_FEATURE_VME | CPU_FEATURE_X86 | CPU_FEATURE_PGE;
272 info->Level = 3;
274 if (!have_cpuid()) return;
276 do_cpuid( 0x00000000, regs ); /* get standard cpuid level and vendor name */
277 if (regs[0]>=0x00000001) /* Check for supported cpuid version */
279 do_cpuid( 0x00000001, regs2 ); /* get cpu features */
280 if (regs2[3] & (1 << 3 )) info->FeatureSet |= CPU_FEATURE_PSE;
281 if (regs2[3] & (1 << 4 )) info->FeatureSet |= CPU_FEATURE_TSC;
282 if (regs2[3] & (1 << 6 )) info->FeatureSet |= CPU_FEATURE_PAE;
283 if (regs2[3] & (1 << 8 )) info->FeatureSet |= CPU_FEATURE_CX8;
284 if (regs2[3] & (1 << 11)) info->FeatureSet |= CPU_FEATURE_SEP;
285 if (regs2[3] & (1 << 12)) info->FeatureSet |= CPU_FEATURE_MTRR;
286 if (regs2[3] & (1 << 15)) info->FeatureSet |= CPU_FEATURE_CMOV;
287 if (regs2[3] & (1 << 16)) info->FeatureSet |= CPU_FEATURE_PAT;
288 if (regs2[3] & (1 << 23)) info->FeatureSet |= CPU_FEATURE_MMX;
289 if (regs2[3] & (1 << 24)) info->FeatureSet |= CPU_FEATURE_FXSR;
290 if (regs2[3] & (1 << 25)) info->FeatureSet |= CPU_FEATURE_SSE;
291 if (regs2[3] & (1 << 26)) info->FeatureSet |= CPU_FEATURE_SSE2;
292 if (regs2[2] & (1 << 0 )) info->FeatureSet |= CPU_FEATURE_SSE3;
293 if (regs2[2] & (1 << 13)) info->FeatureSet |= CPU_FEATURE_CX128;
294 if (regs2[2] & (1 << 27)) info->FeatureSet |= CPU_FEATURE_XSAVE;
295 if((regs2[3] & (1 << 26)) && (regs2[3] & (1 << 24)) && have_sse_daz_mode()) /* has SSE2 and FXSAVE/FXRSTOR */
296 info->FeatureSet |= CPU_FEATURE_DAZ;
298 if (regs[1] == AUTH && regs[3] == ENTI && regs[2] == CAMD)
300 info->Level = (regs2[0] >> 8) & 0xf; /* family */
301 if (info->Level == 0xf) /* AMD says to add the extended family to the family if family is 0xf */
302 info->Level += (regs2[0] >> 20) & 0xff;
304 /* repack model and stepping to make a "revision" */
305 info->Revision = ((regs2[0] >> 16) & 0xf) << 12; /* extended model */
306 info->Revision |= ((regs2[0] >> 4 ) & 0xf) << 8; /* model */
307 info->Revision |= regs2[0] & 0xf; /* stepping */
309 do_cpuid( 0x80000000, regs ); /* get vendor cpuid level */
310 if (regs[0] >= 0x80000001)
312 do_cpuid( 0x80000001, regs2 ); /* get vendor features */
313 if (regs2[2] & (1 << 2)) info->FeatureSet |= CPU_FEATURE_VIRT;
314 if (regs2[3] & (1 << 20)) info->FeatureSet |= CPU_FEATURE_NX;
315 if (regs2[3] & (1 << 27)) info->FeatureSet |= CPU_FEATURE_TSC;
316 if (regs2[3] & (1u << 31)) info->FeatureSet |= CPU_FEATURE_3DNOW;
319 else if (regs[1] == GENU && regs[3] == INEI && regs[2] == NTEL)
321 info->Level = ((regs2[0] >> 8) & 0xf) + ((regs2[0] >> 20) & 0xff); /* family + extended family */
322 if(info->Level == 15) info->Level = 6;
324 /* repack model and stepping to make a "revision" */
325 info->Revision = ((regs2[0] >> 16) & 0xf) << 12; /* extended model */
326 info->Revision |= ((regs2[0] >> 4 ) & 0xf) << 8; /* model */
327 info->Revision |= regs2[0] & 0xf; /* stepping */
329 if(regs2[2] & (1 << 5)) info->FeatureSet |= CPU_FEATURE_VIRT;
330 if(regs2[3] & (1 << 21)) info->FeatureSet |= CPU_FEATURE_DS;
332 do_cpuid( 0x80000000, regs ); /* get vendor cpuid level */
333 if (regs[0] >= 0x80000001)
335 do_cpuid( 0x80000001, regs2 ); /* get vendor features */
336 if (regs2[3] & (1 << 20)) info->FeatureSet |= CPU_FEATURE_NX;
337 if (regs2[3] & (1 << 27)) info->FeatureSet |= CPU_FEATURE_TSC;
340 else
342 info->Level = (regs2[0] >> 8) & 0xf; /* family */
344 /* repack model and stepping to make a "revision" */
345 info->Revision = ((regs2[0] >> 4 ) & 0xf) << 8; /* model */
346 info->Revision |= regs2[0] & 0xf; /* stepping */
351 #elif defined(__arm__)
353 static inline void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
355 #ifdef linux
356 char line[512];
357 char *s, *value;
358 FILE *f = fopen("/proc/cpuinfo", "r");
359 if (f)
361 while (fgets( line, sizeof(line), f ))
363 /* NOTE: the ':' is the only character we can rely on */
364 if (!(value = strchr(line,':'))) continue;
365 /* terminate the valuename */
366 s = value - 1;
367 while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
368 s[1] = 0;
369 /* and strip leading spaces from value */
370 value += 1;
371 while (*value == ' ' || *value == '\t') value++;
372 if ((s = strchr( value,'\n' ))) *s = 0;
373 if (!strcmp( line, "CPU architecture" ))
375 info->Level = atoi(value);
376 continue;
378 if (!strcmp( line, "CPU revision" ))
380 info->Revision = atoi(value);
381 continue;
383 if (!strcmp( line, "Features" ))
385 if (strstr(value, "crc32")) info->FeatureSet |= CPU_FEATURE_ARM_V8_CRC32;
386 if (strstr(value, "aes")) info->FeatureSet |= CPU_FEATURE_ARM_V8_CRYPTO;
387 continue;
390 fclose( f );
392 #elif defined(__FreeBSD__)
393 size_t valsize;
394 char buf[8];
395 int value;
397 valsize = sizeof(buf);
398 if (!sysctlbyname("hw.machine_arch", &buf, &valsize, NULL, 0) && sscanf(buf, "armv%i", &value) == 1)
399 info->Level = value;
401 valsize = sizeof(value);
402 if (!sysctlbyname("hw.floatingpoint", &value, &valsize, NULL, 0))
403 info->FeatureSet |= CPU_FEATURE_ARM_VFP_32;
404 #else
405 FIXME("CPU Feature detection not implemented.\n");
406 #endif
407 info->Architecture = PROCESSOR_ARCHITECTURE_ARM;
410 #elif defined(__aarch64__)
412 static void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
414 #ifdef linux
415 char line[512];
416 char *s, *value;
417 FILE *f = fopen("/proc/cpuinfo", "r");
418 if (f)
420 while (fgets( line, sizeof(line), f ))
422 /* NOTE: the ':' is the only character we can rely on */
423 if (!(value = strchr(line,':'))) continue;
424 /* terminate the valuename */
425 s = value - 1;
426 while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
427 s[1] = 0;
428 /* and strip leading spaces from value */
429 value += 1;
430 while (*value == ' ' || *value == '\t') value++;
431 if ((s = strchr( value,'\n' ))) *s = 0;
432 if (!strcmp( line, "CPU architecture" ))
434 info->Level = atoi(value);
435 continue;
437 if (!strcmp( line, "CPU revision" ))
439 info->Revision = atoi(value);
440 continue;
442 if (!strcmp( line, "Features" ))
444 if (strstr(value, "crc32")) info->FeatureSet |= CPU_FEATURE_ARM_V8_CRC32;
445 if (strstr(value, "aes")) info->FeatureSet |= CPU_FEATURE_ARM_V8_CRYPTO;
446 continue;
449 fclose( f );
451 #else
452 FIXME("CPU Feature detection not implemented.\n");
453 #endif
454 info->Level = max(info->Level, 8);
455 info->Architecture = PROCESSOR_ARCHITECTURE_ARM64;
458 #endif /* End architecture specific feature detection for CPUs */
460 /******************************************************************
461 * init_cpu_info
463 * inits a couple of places with CPU related information:
464 * - cpu_info in this file
465 * - Peb->NumberOfProcessors
466 * - SharedUserData->ProcessFeatures[] array
468 void init_cpu_info(void)
470 long num;
472 #ifdef _SC_NPROCESSORS_ONLN
473 num = sysconf(_SC_NPROCESSORS_ONLN);
474 if (num < 1)
476 num = 1;
477 WARN("Failed to detect the number of processors.\n");
479 #elif defined(CTL_HW) && defined(HW_NCPU)
480 int mib[2];
481 size_t len = sizeof(num);
482 mib[0] = CTL_HW;
483 mib[1] = HW_NCPU;
484 if (sysctl(mib, 2, &num, &len, NULL, 0) != 0)
486 num = 1;
487 WARN("Failed to detect the number of processors.\n");
489 #else
490 num = 1;
491 FIXME("Detecting the number of processors is not supported.\n");
492 #endif
493 NtCurrentTeb()->Peb->NumberOfProcessors = num;
494 get_cpuinfo( &cpu_info );
495 TRACE( "<- CPU arch %d, level %d, rev %d, features 0x%x\n",
496 cpu_info.Architecture, cpu_info.Level, cpu_info.Revision, cpu_info.FeatureSet );
499 static BOOL grow_logical_proc_buf( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata, DWORD *max_len )
501 SYSTEM_LOGICAL_PROCESSOR_INFORMATION *new_data;
503 *max_len *= 2;
504 if (!(new_data = realloc( *pdata, *max_len*sizeof(*new_data) ))) return FALSE;
505 *pdata = new_data;
506 return TRUE;
509 static BOOL grow_logical_proc_ex_buf( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *max_len )
511 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *new_dataex;
512 DWORD new_len = *max_len * 2;
513 if (!(new_dataex = realloc( *pdataex, new_len * sizeof(*new_dataex) ))) return FALSE;
514 memset( new_dataex + *max_len, 0, (new_len - *max_len) * sizeof(*new_dataex) );
515 *pdataex = new_dataex;
516 *max_len = new_len;
517 return TRUE;
520 static DWORD log_proc_ex_size_plus(DWORD size)
522 /* add SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX.Relationship and .Size */
523 return sizeof(LOGICAL_PROCESSOR_RELATIONSHIP) + sizeof(DWORD) + size;
526 static DWORD count_bits(ULONG_PTR mask)
528 DWORD count = 0;
529 while (mask > 0)
531 mask >>= 1;
532 count++;
534 return count;
537 /* Store package and core information for a logical processor. Parsing of processor
538 * data may happen in multiple passes; the 'id' parameter is then used to locate
539 * previously stored data. The type of data stored in 'id' depends on 'rel':
540 * - RelationProcessorPackage: package id ('CPU socket').
541 * - RelationProcessorCore: physical core number.
543 static BOOL logical_proc_info_add_by_id( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
544 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *len,
545 DWORD *pmax_len, LOGICAL_PROCESSOR_RELATIONSHIP rel,
546 DWORD id, ULONG_PTR mask )
548 if (pdata)
550 DWORD i;
552 for (i = 0; i < *len; i++)
554 if (rel == RelationProcessorPackage && (*pdata)[i].Relationship == rel && (*pdata)[i].u.Reserved[1] == id)
556 (*pdata)[i].ProcessorMask |= mask;
557 return TRUE;
559 else if (rel == RelationProcessorCore && (*pdata)[i].Relationship == rel && (*pdata)[i].u.Reserved[1] == id)
560 return TRUE;
563 while (*len == *pmax_len)
565 if (!grow_logical_proc_buf(pdata, pmax_len)) return FALSE;
568 (*pdata)[i].Relationship = rel;
569 (*pdata)[i].ProcessorMask = mask;
570 if (rel == RelationProcessorCore)
571 (*pdata)[i].u.ProcessorCore.Flags = count_bits(mask) > 1 ? LTP_PC_SMT : 0;
572 (*pdata)[i].u.Reserved[0] = 0;
573 (*pdata)[i].u.Reserved[1] = id;
574 *len = i+1;
576 else
578 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
579 DWORD ofs = 0;
581 while (ofs < *len)
583 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
584 if (rel == RelationProcessorPackage && dataex->Relationship == rel && dataex->u.Processor.Reserved[1] == id)
586 dataex->u.Processor.GroupMask[0].Mask |= mask;
587 return TRUE;
589 else if (rel == RelationProcessorCore && dataex->Relationship == rel && dataex->u.Processor.Reserved[1] == id)
591 return TRUE;
593 ofs += dataex->Size;
596 /* TODO: For now, just one group. If more than 64 processors, then we
597 * need another group. */
599 while (ofs + log_proc_ex_size_plus(sizeof(PROCESSOR_RELATIONSHIP)) > *pmax_len)
601 if (!grow_logical_proc_ex_buf(pdataex, pmax_len)) return FALSE;
604 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
606 dataex->Relationship = rel;
607 dataex->Size = log_proc_ex_size_plus(sizeof(PROCESSOR_RELATIONSHIP));
608 if (rel == RelationProcessorCore)
609 dataex->u.Processor.Flags = count_bits(mask) > 1 ? LTP_PC_SMT : 0;
610 else
611 dataex->u.Processor.Flags = 0;
612 dataex->u.Processor.EfficiencyClass = 0;
613 dataex->u.Processor.GroupCount = 1;
614 dataex->u.Processor.GroupMask[0].Mask = mask;
615 dataex->u.Processor.GroupMask[0].Group = 0;
616 /* mark for future lookup */
617 dataex->u.Processor.Reserved[0] = 0;
618 dataex->u.Processor.Reserved[1] = id;
620 *len += dataex->Size;
623 return TRUE;
626 static BOOL logical_proc_info_add_cache( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
627 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *len,
628 DWORD *pmax_len, ULONG_PTR mask, CACHE_DESCRIPTOR *cache )
630 if (pdata)
632 DWORD i;
634 for (i = 0; i < *len; i++)
636 if ((*pdata)[i].Relationship==RelationCache && (*pdata)[i].ProcessorMask==mask
637 && (*pdata)[i].u.Cache.Level==cache->Level && (*pdata)[i].u.Cache.Type==cache->Type)
638 return TRUE;
641 while (*len == *pmax_len)
642 if (!grow_logical_proc_buf(pdata, pmax_len)) return FALSE;
644 (*pdata)[i].Relationship = RelationCache;
645 (*pdata)[i].ProcessorMask = mask;
646 (*pdata)[i].u.Cache = *cache;
647 *len = i+1;
649 else
651 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
652 DWORD ofs;
654 for (ofs = 0; ofs < *len; )
656 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
657 if (dataex->Relationship == RelationCache && dataex->u.Cache.GroupMask.Mask == mask &&
658 dataex->u.Cache.Level == cache->Level && dataex->u.Cache.Type == cache->Type)
659 return TRUE;
660 ofs += dataex->Size;
663 while (ofs + log_proc_ex_size_plus(sizeof(CACHE_RELATIONSHIP)) > *pmax_len)
665 if (!grow_logical_proc_ex_buf(pdataex, pmax_len)) return FALSE;
668 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
670 dataex->Relationship = RelationCache;
671 dataex->Size = log_proc_ex_size_plus(sizeof(CACHE_RELATIONSHIP));
672 dataex->u.Cache.Level = cache->Level;
673 dataex->u.Cache.Associativity = cache->Associativity;
674 dataex->u.Cache.LineSize = cache->LineSize;
675 dataex->u.Cache.CacheSize = cache->Size;
676 dataex->u.Cache.Type = cache->Type;
677 dataex->u.Cache.GroupMask.Mask = mask;
678 dataex->u.Cache.GroupMask.Group = 0;
680 *len += dataex->Size;
683 return TRUE;
686 static BOOL logical_proc_info_add_numa_node( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
687 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *len,
688 DWORD *pmax_len, ULONG_PTR mask, DWORD node_id )
690 if (pdata)
692 while (*len == *pmax_len)
693 if (!grow_logical_proc_buf(pdata, pmax_len)) return FALSE;
695 (*pdata)[*len].Relationship = RelationNumaNode;
696 (*pdata)[*len].ProcessorMask = mask;
697 (*pdata)[*len].u.NumaNode.NodeNumber = node_id;
698 (*len)++;
700 else
702 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
704 while (*len + log_proc_ex_size_plus(sizeof(NUMA_NODE_RELATIONSHIP)) > *pmax_len)
706 if (!grow_logical_proc_ex_buf(pdataex, pmax_len)) return FALSE;
709 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + *len);
711 dataex->Relationship = RelationNumaNode;
712 dataex->Size = log_proc_ex_size_plus(sizeof(NUMA_NODE_RELATIONSHIP));
713 dataex->u.NumaNode.NodeNumber = node_id;
714 dataex->u.NumaNode.GroupMask.Mask = mask;
715 dataex->u.NumaNode.GroupMask.Group = 0;
717 *len += dataex->Size;
720 return TRUE;
723 static BOOL logical_proc_info_add_group( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex,
724 DWORD *len, DWORD *pmax_len, DWORD num_cpus, ULONG_PTR mask )
726 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
728 while (*len + log_proc_ex_size_plus(sizeof(GROUP_RELATIONSHIP)) > *pmax_len)
729 if (!grow_logical_proc_ex_buf(pdataex, pmax_len)) return FALSE;
731 dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + *len);
733 dataex->Relationship = RelationGroup;
734 dataex->Size = log_proc_ex_size_plus(sizeof(GROUP_RELATIONSHIP));
735 dataex->u.Group.MaximumGroupCount = 1;
736 dataex->u.Group.ActiveGroupCount = 1;
737 dataex->u.Group.GroupInfo[0].MaximumProcessorCount = num_cpus;
738 dataex->u.Group.GroupInfo[0].ActiveProcessorCount = num_cpus;
739 dataex->u.Group.GroupInfo[0].ActiveProcessorMask = mask;
741 *len += dataex->Size;
742 return TRUE;
745 #ifdef linux
747 /* Helper function for counting bitmap values as commonly used by the Linux kernel
748 * for storing CPU masks in sysfs. The format is comma separated lists of hex values
749 * each max 32-bit e.g. "00ff" or even "00,00000000,0000ffff".
751 * Example files include:
752 * - /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_map
753 * - /sys/devices/system/cpu/cpu0/topology/thread_siblings
755 static BOOL sysfs_parse_bitmap(const char *filename, ULONG_PTR *mask)
757 FILE *f;
758 DWORD r;
760 f = fopen(filename, "r");
761 if (!f) return FALSE;
763 while (!feof(f))
765 char op;
766 if (!fscanf(f, "%x%c ", &r, &op)) break;
767 *mask = (sizeof(ULONG_PTR)>sizeof(int) ? *mask << (8 * sizeof(DWORD)) : 0) + r;
769 fclose( f );
770 return TRUE;
773 /* Helper function for counting number of elements in interval lists as used by
774 * the Linux kernel. The format is comma separated list of intervals of which
775 * each interval has the format of "begin-end" where begin and end are decimal
776 * numbers. E.g. "0-7", "0-7,16-23"
778 * Example files include:
779 * - /sys/devices/system/cpu/online
780 * - /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_list
781 * - /sys/devices/system/cpu/cpu0/topology/thread_siblings_list.
783 static BOOL sysfs_count_list_elements(const char *filename, DWORD *result)
785 FILE *f;
787 f = fopen(filename, "r");
788 if (!f) return FALSE;
790 while (!feof(f))
792 char op;
793 DWORD beg, end;
795 if (!fscanf(f, "%u%c ", &beg, &op)) break;
796 if(op == '-')
797 fscanf(f, "%u%c ", &end, &op);
798 else
799 end = beg;
801 *result += end - beg + 1;
803 fclose( f );
804 return TRUE;
807 /* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
808 static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data,
809 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **dataex,
810 DWORD *max_len, DWORD relation )
812 static const char core_info[] = "/sys/devices/system/cpu/cpu%u/topology/%s";
813 static const char cache_info[] = "/sys/devices/system/cpu/cpu%u/cache/index%u/%s";
814 static const char numa_info[] = "/sys/devices/system/node/node%u/cpumap";
816 FILE *fcpu_list, *fnuma_list, *f;
817 DWORD len = 0, beg, end, i, j, r, num_cpus = 0, max_cpus = 0;
818 char op, name[MAX_PATH];
819 ULONG_PTR all_cpus_mask = 0;
821 /* On systems with a large number of CPU cores (32 or 64 depending on 32-bit or 64-bit),
822 * we have issues parsing processor information:
823 * - ULONG_PTR masks as used in data structures can't hold all cores. Requires splitting
824 * data appropriately into "processor groups". We are hard coding 1.
825 * - Thread affinity code in wineserver and our CPU parsing code here work independently.
826 * So far the Windows mask applied directly to Linux, but process groups break that.
827 * (NUMA systems you may have multiple non-full groups.)
829 if(sysfs_count_list_elements("/sys/devices/system/cpu/present", &max_cpus) && max_cpus > MAXIMUM_PROCESSORS)
831 FIXME("Improve CPU info reporting: system supports %u logical cores, but only %u supported!\n",
832 max_cpus, MAXIMUM_PROCESSORS);
835 fcpu_list = fopen("/sys/devices/system/cpu/online", "r");
836 if (!fcpu_list) return STATUS_NOT_IMPLEMENTED;
838 while (!feof(fcpu_list))
840 if (!fscanf(fcpu_list, "%u%c ", &beg, &op)) break;
841 if (op == '-') fscanf(fcpu_list, "%u%c ", &end, &op);
842 else end = beg;
844 for(i = beg; i <= end; i++)
846 DWORD phys_core = 0;
847 ULONG_PTR thread_mask = 0;
849 if (i > 8*sizeof(ULONG_PTR))
851 FIXME("skipping logical processor %d\n", i);
852 continue;
855 if (relation == RelationAll || relation == RelationProcessorPackage)
857 sprintf(name, core_info, i, "physical_package_id");
858 f = fopen(name, "r");
859 if (f)
861 fscanf(f, "%u", &r);
862 fclose(f);
864 else r = 0;
865 if (!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorPackage, r, (ULONG_PTR)1 << i))
867 fclose(fcpu_list);
868 return STATUS_NO_MEMORY;
872 /* Sysfs enumerates logical cores (and not physical cores), but Windows enumerates
873 * by physical core. Upon enumerating a logical core in sysfs, we register a physical
874 * core and all its logical cores. In order to not report physical cores multiple
875 * times, we pass a unique physical core ID to logical_proc_info_add_by_id and let
876 * that call figure out any duplication.
877 * Obtain a unique physical core ID from the first element of thread_siblings_list.
878 * This list provides logical cores sharing the same physical core. The IDs are based
879 * on kernel cpu core numbering as opposed to a hardware core ID like provided through
880 * 'core_id', so are suitable as a unique ID.
882 if(relation == RelationAll || relation == RelationProcessorCore ||
883 relation == RelationNumaNode || relation == RelationGroup)
885 /* Mask of logical threads sharing same physical core in kernel core numbering. */
886 sprintf(name, core_info, i, "thread_siblings");
887 if(!sysfs_parse_bitmap(name, &thread_mask)) thread_mask = 1<<i;
889 /* Needed later for NumaNode and Group. */
890 all_cpus_mask |= thread_mask;
892 if (relation == RelationAll || relation == RelationProcessorCore)
894 sprintf(name, core_info, i, "thread_siblings_list");
895 f = fopen(name, "r");
896 if (f)
898 fscanf(f, "%d%c", &phys_core, &op);
899 fclose(f);
901 else phys_core = i;
903 if (!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorCore, phys_core, thread_mask))
905 fclose(fcpu_list);
906 return STATUS_NO_MEMORY;
911 if (relation == RelationAll || relation == RelationCache)
913 for(j = 0; j < 4; j++)
915 CACHE_DESCRIPTOR cache;
916 ULONG_PTR mask = 0;
918 sprintf(name, cache_info, i, j, "shared_cpu_map");
919 if(!sysfs_parse_bitmap(name, &mask)) continue;
921 sprintf(name, cache_info, i, j, "level");
922 f = fopen(name, "r");
923 if(!f) continue;
924 fscanf(f, "%u", &r);
925 fclose(f);
926 cache.Level = r;
928 sprintf(name, cache_info, i, j, "ways_of_associativity");
929 f = fopen(name, "r");
930 if(!f) continue;
931 fscanf(f, "%u", &r);
932 fclose(f);
933 cache.Associativity = r;
935 sprintf(name, cache_info, i, j, "coherency_line_size");
936 f = fopen(name, "r");
937 if(!f) continue;
938 fscanf(f, "%u", &r);
939 fclose(f);
940 cache.LineSize = r;
942 sprintf(name, cache_info, i, j, "size");
943 f = fopen(name, "r");
944 if(!f) continue;
945 fscanf(f, "%u%c", &r, &op);
946 fclose(f);
947 if(op != 'K')
948 WARN("unknown cache size %u%c\n", r, op);
949 cache.Size = (op=='K' ? r*1024 : r);
951 sprintf(name, cache_info, i, j, "type");
952 f = fopen(name, "r");
953 if(!f) continue;
954 fscanf(f, "%s", name);
955 fclose(f);
956 if (!memcmp(name, "Data", 5))
957 cache.Type = CacheData;
958 else if(!memcmp(name, "Instruction", 11))
959 cache.Type = CacheInstruction;
960 else
961 cache.Type = CacheUnified;
963 if (!logical_proc_info_add_cache(data, dataex, &len, max_len, mask, &cache))
965 fclose(fcpu_list);
966 return STATUS_NO_MEMORY;
972 fclose(fcpu_list);
974 num_cpus = count_bits(all_cpus_mask);
976 if(relation == RelationAll || relation == RelationNumaNode)
978 fnuma_list = fopen("/sys/devices/system/node/online", "r");
979 if (!fnuma_list)
981 if (!logical_proc_info_add_numa_node(data, dataex, &len, max_len, all_cpus_mask, 0))
982 return STATUS_NO_MEMORY;
984 else
986 while (!feof(fnuma_list))
988 if (!fscanf(fnuma_list, "%u%c ", &beg, &op))
989 break;
990 if (op == '-') fscanf(fnuma_list, "%u%c ", &end, &op);
991 else end = beg;
993 for (i = beg; i <= end; i++)
995 ULONG_PTR mask = 0;
997 sprintf(name, numa_info, i);
998 if (!sysfs_parse_bitmap( name, &mask )) continue;
1000 if (!logical_proc_info_add_numa_node(data, dataex, &len, max_len, mask, i))
1002 fclose(fnuma_list);
1003 return STATUS_NO_MEMORY;
1007 fclose(fnuma_list);
1011 if(dataex && (relation == RelationAll || relation == RelationGroup))
1012 logical_proc_info_add_group(dataex, &len, max_len, num_cpus, all_cpus_mask);
1014 if(data)
1015 *max_len = len * sizeof(**data);
1016 else
1017 *max_len = len;
1019 return STATUS_SUCCESS;
1022 #elif defined(__APPLE__)
1024 /* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
1025 static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data,
1026 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **dataex,
1027 DWORD *max_len, DWORD relation)
1029 DWORD pkgs_no, cores_no, lcpu_no, lcpu_per_core, cores_per_package, assoc, len = 0;
1030 DWORD cache_ctrs[10] = {0};
1031 ULONG_PTR all_cpus_mask = 0;
1032 CACHE_DESCRIPTOR cache[10];
1033 LONGLONG cache_size, cache_line_size, cache_sharing[10];
1034 size_t size;
1035 DWORD p,i,j,k;
1037 if (relation != RelationAll)
1038 FIXME("Relationship filtering not implemented: 0x%x\n", relation);
1040 lcpu_no = NtCurrentTeb()->Peb->NumberOfProcessors;
1042 size = sizeof(pkgs_no);
1043 if (sysctlbyname("hw.packages", &pkgs_no, &size, NULL, 0))
1044 pkgs_no = 1;
1046 size = sizeof(cores_no);
1047 if (sysctlbyname("hw.physicalcpu", &cores_no, &size, NULL, 0))
1048 cores_no = lcpu_no;
1050 TRACE("%u logical CPUs from %u physical cores across %u packages\n",
1051 lcpu_no, cores_no, pkgs_no);
1053 lcpu_per_core = lcpu_no / cores_no;
1054 cores_per_package = cores_no / pkgs_no;
1056 memset(cache, 0, sizeof(cache));
1057 cache[1].Level = 1;
1058 cache[1].Type = CacheInstruction;
1059 cache[1].Associativity = 8; /* reasonable default */
1060 cache[1].LineSize = 0x40; /* reasonable default */
1061 cache[2].Level = 1;
1062 cache[2].Type = CacheData;
1063 cache[2].Associativity = 8;
1064 cache[2].LineSize = 0x40;
1065 cache[3].Level = 2;
1066 cache[3].Type = CacheUnified;
1067 cache[3].Associativity = 8;
1068 cache[3].LineSize = 0x40;
1069 cache[4].Level = 3;
1070 cache[4].Type = CacheUnified;
1071 cache[4].Associativity = 12;
1072 cache[4].LineSize = 0x40;
1074 size = sizeof(cache_line_size);
1075 if (!sysctlbyname("hw.cachelinesize", &cache_line_size, &size, NULL, 0))
1077 for (i = 1; i < 5; i++) cache[i].LineSize = cache_line_size;
1080 /* TODO: set actual associativity for all caches */
1081 size = sizeof(assoc);
1082 if (!sysctlbyname("machdep.cpu.cache.L2_associativity", &assoc, &size, NULL, 0))
1083 cache[3].Associativity = assoc;
1085 size = sizeof(cache_size);
1086 if (!sysctlbyname("hw.l1icachesize", &cache_size, &size, NULL, 0))
1087 cache[1].Size = cache_size;
1088 size = sizeof(cache_size);
1089 if (!sysctlbyname("hw.l1dcachesize", &cache_size, &size, NULL, 0))
1090 cache[2].Size = cache_size;
1091 size = sizeof(cache_size);
1092 if (!sysctlbyname("hw.l2cachesize", &cache_size, &size, NULL, 0))
1093 cache[3].Size = cache_size;
1094 size = sizeof(cache_size);
1095 if (!sysctlbyname("hw.l3cachesize", &cache_size, &size, NULL, 0))
1096 cache[4].Size = cache_size;
1098 size = sizeof(cache_sharing);
1099 if (sysctlbyname("hw.cacheconfig", cache_sharing, &size, NULL, 0) < 0)
1101 cache_sharing[1] = lcpu_per_core;
1102 cache_sharing[2] = lcpu_per_core;
1103 cache_sharing[3] = lcpu_per_core;
1104 cache_sharing[4] = lcpu_no;
1106 else
1108 /* in cache[], indexes 1 and 2 are l1 caches */
1109 cache_sharing[4] = cache_sharing[3];
1110 cache_sharing[3] = cache_sharing[2];
1111 cache_sharing[2] = cache_sharing[1];
1114 for(p = 0; p < pkgs_no; ++p)
1116 for(j = 0; j < cores_per_package && p * cores_per_package + j < cores_no; ++j)
1118 ULONG_PTR mask = 0;
1119 DWORD phys_core;
1121 for(k = 0; k < lcpu_per_core; ++k) mask |= (ULONG_PTR)1 << (j * lcpu_per_core + k);
1123 all_cpus_mask |= mask;
1125 /* add to package */
1126 if(!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorPackage, p, mask))
1127 return STATUS_NO_MEMORY;
1129 /* add new core */
1130 phys_core = p * cores_per_package + j;
1131 if(!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorCore, phys_core, mask))
1132 return STATUS_NO_MEMORY;
1134 for(i = 1; i < 5; ++i)
1136 if(cache_ctrs[i] == 0 && cache[i].Size > 0)
1138 mask = 0;
1139 for(k = 0; k < cache_sharing[i]; ++k)
1140 mask |= (ULONG_PTR)1 << (j * lcpu_per_core + k);
1142 if(!logical_proc_info_add_cache(data, dataex, &len, max_len, mask, &cache[i]))
1143 return STATUS_NO_MEMORY;
1146 cache_ctrs[i] += lcpu_per_core;
1147 if(cache_ctrs[i] == cache_sharing[i]) cache_ctrs[i] = 0;
1152 /* OSX doesn't support NUMA, so just make one NUMA node for all CPUs */
1153 if(!logical_proc_info_add_numa_node(data, dataex, &len, max_len, all_cpus_mask, 0))
1154 return STATUS_NO_MEMORY;
1156 if(dataex) logical_proc_info_add_group(dataex, &len, max_len, lcpu_no, all_cpus_mask);
1158 if(data)
1159 *max_len = len * sizeof(**data);
1160 else
1161 *max_len = len;
1163 return STATUS_SUCCESS;
1166 #else
1168 static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data,
1169 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **dataex,
1170 DWORD *max_len, DWORD relation )
1172 FIXME("stub\n");
1173 return STATUS_NOT_IMPLEMENTED;
1175 #endif
1177 #ifdef linux
1179 static void copy_smbios_string( char **buffer, char *s, size_t len )
1181 if (!len) return;
1182 memcpy(*buffer, s, len + 1);
1183 *buffer += len + 1;
1186 static size_t get_smbios_string( const char *path, char *str, size_t size )
1188 FILE *file;
1189 size_t len;
1191 if (!(file = fopen(path, "r"))) return 0;
1193 len = fread( str, 1, size - 1, file );
1194 fclose( file );
1196 if (len >= 1 && str[len - 1] == '\n') len--;
1197 str[len] = 0;
1198 return len;
1201 static void get_system_uuid( GUID *uuid )
1203 static const unsigned char hex[] =
1205 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */
1206 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */
1207 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */
1208 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */
1209 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */
1210 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */
1211 0,10,11,12,13,14,15 /* 0x60 */
1213 int fd;
1215 memset( uuid, 0xff, sizeof(*uuid) );
1216 if ((fd = open( "/var/lib/dbus/machine-id", O_RDONLY )) != -1)
1218 unsigned char buf[32], *p = buf;
1219 if (read( fd, buf, sizeof(buf) ) == sizeof(buf))
1221 uuid->Data1 = hex[p[6]] << 28 | hex[p[7]] << 24 | hex[p[4]] << 20 | hex[p[5]] << 16 |
1222 hex[p[2]] << 12 | hex[p[3]] << 8 | hex[p[0]] << 4 | hex[p[1]];
1224 uuid->Data2 = hex[p[10]] << 12 | hex[p[11]] << 8 | hex[p[8]] << 4 | hex[p[9]];
1225 uuid->Data3 = hex[p[14]] << 12 | hex[p[15]] << 8 | hex[p[12]] << 4 | hex[p[13]];
1227 uuid->Data4[0] = hex[p[16]] << 4 | hex[p[17]];
1228 uuid->Data4[1] = hex[p[18]] << 4 | hex[p[19]];
1229 uuid->Data4[2] = hex[p[20]] << 4 | hex[p[21]];
1230 uuid->Data4[3] = hex[p[22]] << 4 | hex[p[23]];
1231 uuid->Data4[4] = hex[p[24]] << 4 | hex[p[25]];
1232 uuid->Data4[5] = hex[p[26]] << 4 | hex[p[27]];
1233 uuid->Data4[6] = hex[p[28]] << 4 | hex[p[29]];
1234 uuid->Data4[7] = hex[p[30]] << 4 | hex[p[31]];
1236 close( fd );
1240 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1241 ULONG *required_len )
1243 switch (sfti->ProviderSignature)
1245 case RSMB:
1247 char bios_vendor[128], bios_version[128], bios_date[128];
1248 size_t bios_vendor_len, bios_version_len, bios_date_len;
1249 char system_vendor[128], system_product[128], system_version[128], system_serial[128];
1250 size_t system_vendor_len, system_product_len, system_version_len, system_serial_len;
1251 char system_sku[128], system_family[128];
1252 size_t system_sku_len, system_family_len;
1253 char board_vendor[128], board_product[128], board_version[128], board_serial[128];
1254 size_t board_vendor_len, board_product_len, board_version_len, board_serial_len;
1255 char chassis_vendor[128], chassis_version[128], chassis_serial[128], chassis_asset_tag[128];
1256 char chassis_type[11] = "2"; /* unknown */
1257 size_t chassis_vendor_len, chassis_version_len, chassis_serial_len, chassis_asset_tag_len;
1258 char *buffer = (char*)sfti->TableBuffer;
1259 BYTE string_count;
1260 struct smbios_prologue *prologue;
1261 struct smbios_bios *bios;
1262 struct smbios_system *system;
1263 struct smbios_board *board;
1264 struct smbios_chassis *chassis;
1266 #define S(s) s, sizeof(s)
1267 bios_vendor_len = get_smbios_string("/sys/class/dmi/id/bios_vendor", S(bios_vendor));
1268 bios_version_len = get_smbios_string("/sys/class/dmi/id/bios_version", S(bios_version));
1269 bios_date_len = get_smbios_string("/sys/class/dmi/id/bios_date", S(bios_date));
1270 system_vendor_len = get_smbios_string("/sys/class/dmi/id/sys_vendor", S(system_vendor));
1271 system_product_len = get_smbios_string("/sys/class/dmi/id/product_name", S(system_product));
1272 system_version_len = get_smbios_string("/sys/class/dmi/id/product_version", S(system_version));
1273 system_serial_len = get_smbios_string("/sys/class/dmi/id/product_serial", S(system_serial));
1274 system_sku_len = get_smbios_string("/sys/class/dmi/id/product_sku", S(system_sku));
1275 system_family_len = get_smbios_string("/sys/class/dmi/id/product_family", S(system_family));
1276 board_vendor_len = get_smbios_string("/sys/class/dmi/id/board_vendor", S(board_vendor));
1277 board_product_len = get_smbios_string("/sys/class/dmi/id/board_name", S(board_product));
1278 board_version_len = get_smbios_string("/sys/class/dmi/id/board_version", S(board_version));
1279 board_serial_len = get_smbios_string("/sys/class/dmi/id/board_serial", S(board_serial));
1280 chassis_vendor_len = get_smbios_string("/sys/class/dmi/id/chassis_vendor", S(chassis_vendor));
1281 chassis_version_len = get_smbios_string("/sys/class/dmi/id/chassis_version", S(chassis_version));
1282 chassis_serial_len = get_smbios_string("/sys/class/dmi/id/chassis_serial", S(chassis_serial));
1283 chassis_asset_tag_len = get_smbios_string("/sys/class/dmi/id/chassis_tag", S(chassis_asset_tag));
1284 get_smbios_string("/sys/class/dmi/id/chassis_type", S(chassis_type));
1285 #undef S
1287 *required_len = sizeof(struct smbios_prologue);
1289 #define L(l) (l + (l ? 1 : 0))
1290 *required_len += sizeof(struct smbios_bios);
1291 *required_len += max(L(bios_vendor_len) + L(bios_version_len) + L(bios_date_len) + 1, 2);
1293 *required_len += sizeof(struct smbios_system);
1294 *required_len += max(L(system_vendor_len) + L(system_product_len) + L(system_version_len) +
1295 L(system_serial_len) + L(system_sku_len) + L(system_family_len) + 1, 2);
1297 *required_len += sizeof(struct smbios_board);
1298 *required_len += max(L(board_vendor_len) + L(board_product_len) + L(board_version_len) + L(board_serial_len) + 1, 2);
1300 *required_len += sizeof(struct smbios_chassis);
1301 *required_len += max(L(chassis_vendor_len) + L(chassis_version_len) + L(chassis_serial_len) +
1302 L(chassis_asset_tag_len) + 1, 2);
1303 #undef L
1305 sfti->TableBufferLength = *required_len;
1307 *required_len += FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
1309 if (available_len < *required_len)
1310 return STATUS_BUFFER_TOO_SMALL;
1312 prologue = (struct smbios_prologue*)buffer;
1313 prologue->calling_method = 0;
1314 prologue->major_version = 2;
1315 prologue->minor_version = 4;
1316 prologue->revision = 0;
1317 prologue->length = sfti->TableBufferLength - sizeof(struct smbios_prologue);
1318 buffer += sizeof(struct smbios_prologue);
1320 string_count = 0;
1321 bios = (struct smbios_bios*)buffer;
1322 bios->hdr.type = 0;
1323 bios->hdr.length = sizeof(struct smbios_bios);
1324 bios->hdr.handle = 0;
1325 bios->vendor = bios_vendor_len ? ++string_count : 0;
1326 bios->version = bios_version_len ? ++string_count : 0;
1327 bios->start = 0;
1328 bios->date = bios_date_len ? ++string_count : 0;
1329 bios->size = 0;
1330 bios->characteristics = 0x4; /* not supported */
1331 bios->characteristics_ext[0] = 0;
1332 bios->characteristics_ext[1] = 0;
1333 bios->system_bios_major_release = 0xFF; /* not supported */
1334 bios->system_bios_minor_release = 0xFF; /* not supported */
1335 bios->ec_firmware_major_release = 0xFF; /* not supported */
1336 bios->ec_firmware_minor_release = 0xFF; /* not supported */
1337 buffer += sizeof(struct smbios_bios);
1339 copy_smbios_string(&buffer, bios_vendor, bios_vendor_len);
1340 copy_smbios_string(&buffer, bios_version, bios_version_len);
1341 copy_smbios_string(&buffer, bios_date, bios_date_len);
1342 if (!string_count) *buffer++ = 0;
1343 *buffer++ = 0;
1345 string_count = 0;
1346 system = (struct smbios_system*)buffer;
1347 system->hdr.type = 1;
1348 system->hdr.length = sizeof(struct smbios_system);
1349 system->hdr.handle = 0;
1350 system->vendor = system_vendor_len ? ++string_count : 0;
1351 system->product = system_product_len ? ++string_count : 0;
1352 system->version = system_version_len ? ++string_count : 0;
1353 system->serial = system_serial_len ? ++string_count : 0;
1354 get_system_uuid( (GUID *)system->uuid );
1355 system->wake_up_type = 0x02; /* unknown */
1356 system->sku_number = system_sku_len ? ++string_count : 0;
1357 system->family = system_family_len ? ++string_count : 0;
1358 buffer += sizeof(struct smbios_system);
1360 copy_smbios_string(&buffer, system_vendor, system_vendor_len);
1361 copy_smbios_string(&buffer, system_product, system_product_len);
1362 copy_smbios_string(&buffer, system_version, system_version_len);
1363 copy_smbios_string(&buffer, system_serial, system_serial_len);
1364 copy_smbios_string(&buffer, system_sku, system_sku_len);
1365 copy_smbios_string(&buffer, system_family, system_family_len);
1366 if (!string_count) *buffer++ = 0;
1367 *buffer++ = 0;
1369 string_count = 0;
1370 board = (struct smbios_board*)buffer;
1371 board->hdr.type = 2;
1372 board->hdr.length = sizeof(struct smbios_board);
1373 board->hdr.handle = 0;
1374 board->vendor = board_vendor_len ? ++string_count : 0;
1375 board->product = board_product_len ? ++string_count : 0;
1376 board->version = board_version_len ? ++string_count : 0;
1377 board->serial = board_serial_len ? ++string_count : 0;
1378 buffer += sizeof(struct smbios_board);
1380 copy_smbios_string(&buffer, board_vendor, board_vendor_len);
1381 copy_smbios_string(&buffer, board_product, board_product_len);
1382 copy_smbios_string(&buffer, board_version, board_version_len);
1383 copy_smbios_string(&buffer, board_serial, board_serial_len);
1384 if (!string_count) *buffer++ = 0;
1385 *buffer++ = 0;
1387 string_count = 0;
1388 chassis = (struct smbios_chassis*)buffer;
1389 chassis->hdr.type = 3;
1390 chassis->hdr.length = sizeof(struct smbios_chassis);
1391 chassis->hdr.handle = 0;
1392 chassis->vendor = chassis_vendor_len ? ++string_count : 0;
1393 chassis->type = atoi(chassis_type);
1394 chassis->version = chassis_version_len ? ++string_count : 0;
1395 chassis->serial = chassis_serial_len ? ++string_count : 0;
1396 chassis->asset_tag = chassis_asset_tag_len ? ++string_count : 0;
1397 chassis->boot_state = 0x02; /* unknown */
1398 chassis->power_supply_state = 0x02; /* unknown */
1399 chassis->thermal_state = 0x02; /* unknown */
1400 chassis->security_status = 0x02; /* unknown */
1401 buffer += sizeof(struct smbios_chassis);
1403 copy_smbios_string(&buffer, chassis_vendor, chassis_vendor_len);
1404 copy_smbios_string(&buffer, chassis_version, chassis_version_len);
1405 copy_smbios_string(&buffer, chassis_serial, chassis_serial_len);
1406 copy_smbios_string(&buffer, chassis_asset_tag, chassis_asset_tag_len);
1407 if (!string_count) *buffer++ = 0;
1408 *buffer++ = 0;
1410 return STATUS_SUCCESS;
1412 default:
1413 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION provider %08x\n", sfti->ProviderSignature);
1414 return STATUS_NOT_IMPLEMENTED;
1418 #elif defined(__APPLE__)
1420 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1421 ULONG *required_len )
1423 switch (sfti->ProviderSignature)
1425 case RSMB:
1427 io_service_t service;
1428 CFDataRef data;
1429 const UInt8 *ptr;
1430 CFIndex len;
1431 struct smbios_prologue *prologue;
1432 BYTE major_version = 2, minor_version = 0;
1434 if (!(service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleSMBIOS"))))
1436 WARN("can't find AppleSMBIOS service\n");
1437 return STATUS_NO_MEMORY;
1440 if (!(data = IORegistryEntryCreateCFProperty(service, CFSTR("SMBIOS-EPS"), kCFAllocatorDefault, 0)))
1442 WARN("can't find SMBIOS entry point\n");
1443 IOObjectRelease(service);
1444 return STATUS_NO_MEMORY;
1447 len = CFDataGetLength(data);
1448 ptr = CFDataGetBytePtr(data);
1449 if (len >= 8 && !memcmp(ptr, "_SM_", 4))
1451 major_version = ptr[6];
1452 minor_version = ptr[7];
1454 CFRelease(data);
1456 if (!(data = IORegistryEntryCreateCFProperty(service, CFSTR("SMBIOS"), kCFAllocatorDefault, 0)))
1458 WARN("can't find SMBIOS table\n");
1459 IOObjectRelease(service);
1460 return STATUS_NO_MEMORY;
1463 len = CFDataGetLength(data);
1464 ptr = CFDataGetBytePtr(data);
1465 sfti->TableBufferLength = sizeof(*prologue) + len;
1466 *required_len = sfti->TableBufferLength + FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
1467 if (available_len < *required_len)
1469 CFRelease(data);
1470 IOObjectRelease(service);
1471 return STATUS_BUFFER_TOO_SMALL;
1474 prologue = (struct smbios_prologue *)sfti->TableBuffer;
1475 prologue->calling_method = 0;
1476 prologue->major_version = major_version;
1477 prologue->minor_version = minor_version;
1478 prologue->revision = 0;
1479 prologue->length = sfti->TableBufferLength - sizeof(*prologue);
1481 memcpy(sfti->TableBuffer + sizeof(*prologue), ptr, len);
1483 CFRelease(data);
1484 IOObjectRelease(service);
1485 return STATUS_SUCCESS;
1487 default:
1488 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION provider %08x\n", sfti->ProviderSignature);
1489 return STATUS_NOT_IMPLEMENTED;
1493 #else
1495 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
1496 ULONG *required_len )
1498 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION\n");
1499 sfti->TableBufferLength = 0;
1500 return STATUS_NOT_IMPLEMENTED;
1503 #endif
1505 static void get_performance_info( SYSTEM_PERFORMANCE_INFORMATION *info )
1507 unsigned long long totalram = 0, freeram = 0, totalswap = 0, freeswap = 0;
1508 FILE *fp;
1510 memset( info, 0, sizeof(*info) );
1512 if ((fp = fopen("/proc/uptime", "r")))
1514 double uptime, idle_time;
1516 fscanf(fp, "%lf %lf", &uptime, &idle_time);
1517 fclose(fp);
1518 info->IdleTime.QuadPart = 10000000 * idle_time;
1520 else
1522 static ULONGLONG idle;
1523 /* many programs expect IdleTime to change so fake change */
1524 info->IdleTime.QuadPart = ++idle;
1527 #ifdef linux
1528 if ((fp = fopen("/proc/meminfo", "r")))
1530 unsigned long long value;
1531 char line[64];
1533 while (fgets(line, sizeof(line), fp))
1535 if(sscanf(line, "MemTotal: %llu kB", &value) == 1)
1536 totalram += value * 1024;
1537 else if(sscanf(line, "MemFree: %llu kB", &value) == 1)
1538 freeram += value * 1024;
1539 else if(sscanf(line, "SwapTotal: %llu kB", &value) == 1)
1540 totalswap += value * 1024;
1541 else if(sscanf(line, "SwapFree: %llu kB", &value) == 1)
1542 freeswap += value * 1024;
1543 else if (sscanf(line, "Buffers: %llu", &value))
1544 freeram += value * 1024;
1545 else if (sscanf(line, "Cached: %llu", &value))
1546 freeram += value * 1024;
1548 fclose(fp);
1550 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || \
1551 defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
1553 #ifdef __APPLE__
1554 unsigned int val;
1555 #else
1556 unsigned long val;
1557 #endif
1558 int mib[2];
1559 size_t size_sys;
1561 mib[0] = CTL_HW;
1562 #ifdef HW_MEMSIZE
1564 uint64_t val64;
1565 mib[1] = HW_MEMSIZE;
1566 size_sys = sizeof(val64);
1567 if (!sysctl(mib, 2, &val64, &size_sys, NULL, 0) && size_sys == sizeof(val64)) totalram = val64;
1569 #endif
1571 #ifdef HAVE_MACH_MACH_H
1573 host_name_port_t host = mach_host_self();
1574 mach_msg_type_number_t count;
1575 #ifdef HOST_VM_INFO64_COUNT
1576 vm_statistics64_data_t vm_stat;
1578 count = HOST_VM_INFO64_COUNT;
1579 if (host_statistics64(host, HOST_VM_INFO64, (host_info64_t)&vm_stat, &count) == KERN_SUCCESS)
1580 freeram = (vm_stat.free_count + vm_stat.inactive_count) * (ULONGLONG)page_size;
1581 #endif
1582 if (!totalram)
1584 host_basic_info_data_t info;
1585 count = HOST_BASIC_INFO_COUNT;
1586 if (host_info(host, HOST_BASIC_INFO, (host_info_t)&info, &count) == KERN_SUCCESS)
1587 totalram = info.max_mem;
1589 mach_port_deallocate(mach_task_self(), host);
1591 #endif
1593 if (!totalram)
1595 mib[1] = HW_PHYSMEM;
1596 size_sys = sizeof(val);
1597 if (!sysctl(mib, 2, &val, &size_sys, NULL, 0) && size_sys == sizeof(val)) totalram = val;
1599 if (!freeram)
1601 mib[1] = HW_USERMEM;
1602 size_sys = sizeof(val);
1603 if (!sysctl(mib, 2, &val, &size_sys, NULL, 0) && size_sys == sizeof(val)) freeram = val;
1605 #ifdef VM_SWAPUSAGE
1607 struct xsw_usage swap;
1608 mib[0] = CTL_VM;
1609 mib[1] = VM_SWAPUSAGE;
1610 size_sys = sizeof(swap);
1611 if (!sysctl(mib, 2, &swap, &size_sys, NULL, 0) && size_sys == sizeof(swap))
1613 totalswap = swap.xsu_total;
1614 freeswap = swap.xsu_avail;
1617 #endif
1619 #endif
1620 info->AvailablePages = freeram / page_size;
1621 info->TotalCommittedPages = (totalram + totalswap - freeram - freeswap) / page_size;
1622 info->TotalCommitLimit = (totalram + totalswap) / page_size;
1626 /* calculate the mday of dst change date, so that for instance Sun 5 Oct 2007
1627 * (last Sunday in October of 2007) becomes Sun Oct 28 2007
1629 * Note: year, day and month must be in unix format.
1631 static int weekday_to_mday(int year, int day, int mon, int day_of_week)
1633 struct tm date;
1634 time_t tmp;
1635 int wday, mday;
1637 /* find first day in the month matching week day of the date */
1638 memset(&date, 0, sizeof(date));
1639 date.tm_year = year;
1640 date.tm_mon = mon;
1641 date.tm_mday = -1;
1642 date.tm_wday = -1;
1645 date.tm_mday++;
1646 tmp = mktime(&date);
1647 } while (date.tm_wday != day_of_week || date.tm_mon != mon);
1649 mday = date.tm_mday;
1651 /* find number of week days in the month matching week day of the date */
1652 wday = 1; /* 1 - 1st, ...., 5 - last */
1653 while (wday < day)
1655 struct tm *tm;
1657 date.tm_mday += 7;
1658 tmp = mktime(&date);
1659 tm = localtime(&tmp);
1660 if (tm->tm_mon != mon)
1661 break;
1662 mday = tm->tm_mday;
1663 wday++;
1666 return mday;
1669 static BOOL match_tz_date( const RTL_SYSTEM_TIME *st, const RTL_SYSTEM_TIME *reg_st )
1671 WORD wDay;
1673 if (st->wMonth != reg_st->wMonth) return FALSE;
1674 if (!st->wMonth) return TRUE; /* no transition dates */
1675 wDay = reg_st->wDay;
1676 if (!reg_st->wYear) /* date in a day-of-week format */
1677 wDay = weekday_to_mday(st->wYear - 1900, reg_st->wDay, reg_st->wMonth - 1, reg_st->wDayOfWeek);
1679 return (st->wDay == wDay &&
1680 st->wHour == reg_st->wHour &&
1681 st->wMinute == reg_st->wMinute &&
1682 st->wSecond == reg_st->wSecond &&
1683 st->wMilliseconds == reg_st->wMilliseconds);
1686 static BOOL match_tz_info( const RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi,
1687 const RTL_DYNAMIC_TIME_ZONE_INFORMATION *reg_tzi )
1689 return (tzi->Bias == reg_tzi->Bias &&
1690 match_tz_date(&tzi->StandardDate, &reg_tzi->StandardDate) &&
1691 match_tz_date(&tzi->DaylightDate, &reg_tzi->DaylightDate));
1694 static BOOL match_tz_name( const char *tz_name, const RTL_DYNAMIC_TIME_ZONE_INFORMATION *reg_tzi )
1696 static const struct { WCHAR key_name[32]; const char *short_name; } mapping[] =
1698 { {'K','o','r','e','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
1699 "KST" },
1700 { {'T','o','k','y','o',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
1701 "JST" },
1702 { {'Y','a','k','u','t','s','k',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
1703 "+09" }, /* YAKST was used until tzdata 2016f */
1705 unsigned int i;
1707 if (reg_tzi->DaylightDate.wMonth) return TRUE;
1708 for (i = 0; i < ARRAY_SIZE(mapping); i++)
1710 if (!wcscmp( mapping[i].key_name, reg_tzi->TimeZoneKeyName ))
1711 return !strcmp( mapping[i].short_name, tz_name );
1713 return TRUE;
1716 static BOOL reg_query_value( HKEY key, LPCWSTR name, DWORD type, void *data, DWORD count )
1718 char buf[256];
1719 UNICODE_STRING nameW;
1720 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buf;
1722 if (count > sizeof(buf) - sizeof(KEY_VALUE_PARTIAL_INFORMATION)) return FALSE;
1724 nameW.Buffer = (WCHAR *)name;
1725 nameW.Length = wcslen( name ) * sizeof(WCHAR);
1726 if (NtQueryValueKey( key, &nameW, KeyValuePartialInformation, buf, sizeof(buf), &count ))
1727 return FALSE;
1729 if (info->Type != type) return FALSE;
1730 memcpy( data, info->Data, info->DataLength );
1731 return TRUE;
1734 static void find_reg_tz_info(RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi, const char* tz_name, int year)
1736 static const WCHAR stdW[] = { 'S','t','d',0 };
1737 static const WCHAR dltW[] = { 'D','l','t',0 };
1738 static const WCHAR mui_stdW[] = { 'M','U','I','_','S','t','d',0 };
1739 static const WCHAR mui_dltW[] = { 'M','U','I','_','D','l','t',0 };
1740 static const WCHAR tziW[] = { 'T','Z','I',0 };
1741 static const WCHAR Time_ZonesW[] = { 'M','a','c','h','i','n','e','\\',
1742 'S','o','f','t','w','a','r','e','\\',
1743 'M','i','c','r','o','s','o','f','t','\\',
1744 'W','i','n','d','o','w','s',' ','N','T','\\',
1745 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1746 'T','i','m','e',' ','Z','o','n','e','s',0 };
1747 static const WCHAR Dynamic_DstW[] = { 'D','y','n','a','m','i','c',' ','D','S','T',0 };
1748 RTL_DYNAMIC_TIME_ZONE_INFORMATION reg_tzi;
1749 HANDLE key, subkey, subkey_dyn = 0;
1750 ULONG idx, len;
1751 OBJECT_ATTRIBUTES attr;
1752 UNICODE_STRING nameW;
1753 WCHAR yearW[16];
1754 char buffer[128];
1755 KEY_BASIC_INFORMATION *info = (KEY_BASIC_INFORMATION *)buffer;
1757 sprintf( buffer, "%u", year );
1758 ascii_to_unicode( yearW, buffer, strlen(buffer) + 1 );
1760 nameW.Buffer = (WCHAR *)Time_ZonesW;
1761 nameW.Length = sizeof(Time_ZonesW) - sizeof(WCHAR);
1762 InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
1763 if (NtOpenKey( &key, KEY_READ, &attr )) return;
1765 idx = 0;
1766 while (!NtEnumerateKey( key, idx++, KeyBasicInformation, buffer, sizeof(buffer), &len ))
1768 struct tz_reg_data
1770 LONG bias;
1771 LONG std_bias;
1772 LONG dlt_bias;
1773 RTL_SYSTEM_TIME std_date;
1774 RTL_SYSTEM_TIME dlt_date;
1775 } tz_data;
1776 BOOL is_dynamic = FALSE;
1778 nameW.Buffer = info->Name;
1779 nameW.Length = info->NameLength;
1780 attr.RootDirectory = key;
1781 if (NtOpenKey( &subkey, KEY_READ, &attr )) continue;
1783 memset( &reg_tzi, 0, sizeof(reg_tzi) );
1784 memcpy(reg_tzi.TimeZoneKeyName, nameW.Buffer, nameW.Length);
1785 reg_tzi.TimeZoneKeyName[nameW.Length/sizeof(WCHAR)] = 0;
1787 if (!reg_query_value(subkey, mui_stdW, REG_SZ, reg_tzi.StandardName, sizeof(reg_tzi.StandardName)) &&
1788 !reg_query_value(subkey, stdW, REG_SZ, reg_tzi.StandardName, sizeof(reg_tzi.StandardName)))
1789 goto next;
1791 if (!reg_query_value(subkey, mui_dltW, REG_SZ, reg_tzi.DaylightName, sizeof(reg_tzi.DaylightName)) &&
1792 !reg_query_value(subkey, dltW, REG_SZ, reg_tzi.DaylightName, sizeof(reg_tzi.DaylightName)))
1793 goto next;
1795 /* Check for Dynamic DST entry first */
1796 nameW.Buffer = (WCHAR *)Dynamic_DstW;
1797 nameW.Length = sizeof(Dynamic_DstW) - sizeof(WCHAR);
1798 attr.RootDirectory = subkey;
1799 if (!NtOpenKey( &subkey_dyn, KEY_READ, &attr ))
1801 is_dynamic = reg_query_value( subkey_dyn, yearW, REG_BINARY, &tz_data, sizeof(tz_data) );
1802 NtClose( subkey_dyn );
1804 if (!is_dynamic && !reg_query_value( subkey, tziW, REG_BINARY, &tz_data, sizeof(tz_data) ))
1805 goto next;
1807 reg_tzi.Bias = tz_data.bias;
1808 reg_tzi.StandardBias = tz_data.std_bias;
1809 reg_tzi.DaylightBias = tz_data.dlt_bias;
1810 reg_tzi.StandardDate = tz_data.std_date;
1811 reg_tzi.DaylightDate = tz_data.dlt_date;
1813 TRACE("%s: bias %d\n", debugstr_us(&nameW), reg_tzi.Bias);
1814 TRACE("std (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
1815 reg_tzi.StandardDate.wDay, reg_tzi.StandardDate.wMonth,
1816 reg_tzi.StandardDate.wYear, reg_tzi.StandardDate.wDayOfWeek,
1817 reg_tzi.StandardDate.wHour, reg_tzi.StandardDate.wMinute,
1818 reg_tzi.StandardDate.wSecond, reg_tzi.StandardDate.wMilliseconds,
1819 reg_tzi.StandardBias);
1820 TRACE("dst (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
1821 reg_tzi.DaylightDate.wDay, reg_tzi.DaylightDate.wMonth,
1822 reg_tzi.DaylightDate.wYear, reg_tzi.DaylightDate.wDayOfWeek,
1823 reg_tzi.DaylightDate.wHour, reg_tzi.DaylightDate.wMinute,
1824 reg_tzi.DaylightDate.wSecond, reg_tzi.DaylightDate.wMilliseconds,
1825 reg_tzi.DaylightBias);
1827 if (match_tz_info( tzi, &reg_tzi ) && match_tz_name( tz_name, &reg_tzi ))
1829 *tzi = reg_tzi;
1830 NtClose( subkey );
1831 NtClose( key );
1832 return;
1834 next:
1835 NtClose( subkey );
1837 NtClose( key );
1839 if (idx == 1) return; /* registry info not initialized yet */
1841 FIXME("Can't find matching timezone information in the registry for "
1842 "%s, bias %d, std (d/m/y): %u/%02u/%04u, dlt (d/m/y): %u/%02u/%04u\n",
1843 tz_name, tzi->Bias,
1844 tzi->StandardDate.wDay, tzi->StandardDate.wMonth, tzi->StandardDate.wYear,
1845 tzi->DaylightDate.wDay, tzi->DaylightDate.wMonth, tzi->DaylightDate.wYear);
1848 static time_t find_dst_change(unsigned long min, unsigned long max, int *is_dst)
1850 time_t start;
1851 struct tm *tm;
1853 start = min;
1854 tm = localtime(&start);
1855 *is_dst = !tm->tm_isdst;
1856 TRACE("starting date isdst %d, %s", !*is_dst, ctime(&start));
1858 while (min <= max)
1860 time_t pos = (min + max) / 2;
1861 tm = localtime(&pos);
1863 if (tm->tm_isdst != *is_dst)
1864 min = pos + 1;
1865 else
1866 max = pos - 1;
1868 return min;
1871 static void get_timezone_info( RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi )
1873 static pthread_mutex_t tz_mutex = PTHREAD_MUTEX_INITIALIZER;
1874 static RTL_DYNAMIC_TIME_ZONE_INFORMATION cached_tzi;
1875 static int current_year = -1, current_bias = 65535;
1876 struct tm *tm;
1877 char tz_name[16];
1878 time_t year_start, year_end, tmp, dlt = 0, std = 0;
1879 int is_dst, bias;
1881 pthread_mutex_lock( &tz_mutex );
1883 year_start = time(NULL);
1884 tm = gmtime(&year_start);
1885 bias = (LONG)(mktime(tm) - year_start) / 60;
1887 tm = localtime(&year_start);
1888 if (current_year == tm->tm_year && current_bias == bias)
1890 *tzi = cached_tzi;
1891 pthread_mutex_unlock( &tz_mutex );
1892 return;
1895 memset(tzi, 0, sizeof(*tzi));
1896 if (!strftime(tz_name, sizeof(tz_name), "%Z", tm)) {
1897 /* not enough room or another error */
1898 tz_name[0] = '\0';
1901 TRACE("tz data will be valid through year %d, bias %d\n", tm->tm_year + 1900, bias);
1902 current_year = tm->tm_year;
1903 current_bias = bias;
1905 tzi->Bias = bias;
1907 tm->tm_isdst = 0;
1908 tm->tm_mday = 1;
1909 tm->tm_mon = tm->tm_hour = tm->tm_min = tm->tm_sec = tm->tm_wday = tm->tm_yday = 0;
1910 year_start = mktime(tm);
1911 TRACE("year_start: %s", ctime(&year_start));
1913 tm->tm_mday = tm->tm_wday = tm->tm_yday = 0;
1914 tm->tm_mon = 12;
1915 tm->tm_hour = 23;
1916 tm->tm_min = tm->tm_sec = 59;
1917 year_end = mktime(tm);
1918 TRACE("year_end: %s", ctime(&year_end));
1920 tmp = find_dst_change(year_start, year_end, &is_dst);
1921 if (is_dst)
1922 dlt = tmp;
1923 else
1924 std = tmp;
1926 tmp = find_dst_change(tmp, year_end, &is_dst);
1927 if (is_dst)
1928 dlt = tmp;
1929 else
1930 std = tmp;
1932 TRACE("std: %s", ctime(&std));
1933 TRACE("dlt: %s", ctime(&dlt));
1935 if (dlt == std || !dlt || !std)
1936 TRACE("there is no daylight saving rules in this time zone\n");
1937 else
1939 tmp = dlt - tzi->Bias * 60;
1940 tm = gmtime(&tmp);
1941 TRACE("dlt gmtime: %s", asctime(tm));
1943 tzi->DaylightBias = -60;
1944 tzi->DaylightDate.wYear = tm->tm_year + 1900;
1945 tzi->DaylightDate.wMonth = tm->tm_mon + 1;
1946 tzi->DaylightDate.wDayOfWeek = tm->tm_wday;
1947 tzi->DaylightDate.wDay = tm->tm_mday;
1948 tzi->DaylightDate.wHour = tm->tm_hour;
1949 tzi->DaylightDate.wMinute = tm->tm_min;
1950 tzi->DaylightDate.wSecond = tm->tm_sec;
1951 tzi->DaylightDate.wMilliseconds = 0;
1953 TRACE("daylight (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
1954 tzi->DaylightDate.wDay, tzi->DaylightDate.wMonth,
1955 tzi->DaylightDate.wYear, tzi->DaylightDate.wDayOfWeek,
1956 tzi->DaylightDate.wHour, tzi->DaylightDate.wMinute,
1957 tzi->DaylightDate.wSecond, tzi->DaylightDate.wMilliseconds,
1958 tzi->DaylightBias);
1960 tmp = std - tzi->Bias * 60 - tzi->DaylightBias * 60;
1961 tm = gmtime(&tmp);
1962 TRACE("std gmtime: %s", asctime(tm));
1964 tzi->StandardBias = 0;
1965 tzi->StandardDate.wYear = tm->tm_year + 1900;
1966 tzi->StandardDate.wMonth = tm->tm_mon + 1;
1967 tzi->StandardDate.wDayOfWeek = tm->tm_wday;
1968 tzi->StandardDate.wDay = tm->tm_mday;
1969 tzi->StandardDate.wHour = tm->tm_hour;
1970 tzi->StandardDate.wMinute = tm->tm_min;
1971 tzi->StandardDate.wSecond = tm->tm_sec;
1972 tzi->StandardDate.wMilliseconds = 0;
1974 TRACE("standard (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
1975 tzi->StandardDate.wDay, tzi->StandardDate.wMonth,
1976 tzi->StandardDate.wYear, tzi->StandardDate.wDayOfWeek,
1977 tzi->StandardDate.wHour, tzi->StandardDate.wMinute,
1978 tzi->StandardDate.wSecond, tzi->StandardDate.wMilliseconds,
1979 tzi->StandardBias);
1982 find_reg_tz_info(tzi, tz_name, current_year + 1900);
1983 cached_tzi = *tzi;
1984 pthread_mutex_unlock( &tz_mutex );
1988 /******************************************************************************
1989 * NtQuerySystemInformation (NTDLL.@)
1991 NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class,
1992 void *info, ULONG size, ULONG *ret_size )
1994 NTSTATUS ret = STATUS_SUCCESS;
1995 ULONG len = 0;
1997 TRACE( "(0x%08x,%p,0x%08x,%p)\n", class, info, size, ret_size );
1999 switch (class)
2001 case SystemBasicInformation:
2003 SYSTEM_BASIC_INFORMATION sbi;
2005 virtual_get_system_info( &sbi );
2006 len = sizeof(sbi);
2007 if (size == len)
2009 if (!info) ret = STATUS_ACCESS_VIOLATION;
2010 else memcpy( info, &sbi, len);
2012 else ret = STATUS_INFO_LENGTH_MISMATCH;
2013 break;
2016 case SystemCpuInformation:
2017 if (size >= (len = sizeof(cpu_info)))
2019 if (!info) ret = STATUS_ACCESS_VIOLATION;
2020 else memcpy(info, &cpu_info, len);
2022 else ret = STATUS_INFO_LENGTH_MISMATCH;
2023 break;
2025 case SystemPerformanceInformation:
2027 SYSTEM_PERFORMANCE_INFORMATION spi;
2028 static BOOL fixme_written = FALSE;
2030 get_performance_info( &spi );
2031 len = sizeof(spi);
2032 if (size >= len)
2034 if (!info) ret = STATUS_ACCESS_VIOLATION;
2035 else memcpy( info, &spi, len);
2037 else ret = STATUS_INFO_LENGTH_MISMATCH;
2038 if(!fixme_written) {
2039 FIXME("info_class SYSTEM_PERFORMANCE_INFORMATION\n");
2040 fixme_written = TRUE;
2042 break;
2045 case SystemTimeOfDayInformation:
2047 struct tm *tm;
2048 time_t now;
2049 SYSTEM_TIMEOFDAY_INFORMATION sti = {{{ 0 }}};
2051 sti.BootTime.QuadPart = server_start_time;
2052 now = time( NULL );
2053 tm = gmtime( &now );
2054 sti.TimeZoneBias.QuadPart = mktime( tm ) - now;
2055 tm = localtime( &now );
2056 if (tm->tm_isdst) sti.TimeZoneBias.QuadPart -= 3600;
2057 sti.TimeZoneBias.QuadPart *= TICKSPERSEC;
2058 NtQuerySystemTime( &sti.SystemTime );
2060 if (size <= sizeof(sti))
2062 len = size;
2063 if (!info) ret = STATUS_ACCESS_VIOLATION;
2064 else memcpy( info, &sti, size);
2066 else ret = STATUS_INFO_LENGTH_MISMATCH;
2067 break;
2070 case SystemProcessInformation:
2072 unsigned int process_count, i, j;
2073 char *buffer = NULL;
2074 unsigned int pos = 0;
2076 if (size && !(buffer = malloc( size )))
2078 ret = STATUS_NO_MEMORY;
2079 break;
2082 SERVER_START_REQ( list_processes )
2084 wine_server_set_reply( req, buffer, size );
2085 ret = wine_server_call( req );
2086 len = reply->info_size;
2087 process_count = reply->process_count;
2089 SERVER_END_REQ;
2091 if (ret)
2093 free( buffer );
2094 break;
2097 len = 0;
2099 for (i = 0; i < process_count; i++)
2101 SYSTEM_PROCESS_INFORMATION *nt_process = (SYSTEM_PROCESS_INFORMATION *)((char *)info + len);
2102 const struct process_info *server_process;
2103 const WCHAR *server_name, *file_part;
2104 ULONG proc_len;
2105 ULONG name_len = 0;
2107 pos = (pos + 7) & ~7;
2108 server_process = (const struct process_info *)(buffer + pos);
2109 pos += sizeof(*server_process);
2111 server_name = (const WCHAR *)(buffer + pos);
2112 file_part = server_name + (server_process->name_len / sizeof(WCHAR));
2113 pos += server_process->name_len;
2114 while (file_part > server_name && file_part[-1] != '\\')
2116 file_part--;
2117 name_len++;
2120 proc_len = sizeof(*nt_process) + server_process->thread_count * sizeof(SYSTEM_THREAD_INFORMATION)
2121 + (name_len + 1) * sizeof(WCHAR);
2122 len += proc_len;
2124 if (len <= size)
2126 memset(nt_process, 0, sizeof(*nt_process));
2127 if (i < process_count - 1)
2128 nt_process->NextEntryOffset = proc_len;
2129 nt_process->CreationTime.QuadPart = server_process->start_time;
2130 nt_process->dwThreadCount = server_process->thread_count;
2131 nt_process->dwBasePriority = server_process->priority;
2132 nt_process->UniqueProcessId = UlongToHandle(server_process->pid);
2133 nt_process->ParentProcessId = UlongToHandle(server_process->parent_pid);
2134 nt_process->HandleCount = server_process->handle_count;
2135 get_thread_times( server_process->unix_pid, -1, &nt_process->KernelTime, &nt_process->UserTime );
2136 fill_vm_counters( &nt_process->vmCounters, server_process->unix_pid );
2139 pos = (pos + 7) & ~7;
2140 for (j = 0; j < server_process->thread_count; j++)
2142 const struct thread_info *server_thread = (const struct thread_info *)(buffer + pos);
2144 if (len <= size)
2146 nt_process->ti[j].CreateTime.QuadPart = server_thread->start_time;
2147 nt_process->ti[j].ClientId.UniqueProcess = UlongToHandle(server_process->pid);
2148 nt_process->ti[j].ClientId.UniqueThread = UlongToHandle(server_thread->tid);
2149 nt_process->ti[j].dwCurrentPriority = server_thread->current_priority;
2150 nt_process->ti[j].dwBasePriority = server_thread->base_priority;
2151 get_thread_times( server_process->unix_pid, server_thread->unix_tid,
2152 &nt_process->ti[j].KernelTime, &nt_process->ti[j].UserTime );
2155 pos += sizeof(*server_thread);
2158 if (len <= size)
2160 nt_process->ProcessName.Buffer = (WCHAR *)&nt_process->ti[server_process->thread_count];
2161 nt_process->ProcessName.Length = name_len * sizeof(WCHAR);
2162 nt_process->ProcessName.MaximumLength = (name_len + 1) * sizeof(WCHAR);
2163 memcpy(nt_process->ProcessName.Buffer, file_part, name_len * sizeof(WCHAR));
2164 nt_process->ProcessName.Buffer[name_len] = 0;
2168 if (len > size) ret = STATUS_INFO_LENGTH_MISMATCH;
2169 free( buffer );
2170 break;
2173 case SystemProcessorPerformanceInformation:
2175 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL;
2176 unsigned int cpus = 0;
2177 int out_cpus = size / sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
2179 if (out_cpus == 0)
2181 len = 0;
2182 ret = STATUS_INFO_LENGTH_MISMATCH;
2183 break;
2185 if (!(sppi = calloc( out_cpus, sizeof(*sppi) )))
2187 ret = STATUS_NO_MEMORY;
2188 break;
2190 else
2191 #ifdef __APPLE__
2193 processor_cpu_load_info_data_t *pinfo;
2194 mach_msg_type_number_t info_count;
2196 if (host_processor_info( mach_host_self (),
2197 PROCESSOR_CPU_LOAD_INFO,
2198 &cpus,
2199 (processor_info_array_t*)&pinfo,
2200 &info_count) == 0)
2202 int i;
2203 cpus = min(cpus,out_cpus);
2204 for (i = 0; i < cpus; i++)
2206 sppi[i].IdleTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_IDLE];
2207 sppi[i].KernelTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_SYSTEM];
2208 sppi[i].UserTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_USER];
2210 vm_deallocate (mach_task_self (), (vm_address_t) pinfo, info_count * sizeof(natural_t));
2213 #else
2215 FILE *cpuinfo = fopen("/proc/stat", "r");
2216 if (cpuinfo)
2218 unsigned long clk_tck = sysconf(_SC_CLK_TCK);
2219 unsigned long usr,nice,sys,idle,remainder[8];
2220 int i, count, id;
2221 char name[32];
2222 char line[255];
2224 /* first line is combined usage */
2225 while (fgets(line,255,cpuinfo))
2227 count = sscanf(line, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
2228 name, &usr, &nice, &sys, &idle,
2229 &remainder[0], &remainder[1], &remainder[2], &remainder[3],
2230 &remainder[4], &remainder[5], &remainder[6], &remainder[7]);
2232 if (count < 5 || strncmp( name, "cpu", 3 )) break;
2233 for (i = 0; i + 5 < count; ++i) sys += remainder[i];
2234 sys += idle;
2235 usr += nice;
2236 id = atoi( name + 3 ) + 1;
2237 if (id > out_cpus) break;
2238 if (id > cpus) cpus = id;
2239 sppi[id-1].IdleTime.QuadPart = (ULONGLONG)idle * 10000000 / clk_tck;
2240 sppi[id-1].KernelTime.QuadPart = (ULONGLONG)sys * 10000000 / clk_tck;
2241 sppi[id-1].UserTime.QuadPart = (ULONGLONG)usr * 10000000 / clk_tck;
2243 fclose(cpuinfo);
2246 #endif
2247 if (cpus == 0)
2249 static int i = 1;
2250 unsigned int n;
2251 cpus = min(NtCurrentTeb()->Peb->NumberOfProcessors, out_cpus);
2252 FIXME("stub info_class SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION\n");
2253 /* many programs expect these values to change so fake change */
2254 for (n = 0; n < cpus; n++)
2256 sppi[n].KernelTime.QuadPart = 1 * i;
2257 sppi[n].UserTime.QuadPart = 2 * i;
2258 sppi[n].IdleTime.QuadPart = 3 * i;
2260 i++;
2263 len = sizeof(*sppi) * cpus;
2264 if (size >= len)
2266 if (!info) ret = STATUS_ACCESS_VIOLATION;
2267 else memcpy( info, sppi, len);
2269 else ret = STATUS_INFO_LENGTH_MISMATCH;
2271 free( sppi );
2272 break;
2275 case SystemModuleInformation:
2277 /* FIXME: return some fake info for now */
2278 static const char *fake_modules[] =
2280 "\\SystemRoot\\system32\\ntoskrnl.exe",
2281 "\\SystemRoot\\system32\\hal.dll",
2282 "\\SystemRoot\\system32\\drivers\\mountmgr.sys"
2285 if (!info) ret = STATUS_ACCESS_VIOLATION;
2286 else
2288 ULONG i;
2289 SYSTEM_MODULE_INFORMATION *smi = info;
2291 len = offsetof( SYSTEM_MODULE_INFORMATION, Modules[ARRAY_SIZE(fake_modules)] );
2292 if (len <= size)
2294 memset( smi, 0, len );
2295 for (i = 0; i < ARRAY_SIZE(fake_modules); i++)
2297 SYSTEM_MODULE *sm = &smi->Modules[i];
2298 sm->ImageBaseAddress = (char *)0x10000000 + 0x200000 * i;
2299 sm->ImageSize = 0x200000;
2300 sm->LoadOrderIndex = i;
2301 sm->LoadCount = 1;
2302 strcpy( (char *)sm->Name, fake_modules[i] );
2303 sm->NameOffset = strrchr( fake_modules[i], '\\' ) - fake_modules[i] + 1;
2305 smi->ModulesCount = i;
2307 else ret = STATUS_INFO_LENGTH_MISMATCH;
2309 break;
2312 case SystemHandleInformation:
2314 struct handle_info *handle_info;
2315 DWORD i, num_handles;
2317 if (size < sizeof(SYSTEM_HANDLE_INFORMATION))
2319 ret = STATUS_INFO_LENGTH_MISMATCH;
2320 break;
2323 if (!info)
2325 ret = STATUS_ACCESS_VIOLATION;
2326 break;
2329 num_handles = (size - FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle )) / sizeof(SYSTEM_HANDLE_ENTRY);
2330 if (!(handle_info = malloc( sizeof(*handle_info) * num_handles ))) return STATUS_NO_MEMORY;
2332 SERVER_START_REQ( get_system_handles )
2334 wine_server_set_reply( req, handle_info, sizeof(*handle_info) * num_handles );
2335 if (!(ret = wine_server_call( req )))
2337 SYSTEM_HANDLE_INFORMATION *shi = info;
2338 shi->Count = wine_server_reply_size( req ) / sizeof(*handle_info);
2339 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle[shi->Count] );
2340 for (i = 0; i < shi->Count; i++)
2342 memset( &shi->Handle[i], 0, sizeof(shi->Handle[i]) );
2343 shi->Handle[i].OwnerPid = handle_info[i].owner;
2344 shi->Handle[i].HandleValue = handle_info[i].handle;
2345 shi->Handle[i].AccessMask = handle_info[i].access;
2346 /* FIXME: Fill out ObjectType, HandleFlags, ObjectPointer */
2349 else if (ret == STATUS_BUFFER_TOO_SMALL)
2351 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle[reply->count] );
2352 ret = STATUS_INFO_LENGTH_MISMATCH;
2355 SERVER_END_REQ;
2357 free( handle_info );
2358 break;
2361 case SystemCacheInformation:
2363 SYSTEM_CACHE_INFORMATION sci = { 0 };
2365 len = sizeof(sci);
2366 if (size >= len)
2368 if (!info) ret = STATUS_ACCESS_VIOLATION;
2369 else memcpy( info, &sci, len);
2371 else ret = STATUS_INFO_LENGTH_MISMATCH;
2372 FIXME("info_class SYSTEM_CACHE_INFORMATION\n");
2373 break;
2376 case SystemInterruptInformation:
2378 SYSTEM_INTERRUPT_INFORMATION sii = {{ 0 }};
2380 len = sizeof(sii);
2381 if (size >= len)
2383 if (!info) ret = STATUS_ACCESS_VIOLATION;
2384 else memcpy( info, &sii, len);
2386 else ret = STATUS_INFO_LENGTH_MISMATCH;
2387 FIXME("info_class SYSTEM_INTERRUPT_INFORMATION\n");
2388 break;
2391 case SystemTimeAdjustmentInformation:
2393 SYSTEM_TIME_ADJUSTMENT_QUERY query = { 156250, 156250, TRUE };
2395 len = sizeof(query);
2396 if (size == len)
2398 if (!info) ret = STATUS_ACCESS_VIOLATION;
2399 else memcpy( info, &query, len );
2401 else ret = STATUS_INFO_LENGTH_MISMATCH;
2402 break;
2405 case SystemKernelDebuggerInformation:
2407 SYSTEM_KERNEL_DEBUGGER_INFORMATION skdi;
2409 skdi.DebuggerEnabled = FALSE;
2410 skdi.DebuggerNotPresent = TRUE;
2411 len = sizeof(skdi);
2412 if (size >= len)
2414 if (!info) ret = STATUS_ACCESS_VIOLATION;
2415 else memcpy( info, &skdi, len);
2417 else ret = STATUS_INFO_LENGTH_MISMATCH;
2418 break;
2421 case SystemRegistryQuotaInformation:
2423 /* Something to do with the size of the registry *
2424 * Since we don't have a size limitation, fake it *
2425 * This is almost certainly wrong. *
2426 * This sets each of the three words in the struct to 32 MB, *
2427 * which is enough to make the IE 5 installer happy. */
2428 SYSTEM_REGISTRY_QUOTA_INFORMATION srqi;
2430 srqi.RegistryQuotaAllowed = 0x2000000;
2431 srqi.RegistryQuotaUsed = 0x200000;
2432 srqi.Reserved1 = (void*)0x200000;
2433 len = sizeof(srqi);
2435 if (size >= len)
2437 if (!info) ret = STATUS_ACCESS_VIOLATION;
2438 else
2440 FIXME("SystemRegistryQuotaInformation: faking max registry size of 32 MB\n");
2441 memcpy( info, &srqi, len);
2444 else ret = STATUS_INFO_LENGTH_MISMATCH;
2445 break;
2448 case SystemTimeZoneInformation:
2450 RTL_DYNAMIC_TIME_ZONE_INFORMATION tz;
2452 get_timezone_info( &tz );
2453 len = sizeof(RTL_TIME_ZONE_INFORMATION);
2454 if (size >= len)
2456 if (!info) ret = STATUS_ACCESS_VIOLATION;
2457 else memcpy( info, &tz, len);
2459 else ret = STATUS_INFO_LENGTH_MISMATCH;
2460 break;
2463 case SystemLogicalProcessorInformation:
2465 SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buf;
2467 /* Each logical processor may use up to 7 entries in returned table:
2468 * core, numa node, package, L1i, L1d, L2, L3 */
2469 len = 7 * NtCurrentTeb()->Peb->NumberOfProcessors;
2470 buf = malloc( len * sizeof(*buf) );
2471 if (!buf)
2473 ret = STATUS_NO_MEMORY;
2474 break;
2476 ret = create_logical_proc_info(&buf, NULL, &len, RelationAll);
2477 if (!ret)
2479 if (size >= len)
2481 if (!info) ret = STATUS_ACCESS_VIOLATION;
2482 else memcpy( info, buf, len);
2484 else ret = STATUS_INFO_LENGTH_MISMATCH;
2486 free( buf );
2487 break;
2490 case SystemRecommendedSharedDataAlignment:
2492 len = sizeof(DWORD);
2493 if (size >= len)
2495 if (!info) ret = STATUS_ACCESS_VIOLATION;
2496 else
2498 #ifdef __arm__
2499 *((DWORD *)info) = 32;
2500 #else
2501 *((DWORD *)info) = 64;
2502 #endif
2505 else ret = STATUS_INFO_LENGTH_MISMATCH;
2506 break;
2509 case SystemFirmwareTableInformation:
2511 SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti = info;
2512 len = FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
2513 if (size < len)
2515 ret = STATUS_INFO_LENGTH_MISMATCH;
2516 break;
2519 switch (sfti->Action)
2521 case SystemFirmwareTable_Get:
2522 ret = get_firmware_info(sfti, size, &len);
2523 break;
2524 default:
2525 len = 0;
2526 ret = STATUS_NOT_IMPLEMENTED;
2527 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION action %d\n", sfti->Action);
2529 break;
2532 case SystemDynamicTimeZoneInformation:
2534 RTL_DYNAMIC_TIME_ZONE_INFORMATION tz;
2536 get_timezone_info( &tz );
2537 len = sizeof(tz);
2538 if (size >= len)
2540 if (!info) ret = STATUS_ACCESS_VIOLATION;
2541 else memcpy( info, &tz, len);
2543 else ret = STATUS_INFO_LENGTH_MISMATCH;
2544 break;
2547 default:
2548 FIXME( "(0x%08x,%p,0x%08x,%p) stub\n", class, info, size, ret_size );
2550 /* Several Information Classes are not implemented on Windows and return 2 different values
2551 * STATUS_NOT_IMPLEMENTED or STATUS_INVALID_INFO_CLASS
2552 * in 95% of the cases it's STATUS_INVALID_INFO_CLASS, so use this as the default
2554 ret = STATUS_INVALID_INFO_CLASS;
2557 if (ret_size) *ret_size = len;
2558 return ret;
2562 /******************************************************************************
2563 * NtQuerySystemInformationEx (NTDLL.@)
2565 NTSTATUS WINAPI NtQuerySystemInformationEx( SYSTEM_INFORMATION_CLASS class,
2566 void *query, ULONG query_len,
2567 void *info, ULONG size, ULONG *ret_size )
2569 ULONG len = 0;
2570 NTSTATUS ret = STATUS_NOT_IMPLEMENTED;
2572 TRACE( "(0x%08x,%p,%u,%p,%u,%p) stub\n", class, query, query_len, info, size, ret_size );
2574 switch (class)
2576 case SystemLogicalProcessorInformationEx:
2578 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buf;
2580 if (!query || query_len < sizeof(DWORD))
2582 ret = STATUS_INVALID_PARAMETER;
2583 break;
2586 len = 3 * sizeof(*buf);
2587 if (!(buf = malloc( len )))
2589 ret = STATUS_NO_MEMORY;
2590 break;
2592 ret = create_logical_proc_info(NULL, &buf, &len, *(DWORD *)query);
2593 if (!ret)
2595 if (size >= len)
2597 if (!info) ret = STATUS_ACCESS_VIOLATION;
2598 else memcpy(info, buf, len);
2600 else ret = STATUS_INFO_LENGTH_MISMATCH;
2602 free( buf );
2603 break;
2606 default:
2607 FIXME( "(0x%08x,%p,%u,%p,%u,%p) stub\n", class, query, query_len, info, size, ret_size );
2608 break;
2610 if (ret_size) *ret_size = len;
2611 return ret;
2615 /******************************************************************************
2616 * NtSetSystemInformation (NTDLL.@)
2618 NTSTATUS WINAPI NtSetSystemInformation( SYSTEM_INFORMATION_CLASS class, void *info, ULONG length )
2620 FIXME( "(0x%08x,%p,0x%08x) stub\n", class, info, length );
2621 return STATUS_SUCCESS;
2625 /******************************************************************************
2626 * NtQuerySystemEnvironmentValue (NTDLL.@)
2628 NTSTATUS WINAPI NtQuerySystemEnvironmentValue( UNICODE_STRING *name, WCHAR *buffer, ULONG length,
2629 ULONG *retlen )
2631 FIXME( "(%s, %p, %u, %p), stub\n", debugstr_us(name), buffer, length, retlen );
2632 return STATUS_NOT_IMPLEMENTED;
2636 /******************************************************************************
2637 * NtQuerySystemEnvironmentValueEx (NTDLL.@)
2639 NTSTATUS WINAPI NtQuerySystemEnvironmentValueEx( UNICODE_STRING *name, GUID *vendor, void *buffer,
2640 ULONG *retlen, ULONG *attrib )
2642 FIXME( "(%s, %s, %p, %p, %p), stub\n", debugstr_us(name),
2643 debugstr_guid(vendor), buffer, retlen, attrib );
2644 return STATUS_NOT_IMPLEMENTED;
2648 /******************************************************************************
2649 * NtSystemDebugControl (NTDLL.@)
2651 NTSTATUS WINAPI NtSystemDebugControl( SYSDBG_COMMAND command, void *in_buff, ULONG in_len,
2652 void *out_buff, ULONG out_len, ULONG *retlen )
2654 FIXME( "(%d, %p, %d, %p, %d, %p), stub\n", command, in_buff, in_len, out_buff, out_len, retlen );
2655 return STATUS_NOT_IMPLEMENTED;
2659 /******************************************************************************
2660 * NtShutdownSystem (NTDLL.@)
2662 NTSTATUS WINAPI NtShutdownSystem( SHUTDOWN_ACTION action )
2664 FIXME( "%d\n", action );
2665 return STATUS_SUCCESS;
2669 #ifdef linux
2671 /* Fallback using /proc/cpuinfo for Linux systems without cpufreq. For
2672 * most distributions on recent enough hardware, this is only likely to
2673 * happen while running in virtualized environments such as QEMU. */
2674 static ULONG mhz_from_cpuinfo(void)
2676 char line[512];
2677 char *s, *value;
2678 double cmz = 0;
2679 FILE *f = fopen("/proc/cpuinfo", "r");
2680 if(f)
2682 while (fgets(line, sizeof(line), f) != NULL)
2684 if (!(value = strchr(line,':'))) continue;
2685 s = value - 1;
2686 while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
2687 s[1] = 0;
2688 value++;
2689 if (!strcmp( line, "cpu MHz" ))
2691 sscanf(value, " %lf", &cmz);
2692 break;
2695 fclose( f );
2697 return cmz;
2700 static const char * get_sys_str(const char *path, char *s)
2702 FILE *f = fopen(path, "r");
2703 const char *ret = NULL;
2705 if (f)
2707 if (fgets(s, 16, f)) ret = s;
2708 fclose(f);
2710 return ret;
2713 static int get_sys_int(const char *path, int def)
2715 char s[16];
2716 return get_sys_str(path, s) ? atoi(s) : def;
2719 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
2721 char s[16], path[64];
2722 unsigned int i = 0;
2723 LONG64 voltage; /* microvolts */
2725 bs->AcOnLine = get_sys_int("/sys/class/power_supply/AC/online", 1);
2727 for (;;)
2729 sprintf(path, "/sys/class/power_supply/BAT%u/status", i);
2730 if (!get_sys_str(path, s)) break;
2731 bs->Charging |= (strcmp(s, "Charging\n") == 0);
2732 bs->Discharging |= (strcmp(s, "Discharging\n") == 0);
2733 bs->BatteryPresent = TRUE;
2734 i++;
2737 if (bs->BatteryPresent)
2739 voltage = get_sys_int("/sys/class/power_supply/BAT0/voltage_now", 0);
2740 bs->MaxCapacity = get_sys_int("/sys/class/power_supply/BAT0/charge_full", 0) * voltage / 1e9;
2741 bs->RemainingCapacity = get_sys_int("/sys/class/power_supply/BAT0/charge_now", 0) * voltage / 1e9;
2742 bs->Rate = -get_sys_int("/sys/class/power_supply/BAT0/current_now", 0) * voltage / 1e9;
2743 if (!bs->Charging && (LONG)bs->Rate < 0)
2744 bs->EstimatedTime = 3600 * bs->RemainingCapacity / -(LONG)bs->Rate;
2745 else
2746 bs->EstimatedTime = ~0u;
2749 return STATUS_SUCCESS;
2752 #elif defined(HAVE_IOKIT_IOKITLIB_H)
2754 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
2756 CFArrayRef batteries;
2757 CFDictionaryRef battery;
2758 CFNumberRef prop;
2759 uint32_t value, voltage;
2760 CFTimeInterval remain;
2762 if (IOPMCopyBatteryInfo( kIOMasterPortDefault, &batteries ) != kIOReturnSuccess)
2763 return STATUS_ACCESS_DENIED;
2765 if (CFArrayGetCount( batteries ) == 0)
2767 /* Just assume we're on AC with no battery. */
2768 bs->AcOnLine = TRUE;
2769 return STATUS_SUCCESS;
2771 /* Just use the first battery. */
2772 battery = CFArrayGetValueAtIndex( batteries, 0 );
2774 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryFlagsKey) );
2775 CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
2777 if (value & kIOBatteryInstalled)
2778 bs->BatteryPresent = TRUE;
2779 else
2780 /* Since we are executing code, we must have AC power. */
2781 bs->AcOnLine = TRUE;
2782 if (value & kIOBatteryChargerConnect)
2784 bs->AcOnLine = TRUE;
2785 if (value & kIOBatteryCharge)
2786 bs->Charging = TRUE;
2788 else
2789 bs->Discharging = TRUE;
2791 /* We'll need the voltage to be able to interpret the other values. */
2792 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryVoltageKey) );
2793 CFNumberGetValue( prop, kCFNumberSInt32Type, &voltage );
2795 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryCapacityKey) );
2796 CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
2797 bs->MaxCapacity = value * voltage;
2798 /* Apple uses "estimated time < 10:00" and "22%" for these, but we'll follow
2799 * Windows for now (5% and 33%). */
2800 bs->DefaultAlert1 = bs->MaxCapacity / 20;
2801 bs->DefaultAlert2 = bs->MaxCapacity / 3;
2803 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryCurrentChargeKey) );
2804 CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
2805 bs->RemainingCapacity = value * voltage;
2807 prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryAmperageKey) );
2808 CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
2809 bs->Rate = value * voltage;
2811 remain = IOPSGetTimeRemainingEstimate();
2812 if (remain != kIOPSTimeRemainingUnknown && remain != kIOPSTimeRemainingUnlimited)
2813 bs->EstimatedTime = (ULONG)remain;
2815 CFRelease( batteries );
2816 return STATUS_SUCCESS;
2819 #else
2821 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
2823 FIXME("SystemBatteryState not implemented on this platform\n");
2824 return STATUS_NOT_IMPLEMENTED;
2827 #endif
2829 /******************************************************************************
2830 * NtPowerInformation (NTDLL.@)
2832 NTSTATUS WINAPI NtPowerInformation( POWER_INFORMATION_LEVEL level, void *input, ULONG in_size,
2833 void *output, ULONG out_size )
2835 TRACE( "(%d,%p,%d,%p,%d)\n", level, input, in_size, output, out_size );
2836 switch (level)
2838 case SystemPowerCapabilities:
2840 PSYSTEM_POWER_CAPABILITIES PowerCaps = output;
2841 FIXME("semi-stub: SystemPowerCapabilities\n");
2842 if (out_size < sizeof(SYSTEM_POWER_CAPABILITIES)) return STATUS_BUFFER_TOO_SMALL;
2843 /* FIXME: These values are based off a native XP desktop, should probably use APM/ACPI to get the 'real' values */
2844 PowerCaps->PowerButtonPresent = TRUE;
2845 PowerCaps->SleepButtonPresent = FALSE;
2846 PowerCaps->LidPresent = FALSE;
2847 PowerCaps->SystemS1 = TRUE;
2848 PowerCaps->SystemS2 = FALSE;
2849 PowerCaps->SystemS3 = FALSE;
2850 PowerCaps->SystemS4 = TRUE;
2851 PowerCaps->SystemS5 = TRUE;
2852 PowerCaps->HiberFilePresent = TRUE;
2853 PowerCaps->FullWake = TRUE;
2854 PowerCaps->VideoDimPresent = FALSE;
2855 PowerCaps->ApmPresent = FALSE;
2856 PowerCaps->UpsPresent = FALSE;
2857 PowerCaps->ThermalControl = FALSE;
2858 PowerCaps->ProcessorThrottle = FALSE;
2859 PowerCaps->ProcessorMinThrottle = 100;
2860 PowerCaps->ProcessorMaxThrottle = 100;
2861 PowerCaps->DiskSpinDown = TRUE;
2862 PowerCaps->SystemBatteriesPresent = FALSE;
2863 PowerCaps->BatteriesAreShortTerm = FALSE;
2864 PowerCaps->BatteryScale[0].Granularity = 0;
2865 PowerCaps->BatteryScale[0].Capacity = 0;
2866 PowerCaps->BatteryScale[1].Granularity = 0;
2867 PowerCaps->BatteryScale[1].Capacity = 0;
2868 PowerCaps->BatteryScale[2].Granularity = 0;
2869 PowerCaps->BatteryScale[2].Capacity = 0;
2870 PowerCaps->AcOnLineWake = PowerSystemUnspecified;
2871 PowerCaps->SoftLidWake = PowerSystemUnspecified;
2872 PowerCaps->RtcWake = PowerSystemSleeping1;
2873 PowerCaps->MinDeviceWakeState = PowerSystemUnspecified;
2874 PowerCaps->DefaultLowLatencyWake = PowerSystemUnspecified;
2875 return STATUS_SUCCESS;
2878 case SystemBatteryState:
2880 if (out_size < sizeof(SYSTEM_BATTERY_STATE)) return STATUS_BUFFER_TOO_SMALL;
2881 memset(output, 0, sizeof(SYSTEM_BATTERY_STATE));
2882 return fill_battery_state(output);
2885 case SystemExecutionState:
2887 ULONG *state = output;
2888 WARN("semi-stub: SystemExecutionState\n"); /* Needed for .NET Framework, but using a FIXME is really noisy. */
2889 if (input != NULL) return STATUS_INVALID_PARAMETER;
2890 /* FIXME: The actual state should be the value set by SetThreadExecutionState which is not currently implemented. */
2891 *state = ES_USER_PRESENT;
2892 return STATUS_SUCCESS;
2895 case ProcessorInformation:
2897 const int cannedMHz = 1000; /* We fake a 1GHz processor if we can't conjure up real values */
2898 PROCESSOR_POWER_INFORMATION* cpu_power = output;
2899 int i, out_cpus;
2901 if ((output == NULL) || (out_size == 0)) return STATUS_INVALID_PARAMETER;
2902 out_cpus = NtCurrentTeb()->Peb->NumberOfProcessors;
2903 if ((out_size / sizeof(PROCESSOR_POWER_INFORMATION)) < out_cpus) return STATUS_BUFFER_TOO_SMALL;
2904 #if defined(linux)
2906 char filename[128];
2907 FILE* f;
2909 for(i = 0; i < out_cpus; i++) {
2910 sprintf(filename, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", i);
2911 f = fopen(filename, "r");
2912 if (f && (fscanf(f, "%d", &cpu_power[i].CurrentMhz) == 1)) {
2913 cpu_power[i].CurrentMhz /= 1000;
2914 fclose(f);
2916 else {
2917 if(i == 0) {
2918 cpu_power[0].CurrentMhz = mhz_from_cpuinfo();
2919 if(cpu_power[0].CurrentMhz == 0)
2920 cpu_power[0].CurrentMhz = cannedMHz;
2922 else
2923 cpu_power[i].CurrentMhz = cpu_power[0].CurrentMhz;
2924 if(f) fclose(f);
2927 sprintf(filename, "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", i);
2928 f = fopen(filename, "r");
2929 if (f && (fscanf(f, "%d", &cpu_power[i].MaxMhz) == 1)) {
2930 cpu_power[i].MaxMhz /= 1000;
2931 fclose(f);
2933 else {
2934 cpu_power[i].MaxMhz = cpu_power[i].CurrentMhz;
2935 if(f) fclose(f);
2938 sprintf(filename, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", i);
2939 f = fopen(filename, "r");
2940 if(f && (fscanf(f, "%d", &cpu_power[i].MhzLimit) == 1)) {
2941 cpu_power[i].MhzLimit /= 1000;
2942 fclose(f);
2944 else
2946 cpu_power[i].MhzLimit = cpu_power[i].MaxMhz;
2947 if(f) fclose(f);
2950 cpu_power[i].Number = i;
2951 cpu_power[i].MaxIdleState = 0; /* FIXME */
2952 cpu_power[i].CurrentIdleState = 0; /* FIXME */
2955 #elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__)
2957 int num;
2958 size_t valSize = sizeof(num);
2959 if (sysctlbyname("hw.clockrate", &num, &valSize, NULL, 0))
2960 num = cannedMHz;
2961 for(i = 0; i < out_cpus; i++) {
2962 cpu_power[i].CurrentMhz = num;
2963 cpu_power[i].MaxMhz = num;
2964 cpu_power[i].MhzLimit = num;
2965 cpu_power[i].Number = i;
2966 cpu_power[i].MaxIdleState = 0; /* FIXME */
2967 cpu_power[i].CurrentIdleState = 0; /* FIXME */
2970 #elif defined (__APPLE__)
2972 size_t valSize;
2973 unsigned long long currentMhz;
2974 unsigned long long maxMhz;
2976 valSize = sizeof(currentMhz);
2977 if (!sysctlbyname("hw.cpufrequency", &currentMhz, &valSize, NULL, 0))
2978 currentMhz /= 1000000;
2979 else
2980 currentMhz = cannedMHz;
2982 valSize = sizeof(maxMhz);
2983 if (!sysctlbyname("hw.cpufrequency_max", &maxMhz, &valSize, NULL, 0))
2984 maxMhz /= 1000000;
2985 else
2986 maxMhz = currentMhz;
2988 for(i = 0; i < out_cpus; i++) {
2989 cpu_power[i].CurrentMhz = currentMhz;
2990 cpu_power[i].MaxMhz = maxMhz;
2991 cpu_power[i].MhzLimit = maxMhz;
2992 cpu_power[i].Number = i;
2993 cpu_power[i].MaxIdleState = 0; /* FIXME */
2994 cpu_power[i].CurrentIdleState = 0; /* FIXME */
2997 #else
2998 for(i = 0; i < out_cpus; i++) {
2999 cpu_power[i].CurrentMhz = cannedMHz;
3000 cpu_power[i].MaxMhz = cannedMHz;
3001 cpu_power[i].MhzLimit = cannedMHz;
3002 cpu_power[i].Number = i;
3003 cpu_power[i].MaxIdleState = 0; /* FIXME */
3004 cpu_power[i].CurrentIdleState = 0; /* FIXME */
3006 WARN("Unable to detect CPU MHz for this platform. Reporting %d MHz.\n", cannedMHz);
3007 #endif
3008 for(i = 0; i < out_cpus; i++) {
3009 TRACE("cpu_power[%d] = %u %u %u %u %u %u\n", i, cpu_power[i].Number,
3010 cpu_power[i].MaxMhz, cpu_power[i].CurrentMhz, cpu_power[i].MhzLimit,
3011 cpu_power[i].MaxIdleState, cpu_power[i].CurrentIdleState);
3013 return STATUS_SUCCESS;
3016 default:
3017 /* FIXME: Needed by .NET Framework */
3018 WARN( "Unimplemented NtPowerInformation action: %d\n", level );
3019 return STATUS_NOT_IMPLEMENTED;
3024 /******************************************************************************
3025 * NtLoadDriver (NTDLL.@)
3027 NTSTATUS WINAPI NtLoadDriver( const UNICODE_STRING *name )
3029 FIXME( "(%s), stub!\n", debugstr_us(name) );
3030 return STATUS_NOT_IMPLEMENTED;
3034 /******************************************************************************
3035 * NtUnloadDriver (NTDLL.@)
3037 NTSTATUS WINAPI NtUnloadDriver( const UNICODE_STRING *name )
3039 FIXME( "(%s), stub!\n", debugstr_us(name) );
3040 return STATUS_NOT_IMPLEMENTED;
3044 /******************************************************************************
3045 * NtDisplayString (NTDLL.@)
3047 NTSTATUS WINAPI NtDisplayString( UNICODE_STRING *string )
3049 ERR( "%s\n", debugstr_us(string) );
3050 return STATUS_SUCCESS;
3054 /******************************************************************************
3055 * NtRaiseHardError (NTDLL.@)
3057 NTSTATUS WINAPI NtRaiseHardError( NTSTATUS status, ULONG count,
3058 UNICODE_STRING *params_mask, void **params,
3059 HARDERROR_RESPONSE_OPTION option, HARDERROR_RESPONSE *response )
3061 FIXME( "%08x stub\n", status );
3062 return STATUS_NOT_IMPLEMENTED;
3066 /******************************************************************************
3067 * NtInitiatePowerAction (NTDLL.@)
3069 NTSTATUS WINAPI NtInitiatePowerAction( POWER_ACTION action, SYSTEM_POWER_STATE state,
3070 ULONG flags, BOOLEAN async )
3072 FIXME( "(%d,%d,0x%08x,%d),stub\n", action, state, flags, async );
3073 return STATUS_NOT_IMPLEMENTED;
3077 /******************************************************************************
3078 * NtCreatePowerRequest (NTDLL.@)
3080 NTSTATUS WINAPI NtCreatePowerRequest( HANDLE *handle, COUNTED_REASON_CONTEXT *context )
3082 FIXME( "(%p, %p): stub\n", handle, context );
3083 return STATUS_NOT_IMPLEMENTED;
3087 /******************************************************************************
3088 * NtSetPowerRequest (NTDLL.@)
3090 NTSTATUS WINAPI NtSetPowerRequest( HANDLE handle, POWER_REQUEST_TYPE type )
3092 FIXME( "(%p, %u): stub\n", handle, type );
3093 return STATUS_NOT_IMPLEMENTED;
3097 /******************************************************************************
3098 * NtClearPowerRequest (NTDLL.@)
3100 NTSTATUS WINAPI NtClearPowerRequest( HANDLE handle, POWER_REQUEST_TYPE type )
3102 FIXME( "(%p, %u): stub\n", handle, type );
3103 return STATUS_NOT_IMPLEMENTED;
3107 /******************************************************************************
3108 * NtSetThreadExecutionState (NTDLL.@)
3110 NTSTATUS WINAPI NtSetThreadExecutionState( EXECUTION_STATE new_state, EXECUTION_STATE *old_state )
3112 static EXECUTION_STATE current = ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED | ES_USER_PRESENT;
3114 WARN( "(0x%x, %p): stub, harmless.\n", new_state, old_state );
3115 *old_state = current;
3116 if (!(current & ES_CONTINUOUS) || (new_state & ES_CONTINUOUS)) current = new_state;
3117 return STATUS_SUCCESS;