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