2 * Fast486 386/486 CPU Emulation Library
5 * Copyright (C) 2015 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 (InstFetch
|| !CachedDescriptor
->DirConf
)
52 if ((Offset
+ Size
- 1) > CachedDescriptor
->Limit
)
54 /* Read beyond limit */
55 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
61 if (Offset
< CachedDescriptor
->Limit
)
63 /* Read beyond limit */
64 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
69 /* Check for protected mode */
70 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
72 /* Privilege checks */
74 if (!CachedDescriptor
->Present
)
76 Fast486Exception(State
, FAST486_EXCEPTION_NP
);
80 if ((!InstFetch
&& (CachedDescriptor
->Rpl
> CachedDescriptor
->Dpl
))
81 || (Fast486GetCurrentPrivLevel(State
) > CachedDescriptor
->Dpl
))
83 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
89 if (!CachedDescriptor
->Executable
)
91 /* Data segment not executable */
92 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
98 if (CachedDescriptor
->Executable
&& (!CachedDescriptor
->ReadWrite
))
100 /* Code segment not readable */
101 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
107 /* Find the linear address */
108 LinearAddress
= CachedDescriptor
->Base
+ Offset
;
110 #ifndef FAST486_NO_PREFETCH
111 if (InstFetch
&& ((Offset
+ FAST486_CACHE_SIZE
- 1) <= CachedDescriptor
->Limit
))
113 State
->PrefetchAddress
= LinearAddress
;
115 if ((State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PG
)
116 && (PAGE_OFFSET(State
->PrefetchAddress
) > (FAST486_PAGE_SIZE
- FAST486_CACHE_SIZE
)))
118 /* We mustn't prefetch across a page boundary */
119 State
->PrefetchAddress
= PAGE_ALIGN(State
->PrefetchAddress
)
120 | (FAST486_PAGE_SIZE
- FAST486_CACHE_SIZE
);
122 if ((LinearAddress
- State
->PrefetchAddress
+ Size
) >= FAST486_CACHE_SIZE
)
124 /* We can't prefetch without possibly violating page permissions */
125 State
->PrefetchValid
= FALSE
;
126 return Fast486ReadLinearMemory(State
, LinearAddress
, Buffer
, Size
);
131 if (Fast486ReadLinearMemory(State
,
132 State
->PrefetchAddress
,
133 State
->PrefetchCache
,
136 State
->PrefetchValid
= TRUE
;
138 RtlMoveMemory(Buffer
,
139 &State
->PrefetchCache
[LinearAddress
- State
->PrefetchAddress
],
145 State
->PrefetchValid
= FALSE
;
152 /* Read from the linear address */
153 return Fast486ReadLinearMemory(State
, LinearAddress
, Buffer
, Size
);
158 Fast486WriteMemory(PFAST486_STATE State
,
159 FAST486_SEG_REGS SegmentReg
,
165 PFAST486_SEG_REG CachedDescriptor
;
167 ASSERT(SegmentReg
< FAST486_NUM_SEG_REGS
);
169 /* Get the cached descriptor */
170 CachedDescriptor
= &State
->SegmentRegs
[SegmentReg
];
172 if (!CachedDescriptor
->DirConf
)
174 if ((Offset
+ Size
- 1) > CachedDescriptor
->Limit
)
176 /* Write beyond limit */
177 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
183 if (Offset
< CachedDescriptor
->Limit
)
185 /* Read beyond limit */
186 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
191 /* Check for protected mode */
192 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
194 /* Privilege checks */
196 if (!CachedDescriptor
->Present
)
198 Fast486Exception(State
, FAST486_EXCEPTION_NP
);
202 if ((CachedDescriptor
->Rpl
> CachedDescriptor
->Dpl
)
203 || (Fast486GetCurrentPrivLevel(State
) > CachedDescriptor
->Dpl
))
205 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
209 if (CachedDescriptor
->Executable
)
211 /* Code segment not writable */
212 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
215 else if (!CachedDescriptor
->ReadWrite
)
217 /* Data segment not writeable */
218 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
223 /* Find the linear address */
224 LinearAddress
= CachedDescriptor
->Base
+ Offset
;
226 #ifndef FAST486_NO_PREFETCH
227 if (State
->PrefetchValid
228 && (LinearAddress
>= State
->PrefetchAddress
)
229 && ((LinearAddress
+ Size
) <= (State
->PrefetchAddress
+ FAST486_CACHE_SIZE
)))
231 /* Update the prefetch */
232 RtlMoveMemory(&State
->PrefetchCache
[LinearAddress
- State
->PrefetchAddress
],
234 min(Size
, FAST486_CACHE_SIZE
+ State
->PrefetchAddress
- LinearAddress
));
238 /* Write to the linear address */
239 return Fast486WriteLinearMemory(State
, LinearAddress
, Buffer
, Size
);
242 static inline BOOLEAN
244 Fast486GetIntVector(PFAST486_STATE State
,
246 PFAST486_IDT_ENTRY IdtEntry
)
248 /* Check for protected mode */
249 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
251 /* Read from the IDT */
252 if (!Fast486ReadLinearMemory(State
,
254 + Number
* sizeof(*IdtEntry
),
258 /* Exception occurred */
264 /* Read from the real-mode IVT */
267 /* Paging is always disabled in real mode */
268 State
->MemReadCallback(State
,
270 + Number
* sizeof(FarPointer
),
274 /* Fill a fake IDT entry */
275 IdtEntry
->Offset
= LOWORD(FarPointer
);
276 IdtEntry
->Selector
= HIWORD(FarPointer
);
278 IdtEntry
->Type
= FAST486_IDT_INT_GATE
;
279 IdtEntry
->Storage
= FALSE
;
281 IdtEntry
->Present
= TRUE
;
282 IdtEntry
->OffsetHigh
= 0;
288 static inline BOOLEAN
290 Fast486InterruptInternal(PFAST486_STATE State
,
291 PFAST486_IDT_ENTRY IdtEntry
,
292 BOOLEAN PushErrorCode
,
295 BOOLEAN GateSize
= (IdtEntry
->Type
== FAST486_IDT_INT_GATE_32
) ||
296 (IdtEntry
->Type
== FAST486_IDT_TRAP_GATE_32
);
297 USHORT OldCs
= State
->SegmentRegs
[FAST486_REG_CS
].Selector
;
298 ULONG OldEip
= State
->InstPtr
.Long
;
299 ULONG OldFlags
= State
->Flags
.Long
;
300 UCHAR OldCpl
= State
->Cpl
;
302 /* Check for protected mode */
303 if (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
)
305 USHORT OldSs
= State
->SegmentRegs
[FAST486_REG_SS
].Selector
;
306 ULONG OldEsp
= State
->GeneralRegs
[FAST486_REG_ESP
].Long
;
308 if (IdtEntry
->Type
== FAST486_TASK_GATE_SIGNATURE
)
311 return Fast486TaskSwitch(State
, FAST486_TASK_CALL
, IdtEntry
->Selector
);
314 /* Check if the interrupt handler is more privileged or if we're in V86 mode */
315 if ((OldCpl
> GET_SEGMENT_RPL(IdtEntry
->Selector
)) || State
->Flags
.Vm
)
320 if (!Fast486ReadLinearMemory(State
,
325 /* Exception occurred */
329 /* Switch to the new privilege level */
330 State
->Cpl
= GET_SEGMENT_RPL(IdtEntry
->Selector
);
332 /* Check the new (higher) privilege level */
337 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, Tss
.Ss0
))
339 /* Exception occurred */
342 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= Tss
.Esp0
;
349 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, Tss
.Ss1
))
351 /* Exception occurred */
354 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= Tss
.Esp1
;
361 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, Tss
.Ss2
))
363 /* Exception occurred */
366 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= Tss
.Esp2
;
373 /* Should never reach here! */
380 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, IdtEntry
->Selector
))
382 /* An exception occurred during the jump */
388 /* 32-bit code segment, use EIP */
389 State
->InstPtr
.Long
= MAKELONG(IdtEntry
->Offset
, IdtEntry
->OffsetHigh
);
393 /* 16-bit code segment, use IP */
394 State
->InstPtr
.LowWord
= IdtEntry
->Offset
;
397 /* Check if the interrupt handler is more privileged or we're in VM86 mode (again) */
398 if ((OldCpl
> GET_SEGMENT_RPL(IdtEntry
->Selector
)) || State
->Flags
.Vm
)
402 /* Clear the VM flag */
403 State
->Flags
.Vm
= FALSE
;
405 /* Push GS, FS, DS and ES */
406 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_GS
].Selector
)) return FALSE
;
407 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_FS
].Selector
)) return FALSE
;
408 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_DS
].Selector
)) return FALSE
;
409 if (!Fast486StackPush(State
, State
->SegmentRegs
[FAST486_REG_ES
].Selector
)) return FALSE
;
411 /* Now load them with NULL selectors, since they are useless in protected mode */
412 if (!Fast486LoadSegment(State
, FAST486_REG_GS
, 0)) return FALSE
;
413 if (!Fast486LoadSegment(State
, FAST486_REG_FS
, 0)) return FALSE
;
414 if (!Fast486LoadSegment(State
, FAST486_REG_DS
, 0)) return FALSE
;
415 if (!Fast486LoadSegment(State
, FAST486_REG_ES
, 0)) return FALSE
;
418 /* Push SS selector */
419 if (!Fast486StackPushInternal(State
, GateSize
, OldSs
)) return FALSE
;
421 /* Push the stack pointer */
422 if (!Fast486StackPushInternal(State
, GateSize
, OldEsp
)) return FALSE
;
428 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, IdtEntry
->Selector
))
430 /* An exception occurred during the jump */
435 State
->InstPtr
.LowWord
= IdtEntry
->Offset
;
439 if (!Fast486StackPushInternal(State
, GateSize
, OldFlags
)) return FALSE
;
441 /* Push CS selector */
442 if (!Fast486StackPushInternal(State
, GateSize
, OldCs
)) return FALSE
;
444 /* Push the instruction pointer */
445 if (!Fast486StackPushInternal(State
, GateSize
, OldEip
)) return FALSE
;
449 /* Push the error code */
450 if (!Fast486StackPushInternal(State
, GateSize
, ErrorCode
)) return FALSE
;
453 if ((IdtEntry
->Type
== FAST486_IDT_INT_GATE
)
454 || (IdtEntry
->Type
== FAST486_IDT_INT_GATE_32
))
456 /* Disable interrupts after a jump to an interrupt gate handler */
457 State
->Flags
.If
= FALSE
;
465 Fast486PerformInterrupt(PFAST486_STATE State
,
468 FAST486_IDT_ENTRY IdtEntry
;
470 /* Get the interrupt vector */
471 if (!Fast486GetIntVector(State
, Number
, &IdtEntry
))
473 /* Exception occurred */
477 /* Perform the interrupt */
478 if (!Fast486InterruptInternal(State
, &IdtEntry
, FALSE
, 0))
480 /* Exception occurred */
489 Fast486ExceptionWithErrorCode(PFAST486_STATE State
,
490 FAST486_EXCEPTIONS ExceptionCode
,
493 FAST486_IDT_ENTRY IdtEntry
;
495 /* Increment the exception count */
496 State
->ExceptionCount
++;
498 /* Check if the exception occurred more than once */
499 if (State
->ExceptionCount
> 1)
501 /* Then this is a double fault */
502 ExceptionCode
= FAST486_EXCEPTION_DF
;
505 /* Check if this is a triple fault */
506 if (State
->ExceptionCount
== 3)
508 DPRINT("Fast486ExceptionWithErrorCode(%04X:%08X) -- Triple fault\n",
509 State
->SegmentRegs
[FAST486_REG_CS
].Selector
,
510 State
->InstPtr
.Long
);
517 /* Clear the prefix flags */
518 State
->PrefixFlags
= 0;
520 /* Restore the IP to the saved IP */
521 State
->InstPtr
= State
->SavedInstPtr
;
523 /* Get the interrupt vector */
524 if (!Fast486GetIntVector(State
, ExceptionCode
, &IdtEntry
))
527 * If this function failed, that means Fast486Exception
528 * was called again, so just return in this case.
533 /* Perform the interrupt */
534 if (!Fast486InterruptInternal(State
,
536 EXCEPTION_HAS_ERROR_CODE(ExceptionCode
)
537 && (State
->ControlRegisters
[FAST486_REG_CR0
] & FAST486_CR0_PE
),
541 * If this function failed, that means Fast486Exception
542 * was called again, so just return in this case.
547 /* Reset the exception count */
548 State
->ExceptionCount
= 0;
553 Fast486TaskSwitch(PFAST486_STATE State
, FAST486_TASK_SWITCH_TYPE Type
, USHORT Selector
)
557 FAST486_SYSTEM_DESCRIPTOR NewTssDescriptor
;
559 PFAST486_LEGACY_TSS OldLegacyTss
= (PFAST486_LEGACY_TSS
)&OldTss
;
561 PFAST486_LEGACY_TSS NewLegacyTss
= (PFAST486_LEGACY_TSS
)&NewTss
;
562 USHORT NewLdtr
, NewEs
, NewCs
, NewSs
, NewDs
;
564 if (State
->TaskReg
.Limit
< sizeof(FAST486_TSS
)
565 && State
->TaskReg
.Limit
!= sizeof(FAST486_LEGACY_TSS
))
567 /* Invalid task register limit */
568 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_TS
, State
->TaskReg
.Selector
);
572 /* Read the old TSS */
573 if (!Fast486ReadLinearMemory(State
,
576 State
->TaskReg
.Limit
>= sizeof(FAST486_TSS
)
577 ? sizeof(FAST486_TSS
) : sizeof(FAST486_LEGACY_TSS
)))
579 /* Exception occurred */
584 /* If this is a task return, use the linked previous selector */
585 if (Type
== FAST486_TASK_RETURN
)
587 if (State
->TaskReg
.Limit
>= sizeof(FAST486_TSS
)) Selector
= LOWORD(OldTss
.Link
);
588 else Selector
= OldLegacyTss
->Link
;
591 /* Make sure the entry exists in the GDT (not LDT!) */
592 if ((GET_SEGMENT_INDEX(Selector
) == 0)
593 || (Selector
& SEGMENT_TABLE_INDICATOR
)
594 || GET_SEGMENT_INDEX(Selector
) >= (State
->Gdtr
.Size
+ 1u))
596 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_TS
, Selector
);
600 /* Get the TSS descriptor from the GDT */
601 if (!Fast486ReadLinearMemory(State
,
602 State
->Gdtr
.Address
+ GET_SEGMENT_INDEX(Selector
),
604 sizeof(NewTssDescriptor
)))
606 /* Exception occurred */
610 if (!NewTssDescriptor
.Present
)
612 /* Incoming task TSS not present */
613 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_NP
, Selector
);
617 /* Calculate the linear address of the new TSS */
618 NewTssAddress
= NewTssDescriptor
.Base
;
619 NewTssAddress
|= NewTssDescriptor
.BaseMid
<< 16;
620 NewTssAddress
|= NewTssDescriptor
.BaseHigh
<< 24;
622 /* Calculate the limit of the new TSS */
623 NewTssLimit
= NewTssDescriptor
.Limit
| (NewTssDescriptor
.LimitHigh
<< 16);
625 if (NewTssDescriptor
.Granularity
)
628 NewTssLimit
|= 0x00000FFF;
631 if (NewTssLimit
< sizeof(FAST486_TSS
) && NewTssLimit
!= sizeof(FAST486_LEGACY_TSS
))
633 /* TSS limit invalid */
634 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_TS
, Selector
);
639 * The incoming task shouldn't be busy if we're executing it as a
640 * new task, and it should be busy if we're returning to it.
642 if ((((NewTssDescriptor
.Signature
!= FAST486_TSS_SIGNATURE
)
643 && (NewTssDescriptor
.Signature
!= FAST486_TSS_16_SIGNATURE
))
644 || (Type
== FAST486_TASK_RETURN
))
645 && (((NewTssDescriptor
.Signature
!= FAST486_BUSY_TSS_SIGNATURE
)
646 && (NewTssDescriptor
.Signature
!= FAST486_BUSY_TSS_16_SIGNATURE
))
647 || (Type
!= FAST486_TASK_RETURN
)))
649 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Selector
);
653 /* Read the new TSS */
654 if (!Fast486ReadLinearMemory(State
,
657 NewTssLimit
>= sizeof(FAST486_TSS
)
658 ? sizeof(FAST486_TSS
) : sizeof(FAST486_LEGACY_TSS
)))
660 /* Exception occurred */
664 if (Type
!= FAST486_TASK_CALL
)
666 /* Clear the busy bit of the outgoing task */
667 FAST486_SYSTEM_DESCRIPTOR OldTssDescriptor
;
669 if (!Fast486ReadLinearMemory(State
,
671 + GET_SEGMENT_INDEX(State
->TaskReg
.Selector
),
673 sizeof(OldTssDescriptor
)))
675 /* Exception occurred */
679 OldTssDescriptor
.Signature
= FAST486_TSS_SIGNATURE
;
681 if (!Fast486WriteLinearMemory(State
,
683 + GET_SEGMENT_INDEX(State
->TaskReg
.Selector
),
685 sizeof(OldTssDescriptor
)))
687 /* Exception occurred */
694 if (NewTssLimit
>= sizeof(FAST486_TSS
)) NewTss
.Link
= State
->TaskReg
.Selector
;
695 else NewLegacyTss
->Link
= State
->TaskReg
.Selector
;
698 /* Save the current task into the TSS */
699 if (State
->TaskReg
.Limit
>= sizeof(FAST486_TSS
))
701 OldTss
.Cr3
= State
->ControlRegisters
[FAST486_REG_CR3
];
702 OldTss
.Eip
= State
->InstPtr
.Long
;
703 OldTss
.Eflags
= State
->Flags
.Long
;
704 OldTss
.Eax
= State
->GeneralRegs
[FAST486_REG_EAX
].Long
;
705 OldTss
.Ecx
= State
->GeneralRegs
[FAST486_REG_ECX
].Long
;
706 OldTss
.Edx
= State
->GeneralRegs
[FAST486_REG_EDX
].Long
;
707 OldTss
.Ebx
= State
->GeneralRegs
[FAST486_REG_EBX
].Long
;
708 OldTss
.Esp
= State
->GeneralRegs
[FAST486_REG_ESP
].Long
;
709 OldTss
.Ebp
= State
->GeneralRegs
[FAST486_REG_EBP
].Long
;
710 OldTss
.Esi
= State
->GeneralRegs
[FAST486_REG_ESI
].Long
;
711 OldTss
.Edi
= State
->GeneralRegs
[FAST486_REG_EDI
].Long
;
712 OldTss
.Es
= State
->SegmentRegs
[FAST486_REG_ES
].Selector
;
713 OldTss
.Cs
= State
->SegmentRegs
[FAST486_REG_CS
].Selector
;
714 OldTss
.Ss
= State
->SegmentRegs
[FAST486_REG_SS
].Selector
;
715 OldTss
.Ds
= State
->SegmentRegs
[FAST486_REG_DS
].Selector
;
716 OldTss
.Fs
= State
->SegmentRegs
[FAST486_REG_FS
].Selector
;
717 OldTss
.Gs
= State
->SegmentRegs
[FAST486_REG_GS
].Selector
;
718 OldTss
.Ldtr
= State
->Ldtr
.Selector
;
722 OldLegacyTss
->Ip
= State
->InstPtr
.LowWord
;
723 OldLegacyTss
->Flags
= State
->Flags
.LowWord
;
724 OldLegacyTss
->Ax
= State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
;
725 OldLegacyTss
->Cx
= State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
;
726 OldLegacyTss
->Dx
= State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
;
727 OldLegacyTss
->Bx
= State
->GeneralRegs
[FAST486_REG_EBX
].LowWord
;
728 OldLegacyTss
->Sp
= State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
;
729 OldLegacyTss
->Bp
= State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
;
730 OldLegacyTss
->Si
= State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
;
731 OldLegacyTss
->Di
= State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
;
732 OldLegacyTss
->Es
= State
->SegmentRegs
[FAST486_REG_ES
].Selector
;
733 OldLegacyTss
->Cs
= State
->SegmentRegs
[FAST486_REG_CS
].Selector
;
734 OldLegacyTss
->Ss
= State
->SegmentRegs
[FAST486_REG_SS
].Selector
;
735 OldLegacyTss
->Ds
= State
->SegmentRegs
[FAST486_REG_DS
].Selector
;
736 OldLegacyTss
->Ldtr
= State
->Ldtr
.Selector
;
739 /* Write back the old TSS */
740 if (!Fast486WriteLinearMemory(State
,
743 State
->TaskReg
.Limit
>= sizeof(FAST486_TSS
)
744 ? sizeof(FAST486_TSS
) : sizeof(FAST486_LEGACY_TSS
)))
746 /* Exception occurred */
750 /* Mark the new task as busy */
751 NewTssDescriptor
.Signature
= FAST486_BUSY_TSS_SIGNATURE
;
753 /* Write back the new TSS descriptor */
754 if (!Fast486WriteLinearMemory(State
,
755 State
->Gdtr
.Address
+ GET_SEGMENT_INDEX(Selector
),
757 sizeof(NewTssDescriptor
)))
759 /* Exception occurred */
763 /* Set the task switch bit */
764 State
->ControlRegisters
[FAST486_REG_CR0
] |= FAST486_CR0_TS
;
766 /* Load the task register with the new values */
767 State
->TaskReg
.Selector
= Selector
;
768 State
->TaskReg
.Base
= NewTssAddress
;
769 State
->TaskReg
.Limit
= NewTssLimit
;
771 if (NewTssLimit
>= sizeof(FAST486_TSS
))
773 /* Change the page directory */
774 State
->ControlRegisters
[FAST486_REG_CR3
] = NewTss
.Cr3
;
778 if (State
->Tlb
) RtlZeroMemory(State
->Tlb
, NUM_TLB_ENTRIES
* sizeof(ULONG
));
781 if (NewTssLimit
>= sizeof(FAST486_TSS
)) State
->Cpl
= GET_SEGMENT_RPL(NewTss
.Cs
);
782 else State
->Cpl
= GET_SEGMENT_RPL(NewLegacyTss
->Cs
);
784 #ifndef FAST486_NO_PREFETCH
785 /* Context switching invalidates the prefetch */
786 State
->PrefetchValid
= FALSE
;
789 /* Load the registers */
790 if (NewTssLimit
>= sizeof(FAST486_TSS
))
792 State
->InstPtr
.Long
= State
->SavedInstPtr
.Long
= NewTss
.Eip
;
793 State
->Flags
.Long
= NewTss
.Eflags
;
794 State
->GeneralRegs
[FAST486_REG_EAX
].Long
= NewTss
.Eax
;
795 State
->GeneralRegs
[FAST486_REG_ECX
].Long
= NewTss
.Ecx
;
796 State
->GeneralRegs
[FAST486_REG_EDX
].Long
= NewTss
.Edx
;
797 State
->GeneralRegs
[FAST486_REG_EBX
].Long
= NewTss
.Ebx
;
798 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= NewTss
.Esp
;
799 State
->GeneralRegs
[FAST486_REG_EBP
].Long
= NewTss
.Ebp
;
800 State
->GeneralRegs
[FAST486_REG_ESI
].Long
= NewTss
.Esi
;
801 State
->GeneralRegs
[FAST486_REG_EDI
].Long
= NewTss
.Edi
;
806 NewLdtr
= NewTss
.Ldtr
;
810 State
->InstPtr
.LowWord
= State
->SavedInstPtr
.LowWord
= NewLegacyTss
->Ip
;
811 State
->Flags
.LowWord
= NewLegacyTss
->Flags
;
812 State
->GeneralRegs
[FAST486_REG_EAX
].LowWord
= NewLegacyTss
->Ax
;
813 State
->GeneralRegs
[FAST486_REG_ECX
].LowWord
= NewLegacyTss
->Cx
;
814 State
->GeneralRegs
[FAST486_REG_EDX
].LowWord
= NewLegacyTss
->Dx
;
815 State
->GeneralRegs
[FAST486_REG_EBX
].LowWord
= NewLegacyTss
->Bx
;
816 State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
= NewLegacyTss
->Sp
;
817 State
->GeneralRegs
[FAST486_REG_EBP
].LowWord
= NewLegacyTss
->Bp
;
818 State
->GeneralRegs
[FAST486_REG_ESI
].LowWord
= NewLegacyTss
->Si
;
819 State
->GeneralRegs
[FAST486_REG_EDI
].LowWord
= NewLegacyTss
->Di
;
820 NewEs
= NewLegacyTss
->Es
;
821 NewCs
= NewLegacyTss
->Cs
;
822 NewSs
= NewLegacyTss
->Ss
;
823 NewDs
= NewLegacyTss
->Ds
;
824 NewLdtr
= NewLegacyTss
->Ldtr
;
827 /* Set the NT flag if nesting */
828 if (Type
== FAST486_TASK_CALL
) State
->Flags
.Nt
= TRUE
;
830 if (GET_SEGMENT_INDEX(NewLdtr
) != 0)
833 FAST486_SYSTEM_DESCRIPTOR GdtEntry
;
835 if (NewLdtr
& SEGMENT_TABLE_INDICATOR
)
837 /* This selector doesn't point to the GDT */
838 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_TS
, NewLdtr
);
842 if (!Fast486ReadDescriptorEntry(State
, NewLdtr
, &Valid
, (PFAST486_GDT_ENTRY
)&GdtEntry
))
844 /* Exception occurred */
850 /* Invalid selector */
851 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_TS
, NewLdtr
);
855 if (GdtEntry
.Signature
!= FAST486_LDT_SIGNATURE
)
857 /* This is not an LDT descriptor */
858 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_TS
, NewLdtr
);
862 if (!GdtEntry
.Present
)
864 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_TS
, NewLdtr
);
868 /* Update the LDTR */
869 State
->Ldtr
.Selector
= NewLdtr
;
870 State
->Ldtr
.Base
= GdtEntry
.Base
| (GdtEntry
.BaseMid
<< 16) | (GdtEntry
.BaseHigh
<< 24);
871 State
->Ldtr
.Limit
= GdtEntry
.Limit
| (GdtEntry
.LimitHigh
<< 16);
873 if (GdtEntry
.Granularity
)
875 State
->Ldtr
.Limit
<<= 12;
876 State
->Ldtr
.Limit
|= 0x00000FFF;
881 /* The LDT of this task is empty */
882 RtlZeroMemory(&State
->Ldtr
, sizeof(State
->Ldtr
));
885 /* Load the new segments */
886 if (!Fast486LoadSegmentInternal(State
, FAST486_REG_CS
, NewCs
, FAST486_EXCEPTION_TS
))
891 if (!Fast486LoadSegmentInternal(State
, FAST486_REG_SS
, NewSs
, FAST486_EXCEPTION_TS
))
896 if (!Fast486LoadSegmentInternal(State
, FAST486_REG_ES
, NewEs
, FAST486_EXCEPTION_TS
))
901 if (!Fast486LoadSegmentInternal(State
, FAST486_REG_DS
, NewDs
, FAST486_EXCEPTION_TS
))
906 if (NewTssLimit
>= sizeof(FAST486_TSS
))
908 if (!Fast486LoadSegmentInternal(State
,
911 FAST486_EXCEPTION_TS
))
916 if (!Fast486LoadSegmentInternal(State
,
919 FAST486_EXCEPTION_TS
))
930 Fast486CallGate(PFAST486_STATE State
,
931 PFAST486_CALL_GATE Gate
,
935 FAST486_GDT_ENTRY NewCodeSegment
;
936 BOOLEAN GateSize
= (Gate
->Type
== FAST486_CALL_GATE_SIGNATURE
);
938 USHORT OldCs
= State
->SegmentRegs
[FAST486_REG_CS
].Selector
;
939 ULONG OldEip
= State
->InstPtr
.Long
;
940 USHORT OldCpl
= State
->Cpl
;
941 USHORT OldSs
= State
->SegmentRegs
[FAST486_REG_SS
].Selector
;
942 ULONG OldEsp
= State
->GeneralRegs
[FAST486_REG_ESP
].Long
;
943 ULONG ParamBuffer
[32]; /* Maximum possible size - 32 DWORDs */
944 PULONG LongParams
= (PULONG
)ParamBuffer
;
945 PUSHORT ShortParams
= (PUSHORT
)ParamBuffer
;
949 /* The code segment is NULL */
950 Fast486Exception(State
, FAST486_EXCEPTION_GP
);
954 if (!Fast486ReadDescriptorEntry(State
, Gate
->Selector
, &Valid
, &NewCodeSegment
))
956 /* Exception occurred */
960 if (!Valid
|| (NewCodeSegment
.Dpl
> Fast486GetCurrentPrivLevel(State
)))
962 /* Code segment invalid */
963 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Gate
->Selector
);
967 if (Call
&& Gate
->ParamCount
)
969 /* Read the parameters */
970 if (!Fast486ReadMemory(State
,
975 Gate
->ParamCount
* sizeof(ULONG
)))
977 /* Exception occurred */
982 /* Check if the new code segment is more privileged */
983 if (NewCodeSegment
.Dpl
< OldCpl
)
988 if (!Fast486ReadLinearMemory(State
,
993 /* Exception occurred */
997 /* Switch to the new privilege level */
998 State
->Cpl
= NewCodeSegment
.Dpl
;
1000 /* Check the new (higher) privilege level */
1005 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, Tss
.Ss0
))
1007 /* Exception occurred */
1010 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= Tss
.Esp0
;
1017 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, Tss
.Ss1
))
1019 /* Exception occurred */
1022 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= Tss
.Esp1
;
1029 if (!Fast486LoadSegment(State
, FAST486_REG_SS
, Tss
.Ss2
))
1031 /* Exception occurred */
1034 State
->GeneralRegs
[FAST486_REG_ESP
].Long
= Tss
.Esp2
;
1041 /* Should never reach here! */
1046 else if (!NewCodeSegment
.DirConf
)
1048 /* This is not allowed for jumps */
1049 Fast486ExceptionWithErrorCode(State
, FAST486_EXCEPTION_GP
, Gate
->Selector
);
1055 if (!Fast486LoadSegment(State
, FAST486_REG_CS
, Gate
->Selector
))
1057 /* An exception occurred during the jump */
1061 /* Set the instruction pointer */
1062 if (GateSize
) State
->InstPtr
.Long
= MAKELONG(Gate
->Offset
, Gate
->OffsetHigh
);
1063 else State
->InstPtr
.Long
= Gate
->Offset
;
1069 /* Check if the new code segment is more privileged (again) */
1070 if (NewCodeSegment
.Dpl
< OldCpl
)
1072 /* Push SS selector */
1073 if (!Fast486StackPushInternal(State
, GateSize
, OldSs
)) return FALSE
;
1075 /* Push stack pointer */
1076 if (!Fast486StackPushInternal(State
, GateSize
, OldEsp
)) return FALSE
;
1079 /* Push the parameters in reverse order */
1080 for (i
= Gate
->ParamCount
- 1; i
>= 0; i
--)
1082 if (!Fast486StackPushInternal(State
,
1084 GateSize
? LongParams
[i
] : ShortParams
[i
]))
1086 /* Exception occurred */
1091 /* Push CS selector */
1092 if (!Fast486StackPushInternal(State
, GateSize
, OldCs
)) return FALSE
;
1094 /* Push the instruction pointer */
1095 if (!Fast486StackPushInternal(State
, GateSize
, OldEip
)) return FALSE
;