From d25e0399ba2ab8b276780dc86505049e3fda6833 Mon Sep 17 00:00:00 2001 From: Jukka Heinonen Date: Tue, 8 Oct 2002 00:35:03 +0000 Subject: [PATCH] Add support for interrupts in 32-bit code. Remove some unnecessary code from 16-bit interrupt emulation. --- include/miscemu.h | 10 ++++++++++ memory/instr.c | 19 +++++++++++-------- msdos/dosmem.c | 15 +++++++++++++++ msdos/interrupts.c | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 8 deletions(-) diff --git a/include/miscemu.h b/include/miscemu.h index 8c8367e4f29..31464f8bb90 100644 --- a/include/miscemu.h +++ b/include/miscemu.h @@ -171,8 +171,16 @@ struct DPMI_segments WORD xms_seg; WORD dpmi_seg; WORD dpmi_sel; + WORD int48_seg; + WORD int48_sel; }; +/* 48-bit segmented pointers for DOS DPMI32 */ +typedef struct { + WORD selector; + DWORD offset; +} SEGPTR48, FARPROC48; + extern struct DPMI_segments DOSMEM_dpmi_segments; extern const struct DPMI_segments *DOSMEM_GetDPMISegments(void); @@ -194,6 +202,8 @@ extern BOOL INSTR_EmulateInstruction( CONTEXT86 *context ); typedef void (WINAPI *INTPROC)(CONTEXT86*); extern FARPROC16 INT_GetPMHandler( BYTE intnum ); extern void INT_SetPMHandler( BYTE intnum, FARPROC16 handler ); +extern FARPROC48 INT_GetPMHandler48( BYTE intnum ); +extern void INT_SetPMHandler48( BYTE intnum, FARPROC48 handler ); /* msdos/ioports.c */ extern DWORD IO_inport( int port, int count ); diff --git a/memory/instr.c b/memory/instr.c index f1a30d24fbb..dc1c45986cc 100644 --- a/memory/instr.c +++ b/memory/instr.c @@ -686,19 +686,22 @@ BOOL INSTR_EmulateInstruction( CONTEXT86 *context ) case 0xcd: /* int */ if (long_op) { - ERR("int xx from 32-bit code is not supported.\n"); - break; /* Unable to emulate it */ + 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; + return TRUE; } else { FARPROC16 addr = INT_GetPMHandler( instr[1] ); WORD *stack = get_stack( context ); - if (!addr) - { - FIXME("no handler for interrupt %02x, ignoring it\n", instr[1]); - context->Eip += prefixlen + 2; - return TRUE; - } /* Push the flags and return address on the stack */ *(--stack) = LOWORD(context->EFlags); *(--stack) = context->SegCs; diff --git a/msdos/dosmem.c b/msdos/dosmem.c index 8b361fcfae8..c4685c4812b 100644 --- a/msdos/dosmem.c +++ b/msdos/dosmem.c @@ -161,6 +161,7 @@ static void DOSMEM_MakeIsrStubs(void) static void DOSMEM_InitDPMI(void) { LPSTR ptr; + int i; static const char wrap_code[]={ 0xCD,0x31, /* int $0x31 */ @@ -210,6 +211,20 @@ static void DOSMEM_InitDPMI(void) ptr = DOSMEM_GetBlock( sizeof(enter_pm), &DOSMEM_dpmi_segments.dpmi_seg ); memcpy( ptr, enter_pm, sizeof(enter_pm) ); DOSMEM_dpmi_segments.dpmi_sel = SELECTOR_AllocBlock( ptr, sizeof(enter_pm), WINE_LDT_FLAGS_CODE ); + + ptr = DOSMEM_GetBlock( 4 * 256, &DOSMEM_dpmi_segments.int48_seg ); + for(i=0; i<256; i++) { + /* + * Each 32-bit interrupt handler is 4 bytes: + * 0xCD, = int (nested 16-bit interrupt) + * 0x66,0xCF = iretd (32-bit interrupt return) + */ + ptr[i * 4 + 0] = 0xCD; + ptr[i * 4 + 1] = i; + ptr[i * 4 + 2] = 0x66; + ptr[i * 4 + 3] = 0xCF; + } + DOSMEM_dpmi_segments.int48_sel = SELECTOR_AllocBlock( ptr, 4 * 256, WINE_LDT_FLAGS_CODE ); } static BIOSDATA * DOSMEM_BiosData(void) diff --git a/msdos/interrupts.c b/msdos/interrupts.c index 27e75c6edd1..0802c699963 100644 --- a/msdos/interrupts.c +++ b/msdos/interrupts.c @@ -29,6 +29,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(int); static FARPROC16 INT_Vectors[256]; +static FARPROC48 INT_Vectors48[256]; /* Ordinal number for interrupt 0 handler in WPROCS.DLL */ #define FIRST_INTERRUPT 100 @@ -76,6 +77,37 @@ void INT_SetPMHandler( BYTE intnum, FARPROC16 handler ) } +/********************************************************************** + * INT_GetPMHandler48 + * + * Return the protected mode interrupt vector for a given interrupt. + * Used to get 48-bit pointer for 32-bit interrupt handlers in DPMI32. + */ +FARPROC48 INT_GetPMHandler48( BYTE intnum ) +{ + if (!INT_Vectors48[intnum].selector) + { + INT_Vectors48[intnum].selector = DOSMEM_dpmi_segments.int48_sel; + INT_Vectors48[intnum].offset = 4 * intnum; + } + return INT_Vectors48[intnum]; +} + + +/********************************************************************** + * INT_SetPMHandler48 + * + * Set the protected mode interrupt handler for a given interrupt. + * Used to set 48-bit pointer for 32-bit interrupt handlers in DPMI32. + */ +void INT_SetPMHandler48( BYTE intnum, FARPROC48 handler ) +{ + TRACE("Set 32-bit protected mode interrupt vector %02x <- %04x:%08x\n", + intnum, handler.selector, handler.offset ); + INT_Vectors48[intnum] = handler; +} + + /********************************************************************** * INT_DefaultHandler (WPROCS.356) *