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