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