2caed1c17951e9f77bb319c00dc779d69d45bf4f
[reactos.git] / subsystems / ntvdm / emulator.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: emulator.c
5 * PURPOSE: Minimal x86 machine emulator for the VDM
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #define NDEBUG
12
13 #include "emulator.h"
14 #include "bios/bios.h"
15 #include "bop.h"
16 #include "vddsup.h"
17 #include "io.h"
18 #include "registers.h"
19 #include "hardware/vga.h"
20 #include "hardware/pic.h"
21
22 // HACK
23 typedef INT VDM_MODE;
24
25 /* PRIVATE VARIABLES **********************************************************/
26
27 FAST486_STATE EmulatorContext;
28
29 static BOOLEAN A20Line = FALSE;
30
31 /* BOP Identifiers */
32 #define BOP_DEBUGGER 0x56 // Break into the debugger from a 16-bit app
33
34 /* PRIVATE FUNCTIONS **********************************************************/
35
36 VOID WINAPI EmulatorReadMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
37 {
38 UNREFERENCED_PARAMETER(State);
39
40 /* If the A20 line is disabled, mask bit 20 */
41 if (!A20Line) Address &= ~(1 << 20);
42
43 /* Make sure the requested address is valid */
44 if ((Address + Size) >= MAX_ADDRESS) return;
45
46 /*
47 * Check if we are going to read the VGA memory and
48 * copy it into the virtual address space if needed.
49 */
50 if (((Address + Size) >= VgaGetVideoBaseAddress())
51 && (Address < VgaGetVideoLimitAddress()))
52 {
53 DWORD VgaAddress = max(Address, VgaGetVideoBaseAddress());
54 DWORD ActualSize = min(Address + Size - 1, VgaGetVideoLimitAddress())
55 - VgaAddress + 1;
56 LPBYTE DestBuffer = (LPBYTE)((ULONG_PTR)BaseAddress + VgaAddress);
57
58 /* Read from the VGA memory */
59 VgaReadMemory(VgaAddress, DestBuffer, ActualSize);
60 }
61
62 /* Read the data from the virtual address space and store it in the buffer */
63 RtlCopyMemory(Buffer, (LPVOID)((ULONG_PTR)BaseAddress + Address), Size);
64 }
65
66 VOID WINAPI EmulatorWriteMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
67 {
68 UNREFERENCED_PARAMETER(State);
69
70 /* If the A20 line is disabled, mask bit 20 */
71 if (!A20Line) Address &= ~(1 << 20);
72
73 /* Make sure the requested address is valid */
74 if ((Address + Size) >= MAX_ADDRESS) return;
75
76 /* Make sure we don't write to the ROM area */
77 if ((Address + Size) >= ROM_AREA_START && (Address < ROM_AREA_END)) return;
78
79 /* Read the data from the buffer and store it in the virtual address space */
80 RtlCopyMemory((LPVOID)((ULONG_PTR)BaseAddress + Address), Buffer, Size);
81
82 /*
83 * Check if we modified the VGA memory.
84 */
85 if (((Address + Size) >= VgaGetVideoBaseAddress())
86 && (Address < VgaGetVideoLimitAddress()))
87 {
88 DWORD VgaAddress = max(Address, VgaGetVideoBaseAddress());
89 DWORD ActualSize = min(Address + Size - 1, VgaGetVideoLimitAddress())
90 - VgaAddress + 1;
91 LPBYTE SrcBuffer = (LPBYTE)((ULONG_PTR)BaseAddress + VgaAddress);
92
93 /* Write to the VGA memory */
94 VgaWriteMemory(VgaAddress, SrcBuffer, ActualSize);
95 }
96 }
97
98 UCHAR WINAPI EmulatorIntAcknowledge(PFAST486_STATE State)
99 {
100 UNREFERENCED_PARAMETER(State);
101
102 /* Get the interrupt number from the PIC */
103 return PicGetInterrupt();
104 }
105
106 VOID WINAPI EmulatorDebugBreak(LPWORD Stack)
107 {
108 DPRINT1("NTVDM: BOP_DEBUGGER\n");
109 DebugBreak();
110 }
111
112 /* PUBLIC FUNCTIONS ***********************************************************/
113
114 BOOLEAN EmulatorInitialize(VOID)
115 {
116 /* Allocate memory for the 16-bit address space */
117 BaseAddress = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_ADDRESS);
118 if (BaseAddress == NULL) return FALSE;
119
120 /* Initialize the CPU */
121 Fast486Initialize(&EmulatorContext,
122 EmulatorReadMemory,
123 EmulatorWriteMemory,
124 EmulatorReadIo,
125 EmulatorWriteIo,
126 NULL,
127 EmulatorBiosOperation,
128 EmulatorIntAcknowledge,
129 NULL /* TODO: Use a TLB */);
130
131 /* Enable interrupts */
132 setIF(1);
133
134 /* Initialize VDD support */
135 VDDSupInitialize();
136
137 /* Register the DebugBreak BOP */
138 RegisterBop(BOP_DEBUGGER, EmulatorDebugBreak);
139
140 return TRUE;
141 }
142
143 VOID EmulatorCleanup(VOID)
144 {
145 /* Free the memory allocated for the 16-bit address space */
146 if (BaseAddress != NULL) HeapFree(GetProcessHeap(), 0, BaseAddress);
147 }
148
149 // FIXME: This function assumes 16-bit mode!!!
150 VOID EmulatorExecute(WORD Segment, WORD Offset)
151 {
152 /* Tell Fast486 to move the instruction pointer */
153 Fast486ExecuteAt(&EmulatorContext, Segment, Offset);
154 }
155
156 VOID EmulatorInterrupt(BYTE Number)
157 {
158 /* Call the Fast486 API */
159 Fast486Interrupt(&EmulatorContext, Number);
160 }
161
162 VOID EmulatorInterruptSignal(VOID)
163 {
164 /* Call the Fast486 API */
165 Fast486InterruptSignal(&EmulatorContext);
166 }
167
168 VOID EmulatorStep(VOID)
169 {
170 /* Dump the state for debugging purposes */
171 // Fast486DumpState(&EmulatorContext);
172
173 /* Execute the next instruction */
174 Fast486StepInto(&EmulatorContext);
175 }
176
177 VOID EmulatorSetA20(BOOLEAN Enabled)
178 {
179 A20Line = Enabled;
180 }
181
182
183
184 VOID
185 WINAPI
186 VDDTerminateVDM(VOID)
187 {
188 /* Stop the VDM */
189 VdmRunning = FALSE;
190 }
191
192 PBYTE
193 WINAPI
194 Sim32pGetVDMPointer(IN ULONG Address,
195 IN BOOLEAN ProtectedMode)
196 {
197 // FIXME
198 UNREFERENCED_PARAMETER(ProtectedMode);
199
200 /*
201 * HIWORD(Address) == Segment (if ProtectedMode == FALSE)
202 * or Selector (if ProtectedMode == TRUE )
203 * LOWORD(Address) == Offset
204 */
205 return (PBYTE)FAR_POINTER(Address);
206 }
207
208 PBYTE
209 WINAPI
210 MGetVdmPointer(IN ULONG Address,
211 IN ULONG Size,
212 IN BOOLEAN ProtectedMode)
213 {
214 UNREFERENCED_PARAMETER(Size);
215 return Sim32pGetVDMPointer(Address, ProtectedMode);
216 }
217
218 PVOID
219 WINAPI
220 VdmMapFlat(IN USHORT Segment,
221 IN ULONG Offset,
222 IN VDM_MODE Mode)
223 {
224 // FIXME
225 UNREFERENCED_PARAMETER(Mode);
226
227 return SEG_OFF_TO_PTR(Segment, Offset);
228 }
229
230 BOOL
231 WINAPI
232 VdmFlushCache(IN USHORT Segment,
233 IN ULONG Offset,
234 IN ULONG Size,
235 IN VDM_MODE Mode)
236 {
237 // FIXME
238 UNIMPLEMENTED;
239 return TRUE;
240 }
241
242 BOOL
243 WINAPI
244 VdmUnmapFlat(IN USHORT Segment,
245 IN ULONG Offset,
246 IN PVOID Buffer,
247 IN VDM_MODE Mode)
248 {
249 // FIXME
250 UNIMPLEMENTED;
251 return TRUE;
252 }
253
254 /* EOF */