diff --git a/dlls/winedos/Makefile.in b/dlls/winedos/Makefile.in index 873af5d1fca..a61a50948c2 100644 --- a/dlls/winedos/Makefile.in +++ b/dlls/winedos/Makefile.in @@ -25,6 +25,7 @@ C_SRCS = \ int31.c \ int33.c \ int67.c \ + interrupts.c \ ioports.c \ module.c \ soundblaster.c \ diff --git a/dlls/winedos/dosexe.h b/dlls/winedos/dosexe.h index be2ec5b4ca3..2a21d15fe1b 100644 --- a/dlls/winedos/dosexe.h +++ b/dlls/winedos/dosexe.h @@ -115,6 +115,7 @@ extern void WINAPI DOSVM_Int29Handler(CONTEXT86*); /* int31.c */ extern void WINAPI DOSVM_Int31Handler(CONTEXT86*); +extern BOOL WINAPI DOSVM_IsDos32(); /* int33.c */ extern void WINAPI DOSVM_Int33Handler(CONTEXT86*); diff --git a/dlls/winedos/dosvm.c b/dlls/winedos/dosvm.c index fc7ac71228f..a81ec9d9b7f 100644 --- a/dlls/winedos/dosvm.c +++ b/dlls/winedos/dosvm.c @@ -696,10 +696,6 @@ BOOL WINAPI DOSVM_Init( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved if (fdwReason == DLL_PROCESS_ATTACH) { - /* initialize the memory */ - TRACE("Initializing DOS memory structures\n"); - DOSMEM_Init( TRUE ); - DOSDEV_InstallDOSDevices(); DOSVM_dpmi_segments = DOSMEM_GetDPMISegments(); #ifdef MZ_SUPPORTED diff --git a/dlls/winedos/int31.c b/dlls/winedos/int31.c index e8903b6d74e..5ba3da791b7 100644 --- a/dlls/winedos/int31.c +++ b/dlls/winedos/int31.c @@ -64,6 +64,17 @@ typedef struct tagRMCB { static RMCB *FirstRMCB = NULL; static WORD dpmi_flag; +/********************************************************************** + * DOSVM_IsDos32 + * + * Return TRUE if we are in 32-bit protected mode DOS process. + */ +BOOL DOSVM_IsDos32() +{ + return (dpmi_flag & 1) ? TRUE : FALSE; +} + + /********************************************************************** * INT_GetRealModeContext */ diff --git a/dlls/winedos/interrupts.c b/dlls/winedos/interrupts.c new file mode 100644 index 00000000000..f5d254fe2dc --- /dev/null +++ b/dlls/winedos/interrupts.c @@ -0,0 +1,84 @@ +/* + * Interrupt emulation + * + * Copyright 2002 Jukka Heinonen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "dosexe.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(int); + +/********************************************************************** + * DOSVM_EmulateInterruptPM + * + * Emulate software interrupt in 16-bit or 32-bit protected mode. + * Called from signal handler when intXX opcode is executed. + * + * Pushes interrupt frame to stack and changes instruction + * pointer to interrupt handler. + */ +void WINAPI DOSVM_EmulateInterruptPM( CONTEXT86 *context, BYTE intnum ) +{ + BOOL islong; + + if(context->SegCs == DOSVM_dpmi_segments->int48_sel) + islong = FALSE; + else if(DOSVM_IsDos32()) + islong = TRUE; + else if(IS_SELECTOR_32BIT(context->SegCs)) { + WARN("Interrupt in 32-bit code and mode is not DPMI32\n"); + islong = TRUE; + } else + islong = FALSE; + + /* FIXME: Remove this check when DPMI32 support has been added */ + if(islong) { + ERR("Interrupts not supported in 32-bit DPMI\n"); + islong = FALSE; + } + + if(islong) + { + FARPROC48 addr = {0,0}; /* FIXME: INT_GetPMHandler48( intnum ); */ + DWORD *stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp); + /* Push the flags and return address on the stack */ + *(--stack) = context->EFlags; + *(--stack) = context->SegCs; + *(--stack) = context->Eip; + /* Jump to the interrupt handler */ + context->SegCs = addr.selector; + context->Eip = addr.offset; + } + else + { + FARPROC16 addr = INT_GetPMHandler( intnum ); + WORD *stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp); + /* Push the flags and return address on the stack */ + *(--stack) = LOWORD(context->EFlags); + *(--stack) = context->SegCs; + *(--stack) = LOWORD(context->Eip); + /* Jump to the interrupt handler */ + context->SegCs = HIWORD(addr); + context->Eip = LOWORD(addr); + } + + if (IS_SELECTOR_32BIT(context->SegSs)) + context->Esp += islong ? -12 : -6; + else + ADD_LOWORD( context->Esp, islong ? -12 : -6 ); +} diff --git a/dlls/winedos/module.c b/dlls/winedos/module.c index 9ecafb880fc..27e4ade296d 100644 --- a/dlls/winedos/module.c +++ b/dlls/winedos/module.c @@ -198,6 +198,7 @@ static BOOL MZ_InitMemory(void) /* initialize the memory */ TRACE("Initializing DOS memory structures\n"); DOSMEM_Init(TRUE); + DOSDEV_InstallDOSDevices(); MZ_InitHandlers(); return TRUE; diff --git a/dlls/winedos/winedos.spec b/dlls/winedos/winedos.spec index d2457971789..a08ad6092bd 100644 --- a/dlls/winedos/winedos.spec +++ b/dlls/winedos/winedos.spec @@ -1,6 +1,7 @@ init DOSVM_Init @ stdcall LoadDosExe(str long) MZ_LoadImage +@ stdcall EmulateInterruptPM(ptr long) DOSVM_EmulateInterruptPM # DPMI functions @ stdcall CallRMInt(ptr) DOSVM_CallRMInt diff --git a/include/callback.h b/include/callback.h index ddf73daaf2b..18a49d0f911 100644 --- a/include/callback.h +++ b/include/callback.h @@ -26,6 +26,7 @@ typedef struct { void (WINAPI *LoadDosExe)( LPCSTR filename, HANDLE hFile ); + void (WINAPI *EmulateInterruptPM)( CONTEXT86 *context, BYTE intnum ); /* DPMI functions */ void (WINAPI *CallRMInt)( CONTEXT86 *context ); diff --git a/include/miscemu.h b/include/miscemu.h index 31464f8bb90..fd0302dcea6 100644 --- a/include/miscemu.h +++ b/include/miscemu.h @@ -270,8 +270,9 @@ extern char IO_pp_init(void); #define PTR_REAL_TO_LIN(seg,off) \ ((void*)(((unsigned int)(seg) << 4) + LOWORD(off))) -/* NOTE: Interrupts might get called from three modes: real mode, 16-bit, and - * (via DeviceIoControl) 32-bit. For automatic conversion of pointer +/* NOTE: Interrupts might get called from four modes: real mode, 16-bit, + * 32-bit segmented (DPMI32) and 32-bit linear (via DeviceIoControl). + * For automatic conversion of pointer * parameters, interrupt handlers should use CTX_SEG_OFF_TO_LIN with * the contents of a segment register as second and the contents of * a *32-bit* general register as third parameter, e.g. @@ -279,15 +280,21 @@ extern char IO_pp_init(void); * This will generate a linear pointer in all three cases: * Real-Mode: Seg*16 + LOWORD(Offset) * 16-bit: convert (Seg, LOWORD(Offset)) to linear - * 32-bit: use Offset as linear address (DeviceIoControl!) + * 32-bit segmented: convert (Seg, Offset) to linear + * 32-bit linear: use Offset as linear address (DeviceIoControl!) * * Real-mode is recognized by checking the V86 bit in the flags register, - * 32-bit mode is recognized by checking whether 'seg' is a system selector - * (0 counts also as 32-bit segment). + * 32-bit linear mode is recognized by checking whether 'seg' is + * a system selector (0 counts also as 32-bit segment) and 32-bit + * segmented mode is recognized by checking whether 'seg' is 32-bit + * selector which is neither system selector nor zero. */ #define CTX_SEG_OFF_TO_LIN(context,seg,off) \ (ISV86(context) ? PTR_REAL_TO_LIN((seg),(off)) : \ - (!seg || IS_SELECTOR_SYSTEM(seg))? (void *)(ULONG_PTR)(off) : MapSL(MAKESEGPTR((seg),(off)))) + (!seg || IS_SELECTOR_SYSTEM(seg))? (void *)(ULONG_PTR)(off) : \ + (IS_SELECTOR_32BIT(seg) ? \ + (void *)((off) + (char*)MapSL(MAKESEGPTR((seg),0))) : \ + MapSL(MAKESEGPTR((seg),(off))))) #define INT_BARF(context,num) \ ERR( "int%x: unknown/not implemented parameters:\n" \ diff --git a/memory/instr.c b/memory/instr.c index dc1c45986cc..d2c93e9447e 100644 --- a/memory/instr.c +++ b/memory/instr.c @@ -25,6 +25,7 @@ #include "miscemu.h" #include "selectors.h" #include "wine/debug.h" +#include "callback.h" WINE_DEFAULT_DEBUG_CHANNEL(int); WINE_DECLARE_DEBUG_CHANNEL(io); @@ -684,34 +685,14 @@ BOOL INSTR_EmulateInstruction( CONTEXT86 *context ) break; /* Unable to emulate it */ case 0xcd: /* int */ - if (long_op) - { - FARPROC48 addr = INT_GetPMHandler48( instr[1] ); - DWORD *stack = get_stack( context ); - /* Push the flags and return address on the stack */ - *(--stack) = context->EFlags; - *(--stack) = context->SegCs; - *(--stack) = context->Eip + prefixlen + 2; - add_stack(context, -3 * sizeof(DWORD)); - /* Jump to the interrupt handler */ - context->SegCs = addr.selector; - context->Eip = addr.offset; + if(!Dosvm.EmulateInterruptPM && !DPMI_LoadDosSystem()) + ERR("could not initialize interrupt handling\n"); + else { + context->Eip += prefixlen + 2; + Dosvm.EmulateInterruptPM( context, instr[1] ); return TRUE; - } - else - { - FARPROC16 addr = INT_GetPMHandler( instr[1] ); - WORD *stack = get_stack( context ); - /* Push the flags and return address on the stack */ - *(--stack) = LOWORD(context->EFlags); - *(--stack) = context->SegCs; - *(--stack) = LOWORD(context->Eip) + prefixlen + 2; - add_stack(context, -3 * sizeof(WORD)); - /* Jump to the interrupt handler */ - context->SegCs = HIWORD(addr); - context->Eip = LOWORD(addr); - } - return TRUE; + } + break; /* Unable to emulate it */ case 0xcf: /* iret */ if (long_op) diff --git a/msdos/dpmi.c b/msdos/dpmi.c index 08e7748a1d5..27982547074 100644 --- a/msdos/dpmi.c +++ b/msdos/dpmi.c @@ -74,6 +74,7 @@ BOOL DPMI_LoadDosSystem(void) GET_ADDR(inport); GET_ADDR(outport); GET_ADDR(ASPIHandler); + GET_ADDR(EmulateInterruptPM); #undef GET_ADDR return TRUE; }