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