[NTVDM]
[reactos.git] / reactos / subsystems / ntvdm / callback.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: callback.c
5 * PURPOSE: 16 and 32-bit Callbacks Support
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 #define NDEBUG
13
14 #include "emulator.h"
15 #include "callback.h"
16
17 #include "bop.h"
18 #include <isvbop.h>
19
20 /* PRIVATE VARIABLES **********************************************************/
21
22 /*
23 * This is the list of registered 32-bit Interrupt handlers.
24 */
25 EMULATOR_INT32_PROC Int32Proc[EMULATOR_MAX_INT32_NUM] = { NULL };
26
27 /* BOP Identifiers */
28 #define BOP_CONTROL 0xFF // Control BOP Handler
29 #define BOP_CONTROL_DEFFUNC 0x00 // Default Control BOP Function
30
31 /* 32-bit Interrupt dispatcher function code for the Control BOP Handler */
32 #define BOP_CONTROL_INT32 0xFF
33
34
35 #define BOP(num) LOBYTE(EMULATOR_BOP), HIBYTE(EMULATOR_BOP), (num)
36 #define UnSimulate16(trap) \
37 do { \
38 *(PUSHORT)(trap) = EMULATOR_BOP; \
39 (trap) += sizeof(USHORT); \
40 *(trap) = BOP_UNSIMULATE; \
41 } while(0)
42 // #define UnSimulate16 MAKELONG(EMULATOR_BOP, BOP_UNSIMULATE) // BOP(BOP_UNSIMULATE)
43
44 #define CALL16_TRAMPOLINE_SIZE (1 * sizeof(ULONGLONG))
45 #define INT16_TRAMPOLINE_SIZE (1 * sizeof(ULONGLONG))
46
47 //
48 // WARNING WARNING!!
49 //
50 // If you modify the code stubs here, think also
51 // about updating them in int32.c too!!
52 //
53
54 /* 16-bit generic interrupt code for calling a 32-bit interrupt handler */
55 BYTE Int16To32[] =
56 {
57 0xFA, // cli
58
59 /* Push the value of the interrupt to be called */
60 0x6A, 0xFF, // push i (patchable to 0x6A, 0xIntNum)
61
62 /* The BOP Sequence */
63 // BOP_SEQ:
64 0xF8, // clc
65 BOP(BOP_CONTROL), // Control BOP
66 BOP_CONTROL_INT32, // 32-bit Interrupt dispatcher
67
68 0x73, 0x04, // jnc EXIT (offset +4)
69
70 0xFB, // sti
71
72 // HACK: The following instruction should be HLT!
73 0x90, // nop
74
75 0xEB, 0xF5, // jmp BOP_SEQ (offset -11)
76
77 // EXIT:
78 // 0x44, 0x44, // inc sp, inc sp
79 0x83, 0xC4, 0x02, // add sp, 2
80 0xCF, // iret
81 };
82
83 /* PUBLIC FUNCTIONS ***********************************************************/
84
85 VOID
86 InitializeContext(IN PCALLBACK16 Context,
87 IN USHORT Segment,
88 IN USHORT Offset)
89 {
90 Context->TrampolineFarPtr = MAKELONG(Offset, Segment);
91 Context->Segment = Segment;
92 Context->NextOffset = Offset + max(CALL16_TRAMPOLINE_SIZE,
93 INT16_TRAMPOLINE_SIZE);
94 }
95
96 VOID
97 Call16(IN USHORT Segment,
98 IN USHORT Offset)
99 {
100 /* Save CS:IP */
101 USHORT OrgCS = getCS();
102 USHORT OrgIP = getIP();
103
104 /* Set the new CS:IP */
105 setCS(Segment);
106 setIP(Offset);
107
108 DPRINT("Call16(%04X:%04X)\n", Segment, Offset);
109
110 /* Start CPU simulation */
111 EmulatorSimulate();
112
113 /* Restore CS:IP */
114 setCS(OrgCS);
115 setIP(OrgIP);
116 }
117
118
119
120 ULONG
121 RegisterCallback16(IN ULONG FarPtr,
122 IN LPBYTE CallbackCode,
123 IN SIZE_T CallbackSize,
124 OUT PSIZE_T CodeSize OPTIONAL)
125 {
126 LPBYTE CodeStart = (LPBYTE)FAR_POINTER(FarPtr);
127 LPBYTE Code = CodeStart;
128
129 SIZE_T OurCodeSize = CallbackSize;
130
131 if (CallbackCode == NULL) CallbackSize = 0;
132
133 if (CallbackCode)
134 {
135 /* 16-bit interrupt code */
136 RtlCopyMemory(Code, CallbackCode, CallbackSize);
137 Code += CallbackSize;
138 }
139
140 /* Return the real size of the code if needed */
141 if (CodeSize) *CodeSize = OurCodeSize; // == (ULONG_PTR)Code - (ULONG_PTR)CodeStart;
142
143 // /* Return the entry-point address for 32-bit calls */
144 // return (ULONG_PTR)(CodeStart + CallbackSize);
145 return OurCodeSize;
146 }
147
148 VOID
149 RunCallback16(IN PCALLBACK16 Context,
150 IN ULONG FarPtr)
151 {
152 PUCHAR TrampolineBase = (PUCHAR)FAR_POINTER(Context->TrampolineFarPtr);
153 PUCHAR Trampoline = TrampolineBase;
154 UCHAR OldTrampoline[CALL16_TRAMPOLINE_SIZE];
155
156 /* Save the old trampoline */
157 ((PULONGLONG)&OldTrampoline)[0] = ((PULONGLONG)TrampolineBase)[0];
158
159 DPRINT1("RunCallback16(0x%p)\n", FarPtr);
160
161 /* Build the generic entry-point for 16-bit far calls */
162 *Trampoline++ = 0x9A; // Call far seg:off
163 *(PULONG)Trampoline = FarPtr;
164 Trampoline += sizeof(ULONG);
165 UnSimulate16(Trampoline);
166
167 /* Perform the call */
168 Call16(HIWORD(Context->TrampolineFarPtr),
169 LOWORD(Context->TrampolineFarPtr));
170
171 /* Restore the old trampoline */
172 ((PULONGLONG)TrampolineBase)[0] = ((PULONGLONG)&OldTrampoline)[0];
173 }
174
175
176
177 ULONG
178 RegisterInt16(IN ULONG FarPtr,
179 IN BYTE IntNumber,
180 IN LPBYTE CallbackCode,
181 IN SIZE_T CallbackSize,
182 OUT PSIZE_T CodeSize OPTIONAL)
183 {
184 /* Get a pointer to the IVT and set the corresponding entry (far pointer) */
185 LPDWORD IntVecTable = (LPDWORD)SEG_OFF_TO_PTR(0x0000, 0x0000);
186 IntVecTable[IntNumber] = FarPtr;
187
188 /* Register the 16-bit callback */
189 return RegisterCallback16(FarPtr,
190 CallbackCode,
191 CallbackSize,
192 CodeSize);
193 }
194
195 ULONG
196 RegisterInt32(IN ULONG FarPtr,
197 IN BYTE IntNumber,
198 IN EMULATOR_INT32_PROC IntHandler,
199 OUT PSIZE_T CodeSize OPTIONAL)
200 {
201 /* Array for holding our copy of the 16-bit interrupt callback */
202 BYTE IntCallback[sizeof(Int16To32)/sizeof(BYTE)];
203
204 /* Check whether the 32-bit interrupt was already registered */
205 // if (Int32Proc[IntNumber] != NULL)
206 // {
207 // DPRINT1("RegisterInt32: Interrupt 0x%X already registered!\n", IntNumber);
208 // return 0;
209 // }
210
211 /* Register the 32-bit interrupt handler */
212 Int32Proc[IntNumber] = IntHandler;
213
214 /* Copy the generic 16-bit interrupt callback and patch it */
215 RtlCopyMemory(IntCallback, Int16To32, sizeof(Int16To32));
216 IntCallback[2] = IntNumber;
217
218 /* Register the 16-bit interrupt callback */
219 return RegisterInt16(FarPtr,
220 IntNumber,
221 IntCallback,
222 sizeof(IntCallback),
223 CodeSize);
224 }
225
226 VOID
227 Int32Call(IN PCALLBACK16 Context,
228 IN BYTE IntNumber)
229 {
230 PUCHAR TrampolineBase = (PUCHAR)FAR_POINTER(Context->TrampolineFarPtr);
231 PUCHAR Trampoline = TrampolineBase;
232 UCHAR OldTrampoline[INT16_TRAMPOLINE_SIZE];
233
234 DPRINT("Int32Call(0x%X)\n", IntNumber);
235
236 /* Save the old trampoline */
237 ((PULONGLONG)&OldTrampoline)[0] = ((PULONGLONG)TrampolineBase)[0];
238
239 /* Build the generic entry-point for 16-bit calls */
240 if (IntNumber == 0x03)
241 {
242 /* We are redefining for INT 03h */
243 *Trampoline++ = 0xCC; // Call INT 03h
244 /** *Trampoline++ = 0x90; // nop **/
245 }
246 else
247 {
248 /* Normal interrupt */
249 *Trampoline++ = 0xCD; // Call INT XXh
250 *Trampoline++ = IntNumber;
251 }
252 UnSimulate16(Trampoline);
253
254 /* Perform the call */
255 Call16(HIWORD(Context->TrampolineFarPtr),
256 LOWORD(Context->TrampolineFarPtr));
257
258 /* Restore the old trampoline */
259 ((PULONGLONG)TrampolineBase)[0] = ((PULONGLONG)&OldTrampoline)[0];
260 }
261
262
263
264 VOID WINAPI Int32Dispatch(LPWORD Stack)
265 {
266 /* Get the interrupt number */
267 BYTE IntNum = LOBYTE(Stack[STACK_INT_NUM]);
268
269 /* Call the 32-bit Interrupt handler */
270 if (Int32Proc[IntNum] != NULL)
271 Int32Proc[IntNum](Stack);
272 else
273 DPRINT1("Unhandled 32-bit interrupt: 0x%02X, AX = 0x%04X\n", IntNum, getAX());
274 }
275
276 static VOID WINAPI ControlBop(LPWORD Stack)
277 {
278 /* Get the Function Number and skip it */
279 BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
280 setIP(getIP() + 1);
281
282 if (FuncNum == BOP_CONTROL_INT32)
283 Int32Dispatch(Stack);
284 else
285 // DPRINT1("Unassigned Control BOP Function: 0x%02X\n", FuncNum);
286 DisplayMessage(L"Unassigned Control BOP Function: 0x%02X\n", FuncNum);
287 }
288
289 VOID InitializeCallbacks(VOID)
290 {
291 /* Register the Control BOP */
292 RegisterBop(BOP_CONTROL, ControlBop);
293 }
294
295 /* EOF */