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 */ 1314