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:
parent
5a1ede3345
commit
eca6182749
|
@ -25,6 +25,7 @@ C_SRCS = \
|
|||
int31.c \
|
||||
int33.c \
|
||||
int67.c \
|
||||
interrupts.c \
|
||||
ioports.c \
|
||||
module.c \
|
||||
soundblaster.c \
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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 );
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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" \
|
||||
|
|
|
@ -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 <XX> */
|
||||
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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue