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