mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-31 14:50:48 +00:00
ntdll: Implement RtlWow64GetThreadSelectorEntry().
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
dbabe2fa49
commit
3469ebf90e
5 changed files with 207 additions and 1 deletions
|
@ -1079,6 +1079,7 @@
|
|||
@ stdcall RtlWow64GetCurrentMachine()
|
||||
@ stdcall RtlWow64GetProcessMachines(long ptr ptr)
|
||||
@ stdcall -arch=win64 RtlWow64GetThreadContext(long ptr)
|
||||
@ stdcall -arch=win64 RtlWow64GetThreadSelectorEntry(long ptr long ptr)
|
||||
@ stdcall RtlWow64IsWowGuestMachineSupported(long ptr)
|
||||
@ stdcall -arch=win64 RtlWow64SetThreadContext(long ptr)
|
||||
@ stub RtlWriteMemoryStream
|
||||
|
|
|
@ -178,6 +178,73 @@ NTSTATUS WINAPI RtlWow64SetThreadContext( HANDLE handle, const WOW64_CONTEXT *co
|
|||
return NtSetInformationThread( handle, ThreadWow64Context, context, sizeof(*context) );
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* RtlWow64GetThreadSelectorEntry (NTDLL.@)
|
||||
*/
|
||||
NTSTATUS WINAPI RtlWow64GetThreadSelectorEntry( HANDLE handle, THREAD_DESCRIPTOR_INFORMATION *info,
|
||||
ULONG size, ULONG *retlen )
|
||||
{
|
||||
DWORD sel;
|
||||
WOW64_CONTEXT context = { WOW64_CONTEXT_CONTROL | WOW64_CONTEXT_SEGMENTS };
|
||||
LDT_ENTRY entry = { 0 };
|
||||
|
||||
if (size != sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH;
|
||||
if (RtlWow64GetThreadContext( handle, &context ))
|
||||
{
|
||||
/* hardcoded values */
|
||||
context.SegCs = 0x23;
|
||||
#ifdef __x86_64__
|
||||
__asm__( "movw %%fs,%0" : "=m" (context.SegFs) );
|
||||
__asm__( "movw %%ss,%0" : "=m" (context.SegSs) );
|
||||
#else
|
||||
context.SegSs = 0x2b;
|
||||
context.SegFs = 0x53;
|
||||
#endif
|
||||
}
|
||||
|
||||
sel = info->Selector | 3;
|
||||
if (sel == 0x03) goto done; /* null selector */
|
||||
|
||||
/* set common data */
|
||||
entry.HighWord.Bits.Dpl = 3;
|
||||
entry.HighWord.Bits.Pres = 1;
|
||||
entry.HighWord.Bits.Default_Big = 1;
|
||||
if (sel == context.SegCs) /* code selector */
|
||||
{
|
||||
entry.LimitLow = 0xffff;
|
||||
entry.HighWord.Bits.LimitHi = 0xf;
|
||||
entry.HighWord.Bits.Type = 0x1b; /* code */
|
||||
entry.HighWord.Bits.Granularity = 1;
|
||||
}
|
||||
else if (sel == context.SegSs) /* data selector */
|
||||
{
|
||||
entry.LimitLow = 0xffff;
|
||||
entry.HighWord.Bits.LimitHi = 0xf;
|
||||
entry.HighWord.Bits.Type = 0x13; /* data */
|
||||
entry.HighWord.Bits.Granularity = 1;
|
||||
}
|
||||
else if (sel == context.SegFs) /* TEB selector */
|
||||
{
|
||||
THREAD_BASIC_INFORMATION tbi;
|
||||
|
||||
entry.LimitLow = 0xfff;
|
||||
entry.HighWord.Bits.Type = 0x13; /* data */
|
||||
if (!NtQueryInformationThread( handle, ThreadBasicInformation, &tbi, sizeof(tbi), NULL ))
|
||||
{
|
||||
ULONG addr = (ULONG_PTR)tbi.TebBaseAddress + 0x2000; /* 32-bit teb offset */
|
||||
entry.BaseLow = addr;
|
||||
entry.HighWord.Bytes.BaseMid = addr >> 16;
|
||||
entry.HighWord.Bytes.BaseHi = addr >> 24;
|
||||
}
|
||||
}
|
||||
else return STATUS_UNSUCCESSFUL;
|
||||
|
||||
done:
|
||||
info->Entry = entry;
|
||||
if (retlen) *retlen = sizeof(entry);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**********************************************************************
|
||||
|
|
|
@ -24,9 +24,11 @@
|
|||
static NTSTATUS (WINAPI *pNtQuerySystemInformationEx)(SYSTEM_INFORMATION_CLASS,void*,ULONG,void*,ULONG,ULONG*);
|
||||
static USHORT (WINAPI *pRtlWow64GetCurrentMachine)(void);
|
||||
static NTSTATUS (WINAPI *pRtlWow64GetProcessMachines)(HANDLE,WORD*,WORD*);
|
||||
static NTSTATUS (WINAPI *pRtlWow64GetThreadContext)(HANDLE,WOW64_CONTEXT*);
|
||||
static NTSTATUS (WINAPI *pRtlWow64IsWowGuestMachineSupported)(USHORT,BOOLEAN*);
|
||||
#ifdef _WIN64
|
||||
static NTSTATUS (WINAPI *pRtlWow64GetCpuAreaInfo)(WOW64_CPURESERVED*,ULONG,WOW64_CPU_AREA_INFO*);
|
||||
static NTSTATUS (WINAPI *pRtlWow64GetThreadSelectorEntry)(HANDLE,THREAD_DESCRIPTOR_INFORMATION*,ULONG,ULONG*);
|
||||
#else
|
||||
static NTSTATUS (WINAPI *pNtWow64AllocateVirtualMemory64)(HANDLE,ULONG64*,ULONG64,ULONG64*,ULONG,ULONG);
|
||||
static NTSTATUS (WINAPI *pNtWow64ReadVirtualMemory64)(HANDLE,ULONG64,void*,ULONG64,ULONG64*);
|
||||
|
@ -46,9 +48,11 @@ static void init(void)
|
|||
GET_PROC( NtQuerySystemInformationEx );
|
||||
GET_PROC( RtlWow64GetCurrentMachine );
|
||||
GET_PROC( RtlWow64GetProcessMachines );
|
||||
GET_PROC( RtlWow64GetThreadContext );
|
||||
GET_PROC( RtlWow64IsWowGuestMachineSupported );
|
||||
#ifdef _WIN64
|
||||
GET_PROC( RtlWow64GetCpuAreaInfo );
|
||||
GET_PROC( RtlWow64GetThreadSelectorEntry );
|
||||
#else
|
||||
GET_PROC( NtWow64AllocateVirtualMemory64 );
|
||||
GET_PROC( NtWow64ReadVirtualMemory64 );
|
||||
|
@ -410,6 +414,138 @@ static void test_peb_teb(void)
|
|||
"WowTebOffset set to %x\n", NtCurrentTeb()->WowTebOffset );
|
||||
}
|
||||
|
||||
static void test_selectors(void)
|
||||
{
|
||||
THREAD_DESCRIPTOR_INFORMATION info;
|
||||
NTSTATUS status;
|
||||
ULONG base, limit, sel, retlen;
|
||||
I386_CONTEXT context = { CONTEXT_I386_CONTROL | CONTEXT_I386_SEGMENTS };
|
||||
|
||||
#ifdef _WIN64
|
||||
if (!pRtlWow64GetThreadSelectorEntry)
|
||||
{
|
||||
win_skip( "RtlWow64GetThreadSelectorEntry not supported\n" );
|
||||
return;
|
||||
}
|
||||
if (!pRtlWow64GetThreadContext || pRtlWow64GetThreadContext( GetCurrentThread(), &context ))
|
||||
{
|
||||
/* hardcoded values */
|
||||
context.SegCs = 0x23;
|
||||
context.SegSs = 0x2b;
|
||||
context.SegFs = 0x53;
|
||||
}
|
||||
#define GET_ENTRY(info,size,ret) \
|
||||
pRtlWow64GetThreadSelectorEntry( GetCurrentThread(), info, size, ret )
|
||||
|
||||
#else
|
||||
GetThreadContext( GetCurrentThread(), &context );
|
||||
#define GET_ENTRY(info,size,ret) \
|
||||
NtQueryInformationThread( GetCurrentThread(), ThreadDescriptorTableEntry, info, size, ret )
|
||||
#endif
|
||||
|
||||
trace( "cs %04x ss %04x fs %04x\n", context.SegCs, context.SegSs, context.SegFs );
|
||||
retlen = 0xdeadbeef;
|
||||
info.Selector = 0;
|
||||
status = GET_ENTRY( &info, sizeof(info) - 1, &retlen );
|
||||
ok( status == STATUS_INFO_LENGTH_MISMATCH, "wrong status %x\n", status );
|
||||
ok( retlen == 0xdeadbeef, "len set %u\n", retlen );
|
||||
|
||||
retlen = 0xdeadbeef;
|
||||
status = GET_ENTRY( &info, sizeof(info) + 1, &retlen );
|
||||
ok( status == STATUS_INFO_LENGTH_MISMATCH, "wrong status %x\n", status );
|
||||
ok( retlen == 0xdeadbeef, "len set %u\n", retlen );
|
||||
|
||||
retlen = 0xdeadbeef;
|
||||
status = GET_ENTRY( NULL, 0, &retlen );
|
||||
ok( status == STATUS_INFO_LENGTH_MISMATCH, "wrong status %x\n", status );
|
||||
ok( retlen == 0xdeadbeef, "len set %u\n", retlen );
|
||||
|
||||
status = GET_ENTRY( &info, sizeof(info), NULL );
|
||||
ok( !status, "wrong status %x\n", status );
|
||||
|
||||
for (info.Selector = 0; info.Selector < 0x100; info.Selector++)
|
||||
{
|
||||
retlen = 0xdeadbeef;
|
||||
status = GET_ENTRY( &info, sizeof(info), &retlen );
|
||||
base = (info.Entry.BaseLow |
|
||||
(info.Entry.HighWord.Bytes.BaseMid << 16) |
|
||||
(info.Entry.HighWord.Bytes.BaseHi << 24));
|
||||
limit = (info.Entry.LimitLow | info.Entry.HighWord.Bits.LimitHi << 16);
|
||||
sel = info.Selector | 3;
|
||||
|
||||
if (sel == 0x03) /* null selector */
|
||||
{
|
||||
ok( !status, "wrong status %x\n", status );
|
||||
ok( retlen == sizeof(info.Entry), "len set %u\n", retlen );
|
||||
ok( !base, "wrong base %x\n", base );
|
||||
ok( !limit, "wrong limit %x\n", limit );
|
||||
ok( !info.Entry.HighWord.Bytes.Flags1, "wrong flags1 %x\n", info.Entry.HighWord.Bytes.Flags1 );
|
||||
ok( !info.Entry.HighWord.Bytes.Flags2, "wrong flags2 %x\n", info.Entry.HighWord.Bytes.Flags2 );
|
||||
}
|
||||
else if (sel == context.SegCs) /* 32-bit code selector */
|
||||
{
|
||||
ok( !status, "wrong status %x\n", status );
|
||||
ok( retlen == sizeof(info.Entry), "len set %u\n", retlen );
|
||||
ok( !base, "wrong base %x\n", base );
|
||||
ok( limit == 0xfffff, "wrong limit %x\n", limit );
|
||||
ok( info.Entry.HighWord.Bits.Type == 0x1b, "wrong type %x\n", info.Entry.HighWord.Bits.Type );
|
||||
ok( info.Entry.HighWord.Bits.Dpl == 3, "wrong dpl %x\n", info.Entry.HighWord.Bits.Dpl );
|
||||
ok( info.Entry.HighWord.Bits.Pres, "wrong pres\n" );
|
||||
ok( !info.Entry.HighWord.Bits.Sys, "wrong sys\n" );
|
||||
ok( info.Entry.HighWord.Bits.Default_Big, "wrong big\n" );
|
||||
ok( info.Entry.HighWord.Bits.Granularity, "wrong granularity\n" );
|
||||
}
|
||||
else if (sel == context.SegSs) /* 32-bit data selector */
|
||||
{
|
||||
ok( !status, "wrong status %x\n", status );
|
||||
ok( retlen == sizeof(info.Entry), "len set %u\n", retlen );
|
||||
ok( !base, "wrong base %x\n", base );
|
||||
ok( limit == 0xfffff, "wrong limit %x\n", limit );
|
||||
ok( info.Entry.HighWord.Bits.Type == 0x13, "wrong type %x\n", info.Entry.HighWord.Bits.Type );
|
||||
ok( info.Entry.HighWord.Bits.Dpl == 3, "wrong dpl %x\n", info.Entry.HighWord.Bits.Dpl );
|
||||
ok( info.Entry.HighWord.Bits.Pres, "wrong pres\n" );
|
||||
ok( !info.Entry.HighWord.Bits.Sys, "wrong sys\n" );
|
||||
ok( info.Entry.HighWord.Bits.Default_Big, "wrong big\n" );
|
||||
ok( info.Entry.HighWord.Bits.Granularity, "wrong granularity\n" );
|
||||
}
|
||||
else if (sel == context.SegFs) /* TEB selector */
|
||||
{
|
||||
ok( !status, "wrong status %x\n", status );
|
||||
ok( retlen == sizeof(info.Entry), "len set %u\n", retlen );
|
||||
#ifdef _WIN64
|
||||
if (NtCurrentTeb()->WowTebOffset == 0x2000)
|
||||
ok( base == (ULONG_PTR)NtCurrentTeb() + 0x2000, "wrong base %x / %p\n",
|
||||
base, NtCurrentTeb() );
|
||||
#else
|
||||
ok( base == (ULONG_PTR)NtCurrentTeb(), "wrong base %x / %p\n", base, NtCurrentTeb() );
|
||||
#endif
|
||||
ok( limit == 0xfff || broken(limit == 0x4000), /* <= win8 */
|
||||
"wrong limit %x\n", limit );
|
||||
ok( info.Entry.HighWord.Bits.Type == 0x13, "wrong type %x\n", info.Entry.HighWord.Bits.Type );
|
||||
ok( info.Entry.HighWord.Bits.Dpl == 3, "wrong dpl %x\n", info.Entry.HighWord.Bits.Dpl );
|
||||
ok( info.Entry.HighWord.Bits.Pres, "wrong pres\n" );
|
||||
ok( !info.Entry.HighWord.Bits.Sys, "wrong sys\n" );
|
||||
ok( info.Entry.HighWord.Bits.Default_Big, "wrong big\n" );
|
||||
ok( !info.Entry.HighWord.Bits.Granularity, "wrong granularity\n" );
|
||||
}
|
||||
else if (!status)
|
||||
{
|
||||
ok( retlen == sizeof(info.Entry), "len set %u\n", retlen );
|
||||
trace( "succeeded for %x base %x limit %x type %x\n",
|
||||
sel, base, limit, info.Entry.HighWord.Bits.Type );
|
||||
}
|
||||
else
|
||||
{
|
||||
ok( status == STATUS_UNSUCCESSFUL ||
|
||||
((sel & 4) && (status == STATUS_NO_LDT)) ||
|
||||
broken( status == STATUS_ACCESS_VIOLATION), /* <= win8 */
|
||||
"%x: wrong status %x\n", info.Selector, status );
|
||||
ok( retlen == 0xdeadbeef, "len set %u\n", retlen );
|
||||
}
|
||||
}
|
||||
#undef GET_ENTRY
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
|
||||
static void test_cpu_area(void)
|
||||
|
@ -783,6 +919,7 @@ START_TEST(wow64)
|
|||
init();
|
||||
test_query_architectures();
|
||||
test_peb_teb();
|
||||
test_selectors();
|
||||
#ifndef _WIN64
|
||||
test_nt_wow64();
|
||||
test_modules();
|
||||
|
|
|
@ -2111,7 +2111,7 @@ NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_
|
|||
THREAD_DESCRIPTOR_INFORMATION *info = data;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
if (len < sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH;
|
||||
if (len != sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH;
|
||||
if (info->Selector >> 16) return STATUS_UNSUCCESSFUL;
|
||||
|
||||
if (is_gdt_sel( info->Selector ))
|
||||
|
|
|
@ -4406,6 +4406,7 @@ NTSYSAPI int __cdecl _strnicmp(LPCSTR,LPCSTR,size_t);
|
|||
NTSYSAPI NTSTATUS WINAPI RtlWow64GetCpuAreaInfo(WOW64_CPURESERVED*,ULONG,WOW64_CPU_AREA_INFO*);
|
||||
NTSYSAPI NTSTATUS WINAPI RtlWow64GetCurrentCpuArea(USHORT*,void**,void**);
|
||||
NTSYSAPI NTSTATUS WINAPI RtlWow64GetThreadContext(HANDLE,WOW64_CONTEXT*);
|
||||
NTSYSAPI NTSTATUS WINAPI RtlWow64GetThreadSelectorEntry(HANDLE,THREAD_DESCRIPTOR_INFORMATION*,ULONG,ULONG*);
|
||||
NTSYSAPI NTSTATUS WINAPI RtlWow64SetThreadContext(HANDLE,const WOW64_CONTEXT*);
|
||||
#else
|
||||
NTSYSAPI NTSTATUS WINAPI NtWow64AllocateVirtualMemory64(HANDLE,ULONG64*,ULONG64,ULONG64*,ULONG,ULONG);
|
||||
|
|
Loading…
Reference in a new issue