"Fossies" - the Fresh Open Source Software Archive

Member "wine-6.0.1/dlls/ntdll/unix/system.c" (7 Jun 2021, 115412 Bytes) of package /linux/misc/wine-6.0.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "system.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 6.0_vs_6.0.1.

    1 /*
    2  * System information APIs
    3  *
    4  * Copyright 1996-1998 Marcus Meissner
    5  *
    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.
   10  *
   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.
   15  *
   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
   19  */
   20 
   21 #if 0
   22 #pragma makedep unix
   23 #endif
   24 
   25 #include "config.h"
   26 #include "wine/port.h"
   27 
   28 #include <string.h>
   29 #include <stdarg.h>
   30 #include <stdio.h>
   31 #include <stdlib.h>
   32 #include <errno.h>
   33 #ifdef HAVE_SYS_TIME_H
   34 # include <sys/time.h>
   35 #endif
   36 #include <time.h>
   37 #ifdef HAVE_SYS_PARAM_H
   38 # include <sys/param.h>
   39 #endif
   40 #ifdef HAVE_SYS_SYSCTL_H
   41 # include <sys/sysctl.h>
   42 #endif
   43 #ifdef HAVE_MACHINE_CPU_H
   44 # include <machine/cpu.h>
   45 #endif
   46 #ifdef HAVE_SYS_RANDOM_H
   47 # include <sys/random.h>
   48 #endif
   49 #ifdef HAVE_IOKIT_IOKITLIB_H
   50 # include <CoreFoundation/CoreFoundation.h>
   51 # include <IOKit/IOKitLib.h>
   52 # include <IOKit/pwr_mgt/IOPM.h>
   53 # include <IOKit/pwr_mgt/IOPMLib.h>
   54 # include <IOKit/ps/IOPowerSources.h>
   55 #endif
   56 #ifdef __APPLE__
   57 # include <mach/mach.h>
   58 # include <mach/machine.h>
   59 # include <mach/mach_init.h>
   60 # include <mach/mach_host.h>
   61 # include <mach/vm_map.h>
   62 #endif
   63 
   64 #define NONAMELESSUNION
   65 #include "ntstatus.h"
   66 #define WIN32_NO_STATUS
   67 #include "windef.h"
   68 #include "winternl.h"
   69 #include "ddk/wdm.h"
   70 #include "wine/asm.h"
   71 #include "unix_private.h"
   72 #include "wine/debug.h"
   73 
   74 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
   75 
   76 #include "pshpack1.h"
   77 
   78 struct smbios_prologue
   79 {
   80     BYTE calling_method;
   81     BYTE major_version;
   82     BYTE minor_version;
   83     BYTE revision;
   84     DWORD length;
   85 };
   86 
   87 struct smbios_header
   88 {
   89     BYTE type;
   90     BYTE length;
   91     WORD handle;
   92 };
   93 
   94 struct smbios_bios
   95 {
   96     struct smbios_header hdr;
   97     BYTE vendor;
   98     BYTE version;
   99     WORD start;
  100     BYTE date;
  101     BYTE size;
  102     UINT64 characteristics;
  103     BYTE characteristics_ext[2];
  104     BYTE system_bios_major_release;
  105     BYTE system_bios_minor_release;
  106     BYTE ec_firmware_major_release;
  107     BYTE ec_firmware_minor_release;
  108 };
  109 
  110 struct smbios_system
  111 {
  112     struct smbios_header hdr;
  113     BYTE vendor;
  114     BYTE product;
  115     BYTE version;
  116     BYTE serial;
  117     BYTE uuid[16];
  118     BYTE wake_up_type;
  119     BYTE sku_number;
  120     BYTE family;
  121 };
  122 
  123 struct smbios_board
  124 {
  125     struct smbios_header hdr;
  126     BYTE vendor;
  127     BYTE product;
  128     BYTE version;
  129     BYTE serial;
  130     BYTE asset_tag;
  131     BYTE feature_flags;
  132     BYTE location;
  133     WORD chassis_handle;
  134     BYTE board_type;
  135     BYTE num_contained_handles;
  136 };
  137 
  138 struct smbios_chassis
  139 {
  140     struct smbios_header hdr;
  141     BYTE vendor;
  142     BYTE type;
  143     BYTE version;
  144     BYTE serial;
  145     BYTE asset_tag;
  146     BYTE boot_state;
  147     BYTE power_supply_state;
  148     BYTE thermal_state;
  149     BYTE security_status;
  150     DWORD oem_defined;
  151     BYTE height;
  152     BYTE num_power_cords;
  153     BYTE num_contained_elements;
  154     BYTE contained_element_rec_length;
  155 };
  156 
  157 struct smbios_boot_info
  158 {
  159     struct smbios_header hdr;
  160     BYTE reserved[6];
  161     BYTE boot_status[10];
  162 };
  163 
  164 #include "poppack.h"
  165 
  166 /* Firmware table providers */
  167 #define ACPI 0x41435049
  168 #define FIRM 0x4649524D
  169 #define RSMB 0x52534D42
  170 
  171 static SYSTEM_CPU_INFORMATION cpu_info;
  172 
  173 /*******************************************************************************
  174  * Architecture specific feature detection for CPUs
  175  *
  176  * This a set of mutually exclusive #if define()s each providing its own get_cpuinfo() to be called
  177  * from init_cpu_info();
  178  */
  179 #if defined(__i386__) || defined(__x86_64__)
  180 
  181 #define AUTH    0x68747541  /* "Auth" */
  182 #define ENTI    0x69746e65  /* "enti" */
  183 #define CAMD    0x444d4163  /* "cAMD" */
  184 
  185 #define GENU    0x756e6547  /* "Genu" */
  186 #define INEI    0x49656e69  /* "ineI" */
  187 #define NTEL    0x6c65746e  /* "ntel" */
  188 
  189 extern void do_cpuid(unsigned int ax, unsigned int *p);
  190 
  191 #ifdef __i386__
  192 __ASM_GLOBAL_FUNC( do_cpuid,
  193                    "pushl %esi\n\t"
  194                    "pushl %ebx\n\t"
  195                    "movl 12(%esp),%eax\n\t"
  196                    "movl 16(%esp),%esi\n\t"
  197                    "xorl %ecx,%ecx\n\t"
  198                    "cpuid\n\t"
  199                    "movl %eax,(%esi)\n\t"
  200                    "movl %ebx,4(%esi)\n\t"
  201                    "movl %ecx,8(%esi)\n\t"
  202                    "movl %edx,12(%esi)\n\t"
  203                    "popl %ebx\n\t"
  204                    "popl %esi\n\t"
  205                    "ret" )
  206 #else
  207 __ASM_GLOBAL_FUNC( do_cpuid,
  208                    "pushq %rbx\n\t"
  209                    "movl %edi,%eax\n\t"
  210                    "xorl %ecx,%ecx\n\t"
  211                    "cpuid\n\t"
  212                    "movl %eax,(%rsi)\n\t"
  213                    "movl %ebx,4(%rsi)\n\t"
  214                    "movl %ecx,8(%rsi)\n\t"
  215                    "movl %edx,12(%rsi)\n\t"
  216                    "popq %rbx\n\t"
  217                    "ret" )
  218 #endif
  219 
  220 #ifdef __i386__
  221 extern int have_cpuid(void);
  222 __ASM_GLOBAL_FUNC( have_cpuid,
  223                    "pushfl\n\t"
  224                    "pushfl\n\t"
  225                    "movl (%esp),%ecx\n\t"
  226                    "xorl $0x00200000,(%esp)\n\t"
  227                    "popfl\n\t"
  228                    "pushfl\n\t"
  229                    "popl %eax\n\t"
  230                    "popfl\n\t"
  231                    "xorl %ecx,%eax\n\t"
  232                    "andl $0x00200000,%eax\n\t"
  233                    "ret" )
  234 #else
  235 static int have_cpuid(void)
  236 {
  237     return 1;
  238 }
  239 #endif
  240 
  241 /* Detect if a SSE2 processor is capable of Denormals Are Zero (DAZ) mode.
  242  *
  243  * This function assumes you have already checked for SSE2/FXSAVE support. */
  244 static inline BOOL have_sse_daz_mode(void)
  245 {
  246 #ifdef __i386__
  247     /* Intel says we need a zeroed 16-byte aligned buffer */
  248     char buffer[512 + 16];
  249     XSAVE_FORMAT *state = (XSAVE_FORMAT *)(((ULONG_PTR)buffer + 15) & ~15);
  250     memset(buffer, 0, sizeof(buffer));
  251 
  252     __asm__ __volatile__( "fxsave %0" : "=m" (*state) : "m" (*state) );
  253 
  254     return (state->MxCsr_Mask & (1 << 6)) >> 6;
  255 #else /* all x86_64 processors include SSE2 with DAZ mode */
  256     return TRUE;
  257 #endif
  258 }
  259 
  260 static void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
  261 {
  262     unsigned int regs[4], regs2[4], regs3[4];
  263 
  264 #if defined(__i386__)
  265     info->Architecture = PROCESSOR_ARCHITECTURE_INTEL;
  266 #elif defined(__x86_64__)
  267     info->Architecture = PROCESSOR_ARCHITECTURE_AMD64;
  268 #endif
  269 
  270     /* We're at least a 386 */
  271     info->FeatureSet = CPU_FEATURE_VME | CPU_FEATURE_X86 | CPU_FEATURE_PGE;
  272     info->Level = 3;
  273 
  274     if (!have_cpuid()) return;
  275 
  276     do_cpuid( 0x00000000, regs );  /* get standard cpuid level and vendor name */
  277     if (regs[0]>=0x00000001)   /* Check for supported cpuid version */
  278     {
  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 << 9 )) info->FeatureSet |= CPU_FEATURE_SSSE3;
  294         if (regs2[2] & (1 << 13)) info->FeatureSet |= CPU_FEATURE_CX128;
  295         if (regs2[2] & (1 << 19)) info->FeatureSet |= CPU_FEATURE_SSE41;
  296         if (regs2[2] & (1 << 20)) info->FeatureSet |= CPU_FEATURE_SSE42;
  297         if (regs2[2] & (1 << 27)) info->FeatureSet |= CPU_FEATURE_XSAVE;
  298         if (regs2[2] & (1 << 28)) info->FeatureSet |= CPU_FEATURE_AVX;
  299         if((regs2[3] & (1 << 26)) && (regs2[3] & (1 << 24)) && have_sse_daz_mode()) /* has SSE2 and FXSAVE/FXRSTOR */
  300             info->FeatureSet |= CPU_FEATURE_DAZ;
  301 
  302         if (regs[0] >= 0x00000007)
  303         {
  304             do_cpuid( 0x00000007, regs3 ); /* get extended features */
  305             if (regs3[1] & (1 << 5)) info->FeatureSet |= CPU_FEATURE_AVX2;
  306         }
  307 
  308         if (regs[1] == AUTH && regs[3] == ENTI && regs[2] == CAMD)
  309         {
  310             info->Level = (regs2[0] >> 8) & 0xf; /* family */
  311             if (info->Level == 0xf)  /* AMD says to add the extended family to the family if family is 0xf */
  312                 info->Level += (regs2[0] >> 20) & 0xff;
  313 
  314             /* repack model and stepping to make a "revision" */
  315             info->Revision  = ((regs2[0] >> 16) & 0xf) << 12; /* extended model */
  316             info->Revision |= ((regs2[0] >> 4 ) & 0xf) << 8;  /* model          */
  317             info->Revision |= regs2[0] & 0xf;                 /* stepping       */
  318 
  319             do_cpuid( 0x80000000, regs );  /* get vendor cpuid level */
  320             if (regs[0] >= 0x80000001)
  321             {
  322                 do_cpuid( 0x80000001, regs2 );  /* get vendor features */
  323                 if (regs2[2] & (1 << 2))   info->FeatureSet |= CPU_FEATURE_VIRT;
  324                 if (regs2[3] & (1 << 20))  info->FeatureSet |= CPU_FEATURE_NX;
  325                 if (regs2[3] & (1 << 27))  info->FeatureSet |= CPU_FEATURE_TSC;
  326                 if (regs2[3] & (1u << 31)) info->FeatureSet |= CPU_FEATURE_3DNOW;
  327             }
  328         }
  329         else if (regs[1] == GENU && regs[3] == INEI && regs[2] == NTEL)
  330         {
  331             info->Level = ((regs2[0] >> 8) & 0xf) + ((regs2[0] >> 20) & 0xff); /* family + extended family */
  332             if(info->Level == 15) info->Level = 6;
  333 
  334             /* repack model and stepping to make a "revision" */
  335             info->Revision  = ((regs2[0] >> 16) & 0xf) << 12; /* extended model */
  336             info->Revision |= ((regs2[0] >> 4 ) & 0xf) << 8;  /* model          */
  337             info->Revision |= regs2[0] & 0xf;                 /* stepping       */
  338 
  339             if(regs2[2] & (1 << 5))  info->FeatureSet |= CPU_FEATURE_VIRT;
  340             if(regs2[3] & (1 << 21)) info->FeatureSet |= CPU_FEATURE_DS;
  341 
  342             do_cpuid( 0x80000000, regs );  /* get vendor cpuid level */
  343             if (regs[0] >= 0x80000001)
  344             {
  345                 do_cpuid( 0x80000001, regs2 );  /* get vendor features */
  346                 if (regs2[3] & (1 << 20)) info->FeatureSet |= CPU_FEATURE_NX;
  347                 if (regs2[3] & (1 << 27)) info->FeatureSet |= CPU_FEATURE_TSC;
  348             }
  349         }
  350         else
  351         {
  352             info->Level = (regs2[0] >> 8) & 0xf; /* family */
  353 
  354             /* repack model and stepping to make a "revision" */
  355             info->Revision = ((regs2[0] >> 4 ) & 0xf) << 8;  /* model    */
  356             info->Revision |= regs2[0] & 0xf;                /* stepping */
  357         }
  358     }
  359 }
  360 
  361 #elif defined(__arm__)
  362 
  363 static inline void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
  364 {
  365 #ifdef linux
  366     char line[512];
  367     char *s, *value;
  368     FILE *f = fopen("/proc/cpuinfo", "r");
  369     if (f)
  370     {
  371         while (fgets( line, sizeof(line), f ))
  372         {
  373             /* NOTE: the ':' is the only character we can rely on */
  374             if (!(value = strchr(line,':'))) continue;
  375             /* terminate the valuename */
  376             s = value - 1;
  377             while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
  378             s[1] = 0;
  379             /* and strip leading spaces from value */
  380             value += 1;
  381             while (*value == ' ' || *value == '\t') value++;
  382             if ((s = strchr( value,'\n' ))) *s = 0;
  383             if (!strcmp( line, "CPU architecture" ))
  384             {
  385                 info->Level = atoi(value);
  386                 continue;
  387             }
  388             if (!strcmp( line, "CPU revision" ))
  389             {
  390                 info->Revision = atoi(value);
  391                 continue;
  392             }
  393             if (!strcmp( line, "Features" ))
  394             {
  395                 if (strstr(value, "crc32")) info->FeatureSet |= CPU_FEATURE_ARM_V8_CRC32;
  396                 if (strstr(value, "aes"))   info->FeatureSet |= CPU_FEATURE_ARM_V8_CRYPTO;
  397                 continue;
  398             }
  399         }
  400         fclose( f );
  401     }
  402 #elif defined(__FreeBSD__)
  403     size_t valsize;
  404     char buf[8];
  405     int value;
  406 
  407     valsize = sizeof(buf);
  408     if (!sysctlbyname("hw.machine_arch", &buf, &valsize, NULL, 0) && sscanf(buf, "armv%i", &value) == 1)
  409         info->Level = value;
  410 
  411     valsize = sizeof(value);
  412     if (!sysctlbyname("hw.floatingpoint", &value, &valsize, NULL, 0))
  413         info->FeatureSet |= CPU_FEATURE_ARM_VFP_32;
  414 #else
  415     FIXME("CPU Feature detection not implemented.\n");
  416 #endif
  417     info->Architecture = PROCESSOR_ARCHITECTURE_ARM;
  418 }
  419 
  420 #elif defined(__aarch64__)
  421 
  422 static void get_cpuinfo( SYSTEM_CPU_INFORMATION *info )
  423 {
  424 #ifdef linux
  425     char line[512];
  426     char *s, *value;
  427     FILE *f = fopen("/proc/cpuinfo", "r");
  428     if (f)
  429     {
  430         while (fgets( line, sizeof(line), f ))
  431         {
  432             /* NOTE: the ':' is the only character we can rely on */
  433             if (!(value = strchr(line,':'))) continue;
  434             /* terminate the valuename */
  435             s = value - 1;
  436             while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
  437             s[1] = 0;
  438             /* and strip leading spaces from value */
  439             value += 1;
  440             while (*value == ' ' || *value == '\t') value++;
  441             if ((s = strchr( value,'\n' ))) *s = 0;
  442             if (!strcmp( line, "CPU architecture" ))
  443             {
  444                 info->Level = atoi(value);
  445                 continue;
  446             }
  447             if (!strcmp( line, "CPU revision" ))
  448             {
  449                 info->Revision = atoi(value);
  450                 continue;
  451             }
  452             if (!strcmp( line, "Features" ))
  453             {
  454                 if (strstr(value, "crc32")) info->FeatureSet |= CPU_FEATURE_ARM_V8_CRC32;
  455                 if (strstr(value, "aes"))   info->FeatureSet |= CPU_FEATURE_ARM_V8_CRYPTO;
  456                 continue;
  457             }
  458         }
  459         fclose( f );
  460     }
  461 #else
  462     FIXME("CPU Feature detection not implemented.\n");
  463 #endif
  464     info->Level = max(info->Level, 8);
  465     info->Architecture = PROCESSOR_ARCHITECTURE_ARM64;
  466 }
  467 
  468 #endif /* End architecture specific feature detection for CPUs */
  469 
  470 /******************************************************************
  471  *      init_cpu_info
  472  *
  473  * inits a couple of places with CPU related information:
  474  * - cpu_info in this file
  475  * - Peb->NumberOfProcessors
  476  * - SharedUserData->ProcessFeatures[] array
  477  */
  478 void init_cpu_info(void)
  479 {
  480     long num;
  481 
  482 #ifdef _SC_NPROCESSORS_ONLN
  483     num = sysconf(_SC_NPROCESSORS_ONLN);
  484     if (num < 1)
  485     {
  486         num = 1;
  487         WARN("Failed to detect the number of processors.\n");
  488     }
  489 #elif defined(CTL_HW) && defined(HW_NCPU)
  490     int mib[2];
  491     size_t len = sizeof(num);
  492     mib[0] = CTL_HW;
  493     mib[1] = HW_NCPU;
  494     if (sysctl(mib, 2, &num, &len, NULL, 0) != 0)
  495     {
  496         num = 1;
  497         WARN("Failed to detect the number of processors.\n");
  498     }
  499 #else
  500     num = 1;
  501     FIXME("Detecting the number of processors is not supported.\n");
  502 #endif
  503     NtCurrentTeb()->Peb->NumberOfProcessors = num;
  504     get_cpuinfo( &cpu_info );
  505     TRACE( "<- CPU arch %d, level %d, rev %d, features 0x%x\n",
  506            cpu_info.Architecture, cpu_info.Level, cpu_info.Revision, cpu_info.FeatureSet );
  507 }
  508 
  509 static BOOL grow_logical_proc_buf( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata, DWORD *max_len )
  510 {
  511     SYSTEM_LOGICAL_PROCESSOR_INFORMATION *new_data;
  512 
  513     *max_len *= 2;
  514     if (!(new_data = realloc( *pdata, *max_len*sizeof(*new_data) ))) return FALSE;
  515     *pdata = new_data;
  516     return TRUE;
  517 }
  518 
  519 static BOOL grow_logical_proc_ex_buf( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *max_len )
  520 {
  521     SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *new_dataex;
  522     DWORD new_len = *max_len * 2;
  523     if (!(new_dataex = realloc( *pdataex, new_len * sizeof(*new_dataex) ))) return FALSE;
  524     memset( new_dataex + *max_len, 0, (new_len - *max_len) * sizeof(*new_dataex) );
  525     *pdataex = new_dataex;
  526     *max_len = new_len;
  527     return TRUE;
  528 }
  529 
  530 static DWORD log_proc_ex_size_plus(DWORD size)
  531 {
  532     /* add SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX.Relationship and .Size */
  533     return sizeof(LOGICAL_PROCESSOR_RELATIONSHIP) + sizeof(DWORD) + size;
  534 }
  535 
  536 static DWORD count_bits(ULONG_PTR mask)
  537 {
  538     DWORD count = 0;
  539     while (mask > 0)
  540     {
  541         if (mask & 1) ++count;
  542         mask >>= 1;
  543     }
  544     return count;
  545 }
  546 
  547 /* Store package and core information for a logical processor. Parsing of processor
  548  * data may happen in multiple passes; the 'id' parameter is then used to locate
  549  * previously stored data. The type of data stored in 'id' depends on 'rel':
  550  * - RelationProcessorPackage: package id ('CPU socket').
  551  * - RelationProcessorCore: physical core number.
  552  */
  553 static BOOL logical_proc_info_add_by_id( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
  554                                          SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *len,
  555                                          DWORD *pmax_len, LOGICAL_PROCESSOR_RELATIONSHIP rel,
  556                                          DWORD id, ULONG_PTR mask )
  557 {
  558     if (pdata)
  559     {
  560         DWORD i;
  561 
  562         for (i = 0; i < *len; i++)
  563         {
  564             if (rel == RelationProcessorPackage && (*pdata)[i].Relationship == rel && (*pdata)[i].u.Reserved[1] == id)
  565             {
  566                 (*pdata)[i].ProcessorMask |= mask;
  567                 return TRUE;
  568             }
  569             else if (rel == RelationProcessorCore && (*pdata)[i].Relationship == rel && (*pdata)[i].u.Reserved[1] == id)
  570                 return TRUE;
  571         }
  572 
  573         while (*len == *pmax_len)
  574         {
  575             if (!grow_logical_proc_buf(pdata, pmax_len)) return FALSE;
  576         }
  577 
  578         (*pdata)[i].Relationship = rel;
  579         (*pdata)[i].ProcessorMask = mask;
  580         if (rel == RelationProcessorCore)
  581             (*pdata)[i].u.ProcessorCore.Flags = count_bits(mask) > 1 ? LTP_PC_SMT : 0;
  582         (*pdata)[i].u.Reserved[0] = 0;
  583         (*pdata)[i].u.Reserved[1] = id;
  584         *len = i+1;
  585     }
  586     else
  587     {
  588         SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
  589         DWORD ofs = 0;
  590 
  591         while (ofs < *len)
  592         {
  593             dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
  594             if (rel == RelationProcessorPackage && dataex->Relationship == rel && dataex->u.Processor.Reserved[1] == id)
  595             {
  596                 dataex->u.Processor.GroupMask[0].Mask |= mask;
  597                 return TRUE;
  598             }
  599             else if (rel == RelationProcessorCore && dataex->Relationship == rel && dataex->u.Processor.Reserved[1] == id)
  600             {
  601                 return TRUE;
  602             }
  603             ofs += dataex->Size;
  604         }
  605 
  606         /* TODO: For now, just one group. If more than 64 processors, then we
  607          * need another group. */
  608 
  609         while (ofs + log_proc_ex_size_plus(sizeof(PROCESSOR_RELATIONSHIP)) > *pmax_len)
  610         {
  611             if (!grow_logical_proc_ex_buf(pdataex, pmax_len)) return FALSE;
  612         }
  613 
  614         dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
  615 
  616         dataex->Relationship = rel;
  617         dataex->Size = log_proc_ex_size_plus(sizeof(PROCESSOR_RELATIONSHIP));
  618         if (rel == RelationProcessorCore)
  619             dataex->u.Processor.Flags = count_bits(mask) > 1 ? LTP_PC_SMT : 0;
  620         else
  621             dataex->u.Processor.Flags = 0;
  622         dataex->u.Processor.EfficiencyClass = 0;
  623         dataex->u.Processor.GroupCount = 1;
  624         dataex->u.Processor.GroupMask[0].Mask = mask;
  625         dataex->u.Processor.GroupMask[0].Group = 0;
  626         /* mark for future lookup */
  627         dataex->u.Processor.Reserved[0] = 0;
  628         dataex->u.Processor.Reserved[1] = id;
  629 
  630         *len += dataex->Size;
  631     }
  632 
  633     return TRUE;
  634 }
  635 
  636 static BOOL logical_proc_info_add_cache( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
  637                                          SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *len,
  638                                          DWORD *pmax_len, ULONG_PTR mask, CACHE_DESCRIPTOR *cache )
  639 {
  640     if (pdata)
  641     {
  642         DWORD i;
  643 
  644         for (i = 0; i < *len; i++)
  645         {
  646             if ((*pdata)[i].Relationship==RelationCache && (*pdata)[i].ProcessorMask==mask
  647                     && (*pdata)[i].u.Cache.Level==cache->Level && (*pdata)[i].u.Cache.Type==cache->Type)
  648                 return TRUE;
  649         }
  650 
  651         while (*len == *pmax_len)
  652             if (!grow_logical_proc_buf(pdata, pmax_len)) return FALSE;
  653 
  654         (*pdata)[i].Relationship = RelationCache;
  655         (*pdata)[i].ProcessorMask = mask;
  656         (*pdata)[i].u.Cache = *cache;
  657         *len = i+1;
  658     }
  659     else
  660     {
  661         SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
  662         DWORD ofs;
  663 
  664         for (ofs = 0; ofs < *len; )
  665         {
  666             dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
  667             if (dataex->Relationship == RelationCache && dataex->u.Cache.GroupMask.Mask == mask &&
  668                     dataex->u.Cache.Level == cache->Level && dataex->u.Cache.Type == cache->Type)
  669                 return TRUE;
  670             ofs += dataex->Size;
  671         }
  672 
  673         while (ofs + log_proc_ex_size_plus(sizeof(CACHE_RELATIONSHIP)) > *pmax_len)
  674         {
  675             if (!grow_logical_proc_ex_buf(pdataex, pmax_len)) return FALSE;
  676         }
  677 
  678         dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + ofs);
  679 
  680         dataex->Relationship = RelationCache;
  681         dataex->Size = log_proc_ex_size_plus(sizeof(CACHE_RELATIONSHIP));
  682         dataex->u.Cache.Level = cache->Level;
  683         dataex->u.Cache.Associativity = cache->Associativity;
  684         dataex->u.Cache.LineSize = cache->LineSize;
  685         dataex->u.Cache.CacheSize = cache->Size;
  686         dataex->u.Cache.Type = cache->Type;
  687         dataex->u.Cache.GroupMask.Mask = mask;
  688         dataex->u.Cache.GroupMask.Group = 0;
  689 
  690         *len += dataex->Size;
  691     }
  692 
  693     return TRUE;
  694 }
  695 
  696 static BOOL logical_proc_info_add_numa_node( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **pdata,
  697                                              SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex, DWORD *len,
  698                                              DWORD *pmax_len, ULONG_PTR mask, DWORD node_id )
  699 {
  700     if (pdata)
  701     {
  702         while (*len == *pmax_len)
  703             if (!grow_logical_proc_buf(pdata, pmax_len)) return FALSE;
  704 
  705         (*pdata)[*len].Relationship = RelationNumaNode;
  706         (*pdata)[*len].ProcessorMask = mask;
  707         (*pdata)[*len].u.NumaNode.NodeNumber = node_id;
  708         (*len)++;
  709     }
  710     else
  711     {
  712         SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
  713 
  714         while (*len + log_proc_ex_size_plus(sizeof(NUMA_NODE_RELATIONSHIP)) > *pmax_len)
  715         {
  716             if (!grow_logical_proc_ex_buf(pdataex, pmax_len)) return FALSE;
  717         }
  718 
  719         dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + *len);
  720 
  721         dataex->Relationship = RelationNumaNode;
  722         dataex->Size = log_proc_ex_size_plus(sizeof(NUMA_NODE_RELATIONSHIP));
  723         dataex->u.NumaNode.NodeNumber = node_id;
  724         dataex->u.NumaNode.GroupMask.Mask = mask;
  725         dataex->u.NumaNode.GroupMask.Group = 0;
  726 
  727         *len += dataex->Size;
  728     }
  729 
  730     return TRUE;
  731 }
  732 
  733 static BOOL logical_proc_info_add_group( SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **pdataex,
  734                                          DWORD *len, DWORD *pmax_len, DWORD num_cpus, ULONG_PTR mask )
  735 {
  736     SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *dataex;
  737 
  738     while (*len + log_proc_ex_size_plus(sizeof(GROUP_RELATIONSHIP)) > *pmax_len)
  739         if (!grow_logical_proc_ex_buf(pdataex, pmax_len)) return FALSE;
  740 
  741     dataex = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(((char *)*pdataex) + *len);
  742 
  743     dataex->Relationship = RelationGroup;
  744     dataex->Size = log_proc_ex_size_plus(sizeof(GROUP_RELATIONSHIP));
  745     dataex->u.Group.MaximumGroupCount = 1;
  746     dataex->u.Group.ActiveGroupCount = 1;
  747     dataex->u.Group.GroupInfo[0].MaximumProcessorCount = num_cpus;
  748     dataex->u.Group.GroupInfo[0].ActiveProcessorCount = num_cpus;
  749     dataex->u.Group.GroupInfo[0].ActiveProcessorMask = mask;
  750 
  751     *len += dataex->Size;
  752     return TRUE;
  753 }
  754 
  755 #ifdef linux
  756 
  757 /* Helper function for counting bitmap values as commonly used by the Linux kernel
  758  * for storing CPU masks in sysfs. The format is comma separated lists of hex values
  759  * each max 32-bit e.g. "00ff" or even "00,00000000,0000ffff".
  760  *
  761  * Example files include:
  762  * - /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_map
  763  * - /sys/devices/system/cpu/cpu0/topology/thread_siblings
  764  */
  765 static BOOL sysfs_parse_bitmap(const char *filename, ULONG_PTR *mask)
  766 {
  767     FILE *f;
  768     DWORD r;
  769 
  770     f = fopen(filename, "r");
  771     if (!f) return FALSE;
  772 
  773     while (!feof(f))
  774     {
  775         char op;
  776         if (!fscanf(f, "%x%c ", &r, &op)) break;
  777         *mask = (sizeof(ULONG_PTR)>sizeof(int) ? *mask << (8 * sizeof(DWORD)) : 0) + r;
  778     }
  779     fclose( f );
  780     return TRUE;
  781 }
  782 
  783 /* Helper function for counting number of elements in interval lists as used by
  784  * the Linux kernel. The format is comma separated list of intervals of which
  785  * each interval has the format of "begin-end" where begin and end are decimal
  786  * numbers. E.g. "0-7", "0-7,16-23"
  787  *
  788  * Example files include:
  789  * - /sys/devices/system/cpu/online
  790  * - /sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_list
  791  * - /sys/devices/system/cpu/cpu0/topology/thread_siblings_list.
  792  */
  793 static BOOL sysfs_count_list_elements(const char *filename, DWORD *result)
  794 {
  795     FILE *f;
  796 
  797     f = fopen(filename, "r");
  798     if (!f) return FALSE;
  799 
  800     while (!feof(f))
  801     {
  802         char op;
  803         DWORD beg, end;
  804 
  805         if (!fscanf(f, "%u%c ", &beg, &op)) break;
  806         if(op == '-')
  807             fscanf(f, "%u%c ", &end, &op);
  808         else
  809             end = beg;
  810 
  811         *result += end - beg + 1;
  812     }
  813     fclose( f );
  814     return TRUE;
  815 }
  816 
  817 /* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
  818 static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data,
  819                                           SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **dataex,
  820                                           DWORD *max_len, DWORD relation )
  821 {
  822     static const char core_info[] = "/sys/devices/system/cpu/cpu%u/topology/%s";
  823     static const char cache_info[] = "/sys/devices/system/cpu/cpu%u/cache/index%u/%s";
  824     static const char numa_info[] = "/sys/devices/system/node/node%u/cpumap";
  825 
  826     FILE *fcpu_list, *fnuma_list, *f;
  827     DWORD len = 0, beg, end, i, j, r, num_cpus = 0, max_cpus = 0;
  828     char op, name[MAX_PATH];
  829     ULONG_PTR all_cpus_mask = 0;
  830 
  831     /* On systems with a large number of CPU cores (32 or 64 depending on 32-bit or 64-bit),
  832      * we have issues parsing processor information:
  833      * - ULONG_PTR masks as used in data structures can't hold all cores. Requires splitting
  834      *   data appropriately into "processor groups". We are hard coding 1.
  835      * - Thread affinity code in wineserver and our CPU parsing code here work independently.
  836      *   So far the Windows mask applied directly to Linux, but process groups break that.
  837      *   (NUMA systems you may have multiple non-full groups.)
  838      */
  839     if(sysfs_count_list_elements("/sys/devices/system/cpu/present", &max_cpus) && max_cpus > MAXIMUM_PROCESSORS)
  840     {
  841         FIXME("Improve CPU info reporting: system supports %u logical cores, but only %u supported!\n",
  842                 max_cpus, MAXIMUM_PROCESSORS);
  843     }
  844 
  845     fcpu_list = fopen("/sys/devices/system/cpu/online", "r");
  846     if (!fcpu_list) return STATUS_NOT_IMPLEMENTED;
  847 
  848     while (!feof(fcpu_list))
  849     {
  850         if (!fscanf(fcpu_list, "%u%c ", &beg, &op)) break;
  851         if (op == '-') fscanf(fcpu_list, "%u%c ", &end, &op);
  852         else end = beg;
  853 
  854         for(i = beg; i <= end; i++)
  855         {
  856             DWORD phys_core = 0;
  857             ULONG_PTR thread_mask = 0;
  858 
  859             if (i > 8*sizeof(ULONG_PTR))
  860             {
  861                 FIXME("skipping logical processor %d\n", i);
  862                 continue;
  863             }
  864 
  865             if (relation == RelationAll || relation == RelationProcessorPackage)
  866             {
  867                 sprintf(name, core_info, i, "physical_package_id");
  868                 f = fopen(name, "r");
  869                 if (f)
  870                 {
  871                     fscanf(f, "%u", &r);
  872                     fclose(f);
  873                 }
  874                 else r = 0;
  875                 if (!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorPackage, r, (ULONG_PTR)1 << i))
  876                 {
  877                     fclose(fcpu_list);
  878                     return STATUS_NO_MEMORY;
  879                 }
  880             }
  881 
  882             /* Sysfs enumerates logical cores (and not physical cores), but Windows enumerates
  883              * by physical core. Upon enumerating a logical core in sysfs, we register a physical
  884              * core and all its logical cores. In order to not report physical cores multiple
  885              * times, we pass a unique physical core ID to logical_proc_info_add_by_id and let
  886              * that call figure out any duplication.
  887              * Obtain a unique physical core ID from the first element of thread_siblings_list.
  888              * This list provides logical cores sharing the same physical core. The IDs are based
  889              * on kernel cpu core numbering as opposed to a hardware core ID like provided through
  890              * 'core_id', so are suitable as a unique ID.
  891              */
  892             if(relation == RelationAll || relation == RelationProcessorCore ||
  893                relation == RelationNumaNode || relation == RelationGroup)
  894             {
  895                 /* Mask of logical threads sharing same physical core in kernel core numbering. */
  896                 sprintf(name, core_info, i, "thread_siblings");
  897                 if(!sysfs_parse_bitmap(name, &thread_mask)) thread_mask = 1<<i;
  898 
  899                 /* Needed later for NumaNode and Group. */
  900                 all_cpus_mask |= thread_mask;
  901 
  902                 if (relation == RelationAll || relation == RelationProcessorCore)
  903                 {
  904                     sprintf(name, core_info, i, "thread_siblings_list");
  905                     f = fopen(name, "r");
  906                     if (f)
  907                     {
  908                         fscanf(f, "%d%c", &phys_core, &op);
  909                         fclose(f);
  910                     }
  911                     else phys_core = i;
  912 
  913                     if (!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorCore, phys_core, thread_mask))
  914                     {
  915                         fclose(fcpu_list);
  916                         return STATUS_NO_MEMORY;
  917                     }
  918                 }
  919             }
  920 
  921             if (relation == RelationAll || relation == RelationCache)
  922             {
  923                 for(j = 0; j < 4; j++)
  924                 {
  925                     CACHE_DESCRIPTOR cache;
  926                     ULONG_PTR mask = 0;
  927 
  928                     sprintf(name, cache_info, i, j, "shared_cpu_map");
  929                     if(!sysfs_parse_bitmap(name, &mask)) continue;
  930 
  931                     sprintf(name, cache_info, i, j, "level");
  932                     f = fopen(name, "r");
  933                     if(!f) continue;
  934                     fscanf(f, "%u", &r);
  935                     fclose(f);
  936                     cache.Level = r;
  937 
  938                     sprintf(name, cache_info, i, j, "ways_of_associativity");
  939                     f = fopen(name, "r");
  940                     if(!f) continue;
  941                     fscanf(f, "%u", &r);
  942                     fclose(f);
  943                     cache.Associativity = r;
  944 
  945                     sprintf(name, cache_info, i, j, "coherency_line_size");
  946                     f = fopen(name, "r");
  947                     if(!f) continue;
  948                     fscanf(f, "%u", &r);
  949                     fclose(f);
  950                     cache.LineSize = r;
  951 
  952                     sprintf(name, cache_info, i, j, "size");
  953                     f = fopen(name, "r");
  954                     if(!f) continue;
  955                     fscanf(f, "%u%c", &r, &op);
  956                     fclose(f);
  957                     if(op != 'K')
  958                         WARN("unknown cache size %u%c\n", r, op);
  959                     cache.Size = (op=='K' ? r*1024 : r);
  960 
  961                     sprintf(name, cache_info, i, j, "type");
  962                     f = fopen(name, "r");
  963                     if(!f) continue;
  964                     fscanf(f, "%s", name);
  965                     fclose(f);
  966                     if (!memcmp(name, "Data", 5))
  967                         cache.Type = CacheData;
  968                     else if(!memcmp(name, "Instruction", 11))
  969                         cache.Type = CacheInstruction;
  970                     else
  971                         cache.Type = CacheUnified;
  972 
  973                     if (!logical_proc_info_add_cache(data, dataex, &len, max_len, mask, &cache))
  974                     {
  975                         fclose(fcpu_list);
  976                         return STATUS_NO_MEMORY;
  977                     }
  978                 }
  979             }
  980         }
  981     }
  982     fclose(fcpu_list);
  983 
  984     num_cpus = count_bits(all_cpus_mask);
  985 
  986     if(relation == RelationAll || relation == RelationNumaNode)
  987     {
  988         fnuma_list = fopen("/sys/devices/system/node/online", "r");
  989         if (!fnuma_list)
  990         {
  991             if (!logical_proc_info_add_numa_node(data, dataex, &len, max_len, all_cpus_mask, 0))
  992                 return STATUS_NO_MEMORY;
  993         }
  994         else
  995         {
  996             while (!feof(fnuma_list))
  997             {
  998                 if (!fscanf(fnuma_list, "%u%c ", &beg, &op))
  999                     break;
 1000                 if (op == '-') fscanf(fnuma_list, "%u%c ", &end, &op);
 1001                 else end = beg;
 1002 
 1003                 for (i = beg; i <= end; i++)
 1004                 {
 1005                     ULONG_PTR mask = 0;
 1006 
 1007                     sprintf(name, numa_info, i);
 1008                     if (!sysfs_parse_bitmap( name, &mask )) continue;
 1009 
 1010                     if (!logical_proc_info_add_numa_node(data, dataex, &len, max_len, mask, i))
 1011                     {
 1012                         fclose(fnuma_list);
 1013                         return STATUS_NO_MEMORY;
 1014                     }
 1015                 }
 1016             }
 1017             fclose(fnuma_list);
 1018         }
 1019     }
 1020 
 1021     if(dataex && (relation == RelationAll || relation == RelationGroup))
 1022         logical_proc_info_add_group(dataex, &len, max_len, num_cpus, all_cpus_mask);
 1023 
 1024     if(data)
 1025         *max_len = len * sizeof(**data);
 1026     else
 1027         *max_len = len;
 1028 
 1029     return STATUS_SUCCESS;
 1030 }
 1031 
 1032 #elif defined(__APPLE__)
 1033 
 1034 /* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
 1035 static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data,
 1036                                           SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **dataex,
 1037                                           DWORD *max_len, DWORD relation)
 1038 {
 1039     DWORD pkgs_no, cores_no, lcpu_no, lcpu_per_core, cores_per_package, assoc, len = 0;
 1040     DWORD cache_ctrs[10] = {0};
 1041     ULONG_PTR all_cpus_mask = 0;
 1042     CACHE_DESCRIPTOR cache[10];
 1043     LONGLONG cache_size, cache_line_size, cache_sharing[10];
 1044     size_t size;
 1045     DWORD p,i,j,k;
 1046 
 1047     if (relation != RelationAll)
 1048         FIXME("Relationship filtering not implemented: 0x%x\n", relation);
 1049 
 1050     lcpu_no = NtCurrentTeb()->Peb->NumberOfProcessors;
 1051 
 1052     size = sizeof(pkgs_no);
 1053     if (sysctlbyname("hw.packages", &pkgs_no, &size, NULL, 0))
 1054         pkgs_no = 1;
 1055 
 1056     size = sizeof(cores_no);
 1057     if (sysctlbyname("hw.physicalcpu", &cores_no, &size, NULL, 0))
 1058         cores_no = lcpu_no;
 1059 
 1060     TRACE("%u logical CPUs from %u physical cores across %u packages\n",
 1061             lcpu_no, cores_no, pkgs_no);
 1062 
 1063     lcpu_per_core = lcpu_no / cores_no;
 1064     cores_per_package = cores_no / pkgs_no;
 1065 
 1066     memset(cache, 0, sizeof(cache));
 1067     cache[1].Level = 1;
 1068     cache[1].Type = CacheInstruction;
 1069     cache[1].Associativity = 8; /* reasonable default */
 1070     cache[1].LineSize = 0x40; /* reasonable default */
 1071     cache[2].Level = 1;
 1072     cache[2].Type = CacheData;
 1073     cache[2].Associativity = 8;
 1074     cache[2].LineSize = 0x40;
 1075     cache[3].Level = 2;
 1076     cache[3].Type = CacheUnified;
 1077     cache[3].Associativity = 8;
 1078     cache[3].LineSize = 0x40;
 1079     cache[4].Level = 3;
 1080     cache[4].Type = CacheUnified;
 1081     cache[4].Associativity = 12;
 1082     cache[4].LineSize = 0x40;
 1083 
 1084     size = sizeof(cache_line_size);
 1085     if (!sysctlbyname("hw.cachelinesize", &cache_line_size, &size, NULL, 0))
 1086     {
 1087         for (i = 1; i < 5; i++) cache[i].LineSize = cache_line_size;
 1088     }
 1089 
 1090     /* TODO: set actual associativity for all caches */
 1091     size = sizeof(assoc);
 1092     if (!sysctlbyname("machdep.cpu.cache.L2_associativity", &assoc, &size, NULL, 0))
 1093         cache[3].Associativity = assoc;
 1094 
 1095     size = sizeof(cache_size);
 1096     if (!sysctlbyname("hw.l1icachesize", &cache_size, &size, NULL, 0))
 1097         cache[1].Size = cache_size;
 1098     size = sizeof(cache_size);
 1099     if (!sysctlbyname("hw.l1dcachesize", &cache_size, &size, NULL, 0))
 1100         cache[2].Size = cache_size;
 1101     size = sizeof(cache_size);
 1102     if (!sysctlbyname("hw.l2cachesize", &cache_size, &size, NULL, 0))
 1103         cache[3].Size = cache_size;
 1104     size = sizeof(cache_size);
 1105     if (!sysctlbyname("hw.l3cachesize", &cache_size, &size, NULL, 0))
 1106         cache[4].Size = cache_size;
 1107 
 1108     size = sizeof(cache_sharing);
 1109     if (sysctlbyname("hw.cacheconfig", cache_sharing, &size, NULL, 0) < 0)
 1110     {
 1111         cache_sharing[1] = lcpu_per_core;
 1112         cache_sharing[2] = lcpu_per_core;
 1113         cache_sharing[3] = lcpu_per_core;
 1114         cache_sharing[4] = lcpu_no;
 1115     }
 1116     else
 1117     {
 1118         /* in cache[], indexes 1 and 2 are l1 caches */
 1119         cache_sharing[4] = cache_sharing[3];
 1120         cache_sharing[3] = cache_sharing[2];
 1121         cache_sharing[2] = cache_sharing[1];
 1122     }
 1123 
 1124     for(p = 0; p < pkgs_no; ++p)
 1125     {
 1126         for(j = 0; j < cores_per_package && p * cores_per_package + j < cores_no; ++j)
 1127         {
 1128             ULONG_PTR mask = 0;
 1129             DWORD phys_core;
 1130 
 1131             for(k = 0; k < lcpu_per_core; ++k) mask |= (ULONG_PTR)1 << (j * lcpu_per_core + k);
 1132 
 1133             all_cpus_mask |= mask;
 1134 
 1135             /* add to package */
 1136             if(!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorPackage, p, mask))
 1137                 return STATUS_NO_MEMORY;
 1138 
 1139             /* add new core */
 1140             phys_core = p * cores_per_package + j;
 1141             if(!logical_proc_info_add_by_id(data, dataex, &len, max_len, RelationProcessorCore, phys_core, mask))
 1142                 return STATUS_NO_MEMORY;
 1143 
 1144             for(i = 1; i < 5; ++i)
 1145             {
 1146                 if(cache_ctrs[i] == 0 && cache[i].Size > 0)
 1147                 {
 1148                     mask = 0;
 1149                     for(k = 0; k < cache_sharing[i]; ++k)
 1150                         mask |= (ULONG_PTR)1 << (j * lcpu_per_core + k);
 1151 
 1152                     if(!logical_proc_info_add_cache(data, dataex, &len, max_len, mask, &cache[i]))
 1153                         return STATUS_NO_MEMORY;
 1154                 }
 1155 
 1156                 cache_ctrs[i] += lcpu_per_core;
 1157                 if(cache_ctrs[i] == cache_sharing[i]) cache_ctrs[i] = 0;
 1158             }
 1159         }
 1160     }
 1161 
 1162     /* OSX doesn't support NUMA, so just make one NUMA node for all CPUs */
 1163     if(!logical_proc_info_add_numa_node(data, dataex, &len, max_len, all_cpus_mask, 0))
 1164         return STATUS_NO_MEMORY;
 1165 
 1166     if(dataex) logical_proc_info_add_group(dataex, &len, max_len, lcpu_no, all_cpus_mask);
 1167 
 1168     if(data)
 1169         *max_len = len * sizeof(**data);
 1170     else
 1171         *max_len = len;
 1172 
 1173     return STATUS_SUCCESS;
 1174 }
 1175 
 1176 #else
 1177 
 1178 static NTSTATUS create_logical_proc_info( SYSTEM_LOGICAL_PROCESSOR_INFORMATION **data,
 1179                                           SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX **dataex,
 1180                                           DWORD *max_len, DWORD relation )
 1181 {
 1182     FIXME("stub\n");
 1183     return STATUS_NOT_IMPLEMENTED;
 1184 }
 1185 #endif
 1186 
 1187 #ifdef linux
 1188 
 1189 static void copy_smbios_string( char **buffer, char *s, size_t len )
 1190 {
 1191     if (!len) return;
 1192     memcpy(*buffer, s, len + 1);
 1193     *buffer += len + 1;
 1194 }
 1195 
 1196 static size_t get_smbios_string( const char *path, char *str, size_t size )
 1197 {
 1198     FILE *file;
 1199     size_t len;
 1200 
 1201     if (!(file = fopen(path, "r"))) return 0;
 1202 
 1203     len = fread( str, 1, size - 1, file );
 1204     fclose( file );
 1205 
 1206     if (len >= 1 && str[len - 1] == '\n') len--;
 1207     str[len] = 0;
 1208     return len;
 1209 }
 1210 
 1211 static void get_system_uuid( GUID *uuid )
 1212 {
 1213     static const unsigned char hex[] =
 1214     {
 1215         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,        /* 0x00 */
 1216         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,        /* 0x10 */
 1217         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,        /* 0x20 */
 1218         0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0,        /* 0x30 */
 1219         0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0,  /* 0x40 */
 1220         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,        /* 0x50 */
 1221         0,10,11,12,13,14,15                     /* 0x60 */
 1222     };
 1223     int fd;
 1224 
 1225     memset( uuid, 0xff, sizeof(*uuid) );
 1226     if ((fd = open( "/var/lib/dbus/machine-id", O_RDONLY )) != -1)
 1227     {
 1228         unsigned char buf[32], *p = buf;
 1229         if (read( fd, buf, sizeof(buf) ) == sizeof(buf))
 1230         {
 1231             uuid->Data1 = hex[p[6]] << 28 | hex[p[7]] << 24 | hex[p[4]] << 20 | hex[p[5]] << 16 |
 1232                           hex[p[2]] << 12 | hex[p[3]] << 8  | hex[p[0]] << 4  | hex[p[1]];
 1233 
 1234             uuid->Data2 = hex[p[10]] << 12 | hex[p[11]] << 8 | hex[p[8]]  << 4 | hex[p[9]];
 1235             uuid->Data3 = hex[p[14]] << 12 | hex[p[15]] << 8 | hex[p[12]] << 4 | hex[p[13]];
 1236 
 1237             uuid->Data4[0] = hex[p[16]] << 4 | hex[p[17]];
 1238             uuid->Data4[1] = hex[p[18]] << 4 | hex[p[19]];
 1239             uuid->Data4[2] = hex[p[20]] << 4 | hex[p[21]];
 1240             uuid->Data4[3] = hex[p[22]] << 4 | hex[p[23]];
 1241             uuid->Data4[4] = hex[p[24]] << 4 | hex[p[25]];
 1242             uuid->Data4[5] = hex[p[26]] << 4 | hex[p[27]];
 1243             uuid->Data4[6] = hex[p[28]] << 4 | hex[p[29]];
 1244             uuid->Data4[7] = hex[p[30]] << 4 | hex[p[31]];
 1245         }
 1246         close( fd );
 1247     }
 1248 }
 1249 
 1250 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
 1251                                    ULONG *required_len )
 1252 {
 1253     switch (sfti->ProviderSignature)
 1254     {
 1255     case RSMB:
 1256     {
 1257         char bios_vendor[128], bios_version[128], bios_date[128];
 1258         size_t bios_vendor_len, bios_version_len, bios_date_len;
 1259         char system_vendor[128], system_product[128], system_version[128], system_serial[128];
 1260         size_t system_vendor_len, system_product_len, system_version_len, system_serial_len;
 1261         char system_sku[128], system_family[128];
 1262         size_t system_sku_len, system_family_len;
 1263         char board_vendor[128], board_product[128], board_version[128], board_serial[128], board_asset_tag[128];
 1264         size_t board_vendor_len, board_product_len, board_version_len, board_serial_len, board_asset_tag_len;
 1265         char chassis_vendor[128], chassis_version[128], chassis_serial[128], chassis_asset_tag[128];
 1266         char chassis_type[11] = "2"; /* unknown */
 1267         size_t chassis_vendor_len, chassis_version_len, chassis_serial_len, chassis_asset_tag_len;
 1268         char *buffer = (char*)sfti->TableBuffer;
 1269         BYTE string_count;
 1270         BYTE handle_count = 0;
 1271         struct smbios_prologue *prologue;
 1272         struct smbios_bios *bios;
 1273         struct smbios_system *system;
 1274         struct smbios_board *board;
 1275         struct smbios_chassis *chassis;
 1276         struct smbios_boot_info *boot_info;
 1277         struct smbios_header *end_of_table;
 1278 
 1279 #define S(s) s, sizeof(s)
 1280         bios_vendor_len = get_smbios_string("/sys/class/dmi/id/bios_vendor", S(bios_vendor));
 1281         bios_version_len = get_smbios_string("/sys/class/dmi/id/bios_version", S(bios_version));
 1282         bios_date_len = get_smbios_string("/sys/class/dmi/id/bios_date", S(bios_date));
 1283         system_vendor_len = get_smbios_string("/sys/class/dmi/id/sys_vendor", S(system_vendor));
 1284         system_product_len = get_smbios_string("/sys/class/dmi/id/product_name", S(system_product));
 1285         system_version_len = get_smbios_string("/sys/class/dmi/id/product_version", S(system_version));
 1286         system_serial_len = get_smbios_string("/sys/class/dmi/id/product_serial", S(system_serial));
 1287         system_sku_len = get_smbios_string("/sys/class/dmi/id/product_sku", S(system_sku));
 1288         system_family_len = get_smbios_string("/sys/class/dmi/id/product_family", S(system_family));
 1289         board_vendor_len = get_smbios_string("/sys/class/dmi/id/board_vendor", S(board_vendor));
 1290         board_product_len = get_smbios_string("/sys/class/dmi/id/board_name", S(board_product));
 1291         board_version_len = get_smbios_string("/sys/class/dmi/id/board_version", S(board_version));
 1292         board_serial_len = get_smbios_string("/sys/class/dmi/id/board_serial", S(board_serial));
 1293         board_asset_tag_len = get_smbios_string("/sys/class/dmi/id/board_asset_tag", S(board_asset_tag));
 1294         chassis_vendor_len = get_smbios_string("/sys/class/dmi/id/chassis_vendor", S(chassis_vendor));
 1295         chassis_version_len = get_smbios_string("/sys/class/dmi/id/chassis_version", S(chassis_version));
 1296         chassis_serial_len = get_smbios_string("/sys/class/dmi/id/chassis_serial", S(chassis_serial));
 1297         chassis_asset_tag_len = get_smbios_string("/sys/class/dmi/id/chassis_tag", S(chassis_asset_tag));
 1298         get_smbios_string("/sys/class/dmi/id/chassis_type", S(chassis_type));
 1299 #undef S
 1300 
 1301         *required_len = sizeof(struct smbios_prologue);
 1302 
 1303 #define L(l) (l + (l ? 1 : 0))
 1304         *required_len += sizeof(struct smbios_bios);
 1305         *required_len += max(L(bios_vendor_len) + L(bios_version_len) + L(bios_date_len) + 1, 2);
 1306 
 1307         *required_len += sizeof(struct smbios_system);
 1308         *required_len += max(L(system_vendor_len) + L(system_product_len) + L(system_version_len) +
 1309                              L(system_serial_len) + L(system_sku_len) + L(system_family_len) + 1, 2);
 1310 
 1311         *required_len += sizeof(struct smbios_board);
 1312         *required_len += max(L(board_vendor_len) + L(board_product_len) + L(board_version_len) +
 1313                              L(board_serial_len) + L(board_asset_tag_len) + 1, 2);
 1314 
 1315         *required_len += sizeof(struct smbios_chassis);
 1316         *required_len += max(L(chassis_vendor_len) + L(chassis_version_len) + L(chassis_serial_len) +
 1317                              L(chassis_asset_tag_len) + 1, 2);
 1318 
 1319         *required_len += sizeof(struct smbios_boot_info);
 1320         *required_len += 2;
 1321 
 1322         *required_len += sizeof(struct smbios_header);
 1323         *required_len += 2;
 1324 #undef L
 1325 
 1326         sfti->TableBufferLength = *required_len;
 1327 
 1328         *required_len += FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
 1329 
 1330         if (available_len < *required_len)
 1331             return STATUS_BUFFER_TOO_SMALL;
 1332 
 1333         prologue = (struct smbios_prologue*)buffer;
 1334         prologue->calling_method = 0;
 1335         prologue->major_version = 2;
 1336         prologue->minor_version = 4;
 1337         prologue->revision = 0;
 1338         prologue->length = sfti->TableBufferLength - sizeof(struct smbios_prologue);
 1339         buffer += sizeof(struct smbios_prologue);
 1340 
 1341         string_count = 0;
 1342         bios = (struct smbios_bios*)buffer;
 1343         bios->hdr.type = 0;
 1344         bios->hdr.length = sizeof(struct smbios_bios);
 1345         bios->hdr.handle = handle_count++;
 1346         bios->vendor = bios_vendor_len ? ++string_count : 0;
 1347         bios->version = bios_version_len ? ++string_count : 0;
 1348         bios->start = 0;
 1349         bios->date = bios_date_len ? ++string_count : 0;
 1350         bios->size = 0;
 1351         bios->characteristics = 0x4; /* not supported */
 1352         bios->characteristics_ext[0] = 0;
 1353         bios->characteristics_ext[1] = 0;
 1354         bios->system_bios_major_release = 0xFF; /* not supported */
 1355         bios->system_bios_minor_release = 0xFF; /* not supported */
 1356         bios->ec_firmware_major_release = 0xFF; /* not supported */
 1357         bios->ec_firmware_minor_release = 0xFF; /* not supported */
 1358         buffer += sizeof(struct smbios_bios);
 1359 
 1360         copy_smbios_string(&buffer, bios_vendor, bios_vendor_len);
 1361         copy_smbios_string(&buffer, bios_version, bios_version_len);
 1362         copy_smbios_string(&buffer, bios_date, bios_date_len);
 1363         if (!string_count) *buffer++ = 0;
 1364         *buffer++ = 0;
 1365 
 1366         string_count = 0;
 1367         system = (struct smbios_system*)buffer;
 1368         system->hdr.type = 1;
 1369         system->hdr.length = sizeof(struct smbios_system);
 1370         system->hdr.handle = handle_count++;
 1371         system->vendor = system_vendor_len ? ++string_count : 0;
 1372         system->product = system_product_len ? ++string_count : 0;
 1373         system->version = system_version_len ? ++string_count : 0;
 1374         system->serial = system_serial_len ? ++string_count : 0;
 1375         get_system_uuid( (GUID *)system->uuid );
 1376         system->wake_up_type = 0x02; /* unknown */
 1377         system->sku_number = system_sku_len ? ++string_count : 0;
 1378         system->family = system_family_len ? ++string_count : 0;
 1379         buffer += sizeof(struct smbios_system);
 1380 
 1381         copy_smbios_string(&buffer, system_vendor, system_vendor_len);
 1382         copy_smbios_string(&buffer, system_product, system_product_len);
 1383         copy_smbios_string(&buffer, system_version, system_version_len);
 1384         copy_smbios_string(&buffer, system_serial, system_serial_len);
 1385         copy_smbios_string(&buffer, system_sku, system_sku_len);
 1386         copy_smbios_string(&buffer, system_family, system_family_len);
 1387         if (!string_count) *buffer++ = 0;
 1388         *buffer++ = 0;
 1389 
 1390         string_count = 0;
 1391         chassis = (struct smbios_chassis*)buffer;
 1392         chassis->hdr.type = 3;
 1393         chassis->hdr.length = sizeof(struct smbios_chassis);
 1394         chassis->hdr.handle = handle_count++;
 1395         chassis->vendor = chassis_vendor_len ? ++string_count : 0;
 1396         chassis->type = atoi(chassis_type);
 1397         chassis->version = chassis_version_len ? ++string_count : 0;
 1398         chassis->serial = chassis_serial_len ? ++string_count : 0;
 1399         chassis->asset_tag = chassis_asset_tag_len ? ++string_count : 0;
 1400         chassis->boot_state = 0x02; /* unknown */
 1401         chassis->power_supply_state = 0x02; /* unknown */
 1402         chassis->thermal_state = 0x02; /* unknown */
 1403         chassis->security_status = 0x02; /* unknown */
 1404         chassis->oem_defined = 0;
 1405         chassis->height = 0; /* undefined */
 1406         chassis->num_power_cords = 0; /* unspecified */
 1407         chassis->num_contained_elements = 0;
 1408         chassis->contained_element_rec_length = 3;
 1409         buffer += sizeof(struct smbios_chassis);
 1410 
 1411         copy_smbios_string(&buffer, chassis_vendor, chassis_vendor_len);
 1412         copy_smbios_string(&buffer, chassis_version, chassis_version_len);
 1413         copy_smbios_string(&buffer, chassis_serial, chassis_serial_len);
 1414         copy_smbios_string(&buffer, chassis_asset_tag, chassis_asset_tag_len);
 1415         if (!string_count) *buffer++ = 0;
 1416         *buffer++ = 0;
 1417 
 1418         string_count = 0;
 1419         board = (struct smbios_board*)buffer;
 1420         board->hdr.type = 2;
 1421         board->hdr.length = sizeof(struct smbios_board);
 1422         board->hdr.handle = handle_count++;
 1423         board->vendor = board_vendor_len ? ++string_count : 0;
 1424         board->product = board_product_len ? ++string_count : 0;
 1425         board->version = board_version_len ? ++string_count : 0;
 1426         board->serial = board_serial_len ? ++string_count : 0;
 1427         board->asset_tag = board_asset_tag_len ? ++string_count : 0;
 1428         board->feature_flags = 0x5; /* hosting board, removable */
 1429         board->location = 0;
 1430         board->chassis_handle = chassis->hdr.handle;
 1431         board->board_type = 0xa; /* motherboard */
 1432         board->num_contained_handles = 0;
 1433         buffer += sizeof(struct smbios_board);
 1434 
 1435         copy_smbios_string(&buffer, board_vendor, board_vendor_len);
 1436         copy_smbios_string(&buffer, board_product, board_product_len);
 1437         copy_smbios_string(&buffer, board_version, board_version_len);
 1438         copy_smbios_string(&buffer, board_serial, board_serial_len);
 1439         copy_smbios_string(&buffer, board_asset_tag, board_asset_tag_len);
 1440         if (!string_count) *buffer++ = 0;
 1441         *buffer++ = 0;
 1442 
 1443         boot_info = (struct smbios_boot_info*)buffer;
 1444         boot_info->hdr.type = 32;
 1445         boot_info->hdr.length = sizeof(struct smbios_boot_info);
 1446         boot_info->hdr.handle = handle_count++;
 1447         memset(boot_info->reserved, 0, sizeof(boot_info->reserved));
 1448         memset(boot_info->boot_status, 0, sizeof(boot_info->boot_status)); /* no errors detected */
 1449         buffer += sizeof(struct smbios_boot_info);
 1450         *buffer++ = 0;
 1451         *buffer++ = 0;
 1452 
 1453         end_of_table = (struct smbios_header*)buffer;
 1454         end_of_table->type = 127;
 1455         end_of_table->length = sizeof(struct smbios_header);
 1456         end_of_table->handle = handle_count++;
 1457         buffer += sizeof(struct smbios_header);
 1458         *buffer++ = 0;
 1459         *buffer++ = 0;
 1460 
 1461         return STATUS_SUCCESS;
 1462     }
 1463     default:
 1464         FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION provider %08x\n", sfti->ProviderSignature);
 1465         return STATUS_NOT_IMPLEMENTED;
 1466     }
 1467 }
 1468 
 1469 #elif defined(__APPLE__)
 1470 
 1471 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
 1472                                    ULONG *required_len )
 1473 {
 1474     switch (sfti->ProviderSignature)
 1475     {
 1476     case RSMB:
 1477     {
 1478         io_service_t service;
 1479         CFDataRef data;
 1480         const UInt8 *ptr;
 1481         CFIndex len;
 1482         struct smbios_prologue *prologue;
 1483         BYTE major_version = 2, minor_version = 0;
 1484 
 1485         if (!(service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleSMBIOS"))))
 1486         {
 1487             WARN("can't find AppleSMBIOS service\n");
 1488             return STATUS_NO_MEMORY;
 1489         }
 1490 
 1491         if (!(data = IORegistryEntryCreateCFProperty(service, CFSTR("SMBIOS-EPS"), kCFAllocatorDefault, 0)))
 1492         {
 1493             WARN("can't find SMBIOS entry point\n");
 1494             IOObjectRelease(service);
 1495             return STATUS_NO_MEMORY;
 1496         }
 1497 
 1498         len = CFDataGetLength(data);
 1499         ptr = CFDataGetBytePtr(data);
 1500         if (len >= 8 && !memcmp(ptr, "_SM_", 4))
 1501         {
 1502             major_version = ptr[6];
 1503             minor_version = ptr[7];
 1504         }
 1505         CFRelease(data);
 1506 
 1507         if (!(data = IORegistryEntryCreateCFProperty(service, CFSTR("SMBIOS"), kCFAllocatorDefault, 0)))
 1508         {
 1509             WARN("can't find SMBIOS table\n");
 1510             IOObjectRelease(service);
 1511             return STATUS_NO_MEMORY;
 1512         }
 1513 
 1514         len = CFDataGetLength(data);
 1515         ptr = CFDataGetBytePtr(data);
 1516         sfti->TableBufferLength = sizeof(*prologue) + len;
 1517         *required_len = sfti->TableBufferLength + FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
 1518         if (available_len < *required_len)
 1519         {
 1520             CFRelease(data);
 1521             IOObjectRelease(service);
 1522             return STATUS_BUFFER_TOO_SMALL;
 1523         }
 1524 
 1525         prologue = (struct smbios_prologue *)sfti->TableBuffer;
 1526         prologue->calling_method = 0;
 1527         prologue->major_version = major_version;
 1528         prologue->minor_version = minor_version;
 1529         prologue->revision = 0;
 1530         prologue->length = sfti->TableBufferLength - sizeof(*prologue);
 1531 
 1532         memcpy(sfti->TableBuffer + sizeof(*prologue), ptr, len);
 1533 
 1534         CFRelease(data);
 1535         IOObjectRelease(service);
 1536         return STATUS_SUCCESS;
 1537     }
 1538     default:
 1539         FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION provider %08x\n", sfti->ProviderSignature);
 1540         return STATUS_NOT_IMPLEMENTED;
 1541     }
 1542 }
 1543 
 1544 #else
 1545 
 1546 static NTSTATUS get_firmware_info( SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti, ULONG available_len,
 1547                                    ULONG *required_len )
 1548 {
 1549     FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION\n");
 1550     sfti->TableBufferLength = 0;
 1551     return STATUS_NOT_IMPLEMENTED;
 1552 }
 1553 
 1554 #endif
 1555 
 1556 static void get_performance_info( SYSTEM_PERFORMANCE_INFORMATION *info )
 1557 {
 1558     unsigned long long totalram = 0, freeram = 0, totalswap = 0, freeswap = 0;
 1559     FILE *fp;
 1560 
 1561     memset( info, 0, sizeof(*info) );
 1562 
 1563     if ((fp = fopen("/proc/uptime", "r")))
 1564     {
 1565         double uptime, idle_time;
 1566 
 1567         fscanf(fp, "%lf %lf", &uptime, &idle_time);
 1568         fclose(fp);
 1569         info->IdleTime.QuadPart = 10000000 * idle_time;
 1570     }
 1571     else
 1572     {
 1573         static ULONGLONG idle;
 1574         /* many programs expect IdleTime to change so fake change */
 1575         info->IdleTime.QuadPart = ++idle;
 1576     }
 1577 
 1578 #ifdef linux
 1579     if ((fp = fopen("/proc/meminfo", "r")))
 1580     {
 1581         unsigned long long value;
 1582         char line[64];
 1583 
 1584         while (fgets(line, sizeof(line), fp))
 1585         {
 1586             if(sscanf(line, "MemTotal: %llu kB", &value) == 1)
 1587                 totalram += value * 1024;
 1588             else if(sscanf(line, "MemFree: %llu kB", &value) == 1)
 1589                 freeram += value * 1024;
 1590             else if(sscanf(line, "SwapTotal: %llu kB", &value) == 1)
 1591                 totalswap += value * 1024;
 1592             else if(sscanf(line, "SwapFree: %llu kB", &value) == 1)
 1593                 freeswap += value * 1024;
 1594             else if (sscanf(line, "Buffers: %llu", &value))
 1595                 freeram += value * 1024;
 1596             else if (sscanf(line, "Cached: %llu", &value))
 1597                 freeram += value * 1024;
 1598         }
 1599         fclose(fp);
 1600     }
 1601 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || \
 1602     defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
 1603     {
 1604 #ifdef __APPLE__
 1605         unsigned int val;
 1606 #else
 1607         unsigned long val;
 1608 #endif
 1609         int mib[2];
 1610         size_t size_sys;
 1611 
 1612         mib[0] = CTL_HW;
 1613 #ifdef HW_MEMSIZE
 1614         {
 1615             uint64_t val64;
 1616             mib[1] = HW_MEMSIZE;
 1617             size_sys = sizeof(val64);
 1618             if (!sysctl(mib, 2, &val64, &size_sys, NULL, 0) && size_sys == sizeof(val64)) totalram = val64;
 1619         }
 1620 #endif
 1621 
 1622 #ifdef HAVE_MACH_MACH_H
 1623         {
 1624             host_name_port_t host = mach_host_self();
 1625             mach_msg_type_number_t count;
 1626 #ifdef HOST_VM_INFO64_COUNT
 1627             vm_statistics64_data_t vm_stat;
 1628 
 1629             count = HOST_VM_INFO64_COUNT;
 1630             if (host_statistics64(host, HOST_VM_INFO64, (host_info64_t)&vm_stat, &count) == KERN_SUCCESS)
 1631                 freeram = (vm_stat.free_count + vm_stat.inactive_count) * (ULONGLONG)page_size;
 1632 #endif
 1633             if (!totalram)
 1634             {
 1635                 host_basic_info_data_t info;
 1636                 count = HOST_BASIC_INFO_COUNT;
 1637                 if (host_info(host, HOST_BASIC_INFO, (host_info_t)&info, &count) == KERN_SUCCESS)
 1638                     totalram = info.max_mem;
 1639             }
 1640             mach_port_deallocate(mach_task_self(), host);
 1641         }
 1642 #endif
 1643 
 1644         if (!totalram)
 1645         {
 1646             mib[1] = HW_PHYSMEM;
 1647             size_sys = sizeof(val);
 1648             if (!sysctl(mib, 2, &val, &size_sys, NULL, 0) && size_sys == sizeof(val)) totalram = val;
 1649         }
 1650         if (!freeram)
 1651         {
 1652             mib[1] = HW_USERMEM;
 1653             size_sys = sizeof(val);
 1654             if (!sysctl(mib, 2, &val, &size_sys, NULL, 0) && size_sys == sizeof(val)) freeram = val;
 1655         }
 1656 #ifdef VM_SWAPUSAGE
 1657         {
 1658             struct xsw_usage swap;
 1659             mib[0] = CTL_VM;
 1660             mib[1] = VM_SWAPUSAGE;
 1661             size_sys = sizeof(swap);
 1662             if (!sysctl(mib, 2, &swap, &size_sys, NULL, 0) && size_sys == sizeof(swap))
 1663             {
 1664                 totalswap = swap.xsu_total;
 1665                 freeswap = swap.xsu_avail;
 1666             }
 1667         }
 1668 #endif
 1669     }
 1670 #endif
 1671     info->AvailablePages      = freeram / page_size;
 1672     info->TotalCommittedPages = (totalram + totalswap - freeram - freeswap) / page_size;
 1673     info->TotalCommitLimit    = (totalram + totalswap) / page_size;
 1674 }
 1675 
 1676 
 1677 /* calculate the mday of dst change date, so that for instance Sun 5 Oct 2007
 1678  * (last Sunday in October of 2007) becomes Sun Oct 28 2007
 1679  *
 1680  * Note: year, day and month must be in unix format.
 1681  */
 1682 static int weekday_to_mday(int year, int day, int mon, int day_of_week)
 1683 {
 1684     struct tm date;
 1685     time_t tmp;
 1686     int wday, mday;
 1687 
 1688     /* find first day in the month matching week day of the date */
 1689     memset(&date, 0, sizeof(date));
 1690     date.tm_year = year;
 1691     date.tm_mon = mon;
 1692     date.tm_mday = -1;
 1693     date.tm_wday = -1;
 1694     do
 1695     {
 1696         date.tm_mday++;
 1697         tmp = mktime(&date);
 1698     } while (date.tm_wday != day_of_week || date.tm_mon != mon);
 1699 
 1700     mday = date.tm_mday;
 1701 
 1702     /* find number of week days in the month matching week day of the date */
 1703     wday = 1; /* 1 - 1st, ...., 5 - last */
 1704     while (wday < day)
 1705     {
 1706         struct tm *tm;
 1707 
 1708         date.tm_mday += 7;
 1709         tmp = mktime(&date);
 1710         tm = localtime(&tmp);
 1711         if (tm->tm_mon != mon)
 1712             break;
 1713         mday = tm->tm_mday;
 1714         wday++;
 1715     }
 1716 
 1717     return mday;
 1718 }
 1719 
 1720 static BOOL match_tz_date( const RTL_SYSTEM_TIME *st, const RTL_SYSTEM_TIME *reg_st )
 1721 {
 1722     WORD wDay;
 1723 
 1724     if (st->wMonth != reg_st->wMonth) return FALSE;
 1725     if (!st->wMonth) return TRUE; /* no transition dates */
 1726     wDay = reg_st->wDay;
 1727     if (!reg_st->wYear) /* date in a day-of-week format */
 1728         wDay = weekday_to_mday(st->wYear - 1900, reg_st->wDay, reg_st->wMonth - 1, reg_st->wDayOfWeek);
 1729 
 1730     return (st->wDay == wDay &&
 1731             st->wHour == reg_st->wHour &&
 1732             st->wMinute == reg_st->wMinute &&
 1733             st->wSecond == reg_st->wSecond &&
 1734             st->wMilliseconds == reg_st->wMilliseconds);
 1735 }
 1736 
 1737 static BOOL match_tz_info( const RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi,
 1738                            const RTL_DYNAMIC_TIME_ZONE_INFORMATION *reg_tzi )
 1739 {
 1740     return (tzi->Bias == reg_tzi->Bias &&
 1741             match_tz_date(&tzi->StandardDate, &reg_tzi->StandardDate) &&
 1742             match_tz_date(&tzi->DaylightDate, &reg_tzi->DaylightDate));
 1743 }
 1744 
 1745 static BOOL match_past_tz_bias( time_t past_time, LONG past_bias )
 1746 {
 1747     LONG bias;
 1748     struct tm *tm;
 1749     if (!past_time) return TRUE;
 1750 
 1751     tm = gmtime( &past_time );
 1752     bias = (LONG)(mktime(tm) - past_time) / 60;
 1753     return bias == past_bias;
 1754 }
 1755 
 1756 static BOOL match_tz_name( const char *tz_name, const RTL_DYNAMIC_TIME_ZONE_INFORMATION *reg_tzi )
 1757 {
 1758     static const struct {
 1759         WCHAR key_name[32];
 1760         const char *short_name;
 1761         time_t past_time;
 1762         LONG past_bias;
 1763     }
 1764     mapping[] =
 1765     {
 1766         { {'N','o','r','t','h',' ','K','o','r','e','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
 1767           "KST", 1451606400 /* 2016-01-01 00:00:00 UTC */, -510 },
 1768         { {'K','o','r','e','a',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
 1769           "KST", 1451606400 /* 2016-01-01 00:00:00 UTC */, -540 },
 1770         { {'T','o','k','y','o',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
 1771           "JST" },
 1772         { {'Y','a','k','u','t','s','k',' ','S','t','a','n','d','a','r','d',' ','T','i','m','e',0 },
 1773           "+09" }, /* YAKST was used until tzdata 2016f */
 1774     };
 1775     unsigned int i;
 1776 
 1777     if (reg_tzi->DaylightDate.wMonth) return TRUE;
 1778     for (i = 0; i < ARRAY_SIZE(mapping); i++)
 1779     {
 1780         if (!wcscmp( mapping[i].key_name, reg_tzi->TimeZoneKeyName ))
 1781             return !strcmp( mapping[i].short_name, tz_name )
 1782                 && match_past_tz_bias( mapping[i].past_time, mapping[i].past_bias );
 1783     }
 1784     return TRUE;
 1785 }
 1786 
 1787 static BOOL reg_query_value( HKEY key, LPCWSTR name, DWORD type, void *data, DWORD count )
 1788 {
 1789     char buf[256];
 1790     UNICODE_STRING nameW;
 1791     KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buf;
 1792 
 1793     if (count > sizeof(buf) - sizeof(KEY_VALUE_PARTIAL_INFORMATION)) return FALSE;
 1794 
 1795     nameW.Buffer = (WCHAR *)name;
 1796     nameW.Length = wcslen( name ) * sizeof(WCHAR);
 1797     if (NtQueryValueKey( key, &nameW, KeyValuePartialInformation, buf, sizeof(buf), &count ))
 1798         return FALSE;
 1799 
 1800     if (info->Type != type) return FALSE;
 1801     memcpy( data, info->Data, info->DataLength );
 1802     return TRUE;
 1803 }
 1804 
 1805 static void find_reg_tz_info(RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi, const char* tz_name, int year)
 1806 {
 1807     static const WCHAR stdW[] = { 'S','t','d',0 };
 1808     static const WCHAR dltW[] = { 'D','l','t',0 };
 1809     static const WCHAR mui_stdW[] = { 'M','U','I','_','S','t','d',0 };
 1810     static const WCHAR mui_dltW[] = { 'M','U','I','_','D','l','t',0 };
 1811     static const WCHAR tziW[] = { 'T','Z','I',0 };
 1812     static const WCHAR Time_ZonesW[] = { 'M','a','c','h','i','n','e','\\',
 1813         'S','o','f','t','w','a','r','e','\\',
 1814         'M','i','c','r','o','s','o','f','t','\\',
 1815         'W','i','n','d','o','w','s',' ','N','T','\\',
 1816         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
 1817         'T','i','m','e',' ','Z','o','n','e','s',0 };
 1818     static const WCHAR Dynamic_DstW[] = { 'D','y','n','a','m','i','c',' ','D','S','T',0 };
 1819     RTL_DYNAMIC_TIME_ZONE_INFORMATION reg_tzi;
 1820     HANDLE key, subkey, subkey_dyn = 0;
 1821     ULONG idx, len;
 1822     OBJECT_ATTRIBUTES attr;
 1823     UNICODE_STRING nameW;
 1824     WCHAR yearW[16];
 1825     char buffer[128];
 1826     KEY_BASIC_INFORMATION *info = (KEY_BASIC_INFORMATION *)buffer;
 1827 
 1828     sprintf( buffer, "%u", year );
 1829     ascii_to_unicode( yearW, buffer, strlen(buffer) + 1 );
 1830 
 1831     nameW.Buffer = (WCHAR *)Time_ZonesW;
 1832     nameW.Length = sizeof(Time_ZonesW) - sizeof(WCHAR);
 1833     InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
 1834     if (NtOpenKey( &key, KEY_READ, &attr )) return;
 1835 
 1836     idx = 0;
 1837     while (!NtEnumerateKey( key, idx++, KeyBasicInformation, buffer, sizeof(buffer), &len ))
 1838     {
 1839         struct tz_reg_data
 1840         {
 1841             LONG bias;
 1842             LONG std_bias;
 1843             LONG dlt_bias;
 1844             RTL_SYSTEM_TIME std_date;
 1845             RTL_SYSTEM_TIME dlt_date;
 1846         } tz_data;
 1847         BOOL is_dynamic = FALSE;
 1848 
 1849         nameW.Buffer = info->Name;
 1850         nameW.Length = info->NameLength;
 1851         attr.RootDirectory = key;
 1852         if (NtOpenKey( &subkey, KEY_READ, &attr )) continue;
 1853 
 1854         memset( &reg_tzi, 0, sizeof(reg_tzi) );
 1855         memcpy(reg_tzi.TimeZoneKeyName, nameW.Buffer, nameW.Length);
 1856         reg_tzi.TimeZoneKeyName[nameW.Length/sizeof(WCHAR)] = 0;
 1857 
 1858         if (!reg_query_value(subkey, mui_stdW, REG_SZ, reg_tzi.StandardName, sizeof(reg_tzi.StandardName)) &&
 1859             !reg_query_value(subkey, stdW, REG_SZ, reg_tzi.StandardName, sizeof(reg_tzi.StandardName)))
 1860             goto next;
 1861 
 1862         if (!reg_query_value(subkey, mui_dltW, REG_SZ, reg_tzi.DaylightName, sizeof(reg_tzi.DaylightName)) &&
 1863             !reg_query_value(subkey, dltW, REG_SZ, reg_tzi.DaylightName, sizeof(reg_tzi.DaylightName)))
 1864             goto next;
 1865 
 1866         /* Check for Dynamic DST entry first */
 1867         nameW.Buffer = (WCHAR *)Dynamic_DstW;
 1868         nameW.Length = sizeof(Dynamic_DstW) - sizeof(WCHAR);
 1869         attr.RootDirectory = subkey;
 1870         if (!NtOpenKey( &subkey_dyn, KEY_READ, &attr ))
 1871         {
 1872             is_dynamic = reg_query_value( subkey_dyn, yearW, REG_BINARY, &tz_data, sizeof(tz_data) );
 1873             NtClose( subkey_dyn );
 1874         }
 1875         if (!is_dynamic && !reg_query_value( subkey, tziW, REG_BINARY, &tz_data, sizeof(tz_data) ))
 1876             goto next;
 1877 
 1878         reg_tzi.Bias = tz_data.bias;
 1879         reg_tzi.StandardBias = tz_data.std_bias;
 1880         reg_tzi.DaylightBias = tz_data.dlt_bias;
 1881         reg_tzi.StandardDate = tz_data.std_date;
 1882         reg_tzi.DaylightDate = tz_data.dlt_date;
 1883 
 1884         TRACE("%s: bias %d\n", debugstr_us(&nameW), reg_tzi.Bias);
 1885         TRACE("std (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
 1886               reg_tzi.StandardDate.wDay, reg_tzi.StandardDate.wMonth,
 1887               reg_tzi.StandardDate.wYear, reg_tzi.StandardDate.wDayOfWeek,
 1888               reg_tzi.StandardDate.wHour, reg_tzi.StandardDate.wMinute,
 1889               reg_tzi.StandardDate.wSecond, reg_tzi.StandardDate.wMilliseconds,
 1890               reg_tzi.StandardBias);
 1891         TRACE("dst (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
 1892               reg_tzi.DaylightDate.wDay, reg_tzi.DaylightDate.wMonth,
 1893               reg_tzi.DaylightDate.wYear, reg_tzi.DaylightDate.wDayOfWeek,
 1894               reg_tzi.DaylightDate.wHour, reg_tzi.DaylightDate.wMinute,
 1895               reg_tzi.DaylightDate.wSecond, reg_tzi.DaylightDate.wMilliseconds,
 1896               reg_tzi.DaylightBias);
 1897 
 1898         if (match_tz_info( tzi, &reg_tzi ) && match_tz_name( tz_name, &reg_tzi ))
 1899         {
 1900             *tzi = reg_tzi;
 1901             NtClose( subkey );
 1902             NtClose( key );
 1903             return;
 1904         }
 1905     next:
 1906         NtClose( subkey );
 1907     }
 1908     NtClose( key );
 1909 
 1910     if (idx == 1) return;  /* registry info not initialized yet */
 1911 
 1912     FIXME("Can't find matching timezone information in the registry for "
 1913           "%s, bias %d, std (d/m/y): %u/%02u/%04u, dlt (d/m/y): %u/%02u/%04u\n",
 1914           tz_name, tzi->Bias,
 1915           tzi->StandardDate.wDay, tzi->StandardDate.wMonth, tzi->StandardDate.wYear,
 1916           tzi->DaylightDate.wDay, tzi->DaylightDate.wMonth, tzi->DaylightDate.wYear);
 1917 }
 1918 
 1919 static time_t find_dst_change(unsigned long min, unsigned long max, int *is_dst)
 1920 {
 1921     time_t start;
 1922     struct tm *tm;
 1923 
 1924     start = min;
 1925     tm = localtime(&start);
 1926     *is_dst = !tm->tm_isdst;
 1927     TRACE("starting date isdst %d, %s", !*is_dst, ctime(&start));
 1928 
 1929     while (min <= max)
 1930     {
 1931         time_t pos = (min + max) / 2;
 1932         tm = localtime(&pos);
 1933 
 1934         if (tm->tm_isdst != *is_dst)
 1935             min = pos + 1;
 1936         else
 1937             max = pos - 1;
 1938     }
 1939     return min;
 1940 }
 1941 
 1942 static void get_timezone_info( RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi )
 1943 {
 1944     static pthread_mutex_t tz_mutex = PTHREAD_MUTEX_INITIALIZER;
 1945     static RTL_DYNAMIC_TIME_ZONE_INFORMATION cached_tzi;
 1946     static int current_year = -1, current_bias = 65535;
 1947     struct tm *tm;
 1948     char tz_name[16];
 1949     time_t year_start, year_end, tmp, dlt = 0, std = 0;
 1950     int is_dst, bias;
 1951 
 1952     mutex_lock( &tz_mutex );
 1953 
 1954     year_start = time(NULL);
 1955     tm = gmtime(&year_start);
 1956     bias = (LONG)(mktime(tm) - year_start) / 60;
 1957 
 1958     tm = localtime(&year_start);
 1959     if (current_year == tm->tm_year && current_bias == bias)
 1960     {
 1961         *tzi = cached_tzi;
 1962         mutex_unlock( &tz_mutex );
 1963         return;
 1964     }
 1965 
 1966     memset(tzi, 0, sizeof(*tzi));
 1967     if (!strftime(tz_name, sizeof(tz_name), "%Z", tm)) {
 1968         /* not enough room or another error */
 1969         tz_name[0] = '\0';
 1970     }
 1971 
 1972     TRACE("tz data will be valid through year %d, bias %d\n", tm->tm_year + 1900, bias);
 1973     current_year = tm->tm_year;
 1974     current_bias = bias;
 1975 
 1976     tzi->Bias = bias;
 1977 
 1978     tm->tm_isdst = 0;
 1979     tm->tm_mday = 1;
 1980     tm->tm_mon = tm->tm_hour = tm->tm_min = tm->tm_sec = tm->tm_wday = tm->tm_yday = 0;
 1981     year_start = mktime(tm);
 1982     TRACE("year_start: %s", ctime(&year_start));
 1983 
 1984     tm->tm_mday = tm->tm_wday = tm->tm_yday = 0;
 1985     tm->tm_mon = 12;
 1986     tm->tm_hour = 23;
 1987     tm->tm_min = tm->tm_sec = 59;
 1988     year_end = mktime(tm);
 1989     TRACE("year_end: %s", ctime(&year_end));
 1990 
 1991     tmp = find_dst_change(year_start, year_end, &is_dst);
 1992     if (is_dst)
 1993         dlt = tmp;
 1994     else
 1995         std = tmp;
 1996 
 1997     tmp = find_dst_change(tmp, year_end, &is_dst);
 1998     if (is_dst)
 1999         dlt = tmp;
 2000     else
 2001         std = tmp;
 2002 
 2003     TRACE("std: %s", ctime(&std));
 2004     TRACE("dlt: %s", ctime(&dlt));
 2005 
 2006     if (dlt == std || !dlt || !std)
 2007         TRACE("there is no daylight saving rules in this time zone\n");
 2008     else
 2009     {
 2010         tmp = dlt - tzi->Bias * 60;
 2011         tm = gmtime(&tmp);
 2012         TRACE("dlt gmtime: %s", asctime(tm));
 2013 
 2014         tzi->DaylightBias = -60;
 2015         tzi->DaylightDate.wYear = tm->tm_year + 1900;
 2016         tzi->DaylightDate.wMonth = tm->tm_mon + 1;
 2017         tzi->DaylightDate.wDayOfWeek = tm->tm_wday;
 2018         tzi->DaylightDate.wDay = tm->tm_mday;
 2019         tzi->DaylightDate.wHour = tm->tm_hour;
 2020         tzi->DaylightDate.wMinute = tm->tm_min;
 2021         tzi->DaylightDate.wSecond = tm->tm_sec;
 2022         tzi->DaylightDate.wMilliseconds = 0;
 2023 
 2024         TRACE("daylight (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
 2025             tzi->DaylightDate.wDay, tzi->DaylightDate.wMonth,
 2026             tzi->DaylightDate.wYear, tzi->DaylightDate.wDayOfWeek,
 2027             tzi->DaylightDate.wHour, tzi->DaylightDate.wMinute,
 2028             tzi->DaylightDate.wSecond, tzi->DaylightDate.wMilliseconds,
 2029             tzi->DaylightBias);
 2030 
 2031         tmp = std - tzi->Bias * 60 - tzi->DaylightBias * 60;
 2032         tm = gmtime(&tmp);
 2033         TRACE("std gmtime: %s", asctime(tm));
 2034 
 2035         tzi->StandardBias = 0;
 2036         tzi->StandardDate.wYear = tm->tm_year + 1900;
 2037         tzi->StandardDate.wMonth = tm->tm_mon + 1;
 2038         tzi->StandardDate.wDayOfWeek = tm->tm_wday;
 2039         tzi->StandardDate.wDay = tm->tm_mday;
 2040         tzi->StandardDate.wHour = tm->tm_hour;
 2041         tzi->StandardDate.wMinute = tm->tm_min;
 2042         tzi->StandardDate.wSecond = tm->tm_sec;
 2043         tzi->StandardDate.wMilliseconds = 0;
 2044 
 2045         TRACE("standard (d/m/y): %u/%02u/%04u day of week %u %u:%02u:%02u.%03u bias %d\n",
 2046             tzi->StandardDate.wDay, tzi->StandardDate.wMonth,
 2047             tzi->StandardDate.wYear, tzi->StandardDate.wDayOfWeek,
 2048             tzi->StandardDate.wHour, tzi->StandardDate.wMinute,
 2049             tzi->StandardDate.wSecond, tzi->StandardDate.wMilliseconds,
 2050             tzi->StandardBias);
 2051     }
 2052 
 2053     find_reg_tz_info(tzi, tz_name, current_year + 1900);
 2054     cached_tzi = *tzi;
 2055     mutex_unlock( &tz_mutex );
 2056 }
 2057 
 2058 
 2059 /******************************************************************************
 2060  *              NtQuerySystemInformation  (NTDLL.@)
 2061  */
 2062 NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class,
 2063                                           void *info, ULONG size, ULONG *ret_size )
 2064 {
 2065     NTSTATUS ret = STATUS_SUCCESS;
 2066     ULONG len = 0;
 2067 
 2068     TRACE( "(0x%08x,%p,0x%08x,%p)\n", class, info, size, ret_size );
 2069 
 2070     switch (class)
 2071     {
 2072     case SystemBasicInformation:
 2073     {
 2074         SYSTEM_BASIC_INFORMATION sbi;
 2075 
 2076         virtual_get_system_info( &sbi );
 2077         len = sizeof(sbi);
 2078         if (size == len)
 2079         {
 2080             if (!info) ret = STATUS_ACCESS_VIOLATION;
 2081             else memcpy( info, &sbi, len);
 2082         }
 2083         else ret = STATUS_INFO_LENGTH_MISMATCH;
 2084         break;
 2085     }
 2086 
 2087     case SystemCpuInformation:
 2088         if (size >= (len = sizeof(cpu_info)))
 2089         {
 2090             if (!info) ret = STATUS_ACCESS_VIOLATION;
 2091             else memcpy(info, &cpu_info, len);
 2092         }
 2093         else ret = STATUS_INFO_LENGTH_MISMATCH;
 2094         break;
 2095 
 2096     case SystemPerformanceInformation:
 2097     {
 2098         SYSTEM_PERFORMANCE_INFORMATION spi;
 2099         static BOOL fixme_written = FALSE;
 2100 
 2101         get_performance_info( &spi );
 2102         len = sizeof(spi);
 2103         if (size >= len)
 2104         {
 2105             if (!info) ret = STATUS_ACCESS_VIOLATION;
 2106             else memcpy( info, &spi, len);
 2107         }
 2108         else ret = STATUS_INFO_LENGTH_MISMATCH;
 2109         if(!fixme_written) {
 2110             FIXME("info_class SYSTEM_PERFORMANCE_INFORMATION\n");
 2111             fixme_written = TRUE;
 2112         }
 2113         break;
 2114     }
 2115 
 2116     case SystemTimeOfDayInformation:
 2117     {
 2118         struct tm *tm;
 2119         time_t now;
 2120         SYSTEM_TIMEOFDAY_INFORMATION sti = {{{ 0 }}};
 2121 
 2122         sti.BootTime.QuadPart = server_start_time;
 2123         now = time( NULL );
 2124         tm = gmtime( &now );
 2125         sti.TimeZoneBias.QuadPart = mktime( tm ) - now;
 2126         tm = localtime( &now );
 2127         if (tm->tm_isdst) sti.TimeZoneBias.QuadPart -= 3600;
 2128         sti.TimeZoneBias.QuadPart *= TICKSPERSEC;
 2129         NtQuerySystemTime( &sti.SystemTime );
 2130 
 2131         if (size <= sizeof(sti))
 2132         {
 2133             len = size;
 2134             if (!info) ret = STATUS_ACCESS_VIOLATION;
 2135             else memcpy( info, &sti, size);
 2136         }
 2137         else ret = STATUS_INFO_LENGTH_MISMATCH;
 2138         break;
 2139     }
 2140 
 2141     case SystemProcessInformation:
 2142     {
 2143         unsigned int process_count, i, j;
 2144         char *buffer = NULL;
 2145         unsigned int pos = 0;
 2146 
 2147         if (size && !(buffer = malloc( size )))
 2148         {
 2149             ret = STATUS_NO_MEMORY;
 2150             break;
 2151         }
 2152 
 2153         SERVER_START_REQ( list_processes )
 2154         {
 2155             wine_server_set_reply( req, buffer, size );
 2156             ret = wine_server_call( req );
 2157             len = reply->info_size;
 2158             process_count = reply->process_count;
 2159         }
 2160         SERVER_END_REQ;
 2161 
 2162         if (ret)
 2163         {
 2164             free( buffer );
 2165             break;
 2166         }
 2167 
 2168         len = 0;
 2169 
 2170         for (i = 0; i < process_count; i++)
 2171         {
 2172             SYSTEM_PROCESS_INFORMATION *nt_process = (SYSTEM_PROCESS_INFORMATION *)((char *)info + len);
 2173             const struct process_info *server_process;
 2174             const WCHAR *server_name, *file_part;
 2175             ULONG proc_len;
 2176             ULONG name_len = 0;
 2177 
 2178             pos = (pos + 7) & ~7;
 2179             server_process = (const struct process_info *)(buffer + pos);
 2180             pos += sizeof(*server_process);
 2181 
 2182             server_name = (const WCHAR *)(buffer + pos);
 2183             file_part = server_name + (server_process->name_len / sizeof(WCHAR));
 2184             pos += server_process->name_len;
 2185             while (file_part > server_name && file_part[-1] != '\\')
 2186             {
 2187                 file_part--;
 2188                 name_len++;
 2189             }
 2190 
 2191             proc_len = sizeof(*nt_process) + server_process->thread_count * sizeof(SYSTEM_THREAD_INFORMATION)
 2192                          + (name_len + 1) * sizeof(WCHAR);
 2193             len += proc_len;
 2194 
 2195             if (len <= size)
 2196             {
 2197                 memset(nt_process, 0, sizeof(*nt_process));
 2198                 if (i < process_count - 1)
 2199                     nt_process->NextEntryOffset = proc_len;
 2200                 nt_process->CreationTime.QuadPart = server_process->start_time;
 2201                 nt_process->dwThreadCount = server_process->thread_count;
 2202                 nt_process->dwBasePriority = server_process->priority;
 2203                 nt_process->UniqueProcessId = UlongToHandle(server_process->pid);
 2204                 nt_process->ParentProcessId = UlongToHandle(server_process->parent_pid);
 2205                 nt_process->HandleCount = server_process->handle_count;
 2206                 get_thread_times( server_process->unix_pid, -1, &nt_process->KernelTime, &nt_process->UserTime );
 2207                 fill_vm_counters( &nt_process->vmCounters, server_process->unix_pid );
 2208             }
 2209 
 2210             pos = (pos + 7) & ~7;
 2211             for (j = 0; j < server_process->thread_count; j++)
 2212             {
 2213                 const struct thread_info *server_thread = (const struct thread_info *)(buffer + pos);
 2214 
 2215                 if (len <= size)
 2216                 {
 2217                     nt_process->ti[j].CreateTime.QuadPart = server_thread->start_time;
 2218                     nt_process->ti[j].ClientId.UniqueProcess = UlongToHandle(server_process->pid);
 2219                     nt_process->ti[j].ClientId.UniqueThread = UlongToHandle(server_thread->tid);
 2220                     nt_process->ti[j].dwCurrentPriority = server_thread->current_priority;
 2221                     nt_process->ti[j].dwBasePriority = server_thread->base_priority;
 2222                     get_thread_times( server_process->unix_pid, server_thread->unix_tid,
 2223                                       &nt_process->ti[j].KernelTime, &nt_process->ti[j].UserTime );
 2224                 }
 2225 
 2226                 pos += sizeof(*server_thread);
 2227             }
 2228 
 2229             if (len <= size)
 2230             {
 2231                 nt_process->ProcessName.Buffer = (WCHAR *)&nt_process->ti[server_process->thread_count];
 2232                 nt_process->ProcessName.Length = name_len * sizeof(WCHAR);
 2233                 nt_process->ProcessName.MaximumLength = (name_len + 1) * sizeof(WCHAR);
 2234                 memcpy(nt_process->ProcessName.Buffer, file_part, name_len * sizeof(WCHAR));
 2235                 nt_process->ProcessName.Buffer[name_len] = 0;
 2236             }
 2237         }
 2238 
 2239         if (len > size) ret = STATUS_INFO_LENGTH_MISMATCH;
 2240         free( buffer );
 2241         break;
 2242     }
 2243 
 2244     case SystemProcessorPerformanceInformation:
 2245     {
 2246         SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *sppi = NULL;
 2247         unsigned int cpus = 0;
 2248         int out_cpus = size / sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
 2249 
 2250         if (out_cpus == 0)
 2251         {
 2252             len = 0;
 2253             ret = STATUS_INFO_LENGTH_MISMATCH;
 2254             break;
 2255         }
 2256         if (!(sppi = calloc( out_cpus, sizeof(*sppi) )))
 2257         {
 2258             ret = STATUS_NO_MEMORY;
 2259             break;
 2260         }
 2261         else
 2262 #ifdef __APPLE__
 2263         {
 2264             processor_cpu_load_info_data_t *pinfo;
 2265             mach_msg_type_number_t info_count;
 2266 
 2267             if (host_processor_info( mach_host_self (),
 2268                                      PROCESSOR_CPU_LOAD_INFO,
 2269                                      &cpus,
 2270                                      (processor_info_array_t*)&pinfo,
 2271                                      &info_count) == 0)
 2272             {
 2273                 int i;
 2274                 cpus = min(cpus,out_cpus);
 2275                 for (i = 0; i < cpus; i++)
 2276                 {
 2277                     sppi[i].IdleTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_IDLE];
 2278                     sppi[i].KernelTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_SYSTEM];
 2279                     sppi[i].UserTime.QuadPart = pinfo[i].cpu_ticks[CPU_STATE_USER];
 2280                 }
 2281                 vm_deallocate (mach_task_self (), (vm_address_t) pinfo, info_count * sizeof(natural_t));
 2282             }
 2283         }
 2284 #else
 2285         {
 2286             FILE *cpuinfo = fopen("/proc/stat", "r");
 2287             if (cpuinfo)
 2288             {
 2289                 unsigned long clk_tck = sysconf(_SC_CLK_TCK);
 2290                 unsigned long usr,nice,sys,idle,remainder[8];
 2291                 int i, count, id;
 2292                 char name[32];
 2293                 char line[255];
 2294 
 2295                 /* first line is combined usage */
 2296                 while (fgets(line,255,cpuinfo))
 2297                 {
 2298                     count = sscanf(line, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
 2299                                    name, &usr, &nice, &sys, &idle,
 2300                                    &remainder[0], &remainder[1], &remainder[2], &remainder[3],
 2301                                    &remainder[4], &remainder[5], &remainder[6], &remainder[7]);
 2302 
 2303                     if (count < 5 || strncmp( name, "cpu", 3 )) break;
 2304                     for (i = 0; i + 5 < count; ++i) sys += remainder[i];
 2305                     sys += idle;
 2306                     usr += nice;
 2307                     id = atoi( name + 3 ) + 1;
 2308                     if (id > out_cpus) break;
 2309                     if (id > cpus) cpus = id;
 2310                     sppi[id-1].IdleTime.QuadPart   = (ULONGLONG)idle * 10000000 / clk_tck;
 2311                     sppi[id-1].KernelTime.QuadPart = (ULONGLONG)sys * 10000000 / clk_tck;
 2312                     sppi[id-1].UserTime.QuadPart   = (ULONGLONG)usr * 10000000 / clk_tck;
 2313                 }
 2314                 fclose(cpuinfo);
 2315             }
 2316         }
 2317 #endif
 2318         if (cpus == 0)
 2319         {
 2320             static int i = 1;
 2321             unsigned int n;
 2322             cpus = min(NtCurrentTeb()->Peb->NumberOfProcessors, out_cpus);
 2323             FIXME("stub info_class SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION\n");
 2324             /* many programs expect these values to change so fake change */
 2325             for (n = 0; n < cpus; n++)
 2326             {
 2327                 sppi[n].KernelTime.QuadPart = 1 * i;
 2328                 sppi[n].UserTime.QuadPart   = 2 * i;
 2329                 sppi[n].IdleTime.QuadPart   = 3 * i;
 2330             }
 2331             i++;
 2332         }
 2333 
 2334         len = sizeof(*sppi) * cpus;
 2335         if (size >= len)
 2336         {
 2337             if (!info) ret = STATUS_ACCESS_VIOLATION;
 2338             else memcpy( info, sppi, len);
 2339         }
 2340         else ret = STATUS_INFO_LENGTH_MISMATCH;
 2341 
 2342         free( sppi );
 2343         break;
 2344     }
 2345 
 2346     case SystemModuleInformation:
 2347     {
 2348         /* FIXME: return some fake info for now */
 2349         static const char *fake_modules[] =
 2350         {
 2351             "\\SystemRoot\\system32\\ntoskrnl.exe",
 2352             "\\SystemRoot\\system32\\hal.dll",
 2353             "\\SystemRoot\\system32\\drivers\\mountmgr.sys"
 2354         };
 2355 
 2356         ULONG i;
 2357         SYSTEM_MODULE_INFORMATION *smi = info;
 2358 
 2359         len = offsetof( SYSTEM_MODULE_INFORMATION, Modules[ARRAY_SIZE(fake_modules)] );
 2360         if (len <= size)
 2361         {
 2362             memset( smi, 0, len );
 2363             for (i = 0; i < ARRAY_SIZE(fake_modules); i++)
 2364             {
 2365                 SYSTEM_MODULE *sm = &smi->Modules[i];
 2366                 sm->ImageBaseAddress = (char *)0x10000000 + 0x200000 * i;
 2367                 sm->ImageSize = 0x200000;
 2368                 sm->LoadOrderIndex = i;
 2369                 sm->LoadCount = 1;
 2370                 strcpy( (char *)sm->Name, fake_modules[i] );
 2371                 sm->NameOffset = strrchr( fake_modules[i], '\\' ) - fake_modules[i] + 1;
 2372             }
 2373             smi->ModulesCount = i;
 2374         }
 2375         else ret = STATUS_INFO_LENGTH_MISMATCH;
 2376 
 2377         break;
 2378     }
 2379 
 2380     case SystemModuleInformationEx:
 2381     {
 2382         /* FIXME: return some fake info for now */
 2383         static const char *fake_modules[] =
 2384         {
 2385             "\\SystemRoot\\system32\\ntoskrnl.exe",
 2386             "\\SystemRoot\\system32\\hal.dll",
 2387             "\\SystemRoot\\system32\\drivers\\mountmgr.sys"
 2388         };
 2389 
 2390         ULONG i;
 2391         RTL_PROCESS_MODULE_INFORMATION_EX *module_info = info;
 2392 
 2393         len = sizeof(*module_info) * ARRAY_SIZE(fake_modules) + sizeof(module_info->NextOffset);
 2394         if (len <= size)
 2395         {
 2396             memset( info, 0, len );
 2397             for (i = 0; i < ARRAY_SIZE(fake_modules); i++)
 2398             {
 2399                 SYSTEM_MODULE *sm = &module_info[i].BaseInfo;
 2400                 sm->ImageBaseAddress = (char *)0x10000000 + 0x200000 * i;
 2401                 sm->ImageSize = 0x200000;
 2402                 sm->LoadOrderIndex = i;
 2403                 sm->LoadCount = 1;
 2404                 strcpy( (char *)sm->Name, fake_modules[i] );
 2405                 sm->NameOffset = strrchr( fake_modules[i], '\\' ) - fake_modules[i] + 1;
 2406                 module_info[i].NextOffset = sizeof(*module_info);
 2407             }
 2408             module_info[ARRAY_SIZE(fake_modules)].NextOffset = 0;
 2409         }
 2410         else ret = STATUS_INFO_LENGTH_MISMATCH;
 2411 
 2412         break;
 2413     }
 2414 
 2415     case SystemHandleInformation:
 2416     {
 2417         struct handle_info *handle_info;
 2418         DWORD i, num_handles;
 2419 
 2420         if (size < sizeof(SYSTEM_HANDLE_INFORMATION))
 2421         {
 2422             ret = STATUS_INFO_LENGTH_MISMATCH;
 2423             break;
 2424         }
 2425 
 2426         if (!info)
 2427         {
 2428             ret = STATUS_ACCESS_VIOLATION;
 2429             break;
 2430         }
 2431 
 2432         num_handles = (size - FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle )) / sizeof(SYSTEM_HANDLE_ENTRY);
 2433         if (!(handle_info = malloc( sizeof(*handle_info) * num_handles ))) return STATUS_NO_MEMORY;
 2434 
 2435         SERVER_START_REQ( get_system_handles )
 2436         {
 2437             wine_server_set_reply( req, handle_info, sizeof(*handle_info) * num_handles );
 2438             if (!(ret = wine_server_call( req )))
 2439             {
 2440                 SYSTEM_HANDLE_INFORMATION *shi = info;
 2441                 shi->Count = wine_server_reply_size( req ) / sizeof(*handle_info);
 2442                 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle[shi->Count] );
 2443                 for (i = 0; i < shi->Count; i++)
 2444                 {
 2445                     memset( &shi->Handle[i], 0, sizeof(shi->Handle[i]) );
 2446                     shi->Handle[i].OwnerPid     = handle_info[i].owner;
 2447                     shi->Handle[i].HandleValue  = handle_info[i].handle;
 2448                     shi->Handle[i].AccessMask   = handle_info[i].access;
 2449                     /* FIXME: Fill out ObjectType, HandleFlags, ObjectPointer */
 2450                 }
 2451             }
 2452             else if (ret == STATUS_BUFFER_TOO_SMALL)
 2453             {
 2454                 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION, Handle[reply->count] );
 2455                 ret = STATUS_INFO_LENGTH_MISMATCH;
 2456             }
 2457         }
 2458         SERVER_END_REQ;
 2459 
 2460         free( handle_info );
 2461         break;
 2462     }
 2463 
 2464     case SystemExtendedHandleInformation:
 2465     {
 2466         struct handle_info *handle_info;
 2467         DWORD i, num_handles;
 2468 
 2469         if (size < sizeof(SYSTEM_HANDLE_INFORMATION_EX))
 2470         {
 2471             ret = STATUS_INFO_LENGTH_MISMATCH;
 2472             break;
 2473         }
 2474 
 2475         if (!info)
 2476         {
 2477             ret = STATUS_ACCESS_VIOLATION;
 2478             break;
 2479         }
 2480 
 2481         num_handles = (size - FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handles ))
 2482                       / sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX);
 2483         if (!(handle_info = malloc( sizeof(*handle_info) * num_handles ))) return STATUS_NO_MEMORY;
 2484 
 2485         SERVER_START_REQ( get_system_handles )
 2486         {
 2487             wine_server_set_reply( req, handle_info, sizeof(*handle_info) * num_handles );
 2488             if (!(ret = wine_server_call( req )))
 2489             {
 2490                 SYSTEM_HANDLE_INFORMATION_EX *shi = info;
 2491                 shi->NumberOfHandles = wine_server_reply_size( req ) / sizeof(*handle_info);
 2492                 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handles[shi->NumberOfHandles] );
 2493                 for (i = 0; i < shi->NumberOfHandles; i++)
 2494                 {
 2495                     memset( &shi->Handles[i], 0, sizeof(shi->Handles[i]) );
 2496                     shi->Handles[i].UniqueProcessId = handle_info[i].owner;
 2497                     shi->Handles[i].HandleValue     = handle_info[i].handle;
 2498                     shi->Handles[i].GrantedAccess   = handle_info[i].access;
 2499                     /* FIXME: Fill out Object, HandleAttributes, ObjectTypeIndex */
 2500                 }
 2501             }
 2502             else if (ret == STATUS_BUFFER_TOO_SMALL)
 2503             {
 2504                 len = FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION_EX, Handles[reply->count] );
 2505                 ret = STATUS_INFO_LENGTH_MISMATCH;
 2506             }
 2507         }
 2508         SERVER_END_REQ;
 2509 
 2510         free( handle_info );
 2511         break;
 2512     }
 2513 
 2514     case SystemCacheInformation:
 2515     {
 2516         SYSTEM_CACHE_INFORMATION sci = { 0 };
 2517 
 2518         len = sizeof(sci);
 2519         if (size >= len)
 2520         {
 2521             if (!info) ret = STATUS_ACCESS_VIOLATION;
 2522             else memcpy( info, &sci, len);
 2523         }
 2524         else ret = STATUS_INFO_LENGTH_MISMATCH;
 2525         FIXME("info_class SYSTEM_CACHE_INFORMATION\n");
 2526         break;
 2527     }
 2528 
 2529     case SystemInterruptInformation:
 2530     {
 2531         len = NtCurrentTeb()->Peb->NumberOfProcessors * sizeof(SYSTEM_INTERRUPT_INFORMATION);
 2532         if (size >= len)
 2533         {
 2534             if (!info) ret = STATUS_ACCESS_VIOLATION;
 2535             else
 2536             {
 2537 #ifdef HAVE_GETRANDOM
 2538                 int ret;
 2539                 do
 2540                 {
 2541                     ret = getrandom( info, len, 0 );
 2542                 }
 2543                 while (ret == -1 && errno == EINTR);
 2544 #else
 2545                 int fd = open( "/dev/urandom", O_RDONLY );
 2546                 if (fd != -1)
 2547                 {
 2548                     int ret;
 2549                     do
 2550                     {
 2551                         ret = read( fd, info, len );
 2552                     }
 2553                     while (ret == -1 && errno == EINTR);
 2554                     close( fd );
 2555                 }
 2556                 else WARN( "can't open /dev/urandom\n" );
 2557 #endif
 2558             }
 2559         }
 2560         else ret = STATUS_INFO_LENGTH_MISMATCH;
 2561         break;
 2562     }
 2563 
 2564     case SystemTimeAdjustmentInformation:
 2565     {
 2566         SYSTEM_TIME_ADJUSTMENT_QUERY query = { 156250, 156250, TRUE };
 2567 
 2568         len = sizeof(query);
 2569         if (size == len)
 2570         {
 2571             if (!info) ret = STATUS_ACCESS_VIOLATION;
 2572             else memcpy( info, &query, len );
 2573         }
 2574         else ret = STATUS_INFO_LENGTH_MISMATCH;
 2575         break;
 2576     }
 2577 
 2578     case SystemKernelDebuggerInformation:
 2579     {
 2580         SYSTEM_KERNEL_DEBUGGER_INFORMATION skdi;
 2581 
 2582         skdi.DebuggerEnabled = FALSE;
 2583         skdi.DebuggerNotPresent = TRUE;
 2584         len = sizeof(skdi);
 2585         if (size >= len)
 2586         {
 2587             if (!info) ret = STATUS_ACCESS_VIOLATION;
 2588             else memcpy( info, &skdi, len);
 2589         }
 2590         else ret = STATUS_INFO_LENGTH_MISMATCH;
 2591         break;
 2592     }
 2593 
 2594     case SystemRegistryQuotaInformation:
 2595     {
 2596         /* Something to do with the size of the registry             *
 2597          * Since we don't have a size limitation, fake it            *
 2598          * This is almost certainly wrong.                           *
 2599          * This sets each of the three words in the struct to 32 MB, *
 2600          * which is enough to make the IE 5 installer happy.         */
 2601         SYSTEM_REGISTRY_QUOTA_INFORMATION srqi;
 2602 
 2603         srqi.RegistryQuotaAllowed = 0x2000000;
 2604         srqi.RegistryQuotaUsed = 0x200000;
 2605         srqi.Reserved1 = (void*)0x200000;
 2606         len = sizeof(srqi);
 2607 
 2608         if (size >= len)
 2609         {
 2610             if (!info) ret = STATUS_ACCESS_VIOLATION;
 2611             else
 2612             {
 2613                 FIXME("SystemRegistryQuotaInformation: faking max registry size of 32 MB\n");
 2614                 memcpy( info, &srqi, len);
 2615             }
 2616         }
 2617         else ret = STATUS_INFO_LENGTH_MISMATCH;
 2618         break;
 2619     }
 2620 
 2621     case SystemTimeZoneInformation:
 2622     {
 2623         RTL_DYNAMIC_TIME_ZONE_INFORMATION tz;
 2624 
 2625         get_timezone_info( &tz );
 2626         len = sizeof(RTL_TIME_ZONE_INFORMATION);
 2627         if (size >= len)
 2628         {
 2629             if (!info) ret = STATUS_ACCESS_VIOLATION;
 2630             else memcpy( info, &tz, len);
 2631         }
 2632         else ret = STATUS_INFO_LENGTH_MISMATCH;
 2633         break;
 2634     }
 2635 
 2636     case SystemLogicalProcessorInformation:
 2637     {
 2638         SYSTEM_LOGICAL_PROCESSOR_INFORMATION *buf;
 2639 
 2640         /* Each logical processor may use up to 7 entries in returned table:
 2641          * core, numa node, package, L1i, L1d, L2, L3 */
 2642         len = 7 * NtCurrentTeb()->Peb->NumberOfProcessors;
 2643         buf = malloc( len * sizeof(*buf) );
 2644         if (!buf)
 2645         {
 2646             ret = STATUS_NO_MEMORY;
 2647             break;
 2648         }
 2649         ret = create_logical_proc_info(&buf, NULL, &len, RelationAll);
 2650         if (!ret)
 2651         {
 2652             if (size >= len)
 2653             {
 2654                 if (!info) ret = STATUS_ACCESS_VIOLATION;
 2655                 else memcpy( info, buf, len);
 2656             }
 2657             else ret = STATUS_INFO_LENGTH_MISMATCH;
 2658         }
 2659         free( buf );
 2660         break;
 2661     }
 2662 
 2663     case SystemRecommendedSharedDataAlignment:
 2664     {
 2665         len = sizeof(DWORD);
 2666         if (size >= len)
 2667         {
 2668             if (!info) ret = STATUS_ACCESS_VIOLATION;
 2669             else
 2670             {
 2671 #ifdef __arm__
 2672                 *((DWORD *)info) = 32;
 2673 #else
 2674                 *((DWORD *)info) = 64;
 2675 #endif
 2676             }
 2677         }
 2678         else ret = STATUS_INFO_LENGTH_MISMATCH;
 2679         break;
 2680     }
 2681 
 2682     case SystemFirmwareTableInformation:
 2683     {
 2684         SYSTEM_FIRMWARE_TABLE_INFORMATION *sfti = info;
 2685         len = FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION, TableBuffer);
 2686         if (size < len)
 2687         {
 2688             ret = STATUS_INFO_LENGTH_MISMATCH;
 2689             break;
 2690         }
 2691 
 2692         switch (sfti->Action)
 2693         {
 2694         case SystemFirmwareTable_Get:
 2695             ret = get_firmware_info(sfti, size, &len);
 2696             break;
 2697         default:
 2698             len = 0;
 2699             ret = STATUS_NOT_IMPLEMENTED;
 2700             FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION action %d\n", sfti->Action);
 2701         }
 2702         break;
 2703     }
 2704 
 2705     case SystemDynamicTimeZoneInformation:
 2706     {
 2707         RTL_DYNAMIC_TIME_ZONE_INFORMATION tz;
 2708 
 2709         get_timezone_info( &tz );
 2710         len = sizeof(tz);
 2711         if (size >= len)
 2712         {
 2713             if (!info) ret = STATUS_ACCESS_VIOLATION;
 2714             else memcpy( info, &tz, len);
 2715         }
 2716         else ret = STATUS_INFO_LENGTH_MISMATCH;
 2717         break;
 2718     }
 2719 
 2720     case SystemExtendedProcessInformation:
 2721         FIXME("SystemExtendedProcessInformation, size %u, info %p, stub!\n", size, info);
 2722         memset( info, 0, size );
 2723         ret = STATUS_SUCCESS;
 2724         break;
 2725 
 2726     default:
 2727     FIXME( "(0x%08x,%p,0x%08x,%p) stub\n", class, info, size, ret_size );
 2728 
 2729         /* Several Information Classes are not implemented on Windows and return 2 different values
 2730          * STATUS_NOT_IMPLEMENTED or STATUS_INVALID_INFO_CLASS
 2731          * in 95% of the cases it's STATUS_INVALID_INFO_CLASS, so use this as the default
 2732          */
 2733         ret = STATUS_INVALID_INFO_CLASS;
 2734     }
 2735 
 2736     if (ret_size) *ret_size = len;
 2737     return ret;
 2738 }
 2739 
 2740 
 2741 /******************************************************************************
 2742  *              NtQuerySystemInformationEx  (NTDLL.@)
 2743  */
 2744 NTSTATUS WINAPI NtQuerySystemInformationEx( SYSTEM_INFORMATION_CLASS class,
 2745                                             void *query, ULONG query_len,
 2746                                             void *info, ULONG size, ULONG *ret_size )
 2747 {
 2748     ULONG len = 0;
 2749     NTSTATUS ret = STATUS_NOT_IMPLEMENTED;
 2750 
 2751     TRACE( "(0x%08x,%p,%u,%p,%u,%p) stub\n", class, query, query_len, info, size, ret_size );
 2752 
 2753     switch (class)
 2754     {
 2755     case SystemLogicalProcessorInformationEx:
 2756     {
 2757         SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buf;
 2758 
 2759         if (!query || query_len < sizeof(DWORD))
 2760         {
 2761             ret = STATUS_INVALID_PARAMETER;
 2762             break;
 2763         }
 2764 
 2765         len = 3 * sizeof(*buf);
 2766         if (!(buf = malloc( len )))
 2767         {
 2768             ret = STATUS_NO_MEMORY;
 2769             break;
 2770         }
 2771         ret = create_logical_proc_info(NULL, &buf, &len, *(DWORD *)query);
 2772         if (!ret)
 2773         {
 2774             if (size >= len)
 2775             {
 2776                 if (!info) ret = STATUS_ACCESS_VIOLATION;
 2777                 else memcpy(info, buf, len);
 2778             }
 2779             else ret = STATUS_INFO_LENGTH_MISMATCH;
 2780         }
 2781         free( buf );
 2782         break;
 2783     }
 2784 
 2785     default:
 2786         FIXME( "(0x%08x,%p,%u,%p,%u,%p) stub\n", class, query, query_len, info, size, ret_size );
 2787         break;
 2788     }
 2789     if (ret_size) *ret_size = len;
 2790     return ret;
 2791 }
 2792 
 2793 
 2794 /******************************************************************************
 2795  *              NtSetSystemInformation  (NTDLL.@)
 2796  */
 2797 NTSTATUS WINAPI NtSetSystemInformation( SYSTEM_INFORMATION_CLASS class, void *info, ULONG length )
 2798 {
 2799     FIXME( "(0x%08x,%p,0x%08x) stub\n", class, info, length );
 2800     return STATUS_SUCCESS;
 2801 }
 2802 
 2803 
 2804 /******************************************************************************
 2805  *              NtQuerySystemEnvironmentValue  (NTDLL.@)
 2806  */
 2807 NTSTATUS WINAPI NtQuerySystemEnvironmentValue( UNICODE_STRING *name, WCHAR *buffer, ULONG length,
 2808                                                ULONG *retlen )
 2809 {
 2810     FIXME( "(%s, %p, %u, %p), stub\n", debugstr_us(name), buffer, length, retlen );
 2811     return STATUS_NOT_IMPLEMENTED;
 2812 }
 2813 
 2814 
 2815 /******************************************************************************
 2816  *              NtQuerySystemEnvironmentValueEx  (NTDLL.@)
 2817  */
 2818 NTSTATUS WINAPI NtQuerySystemEnvironmentValueEx( UNICODE_STRING *name, GUID *vendor, void *buffer,
 2819                                                  ULONG *retlen, ULONG *attrib )
 2820 {
 2821     FIXME( "(%s, %s, %p, %p, %p), stub\n", debugstr_us(name),
 2822            debugstr_guid(vendor), buffer, retlen, attrib );
 2823     return STATUS_NOT_IMPLEMENTED;
 2824 }
 2825 
 2826 
 2827 /******************************************************************************
 2828  *              NtSystemDebugControl  (NTDLL.@)
 2829  */
 2830 NTSTATUS WINAPI NtSystemDebugControl( SYSDBG_COMMAND command, void *in_buff, ULONG in_len,
 2831                                       void *out_buff, ULONG out_len, ULONG *retlen )
 2832 {
 2833     FIXME( "(%d, %p, %d, %p, %d, %p), stub\n", command, in_buff, in_len, out_buff, out_len, retlen );
 2834     return STATUS_NOT_IMPLEMENTED;
 2835 }
 2836 
 2837 
 2838 /******************************************************************************
 2839  *              NtShutdownSystem  (NTDLL.@)
 2840  */
 2841 NTSTATUS WINAPI NtShutdownSystem( SHUTDOWN_ACTION action )
 2842 {
 2843     FIXME( "%d\n", action );
 2844     return STATUS_SUCCESS;
 2845 }
 2846 
 2847 
 2848 #ifdef linux
 2849 
 2850 /* Fallback using /proc/cpuinfo for Linux systems without cpufreq. For
 2851  * most distributions on recent enough hardware, this is only likely to
 2852  * happen while running in virtualized environments such as QEMU. */
 2853 static ULONG mhz_from_cpuinfo(void)
 2854 {
 2855     char line[512];
 2856     char *s, *value;
 2857     double cmz = 0;
 2858     FILE *f = fopen("/proc/cpuinfo", "r");
 2859     if(f)
 2860     {
 2861         while (fgets(line, sizeof(line), f) != NULL)
 2862         {
 2863             if (!(value = strchr(line,':'))) continue;
 2864             s = value - 1;
 2865             while ((s >= line) && (*s == ' ' || *s == '\t')) s--;
 2866             s[1] = 0;
 2867             value++;
 2868             if (!strcmp( line, "cpu MHz" ))
 2869             {
 2870                 sscanf(value, " %lf", &cmz);
 2871                 break;
 2872             }
 2873         }
 2874         fclose( f );
 2875     }
 2876     return cmz;
 2877 }
 2878 
 2879 static const char * get_sys_str(const char *path, char *s)
 2880 {
 2881     FILE *f = fopen(path, "r");
 2882     const char *ret = NULL;
 2883 
 2884     if (f)
 2885     {
 2886         if (fgets(s, 16, f)) ret = s;
 2887         fclose(f);
 2888     }
 2889     return ret;
 2890 }
 2891 
 2892 static int get_sys_int(const char *path, int def)
 2893 {
 2894     char s[16];
 2895     return get_sys_str(path, s) ? atoi(s) : def;
 2896 }
 2897 
 2898 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
 2899 {
 2900     char s[16], path[64];
 2901     unsigned int i = 0;
 2902     LONG64 voltage; /* microvolts */
 2903 
 2904     bs->AcOnLine = get_sys_int("/sys/class/power_supply/AC/online", 1);
 2905 
 2906     for (;;)
 2907     {
 2908         sprintf(path, "/sys/class/power_supply/BAT%u/status", i);
 2909         if (!get_sys_str(path, s)) break;
 2910         bs->Charging |= (strcmp(s, "Charging\n") == 0);
 2911         bs->Discharging |= (strcmp(s, "Discharging\n") == 0);
 2912         bs->BatteryPresent = TRUE;
 2913         i++;
 2914     }
 2915 
 2916     if (bs->BatteryPresent)
 2917     {
 2918         voltage = get_sys_int("/sys/class/power_supply/BAT0/voltage_now", 0);
 2919         bs->MaxCapacity = get_sys_int("/sys/class/power_supply/BAT0/charge_full", 0) * voltage / 1e9;
 2920         bs->RemainingCapacity = get_sys_int("/sys/class/power_supply/BAT0/charge_now", 0) * voltage / 1e9;
 2921         bs->Rate = -get_sys_int("/sys/class/power_supply/BAT0/current_now", 0) * voltage / 1e9;
 2922         if (!bs->Charging && (LONG)bs->Rate < 0)
 2923             bs->EstimatedTime = 3600 * bs->RemainingCapacity / -(LONG)bs->Rate;
 2924         else
 2925             bs->EstimatedTime = ~0u;
 2926     }
 2927 
 2928     return STATUS_SUCCESS;
 2929 }
 2930 
 2931 #elif defined(HAVE_IOKIT_IOKITLIB_H)
 2932 
 2933 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
 2934 {
 2935     CFArrayRef batteries;
 2936     CFDictionaryRef battery;
 2937     CFNumberRef prop;
 2938     uint32_t value, voltage;
 2939     CFTimeInterval remain;
 2940 
 2941     if (IOPMCopyBatteryInfo( kIOMasterPortDefault, &batteries ) != kIOReturnSuccess)
 2942         return STATUS_ACCESS_DENIED;
 2943 
 2944     if (CFArrayGetCount( batteries ) == 0)
 2945     {
 2946         /* Just assume we're on AC with no battery. */
 2947         bs->AcOnLine = TRUE;
 2948         return STATUS_SUCCESS;
 2949     }
 2950     /* Just use the first battery. */
 2951     battery = CFArrayGetValueAtIndex( batteries, 0 );
 2952 
 2953     prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryFlagsKey) );
 2954     CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
 2955 
 2956     if (value & kIOBatteryInstalled)
 2957         bs->BatteryPresent = TRUE;
 2958     else
 2959         /* Since we are executing code, we must have AC power. */
 2960         bs->AcOnLine = TRUE;
 2961     if (value & kIOBatteryChargerConnect)
 2962     {
 2963         bs->AcOnLine = TRUE;
 2964         if (value & kIOBatteryCharge)
 2965             bs->Charging = TRUE;
 2966     }
 2967     else
 2968         bs->Discharging = TRUE;
 2969 
 2970     /* We'll need the voltage to be able to interpret the other values. */
 2971     prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryVoltageKey) );
 2972     CFNumberGetValue( prop, kCFNumberSInt32Type, &voltage );
 2973 
 2974     prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryCapacityKey) );
 2975     CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
 2976     bs->MaxCapacity = value * voltage;
 2977     /* Apple uses "estimated time < 10:00" and "22%" for these, but we'll follow
 2978      * Windows for now (5% and 33%). */
 2979     bs->DefaultAlert1 = bs->MaxCapacity / 20;
 2980     bs->DefaultAlert2 = bs->MaxCapacity / 3;
 2981 
 2982     prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryCurrentChargeKey) );
 2983     CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
 2984     bs->RemainingCapacity = value * voltage;
 2985 
 2986     prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryAmperageKey) );
 2987     CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
 2988     bs->Rate = value * voltage;
 2989 
 2990     remain = IOPSGetTimeRemainingEstimate();
 2991     if (remain != kIOPSTimeRemainingUnknown && remain != kIOPSTimeRemainingUnlimited)
 2992         bs->EstimatedTime = (ULONG)remain;
 2993 
 2994     CFRelease( batteries );
 2995     return STATUS_SUCCESS;
 2996 }
 2997 
 2998 #else
 2999 
 3000 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
 3001 {
 3002     FIXME("SystemBatteryState not implemented on this platform\n");
 3003     return STATUS_NOT_IMPLEMENTED;
 3004 }
 3005 
 3006 #endif
 3007 
 3008 /******************************************************************************
 3009  *              NtPowerInformation  (NTDLL.@)
 3010  */
 3011 NTSTATUS WINAPI NtPowerInformation( POWER_INFORMATION_LEVEL level, void *input, ULONG in_size,
 3012                                     void *output, ULONG out_size )
 3013 {
 3014     TRACE( "(%d,%p,%d,%p,%d)\n", level, input, in_size, output, out_size );
 3015     switch (level)
 3016     {
 3017     case SystemPowerCapabilities:
 3018     {
 3019         PSYSTEM_POWER_CAPABILITIES PowerCaps = output;
 3020         FIXME("semi-stub: SystemPowerCapabilities\n");
 3021         if (out_size < sizeof(SYSTEM_POWER_CAPABILITIES)) return STATUS_BUFFER_TOO_SMALL;
 3022         /* FIXME: These values are based off a native XP desktop, should probably use APM/ACPI to get the 'real' values */
 3023         PowerCaps->PowerButtonPresent = TRUE;
 3024         PowerCaps->SleepButtonPresent = FALSE;
 3025         PowerCaps->LidPresent = FALSE;
 3026         PowerCaps->SystemS1 = TRUE;
 3027         PowerCaps->SystemS2 = FALSE;
 3028         PowerCaps->SystemS3 = FALSE;
 3029         PowerCaps->SystemS4 = TRUE;
 3030         PowerCaps->SystemS5 = TRUE;
 3031         PowerCaps->HiberFilePresent = TRUE;
 3032         PowerCaps->FullWake = TRUE;
 3033         PowerCaps->VideoDimPresent = FALSE;
 3034         PowerCaps->ApmPresent = FALSE;
 3035         PowerCaps->UpsPresent = FALSE;
 3036         PowerCaps->ThermalControl = FALSE;
 3037         PowerCaps->ProcessorThrottle = FALSE;
 3038         PowerCaps->ProcessorMinThrottle = 100;
 3039         PowerCaps->ProcessorMaxThrottle = 100;
 3040         PowerCaps->DiskSpinDown = TRUE;
 3041         PowerCaps->SystemBatteriesPresent = FALSE;
 3042         PowerCaps->BatteriesAreShortTerm = FALSE;
 3043         PowerCaps->BatteryScale[0].Granularity = 0;
 3044         PowerCaps->BatteryScale[0].Capacity = 0;
 3045         PowerCaps->BatteryScale[1].Granularity = 0;
 3046         PowerCaps->BatteryScale[1].Capacity = 0;
 3047         PowerCaps->BatteryScale[2].Granularity = 0;
 3048         PowerCaps->BatteryScale[2].Capacity = 0;
 3049         PowerCaps->AcOnLineWake = PowerSystemUnspecified;
 3050         PowerCaps->SoftLidWake = PowerSystemUnspecified;
 3051         PowerCaps->RtcWake = PowerSystemSleeping1;
 3052         PowerCaps->MinDeviceWakeState = PowerSystemUnspecified;
 3053         PowerCaps->DefaultLowLatencyWake = PowerSystemUnspecified;
 3054         return STATUS_SUCCESS;
 3055     }
 3056 
 3057     case SystemBatteryState:
 3058     {
 3059         if (out_size < sizeof(SYSTEM_BATTERY_STATE)) return STATUS_BUFFER_TOO_SMALL;
 3060         memset(output, 0, sizeof(SYSTEM_BATTERY_STATE));
 3061         return fill_battery_state(output);
 3062     }
 3063 
 3064     case SystemExecutionState:
 3065     {
 3066         ULONG *state = output;
 3067         WARN("semi-stub: SystemExecutionState\n"); /* Needed for .NET Framework, but using a FIXME is really noisy. */
 3068         if (input != NULL) return STATUS_INVALID_PARAMETER;
 3069         /* FIXME: The actual state should be the value set by SetThreadExecutionState which is not currently implemented. */
 3070         *state = ES_USER_PRESENT;
 3071         return STATUS_SUCCESS;
 3072     }
 3073 
 3074     case ProcessorInformation:
 3075     {
 3076         const int cannedMHz = 1000; /* We fake a 1GHz processor if we can't conjure up real values */
 3077         PROCESSOR_POWER_INFORMATION* cpu_power = output;
 3078         int i, out_cpus;
 3079 
 3080         if ((output == NULL) || (out_size == 0)) return STATUS_INVALID_PARAMETER;
 3081         out_cpus = NtCurrentTeb()->Peb->NumberOfProcessors;
 3082         if ((out_size / sizeof(PROCESSOR_POWER_INFORMATION)) < out_cpus) return STATUS_BUFFER_TOO_SMALL;
 3083 #if defined(linux)
 3084         {
 3085             char filename[128];
 3086             FILE* f;
 3087 
 3088             for(i = 0; i < out_cpus; i++) {
 3089                 sprintf(filename, "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", i);
 3090                 f = fopen(filename, "r");
 3091                 if (f && (fscanf(f, "%d", &cpu_power[i].MaxMhz) == 1)) {
 3092                     cpu_power[i].MaxMhz /= 1000;
 3093                     fclose(f);
 3094                     cpu_power[i].CurrentMhz = cpu_power[i].MaxMhz;
 3095                 }
 3096                 else {
 3097                     if(i == 0) {
 3098                         cpu_power[0].CurrentMhz = mhz_from_cpuinfo();
 3099                         if(cpu_power[0].CurrentMhz == 0)
 3100                             cpu_power[0].CurrentMhz = cannedMHz;
 3101                     }
 3102                     else
 3103                         cpu_power[i].CurrentMhz = cpu_power[0].CurrentMhz;
 3104                     cpu_power[i].MaxMhz = cpu_power[i].CurrentMhz;
 3105                     if(f) fclose(f);
 3106                 }
 3107 
 3108                 sprintf(filename, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", i);
 3109                 f = fopen(filename, "r");
 3110                 if(f && (fscanf(f, "%d", &cpu_power[i].MhzLimit) == 1)) {
 3111                     cpu_power[i].MhzLimit /= 1000;
 3112                     fclose(f);
 3113                 }
 3114                 else
 3115                 {
 3116                     cpu_power[i].MhzLimit = cpu_power[i].MaxMhz;
 3117                     if(f) fclose(f);
 3118                 }
 3119 
 3120                 cpu_power[i].Number = i;
 3121                 cpu_power[i].MaxIdleState = 0;     /* FIXME */
 3122                 cpu_power[i].CurrentIdleState = 0; /* FIXME */
 3123             }
 3124         }
 3125 #elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__)
 3126         {
 3127             int num;
 3128             size_t valSize = sizeof(num);
 3129             if (sysctlbyname("hw.clockrate", &num, &valSize, NULL, 0))
 3130                 num = cannedMHz;
 3131             for(i = 0; i < out_cpus; i++) {
 3132                 cpu_power[i].CurrentMhz = num;
 3133                 cpu_power[i].MaxMhz = num;
 3134                 cpu_power[i].MhzLimit = num;
 3135                 cpu_power[i].Number = i;
 3136                 cpu_power[i].MaxIdleState = 0;     /* FIXME */
 3137                 cpu_power[i].CurrentIdleState = 0; /* FIXME */
 3138             }
 3139         }
 3140 #elif defined (__APPLE__)
 3141         {
 3142             size_t valSize;
 3143             unsigned long long currentMhz;
 3144             unsigned long long maxMhz;
 3145 
 3146             valSize = sizeof(currentMhz);
 3147             if (!sysctlbyname("hw.cpufrequency", &currentMhz, &valSize, NULL, 0))
 3148                 currentMhz /= 1000000;
 3149             else
 3150                 currentMhz = cannedMHz;
 3151 
 3152             valSize = sizeof(maxMhz);
 3153             if (!sysctlbyname("hw.cpufrequency_max", &maxMhz, &valSize, NULL, 0))
 3154                 maxMhz /= 1000000;
 3155             else
 3156                 maxMhz = currentMhz;
 3157 
 3158             for(i = 0; i < out_cpus; i++) {
 3159                 cpu_power[i].CurrentMhz = currentMhz;
 3160                 cpu_power[i].MaxMhz = maxMhz;
 3161                 cpu_power[i].MhzLimit = maxMhz;
 3162                 cpu_power[i].Number = i;
 3163                 cpu_power[i].MaxIdleState = 0;     /* FIXME */
 3164                 cpu_power[i].CurrentIdleState = 0; /* FIXME */
 3165             }
 3166         }
 3167 #else
 3168         for(i = 0; i < out_cpus; i++) {
 3169             cpu_power[i].CurrentMhz = cannedMHz;
 3170             cpu_power[i].MaxMhz = cannedMHz;
 3171             cpu_power[i].MhzLimit = cannedMHz;
 3172             cpu_power[i].Number = i;
 3173             cpu_power[i].MaxIdleState = 0; /* FIXME */
 3174             cpu_power[i].CurrentIdleState = 0; /* FIXME */
 3175         }
 3176         WARN("Unable to detect CPU MHz for this platform. Reporting %d MHz.\n", cannedMHz);
 3177 #endif
 3178         for(i = 0; i < out_cpus; i++) {
 3179             TRACE("cpu_power[%d] = %u %u %u %u %u %u\n", i, cpu_power[i].Number,
 3180                   cpu_power[i].MaxMhz, cpu_power[i].CurrentMhz, cpu_power[i].MhzLimit,
 3181                   cpu_power[i].MaxIdleState, cpu_power[i].CurrentIdleState);
 3182         }
 3183         return STATUS_SUCCESS;
 3184     }
 3185 
 3186     default:
 3187         /* FIXME: Needed by .NET Framework */
 3188         WARN( "Unimplemented NtPowerInformation action: %d\n", level );
 3189         return STATUS_NOT_IMPLEMENTED;
 3190     }
 3191 }
 3192 
 3193 
 3194 /******************************************************************************
 3195  *              NtLoadDriver  (NTDLL.@)
 3196  */
 3197 NTSTATUS WINAPI NtLoadDriver( const UNICODE_STRING *name )
 3198 {
 3199     FIXME( "(%s), stub!\n", debugstr_us(name) );
 3200     return STATUS_NOT_IMPLEMENTED;
 3201 }
 3202 
 3203 
 3204 /******************************************************************************
 3205  *              NtUnloadDriver  (NTDLL.@)
 3206  */
 3207 NTSTATUS WINAPI NtUnloadDriver( const UNICODE_STRING *name )
 3208 {
 3209     FIXME( "(%s), stub!\n", debugstr_us(name) );
 3210     return STATUS_NOT_IMPLEMENTED;
 3211 }
 3212 
 3213 
 3214 /******************************************************************************
 3215  *              NtDisplayString  (NTDLL.@)
 3216  */
 3217 NTSTATUS WINAPI NtDisplayString( UNICODE_STRING *string )
 3218 {
 3219     ERR( "%s\n", debugstr_us(string) );
 3220     return STATUS_SUCCESS;
 3221 }
 3222 
 3223 
 3224 /******************************************************************************
 3225  *              NtRaiseHardError  (NTDLL.@)
 3226  */
 3227 NTSTATUS WINAPI NtRaiseHardError( NTSTATUS status, ULONG count,
 3228                                   UNICODE_STRING *params_mask, void **params,
 3229                                   HARDERROR_RESPONSE_OPTION option, HARDERROR_RESPONSE *response )
 3230 {
 3231     FIXME( "%08x stub\n", status );
 3232     return STATUS_NOT_IMPLEMENTED;
 3233 }
 3234 
 3235 
 3236 /******************************************************************************
 3237  *              NtInitiatePowerAction  (NTDLL.@)
 3238  */
 3239 NTSTATUS WINAPI NtInitiatePowerAction( POWER_ACTION action, SYSTEM_POWER_STATE state,
 3240                                        ULONG flags, BOOLEAN async )
 3241 {
 3242     FIXME( "(%d,%d,0x%08x,%d),stub\n", action, state, flags, async );
 3243     return STATUS_NOT_IMPLEMENTED;
 3244 }
 3245 
 3246 
 3247 /******************************************************************************
 3248  *              NtCreatePowerRequest  (NTDLL.@)
 3249  */
 3250 NTSTATUS WINAPI NtCreatePowerRequest( HANDLE *handle, COUNTED_REASON_CONTEXT *context )
 3251 {
 3252     FIXME( "(%p, %p): stub\n", handle, context );
 3253     return STATUS_NOT_IMPLEMENTED;
 3254 }
 3255 
 3256 
 3257 /******************************************************************************
 3258  *              NtSetPowerRequest  (NTDLL.@)
 3259  */
 3260 NTSTATUS WINAPI NtSetPowerRequest( HANDLE handle, POWER_REQUEST_TYPE type )
 3261 {
 3262     FIXME( "(%p, %u): stub\n", handle, type );
 3263     return STATUS_NOT_IMPLEMENTED;
 3264 }
 3265 
 3266 
 3267 /******************************************************************************
 3268  *              NtClearPowerRequest  (NTDLL.@)
 3269  */
 3270 NTSTATUS WINAPI NtClearPowerRequest( HANDLE handle, POWER_REQUEST_TYPE type )
 3271 {
 3272     FIXME( "(%p, %u): stub\n", handle, type );
 3273     return STATUS_NOT_IMPLEMENTED;
 3274 }
 3275 
 3276 
 3277 /******************************************************************************
 3278  *              NtSetThreadExecutionState  (NTDLL.@)
 3279  */
 3280 NTSTATUS WINAPI NtSetThreadExecutionState( EXECUTION_STATE new_state, EXECUTION_STATE *old_state )
 3281 {
 3282     static EXECUTION_STATE current = ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED | ES_USER_PRESENT;
 3283 
 3284     WARN( "(0x%x, %p): stub, harmless.\n", new_state, old_state );
 3285     *old_state = current;
 3286     if (!(current & ES_CONTINUOUS) || (new_state & ES_CONTINUOUS)) current = new_state;
 3287     return STATUS_SUCCESS;
 3288 }