1 /* 2 * COPYRIGHT: GPL - See COPYING in the top level directory 3 * PROJECT: ReactOS Virtual DOS Machine 4 * FILE: subsystems/mvdm/ntvdm/int32.c 5 * PURPOSE: 32-bit Interrupt Handlers 6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org> 7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr) 8 */ 9 10 /* INCLUDES *******************************************************************/ 11 12 #include "ntvdm.h" 13 14 #define NDEBUG 15 #include <debug.h> 16 17 #include "emulator.h" 18 #include "int32.h" 19 20 #include "cpu/bop.h" 21 #include <isvbop.h> 22 23 /* PRIVATE VARIABLES **********************************************************/ 24 25 /* 26 * This is the list of registered 32-bit Interrupt handlers. 27 */ 28 static EMULATOR_INT32_PROC Int32Proc[EMULATOR_MAX_INT32_NUM] = { NULL }; 29 30 /* BOP Identifiers */ 31 #define BOP_CONTROL 0xFF // Control BOP Handler 32 #define BOP_CONTROL_DEFFUNC 0x00 // Default Control BOP Function 33 #define BOP_CONTROL_INT32 0xFF // 32-bit Interrupt dispatcher 34 35 #define INT16_TRAMPOLINE_SIZE sizeof(ULONGLONG) // == TRAMPOLINE_SIZE 36 37 /* 16-bit generic interrupt code for calling a 32-bit interrupt handler */ 38 static BYTE Int16To32[] = 39 { 40 0xFA, // cli 41 42 /* Push the value of the interrupt to be called */ 43 0x6A, 0xFF, // push i (patchable to 0x6A, 0xIntNum) 44 45 0xF8, // clc 46 47 /* The BOP Sequence */ 48 // BOP_SEQ: 49 BOP(BOP_CONTROL), // Control BOP 50 BOP_CONTROL_INT32, // 32-bit Interrupt dispatcher 51 52 0x73, 0x04, // jnc EXIT (offset +4) 53 54 0xFB, // sti 55 56 0xF4, // hlt 57 58 0xEB, 0xF6, // jmp BOP_SEQ (offset -10) 59 60 // EXIT: 61 0x44, 0x44, // inc sp, inc sp 62 0xCF, // iret 63 }; 64 C_ASSERT(sizeof(Int16To32) == Int16To32StubSize); 65 66 /* PUBLIC FUNCTIONS ***********************************************************/ 67 68 static VOID WINAPI Int32Dispatch(LPWORD Stack) 69 { 70 /* Get the interrupt number */ 71 BYTE IntNum = LOBYTE(Stack[STACK_INT_NUM]); 72 73 /* Call the 32-bit Interrupt handler */ 74 if (Int32Proc[IntNum] != NULL) 75 Int32Proc[IntNum](Stack); 76 else 77 DPRINT1("Unhandled 32-bit interrupt: 0x%02X, AX = 0x%04X\n", IntNum, getAX()); 78 } 79 80 static VOID WINAPI ControlBop(LPWORD Stack) 81 { 82 /* Get the Function Number and skip it */ 83 BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP()); 84 setIP(getIP() + 1); 85 86 switch (FuncNum) 87 { 88 case BOP_CONTROL_INT32: 89 Int32Dispatch(Stack); 90 break; 91 92 default: 93 // DPRINT1("Unassigned Control BOP Function: 0x%02X\n", FuncNum); 94 DisplayMessage(L"Unassigned Control BOP Function: 0x%02X", FuncNum); 95 break; 96 } 97 } 98 99 ULONG 100 RegisterInt16(IN ULONG FarPtr, 101 IN BYTE IntNumber, 102 IN LPBYTE CallbackCode, 103 IN SIZE_T CallbackSize, 104 OUT PSIZE_T CodeSize OPTIONAL) 105 { 106 /* Get a pointer to the IVT and set the corresponding entry (far pointer) */ 107 LPDWORD IntVecTable = (LPDWORD)SEG_OFF_TO_PTR(0x0000, 0x0000); 108 IntVecTable[IntNumber] = FarPtr; 109 110 /* Register the 16-bit callback */ 111 return RegisterCallback16(FarPtr, 112 CallbackCode, 113 CallbackSize, 114 CodeSize); 115 } 116 117 ULONG 118 RegisterInt32(IN ULONG FarPtr, 119 IN BYTE IntNumber, 120 IN EMULATOR_INT32_PROC IntHandler, 121 OUT PSIZE_T CodeSize OPTIONAL) 122 { 123 /* Array for holding our copy of the 16-bit interrupt callback */ 124 BYTE IntCallback[sizeof(Int16To32)/sizeof(BYTE)]; 125 126 /* Check whether the 32-bit interrupt was already registered */ 127 #if 0 128 if (Int32Proc[IntNumber] != NULL) 129 { 130 DPRINT1("RegisterInt32: Interrupt 0x%02X already registered!\n", IntNumber); 131 return 0; 132 } 133 #endif 134 135 /* Register the 32-bit interrupt handler */ 136 Int32Proc[IntNumber] = IntHandler; 137 138 /* Copy the generic 16-bit interrupt callback and patch it */ 139 RtlCopyMemory(IntCallback, Int16To32, sizeof(Int16To32)); 140 IntCallback[2] = IntNumber; 141 142 /* Register the 16-bit interrupt callback */ 143 return RegisterInt16(FarPtr, 144 IntNumber, 145 IntCallback, 146 sizeof(IntCallback), 147 CodeSize); 148 } 149 150 VOID 151 Int32Call(IN PCALLBACK16 Context, 152 IN BYTE IntNumber) 153 { 154 /* 155 * TODO: This function has almost the same code as RunCallback16. 156 * Something that may be nice is to have a common interface to 157 * build the trampoline... 158 */ 159 160 PUCHAR TrampolineBase = (PUCHAR)FAR_POINTER(Context->TrampolineFarPtr); 161 PUCHAR Trampoline = TrampolineBase; 162 UCHAR OldTrampoline[INT16_TRAMPOLINE_SIZE]; 163 164 DPRINT("Int32Call(0x%02X)\n", IntNumber); 165 166 ASSERT(Context->TrampolineSize == INT16_TRAMPOLINE_SIZE); 167 168 /* Save the old trampoline */ 169 ((PULONGLONG)&OldTrampoline)[0] = ((PULONGLONG)TrampolineBase)[0]; 170 171 /* Build the generic entry-point for 16-bit calls */ 172 if (IntNumber == 0x03) 173 { 174 /* We are redefining for INT 03h */ 175 *Trampoline++ = 0xCC; // Call INT 03h 176 /** *Trampoline++ = 0x90; // nop **/ 177 } 178 else 179 { 180 /* Normal interrupt */ 181 *Trampoline++ = 0xCD; // Call INT XXh 182 *Trampoline++ = IntNumber; 183 } 184 UnSimulate16(Trampoline); 185 186 /* Perform the call */ 187 Call16(HIWORD(Context->TrampolineFarPtr), 188 LOWORD(Context->TrampolineFarPtr)); 189 190 /* Restore the old trampoline */ 191 ((PULONGLONG)TrampolineBase)[0] = ((PULONGLONG)&OldTrampoline)[0]; 192 } 193 194 VOID InitializeInt32(VOID) 195 { 196 /* Register the Control BOP */ 197 RegisterBop(BOP_CONTROL, ControlBop); 198 } 199 200 /* EOF */ 201