a5deaf86eb825ca57ac96a61c697ed1b05e82e27
[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 FASTCALL
36 Fast486ReadMemory(PFAST486_STATE State,
37 FAST486_SEG_REGS SegmentReg,
38 ULONG Offset,
39 BOOLEAN InstFetch,
40 PVOID Buffer,
41 ULONG Size)
42 {
43 ULONG LinearAddress;
44 PFAST486_SEG_REG CachedDescriptor;
45
46 ASSERT(SegmentReg < FAST486_NUM_SEG_REGS);
47
48 /* Get the cached descriptor */
49 CachedDescriptor = &State->SegmentRegs[SegmentReg];
50
51 if (InstFetch || CachedDescriptor->Executable || !CachedDescriptor->DirConf)
52 {
53 if ((Offset + Size - 1) > CachedDescriptor->Limit)
54 {
55 /* Read beyond limit */
56 Fast486Exception(State, FAST486_EXCEPTION_GP);
57 return FALSE;
58 }
59 }
60 else
61 {
62 if (Offset < CachedDescriptor->Limit)
63 {
64 /* Read beyond limit */
65 Fast486Exception(State, FAST486_EXCEPTION_GP);
66 return FALSE;
67 }
68 }
69
70 /* Check for protected mode */
71 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
72 {
73 /* Privilege checks */
74
75 if (!CachedDescriptor->Present)
76 {
77 Fast486Exception(State, FAST486_EXCEPTION_NP);
78 return FALSE;
79 }
80
81 if ((!InstFetch && (CachedDescriptor->Rpl > CachedDescriptor->Dpl))
82 || (Fast486GetCurrentPrivLevel(State) > CachedDescriptor->Dpl))
83 {
84 Fast486Exception(State, FAST486_EXCEPTION_GP);
85 return FALSE;
86 }
87
88 if (InstFetch)
89 {
90 if (!CachedDescriptor->Executable)
91 {
92 /* Data segment not executable */
93 Fast486Exception(State, FAST486_EXCEPTION_GP);
94 return FALSE;
95 }
96 }
97 else
98 {
99 if (CachedDescriptor->Executable && (!CachedDescriptor->ReadWrite))
100 {
101 /* Code segment not readable */
102 Fast486Exception(State, FAST486_EXCEPTION_GP);
103 return FALSE;
104 }
105 }
106 }
107
108 /* Find the linear address */
109 LinearAddress = CachedDescriptor->Base + Offset;
110
111 #ifndef FAST486_NO_PREFETCH
112 if (InstFetch && ((Offset + FAST486_CACHE_SIZE - 1) <= CachedDescriptor->Limit))
113 {
114 State->PrefetchAddress = LinearAddress;
115
116 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG)
117 && (PAGE_OFFSET(State->PrefetchAddress) > (FAST486_PAGE_SIZE - FAST486_CACHE_SIZE)))
118 {
119 /* We mustn't prefetch across a page boundary */
120 State->PrefetchAddress = PAGE_ALIGN(State->PrefetchAddress)
121 | (FAST486_PAGE_SIZE - FAST486_CACHE_SIZE);
122
123 if ((LinearAddress - State->PrefetchAddress + Size) >= FAST486_CACHE_SIZE)
124 {
125 /* We can't prefetch without possibly violating page permissions */
126 State->PrefetchValid = FALSE;
127 return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size, TRUE);
128 }
129 }
130
131 /* Prefetch */
132 if (Fast486ReadLinearMemory(State,
133 State->PrefetchAddress,
134 State->PrefetchCache,
135 FAST486_CACHE_SIZE,
136 TRUE))
137 {
138 State->PrefetchValid = TRUE;
139
140 RtlMoveMemory(Buffer,
141 &State->PrefetchCache[LinearAddress - State->PrefetchAddress],
142 Size);
143 return TRUE;
144 }
145 else
146 {
147 State->PrefetchValid = FALSE;
148 return FALSE;
149 }
150 }
151 else
152 #endif
153 {
154 /* Read from the linear address */
155 return Fast486ReadLinearMemory(State, LinearAddress, Buffer, Size, TRUE);
156 }
157 }
158
159 BOOLEAN
160 FASTCALL
161 Fast486WriteMemory(PFAST486_STATE State,
162 FAST486_SEG_REGS SegmentReg,
163 ULONG Offset,
164 PVOID Buffer,
165 ULONG Size)
166 {
167 ULONG LinearAddress;
168 PFAST486_SEG_REG CachedDescriptor;
169
170 ASSERT(SegmentReg < FAST486_NUM_SEG_REGS);
171
172 /* Get the cached descriptor */
173 CachedDescriptor = &State->SegmentRegs[SegmentReg];
174
175 if (CachedDescriptor->Executable || !CachedDescriptor->DirConf)
176 {
177 if ((Offset + Size - 1) > CachedDescriptor->Limit)
178 {
179 /* Write beyond limit */
180 Fast486Exception(State, FAST486_EXCEPTION_GP);
181 return FALSE;
182 }
183 }
184 else
185 {
186 if (Offset < CachedDescriptor->Limit)
187 {
188 /* Read beyond limit */
189 Fast486Exception(State, FAST486_EXCEPTION_GP);
190 return FALSE;
191 }
192 }
193
194 /* Check for protected mode */
195 if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm)
196 {
197 /* Privilege checks */
198
199 if (!CachedDescriptor->Present)
200 {
201 Fast486Exception(State, FAST486_EXCEPTION_NP);
202 return FALSE;
203 }
204
205 if ((CachedDescriptor->Rpl > CachedDescriptor->Dpl)
206 || (Fast486GetCurrentPrivLevel(State) > CachedDescriptor->Dpl))
207 {
208 Fast486Exception(State, FAST486_EXCEPTION_GP);
209 return FALSE;
210 }
211
212 if (CachedDescriptor->Executable)
213 {
214 /* Code segment not writable */
215 Fast486Exception(State, FAST486_EXCEPTION_GP);
216 return FALSE;
217 }
218 else if (!CachedDescriptor->ReadWrite)
219 {
220 /* Data segment not writeable */
221 Fast486Exception(State, FAST486_EXCEPTION_GP);
222 return FALSE;
223 }
224 }
225
226 /* Find the linear address */
227 LinearAddress = CachedDescriptor->Base + Offset;
228
229 #ifndef FAST486_NO_PREFETCH
230 if (State->PrefetchValid
231 && (LinearAddress >= State->PrefetchAddress)
232 && ((LinearAddress + Size) <= (State->PrefetchAddress + FAST486_CACHE_SIZE)))
233 {
234 /* Update the prefetch */
235 RtlMoveMemory(&State->PrefetchCache[LinearAddress - State->PrefetchAddress],
236 Buffer,
237 min(Size, FAST486_CACHE_SIZE + State->PrefetchAddress - LinearAddress));
238 }
239 #endif
240
241 /* Write to the linear address */
242 return Fast486WriteLinearMemory(State, LinearAddress, Buffer, Size, TRUE);
243 }
244
245 static inline BOOLEAN
246 FASTCALL
247 Fast486GetIntVector(PFAST486_STATE State,
248 UCHAR Number,
249 PFAST486_IDT_ENTRY IdtEntry)
250 {
251 /* Check for protected mode */
252 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
253 {
254 /* Read from the IDT */
255 if (!Fast486ReadLinearMemory(State,
256 State->Idtr.Address
257 + Number * sizeof(*IdtEntry),
258 IdtEntry,
259 sizeof(*IdtEntry),
260 FALSE))
261 {
262 /* Exception occurred */
263 return FALSE;
264 }
265 }
266 else
267 {
268 /* Read from the real-mode IVT */
269 ULONG FarPointer;
270
271 /* Paging is always disabled in real mode */
272 State->MemReadCallback(State,
273 State->Idtr.Address
274 + Number * sizeof(FarPointer),
275 &FarPointer,
276 sizeof(FarPointer));
277
278 /* Fill a fake IDT entry */
279 IdtEntry->Offset = LOWORD(FarPointer);
280 IdtEntry->Selector = HIWORD(FarPointer);
281 IdtEntry->Zero = 0;
282 IdtEntry->Type = FAST486_IDT_INT_GATE;
283 IdtEntry->Storage = FALSE;
284 IdtEntry->Dpl = 0;
285 IdtEntry->Present = TRUE;
286 IdtEntry->OffsetHigh = 0;
287 }
288
289 return TRUE;
290 }
291
292 static inline BOOLEAN
293 FASTCALL
294 Fast486InterruptInternal(PFAST486_STATE State,
295 PFAST486_IDT_ENTRY IdtEntry,
296 BOOLEAN PushErrorCode,
297 ULONG ErrorCode)
298 {
299 BOOLEAN GateSize = (IdtEntry->Type == FAST486_IDT_INT_GATE_32) ||
300 (IdtEntry->Type == FAST486_IDT_TRAP_GATE_32);
301 USHORT OldCs = State->SegmentRegs[FAST486_REG_CS].Selector;
302 ULONG OldEip = State->InstPtr.Long;
303 ULONG OldFlags = State->Flags.Long;
304 UCHAR OldCpl = State->Cpl;
305
306 /* Check for protected mode */
307 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE)
308 {
309 USHORT OldSs = State->SegmentRegs[FAST486_REG_SS].Selector;
310 ULONG OldEsp = State->GeneralRegs[FAST486_REG_ESP].Long;
311 BOOLEAN OldVm = State->Flags.Vm;
312
313 if (IdtEntry->Type == FAST486_TASK_GATE_SIGNATURE)
314 {
315 /* Task call */
316 return Fast486TaskSwitch(State, FAST486_TASK_CALL, IdtEntry->Selector);
317 }
318
319 /* Check if the interrupt handler is more privileged or if we're in V86 mode */
320 if ((OldCpl > GET_SEGMENT_RPL(IdtEntry->Selector)) || State->Flags.Vm)
321 {
322 FAST486_TSS Tss;
323 PFAST486_LEGACY_TSS LegacyTss = (PFAST486_LEGACY_TSS)&Tss;
324 USHORT NewSs;
325 ULONG NewEsp;
326
327 /* Read the TSS */
328 if (!Fast486ReadLinearMemory(State,
329 State->TaskReg.Base,
330 &Tss,
331 State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1)
332 ? sizeof(FAST486_TSS) : sizeof(FAST486_LEGACY_TSS),
333 FALSE))
334 {
335 /* Exception occurred */
336 return FALSE;
337 }
338
339 /* Switch to the new privilege level */
340 State->Cpl = GET_SEGMENT_RPL(IdtEntry->Selector);
341
342 /* Check the new (higher) privilege level */
343 switch (State->Cpl)
344 {
345 case 0:
346 {
347 if (State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1))
348 {
349 NewSs = Tss.Ss0;
350 NewEsp = Tss.Esp0;
351 }
352 else
353 {
354 NewSs = LegacyTss->Ss0;
355 NewEsp = LegacyTss->Sp0;
356 }
357
358 break;
359 }
360
361 case 1:
362 {
363 if (State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1))
364 {
365 NewSs = Tss.Ss1;
366 NewEsp = Tss.Esp1;
367 }
368 else
369 {
370 NewSs = LegacyTss->Ss1;
371 NewEsp = LegacyTss->Sp1;
372 }
373
374 break;
375 }
376
377 case 2:
378 {
379 if (State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1))
380 {
381 NewSs = Tss.Ss2;
382 NewEsp = Tss.Esp2;
383 }
384 else
385 {
386 NewSs = LegacyTss->Ss2;
387 NewEsp = LegacyTss->Sp2;
388 }
389
390 break;
391 }
392
393 default:
394 {
395 /* Should never reach here! */
396 ASSERT(FALSE);
397 }
398 }
399
400 if (!Fast486LoadSegment(State, FAST486_REG_SS, NewSs))
401 {
402 /* Exception occurred */
403 return FALSE;
404 }
405
406 State->GeneralRegs[FAST486_REG_ESP].Long = NewEsp;
407
408 if (State->Flags.Vm)
409 {
410 /* Clear the VM flag */
411 State->Flags.Vm = FALSE;
412 }
413 }
414
415 /* Load new CS */
416 if (!Fast486LoadSegment(State, FAST486_REG_CS, IdtEntry->Selector))
417 {
418 /* An exception occurred during the jump */
419 return FALSE;
420 }
421
422 if (GateSize)
423 {
424 /* 32-bit code segment, use EIP */
425 State->InstPtr.Long = MAKELONG(IdtEntry->Offset, IdtEntry->OffsetHigh);
426 }
427 else
428 {
429 /* 16-bit code segment, use IP */
430 State->InstPtr.LowWord = IdtEntry->Offset;
431 }
432
433 /* Clear NT */
434 State->Flags.Nt = FALSE;
435
436 if (OldVm)
437 {
438 /* Push GS, FS, DS and ES */
439 if (!Fast486StackPushInternal(State,
440 GateSize,
441 State->SegmentRegs[FAST486_REG_GS].Selector))
442 {
443 return FALSE;
444 }
445 if (!Fast486StackPushInternal(State,
446 GateSize,
447 State->SegmentRegs[FAST486_REG_FS].Selector))
448 {
449 return FALSE;
450 }
451 if (!Fast486StackPushInternal(State,
452 GateSize,
453 State->SegmentRegs[FAST486_REG_DS].Selector))
454 {
455 return FALSE;
456 }
457 if (!Fast486StackPushInternal(State,
458 GateSize,
459 State->SegmentRegs[FAST486_REG_ES].Selector))
460 {
461 return FALSE;
462 }
463
464 /* Now load them with NULL selectors, since they are useless in protected mode */
465 if (!Fast486LoadSegment(State, FAST486_REG_GS, 0)) return FALSE;
466 if (!Fast486LoadSegment(State, FAST486_REG_FS, 0)) return FALSE;
467 if (!Fast486LoadSegment(State, FAST486_REG_DS, 0)) return FALSE;
468 if (!Fast486LoadSegment(State, FAST486_REG_ES, 0)) return FALSE;
469 }
470
471 /* Check if the interrupt handler is more privileged or we're in VM86 mode (again) */
472 if ((OldCpl > GET_SEGMENT_RPL(IdtEntry->Selector)) || OldVm)
473 {
474 /* Push SS selector */
475 if (!Fast486StackPushInternal(State, GateSize, OldSs)) return FALSE;
476
477 /* Push the stack pointer */
478 if (!Fast486StackPushInternal(State, GateSize, OldEsp)) return FALSE;
479 }
480 }
481 else
482 {
483 /* Load new CS */
484 if (!Fast486LoadSegment(State, FAST486_REG_CS, IdtEntry->Selector))
485 {
486 /* An exception occurred during the jump */
487 return FALSE;
488 }
489
490 /* Set the new IP */
491 State->InstPtr.LowWord = IdtEntry->Offset;
492 }
493
494 /* Push EFLAGS */
495 if (!Fast486StackPushInternal(State, GateSize, OldFlags)) return FALSE;
496
497 /* Push CS selector */
498 if (!Fast486StackPushInternal(State, GateSize, OldCs)) return FALSE;
499
500 /* Push the instruction pointer */
501 if (!Fast486StackPushInternal(State, GateSize, OldEip)) return FALSE;
502
503 if (PushErrorCode)
504 {
505 /* Push the error code */
506 if (!Fast486StackPushInternal(State, GateSize, ErrorCode)) return FALSE;
507 }
508
509 if ((IdtEntry->Type == FAST486_IDT_INT_GATE)
510 || (IdtEntry->Type == FAST486_IDT_INT_GATE_32))
511 {
512 /* Disable interrupts after a jump to an interrupt gate handler */
513 State->Flags.If = FALSE;
514 }
515
516 /* Clear TF */
517 State->Flags.Tf = FALSE;
518
519 return TRUE;
520 }
521
522 BOOLEAN
523 FASTCALL
524 Fast486PerformInterrupt(PFAST486_STATE State,
525 UCHAR Number)
526 {
527 FAST486_IDT_ENTRY IdtEntry;
528
529 /* Get the interrupt vector */
530 if (!Fast486GetIntVector(State, Number, &IdtEntry))
531 {
532 /* Exception occurred */
533 return FALSE;
534 }
535
536 /* Perform the interrupt */
537 if (!Fast486InterruptInternal(State, &IdtEntry, FALSE, 0))
538 {
539 /* Exception occurred */
540 return FALSE;
541 }
542
543 return TRUE;
544 }
545
546 VOID
547 FASTCALL
548 Fast486ExceptionWithErrorCode(PFAST486_STATE State,
549 FAST486_EXCEPTIONS ExceptionCode,
550 ULONG ErrorCode)
551 {
552 FAST486_IDT_ENTRY IdtEntry;
553
554 /* Increment the exception count */
555 State->ExceptionCount++;
556
557 /* Check if the exception occurred more than once */
558 if (State->ExceptionCount > 1)
559 {
560 /* Then this is a double fault */
561 ExceptionCode = FAST486_EXCEPTION_DF;
562 }
563
564 /* Check if this is a triple fault */
565 if (State->ExceptionCount == 3)
566 {
567 DPRINT("Fast486ExceptionWithErrorCode(%04X:%08X) -- Triple fault\n",
568 State->SegmentRegs[FAST486_REG_CS].Selector,
569 State->InstPtr.Long);
570
571 /* Reset the CPU */
572 Fast486Reset(State);
573 return;
574 }
575
576 /* Clear the prefix flags */
577 State->PrefixFlags = 0;
578
579 /* Restore the IP to the saved IP */
580 State->InstPtr = State->SavedInstPtr;
581
582 /* Restore the SP to the saved SP */
583 State->GeneralRegs[FAST486_REG_ESP] = State->SavedStackPtr;
584
585 /* Get the interrupt vector */
586 if (!Fast486GetIntVector(State, ExceptionCode, &IdtEntry))
587 {
588 /*
589 * If this function failed, that means Fast486Exception
590 * was called again, so just return in this case.
591 */
592 return;
593 }
594
595 /* Perform the interrupt */
596 if (!Fast486InterruptInternal(State,
597 &IdtEntry,
598 EXCEPTION_HAS_ERROR_CODE(ExceptionCode)
599 && (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE),
600 ErrorCode))
601 {
602 /*
603 * If this function failed, that means Fast486Exception
604 * was called again, so just return in this case.
605 */
606 return;
607 }
608
609 /* Reset the exception count */
610 State->ExceptionCount = 0;
611 }
612
613 BOOLEAN
614 FASTCALL
615 Fast486TaskSwitch(PFAST486_STATE State, FAST486_TASK_SWITCH_TYPE Type, USHORT Selector)
616 {
617 ULONG NewTssAddress;
618 ULONG NewTssLimit;
619 FAST486_SYSTEM_DESCRIPTOR NewTssDescriptor;
620 FAST486_TSS OldTss;
621 PFAST486_LEGACY_TSS OldLegacyTss = (PFAST486_LEGACY_TSS)&OldTss;
622 FAST486_TSS NewTss;
623 PFAST486_LEGACY_TSS NewLegacyTss = (PFAST486_LEGACY_TSS)&NewTss;
624 USHORT NewLdtr, NewEs, NewCs, NewSs, NewDs;
625
626 if (State->TaskReg.Limit < (sizeof(FAST486_TSS) - 1)
627 && State->TaskReg.Limit != (sizeof(FAST486_LEGACY_TSS) - 1))
628 {
629 /* Invalid task register limit */
630 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, State->TaskReg.Selector);
631 return FALSE;
632 }
633
634 /* Read the old TSS */
635 if (!Fast486ReadLinearMemory(State,
636 State->TaskReg.Base,
637 &OldTss,
638 State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1)
639 ? sizeof(FAST486_TSS) : sizeof(FAST486_LEGACY_TSS),
640 FALSE))
641 {
642 /* Exception occurred */
643 return FALSE;
644 }
645
646
647 /* If this is a task return, use the linked previous selector */
648 if (Type == FAST486_TASK_RETURN)
649 {
650 if (State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1)) Selector = LOWORD(OldTss.Link);
651 else Selector = OldLegacyTss->Link;
652 }
653
654 /* Make sure the entry exists in the GDT (not LDT!) */
655 if ((GET_SEGMENT_INDEX(Selector) == 0)
656 || (Selector & SEGMENT_TABLE_INDICATOR)
657 || GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1u))
658 {
659 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, Selector);
660 return FALSE;
661 }
662
663 /* Get the TSS descriptor from the GDT */
664 if (!Fast486ReadLinearMemory(State,
665 State->Gdtr.Address + GET_SEGMENT_INDEX(Selector),
666 &NewTssDescriptor,
667 sizeof(NewTssDescriptor),
668 FALSE))
669 {
670 /* Exception occurred */
671 return FALSE;
672 }
673
674 if (!NewTssDescriptor.Present)
675 {
676 /* Incoming task TSS not present */
677 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
678 return FALSE;
679 }
680
681 /* Calculate the linear address of the new TSS */
682 NewTssAddress = NewTssDescriptor.Base;
683 NewTssAddress |= NewTssDescriptor.BaseMid << 16;
684 NewTssAddress |= NewTssDescriptor.BaseHigh << 24;
685
686 /* Calculate the limit of the new TSS */
687 NewTssLimit = NewTssDescriptor.Limit | (NewTssDescriptor.LimitHigh << 16);
688
689 if (NewTssDescriptor.Granularity)
690 {
691 NewTssLimit <<= 12;
692 NewTssLimit |= 0x00000FFF;
693 }
694
695 if (NewTssLimit < (sizeof(FAST486_TSS) - 1)
696 && NewTssLimit != (sizeof(FAST486_LEGACY_TSS) - 1))
697 {
698 /* TSS limit invalid */
699 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, Selector);
700 return FALSE;
701 }
702
703 /*
704 * The incoming task shouldn't be busy if we're executing it as a
705 * new task, and it should be busy if we're returning to it.
706 */
707 if ((((NewTssDescriptor.Signature != FAST486_TSS_SIGNATURE)
708 && (NewTssDescriptor.Signature != FAST486_TSS_16_SIGNATURE))
709 || (Type == FAST486_TASK_RETURN))
710 && (((NewTssDescriptor.Signature != FAST486_BUSY_TSS_SIGNATURE)
711 && (NewTssDescriptor.Signature != FAST486_BUSY_TSS_16_SIGNATURE))
712 || (Type != FAST486_TASK_RETURN)))
713 {
714 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
715 return FALSE;
716 }
717
718 /* Read the new TSS */
719 if (!Fast486ReadLinearMemory(State,
720 NewTssAddress,
721 &NewTss,
722 NewTssLimit >= (sizeof(FAST486_TSS) - 1)
723 ? sizeof(FAST486_TSS) : sizeof(FAST486_LEGACY_TSS),
724 FALSE))
725 {
726 /* Exception occurred */
727 return FALSE;
728 }
729
730 if (Type != FAST486_TASK_CALL)
731 {
732 /* Clear the busy bit of the outgoing task */
733 FAST486_SYSTEM_DESCRIPTOR OldTssDescriptor;
734
735 if (!Fast486ReadLinearMemory(State,
736 State->Gdtr.Address
737 + GET_SEGMENT_INDEX(State->TaskReg.Selector),
738 &OldTssDescriptor,
739 sizeof(OldTssDescriptor),
740 FALSE))
741 {
742 /* Exception occurred */
743 return FALSE;
744 }
745
746 OldTssDescriptor.Signature = FAST486_TSS_SIGNATURE;
747
748 if (!Fast486WriteLinearMemory(State,
749 State->Gdtr.Address
750 + GET_SEGMENT_INDEX(State->TaskReg.Selector),
751 &OldTssDescriptor,
752 sizeof(OldTssDescriptor),
753 FALSE))
754 {
755 /* Exception occurred */
756 return FALSE;
757 }
758 }
759 else
760 {
761 /* Store the link */
762 if (NewTssLimit >= (sizeof(FAST486_TSS) - 1)) NewTss.Link = State->TaskReg.Selector;
763 else NewLegacyTss->Link = State->TaskReg.Selector;
764 }
765
766 /* Save the current task into the TSS */
767 if (State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1))
768 {
769 OldTss.Cr3 = State->ControlRegisters[FAST486_REG_CR3];
770 OldTss.Eip = State->InstPtr.Long;
771 OldTss.Eflags = State->Flags.Long;
772 OldTss.Eax = State->GeneralRegs[FAST486_REG_EAX].Long;
773 OldTss.Ecx = State->GeneralRegs[FAST486_REG_ECX].Long;
774 OldTss.Edx = State->GeneralRegs[FAST486_REG_EDX].Long;
775 OldTss.Ebx = State->GeneralRegs[FAST486_REG_EBX].Long;
776 OldTss.Esp = State->GeneralRegs[FAST486_REG_ESP].Long;
777 OldTss.Ebp = State->GeneralRegs[FAST486_REG_EBP].Long;
778 OldTss.Esi = State->GeneralRegs[FAST486_REG_ESI].Long;
779 OldTss.Edi = State->GeneralRegs[FAST486_REG_EDI].Long;
780 OldTss.Es = State->SegmentRegs[FAST486_REG_ES].Selector;
781 OldTss.Cs = State->SegmentRegs[FAST486_REG_CS].Selector;
782 OldTss.Ss = State->SegmentRegs[FAST486_REG_SS].Selector;
783 OldTss.Ds = State->SegmentRegs[FAST486_REG_DS].Selector;
784 OldTss.Fs = State->SegmentRegs[FAST486_REG_FS].Selector;
785 OldTss.Gs = State->SegmentRegs[FAST486_REG_GS].Selector;
786 OldTss.Ldtr = State->Ldtr.Selector;
787 }
788 else
789 {
790 OldLegacyTss->Ip = State->InstPtr.LowWord;
791 OldLegacyTss->Flags = State->Flags.LowWord;
792 OldLegacyTss->Ax = State->GeneralRegs[FAST486_REG_EAX].LowWord;
793 OldLegacyTss->Cx = State->GeneralRegs[FAST486_REG_ECX].LowWord;
794 OldLegacyTss->Dx = State->GeneralRegs[FAST486_REG_EDX].LowWord;
795 OldLegacyTss->Bx = State->GeneralRegs[FAST486_REG_EBX].LowWord;
796 OldLegacyTss->Sp = State->GeneralRegs[FAST486_REG_ESP].LowWord;
797 OldLegacyTss->Bp = State->GeneralRegs[FAST486_REG_EBP].LowWord;
798 OldLegacyTss->Si = State->GeneralRegs[FAST486_REG_ESI].LowWord;
799 OldLegacyTss->Di = State->GeneralRegs[FAST486_REG_EDI].LowWord;
800 OldLegacyTss->Es = State->SegmentRegs[FAST486_REG_ES].Selector;
801 OldLegacyTss->Cs = State->SegmentRegs[FAST486_REG_CS].Selector;
802 OldLegacyTss->Ss = State->SegmentRegs[FAST486_REG_SS].Selector;
803 OldLegacyTss->Ds = State->SegmentRegs[FAST486_REG_DS].Selector;
804 OldLegacyTss->Ldtr = State->Ldtr.Selector;
805 }
806
807 /* Write back the old TSS */
808 if (!Fast486WriteLinearMemory(State,
809 State->TaskReg.Base,
810 &OldTss,
811 State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1)
812 ? sizeof(FAST486_TSS) : sizeof(FAST486_LEGACY_TSS),
813 FALSE))
814 {
815 /* Exception occurred */
816 return FALSE;
817 }
818
819 /* Mark the new task as busy */
820 NewTssDescriptor.Signature = FAST486_BUSY_TSS_SIGNATURE;
821
822 /* Write back the new TSS descriptor */
823 if (!Fast486WriteLinearMemory(State,
824 State->Gdtr.Address + GET_SEGMENT_INDEX(Selector),
825 &NewTssDescriptor,
826 sizeof(NewTssDescriptor),
827 FALSE))
828 {
829 /* Exception occurred */
830 return FALSE;
831 }
832
833 /* Set the task switch bit */
834 State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_TS;
835
836 /* Load the task register with the new values */
837 State->TaskReg.Selector = Selector;
838 State->TaskReg.Base = NewTssAddress;
839 State->TaskReg.Limit = NewTssLimit;
840
841 if (NewTssLimit >= (sizeof(FAST486_TSS) - 1))
842 {
843 /* Change the page directory */
844 State->ControlRegisters[FAST486_REG_CR3] = NewTss.Cr3;
845 }
846
847 /* Flush the TLB */
848 Fast486FlushTlb(State);
849
850 /* Update the CPL */
851 if (NewTssLimit >= (sizeof(FAST486_TSS) - 1)) State->Cpl = GET_SEGMENT_RPL(NewTss.Cs);
852 else State->Cpl = GET_SEGMENT_RPL(NewLegacyTss->Cs);
853
854 #ifndef FAST486_NO_PREFETCH
855 /* Context switching invalidates the prefetch */
856 State->PrefetchValid = FALSE;
857 #endif
858
859 /* Load the registers */
860 if (NewTssLimit >= (sizeof(FAST486_TSS) - 1))
861 {
862 State->InstPtr.Long = State->SavedInstPtr.Long = NewTss.Eip;
863 State->Flags.Long = NewTss.Eflags;
864 State->GeneralRegs[FAST486_REG_EAX].Long = NewTss.Eax;
865 State->GeneralRegs[FAST486_REG_ECX].Long = NewTss.Ecx;
866 State->GeneralRegs[FAST486_REG_EDX].Long = NewTss.Edx;
867 State->GeneralRegs[FAST486_REG_EBX].Long = NewTss.Ebx;
868 State->GeneralRegs[FAST486_REG_ESP].Long = NewTss.Esp;
869 State->GeneralRegs[FAST486_REG_EBP].Long = NewTss.Ebp;
870 State->GeneralRegs[FAST486_REG_ESI].Long = NewTss.Esi;
871 State->GeneralRegs[FAST486_REG_EDI].Long = NewTss.Edi;
872 NewEs = NewTss.Es;
873 NewCs = NewTss.Cs;
874 NewSs = NewTss.Ss;
875 NewDs = NewTss.Ds;
876 NewLdtr = NewTss.Ldtr;
877 }
878 else
879 {
880 State->InstPtr.LowWord = State->SavedInstPtr.LowWord = NewLegacyTss->Ip;
881 State->Flags.LowWord = NewLegacyTss->Flags;
882 State->GeneralRegs[FAST486_REG_EAX].LowWord = NewLegacyTss->Ax;
883 State->GeneralRegs[FAST486_REG_ECX].LowWord = NewLegacyTss->Cx;
884 State->GeneralRegs[FAST486_REG_EDX].LowWord = NewLegacyTss->Dx;
885 State->GeneralRegs[FAST486_REG_EBX].LowWord = NewLegacyTss->Bx;
886 State->GeneralRegs[FAST486_REG_ESP].LowWord = NewLegacyTss->Sp;
887 State->GeneralRegs[FAST486_REG_EBP].LowWord = NewLegacyTss->Bp;
888 State->GeneralRegs[FAST486_REG_ESI].LowWord = NewLegacyTss->Si;
889 State->GeneralRegs[FAST486_REG_EDI].LowWord = NewLegacyTss->Di;
890 NewEs = NewLegacyTss->Es;
891 NewCs = NewLegacyTss->Cs;
892 NewSs = NewLegacyTss->Ss;
893 NewDs = NewLegacyTss->Ds;
894 NewLdtr = NewLegacyTss->Ldtr;
895 }
896
897 /* Set the NT flag if nesting */
898 if (Type == FAST486_TASK_CALL) State->Flags.Nt = TRUE;
899
900 if (GET_SEGMENT_INDEX(NewLdtr) != 0)
901 {
902 BOOLEAN Valid;
903 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
904
905 if (NewLdtr & SEGMENT_TABLE_INDICATOR)
906 {
907 /* This selector doesn't point to the GDT */
908 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewLdtr);
909 return FALSE;
910 }
911
912 if (!Fast486ReadDescriptorEntry(State, NewLdtr, &Valid, (PFAST486_GDT_ENTRY)&GdtEntry))
913 {
914 /* Exception occurred */
915 return FALSE;
916 }
917
918 if (!Valid)
919 {
920 /* Invalid selector */
921 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewLdtr);
922 return FALSE;
923 }
924
925 if (GdtEntry.Signature != FAST486_LDT_SIGNATURE)
926 {
927 /* This is not an LDT descriptor */
928 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewLdtr);
929 return FALSE;
930 }
931
932 if (!GdtEntry.Present)
933 {
934 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewLdtr);
935 return FALSE;
936 }
937
938 /* Update the LDTR */
939 State->Ldtr.Selector = NewLdtr;
940 State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
941 State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
942
943 if (GdtEntry.Granularity)
944 {
945 State->Ldtr.Limit <<= 12;
946 State->Ldtr.Limit |= 0x00000FFF;
947 }
948 }
949 else
950 {
951 /* The LDT of this task is empty */
952 RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr));
953 }
954
955 /* Load the new segments */
956 if (!Fast486LoadSegmentInternal(State, FAST486_REG_CS, NewCs, FAST486_EXCEPTION_TS))
957 {
958 return FALSE;
959 }
960
961 if (!Fast486LoadSegmentInternal(State, FAST486_REG_SS, NewSs, FAST486_EXCEPTION_TS))
962 {
963 return FALSE;
964 }
965
966 if (!Fast486LoadSegmentInternal(State, FAST486_REG_ES, NewEs, FAST486_EXCEPTION_TS))
967 {
968 return FALSE;
969 }
970
971 if (!Fast486LoadSegmentInternal(State, FAST486_REG_DS, NewDs, FAST486_EXCEPTION_TS))
972 {
973 return FALSE;
974 }
975
976 if (NewTssLimit >= (sizeof(FAST486_TSS) - 1))
977 {
978 if (!Fast486LoadSegmentInternal(State,
979 FAST486_REG_FS,
980 NewTss.Fs,
981 FAST486_EXCEPTION_TS))
982 {
983 return FALSE;
984 }
985
986 if (!Fast486LoadSegmentInternal(State,
987 FAST486_REG_GS,
988 NewTss.Gs,
989 FAST486_EXCEPTION_TS))
990 {
991 return FALSE;
992 }
993 }
994
995 return TRUE;
996 }
997
998 BOOLEAN
999 FASTCALL
1000 Fast486CallGate(PFAST486_STATE State,
1001 PFAST486_CALL_GATE Gate,
1002 BOOLEAN Call)
1003 {
1004 BOOLEAN Valid;
1005 FAST486_GDT_ENTRY NewCodeSegment;
1006 BOOLEAN GateSize = (Gate->Type == FAST486_CALL_GATE_SIGNATURE);
1007 FAST486_TSS Tss;
1008 PFAST486_LEGACY_TSS LegacyTss = (PFAST486_LEGACY_TSS)&Tss;
1009 USHORT OldCs = State->SegmentRegs[FAST486_REG_CS].Selector;
1010 ULONG OldEip = State->InstPtr.Long;
1011 USHORT OldCpl = State->Cpl;
1012 USHORT OldSs = State->SegmentRegs[FAST486_REG_SS].Selector;
1013 ULONG OldEsp = State->GeneralRegs[FAST486_REG_ESP].Long;
1014 ULONG ParamBuffer[32]; /* Maximum possible size - 32 DWORDs */
1015 PULONG LongParams = (PULONG)ParamBuffer;
1016 PUSHORT ShortParams = (PUSHORT)ParamBuffer;
1017
1018 if (!Gate->Selector)
1019 {
1020 /* The code segment is NULL */
1021 Fast486Exception(State, FAST486_EXCEPTION_GP);
1022 return FALSE;
1023 }
1024
1025 if (!Fast486ReadDescriptorEntry(State, Gate->Selector, &Valid, &NewCodeSegment))
1026 {
1027 /* Exception occurred */
1028 return FALSE;
1029 }
1030
1031 if (!Valid || (NewCodeSegment.Dpl > Fast486GetCurrentPrivLevel(State)))
1032 {
1033 /* Code segment invalid */
1034 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Gate->Selector);
1035 return FALSE;
1036 }
1037
1038 if (Call && Gate->ParamCount)
1039 {
1040 /* Read the parameters */
1041 if (!Fast486ReadMemory(State,
1042 FAST486_REG_SS,
1043 OldEsp,
1044 FALSE,
1045 ParamBuffer,
1046 Gate->ParamCount * (GateSize ? sizeof(ULONG) : sizeof(USHORT))))
1047 {
1048 /* Exception occurred */
1049 return FALSE;
1050 }
1051 }
1052
1053 /* Check if the new code segment is more privileged */
1054 if (NewCodeSegment.Dpl < OldCpl)
1055 {
1056 if (Call)
1057 {
1058 USHORT NewSs;
1059 ULONG NewEsp;
1060
1061 /* Read the TSS */
1062 if (!Fast486ReadLinearMemory(State,
1063 State->TaskReg.Base,
1064 &Tss,
1065 State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1)
1066 ? sizeof(FAST486_TSS) : sizeof(FAST486_LEGACY_TSS),
1067 FALSE))
1068 {
1069 /* Exception occurred */
1070 return FALSE;
1071 }
1072
1073 /* Switch to the new privilege level */
1074 State->Cpl = NewCodeSegment.Dpl;
1075
1076 /* Check the new (higher) privilege level */
1077 switch (State->Cpl)
1078 {
1079 case 0:
1080 {
1081 if (State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1))
1082 {
1083 NewSs = Tss.Ss0;
1084 NewEsp = Tss.Esp0;
1085 }
1086 else
1087 {
1088 NewSs = LegacyTss->Ss0;
1089 NewEsp = LegacyTss->Sp0;
1090 }
1091
1092 break;
1093 }
1094
1095 case 1:
1096 {
1097 if (State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1))
1098 {
1099 NewSs = Tss.Ss1;
1100 NewEsp = Tss.Esp1;
1101 }
1102 else
1103 {
1104 NewSs = LegacyTss->Ss1;
1105 NewEsp = LegacyTss->Sp1;
1106 }
1107
1108 break;
1109 }
1110
1111 case 2:
1112 {
1113 if (State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1))
1114 {
1115 NewSs = Tss.Ss2;
1116 NewEsp = Tss.Esp2;
1117 }
1118 else
1119 {
1120 NewSs = LegacyTss->Ss2;
1121 NewEsp = LegacyTss->Sp2;
1122 }
1123
1124 break;
1125 }
1126
1127 default:
1128 {
1129 /* Should never reach here! */
1130 ASSERT(FALSE);
1131 }
1132 }
1133
1134 if (!Fast486LoadSegment(State, FAST486_REG_SS, NewSs))
1135 {
1136 /* Exception occurred */
1137 return FALSE;
1138 }
1139
1140 State->GeneralRegs[FAST486_REG_ESP].Long = NewEsp;
1141 }
1142 else if (!NewCodeSegment.DirConf)
1143 {
1144 /* This is not allowed for jumps */
1145 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Gate->Selector);
1146 return FALSE;
1147 }
1148 }
1149
1150 /* Load new CS */
1151 if (!Fast486LoadSegment(State, FAST486_REG_CS, Gate->Selector))
1152 {
1153 /* An exception occurred during the jump */
1154 return FALSE;
1155 }
1156
1157 /* Set the instruction pointer */
1158 if (GateSize) State->InstPtr.Long = MAKELONG(Gate->Offset, Gate->OffsetHigh);
1159 else State->InstPtr.Long = Gate->Offset;
1160
1161 if (Call)
1162 {
1163 INT i;
1164
1165 /* Check if the new code segment is more privileged (again) */
1166 if (NewCodeSegment.Dpl < OldCpl)
1167 {
1168 /* Push SS selector */
1169 if (!Fast486StackPushInternal(State, GateSize, OldSs)) return FALSE;
1170
1171 /* Push stack pointer */
1172 if (!Fast486StackPushInternal(State, GateSize, OldEsp)) return FALSE;
1173 }
1174
1175 /* Push the parameters in reverse order */
1176 for (i = Gate->ParamCount - 1; i >= 0; i--)
1177 {
1178 if (!Fast486StackPushInternal(State,
1179 GateSize,
1180 GateSize ? LongParams[i] : ShortParams[i]))
1181 {
1182 /* Exception occurred */
1183 return FALSE;
1184 }
1185 }
1186
1187 /* Push CS selector */
1188 if (!Fast486StackPushInternal(State, GateSize, OldCs)) return FALSE;
1189
1190 /* Push the instruction pointer */
1191 if (!Fast486StackPushInternal(State, GateSize, OldEip)) return FALSE;
1192 }
1193
1194 return TRUE;
1195 }
1196
1197 /* EOF */