[FAST486]
[reactos.git] / lib / fast486 / common.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * common.c
4 *
5 * Copyright (C) 2013 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 (GET_SEGMENT_RPL(CachedDescriptor->Selector) > CachedDescriptor->Dpl)
69 {
70 Fast486Exception(State, FAST486_EXCEPTION_GP);
71 return FALSE;
72 }
73
74 if (InstFetch)
75 {
76 if (!CachedDescriptor->Executable)
77 {
78 /* Data segment not executable */
79 Fast486Exception(State, FAST486_EXCEPTION_GP);
80 return FALSE;
81 }
82 }
83 else
84 {
85 if (CachedDescriptor->Executable && (!CachedDescriptor->ReadWrite))
86 {
87 /* Code segment not readable */
88 Fast486Exception(State, FAST486_EXCEPTION_GP);
89 return FALSE;
90 }
91 }
92 }
93
94 /* Find the linear address */
95 LinearAddress = CachedDescriptor->Base + Offset;
96
97 /* Read from the linear address */
98 return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size);
99 }
100
101 BOOLEAN
102 Fast486WriteMemory(PFAST486_STATE State,
103 FAST486_SEG_REGS SegmentReg,
104 ULONG Offset,
105 PVOID Buffer,
106 ULONG Size)
107 {
108 ULONG LinearAddress;
109 PFAST486_SEG_REG CachedDescriptor;
110
111 ASSERT(SegmentReg < FAST486_NUM_SEG_REGS);
112
113 /* Get the cached descriptor */
114 CachedDescriptor = &State->SegmentRegs[SegmentReg];
115
116 if ((Offset + Size - 1) > CachedDescriptor->Limit)
117 {
118 /* Write beyond limit */
119 Fast486Exception(State, FAST486_EXCEPTION_GP);
120
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 (GET_SEGMENT_RPL(CachedDescriptor->Selector) > CachedDescriptor->Dpl)
136 {
137 Fast486Exception(State, FAST486_EXCEPTION_GP);
138 return FALSE;
139 }
140
141 if (CachedDescriptor->Executable)
142 {
143 /* Code segment not writable */
144 Fast486Exception(State, FAST486_EXCEPTION_GP);
145 return FALSE;
146 }
147 else if (!CachedDescriptor->ReadWrite)
148 {
149 /* Data segment not writeable */
150 Fast486Exception(State, FAST486_EXCEPTION_GP);
151 return FALSE;
152 }
153 }
154
155 /* Find the linear address */
156 LinearAddress = CachedDescriptor->Base + Offset;
157
158 /* Write to the linear address */
159 return Fast486WriteLinearMemory(State, LinearAddress, Buffer, Size);
160 }
161
162 BOOLEAN
163 Fast486InterruptInternal(PFAST486_STATE State,
164 USHORT SegmentSelector,
165 ULONG Offset,
166 BOOLEAN InterruptGate)
167 {
168 /* Check for protected mode */
169 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
170 {
171 FAST486_TSS Tss;
172 USHORT OldSs = State->SegmentRegs[FAST486_REG_SS].Selector;
173 ULONG OldEsp = State->GeneralRegs[FAST486_REG_ESP].Long;
174
175 /* Check if the interrupt handler is more privileged */
176 if (Fast486GetCurrentPrivLevel(State) > GET_SEGMENT_RPL(SegmentSelector))
177 {
178 /* Read the TSS */
179 if (!Fast486ReadLinearMemory(State,
180 State->Tss.Address,
181 &Tss,
182 sizeof(Tss)))
183 {
184 /* Exception occurred */
185 return FALSE;
186 }
187
188 /* Check the new (higher) privilege level */
189 switch (GET_SEGMENT_RPL(SegmentSelector))
190 {
191 case 0:
192 {
193 if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss0))
194 {
195 /* Exception occurred */
196 return FALSE;
197 }
198 State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp0;
199
200 break;
201 }
202
203 case 1:
204 {
205 if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss1))
206 {
207 /* Exception occurred */
208 return FALSE;
209 }
210 State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp1;
211
212 break;
213 }
214
215 case 2:
216 {
217 if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss2))
218 {
219 /* Exception occurred */
220 return FALSE;
221 }
222 State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp2;
223
224 break;
225 }
226
227 default:
228 {
229 /* Should never reach here! */
230 ASSERT(FALSE);
231 }
232 }
233
234 /* Push SS selector */
235 if (!Fast486StackPush(State, OldSs)) return FALSE;
236
237 /* Push stack pointer */
238 if (!Fast486StackPush(State, OldEsp)) return FALSE;
239 }
240 }
241
242 /* Push EFLAGS */
243 if (!Fast486StackPush(State, State->Flags.Long)) return FALSE;
244
245 /* Push CS selector */
246 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector)) return FALSE;
247
248 /* Push the instruction pointer */
249 if (!Fast486StackPush(State, State->InstPtr.Long)) return FALSE;
250
251 if (InterruptGate)
252 {
253 /* Disable interrupts after a jump to an interrupt gate handler */
254 State->Flags.If = FALSE;
255 }
256
257 /* Load new CS */
258 if (!Fast486LoadSegment(State, FAST486_REG_CS, SegmentSelector))
259 {
260 /* An exception occurred during the jump */
261 return FALSE;
262 }
263
264 if (State->SegmentRegs[FAST486_REG_CS].Size)
265 {
266 /* 32-bit code segment, use EIP */
267 State->InstPtr.Long = Offset;
268 }
269 else
270 {
271 /* 16-bit code segment, use IP */
272 State->InstPtr.LowWord = LOWORD(Offset);
273 }
274
275 return TRUE;
276 }
277
278 VOID
279 FASTCALL
280 Fast486ExceptionWithErrorCode(PFAST486_STATE State,
281 FAST486_EXCEPTIONS ExceptionCode,
282 ULONG ErrorCode)
283 {
284 FAST486_IDT_ENTRY IdtEntry;
285
286 /* Increment the exception count */
287 State->ExceptionCount++;
288
289 /* Check if the exception occurred more than once */
290 if (State->ExceptionCount > 1)
291 {
292 /* Then this is a double fault */
293 ExceptionCode = FAST486_EXCEPTION_DF;
294 }
295
296 /* Check if this is a triple fault */
297 if (State->ExceptionCount == 3)
298 {
299 /* Reset the CPU */
300 Fast486Reset(State);
301 return;
302 }
303
304 /* Restore the IP to the saved IP */
305 State->InstPtr = State->SavedInstPtr;
306
307 if (!Fast486GetIntVector(State, ExceptionCode, &IdtEntry))
308 {
309 /*
310 * If this function failed, that means Fast486Exception
311 * was called again, so just return in this case.
312 */
313 return;
314 }
315
316 /* Perform the interrupt */
317 if (!Fast486InterruptInternal(State,
318 IdtEntry.Selector,
319 MAKELONG(IdtEntry.Offset, IdtEntry.OffsetHigh),
320 IdtEntry.Type))
321 {
322 /*
323 * If this function failed, that means Fast486Exception
324 * was called again, so just return in this case.
325 */
326 return;
327 }
328
329 if (EXCEPTION_HAS_ERROR_CODE(ExceptionCode)
330 && (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE))
331 {
332 /* Push the error code */
333 Fast486StackPush(State, ErrorCode);
334 }
335 }
336
337 /* EOF */