|
|
/*++
Copyright (c) 1996-1998 Microsoft Corporation
Module Name:
miscfns.c
Abstract: Miscellaneous instuctions
Author:
29-Jun-1995 BarryBo
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdio.h>
#include "wx86.h"
#include "cpuassrt.h"
#include "threadst.h"
#include "instr.h"
#include "decoderp.h"
ASSERTNAME;
// table used by ProcessPrefixes
pfnDispatchInstruction *DispatchTables[4] = { Dispatch32, Dispatch16, LockDispatch32, LockDispatch16 };
// ---------------- single-byte functions -------------------------------
DISPATCH(ProcessPrefixes) { int DataPrefix = 0; int LockPrefix = 0; int cbInstr = 0;
for (;;) { switch (*(PBYTE)(eipTemp)) { case 0x64: // fs:
Instr->FsOverride = TRUE; break;
case 0xf3: // repz
State->RepPrefix = PREFIX_REPZ; break;
case 0xf2: // repnz
State->RepPrefix = PREFIX_REPNZ; break;
case 0xf0: // lock
LockPrefix = 2; // The lock tables are in locations 2 and 3 DispatchTables
break;
case 0x2e: // cs:
case 0x36: // ss:
case 0x3e: // ds:
case 0x26: // es:
case 0x65: // gs:
Instr->FsOverride = FALSE; break;
case 0x66: // data
DataPrefix = 1; break;
case 0x67: // adr
State->AdrPrefix=TRUE; break;
default: // No more prefixes found. Set up dispatch tables based on
// the prefixes seen.
// Decode and execute the actual instruction
((DispatchTables[DataPrefix+LockPrefix])[GET_BYTE(eipTemp)])(State, Instr);
// Adjust the Intel instruction size by the number of prefixes
Instr->Size += cbInstr;
#if DBG
// Ensure that if we saw an ADR: prefix, the decoder had code
// to handle the prefix. In the checked build, all functions which
// handle the ADR: prefix clear State->AdrPrefix.
if (State->AdrPrefix) { LOGPRINT((TRACELOG, "CPU Decoder: An unsupported instruction had an ADR: prefix.\r\n" "Instruction Address = 0x%x. Ignoring ADR: - this address may be data\r\n", Instr->IntelAddress )); } #endif
State->AdrPrefix = FALSE;
// return to the decoder
return; } eipTemp++; cbInstr++; } } DISPATCH(bad) { BAD_INSTR; } DISPATCH(privileged) { PRIVILEGED_INSTR; } DISPATCH(push_es) { Instr->Operation = OP_PushEs; } DISPATCH(pop_es) { Instr->Operation = OP_PopEs; } DISPATCH(push_cs) { Instr->Operation = OP_PushCs; } DISPATCH(aas) { Instr->Operation = OP_Aas; } DISPATCH(push_ss) { Instr->Operation = OP_PushSs; } DISPATCH(pop_ss) { Instr->Operation = OP_PopSs; } DISPATCH(push_ds) { Instr->Operation = OP_PushDs; } DISPATCH(pop_ds) { Instr->Operation = OP_PopDs; } DISPATCH(daa) { Instr->Operation = OP_Daa; } DISPATCH(das) { Instr->Operation = OP_Das; } DISPATCH(aaa) { Instr->Operation = OP_Aaa; } DISPATCH(aad_ib) { Instr->Operation = OP_Aad; Instr->Operand1.Type = OPND_IMM; Instr->Operand1.Immed = GET_BYTE(eipTemp+1); Instr->Size = 2; } DISPATCH(imul_rw_m_iw16) // reg16 = rm16 * immediate word
{ int cbInstr = mod_rm_reg16(State, &Instr->Operand2, &Instr->Operand1);
Instr->Operation = OP_Imul3Arg16; DEREF16(Instr->Operand2); Instr->Operand3.Type = OPND_IMM; Instr->Operand3.Immed = GET_SHORT(eipTemp+1+cbInstr); Instr->Size = 3+cbInstr; } DISPATCH(imul_rw_m_iw32) { int cbInstr = mod_rm_reg32(State, &Instr->Operand2, &Instr->Operand1);
Instr->Operation = OP_Imul3Arg32; DEREF32(Instr->Operand2); Instr->Operand3.Type = OPND_IMM; Instr->Operand3.Immed = GET_LONG(eipTemp+1+cbInstr); Instr->Size = 5+cbInstr; } DISPATCH(imul_rw_m_ib16) // reg16 = rm16 * sign-extended immediate byte
{ int cbInstr = mod_rm_reg16(State, &Instr->Operand2, &Instr->Operand1);
Instr->Operation = OP_Imul3Arg16; DEREF16(Instr->Operand2); Instr->Operand3.Type = OPND_IMM; Instr->Operand3.Immed = (DWORD)(short)(char)GET_BYTE(eipTemp+1+cbInstr); Instr->Size = 2+cbInstr; } DISPATCH(imul_rw_m_ib32) // reg32 = rm32 * sign-extended immediate byte
{ int cbInstr = mod_rm_reg32(State, &Instr->Operand2, &Instr->Operand1);
Instr->Operation = OP_Imul3Arg32; DEREF32(Instr->Operand2); Instr->Operand3.Type = OPND_IMM; Instr->Operand3.Immed = (DWORD)(long)(char)GET_BYTE(eipTemp+1+cbInstr); Instr->Size = 2+cbInstr; } DISPATCH(mov_mw_seg) { int cbInstr = mod_rm_reg16(State, &Instr->Operand1, NULL); get_segreg(State, &Instr->Operand2);
Instr->Operation = OP_Mov16; Instr->Size = cbInstr+1; } DISPATCH(mov_seg_mw) { int cbInstr = mod_rm_reg16(State, &Instr->Operand2, NULL); get_segreg(State, &Instr->Operand1);
Instr->Operation = OP_Mov16; DEREF16(Instr->Operand2); CPUASSERT(Instr->Operand1.Type == OPND_REGVALUE); Instr->Operand1.Type = OPND_REGREF; Instr->Size = cbInstr+1; } DISPATCH(nop) { Instr->Operation = OP_Nop; } DISPATCH(call_md) { Instr->Operation = OP_CTRL_UNCOND_Callf; Instr->Operand1.Type = OPND_IMM; Instr->Operand1.Immed = eipTemp+1; Instr->Operand2.Type = OPND_IMM; Instr->Operand2.Immed = eipTemp+sizeof(ULONG)+sizeof(USHORT)+1; Instr->Size = sizeof(ULONG)+sizeof(USHORT)+1; } DISPATCH(sahf) { Instr->Operation = OP_Sahf; } DISPATCH(lahf) { Instr->Operation = OP_Lahf; } DISPATCH(mov_ah_ib) { Instr->Operation = OP_Mov8; Instr->Operand1.Type = OPND_REGREF; Instr->Operand1.Reg = GP_AH; Instr->Operand2.Type = OPND_IMM; Instr->Operand2.Immed = GET_BYTE(eipTemp+1); Instr->Size = 2; } DISPATCH(mov_ch_ib) { Instr->Operation = OP_Mov8; Instr->Operand1.Type = OPND_REGREF; Instr->Operand1.Reg = GP_CH; Instr->Operand2.Type = OPND_IMM; Instr->Operand2.Immed = GET_BYTE(eipTemp+1); Instr->Size = 2; } DISPATCH(mov_dh_ib) { Instr->Operation = OP_Mov8; Instr->Operand1.Type = OPND_REGREF; Instr->Operand1.Reg = GP_DH; Instr->Operand2.Type = OPND_IMM; Instr->Operand2.Immed = GET_BYTE(eipTemp+1); Instr->Size = 2; } DISPATCH(mov_bh_ib) { Instr->Operation = OP_Mov8; Instr->Operand1.Type = OPND_REGREF; Instr->Operand1.Reg = GP_BH; Instr->Operand2.Type = OPND_IMM; Instr->Operand2.Immed = GET_BYTE(eipTemp+1); Instr->Size = 2; } DISPATCH(int3) { Instr->Operation = OP_Int; } DISPATCH(int_ib) { Instr->Operation = OP_Int; Instr->Size = 2; } DISPATCH(into) { Instr->Operation = OP_IntO; } DISPATCH(iret) { Instr->Operation = OP_CTRL_INDIR_IRet; } DISPATCH(aam_ib) { Instr->Operation = OP_Aam; Instr->Operand1.Type = OPND_IMM; Instr->Operand1.Immed = GET_BYTE(eipTemp+1); Instr->Size = 2; } DISPATCH(xlat) { Instr->Operation = OP_Xlat; } DISPATCH(jmpf_md) { Instr->Operation = OP_CTRL_UNCOND_Jmpf; Instr->Operand1.Type = OPND_IMM; Instr->Operand1.Immed = eipTemp+1; Instr->Size = 7; } DISPATCH(jmp_jb) { Instr->Operand1.Type = OPND_NOCODEGEN; if (State->AdrPrefix) { Instr->Operand1.Immed = MAKELONG((short)(char)GET_BYTE(eipTemp+1)+2+(short)LOWORD(eipTemp), HIWORD(eipTemp)); #if DBG
State->AdrPrefix = FALSE; #endif
} else { Instr->Operand1.Immed = (DWORD)(long)(char)GET_BYTE(eipTemp+1)+2+eipTemp; } if (Instr->Operand1.Immed > eipTemp) { Instr->Operation = OP_CTRL_UNCOND_JmpFwd; } else { Instr->Operation = OP_CTRL_UNCOND_Jmp; } Instr->Size = 2; } DISPATCH(cmc) { Instr->Operation = OP_Cmc; } DISPATCH(clc) { Instr->Operation = OP_Clc; } DISPATCH(stc) { Instr->Operation = OP_Stc; } DISPATCH(cld) { Instr->Operation = OP_Cld; } DISPATCH(std) { Instr->Operation = OP_Std; } DISPATCH(GROUP_4) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL); BYTE g = GET_BYTE(eipTemp+1);
switch ((g >> 3) & 0x07) { case 0: // inc modrmB
Instr->Operation = OP_Inc8; Instr->Size = 1+cbInstr; break; case 1: // dec modrmB
Instr->Operation = OP_Dec8; Instr->Size = 1+cbInstr; break; default: BAD_INSTR; } }
//-------- double-byte functions -----------------------------------------------
DISPATCH(GROUP_6) { BYTE g = GET_BYTE(eipTemp+1); int cbInstr;
switch ((g >> 3) & 0x07) { case 0: // sldt modrmw
case 1: // str modrmw
case 2: // lldt modrmw
case 3: // ltr modrmw
PRIVILEGED_INSTR; break;
case 4: // verr modrmw
cbInstr = mod_rm_reg16(State, &Instr->Operand1, NULL); Instr->Operation = OP_Verr; Instr->Size = 2+cbInstr; break;
case 5: // verw modrmw
cbInstr = mod_rm_reg16(State, &Instr->Operand1, NULL); Instr->Operation = OP_Verw; Instr->Size = 2+cbInstr; break;
default: BAD_INSTR; // bad
} } DISPATCH(GROUP_7) { BYTE g = GET_BYTE(eipTemp+1); int cbInstr;
switch ((g >> 3) & 0x07) { case 0: // sgdt modrmw
case 1: // sidt modrmw
case 2: // lgdt modrmw
case 3: // lidt modrmw
case 6: // lmsw modrmw
PRIVILEGED_INSTR; break;
case 4: // smsw modrmw
cbInstr = mod_rm_reg16(State, &Instr->Operand1, NULL); Instr->Operation = OP_Smsw; Instr->Size = 2+cbInstr; break;
case 5: // bad
case 7: // bad
BAD_INSTR; } } DISPATCH(seto_modrmb) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Seto; Instr->Size = 2+cbInstr; } DISPATCH(setno_modrmb) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setno; Instr->Size = 2+cbInstr; } DISPATCH(setb_modrmb) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setb; Instr->Size = 2+cbInstr; } DISPATCH(setae_modrmb) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setae; Instr->Size = 2+cbInstr; } DISPATCH(sete_modrmb) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Sete; Instr->Size = 2+cbInstr; } DISPATCH(setne_modrmb) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setne; Instr->Size = 2+cbInstr; } DISPATCH(setbe_modrmb) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setbe; Instr->Size = 2+cbInstr; } DISPATCH(seta_modrmb) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Seta; Instr->Size = 2+cbInstr; } DISPATCH(sets_modrmb) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Sets; Instr->Size = 2+cbInstr; } DISPATCH(setns_modrmb) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setns; Instr->Size = 2+cbInstr; } DISPATCH(setp_modrmb) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setp; Instr->Size = 2+cbInstr; } DISPATCH(setnp_modrmb) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setnp; Instr->Size = 2+cbInstr; } DISPATCH(setl_modrmb) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setl; Instr->Size = 2+cbInstr; } DISPATCH(setge_modrmb) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setge; Instr->Size = 2+cbInstr; } DISPATCH(setle_modrmb) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setle; Instr->Size = 2+cbInstr; } DISPATCH(setg_modrmb) { int cbInstr = mod_rm_reg8(State, &Instr->Operand1, NULL);
Instr->Operation = OP_Setg; Instr->Size = 2+cbInstr; } DISPATCH(push_fs) { Instr->Operation = OP_PushFs; Instr->Size = 2; } DISPATCH(pop_fs) { Instr->Operation = OP_PopFs; Instr->Size = 2; } DISPATCH(push_gs) { Instr->Operation = OP_PushGs; Instr->Size = 2; } DISPATCH(pop_gs) { Instr->Operation = OP_PopGs; Instr->Size = 2; } DISPATCH(imul_regw_modrmw16) // reg16 = reg16 * mod/rm
{ int cbInstr = mod_rm_reg16(State, &Instr->Operand2, &Instr->Operand1);
Instr->Operation = OP_Imul16; DEREF32(Instr->Operand2); Instr->Size = 2+cbInstr;
} DISPATCH(imul_regw_modrmw32) // reg32 = reg32 * mod/rm
{ int cbInstr = mod_rm_reg32(State, &Instr->Operand2, &Instr->Operand1);
Instr->Operation = OP_Imul32; DEREF32(Instr->Operand2); Instr->Size = 2+cbInstr; } DISPATCH(movzx_regw_modrmw) { int cbInstr = mod_rm_reg16(State, &Instr->Operand1, NULL);
DEREF16(Instr->Operand1); Instr->Operation = OP_Movzx16To32; Instr->Operand2.Type = OPND_NOCODEGEN; Instr->Operand2.Reg = get_reg32(State); Instr->Size = 2+cbInstr; } DISPATCH(movsx_regw_modrmw) { int cbInstr = mod_rm_reg16(State, &Instr->Operand1, NULL); DEREF16(Instr->Operand1); Instr->Operation = OP_Movsx16To32; Instr->Operand2.Type = OPND_NOCODEGEN; Instr->Operand2.Reg = get_reg32(State); Instr->Size = 2+cbInstr; } DISPATCH(wait) { Instr->Operation = OP_Wait; } DISPATCH(bswap_eax) { Instr->Operation = OP_Bswap32; Instr->Operand1.Type = OPND_REGREF; Instr->Operand1.Reg = GP_EAX; Instr->Size = 2; } DISPATCH(bswap_ebx) { Instr->Operation = OP_Bswap32; Instr->Operand1.Type = OPND_REGREF; Instr->Operand1.Reg = GP_EBX; Instr->Size = 2; } DISPATCH(bswap_ecx) { Instr->Operation = OP_Bswap32; Instr->Operand1.Type = OPND_REGREF; Instr->Operand1.Reg = GP_ECX; Instr->Size = 2; } DISPATCH(bswap_edx) { Instr->Operation = OP_Bswap32; Instr->Operand1.Type = OPND_REGREF; Instr->Operand1.Reg = GP_EDX; Instr->Size = 2; } DISPATCH(bswap_esp) { Instr->Operation = OP_Bswap32; Instr->Operand1.Type = OPND_REGREF; Instr->Operand1.Reg = GP_ESP; Instr->Size = 2; } DISPATCH(bswap_ebp) { Instr->Operation = OP_Bswap32; Instr->Operand1.Type = OPND_REGREF; Instr->Operand1.Reg = GP_EBP; Instr->Size = 2; } DISPATCH(bswap_esi) { Instr->Operation = OP_Bswap32; Instr->Operand1.Type = OPND_REGREF; Instr->Operand1.Reg = GP_ESI; Instr->Size = 2; } DISPATCH(bswap_edi) { Instr->Operation = OP_Bswap32; Instr->Operand1.Type = OPND_REGREF; Instr->Operand1.Reg = GP_EDI; Instr->Size = 2; } DISPATCH(arpl) { int cbInstr = mod_rm_reg16(State, &Instr->Operand1, &Instr->Operand2);
Instr->Operation = OP_Arpl; CPUASSERT(Instr->Operand2.Type == OPND_REGREF); Instr->Operand2.Type = OPND_REGVALUE; Instr->Size = 1+cbInstr; } DISPATCH(cpuid) { Instr->Operation = OP_CPUID; Instr->Size = 2; } DISPATCH(rdtsc) { Instr->Operation = OP_Rdtsc; Instr->Size = 2; } DISPATCH(cmpxchg8b) { int cbInstr = mod_rm_reg32(State, &Instr->Operand1, &Instr->Operand2);
Instr->Operation = OP_CMPXCHG8B; Instr->Size = 2+cbInstr; } DISPATCH(LOCKcmpxchg8b) { int cbInstr = mod_rm_reg32(State, &Instr->Operand1, &Instr->Operand2);
Instr->Operation = OP_SynchLockCMPXCHG8B; Instr->Size = 2+cbInstr; }
|