/*********************************************************************** * WOWTHUNK_Init */ BOOL WOWTHUNK_Init(void) { /* allocate the code selector for CallTo16 routines */ LDT_ENTRY entry; WORD codesel = wine_ldt_alloc_entries(1); if (!codesel) return FALSE; wine_ldt_set_base( &entry, __wine_call16_start ); wine_ldt_set_limit( &entry, (BYTE *)(&CallTo16_TebSelector + 1) - __wine_call16_start - 1 ); wine_ldt_set_flags( &entry, WINE_LDT_FLAGS_CODE | WINE_LDT_FLAGS_32BIT ); wine_ldt_set_entry( codesel, &entry ); /* Patch the return addresses for CallTo16 routines */ CallTo16_DataSelector = wine_get_ds(); call16_ret_addr = MAKESEGPTR( codesel, (BYTE *)__wine_call_to_16_ret - __wine_call16_start ); CALL32_CBClient_RetAddr = MAKESEGPTR( codesel, (BYTE *)CALL32_CBClient_Ret - __wine_call16_start ); CALL32_CBClientEx_RetAddr = MAKESEGPTR( codesel, (BYTE *)CALL32_CBClientEx_Ret - __wine_call16_start ); /* Prepare selector and offsets for DPMI event checking. */ dpmi_checker_selector = codesel; dpmi_checker_offset_call = (BYTE *)DPMI_PendingEventCheck - __wine_call16_start; dpmi_checker_offset_cleanup = (BYTE *)DPMI_PendingEventCheck_Cleanup - __wine_call16_start; dpmi_checker_offset_return = (BYTE *)DPMI_PendingEventCheck_Return - __wine_call16_start; if (TRACE_ON(relay) || TRACE_ON(snoop)) RELAY16_InitDebugLists(); return TRUE; }
/************************************************************************** * DllEntryPoint (KERNEL.669) */ BOOL WINAPI KERNEL_DllEntryPoint( DWORD reasion, HINSTANCE16 inst, WORD ds, WORD heap, DWORD reserved1, WORD reserved2 ) { static BOOL done; /* the entry point can be called multiple times */ if (done) return TRUE; done = TRUE; /* create the shared heap for broken win95 native dlls */ HeapCreate( HEAP_SHARED, 0, 0 ); /* setup emulation of protected instructions from 32-bit code */ if (GetVersion() & 0x80000000) RtlAddVectoredExceptionHandler( TRUE, INSTR_vectored_handler ); /* Initialize 16-bit thunking entry points */ if (!WOWTHUNK_Init()) return FALSE; /* Initialize DOS memory */ if (!DOSMEM_Init()) return FALSE; /* Initialize special KERNEL entry points */ NE_SetEntryPoint( inst, 178, GetWinFlags16() ); NE_SetEntryPoint( inst, 454, wine_get_cs() ); NE_SetEntryPoint( inst, 455, wine_get_ds() ); NE_SetEntryPoint( inst, 183, DOSMEM_0000H ); /* KERNEL.183: __0000H */ NE_SetEntryPoint( inst, 173, DOSMEM_BiosSysSeg ); /* KERNEL.173: __ROMBIOS */ NE_SetEntryPoint( inst, 193, DOSMEM_BiosDataSeg ); /* KERNEL.193: __0040H */ NE_SetEntryPoint( inst, 194, DOSMEM_BiosSysSeg ); /* KERNEL.194: __F000H */ /* Initialize KERNEL.THHOOK */ TASK_InstallTHHook(MapSL((SEGPTR)GetProcAddress16( inst, (LPCSTR)332 ))); TASK_CreateMainTask(); /* Initialize the real-mode selector entry points */ #define SET_ENTRY_POINT( num, addr ) \ NE_SetEntryPoint( inst, (num), GLOBAL_CreateBlock( GMEM_FIXED, \ DOSMEM_MapDosToLinear(addr), 0x10000, inst, \ WINE_LDT_FLAGS_DATA )) SET_ENTRY_POINT( 174, 0xa0000 ); /* KERNEL.174: __A000H */ SET_ENTRY_POINT( 181, 0xb0000 ); /* KERNEL.181: __B000H */ SET_ENTRY_POINT( 182, 0xb8000 ); /* KERNEL.182: __B800H */ SET_ENTRY_POINT( 195, 0xc0000 ); /* KERNEL.195: __C000H */ SET_ENTRY_POINT( 179, 0xd0000 ); /* KERNEL.179: __D000H */ SET_ENTRY_POINT( 190, 0xe0000 ); /* KERNEL.190: __E000H */ #undef SET_ENTRY_POINT /* Force loading of some dlls */ LoadLibrary16( "system.drv" ); LoadLibrary16( "comm.drv" ); return TRUE; }
/************************************************************************** * DllEntryPoint (KERNEL.669) */ BOOL WINAPI KERNEL_DllEntryPoint( DWORD reasion, HINSTANCE16 inst, WORD ds, WORD heap, DWORD reserved1, WORD reserved2 ) { static int done; /* the entry point can be called multiple times */ if (done) return TRUE; done = 1; /* Initialize 16-bit thunking entry points */ if (!WOWTHUNK_Init()) return FALSE; /* Initialize DOS memory */ if (!DOSMEM_Init()) return FALSE; /* Initialize special KERNEL entry points */ NE_SetEntryPoint( inst, 178, GetWinFlags16() ); NE_SetEntryPoint( inst, 454, wine_get_cs() ); NE_SetEntryPoint( inst, 455, wine_get_ds() ); NE_SetEntryPoint( inst, 183, DOSMEM_0000H ); /* KERNEL.183: __0000H */ NE_SetEntryPoint( inst, 173, DOSMEM_BiosSysSeg ); /* KERNEL.173: __ROMBIOS */ NE_SetEntryPoint( inst, 193, DOSMEM_BiosDataSeg ); /* KERNEL.193: __0040H */ NE_SetEntryPoint( inst, 194, DOSMEM_BiosSysSeg ); /* KERNEL.194: __F000H */ /* Initialize KERNEL.THHOOK */ TASK_InstallTHHook(MapSL((SEGPTR)GetProcAddress16( inst, (LPCSTR)332 ))); /* Initialize the real-mode selector entry points */ #define SET_ENTRY_POINT( num, addr ) \ NE_SetEntryPoint( inst, (num), GLOBAL_CreateBlock( GMEM_FIXED, \ DOSMEM_MapDosToLinear(addr), 0x10000, inst, \ WINE_LDT_FLAGS_DATA )) SET_ENTRY_POINT( 174, 0xa0000 ); /* KERNEL.174: __A000H */ SET_ENTRY_POINT( 181, 0xb0000 ); /* KERNEL.181: __B000H */ SET_ENTRY_POINT( 182, 0xb8000 ); /* KERNEL.182: __B800H */ SET_ENTRY_POINT( 195, 0xc0000 ); /* KERNEL.195: __C000H */ SET_ENTRY_POINT( 179, 0xd0000 ); /* KERNEL.179: __D000H */ SET_ENTRY_POINT( 190, 0xe0000 ); /* KERNEL.190: __E000H */ #undef SET_ENTRY_POINT /* Force loading of some dlls */ LoadLibrary16( "system.drv" ); return TRUE; }
/********************************************************************** * K32WOWCallback16Ex (KERNEL32.55) */ BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags, DWORD cbArgs, LPVOID pArgs, LPDWORD pdwRetCode ) { #ifdef __i386__ /* * Arguments must be prepared in the correct order by the caller * (both for PASCAL and CDECL calling convention), so we simply * copy them to the 16-bit stack ... */ char *stack = (char *)CURRENT_STACK16 - cbArgs; memcpy( stack, pArgs, cbArgs ); if (dwFlags & (WCB16_REGS|WCB16_REGS_LONG)) { CONTEXT *context = (CONTEXT *)pdwRetCode; if (TRACE_ON(relay)) { DWORD count = cbArgs / sizeof(WORD); WORD * wstack = (WORD *)stack; DPRINTF("%04lx:CallTo16(func=%04lx:%04x,ds=%04lx", GetCurrentThreadId(), context->SegCs, LOWORD(context->Eip), context->SegDs ); while (count) DPRINTF( ",%04x", wstack[--count] ); DPRINTF(") ss:sp=%04x:%04x", SELECTOROF(NtCurrentTeb()->WOW32Reserved), OFFSETOF(NtCurrentTeb()->WOW32Reserved) ); DPRINTF(" ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x bp=%04x es=%04x fs=%04x\n", (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx, (WORD)context->Edx, (WORD)context->Esi, (WORD)context->Edi, (WORD)context->Ebp, (WORD)context->SegEs, (WORD)context->SegFs ); SYSLEVEL_CheckNotLevel( 2 ); } if (context->EFlags & 0x00020000) /* v86 mode */ { EXCEPTION_REGISTRATION_RECORD frame; frame.Handler = vm86_handler; __wine_push_frame( &frame ); __wine_enter_vm86( context ); __wine_pop_frame( &frame ); } else { /* push return address */ if (dwFlags & WCB16_REGS_LONG) { stack -= sizeof(DWORD); *((DWORD *)stack) = HIWORD(call16_ret_addr); stack -= sizeof(DWORD); *((DWORD *)stack) = LOWORD(call16_ret_addr); cbArgs += 2 * sizeof(DWORD); } else { stack -= sizeof(SEGPTR); *((SEGPTR *)stack) = call16_ret_addr; cbArgs += sizeof(SEGPTR); } /* * Start call by checking for pending events. * Note that wine_call_to_16_regs overwrites context stack * pointer so we may modify it here without a problem. */ if (NtCurrentTeb()->dpmi_vif) { context->SegSs = wine_get_ds(); context->Esp = (DWORD)stack; insert_event_check( context ); cbArgs += (DWORD)stack - context->Esp; } _EnterWin16Lock(); wine_call_to_16_regs( context, cbArgs, call16_handler ); _LeaveWin16Lock(); } if (TRACE_ON(relay)) { DPRINTF("%04lx:RetFrom16() ss:sp=%04x:%04x ", GetCurrentThreadId(), SELECTOROF(NtCurrentTeb()->WOW32Reserved), OFFSETOF(NtCurrentTeb()->WOW32Reserved)); DPRINTF(" ax=%04x bx=%04x cx=%04x dx=%04x bp=%04x sp=%04x\n", (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx, (WORD)context->Edx, (WORD)context->Ebp, (WORD)context->Esp ); SYSLEVEL_CheckNotLevel( 2 ); } } else { DWORD ret; if (TRACE_ON(relay)) { DWORD count = cbArgs / sizeof(WORD); WORD * wstack = (WORD *)stack; DPRINTF("%04lx:CallTo16(func=%04x:%04x,ds=%04x", GetCurrentThreadId(), HIWORD(vpfn16), LOWORD(vpfn16), SELECTOROF(NtCurrentTeb()->WOW32Reserved) ); while (count) DPRINTF( ",%04x", wstack[--count] ); DPRINTF(") ss:sp=%04x:%04x\n", SELECTOROF(NtCurrentTeb()->WOW32Reserved), OFFSETOF(NtCurrentTeb()->WOW32Reserved) ); SYSLEVEL_CheckNotLevel( 2 ); } /* push return address */ stack -= sizeof(SEGPTR); *((SEGPTR *)stack) = call16_ret_addr; cbArgs += sizeof(SEGPTR); /* * Actually, we should take care whether the called routine cleans up * its stack or not. Fortunately, our wine_call_to_16 core doesn't rely on * the callee to do so; after the routine has returned, the 16-bit * stack pointer is always reset to the position it had before. */ _EnterWin16Lock(); ret = wine_call_to_16( (FARPROC16)vpfn16, cbArgs, call16_handler ); if (pdwRetCode) *pdwRetCode = ret; _LeaveWin16Lock(); if (TRACE_ON(relay)) { DPRINTF("%04lx:RetFrom16() ss:sp=%04x:%04x retval=%08lx\n", GetCurrentThreadId(), SELECTOROF(NtCurrentTeb()->WOW32Reserved), OFFSETOF(NtCurrentTeb()->WOW32Reserved), ret); SYSLEVEL_CheckNotLevel( 2 ); } } #else assert(0); /* cannot call to 16-bit on non-Intel architectures */ #endif /* __i386__ */ return TRUE; /* success */ }
/********************************************************************** * K32WOWCallback16Ex (KERNEL32.55) */ BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags, DWORD cbArgs, LPVOID pArgs, LPDWORD pdwRetCode ) { /* * Arguments must be prepared in the correct order by the caller * (both for PASCAL and CDECL calling convention), so we simply * copy them to the 16-bit stack ... */ char *stack = (char *)CURRENT_STACK16 - cbArgs; memcpy( stack, pArgs, cbArgs ); if (dwFlags & (WCB16_REGS|WCB16_REGS_LONG)) { CONTEXT *context = (CONTEXT *)pdwRetCode; if (TRACE_ON(relay)) { DWORD count = cbArgs / sizeof(WORD); WORD * wstack = (WORD *)stack; TRACE_(relay)( "\1CallTo16(func=%04x:%04x", context->SegCs, LOWORD(context->Eip) ); while (count) TRACE_(relay)( ",%04x", wstack[--count] ); TRACE_(relay)( ") ss:sp=%04x:%04x ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x bp=%04x ds=%04x es=%04x\n", SELECTOROF(NtCurrentTeb()->WOW32Reserved), OFFSETOF(NtCurrentTeb()->WOW32Reserved), (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx, (WORD)context->Edx, (WORD)context->Esi, (WORD)context->Edi, (WORD)context->Ebp, (WORD)context->SegDs, (WORD)context->SegEs ); SYSLEVEL_CheckNotLevel( 2 ); } if (context->EFlags & 0x00020000) /* v86 mode */ { EXCEPTION_REGISTRATION_RECORD frame; frame.Handler = vm86_handler; errno = 0; __wine_push_frame( &frame ); __wine_enter_vm86( context ); __wine_pop_frame( &frame ); if (errno != 0) /* enter_vm86 will fail with ENOSYS on x64 kernels */ { WARN("__wine_enter_vm86 failed (errno=%d)\n", errno); if (errno == ENOSYS) SetLastError(ERROR_NOT_SUPPORTED); else SetLastError(ERROR_GEN_FAILURE); return FALSE; } } else { /* push return address */ if (dwFlags & WCB16_REGS_LONG) { stack -= sizeof(DWORD); *((DWORD *)stack) = HIWORD(call16_ret_addr); stack -= sizeof(DWORD); *((DWORD *)stack) = LOWORD(call16_ret_addr); cbArgs += 2 * sizeof(DWORD); } else { stack -= sizeof(SEGPTR); *((SEGPTR *)stack) = call16_ret_addr; cbArgs += sizeof(SEGPTR); } /* * Start call by checking for pending events. * Note that wine_call_to_16_regs overwrites context stack * pointer so we may modify it here without a problem. */ if (get_vm86_teb_info()->dpmi_vif) { context->SegSs = wine_get_ds(); context->Esp = (DWORD)stack; insert_event_check( context ); cbArgs += (DWORD)stack - context->Esp; } _EnterWin16Lock(); wine_call_to_16_regs( context, cbArgs, call16_handler ); _LeaveWin16Lock(); } if (TRACE_ON(relay)) { TRACE_(relay)( "\1RetFrom16() ss:sp=%04x:%04x ax=%04x bx=%04x cx=%04x dx=%04x bp=%04x sp=%04x\n", SELECTOROF(NtCurrentTeb()->WOW32Reserved), OFFSETOF(NtCurrentTeb()->WOW32Reserved), (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx, (WORD)context->Edx, (WORD)context->Ebp, (WORD)context->Esp ); SYSLEVEL_CheckNotLevel( 2 ); } } else { DWORD ret; if (TRACE_ON(relay)) { DWORD count = cbArgs / sizeof(WORD); WORD * wstack = (WORD *)stack; TRACE_(relay)( "\1CallTo16(func=%04x:%04x,ds=%04x", HIWORD(vpfn16), LOWORD(vpfn16), SELECTOROF(NtCurrentTeb()->WOW32Reserved) ); while (count) TRACE_(relay)( ",%04x", wstack[--count] ); TRACE_(relay)( ") ss:sp=%04x:%04x\n", SELECTOROF(NtCurrentTeb()->WOW32Reserved), OFFSETOF(NtCurrentTeb()->WOW32Reserved) ); SYSLEVEL_CheckNotLevel( 2 ); } /* push return address */ stack -= sizeof(SEGPTR); *((SEGPTR *)stack) = call16_ret_addr; cbArgs += sizeof(SEGPTR); /* * Actually, we should take care whether the called routine cleans up * its stack or not. Fortunately, our wine_call_to_16 core doesn't rely on * the callee to do so; after the routine has returned, the 16-bit * stack pointer is always reset to the position it had before. */ _EnterWin16Lock(); ret = wine_call_to_16( (FARPROC16)vpfn16, cbArgs, call16_handler ); if (pdwRetCode) *pdwRetCode = ret; _LeaveWin16Lock(); if (TRACE_ON(relay)) { TRACE_(relay)( "\1RetFrom16() ss:sp=%04x:%04x retval=%08x\n", SELECTOROF(NtCurrentTeb()->WOW32Reserved), OFFSETOF(NtCurrentTeb()->WOW32Reserved), ret ); SYSLEVEL_CheckNotLevel( 2 ); } } return TRUE; /* success */ }