2 * Fast486 386/486 CPU Emulation Library
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
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.
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.
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.
22 /* INCLUDES *******************************************************************/
32 /* PUBLIC FUNCTIONS ***********************************************************/
35 Fast486ReadMemory(PFAST486_STATE State
,
36 FAST486_SEG_REGS SegmentReg
,
43 PFAST486_SEG_REG CachedDescriptor
;
45 ASSERT(SegmentReg
< FAST486_NUM_SEG_REGS
);
47 /* Get the cached descriptor */
48 CachedDescriptor
= &State
->SegmentRegs
[SegmentReg
];
50 if ((Offset
+ Size
- 1) > CachedDescriptor
->Limit
)
52 /* Read beyond limit */
53 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
57 /* Check for protected mode */
58 if (State
->ControlRegisters
[0] & FAST486_CR0_PE
)
60 /* Privilege checks */
62 if (!CachedDescriptor
->Present
)
64 Fast486Exception(State
, FAST486_EXCEPTION_NP
);
68 if (GET_SEGMENT_RPL(CachedDescriptor
->Selector
) > CachedDescriptor
->Dpl
)
70 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
76 if (!CachedDescriptor
->Executable
)
78 /* Data segment not executable */
79 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
85 if (CachedDescriptor
->Executable
&& (!CachedDescriptor
->ReadWrite
))
87 /* Code segment not readable */
88 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
94 /* Find the linear address */
95 LinearAddress
= CachedDescriptor
->Base
+ Offset
;
97 /* Read from the linear address */
98 return Fast486ReadLinearMemory(State
, LinearAddress
, Buffer
, Size
);
102 Fast486WriteMemory(PFAST486_STATE State
,
103 FAST486_SEG_REGS SegmentReg
,
109 PFAST486_SEG_REG CachedDescriptor
;
111 ASSERT(SegmentReg
< FAST486_NUM_SEG_REGS
);
113 /* Get the cached descriptor */
114 CachedDescriptor
= &State
->SegmentRegs
[SegmentReg
];
116 if ((Offset
+ Size
- 1) > CachedDescriptor
->Limit
)
118 /* Write beyond limit */
119 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
124 /* Check for protected mode */
125 if (State
->ControlRegisters
[0] & FAST486_CR0_PE
)
127 /* Privilege checks */
129 if (!CachedDescriptor
->Present
)
131 Fast486Exception(State
, FAST486_EXCEPTION_NP
);
135 if (GET_SEGMENT_RPL(CachedDescriptor
->Selector
) > CachedDescriptor
->Dpl
)
137 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
141 if (CachedDescriptor
->Executable
)
143 /* Code segment not writable */
144 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
147 else if (!CachedDescriptor
->ReadWrite
)
149 /* Data segment not writeable */
150 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
155 /* Find the linear address */
156 LinearAddress
= CachedDescriptor
->Base
+ Offset
;
158 /* Write to the linear address */
159 return Fast486WriteLinearMemory(State
, LinearAddress
, Buffer
, Size
);
163 Fast486InterruptInternal(PFAST486_STATE State
,
164 USHORT SegmentSelector
,
166 BOOLEAN InterruptGate
)
168 /* Check for protected mode */
169 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
172 USHORT OldSs
= State
->SegmentRegs
[FAST486_REG_SS
].Selector
;
173 ULONG OldEsp
= State
->GeneralRegs
[FAST486_REG_ESP
].Long
;
175 /* Check if the interrupt handler is more privileged */
176 if (Fast486GetCurrentPrivLevel(State
) > GET_SEGMENT_RPL(SegmentSelector
))
179 if (!Fast486ReadLinearMemory(State
,
184 /* Exception occurred */
188 /* Check the new (higher) privilege level */
189 switch (GET_SEGMENT_RPL(SegmentSelector
))
193 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, Tss
.Ss0
))
195 /* Exception occurred */
198 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= Tss
.Esp0
;
205 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, Tss
.Ss1
))
207 /* Exception occurred */
210 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= Tss
.Esp1
;
217 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, Tss
.Ss2
))
219 /* Exception occurred */
222 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= Tss
.Esp2
;
229 /* Should never reach here! */
234 /* Push SS selector */
235 if (!Fast486StackPush(State
, OldSs
)) return FALSE
;
237 /* Push stack pointer */
238 if (!Fast486StackPush(State
, OldEsp
)) return FALSE
;
243 if (!Fast486StackPush(State
, State
->Flags
.Long
)) return FALSE
;
245 /* Push CS selector */
246 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_CS
].Selector
)) return FALSE
;
248 /* Push the instruction pointer */
249 if (!Fast486StackPush(State
, State
->InstPtr
.Long
)) return FALSE
;
253 /* Disable interrupts after a jump to an interrupt gate handler */
254 State
->Flags
.If
= FALSE
;
258 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, SegmentSelector
))
260 /* An exception occurred during the jump */
264 if (State
->SegmentRegs
[FAST486_REG_CS
].Size
)
266 /* 32-bit code segment, use EIP */
267 State
->InstPtr
.Long
= Offset
;
271 /* 16-bit code segment, use IP */
272 State
->InstPtr
.LowWord
= LOWORD(Offset
);
280 Fast486ExceptionWithErrorCode(PFAST486_STATE State
,
281 FAST486_EXCEPTIONS ExceptionCode
,
284 FAST486_IDT_ENTRY IdtEntry
;
286 /* Increment the exception count */
287 State
->ExceptionCount
++;
289 /* Check if the exception occurred more than once */
290 if (State
->ExceptionCount
> 1)
292 /* Then this is a double fault */
293 ExceptionCode
= FAST486_EXCEPTION_DF
;
296 /* Check if this is a triple fault */
297 if (State
->ExceptionCount
== 3)
304 /* Restore the IP to the saved IP */
305 State
->InstPtr
= State
->SavedInstPtr
;
307 if (!Fast486GetIntVector(State
, ExceptionCode
, &IdtEntry
))
310 * If this function failed, that means Fast486Exception
311 * was called again, so just return in this case.
316 /* Perform the interrupt */
317 if (!Fast486InterruptInternal(State
,
319 MAKELONG(IdtEntry
.Offset
, IdtEntry
.OffsetHigh
),
323 * If this function failed, that means Fast486Exception
324 * was called again, so just return in this case.
329 if (EXCEPTION_HAS_ERROR_CODE(ExceptionCode
)
330 && (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
))
332 /* Push the error code */
333 Fast486StackPush(State
, ErrorCode
);