uboot/drivers/bios_emulator/x86emu/decode.c
<<
>>
Prefs
   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/****************************************************************************
  45REMARKS:
  46Handles any pending asychronous interrupts.
  47****************************************************************************/
  48static 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/****************************************************************************
  70PARAMETERS:
  71intrnum - Interrupt number to raise
  72
  73REMARKS:
  74Raise the specified interrupt to be handled before the execution of the
  75next instruction.
  76****************************************************************************/
  77void x86emu_intr_raise(
  78    u8 intrnum)
  79{
  80    M.x86.intno = intrnum;
  81    M.x86.intr |= INTR_SYNCH;
  82}
  83
  84/****************************************************************************
  85REMARKS:
  86Main execution loop for the emulator. We return from here when the system
  87halts, which is normally caused by a stack fault when we return from the
  88original real mode call.
  89****************************************************************************/
  90void X86EMU_exec(void)
  91{
  92    u8 op1;
  93
  94    M.x86.intr = 0;
  95    DB(x86emu_end_instr();)
  96
  97    for (;;) {
  98DB(     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) {
 105DB(             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/****************************************************************************
 130REMARKS:
 131Halts the system by setting the halted system flag.
 132****************************************************************************/
 133void X86EMU_halt_sys(void)
 134{
 135    M.x86.intr |= INTR_HALTED;
 136}
 137
 138/****************************************************************************
 139PARAMETERS:
 140mod     - Mod value from decoded byte
 141regh    - Reg h value from decoded byte
 142regl    - Reg l value from decoded byte
 143
 144REMARKS:
 145Raise the specified interrupt to be handled before the execution of the
 146next instruction.
 147
 148NOTE: Do not inline this function, as (*sys_rdb) is already inline!
 149****************************************************************************/
 150void fetch_decode_modrm(
 151    int *mod,
 152    int *regh,
 153    int *regl)
 154{
 155    int fetched;
 156
 157DB( 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/****************************************************************************
 167RETURNS:
 168Immediate byte value read from instruction queue
 169
 170REMARKS:
 171This function returns the immediate byte from the instruction queue, and
 172moves the instruction pointer to the next value.
 173
 174NOTE: Do not inline this function, as (*sys_rdb) is already inline!
 175****************************************************************************/
 176u8 fetch_byte_imm(void)
 177{
 178    u8 fetched;
 179
 180DB( 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/****************************************************************************
 188RETURNS:
 189Immediate word value read from instruction queue
 190
 191REMARKS:
 192This function returns the immediate byte from the instruction queue, and
 193moves the instruction pointer to the next value.
 194
 195NOTE: Do not inline this function, as (*sys_rdw) is already inline!
 196****************************************************************************/
 197u16 fetch_word_imm(void)
 198{
 199    u16 fetched;
 200
 201DB( 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/****************************************************************************
 210RETURNS:
 211Immediate lone value read from instruction queue
 212
 213REMARKS:
 214This function returns the immediate byte from the instruction queue, and
 215moves the instruction pointer to the next value.
 216
 217NOTE: Do not inline this function, as (*sys_rdw) is already inline!
 218****************************************************************************/
 219u32 fetch_long_imm(void)
 220{
 221    u32 fetched;
 222
 223DB( 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/****************************************************************************
 232RETURNS:
 233Value of the default data segment
 234
 235REMARKS:
 236Inline function that returns the default data segment for the current
 237instruction.
 238
 239On the x86 processor, the default segment is not always DS if there is
 240no segment override. Address modes such as -3[BP] or 10[BP+SI] all refer to
 241addresses relative to SS (ie: on the stack). So, at the minimum, all
 242decodings of addressing modes would have to set/clear a bit describing
 243whether the access is relative to DS or SS.  That is the function of the
 244cpu-state-variable 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
 258Each 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/****************************************************************************
 295PARAMETERS:
 296offset  - Offset to load data from
 297
 298RETURNS:
 299Byte value read from the absolute memory location.
 300
 301NOTE: Do not inline this function as (*sys_rdX) is already inline!
 302****************************************************************************/
 303u8 fetch_data_byte(
 304    uint offset)
 305{
 306#ifdef CONFIG_X86EMU_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/****************************************************************************
 314PARAMETERS:
 315offset  - Offset to load data from
 316
 317RETURNS:
 318Word value read from the absolute memory location.
 319
 320NOTE: Do not inline this function as (*sys_rdX) is already inline!
 321****************************************************************************/
 322u16 fetch_data_word(
 323    uint offset)
 324{
 325#ifdef CONFIG_X86EMU_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/****************************************************************************
 333PARAMETERS:
 334offset  - Offset to load data from
 335
 336RETURNS:
 337Long value read from the absolute memory location.
 338
 339NOTE: Do not inline this function as (*sys_rdX) is already inline!
 340****************************************************************************/
 341u32 fetch_data_long(
 342    uint offset)
 343{
 344#ifdef CONFIG_X86EMU_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/****************************************************************************
 352PARAMETERS:
 353segment - Segment to load data from
 354offset  - Offset to load data from
 355
 356RETURNS:
 357Byte value read from the absolute memory location.
 358
 359NOTE: Do not inline this function as (*sys_rdX) is already inline!
 360****************************************************************************/
 361u8 fetch_data_byte_abs(
 362    uint segment,
 363    uint offset)
 364{
 365#ifdef CONFIG_X86EMU_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/****************************************************************************
 373PARAMETERS:
 374segment - Segment to load data from
 375offset  - Offset to load data from
 376
 377RETURNS:
 378Word value read from the absolute memory location.
 379
 380NOTE: Do not inline this function as (*sys_rdX) is already inline!
 381****************************************************************************/
 382u16 fetch_data_word_abs(
 383    uint segment,
 384    uint offset)
 385{
 386#ifdef CONFIG_X86EMU_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/****************************************************************************
 394PARAMETERS:
 395segment - Segment to load data from
 396offset  - Offset to load data from
 397
 398RETURNS:
 399Long value read from the absolute memory location.
 400
 401NOTE: Do not inline this function as (*sys_rdX) is already inline!
 402****************************************************************************/
 403u32 fetch_data_long_abs(
 404    uint segment,
 405    uint offset)
 406{
 407#ifdef CONFIG_X86EMU_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/****************************************************************************
 415PARAMETERS:
 416offset  - Offset to store data at
 417val     - Value to store
 418
 419REMARKS:
 420Writes a word value to an segmented memory location. The segment used is
 421the current 'default' segment, which may have been overridden.
 422
 423NOTE: Do not inline this function as (*sys_wrX) is already inline!
 424****************************************************************************/
 425void store_data_byte(
 426    uint offset,
 427    u8 val)
 428{
 429#ifdef CONFIG_X86EMU_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/****************************************************************************
 437PARAMETERS:
 438offset  - Offset to store data at
 439val     - Value to store
 440
 441REMARKS:
 442Writes a word value to an segmented memory location. The segment used is
 443the current 'default' segment, which may have been overridden.
 444
 445NOTE: Do not inline this function as (*sys_wrX) is already inline!
 446****************************************************************************/
 447void store_data_word(
 448    uint offset,
 449    u16 val)
 450{
 451#ifdef CONFIG_X86EMU_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/****************************************************************************
 459PARAMETERS:
 460offset  - Offset to store data at
 461val     - Value to store
 462
 463REMARKS:
 464Writes a long value to an segmented memory location. The segment used is
 465the current 'default' segment, which may have been overridden.
 466
 467NOTE: Do not inline this function as (*sys_wrX) is already inline!
 468****************************************************************************/
 469void store_data_long(
 470    uint offset,
 471    u32 val)
 472{
 473#ifdef CONFIG_X86EMU_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/****************************************************************************
 481PARAMETERS:
 482segment - Segment to store data at
 483offset  - Offset to store data at
 484val     - Value to store
 485
 486REMARKS:
 487Writes a byte value to an absolute memory location.
 488
 489NOTE: Do not inline this function as (*sys_wrX) is already inline!
 490****************************************************************************/
 491void store_data_byte_abs(
 492    uint segment,
 493    uint offset,
 494    u8 val)
 495{
 496#ifdef CONFIG_X86EMU_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/****************************************************************************
 504PARAMETERS:
 505segment - Segment to store data at
 506offset  - Offset to store data at
 507val     - Value to store
 508
 509REMARKS:
 510Writes a word value to an absolute memory location.
 511
 512NOTE: Do not inline this function as (*sys_wrX) is already inline!
 513****************************************************************************/
 514void store_data_word_abs(
 515    uint segment,
 516    uint offset,
 517    u16 val)
 518{
 519#ifdef CONFIG_X86EMU_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/****************************************************************************
 527PARAMETERS:
 528segment - Segment to store data at
 529offset  - Offset to store data at
 530val     - Value to store
 531
 532REMARKS:
 533Writes a long value to an absolute memory location.
 534
 535NOTE: Do not inline this function as (*sys_wrX) is already inline!
 536****************************************************************************/
 537void store_data_long_abs(
 538    uint segment,
 539    uint offset,
 540    u32 val)
 541{
 542#ifdef CONFIG_X86EMU_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/****************************************************************************
 550PARAMETERS:
 551reg - Register to decode
 552
 553RETURNS:
 554Pointer to the appropriate register
 555
 556REMARKS:
 557Return a pointer to the register given by the R/RM field of the
 558modrm byte, for byte operands. Also enables the decoding of instructions.
 559****************************************************************************/
 560u8* 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/****************************************************************************
 594PARAMETERS:
 595reg - Register to decode
 596
 597RETURNS:
 598Pointer to the appropriate register
 599
 600REMARKS:
 601Return a pointer to the register given by the R/RM field of the
 602modrm byte, for word operands.  Also enables the decoding of instructions.
 603****************************************************************************/
 604u16* 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/****************************************************************************
 638PARAMETERS:
 639reg - Register to decode
 640
 641RETURNS:
 642Pointer to the appropriate register
 643
 644REMARKS:
 645Return a pointer to the register given by the R/RM field of the
 646modrm byte, for dword operands.  Also enables the decoding of instructions.
 647****************************************************************************/
 648u32* 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/****************************************************************************
 682PARAMETERS:
 683reg - Register to decode
 684
 685RETURNS:
 686Pointer to the appropriate register
 687
 688REMARKS:
 689Return a pointer to the register given by the R/RM field of the
 690modrm byte, for word operands, modified from above for the weirdo
 691special case of segreg operands.  Also enables the decoding of instructions.
 692****************************************************************************/
 693u16* 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/****************************************************************************
 725PARAMETERS:
 726scale - scale value of SIB byte
 727index - index value of SIB byte
 728
 729RETURNS:
 730Value of scale * index
 731
 732REMARKS:
 733Decodes scale/index of SIB byte and returns relevant offset part of
 734effective address.
 735****************************************************************************/
 736unsigned 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/****************************************************************************
 777PARAMETERS:
 778mod - MOD value of preceding ModR/M byte
 779
 780RETURNS:
 781Offset in memory for the address decoding
 782
 783REMARKS:
 784Decodes SIB addressing byte and returns calculated effective address.
 785****************************************************************************/
 786unsigned 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/****************************************************************************
 857PARAMETERS:
 858rm  - RM value to decode
 859
 860RETURNS:
 861Offset in memory for the address decoding
 862
 863REMARKS:
 864Return the offset given by mod=00 addressing.  Also enables the
 865decoding of instructions.
 866
 867NOTE:   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****************************************************************************/
 876unsigned 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/****************************************************************************
 946PARAMETERS:
 947rm  - RM value to decode
 948
 949RETURNS:
 950Offset in memory for the address decoding
 951
 952REMARKS:
 953Return the offset given by mod=01 addressing.  Also enables the
 954decoding of instructions.
 955****************************************************************************/
 956unsigned 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/****************************************************************************
1035PARAMETERS:
1036rm  - RM value to decode
1037
1038RETURNS:
1039Offset in memory for the address decoding
1040
1041REMARKS:
1042Return the offset given by mod=10 addressing.  Also enables the
1043decoding of instructions.
1044****************************************************************************/
1045unsigned 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/****************************************************************************
1125PARAMETERS:
1126mod - modifier
1127rm  - RM value to decode
1128
1129RETURNS:
1130Offset in memory for the address decoding, multiplexing calls to
1131the decode_rmXX_address functions
1132
1133REMARKS:
1134Return the offset given by "mod" addressing.
1135****************************************************************************/
1136
1137unsigned 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