From: Alex Henrie alexhenrie24@gmail.com
This partially reverts commit ed6bdb3c51cd4b8c94f9839806321703e7aa9765 and commit 526b245237b9571beebac8a4653e7dd74c62c7de.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=56225 --- dlls/krnl386.exe16/dosexe.h | 9 +++- dlls/krnl386.exe16/int31.c | 80 ++++++++++++++++++++++++++++++++- dlls/krnl386.exe16/interrupts.c | 2 +- 3 files changed, 88 insertions(+), 3 deletions(-)
diff --git a/dlls/krnl386.exe16/dosexe.h b/dlls/krnl386.exe16/dosexe.h index f2064c2b758..89fac53db72 100644 --- a/dlls/krnl386.exe16/dosexe.h +++ b/dlls/krnl386.exe16/dosexe.h @@ -41,8 +41,12 @@ typedef void (WINAPI *INTPROC)(CONTEXT*); extern WORD DOSVM_psp; /* psp of current DOS task */ extern WORD int16_sel;
+#define V86_FLAG 0x00020000 + #define ADD_LOWORD(dw,val) ((dw) = ((dw) & 0xffff0000) | LOWORD((DWORD)(dw)+(val)))
+#define PTR_REAL_TO_LIN(seg,off) ((void*)(((unsigned int)(seg) << 4) + LOWORD(off))) + /* 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 @@ -62,7 +66,8 @@ extern WORD int16_sel; * 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) (ldt_get_ptr((seg),(off))) +#define CTX_SEG_OFF_TO_LIN(context,seg,off) \ + (ISV86(context) ? PTR_REAL_TO_LIN((seg),(off)) : ldt_get_ptr((seg),(off)))
#define INT_BARF(context,num) \ ERR( "int%x: unknown/not implemented parameters:\n" \ @@ -99,6 +104,7 @@ extern WORD int16_sel; #define RESET_CFLAG(context) ((context)->EFlags &= ~0x0001) #define SET_ZFLAG(context) ((context)->EFlags |= 0x0040) #define RESET_ZFLAG(context) ((context)->EFlags &= ~0x0040) +#define ISV86(context) ((context)->EFlags & 0x00020000)
#define SET_AX(context,val) ((void)((context)->Eax = ((context)->Eax & ~0xffff) | (WORD)(val))) #define SET_BX(context,val) ((void)((context)->Ebx = ((context)->Ebx & ~0xffff) | (WORD)(val))) @@ -236,6 +242,7 @@ extern void WINAPI DOSVM_Int31Handler(CONTEXT*);
/* interrupts.c */ extern void WINAPI __wine_call_int_handler16( BYTE, CONTEXT * ); +extern void DOSVM_CallBuiltinHandler( CONTEXT *, BYTE ); extern BOOL DOSVM_EmulateInterruptPM( CONTEXT *, BYTE ); extern FARPROC16 DOSVM_GetPMHandler16( BYTE ); extern void DOSVM_SetPMHandler16( BYTE, FARPROC16 ); diff --git a/dlls/krnl386.exe16/int31.c b/dlls/krnl386.exe16/int31.c index b5af832f4f2..841f73368ea 100644 --- a/dlls/krnl386.exe16/int31.c +++ b/dlls/krnl386.exe16/int31.c @@ -35,6 +35,74 @@ WINE_DEFAULT_DEBUG_CHANNEL(int31);
static void* lastvalloced = NULL;
+/* Structure for real-mode callbacks */ +typedef struct +{ + DWORD edi; + DWORD esi; + DWORD ebp; + DWORD reserved; + DWORD ebx; + DWORD edx; + DWORD ecx; + DWORD eax; + WORD fl; + WORD es; + WORD ds; + WORD fs; + WORD gs; + WORD ip; + WORD cs; + WORD sp; + WORD ss; +} REALMODECALL; + +/********************************************************************** + * INT_GetRealModeContext + */ +static void INT_GetRealModeContext( REALMODECALL *call, CONTEXT *context ) +{ + context->Eax = call->eax; + context->Ebx = call->ebx; + context->Ecx = call->ecx; + context->Edx = call->edx; + context->Esi = call->esi; + context->Edi = call->edi; + context->Ebp = call->ebp; + context->EFlags = call->fl | V86_FLAG; + context->Eip = call->ip; + context->Esp = call->sp; + context->SegCs = call->cs; + context->SegDs = call->ds; + context->SegEs = call->es; + context->SegFs = call->fs; + context->SegGs = call->gs; + context->SegSs = call->ss; +} + +/********************************************************************** + * INT_SetRealModeContext + */ +static void INT_SetRealModeContext( REALMODECALL *call, CONTEXT *context ) +{ + call->eax = context->Eax; + call->ebx = context->Ebx; + call->ecx = context->Ecx; + call->edx = context->Edx; + call->esi = context->Esi; + call->edi = context->Edi; + call->ebp = context->Ebp; + call->fl = LOWORD(context->EFlags); + call->ip = LOWORD(context->Eip); + call->sp = LOWORD(context->Esp); + call->cs = context->SegCs; + call->ds = context->SegDs; + call->es = context->SegEs; + call->fs = context->SegFs; + call->gs = context->SegGs; + call->ss = context->SegSs; +} + /********************************************************************** * DPMI_xalloc * special virtualalloc, allocates linearly monoton growing memory. @@ -395,7 +463,17 @@ void WINAPI DOSVM_Int31Handler( CONTEXT *context ) break;
case 0x0300: /* Simulate real mode interrupt */ - TRACE( "Simulate real mode interrupt %02x - not supported\n", BL_reg(context)); + TRACE( "Simulate real mode interrupt %02x\n", BL_reg(context) ); + { + CONTEXT realmode_ctx; + REALMODECALL *call = CTX_SEG_OFF_TO_LIN( context, + context->SegEs, + context->Edi ); + INT_GetRealModeContext( call, &realmode_ctx ); + RESET_CFLAG( context ); + DOSVM_CallBuiltinHandler( &realmode_ctx, BL_reg(context) ); + INT_SetRealModeContext( call, &realmode_ctx ); + } break;
case 0x0301: /* Call real mode procedure with far return */ diff --git a/dlls/krnl386.exe16/interrupts.c b/dlls/krnl386.exe16/interrupts.c index 5087d1b7a03..02faf419480 100644 --- a/dlls/krnl386.exe16/interrupts.c +++ b/dlls/krnl386.exe16/interrupts.c @@ -383,7 +383,7 @@ void DOSVM_SetPMHandler16( BYTE intnum, FARPROC16 handler ) * * Execute Wine interrupt handler procedure. */ -static void DOSVM_CallBuiltinHandler( CONTEXT *context, BYTE intnum ) +void DOSVM_CallBuiltinHandler( CONTEXT *context, BYTE intnum ) { /* * FIXME: Make all builtin interrupt calls go via this routine.