Move interrupt emulation code from INSTR_EmulateInstruction to winedos

dll. Make CTX_SEG_OFF_TO_LIN work with 32-bit segmented pointers
common in DPMI32. Fix winedos initialization so that DOSMEM_Init(TRUE)
is only called when DOS executable is started.
This commit is contained in:
Jukka Heinonen 2002-10-23 22:24:10 +00:00 committed by Alexandre Julliard
parent 5a1ede3345
commit eca6182749
11 changed files with 122 additions and 37 deletions

View File

@ -25,6 +25,7 @@ C_SRCS = \
int31.c \ int31.c \
int33.c \ int33.c \
int67.c \ int67.c \
interrupts.c \
ioports.c \ ioports.c \
module.c \ module.c \
soundblaster.c \ soundblaster.c \

View File

@ -115,6 +115,7 @@ extern void WINAPI DOSVM_Int29Handler(CONTEXT86*);
/* int31.c */ /* int31.c */
extern void WINAPI DOSVM_Int31Handler(CONTEXT86*); extern void WINAPI DOSVM_Int31Handler(CONTEXT86*);
extern BOOL WINAPI DOSVM_IsDos32();
/* int33.c */ /* int33.c */
extern void WINAPI DOSVM_Int33Handler(CONTEXT86*); extern void WINAPI DOSVM_Int33Handler(CONTEXT86*);

View File

@ -696,10 +696,6 @@ BOOL WINAPI DOSVM_Init( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved
if (fdwReason == DLL_PROCESS_ATTACH) if (fdwReason == DLL_PROCESS_ATTACH)
{ {
/* initialize the memory */
TRACE("Initializing DOS memory structures\n");
DOSMEM_Init( TRUE );
DOSDEV_InstallDOSDevices();
DOSVM_dpmi_segments = DOSMEM_GetDPMISegments(); DOSVM_dpmi_segments = DOSMEM_GetDPMISegments();
#ifdef MZ_SUPPORTED #ifdef MZ_SUPPORTED

View File

@ -64,6 +64,17 @@ typedef struct tagRMCB {
static RMCB *FirstRMCB = NULL; static RMCB *FirstRMCB = NULL;
static WORD dpmi_flag; 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 * INT_GetRealModeContext
*/ */

84
dlls/winedos/interrupts.c Normal file
View File

@ -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 );
}

View File

@ -198,6 +198,7 @@ static BOOL MZ_InitMemory(void)
/* initialize the memory */ /* initialize the memory */
TRACE("Initializing DOS memory structures\n"); TRACE("Initializing DOS memory structures\n");
DOSMEM_Init(TRUE); DOSMEM_Init(TRUE);
DOSDEV_InstallDOSDevices();
MZ_InitHandlers(); MZ_InitHandlers();
return TRUE; return TRUE;

View File

@ -1,6 +1,7 @@
init DOSVM_Init init DOSVM_Init
@ stdcall LoadDosExe(str long) MZ_LoadImage @ stdcall LoadDosExe(str long) MZ_LoadImage
@ stdcall EmulateInterruptPM(ptr long) DOSVM_EmulateInterruptPM
# DPMI functions # DPMI functions
@ stdcall CallRMInt(ptr) DOSVM_CallRMInt @ stdcall CallRMInt(ptr) DOSVM_CallRMInt

View File

@ -26,6 +26,7 @@
typedef struct { typedef struct {
void (WINAPI *LoadDosExe)( LPCSTR filename, HANDLE hFile ); void (WINAPI *LoadDosExe)( LPCSTR filename, HANDLE hFile );
void (WINAPI *EmulateInterruptPM)( CONTEXT86 *context, BYTE intnum );
/* DPMI functions */ /* DPMI functions */
void (WINAPI *CallRMInt)( CONTEXT86 *context ); void (WINAPI *CallRMInt)( CONTEXT86 *context );

View File

@ -270,8 +270,9 @@ extern char IO_pp_init(void);
#define PTR_REAL_TO_LIN(seg,off) \ #define PTR_REAL_TO_LIN(seg,off) \
((void*)(((unsigned int)(seg) << 4) + LOWORD(off))) ((void*)(((unsigned int)(seg) << 4) + LOWORD(off)))
/* NOTE: Interrupts might get called from three modes: real mode, 16-bit, and /* NOTE: Interrupts might get called from four modes: real mode, 16-bit,
* (via DeviceIoControl) 32-bit. For automatic conversion of pointer * 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 * parameters, interrupt handlers should use CTX_SEG_OFF_TO_LIN with
* the contents of a segment register as second and the contents of * the contents of a segment register as second and the contents of
* a *32-bit* general register as third parameter, e.g. * 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: * This will generate a linear pointer in all three cases:
* Real-Mode: Seg*16 + LOWORD(Offset) * Real-Mode: Seg*16 + LOWORD(Offset)
* 16-bit: convert (Seg, LOWORD(Offset)) to linear * 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, * 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 * 32-bit linear mode is recognized by checking whether 'seg' is
* (0 counts also as 32-bit segment). * 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) \ #define CTX_SEG_OFF_TO_LIN(context,seg,off) \
(ISV86(context) ? PTR_REAL_TO_LIN((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) \ #define INT_BARF(context,num) \
ERR( "int%x: unknown/not implemented parameters:\n" \ ERR( "int%x: unknown/not implemented parameters:\n" \

View File

@ -25,6 +25,7 @@
#include "miscemu.h" #include "miscemu.h"
#include "selectors.h" #include "selectors.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "callback.h"
WINE_DEFAULT_DEBUG_CHANNEL(int); WINE_DEFAULT_DEBUG_CHANNEL(int);
WINE_DECLARE_DEBUG_CHANNEL(io); WINE_DECLARE_DEBUG_CHANNEL(io);
@ -684,34 +685,14 @@ BOOL INSTR_EmulateInstruction( CONTEXT86 *context )
break; /* Unable to emulate it */ break; /* Unable to emulate it */
case 0xcd: /* int <XX> */ case 0xcd: /* int <XX> */
if (long_op) if(!Dosvm.EmulateInterruptPM && !DPMI_LoadDosSystem())
{ ERR("could not initialize interrupt handling\n");
FARPROC48 addr = INT_GetPMHandler48( instr[1] ); else {
DWORD *stack = get_stack( context ); context->Eip += prefixlen + 2;
/* Push the flags and return address on the stack */ Dosvm.EmulateInterruptPM( context, instr[1] );
*(--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;
return TRUE; return TRUE;
} }
else break; /* Unable to emulate it */
{
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;
case 0xcf: /* iret */ case 0xcf: /* iret */
if (long_op) if (long_op)

View File

@ -74,6 +74,7 @@ BOOL DPMI_LoadDosSystem(void)
GET_ADDR(inport); GET_ADDR(inport);
GET_ADDR(outport); GET_ADDR(outport);
GET_ADDR(ASPIHandler); GET_ADDR(ASPIHandler);
GET_ADDR(EmulateInterruptPM);
#undef GET_ADDR #undef GET_ADDR
return TRUE; return TRUE;
} }