/*********************************************************************** * server_exit_thread */ void server_exit_thread( int status ) { struct wine_pthread_thread_info info; int fds[4]; RtlAcquirePebLock(); RemoveEntryList( &NtCurrentTeb()->TlsLinks ); RtlReleasePebLock(); RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->FlsSlots ); RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->TlsExpansionSlots ); info.stack_base = NtCurrentTeb()->DeallocationStack; info.teb_base = NtCurrentTeb(); info.teb_sel = wine_get_fs(); info.exit_status = status; fds[0] = ntdll_get_thread_data()->wait_fd[0]; fds[1] = ntdll_get_thread_data()->wait_fd[1]; fds[2] = ntdll_get_thread_data()->reply_fd; fds[3] = ntdll_get_thread_data()->request_fd; pthread_functions.sigprocmask( SIG_BLOCK, &server_block_set, NULL ); info.stack_size = virtual_free_system_view( &info.stack_base ); info.teb_size = virtual_free_system_view( &info.teb_base ); close( fds[0] ); close( fds[1] ); close( fds[2] ); close( fds[3] ); pthread_functions.exit_thread( &info ); }
/*********************************************************************** * NE_InitDLL * * Call the DLL initialization code */ static BOOL NE_InitDLL( NE_MODULE *pModule ) { SEGTABLEENTRY *pSegTable; WORD hInst, ds, heap; CONTEXT context; pSegTable = NE_SEG_TABLE( pModule ); if (!(pModule->ne_flags & NE_FFLAGS_LIBMODULE) || (pModule->ne_flags & NE_FFLAGS_WIN32)) return TRUE; /*not a library*/ /* Call USER signal handler for Win3.1 compatibility. */ NE_CallUserSignalProc( pModule->self, USIG16_DLL_LOAD ); if (!SELECTOROF(pModule->ne_csip)) return TRUE; /* no initialization code */ /* Registers at initialization must be: * cx heap size * di library instance * ds data segment if any * es:si command line (always 0) */ memset( &context, 0, sizeof(context) ); NE_GetDLLInitParams( pModule, &hInst, &ds, &heap ); context.Ecx = heap; context.Edi = hInst; context.SegDs = ds; context.SegEs = ds; /* who knows ... */ context.SegFs = wine_get_fs(); context.SegGs = wine_get_gs(); context.SegCs = SEL(pSegTable[SELECTOROF(pModule->ne_csip)-1].hSeg); context.Eip = OFFSETOF(pModule->ne_csip); context.Ebp = OFFSETOF(getWOW32Reserved()) + FIELD_OFFSET(STACK16FRAME,bp); pModule->ne_csip = 0; /* Don't initialize it twice */ TRACE_(dll)("Calling LibMain for %.*s, cs:ip=%04x:%04x ds=%04x di=%04x cx=%04x\n", *((BYTE*)pModule + pModule->ne_restab), (char *)pModule + pModule->ne_restab + 1, context.SegCs, context.Eip, context.SegDs, LOWORD(context.Edi), LOWORD(context.Ecx) ); WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)&context ); return TRUE; }
static void NE_CallDllEntryPoint( NE_MODULE *pModule, DWORD dwReason ) { WORD hInst, ds, heap; FARPROC16 entryPoint; if (!(pModule->ne_flags & NE_FFLAGS_LIBMODULE)) return; if (!(pModule->ne_flags & NE_FFLAGS_BUILTIN) && pModule->ne_expver < 0x0400) return; if (!(entryPoint = GetProcAddress16( pModule->self, "DllEntryPoint" ))) return; NE_GetDLLInitParams( pModule, &hInst, &ds, &heap ); TRACE_(dll)( "Calling %s DllEntryPoint, cs:ip=%04x:%04x\n", NE_MODULE_NAME( pModule ), SELECTOROF(entryPoint), OFFSETOF(entryPoint) ); if ( pModule->ne_flags & NE_FFLAGS_BUILTIN ) { WinNEEntryProc entryProc = (WinNEEntryProc)((ENTRYPOINT16 *)MapSL( (SEGPTR)entryPoint ))->target; entryProc( dwReason, hInst, ds, heap, 0, 0 ); } else { CONTEXT context; WORD args[8]; memset( &context, 0, sizeof(context) ); context.SegDs = ds; context.SegEs = ds; /* who knows ... */ context.SegFs = wine_get_fs(); context.SegGs = wine_get_gs(); context.SegCs = HIWORD(entryPoint); context.Eip = LOWORD(entryPoint); context.Ebp = OFFSETOF(getWOW32Reserved()) + FIELD_OFFSET(STACK16FRAME,bp); args[7] = HIWORD(dwReason); args[6] = LOWORD(dwReason); args[5] = hInst; args[4] = ds; args[3] = heap; args[2] = 0; /* HIWORD(dwReserved1) */ args[1] = 0; /* LOWORD(dwReserved1) */ args[0] = 0; /* wReserved2 */ WOWCallback16Ex( 0, WCB16_REGS, sizeof(args), args, (DWORD *)&context ); } }
/************************************************************* * insert_event_check * * Make resuming the context check for pending DPMI events * before the original context is restored. This is required * because DPMI events are asynchronous, they are blocked while * Wine 32-bit code is being executed and we want to prevent * a race when returning back to 16-bit or 32-bit DPMI context. */ static void insert_event_check( CONTEXT *context ) { char *stack = wine_ldt_get_ptr( context->SegSs, context->Esp ); /* don't do event check while in system code */ if (wine_ldt_is_system(context->SegCs)) return; if(context->SegCs == dpmi_checker_selector && context->Eip >= dpmi_checker_offset_call && context->Eip <= dpmi_checker_offset_cleanup) { /* * Nested call. Stack will be preserved. */ } else if(context->SegCs == dpmi_checker_selector && context->Eip == dpmi_checker_offset_return) { /* * Nested call. We have just finished popping the fs * register, lets put it back into stack. */ stack -= sizeof(WORD); *(WORD*)stack = context->SegFs; context->Esp -= 2; } else { /* * Call is not nested. * Push modified registers into stack. * These will be popped by the assembler stub. */ stack -= sizeof(DWORD); *(DWORD*)stack = context->EFlags; stack -= sizeof(DWORD); *(DWORD*)stack = context->SegCs; stack -= sizeof(DWORD); *(DWORD*)stack = context->Eip; stack -= sizeof(WORD); *(WORD*)stack = context->SegFs; context->Esp -= 14; } /* * Modify the context so that we jump into assembler stub. * TEB access is made easier by providing the stub * with the correct fs register value. */ context->SegCs = dpmi_checker_selector; context->Eip = dpmi_checker_offset_call; context->SegFs = wine_get_fs(); }
/* (see dosmem.c, function DOSMEM_InitDPMI) */ static void StartPM( CONTEXT86 *context ) { UINT16 cs, ss, ds, es; CONTEXT86 pm_ctx; DWORD psp_ofs = (DWORD)(DOSVM_psp<<4); PDB16 *psp = (PDB16 *)psp_ofs; HANDLE16 env_seg = psp->environment; unsigned char selflags = WINE_LDT_FLAGS_DATA; RESET_CFLAG(context); dpmi_flag = AX_reg(context); /* our mode switch wrapper have placed the desired CS into DX */ cs = alloc_pm_selector( context->Edx, WINE_LDT_FLAGS_CODE ); /* due to a flaw in some CPUs (at least mine), it is best to mark stack segments as 32-bit if they can be used in 32-bit code. Otherwise, these CPUs may not set the high word of esp during a ring transition (from kernel code) to the 16-bit stack, and this causes trouble if executing 32-bit code using this stack. */ if (dpmi_flag & 1) selflags |= WINE_LDT_FLAGS_32BIT; ss = alloc_pm_selector( context->SegSs, selflags ); /* do the same for the data segments, just in case */ if (context->SegDs == context->SegSs) ds = ss; else ds = alloc_pm_selector( context->SegDs, selflags ); es = alloc_pm_selector( DOSVM_psp, selflags ); /* convert environment pointer, as the spec says, but we're a bit lazy about the size here... */ psp->environment = alloc_pm_selector( env_seg, WINE_LDT_FLAGS_DATA ); pm_ctx = *context; pm_ctx.SegCs = DOSVM_dpmi_segments->dpmi_sel; /* our mode switch wrapper expects the new CS in DX, and the new SS in AX */ pm_ctx.Eax = ss; pm_ctx.Edx = cs; pm_ctx.SegDs = ds; pm_ctx.SegEs = es; pm_ctx.SegFs = wine_get_fs(); pm_ctx.SegGs = wine_get_gs(); pm_ctx.EFlags &= ~V86_FLAG; TRACE("DOS program is now entering %d-bit protected mode\n", DOSVM_IsDos32() ? 32 : 16); __TRY { WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)&pm_ctx ); } __EXCEPT(dpmi_exception_handler) { } __ENDTRY TRACE( "Protected mode DOS program is terminating\n" ); /* * FIXME: Instead of calling ExitThread, we should release all * allocated protected mode resources and call MZ_Exit * using real mode context. See DPMI specification. */ ExitThread( DPMI_retval ); #if 0 wine_ldt_free_entries( psp->environment, 1 ); psp->environment = env_seg; wine_ldt_free_entries(es,1); if (ds != ss) wine_ldt_free_entries(ds,1); wine_ldt_free_entries(ss,1); wine_ldt_free_entries(cs,1); #endif }