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