blob: aba2b3ed7595681cfd235ebe702dc318e96e0441 (
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
|
#ifndef __X86EMU_PRIVATE_H_
#define __X86EMU_PRIVATE_H_
#include "regs.h"
#include "os.h"
typedef struct box64context_s box64context_t;
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
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_
|