ntdll: Implement SystemEmulation* information classes.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-07-05 12:02:39 +02:00
parent 0e64e05600
commit 5071a28743
4 changed files with 225 additions and 13 deletions

View File

@ -110,8 +110,8 @@ static void InitFunctionPtrs(void)
static void test_query_basic(void)
{
NTSTATUS status;
ULONG ReturnLength;
SYSTEM_BASIC_INFORMATION sbi, sbi2;
ULONG i, ReturnLength;
SYSTEM_BASIC_INFORMATION sbi, sbi2, sbi3;
/* This test also covers some basic parameter testing that should be the same for
* every information class
@ -140,6 +140,7 @@ static void test_query_basic(void)
ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH, got %08x\n", status);
/* Finally some correct calls */
memset(&sbi, 0xcc, sizeof(sbi));
status = pNtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), &ReturnLength);
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
ok( sizeof(sbi) == ReturnLength, "Inconsistent length %d\n", ReturnLength);
@ -148,7 +149,7 @@ static void test_query_basic(void)
if (winetest_debug > 1) trace("Number of Processors : %d\n", sbi.NumberOfProcessors);
ok( sbi.NumberOfProcessors > 0, "Expected more than 0 processors, got %d\n", sbi.NumberOfProcessors);
memset(&sbi2, 0, sizeof(sbi2));
memset(&sbi2, 0xcc, sizeof(sbi2));
status = pRtlGetNativeSystemInformation(SystemBasicInformation, &sbi2, sizeof(sbi2), &ReturnLength);
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x.\n", status);
ok( sizeof(sbi2) == ReturnLength, "Unexpected length %u.\n", ReturnLength);
@ -169,24 +170,142 @@ static void test_query_basic(void)
"Expected AllocationGranularity %#lx, got %#lx.\n",
sbi.AllocationGranularity, sbi2.AllocationGranularity);
ok( sbi.LowestUserAddress == sbi2.LowestUserAddress, "Expected LowestUserAddress %p, got %p.\n",
(void *)sbi.LowestUserAddress, (void *)sbi2.LowestUserAddress);
/* Not testing HighestUserAddress. The field is different from NtQuerySystemInformation result
* on 32 bit Windows (some of Win8 versions are the exception). Whenever it is different,
* NtQuerySystemInformation returns user space limit (0x0x7ffeffff) and RtlGetNativeSystemInformation
* returns address space limit (0xfffeffff). */
sbi.LowestUserAddress, sbi2.LowestUserAddress);
ok( sbi.ActiveProcessorsAffinityMask == sbi2.ActiveProcessorsAffinityMask,
"Expected ActiveProcessorsAffinityMask %#lx, got %#lx.\n",
sbi.ActiveProcessorsAffinityMask, sbi2.ActiveProcessorsAffinityMask);
ok( sbi.NumberOfProcessors == sbi2.NumberOfProcessors, "Expected NumberOfProcessors %u, got %u.\n",
sbi.NumberOfProcessors, sbi2.NumberOfProcessors);
#ifdef _WIN64
ok( sbi.HighestUserAddress == sbi2.HighestUserAddress, "Expected HighestUserAddress %p, got %p.\n",
(void *)sbi.HighestUserAddress, (void *)sbi2.HighestUserAddress);
#else
ok( sbi.HighestUserAddress == (void *)0x7ffeffff, "wrong limit %p\n", sbi.HighestUserAddress);
todo_wine_if( is_wow64 )
ok( sbi2.HighestUserAddress == (is_wow64 ? (void *)0xfffeffff : (void *)0x7ffeffff),
"wrong limit %p\n", sbi.HighestUserAddress);
#endif
memset(&sbi3, 0xcc, sizeof(sbi3));
status = pNtQuerySystemInformation(SystemNativeBasicInformation, &sbi3, sizeof(sbi3), &ReturnLength);
#ifdef _WIN64
ok( status == STATUS_SUCCESS || broken(status == STATUS_INVALID_INFO_CLASS), "got %08x\n", status);
if (!status)
{
ok( sizeof(sbi3) == ReturnLength, "Unexpected length %u.\n", ReturnLength);
ok( !memcmp( &sbi2, &sbi3, offsetof(SYSTEM_BASIC_INFORMATION,NumberOfProcessors)+1 ),
"info is different\n" );
}
#else
ok( status == STATUS_INVALID_INFO_CLASS || broken(STATUS_NOT_IMPLEMENTED), /* vista */
"got %08x\n", status);
status = pRtlGetNativeSystemInformation( SystemNativeBasicInformation, &sbi3, sizeof(sbi3), &ReturnLength );
todo_wine
ok( !status || status == STATUS_INFO_LENGTH_MISMATCH ||
broken(status == STATUS_INVALID_INFO_CLASS) || broken(status == STATUS_NOT_IMPLEMENTED),
"failed %x\n", status );
if (!status || status == STATUS_INFO_LENGTH_MISMATCH)
ok( !status == !is_wow64, "got wrong status %x wow64 %u\n", status, is_wow64 );
if (!status)
{
ok( sizeof(sbi3) == ReturnLength, "Unexpected length %u.\n", ReturnLength);
ok( !memcmp( &sbi2, &sbi3, offsetof(SYSTEM_BASIC_INFORMATION,NumberOfProcessors)+1 ),
"info is different\n" );
}
else if (status == STATUS_INFO_LENGTH_MISMATCH)
{
/* SystemNativeBasicInformation uses the 64-bit structure on Wow64 */
struct
{
DWORD unknown;
ULONG KeMaximumIncrement;
ULONG PageSize;
ULONG MmNumberOfPhysicalPages;
ULONG MmLowestPhysicalPage;
ULONG MmHighestPhysicalPage;
ULONG64 AllocationGranularity;
ULONG64 LowestUserAddress;
ULONG64 HighestUserAddress;
ULONG64 ActiveProcessorsAffinityMask;
BYTE NumberOfProcessors;
} sbi64;
ok( ReturnLength == sizeof(sbi64), "len %x\n", ReturnLength );
memset( &sbi64, 0xcc, sizeof(sbi64) );
ReturnLength = 0;
status = pRtlGetNativeSystemInformation( SystemNativeBasicInformation, &sbi64, sizeof(sbi64), &ReturnLength );
ok( !status, "failed %x\n", status );
ok( ReturnLength == sizeof(sbi64), "len %x\n", ReturnLength );
ok( sbi.unknown == sbi64.unknown, "unknown %#x / %#x\n", sbi.unknown, sbi64.unknown);
ok( sbi.KeMaximumIncrement == sbi64.KeMaximumIncrement, "KeMaximumIncrement %u / %u\n",
sbi.KeMaximumIncrement, sbi64.KeMaximumIncrement);
ok( sbi.PageSize == sbi64.PageSize, "PageSize %u / %u\n", sbi.PageSize, sbi64.PageSize);
ok( sbi.MmNumberOfPhysicalPages == sbi64.MmNumberOfPhysicalPages,
"MmNumberOfPhysicalPages %u / %u\n",
sbi.MmNumberOfPhysicalPages, sbi64.MmNumberOfPhysicalPages);
ok( sbi.MmLowestPhysicalPage == sbi64.MmLowestPhysicalPage, "MmLowestPhysicalPage %u / %u\n",
sbi.MmLowestPhysicalPage, sbi64.MmLowestPhysicalPage);
ok( sbi.MmHighestPhysicalPage == sbi64.MmHighestPhysicalPage, "MmHighestPhysicalPage %u / %u\n",
sbi.MmHighestPhysicalPage, sbi64.MmHighestPhysicalPage);
ok( sbi.AllocationGranularity == (ULONG_PTR)sbi64.AllocationGranularity,
"AllocationGranularity %#lx / %#lx\n", sbi.AllocationGranularity,
(ULONG_PTR)sbi64.AllocationGranularity);
ok( (ULONG_PTR)sbi.LowestUserAddress == sbi64.LowestUserAddress, "LowestUserAddress %p / %s\n",
sbi.LowestUserAddress, wine_dbgstr_longlong(sbi64.LowestUserAddress));
ok( sbi.ActiveProcessorsAffinityMask == sbi64.ActiveProcessorsAffinityMask,
"ActiveProcessorsAffinityMask %#lx / %s\n",
sbi.ActiveProcessorsAffinityMask, wine_dbgstr_longlong(sbi64.ActiveProcessorsAffinityMask));
ok( sbi.NumberOfProcessors == sbi64.NumberOfProcessors, "NumberOfProcessors %u / %u\n",
sbi.NumberOfProcessors, sbi64.NumberOfProcessors);
ok( sbi64.HighestUserAddress == 0x7ffffffeffff, "wrong limit %s\n",
wine_dbgstr_longlong(sbi64.HighestUserAddress));
}
#endif
memset(&sbi3, 0xcc, sizeof(sbi3));
status = pNtQuerySystemInformation(SystemEmulationBasicInformation, &sbi3, sizeof(sbi3), &ReturnLength);
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x.\n", status);
ok( sizeof(sbi3) == ReturnLength, "Unexpected length %u.\n", ReturnLength);
ok( !memcmp( &sbi, &sbi3, offsetof(SYSTEM_BASIC_INFORMATION,NumberOfProcessors)+1 ),
"info is different\n" );
for (i = 0; i < 256; i++)
{
NTSTATUS expect = pNtQuerySystemInformation( i, NULL, 0, &ReturnLength );
status = pRtlGetNativeSystemInformation( i, NULL, 0, &ReturnLength );
switch (i)
{
case SystemNativeBasicInformation:
ok( status == STATUS_INVALID_INFO_CLASS || status == STATUS_INFO_LENGTH_MISMATCH ||
broken(status == STATUS_NOT_IMPLEMENTED) /* vista */, "%u: %x / %x\n", i, status, expect );
break;
case SystemBasicInformation:
case SystemCpuInformation:
case SystemEmulationBasicInformation:
case SystemEmulationProcessorInformation:
ok( status == expect, "%u: %x / %x\n", i, status, expect );
break;
default:
if (is_wow64) /* only a few info classes are supported on Wow64 */
todo_wine_if (is_wow64 && status != STATUS_INVALID_INFO_CLASS)
ok( status == STATUS_INVALID_INFO_CLASS ||
broken(status == STATUS_NOT_IMPLEMENTED), /* vista */
"%u: %x\n", i, status );
else
ok( status == expect, "%u: %x / %x\n", i, status, expect );
break;
}
}
}
static void test_query_cpu(void)
{
DWORD status;
ULONG ReturnLength;
SYSTEM_CPU_INFORMATION sci;
SYSTEM_CPU_INFORMATION sci, sci2;
memset(&sci, 0xcc, sizeof(sci));
status = pNtQuerySystemInformation(SystemCpuInformation, &sci, sizeof(sci), &ReturnLength);
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
ok( sizeof(sci) == ReturnLength, "Inconsistent length %d\n", ReturnLength);
@ -195,6 +314,55 @@ static void test_query_cpu(void)
if (winetest_debug > 1) trace("Processor FeatureSet : %08x\n", sci.ProcessorFeatureBits);
ok( sci.ProcessorFeatureBits != 0, "Expected some features for this processor, got %08x\n",
sci.ProcessorFeatureBits);
memset(&sci2, 0xcc, sizeof(sci2));
status = pRtlGetNativeSystemInformation(SystemCpuInformation, &sci2, sizeof(sci2), &ReturnLength);
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x.\n", status);
ok( sizeof(sci2) == ReturnLength, "Unexpected length %u.\n", ReturnLength);
if (is_wow64)
{
ok( sci.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL, "ProcessorArchitecture wrong %x\n",
sci.ProcessorArchitecture );
todo_wine
ok( sci2.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64, "ProcessorArchitecture wrong %x\n",
sci2.ProcessorArchitecture );
}
else
ok( sci.ProcessorArchitecture == sci2.ProcessorArchitecture,
"ProcessorArchitecture differs %x / %x\n",
sci.ProcessorArchitecture, sci2.ProcessorArchitecture );
ok( sci.ProcessorLevel == sci2.ProcessorLevel, "ProcessorLevel differs %x / %x\n",
sci.ProcessorLevel, sci2.ProcessorLevel );
ok( sci.ProcessorRevision == sci2.ProcessorRevision, "ProcessorRevision differs %x / %x\n",
sci.ProcessorRevision, sci2.ProcessorRevision );
ok( sci.MaximumProcessors == sci2.MaximumProcessors, "MaximumProcessors differs %x / %x\n",
sci.MaximumProcessors, sci2.MaximumProcessors );
ok( sci.ProcessorFeatureBits == sci2.ProcessorFeatureBits, "ProcessorFeatureBits differs %x / %x\n",
sci.ProcessorFeatureBits, sci2.ProcessorFeatureBits );
memset(&sci2, 0xcc, sizeof(sci2));
status = pNtQuerySystemInformation(SystemEmulationProcessorInformation, &sci2, sizeof(sci2), &ReturnLength);
ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x.\n", status);
ok( sizeof(sci2) == ReturnLength, "Unexpected length %u.\n", ReturnLength);
#ifdef _WIN64
ok( sci2.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL, "ProcessorArchitecture wrong %x\n",
sci2.ProcessorArchitecture );
#else
ok( sci.ProcessorArchitecture == sci2.ProcessorArchitecture,
"ProcessorArchitecture differs %x / %x\n",
sci.ProcessorArchitecture, sci2.ProcessorArchitecture );
#endif
ok( sci.ProcessorLevel == sci2.ProcessorLevel, "ProcessorLevel differs %x / %x\n",
sci.ProcessorLevel, sci2.ProcessorLevel );
ok( sci.ProcessorRevision == sci2.ProcessorRevision, "ProcessorRevision differs %x / %x\n",
sci.ProcessorRevision, sci2.ProcessorRevision );
ok( sci.MaximumProcessors == sci2.MaximumProcessors, "MaximumProcessors differs %x / %x\n",
sci.MaximumProcessors, sci2.MaximumProcessors );
ok( sci.ProcessorFeatureBits == sci2.ProcessorFeatureBits, "ProcessorFeatureBits differs %x / %x\n",
sci.ProcessorFeatureBits, sci2.ProcessorFeatureBits );
}
static void test_query_performance(void)

View File

@ -2161,11 +2161,14 @@ NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class,
switch (class)
{
case SystemNativeBasicInformation: /* 114 */
if (!is_win64) return STATUS_INVALID_INFO_CLASS;
/* fall through */
case SystemBasicInformation: /* 0 */
{
SYSTEM_BASIC_INFORMATION sbi;
virtual_get_system_info( &sbi );
virtual_get_system_info( &sbi, FALSE );
len = sizeof(sbi);
if (size == len)
{
@ -2659,6 +2662,37 @@ NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class,
break;
}
case SystemEmulationBasicInformation: /* 62 */
{
SYSTEM_BASIC_INFORMATION sbi;
virtual_get_system_info( &sbi, !!NtCurrentTeb()->WowTebOffset );
len = sizeof(sbi);
if (size == len)
{
if (!info) ret = STATUS_ACCESS_VIOLATION;
else memcpy( info, &sbi, len);
}
else ret = STATUS_INFO_LENGTH_MISMATCH;
break;
}
case SystemEmulationProcessorInformation: /* 63 */
if (size >= (len = sizeof(cpu_info)))
{
SYSTEM_CPU_INFORMATION cpu = cpu_info;
if (is_win64)
{
if (cpu_info.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
cpu.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
else if (cpu_info.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64)
cpu.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_ARM;
}
memcpy(info, &cpu, len);
}
else ret = STATUS_INFO_LENGTH_MISMATCH;
break;
case SystemExtendedHandleInformation: /* 64 */
{
struct handle_info *handle_info;

View File

@ -198,7 +198,7 @@ extern void *anon_mmap_fixed( void *start, size_t size, int prot, int flags ) DE
extern void *anon_mmap_alloc( size_t size, int prot ) DECLSPEC_HIDDEN;
extern void virtual_init(void) DECLSPEC_HIDDEN;
extern ULONG_PTR get_system_affinity_mask(void) DECLSPEC_HIDDEN;
extern void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info ) DECLSPEC_HIDDEN;
extern void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info, BOOL wow64 ) DECLSPEC_HIDDEN;
extern NTSTATUS virtual_map_builtin_module( HANDLE mapping, void **module, SIZE_T *size,
SECTION_IMAGE_INFORMATION *info, WORD machine, BOOL prefer_native ) DECLSPEC_HIDDEN;
extern NTSTATUS virtual_create_builtin_view( void *module, const UNICODE_STRING *nt_name,

View File

@ -2682,7 +2682,7 @@ ULONG_PTR get_system_affinity_mask(void)
/***********************************************************************
* virtual_get_system_info
*/
void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info )
void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info, BOOL wow64 )
{
#if defined(HAVE_STRUCT_SYSINFO_TOTALRAM) && defined(HAVE_STRUCT_SYSINFO_MEM_UNIT)
struct sysinfo sinfo;
@ -2707,9 +2707,19 @@ void virtual_get_system_info( SYSTEM_BASIC_INFORMATION *info )
info->MmNumberOfPhysicalPages = info->MmHighestPhysicalPage - info->MmLowestPhysicalPage;
info->AllocationGranularity = granularity_mask + 1;
info->LowestUserAddress = (void *)0x10000;
info->HighestUserAddress = (char *)user_space_limit - 1;
info->ActiveProcessorsAffinityMask = get_system_affinity_mask();
info->NumberOfProcessors = peb->NumberOfProcessors;
#ifdef _WIN64
if (wow64)
{
if (main_image_info.ImageCharacteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)
info->HighestUserAddress = (char *)0xc0000000 - 1;
else
info->HighestUserAddress = (char *)0x7fff0000 - 1;
return;
}
#endif
info->HighestUserAddress = (char *)user_space_limit - 1;
}