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