[NTVDM]
[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 "bop.h"
18 #include "bios.h"
19 #include "registers.h"
20
21 /* PRIVATE VARIABLES **********************************************************/
22
23 LPCWSTR ExceptionName[] =
24 {
25 L"Division By Zero",
26 L"Debug",
27 L"Unexpected Error",
28 L"Breakpoint",
29 L"Integer Overflow",
30 L"Bound Range Exceeded",
31 L"Invalid Opcode",
32 L"FPU Not Available"
33 };
34
35 /*
36 * This is the list of registered 32-bit Interrupt handlers.
37 */
38 EMULATOR_INT32_PROC Int32Proc[EMULATOR_MAX_INT32_NUM] = { NULL };
39
40 /* BOP Identifiers */
41 #define BOP_CONTROL 0xFF // Control BOP Handler
42 #define BOP_CONTROL_DEFFUNC 0x00 // Default Control BOP Function
43
44 /* 32-bit Interrupt dispatcher function code for the Control BOP Handler */
45 #define BOP_CONTROL_INT32 0xFF
46
47 /* PUBLIC FUNCTIONS ***********************************************************/
48
49 VOID WINAPI Exception(BYTE ExceptionNumber, LPWORD Stack)
50 {
51 WORD CodeSegment, InstructionPointer;
52 PBYTE Opcode;
53
54 ASSERT(ExceptionNumber < 8);
55
56 /* Get the CS:IP */
57 InstructionPointer = Stack[STACK_IP];
58 CodeSegment = Stack[STACK_CS];
59 Opcode = (PBYTE)SEG_OFF_TO_PTR(CodeSegment, InstructionPointer);
60
61 /* Display a message to the user */
62 DisplayMessage(L"Exception: %s occured at %04X:%04X\n"
63 L"Opcode: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
64 ExceptionName[ExceptionNumber],
65 CodeSegment,
66 InstructionPointer,
67 Opcode[0],
68 Opcode[1],
69 Opcode[2],
70 Opcode[3],
71 Opcode[4],
72 Opcode[5],
73 Opcode[6],
74 Opcode[7],
75 Opcode[8],
76 Opcode[9]);
77
78 /* Stop the VDM */
79 VdmRunning = FALSE;
80 return;
81 }
82
83 #if 0
84 VOID WINAPI IrqDispatch(BYTE IrqNumber, LPWORD Stack)
85 {
86 /* Check if this was an PIC IRQ */
87 if (IntNum >= BIOS_PIC_MASTER_INT && IntNum < BIOS_PIC_MASTER_INT + 8)
88 {
89 /* It was an IRQ from the master PIC */
90 BiosHandleIrq(IntNum - BIOS_PIC_MASTER_INT, Stack);
91 }
92 else if (IntNum >= BIOS_PIC_SLAVE_INT && IntNum < BIOS_PIC_SLAVE_INT + 8)
93 {
94 /* It was an IRQ from the slave PIC */
95 BiosHandleIrq(IntNum - BIOS_PIC_SLAVE_INT + 8, Stack);
96 }
97
98 return;
99 }
100 #endif
101
102 VOID WINAPI Int32Dispatch(LPWORD Stack)
103 {
104 BYTE IntNum;
105
106 /* Get the interrupt number */
107 IntNum = LOBYTE(Stack[STACK_INT_NUM]);
108
109 /* Check if this was an exception */
110 if (IntNum < 8)
111 {
112 Exception(IntNum, Stack);
113 return;
114 }
115
116 /* Check if this was an PIC IRQ */
117 if (IntNum >= BIOS_PIC_MASTER_INT && IntNum < BIOS_PIC_MASTER_INT + 8)
118 {
119 /* It was an IRQ from the master PIC */
120 BiosHandleIrq(IntNum - BIOS_PIC_MASTER_INT, Stack);
121 return;
122 }
123 else if (IntNum >= BIOS_PIC_SLAVE_INT && IntNum < BIOS_PIC_SLAVE_INT + 8)
124 {
125 /* It was an IRQ from the slave PIC */
126 BiosHandleIrq(IntNum - BIOS_PIC_SLAVE_INT + 8, Stack);
127 return;
128 }
129
130 /* Call the 32-bit Interrupt handler */
131 if (Int32Proc[IntNum] != NULL)
132 Int32Proc[IntNum](Stack);
133 else
134 DPRINT("Unhandled 32-bit interrupt: 0x%02X, AX = 0x%04X\n", IntNum, getAX());
135 }
136
137 VOID WINAPI ControlBop(LPWORD Stack)
138 {
139 /* Get the Function Number and skip it */
140 BYTE FuncNum = *(PBYTE)SEG_OFF_TO_PTR(getCS(), getIP());
141 setIP(getIP() + 1);
142
143 if (FuncNum == BOP_CONTROL_INT32)
144 Int32Dispatch(Stack);
145 else
146 DPRINT("Unassigned Control BOP Function: 0x%02X\n", FuncNum);
147 }
148
149 VOID InitializeInt32(WORD BiosSegment)
150 {
151 LPDWORD IntVecTable = (LPDWORD)BaseAddress;
152 LPBYTE BiosCode = (LPBYTE)SEG_OFF_TO_PTR(BiosSegment, 0);
153 USHORT i;
154 WORD BopSeqOffset, Offset = 0;
155
156 /* Generate ISR stubs and fill the IVT */
157 for (i = 0x00; i <= 0xFF; i++)
158 {
159 Offset = INT_HANDLER_OFFSET + (i << 4);
160 IntVecTable[i] = MAKELONG(Offset, BiosSegment);
161
162 BiosCode[Offset++] = 0xFA; // cli
163
164 BiosCode[Offset++] = 0x6A; // push i
165 BiosCode[Offset++] = (UCHAR)i;
166
167 BiosCode[Offset++] = 0x6A; // push 0
168 BiosCode[Offset++] = 0x00;
169
170 BopSeqOffset = COMMON_STUB_OFFSET - (Offset + 3);
171
172 BiosCode[Offset++] = 0xE9; // jmp near BOP_SEQ
173 BiosCode[Offset++] = LOBYTE(BopSeqOffset);
174 BiosCode[Offset++] = HIBYTE(BopSeqOffset);
175 }
176
177 /* Write the common stub code */
178 Offset = COMMON_STUB_OFFSET;
179
180 // BOP_SEQ:
181 BiosCode[Offset++] = 0xF8; // clc
182
183 BiosCode[Offset++] = LOBYTE(EMULATOR_BOP); // BOP sequence
184 BiosCode[Offset++] = HIBYTE(EMULATOR_BOP);
185 BiosCode[Offset++] = BOP_CONTROL; // Control BOP
186 BiosCode[Offset++] = BOP_CONTROL_INT32; // 32-bit Interrupt dispatcher
187
188 BiosCode[Offset++] = 0x73; // jnc EXIT (offset +4)
189 BiosCode[Offset++] = 0x04;
190
191 BiosCode[Offset++] = 0xFB; // sti
192
193 // HACK: The following instruction should be HLT!
194 BiosCode[Offset++] = 0x90; // nop
195
196 BiosCode[Offset++] = 0xEB; // jmp BOP_SEQ (offset -11)
197 BiosCode[Offset++] = 0xF5;
198
199 // EXIT:
200 BiosCode[Offset++] = 0x83; // add sp, 4
201 BiosCode[Offset++] = 0xC4;
202 BiosCode[Offset++] = 0x04;
203
204 BiosCode[Offset++] = 0xCF; // iret
205
206 /* Register the Control BOP */
207 RegisterBop(BOP_CONTROL, ControlBop);
208 }
209
210 VOID RegisterInt32(BYTE IntNumber, EMULATOR_INT32_PROC IntHandler)
211 {
212 Int32Proc[IntNumber] = IntHandler;
213 }
214
215 /* EOF */