46556e2310c1e34229138ed4af24c1c5c651f2e3
[reactos.git] / reactos / lib / fast486 / common.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * common.c
4 *
5 * Copyright (C) 2014 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 #include <windef.h>
25
26 // #define NDEBUG
27 #include <debug.h>
28
29 #include <fast486.h>
30 #include "common.h"
31
32 /* PUBLIC FUNCTIONS ***********************************************************/
33
34 BOOLEAN
35 Fast486ReadMemory(PFAST486_STATE State,
36 FAST486_SEG_REGS SegmentReg,
37 ULONG Offset,
38 BOOLEAN InstFetch,
39 PVOID Buffer,
40 ULONG Size)
41 {
42 ULONG LinearAddress;
43 PFAST486_SEG_REG CachedDescriptor;
44
45 ASSERT(SegmentReg < FAST486_NUM_SEG_REGS);
46
47 /* Get the cached descriptor */
48 CachedDescriptor = &State->SegmentRegs[SegmentReg];
49
50 if ((Offset + Size - 1) > CachedDescriptor->Limit)
51 {
52 /* Read beyond limit */
53 Fast486Exception(State, FAST486_EXCEPTION_GP);
54 return FALSE;
55 }
56
57 /* Check for protected mode */
58 if (State->ControlRegisters[0] & FAST486_CR0_PE)
59 {
60 /* Privilege checks */
61
62 if (!CachedDescriptor->Present)
63 {
64 Fast486Exception(State, FAST486_EXCEPTION_NP);
65 return FALSE;
66 }
67
68 if ((!InstFetch && (CachedDescriptor->Rpl > CachedDescriptor->Dpl))
69 || (Fast486GetCurrentPrivLevel(State) > CachedDescriptor->Dpl))
70 {
71 Fast486Exception(State, FAST486_EXCEPTION_GP);
72 return FALSE;
73 }
74
75 if (InstFetch)
76 {
77 if (!CachedDescriptor->Executable)
78 {
79 /* Data segment not executable */
80 Fast486Exception(State, FAST486_EXCEPTION_GP);
81 return FALSE;
82 }
83 }
84 else
85 {
86 if (CachedDescriptor->Executable && (!CachedDescriptor->ReadWrite))
87 {
88 /* Code segment not readable */
89 Fast486Exception(State, FAST486_EXCEPTION_GP);
90 return FALSE;
91 }
92 }
93 }
94
95 /* Find the linear address */
96 LinearAddress = CachedDescriptor->Base + Offset;
97
98 /* Read from the linear address */
99 return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size);
100 }
101
102 BOOLEAN
103 Fast486WriteMemory(PFAST486_STATE State,
104 FAST486_SEG_REGS SegmentReg,
105 ULONG Offset,
106 PVOID Buffer,
107 ULONG Size)
108 {
109 ULONG LinearAddress;
110 PFAST486_SEG_REG CachedDescriptor;
111
112 ASSERT(SegmentReg < FAST486_NUM_SEG_REGS);
113
114 /* Get the cached descriptor */
115 CachedDescriptor = &State->SegmentRegs[SegmentReg];
116
117 if ((Offset + Size - 1) > CachedDescriptor->Limit)
118 {
119 /* Write beyond limit */
120 Fast486Exception(State, FAST486_EXCEPTION_GP);
121 return FALSE;
122 }
123
124 /* Check for protected mode */
125 if (State->ControlRegisters[0] & FAST486_CR0_PE)
126 {
127 /* Privilege checks */
128
129 if (!CachedDescriptor->Present)
130 {
131 Fast486Exception(State, FAST486_EXCEPTION_NP);
132 return FALSE;
133 }
134
135 if ((CachedDescriptor->Rpl > CachedDescriptor->Dpl)
136 || (Fast486GetCurrentPrivLevel(State) > CachedDescriptor->Dpl))
137 {
138 Fast486Exception(State, FAST486_EXCEPTION_GP);
139 return FALSE;
140 }
141
142 if (CachedDescriptor->Executable)
143 {
144 /* Code segment not writable */
145 Fast486Exception(State, FAST486_EXCEPTION_GP);
146 return FALSE;
147 }
148 else if (!CachedDescriptor->ReadWrite)
149 {
150 /* Data segment not writeable */
151 Fast486Exception(State, FAST486_EXCEPTION_GP);
152 return FALSE;
153 }
154 }
155
156 /* Find the linear address */
157 LinearAddress = CachedDescriptor->Base + Offset;
158
159 /* Write to the linear address */
160 return Fast486WriteLinearMemory(State, LinearAddress, Buffer, Size);
161 }
162
163 static inline BOOLEAN
164 FASTCALL
165 Fast486GetIntVector(PFAST486_STATE State,
166 UCHAR Number,
167 PFAST486_IDT_ENTRY IdtEntry)
168 {
169 ULONG FarPointer;
170
171 /* Check for protected mode */
172 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
173 {
174 /* Read from the IDT */
175 if (!Fast486ReadLinearMemory(State,
176 State->Idtr.Address
177 + Number * sizeof(*IdtEntry),
178 IdtEntry,
179 sizeof(*IdtEntry)))
180 {
181 /* Exception occurred */
182 return FALSE;
183 }
184 }
185 else
186 {
187 /* Read from the real-mode IVT */
188
189 /* Paging is always disabled in real mode */
190 State->MemReadCallback(State,
191 State->Idtr.Address
192 + Number * sizeof(FarPointer),
193 &FarPointer,
194 sizeof(FarPointer));
195
196 /* Fill a fake IDT entry */
197 IdtEntry->Offset = LOWORD(FarPointer);
198 IdtEntry->Selector = HIWORD(FarPointer);
199 IdtEntry->Zero = 0;
200 IdtEntry->Type = FAST486_IDT_INT_GATE;
201 IdtEntry->Storage = FALSE;
202 IdtEntry->Dpl = 0;
203 IdtEntry->Present = TRUE;
204 IdtEntry->OffsetHigh = 0;
205 }
206
207 return TRUE;
208 }
209
210 static inline BOOLEAN
211 FASTCALL
212 Fast486InterruptInternal(PFAST486_STATE State,
213 PFAST486_IDT_ENTRY IdtEntry)
214 {
215 USHORT SegmentSelector = IdtEntry->Selector;
216 ULONG Offset = MAKELONG(IdtEntry->Offset, IdtEntry->OffsetHigh);
217 ULONG GateType = IdtEntry->Type;
218
219 BOOLEAN GateSize = (GateType == FAST486_IDT_INT_GATE_32)
220 || (GateType == FAST486_IDT_TRAP_GATE_32);
221 BOOLEAN Success = FALSE;
222 ULONG OldPrefixFlags = State->PrefixFlags;
223
224 /* Check for protected mode */
225 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
226 {
227 FAST486_TSS Tss;
228 USHORT OldSs = State->SegmentRegs[FAST486_REG_SS].Selector;
229 ULONG OldEsp = State->GeneralRegs[FAST486_REG_ESP].Long;
230
231 if (GateSize != (State->SegmentRegs[FAST486_REG_CS].Size))
232 {
233 /*
234 * The gate size doesn't match the current operand size, so toggle
235 * the OPSIZE flag.
236 */
237 State->PrefixFlags ^= FAST486_PREFIX_OPSIZE;
238 }
239
240 /* Check if the interrupt handler is more privileged */
241 if (Fast486GetCurrentPrivLevel(State) > GET_SEGMENT_RPL(SegmentSelector))
242 {
243 /* Read the TSS */
244 if (!Fast486ReadLinearMemory(State,
245 State->TaskReg.Base,
246 &Tss,
247 sizeof(Tss)))
248 {
249 /* Exception occurred */
250 goto Cleanup;
251 }
252
253 /* Check the new (higher) privilege level */
254 switch (GET_SEGMENT_RPL(SegmentSelector))
255 {
256 case 0:
257 {
258 if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss0))
259 {
260 /* Exception occurred */
261 goto Cleanup;
262 }
263 State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp0;
264
265 break;
266 }
267
268 case 1:
269 {
270 if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss1))
271 {
272 /* Exception occurred */
273 goto Cleanup;
274 }
275 State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp1;
276
277 break;
278 }
279
280 case 2:
281 {
282 if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss2))
283 {
284 /* Exception occurred */
285 goto Cleanup;
286 }
287 State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp2;
288
289 break;
290 }
291
292 default:
293 {
294 /* Should never reach here! */
295 ASSERT(FALSE);
296 }
297 }
298
299 /* Push SS selector */
300 if (!Fast486StackPush(State, OldSs)) goto Cleanup;
301
302 /* Push stack pointer */
303 if (!Fast486StackPush(State, OldEsp)) goto Cleanup;
304 }
305 }
306 else
307 {
308 if (State->SegmentRegs[FAST486_REG_CS].Size)
309 {
310 /* Set OPSIZE, because INT always pushes 16-bit values in real mode */
311 State->PrefixFlags |= FAST486_PREFIX_OPSIZE;
312 }
313 }
314
315 /* Push EFLAGS */
316 if (!Fast486StackPush(State, State->Flags.Long)) goto Cleanup;
317
318 /* Push CS selector */
319 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector)) goto Cleanup;
320
321 /* Push the instruction pointer */
322 if (!Fast486StackPush(State, State->InstPtr.Long)) goto Cleanup;
323
324 if ((GateType == FAST486_IDT_INT_GATE) || (GateType == FAST486_IDT_INT_GATE_32))
325 {
326 /* Disable interrupts after a jump to an interrupt gate handler */
327 State->Flags.If = FALSE;
328 }
329
330 /* Load new CS */
331 if (!Fast486LoadSegment(State, FAST486_REG_CS, SegmentSelector))
332 {
333 /* An exception occurred during the jump */
334 goto Cleanup;
335 }
336
337 if (GateSize)
338 {
339 /* 32-bit code segment, use EIP */
340 State->InstPtr.Long = Offset;
341 }
342 else
343 {
344 /* 16-bit code segment, use IP */
345 State->InstPtr.LowWord = LOWORD(Offset);
346 }
347
348 Success = TRUE;
349
350 Cleanup:
351 /* Restore the prefix flags */
352 State->PrefixFlags = OldPrefixFlags;
353
354 return Success;
355 }
356
357 BOOLEAN
358 FASTCALL
359 Fast486PerformInterrupt(PFAST486_STATE State,
360 UCHAR Number)
361 {
362 FAST486_IDT_ENTRY IdtEntry;
363
364 /* Get the interrupt vector */
365 if (!Fast486GetIntVector(State, Number, &IdtEntry))
366 {
367 /* Exception occurred */
368 return FALSE;
369 }
370
371 /* Perform the interrupt */
372 if (!Fast486InterruptInternal(State, &IdtEntry))
373 {
374 /* Exception occurred */
375 return FALSE;
376 }
377
378 return TRUE;
379 }
380
381 VOID
382 FASTCALL
383 Fast486ExceptionWithErrorCode(PFAST486_STATE State,
384 FAST486_EXCEPTIONS ExceptionCode,
385 ULONG ErrorCode)
386 {
387 /* Increment the exception count */
388 State->ExceptionCount++;
389
390 /* Check if the exception occurred more than once */
391 if (State->ExceptionCount > 1)
392 {
393 /* Then this is a double fault */
394 ExceptionCode = FAST486_EXCEPTION_DF;
395 }
396
397 /* Check if this is a triple fault */
398 if (State->ExceptionCount == 3)
399 {
400 DPRINT("Fast486ExceptionWithErrorCode(%04X:%08X) -- Triple fault\n",
401 State->SegmentRegs[FAST486_REG_CS].Selector,
402 State->InstPtr.Long);
403
404 /* Reset the CPU */
405 Fast486Reset(State);
406 return;
407 }
408
409 /* Restore the IP to the saved IP */
410 State->InstPtr = State->SavedInstPtr;
411
412 /* Perform the interrupt */
413 if (!Fast486PerformInterrupt(State, ExceptionCode))
414 {
415 /*
416 * If this function failed, that means Fast486Exception
417 * was called again, so just return in this case.
418 */
419 return;
420 }
421
422 if (EXCEPTION_HAS_ERROR_CODE(ExceptionCode)
423 && (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE))
424 {
425 /* Push the error code */
426 if (!Fast486StackPush(State, ErrorCode))
427 {
428 /*
429 * If this function failed, that means Fast486Exception
430 * was called again, so just return in this case.
431 */
432 return;
433 }
434 }
435
436 /* Reset the exception count */
437 State->ExceptionCount = 0;
438 }
439
440 /* EOF */