/*********************************************************************** * 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; }
static SEGPTR alloc_segptr_frame(struct frame_wrapper16 *wrapper, void *ptr, DWORD size) { int i; if (wrapper->sel) { if (wrapper->ptr == ptr && wrapper->size == size) return MAKESEGPTR(wrapper->sel, 0); free_segptr_frame(wrapper); } wrapper->ptr = ptr; wrapper->size = size; wrapper->count = (size + 0xffff) / 0x10000; wrapper->sel = AllocSelectorArray16(wrapper->count); if (!wrapper->sel) return 0; for (i = 0; i < wrapper->count; i++) { SetSelectorBase(wrapper->sel + (i << __AHSHIFT), (DWORD)ptr + i * 0x10000); SetSelectorLimit16(wrapper->sel + (i << __AHSHIFT), size - 1); size -= 0x10000; } return MAKESEGPTR(wrapper->sel, 0); }
/********************************************************************** * DPMI_CallRMCBProc * * This routine does the hard work of calling a callback procedure. */ static void DPMI_CallRMCBProc( CONTEXT86 *context, RMCB *rmcb, WORD flag ) { DWORD old_vif = NtCurrentTeb()->dpmi_vif; /* Disable virtual interrupts. */ NtCurrentTeb()->dpmi_vif = 0; if (wine_ldt_is_system( rmcb->proc_sel )) { /* Wine-internal RMCB, call directly */ ((RMCBPROC)rmcb->proc_ofs)(context); } else __TRY { #ifdef __i386__ UINT16 ss,es; DWORD esp,edi; INT_SetRealModeContext(MapSL(MAKESEGPTR( rmcb->regs_sel, rmcb->regs_ofs )), context); ss = alloc_pm_selector( context->SegSs, WINE_LDT_FLAGS_DATA ); esp = context->Esp; FIXME("untested!\n"); /* The called proc ends with an IRET, and takes these parameters: * DS:ESI = pointer to real-mode SS:SP * ES:EDI = pointer to real-mode call structure * It returns: * ES:EDI = pointer to real-mode call structure (may be a copy) * It is the proc's responsibility to change the return CS:IP in the * real-mode call structure. */ if (flag & 1) { /* 32-bit DPMI client */ DPMI_CallRMCB32(rmcb, ss, esp, &es, &edi); } else { /* 16-bit DPMI client */ CONTEXT86 ctx = *context; ctx.SegCs = rmcb->proc_sel; ctx.Eip = rmcb->proc_ofs; ctx.SegDs = ss; ctx.Esi = esp; ctx.SegEs = rmcb->regs_sel; ctx.Edi = rmcb->regs_ofs; /* FIXME: I'm pretty sure this isn't right - should push flags first */ WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)&ctx ); es = ctx.SegEs; edi = ctx.Edi; } wine_ldt_free_entries( ss, 1 ); INT_GetRealModeContext( MapSL( MAKESEGPTR( es, edi )), context); #else ERR("RMCBs only implemented for i386\n"); #endif } __EXCEPT(dpmi_exception_handler) { } __ENDTRY /* Restore virtual interrupt flag. */ NtCurrentTeb()->dpmi_vif = old_vif; }
/*********************************************************************** * NE_LoadAllSegments */ BOOL NE_LoadAllSegments( NE_MODULE *pModule ) { int i; SEGTABLEENTRY * pSegTable = (SEGTABLEENTRY *) NE_SEG_TABLE(pModule); if (pModule->flags & NE_FFLAGS_SELFLOAD) { HANDLE hf; HFILE16 hFile16; HGLOBAL16 sel; /* Handle self-loading modules */ SELFLOADHEADER *selfloadheader; HMODULE16 mod = GetModuleHandle16("KERNEL"); DWORD oldstack; TRACE_(module)("%.*s is a self-loading module!\n", *((BYTE*)pModule + pModule->name_table), (char *)pModule + pModule->name_table + 1); if (!NE_LoadSegment( pModule, 1 )) return FALSE; selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg), 0) ); selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc"); selfloadheader->MyAlloc = GetProcAddress16(mod,"MyAlloc"); selfloadheader->SetOwner = GetProcAddress16(mod,"FarSetOwner"); sel = GlobalAlloc16( GMEM_ZEROINIT, 0xFF00 ); pModule->self_loading_sel = SEL(sel); FarSetOwner16( sel, pModule->self ); oldstack = NtCurrentTeb()->WOW32Reserved; NtCurrentTeb()->WOW32Reserved = MAKESEGPTR(pModule->self_loading_sel, 0xff00 - sizeof(STACK16FRAME) ); DuplicateHandle( GetCurrentProcess(), NE_OpenFile(pModule), GetCurrentProcess(), &hf, 0, FALSE, DUPLICATE_SAME_ACCESS ); hFile16 = Win32HandleToDosFileHandle( hf ); TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n", pModule->self,hFile16); NE_CallTo16_word_ww(selfloadheader->BootApp, pModule->self,hFile16); TRACE_(dll)("Return from CallBootAppProc\n"); _lclose16(hFile16); NtCurrentTeb()->WOW32Reserved = oldstack; for (i = 2; i <= pModule->seg_count; i++) if (!NE_LoadSegment( pModule, i )) return FALSE; } else { for (i = 1; i <= pModule->seg_count; i++) if (!NE_LoadSegment( pModule, i )) return FALSE; } return TRUE; }
/*********************************************************************** * NE_LoadAllSegments */ BOOL NE_LoadAllSegments( NE_MODULE *pModule ) { int i; SEGTABLEENTRY * pSegTable = NE_SEG_TABLE(pModule); if (pModule->ne_flags & NE_FFLAGS_SELFLOAD) { HFILE16 hFile16; HGLOBAL16 sel; /* Handle self-loading modules */ SELFLOADHEADER *selfloadheader; HMODULE16 mod = GetModuleHandle16("KERNEL"); void *oldstack; WORD args[2]; TRACE_(module)("%.*s is a self-loading module!\n", *((BYTE*)pModule + pModule->ne_restab), (char *)pModule + pModule->ne_restab + 1); if (!NE_LoadSegment( pModule, 1 )) return FALSE; selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg), 0) ); selfloadheader->EntryAddrProc = GetProcAddress16(mod,"EntryAddrProc"); selfloadheader->MyAlloc = GetProcAddress16(mod,"MyAlloc"); selfloadheader->SetOwner = GetProcAddress16(mod,"FarSetOwner"); sel = GlobalAlloc16( GMEM_ZEROINIT, 0xFF00 ); pModule->self_loading_sel = SEL(sel); FarSetOwner16( sel, pModule->self ); oldstack = getWOW32Reserved(); setWOW32Reserved((void *)MAKESEGPTR(pModule->self_loading_sel, 0xff00 - sizeof(STACK16FRAME) )); hFile16 = NE_OpenFile(pModule); TRACE_(dll)("CallBootAppProc(hModule=0x%04x,hf=0x%04x)\n", pModule->self,hFile16); args[1] = pModule->self; args[0] = hFile16; WOWCallback16Ex( (DWORD)selfloadheader->BootApp, WCB16_PASCAL, sizeof(args), args, NULL ); TRACE_(dll)("Return from CallBootAppProc\n"); _lclose16(hFile16); setWOW32Reserved(oldstack); for (i = 2; i <= pModule->ne_cseg; i++) if (!NE_LoadSegment( pModule, i )) return FALSE; } else { for (i = 1; i <= pModule->ne_cseg; i++) if (!NE_LoadSegment( pModule, i )) return FALSE; } return TRUE; }
/*********************************************************************** * DOSMEM_FillIsrTable * * Fill the interrupt table with fake BIOS calls to BIOSSEG (0xf000). * * NOTES: * Linux normally only traps INTs performed from or destined to BIOSSEG * for us to handle, if the int_revectored table is empty. Filling the * interrupt table with calls to INT stubs in BIOSSEG allows DOS programs * to hook interrupts, as well as use their familiar retf tricks to call * them, AND let Wine handle any unhooked interrupts transparently. */ static void DOSMEM_FillIsrTable(void) { SEGPTR *isr = (SEGPTR*)DOSMEM_sysmem; int x; for (x=0; x<256; x++) isr[x]=MAKESEGPTR(VM_STUB_SEGMENT,x*4); }
/*********************************************************************** * TaskNext (TOOLHELP.64) */ BOOL16 WINAPI TaskNext16( TASKENTRY *lpte ) { TDB *pTask; INSTANCEDATA *pInstData; TRACE_(toolhelp)("(%p): task=%04x\n", lpte, lpte->hNext ); if (!lpte->hNext) return FALSE; /* make sure that task and hInstance are valid (skip initial Wine task !) */ while (1) { pTask = TASK_GetPtr( lpte->hNext ); if (!pTask || pTask->magic != TDB_MAGIC) return FALSE; if (pTask->hInstance) break; lpte->hNext = pTask->hNext; } pInstData = MapSL( MAKESEGPTR( GlobalHandleToSel16(pTask->hInstance), 0 ) ); lpte->hTask = lpte->hNext; lpte->hTaskParent = pTask->hParent; lpte->hInst = pTask->hInstance; lpte->hModule = pTask->hModule; lpte->wSS = SELECTOROF( pTask->teb->WOW32Reserved ); lpte->wSP = OFFSETOF( pTask->teb->WOW32Reserved ); lpte->wStackTop = pInstData->stacktop; lpte->wStackMinimum = pInstData->stackmin; lpte->wStackBottom = pInstData->stackbottom; lpte->wcEvents = pTask->nEvents; lpte->hQueue = pTask->hQueue; lstrcpynA( lpte->szModule, pTask->module_name, sizeof(lpte->szModule) ); lpte->wPSPOffset = 0x100; /*??*/ lpte->hNext = pTask->hNext; return TRUE; }
static DWORD MZ_Launch( LPCSTR cmdtail, int length ) { TDB *pTask = GlobalLock16( GetCurrentTask() ); BYTE *psp_start = PTR_REAL_TO_LIN( DOSVM_psp, 0 ); DWORD rv; SYSLEVEL *lock; MSG msg; MZ_FillPSP(psp_start, cmdtail, length); pTask->flags |= TDBF_WINOLDAP; /* DTA is set to PSP:0080h when a program is started. */ pTask->dta = MAKESEGPTR( DOSVM_psp, 0x80 ); GetpWin16Lock( &lock ); _LeaveSysLevel( lock ); /* force the message queue to be created */ PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); ResumeThread(dosvm_thread); rv = DOSVM_Loop(dosvm_thread); CloseHandle(dosvm_thread); dosvm_thread = 0; dosvm_tid = 0; CloseHandle(loop_thread); loop_thread = 0; loop_tid = 0; if (rv) return rv; VGA_Clean(); ExitProcess(0); }
static void WINAPI SNOOP16_Return(FARPROC proc, LPBYTE args, CONTEXT *context) { SNOOP16_RETURNENTRY *ret = (SNOOP16_RETURNENTRY*)((char *) MapSL( MAKESEGPTR(context->SegCs,LOWORD(context->Eip)) )-5); /* We haven't found out the nrofargs yet. If we called a cdecl * function it is too late anyway and we can just set '0' (which * will be the difference between orig and current SP * If pascal -> everything ok. */ if (ret->dll->funs[ret->ordinal].nrofargs<0) { ret->dll->funs[ret->ordinal].nrofargs=(LOWORD(context->Esp)-ret->origSP-4)/2; } context->Eip = LOWORD(ret->origreturn); context->SegCs = HIWORD(ret->origreturn); TRACE("\1RET %s.%d: %s(", ret->dll->name, ret->ordinal, ret->dll->funs[ret->ordinal].name); if (ret->args) { int i,max; max = ret->dll->funs[ret->ordinal].nrofargs; if (max>16) max=16; if (max<0) max=0; for (i=max;i--;) TRACE("%04x%s",ret->args[i],i?",":""); if (max!=ret->dll->funs[ret->ordinal].nrofargs) TRACE(" ..."); HeapFree(GetProcessHeap(),0,ret->args); ret->args = NULL; } TRACE(") retval = %04x:%04x ret=%04x:%04x\n", (WORD)context->Edx,(WORD)context->Eax, HIWORD(ret->origreturn),LOWORD(ret->origreturn)); ret->origreturn = NULL; /* mark as empty */ }
/*********************************************************************** * TASK_AllocThunk * * Allocate a thunk for MakeProcInstance(). */ static SEGPTR TASK_AllocThunk(void) { TDB *pTask; THUNKS *pThunk; WORD sel, base; if (!(pTask = TASK_GetCurrent())) return 0; sel = pTask->hCSAlias; pThunk = (THUNKS *)pTask->thunks; base = (char *)pThunk - (char *)pTask; while (!pThunk->free) { sel = pThunk->next; if (!sel) /* Allocate a new segment */ { sel = GLOBAL_Alloc( GMEM_FIXED, FIELD_OFFSET( THUNKS, thunks[MIN_THUNKS] ), pTask->hPDB, WINE_LDT_FLAGS_CODE ); if (!sel) return 0; TASK_CreateThunks( sel, 0, MIN_THUNKS ); pThunk->next = sel; } pThunk = GlobalLock16( sel ); base = 0; } base += pThunk->free; pThunk->free = *(WORD *)((BYTE *)pThunk + pThunk->free); return MAKESEGPTR( sel, base ); }
static void MZ_Launch( LPCSTR cmdtail, int length ) { TDB *pTask = GlobalLock16( GetCurrentTask() ); BYTE *psp_start = PTR_REAL_TO_LIN( DOSVM_psp, 0 ); DWORD rv; SYSLEVEL *lock; MZ_FillPSP(psp_start, cmdtail, length); pTask->flags |= TDBF_WINOLDAP; /* DTA is set to PSP:0080h when a program is started. */ pTask->dta = MAKESEGPTR( DOSVM_psp, 0x80 ); GetpWin16Lock( &lock ); _LeaveSysLevel( lock ); ResumeThread(dosvm_thread); rv = DOSVM_Loop(dosvm_thread); CloseHandle(dosvm_thread); dosvm_thread = 0; dosvm_tid = 0; CloseHandle(loop_thread); loop_thread = 0; loop_tid = 0; VGA_Clean(); ExitProcess(rv); }
/*********************************************************************** * DOSVM_Int5cHandler * * Called from NetBIOSCall16. */ static void WINAPI DOSVM_Int5cHandler( CONTEXT86 *context ) { BYTE* ptr; ptr = MapSL( MAKESEGPTR(context->SegEs,BX_reg(context)) ); FIXME("(%p): command code %02x (ignored)\n",context, *ptr); *(ptr+0x01) = 0xFB; /* NetBIOS emulator not found */ SET_AL( context, 0xFB ); }
/************************************************************* * call16_handler * * Handler for exceptions occurring in 16-bit code. */ static DWORD call16_handler( EXCEPTION_RECORD *record, EXCEPTION_REGISTRATION_RECORD *frame, CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **pdispatcher ) { if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND)) { /* unwinding: restore the stack pointer in the TEB, and leave the Win16 mutex */ STACK32FRAME *frame32 = (STACK32FRAME *)((char *)frame - offsetof(STACK32FRAME,frame)); NtCurrentTeb()->WOW32Reserved = (void *)frame32->frame16; _LeaveWin16Lock(); } else if (record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION || record->ExceptionCode == EXCEPTION_PRIV_INSTRUCTION) { if (wine_ldt_is_system(context->SegCs)) { if (fix_selector( context )) return ExceptionContinueExecution; } else { SEGPTR gpHandler; DWORD ret = INSTR_EmulateInstruction( record, context ); /* * Insert check for pending DPMI events. Note that this * check must be inserted after instructions have been * emulated because the instruction emulation requires * original CS:IP and the emulation may change TEB.dpmi_vif. */ if(NtCurrentTeb()->dpmi_vif) insert_event_check( context ); if (ret != ExceptionContinueSearch) return ret; /* check for Win16 __GP handler */ if ((gpHandler = HasGPHandler16( MAKESEGPTR( context->SegCs, context->Eip ) ))) { WORD *stack = wine_ldt_get_ptr( context->SegSs, context->Esp ); *--stack = context->SegCs; *--stack = context->Eip; if (!IS_SELECTOR_32BIT(context->SegSs)) context->Esp = MAKELONG( LOWORD(context->Esp - 2*sizeof(WORD)), HIWORD(context->Esp) ); else context->Esp -= 2*sizeof(WORD); context->SegCs = SELECTOROF( gpHandler ); context->Eip = OFFSETOF( gpHandler ); return ExceptionContinueExecution; } } } else if (record->ExceptionCode == EXCEPTION_VM86_STI) { insert_event_check( context ); } return ExceptionContinueSearch; }
/*********************************************************************** * KERNEL thread initialisation routine */ static void thread_attach(void) { /* allocate the 16-bit stack (FIXME: should be done lazily) */ HGLOBAL16 hstack = WOWGlobalAlloc16( GMEM_FIXED, 0x10000 ); kernel_get_thread_data()->stack_sel = GlobalHandleToSel16( hstack ); NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR( kernel_get_thread_data()->stack_sel, 0x10000 - sizeof(STACK16FRAME) ); memset( (char *)GlobalLock16(hstack) + 0x10000 - sizeof(STACK16FRAME), 0, sizeof(STACK16FRAME) ); }
/*********************************************************************** * InitTask (KERNEL.91) * * Called by the application startup code. */ void WINAPI InitTask16( CONTEXT *context ) { TDB *pTask; INSTANCEDATA *pinstance; SEGPTR ptr; context->Eax = 0; if (!(pTask = TASK_GetCurrent())) return; /* Note: we need to trust that BX/CX contain the stack/heap sizes, as some apps, notably Visual Basic apps, *modify* the heap/stack size of the instance data segment before calling InitTask() */ /* Initialize the INSTANCEDATA structure */ pinstance = MapSL( MAKESEGPTR(CURRENT_DS, 0) ); pinstance->stackmin = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + sizeof( STACK16FRAME ); pinstance->stackbottom = pinstance->stackmin; /* yup, that's right. Confused me too. */ pinstance->stacktop = ( pinstance->stackmin > LOWORD(context->Ebx) ? pinstance->stackmin - LOWORD(context->Ebx) : 0 ) + 150; /* Initialize the local heap */ if (LOWORD(context->Ecx)) LocalInit16( GlobalHandleToSel16(pTask->hInstance), 0, LOWORD(context->Ecx) ); /* Initialize implicitly loaded DLLs */ NE_InitializeDLLs( pTask->hModule ); NE_DllProcessAttach( pTask->hModule ); /* Registers on return are: * ax 1 if OK, 0 on error * cx stack limit in bytes * dx cmdShow parameter * si instance handle of the previous instance * di instance handle of the new task * es:bx pointer to command line inside PSP * * 0 (=%bp) is pushed on the stack */ ptr = stack16_push( sizeof(WORD) ); *(WORD *)MapSL(ptr) = 0; context->Esp -= 2; context->Eax = 1; if (!pTask->pdb.cmdLine[0]) context->Ebx = 0x80; else { LPBYTE p = &pTask->pdb.cmdLine[1]; while ((*p == ' ') || (*p == '\t')) p++; context->Ebx = 0x80 + (p - pTask->pdb.cmdLine); } context->Ecx = pinstance->stacktop; context->Edx = pTask->nCmdShow; context->Esi = (DWORD)pTask->hPrevInstance; context->Edi = (DWORD)pTask->hInstance; context->SegEs = (WORD)pTask->hPDB; }
/*********************************************************************** * get_entry_point * * Return the ordinal, name, and type info corresponding to a CS:IP address. */ static const CALLFROM16 *get_entry_point( STACK16FRAME *frame, LPSTR module, LPSTR func, WORD *pOrd ) { WORD i, max_offset; register BYTE *p; NE_MODULE *pModule; ET_BUNDLE *bundle; ET_ENTRY *entry; *pOrd = 0; if (!(pModule = NE_GetPtr( FarGetOwner16( GlobalHandle16( frame->module_cs ) )))) return NULL; max_offset = 0; bundle = (ET_BUNDLE *)((BYTE *)pModule + pModule->ne_enttab); do { entry = (ET_ENTRY *)((BYTE *)bundle+6); for (i = bundle->first + 1; i <= bundle->last; i++) { if ((entry->offs < frame->entry_ip) && (entry->segnum == 1) /* code segment ? */ && (entry->offs >= max_offset)) { max_offset = entry->offs; *pOrd = i; } entry++; } } while ( (bundle->next) && (bundle = (ET_BUNDLE *)((BYTE *)pModule+bundle->next))); /* Search for the name in the resident names table */ /* (built-in modules have no non-resident table) */ p = (BYTE *)pModule + pModule->ne_restab; memcpy( module, p + 1, *p ); module[*p] = 0; while (*p) { p += *p + 1 + sizeof(WORD); if (*(WORD *)(p + *p + 1) == *pOrd) break; } memcpy( func, p + 1, *p ); func[*p] = 0; /* Retrieve entry point call structure */ p = MapSL( MAKESEGPTR( frame->module_cs, frame->callfrom_ip ) ); /* p now points to lret, get the start of CALLFROM16 structure */ return (CALLFROM16 *)(p - FIELD_OFFSET( CALLFROM16, ret )); }
/*********************************************************************** * SwitchStackTo (KERNEL.108) */ void WINAPI SwitchStackTo16( WORD seg, WORD ptr, WORD top ) { STACK16FRAME *oldFrame, *newFrame; INSTANCEDATA *pData; UINT16 copySize; if (!(pData = GlobalLock16( seg ))) return; TRACE("old=%04x:%04x new=%04x:%04x\n", SELECTOROF( NtCurrentTeb()->WOW32Reserved ), OFFSETOF( NtCurrentTeb()->WOW32Reserved ), seg, ptr ); /* Save the old stack */ oldFrame = CURRENT_STACK16; /* pop frame + args and push bp */ pData->old_ss_sp = (SEGPTR)NtCurrentTeb()->WOW32Reserved + sizeof(STACK16FRAME) + 2 * sizeof(WORD); *(WORD *)MapSL(pData->old_ss_sp) = oldFrame->bp; pData->stacktop = top; pData->stackmin = ptr; pData->stackbottom = ptr; /* Switch to the new stack */ /* Note: we need to take the 3 arguments into account; otherwise, * the stack will underflow upon return from this function. */ copySize = oldFrame->bp - OFFSETOF(pData->old_ss_sp); copySize += 3 * sizeof(WORD) + sizeof(STACK16FRAME); NtCurrentTeb()->WOW32Reserved = (void *)MAKESEGPTR( seg, ptr - copySize ); newFrame = CURRENT_STACK16; /* Copy the stack frame and the local variables to the new stack */ memmove( newFrame, oldFrame, copySize ); newFrame->bp = ptr; *(WORD *)MapSL( MAKESEGPTR( seg, ptr ) ) = 0; /* clear previous bp */ }
/*********************************************************************** * K327 (KERNEL.327) */ void WINAPI HandleParamError( CONTEXT *context ) { UINT16 uErr = LOWORD(context->Ebx); FARPROC16 lpfn = (FARPROC16)MAKESEGPTR( context->SegCs, context->Eip ); LPVOID lpvParam = (LPVOID)MAKELONG( LOWORD(context->Eax), LOWORD(context->Ecx) ); LogParamError16( uErr, lpfn, lpvParam ); if (!(uErr & ERR_WARNING)) { /* Abort current procedure: Unwind stack frame and jump to error handler (location at [bp-2]) */ WORD *stack = MapSL( MAKESEGPTR( context->SegSs, LOWORD(context->Ebp) )); context->Esp = LOWORD(context->Ebp) - 2; context->Ebp = stack[0] & 0xfffe; context->Eip = stack[-1]; context->Eax = context->Ecx = context->Edx = 0; context->SegEs = 0; } }
void DOSDEV_InstallDOSDevices(void) { DOS_DATASEG *dataseg; WORD seg; WORD selector; unsigned int n; /* allocate DOS data segment or something */ dataseg = DOSVM_AllocDataUMB( sizeof(DOS_DATASEG), &seg, &selector ); DOS_LOLSeg = MAKESEGPTR( seg, 0 ); DOSMEM_LOL()->wine_rm_lol = MAKESEGPTR( seg, FIELD_OFFSET(DOS_LISTOFLISTS, ptr_first_DPB) ); DOSMEM_LOL()->wine_pm_lol = MAKESEGPTR( selector, FIELD_OFFSET(DOS_LISTOFLISTS, ptr_first_DPB) ); /* initialize the magnificent List Of Lists */ InitListOfLists(&dataseg->lol); /* Set up first device (NUL) */ dataseg->last_dev = NULL; DOSDEV_SetupDevice( &devs[0], seg, DOS_DATASEG_OFF(lol.NUL_dev), DOS_DATASEG_OFF(thunk[0]) ); /* Set up the remaining devices */ for (n = 1; n < NR_DEVS; n++) DOSDEV_SetupDevice( &devs[n], seg, DOS_DATASEG_OFF(dev[n-1]), DOS_DATASEG_OFF(thunk[n]) ); /* CON is device 1 */ dataseg->lol.ptr_CON_dev_hdr = MAKESEGPTR(seg, DOS_DATASEG_OFF(dev[0])); }
/********************************************************************** * DOSVM_GetPMHandler16 * * Return the protected mode interrupt vector for a given interrupt. */ FARPROC16 DOSVM_GetPMHandler16( BYTE intnum ) { TDB *pTask; FARPROC16 proc = 0; pTask = GlobalLock16(GetCurrentTask()); if (pTask) { switch( intnum ) { case 0x00: proc = pTask->int0; break; case 0x02: proc = pTask->int2; break; case 0x04: proc = pTask->int4; break; case 0x06: proc = pTask->int6; break; case 0x07: proc = pTask->int7; break; case 0x3e: proc = pTask->int3e; break; case 0x75: proc = pTask->int75; break; } if( proc ) return proc; } if (!DOSVM_Vectors16[intnum]) { proc = (FARPROC16)MAKESEGPTR( DOSVM_dpmi_segments->int16_sel, DOSVM_STUB_PM16 * intnum ); DOSVM_Vectors16[intnum] = proc; } return DOSVM_Vectors16[intnum]; }
void DOSDEV_SetupDevice(const WINEDEV * devinfo, WORD seg, WORD off_dev, WORD off_thunk) { DOS_DEVICE_HEADER *dev = PTR_REAL_TO_LIN(seg, off_dev); WINEDEV_THUNK *thunk = PTR_REAL_TO_LIN(seg, off_thunk); DOS_DATASEG *dataseg = (DOS_DATASEG*)DOSMEM_LOL(); dev->attr = devinfo->attr; dev->strategy = off_thunk + FIELD_OFFSET(WINEDEV_THUNK, ljmp1); dev->interrupt = off_thunk + FIELD_OFFSET(WINEDEV_THUNK, ljmp2); memcpy(dev->name, devinfo->name, 8); thunk->ljmp1 = LJMP; thunk->strategy = DPMI_AllocInternalRMCB(devinfo->strategy); thunk->ljmp2 = LJMP; thunk->interrupt = DPMI_AllocInternalRMCB(devinfo->interrupt); dev->next_dev = NONEXT; if (dataseg->last_dev) dataseg->last_dev->next_dev = MAKESEGPTR(seg, off_dev); dataseg->last_dev = dev; }
/*********************************************************************** * VXD_VXDLoader (WPROCS.439) */ void WINAPI VXD_VXDLoader( CONTEXT86 *context ) { unsigned service = AX_reg(context); TRACE("[%04x] VXDLoader\n", (UINT16)service); switch (service) { case 0x0000: /* get version */ TRACE("returning version\n"); AX_reg(context) = 0x0000; DX_reg(context) = VXD_WinVersion(); RESET_CFLAG(context); break; case 0x0001: /* load device */ FIXME("load device %04lx:%04x (%s)\n", context->SegDs, DX_reg(context), debugstr_a(MapSL(MAKESEGPTR(context->SegDs, DX_reg(context))))); AX_reg(context) = 0x0000; context->SegEs = 0x0000; DI_reg(context) = 0x0000; RESET_CFLAG(context); break; case 0x0002: /* unload device */ FIXME("unload device (%08lx)\n", context->Ebx); AX_reg(context) = 0x0000; RESET_CFLAG(context); break; default: VXD_BARF( context, "VXDLDR" ); AX_reg(context) = 0x000B; /* invalid function number */ SET_CFLAG(context); break; } }
/********************************************************************** * CallRMProc (WINEDOS.@) */ void WINAPI DOSVM_CallRMProc( CONTEXT86 *context, int iret ) { REALMODECALL *p = CTX_SEG_OFF_TO_LIN( context, context->SegEs, context->Edi ); CONTEXT86 context16; TRACE("RealModeCall: EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n", p->eax, p->ebx, p->ecx, p->edx); TRACE(" ESI=%08lx EDI=%08lx ES=%04x DS=%04x CS:IP=%04x:%04x, %d WORD arguments, %s\n", p->esi, p->edi, p->es, p->ds, p->cs, p->ip, CX_reg(context), iret?"IRET":"FAR" ); if (!(p->cs) && !(p->ip)) { /* remove this check if Int21/6501 case map function has been implemented */ SET_CFLAG(context); return; } INT_GetRealModeContext(p, &context16); DPMI_CallRMProc( &context16, ((LPWORD)MapSL(MAKESEGPTR(context->SegSs, LOWORD(context->Esp))))+3, CX_reg(context), iret ); INT_SetRealModeContext(p, &context16); }
DWORD DOSDEV_FindCharDevice(char*name) { SEGPTR cur_ptr = MAKESEGPTR(HIWORD(DOS_LOLSeg), FIELD_OFFSET(DOS_LISTOFLISTS,NUL_dev)); DOS_DEVICE_HEADER *cur = PTR_REAL_TO_LIN(SELECTOROF(cur_ptr),OFFSETOF(cur_ptr)); char dname[8]; int cnt; /* get first 8 characters */ /* if less than 8 characters, pad with spaces */ for (cnt=0; name[cnt] && cnt<8; cnt++) dname[cnt]=name[cnt]; while(cnt<8) dname[cnt++] = ' '; /* search for char devices with the right name */ while (cur && ((!(cur->attr & ATTR_CHAR)) || memcmp(cur->name,dname,8))) { cur_ptr = cur->next_dev; if (cur_ptr == NONEXT) cur=NULL; else cur = PTR_REAL_TO_LIN(SELECTOROF(cur_ptr),OFFSETOF(cur_ptr)); } return cur_ptr; }
/********************************************************************** * INT10_FillControllerInformation * * Fill 256-byte (VBE1.x) or 512-byte buffer (VBE2.0+) with * capabilities of the video controller. */ static void INT10_FillControllerInformation( BYTE *buffer ) { INT10_HEAP *heap = INT10_GetHeap(); /* 00 - BYTE[4]: signature */ memmove( buffer, "VESA", 4 ); /* 04 - WORD: version number */ *(WORD*)(buffer + 4) = 0x0300; /* version 3.0 */ /* 06 - DWORD: pointer to OEM name */ *(SEGPTR*)(buffer + 6) = MAKESEGPTR( heap->WineHeapSegment, offsetof(INT10_HEAP, VesaOEMName) ); /* * 10 - DWORD: capabilities flags * Bits: * 0 - DAC can be switched into 8-bit mode * 1 - non-VGA controller * 2 - programmed DAC with blank bit * 3 - controller supports hardware stereoscopic signalling * 4 - =0 stereo signalling via external VESA stereo connector * =1 stereo signalling via VESA EVC connector * 5 - controller supports hardware mouse cursor * 6 - controller supports hardware clipping * 7 - controller supports transparent BitBLT * 8-31 - reserved (0) */ *(DWORD*)(buffer + 10) = 0; /* FIXME */ /* 14 - DWORD: pointer to list of supported VESA and OEM video modes */ *(SEGPTR*)(buffer + 14) = MAKESEGPTR( heap->WineHeapSegment, offsetof(INT10_HEAP, VesaModeList) ); /* 18 - WORD: total amount of video memory in 64K blocks */ *(WORD*)(buffer + 18) = 16; /* FIXME */ /* 20 - WORD: OEM software version (BCD, high byte = major) */ *(WORD*)(buffer + 20) = 0x0100; /* version 1.0 */ /* 22 - DWORD: pointer to vendor name */ *(SEGPTR*)(buffer + 22) = MAKESEGPTR( heap->WineHeapSegment, offsetof(INT10_HEAP, VesaVendorName) ); /* 26 - DWORD: pointer to product name */ *(SEGPTR*)(buffer + 26) = MAKESEGPTR( heap->WineHeapSegment, offsetof(INT10_HEAP, VesaProductName) ); /* 30 - DWORD: pointer to product revision string */ *(SEGPTR*)(buffer + 30) = MAKESEGPTR( heap->WineHeapSegment, offsetof(INT10_HEAP, VesaProductRev) ); /* 34 - WORD: VBE/AF version (if capabilities bit 3 set) */ *(WORD*)(buffer + 34) = 0; /* * 36 - DWORD: pointer to list of accelerated modes * (if capabilities bit 3 set) */ *(SEGPTR*)(buffer + 36) = 0; /* 40 - BYTE[216]: reserved for VBE implementation, set to zero */ memset( buffer + 40, 0, 216 ); /* * 256 - BYTE[256]: reserved for VBE3.0 implementation, * ignored in order to support older programs */ }
/*********************************************************************** * TASK_Create * * NOTE: This routine might be called by a Win32 thread. Thus, we need * to be careful to protect global data structures. We do this * by entering the Win16Lock while linking the task into the * global task list. */ static TDB *TASK_Create( NE_MODULE *pModule, UINT16 cmdShow, LPCSTR cmdline, BYTE len ) { HTASK16 hTask; TDB *pTask; FARPROC16 proc; char curdir[MAX_PATH]; HMODULE16 hModule = pModule ? pModule->self : 0; /* Allocate the task structure */ hTask = GlobalAlloc16( GMEM_FIXED | GMEM_ZEROINIT, sizeof(TDB) ); if (!hTask) return NULL; pTask = TASK_GetPtr( hTask ); FarSetOwner16( hTask, hModule ); /* Fill the task structure */ pTask->hSelf = hTask; pTask->version = pModule ? pModule->ne_expver : 0x0400; pTask->hModule = hModule; pTask->hParent = GetCurrentTask(); pTask->magic = TDB_MAGIC; pTask->nCmdShow = cmdShow; GetCurrentDirectoryA( sizeof(curdir), curdir ); GetShortPathNameA( curdir, curdir, sizeof(curdir) ); pTask->curdrive = (curdir[0] - 'A') | 0x80; lstrcpynA( pTask->curdir, curdir + 2, sizeof(pTask->curdir) ); /* Create the thunks block */ TASK_CreateThunks( hTask, (char *)pTask->thunks - (char *)pTask, 7 ); /* Copy the module name */ if (hModule) { char name[sizeof(pTask->module_name)+1]; size_t len; GetModuleName16( hModule, name, sizeof(name) ); len = strlen(name) + 1; memcpy(pTask->module_name, name, min(len,sizeof(pTask->module_name))); pTask->compat_flags = GetProfileIntA( "Compatibility", name, 0 ); } /* Allocate a selector for the PDB */ pTask->hPDB = GLOBAL_CreateBlock( GMEM_FIXED, &pTask->pdb, sizeof(PDB16), hModule, WINE_LDT_FLAGS_DATA ); /* Fill the PDB */ pTask->pdb.int20 = 0x20cd; pTask->pdb.dispatcher[0] = 0x9a; /* ljmp */ proc = GetProcAddress16( GetModuleHandle16("KERNEL"), "DOS3Call" ); memcpy( &pTask->pdb.dispatcher[1], &proc, sizeof(proc) ); pTask->pdb.savedint22 = 0; pTask->pdb.savedint23 = 0; pTask->pdb.savedint24 = 0; pTask->pdb.fileHandlesPtr = MAKESEGPTR( GlobalHandleToSel16(pTask->hPDB), FIELD_OFFSET( PDB16, fileHandles )); pTask->pdb.hFileHandles = 0; memset( pTask->pdb.fileHandles, 0xff, sizeof(pTask->pdb.fileHandles) ); /* FIXME: should we make a copy of the environment? */ pTask->pdb.environment = SELECTOROF(GetDOSEnvironment16()); pTask->pdb.nbFiles = 20; /* Fill the command line */ if (!cmdline) { cmdline = GetCommandLineA(); /* remove the first word (program name) */ if (*cmdline == '"') if (!(cmdline = strchr( cmdline+1, '"' ))) cmdline = GetCommandLineA(); while (*cmdline && (*cmdline != ' ') && (*cmdline != '\t')) cmdline++; while ((*cmdline == ' ') || (*cmdline == '\t')) cmdline++; len = strlen(cmdline); } if (len >= sizeof(pTask->pdb.cmdLine)) len = sizeof(pTask->pdb.cmdLine)-1; pTask->pdb.cmdLine[0] = len; memcpy( pTask->pdb.cmdLine + 1, cmdline, len ); /* pTask->pdb.cmdLine[len+1] = 0; */ TRACE("cmdline='%.*s' task=%04x\n", len, cmdline, hTask ); /* Allocate a code segment alias for the TDB */ pTask->hCSAlias = GLOBAL_CreateBlock( GMEM_FIXED, pTask, sizeof(TDB), pTask->hPDB, WINE_LDT_FLAGS_CODE ); /* Default DTA overwrites command line */ pTask->dta = MAKESEGPTR( pTask->hPDB, FIELD_OFFSET( PDB16, cmdLine )); /* Create scheduler event for 16-bit tasks */ if ( !(pTask->flags & TDBF_WIN32) ) NtCreateEvent( &pTask->hEvent, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE ); if (!initial_task) initial_task = hTask; return pTask; }
/*********************************************************************** * NE_FixupSegmentPrologs * * Fixup exported functions prologs of one segment */ static void NE_FixupSegmentPrologs(NE_MODULE *pModule, WORD segnum) { SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule ); ET_BUNDLE *bundle; ET_ENTRY *entry; WORD dgroup, num_entries, sel = SEL(pSegTable[segnum-1].hSeg); BYTE *pSeg, *pFunc; TRACE("(%d);\n", segnum); if (pSegTable[segnum-1].flags & NE_SEGFLAGS_DATA) { pSegTable[segnum-1].flags |= NE_SEGFLAGS_LOADED; return; } if (!pModule->ne_autodata) return; if (!pSegTable[pModule->ne_autodata-1].hSeg) return; dgroup = SEL(pSegTable[pModule->ne_autodata-1].hSeg); pSeg = MapSL( MAKESEGPTR(sel, 0) ); bundle = (ET_BUNDLE *)((BYTE *)pModule+pModule->ne_enttab); do { TRACE("num_entries: %d, bundle: %p, next: %04x, pSeg: %p\n", bundle->last - bundle->first, bundle, bundle->next, pSeg); if (!(num_entries = bundle->last - bundle->first)) return; entry = (ET_ENTRY *)((BYTE *)bundle+6); while (num_entries--) { /*TRACE("entry: %p, entry->segnum: %d, entry->offs: %04x\n", entry, entry->segnum, entry->offs);*/ if (entry->segnum == segnum) { pFunc = pSeg+entry->offs; TRACE("pFunc: %p, *(DWORD *)pFunc: %08x, num_entries: %d\n", pFunc, *(DWORD *)pFunc, num_entries); if (*(pFunc+2) == 0x90) { if (*(WORD *)pFunc == 0x581e) /* push ds, pop ax */ { TRACE("patch %04x:%04x -> mov ax, ds\n", sel, entry->offs); *(WORD *)pFunc = 0xd88c; /* mov ax, ds */ } if (*(WORD *)pFunc == 0xd88c) { if ((entry->flags & 2)) /* public data ? */ { TRACE("patch %04x:%04x -> mov ax, dgroup [%04x]\n", sel, entry->offs, dgroup); *pFunc = 0xb8; /* mov ax, */ *(WORD *)(pFunc+1) = dgroup; } else if ((pModule->ne_flags & NE_FFLAGS_MULTIPLEDATA) && (entry->flags & 1)) /* exported ? */ { TRACE("patch %04x:%04x -> nop, nop\n", sel, entry->offs); *(WORD *)pFunc = 0x9090; /* nop, nop */ } } } } entry++; } } while ( (bundle->next) && (bundle = ((ET_BUNDLE *)((BYTE *)pModule + bundle->next))) ); }
/*********************************************************************** * NE_LoadSegment */ BOOL NE_LoadSegment( NE_MODULE *pModule, WORD segnum ) { WORD count; DWORD pos; const struct relocation_entry_s *rep; int size; SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule ); SEGTABLEENTRY *pSeg = pSegTable + segnum - 1; if (pSeg->flags & NE_SEGFLAGS_LOADED) { /* self-loader ? -> already loaded it */ if (pModule->ne_flags & NE_FFLAGS_SELFLOAD) return TRUE; /* leave, except for DGROUP, as this may be the second instance */ if (segnum != pModule->ne_autodata) return TRUE; } if (!pSeg->filepos) return TRUE; /* No file image, just return */ TRACE_(module)("Loading segment %d, hSeg=%04x, flags=%04x\n", segnum, pSeg->hSeg, pSeg->flags ); pos = pSeg->filepos << pModule->ne_align; if (pSeg->size) size = pSeg->size; else size = pSeg->minsize ? pSeg->minsize : 0x10000; if (pModule->ne_flags & NE_FFLAGS_SELFLOAD && segnum > 1) { /* Implement self-loading segments */ SELFLOADHEADER *selfloadheader; void *oldstack; HFILE16 hFile16; WORD args[3]; DWORD ret; selfloadheader = MapSL( MAKESEGPTR(SEL(pSegTable->hSeg),0) ); oldstack = getWOW32Reserved(); setWOW32Reserved((void *)MAKESEGPTR(pModule->self_loading_sel, 0xff00 - sizeof(STACK16FRAME))); hFile16 = NE_OpenFile( pModule ); TRACE_(dll)("Call LoadAppSegProc(hmodule=0x%04x,hf=%x,segnum=%d)\n", pModule->self,hFile16,segnum ); args[2] = pModule->self; args[1] = hFile16; args[0] = segnum; WOWCallback16Ex( (DWORD)selfloadheader->LoadAppSeg, WCB16_PASCAL, sizeof(args), args, &ret ); pSeg->hSeg = LOWORD(ret); TRACE_(dll)("Ret LoadAppSegProc: hSeg=0x%04x\n", pSeg->hSeg); _lclose16( hFile16 ); setWOW32Reserved(oldstack); pSeg->flags |= NE_SEGFLAGS_LOADED; return TRUE; } else if (!(pSeg->flags & NE_SEGFLAGS_ITERATED)) { void *mem = GlobalLock16(pSeg->hSeg); if (!NE_READ_DATA( pModule, mem, pos, size )) return FALSE; pos += size; } else { /* The following bit of code for "iterated segments" was written without any documentation on the format of these segments. It seems to work, but may be missing something. */ const char *buff = NE_GET_DATA( pModule, pos, size ); const char* curr = buff; char *mem = GlobalLock16(pSeg->hSeg); pos += size; if (buff == NULL) return FALSE; while(curr < buff + size) { unsigned int rept = ((const short *)curr)[0]; unsigned int len = ((const short *)curr)[1]; curr += 2*sizeof(short); while (rept--) { memcpy( mem, curr, len ); mem += len; } curr += len; } } pSeg->flags |= NE_SEGFLAGS_LOADED; /* Perform exported function prolog fixups */ NE_FixupSegmentPrologs( pModule, segnum ); if (!(pSeg->flags & NE_SEGFLAGS_RELOC_DATA)) return TRUE; /* No relocation data, we are done */ if (!NE_READ_DATA( pModule, &count, pos, sizeof(count) ) || !count) return TRUE; pos += sizeof(count); TRACE("Fixups for %.*s, segment %d, hSeg %04x\n", *((BYTE *)pModule + pModule->ne_restab), (char *)pModule + pModule->ne_restab + 1, segnum, pSeg->hSeg ); if (!(rep = NE_GET_DATA( pModule, pos, count * sizeof(struct relocation_entry_s) ))) return FALSE; return apply_relocations( pModule, rep, count, segnum ); }
/*********************************************************************** * apply_relocations * * Apply relocations to a segment. Helper for NE_LoadSegment. */ static inline BOOL apply_relocations( NE_MODULE *pModule, const struct relocation_entry_s *rep, int count, int segnum ) { BYTE *func_name; char buffer[256]; int i, ordinal; WORD offset, *sp; HMODULE16 module; FARPROC16 address = 0; HMODULE16 *pModuleTable = (HMODULE16 *)((char *)pModule + pModule->ne_modtab); SEGTABLEENTRY *pSegTable = NE_SEG_TABLE( pModule ); SEGTABLEENTRY *pSeg = pSegTable + segnum - 1; /* * Go through the relocation table one entry at a time. */ for (i = 0; i < count; i++, rep++) { /* * Get the target address corresponding to this entry. */ /* If additive, there is no target chain list. Instead, add source and target */ int additive = rep->relocation_type & NE_RELFLAG_ADDITIVE; switch (rep->relocation_type & 3) { case NE_RELTYPE_ORDINAL: module = pModuleTable[rep->target1-1]; ordinal = rep->target2; address = NE_GetEntryPoint( module, ordinal ); if (!address) { NE_MODULE *pTarget = NE_GetPtr( module ); if (!pTarget) WARN_(module)("Module not found: %04x, reference %d of module %*.*s\n", module, rep->target1, *((BYTE *)pModule + pModule->ne_restab), *((BYTE *)pModule + pModule->ne_restab), (char *)pModule + pModule->ne_restab + 1 ); else { ERR("No implementation for %.*s.%d, setting to 0xdeadbeef\n", *((BYTE *)pTarget + pTarget->ne_restab), (char *)pTarget + pTarget->ne_restab + 1, ordinal ); address = (FARPROC16)0xdeadbeef; } } if (TRACE_ON(fixup)) { NE_MODULE *pTarget = NE_GetPtr( module ); TRACE("%d: %.*s.%d=%04x:%04x %s\n", i + 1, *((BYTE *)pTarget + pTarget->ne_restab), (char *)pTarget + pTarget->ne_restab + 1, ordinal, HIWORD(address), LOWORD(address), NE_GetRelocAddrName( rep->address_type, additive ) ); } break; case NE_RELTYPE_NAME: module = pModuleTable[rep->target1-1]; func_name = (BYTE *)pModule + pModule->ne_imptab + rep->target2; memcpy( buffer, func_name+1, *func_name ); buffer[*func_name] = '\0'; ordinal = NE_GetOrdinal( module, buffer ); address = NE_GetEntryPoint( module, ordinal ); if (ERR_ON(fixup) && !address) { NE_MODULE *pTarget = NE_GetPtr( module ); ERR("No implementation for %.*s.%s, setting to 0xdeadbeef\n", *((BYTE *)pTarget + pTarget->ne_restab), (char *)pTarget + pTarget->ne_restab + 1, buffer ); } if (!address) address = (FARPROC16) 0xdeadbeef; if (TRACE_ON(fixup)) { NE_MODULE *pTarget = NE_GetPtr( module ); TRACE("%d: %.*s.%s=%04x:%04x %s\n", i + 1, *((BYTE *)pTarget + pTarget->ne_restab), (char *)pTarget + pTarget->ne_restab + 1, buffer, HIWORD(address), LOWORD(address), NE_GetRelocAddrName( rep->address_type, additive ) ); } break; case NE_RELTYPE_INTERNAL: if ((rep->target1 & 0xff) == 0xff) { address = NE_GetEntryPoint( pModule->self, rep->target2 ); } else { address = (FARPROC16)MAKESEGPTR( SEL(pSegTable[rep->target1-1].hSeg), rep->target2 ); } TRACE("%d: %04x:%04x %s\n", i + 1, HIWORD(address), LOWORD(address), NE_GetRelocAddrName( rep->address_type, additive ) ); break; case NE_RELTYPE_OSFIXUP: /* Relocation type 7: * * These appear to be used as fixups for the Windows * floating point emulator. Let's just ignore them and * try to use the hardware floating point. Linux should * successfully emulate the coprocessor if it doesn't * exist. */ TRACE("%d: TYPE %d, OFFSET %04x, TARGET %04x %04x %s\n", i + 1, rep->relocation_type, rep->offset, rep->target1, rep->target2, NE_GetRelocAddrName( rep->address_type, additive ) ); continue; } offset = rep->offset; /* Apparently, high bit of address_type is sometimes set; */ /* we ignore it for now */ if (rep->address_type > NE_RADDR_OFFSET32) { char module[10]; GetModuleName16( pModule->self, module, sizeof(module) ); ERR("WARNING: module %s: unknown reloc addr type = 0x%02x. Please report.\n", module, rep->address_type ); } if (additive) { sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) ); TRACE(" %04x:%04x\n", offset, *sp ); switch (rep->address_type & 0x7f) { case NE_RADDR_LOWBYTE: *(BYTE *)sp += LOBYTE((int)address); break; case NE_RADDR_OFFSET16: *sp += LOWORD(address); break; case NE_RADDR_POINTER32: *sp += LOWORD(address); *(sp+1) = HIWORD(address); break; case NE_RADDR_SELECTOR: /* Borland creates additive records with offset zero. Strange, but OK */ if (*sp) ERR("Additive selector to %04x.Please report\n",*sp); else *sp = HIWORD(address); break; default: goto unknown; } } else /* non-additive fixup */ { do { WORD next_offset; sp = MapSL( MAKESEGPTR( SEL(pSeg->hSeg), offset ) ); next_offset = *sp; TRACE(" %04x:%04x\n", offset, *sp ); switch (rep->address_type & 0x7f) { case NE_RADDR_LOWBYTE: *(BYTE *)sp = LOBYTE((int)address); break; case NE_RADDR_OFFSET16: *sp = LOWORD(address); break; case NE_RADDR_POINTER32: *(FARPROC16 *)sp = address; break; case NE_RADDR_SELECTOR: *sp = SELECTOROF(address); break; default: goto unknown; } if (next_offset == offset) break; /* avoid infinite loop */ if (next_offset >= GlobalSize16(pSeg->hSeg)) break; offset = next_offset; } while (offset != 0xffff); } } return TRUE; unknown: WARN("WARNING: %d: unknown ADDR TYPE %d, " "TYPE %d, OFFSET %04x, TARGET %04x %04x\n", i + 1, rep->address_type, rep->relocation_type, rep->offset, rep->target1, rep->target2); return FALSE; }
/********************************************************************** * INT10_FillStateInformation * * Fill 64-byte buffer with VGA state and functionality information. */ static void INT10_FillStateInformation( BYTE *buffer, BIOSDATA *data ) { INT10_HEAP *heap = INT10_GetHeap(); /* 00 - DWORD: address of static functionality table */ *(SEGPTR*)(buffer + 0) = MAKESEGPTR( heap->WineHeapSegment, offsetof(INT10_HEAP, StaticModeSupport) ); /* 04 - BYTE[30]: copy of BIOS data starting from 0x49 (VideoMode) */ memmove( buffer + 4, &data->VideoMode, 30 ); /* 34 - BYTE: number of rows - 1 */ buffer[34] = data->RowsOnScreenMinus1; /* 35 - WORD: bytes/character */ *(WORD*)(buffer + 35) = data->BytesPerChar; /* 37 - BYTE: display combination code of active display */ buffer[37] = INT10_DCC; /* 38 - BYTE: DCC of alternate display */ buffer[38] = 0; /* no secondary display */ /* 39 - WORD: number of colors supported in current mode (0000h = mono) */ *(WORD*)(buffer + 39) = 16; /* FIXME */ /* 41 - BYTE: number of pages supported in current mode */ buffer[41] = 1; /* FIXME */ /* * 42 - BYTE: number of scan lines active * Values (hex): * 00 = 200 * 01 = 350 * 02 = 400 * 03 = 480 */ buffer[42] = 3; /* FIXME */ /* 43 - BYTE: primary character block */ buffer[43] = 0; /* FIXME */ /* 44 - BYTE: secondary character block */ buffer[44] = 0; /* FIXME */ /* * 45 - BYTE: miscellaneous flags * Bits: * 0 - all modes on all displays on * 1 - gray summing on * 2 - monochrome display attached * 3 - default palette loading disabled * 4 - cursor emulation enabled * 5 - 0 = intensity; 1 = blinking * 6 - flat-panel display is active * 7 - unused (0) */ /* FIXME: Correct value? */ buffer[45] = (data->VGASettings & 0x0f) | ((data->ModeOptions & 1) << 4); /* cursor emulation */ /* * 46 - BYTE: non-VGA mode support * Bits: * 0 - BIOS supports information return for adapter interface * 1 - adapter interface driver required * 2 - 16-bit VGA graphics present * 3 - =1 MFI attributes enabled * =0 VGA attributes enabled * 4 - 132-column mode supported * 5-7 - reserved */ buffer[46] = 0; /* FIXME: correct value? */ /* 47 - BYTE[2]: reserved, set to zero */ memset( buffer + 47, 0, 2 ); /* * 49 - BYTE: video memory available * Values (hex): * 00 - 64K * 01 - 128K * 02 - 192K * 03 - 256K */ buffer[49] = (data->ModeOptions & 0x60) >> 5; /* FIXME */ /* * 50 - BYTE: save pointer state flags * Bits: * 0 - 512 character set active * 1 - dynamic save area present * 2 - alpha font override active * 3 - graphics font override active * 4 - palette override active * 5 - DCC override active * 6-7 - unused (0) */ buffer[50] = heap->StaticSavePointerFlags; /* * 51 - BYTE: display information and status * Bits: * 0 - flat-panel display attached * 1 - flat-panel display active * 2 - color display * 3-6 - reserved * 7 - 640x480 flat-panel can be used simultaneously with CRT */ buffer[51] = 4; /* FIXME: correct value? */ /* 52 - BYTE[12]: reserved, set to zero */ memset( buffer + 52, 0, 12 ); }