1/* 2 * Fast486 386/486 CPU Emulation Library 3 * common.inl 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#include "common.h" 23#include "fpu.h" 24 25/* PUBLIC FUNCTIONS ***********************************************************/ 26 27#if defined (__GNUC__) 28 #define CountLeadingZeros64(x) __builtin_clzll(x) 29 30/* 31#elif (_MSC_VER >= 1500) && defined(_WIN64) 32 #define CountLeadingZeros64(x) __lzcnt64(x) 33#elif (_MSC_VER >= 1500) 34 #define CountLeadingZeros64(x) ((x) > 0xFFFFFFFFULL) ? __lzcnt((x) >> 32) \ 35 : (__lzcnt(x) + 32) 36*/ 37 38#else 39 FORCEINLINE 40 ULONG 41 CountLeadingZeros64(ULONGLONG Value) 42 { 43 ULONG Count = 0; 44 Value = ~Value; 45 while ((LONGLONG)Value < 0) 46 { 47 Count++; 48 Value <<= 1; 49 } 50 return Count; 51 } 52#endif 53 54FORCEINLINE 55UINT 56FASTCALL 57Fast486GetCurrentPrivLevel(PFAST486_STATE State) 58{ 59 /* Return the CPL, or 3 if we're in virtual 8086 mode */ 60 return (!State->Flags.Vm) ? State->Cpl : 3; 61} 62 63FORCEINLINE 64ULONG 65FASTCALL 66Fast486GetPageTableEntry(PFAST486_STATE State, 67 ULONG VirtualAddress, 68 BOOLEAN MarkAsDirty) 69{ 70 ULONG PdeIndex = GET_ADDR_PDE(VirtualAddress); 71 ULONG PteIndex = GET_ADDR_PTE(VirtualAddress); 72 FAST486_PAGE_DIR DirectoryEntry; 73 FAST486_PAGE_TABLE TableEntry; 74 ULONG PageDirectory = State->ControlRegisters[FAST486_REG_CR3]; 75 76 if ((State->Tlb != NULL) 77 && (State->Tlb[VirtualAddress >> 12] != INVALID_TLB_FIELD)) 78 { 79 /* Return the cached entry */ 80 return State->Tlb[VirtualAddress >> 12]; 81 } 82 83 /* Read the directory entry */ 84 State->MemReadCallback(State, 85 PageDirectory + PdeIndex * sizeof(ULONG), 86 &DirectoryEntry.Value, 87 sizeof(DirectoryEntry)); 88 89 /* Make sure it is present */ 90 if (!DirectoryEntry.Present) return 0; 91 92 /* Was the directory entry accessed before? */ 93 if (!DirectoryEntry.Accessed) 94 { 95 /* Well, it is now */ 96 DirectoryEntry.Accessed = TRUE; 97 98 /* Write back the directory entry */ 99 State->MemWriteCallback(State, 100 PageDirectory + PdeIndex * sizeof(ULONG), 101 &DirectoryEntry.Value, 102 sizeof(DirectoryEntry)); 103 } 104 105 /* Read the table entry */ 106 State->MemReadCallback(State, 107 (DirectoryEntry.TableAddress << 12) 108 + PteIndex * sizeof(ULONG), 109 &TableEntry.Value, 110 sizeof(TableEntry)); 111 112 /* Make sure it is present */ 113 if (!TableEntry.Present) return 0; 114 115 /* Do we need to change any flags? */ 116 if (!TableEntry.Accessed || (MarkAsDirty && !TableEntry.Dirty)) 117 { 118 /* Mark it as accessed and optionally dirty too */ 119 TableEntry.Accessed = TRUE; 120 if (MarkAsDirty) TableEntry.Dirty = TRUE; 121 122 /* Write back the table entry */ 123 State->MemWriteCallback(State, 124 (DirectoryEntry.TableAddress << 12) 125 + PteIndex * sizeof(ULONG), 126 &TableEntry.Value, 127 sizeof(TableEntry)); 128 } 129 130 /* 131 * The resulting permissions depend on the permissions 132 * in the page directory table too 133 */ 134 TableEntry.Writeable &= DirectoryEntry.Writeable; 135 TableEntry.Usermode &= DirectoryEntry.Usermode; 136 137 if (State->Tlb != NULL) 138 { 139 /* Set the TLB entry */ 140 State->Tlb[VirtualAddress >> 12] = TableEntry.Value; 141 State->TlbEmpty = FALSE; 142 } 143 144 /* Return the table entry */ 145 return TableEntry.Value; 146} 147 148FORCEINLINE 149VOID 150FASTCALL 151Fast486FlushTlb(PFAST486_STATE State) 152{ 153 if (!State->Tlb || State->TlbEmpty) return; 154 RtlFillMemory(State->Tlb, NUM_TLB_ENTRIES * sizeof(ULONG), 0xFF); 155 State->TlbEmpty = TRUE; 156} 157 158FORCEINLINE 159BOOLEAN 160FASTCALL 161Fast486ReadLinearMemory(PFAST486_STATE State, 162 ULONG LinearAddress, 163 PVOID Buffer, 164 ULONG Size, 165 BOOLEAN CheckPrivilege) 166{ 167 /* Check if paging is enabled */ 168 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG) 169 { 170 ULONG Page; 171 FAST486_PAGE_TABLE TableEntry; 172 INT Cpl = Fast486GetCurrentPrivLevel(State); 173 ULONG BufferOffset = 0; 174 175 for (Page = PAGE_ALIGN(LinearAddress); 176 Page <= PAGE_ALIGN(LinearAddress + Size - 1); 177 Page += FAST486_PAGE_SIZE) 178 { 179 ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE; 180 181 /* Get the table entry */ 182 TableEntry.Value = Fast486GetPageTableEntry(State, Page, FALSE); 183 184 /* Check if this is the first page */ 185 if (Page == PAGE_ALIGN(LinearAddress)) 186 { 187 /* Start reading from the offset from the beginning of the page */ 188 PageOffset = PAGE_OFFSET(LinearAddress); 189 PageLength -= PageOffset; 190 } 191 192 if (CheckPrivilege && (!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0)))) 193 { 194 State->ControlRegisters[FAST486_REG_CR2] = Page + PageOffset; 195 196 /* Exception */ 197 Fast486ExceptionWithErrorCode(State, 198 FAST486_EXCEPTION_PF, 199 TableEntry.Present | (State->Cpl ? 0x04 : 0)); 200 return FALSE; 201 } 202 203 /* Check if this is the last page */ 204 if (Page == PAGE_ALIGN(LinearAddress + Size - 1)) 205 { 206 /* Read only a part of the page */ 207 PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1; 208 } 209 210 /* Read the memory */ 211 State->MemReadCallback(State, 212 (TableEntry.Address << 12) | PageOffset, 213 (PVOID)((ULONG_PTR)Buffer + BufferOffset), 214 PageLength); 215 216 BufferOffset += PageLength; 217 } 218 } 219 else 220 { 221 /* Read the memory */ 222 State->MemReadCallback(State, LinearAddress, Buffer, Size); 223 } 224 225 return TRUE; 226} 227 228FORCEINLINE 229BOOLEAN 230FASTCALL 231Fast486WriteLinearMemory(PFAST486_STATE State, 232 ULONG LinearAddress, 233 PVOID Buffer, 234 ULONG Size, 235 BOOLEAN CheckPrivilege) 236{ 237 /* Check if paging is enabled */ 238 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PG) 239 { 240 ULONG Page; 241 FAST486_PAGE_TABLE TableEntry; 242 INT Cpl = Fast486GetCurrentPrivLevel(State); 243 ULONG BufferOffset = 0; 244 245 for (Page = PAGE_ALIGN(LinearAddress); 246 Page <= PAGE_ALIGN(LinearAddress + Size - 1); 247 Page += FAST486_PAGE_SIZE) 248 { 249 ULONG PageOffset = 0, PageLength = FAST486_PAGE_SIZE; 250 251 /* Get the table entry */ 252 TableEntry.Value = Fast486GetPageTableEntry(State, Page, TRUE); 253 254 /* Check if this is the first page */ 255 if (Page == PAGE_ALIGN(LinearAddress)) 256 { 257 /* Start writing from the offset from the beginning of the page */ 258 PageOffset = PAGE_OFFSET(LinearAddress); 259 PageLength -= PageOffset; 260 } 261 262 if (CheckPrivilege 263 && ((!TableEntry.Present || (!TableEntry.Usermode && (Cpl > 0))) 264 || ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_WP) 265 && !TableEntry.Writeable))) 266 { 267 State->ControlRegisters[FAST486_REG_CR2] = Page + PageOffset; 268 269 /* Exception */ 270 Fast486ExceptionWithErrorCode(State, 271 FAST486_EXCEPTION_PF, 272 TableEntry.Present | 0x02 | (State->Cpl ? 0x04 : 0)); 273 return FALSE; 274 } 275 276 /* Check if this is the last page */ 277 if (Page == PAGE_ALIGN(LinearAddress + Size - 1)) 278 { 279 /* Write only a part of the page */ 280 PageLength = PAGE_OFFSET(LinearAddress + Size - 1) - PageOffset + 1; 281 } 282 283 /* Write the memory */ 284 State->MemWriteCallback(State, 285 (TableEntry.Address << 12) | PageOffset, 286 (PVOID)((ULONG_PTR)Buffer + BufferOffset), 287 PageLength); 288 289 BufferOffset += PageLength; 290 } 291 } 292 else 293 { 294 /* Write the memory */ 295 State->MemWriteCallback(State, LinearAddress, Buffer, Size); 296 } 297 298 return TRUE; 299} 300 301FORCEINLINE 302VOID 303FASTCALL 304Fast486Exception(PFAST486_STATE State, 305 FAST486_EXCEPTIONS ExceptionCode) 306{ 307 /* Call the internal function */ 308 Fast486ExceptionWithErrorCode(State, ExceptionCode, 0); 309} 310 311FORCEINLINE 312BOOLEAN 313FASTCALL 314Fast486StackPushInternal(PFAST486_STATE State, BOOLEAN Size, ULONG Value) 315{ 316 ULONG StackPointer = State->GeneralRegs[FAST486_REG_ESP].Long; 317 318 if (Size) 319 { 320 /* Check if ESP is between 1 and 3 */ 321 if (State->GeneralRegs[FAST486_REG_ESP].Long >= 1 322 && State->GeneralRegs[FAST486_REG_ESP].Long <= 3) 323 { 324 Fast486Exception(State, FAST486_EXCEPTION_SS); 325 return FALSE; 326 } 327 328 /* Store the value in SS:[ESP - 4] */ 329 if (!Fast486WriteMemory(State, 330 FAST486_REG_SS, 331 State->SegmentRegs[FAST486_REG_SS].Size 332 ? StackPointer - sizeof(ULONG) 333 : LOWORD(StackPointer - sizeof(ULONG)), 334 &Value, 335 sizeof(ULONG))) 336 { 337 /* Exception occurred */ 338 return FALSE; 339 } 340 341 if (State->SegmentRegs[FAST486_REG_SS].Size) 342 { 343 /* Subtract ESP by 4 */ 344 State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(ULONG); 345 } 346 else 347 { 348 /* Subtract SP by 4 */ 349 State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(ULONG); 350 } 351 } 352 else 353 { 354 /* Check if SP is 1 */ 355 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 1) 356 { 357 Fast486Exception(State, FAST486_EXCEPTION_SS); 358 return FALSE; 359 } 360 361 /* Store the value in SS:[SP - 2] */ 362 if (!Fast486WriteMemory(State, 363 FAST486_REG_SS, 364 State->SegmentRegs[FAST486_REG_SS].Size 365 ? StackPointer - sizeof(USHORT) 366 : LOWORD(StackPointer - sizeof(USHORT)), 367 &Value, 368 sizeof(USHORT))) 369 { 370 /* Exception occurred */ 371 return FALSE; 372 } 373 374 if (State->SegmentRegs[FAST486_REG_SS].Size) 375 { 376 /* Subtract ESP by 2 */ 377 State->GeneralRegs[FAST486_REG_ESP].Long -= sizeof(USHORT); 378 } 379 else 380 { 381 /* Subtract SP by 2 */ 382 State->GeneralRegs[FAST486_REG_ESP].LowWord -= sizeof(USHORT); 383 } 384 } 385 386 return TRUE; 387} 388 389FORCEINLINE 390BOOLEAN 391FASTCALL 392Fast486StackPush(PFAST486_STATE State, ULONG Value) 393{ 394 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size; 395 396 /* The OPSIZE prefix toggles the size */ 397 TOGGLE_OPSIZE(Size); 398 399 /* Call the internal function */ 400 return Fast486StackPushInternal(State, Size, Value); 401} 402 403FORCEINLINE 404BOOLEAN 405FASTCALL 406Fast486StackPop(PFAST486_STATE State, 407 PULONG Value) 408{ 409 BOOLEAN Size = State->SegmentRegs[FAST486_REG_CS].Size; 410 411 /* The OPSIZE prefix toggles the size */ 412 TOGGLE_OPSIZE(Size); 413 414 if (Size) 415 { 416 /* 32-bit size */ 417 ULONG LongValue; 418 419 /* Check if ESP is 0xFFFFFFFF */ 420 if (State->GeneralRegs[FAST486_REG_ESP].Long == 0xFFFFFFFF) 421 { 422 Fast486Exception(State, FAST486_EXCEPTION_SS); 423 return FALSE; 424 } 425 426 /* Read the value from SS:ESP */ 427 if (!Fast486ReadMemory(State, 428 FAST486_REG_SS, 429 State->SegmentRegs[FAST486_REG_SS].Size 430 ? State->GeneralRegs[FAST486_REG_ESP].Long 431 : State->GeneralRegs[FAST486_REG_ESP].LowWord, 432 FALSE, 433 &LongValue, 434 sizeof(LongValue))) 435 { 436 /* An exception occurred */ 437 return FALSE; 438 } 439 440 if (State->SegmentRegs[FAST486_REG_SS].Size) 441 { 442 /* Increment ESP by 4 */ 443 State->GeneralRegs[FAST486_REG_ESP].Long += sizeof(ULONG); 444 } 445 else 446 { 447 /* Increment SP by 4 */ 448 State->GeneralRegs[FAST486_REG_ESP].LowWord += sizeof(ULONG); 449 } 450 451 /* Store the value in the result */ 452 *Value = LongValue; 453 } 454 else 455 { 456 /* 16-bit size */ 457 USHORT ShortValue; 458 459 /* Check if SP is 0xFFFF */ 460 if (State->GeneralRegs[FAST486_REG_ESP].LowWord == 0xFFFF) 461 { 462 Fast486Exception(State, FAST486_EXCEPTION_SS); 463 return FALSE; 464 } 465 466 /* Read the value from SS:SP */ 467 if (!Fast486ReadMemory(State, 468 FAST486_REG_SS, 469 State->SegmentRegs[FAST486_REG_SS].Size 470 ? State->GeneralRegs[FAST486_REG_ESP].Long 471 : State->GeneralRegs[FAST486_REG_ESP].LowWord, 472 FALSE, 473 &ShortValue, 474 sizeof(ShortValue))) 475 { 476 /* An exception occurred */ 477 return FALSE; 478 } 479 480 if (State->SegmentRegs[FAST486_REG_SS].Size) 481 { 482 /* Increment ESP by 2 */ 483 State->GeneralRegs[FAST486_REG_ESP].Long += sizeof(USHORT); 484 } 485 else 486 { 487 /* Increment SP by 2 */ 488 State->GeneralRegs[FAST486_REG_ESP].LowWord += sizeof(USHORT); 489 } 490 491 /* Store the value in the result */ 492 *Value = ShortValue; 493 } 494 495 return TRUE; 496} 497 498FORCEINLINE 499BOOLEAN 500FASTCALL 501Fast486ReadDescriptorEntry(PFAST486_STATE State, 502 USHORT Selector, 503 PBOOLEAN EntryValid, 504 PFAST486_GDT_ENTRY Entry) 505{ 506 if (!(Selector & SEGMENT_TABLE_INDICATOR)) 507 { 508 /* Make sure the GDT contains the entry */ 509 if (GET_SEGMENT_INDEX(Selector) >= (State->Gdtr.Size + 1u)) 510 { 511 *EntryValid = FALSE; 512 return TRUE; 513 } 514 515 /* Read the GDT */ 516 if (!Fast486ReadLinearMemory(State, 517 State->Gdtr.Address 518 + GET_SEGMENT_INDEX(Selector), 519 Entry, 520 sizeof(*Entry), 521 FALSE)) 522 { 523 /* Exception occurred */ 524 *EntryValid = FALSE; 525 return FALSE; 526 } 527 } 528 else 529 { 530 /* Make sure the LDT contains the entry */ 531 if (GET_SEGMENT_INDEX(Selector) >= (State->Ldtr.Limit + 1u)) 532 { 533 *EntryValid = FALSE; 534 return TRUE; 535 } 536 537 /* Read the LDT */ 538 if (!Fast486ReadLinearMemory(State, 539 State->Ldtr.Base 540 + GET_SEGMENT_INDEX(Selector), 541 Entry, 542 sizeof(*Entry), 543 FALSE)) 544 { 545 /* Exception occurred */ 546 *EntryValid = FALSE; 547 return FALSE; 548 } 549 } 550 551 *EntryValid = TRUE; 552 return TRUE; 553} 554 555FORCEINLINE 556BOOLEAN 557FASTCALL 558Fast486LoadSegmentInternal(PFAST486_STATE State, 559 FAST486_SEG_REGS Segment, 560 USHORT Selector, 561 FAST486_EXCEPTIONS Exception) 562{ 563 PFAST486_SEG_REG CachedDescriptor; 564 BOOLEAN Valid; 565 FAST486_GDT_ENTRY GdtEntry; 566 567 ASSERT(Segment < FAST486_NUM_SEG_REGS); 568 569 /* Get the cached descriptor */ 570 CachedDescriptor = &State->SegmentRegs[Segment]; 571 572 /* Check for protected mode */ 573 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) 574 { 575 /* Check for VM86 mode */ 576 if (State->Flags.Vm) 577 { 578 /* Update the cached descriptor with VM86 values */ 579 CachedDescriptor->Selector = Selector; 580 CachedDescriptor->Base = Selector << 4; 581 CachedDescriptor->Limit = 0xFFFF; 582 CachedDescriptor->ReadWrite = TRUE; 583 CachedDescriptor->DirConf = FALSE; 584 CachedDescriptor->SystemType = TRUE; 585 CachedDescriptor->Dpl = CachedDescriptor->Rpl = 3; 586 CachedDescriptor->Present = TRUE; 587 CachedDescriptor->Size = FALSE; 588 return TRUE; 589 } 590 591 if (!Fast486ReadDescriptorEntry(State, Selector, &Valid, &GdtEntry)) 592 { 593 /* Exception occurred */ 594 return FALSE; 595 } 596 597 if (!Valid) 598 { 599 /* Invalid selector */ 600 Fast486ExceptionWithErrorCode(State, Exception, Selector); 601 return FALSE; 602 } 603 604 if (Segment == FAST486_REG_SS) 605 { 606 /* Loading the stack segment */ 607 608 if (!(Selector & SEGMENT_TABLE_INDICATOR) && GET_SEGMENT_INDEX(Selector) == 0) 609 { 610 Fast486Exception(State, Exception); 611 return FALSE; 612 } 613 614 if (!GdtEntry.SystemType) 615 { 616 /* This is a special descriptor */ 617 Fast486ExceptionWithErrorCode(State, Exception, Selector); 618 return FALSE; 619 } 620 621 if (GdtEntry.Executable || !GdtEntry.ReadWrite) 622 { 623 Fast486ExceptionWithErrorCode(State, Exception, Selector); 624 return FALSE; 625 } 626 627 if ((GET_SEGMENT_RPL(Selector) != Fast486GetCurrentPrivLevel(State)) 628 || (GET_SEGMENT_RPL(Selector) != GdtEntry.Dpl)) 629 { 630 Fast486ExceptionWithErrorCode(State, Exception, Selector); 631 return FALSE; 632 } 633 634 if (!GdtEntry.Present) 635 { 636 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_SS, Selector); 637 return FALSE; 638 } 639 } 640 else if (Segment == FAST486_REG_CS) 641 { 642 /* Loading the code segment */ 643 644#ifndef FAST486_NO_PREFETCH 645 /* Invalidate the prefetch */ 646 State->PrefetchValid = FALSE; 647#endif 648 649 if (!(Selector & SEGMENT_TABLE_INDICATOR) && GET_SEGMENT_INDEX(Selector) == 0) 650 { 651 Fast486Exception(State, Exception); 652 return FALSE; 653 } 654 655 if (!GdtEntry.SystemType) 656 { 657 /* Must be a segment descriptor */ 658 Fast486ExceptionWithErrorCode(State, Exception, Selector); 659 return FALSE; 660 } 661 662 if (!GdtEntry.Present) 663 { 664 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector); 665 return FALSE; 666 } 667 668 if (!GdtEntry.Executable) 669 { 670 Fast486ExceptionWithErrorCode(State, Exception, Selector); 671 return FALSE; 672 } 673 674 if (GdtEntry.DirConf) 675 { 676 /* Conforming Code Segment */ 677 678 if (GdtEntry.Dpl > Fast486GetCurrentPrivLevel(State)) 679 { 680 /* Must be accessed from lower-privileged code */ 681 Fast486ExceptionWithErrorCode(State, Exception, Selector); 682 return FALSE; 683 } 684 } 685 else 686 { 687 /* Regular code segment */ 688 689 if ((GET_SEGMENT_RPL(Selector) < Fast486GetCurrentPrivLevel(State))) 690 { 691 Fast486ExceptionWithErrorCode(State, Exception, Selector); 692 return FALSE; 693 } 694 } 695 } 696 else 697 { 698 /* Loading a data segment */ 699 700 if (GET_SEGMENT_INDEX(Selector) != 0 || (Selector & SEGMENT_TABLE_INDICATOR)) 701 { 702 if (!GdtEntry.SystemType) 703 { 704 /* This is a special descriptor */ 705 Fast486ExceptionWithErrorCode(State, Exception, Selector); 706 return FALSE; 707 } 708 709 if ((GET_SEGMENT_RPL(Selector) > GdtEntry.Dpl) 710 || (Fast486GetCurrentPrivLevel(State) > GdtEntry.Dpl)) 711 { 712 Fast486ExceptionWithErrorCode(State, Exception, Selector); 713 return FALSE; 714 } 715 716 if (!GdtEntry.Present) 717 { 718 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector); 719 return FALSE; 720 } 721 } 722 else 723 { 724 /* This is a NULL selector */ 725 RtlZeroMemory(&GdtEntry, sizeof(GdtEntry)); 726 } 727 } 728 729 /* Update the cache entry */ 730 CachedDescriptor->Selector = Selector; 731 CachedDescriptor->Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24); 732 CachedDescriptor->Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16); 733 CachedDescriptor->Accessed = GdtEntry.Accessed; 734 CachedDescriptor->ReadWrite = GdtEntry.ReadWrite; 735 CachedDescriptor->DirConf = GdtEntry.DirConf; 736 CachedDescriptor->Executable = GdtEntry.Executable; 737 CachedDescriptor->SystemType = GdtEntry.SystemType; 738 CachedDescriptor->Rpl = GET_SEGMENT_RPL(Selector); 739 CachedDescriptor->Dpl = GdtEntry.Dpl; 740 CachedDescriptor->Present = GdtEntry.Present; 741 CachedDescriptor->Size = GdtEntry.Size; 742 743 /* Check for page granularity */ 744 if (GdtEntry.Granularity) 745 { 746 CachedDescriptor->Limit <<= 12; 747 CachedDescriptor->Limit |= 0x00000FFF; 748 } 749 } 750 else 751 { 752 /* Update the selector and base */ 753 CachedDescriptor->Selector = Selector; 754 CachedDescriptor->Base = Selector << 4; 755 } 756 757 return TRUE; 758} 759 760FORCEINLINE 761BOOLEAN 762FASTCALL 763Fast486LoadSegment(PFAST486_STATE State, 764 FAST486_SEG_REGS Segment, 765 USHORT Selector) 766{ 767 return Fast486LoadSegmentInternal(State, 768 Segment, 769 Selector, 770 FAST486_EXCEPTION_GP); 771} 772 773FORCEINLINE 774BOOLEAN 775FASTCALL 776Fast486ProcessGate(PFAST486_STATE State, USHORT Selector, ULONG Offset, BOOLEAN Call) 777{ 778 BOOLEAN Valid; 779 FAST486_SYSTEM_DESCRIPTOR Descriptor; 780 781 if (!Fast486ReadDescriptorEntry(State, 782 Selector, 783 &Valid, 784 (PFAST486_GDT_ENTRY)&Descriptor)) 785 { 786 /* Exception occurred */ 787 return FALSE; 788 } 789 790 if (!Valid) 791 { 792 /* Invalid selector */ 793 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); 794 return FALSE; 795 } 796 797 switch (Descriptor.Signature) 798 { 799 case FAST486_TASK_GATE_SIGNATURE: 800 { 801 Fast486TaskSwitch(State, 802 Call ? FAST486_TASK_CALL : FAST486_TASK_JUMP, 803 ((PFAST486_IDT_ENTRY)&Descriptor)->Selector); 804 805 return FALSE; 806 } 807 808 case FAST486_TSS_16_SIGNATURE: 809 case FAST486_BUSY_TSS_16_SIGNATURE: 810 case FAST486_TSS_SIGNATURE: 811 case FAST486_BUSY_TSS_SIGNATURE: 812 { 813 Fast486TaskSwitch(State, 814 Call ? FAST486_TASK_CALL : FAST486_TASK_JUMP, 815 Selector); 816 817 return FALSE; 818 } 819 820 case FAST486_CALL_GATE_16_SIGNATURE: 821 case FAST486_CALL_GATE_SIGNATURE: 822 { 823 if ((Descriptor.Dpl < Fast486GetCurrentPrivLevel(State)) 824 && (Descriptor.Dpl < GET_SEGMENT_RPL(Selector))) 825 { 826 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); 827 return FALSE; 828 } 829 830 if (!Descriptor.Present) 831 { 832 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_NP, Selector); 833 return FALSE; 834 } 835 836 Fast486CallGate(State, (PFAST486_CALL_GATE)&Descriptor, Call); 837 838 /* The gate has been processed here, so return FALSE */ 839 return FALSE; 840 } 841 842 default: 843 { 844 /* Security check for jumps and calls only */ 845 if (State->Cpl != Descriptor.Dpl) 846 { 847 Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); 848 return FALSE; 849 } 850 851 return TRUE; 852 } 853 } 854} 855 856FORCEINLINE 857BOOLEAN 858FASTCALL 859Fast486FetchByte(PFAST486_STATE State, 860 PUCHAR Data) 861{ 862 PFAST486_SEG_REG CachedDescriptor; 863 ULONG Offset; 864#ifndef FAST486_NO_PREFETCH 865 ULONG LinearAddress; 866#endif 867 868 /* Get the cached descriptor of CS */ 869 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS]; 870 871 Offset = (CachedDescriptor->Size) ? State->InstPtr.Long 872 : State->InstPtr.LowWord; 873#ifndef FAST486_NO_PREFETCH 874 LinearAddress = CachedDescriptor->Base + Offset; 875 876 if (State->PrefetchValid 877 && (LinearAddress >= State->PrefetchAddress) 878 && ((LinearAddress + sizeof(UCHAR)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE))) 879 { 880 *Data = *(PUCHAR)&State->PrefetchCache[LinearAddress - State->PrefetchAddress]; 881 } 882 else 883#endif 884 { 885 /* Read from memory */ 886 if (!Fast486ReadMemory(State, 887 FAST486_REG_CS, 888 Offset, 889 TRUE, 890 Data, 891 sizeof(UCHAR))) 892 { 893 /* Exception occurred during instruction fetch */ 894 return FALSE; 895 } 896 } 897 898 /* Advance the instruction pointer */ 899 if (CachedDescriptor->Size) State->InstPtr.Long++; 900 else State->InstPtr.LowWord++; 901 902 return TRUE; 903} 904 905FORCEINLINE 906BOOLEAN 907FASTCALL 908Fast486FetchWord(PFAST486_STATE State, 909 PUSHORT Data) 910{ 911 PFAST486_SEG_REG CachedDescriptor; 912 ULONG Offset; 913#ifndef FAST486_NO_PREFETCH 914 ULONG LinearAddress; 915#endif 916 917 /* Get the cached descriptor of CS */ 918 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS]; 919 920 Offset = (CachedDescriptor->Size) ? State->InstPtr.Long 921 : State->InstPtr.LowWord; 922 923#ifndef FAST486_NO_PREFETCH 924 LinearAddress = CachedDescriptor->Base + Offset; 925 926 if (State->PrefetchValid 927 && (LinearAddress >= State->PrefetchAddress) 928 && ((LinearAddress + sizeof(USHORT)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE))) 929 { 930 *Data = *(PUSHORT)&State->PrefetchCache[LinearAddress - State->PrefetchAddress]; 931 } 932 else 933#endif 934 { 935 /* Read from memory */ 936 // FIXME: Fix byte order on big-endian machines 937 if (!Fast486ReadMemory(State, 938 FAST486_REG_CS, 939 Offset, 940 TRUE, 941 Data, 942 sizeof(USHORT))) 943 { 944 /* Exception occurred during instruction fetch */ 945 return FALSE; 946 } 947 } 948 949 /* Advance the instruction pointer */ 950 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(USHORT); 951 else State->InstPtr.LowWord += sizeof(USHORT); 952 953 return TRUE; 954} 955 956FORCEINLINE 957BOOLEAN 958FASTCALL 959Fast486FetchDword(PFAST486_STATE State, 960 PULONG Data) 961{ 962 PFAST486_SEG_REG CachedDescriptor; 963 ULONG Offset; 964#ifndef FAST486_NO_PREFETCH 965 ULONG LinearAddress; 966#endif 967 968 /* Get the cached descriptor of CS */ 969 CachedDescriptor = &State->SegmentRegs[FAST486_REG_CS]; 970 971 Offset = (CachedDescriptor->Size) ? State->InstPtr.Long 972 : State->InstPtr.LowWord; 973 974#ifndef FAST486_NO_PREFETCH 975 LinearAddress = CachedDescriptor->Base + Offset; 976 977 if (State->PrefetchValid 978 && (LinearAddress >= State->PrefetchAddress) 979 && ((LinearAddress + sizeof(ULONG)) <= (State->PrefetchAddress + FAST486_CACHE_SIZE))) 980 { 981 *Data = *(PULONG)&State->PrefetchCache[LinearAddress - State->PrefetchAddress]; 982 } 983 else 984#endif 985 { 986 /* Read from memory */ 987 // FIXME: Fix byte order on big-endian machines 988 if (!Fast486ReadMemory(State, 989 FAST486_REG_CS, 990 Offset, 991 TRUE, 992 Data, 993 sizeof(ULONG))) 994 { 995 /* Exception occurred during instruction fetch */ 996 return FALSE; 997 } 998 } 999 1000 /* Advance the instruction pointer */ 1001 if (CachedDescriptor->Size) State->InstPtr.Long += sizeof(ULONG); 1002 else State->InstPtr.LowWord += sizeof(ULONG); 1003 1004 return TRUE; 1005} 1006 1007FORCEINLINE 1008BOOLEAN 1009FASTCALL 1010Fast486CalculateParity(UCHAR Number) 1011{ 1012 // See http://graphics.stanford.edu/~seander/bithacks.html#ParityLookupTable too... 1013 return (0x9669 >> ((Number & 0x0F) ^ (Number >> 4))) & 1; 1014} 1015 1016FORCEINLINE 1017BOOLEAN 1018FASTCALL 1019Fast486ParseModRegRm(PFAST486_STATE State, 1020 BOOLEAN AddressSize, 1021 PFAST486_MOD_REG_RM ModRegRm) 1022{ 1023 UCHAR ModRmByte, Mode, RegMem; 1024 1025 /* Fetch the MOD REG R/M byte */ 1026 if (!Fast486FetchByte(State, &ModRmByte)) 1027 { 1028 /* Exception occurred */ 1029 return FALSE; 1030 } 1031 1032 /* Unpack the mode and R/M */ 1033 Mode = ModRmByte >> 6; 1034 RegMem = ModRmByte & 0x07; 1035 1036 /* Set the register operand */ 1037 ModRegRm->Register = (ModRmByte >> 3) & 0x07; 1038 1039 /* Check the mode */ 1040 if (Mode == 3) 1041 { 1042 /* The second operand is also a register */ 1043 ModRegRm->Memory = FALSE; 1044 ModRegRm->SecondRegister = RegMem; 1045 1046 /* Done parsing */ 1047 return TRUE; 1048 } 1049 1050 /* The second operand is memory */ 1051 ModRegRm->Memory = TRUE; 1052 1053 if (AddressSize) 1054 { 1055 if (RegMem == FAST486_REG_ESP) 1056 { 1057 UCHAR SibByte; 1058 ULONG Scale, Index, Base; 1059 1060 /* Fetch the SIB byte */ 1061 if (!Fast486FetchByte(State, &SibByte)) 1062 { 1063 /* Exception occurred */ 1064 return FALSE; 1065 } 1066 1067 /* Unpack the scale, index and base */ 1068 Scale = 1 << (SibByte >> 6); 1069 Index = (SibByte >> 3) & 0x07; 1070 if (Index != FAST486_REG_ESP) Index = State->GeneralRegs[Index].Long; 1071 else Index = 0; 1072 1073 if (((SibByte & 0x07) != FAST486_REG_EBP) || (Mode != 0)) 1074 { 1075 /* Use the register a base */ 1076 Base = State->GeneralRegs[SibByte & 0x07].Long; 1077 } 1078 else 1079 { 1080 /* Fetch the base */ 1081 if (!Fast486FetchDword(State, &Base)) 1082 { 1083 /* Exception occurred */ 1084 return FALSE; 1085 } 1086 } 1087 1088 if (((SibByte & 0x07) == FAST486_REG_ESP) 1089 || ((SibByte & 0x07) == FAST486_REG_EBP && Mode != 0)) 1090 { 1091 /* Check if there is no segment override */ 1092 if (!(State->PrefixFlags & FAST486_PREFIX_SEG)) 1093 { 1094 /* Add a SS: prefix */ 1095 State->PrefixFlags |= FAST486_PREFIX_SEG; 1096 State->SegmentOverride = FAST486_REG_SS; 1097 } 1098 } 1099 1100 /* Calculate the address */ 1101 ModRegRm->MemoryAddress = Base + Index * Scale; 1102 } 1103 else if (RegMem == FAST486_REG_EBP) 1104 { 1105 if (Mode) ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].Long; 1106 else ModRegRm->MemoryAddress = 0; 1107 } 1108 else 1109 { 1110 /* Get the base from the register */ 1111 ModRegRm->MemoryAddress = State->GeneralRegs[RegMem].Long; 1112 } 1113 1114 /* Check if there is no segment override */ 1115 if (!(State->PrefixFlags & FAST486_PREFIX_SEG)) 1116 { 1117 /* Check if the default segment should be SS */ 1118 if ((RegMem == FAST486_REG_EBP) && Mode) 1119 { 1120 /* Add a SS: prefix */ 1121 State->PrefixFlags |= FAST486_PREFIX_SEG; 1122 State->SegmentOverride = FAST486_REG_SS; 1123 } 1124 } 1125 1126 if (Mode == 1) 1127 { 1128 CHAR Offset; 1129 1130 /* Fetch the byte */ 1131 if (!Fast486FetchByte(State, (PUCHAR)&Offset)) 1132 { 1133 /* Exception occurred */ 1134 return FALSE; 1135 } 1136 1137 /* Add the signed offset to the address */ 1138 ModRegRm->MemoryAddress += (LONG)Offset; 1139 } 1140 else if ((Mode == 2) || ((Mode == 0) && (RegMem == FAST486_REG_EBP))) 1141 { 1142 LONG Offset; 1143 1144 /* Fetch the dword */ 1145 if (!Fast486FetchDword(State, (PULONG)&Offset)) 1146 { 1147 /* Exception occurred */ 1148 return FALSE; 1149 } 1150 1151 /* Add the signed offset to the address */ 1152 ModRegRm->MemoryAddress += Offset; 1153 } 1154 } 1155 else 1156 { 1157 /* Check the operand */ 1158 switch (RegMem) 1159 { 1160 case 0: 1161 { 1162 /* [BX + SI] */ 1163 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord 1164 + State->GeneralRegs[FAST486_REG_ESI].LowWord; 1165 break; 1166 } 1167 1168 case 1: 1169 { 1170 /* [BX + DI] */ 1171 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord 1172 + State->GeneralRegs[FAST486_REG_EDI].LowWord; 1173 break; 1174 } 1175 1176 case 2: 1177 { 1178 /* SS:[BP + SI] */ 1179 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord 1180 + State->GeneralRegs[FAST486_REG_ESI].LowWord; 1181 break; 1182 } 1183 1184 case 3: 1185 { 1186 /* SS:[BP + DI] */ 1187 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord 1188 + State->GeneralRegs[FAST486_REG_EDI].LowWord; 1189 break; 1190 } 1191 1192 case 4: 1193 { 1194 /* [SI] */ 1195 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_ESI].LowWord; 1196 break; 1197 } 1198 1199 case 5: 1200 { 1201 /* [DI] */ 1202 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EDI].LowWord; 1203 break; 1204 } 1205 1206 case 6: 1207 { 1208 if (Mode) 1209 { 1210 /* [BP] */ 1211 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBP].LowWord; 1212 } 1213 else 1214 { 1215 /* [constant] (added later) */ 1216 ModRegRm->MemoryAddress = 0; 1217 } 1218 1219 break; 1220 } 1221 1222 case 7: 1223 { 1224 /* [BX] */ 1225 ModRegRm->MemoryAddress = State->GeneralRegs[FAST486_REG_EBX].LowWord; 1226 break; 1227 } 1228 } 1229 1230 /* Check if there is no segment override */ 1231 if (!(State->PrefixFlags & FAST486_PREFIX_SEG)) 1232 { 1233 /* Check if the default segment should be SS */ 1234 if ((RegMem == 2) || (RegMem == 3) || ((RegMem == 6) && Mode)) 1235 { 1236 /* Add a SS: prefix */ 1237 State->PrefixFlags |= FAST486_PREFIX_SEG; 1238 State->SegmentOverride = FAST486_REG_SS; 1239 } 1240 } 1241 1242 if (Mode == 1) 1243 { 1244 CHAR Offset; 1245 1246 /* Fetch the byte */ 1247 if (!Fast486FetchByte(State, (PUCHAR)&Offset)) 1248 { 1249 /* Exception occurred */ 1250 return FALSE; 1251 } 1252 1253 /* Add the signed offset to the address */ 1254 ModRegRm->MemoryAddress += (LONG)Offset; 1255 } 1256 else if ((Mode == 2) || ((Mode == 0) && (RegMem == 6))) 1257 { 1258 SHORT Offset; 1259 1260 /* Fetch the word */ 1261 if (!Fast486FetchWord(State, (PUSHORT)&Offset)) 1262 { 1263 /* Exception occurred */ 1264 return FALSE; 1265 } 1266 1267 /* Add the signed offset to the address */ 1268 ModRegRm->MemoryAddress += (LONG)Offset; 1269 } 1270 1271 /* Clear the top 16 bits */ 1272 ModRegRm->MemoryAddress &= 0x0000FFFF; 1273 } 1274 1275 return TRUE; 1276} 1277 1278FORCEINLINE 1279BOOLEAN 1280FASTCALL 1281Fast486ReadModrmByteOperands(PFAST486_STATE State, 1282 PFAST486_MOD_REG_RM ModRegRm, 1283 PUCHAR RegValue, 1284 PUCHAR RmValue) 1285{ 1286 FAST486_SEG_REGS Segment = FAST486_REG_DS; 1287 1288 if (RegValue) 1289 { 1290 /* Get the register value */ 1291 if (ModRegRm->Register & 0x04) 1292 { 1293 /* AH, CH, DH, BH */ 1294 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].HighByte; 1295 } 1296 else 1297 { 1298 /* AL, CL, DL, BL */ 1299 *RegValue = State->GeneralRegs[ModRegRm->Register & 0x03].LowByte; 1300 } 1301 } 1302 1303 if (RmValue) 1304 { 1305 if (!ModRegRm->Memory) 1306 { 1307 /* Get the second register value */ 1308 if (ModRegRm->SecondRegister & 0x04) 1309 { 1310 /* AH, CH, DH, BH */ 1311 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte; 1312 } 1313 else 1314 { 1315 /* AL, CL, DL, BL */ 1316 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte; 1317 } 1318 } 1319 else 1320 { 1321 /* Check for the segment override */ 1322 if (State->PrefixFlags & FAST486_PREFIX_SEG) 1323 { 1324 /* Use the override segment instead */ 1325 Segment = State->SegmentOverride; 1326 } 1327 1328 /* Read memory */ 1329 if (!Fast486ReadMemory(State, 1330 Segment, 1331 ModRegRm->MemoryAddress, 1332 FALSE, 1333 RmValue, 1334 sizeof(UCHAR))) 1335 { 1336 /* Exception occurred */ 1337 return FALSE; 1338 } 1339 } 1340 } 1341 1342 return TRUE; 1343} 1344 1345FORCEINLINE 1346BOOLEAN 1347FASTCALL 1348Fast486ReadModrmWordOperands(PFAST486_STATE State, 1349 PFAST486_MOD_REG_RM ModRegRm, 1350 PUSHORT RegValue, 1351 PUSHORT RmValue) 1352{ 1353 FAST486_SEG_REGS Segment = FAST486_REG_DS; 1354 1355 if (RegValue) 1356 { 1357 /* Get the register value */ 1358 *RegValue = State->GeneralRegs[ModRegRm->Register].LowWord; 1359 } 1360 1361 if (RmValue) 1362 { 1363 if (!ModRegRm->Memory) 1364 { 1365 /* Get the second register value */ 1366 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].LowWord; 1367 } 1368 else 1369 { 1370 /* Check for the segment override */ 1371 if (State->PrefixFlags & FAST486_PREFIX_SEG) 1372 { 1373 /* Use the override segment instead */ 1374 Segment = State->SegmentOverride; 1375 } 1376 1377 /* Read memory */ 1378 if (!Fast486ReadMemory(State, 1379 Segment, 1380 ModRegRm->MemoryAddress, 1381 FALSE, 1382 RmValue, 1383 sizeof(USHORT))) 1384 { 1385 /* Exception occurred */ 1386 return FALSE; 1387 } 1388 } 1389 } 1390 1391 return TRUE; 1392} 1393 1394FORCEINLINE 1395BOOLEAN 1396FASTCALL 1397Fast486ReadModrmDwordOperands(PFAST486_STATE State, 1398 PFAST486_MOD_REG_RM ModRegRm, 1399 PULONG RegValue, 1400 PULONG RmValue) 1401{ 1402 FAST486_SEG_REGS Segment = FAST486_REG_DS; 1403 1404 if (RegValue) 1405 { 1406 /* Get the register value */ 1407 *RegValue = State->GeneralRegs[ModRegRm->Register].Long; 1408 } 1409 1410 if (RmValue) 1411 { 1412 if (!ModRegRm->Memory) 1413 { 1414 /* Get the second register value */ 1415 *RmValue = State->GeneralRegs[ModRegRm->SecondRegister].Long; 1416 } 1417 else 1418 { 1419 /* Check for the segment override */ 1420 if (State->PrefixFlags & FAST486_PREFIX_SEG) 1421 { 1422 /* Use the override segment instead */ 1423 Segment = State->SegmentOverride; 1424 } 1425 1426 /* Read memory */ 1427 if (!Fast486ReadMemory(State, 1428 Segment, 1429 ModRegRm->MemoryAddress, 1430 FALSE, 1431 RmValue, 1432 sizeof(ULONG))) 1433 { 1434 /* Exception occurred */ 1435 return FALSE; 1436 } 1437 } 1438 } 1439 1440 return TRUE; 1441} 1442 1443FORCEINLINE 1444BOOLEAN 1445FASTCALL 1446Fast486WriteModrmByteOperands(PFAST486_STATE State, 1447 PFAST486_MOD_REG_RM ModRegRm, 1448 BOOLEAN WriteRegister, 1449 UCHAR Value) 1450{ 1451 FAST486_SEG_REGS Segment = FAST486_REG_DS; 1452 1453 if (WriteRegister) 1454 { 1455 /* Store the value in the register */ 1456 if (ModRegRm->Register & 0x04) 1457 { 1458 /* AH, CH, DH, BH */ 1459 State->GeneralRegs[ModRegRm->Register & 0x03].HighByte = Value; 1460 } 1461 else 1462 { 1463 /* AL, CL, DL, BL */ 1464 State->GeneralRegs[ModRegRm->Register & 0x03].LowByte = Value; 1465 } 1466 } 1467 else 1468 { 1469 if (!ModRegRm->Memory) 1470 { 1471 /* Store the value in the second register */ 1472 if (ModRegRm->SecondRegister & 0x04) 1473 { 1474 /* AH, CH, DH, BH */ 1475 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].HighByte = Value; 1476 } 1477 else 1478 { 1479 /* AL, CL, DL, BL */ 1480 State->GeneralRegs[ModRegRm->SecondRegister & 0x03].LowByte = Value; 1481 } 1482 } 1483 else 1484 { 1485 /* Check for the segment override */ 1486 if (State->PrefixFlags & FAST486_PREFIX_SEG) 1487 { 1488 /* Use the override segment instead */ 1489 Segment = State->SegmentOverride; 1490 } 1491 1492 /* Write memory */ 1493 if (!Fast486WriteMemory(State, 1494 Segment, 1495 ModRegRm->MemoryAddress, 1496 &Value, 1497 sizeof(UCHAR))) 1498 { 1499 /* Exception occurred */ 1500 return FALSE; 1501 } 1502 } 1503 } 1504 1505 return TRUE; 1506} 1507 1508FORCEINLINE 1509BOOLEAN 1510FASTCALL 1511Fast486WriteModrmWordOperands(PFAST486_STATE State, 1512 PFAST486_MOD_REG_RM ModRegRm, 1513 BOOLEAN WriteRegister, 1514 USHORT Value) 1515{ 1516 FAST486_SEG_REGS Segment = FAST486_REG_DS; 1517 1518 if (WriteRegister) 1519 { 1520 /* Store the value in the register */ 1521 State->GeneralRegs[ModRegRm->Register].LowWord = Value; 1522 } 1523 else 1524 { 1525 if (!ModRegRm->Memory) 1526 { 1527 /* Store the value in the second register */ 1528 State->GeneralRegs[ModRegRm->SecondRegister].LowWord = Value; 1529 } 1530 else 1531 { 1532 /* Check for the segment override */ 1533 if (State->PrefixFlags & FAST486_PREFIX_SEG) 1534 { 1535 /* Use the override segment instead */ 1536 Segment = State->SegmentOverride; 1537 } 1538 1539 /* Write memory */ 1540 if (!Fast486WriteMemory(State, 1541 Segment, 1542 ModRegRm->MemoryAddress, 1543 &Value, 1544 sizeof(USHORT))) 1545 { 1546 /* Exception occurred */ 1547 return FALSE; 1548 } 1549 } 1550 } 1551 1552 return TRUE; 1553} 1554 1555FORCEINLINE 1556BOOLEAN 1557FASTCALL 1558Fast486WriteModrmDwordOperands(PFAST486_STATE State, 1559 PFAST486_MOD_REG_RM ModRegRm, 1560 BOOLEAN WriteRegister, 1561 ULONG Value) 1562{ 1563 FAST486_SEG_REGS Segment = FAST486_REG_DS; 1564 1565 if (WriteRegister) 1566 { 1567 /* Store the value in the register */ 1568 State->GeneralRegs[ModRegRm->Register].Long = Value; 1569 } 1570 else 1571 { 1572 if (!ModRegRm->Memory) 1573 { 1574 /* Store the value in the second register */ 1575 State->GeneralRegs[ModRegRm->SecondRegister].Long = Value; 1576 } 1577 else 1578 { 1579 /* Check for the segment override */ 1580 if (State->PrefixFlags & FAST486_PREFIX_SEG) 1581 { 1582 /* Use the override segment instead */ 1583 Segment = State->SegmentOverride; 1584 } 1585 1586 /* Write memory */ 1587 if (!Fast486WriteMemory(State, 1588 Segment, 1589 ModRegRm->MemoryAddress, 1590 &Value, 1591 sizeof(ULONG))) 1592 { 1593 /* Exception occurred */ 1594 return FALSE; 1595 } 1596 } 1597 } 1598 1599 return TRUE; 1600} 1601 1602FORCEINLINE 1603BOOLEAN 1604FASTCALL 1605Fast486IoPrivilegeCheck(PFAST486_STATE State, USHORT Port) 1606{ 1607 UCHAR Bits; 1608 ULONG Location; 1609 FAST486_TSS Tss; 1610 1611 /* Access is always allowed if the CPL is less than or equal to the IOPL */ 1612 if (State->Cpl <= State->Flags.Iopl) return TRUE; 1613 1614 /* Legacy Task State Segments have no IOPB */ 1615 if (!State->TaskReg.Modern) return FALSE; 1616 1617 /* Read the TSS */ 1618 if (!Fast486ReadLinearMemory(State, State->TaskReg.Base, &Tss, sizeof(FAST486_TSS), FALSE)) 1619 { 1620 /* Exception occurred */ 1621 return FALSE; 1622 } 1623 1624 Location = State->TaskReg.Base + HIWORD(Tss.IopbOffset) + (Port >> 3); 1625 1626 if (Location > State->TaskReg.Limit) 1627 { 1628 /* Access denied */ 1629 Fast486Exception(State, FAST486_EXCEPTION_GP); 1630 return FALSE; 1631 } 1632 1633 /* Read the appropriate bit from the TSS IOPB */ 1634 if (!Fast486ReadLinearMemory(State, Location, &Bits, sizeof(UCHAR), FALSE)) 1635 { 1636 /* Exception occurred */ 1637 return FALSE; 1638 } 1639 1640 if (Bits & (1 << (Port & 0x07))) 1641 { 1642 /* Access denied */ 1643 Fast486Exception(State, FAST486_EXCEPTION_GP); 1644 return FALSE; 1645 } 1646 1647 return TRUE; 1648} 1649 1650#ifndef FAST486_NO_FPU 1651 1652FORCEINLINE 1653VOID 1654FASTCALL 1655Fast486FpuExceptionCheck(PFAST486_STATE State) 1656{ 1657 /* Check if an unmasked exception occurred */ 1658 if ((State->FpuStatus.Ie && !State->FpuControl.Im) 1659 || (State->FpuStatus.De && !State->FpuControl.Dm) 1660 || (State->FpuStatus.Ze && !State->FpuControl.Zm) 1661 || (State->FpuStatus.Oe && !State->FpuControl.Om) 1662 || (State->FpuStatus.Ue && !State->FpuControl.Um) 1663 || (State->FpuStatus.Pe && !State->FpuControl.Pm)) 1664 { 1665 if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_NE) 1666 { 1667 /* Call the #MF handler */ 1668 Fast486Exception(State, FAST486_EXCEPTION_MF); 1669 } 1670 else 1671 { 1672 /* Use the external interrupt */ 1673 State->FpuCallback(State); 1674 } 1675 } 1676} 1677 1678FORCEINLINE 1679BOOLEAN 1680FASTCALL 1681Fast486FpuNormalize(PFAST486_STATE State, 1682 PFAST486_FPU_DATA_REG Data) 1683{ 1684 UINT LeadingZeros; 1685 1686 if (FPU_IS_ZERO(Data)) 1687 { 1688 Data->Exponent = 0; 1689 return TRUE; 1690 } 1691 1692 if (FPU_IS_NORMALIZED(Data)) return TRUE; 1693 1694 LeadingZeros = CountLeadingZeros64(Data->Mantissa); 1695 1696 if (LeadingZeros < Data->Exponent) 1697 { 1698 Data->Mantissa <<= LeadingZeros; 1699 Data->Exponent -= LeadingZeros; 1700 } 1701 else 1702 { 1703 /* Raise the underflow exception */ 1704 State->FpuStatus.Ue = TRUE; 1705 1706 if (State->FpuControl.Um) 1707 { 1708 /* Make it denormalized */ 1709 Data->Mantissa <<= Data->Exponent - 1; 1710 Data->Exponent = 1; 1711 } 1712 else 1713 { 1714 return FALSE; 1715 } 1716 } 1717 1718 return TRUE; 1719} 1720 1721FORCEINLINE 1722USHORT 1723FASTCALL 1724Fast486FpuGetValueTag(PFAST486_FPU_DATA_REG Data) 1725{ 1726 if (FPU_IS_ZERO(Data)) return FPU_TAG_ZERO; 1727 else if (FPU_IS_NAN(Data)) return FPU_TAG_SPECIAL; 1728 else return FPU_TAG_VALID; 1729} 1730 1731FORCEINLINE 1732BOOLEAN 1733FASTCALL 1734Fast486FpuPush(PFAST486_STATE State, 1735 PCFAST486_FPU_DATA_REG Data) 1736{ 1737 State->FpuStatus.Top--; 1738 1739 if (FPU_GET_TAG(0) == FPU_TAG_EMPTY) 1740 { 1741 FPU_ST(0) = *Data; 1742 FPU_UPDATE_TAG(0); 1743 1744 return TRUE; 1745 } 1746 else 1747 { 1748 /* Raise the stack fault and invalid operation exception */ 1749 State->FpuStatus.Sf = State->FpuStatus.Ie = TRUE; 1750 1751 /* Set the C1 condition code bit (stack overflow) */ 1752 State->FpuStatus.Code1 = TRUE; 1753 1754 return FALSE; 1755 } 1756} 1757 1758FORCEINLINE 1759BOOLEAN 1760FASTCALL 1761Fast486FpuPop(PFAST486_STATE State) 1762{ 1763 if (FPU_GET_TAG(0) != FPU_TAG_EMPTY) 1764 { 1765 FPU_SET_TAG(0, FPU_TAG_EMPTY); 1766 State->FpuStatus.Top++; 1767 1768 return TRUE; 1769 } 1770 else 1771 { 1772 /* Raise the stack fault and invalid operation exception */ 1773 State->FpuStatus.Sf = State->FpuStatus.Ie = TRUE; 1774 1775 /* Clear the C1 condition code bit (stack underflow) */ 1776 State->FpuStatus.Code1 = FALSE; 1777 1778 return FALSE; 1779 } 1780} 1781 1782#endif 1783 1784/* EOF */ 1785