1a2bb09136b8f8bddb732b23ca7c5e0d541756e9
[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 TF and NT */
434 State->Flags.Tf = 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 return TRUE;
517 }
518
519 BOOLEAN
520 FASTCALL
521 Fast486PerformInterrupt(PFAST486_STATE State,
522 UCHAR Number)
523 {
524 FAST486_IDT_ENTRY IdtEntry;
525
526 /* Get the interrupt vector */
527 if (!Fast486GetIntVector(State, Number, &IdtEntry))
528 {
529 /* Exception occurred */
530 return FALSE;
531 }
532
533 /* Perform the interrupt */
534 if (!Fast486InterruptInternal(State, &IdtEntry, FALSE, 0))
535 {
536 /* Exception occurred */
537 return FALSE;
538 }
539
540 return TRUE;
541 }
542
543 VOID
544 FASTCALL
545 Fast486ExceptionWithErrorCode(PFAST486_STATE State,
546 FAST486_EXCEPTIONS ExceptionCode,
547 ULONG ErrorCode)
548 {
549 FAST486_IDT_ENTRY IdtEntry;
550
551 /* Increment the exception count */
552 State->ExceptionCount++;
553
554 /* Check if the exception occurred more than once */
555 if (State->ExceptionCount > 1)
556 {
557 /* Then this is a double fault */
558 ExceptionCode = FAST486_EXCEPTION_DF;
559 }
560
561 /* Check if this is a triple fault */
562 if (State->ExceptionCount == 3)
563 {
564 DPRINT("Fast486ExceptionWithErrorCode(%04X:%08X) -- Triple fault\n",
565 State->SegmentRegs[FAST486_REG_CS].Selector,
566 State->InstPtr.Long);
567
568 /* Reset the CPU */
569 Fast486Reset(State);
570 return;
571 }
572
573 /* Clear the prefix flags */
574 State->PrefixFlags = 0;
575
576 /* Restore the IP to the saved IP */
577 State->InstPtr = State->SavedInstPtr;
578
579 /* Get the interrupt vector */
580 if (!Fast486GetIntVector(State, ExceptionCode, &IdtEntry))
581 {
582 /*
583 * If this function failed, that means Fast486Exception
584 * was called again, so just return in this case.
585 */
586 return;
587 }
588
589 /* Perform the interrupt */
590 if (!Fast486InterruptInternal(State,
591 &IdtEntry,
592 EXCEPTION_HAS_ERROR_CODE(ExceptionCode)
593 && (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE),
594 ErrorCode))
595 {
596 /*
597 * If this function failed, that means Fast486Exception
598 * was called again, so just return in this case.
599 */
600 return;
601 }
602
603 /* Reset the exception count */
604 State->ExceptionCount = 0;
605 }
606
607 BOOLEAN
608 FASTCALL
609 Fast486TaskSwitch(PFAST486_STATE State, FAST486_TASK_SWITCH_TYPE Type, USHORT Selector)
610 {
611 ULONG NewTssAddress;
612 ULONG NewTssLimit;
613 FAST486_SYSTEM_DESCRIPTOR NewTssDescriptor;
614 FAST486_TSS OldTss;
615 PFAST486_LEGACY_TSS OldLegacyTss = (PFAST486_LEGACY_TSS)&OldTss;
616 FAST486_TSS NewTss;
617 PFAST486_LEGACY_TSS NewLegacyTss = (PFAST486_LEGACY_TSS)&NewTss;
618 USHORT NewLdtr, NewEs, NewCs, NewSs, NewDs;
619
620 if (State->TaskReg.Limit < (sizeof(FAST486_TSS) - 1)
621 && State->TaskReg.Limit != (sizeof(FAST486_LEGACY_TSS) - 1))
622 {
623 /* Invalid task register limit */
624 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, State->TaskReg.Selector);
625 return FALSE;
626 }
627
628 /* Read the old TSS */
629 if (!Fast486ReadLinearMemory(State,
630 State->TaskReg.Base,
631 &OldTss,
632 State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1)
633 ? sizeof(FAST486_TSS) : sizeof(FAST486_LEGACY_TSS),
634 FALSE))
635 {
636 /* Exception occurred */
637 return FALSE;
638 }
639
640
641 /* If this is a task return, use the linked previous selector */
642 if (Type == FAST486_TASK_RETURN)
643 {
644 if (State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1)) Selector = LOWORD(OldTss.Link);
645 else Selector = OldLegacyTss->Link;
646 }
647
648 /* Make sure the entry exists in the GDT (not LDT!) */
649 if ((GET_SEGMENT_INDEX(Selector) == 0)
650 || (Selector & SEGMENT_TABLE_INDICATOR)
651 || GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1u))
652 {
653 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, Selector);
654 return FALSE;
655 }
656
657 /* Get the TSS descriptor from the GDT */
658 if (!Fast486ReadLinearMemory(State,
659 State->Gdtr.Address + GET_SEGMENT_INDEX(Selector),
660 &NewTssDescriptor,
661 sizeof(NewTssDescriptor),
662 FALSE))
663 {
664 /* Exception occurred */
665 return FALSE;
666 }
667
668 if (!NewTssDescriptor.Present)
669 {
670 /* Incoming task TSS not present */
671 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector);
672 return FALSE;
673 }
674
675 /* Calculate the linear address of the new TSS */
676 NewTssAddress = NewTssDescriptor.Base;
677 NewTssAddress |= NewTssDescriptor.BaseMid << 16;
678 NewTssAddress |= NewTssDescriptor.BaseHigh << 24;
679
680 /* Calculate the limit of the new TSS */
681 NewTssLimit = NewTssDescriptor.Limit | (NewTssDescriptor.LimitHigh << 16);
682
683 if (NewTssDescriptor.Granularity)
684 {
685 NewTssLimit <<= 12;
686 NewTssLimit |= 0x00000FFF;
687 }
688
689 if (NewTssLimit < (sizeof(FAST486_TSS) - 1)
690 && NewTssLimit != (sizeof(FAST486_LEGACY_TSS) - 1))
691 {
692 /* TSS limit invalid */
693 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, Selector);
694 return FALSE;
695 }
696
697 /*
698 * The incoming task shouldn't be busy if we're executing it as a
699 * new task, and it should be busy if we're returning to it.
700 */
701 if ((((NewTssDescriptor.Signature != FAST486_TSS_SIGNATURE)
702 && (NewTssDescriptor.Signature != FAST486_TSS_16_SIGNATURE))
703 || (Type == FAST486_TASK_RETURN))
704 && (((NewTssDescriptor.Signature != FAST486_BUSY_TSS_SIGNATURE)
705 && (NewTssDescriptor.Signature != FAST486_BUSY_TSS_16_SIGNATURE))
706 || (Type != FAST486_TASK_RETURN)))
707 {
708 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector);
709 return FALSE;
710 }
711
712 /* Read the new TSS */
713 if (!Fast486ReadLinearMemory(State,
714 NewTssAddress,
715 &NewTss,
716 NewTssLimit >= (sizeof(FAST486_TSS) - 1)
717 ? sizeof(FAST486_TSS) : sizeof(FAST486_LEGACY_TSS),
718 FALSE))
719 {
720 /* Exception occurred */
721 return FALSE;
722 }
723
724 if (Type != FAST486_TASK_CALL)
725 {
726 /* Clear the busy bit of the outgoing task */
727 FAST486_SYSTEM_DESCRIPTOR OldTssDescriptor;
728
729 if (!Fast486ReadLinearMemory(State,
730 State->Gdtr.Address
731 + GET_SEGMENT_INDEX(State->TaskReg.Selector),
732 &OldTssDescriptor,
733 sizeof(OldTssDescriptor),
734 FALSE))
735 {
736 /* Exception occurred */
737 return FALSE;
738 }
739
740 OldTssDescriptor.Signature = FAST486_TSS_SIGNATURE;
741
742 if (!Fast486WriteLinearMemory(State,
743 State->Gdtr.Address
744 + GET_SEGMENT_INDEX(State->TaskReg.Selector),
745 &OldTssDescriptor,
746 sizeof(OldTssDescriptor),
747 FALSE))
748 {
749 /* Exception occurred */
750 return FALSE;
751 }
752 }
753 else
754 {
755 /* Store the link */
756 if (NewTssLimit >= (sizeof(FAST486_TSS) - 1)) NewTss.Link = State->TaskReg.Selector;
757 else NewLegacyTss->Link = State->TaskReg.Selector;
758 }
759
760 /* Save the current task into the TSS */
761 if (State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1))
762 {
763 OldTss.Cr3 = State->ControlRegisters[FAST486_REG_CR3];
764 OldTss.Eip = State->InstPtr.Long;
765 OldTss.Eflags = State->Flags.Long;
766 OldTss.Eax = State->GeneralRegs[FAST486_REG_EAX].Long;
767 OldTss.Ecx = State->GeneralRegs[FAST486_REG_ECX].Long;
768 OldTss.Edx = State->GeneralRegs[FAST486_REG_EDX].Long;
769 OldTss.Ebx = State->GeneralRegs[FAST486_REG_EBX].Long;
770 OldTss.Esp = State->GeneralRegs[FAST486_REG_ESP].Long;
771 OldTss.Ebp = State->GeneralRegs[FAST486_REG_EBP].Long;
772 OldTss.Esi = State->GeneralRegs[FAST486_REG_ESI].Long;
773 OldTss.Edi = State->GeneralRegs[FAST486_REG_EDI].Long;
774 OldTss.Es = State->SegmentRegs[FAST486_REG_ES].Selector;
775 OldTss.Cs = State->SegmentRegs[FAST486_REG_CS].Selector;
776 OldTss.Ss = State->SegmentRegs[FAST486_REG_SS].Selector;
777 OldTss.Ds = State->SegmentRegs[FAST486_REG_DS].Selector;
778 OldTss.Fs = State->SegmentRegs[FAST486_REG_FS].Selector;
779 OldTss.Gs = State->SegmentRegs[FAST486_REG_GS].Selector;
780 OldTss.Ldtr = State->Ldtr.Selector;
781 }
782 else
783 {
784 OldLegacyTss->Ip = State->InstPtr.LowWord;
785 OldLegacyTss->Flags = State->Flags.LowWord;
786 OldLegacyTss->Ax = State->GeneralRegs[FAST486_REG_EAX].LowWord;
787 OldLegacyTss->Cx = State->GeneralRegs[FAST486_REG_ECX].LowWord;
788 OldLegacyTss->Dx = State->GeneralRegs[FAST486_REG_EDX].LowWord;
789 OldLegacyTss->Bx = State->GeneralRegs[FAST486_REG_EBX].LowWord;
790 OldLegacyTss->Sp = State->GeneralRegs[FAST486_REG_ESP].LowWord;
791 OldLegacyTss->Bp = State->GeneralRegs[FAST486_REG_EBP].LowWord;
792 OldLegacyTss->Si = State->GeneralRegs[FAST486_REG_ESI].LowWord;
793 OldLegacyTss->Di = State->GeneralRegs[FAST486_REG_EDI].LowWord;
794 OldLegacyTss->Es = State->SegmentRegs[FAST486_REG_ES].Selector;
795 OldLegacyTss->Cs = State->SegmentRegs[FAST486_REG_CS].Selector;
796 OldLegacyTss->Ss = State->SegmentRegs[FAST486_REG_SS].Selector;
797 OldLegacyTss->Ds = State->SegmentRegs[FAST486_REG_DS].Selector;
798 OldLegacyTss->Ldtr = State->Ldtr.Selector;
799 }
800
801 /* Write back the old TSS */
802 if (!Fast486WriteLinearMemory(State,
803 State->TaskReg.Base,
804 &OldTss,
805 State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1)
806 ? sizeof(FAST486_TSS) : sizeof(FAST486_LEGACY_TSS),
807 FALSE))
808 {
809 /* Exception occurred */
810 return FALSE;
811 }
812
813 /* Mark the new task as busy */
814 NewTssDescriptor.Signature = FAST486_BUSY_TSS_SIGNATURE;
815
816 /* Write back the new TSS descriptor */
817 if (!Fast486WriteLinearMemory(State,
818 State->Gdtr.Address + GET_SEGMENT_INDEX(Selector),
819 &NewTssDescriptor,
820 sizeof(NewTssDescriptor),
821 FALSE))
822 {
823 /* Exception occurred */
824 return FALSE;
825 }
826
827 /* Set the task switch bit */
828 State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_TS;
829
830 /* Load the task register with the new values */
831 State->TaskReg.Selector = Selector;
832 State->TaskReg.Base = NewTssAddress;
833 State->TaskReg.Limit = NewTssLimit;
834
835 if (NewTssLimit >= (sizeof(FAST486_TSS) - 1))
836 {
837 /* Change the page directory */
838 State->ControlRegisters[FAST486_REG_CR3] = NewTss.Cr3;
839 }
840
841 /* Flush the TLB */
842 Fast486FlushTlb(State);
843
844 /* Update the CPL */
845 if (NewTssLimit >= (sizeof(FAST486_TSS) - 1)) State->Cpl = GET_SEGMENT_RPL(NewTss.Cs);
846 else State->Cpl = GET_SEGMENT_RPL(NewLegacyTss->Cs);
847
848 #ifndef FAST486_NO_PREFETCH
849 /* Context switching invalidates the prefetch */
850 State->PrefetchValid = FALSE;
851 #endif
852
853 /* Load the registers */
854 if (NewTssLimit >= (sizeof(FAST486_TSS) - 1))
855 {
856 State->InstPtr.Long = State->SavedInstPtr.Long = NewTss.Eip;
857 State->Flags.Long = NewTss.Eflags;
858 State->GeneralRegs[FAST486_REG_EAX].Long = NewTss.Eax;
859 State->GeneralRegs[FAST486_REG_ECX].Long = NewTss.Ecx;
860 State->GeneralRegs[FAST486_REG_EDX].Long = NewTss.Edx;
861 State->GeneralRegs[FAST486_REG_EBX].Long = NewTss.Ebx;
862 State->GeneralRegs[FAST486_REG_ESP].Long = NewTss.Esp;
863 State->GeneralRegs[FAST486_REG_EBP].Long = NewTss.Ebp;
864 State->GeneralRegs[FAST486_REG_ESI].Long = NewTss.Esi;
865 State->GeneralRegs[FAST486_REG_EDI].Long = NewTss.Edi;
866 NewEs = NewTss.Es;
867 NewCs = NewTss.Cs;
868 NewSs = NewTss.Ss;
869 NewDs = NewTss.Ds;
870 NewLdtr = NewTss.Ldtr;
871 }
872 else
873 {
874 State->InstPtr.LowWord = State->SavedInstPtr.LowWord = NewLegacyTss->Ip;
875 State->Flags.LowWord = NewLegacyTss->Flags;
876 State->GeneralRegs[FAST486_REG_EAX].LowWord = NewLegacyTss->Ax;
877 State->GeneralRegs[FAST486_REG_ECX].LowWord = NewLegacyTss->Cx;
878 State->GeneralRegs[FAST486_REG_EDX].LowWord = NewLegacyTss->Dx;
879 State->GeneralRegs[FAST486_REG_EBX].LowWord = NewLegacyTss->Bx;
880 State->GeneralRegs[FAST486_REG_ESP].LowWord = NewLegacyTss->Sp;
881 State->GeneralRegs[FAST486_REG_EBP].LowWord = NewLegacyTss->Bp;
882 State->GeneralRegs[FAST486_REG_ESI].LowWord = NewLegacyTss->Si;
883 State->GeneralRegs[FAST486_REG_EDI].LowWord = NewLegacyTss->Di;
884 NewEs = NewLegacyTss->Es;
885 NewCs = NewLegacyTss->Cs;
886 NewSs = NewLegacyTss->Ss;
887 NewDs = NewLegacyTss->Ds;
888 NewLdtr = NewLegacyTss->Ldtr;
889 }
890
891 /* Set the NT flag if nesting */
892 if (Type == FAST486_TASK_CALL) State->Flags.Nt = TRUE;
893
894 if (GET_SEGMENT_INDEX(NewLdtr) != 0)
895 {
896 BOOLEAN Valid;
897 FAST486_SYSTEM_DESCRIPTOR GdtEntry;
898
899 if (NewLdtr & SEGMENT_TABLE_INDICATOR)
900 {
901 /* This selector doesn't point to the GDT */
902 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewLdtr);
903 return FALSE;
904 }
905
906 if (!Fast486ReadDescriptorEntry(State, NewLdtr, &Valid, (PFAST486_GDT_ENTRY)&GdtEntry))
907 {
908 /* Exception occurred */
909 return FALSE;
910 }
911
912 if (!Valid)
913 {
914 /* Invalid selector */
915 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewLdtr);
916 return FALSE;
917 }
918
919 if (GdtEntry.Signature != FAST486_LDT_SIGNATURE)
920 {
921 /* This is not an LDT descriptor */
922 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewLdtr);
923 return FALSE;
924 }
925
926 if (!GdtEntry.Present)
927 {
928 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_TS, NewLdtr);
929 return FALSE;
930 }
931
932 /* Update the LDTR */
933 State->Ldtr.Selector = NewLdtr;
934 State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24);
935 State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16);
936
937 if (GdtEntry.Granularity)
938 {
939 State->Ldtr.Limit <<= 12;
940 State->Ldtr.Limit |= 0x00000FFF;
941 }
942 }
943 else
944 {
945 /* The LDT of this task is empty */
946 RtlZeroMemory(&State->Ldtr, sizeof(State->Ldtr));
947 }
948
949 /* Load the new segments */
950 if (!Fast486LoadSegmentInternal(State, FAST486_REG_CS, NewCs, FAST486_EXCEPTION_TS))
951 {
952 return FALSE;
953 }
954
955 if (!Fast486LoadSegmentInternal(State, FAST486_REG_SS, NewSs, FAST486_EXCEPTION_TS))
956 {
957 return FALSE;
958 }
959
960 if (!Fast486LoadSegmentInternal(State, FAST486_REG_ES, NewEs, FAST486_EXCEPTION_TS))
961 {
962 return FALSE;
963 }
964
965 if (!Fast486LoadSegmentInternal(State, FAST486_REG_DS, NewDs, FAST486_EXCEPTION_TS))
966 {
967 return FALSE;
968 }
969
970 if (NewTssLimit >= (sizeof(FAST486_TSS) - 1))
971 {
972 if (!Fast486LoadSegmentInternal(State,
973 FAST486_REG_FS,
974 NewTss.Fs,
975 FAST486_EXCEPTION_TS))
976 {
977 return FALSE;
978 }
979
980 if (!Fast486LoadSegmentInternal(State,
981 FAST486_REG_GS,
982 NewTss.Gs,
983 FAST486_EXCEPTION_TS))
984 {
985 return FALSE;
986 }
987 }
988
989 return TRUE;
990 }
991
992 BOOLEAN
993 FASTCALL
994 Fast486CallGate(PFAST486_STATE State,
995 PFAST486_CALL_GATE Gate,
996 BOOLEAN Call)
997 {
998 BOOLEAN Valid;
999 FAST486_GDT_ENTRY NewCodeSegment;
1000 BOOLEAN GateSize = (Gate->Type == FAST486_CALL_GATE_SIGNATURE);
1001 FAST486_TSS Tss;
1002 PFAST486_LEGACY_TSS LegacyTss = (PFAST486_LEGACY_TSS)&Tss;
1003 USHORT OldCs = State->SegmentRegs[FAST486_REG_CS].Selector;
1004 ULONG OldEip = State->InstPtr.Long;
1005 USHORT OldCpl = State->Cpl;
1006 USHORT OldSs = State->SegmentRegs[FAST486_REG_SS].Selector;
1007 ULONG OldEsp = State->GeneralRegs[FAST486_REG_ESP].Long;
1008 ULONG ParamBuffer[32]; /* Maximum possible size - 32 DWORDs */
1009 PULONG LongParams = (PULONG)ParamBuffer;
1010 PUSHORT ShortParams = (PUSHORT)ParamBuffer;
1011
1012 if (!Gate->Selector)
1013 {
1014 /* The code segment is NULL */
1015 Fast486Exception(State, FAST486_EXCEPTION_GP);
1016 return FALSE;
1017 }
1018
1019 if (!Fast486ReadDescriptorEntry(State, Gate->Selector, &Valid, &NewCodeSegment))
1020 {
1021 /* Exception occurred */
1022 return FALSE;
1023 }
1024
1025 if (!Valid || (NewCodeSegment.Dpl > Fast486GetCurrentPrivLevel(State)))
1026 {
1027 /* Code segment invalid */
1028 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Gate->Selector);
1029 return FALSE;
1030 }
1031
1032 if (Call && Gate->ParamCount)
1033 {
1034 /* Read the parameters */
1035 if (!Fast486ReadMemory(State,
1036 FAST486_REG_SS,
1037 OldEsp,
1038 FALSE,
1039 ParamBuffer,
1040 Gate->ParamCount * sizeof(ULONG)))
1041 {
1042 /* Exception occurred */
1043 return FALSE;
1044 }
1045 }
1046
1047 /* Check if the new code segment is more privileged */
1048 if (NewCodeSegment.Dpl < OldCpl)
1049 {
1050 if (Call)
1051 {
1052 USHORT NewSs;
1053 ULONG NewEsp;
1054
1055 /* Read the TSS */
1056 if (!Fast486ReadLinearMemory(State,
1057 State->TaskReg.Base,
1058 &Tss,
1059 State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1)
1060 ? sizeof(FAST486_TSS) : sizeof(FAST486_LEGACY_TSS),
1061 FALSE))
1062 {
1063 /* Exception occurred */
1064 return FALSE;
1065 }
1066
1067 /* Switch to the new privilege level */
1068 State->Cpl = NewCodeSegment.Dpl;
1069
1070 /* Check the new (higher) privilege level */
1071 switch (State->Cpl)
1072 {
1073 case 0:
1074 {
1075 if (State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1))
1076 {
1077 NewSs = Tss.Ss0;
1078 NewEsp = Tss.Esp0;
1079 }
1080 else
1081 {
1082 NewSs = LegacyTss->Ss0;
1083 NewEsp = LegacyTss->Sp0;
1084 }
1085
1086 break;
1087 }
1088
1089 case 1:
1090 {
1091 if (State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1))
1092 {
1093 NewSs = Tss.Ss1;
1094 NewEsp = Tss.Esp1;
1095 }
1096 else
1097 {
1098 NewSs = LegacyTss->Ss1;
1099 NewEsp = LegacyTss->Sp1;
1100 }
1101
1102 break;
1103 }
1104
1105 case 2:
1106 {
1107 if (State->TaskReg.Limit >= (sizeof(FAST486_TSS) - 1))
1108 {
1109 NewSs = Tss.Ss2;
1110 NewEsp = Tss.Esp2;
1111 }
1112 else
1113 {
1114 NewSs = LegacyTss->Ss2;
1115 NewEsp = LegacyTss->Sp2;
1116 }
1117
1118 break;
1119 }
1120
1121 default:
1122 {
1123 /* Should never reach here! */
1124 ASSERT(FALSE);
1125 }
1126 }
1127
1128 if (!Fast486LoadSegment(State, FAST486_REG_SS, NewSs))
1129 {
1130 /* Exception occurred */
1131 return FALSE;
1132 }
1133
1134 State->GeneralRegs[FAST486_REG_ESP].Long = NewEsp;
1135 }
1136 else if (!NewCodeSegment.DirConf)
1137 {
1138 /* This is not allowed for jumps */
1139 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Gate->Selector);
1140 return FALSE;
1141 }
1142 }
1143
1144 /* Load new CS */
1145 if (!Fast486LoadSegment(State, FAST486_REG_CS, Gate->Selector))
1146 {
1147 /* An exception occurred during the jump */
1148 return FALSE;
1149 }
1150
1151 /* Set the instruction pointer */
1152 if (GateSize) State->InstPtr.Long = MAKELONG(Gate->Offset, Gate->OffsetHigh);
1153 else State->InstPtr.Long = Gate->Offset;
1154
1155 if (Call)
1156 {
1157 INT i;
1158
1159 /* Check if the new code segment is more privileged (again) */
1160 if (NewCodeSegment.Dpl < OldCpl)
1161 {
1162 /* Push SS selector */
1163 if (!Fast486StackPushInternal(State, GateSize, OldSs)) return FALSE;
1164
1165 /* Push stack pointer */
1166 if (!Fast486StackPushInternal(State, GateSize, OldEsp)) return FALSE;
1167 }
1168
1169 /* Push the parameters in reverse order */
1170 for (i = Gate->ParamCount - 1; i >= 0; i--)
1171 {
1172 if (!Fast486StackPushInternal(State,
1173 GateSize,
1174 GateSize ? LongParams[i] : ShortParams[i]))
1175 {
1176 /* Exception occurred */
1177 return FALSE;
1178 }
1179 }
1180
1181 /* Push CS selector */
1182 if (!Fast486StackPushInternal(State, GateSize, OldCs)) return FALSE;
1183
1184 /* Push the instruction pointer */
1185 if (!Fast486StackPushInternal(State, GateSize, OldEip)) return FALSE;
1186 }
1187
1188 return TRUE;
1189 }
1190
1191 /* EOF */