/*++

Copyright (c) 1992-1998  Microsoft Corporation

Module Name:

    threadst.h

Abstract:

    This module defines the structures and constant for describing a
    thread's state.
    

Author:

    Dave Hastings (daveh) creation-date 20-May-1995

Revision History:


--*/

#ifndef _THREADST_H_
#define _THREADST_H_

#define EIPLOGSIZE  32    // keep track of the last N instructions run

#define CSSIZE  512       // Size of call stack (512*8 = 2048 bytes = 1 page)

typedef union _REG32 {    // definition of a 32-bit x86 register
    struct {
	BYTE i1;
	BYTE hb;
    };
    USHORT i2;
    ULONG  i4;
} REG32;

#if defined(_ALPHA_)
typedef DWORD FPTAG;        // bytes are too slow on AXP
#else
typedef BYTE  FPTAG;
#endif

typedef struct _FPREG {     // definition of an x86 floating-point register
    union {
        double  r64;
        DWORD   rdw[2];
        BYTE    rb[8];
    };
    FPTAG   Tag;
    FPTAG   TagSpecial;
} FPREG, *PFPREG;

//
// CALLSTACK is an optimization for CALL/RET pairs, so that an expensive
// NativeAddressFromEip() call can be avoided when determining the RISC
// address of an x86 return address.
//
typedef struct _callStack {
    ULONG intelAddr;
    ULONG nativeAddr;
} CALLSTACK, *PCALLSTACK;

// Indices into CPUSTATE.Regs[].  get_reg32() depends on EAX through
// EDI being contiguous and ordered the same as they are in the mod/rm and
// reg instruction encodings (ie. EAX=0,ECX=1,EDX=2,EBX=3,ESP=4,EBP=5,ESI=6,
// EDI=7)
#define GP_EAX  0x00
#define GP_ECX  0x01
#define GP_EDX  0x02
#define GP_EBX  0x03
#define GP_ESP  0x04
#define GP_EBP  0x05
#define GP_ESI  0x06
#define GP_EDI  0x07

// Segment registers.  get_segreg() depends on the order.
#define REG_ES  0x08
#define REG_CS  0x09
#define REG_SS  0x0a
#define REG_DS  0x0b
#define REG_FS  0x0c
#define REG_GS  0x0d


// Identifiers for components of registers.  get_reg16() depends on the order.
#define GP_AX   0x0e
#define GP_CX   0x0f
#define GP_DX   0x10
#define GP_BX   0x11
#define GP_SP   0x12
#define GP_BP   0x13
#define GP_SI   0x14
#define GP_DI   0x15

// PlaceOperandFragments() depends on GP_AH and beyond, and that no registers
// are past GP_BH.
#define GP_AL   0x16
#define GP_CL   0x17
#define GP_DL   0x18
#define GP_BL   0x19
#define GP_AH   0x1a
#define GP_CH   0x1b
#define GP_DH   0x1c
#define GP_BH   0x1d

#define NO_REG  0xffffffff

typedef struct _CPU_SUSPEND_MSG
{
    // Owned by local thread 
    HANDLE StartSuspendCallEvent;
    HANDLE EndSuspendCallEvent;

} CPU_SUSPEND_MSG, *PCPU_SUSPEND_MSG;

// all information related to a particular thread of the CPU belongs here
typedef struct _ThreadState {

    //
    // General-purpose and segment registers
    // accessible as an array of REG32 or by Register Name
    // NOTE: the name orders must match the GP_XXX defines for registers
    //
    union {
        REG32 GpRegs[14];
        struct _RegisterByName {
            REG32 Eax;
            REG32 Ecx;
            REG32 Edx;
            REG32 Ebx;
            REG32 Esp;
            REG32 Ebp;
            REG32 Esi;
            REG32 Edi;
            REG32 Es;
            REG32 Cs;
            REG32 Ss;
            REG32 Ds;
            REG32 Fs;
            REG32 Gs;
            };
        };

    REG32 eipReg;       // Pointer to start of current instruction (never
			//  points into the middle of an instruction)

    DWORD   flag_cf;    // 0 = carry
    DWORD   flag_pf;    // 2 = parity
    DWORD   flag_aux;   // 4 = aux carry
    DWORD   flag_zf;    // 6 = zero
    DWORD   flag_sf;    // 7 = sign
    DWORD   flag_tf;    // 8 = trap
    DWORD   flag_if;    // 9 = interrupt enable
    DWORD   flag_df;    // 10 = direction   (1 = clear, -1 = set)
    DWORD   flag_of;    // 11 = overflow
    DWORD   flag_nt;    // 14 = nested task
    DWORD   flag_rf;    // 16 = resume flag
    DWORD   flag_vm;    // 17 = virtual mode
    DWORD   flag_ac;    // 18 = alignment check

    // Floating-point registers
    FPREG  FpStack[8];
    PFPREG FpST0;
    INT    FpTop;
    INT    FpStatusC3;
    INT    FpStatusC2;
    INT    FpStatusC1;
    INT    FpStatusC0;
    INT    FpStatusSF;
    INT    FpStatusES;      // Error Summary Status
    INT    FpControlInfinity;
    INT    FpControlRounding;
    INT    FpControlPrecision;
    DWORD  FpStatusExceptions;
    DWORD  FpControlMask;
    DWORD  FpEip;           // EIP for the current FP instruction
    PVOID  FpData;          // Effective address for current FP instruction
    PVOID  FpAddTable;      // ptr to table of function pointers for FADD
    PVOID  FpSubTable;      // ptr to table of function pointers for FSUB
    PVOID  FpMulTable;      // ptr to table of function pointers for FMUL
    PVOID  FpDivTable;      // ptr to table of function pointers for FDIV

    ULONG CpuNotify;

    PVOID TraceAddress; // Used by debugger extensions

    DWORD  fTCUnlocked;     // FALSE means TC must be unlocked after exception

    // SuspendThread/ResumeThread support
    PCPU_SUSPEND_MSG SuspendMsg;

    int   eipLogIndex;  // Index of next entry to write into in the log
    DWORD eipLog[EIPLOGSIZE]; // log of last EIPLOGSIZE instructions run

    ULONG CSIndex;    // Index into the stack (offset of current location)
    DWORD CSTimestamp;// Value of TranslationCacheTimestamp corresponding to the callstack cache
    CALLSTACK callStack[CSSIZE];    // callstack optimization

    int ErrnoVal;           // CRT errno value

    DWORD   flag_id;    // 21 = ID (CPUID present if this can be toggled)

}  THREADSTATE, *PTHREADSTATE, CPUCONTEXT, *PCPUCONTEXT;

// Bit offsets in cpu->FpControlMask.  Same as the x86 bit positions
#define FPCONTROL_IM    1       // Invalid operation
#define FPCONTROL_DM    2       // Denormalized operation
#define FPCONTROL_ZM    4       // Zero divide
#define FPCONTROL_OM    8       // Overflow
#define FPCONTROL_UM    16      // Underflow
#define FPCONTROL_PM    32      // Precision

// This macro allows one to access the cpu state via the local variable cpu
#define DECLARE_CPU                                         \
    PCPUCONTEXT cpu=(PCPUCONTEXT)Wow64TlsGetValue(WOW64_TLS_CPURESERVED);

//
// The following macros allow one to push and pop values from the
// call stack
//

#define ISTOPOF_CALLSTACK(iAddr)                            \
    (cpu->callStack[(cpu->CSIndex)].intelAddr == iAddr)

#define PUSH_CALLSTACK(iAddr,nAddr)                         \
{                                                           \
    PCALLSTACK pCallStack;                                  \
                                                            \
    cpu->CSIndex = (cpu->CSIndex+1) % CSSIZE;               \
    pCallStack = &cpu->callStack[cpu->CSIndex];             \
    pCallStack->intelAddr = iAddr;                          \
    pCallStack->nativeAddr = nAddr;                         \
}

#define POP_CALLSTACK(iAddr,nAddr)                          \
{                                                           \
    PCALLSTACK pCallStack;                                  \
    extern ULONG TranslationCacheTimestamp;                 \
                                                            \
    CPUASSERTMSG(                                           \
        (cpu->CSTimestamp == TranslationCacheTimestamp),    \
        "POP_CALLSTACK: About to return and invalid value\n"\
        );                                                  \
                                                            \
    pCallStack = &cpu->callStack[cpu->CSIndex];             \
    if (iAddr == pCallStack->intelAddr) {                   \
        nAddr = pCallStack->nativeAddr;                     \
    } else {                                                \
        nAddr = 0;                                          \
    }                                                       \
    cpu->CSIndex = (cpu->CSIndex-1) % CSSIZE;               \
}

PCPUCONTEXT GetCpuContext ();  //has been implemented in wowproxy

NTSTATUS
CpupSuspendCurrentThread(
    VOID);


#endif  //_THREADST_H_