4 * This file contains the Nt* API functions of NTDLL.DLL.
5 * In the original ntdll.dll they all seem to just call int 0x2e (down to the NTOSKRNL)
7 * Copyright 1996-1998 Marcus Meissner
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
27 #ifdef HAVE_SYS_PARAM_H
28 # include <sys/param.h>
30 #ifdef HAVE_SYS_SYSCTL_H
31 # include <sys/sysctl.h>
33 #ifdef HAVE_MACHINE_CPU_H
34 # include <machine/cpu.h>
36 #ifdef HAVE_MACH_MACHINE_H
37 # include <mach/machine.h>
45 #ifdef HAVE_SYS_TIME_H
46 # include <sys/time.h>
50 #define NONAMELESSUNION
52 #define WIN32_NO_STATUS
53 #include "wine/debug.h"
54 #include "wine/unicode.h"
57 #include "ntdll_misc.h"
58 #include "wine/server.h"
62 #include <mach/mach_init.h>
63 #include <mach/mach_host.h>
64 #include <mach/vm_map.h>
67 WINE_DEFAULT_DEBUG_CHANNEL(ntdll
);
71 struct smbios_prologue
{
88 UINT64 characteristics
;
91 struct smbios_system
{
103 /* Firmware table providers */
104 #define ACPI 0x41435049
105 #define FIRM 0x4649524D
106 #define RSMB 0x52534D42
112 /******************************************************************************
113 * NtDuplicateToken [NTDLL.@]
114 * ZwDuplicateToken [NTDLL.@]
116 NTSTATUS WINAPI
NtDuplicateToken(
117 IN HANDLE ExistingToken
,
118 IN ACCESS_MASK DesiredAccess
,
119 IN POBJECT_ATTRIBUTES ObjectAttributes
,
120 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
,
121 IN TOKEN_TYPE TokenType
,
122 OUT PHANDLE NewToken
)
126 struct object_attributes
*objattr
;
128 TRACE("(%p,0x%08x,%s,0x%08x,0x%08x,%p)\n",
129 ExistingToken
, DesiredAccess
, debugstr_ObjectAttributes(ObjectAttributes
),
130 ImpersonationLevel
, TokenType
, NewToken
);
132 if ((status
= alloc_object_attributes( ObjectAttributes
, &objattr
, &len
))) return status
;
134 if (ObjectAttributes
&& ObjectAttributes
->SecurityQualityOfService
)
136 SECURITY_QUALITY_OF_SERVICE
*SecurityQOS
= ObjectAttributes
->SecurityQualityOfService
;
137 TRACE("ObjectAttributes->SecurityQualityOfService = {%d, %d, %d, %s}\n",
138 SecurityQOS
->Length
, SecurityQOS
->ImpersonationLevel
,
139 SecurityQOS
->ContextTrackingMode
,
140 SecurityQOS
->EffectiveOnly
? "TRUE" : "FALSE");
141 ImpersonationLevel
= SecurityQOS
->ImpersonationLevel
;
144 SERVER_START_REQ( duplicate_token
)
146 req
->handle
= wine_server_obj_handle( ExistingToken
);
147 req
->access
= DesiredAccess
;
148 req
->primary
= (TokenType
== TokenPrimary
);
149 req
->impersonation_level
= ImpersonationLevel
;
150 wine_server_add_data( req
, objattr
, len
);
151 status
= wine_server_call( req
);
152 if (!status
) *NewToken
= wine_server_ptr_handle( reply
->new_handle
);
156 RtlFreeHeap( GetProcessHeap(), 0, objattr
);
160 /******************************************************************************
161 * NtOpenProcessToken [NTDLL.@]
162 * ZwOpenProcessToken [NTDLL.@]
164 NTSTATUS WINAPI
NtOpenProcessToken(
165 HANDLE ProcessHandle
,
169 return NtOpenProcessTokenEx( ProcessHandle
, DesiredAccess
, 0, TokenHandle
);
172 /******************************************************************************
173 * NtOpenProcessTokenEx [NTDLL.@]
174 * ZwOpenProcessTokenEx [NTDLL.@]
176 NTSTATUS WINAPI
NtOpenProcessTokenEx( HANDLE process
, DWORD access
, DWORD attributes
,
181 TRACE("(%p,0x%08x,0x%08x,%p)\n", process
, access
, attributes
, handle
);
183 SERVER_START_REQ( open_token
)
185 req
->handle
= wine_server_obj_handle( process
);
186 req
->access
= access
;
187 req
->attributes
= attributes
;
189 ret
= wine_server_call( req
);
190 if (!ret
) *handle
= wine_server_ptr_handle( reply
->token
);
196 /******************************************************************************
197 * NtOpenThreadToken [NTDLL.@]
198 * ZwOpenThreadToken [NTDLL.@]
200 NTSTATUS WINAPI
NtOpenThreadToken(
206 return NtOpenThreadTokenEx( ThreadHandle
, DesiredAccess
, OpenAsSelf
, 0, TokenHandle
);
209 /******************************************************************************
210 * NtOpenThreadTokenEx [NTDLL.@]
211 * ZwOpenThreadTokenEx [NTDLL.@]
213 NTSTATUS WINAPI
NtOpenThreadTokenEx( HANDLE thread
, DWORD access
, BOOLEAN as_self
, DWORD attributes
,
218 TRACE("(%p,0x%08x,%u,0x%08x,%p)\n", thread
, access
, as_self
, attributes
, handle
);
220 SERVER_START_REQ( open_token
)
222 req
->handle
= wine_server_obj_handle( thread
);
223 req
->access
= access
;
224 req
->attributes
= attributes
;
225 req
->flags
= OPEN_TOKEN_THREAD
;
226 if (as_self
) req
->flags
|= OPEN_TOKEN_AS_SELF
;
227 ret
= wine_server_call( req
);
228 if (!ret
) *handle
= wine_server_ptr_handle( reply
->token
);
235 /******************************************************************************
236 * NtAdjustPrivilegesToken [NTDLL.@]
237 * ZwAdjustPrivilegesToken [NTDLL.@]
239 * FIXME: parameters unsafe
241 NTSTATUS WINAPI
NtAdjustPrivilegesToken(
242 IN HANDLE TokenHandle
,
243 IN BOOLEAN DisableAllPrivileges
,
244 IN PTOKEN_PRIVILEGES NewState
,
245 IN DWORD BufferLength
,
246 OUT PTOKEN_PRIVILEGES PreviousState
,
247 OUT PDWORD ReturnLength
)
251 TRACE("(%p,0x%08x,%p,0x%08x,%p,%p)\n",
252 TokenHandle
, DisableAllPrivileges
, NewState
, BufferLength
, PreviousState
, ReturnLength
);
254 SERVER_START_REQ( adjust_token_privileges
)
256 req
->handle
= wine_server_obj_handle( TokenHandle
);
257 req
->disable_all
= DisableAllPrivileges
;
258 req
->get_modified_state
= (PreviousState
!= NULL
);
259 if (!DisableAllPrivileges
)
261 wine_server_add_data( req
, NewState
->Privileges
,
262 NewState
->PrivilegeCount
* sizeof(NewState
->Privileges
[0]) );
264 if (PreviousState
&& BufferLength
>= FIELD_OFFSET( TOKEN_PRIVILEGES
, Privileges
))
265 wine_server_set_reply( req
, PreviousState
->Privileges
,
266 BufferLength
- FIELD_OFFSET( TOKEN_PRIVILEGES
, Privileges
) );
267 ret
= wine_server_call( req
);
270 if (ReturnLength
) *ReturnLength
= reply
->len
+ FIELD_OFFSET( TOKEN_PRIVILEGES
, Privileges
);
271 PreviousState
->PrivilegeCount
= reply
->len
/ sizeof(LUID_AND_ATTRIBUTES
);
279 /******************************************************************************
280 * NtQueryInformationToken [NTDLL.@]
281 * ZwQueryInformationToken [NTDLL.@]
284 * Buffer for TokenUser:
285 * 0x00 TOKEN_USER the PSID field points to the SID
289 NTSTATUS WINAPI
NtQueryInformationToken(
291 TOKEN_INFORMATION_CLASS tokeninfoclass
,
293 ULONG tokeninfolength
,
296 static const ULONG info_len
[] =
301 0, /* TokenPrivileges */
303 0, /* TokenPrimaryGroup */
304 0, /* TokenDefaultDacl */
305 sizeof(TOKEN_SOURCE
), /* TokenSource */
306 sizeof(TOKEN_TYPE
), /* TokenType */
307 sizeof(SECURITY_IMPERSONATION_LEVEL
), /* TokenImpersonationLevel */
308 sizeof(TOKEN_STATISTICS
), /* TokenStatistics */
309 0, /* TokenRestrictedSids */
310 sizeof(DWORD
), /* TokenSessionId */
311 0, /* TokenGroupsAndPrivileges */
312 0, /* TokenSessionReference */
313 0, /* TokenSandBoxInert */
314 0, /* TokenAuditPolicy */
316 sizeof(TOKEN_ELEVATION_TYPE
), /* TokenElevationType */
317 0, /* TokenLinkedToken */
318 sizeof(TOKEN_ELEVATION
), /* TokenElevation */
319 0, /* TokenHasRestrictions */
320 0, /* TokenAccessInformation */
321 0, /* TokenVirtualizationAllowed */
322 0, /* TokenVirtualizationEnabled */
323 sizeof(TOKEN_MANDATORY_LABEL
) + sizeof(SID
), /* TokenIntegrityLevel [sizeof(SID) includes one SubAuthority] */
324 0, /* TokenUIAccess */
325 0, /* TokenMandatoryPolicy */
326 0, /* TokenLogonSid */
327 sizeof(DWORD
), /* TokenIsAppContainer */
328 0, /* TokenCapabilities */
329 sizeof(TOKEN_APPCONTAINER_INFORMATION
) + sizeof(SID
), /* TokenAppContainerSid */
330 0, /* TokenAppContainerNumber */
331 0, /* TokenUserClaimAttributes*/
332 0, /* TokenDeviceClaimAttributes */
333 0, /* TokenRestrictedUserClaimAttributes */
334 0, /* TokenRestrictedDeviceClaimAttributes */
335 0, /* TokenDeviceGroups */
336 0, /* TokenRestrictedDeviceGroups */
337 0, /* TokenSecurityAttributes */
338 0, /* TokenIsRestricted */
339 0 /* TokenProcessTrustLevel */
343 NTSTATUS status
= STATUS_SUCCESS
;
345 TRACE("(%p,%d,%p,%d,%p)\n",
346 token
,tokeninfoclass
,tokeninfo
,tokeninfolength
,retlen
);
348 if (tokeninfoclass
< MaxTokenInfoClass
)
349 len
= info_len
[tokeninfoclass
];
351 if (retlen
) *retlen
= len
;
353 if (tokeninfolength
< len
)
354 return STATUS_BUFFER_TOO_SMALL
;
356 switch (tokeninfoclass
)
359 SERVER_START_REQ( get_token_sid
)
361 TOKEN_USER
* tuser
= tokeninfo
;
362 PSID sid
= tuser
+ 1;
363 DWORD sid_len
= tokeninfolength
< sizeof(TOKEN_USER
) ? 0 : tokeninfolength
- sizeof(TOKEN_USER
);
365 req
->handle
= wine_server_obj_handle( token
);
366 req
->which_sid
= tokeninfoclass
;
367 wine_server_set_reply( req
, sid
, sid_len
);
368 status
= wine_server_call( req
);
369 if (retlen
) *retlen
= reply
->sid_len
+ sizeof(TOKEN_USER
);
370 if (status
== STATUS_SUCCESS
)
372 tuser
->User
.Sid
= sid
;
373 tuser
->User
.Attributes
= 0;
382 /* reply buffer is always shorter than output one */
383 buffer
= tokeninfolength
? RtlAllocateHeap(GetProcessHeap(), 0, tokeninfolength
) : NULL
;
385 SERVER_START_REQ( get_token_groups
)
387 TOKEN_GROUPS
*groups
= tokeninfo
;
389 req
->handle
= wine_server_obj_handle( token
);
390 wine_server_set_reply( req
, buffer
, tokeninfolength
);
391 status
= wine_server_call( req
);
392 if (status
== STATUS_BUFFER_TOO_SMALL
)
394 if (retlen
) *retlen
= reply
->user_len
;
396 else if (status
== STATUS_SUCCESS
)
398 struct token_groups
*tg
= buffer
;
399 unsigned int *attr
= (unsigned int *)(tg
+ 1);
401 const int non_sid_portion
= (sizeof(struct token_groups
) + tg
->count
* sizeof(unsigned int));
402 SID
*sids
= (SID
*)((char *)tokeninfo
+ FIELD_OFFSET( TOKEN_GROUPS
, Groups
[tg
->count
] ));
404 if (retlen
) *retlen
= reply
->user_len
;
406 groups
->GroupCount
= tg
->count
;
407 memcpy( sids
, (char *)buffer
+ non_sid_portion
,
408 reply
->user_len
- FIELD_OFFSET( TOKEN_GROUPS
, Groups
[tg
->count
] ));
410 for (i
= 0; i
< tg
->count
; i
++)
412 groups
->Groups
[i
].Attributes
= attr
[i
];
413 groups
->Groups
[i
].Sid
= sids
;
414 sids
= (SID
*)((char *)sids
+ RtlLengthSid(sids
));
417 else if (retlen
) *retlen
= 0;
421 RtlFreeHeap(GetProcessHeap(), 0, buffer
);
424 case TokenPrimaryGroup
:
425 SERVER_START_REQ( get_token_sid
)
427 TOKEN_PRIMARY_GROUP
*tgroup
= tokeninfo
;
428 PSID sid
= tgroup
+ 1;
429 DWORD sid_len
= tokeninfolength
< sizeof(TOKEN_PRIMARY_GROUP
) ? 0 : tokeninfolength
- sizeof(TOKEN_PRIMARY_GROUP
);
431 req
->handle
= wine_server_obj_handle( token
);
432 req
->which_sid
= tokeninfoclass
;
433 wine_server_set_reply( req
, sid
, sid_len
);
434 status
= wine_server_call( req
);
435 if (retlen
) *retlen
= reply
->sid_len
+ sizeof(TOKEN_PRIMARY_GROUP
);
436 if (status
== STATUS_SUCCESS
)
437 tgroup
->PrimaryGroup
= sid
;
441 case TokenPrivileges
:
442 SERVER_START_REQ( get_token_privileges
)
444 TOKEN_PRIVILEGES
*tpriv
= tokeninfo
;
445 req
->handle
= wine_server_obj_handle( token
);
446 if (tpriv
&& tokeninfolength
> FIELD_OFFSET( TOKEN_PRIVILEGES
, Privileges
))
447 wine_server_set_reply( req
, tpriv
->Privileges
, tokeninfolength
- FIELD_OFFSET( TOKEN_PRIVILEGES
, Privileges
) );
448 status
= wine_server_call( req
);
449 if (retlen
) *retlen
= FIELD_OFFSET( TOKEN_PRIVILEGES
, Privileges
) + reply
->len
;
450 if (tpriv
) tpriv
->PrivilegeCount
= reply
->len
/ sizeof(LUID_AND_ATTRIBUTES
);
455 SERVER_START_REQ( get_token_sid
)
457 TOKEN_OWNER
*towner
= tokeninfo
;
458 PSID sid
= towner
+ 1;
459 DWORD sid_len
= tokeninfolength
< sizeof(TOKEN_OWNER
) ? 0 : tokeninfolength
- sizeof(TOKEN_OWNER
);
461 req
->handle
= wine_server_obj_handle( token
);
462 req
->which_sid
= tokeninfoclass
;
463 wine_server_set_reply( req
, sid
, sid_len
);
464 status
= wine_server_call( req
);
465 if (retlen
) *retlen
= reply
->sid_len
+ sizeof(TOKEN_OWNER
);
466 if (status
== STATUS_SUCCESS
)
471 case TokenImpersonationLevel
:
472 SERVER_START_REQ( get_token_impersonation_level
)
474 SECURITY_IMPERSONATION_LEVEL
*impersonation_level
= tokeninfo
;
475 req
->handle
= wine_server_obj_handle( token
);
476 status
= wine_server_call( req
);
477 if (status
== STATUS_SUCCESS
)
478 *impersonation_level
= reply
->impersonation_level
;
482 case TokenStatistics
:
483 SERVER_START_REQ( get_token_statistics
)
485 TOKEN_STATISTICS
*statistics
= tokeninfo
;
486 req
->handle
= wine_server_obj_handle( token
);
487 status
= wine_server_call( req
);
488 if (status
== STATUS_SUCCESS
)
490 statistics
->TokenId
.LowPart
= reply
->token_id
.low_part
;
491 statistics
->TokenId
.HighPart
= reply
->token_id
.high_part
;
492 statistics
->AuthenticationId
.LowPart
= 0; /* FIXME */
493 statistics
->AuthenticationId
.HighPart
= 0; /* FIXME */
494 statistics
->ExpirationTime
.u
.HighPart
= 0x7fffffff;
495 statistics
->ExpirationTime
.u
.LowPart
= 0xffffffff;
496 statistics
->TokenType
= reply
->primary
? TokenPrimary
: TokenImpersonation
;
497 statistics
->ImpersonationLevel
= reply
->impersonation_level
;
499 /* kernel information not relevant to us */
500 statistics
->DynamicCharged
= 0;
501 statistics
->DynamicAvailable
= 0;
503 statistics
->GroupCount
= reply
->group_count
;
504 statistics
->PrivilegeCount
= reply
->privilege_count
;
505 statistics
->ModifiedId
.LowPart
= reply
->modified_id
.low_part
;
506 statistics
->ModifiedId
.HighPart
= reply
->modified_id
.high_part
;
512 SERVER_START_REQ( get_token_statistics
)
514 TOKEN_TYPE
*token_type
= tokeninfo
;
515 req
->handle
= wine_server_obj_handle( token
);
516 status
= wine_server_call( req
);
517 if (status
== STATUS_SUCCESS
)
518 *token_type
= reply
->primary
? TokenPrimary
: TokenImpersonation
;
522 case TokenDefaultDacl
:
523 SERVER_START_REQ( get_token_default_dacl
)
525 TOKEN_DEFAULT_DACL
*default_dacl
= tokeninfo
;
526 ACL
*acl
= (ACL
*)(default_dacl
+ 1);
529 if (tokeninfolength
< sizeof(TOKEN_DEFAULT_DACL
)) acl_len
= 0;
530 else acl_len
= tokeninfolength
- sizeof(TOKEN_DEFAULT_DACL
);
532 req
->handle
= wine_server_obj_handle( token
);
533 wine_server_set_reply( req
, acl
, acl_len
);
534 status
= wine_server_call( req
);
536 if (retlen
) *retlen
= reply
->acl_len
+ sizeof(TOKEN_DEFAULT_DACL
);
537 if (status
== STATUS_SUCCESS
)
540 default_dacl
->DefaultDacl
= acl
;
542 default_dacl
->DefaultDacl
= NULL
;
547 case TokenElevationType
:
549 TOKEN_ELEVATION_TYPE
*elevation_type
= tokeninfo
;
550 FIXME("QueryInformationToken( ..., TokenElevationType, ...) semi-stub\n");
551 *elevation_type
= TokenElevationTypeFull
;
556 TOKEN_ELEVATION
*elevation
= tokeninfo
;
557 FIXME("QueryInformationToken( ..., TokenElevation, ...) semi-stub\n");
558 elevation
->TokenIsElevated
= TRUE
;
563 *((DWORD
*)tokeninfo
) = 0;
564 FIXME("QueryInformationToken( ..., TokenSessionId, ...) semi-stub\n");
567 case TokenIntegrityLevel
:
569 /* report always "S-1-16-12288" (high mandatory level) for now */
570 static const SID high_level
= {SID_REVISION
, 1, {SECURITY_MANDATORY_LABEL_AUTHORITY
},
571 {SECURITY_MANDATORY_HIGH_RID
}};
573 TOKEN_MANDATORY_LABEL
*tml
= tokeninfo
;
576 tml
->Label
.Sid
= psid
;
577 tml
->Label
.Attributes
= SE_GROUP_INTEGRITY
| SE_GROUP_INTEGRITY_ENABLED
;
578 memcpy(psid
, &high_level
, sizeof(SID
));
581 case TokenAppContainerSid
:
583 TOKEN_APPCONTAINER_INFORMATION
*container
= tokeninfo
;
584 FIXME("QueryInformationToken( ..., TokenAppContainerSid, ...) semi-stub\n");
585 container
->TokenAppContainer
= NULL
;
588 case TokenIsAppContainer
:
590 TRACE("TokenIsAppContainer semi-stub\n");
591 *(DWORD
*)tokeninfo
= 0;
595 SERVER_START_REQ( get_token_sid
)
597 TOKEN_GROUPS
* groups
= tokeninfo
;
598 PSID sid
= groups
+ 1;
599 DWORD sid_len
= tokeninfolength
< sizeof(TOKEN_GROUPS
) ? 0 : tokeninfolength
- sizeof(TOKEN_GROUPS
);
601 req
->handle
= wine_server_obj_handle( token
);
602 req
->which_sid
= tokeninfoclass
;
603 wine_server_set_reply( req
, sid
, sid_len
);
604 status
= wine_server_call( req
);
605 if (retlen
) *retlen
= reply
->sid_len
+ sizeof(TOKEN_GROUPS
);
606 if (status
== STATUS_SUCCESS
)
608 groups
->GroupCount
= 1;
609 groups
->Groups
[0].Sid
= sid
;
610 groups
->Groups
[0].Attributes
= 0;
617 ERR("Unhandled Token Information class %d!\n", tokeninfoclass
);
618 return STATUS_NOT_IMPLEMENTED
;
624 /******************************************************************************
625 * NtSetInformationToken [NTDLL.@]
626 * ZwSetInformationToken [NTDLL.@]
628 NTSTATUS WINAPI
NtSetInformationToken(
630 TOKEN_INFORMATION_CLASS TokenInformationClass
,
631 PVOID TokenInformation
,
632 ULONG TokenInformationLength
)
634 NTSTATUS ret
= STATUS_NOT_IMPLEMENTED
;
636 TRACE("%p %d %p %u\n", TokenHandle
, TokenInformationClass
,
637 TokenInformation
, TokenInformationLength
);
639 switch (TokenInformationClass
)
641 case TokenDefaultDacl
:
642 if (TokenInformationLength
< sizeof(TOKEN_DEFAULT_DACL
))
644 ret
= STATUS_INFO_LENGTH_MISMATCH
;
647 if (!TokenInformation
)
649 ret
= STATUS_ACCESS_VIOLATION
;
652 SERVER_START_REQ( set_token_default_dacl
)
654 ACL
*acl
= ((TOKEN_DEFAULT_DACL
*)TokenInformation
)->DefaultDacl
;
657 if (acl
) size
= acl
->AclSize
;
660 req
->handle
= wine_server_obj_handle( TokenHandle
);
661 wine_server_add_data( req
, acl
, size
);
662 ret
= wine_server_call( req
);
667 if (TokenInformationLength
< sizeof(DWORD
))
669 ret
= STATUS_INFO_LENGTH_MISMATCH
;
672 if (!TokenInformation
)
674 ret
= STATUS_ACCESS_VIOLATION
;
677 FIXME("TokenSessionId stub!\n");
678 ret
= STATUS_SUCCESS
;
680 case TokenIntegrityLevel
:
681 FIXME("TokenIntegrityLevel stub!\n");
682 ret
= STATUS_SUCCESS
;
685 FIXME("unimplemented class %u\n", TokenInformationClass
);
692 /******************************************************************************
693 * NtAdjustGroupsToken [NTDLL.@]
694 * ZwAdjustGroupsToken [NTDLL.@]
696 NTSTATUS WINAPI
NtAdjustGroupsToken(
698 BOOLEAN ResetToDefault
,
699 PTOKEN_GROUPS NewState
,
701 PTOKEN_GROUPS PreviousState
,
704 FIXME("%p %d %p %u %p %p\n", TokenHandle
, ResetToDefault
,
705 NewState
, BufferLength
, PreviousState
, ReturnLength
);
706 return STATUS_NOT_IMPLEMENTED
;
709 /******************************************************************************
710 * NtPrivilegeCheck [NTDLL.@]
711 * ZwPrivilegeCheck [NTDLL.@]
713 NTSTATUS WINAPI
NtPrivilegeCheck(
715 PPRIVILEGE_SET RequiredPrivileges
,
719 SERVER_START_REQ( check_token_privileges
)
721 req
->handle
= wine_server_obj_handle( ClientToken
);
722 req
->all_required
= (RequiredPrivileges
->Control
& PRIVILEGE_SET_ALL_NECESSARY
) != 0;
723 wine_server_add_data( req
, RequiredPrivileges
->Privilege
,
724 RequiredPrivileges
->PrivilegeCount
* sizeof(RequiredPrivileges
->Privilege
[0]) );
725 wine_server_set_reply( req
, RequiredPrivileges
->Privilege
,
726 RequiredPrivileges
->PrivilegeCount
* sizeof(RequiredPrivileges
->Privilege
[0]) );
728 status
= wine_server_call( req
);
730 if (status
== STATUS_SUCCESS
)
731 *Result
= reply
->has_privileges
!= 0;
741 /******************************************************************************
742 * NtCreatePort [NTDLL.@]
743 * ZwCreatePort [NTDLL.@]
745 NTSTATUS WINAPI
NtCreatePort(PHANDLE PortHandle
,POBJECT_ATTRIBUTES ObjectAttributes
,
746 ULONG MaxConnectInfoLength
,ULONG MaxDataLength
,PULONG reserved
)
748 FIXME("(%p,%p,%u,%u,%p),stub!\n",PortHandle
,ObjectAttributes
,
749 MaxConnectInfoLength
,MaxDataLength
,reserved
);
750 return STATUS_NOT_IMPLEMENTED
;
753 /******************************************************************************
754 * NtConnectPort [NTDLL.@]
755 * ZwConnectPort [NTDLL.@]
757 NTSTATUS WINAPI
NtConnectPort(
759 PUNICODE_STRING PortName
,
760 PSECURITY_QUALITY_OF_SERVICE SecurityQos
,
761 PLPC_SECTION_WRITE WriteSection
,
762 PLPC_SECTION_READ ReadSection
,
763 PULONG MaximumMessageLength
,
765 PULONG pConnectInfoLength
)
767 FIXME("(%p,%s,%p,%p,%p,%p,%p,%p),stub!\n",
768 PortHandle
,debugstr_w(PortName
->Buffer
),SecurityQos
,
769 WriteSection
,ReadSection
,MaximumMessageLength
,ConnectInfo
,
771 if (ConnectInfo
&& pConnectInfoLength
)
772 TRACE("\tMessage = %s\n",debugstr_an(ConnectInfo
,*pConnectInfoLength
));
773 return STATUS_NOT_IMPLEMENTED
;
776 /******************************************************************************
777 * NtSecureConnectPort (NTDLL.@)
778 * ZwSecureConnectPort (NTDLL.@)
780 NTSTATUS WINAPI
NtSecureConnectPort(
782 PUNICODE_STRING PortName
,
783 PSECURITY_QUALITY_OF_SERVICE SecurityQos
,
784 PLPC_SECTION_WRITE WriteSection
,
786 PLPC_SECTION_READ ReadSection
,
787 PULONG MaximumMessageLength
,
789 PULONG pConnectInfoLength
)
791 FIXME("(%p,%s,%p,%p,%p,%p,%p,%p,%p),stub!\n",
792 PortHandle
,debugstr_w(PortName
->Buffer
),SecurityQos
,
793 WriteSection
,pSid
,ReadSection
,MaximumMessageLength
,ConnectInfo
,
795 return STATUS_NOT_IMPLEMENTED
;
798 /******************************************************************************
799 * NtListenPort [NTDLL.@]
800 * ZwListenPort [NTDLL.@]
802 NTSTATUS WINAPI
NtListenPort(HANDLE PortHandle
,PLPC_MESSAGE pLpcMessage
)
804 FIXME("(%p,%p),stub!\n",PortHandle
,pLpcMessage
);
805 return STATUS_NOT_IMPLEMENTED
;
808 /******************************************************************************
809 * NtAcceptConnectPort [NTDLL.@]
810 * ZwAcceptConnectPort [NTDLL.@]
812 NTSTATUS WINAPI
NtAcceptConnectPort(
814 ULONG PortIdentifier
,
815 PLPC_MESSAGE pLpcMessage
,
817 PLPC_SECTION_WRITE WriteSection
,
818 PLPC_SECTION_READ ReadSection
)
820 FIXME("(%p,%u,%p,%d,%p,%p),stub!\n",
821 PortHandle
,PortIdentifier
,pLpcMessage
,Accept
,WriteSection
,ReadSection
);
822 return STATUS_NOT_IMPLEMENTED
;
825 /******************************************************************************
826 * NtCompleteConnectPort [NTDLL.@]
827 * ZwCompleteConnectPort [NTDLL.@]
829 NTSTATUS WINAPI
NtCompleteConnectPort(HANDLE PortHandle
)
831 FIXME("(%p),stub!\n",PortHandle
);
832 return STATUS_NOT_IMPLEMENTED
;
835 /******************************************************************************
836 * NtRegisterThreadTerminatePort [NTDLL.@]
837 * ZwRegisterThreadTerminatePort [NTDLL.@]
839 NTSTATUS WINAPI
NtRegisterThreadTerminatePort(HANDLE PortHandle
)
841 FIXME("(%p),stub!\n",PortHandle
);
842 return STATUS_NOT_IMPLEMENTED
;
845 /******************************************************************************
846 * NtRequestWaitReplyPort [NTDLL.@]
847 * ZwRequestWaitReplyPort [NTDLL.@]
849 NTSTATUS WINAPI
NtRequestWaitReplyPort(
851 PLPC_MESSAGE pLpcMessageIn
,
852 PLPC_MESSAGE pLpcMessageOut
)
854 FIXME("(%p,%p,%p),stub!\n",PortHandle
,pLpcMessageIn
,pLpcMessageOut
);
857 TRACE("Message to send:\n");
858 TRACE("\tDataSize = %u\n",pLpcMessageIn
->DataSize
);
859 TRACE("\tMessageSize = %u\n",pLpcMessageIn
->MessageSize
);
860 TRACE("\tMessageType = %u\n",pLpcMessageIn
->MessageType
);
861 TRACE("\tVirtualRangesOffset = %u\n",pLpcMessageIn
->VirtualRangesOffset
);
862 TRACE("\tClientId.UniqueProcess = %p\n",pLpcMessageIn
->ClientId
.UniqueProcess
);
863 TRACE("\tClientId.UniqueThread = %p\n",pLpcMessageIn
->ClientId
.UniqueThread
);
864 TRACE("\tMessageId = %lu\n",pLpcMessageIn
->MessageId
);
865 TRACE("\tSectionSize = %lu\n",pLpcMessageIn
->SectionSize
);
866 TRACE("\tData = %s\n",
867 debugstr_an((const char*)pLpcMessageIn
->Data
,pLpcMessageIn
->DataSize
));
869 return STATUS_NOT_IMPLEMENTED
;
872 /******************************************************************************
873 * NtReplyWaitReceivePort [NTDLL.@]
874 * ZwReplyWaitReceivePort [NTDLL.@]
876 NTSTATUS WINAPI
NtReplyWaitReceivePort(
878 PULONG PortIdentifier
,
879 PLPC_MESSAGE ReplyMessage
,
880 PLPC_MESSAGE Message
)
882 FIXME("(%p,%p,%p,%p),stub!\n",PortHandle
,PortIdentifier
,ReplyMessage
,Message
);
883 return STATUS_NOT_IMPLEMENTED
;
890 /******************************************************************************
891 * NtSetIntervalProfile [NTDLL.@]
892 * ZwSetIntervalProfile [NTDLL.@]
894 NTSTATUS WINAPI
NtSetIntervalProfile(
896 KPROFILE_SOURCE Source
)
898 FIXME("%u,%d\n", Interval
, Source
);
899 return STATUS_SUCCESS
;
902 static SYSTEM_CPU_INFORMATION cached_sci
;
904 /*******************************************************************************
905 * Architecture specific feature detection for CPUs
907 * This a set of mutually exclusive #if define()s each providing its own get_cpuinfo() to be called
908 * from fill_cpu_info();
910 #if defined(__i386__) || defined(__x86_64__)
912 #define AUTH 0x68747541 /* "Auth" */
913 #define ENTI 0x69746e65 /* "enti" */
914 #define CAMD 0x444d4163 /* "cAMD" */
916 #define GENU 0x756e6547 /* "Genu" */
917 #define INEI 0x49656e69 /* "ineI" */
918 #define NTEL 0x6c65746e /* "ntel" */
920 /* Calls cpuid with an eax of 'ax' and returns the 16 bytes in *p
921 * We are compiled with -fPIC, so we can't clobber ebx.
923 static inline void do_cpuid(unsigned int ax
, unsigned int *p
)
926 __asm__("pushl %%ebx\n\t"
928 "movl %%ebx, %%esi\n\t"
930 : "=a" (p
[0]), "=S" (p
[1]), "=c" (p
[2]), "=d" (p
[3])
932 #elif defined(__x86_64__)
933 __asm__("push %%rbx\n\t"
935 "movq %%rbx, %%rsi\n\t"
937 : "=a" (p
[0]), "=S" (p
[1]), "=c" (p
[2]), "=d" (p
[3])
942 /* From xf86info havecpuid.c 1.11 */
943 static inline BOOL
have_cpuid(void)
957 : "=&r" (f1
), "=&r" (f2
)
958 : "ir" (0x00200000));
959 return ((f1
^f2
) & 0x00200000) != 0;
960 #elif defined(__x86_64__)
967 /* Detect if a SSE2 processor is capable of Denormals Are Zero (DAZ) mode.
969 * This function assumes you have already checked for SSE2/FXSAVE support. */
970 static inline BOOL
have_sse_daz_mode(void)
973 typedef struct DECLSPEC_ALIGN(16) _M128A
{
978 typedef struct _XMM_SAVE_AREA32
{
992 M128A FloatRegisters
[8];
993 M128A XmmRegisters
[16];
997 /* Intel says we need a zeroed 16-byte aligned buffer */
998 char buffer
[512 + 16];
999 XMM_SAVE_AREA32
*state
= (XMM_SAVE_AREA32
*)(((ULONG_PTR
)buffer
+ 15) & ~15);
1000 memset(buffer
, 0, sizeof(buffer
));
1002 __asm__
__volatile__( "fxsave %0" : "=m" (*state
) : "m" (*state
) );
1004 return (state
->MxCsr_Mask
& (1 << 6)) >> 6;
1005 #else /* all x86_64 processors include SSE2 with DAZ mode */
1010 static inline void get_cpuinfo(SYSTEM_CPU_INFORMATION
* info
)
1012 unsigned int regs
[4], regs2
[4];
1014 #if defined(__i386__)
1015 info
->Architecture
= PROCESSOR_ARCHITECTURE_INTEL
;
1016 #elif defined(__x86_64__)
1017 info
->Architecture
= PROCESSOR_ARCHITECTURE_AMD64
;
1020 /* We're at least a 386 */
1021 info
->FeatureSet
= CPU_FEATURE_VME
| CPU_FEATURE_X86
| CPU_FEATURE_PGE
;
1024 if (!have_cpuid()) return;
1026 do_cpuid(0x00000000, regs
); /* get standard cpuid level and vendor name */
1027 if (regs
[0]>=0x00000001) /* Check for supported cpuid version */
1029 do_cpuid(0x00000001, regs2
); /* get cpu features */
1031 if(regs2
[3] & (1 << 3 )) info
->FeatureSet
|= CPU_FEATURE_PSE
;
1032 if(regs2
[3] & (1 << 4 )) info
->FeatureSet
|= CPU_FEATURE_TSC
;
1033 if(regs2
[3] & (1 << 8 )) info
->FeatureSet
|= CPU_FEATURE_CX8
;
1034 if(regs2
[3] & (1 << 11)) info
->FeatureSet
|= CPU_FEATURE_SEP
;
1035 if(regs2
[3] & (1 << 12)) info
->FeatureSet
|= CPU_FEATURE_MTRR
;
1036 if(regs2
[3] & (1 << 15)) info
->FeatureSet
|= CPU_FEATURE_CMOV
;
1037 if(regs2
[3] & (1 << 16)) info
->FeatureSet
|= CPU_FEATURE_PAT
;
1038 if(regs2
[3] & (1 << 23)) info
->FeatureSet
|= CPU_FEATURE_MMX
;
1039 if(regs2
[3] & (1 << 24)) info
->FeatureSet
|= CPU_FEATURE_FXSR
;
1040 if(regs2
[3] & (1 << 25)) info
->FeatureSet
|= CPU_FEATURE_SSE
;
1041 if(regs2
[3] & (1 << 26)) info
->FeatureSet
|= CPU_FEATURE_SSE2
;
1043 user_shared_data
->ProcessorFeatures
[PF_FLOATING_POINT_EMULATED
] = !(regs2
[3] & 1);
1044 user_shared_data
->ProcessorFeatures
[PF_RDTSC_INSTRUCTION_AVAILABLE
] = (regs2
[3] >> 4) & 1;
1045 user_shared_data
->ProcessorFeatures
[PF_PAE_ENABLED
] = (regs2
[3] >> 6) & 1;
1046 user_shared_data
->ProcessorFeatures
[PF_COMPARE_EXCHANGE_DOUBLE
] = (regs2
[3] >> 8) & 1;
1047 user_shared_data
->ProcessorFeatures
[PF_MMX_INSTRUCTIONS_AVAILABLE
] = (regs2
[3] >> 23) & 1;
1048 user_shared_data
->ProcessorFeatures
[PF_XMMI_INSTRUCTIONS_AVAILABLE
] = (regs2
[3] >> 25) & 1;
1049 user_shared_data
->ProcessorFeatures
[PF_XMMI64_INSTRUCTIONS_AVAILABLE
] = (regs2
[3] >> 26) & 1;
1050 user_shared_data
->ProcessorFeatures
[PF_SSE3_INSTRUCTIONS_AVAILABLE
] = regs2
[2] & 1;
1051 user_shared_data
->ProcessorFeatures
[PF_XSAVE_ENABLED
] = (regs2
[2] >> 27) & 1;
1052 user_shared_data
->ProcessorFeatures
[PF_COMPARE_EXCHANGE128
] = (regs2
[2] >> 13) & 1;
1054 if((regs2
[3] & (1 << 26)) && (regs2
[3] & (1 << 24))) /* has SSE2 and FXSAVE/FXRSTOR */
1055 user_shared_data
->ProcessorFeatures
[PF_SSE_DAZ_MODE_AVAILABLE
] = have_sse_daz_mode();
1057 if (regs
[1] == AUTH
&& regs
[3] == ENTI
&& regs
[2] == CAMD
)
1059 info
->Level
= (regs2
[0] >> 8) & 0xf; /* family */
1060 if (info
->Level
== 0xf) /* AMD says to add the extended family to the family if family is 0xf */
1061 info
->Level
+= (regs2
[0] >> 20) & 0xff;
1063 /* repack model and stepping to make a "revision" */
1064 info
->Revision
= ((regs2
[0] >> 16) & 0xf) << 12; /* extended model */
1065 info
->Revision
|= ((regs2
[0] >> 4 ) & 0xf) << 8; /* model */
1066 info
->Revision
|= regs2
[0] & 0xf; /* stepping */
1068 do_cpuid(0x80000000, regs
); /* get vendor cpuid level */
1069 if (regs
[0] >= 0x80000001)
1071 do_cpuid(0x80000001, regs2
); /* get vendor features */
1072 user_shared_data
->ProcessorFeatures
[PF_VIRT_FIRMWARE_ENABLED
] = (regs2
[2] >> 2) & 1;
1073 user_shared_data
->ProcessorFeatures
[PF_NX_ENABLED
] = (regs2
[3] >> 20) & 1;
1074 user_shared_data
->ProcessorFeatures
[PF_3DNOW_INSTRUCTIONS_AVAILABLE
] = (regs2
[3] >> 31) & 1;
1075 if (regs2
[3] >> 31) info
->FeatureSet
|= CPU_FEATURE_3DNOW
;
1078 else if (regs
[1] == GENU
&& regs
[3] == INEI
&& regs
[2] == NTEL
)
1080 info
->Level
= ((regs2
[0] >> 8) & 0xf) + ((regs2
[0] >> 20) & 0xff); /* family + extended family */
1081 if(info
->Level
== 15) info
->Level
= 6;
1083 /* repack model and stepping to make a "revision" */
1084 info
->Revision
= ((regs2
[0] >> 16) & 0xf) << 12; /* extended model */
1085 info
->Revision
|= ((regs2
[0] >> 4 ) & 0xf) << 8; /* model */
1086 info
->Revision
|= regs2
[0] & 0xf; /* stepping */
1088 if(regs2
[3] & (1 << 21)) info
->FeatureSet
|= CPU_FEATURE_DS
;
1089 user_shared_data
->ProcessorFeatures
[PF_VIRT_FIRMWARE_ENABLED
] = (regs2
[2] >> 5) & 1;
1091 do_cpuid(0x80000000, regs
); /* get vendor cpuid level */
1092 if (regs
[0] >= 0x80000001)
1094 do_cpuid(0x80000001, regs2
); /* get vendor features */
1095 user_shared_data
->ProcessorFeatures
[PF_NX_ENABLED
] = (regs2
[3] >> 20) & 1;
1100 info
->Level
= (regs2
[0] >> 8) & 0xf; /* family */
1102 /* repack model and stepping to make a "revision" */
1103 info
->Revision
= ((regs2
[0] >> 4 ) & 0xf) << 8; /* model */
1104 info
->Revision
|= regs2
[0] & 0xf; /* stepping */
1109 #elif defined(__powerpc__) || defined(__ppc__)
1111 static inline void get_cpuinfo(SYSTEM_CPU_INFORMATION
* info
)
1117 valSize
= sizeof(value
);
1118 if (sysctlbyname("hw.optional.floatingpoint", &value
, &valSize
, NULL
, 0) == 0)
1119 user_shared_data
->ProcessorFeatures
[PF_FLOATING_POINT_EMULATED
] = !value
;
1121 valSize
= sizeof(value
);
1122 if (sysctlbyname("hw.cpusubtype", &value
, &valSize
, NULL
, 0) == 0)
1126 case CPU_SUBTYPE_POWERPC_601
:
1127 case CPU_SUBTYPE_POWERPC_602
: info
->Level
= 1; break;
1128 case CPU_SUBTYPE_POWERPC_603
: info
->Level
= 3; break;
1129 case CPU_SUBTYPE_POWERPC_603e
:
1130 case CPU_SUBTYPE_POWERPC_603ev
: info
->Level
= 6; break;
1131 case CPU_SUBTYPE_POWERPC_604
: info
->Level
= 4; break;
1132 case CPU_SUBTYPE_POWERPC_604e
: info
->Level
= 9; break;
1133 case CPU_SUBTYPE_POWERPC_620
: info
->Level
= 20; break;
1134 case CPU_SUBTYPE_POWERPC_750
: /* G3/G4 derive from 603 so ... */
1135 case CPU_SUBTYPE_POWERPC_7400
:
1136 case CPU_SUBTYPE_POWERPC_7450
: info
->Level
= 6; break;
1137 case CPU_SUBTYPE_POWERPC_970
: info
->Level
= 9;
1138 /* :o) user_shared_data->ProcessorFeatures[PF_ALTIVEC_INSTRUCTIONS_AVAILABLE] ;-) */
1144 FIXME("CPU Feature detection not implemented.\n");
1146 info
->Architecture
= PROCESSOR_ARCHITECTURE_PPC
;
1149 #elif defined(__arm__)
1151 static inline void get_cpuinfo(SYSTEM_CPU_INFORMATION
* info
)
1156 FILE *f
= fopen("/proc/cpuinfo", "r");
1159 while (fgets(line
, sizeof(line
), f
) != NULL
)
1161 /* NOTE: the ':' is the only character we can rely on */
1162 if (!(value
= strchr(line
,':')))
1164 /* terminate the valuename */
1166 while ((s
>= line
) && isspace(*s
)) s
--;
1168 /* and strip leading spaces from value */
1170 while (isspace(*value
)) value
++;
1171 if ((s
= strchr(value
,'\n')))
1173 if (!strcasecmp(line
, "CPU architecture"))
1175 if (isdigit(value
[0]))
1176 info
->Level
= atoi(value
);
1179 if (!strcasecmp(line
, "CPU revision"))
1181 if (isdigit(value
[0]))
1182 info
->Revision
= atoi(value
);
1185 if (!strcasecmp(line
, "features"))
1187 if (strstr(value
, "vfpv3"))
1188 user_shared_data
->ProcessorFeatures
[PF_ARM_VFP_32_REGISTERS_AVAILABLE
] = TRUE
;
1189 if (strstr(value
, "neon"))
1190 user_shared_data
->ProcessorFeatures
[PF_ARM_NEON_INSTRUCTIONS_AVAILABLE
] = TRUE
;
1196 #elif defined(__FreeBSD__)
1201 valsize
= sizeof(buf
);
1202 if (!sysctlbyname("hw.machine_arch", &buf
, &valsize
, NULL
, 0) &&
1203 sscanf(buf
, "armv%i", &value
) == 1)
1204 info
->Level
= value
;
1206 valsize
= sizeof(value
);
1207 if (!sysctlbyname("hw.floatingpoint", &value
, &valsize
, NULL
, 0))
1208 user_shared_data
->ProcessorFeatures
[PF_ARM_VFP_32_REGISTERS_AVAILABLE
] = value
;
1210 FIXME("CPU Feature detection not implemented.\n");
1212 if (info
->Level
>= 8)
1213 user_shared_data
->ProcessorFeatures
[PF_ARM_V8_INSTRUCTIONS_AVAILABLE
] = TRUE
;
1214 info
->Architecture
= PROCESSOR_ARCHITECTURE_ARM
;
1217 #elif defined(__aarch64__)
1219 static inline void get_cpuinfo(SYSTEM_CPU_INFORMATION
* info
)
1224 FILE *f
= fopen("/proc/cpuinfo", "r");
1227 while (fgets(line
, sizeof(line
), f
) != NULL
)
1229 /* NOTE: the ':' is the only character we can rely on */
1230 if (!(value
= strchr(line
,':')))
1232 /* terminate the valuename */
1234 while ((s
>= line
) && isspace(*s
)) s
--;
1236 /* and strip leading spaces from value */
1238 while (isspace(*value
)) value
++;
1239 if ((s
= strchr(value
,'\n')))
1241 if (!strcasecmp(line
, "CPU architecture"))
1243 if (isdigit(value
[0]))
1244 info
->Level
= atoi(value
);
1247 if (!strcasecmp(line
, "CPU revision"))
1249 if (isdigit(value
[0]))
1250 info
->Revision
= atoi(value
);
1253 if (!strcasecmp(line
, "Features"))
1255 if (strstr(value
, "crc32"))
1256 user_shared_data
->ProcessorFeatures
[PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE
] = TRUE
;
1257 if (strstr(value
, "aes"))
1258 user_shared_data
->ProcessorFeatures
[PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE
] = TRUE
;
1265 FIXME("CPU Feature detection not implemented.\n");
1267 info
->Level
= max(info
->Level
, 8);
1268 user_shared_data
->ProcessorFeatures
[PF_ARM_V8_INSTRUCTIONS_AVAILABLE
] = TRUE
;
1269 info
->Architecture
= PROCESSOR_ARCHITECTURE_ARM64
;
1272 #endif /* End architecture specific feature detection for CPUs */
1274 /******************************************************************
1277 * inits a couple of places with CPU related information:
1278 * - cached_sci in this file
1279 * - Peb->NumberOfProcessors
1280 * - SharedUserData->ProcessFeatures[] array
1282 void fill_cpu_info(void)
1286 #ifdef _SC_NPROCESSORS_ONLN
1287 num
= sysconf(_SC_NPROCESSORS_ONLN
);
1291 WARN("Failed to detect the number of processors.\n");
1293 #elif defined(CTL_HW) && defined(HW_NCPU)
1295 size_t len
= sizeof(num
);
1298 if (sysctl(mib
, 2, &num
, &len
, NULL
, 0) != 0)
1301 WARN("Failed to detect the number of processors.\n");
1305 FIXME("Detecting the number of processors is not supported.\n");
1307 NtCurrentTeb()->Peb
->NumberOfProcessors
= num
;
1309 memset(&cached_sci
, 0, sizeof(cached_sci
));
1310 get_cpuinfo(&cached_sci
);
1312 TRACE("<- CPU arch %d, level %d, rev %d, features 0x%x\n",
1313 cached_sci
.Architecture
, cached_sci
.Level
, cached_sci
.Revision
, cached_sci
.FeatureSet
);
1316 static BOOL
grow_logical_proc_buf(SYSTEM_LOGICAL_PROCESSOR_INFORMATION
**pdata
,
1317 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
**pdataex
, DWORD
*max_len
)
1321 SYSTEM_LOGICAL_PROCESSOR_INFORMATION
*new_data
;
1324 new_data
= RtlReAllocateHeap(GetProcessHeap(), 0, *pdata
, *max_len
*sizeof(*new_data
));
1332 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*new_dataex
;
1335 new_dataex
= RtlReAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, *pdataex
, *max_len
*sizeof(*new_dataex
));
1339 *pdataex
= new_dataex
;
1345 static DWORD
log_proc_ex_size_plus(DWORD size
)
1347 /* add SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX.Relationship and .Size */
1348 return sizeof(LOGICAL_PROCESSOR_RELATIONSHIP
) + sizeof(DWORD
) + size
;
1351 static DWORD
count_bits(ULONG_PTR mask
)
1362 /* Store package and core information for a logical processor. Parsing of processor
1363 * data may happen in multiple passes; the 'id' parameter is then used to locate
1364 * previously stored data. The type of data stored in 'id' depends on 'rel':
1365 * - RelationProcessorPackage: package id ('CPU socket').
1366 * - RelationProcessorCore: physical core number.
1368 static inline BOOL
logical_proc_info_add_by_id(SYSTEM_LOGICAL_PROCESSOR_INFORMATION
**pdata
,
1369 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
**pdataex
, DWORD
*len
, DWORD
*pmax_len
,
1370 LOGICAL_PROCESSOR_RELATIONSHIP rel
, DWORD id
, ULONG_PTR mask
)
1375 for (i
=0; i
<*len
; i
++)
1377 if (rel
== RelationProcessorPackage
&& (*pdata
)[i
].Relationship
== rel
&& (*pdata
)[i
].u
.Reserved
[1] == id
)
1379 (*pdata
)[i
].ProcessorMask
|= mask
;
1382 else if (rel
== RelationProcessorCore
&& (*pdata
)[i
].Relationship
== rel
&& (*pdata
)[i
].u
.Reserved
[1] == id
)
1386 while(*len
== *pmax_len
)
1388 if (!grow_logical_proc_buf(pdata
, NULL
, pmax_len
))
1392 (*pdata
)[i
].Relationship
= rel
;
1393 (*pdata
)[i
].ProcessorMask
= mask
;
1394 if (rel
== RelationProcessorCore
)
1395 (*pdata
)[i
].u
.ProcessorCore
.Flags
= count_bits(mask
) > 1 ? LTP_PC_SMT
: 0;
1396 (*pdata
)[i
].u
.Reserved
[0] = 0;
1397 (*pdata
)[i
].u
.Reserved
[1] = id
;
1400 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*dataex
;
1405 dataex
= (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*)(((char *)*pdataex
) + ofs
);
1406 if (rel
== RelationProcessorPackage
&& dataex
->Relationship
== rel
&& dataex
->u
.Processor
.Reserved
[1] == id
)
1408 dataex
->u
.Processor
.GroupMask
[0].Mask
|= mask
;
1411 else if (rel
== RelationProcessorCore
&& dataex
->Relationship
== rel
&& dataex
->u
.Processor
.Reserved
[1] == id
)
1415 ofs
+= dataex
->Size
;
1418 /* TODO: For now, just one group. If more than 64 processors, then we
1419 * need another group. */
1421 while (ofs
+ log_proc_ex_size_plus(sizeof(PROCESSOR_RELATIONSHIP
)) > *pmax_len
)
1423 if (!grow_logical_proc_buf(NULL
, pdataex
, pmax_len
))
1427 dataex
= (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*)(((char *)*pdataex
) + ofs
);
1429 dataex
->Relationship
= rel
;
1430 dataex
->Size
= log_proc_ex_size_plus(sizeof(PROCESSOR_RELATIONSHIP
));
1431 if (rel
== RelationProcessorCore
)
1432 dataex
->u
.Processor
.Flags
= count_bits(mask
) > 1 ? LTP_PC_SMT
: 0;
1434 dataex
->u
.Processor
.Flags
= 0;
1435 dataex
->u
.Processor
.EfficiencyClass
= 0;
1436 dataex
->u
.Processor
.GroupCount
= 1;
1437 dataex
->u
.Processor
.GroupMask
[0].Mask
= mask
;
1438 dataex
->u
.Processor
.GroupMask
[0].Group
= 0;
1439 /* mark for future lookup */
1440 dataex
->u
.Processor
.Reserved
[0] = 0;
1441 dataex
->u
.Processor
.Reserved
[1] = id
;
1443 *len
+= dataex
->Size
;
1449 static inline BOOL
logical_proc_info_add_cache(SYSTEM_LOGICAL_PROCESSOR_INFORMATION
**pdata
,
1450 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
**pdataex
, DWORD
*len
,
1451 DWORD
*pmax_len
, ULONG_PTR mask
, CACHE_DESCRIPTOR
*cache
)
1457 for (i
=0; i
<*len
; i
++)
1459 if ((*pdata
)[i
].Relationship
==RelationCache
&& (*pdata
)[i
].ProcessorMask
==mask
1460 && (*pdata
)[i
].u
.Cache
.Level
==cache
->Level
&& (*pdata
)[i
].u
.Cache
.Type
==cache
->Type
)
1464 while (*len
== *pmax_len
)
1465 if (!grow_logical_proc_buf(pdata
, NULL
, pmax_len
))
1468 (*pdata
)[i
].Relationship
= RelationCache
;
1469 (*pdata
)[i
].ProcessorMask
= mask
;
1470 (*pdata
)[i
].u
.Cache
= *cache
;
1475 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*dataex
;
1478 for (ofs
= 0; ofs
< *len
; )
1480 dataex
= (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*)(((char *)*pdataex
) + ofs
);
1481 if (dataex
->Relationship
== RelationCache
&& dataex
->u
.Cache
.GroupMask
.Mask
== mask
&&
1482 dataex
->u
.Cache
.Level
== cache
->Level
&& dataex
->u
.Cache
.Type
== cache
->Type
)
1484 ofs
+= dataex
->Size
;
1487 while (ofs
+ log_proc_ex_size_plus(sizeof(CACHE_RELATIONSHIP
)) > *pmax_len
)
1489 if (!grow_logical_proc_buf(NULL
, pdataex
, pmax_len
))
1493 dataex
= (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*)(((char *)*pdataex
) + ofs
);
1495 dataex
->Relationship
= RelationCache
;
1496 dataex
->Size
= log_proc_ex_size_plus(sizeof(CACHE_RELATIONSHIP
));
1497 dataex
->u
.Cache
.Level
= cache
->Level
;
1498 dataex
->u
.Cache
.Associativity
= cache
->Associativity
;
1499 dataex
->u
.Cache
.LineSize
= cache
->LineSize
;
1500 dataex
->u
.Cache
.CacheSize
= cache
->Size
;
1501 dataex
->u
.Cache
.Type
= cache
->Type
;
1502 dataex
->u
.Cache
.GroupMask
.Mask
= mask
;
1503 dataex
->u
.Cache
.GroupMask
.Group
= 0;
1505 *len
+= dataex
->Size
;
1511 static inline BOOL
logical_proc_info_add_numa_node(SYSTEM_LOGICAL_PROCESSOR_INFORMATION
**pdata
,
1512 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
**pdataex
, DWORD
*len
, DWORD
*pmax_len
, ULONG_PTR mask
,
1517 while (*len
== *pmax_len
)
1518 if (!grow_logical_proc_buf(pdata
, NULL
, pmax_len
))
1521 (*pdata
)[*len
].Relationship
= RelationNumaNode
;
1522 (*pdata
)[*len
].ProcessorMask
= mask
;
1523 (*pdata
)[*len
].u
.NumaNode
.NodeNumber
= node_id
;
1528 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*dataex
;
1530 while (*len
+ log_proc_ex_size_plus(sizeof(NUMA_NODE_RELATIONSHIP
)) > *pmax_len
)
1532 if (!grow_logical_proc_buf(NULL
, pdataex
, pmax_len
))
1536 dataex
= (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*)(((char *)*pdataex
) + *len
);
1538 dataex
->Relationship
= RelationNumaNode
;
1539 dataex
->Size
= log_proc_ex_size_plus(sizeof(NUMA_NODE_RELATIONSHIP
));
1540 dataex
->u
.NumaNode
.NodeNumber
= node_id
;
1541 dataex
->u
.NumaNode
.GroupMask
.Mask
= mask
;
1542 dataex
->u
.NumaNode
.GroupMask
.Group
= 0;
1544 *len
+= dataex
->Size
;
1550 static inline BOOL
logical_proc_info_add_group(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
**pdataex
,
1551 DWORD
*len
, DWORD
*pmax_len
, DWORD num_cpus
, ULONG_PTR mask
)
1553 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*dataex
;
1555 while (*len
+ log_proc_ex_size_plus(sizeof(GROUP_RELATIONSHIP
)) > *pmax_len
)
1557 if (!grow_logical_proc_buf(NULL
, pdataex
, pmax_len
))
1561 dataex
= (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*)(((char *)*pdataex
) + *len
);
1563 dataex
->Relationship
= RelationGroup
;
1564 dataex
->Size
= log_proc_ex_size_plus(sizeof(GROUP_RELATIONSHIP
));
1565 dataex
->u
.Group
.MaximumGroupCount
= 1;
1566 dataex
->u
.Group
.ActiveGroupCount
= 1;
1567 dataex
->u
.Group
.GroupInfo
[0].MaximumProcessorCount
= num_cpus
;
1568 dataex
->u
.Group
.GroupInfo
[0].ActiveProcessorCount
= num_cpus
;
1569 dataex
->u
.Group
.GroupInfo
[0].ActiveProcessorMask
= mask
;
1571 *len
+= dataex
->Size
;
1577 /* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
1578 static NTSTATUS
create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION
**data
,
1579 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
**dataex
, DWORD
*max_len
)
1581 static const char core_info
[] = "/sys/devices/system/cpu/cpu%u/topology/%s";
1582 static const char cache_info
[] = "/sys/devices/system/cpu/cpu%u/cache/index%u/%s";
1583 static const char numa_info
[] = "/sys/devices/system/node/node%u/cpumap";
1585 FILE *fcpu_list
, *fnuma_list
, *f
;
1586 DWORD len
= 0, beg
, end
, i
, j
, r
, num_cpus
= 0;
1587 char op
, name
[MAX_PATH
];
1588 ULONG_PTR all_cpus_mask
= 0;
1590 fcpu_list
= fopen("/sys/devices/system/cpu/online", "r");
1592 return STATUS_NOT_IMPLEMENTED
;
1594 while(!feof(fcpu_list
))
1596 if(!fscanf(fcpu_list
, "%u%c ", &beg
, &op
))
1598 if(op
== '-') fscanf(fcpu_list
, "%u%c ", &end
, &op
);
1601 for(i
=beg
; i
<=end
; i
++)
1603 DWORD phys_core
= 0;
1604 ULONG_PTR thread_mask
= 0;
1606 if(i
> 8*sizeof(ULONG_PTR
))
1608 FIXME("skipping logical processor %d\n", i
);
1612 sprintf(name
, core_info
, i
, "physical_package_id");
1613 f
= fopen(name
, "r");
1616 fscanf(f
, "%u", &r
);
1620 if(!logical_proc_info_add_by_id(data
, dataex
, &len
, max_len
, RelationProcessorPackage
, r
, (ULONG_PTR
)1 << i
))
1623 return STATUS_NO_MEMORY
;
1626 /* Sysfs enumerates logical cores (and not physical cores), but Windows enumerates
1627 * by physical core. Upon enumerating a logical core in sysfs, we register a physical
1628 * core and all its logical cores. In order to not report physical cores multiple
1629 * times, we pass a unique physical core ID to logical_proc_info_add_by_id and let
1630 * that call figure out any duplication.
1631 * Obtain a unique physical core ID from the first element of thread_siblings_list.
1632 * This list provides logical cores sharing the same physical core. The IDs are based
1633 * on kernel cpu core numbering as opposed to a hardware core ID like provided through
1634 * 'core_id', so are suitable as a unique ID.
1636 sprintf(name
, core_info
, i
, "thread_siblings_list");
1637 f
= fopen(name
, "r");
1640 fscanf(f
, "%d%c", &phys_core
, &op
);
1645 /* Mask of logical threads sharing same physical core in kernel core numbering. */
1646 sprintf(name
, core_info
, i
, "thread_siblings");
1647 f
= fopen(name
, "r");
1650 fscanf(f
, "%lx", &thread_mask
);
1653 else thread_mask
= 1<<i
;
1654 if(!logical_proc_info_add_by_id(data
, dataex
, &len
, max_len
, RelationProcessorCore
, phys_core
, thread_mask
))
1657 return STATUS_NO_MEMORY
;
1662 CACHE_DESCRIPTOR cache
;
1665 sprintf(name
, cache_info
, i
, j
, "shared_cpu_map");
1666 f
= fopen(name
, "r");
1670 if(!fscanf(f
, "%x%c ", &r
, &op
))
1672 mask
= (sizeof(ULONG_PTR
)>sizeof(int) ? mask
<<(8*sizeof(DWORD
)) : 0) + r
;
1676 sprintf(name
, cache_info
, i
, j
, "level");
1677 f
= fopen(name
, "r");
1679 fscanf(f
, "%u", &r
);
1683 sprintf(name
, cache_info
, i
, j
, "ways_of_associativity");
1684 f
= fopen(name
, "r");
1686 fscanf(f
, "%u", &r
);
1688 cache
.Associativity
= r
;
1690 sprintf(name
, cache_info
, i
, j
, "coherency_line_size");
1691 f
= fopen(name
, "r");
1693 fscanf(f
, "%u", &r
);
1697 sprintf(name
, cache_info
, i
, j
, "size");
1698 f
= fopen(name
, "r");
1700 fscanf(f
, "%u%c", &r
, &op
);
1703 WARN("unknown cache size %u%c\n", r
, op
);
1704 cache
.Size
= (op
=='K' ? r
*1024 : r
);
1706 sprintf(name
, cache_info
, i
, j
, "type");
1707 f
= fopen(name
, "r");
1709 fscanf(f
, "%s", name
);
1711 if(!memcmp(name
, "Data", 5))
1712 cache
.Type
= CacheData
;
1713 else if(!memcmp(name
, "Instruction", 11))
1714 cache
.Type
= CacheInstruction
;
1716 cache
.Type
= CacheUnified
;
1718 if(!logical_proc_info_add_cache(data
, dataex
, &len
, max_len
, mask
, &cache
))
1721 return STATUS_NO_MEMORY
;
1729 for(i
=0; i
<len
; i
++){
1730 if((*data
)[i
].Relationship
== RelationProcessorCore
){
1731 all_cpus_mask
|= (*data
)[i
].ProcessorMask
;
1735 for(i
= 0; i
< len
; ){
1736 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*infoex
= (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*)(((char *)*dataex
) + i
);
1737 if(infoex
->Relationship
== RelationProcessorCore
){
1738 all_cpus_mask
|= infoex
->u
.Processor
.GroupMask
[0].Mask
;
1743 num_cpus
= count_bits(all_cpus_mask
);
1745 fnuma_list
= fopen("/sys/devices/system/node/online", "r");
1748 if(!logical_proc_info_add_numa_node(data
, dataex
, &len
, max_len
, all_cpus_mask
, 0))
1749 return STATUS_NO_MEMORY
;
1753 while(!feof(fnuma_list
))
1755 if(!fscanf(fnuma_list
, "%u%c ", &beg
, &op
))
1757 if(op
== '-') fscanf(fnuma_list
, "%u%c ", &end
, &op
);
1760 for(i
=beg
; i
<=end
; i
++)
1764 sprintf(name
, numa_info
, i
);
1765 f
= fopen(name
, "r");
1769 if(!fscanf(f
, "%x%c ", &r
, &op
))
1771 mask
= (sizeof(ULONG_PTR
)>sizeof(int) ? mask
<<(8*sizeof(DWORD
)) : 0) + r
;
1775 if(!logical_proc_info_add_numa_node(data
, dataex
, &len
, max_len
, mask
, i
))
1778 return STATUS_NO_MEMORY
;
1786 logical_proc_info_add_group(dataex
, &len
, max_len
, num_cpus
, all_cpus_mask
);
1789 *max_len
= len
* sizeof(**data
);
1793 return STATUS_SUCCESS
;
1795 #elif defined(__APPLE__)
1796 /* for 'data', max_len is the array count. for 'dataex', max_len is in bytes */
1797 static NTSTATUS
create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION
**data
,
1798 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
**dataex
, DWORD
*max_len
)
1800 DWORD pkgs_no
, cores_no
, lcpu_no
, lcpu_per_core
, cores_per_package
, assoc
, len
= 0;
1801 DWORD cache_ctrs
[10] = {0};
1802 ULONG_PTR all_cpus_mask
= 0;
1803 CACHE_DESCRIPTOR cache
[10];
1804 LONGLONG cache_size
, cache_line_size
, cache_sharing
[10];
1808 lcpu_no
= NtCurrentTeb()->Peb
->NumberOfProcessors
;
1810 size
= sizeof(pkgs_no
);
1811 if(sysctlbyname("hw.packages", &pkgs_no
, &size
, NULL
, 0))
1814 size
= sizeof(cores_no
);
1815 if(sysctlbyname("hw.physicalcpu", &cores_no
, &size
, NULL
, 0))
1818 TRACE("%u logical CPUs from %u physical cores across %u packages\n",
1819 lcpu_no
, cores_no
, pkgs_no
);
1821 lcpu_per_core
= lcpu_no
/ cores_no
;
1822 cores_per_package
= cores_no
/ pkgs_no
;
1824 memset(cache
, 0, sizeof(cache
));
1826 cache
[1].Type
= CacheInstruction
;
1827 cache
[1].Associativity
= 8; /* reasonable default */
1828 cache
[1].LineSize
= 0x40; /* reasonable default */
1830 cache
[2].Type
= CacheData
;
1831 cache
[2].Associativity
= 8;
1832 cache
[2].LineSize
= 0x40;
1834 cache
[3].Type
= CacheUnified
;
1835 cache
[3].Associativity
= 8;
1836 cache
[3].LineSize
= 0x40;
1838 cache
[4].Type
= CacheUnified
;
1839 cache
[4].Associativity
= 12;
1840 cache
[4].LineSize
= 0x40;
1842 size
= sizeof(cache_line_size
);
1843 if(!sysctlbyname("hw.cachelinesize", &cache_line_size
, &size
, NULL
, 0))
1846 cache
[i
].LineSize
= cache_line_size
;
1849 /* TODO: set actual associativity for all caches */
1850 size
= sizeof(assoc
);
1851 if(!sysctlbyname("machdep.cpu.cache.L2_associativity", &assoc
, &size
, NULL
, 0))
1852 cache
[3].Associativity
= assoc
;
1854 size
= sizeof(cache_size
);
1855 if(!sysctlbyname("hw.l1icachesize", &cache_size
, &size
, NULL
, 0))
1856 cache
[1].Size
= cache_size
;
1857 size
= sizeof(cache_size
);
1858 if(!sysctlbyname("hw.l1dcachesize", &cache_size
, &size
, NULL
, 0))
1859 cache
[2].Size
= cache_size
;
1860 size
= sizeof(cache_size
);
1861 if(!sysctlbyname("hw.l2cachesize", &cache_size
, &size
, NULL
, 0))
1862 cache
[3].Size
= cache_size
;
1863 size
= sizeof(cache_size
);
1864 if(!sysctlbyname("hw.l3cachesize", &cache_size
, &size
, NULL
, 0))
1865 cache
[4].Size
= cache_size
;
1867 size
= sizeof(cache_sharing
);
1868 if(sysctlbyname("hw.cacheconfig", cache_sharing
, &size
, NULL
, 0) < 0){
1869 cache_sharing
[1] = lcpu_per_core
;
1870 cache_sharing
[2] = lcpu_per_core
;
1871 cache_sharing
[3] = lcpu_per_core
;
1872 cache_sharing
[4] = lcpu_no
;
1874 /* in cache[], indexes 1 and 2 are l1 caches */
1875 cache_sharing
[4] = cache_sharing
[3];
1876 cache_sharing
[3] = cache_sharing
[2];
1877 cache_sharing
[2] = cache_sharing
[1];
1880 for(p
= 0; p
< pkgs_no
; ++p
){
1881 for(j
= 0; j
< cores_per_package
&& p
* cores_per_package
+ j
< cores_no
; ++j
){
1885 for(k
= 0; k
< lcpu_per_core
; ++k
)
1886 mask
|= (ULONG_PTR
)1 << (j
* lcpu_per_core
+ k
);
1888 all_cpus_mask
|= mask
;
1890 /* add to package */
1891 if(!logical_proc_info_add_by_id(data
, dataex
, &len
, max_len
, RelationProcessorPackage
, p
, mask
))
1892 return STATUS_NO_MEMORY
;
1895 phys_core
= p
* cores_per_package
+ j
;
1896 if(!logical_proc_info_add_by_id(data
, dataex
, &len
, max_len
, RelationProcessorCore
, phys_core
, mask
))
1897 return STATUS_NO_MEMORY
;
1899 for(i
= 1; i
< 5; ++i
){
1900 if(cache_ctrs
[i
] == 0 && cache
[i
].Size
> 0){
1902 for(k
= 0; k
< cache_sharing
[i
]; ++k
)
1903 mask
|= (ULONG_PTR
)1 << (j
* lcpu_per_core
+ k
);
1905 if(!logical_proc_info_add_cache(data
, dataex
, &len
, max_len
, mask
, &cache
[i
]))
1906 return STATUS_NO_MEMORY
;
1909 cache_ctrs
[i
] += lcpu_per_core
;
1911 if(cache_ctrs
[i
] == cache_sharing
[i
])
1917 /* OSX doesn't support NUMA, so just make one NUMA node for all CPUs */
1918 if(!logical_proc_info_add_numa_node(data
, dataex
, &len
, max_len
, all_cpus_mask
, 0))
1919 return STATUS_NO_MEMORY
;
1922 logical_proc_info_add_group(dataex
, &len
, max_len
, lcpu_no
, all_cpus_mask
);
1925 *max_len
= len
* sizeof(**data
);
1929 return STATUS_SUCCESS
;
1932 static NTSTATUS
create_logical_proc_info(SYSTEM_LOGICAL_PROCESSOR_INFORMATION
**data
,
1933 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
**dataex
, DWORD
*max_len
)
1936 return STATUS_NOT_IMPLEMENTED
;
1942 static inline void copy_smbios_string(char **buffer
, char *s
, size_t len
)
1945 memcpy(*buffer
, s
, len
+ 1);
1949 static size_t get_smbios_string(const char *path
, char *str
, size_t size
)
1954 if (!(file
= fopen(path
, "r")))
1957 len
= fread(str
, 1, size
- 1, file
);
1960 if (len
>= 1 && str
[len
- 1] == '\n')
1968 static NTSTATUS
get_firmware_info(SYSTEM_FIRMWARE_TABLE_INFORMATION
*sfti
, ULONG available_len
, ULONG
*required_len
)
1970 switch (sfti
->ProviderSignature
)
1974 char bios_vendor
[128], bios_version
[128], bios_date
[128];
1975 size_t bios_vendor_len
, bios_version_len
, bios_date_len
;
1976 char system_vendor
[128], system_product
[128], system_version
[128], system_serial
[128];
1977 size_t system_vendor_len
, system_product_len
, system_version_len
, system_serial_len
;
1978 char *buffer
= (char*)sfti
->TableBuffer
;
1980 struct smbios_prologue
*prologue
;
1981 struct smbios_bios
*bios
;
1982 struct smbios_system
*system
;
1984 #define S(s) s, sizeof(s)
1985 bios_vendor_len
= get_smbios_string("/sys/class/dmi/id/bios_vendor", S(bios_vendor
));
1986 bios_version_len
= get_smbios_string("/sys/class/dmi/id/bios_version", S(bios_version
));
1987 bios_date_len
= get_smbios_string("/sys/class/dmi/id/bios_date", S(bios_date
));
1988 system_vendor_len
= get_smbios_string("/sys/class/dmi/id/sys_vendor", S(system_vendor
));
1989 system_product_len
= get_smbios_string("/sys/class/dmi/id/product", S(system_product
));
1990 system_version_len
= get_smbios_string("/sys/class/dmi/id/product_version", S(system_version
));
1991 system_serial_len
= get_smbios_string("/sys/class/dmi/id/product_serial", S(system_serial
));
1994 *required_len
= sizeof(struct smbios_prologue
);
1996 *required_len
+= sizeof(struct smbios_bios
);
1997 *required_len
+= max(bios_vendor_len
+ bios_version_len
+ bios_date_len
+ 4, 2);
1999 *required_len
+= sizeof(struct smbios_system
);
2000 *required_len
+= max(system_vendor_len
+ system_product_len
+ system_version_len
+
2001 system_serial_len
+ 5, 2);
2003 sfti
->TableBufferLength
= *required_len
;
2005 *required_len
+= FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION
, TableBuffer
);
2007 if (available_len
< *required_len
)
2008 return STATUS_BUFFER_TOO_SMALL
;
2010 prologue
= (struct smbios_prologue
*)buffer
;
2011 prologue
->calling_method
= 0;
2012 prologue
->major_version
= 2;
2013 prologue
->minor_version
= 0;
2014 prologue
->revision
= 0;
2015 prologue
->length
= sfti
->TableBufferLength
- sizeof(struct smbios_prologue
);
2016 buffer
+= sizeof(struct smbios_prologue
);
2019 bios
= (struct smbios_bios
*)buffer
;
2021 bios
->length
= sizeof(struct smbios_bios
);
2023 bios
->vendor
= bios_vendor_len
? ++string_count
: 0;
2024 bios
->version
= bios_version_len
? ++string_count
: 0;
2026 bios
->date
= bios_date_len
? ++string_count
: 0;
2028 bios
->characteristics
= 0x4; /* not supported */
2029 buffer
+= sizeof(struct smbios_bios
);
2031 copy_smbios_string(&buffer
, bios_vendor
, bios_vendor_len
);
2032 copy_smbios_string(&buffer
, bios_version
, bios_version_len
);
2033 copy_smbios_string(&buffer
, bios_date
, bios_date_len
);
2034 if (!string_count
) *buffer
++ = 0;
2038 system
= (struct smbios_system
*)buffer
;
2040 system
->length
= sizeof(struct smbios_system
);
2042 system
->vendor
= system_vendor_len
? ++string_count
: 0;
2043 system
->product
= system_product_len
? ++string_count
: 0;
2044 system
->version
= system_version_len
? ++string_count
: 0;
2045 system
->serial
= system_serial_len
? ++string_count
: 0;
2046 buffer
+= sizeof(struct smbios_system
);
2048 copy_smbios_string(&buffer
, system_vendor
, system_vendor_len
);
2049 copy_smbios_string(&buffer
, system_product
, system_product_len
);
2050 copy_smbios_string(&buffer
, system_version
, system_version_len
);
2051 copy_smbios_string(&buffer
, system_serial
, system_serial_len
);
2052 if (!string_count
) *buffer
++ = 0;
2055 return STATUS_SUCCESS
;
2059 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION provider %08x\n", sfti
->ProviderSignature
);
2060 return STATUS_NOT_IMPLEMENTED
;
2067 static NTSTATUS
get_firmware_info(SYSTEM_FIRMWARE_TABLE_INFORMATION
*sfti
, ULONG available_len
, ULONG
*required_len
)
2069 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION\n");
2070 sfti
->TableBufferLength
= 0;
2071 return STATUS_NOT_IMPLEMENTED
;
2076 /******************************************************************************
2077 * NtQuerySystemInformation [NTDLL.@]
2078 * ZwQuerySystemInformation [NTDLL.@]
2081 * SystemInformationClass Index to a certain information structure
2082 * SystemTimeAdjustmentInformation SYSTEM_TIME_ADJUSTMENT
2083 * SystemCacheInformation SYSTEM_CACHE_INFORMATION
2084 * SystemConfigurationInformation CONFIGURATION_INFORMATION
2085 * observed (class/len):
2091 * SystemInformation caller supplies storage for the information structure
2092 * Length size of the structure
2093 * ResultLength Data written
2095 NTSTATUS WINAPI
NtQuerySystemInformation(
2096 IN SYSTEM_INFORMATION_CLASS SystemInformationClass
,
2097 OUT PVOID SystemInformation
,
2099 OUT PULONG ResultLength
)
2101 NTSTATUS ret
= STATUS_SUCCESS
;
2104 TRACE("(0x%08x,%p,0x%08x,%p)\n",
2105 SystemInformationClass
,SystemInformation
,Length
,ResultLength
);
2107 switch (SystemInformationClass
)
2109 case SystemBasicInformation
:
2111 SYSTEM_BASIC_INFORMATION sbi
;
2113 virtual_get_system_info( &sbi
);
2118 if (!SystemInformation
) ret
= STATUS_ACCESS_VIOLATION
;
2119 else memcpy( SystemInformation
, &sbi
, len
);
2121 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2124 case SystemCpuInformation
:
2125 if (Length
>= (len
= sizeof(cached_sci
)))
2127 if (!SystemInformation
) ret
= STATUS_ACCESS_VIOLATION
;
2128 else memcpy(SystemInformation
, &cached_sci
, len
);
2130 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2132 case SystemPerformanceInformation
:
2134 SYSTEM_PERFORMANCE_INFORMATION spi
;
2135 static BOOL fixme_written
= FALSE
;
2138 memset(&spi
, 0 , sizeof(spi
));
2141 spi
.Reserved3
= 0x7fffffff; /* Available paged pool memory? */
2143 if ((fp
= fopen("/proc/uptime", "r")))
2145 double uptime
, idle_time
;
2147 fscanf(fp
, "%lf %lf", &uptime
, &idle_time
);
2149 spi
.IdleTime
.QuadPart
= 10000000 * idle_time
;
2153 static ULONGLONG idle
;
2154 /* many programs expect IdleTime to change so fake change */
2155 spi
.IdleTime
.QuadPart
= ++idle
;
2160 if (!SystemInformation
) ret
= STATUS_ACCESS_VIOLATION
;
2161 else memcpy( SystemInformation
, &spi
, len
);
2163 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2164 if(!fixme_written
) {
2165 FIXME("info_class SYSTEM_PERFORMANCE_INFORMATION\n");
2166 fixme_written
= TRUE
;
2170 case SystemTimeOfDayInformation
:
2172 SYSTEM_TIMEOFDAY_INFORMATION sti
;
2174 memset(&sti
, 0 , sizeof(sti
));
2176 /* liKeSystemTime, liExpTimeZoneBias, uCurrentTimeZoneId */
2177 sti
.liKeBootTime
.QuadPart
= server_start_time
;
2179 if (Length
<= sizeof(sti
))
2182 if (!SystemInformation
) ret
= STATUS_ACCESS_VIOLATION
;
2183 else memcpy( SystemInformation
, &sti
, Length
);
2185 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2188 case SystemProcessInformation
:
2190 SYSTEM_PROCESS_INFORMATION
* spi
= SystemInformation
;
2191 SYSTEM_PROCESS_INFORMATION
* last
= NULL
;
2193 WCHAR procname
[1024];
2196 DWORD procstructlen
= 0;
2198 SERVER_START_REQ( create_snapshot
)
2200 req
->flags
= SNAP_PROCESS
| SNAP_THREAD
;
2201 req
->attributes
= 0;
2202 if (!(ret
= wine_server_call( req
)))
2203 hSnap
= wine_server_ptr_handle( reply
->handle
);
2207 while (ret
== STATUS_SUCCESS
)
2209 SERVER_START_REQ( next_process
)
2211 req
->handle
= wine_server_obj_handle( hSnap
);
2212 req
->reset
= (len
== 0);
2213 wine_server_set_reply( req
, procname
, sizeof(procname
)-sizeof(WCHAR
) );
2214 if (!(ret
= wine_server_call( req
)))
2216 /* Make sure procname is 0 terminated */
2217 procname
[wine_server_reply_size(reply
) / sizeof(WCHAR
)] = 0;
2219 /* Get only the executable name, not the path */
2220 if ((exename
= strrchrW(procname
, '\\')) != NULL
) exename
++;
2221 else exename
= procname
;
2223 wlen
= (strlenW(exename
) + 1) * sizeof(WCHAR
);
2225 procstructlen
= sizeof(*spi
) + wlen
+ ((reply
->threads
- 1) * sizeof(SYSTEM_THREAD_INFORMATION
));
2227 if (Length
>= len
+ procstructlen
)
2229 /* ftCreationTime, ftUserTime, ftKernelTime;
2230 * vmCounters, ioCounters
2233 memset(spi
, 0, sizeof(*spi
));
2235 spi
->NextEntryOffset
= procstructlen
- wlen
;
2236 spi
->dwThreadCount
= reply
->threads
;
2238 /* spi->pszProcessName will be set later on */
2240 spi
->dwBasePriority
= reply
->priority
;
2241 spi
->UniqueProcessId
= UlongToHandle(reply
->pid
);
2242 spi
->ParentProcessId
= UlongToHandle(reply
->ppid
);
2243 spi
->HandleCount
= reply
->handles
;
2245 /* spi->ti will be set later on */
2248 len
+= procstructlen
;
2253 if (ret
!= STATUS_SUCCESS
)
2255 if (ret
== STATUS_NO_MORE_FILES
) ret
= STATUS_SUCCESS
;
2263 /* set thread info */
2265 while (ret
== STATUS_SUCCESS
)
2267 SERVER_START_REQ( next_thread
)
2269 req
->handle
= wine_server_obj_handle( hSnap
);
2270 req
->reset
= (j
== 0);
2271 if (!(ret
= wine_server_call( req
)))
2274 if (UlongToHandle(reply
->pid
) == spi
->UniqueProcessId
)
2276 /* ftKernelTime, ftUserTime, ftCreateTime;
2277 * dwTickCount, dwStartAddress
2280 memset(&spi
->ti
[i
], 0, sizeof(spi
->ti
));
2282 spi
->ti
[i
].CreateTime
.QuadPart
= 0xdeadbeef;
2283 spi
->ti
[i
].ClientId
.UniqueProcess
= UlongToHandle(reply
->pid
);
2284 spi
->ti
[i
].ClientId
.UniqueThread
= UlongToHandle(reply
->tid
);
2285 spi
->ti
[i
].dwCurrentPriority
= reply
->base_pri
+ reply
->delta_pri
;
2286 spi
->ti
[i
].dwBasePriority
= reply
->base_pri
;
2293 if (ret
== STATUS_NO_MORE_FILES
) ret
= STATUS_SUCCESS
;
2295 /* now append process name */
2296 spi
->ProcessName
.Buffer
= (WCHAR
*)((char*)spi
+ spi
->NextEntryOffset
);
2297 spi
->ProcessName
.Length
= wlen
- sizeof(WCHAR
);
2298 spi
->ProcessName
.MaximumLength
= wlen
;
2299 memcpy( spi
->ProcessName
.Buffer
, exename
, wlen
);
2300 spi
->NextEntryOffset
+= wlen
;
2303 spi
= (SYSTEM_PROCESS_INFORMATION
*)((char*)spi
+ spi
->NextEntryOffset
);
2306 if (ret
== STATUS_SUCCESS
&& last
) last
->NextEntryOffset
= 0;
2307 if (len
> Length
) ret
= STATUS_INFO_LENGTH_MISMATCH
;
2308 if (hSnap
) NtClose(hSnap
);
2311 case SystemProcessorPerformanceInformation
:
2313 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
*sppi
= NULL
;
2314 unsigned int cpus
= 0;
2315 int out_cpus
= Length
/ sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
);
2320 ret
= STATUS_INFO_LENGTH_MISMATCH
;
2326 processor_cpu_load_info_data_t
*pinfo
;
2327 mach_msg_type_number_t info_count
;
2329 if (host_processor_info (mach_host_self (),
2330 PROCESSOR_CPU_LOAD_INFO
,
2332 (processor_info_array_t
*)&pinfo
,
2336 cpus
= min(cpus
,out_cpus
);
2337 len
= sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
) * cpus
;
2338 sppi
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
2339 for (i
= 0; i
< cpus
; i
++)
2341 sppi
[i
].IdleTime
.QuadPart
= pinfo
[i
].cpu_ticks
[CPU_STATE_IDLE
];
2342 sppi
[i
].KernelTime
.QuadPart
= pinfo
[i
].cpu_ticks
[CPU_STATE_SYSTEM
];
2343 sppi
[i
].UserTime
.QuadPart
= pinfo
[i
].cpu_ticks
[CPU_STATE_USER
];
2345 vm_deallocate (mach_task_self (), (vm_address_t
) pinfo
, info_count
* sizeof(natural_t
));
2350 FILE *cpuinfo
= fopen("/proc/stat", "r");
2353 unsigned long clk_tck
= sysconf(_SC_CLK_TCK
);
2354 unsigned long usr
,nice
,sys
,idle
,remainder
[8];
2359 /* first line is combined usage */
2360 while (fgets(line
,255,cpuinfo
))
2362 count
= sscanf(line
, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
2363 name
, &usr
, &nice
, &sys
, &idle
,
2364 &remainder
[0], &remainder
[1], &remainder
[2], &remainder
[3],
2365 &remainder
[4], &remainder
[5], &remainder
[6], &remainder
[7]);
2367 if (count
< 5 || strncmp( name
, "cpu", 3 )) break;
2368 for (i
= 0; i
+ 5 < count
; ++i
) sys
+= remainder
[i
];
2371 cpus
= atoi( name
+ 3 ) + 1;
2372 if (cpus
> out_cpus
) break;
2373 len
= sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
) * cpus
;
2375 sppi
= RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, sppi
, len
);
2377 sppi
= RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
2379 sppi
[cpus
-1].IdleTime
.QuadPart
= (ULONGLONG
)idle
* 10000000 / clk_tck
;
2380 sppi
[cpus
-1].KernelTime
.QuadPart
= (ULONGLONG
)sys
* 10000000 / clk_tck
;
2381 sppi
[cpus
-1].UserTime
.QuadPart
= (ULONGLONG
)usr
* 10000000 / clk_tck
;
2392 cpus
= min(NtCurrentTeb()->Peb
->NumberOfProcessors
, out_cpus
);
2393 len
= sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
) * cpus
;
2394 sppi
= RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY
, len
);
2395 FIXME("stub info_class SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION\n");
2396 /* many programs expect these values to change so fake change */
2397 for (n
= 0; n
< cpus
; n
++)
2399 sppi
[n
].KernelTime
.QuadPart
= 1 * i
;
2400 sppi
[n
].UserTime
.QuadPart
= 2 * i
;
2401 sppi
[n
].IdleTime
.QuadPart
= 3 * i
;
2408 if (!SystemInformation
) ret
= STATUS_ACCESS_VIOLATION
;
2409 else memcpy( SystemInformation
, sppi
, len
);
2411 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2413 RtlFreeHeap(GetProcessHeap(),0,sppi
);
2416 case SystemModuleInformation
:
2417 /* FIXME: should be system-wide */
2418 if (!SystemInformation
) ret
= STATUS_ACCESS_VIOLATION
;
2419 else ret
= LdrQueryProcessModuleInformation( SystemInformation
, Length
, &len
);
2421 case SystemHandleInformation
:
2423 struct handle_info
*info
;
2424 DWORD i
, num_handles
;
2426 if (Length
< sizeof(SYSTEM_HANDLE_INFORMATION
))
2428 ret
= STATUS_INFO_LENGTH_MISMATCH
;
2432 if (!SystemInformation
)
2434 ret
= STATUS_ACCESS_VIOLATION
;
2438 num_handles
= (Length
- FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION
, Handle
)) / sizeof(SYSTEM_HANDLE_ENTRY
);
2439 if (!(info
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*info
) * num_handles
)))
2440 return STATUS_NO_MEMORY
;
2442 SERVER_START_REQ( get_system_handles
)
2444 wine_server_set_reply( req
, info
, sizeof(*info
) * num_handles
);
2445 if (!(ret
= wine_server_call( req
)))
2447 SYSTEM_HANDLE_INFORMATION
*shi
= SystemInformation
;
2448 shi
->Count
= wine_server_reply_size( req
) / sizeof(*info
);
2449 len
= FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION
, Handle
[shi
->Count
] );
2450 for (i
= 0; i
< shi
->Count
; i
++)
2452 memset( &shi
->Handle
[i
], 0, sizeof(shi
->Handle
[i
]) );
2453 shi
->Handle
[i
].OwnerPid
= info
[i
].owner
;
2454 shi
->Handle
[i
].HandleValue
= info
[i
].handle
;
2455 shi
->Handle
[i
].AccessMask
= info
[i
].access
;
2456 /* FIXME: Fill out ObjectType, HandleFlags, ObjectPointer */
2459 else if (ret
== STATUS_BUFFER_TOO_SMALL
)
2461 len
= FIELD_OFFSET( SYSTEM_HANDLE_INFORMATION
, Handle
[reply
->count
] );
2462 ret
= STATUS_INFO_LENGTH_MISMATCH
;
2467 RtlFreeHeap( GetProcessHeap(), 0, info
);
2470 case SystemCacheInformation
:
2472 SYSTEM_CACHE_INFORMATION sci
;
2474 memset(&sci
, 0, sizeof(sci
)); /* FIXME */
2479 if (!SystemInformation
) ret
= STATUS_ACCESS_VIOLATION
;
2480 else memcpy( SystemInformation
, &sci
, len
);
2482 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2483 FIXME("info_class SYSTEM_CACHE_INFORMATION\n");
2486 case SystemInterruptInformation
:
2488 SYSTEM_INTERRUPT_INFORMATION sii
;
2490 memset(&sii
, 0, sizeof(sii
));
2495 if (!SystemInformation
) ret
= STATUS_ACCESS_VIOLATION
;
2496 else memcpy( SystemInformation
, &sii
, len
);
2498 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2499 FIXME("info_class SYSTEM_INTERRUPT_INFORMATION\n");
2502 case SystemKernelDebuggerInformation
:
2504 SYSTEM_KERNEL_DEBUGGER_INFORMATION skdi
;
2506 skdi
.DebuggerEnabled
= FALSE
;
2507 skdi
.DebuggerNotPresent
= TRUE
;
2512 if (!SystemInformation
) ret
= STATUS_ACCESS_VIOLATION
;
2513 else memcpy( SystemInformation
, &skdi
, len
);
2515 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2518 case SystemRegistryQuotaInformation
:
2520 /* Something to do with the size of the registry *
2521 * Since we don't have a size limitation, fake it *
2522 * This is almost certainly wrong. *
2523 * This sets each of the three words in the struct to 32 MB, *
2524 * which is enough to make the IE 5 installer happy. */
2525 SYSTEM_REGISTRY_QUOTA_INFORMATION srqi
;
2527 srqi
.RegistryQuotaAllowed
= 0x2000000;
2528 srqi
.RegistryQuotaUsed
= 0x200000;
2529 srqi
.Reserved1
= (void*)0x200000;
2534 if (!SystemInformation
) ret
= STATUS_ACCESS_VIOLATION
;
2537 FIXME("SystemRegistryQuotaInformation: faking max registry size of 32 MB\n");
2538 memcpy( SystemInformation
, &srqi
, len
);
2541 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2544 case SystemLogicalProcessorInformation
:
2546 SYSTEM_LOGICAL_PROCESSOR_INFORMATION
*buf
;
2548 /* Each logical processor may use up to 7 entries in returned table:
2549 * core, numa node, package, L1i, L1d, L2, L3 */
2550 len
= 7 * NtCurrentTeb()->Peb
->NumberOfProcessors
;
2551 buf
= RtlAllocateHeap(GetProcessHeap(), 0, len
* sizeof(*buf
));
2554 ret
= STATUS_NO_MEMORY
;
2558 ret
= create_logical_proc_info(&buf
, NULL
, &len
);
2559 if( ret
!= STATUS_SUCCESS
)
2561 RtlFreeHeap(GetProcessHeap(), 0, buf
);
2567 if (!SystemInformation
) ret
= STATUS_ACCESS_VIOLATION
;
2568 else memcpy( SystemInformation
, buf
, len
);
2570 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2571 RtlFreeHeap(GetProcessHeap(), 0, buf
);
2574 case SystemRecommendedSharedDataAlignment
:
2576 len
= sizeof(DWORD
);
2579 if (!SystemInformation
) ret
= STATUS_ACCESS_VIOLATION
;
2580 else *((DWORD
*)SystemInformation
) = 64;
2582 else ret
= STATUS_INFO_LENGTH_MISMATCH
;
2585 case SystemFirmwareTableInformation
:
2587 SYSTEM_FIRMWARE_TABLE_INFORMATION
*sfti
= (SYSTEM_FIRMWARE_TABLE_INFORMATION
*)SystemInformation
;
2588 len
= FIELD_OFFSET(SYSTEM_FIRMWARE_TABLE_INFORMATION
, TableBuffer
);
2591 ret
= STATUS_INFO_LENGTH_MISMATCH
;
2595 switch (sfti
->Action
)
2597 case SystemFirmwareTable_Get
:
2598 ret
= get_firmware_info(sfti
, Length
, &len
);
2602 ret
= STATUS_NOT_IMPLEMENTED
;
2603 FIXME("info_class SYSTEM_FIRMWARE_TABLE_INFORMATION action %d\n", sfti
->Action
);
2608 FIXME("(0x%08x,%p,0x%08x,%p) stub\n",
2609 SystemInformationClass
,SystemInformation
,Length
,ResultLength
);
2611 /* Several Information Classes are not implemented on Windows and return 2 different values
2612 * STATUS_NOT_IMPLEMENTED or STATUS_INVALID_INFO_CLASS
2613 * in 95% of the cases it's STATUS_INVALID_INFO_CLASS, so use this as the default
2615 ret
= STATUS_INVALID_INFO_CLASS
;
2618 if (ResultLength
) *ResultLength
= len
;
2623 /******************************************************************************
2624 * NtQuerySystemInformationEx [NTDLL.@]
2625 * ZwQuerySystemInformationEx [NTDLL.@]
2627 NTSTATUS WINAPI
NtQuerySystemInformationEx(SYSTEM_INFORMATION_CLASS SystemInformationClass
,
2628 void *Query
, ULONG QueryLength
, void *SystemInformation
, ULONG Length
, ULONG
*ResultLength
)
2631 NTSTATUS ret
= STATUS_NOT_IMPLEMENTED
;
2633 TRACE("(0x%08x,%p,%u,%p,%u,%p) stub\n", SystemInformationClass
, Query
, QueryLength
, SystemInformation
,
2634 Length
, ResultLength
);
2636 switch (SystemInformationClass
) {
2637 case SystemLogicalProcessorInformationEx
:
2639 SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
*buf
;
2641 if (!Query
|| QueryLength
< sizeof(DWORD
))
2643 ret
= STATUS_INVALID_PARAMETER
;
2647 if (*(DWORD
*)Query
!= RelationAll
)
2648 FIXME("Relationship filtering not implemented: 0x%x\n", *(DWORD
*)Query
);
2650 len
= 3 * sizeof(*buf
);
2651 buf
= RtlAllocateHeap(GetProcessHeap(), 0, len
);
2654 ret
= STATUS_NO_MEMORY
;
2658 ret
= create_logical_proc_info(NULL
, &buf
, &len
);
2659 if (ret
!= STATUS_SUCCESS
)
2661 RtlFreeHeap(GetProcessHeap(), 0, buf
);
2667 if (!SystemInformation
)
2668 ret
= STATUS_ACCESS_VIOLATION
;
2670 memcpy( SystemInformation
, buf
, len
);
2673 ret
= STATUS_INFO_LENGTH_MISMATCH
;
2675 RtlFreeHeap(GetProcessHeap(), 0, buf
);
2680 FIXME("(0x%08x,%p,%u,%p,%u,%p) stub\n", SystemInformationClass
, Query
, QueryLength
, SystemInformation
,
2681 Length
, ResultLength
);
2686 *ResultLength
= len
;
2691 /******************************************************************************
2692 * NtSetSystemInformation [NTDLL.@]
2693 * ZwSetSystemInformation [NTDLL.@]
2695 NTSTATUS WINAPI
NtSetSystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass
, PVOID SystemInformation
, ULONG Length
)
2697 FIXME("(0x%08x,%p,0x%08x) stub\n",SystemInformationClass
,SystemInformation
,Length
);
2698 return STATUS_SUCCESS
;
2701 /******************************************************************************
2702 * NtCreatePagingFile [NTDLL.@]
2703 * ZwCreatePagingFile [NTDLL.@]
2705 NTSTATUS WINAPI
NtCreatePagingFile(
2706 PUNICODE_STRING PageFileName
,
2707 PLARGE_INTEGER MinimumSize
,
2708 PLARGE_INTEGER MaximumSize
,
2709 PLARGE_INTEGER ActualSize
)
2711 FIXME("(%p %p %p %p) stub\n", PageFileName
, MinimumSize
, MaximumSize
, ActualSize
);
2712 return STATUS_SUCCESS
;
2715 /******************************************************************************
2716 * NtDisplayString [NTDLL.@]
2718 * writes a string to the nt-textmode screen eg. during startup
2720 NTSTATUS WINAPI
NtDisplayString ( PUNICODE_STRING string
)
2725 if (!(ret
= RtlUnicodeStringToAnsiString( &stringA
, string
, TRUE
)))
2727 MESSAGE( "%.*s", stringA
.Length
, stringA
.Buffer
);
2728 RtlFreeAnsiString( &stringA
);
2733 /******************************************************************************
2734 * NtInitiatePowerAction [NTDLL.@]
2737 NTSTATUS WINAPI
NtInitiatePowerAction(
2738 IN POWER_ACTION SystemAction
,
2739 IN SYSTEM_POWER_STATE MinSystemState
,
2741 IN BOOLEAN Asynchronous
)
2743 FIXME("(%d,%d,0x%08x,%d),stub\n",
2744 SystemAction
,MinSystemState
,Flags
,Asynchronous
);
2745 return STATUS_NOT_IMPLEMENTED
;
2749 /* Fallback using /proc/cpuinfo for Linux systems without cpufreq. For
2750 * most distributions on recent enough hardware, this is only likely to
2751 * happen while running in virtualized environments such as QEMU. */
2752 static ULONG
mhz_from_cpuinfo(void)
2757 FILE* f
= fopen("/proc/cpuinfo", "r");
2759 while (fgets(line
, sizeof(line
), f
) != NULL
) {
2760 if (!(value
= strchr(line
,':')))
2763 while ((s
>= line
) && isspace(*s
)) s
--;
2766 if (!strcasecmp(line
, "cpu MHz")) {
2767 sscanf(value
, " %lf", &cmz
);
2777 /******************************************************************************
2778 * NtPowerInformation [NTDLL.@]
2781 NTSTATUS WINAPI
NtPowerInformation(
2782 IN POWER_INFORMATION_LEVEL InformationLevel
,
2783 IN PVOID lpInputBuffer
,
2784 IN ULONG nInputBufferSize
,
2785 IN PVOID lpOutputBuffer
,
2786 IN ULONG nOutputBufferSize
)
2788 TRACE("(%d,%p,%d,%p,%d)\n",
2789 InformationLevel
,lpInputBuffer
,nInputBufferSize
,lpOutputBuffer
,nOutputBufferSize
);
2790 switch(InformationLevel
) {
2791 case SystemPowerCapabilities
: {
2792 PSYSTEM_POWER_CAPABILITIES PowerCaps
= lpOutputBuffer
;
2793 FIXME("semi-stub: SystemPowerCapabilities\n");
2794 if (nOutputBufferSize
< sizeof(SYSTEM_POWER_CAPABILITIES
))
2795 return STATUS_BUFFER_TOO_SMALL
;
2796 /* FIXME: These values are based off a native XP desktop, should probably use APM/ACPI to get the 'real' values */
2797 PowerCaps
->PowerButtonPresent
= TRUE
;
2798 PowerCaps
->SleepButtonPresent
= FALSE
;
2799 PowerCaps
->LidPresent
= FALSE
;
2800 PowerCaps
->SystemS1
= TRUE
;
2801 PowerCaps
->SystemS2
= FALSE
;
2802 PowerCaps
->SystemS3
= FALSE
;
2803 PowerCaps
->SystemS4
= TRUE
;
2804 PowerCaps
->SystemS5
= TRUE
;
2805 PowerCaps
->HiberFilePresent
= TRUE
;
2806 PowerCaps
->FullWake
= TRUE
;
2807 PowerCaps
->VideoDimPresent
= FALSE
;
2808 PowerCaps
->ApmPresent
= FALSE
;
2809 PowerCaps
->UpsPresent
= FALSE
;
2810 PowerCaps
->ThermalControl
= FALSE
;
2811 PowerCaps
->ProcessorThrottle
= FALSE
;
2812 PowerCaps
->ProcessorMinThrottle
= 100;
2813 PowerCaps
->ProcessorMaxThrottle
= 100;
2814 PowerCaps
->DiskSpinDown
= TRUE
;
2815 PowerCaps
->SystemBatteriesPresent
= FALSE
;
2816 PowerCaps
->BatteriesAreShortTerm
= FALSE
;
2817 PowerCaps
->BatteryScale
[0].Granularity
= 0;
2818 PowerCaps
->BatteryScale
[0].Capacity
= 0;
2819 PowerCaps
->BatteryScale
[1].Granularity
= 0;
2820 PowerCaps
->BatteryScale
[1].Capacity
= 0;
2821 PowerCaps
->BatteryScale
[2].Granularity
= 0;
2822 PowerCaps
->BatteryScale
[2].Capacity
= 0;
2823 PowerCaps
->AcOnLineWake
= PowerSystemUnspecified
;
2824 PowerCaps
->SoftLidWake
= PowerSystemUnspecified
;
2825 PowerCaps
->RtcWake
= PowerSystemSleeping1
;
2826 PowerCaps
->MinDeviceWakeState
= PowerSystemUnspecified
;
2827 PowerCaps
->DefaultLowLatencyWake
= PowerSystemUnspecified
;
2828 return STATUS_SUCCESS
;
2830 case SystemExecutionState
: {
2831 PULONG ExecutionState
= lpOutputBuffer
;
2832 WARN("semi-stub: SystemExecutionState\n"); /* Needed for .NET Framework, but using a FIXME is really noisy. */
2833 if (lpInputBuffer
!= NULL
)
2834 return STATUS_INVALID_PARAMETER
;
2835 /* FIXME: The actual state should be the value set by SetThreadExecutionState which is not currently implemented. */
2836 *ExecutionState
= ES_USER_PRESENT
;
2837 return STATUS_SUCCESS
;
2839 case ProcessorInformation
: {
2840 const int cannedMHz
= 1000; /* We fake a 1GHz processor if we can't conjure up real values */
2841 PROCESSOR_POWER_INFORMATION
* cpu_power
= lpOutputBuffer
;
2844 if ((lpOutputBuffer
== NULL
) || (nOutputBufferSize
== 0))
2845 return STATUS_INVALID_PARAMETER
;
2846 out_cpus
= NtCurrentTeb()->Peb
->NumberOfProcessors
;
2847 if ((nOutputBufferSize
/ sizeof(PROCESSOR_POWER_INFORMATION
)) < out_cpus
)
2848 return STATUS_BUFFER_TOO_SMALL
;
2854 for(i
= 0; i
< out_cpus
; i
++) {
2855 sprintf(filename
, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", i
);
2856 f
= fopen(filename
, "r");
2857 if (f
&& (fscanf(f
, "%d", &cpu_power
[i
].CurrentMhz
) == 1)) {
2858 cpu_power
[i
].CurrentMhz
/= 1000;
2863 cpu_power
[0].CurrentMhz
= mhz_from_cpuinfo();
2864 if(cpu_power
[0].CurrentMhz
== 0)
2865 cpu_power
[0].CurrentMhz
= cannedMHz
;
2868 cpu_power
[i
].CurrentMhz
= cpu_power
[0].CurrentMhz
;
2872 sprintf(filename
, "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", i
);
2873 f
= fopen(filename
, "r");
2874 if (f
&& (fscanf(f
, "%d", &cpu_power
[i
].MaxMhz
) == 1)) {
2875 cpu_power
[i
].MaxMhz
/= 1000;
2879 cpu_power
[i
].MaxMhz
= cpu_power
[i
].CurrentMhz
;
2883 sprintf(filename
, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", i
);
2884 f
= fopen(filename
, "r");
2885 if(f
&& (fscanf(f
, "%d", &cpu_power
[i
].MhzLimit
) == 1)) {
2886 cpu_power
[i
].MhzLimit
/= 1000;
2891 cpu_power
[i
].MhzLimit
= cpu_power
[i
].MaxMhz
;
2895 cpu_power
[i
].Number
= i
;
2896 cpu_power
[i
].MaxIdleState
= 0; /* FIXME */
2897 cpu_power
[i
].CurrentIdleState
= 0; /* FIXME */
2900 #elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__)
2903 size_t valSize
= sizeof(num
);
2904 if (sysctlbyname("hw.clockrate", &num
, &valSize
, NULL
, 0))
2906 for(i
= 0; i
< out_cpus
; i
++) {
2907 cpu_power
[i
].CurrentMhz
= num
;
2908 cpu_power
[i
].MaxMhz
= num
;
2909 cpu_power
[i
].MhzLimit
= num
;
2910 cpu_power
[i
].Number
= i
;
2911 cpu_power
[i
].MaxIdleState
= 0; /* FIXME */
2912 cpu_power
[i
].CurrentIdleState
= 0; /* FIXME */
2915 #elif defined (__APPLE__)
2918 unsigned long long currentMhz
;
2919 unsigned long long maxMhz
;
2921 valSize
= sizeof(currentMhz
);
2922 if (!sysctlbyname("hw.cpufrequency", ¤tMhz
, &valSize
, NULL
, 0))
2923 currentMhz
/= 1000000;
2925 currentMhz
= cannedMHz
;
2927 valSize
= sizeof(maxMhz
);
2928 if (!sysctlbyname("hw.cpufrequency_max", &maxMhz
, &valSize
, NULL
, 0))
2931 maxMhz
= currentMhz
;
2933 for(i
= 0; i
< out_cpus
; i
++) {
2934 cpu_power
[i
].CurrentMhz
= currentMhz
;
2935 cpu_power
[i
].MaxMhz
= maxMhz
;
2936 cpu_power
[i
].MhzLimit
= maxMhz
;
2937 cpu_power
[i
].Number
= i
;
2938 cpu_power
[i
].MaxIdleState
= 0; /* FIXME */
2939 cpu_power
[i
].CurrentIdleState
= 0; /* FIXME */
2943 for(i
= 0; i
< out_cpus
; i
++) {
2944 cpu_power
[i
].CurrentMhz
= cannedMHz
;
2945 cpu_power
[i
].MaxMhz
= cannedMHz
;
2946 cpu_power
[i
].MhzLimit
= cannedMHz
;
2947 cpu_power
[i
].Number
= i
;
2948 cpu_power
[i
].MaxIdleState
= 0; /* FIXME */
2949 cpu_power
[i
].CurrentIdleState
= 0; /* FIXME */
2951 WARN("Unable to detect CPU MHz for this platform. Reporting %d MHz.\n", cannedMHz
);
2953 for(i
= 0; i
< out_cpus
; i
++) {
2954 TRACE("cpu_power[%d] = %u %u %u %u %u %u\n", i
, cpu_power
[i
].Number
,
2955 cpu_power
[i
].MaxMhz
, cpu_power
[i
].CurrentMhz
, cpu_power
[i
].MhzLimit
,
2956 cpu_power
[i
].MaxIdleState
, cpu_power
[i
].CurrentIdleState
);
2958 return STATUS_SUCCESS
;
2961 /* FIXME: Needed by .NET Framework */
2962 WARN("Unimplemented NtPowerInformation action: %d\n", InformationLevel
);
2963 return STATUS_NOT_IMPLEMENTED
;
2967 /******************************************************************************
2968 * NtShutdownSystem [NTDLL.@]
2971 NTSTATUS WINAPI
NtShutdownSystem(SHUTDOWN_ACTION Action
)
2973 FIXME("%d\n",Action
);
2974 return STATUS_SUCCESS
;
2977 /******************************************************************************
2978 * NtAllocateLocallyUniqueId (NTDLL.@)
2980 NTSTATUS WINAPI
NtAllocateLocallyUniqueId(PLUID Luid
)
2984 TRACE("%p\n", Luid
);
2987 return STATUS_ACCESS_VIOLATION
;
2989 SERVER_START_REQ( allocate_locally_unique_id
)
2991 status
= wine_server_call( req
);
2994 Luid
->LowPart
= reply
->luid
.low_part
;
2995 Luid
->HighPart
= reply
->luid
.high_part
;
3003 /******************************************************************************
3004 * VerSetConditionMask (NTDLL.@)
3006 ULONGLONG WINAPI
VerSetConditionMask( ULONGLONG dwlConditionMask
, DWORD dwTypeBitMask
,
3007 BYTE dwConditionMask
)
3009 if(dwTypeBitMask
== 0)
3010 return dwlConditionMask
;
3011 dwConditionMask
&= 0x07;
3012 if(dwConditionMask
== 0)
3013 return dwlConditionMask
;
3015 if(dwTypeBitMask
& VER_PRODUCT_TYPE
)
3016 dwlConditionMask
|= dwConditionMask
<< 7*3;
3017 else if (dwTypeBitMask
& VER_SUITENAME
)
3018 dwlConditionMask
|= dwConditionMask
<< 6*3;
3019 else if (dwTypeBitMask
& VER_SERVICEPACKMAJOR
)
3020 dwlConditionMask
|= dwConditionMask
<< 5*3;
3021 else if (dwTypeBitMask
& VER_SERVICEPACKMINOR
)
3022 dwlConditionMask
|= dwConditionMask
<< 4*3;
3023 else if (dwTypeBitMask
& VER_PLATFORMID
)
3024 dwlConditionMask
|= dwConditionMask
<< 3*3;
3025 else if (dwTypeBitMask
& VER_BUILDNUMBER
)
3026 dwlConditionMask
|= dwConditionMask
<< 2*3;
3027 else if (dwTypeBitMask
& VER_MAJORVERSION
)
3028 dwlConditionMask
|= dwConditionMask
<< 1*3;
3029 else if (dwTypeBitMask
& VER_MINORVERSION
)
3030 dwlConditionMask
|= dwConditionMask
<< 0*3;
3031 return dwlConditionMask
;
3034 /******************************************************************************
3035 * NtAccessCheckAndAuditAlarm (NTDLL.@)
3036 * ZwAccessCheckAndAuditAlarm (NTDLL.@)
3038 NTSTATUS WINAPI
NtAccessCheckAndAuditAlarm(PUNICODE_STRING SubsystemName
, HANDLE HandleId
, PUNICODE_STRING ObjectTypeName
,
3039 PUNICODE_STRING ObjectName
, PSECURITY_DESCRIPTOR SecurityDescriptor
,
3040 ACCESS_MASK DesiredAccess
, PGENERIC_MAPPING GenericMapping
, BOOLEAN ObjectCreation
,
3041 PACCESS_MASK GrantedAccess
, PBOOLEAN AccessStatus
, PBOOLEAN GenerateOnClose
)
3043 FIXME("(%s, %p, %s, %p, 0x%08x, %p, %d, %p, %p, %p), stub\n", debugstr_us(SubsystemName
), HandleId
,
3044 debugstr_us(ObjectTypeName
), SecurityDescriptor
, DesiredAccess
, GenericMapping
, ObjectCreation
,
3045 GrantedAccess
, AccessStatus
, GenerateOnClose
);
3047 return STATUS_NOT_IMPLEMENTED
;
3050 /******************************************************************************
3051 * NtSystemDebugControl (NTDLL.@)
3052 * ZwSystemDebugControl (NTDLL.@)
3054 NTSTATUS WINAPI
NtSystemDebugControl(SYSDBG_COMMAND command
, PVOID inbuffer
, ULONG inbuflength
, PVOID outbuffer
,
3055 ULONG outbuflength
, PULONG retlength
)
3057 FIXME("(%d, %p, %d, %p, %d, %p), stub\n", command
, inbuffer
, inbuflength
, outbuffer
, outbuflength
, retlength
);
3059 return STATUS_NOT_IMPLEMENTED
;
3062 /******************************************************************************
3063 * NtSetLdtEntries (NTDLL.@)
3064 * ZwSetLdtEntries (NTDLL.@)
3066 NTSTATUS WINAPI
NtSetLdtEntries(ULONG selector1
, ULONG entry1_low
, ULONG entry1_high
,
3067 ULONG selector2
, ULONG entry2_low
, ULONG entry2_high
)
3069 FIXME("(%u, %u, %u, %u, %u, %u): stub\n", selector1
, entry1_low
, entry1_high
, selector2
, entry2_low
, entry2_high
);
3071 return STATUS_NOT_IMPLEMENTED
;