4f39e6a62ce4d091e0b18d9e772f15032ebfcf58
[reactos.git] / reactos / lib / fast486 / common.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * common.c
4 *
5 * Copyright (C) 2015 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[FAST486_REG_CR0] & 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 #ifndef FAST486_NO_PREFETCH
99 if (InstFetch && ((Offset + FAST486_CACHE_SIZE - 1) <= CachedDescriptor->Limit))
100 {
101 State->PrefetchAddress = LinearAddress;
102
103 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
104 && (PAGE_OFFSET(State->PrefetchAddress) > (FAST486_PAGE_SIZE - FAST486_CACHE_SIZE)))
105 {
106 /* We mustn't prefetch across a page boundary */
107 State->PrefetchAddress = PAGE_ALIGN(State->PrefetchAddress)
108 | (FAST486_PAGE_SIZE - FAST486_CACHE_SIZE);
109
110 if ((LinearAddress - State->PrefetchAddress + Size) >= FAST486_CACHE_SIZE)
111 {
112 /* We can't prefetch without possibly violating page permissions */
113 State->PrefetchValid = FALSE;
114 return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size);
115 }
116 }
117
118 /* Prefetch */
119 if (Fast486ReadLinearMemory(State,
120 State->PrefetchAddress,
121 State->PrefetchCache,
122 FAST486_CACHE_SIZE))
123 {
124 State->PrefetchValid = TRUE;
125
126 RtlMoveMemory(Buffer,
127 &State->PrefetchCache[LinearAddress - State->PrefetchAddress],
128 Size);
129 return TRUE;
130 }
131 else
132 {
133 State->PrefetchValid = FALSE;
134 return FALSE;
135 }
136 }
137 else
138 #endif
139 {
140 /* Read from the linear address */
141 return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size);
142 }
143 }
144
145 BOOLEAN
146 Fast486WriteMemory(PFAST486_STATE State,
147 FAST486_SEG_REGS SegmentReg,
148 ULONG Offset,
149 PVOID Buffer,
150 ULONG Size)
151 {
152 ULONG LinearAddress;
153 PFAST486_SEG_REG CachedDescriptor;
154
155 ASSERT(SegmentReg < FAST486_NUM_SEG_REGS);
156
157 /* Get the cached descriptor */
158 CachedDescriptor = &State->SegmentRegs[SegmentReg];
159
160 if ((Offset + Size - 1) > CachedDescriptor->Limit)
161 {
162 /* Write beyond limit */
163 Fast486Exception(State, FAST486_EXCEPTION_GP);
164 return FALSE;
165 }
166
167 /* Check for protected mode */
168 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
169 {
170 /* Privilege checks */
171
172 if (!CachedDescriptor->Present)
173 {
174 Fast486Exception(State, FAST486_EXCEPTION_NP);
175 return FALSE;
176 }
177
178 if ((CachedDescriptor->Rpl > CachedDescriptor->Dpl)
179 || (Fast486GetCurrentPrivLevel(State) > CachedDescriptor->Dpl))
180 {
181 Fast486Exception(State, FAST486_EXCEPTION_GP);
182 return FALSE;
183 }
184
185 if (CachedDescriptor->Executable)
186 {
187 /* Code segment not writable */
188 Fast486Exception(State, FAST486_EXCEPTION_GP);
189 return FALSE;
190 }
191 else if (!CachedDescriptor->ReadWrite)
192 {
193 /* Data segment not writeable */
194 Fast486Exception(State, FAST486_EXCEPTION_GP);
195 return FALSE;
196 }
197 }
198
199 /* Find the linear address */
200 LinearAddress = CachedDescriptor->Base + Offset;
201
202 #ifndef FAST486_NO_PREFETCH
203 if (State->PrefetchValid
204 && (LinearAddress >= State->PrefetchAddress)
205 && ((LinearAddress + Size) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
206 {
207 /* Update the prefetch */
208 RtlMoveMemory(&State->PrefetchCache[LinearAddress - State->PrefetchAddress],
209 Buffer,
210 min(Size, FAST486_CACHE_SIZE + State->PrefetchAddress - LinearAddress));
211 }
212 #endif
213
214 /* Write to the linear address */
215 return Fast486WriteLinearMemory(State, LinearAddress, Buffer, Size);
216 }
217
218 static inline BOOLEAN
219 FASTCALL
220 Fast486GetIntVector(PFAST486_STATE State,
221 UCHAR Number,
222 PFAST486_IDT_ENTRY IdtEntry)
223 {
224 /* Check for protected mode */
225 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
226 {
227 /* Read from the IDT */
228 if (!Fast486ReadLinearMemory(State,
229 State->Idtr.Address
230 + Number * sizeof(*IdtEntry),
231 IdtEntry,
232 sizeof(*IdtEntry)))
233 {
234 /* Exception occurred */
235 return FALSE;
236 }
237 }
238 else
239 {
240 /* Read from the real-mode IVT */
241 ULONG FarPointer;
242
243 /* Paging is always disabled in real mode */
244 State->MemReadCallback(State,
245 State->Idtr.Address
246 + Number * sizeof(FarPointer),
247 &FarPointer,
248 sizeof(FarPointer));
249
250 /* Fill a fake IDT entry */
251 IdtEntry->Offset = LOWORD(FarPointer);
252 IdtEntry->Selector = HIWORD(FarPointer);
253 IdtEntry->Zero = 0;
254 IdtEntry->Type = FAST486_IDT_INT_GATE;
255 IdtEntry->Storage = FALSE;
256 IdtEntry->Dpl = 0;
257 IdtEntry->Present = TRUE;
258 IdtEntry->OffsetHigh = 0;
259 }
260
261 return TRUE;
262 }
263
264 static inline BOOLEAN
265 FASTCALL
266 Fast486InterruptInternal(PFAST486_STATE State,
267 PFAST486_IDT_ENTRY IdtEntry,
268 BOOLEAN PushErrorCode,
269 ULONG ErrorCode)
270 {
271 USHORT SegmentSelector = IdtEntry->Selector;
272 ULONG Offset = MAKELONG(IdtEntry->Offset, IdtEntry->OffsetHigh);
273 ULONG GateType = IdtEntry->Type;
274 BOOLEAN GateSize = (GateType == FAST486_IDT_INT_GATE_32) ||
275 (GateType == FAST486_IDT_TRAP_GATE_32);
276
277 BOOLEAN Success = FALSE;
278 ULONG OldPrefixFlags = State->PrefixFlags;
279
280 /* Check for protected mode */
281 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
282 {
283 FAST486_TSS Tss;
284 USHORT OldSs = State->SegmentRegs[FAST486_REG_SS].Selector;
285 ULONG OldEsp = State->GeneralRegs[FAST486_REG_ESP].Long;
286
287 if (GateType == FAST486_TASK_GATE_SIGNATURE)
288 {
289 /* Task call */
290 return Fast486TaskSwitch(State, FAST486_TASK_CALL, IdtEntry->Selector);
291 }
292
293 if (GateSize != (State->SegmentRegs[FAST486_REG_CS].Size))
294 {
295 /* The gate size doesn't match the current operand size, so set the OPSIZE flag. */
296 State->PrefixFlags |= FAST486_PREFIX_OPSIZE;
297 }
298
299 /* Check if the interrupt handler is more privileged or if we're in V86 mode */
300 if ((Fast486GetCurrentPrivLevel(State) > GET_SEGMENT_RPL(SegmentSelector))
301 || State->Flags.Vm)
302 {
303 /* Read the TSS */
304 if (!Fast486ReadLinearMemory(State,
305 State->TaskReg.Base,
306 &Tss,
307 sizeof(Tss)))
308 {
309 /* Exception occurred */
310 goto Cleanup;
311 }
312
313 /* Switch to the new privilege level */
314 State->Cpl = GET_SEGMENT_RPL(SegmentSelector);
315
316 if (State->Flags.Vm)
317 {
318 /* Clear the VM flag */
319 State->Flags.Vm = FALSE;
320
321 /* Push GS, FS, DS and ES */
322 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_GS].Selector)) goto Cleanup;
323 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_FS].Selector)) goto Cleanup;
324 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_DS].Selector)) goto Cleanup;
325 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_ES].Selector)) goto Cleanup;
326
327 /* Now load them with NULL selectors, since they are useless in protected mode */
328 if (!Fast486LoadSegment(State, FAST486_REG_GS, 0)) goto Cleanup;
329 if (!Fast486LoadSegment(State, FAST486_REG_FS, 0)) goto Cleanup;
330 if (!Fast486LoadSegment(State, FAST486_REG_DS, 0)) goto Cleanup;
331 if (!Fast486LoadSegment(State, FAST486_REG_ES, 0)) goto Cleanup;
332 }
333
334 /* Check the new (higher) privilege level */
335 switch (State->Cpl)
336 {
337 case 0:
338 {
339 if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss0))
340 {
341 /* Exception occurred */
342 goto Cleanup;
343 }
344 State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp0;
345
346 break;
347 }
348
349 case 1:
350 {
351 if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss1))
352 {
353 /* Exception occurred */
354 goto Cleanup;
355 }
356 State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp1;
357
358 break;
359 }
360
361 case 2:
362 {
363 if (!Fast486LoadSegment(State, FAST486_REG_SS, Tss.Ss2))
364 {
365 /* Exception occurred */
366 goto Cleanup;
367 }
368 State->GeneralRegs[FAST486_REG_ESP].Long = Tss.Esp2;
369
370 break;
371 }
372
373 default:
374 {
375 /* Should never reach here! */
376 ASSERT(FALSE);
377 }
378 }
379
380 /* Push SS selector */
381 if (!Fast486StackPush(State, OldSs)) goto Cleanup;
382
383 /* Push stack pointer */
384 if (!Fast486StackPush(State, OldEsp)) goto Cleanup;
385 }
386 }
387 else
388 {
389 if (State->SegmentRegs[FAST486_REG_CS].Size)
390 {
391 /* Set OPSIZE, because INT always pushes 16-bit values in real mode */
392 State->PrefixFlags |= FAST486_PREFIX_OPSIZE;
393 }
394 }
395
396 /* Push EFLAGS */
397 if (!Fast486StackPush(State, State->Flags.Long)) goto Cleanup;
398
399 /* Push CS selector */
400 if (!Fast486StackPush(State, State->SegmentRegs[FAST486_REG_CS].Selector)) goto Cleanup;
401
402 /* Push the instruction pointer */
403 if (!Fast486StackPush(State, State->InstPtr.Long)) goto Cleanup;
404
405 if (PushErrorCode)
406 {
407 /* Push the error code */
408 if (!Fast486StackPush(State, ErrorCode))
409 {
410 /* An exception occurred */
411 goto Cleanup;
412 }
413 }
414
415 if ((GateType == FAST486_IDT_INT_GATE) || (GateType == FAST486_IDT_INT_GATE_32))
416 {
417 /* Disable interrupts after a jump to an interrupt gate handler */
418 State->Flags.If = FALSE;
419 }
420
421 /* Load new CS */
422 if (!Fast486LoadSegment(State, FAST486_REG_CS, SegmentSelector))
423 {
424 /* An exception occurred during the jump */
425 goto Cleanup;
426 }
427
428 if (GateSize)
429 {
430 /* 32-bit code segment, use EIP */
431 State->InstPtr.Long = Offset;
432 }
433 else
434 {
435 /* 16-bit code segment, use IP */
436 State->InstPtr.LowWord = LOWORD(Offset);
437 }
438
439 Success = TRUE;
440
441 Cleanup:
442 /* Restore the prefix flags */
443 State->PrefixFlags = OldPrefixFlags;
444
445 return Success;
446 }
447
448 BOOLEAN
449 FASTCALL
450 Fast486PerformInterrupt(PFAST486_STATE State,
451 UCHAR Number)
452 {
453 FAST486_IDT_ENTRY IdtEntry;
454
455 /* Get the interrupt vector */
456 if (!Fast486GetIntVector(State, Number, &IdtEntry))
457 {
458 /* Exception occurred */
459 return FALSE;
460 }
461
462 /* Perform the interrupt */
463 if (!Fast486InterruptInternal(State, &IdtEntry, FALSE, 0))
464 {
465 /* Exception occurred */
466 return FALSE;
467 }
468
469 return TRUE;
470 }
471
472 VOID
473 FASTCALL
474 Fast486ExceptionWithErrorCode(PFAST486_STATE State,
475 FAST486_EXCEPTIONS ExceptionCode,
476 ULONG ErrorCode)
477 {
478 FAST486_IDT_ENTRY IdtEntry;
479
480 /* Increment the exception count */
481 State->ExceptionCount++;
482
483 /* Check if the exception occurred more than once */
484 if (State->ExceptionCount > 1)
485 {
486 /* Then this is a double fault */
487 ExceptionCode = FAST486_EXCEPTION_DF;
488 }
489
490 /* Check if this is a triple fault */
491 if (State->ExceptionCount == 3)
492 {
493 DPRINT("Fast486ExceptionWithErrorCode(%04X:%08X) -- Triple fault\n",
494 State->SegmentRegs[FAST486_REG_CS].Selector,
495 State->InstPtr.Long);
496
497 /* Reset the CPU */
498 Fast486Reset(State);
499 return;
500 }
501
502 /* Clear the prefix flags */
503 State->PrefixFlags = 0;
504
505 /* Restore the IP to the saved IP */
506 State->InstPtr = State->SavedInstPtr;
507
508 /* Get the interrupt vector */
509 if (!Fast486GetIntVector(State, ExceptionCode, &IdtEntry))
510 {
511 /*
512 * If this function failed, that means Fast486Exception
513 * was called again, so just return in this case.
514 */
515 return;
516 }
517
518 /* Perform the interrupt */
519 if (!Fast486InterruptInternal(State,
520 &IdtEntry,
521 EXCEPTION_HAS_ERROR_CODE(ExceptionCode)
522 && (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE),
523 ErrorCode))
524 {
525 /*
526 * If this function failed, that means Fast486Exception
527 * was called again, so just return in this case.
528 */
529 return;
530 }
531
532 /* Reset the exception count */
533 State->ExceptionCount = 0;
534 }
535
536 BOOLEAN
537 FASTCALL
538 Fast486TaskSwitch(PFAST486_STATE State, FAST486_TASK_SWITCH_TYPE Type, USHORT Selector)
539 {
540 ULONG NewTssAddress;
541 ULONG NewTssLimit;
542 FAST486_TSS OldTss;
543 FAST486_TSS NewTss;
544 FAST486_SYSTEM_DESCRIPTOR NewTssDescriptor;
545
546 /* Read the old TSS */
547 if (!Fast486ReadLinearMemory(State,
548 State->TaskReg.Base,
549 &OldTss,
550 sizeof(OldTss)))
551 {
552 /* Exception occurred */
553 return FALSE;
554 }
555
556 /* If this is a task return, use the linked previous selector */
557 if (Type == FAST486_TASK_RETURN) Selector = LOWORD(OldTss.Link);
558
559 /* Make sure the entry exists in the GDT (not LDT!) */
560 if ((GET_SEGMENT_INDEX(Selector) == 0)
561 || (Selector & SEGMENT_TABLE_INDICATOR)
562 || GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1u))
563 {
564 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, Selector);
565 return FALSE;
566 }
567
568 /* Get the TSS descriptor from the GDT */
569 if (!Fast486ReadLinearMemory(State,
570 State->Gdtr.Address + GET_SEGMENT_INDEX(Selector),
571 &NewTssDescriptor,
572 sizeof(NewTssDescriptor)))
573 {
574 /* Exception occurred */
575 return FALSE;
576 }
577
578 if (!NewTssDescriptor.Present)
579 {
580 /* Incoming task TSS not present */
581 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
582 return FALSE;
583 }
584
585 /* Calculate the linear address of the new TSS */
586 NewTssAddress = NewTssDescriptor.Base;
587 NewTssAddress |= NewTssDescriptor.BaseMid << 16;
588 NewTssAddress |= NewTssDescriptor.BaseHigh << 24;
589
590 /* Calculate the limit of the new TSS */
591 NewTssLimit = NewTssDescriptor.Limit | (NewTssDescriptor.LimitHigh << 16);
592
593 if (NewTssDescriptor.Granularity)
594 {
595 NewTssLimit <<= 12;
596 NewTssLimit |= 0x00000FFF;
597 }
598
599 if (NewTssLimit < sizeof(FAST486_TSS))
600 {
601 /* TSS limit too small */
602 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, Selector);
603 return FALSE;
604 }
605
606 /*
607 * The incoming task shouldn't be busy if we're executing it as a
608 * new task, and it should be busy if we're returning to it.
609 */
610 if (((NewTssDescriptor.Signature != FAST486_TSS_SIGNATURE)
611 || (Type == FAST486_TASK_RETURN))
612 && ((NewTssDescriptor.Signature != FAST486_BUSY_TSS_SIGNATURE)
613 || (Type != FAST486_TASK_RETURN)))
614 {
615 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
616 return FALSE;
617 }
618
619 /* Read the new TSS */
620 if (!Fast486ReadLinearMemory(State,
621 NewTssAddress,
622 &NewTss,
623 sizeof(NewTss)))
624 {
625 /* Exception occurred */
626 return FALSE;
627 }
628
629 if (Type != FAST486_TASK_CALL)
630 {
631 /* Clear the busy bit of the outgoing task */
632 FAST486_SYSTEM_DESCRIPTOR OldTssDescriptor;
633
634 if (!Fast486ReadLinearMemory(State,
635 State->Gdtr.Address
636 + GET_SEGMENT_INDEX(State->TaskReg.Selector),
637 &OldTssDescriptor,
638 sizeof(OldTssDescriptor)))
639 {
640 /* Exception occurred */
641 return FALSE;
642 }
643
644 OldTssDescriptor.Signature = FAST486_TSS_SIGNATURE;
645
646 if (!Fast486WriteLinearMemory(State,
647 State->Gdtr.Address
648 + GET_SEGMENT_INDEX(State->TaskReg.Selector),
649 &OldTssDescriptor,
650 sizeof(OldTssDescriptor)))
651 {
652 /* Exception occurred */
653 return FALSE;
654 }
655 }
656 else
657 {
658 /* Store the link */
659 NewTss.Link = State->TaskReg.Selector;
660 }
661
662 /* Save the current task into the TSS */
663 OldTss.Cr3 = State->ControlRegisters[FAST486_REG_CR3];
664 OldTss.Eip = State->InstPtr.Long;
665 OldTss.Eflags = State->Flags.Long;
666 OldTss.Eax = State->GeneralRegs[FAST486_REG_EAX].Long;
667 OldTss.Ecx = State->GeneralRegs[FAST486_REG_ECX].Long;
668 OldTss.Edx = State->GeneralRegs[FAST486_REG_EDX].Long;
669 OldTss.Ebx = State->GeneralRegs[FAST486_REG_EBX].Long;
670 OldTss.Esp = State->GeneralRegs[FAST486_REG_ESP].Long;
671 OldTss.Ebp = State->GeneralRegs[FAST486_REG_EBP].Long;
672 OldTss.Esi = State->GeneralRegs[FAST486_REG_ESI].Long;
673 OldTss.Edi = State->GeneralRegs[FAST486_REG_EDI].Long;
674 OldTss.Es = State->SegmentRegs[FAST486_REG_ES].Selector;
675 OldTss.Cs = State->SegmentRegs[FAST486_REG_CS].Selector;
676 OldTss.Ss = State->SegmentRegs[FAST486_REG_SS].Selector;
677 OldTss.Ds = State->SegmentRegs[FAST486_REG_DS].Selector;
678 OldTss.Fs = State->SegmentRegs[FAST486_REG_FS].Selector;
679 OldTss.Gs = State->SegmentRegs[FAST486_REG_GS].Selector;
680 OldTss.Ldtr = State->Ldtr.Selector;
681
682 /* Write back the old TSS */
683 if (!Fast486WriteLinearMemory(State,
684 State->TaskReg.Base,
685 &OldTss,
686 sizeof(OldTss)))
687 {
688 /* Exception occurred */
689 return FALSE;
690 }
691
692 /* Mark the new task as busy */
693 NewTssDescriptor.Signature = FAST486_BUSY_TSS_SIGNATURE;
694
695 /* Write back the new TSS descriptor */
696 if (!Fast486WriteLinearMemory(State,
697 State->Gdtr.Address + GET_SEGMENT_INDEX(Selector),
698 &NewTssDescriptor,
699 sizeof(NewTssDescriptor)))
700 {
701 /* Exception occurred */
702 return FALSE;
703 }
704
705 /* Set the task switch bit */
706 State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_TS;
707
708 /* Load the task register with the new values */
709 State->TaskReg.Selector = Selector;
710 State->TaskReg.Base = NewTssAddress;
711 State->TaskReg.Limit = NewTssLimit;
712
713 /* Change the page directory */
714 State->ControlRegisters[FAST486_REG_CR3] = NewTss.Cr3;
715
716 /* Flush the TLB */
717 if (State->Tlb) RtlZeroMemory(State->Tlb, NUM_TLB_ENTRIES * sizeof(ULONG));
718
719 /* Update the CPL */
720 State->Cpl = GET_SEGMENT_RPL(NewTss.Cs);
721
722 #ifndef FAST486_NO_PREFETCH
723 /* Context switching invalidates the prefetch */
724 State->PrefetchValid = FALSE;
725 #endif
726
727 /* Update the CPL */
728 State->Cpl = GET_SEGMENT_RPL(NewTss.Cs);
729
730 /* Load the registers */
731 State->InstPtr.Long = State->SavedInstPtr.Long = NewTss.Eip;
732 State->Flags.Long = NewTss.Eflags;
733 State->GeneralRegs[FAST486_REG_EAX].Long = NewTss.Eax;
734 State->GeneralRegs[FAST486_REG_ECX].Long = NewTss.Ecx;
735 State->GeneralRegs[FAST486_REG_EDX].Long = NewTss.Edx;
736 State->GeneralRegs[FAST486_REG_EBX].Long = NewTss.Ebx;
737 State->GeneralRegs[FAST486_REG_ESP].Long = NewTss.Esp;
738 State->GeneralRegs[FAST486_REG_EBP].Long = NewTss.Ebp;
739 State->GeneralRegs[FAST486_REG_ESI].Long = NewTss.Esi;
740 State->GeneralRegs[FAST486_REG_EDI].Long = NewTss.Edi;
741
742 /* Set the NT flag if nesting */
743 if (Type == FAST486_TASK_CALL) State->Flags.Nt = TRUE;
744
745 if (GET_SEGMENT_INDEX(NewTss.Ldtr) != 0)
746 {
747 BOOLEAN Valid;
748 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
749
750 if (NewTss.Ldtr & SEGMENT_TABLE_INDICATOR)
751 {
752 /* This selector doesn't point to the GDT */
753 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewTss.Ldtr);
754 return FALSE;
755 }
756
757 if (!Fast486ReadDescriptorEntry(State,
758 NewTss.Ldtr,
759 &Valid,
760 (PFAST486_GDT_ENTRY)&GdtEntry))
761 {
762 /* Exception occurred */
763 return FALSE;
764 }
765
766 if (!Valid)
767 {
768 /* Invalid selector */
769 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewTss.Ldtr);
770 return FALSE;
771 }
772
773 if (GdtEntry.Signature != FAST486_LDT_SIGNATURE)
774 {
775 /* This is not an LDT descriptor */
776 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewTss.Ldtr);
777 return FALSE;
778 }
779
780 if (!GdtEntry.Present)
781 {
782 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewTss.Ldtr);
783 return FALSE;
784 }
785
786 /* Update the LDTR */
787 State->Ldtr.Selector = NewTss.Ldtr;
788 State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
789 State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
790
791 if (GdtEntry.Granularity)
792 {
793 State->Ldtr.Limit <<= 12;
794 State->Ldtr.Limit |= 0x00000FFF;
795 }
796 }
797 else
798 {
799 /* The LDT of this task is empty */
800 RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr));
801 }
802
803 /* Load the new segments */
804 if (!Fast486LoadSegmentInternal(State,
805 FAST486_REG_CS,
806 NewTss.Cs,
807 FAST486_EXCEPTION_TS))
808 {
809 return FALSE;
810 }
811
812 if (!Fast486LoadSegmentInternal(State,
813 FAST486_REG_SS,
814 NewTss.Ss,
815 FAST486_EXCEPTION_TS))
816 {
817 return FALSE;
818 }
819
820 if (!Fast486LoadSegmentInternal(State,
821 FAST486_REG_ES,
822 NewTss.Es,
823 FAST486_EXCEPTION_TS))
824 {
825 return FALSE;
826 }
827
828 if (!Fast486LoadSegmentInternal(State,
829 FAST486_REG_DS,
830 NewTss.Ds,
831 FAST486_EXCEPTION_TS))
832 {
833 return FALSE;
834 }
835
836 if (!Fast486LoadSegmentInternal(State,
837 FAST486_REG_FS,
838 NewTss.Fs,
839 FAST486_EXCEPTION_TS))
840 {
841 return FALSE;
842 }
843
844 if (!Fast486LoadSegmentInternal(State,
845 FAST486_REG_GS,
846 NewTss.Gs,
847 FAST486_EXCEPTION_TS))
848 {
849 return FALSE;
850 }
851
852 return TRUE;
853 }
854
855 /* EOF */