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