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