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