1 /**************************************************************************** 2 * 3 * Realmode X86 Emulator Library 4 * 5 * Copyright (C) 1991-2004 SciTech Software, Inc. 6 * Copyright (C) David Mosberger-Tang 7 * Copyright (C) 1999 Egbert Eich 8 * 9 * ======================================================================== 10 * 11 * Permission to use, copy, modify, distribute, and sell this software and 12 * its documentation for any purpose is hereby granted without fee, 13 * provided that the above copyright notice appear in all copies and that 14 * both that copyright notice and this permission notice appear in 15 * supporting documentation, and that the name of the authors not be used 16 * in advertising or publicity pertaining to distribution of the software 17 * without specific, written prior permission. The authors makes no 18 * representations about the suitability of this software for any purpose. 19 * It is provided "as is" without express or implied warranty. 20 * 21 * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 22 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 23 * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 24 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 25 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 26 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 27 * PERFORMANCE OF THIS SOFTWARE. 28 * 29 * ======================================================================== 30 * 31 * Language: ANSI C 32 * Environment: Any 33 * Developer: Kendall Bennett 34 * 35 * Description: This file includes subroutines which are related to 36 * instruction decoding and accessess of immediate data via IP. etc. 37 * 38 ****************************************************************************/ 39 #include <common.h> 40 #include "x86emu/x86emui.h" 41 42 /*----------------------------- Implementation ----------------------------*/ 43 44 /**************************************************************************** 45 REMARKS: 46 Handles any pending asychronous interrupts. 47 ****************************************************************************/ 48 static void x86emu_intr_handle(void) 49 { 50 u8 intno; 51 52 if (M.x86.intr & INTR_SYNCH) { 53 intno = M.x86.intno; 54 if (_X86EMU_intrTab[intno]) { 55 (*_X86EMU_intrTab[intno])(intno); 56 } else { 57 push_word((u16)M.x86.R_FLG); 58 CLEAR_FLAG(F_IF); 59 CLEAR_FLAG(F_TF); 60 push_word(M.x86.R_CS); 61 M.x86.R_CS = mem_access_word(intno * 4 + 2); 62 push_word(M.x86.R_IP); 63 M.x86.R_IP = mem_access_word(intno * 4); 64 M.x86.intr = 0; 65 } 66 } 67 } 68 69 /**************************************************************************** 70 PARAMETERS: 71 intrnum - Interrupt number to raise 72 73 REMARKS: 74 Raise the specified interrupt to be handled before the execution of the 75 next instruction. 76 ****************************************************************************/ 77 void x86emu_intr_raise( 78 u8 intrnum) 79 { 80 M.x86.intno = intrnum; 81 M.x86.intr |= INTR_SYNCH; 82 } 83 84 /**************************************************************************** 85 REMARKS: 86 Main execution loop for the emulator. We return from here when the system 87 halts, which is normally caused by a stack fault when we return from the 88 original real mode call. 89 ****************************************************************************/ 90 void X86EMU_exec(void) 91 { 92 u8 op1; 93 94 M.x86.intr = 0; 95 DB(x86emu_end_instr();) 96 97 for (;;) { 98 DB( if (CHECK_IP_FETCH()) 99 x86emu_check_ip_access();) 100 /* If debugging, save the IP and CS values. */ 101 SAVE_IP_CS(M.x86.R_CS, M.x86.R_IP); 102 INC_DECODED_INST_LEN(1); 103 if (M.x86.intr) { 104 if (M.x86.intr & INTR_HALTED) { 105 DB( if (M.x86.R_SP != 0) { 106 printk("halted\n"); 107 X86EMU_trace_regs(); 108 } 109 else { 110 if (M.x86.debug) 111 printk("Service completed successfully\n"); 112 }) 113 return; 114 } 115 if (((M.x86.intr & INTR_SYNCH) && (M.x86.intno == 0 || M.x86.intno == 2)) || 116 !ACCESS_FLAG(F_IF)) { 117 x86emu_intr_handle(); 118 } 119 } 120 op1 = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++)); 121 (*x86emu_optab[op1])(op1); 122 if (M.x86.debug & DEBUG_EXIT) { 123 M.x86.debug &= ~DEBUG_EXIT; 124 return; 125 } 126 } 127 } 128 129 /**************************************************************************** 130 REMARKS: 131 Halts the system by setting the halted system flag. 132 ****************************************************************************/ 133 void X86EMU_halt_sys(void) 134 { 135 M.x86.intr |= INTR_HALTED; 136 } 137 138 /**************************************************************************** 139 PARAMETERS: 140 mod - Mod value from decoded byte 141 regh - Reg h value from decoded byte 142 regl - Reg l value from decoded byte 143 144 REMARKS: 145 Raise the specified interrupt to be handled before the execution of the 146 next instruction. 147 148 NOTE: Do not inline this function, as (*sys_rdb) is already inline! 149 ****************************************************************************/ 150 void fetch_decode_modrm( 151 int *mod, 152 int *regh, 153 int *regl) 154 { 155 int fetched; 156 157 DB( if (CHECK_IP_FETCH()) 158 x86emu_check_ip_access();) 159 fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++)); 160 INC_DECODED_INST_LEN(1); 161 *mod = (fetched >> 6) & 0x03; 162 *regh = (fetched >> 3) & 0x07; 163 *regl = (fetched >> 0) & 0x07; 164 } 165 166 /**************************************************************************** 167 RETURNS: 168 Immediate byte value read from instruction queue 169 170 REMARKS: 171 This function returns the immediate byte from the instruction queue, and 172 moves the instruction pointer to the next value. 173 174 NOTE: Do not inline this function, as (*sys_rdb) is already inline! 175 ****************************************************************************/ 176 u8 fetch_byte_imm(void) 177 { 178 u8 fetched; 179 180 DB( if (CHECK_IP_FETCH()) 181 x86emu_check_ip_access();) 182 fetched = (*sys_rdb)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP++)); 183 INC_DECODED_INST_LEN(1); 184 return fetched; 185 } 186 187 /**************************************************************************** 188 RETURNS: 189 Immediate word value read from instruction queue 190 191 REMARKS: 192 This function returns the immediate byte from the instruction queue, and 193 moves the instruction pointer to the next value. 194 195 NOTE: Do not inline this function, as (*sys_rdw) is already inline! 196 ****************************************************************************/ 197 u16 fetch_word_imm(void) 198 { 199 u16 fetched; 200 201 DB( if (CHECK_IP_FETCH()) 202 x86emu_check_ip_access();) 203 fetched = (*sys_rdw)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP)); 204 M.x86.R_IP += 2; 205 INC_DECODED_INST_LEN(2); 206 return fetched; 207 } 208 209 /**************************************************************************** 210 RETURNS: 211 Immediate lone value read from instruction queue 212 213 REMARKS: 214 This function returns the immediate byte from the instruction queue, and 215 moves the instruction pointer to the next value. 216 217 NOTE: Do not inline this function, as (*sys_rdw) is already inline! 218 ****************************************************************************/ 219 u32 fetch_long_imm(void) 220 { 221 u32 fetched; 222 223 DB( if (CHECK_IP_FETCH()) 224 x86emu_check_ip_access();) 225 fetched = (*sys_rdl)(((u32)M.x86.R_CS << 4) + (M.x86.R_IP)); 226 M.x86.R_IP += 4; 227 INC_DECODED_INST_LEN(4); 228 return fetched; 229 } 230 231 /**************************************************************************** 232 RETURNS: 233 Value of the default data segment 234 235 REMARKS: 236 Inline function that returns the default data segment for the current 237 instruction. 238 239 On the x86 processor, the default segment is not always DS if there is 240 no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to 241 addresses relative to SS (ie: on the stack). So, at the minimum, all 242 decodings of addressing modes would have to set/clear a bit describing 243 whether the access is relative to DS or SS. That is the function of the 244 cpu-state-varible M.x86.mode. There are several potential states: 245 246 repe prefix seen (handled elsewhere) 247 repne prefix seen (ditto) 248 249 cs segment override 250 ds segment override 251 es segment override 252 fs segment override 253 gs segment override 254 ss segment override 255 256 ds/ss select (in absense of override) 257 258 Each of the above 7 items are handled with a bit in the mode field. 259 ****************************************************************************/ 260 _INLINE u32 get_data_segment(void) 261 { 262 #define GET_SEGMENT(segment) 263 switch (M.x86.mode & SYSMODE_SEGMASK) { 264 case 0: /* default case: use ds register */ 265 case SYSMODE_SEGOVR_DS: 266 case SYSMODE_SEGOVR_DS | SYSMODE_SEG_DS_SS: 267 return M.x86.R_DS; 268 case SYSMODE_SEG_DS_SS: /* non-overridden, use ss register */ 269 return M.x86.R_SS; 270 case SYSMODE_SEGOVR_CS: 271 case SYSMODE_SEGOVR_CS | SYSMODE_SEG_DS_SS: 272 return M.x86.R_CS; 273 case SYSMODE_SEGOVR_ES: 274 case SYSMODE_SEGOVR_ES | SYSMODE_SEG_DS_SS: 275 return M.x86.R_ES; 276 case SYSMODE_SEGOVR_FS: 277 case SYSMODE_SEGOVR_FS | SYSMODE_SEG_DS_SS: 278 return M.x86.R_FS; 279 case SYSMODE_SEGOVR_GS: 280 case SYSMODE_SEGOVR_GS | SYSMODE_SEG_DS_SS: 281 return M.x86.R_GS; 282 case SYSMODE_SEGOVR_SS: 283 case SYSMODE_SEGOVR_SS | SYSMODE_SEG_DS_SS: 284 return M.x86.R_SS; 285 default: 286 #ifdef DEBUG 287 printk("error: should not happen: multiple overrides.\n"); 288 #endif 289 HALT_SYS(); 290 return 0; 291 } 292 } 293 294 /**************************************************************************** 295 PARAMETERS: 296 offset - Offset to load data from 297 298 RETURNS: 299 Byte value read from the absolute memory location. 300 301 NOTE: Do not inline this function as (*sys_rdX) is already inline! 302 ****************************************************************************/ 303 u8 fetch_data_byte( 304 uint offset) 305 { 306 #ifdef DEBUG 307 if (CHECK_DATA_ACCESS()) 308 x86emu_check_data_access((u16)get_data_segment(), offset); 309 #endif 310 return (*sys_rdb)((get_data_segment() << 4) + offset); 311 } 312 313 /**************************************************************************** 314 PARAMETERS: 315 offset - Offset to load data from 316 317 RETURNS: 318 Word value read from the absolute memory location. 319 320 NOTE: Do not inline this function as (*sys_rdX) is already inline! 321 ****************************************************************************/ 322 u16 fetch_data_word( 323 uint offset) 324 { 325 #ifdef DEBUG 326 if (CHECK_DATA_ACCESS()) 327 x86emu_check_data_access((u16)get_data_segment(), offset); 328 #endif 329 return (*sys_rdw)((get_data_segment() << 4) + offset); 330 } 331 332 /**************************************************************************** 333 PARAMETERS: 334 offset - Offset to load data from 335 336 RETURNS: 337 Long value read from the absolute memory location. 338 339 NOTE: Do not inline this function as (*sys_rdX) is already inline! 340 ****************************************************************************/ 341 u32 fetch_data_long( 342 uint offset) 343 { 344 #ifdef DEBUG 345 if (CHECK_DATA_ACCESS()) 346 x86emu_check_data_access((u16)get_data_segment(), offset); 347 #endif 348 return (*sys_rdl)((get_data_segment() << 4) + offset); 349 } 350 351 /**************************************************************************** 352 PARAMETERS: 353 segment - Segment to load data from 354 offset - Offset to load data from 355 356 RETURNS: 357 Byte value read from the absolute memory location. 358 359 NOTE: Do not inline this function as (*sys_rdX) is already inline! 360 ****************************************************************************/ 361 u8 fetch_data_byte_abs( 362 uint segment, 363 uint offset) 364 { 365 #ifdef DEBUG 366 if (CHECK_DATA_ACCESS()) 367 x86emu_check_data_access(segment, offset); 368 #endif 369 return (*sys_rdb)(((u32)segment << 4) + offset); 370 } 371 372 /**************************************************************************** 373 PARAMETERS: 374 segment - Segment to load data from 375 offset - Offset to load data from 376 377 RETURNS: 378 Word value read from the absolute memory location. 379 380 NOTE: Do not inline this function as (*sys_rdX) is already inline! 381 ****************************************************************************/ 382 u16 fetch_data_word_abs( 383 uint segment, 384 uint offset) 385 { 386 #ifdef DEBUG 387 if (CHECK_DATA_ACCESS()) 388 x86emu_check_data_access(segment, offset); 389 #endif 390 return (*sys_rdw)(((u32)segment << 4) + offset); 391 } 392 393 /**************************************************************************** 394 PARAMETERS: 395 segment - Segment to load data from 396 offset - Offset to load data from 397 398 RETURNS: 399 Long value read from the absolute memory location. 400 401 NOTE: Do not inline this function as (*sys_rdX) is already inline! 402 ****************************************************************************/ 403 u32 fetch_data_long_abs( 404 uint segment, 405 uint offset) 406 { 407 #ifdef DEBUG 408 if (CHECK_DATA_ACCESS()) 409 x86emu_check_data_access(segment, offset); 410 #endif 411 return (*sys_rdl)(((u32)segment << 4) + offset); 412 } 413 414 /**************************************************************************** 415 PARAMETERS: 416 offset - Offset to store data at 417 val - Value to store 418 419 REMARKS: 420 Writes a word value to an segmented memory location. The segment used is 421 the current 'default' segment, which may have been overridden. 422 423 NOTE: Do not inline this function as (*sys_wrX) is already inline! 424 ****************************************************************************/ 425 void store_data_byte( 426 uint offset, 427 u8 val) 428 { 429 #ifdef DEBUG 430 if (CHECK_DATA_ACCESS()) 431 x86emu_check_data_access((u16)get_data_segment(), offset); 432 #endif 433 (*sys_wrb)((get_data_segment() << 4) + offset, val); 434 } 435 436 /**************************************************************************** 437 PARAMETERS: 438 offset - Offset to store data at 439 val - Value to store 440 441 REMARKS: 442 Writes a word value to an segmented memory location. The segment used is 443 the current 'default' segment, which may have been overridden. 444 445 NOTE: Do not inline this function as (*sys_wrX) is already inline! 446 ****************************************************************************/ 447 void store_data_word( 448 uint offset, 449 u16 val) 450 { 451 #ifdef DEBUG 452 if (CHECK_DATA_ACCESS()) 453 x86emu_check_data_access((u16)get_data_segment(), offset); 454 #endif 455 (*sys_wrw)((get_data_segment() << 4) + offset, val); 456 } 457 458 /**************************************************************************** 459 PARAMETERS: 460 offset - Offset to store data at 461 val - Value to store 462 463 REMARKS: 464 Writes a long value to an segmented memory location. The segment used is 465 the current 'default' segment, which may have been overridden. 466 467 NOTE: Do not inline this function as (*sys_wrX) is already inline! 468 ****************************************************************************/ 469 void store_data_long( 470 uint offset, 471 u32 val) 472 { 473 #ifdef DEBUG 474 if (CHECK_DATA_ACCESS()) 475 x86emu_check_data_access((u16)get_data_segment(), offset); 476 #endif 477 (*sys_wrl)((get_data_segment() << 4) + offset, val); 478 } 479 480 /**************************************************************************** 481 PARAMETERS: 482 segment - Segment to store data at 483 offset - Offset to store data at 484 val - Value to store 485 486 REMARKS: 487 Writes a byte value to an absolute memory location. 488 489 NOTE: Do not inline this function as (*sys_wrX) is already inline! 490 ****************************************************************************/ 491 void store_data_byte_abs( 492 uint segment, 493 uint offset, 494 u8 val) 495 { 496 #ifdef DEBUG 497 if (CHECK_DATA_ACCESS()) 498 x86emu_check_data_access(segment, offset); 499 #endif 500 (*sys_wrb)(((u32)segment << 4) + offset, val); 501 } 502 503 /**************************************************************************** 504 PARAMETERS: 505 segment - Segment to store data at 506 offset - Offset to store data at 507 val - Value to store 508 509 REMARKS: 510 Writes a word value to an absolute memory location. 511 512 NOTE: Do not inline this function as (*sys_wrX) is already inline! 513 ****************************************************************************/ 514 void store_data_word_abs( 515 uint segment, 516 uint offset, 517 u16 val) 518 { 519 #ifdef DEBUG 520 if (CHECK_DATA_ACCESS()) 521 x86emu_check_data_access(segment, offset); 522 #endif 523 (*sys_wrw)(((u32)segment << 4) + offset, val); 524 } 525 526 /**************************************************************************** 527 PARAMETERS: 528 segment - Segment to store data at 529 offset - Offset to store data at 530 val - Value to store 531 532 REMARKS: 533 Writes a long value to an absolute memory location. 534 535 NOTE: Do not inline this function as (*sys_wrX) is already inline! 536 ****************************************************************************/ 537 void store_data_long_abs( 538 uint segment, 539 uint offset, 540 u32 val) 541 { 542 #ifdef DEBUG 543 if (CHECK_DATA_ACCESS()) 544 x86emu_check_data_access(segment, offset); 545 #endif 546 (*sys_wrl)(((u32)segment << 4) + offset, val); 547 } 548 549 /**************************************************************************** 550 PARAMETERS: 551 reg - Register to decode 552 553 RETURNS: 554 Pointer to the appropriate register 555 556 REMARKS: 557 Return a pointer to the register given by the R/RM field of the 558 modrm byte, for byte operands. Also enables the decoding of instructions. 559 ****************************************************************************/ 560 u8* decode_rm_byte_register( 561 int reg) 562 { 563 switch (reg) { 564 case 0: 565 DECODE_PRINTF("AL"); 566 return &M.x86.R_AL; 567 case 1: 568 DECODE_PRINTF("CL"); 569 return &M.x86.R_CL; 570 case 2: 571 DECODE_PRINTF("DL"); 572 return &M.x86.R_DL; 573 case 3: 574 DECODE_PRINTF("BL"); 575 return &M.x86.R_BL; 576 case 4: 577 DECODE_PRINTF("AH"); 578 return &M.x86.R_AH; 579 case 5: 580 DECODE_PRINTF("CH"); 581 return &M.x86.R_CH; 582 case 6: 583 DECODE_PRINTF("DH"); 584 return &M.x86.R_DH; 585 case 7: 586 DECODE_PRINTF("BH"); 587 return &M.x86.R_BH; 588 } 589 HALT_SYS(); 590 return NULL; /* NOT REACHED OR REACHED ON ERROR */ 591 } 592 593 /**************************************************************************** 594 PARAMETERS: 595 reg - Register to decode 596 597 RETURNS: 598 Pointer to the appropriate register 599 600 REMARKS: 601 Return a pointer to the register given by the R/RM field of the 602 modrm byte, for word operands. Also enables the decoding of instructions. 603 ****************************************************************************/ 604 u16* decode_rm_word_register( 605 int reg) 606 { 607 switch (reg) { 608 case 0: 609 DECODE_PRINTF("AX"); 610 return &M.x86.R_AX; 611 case 1: 612 DECODE_PRINTF("CX"); 613 return &M.x86.R_CX; 614 case 2: 615 DECODE_PRINTF("DX"); 616 return &M.x86.R_DX; 617 case 3: 618 DECODE_PRINTF("BX"); 619 return &M.x86.R_BX; 620 case 4: 621 DECODE_PRINTF("SP"); 622 return &M.x86.R_SP; 623 case 5: 624 DECODE_PRINTF("BP"); 625 return &M.x86.R_BP; 626 case 6: 627 DECODE_PRINTF("SI"); 628 return &M.x86.R_SI; 629 case 7: 630 DECODE_PRINTF("DI"); 631 return &M.x86.R_DI; 632 } 633 HALT_SYS(); 634 return NULL; /* NOTREACHED OR REACHED ON ERROR */ 635 } 636 637 /**************************************************************************** 638 PARAMETERS: 639 reg - Register to decode 640 641 RETURNS: 642 Pointer to the appropriate register 643 644 REMARKS: 645 Return a pointer to the register given by the R/RM field of the 646 modrm byte, for dword operands. Also enables the decoding of instructions. 647 ****************************************************************************/ 648 u32* decode_rm_long_register( 649 int reg) 650 { 651 switch (reg) { 652 case 0: 653 DECODE_PRINTF("EAX"); 654 return &M.x86.R_EAX; 655 case 1: 656 DECODE_PRINTF("ECX"); 657 return &M.x86.R_ECX; 658 case 2: 659 DECODE_PRINTF("EDX"); 660 return &M.x86.R_EDX; 661 case 3: 662 DECODE_PRINTF("EBX"); 663 return &M.x86.R_EBX; 664 case 4: 665 DECODE_PRINTF("ESP"); 666 return &M.x86.R_ESP; 667 case 5: 668 DECODE_PRINTF("EBP"); 669 return &M.x86.R_EBP; 670 case 6: 671 DECODE_PRINTF("ESI"); 672 return &M.x86.R_ESI; 673 case 7: 674 DECODE_PRINTF("EDI"); 675 return &M.x86.R_EDI; 676 } 677 HALT_SYS(); 678 return NULL; /* NOTREACHED OR REACHED ON ERROR */ 679 } 680 681 /**************************************************************************** 682 PARAMETERS: 683 reg - Register to decode 684 685 RETURNS: 686 Pointer to the appropriate register 687 688 REMARKS: 689 Return a pointer to the register given by the R/RM field of the 690 modrm byte, for word operands, modified from above for the weirdo 691 special case of segreg operands. Also enables the decoding of instructions. 692 ****************************************************************************/ 693 u16* decode_rm_seg_register( 694 int reg) 695 { 696 switch (reg) { 697 case 0: 698 DECODE_PRINTF("ES"); 699 return &M.x86.R_ES; 700 case 1: 701 DECODE_PRINTF("CS"); 702 return &M.x86.R_CS; 703 case 2: 704 DECODE_PRINTF("SS"); 705 return &M.x86.R_SS; 706 case 3: 707 DECODE_PRINTF("DS"); 708 return &M.x86.R_DS; 709 case 4: 710 DECODE_PRINTF("FS"); 711 return &M.x86.R_FS; 712 case 5: 713 DECODE_PRINTF("GS"); 714 return &M.x86.R_GS; 715 case 6: 716 case 7: 717 DECODE_PRINTF("ILLEGAL SEGREG"); 718 break; 719 } 720 HALT_SYS(); 721 return NULL; /* NOT REACHED OR REACHED ON ERROR */ 722 } 723 724 /**************************************************************************** 725 PARAMETERS: 726 scale - scale value of SIB byte 727 index - index value of SIB byte 728 729 RETURNS: 730 Value of scale * index 731 732 REMARKS: 733 Decodes scale/index of SIB byte and returns relevant offset part of 734 effective address. 735 ****************************************************************************/ 736 unsigned decode_sib_si( 737 int scale, 738 int index) 739 { 740 scale = 1 << scale; 741 if (scale > 1) { 742 DECODE_PRINTF2("[%d*", scale); 743 } else { 744 DECODE_PRINTF("["); 745 } 746 switch (index) { 747 case 0: 748 DECODE_PRINTF("EAX]"); 749 return M.x86.R_EAX * index; 750 case 1: 751 DECODE_PRINTF("ECX]"); 752 return M.x86.R_ECX * index; 753 case 2: 754 DECODE_PRINTF("EDX]"); 755 return M.x86.R_EDX * index; 756 case 3: 757 DECODE_PRINTF("EBX]"); 758 return M.x86.R_EBX * index; 759 case 4: 760 DECODE_PRINTF("0]"); 761 return 0; 762 case 5: 763 DECODE_PRINTF("EBP]"); 764 return M.x86.R_EBP * index; 765 case 6: 766 DECODE_PRINTF("ESI]"); 767 return M.x86.R_ESI * index; 768 case 7: 769 DECODE_PRINTF("EDI]"); 770 return M.x86.R_EDI * index; 771 } 772 HALT_SYS(); 773 return 0; /* NOT REACHED OR REACHED ON ERROR */ 774 } 775 776 /**************************************************************************** 777 PARAMETERS: 778 mod - MOD value of preceding ModR/M byte 779 780 RETURNS: 781 Offset in memory for the address decoding 782 783 REMARKS: 784 Decodes SIB addressing byte and returns calculated effective address. 785 ****************************************************************************/ 786 unsigned decode_sib_address( 787 int mod) 788 { 789 int sib = fetch_byte_imm(); 790 int ss = (sib >> 6) & 0x03; 791 int index = (sib >> 3) & 0x07; 792 int base = sib & 0x07; 793 int offset = 0; 794 int displacement; 795 796 switch (base) { 797 case 0: 798 DECODE_PRINTF("[EAX]"); 799 offset = M.x86.R_EAX; 800 break; 801 case 1: 802 DECODE_PRINTF("[ECX]"); 803 offset = M.x86.R_ECX; 804 break; 805 case 2: 806 DECODE_PRINTF("[EDX]"); 807 offset = M.x86.R_EDX; 808 break; 809 case 3: 810 DECODE_PRINTF("[EBX]"); 811 offset = M.x86.R_EBX; 812 break; 813 case 4: 814 DECODE_PRINTF("[ESP]"); 815 offset = M.x86.R_ESP; 816 break; 817 case 5: 818 switch (mod) { 819 case 0: 820 displacement = (s32)fetch_long_imm(); 821 DECODE_PRINTF2("[%d]", displacement); 822 offset = displacement; 823 break; 824 case 1: 825 displacement = (s8)fetch_byte_imm(); 826 DECODE_PRINTF2("[%d][EBP]", displacement); 827 offset = M.x86.R_EBP + displacement; 828 break; 829 case 2: 830 displacement = (s32)fetch_long_imm(); 831 DECODE_PRINTF2("[%d][EBP]", displacement); 832 offset = M.x86.R_EBP + displacement; 833 break; 834 default: 835 HALT_SYS(); 836 } 837 DECODE_PRINTF("[EAX]"); 838 offset = M.x86.R_EAX; 839 break; 840 case 6: 841 DECODE_PRINTF("[ESI]"); 842 offset = M.x86.R_ESI; 843 break; 844 case 7: 845 DECODE_PRINTF("[EDI]"); 846 offset = M.x86.R_EDI; 847 break; 848 default: 849 HALT_SYS(); 850 } 851 offset += decode_sib_si(ss, index); 852 return offset; 853 854 } 855 856 /**************************************************************************** 857 PARAMETERS: 858 rm - RM value to decode 859 860 RETURNS: 861 Offset in memory for the address decoding 862 863 REMARKS: 864 Return the offset given by mod=00 addressing. Also enables the 865 decoding of instructions. 866 867 NOTE: The code which specifies the corresponding segment (ds vs ss) 868 below in the case of [BP+..]. The assumption here is that at the 869 point that this subroutine is called, the bit corresponding to 870 SYSMODE_SEG_DS_SS will be zero. After every instruction 871 except the segment override instructions, this bit (as well 872 as any bits indicating segment overrides) will be clear. So 873 if a SS access is needed, set this bit. Otherwise, DS access 874 occurs (unless any of the segment override bits are set). 875 ****************************************************************************/ 876 unsigned decode_rm00_address( 877 int rm) 878 { 879 unsigned offset; 880 881 if (M.x86.mode & SYSMODE_PREFIX_ADDR) { 882 /* 32-bit addressing */ 883 switch (rm) { 884 case 0: 885 DECODE_PRINTF("[EAX]"); 886 return M.x86.R_EAX; 887 case 1: 888 DECODE_PRINTF("[ECX]"); 889 return M.x86.R_ECX; 890 case 2: 891 DECODE_PRINTF("[EDX]"); 892 return M.x86.R_EDX; 893 case 3: 894 DECODE_PRINTF("[EBX]"); 895 return M.x86.R_EBX; 896 case 4: 897 return decode_sib_address(0); 898 case 5: 899 offset = fetch_long_imm(); 900 DECODE_PRINTF2("[%08x]", offset); 901 return offset; 902 case 6: 903 DECODE_PRINTF("[ESI]"); 904 return M.x86.R_ESI; 905 case 7: 906 DECODE_PRINTF("[EDI]"); 907 return M.x86.R_EDI; 908 } 909 } else { 910 /* 16-bit addressing */ 911 switch (rm) { 912 case 0: 913 DECODE_PRINTF("[BX+SI]"); 914 return (M.x86.R_BX + M.x86.R_SI) & 0xffff; 915 case 1: 916 DECODE_PRINTF("[BX+DI]"); 917 return (M.x86.R_BX + M.x86.R_DI) & 0xffff; 918 case 2: 919 DECODE_PRINTF("[BP+SI]"); 920 M.x86.mode |= SYSMODE_SEG_DS_SS; 921 return (M.x86.R_BP + M.x86.R_SI) & 0xffff; 922 case 3: 923 DECODE_PRINTF("[BP+DI]"); 924 M.x86.mode |= SYSMODE_SEG_DS_SS; 925 return (M.x86.R_BP + M.x86.R_DI) & 0xffff; 926 case 4: 927 DECODE_PRINTF("[SI]"); 928 return M.x86.R_SI; 929 case 5: 930 DECODE_PRINTF("[DI]"); 931 return M.x86.R_DI; 932 case 6: 933 offset = fetch_word_imm(); 934 DECODE_PRINTF2("[%04x]", offset); 935 return offset; 936 case 7: 937 DECODE_PRINTF("[BX]"); 938 return M.x86.R_BX; 939 } 940 } 941 HALT_SYS(); 942 return 0; 943 } 944 945 /**************************************************************************** 946 PARAMETERS: 947 rm - RM value to decode 948 949 RETURNS: 950 Offset in memory for the address decoding 951 952 REMARKS: 953 Return the offset given by mod=01 addressing. Also enables the 954 decoding of instructions. 955 ****************************************************************************/ 956 unsigned decode_rm01_address( 957 int rm) 958 { 959 int displacement; 960 961 if (M.x86.mode & SYSMODE_PREFIX_ADDR) { 962 /* 32-bit addressing */ 963 if (rm != 4) 964 displacement = (s8)fetch_byte_imm(); 965 else 966 displacement = 0; 967 968 switch (rm) { 969 case 0: 970 DECODE_PRINTF2("%d[EAX]", displacement); 971 return M.x86.R_EAX + displacement; 972 case 1: 973 DECODE_PRINTF2("%d[ECX]", displacement); 974 return M.x86.R_ECX + displacement; 975 case 2: 976 DECODE_PRINTF2("%d[EDX]", displacement); 977 return M.x86.R_EDX + displacement; 978 case 3: 979 DECODE_PRINTF2("%d[EBX]", displacement); 980 return M.x86.R_EBX + displacement; 981 case 4: { 982 int offset = decode_sib_address(1); 983 displacement = (s8)fetch_byte_imm(); 984 DECODE_PRINTF2("[%d]", displacement); 985 return offset + displacement; 986 } 987 case 5: 988 DECODE_PRINTF2("%d[EBP]", displacement); 989 return M.x86.R_EBP + displacement; 990 case 6: 991 DECODE_PRINTF2("%d[ESI]", displacement); 992 return M.x86.R_ESI + displacement; 993 case 7: 994 DECODE_PRINTF2("%d[EDI]", displacement); 995 return M.x86.R_EDI + displacement; 996 } 997 } else { 998 /* 16-bit addressing */ 999 displacement = (s8)fetch_byte_imm(); 1000 switch (rm) { 1001 case 0: 1002 DECODE_PRINTF2("%d[BX+SI]", displacement); 1003 return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff; 1004 case 1: 1005 DECODE_PRINTF2("%d[BX+DI]", displacement); 1006 return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff; 1007 case 2: 1008 DECODE_PRINTF2("%d[BP+SI]", displacement); 1009 M.x86.mode |= SYSMODE_SEG_DS_SS; 1010 return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff; 1011 case 3: 1012 DECODE_PRINTF2("%d[BP+DI]", displacement); 1013 M.x86.mode |= SYSMODE_SEG_DS_SS; 1014 return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff; 1015 case 4: 1016 DECODE_PRINTF2("%d[SI]", displacement); 1017 return (M.x86.R_SI + displacement) & 0xffff; 1018 case 5: 1019 DECODE_PRINTF2("%d[DI]", displacement); 1020 return (M.x86.R_DI + displacement) & 0xffff; 1021 case 6: 1022 DECODE_PRINTF2("%d[BP]", displacement); 1023 M.x86.mode |= SYSMODE_SEG_DS_SS; 1024 return (M.x86.R_BP + displacement) & 0xffff; 1025 case 7: 1026 DECODE_PRINTF2("%d[BX]", displacement); 1027 return (M.x86.R_BX + displacement) & 0xffff; 1028 } 1029 } 1030 HALT_SYS(); 1031 return 0; /* SHOULD NOT HAPPEN */ 1032 } 1033 1034 /**************************************************************************** 1035 PARAMETERS: 1036 rm - RM value to decode 1037 1038 RETURNS: 1039 Offset in memory for the address decoding 1040 1041 REMARKS: 1042 Return the offset given by mod=10 addressing. Also enables the 1043 decoding of instructions. 1044 ****************************************************************************/ 1045 unsigned decode_rm10_address( 1046 int rm) 1047 { 1048 if (M.x86.mode & SYSMODE_PREFIX_ADDR) { 1049 int displacement; 1050 1051 /* 32-bit addressing */ 1052 if (rm != 4) 1053 displacement = (s32)fetch_long_imm(); 1054 else 1055 displacement = 0; 1056 1057 switch (rm) { 1058 case 0: 1059 DECODE_PRINTF2("%d[EAX]", displacement); 1060 return M.x86.R_EAX + displacement; 1061 case 1: 1062 DECODE_PRINTF2("%d[ECX]", displacement); 1063 return M.x86.R_ECX + displacement; 1064 case 2: 1065 DECODE_PRINTF2("%d[EDX]", displacement); 1066 return M.x86.R_EDX + displacement; 1067 case 3: 1068 DECODE_PRINTF2("%d[EBX]", displacement); 1069 return M.x86.R_EBX + displacement; 1070 case 4: { 1071 int offset = decode_sib_address(2); 1072 displacement = (s32)fetch_long_imm(); 1073 DECODE_PRINTF2("[%d]", displacement); 1074 return offset + displacement; 1075 } 1076 case 5: 1077 DECODE_PRINTF2("%d[EBP]", displacement); 1078 return M.x86.R_EBP + displacement; 1079 case 6: 1080 DECODE_PRINTF2("%d[ESI]", displacement); 1081 return M.x86.R_ESI + displacement; 1082 case 7: 1083 DECODE_PRINTF2("%d[EDI]", displacement); 1084 return M.x86.R_EDI + displacement; 1085 } 1086 } else { 1087 int displacement = (s16)fetch_word_imm(); 1088 1089 /* 16-bit addressing */ 1090 switch (rm) { 1091 case 0: 1092 DECODE_PRINTF2("%d[BX+SI]", displacement); 1093 return (M.x86.R_BX + M.x86.R_SI + displacement) & 0xffff; 1094 case 1: 1095 DECODE_PRINTF2("%d[BX+DI]", displacement); 1096 return (M.x86.R_BX + M.x86.R_DI + displacement) & 0xffff; 1097 case 2: 1098 DECODE_PRINTF2("%d[BP+SI]", displacement); 1099 M.x86.mode |= SYSMODE_SEG_DS_SS; 1100 return (M.x86.R_BP + M.x86.R_SI + displacement) & 0xffff; 1101 case 3: 1102 DECODE_PRINTF2("%d[BP+DI]", displacement); 1103 M.x86.mode |= SYSMODE_SEG_DS_SS; 1104 return (M.x86.R_BP + M.x86.R_DI + displacement) & 0xffff; 1105 case 4: 1106 DECODE_PRINTF2("%d[SI]", displacement); 1107 return (M.x86.R_SI + displacement) & 0xffff; 1108 case 5: 1109 DECODE_PRINTF2("%d[DI]", displacement); 1110 return (M.x86.R_DI + displacement) & 0xffff; 1111 case 6: 1112 DECODE_PRINTF2("%d[BP]", displacement); 1113 M.x86.mode |= SYSMODE_SEG_DS_SS; 1114 return (M.x86.R_BP + displacement) & 0xffff; 1115 case 7: 1116 DECODE_PRINTF2("%d[BX]", displacement); 1117 return (M.x86.R_BX + displacement) & 0xffff; 1118 } 1119 } 1120 HALT_SYS(); 1121 return 0; /* SHOULD NOT HAPPEN */ 1122 } 1123 1124 /**************************************************************************** 1125 PARAMETERS: 1126 mod - modifier 1127 rm - RM value to decode 1128 1129 RETURNS: 1130 Offset in memory for the address decoding, multiplexing calls to 1131 the decode_rmXX_address functions 1132 1133 REMARKS: 1134 Return the offset given by "mod" addressing. 1135 ****************************************************************************/ 1136 1137 unsigned decode_rmXX_address(int mod, int rm) 1138 { 1139 if(mod == 0) 1140 return decode_rm00_address(rm); 1141 if(mod == 1) 1142 return decode_rm01_address(rm); 1143 return decode_rm10_address(rm); 1144 } 1145