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
Int32Dispatch(LPWORD Stack)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
ControlBop(LPWORD Stack)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
RegisterInt16(IN ULONG FarPtr,IN BYTE IntNumber,IN LPBYTE CallbackCode,IN SIZE_T CallbackSize,OUT PSIZE_T CodeSize OPTIONAL)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
RegisterInt32(IN ULONG FarPtr,IN BYTE IntNumber,IN EMULATOR_INT32_PROC IntHandler,OUT PSIZE_T CodeSize OPTIONAL)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
Int32Call(IN PCALLBACK16 Context,IN BYTE IntNumber)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
InitializeInt32(VOID)194 VOID InitializeInt32(VOID)
195 {
196 /* Register the Control BOP */
197 RegisterBop(BOP_CONTROL, ControlBop);
198 }
199
200 /* EOF */
201