about summary refs log tree commit diff stats
path: root/src/emu/x64emu_private.h
blob: bd76c047deada638297eb170ae7a7e352115406e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#ifndef __X86EMU_PRIVATE_H_
#define __X86EMU_PRIVATE_H_

#include "regs.h"
#include "os.h"
#include "box64context.h"

typedef struct x64_ucontext_s x64_ucontext_t;
#ifdef BOX32
typedef struct i386_ucontext_s i386_ucontext_t;
#endif

#define ERR_UNIMPL  1
#define ERR_DIVBY0  2
#define ERR_ILLEGAL 4

typedef struct forkpty_s {
    void*    amaster;
    void*   name;
    void*   termp;
    void*   winp;
    void*   f;  // forkpty function
} forkpty_t;

typedef union multiuint_s {
    uint8_t     u8;
    int8_t      i8;
    uint16_t    u16;
    int16_t     i16;
    uint32_t    u32;
    int32_t     i32;
    uint64_t    u64;
    int64_t     i64;
} multiuint_t;

typedef struct x64emu_s x64emu_t;

typedef struct x64test_s {
    x64emu_t*   emu;
    uintptr_t   memaddr;
    int         memsize;
    int         test;
    int         clean;
    uint8_t     mem[32];
} x64test_t;

typedef struct emu_flags_s {
    uint32_t    need_jmpbuf:1;    // need a new jmpbuff for signal handling
    uint32_t    quitonlongjmp:2;  // quit if longjmp is called
    uint32_t    quitonexit:2;     // quit if exit/_exit is called
    uint32_t    longjmp:1;        // if quit because of longjmp
    uint32_t    jmpbuf_ready:1;   // the jmpbuf in the emu is ok and don't need refresh
} emu_flags_t;

#define N_SCRATCH 200

typedef struct x64emu_s {
    // cpu
    reg64_t     regs[16];
    x64flags_t  eflags;
    reg64_t     ip;
    // sse
    sse_regs_t  xmm[16];
    sse_regs_t  ymm[16];
    // fpu / mmx
    mmx87_regs_t x87[8];
    mmx87_regs_t mmx[8];
    x87flags_t  sw;
    uint32_t    top;        // top is part of sw, but it's faster to have it separately
    int         fpu_stack;
    x87control_t cw;
    uint16_t    dummy_cw;   // align...
    mmxcontrol_t mxcsr;
    #ifdef RV64         // it would be better to use a dedicated register for this like arm64 xSavedSP, but we're running out of free registers.
    uintptr_t xSPSave;  // sp base value of current dynarec frame, used by call/ret optimization to reset stack when unmatch.
    #endif
    fpu_ld_t    fpu_ld[8]; // for long double emulation / 80bits fld fst
    fpu_ll_t    fpu_ll[8]; // for 64bits fild / fist sequence
    uint64_t    fpu_tags;   // tags for the x87 regs, stacked, only on a 16bits anyway
    // old ip
    uintptr_t   old_ip;
    // deferred flags
    int         dummy1;     // to align on 64bits with df
    deferred_flags_t df;
    multiuint_t op1;
    multiuint_t op2;
    multiuint_t res;
    uint32_t    *x64emu_parity_tab; // helper
    // segments
    uint16_t    segs[6];        // only 32bits value?
    uint16_t    dummy_seg6, dummy_seg7; // to stay aligned
    uintptr_t   segs_offs[6];   // computed offset associate with segment
    uint32_t    segs_serial[6];  // are seg offset clean (not 0) or does they need to be re-computed (0)? For GS, serial need to be the same as context->sel_serial
    // parent context
    box64context_t *context;
    // cpu helpers
    reg64_t     zero;
    reg64_t     *sbiidx[16];
    // emu control
    int         quit;
    int         error;
    int         fork;   // quit because need to fork
    int         exit;
    forkpty_t*  forkpty_info;
    emu_flags_t flags;
    x64test_t   test;       // used for dynarec testing
    // scratch stack, used for alignment of double and 64bits ints on arm. 200 elements should be enough
    __int128_t dummy_align; // here to have scratch 128bits aligned
    uint64_t scratch[N_SCRATCH];

    // Warning, offsetof(x64emu_t, xxx) will be too big for fields below.
    #ifdef HAVE_TRACE
    sse_regs_t  old_xmm[16];
    sse_regs_t  old_ymm[16];
    reg64_t     oldregs[16];
    uintptr_t   prev2_ip;
    #endif
    // local stack, do be deleted when emu is freed
    void*       stack2free; // this is the stack to free (can be NULL)
    void*       init_stack; // initial stack (owned or not)
    uint32_t    size_stack; // stack size (owned or not)
    JUMPBUFF*   jmpbuf;
    #ifdef RV64
    uintptr_t   old_savedsp;
    #endif

    #ifdef _WIN32
    uint64_t    win64_teb;
    #endif
    // local selector handling
    base_segment_t  segldt[16];
    base_segment_t  seggdt[16];  // hacky
    tlsdatasize_t  *tlsdata;
    // other informations
    int         type;       // EMUTYPE_xxx define
    #ifdef BOX32
    int         libc_err;   // copy of errno from libc
    int         libc_herr;  // copy of h_errno from libc
    unsigned short          libctype[384];   // copy from __ctype_b address might be too high
    const unsigned short*   ref_ctype;
    const unsigned short*   ctype;
    int         libctolower[384];   // copy from __ctype_b_tolower address might be too high
    const int*  ref_tolower;
    const int*  tolower;
    int         libctoupper[384];   // copy from __ctype_b_toupper address might be too high
    const int*  ref_toupper;
    const int*  toupper;
    void*       res_state_32;  //32bits version of res_state
    void*       res_state_64;
    #endif
} x64emu_t;

#define EMUTYPE_NONE    0
#define EMUTYPE_MAIN    1
#define EMUTYPE_SIGNAL  2

//#define INTR_RAISE_DIV0(emu) {emu->error |= ERR_DIVBY0; emu->quit=1;}
#define INTR_RAISE_DIV0(emu) {emu->error |= ERR_DIVBY0;} // should rise a SIGFPE and not quit

void applyFlushTo0(x64emu_t* emu);

#endif //__X86EMU_PRIVATE_H_