Skip to content

Commit

Permalink
add irq guard to prevent virtual irq to pass down to BIOS.
Browse files Browse the repository at this point in the history
  • Loading branch information
crazii committed Feb 27, 2024
1 parent 65ab7da commit ee16896
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 0 deletions.
92 changes: 92 additions & 0 deletions irqguard.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#include <string.h>
#include <assert.h>
#include "irqguard.h"
#include "sbemu/dpmi/dpmi.h"
#include "sbemu/pic.h"

static BOOL IRQGUARD_Installed;
static uint32_t IRQGUARD_DOSMEM;
static DPMI_ISR_HANDLE IRQGUARD_Handle; //big structure not needed for now, but maybe for future use.
static uint8_t IRQGUARD_IRQ = 0xFF;
#define IRQGUARD_BYTE_LOC 4

static void __NAKED IRQGUARD_Handler()
{
_ASM_BEGIN16
_ASM(cmp byte ptr cs:[4], 1) //IRQGUARD_BYTE_LOC: guard enabled?
_ASM(je skip)
_ASM(pushf) //calling iret
_ASM(call dword ptr cs:[0]) //call handler
_ASMLBL(skip:)
_ASM(iret)
_ASM_END16
}
static void __NAKED IRQGUARD_HandlerEnd() {}

BOOL IRQGUARD_Install(uint8_t irq)
{
if(IRQGUARD_Installed && irq == IRQGUARD_IRQ)
return TRUE;

const uint16_t datasize = IRQGUARD_BYTE_LOC+1; //far ptr + guard byte
if(!IRQGUARD_Installed)
{
assert(IRQGUARD_DOSMEM == 0);
uint32_t codesize = (uintptr_t)&IRQGUARD_HandlerEnd - (uintptr_t)&IRQGUARD_Handler;
IRQGUARD_DOSMEM = DPMI_HighMalloc((codesize+datasize+15)>>4, TRUE);
if(IRQGUARD_DOSMEM == 0)
{
assert(FALSE);
return FALSE;
}
DPMI_CopyLinear(DPMI_SEGOFF2L(IRQGUARD_DOSMEM, datasize), DPMI_PTR2L(&IRQGUARD_Handler), codesize);
}

if(IRQGUARD_Installed && irq != IRQGUARD_IRQ)
//restore old handler
DPMI_UninstallRealModeISR_Direct(&IRQGUARD_Handle);

int vec = PIC_IRQ2VEC(irq);
CLIS();
//install handler
//need install to DPMI because PM games may install DPMI handler
//if rawIVT is used, it will prevent DPMI and PM games to process it
DPMI_InstallRealModeISR_Direct(vec, (uint16_t)(IRQGUARD_DOSMEM&0xFFFF), datasize, &IRQGUARD_Handle, FALSE);
//far ptr
DPMI_CopyLinear(DPMI_SEGOFF2L(IRQGUARD_DOSMEM, 0), DPMI_PTR2L(&IRQGUARD_Handle.old_rm_offset), 2);
DPMI_CopyLinear(DPMI_SEGOFF2L(IRQGUARD_DOSMEM, 2), DPMI_PTR2L(&IRQGUARD_Handle.old_rm_cs), 2);
//init guard byte
IRQGUARD_Installed = TRUE;
IRQGUARD_IRQ = irq;
IRQGUARD_Disable();
STIL();
}

BOOL IRQGUARD_Uninstall()
{
if(IRQGUARD_Installed)
{
assert(IRQGUARD_Handle.old_rm_offset != 0);
assert(IRQGUARD_Handle.old_rm_cs != 0);
DPMI_UninstallRealModeISR_Direct(&IRQGUARD_Handle);
memset(&IRQGUARD_Handle, 0, sizeof(IRQGUARD_Handle));
DPMI_HighFree(IRQGUARD_DOSMEM);
IRQGUARD_DOSMEM = 0;
IRQGUARD_Installed = 0;
IRQGUARD_IRQ = 0xFF;
return TRUE;
}
return FALSE;
}

void IRQGUARD_Enable()
{
if(IRQGUARD_Installed)
DPMI_StoreB(DPMI_SEGOFF2L(IRQGUARD_DOSMEM, IRQGUARD_BYTE_LOC), 1);
}

void IRQGUARD_Disable()
{
if(IRQGUARD_Installed)
DPMI_StoreB(DPMI_SEGOFF2L(IRQGUARD_DOSMEM, IRQGUARD_BYTE_LOC), 0);
}
28 changes: 28 additions & 0 deletions irqguard.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef _IRQGUARD_H_
#define _IRQGUARD_H_
#include "sbemu/platform.h"

//guard the virtual irq to prevent it pass to default IVT handler (bios)
//I've never seen any problem without the guard for my laptop, but it will get more compatibility

#ifdef __cplusplus
extern "C" {
#endif

//install/reinstall
BOOL IRQGUARD_Install(uint8_t irq);

//uninstall
BOOL IRQGUARD_Uninstall();

//enable irq guard
void IRQGUARD_Enable();

//disable irq guard
void IRQGUARD_Disable();

#ifdef __cplusplus
}
#endif

#endif
9 changes: 9 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "qemm.h"
#include "hdpmipt.h"
#include "serial.h"
#include "irqguard.h"

#include <au_cards/au_cards.h>
#include <au_cards/pcibios.h>
Expand Down Expand Up @@ -480,7 +481,9 @@ static void MAIN_InvokeIRQ(uint8_t irq) //generate virtual IRQ
#endif

HDPMIPT_DisableIRQRouting(irq); //disable routing
IRQGUARD_Enable();
VIRQ_Invoke(irq, &MAIN_IntContext.regs, MAIN_IntContext.EFLAGS&CPU_VMFLAG);
IRQGUARD_Disable();
HDPMIPT_EnableIRQRouting(irq); //restore routing

#if MAIN_TRAP_RMPIC_ONDEMAND
Expand Down Expand Up @@ -586,6 +589,8 @@ static void MAIN_Cleanup()
QEMM_Uninstall_IOPortTrap(&MPUIOPT);
if(MPUPMInstalled)
HDPMIPT_Uninstall_IOPortTrap(&MPUIOPT_PM);

IRQGUARD_Uninstall();
}

int main(int argc, char* argv[])
Expand Down Expand Up @@ -985,6 +990,7 @@ int main(int argc, char* argv[])
MAIN_IntHandleRM.wrapper_cs = MAIN_IntHandleRM.wrapper_offset = -1; //skip for HDPMIPT_InstallIRQRouteHandler
#endif

IRQGUARD_Install(MAIN_Options[OPT_IRQ].value);
struct
{
int irq;
Expand Down Expand Up @@ -1556,6 +1562,9 @@ static void MAIN_TSR_Interrupt()
MAIN_Options[OPT_IRQ].value = opt[OPT_IRQ].value;
MAIN_Options[OPT_TYPE].value = opt[OPT_TYPE].value;
MAIN_Options[OPT_FIX_TC].value = opt[OPT_FIX_TC].value;
HDPMIPT_LockIRQRouting(FALSE);
IRQGUARD_Install(MAIN_Options[OPT_IRQ].value);
HDPMIPT_LockIRQRouting(TRUE);
SBEMU_Init(
MAIN_Options[OPT_IRQ].value,
MAIN_Options[OPT_DMA].value,
Expand Down
1 change: 1 addition & 0 deletions makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ SBEMU_SRC := sbemu/dbopl.cpp \
qemm.c \
utility.c \
hdpmipt.c \
irqguard.c \

SRC := $(CARDS_SRC) $(SBEMU_SRC)
OBJS := $(patsubst %.cpp,output/%.o,$(patsubst %.c,output/%.o,$(SRC)))
Expand Down
3 changes: 3 additions & 0 deletions sbemu/dpmi/dpmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,9 @@ uint32_t DPMI_CallOldISR(DPMI_ISR_HANDLE* inputp handle);
uint32_t DPMI_CallOldISRWithContext(DPMI_ISR_HANDLE* inputp handle, const DPMI_REG* regs); //do not call it with VM context (vm context cannot be restored)
uint32_t DPMI_CallRealModeOldISR(DPMI_ISR_HANDLE* inputp handle, DPMI_REG* regs);

uint16_t DPMI_InstallRealModeISR_Direct(uint8_t i, uint16_t seg, uint16_t off, DPMI_ISR_HANDLE* outputp handle, BOOL rawIVT);
uint16_t DPMI_UninstallRealModeISR_Direct(DPMI_ISR_HANDLE* inputp handle);

uint32_t DPMI_GetISR(uint8_t i, DPMI_ISR_HANDLE* outputp handle);

//allocate realmode callback. return: hiword: segment, lowword: offset. return 0 if fail
Expand Down
70 changes: 70 additions & 0 deletions sbemu/dpmi/dpmi_dj2.c
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,76 @@ uint16_t DPMI_InstallRealModeISR(uint8_t i, void(*ISR_RM)(void), DPMI_REG* RMReg
return (uint16_t)result;
}

uint16_t DPMI_InstallRealModeISR_Direct(uint8_t i, uint16_t seg, uint16_t off, DPMI_ISR_HANDLE* outputp handle, BOOL rawIVT)
{
if(i < 0 || i > 255 || handle == NULL)
return -1;

__dpmi_raddr ra;
if(rawIVT)
{
CLIS();
ra.offset16 = DPMI_LoadW(i*4);
ra.segment = DPMI_LoadW(i*4+2);
STIL();
}
else
__dpmi_get_real_mode_interrupt_vector(i, &ra);

int result = -1;
if(rawIVT)
{
CLIS();
DPMI_StoreW(i*4, off);
DPMI_StoreW(i*4+2, seg);
STIL();
result = 0;
}
else
{
__dpmi_raddr ra2;
ra2.segment = seg;
ra2.offset16 = off;
result = __dpmi_set_real_mode_interrupt_vector(i, &ra2);
}

if(result == 0)
{
handle->old_offset = 0;
handle->old_cs = 0;
handle->old_rm_cs = ra.segment;
handle->old_rm_offset = ra.offset16;
handle->n = i;
handle->chained = 0;
memset(handle->internal1, 0, sizeof(handle->internal1));
memset(handle->internal2, 0, sizeof(handle->internal2));
handle->internal1[0] = rawIVT;
}
else
memset(handle, 0, sizeof(*handle));
return (uint16_t)result;
}

uint16_t DPMI_UninstallRealModeISR_Direct(DPMI_ISR_HANDLE* inputp handle)
{
BOOL rawIVT = handle->internal1[0];
if(rawIVT)
{
CLIS();
DPMI_StoreW(handle->n*4, handle->old_rm_offset);
DPMI_StoreW(handle->n*4+2, handle->old_rm_cs);
STIL();
return 0;
}
else
{
__dpmi_raddr ra2;
ra2.segment = handle->old_rm_cs;
ra2.offset16 = handle->old_rm_offset;
return (uint16_t)__dpmi_set_real_mode_interrupt_vector(handle->n, &ra2);
}
}

uint16_t DPMI_UninstallISR(DPMI_ISR_HANDLE* inputp handle)
{
_go32_dpmi_seginfo go32pa;
Expand Down

0 comments on commit ee16896

Please sign in to comment.