diff --git a/hdpmipt.c b/hdpmipt.c index 4c662af6..948ff81d 100644 --- a/hdpmipt.c +++ b/hdpmipt.c @@ -285,7 +285,7 @@ uint8_t HDPMIPT_UntrappedIO_Read(uint16_t port) return result; } -BOOL HDPMIPT_InstallIRQACKHandler(uint8_t irq, uint16_t cs, uint32_t offset) +BOOL HDPMIPT_InstallIRQRoutedHandler(uint8_t irq, uint16_t cs, uint32_t offset, uint16_t rmcs, uint16_t rmoffset) { if(HDPMIPT_Entry.es == 0 || HDPMIPT_Entry.edi == 0) { @@ -293,18 +293,113 @@ BOOL HDPMIPT_InstallIRQACKHandler(uint8_t irq, uint16_t cs, uint32_t offset) return FALSE; } + BOOL result = 0; asm( "push %%esi \n\t" - "mov $0x0B, %%eax \n\t" //function no. - "movzx %1, %%esi \n\t" //esi=irq - "movzx %2, %%ecx \n\t" //ecx=selector - "mov %3, %%edx \n\t" //edx=offset - "lcall *%0\n\t" - "pop %%esi" - : - :"m"(HDPMIPT_Entry),"m"(irq),"m"(cs),"m"(offset) - :"eax","ecx","edx" + "movl $0x0B, %%eax \n\t" //function no. + "movzxb %2, %%esi \n\t" //esi=irq + "movzxw %3, %%ecx \n\t" //ecx=selector + "movl %4, %%edx \n\t" //edx=offset + "movw %5, %%bx \n\t" //ebx=rm far ptr + "shl $16, %%ebx \n\t" + "movw %6, %%bx \n\t" + "lcall *%1 \n\t" + "pop %%esi \n\t" + "movb $1, %0 \n\t " + "jnc 1f \n\t" + "movb $0, %0 \n\t" + "1: \n\t" + :"=m"(result) + :"m"(HDPMIPT_Entry),"m"(irq),"m"(cs),"m"(offset),"m"(rmcs),"m"(rmoffset) + :"eax","ecx","edx","ebx" + ); + return result; +} + +BOOL HDPMIPT_GetIRQRoutedHandler(uint8_t irq, uint16_t* cs, uint32_t* offset, uint16_t* rmcs, uint16_t* rmoffset) +{ + if(HDPMIPT_Entry.es == 0 || HDPMIPT_Entry.edi == 0) + { + if(!HDPMIPT_GetVendorEntry(&HDPMIPT_Entry)) + return FALSE; + } + assert(cs && offset && rmcs && rmoffset); + + uint16_t _cs = 0, _rmcs = 0, _rmoffset = 0; + uint32_t _offset = 0; + + BOOL result = 0; + asm( + "push %%esi \n\t" + "movl $0x0D, %%eax \n\t" //function no. + "movzxb %6, %%esi \n\t" //esi=irq + "lcall *%5\n\t" + "jc 1f \n\t" + + "movw %%cx, %0 \n\t" //ecx=selector + "movl %%edx, %1 \n\t" //edx=offset + "movw %%bx, %2 \n\t" //ebx=rm far ptr + "shl $16, %%ebx \n\t" + "movw %%bx, %3 \n\t" + + "movb $1, %4 \n\t " + "jmp 2f \n\t" + "1: movb $0, %4 \n\t" + "2: pop %%esi \n\t" + :"=m"(_cs),"=m"(_offset),"=m"(_rmcs),"=m"(_rmoffset),"=m"(result) + :"m"(HDPMIPT_Entry),"m"(irq) + :"eax","ecx","edx","ebx" ); + *offset = _offset; *cs = _cs; *rmcs = _rmcs; *rmoffset = _rmoffset; + return result; +} + +static HDPMIPT_IRQRoutedHandle DPMIPT_IRQROutingCache[16]; + +BOOL HDPMIPT_DisableIRQRouting(uint8_t irq) +{ + if(irq > 15) + { + assert(FALSE); + return FALSE; + } + + if(!HDPMIPT_GetIRQRoutedHandlerH(irq, &DPMIPT_IRQROutingCache[irq])) + { + assert(FALSE); + return FALSE; + } + + if(DPMIPT_IRQROutingCache[irq].cs == 0 && DPMIPT_IRQROutingCache[irq].offset == 0 + && DPMIPT_IRQROutingCache[irq].rmcs == 0 && DPMIPT_IRQROutingCache[irq].rmoffset == 0) + { + return TRUE; + } + + BOOL result = HDPMIPT_InstallIRQRoutedHandler(irq, 0, 0, 0, 0); + assert(result); + return result; +} + +BOOL HDPMIPT_EnableIRQRouting(uint8_t irq) +{ + if(irq > 15 || !DPMIPT_IRQROutingCache[irq].valid) + { + assert(FALSE); + return FALSE; + } + + if( DPMIPT_IRQROutingCache[irq].cs == 0 && DPMIPT_IRQROutingCache[irq].offset == 0 + && DPMIPT_IRQROutingCache[irq].rmcs == 0 && DPMIPT_IRQROutingCache[irq].rmoffset == 0) + { + return TRUE; + } + + if(!HDPMIPT_InstallIRQRoutedHandlerH(irq, &DPMIPT_IRQROutingCache[irq])) + { + assert(FALSE); + return FALSE; + } return TRUE; } diff --git a/hdpmipt.h b/hdpmipt.h index 369bcb35..21ceaefc 100644 --- a/hdpmipt.h +++ b/hdpmipt.h @@ -2,6 +2,7 @@ #define _HDPMIPT_H_ //HDPMI port trap utility +#include #include "qemm.h" //QEMM compatible interface BOOL HDPMIPT_Detect(); @@ -13,8 +14,45 @@ BOOL HDPMIPT_Uninstall_IOPortTrap(QEMM_IOPT* inputp iopt); void HDPMIPT_UntrappedIO_Write(uint16_t port, uint8_t value); uint8_t HDPMIPT_UntrappedIO_Read(uint16_t port); -//doom hack -BOOL HDPMIPT_InstallIRQACKHandler(uint8_t irq, uint16_t cs, uint32_t offset); +//irq hack +//rmcs,rmoffset are optional (-1 to skip, 0 to clear) +BOOL HDPMIPT_InstallIRQRoutedHandler(uint8_t irq, uint16_t cs, uint32_t offset, uint16_t rmcs, uint16_t rmoffset); +BOOL HDPMIPT_GetIRQRoutedHandler(uint8_t irq, uint16_t* cs, uint32_t* offset, uint16_t* rmcs, uint16_t* rmoffset); +BOOL HDPMIPT_DisableIRQRouting(uint8_t irq); +BOOL HDPMIPT_EnableIRQRouting(uint8_t irq); + +//helpers +typedef struct +{ + uint32_t offset; + uint16_t cs; + uint16_t rmoffset; + uint16_t rmcs; + uint16_t valid; +}HDPMIPT_IRQRoutedHandle; +#define HDPMIPT_IRQRoutedHandle_Default {-1, -1, -1, -1, 0} + +static inline BOOL HDPMIPT_InstallIRQRoutedHandlerH(uint8_t irq, const HDPMIPT_IRQRoutedHandle* h) +{ + if(h == NULL || !h->valid) + { + assert(FALSE); + return FALSE; + } + return HDPMIPT_InstallIRQRoutedHandler(irq, h->cs, h->offset, h->rmcs, h->rmoffset); +} + +static inline BOOL HDPMIPT_GetIRQRoutedHandlerH(uint8_t irq, HDPMIPT_IRQRoutedHandle* h) +{ + if(h == NULL) + { + assert(FALSE); + return FALSE; + } + h->valid = HDPMIPT_GetIRQRoutedHandler(irq, &h->cs, &h->offset, &h->rmcs, &h->rmoffset); + assert(h->valid); + return h->valid; +} typedef struct IntContext //must be same as in HDPMI { diff --git a/main.c b/main.c index 37aeb22b..4bf8a278 100644 --- a/main.c +++ b/main.c @@ -31,6 +31,7 @@ PROGNAME = "SBEMU"; #define MAIN_TRAP_PIC_ONDEMAND 1 #define MAIN_INSTALL_RM_ISR 1 //not needed. but to workaround some rm games' problem. need RAW_HOOk in dpmi_dj2.c #define MAIN_DOUBLE_OPL_VOLUME 1 //hack: double the amplitude of OPL PCM. should be 1 or 0 +#define MAIN_ISR_CHAINED 0 //experimental, not fully working yet #define MAIN_TSR_INT 0x2D //AMIS multiplex. TODO: 0x2F? #define MAIN_TSR_INTSTART_ID 0x01 //start id @@ -461,7 +462,11 @@ static void MAIN_InvokeIRQ(uint8_t irq) //generate virtual IRQ HDPMIPT_Install_IOPortTrap(0xA0, 0xA1, MAIN_VIRQ_IODT+2, 2, &MAIN_VIRQ_IOPT_PM2); } #endif + + HDPMIPT_DisableIRQRouting(irq); //disable routing VIRQ_Invoke(irq, &MAIN_IntContext.regs, MAIN_IntContext.EFLAGS&CPU_VMFLAG); + HDPMIPT_EnableIRQRouting(irq); //restore routing + #if MAIN_TRAP_PIC_ONDEMAND if(MAIN_Options[OPT_RM].value) QEMM_Uninstall_IOPortTrap(&MAIN_VIRQ_IOPT); if(MAIN_Options[OPT_PM].value) @@ -535,8 +540,11 @@ update_serial_mpu_output() } static BOOL OPLRMInstalled, OPLPMInstalled, MPURMInstalled, MPUPMInstalled; +static HDPMIPT_IRQRoutedHandle OldRoutedHandle = HDPMIPT_IRQRoutedHandle_Default; static void MAIN_Cleanup() { + if(OldRoutedHandle.valid) + HDPMIPT_InstallIRQRoutedHandlerH(aui.card_irq, &OldRoutedHandle); AU_stop(&aui); AU_close(&aui); if(OPLRMInstalled) @@ -737,7 +745,7 @@ int main(int argc, char* argv[]) return 1; atexit(&MAIN_Cleanup); - if(aui.card_irq > 15) + if(aui.card_irq > 31) //UEFI with CSM may have APIC enabled (16-31). { printf("Invalid Sound card IRQ: "); MAIN_CPrintf(RED, "%d", aui.card_irq); @@ -760,14 +768,18 @@ int main(int argc, char* argv[]) } if(aui.card_irq <= 0x07) //SBPCI/CMI use irq 5/7 to gain DOS compatility? { - printf("WARNING: Low IRQ %d used for sound card, higher IRQ number(8~15) is recommended.\nTrying to enable Level triggered mode.\n", aui.card_irq); + printf("WARNING: Low IRQ %d used for sound card, higher IRQ number(8~15) is recommended.\n", aui.card_irq); //TODO: do we need to do this? + #if 0 + printf("Trying to enable Level triggered mode..."); if(aui.card_irq > 2) //don't use level triggering for legacy ISA IRQ (timer/kbd etc) { - uint16_t elcr = inpw(0x4D0); //edge level control reg + uint16_t elcr = ((uint16_t)inp(0x4D1)<<8) | (inp(0x4D0)); //edge level control reg elcr |= (1<>4, TRUE); @@ -909,22 +921,18 @@ int main(int argc, char* argv[]) if(MAIN_Options[OPT_OPL].value) OPL3EMU_Init(aui.freq_card); //aui.freq_card available after AU_setrate - BOOL PM_ISR = DPMI_InstallISR(PIC_IRQ2VEC(aui.card_irq), MAIN_InterruptPM, &MAIN_IntHandlePM) == 0; - //set default ACK, to skip recursion of DOS/4GW - { - DPMI_ISR_HANDLE h; - for(int i = 0; i < 15; ++i) - { - DPMI_GetISR(PIC_IRQ2VEC(i), &h); - HDPMIPT_InstallIRQACKHandler(i, h.old_cs, h.old_offset); - } - } - HDPMIPT_InstallIRQACKHandler(aui.card_irq, MAIN_IntHandlePM.wrapper_cs, MAIN_IntHandlePM.wrapper_offset); + BOOL PM_ISR = DPMI_InstallISR(PIC_IRQ2VEC(aui.card_irq), MAIN_InterruptPM, &MAIN_IntHandlePM, MAIN_ISR_CHAINED) == 0; + #if MAIN_INSTALL_RM_ISR - BOOL RM_ISR = DPMI_InstallRealModeISR(PIC_IRQ2VEC(aui.card_irq), MAIN_InterruptRM, &MAIN_RMIntREG, &MAIN_IntHandleRM) == 0; + BOOL RM_ISR = DPMI_InstallRealModeISR(PIC_IRQ2VEC(aui.card_irq), MAIN_InterruptRM, &MAIN_RMIntREG, &MAIN_IntHandleRM, MAIN_ISR_CHAINED) == 0; #else BOOL RM_ISR = TRUE; + MAIN_IntHandleRM.wrapper_cs = MAIN_IntHandleRM.wrapper_offset = -1; //skip for HDPMIPT_InstallIRQRouteHandler #endif + + HDPMIPT_GetIRQRoutedHandlerH(aui.card_irq, &OldRoutedHandle); + HDPMIPT_InstallIRQRoutedHandler(aui.card_irq, MAIN_IntHandlePM.wrapper_cs, MAIN_IntHandlePM.wrapper_offset, + MAIN_IntHandleRM.wrapper_cs, (uint16_t)MAIN_IntHandleRM.wrapper_offset); PIC_UnmaskIRQ(aui.card_irq); AU_prestart(&aui); @@ -977,18 +985,38 @@ int main(int argc, char* argv[]) return 1; } +//with the modified fork of HDPMI, HDPMI will route PM interrupts to IVT. +//IRQ routing path: +//PM: IDT -> PM handlers after SBEMU -> SBEMU MAIN_InterruptPM(*) -> PM handlers befoe SBEMU -> IVT -> SBEMU MAIN_InterruptRM(*) -> DPMI entrance -> IVT handlers before DPMI installed +//RM: IVT -> RM handlers before SBEMU -> SBEMU MAIN_InterruptRM(*) -> RM handlers after SBEMU -> DPMI entrance -> PM handlers after SBEMU -> SBEMU MAIN_InterruptPM(*) -> PM handlers befoe SBEMU -> IVT handlers before DPMI installed +//(*) means SBEMU might early terminate the calling chain if sound irq is handled. +//early terminating is OK because PCI irq are level triggered, IRQ signal will keep high (raised) unless the hardware IRQ is ACKed. + static void MAIN_InterruptPM() { - if(MAIN_InINT&MAIN_ININT_PM) return; + const uint8_t irq = PIC_GetIRQ(); + if(irq != aui.card_irq) //shared IRQ handled by other handlers(EOI sent) or new irq arrived but not for us + return; + + //if(MAIN_InINT&MAIN_ININT_PM) return; //skip reentrance. go32 will do this so actually we don't need it //DBG_Log("INTPM %d\n", MAIN_InINT); MAIN_InINT |= MAIN_ININT_PM; + //note: we have full control of the calling chain, if the irq belongs to the sound card, + //we send EOI and skip calling the chain - it will be a little faster. if other devices raises irq at the same time, + //the interrupt handler will enterred again (not nested) so won't be a problem. + //also we send EOI on our own and terminate, this doesn't rely on the default implementation in IVT. + // + //an alternative chained methods will always calls next handler, see @MAIN_ISR_CHAINED + + //MAIN_IntContext.EFLAGS |= (MAIN_InINT&MAIN_ININT_RM) ? (MAIN_IntContext.EFLAGS&CPU_VMFLAG) : 0; HDPMIPT_GetInterrupContext(&MAIN_IntContext); - if(!(MAIN_InINT&MAIN_ININT_RM) && aui.card_handler->irq_routine && aui.card_handler->irq_routine(&aui)) //check if the irq belong the sound card + if(/*!(MAIN_InINT&MAIN_ININT_RM) && */aui.card_handler->irq_routine && aui.card_handler->irq_routine(&aui)) //check if the irq belong the sound card { MAIN_Interrupt(); PIC_SendEOIWithIRQ(aui.card_irq); } + #if !MAIN_ISR_CHAINED else { if((MAIN_InINT&MAIN_ININT_RM) || (MAIN_IntContext.EFLAGS&CPU_VMFLAG)) @@ -996,31 +1024,38 @@ static void MAIN_InterruptPM() else DPMI_CallOldISRWithContext(&MAIN_IntHandlePM, &MAIN_IntContext.regs); PIC_UnmaskIRQ(aui.card_irq); - //DBG_Log("INTPME %d\n", MAIN_InINT); } + #endif + //DBG_Log("INTPME %d\n", MAIN_InINT); MAIN_InINT &= ~MAIN_ININT_PM; } static void MAIN_InterruptRM() { - if(MAIN_InINT&MAIN_ININT_RM) return; + const uint8_t irq = PIC_GetIRQ(); + if(irq != aui.card_irq) //shared IRQ handled by other handlers(EOI sent) or new irq arrived but not for us + return; + + //f(MAIN_InINT&MAIN_ININT_RM) return; //skip reentrance. go32 will do this so actually we don't need it //DBG_Log("INTRM %d\n", MAIN_InINT); MAIN_InINT |= MAIN_ININT_RM; - if(!(MAIN_InINT&MAIN_ININT_PM) && aui.card_handler->irq_routine && aui.card_handler->irq_routine(&aui)) //check if the irq belong the sound card + if(/*!(MAIN_InINT&MAIN_ININT_PM) && */aui.card_handler->irq_routine && aui.card_handler->irq_routine(&aui)) //check if the irq belong the sound card { MAIN_IntContext.regs = MAIN_RMIntREG; MAIN_IntContext.EFLAGS = MAIN_RMIntREG.w.flags | CPU_VMFLAG; MAIN_Interrupt(); PIC_SendEOIWithIRQ(aui.card_irq); } + #if !MAIN_ISR_CHAINED else { DPMI_REG r = MAIN_RMIntREG; //don't modify MAIN_RMIntREG on hardware interrupt DPMI_CallRealModeOldISR(&MAIN_IntHandleRM, &r); PIC_UnmaskIRQ(aui.card_irq); - //DBG_Log("INTRME %d\n", MAIN_InINT); } + #endif + //DBG_Log("INTRME %d\n", MAIN_InINT); MAIN_InINT &= ~MAIN_ININT_RM; } diff --git a/sbemu/dpmi/dpmi.h b/sbemu/dpmi/dpmi.h index c8e4f7b4..4d675281 100644 --- a/sbemu/dpmi/dpmi.h +++ b/sbemu/dpmi/dpmi.h @@ -81,6 +81,8 @@ typedef struct //old interrupt handler info returned by install isr. uint32_t wrapper_offset; uint16_t wrapper_cs; uint8_t n; //INTn + uint8_t chained; + uint32_t chainedDOSMem; //internal informations uint32_t internal1[8]; @@ -210,8 +212,8 @@ uint16_t DPMI_CallRealModeINT(uint8_t i, DPMI_REG* reg); uint16_t DPMI_CallRealModeIRET(DPMI_REG* reg); //install interrupt service routine. ISR use normal return, no need to do IRET. //return 0 if succeed -uint16_t DPMI_InstallISR(uint8_t i, void(*ISR)(void), DPMI_ISR_HANDLE* outputp handle); -uint16_t DPMI_InstallRealModeISR(uint8_t i, void(*ISR_RM)(void), DPMI_REG* RMReg, DPMI_ISR_HANDLE* outputp handle); +uint16_t DPMI_InstallISR(uint8_t i, void(*ISR)(void), DPMI_ISR_HANDLE* outputp handle, BOOL chained); +uint16_t DPMI_InstallRealModeISR(uint8_t i, void(*ISR_RM)(void), DPMI_REG* RMReg, DPMI_ISR_HANDLE* outputp handle, BOOL chained); uint16_t DPMI_UninstallISR(DPMI_ISR_HANDLE* inputp handle); uint32_t DPMI_CallOldISR(DPMI_ISR_HANDLE* inputp handle); diff --git a/sbemu/dpmi/dpmi_dj2.c b/sbemu/dpmi/dpmi_dj2.c index 2ae5d210..913d2936 100644 --- a/sbemu/dpmi/dpmi_dj2.c +++ b/sbemu/dpmi/dpmi_dj2.c @@ -418,7 +418,7 @@ uint16_t DPMI_CallRealModeIRET(DPMI_REG* reg) } #define RAW_HOOK 1 -uint16_t DPMI_InstallISR(uint8_t i, void(*ISR)(void), DPMI_ISR_HANDLE* outputp handle) +uint16_t DPMI_InstallISR(uint8_t i, void(*ISR)(void), DPMI_ISR_HANDLE* outputp handle, BOOL chained) { if(i < 0 || i > 255 || handle == NULL || ISR == NULL) return -1; @@ -426,9 +426,12 @@ uint16_t DPMI_InstallISR(uint8_t i, void(*ISR)(void), DPMI_ISR_HANDLE* outputp h _go32_dpmi_seginfo go32pa; go32pa.pm_selector = (uint16_t)_my_cs(); go32pa.pm_offset = (uintptr_t)ISR; - //_go32_interrupt_stack_size = 2048; //512 minimal. default:16K - if(_go32_dpmi_allocate_iret_wrapper(&go32pa) != 0) - return -1; + //_go32_interrupt_stack_size = 2048; //512 minimal, default 16K + if(!chained) + { + if( _go32_dpmi_allocate_iret_wrapper(&go32pa) != 0) + return -1; + } _go32_dpmi_seginfo go32pa_rm = {0}; __dpmi_raddr ra; @@ -450,16 +453,49 @@ uint16_t DPMI_InstallISR(uint8_t i, void(*ISR)(void), DPMI_ISR_HANDLE* outputp h handle->wrapper_offset = go32pa.pm_offset; handle->wrapper_cs = go32pa.pm_selector; handle->n = i; + handle->chained = chained; + handle->chainedDOSMem = 0; memcpy(handle->internal1, &go32pa, sizeof(go32pa)); memset(handle->internal2, 0, sizeof(handle->internal2)); - int result = _go32_dpmi_set_protected_mode_interrupt_vector(i, &go32pa); - return (uint16_t)result; + int result; + if(chained) + { + result = _go32_dpmi_chain_protected_mode_interrupt_vector(i, &go32pa); + if(result == 0) + { + handle->wrapper_offset = go32pa.pm_offset; + handle->wrapper_cs = go32pa.pm_selector; + } + } + else + { + result = _go32_dpmi_set_protected_mode_interrupt_vector(i, &go32pa); + if(result != 0) + _go32_dpmi_free_iret_wrapper(&go32pa); + } + + if(result != 0) + memset(handle, 0, sizeof(*handle)); + + return result; } +static void __NAKED DPMI_RMISR_ChainedWrapper() +{ + _ASM_BEGIN16 + _ASM(pushf) //calling iret + _ASM(call dword ptr cs:[0]) //call target + _ASM(pushf) //calling iret + _ASM(call dword ptr cs:[4]) //call chained next + _ASM(iret) + _ASM_END16 +} +static void __NAKED DPMI_RMISR_ChainedWrapperEnd() {} + //http://www.delorie.com/djgpp/v2faq/faq18_9.html -uint16_t DPMI_InstallRealModeISR(uint8_t i, void(*ISR_RM)(void), DPMI_REG* RMReg, DPMI_ISR_HANDLE* outputp handle) +uint16_t DPMI_InstallRealModeISR(uint8_t i, void(*ISR_RM)(void), DPMI_REG* RMReg, DPMI_ISR_HANDLE* outputp handle, BOOL chained) { if(i < 0 || i > 255 || handle == NULL || ISR_RM == NULL || RMReg == NULL) return -1; @@ -487,12 +523,44 @@ uint16_t DPMI_InstallRealModeISR(uint8_t i, void(*ISR_RM)(void), DPMI_REG* RMReg handle->old_cs = pa.selector; handle->old_rm_cs = ra.segment; handle->old_rm_offset = ra.offset16; - handle->wrapper_offset = 0; - handle->wrapper_cs = 0; + //handle->wrapper_offset = go32pa_rm.rm_offset; + //handle->wrapper_cs = go32pa_rm.rm_segment; handle->n = i; + handle->chained = chained; + handle->chainedDOSMem = 0; memset(handle->internal1, 0, sizeof(handle->internal1)); memcpy(handle->internal2, &go32pa_rm, sizeof(go32pa_rm)); + //there's no go32 chained api for realmode, either we edit gormcb.c + //or we allocate extra memory and do it on our own + if(chained) + { + uint32_t codesize = (uintptr_t)&DPMI_RMISR_ChainedWrapperEnd - (uintptr_t)&DPMI_RMISR_ChainedWrapper; + handle->chainedDOSMem = DPMI_HighMalloc((codesize + 8 + 15)>>4, TRUE); //+target + chained next (both real mode far ptr) + if(handle->chainedDOSMem == 0) + { + _go32_dpmi_free_real_mode_callback(&go32pa_rm); + return -1; + } + + uint8_t* buf = (uint8_t*)malloc(codesize+8); + //copy target + memcpy(buf+0, &go32pa_rm.rm_offset, 2); + memcpy(buf+2, &go32pa_rm.rm_segment, 2); + //copy chained next + memcpy(buf+4, &ra.offset16, 2); + memcpy(buf+6, &ra.segment, 2); + //copy warpper code + memcpy(buf+8, &DPMI_RMISR_ChainedWrapper, codesize); + DPMI_CopyLinear(DPMI_SEGOFF2L(handle->chainedDOSMem, 0), DPMI_PTR2L(buf), codesize+8); + free(buf); + + go32pa_rm.rm_segment = handle->chainedDOSMem&0xFFFF; + go32pa_rm.rm_offset = 8; + } + handle->wrapper_offset = go32pa_rm.rm_offset; + handle->wrapper_cs = go32pa_rm.rm_segment; + ra.segment = go32pa_rm.rm_segment; ra.offset16 = go32pa_rm.rm_offset; #if RAW_HOOK @@ -506,6 +574,9 @@ uint16_t DPMI_InstallRealModeISR(uint8_t i, void(*ISR_RM)(void), DPMI_REG* RMReg #else int result = __dpmi_set_real_mode_interrupt_vector(i, &ra); #endif + + if(result != 0) + memset(handle, 0, sizeof(*handle)); return (uint16_t)result; } @@ -533,14 +604,21 @@ uint16_t DPMI_UninstallISR(DPMI_ISR_HANDLE* inputp handle) result = _go32_dpmi_free_real_mode_callback(&go32pa) | result; memcpy(&go32pa, handle->internal1, sizeof(go32pa)); - return (uint16_t)(_go32_dpmi_free_iret_wrapper(&go32pa) | result); + + if(handle->chained) //chained go32 wrapper cannot be freed. + { + if(handle->chainedDOSMem) + DPMI_HighFree(handle->chainedDOSMem); + return (uint16_t)result; + } + else + return (uint16_t)(_go32_dpmi_free_iret_wrapper(&go32pa) | result); } uint32_t DPMI_CallOldISR(DPMI_ISR_HANDLE* inputp handle) { asm( "pushfl \n\t" - "cli \n\t" "lcall *%0 \n\t" ::"m"(*handle) );