better 16 bit code support
[qemu] / cpu-i386.h
1 /* NOTE: this header is included in op-i386.c where global register
2    variable are used. Care must be used when including glibc headers.
3  */
4 #ifndef CPU_I386_H
5 #define CPU_I386_H
6
7 #include "config.h"
8 #include <setjmp.h>
9
10 #define R_EAX 0
11 #define R_ECX 1
12 #define R_EDX 2
13 #define R_EBX 3
14 #define R_ESP 4
15 #define R_EBP 5
16 #define R_ESI 6
17 #define R_EDI 7
18
19 #define R_AL 0
20 #define R_CL 1
21 #define R_DL 2
22 #define R_BL 3
23 #define R_AH 4
24 #define R_CH 5
25 #define R_DH 6
26 #define R_BH 7
27
28 #define R_ES 0
29 #define R_CS 1
30 #define R_SS 2
31 #define R_DS 3
32 #define R_FS 4
33 #define R_GS 5
34
35 #define CC_C    0x0001
36 #define CC_P    0x0004
37 #define CC_A    0x0010
38 #define CC_Z    0x0040
39 #define CC_S    0x0080
40 #define CC_O    0x0800
41
42 #define TRAP_FLAG               0x0100
43 #define INTERRUPT_FLAG          0x0200
44 #define DIRECTION_FLAG          0x0400
45 #define IOPL_FLAG_MASK          0x3000
46 #define NESTED_FLAG             0x4000
47 #define BYTE_FL                 0x8000  /* Intel reserved! */
48 #define RF_FLAG                 0x10000
49 #define VM_FLAG                 0x20000
50 /* AC                           0x40000 */
51
52 #define EXCP00_DIVZ     1
53 #define EXCP01_SSTP     2
54 #define EXCP02_NMI      3
55 #define EXCP03_INT3     4
56 #define EXCP04_INTO     5
57 #define EXCP05_BOUND    6
58 #define EXCP06_ILLOP    7
59 #define EXCP07_PREX     8
60 #define EXCP08_DBLE     9
61 #define EXCP09_XERR     10
62 #define EXCP0A_TSS      11
63 #define EXCP0B_NOSEG    12
64 #define EXCP0C_STACK    13
65 #define EXCP0D_GPF      14
66 #define EXCP0E_PAGE     15
67 #define EXCP10_COPR     17
68 #define EXCP11_ALGN     18
69 #define EXCP12_MCHK     19
70
71 #define EXCP_SIGNAL     256 /* async signal */
72
73 enum {
74     CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
75     CC_OP_EFLAGS,  /* all cc are explicitely computed, CC_SRC = flags */
76     CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */
77
78     CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
79     CC_OP_ADDW,
80     CC_OP_ADDL,
81
82     CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
83     CC_OP_ADCW,
84     CC_OP_ADCL,
85
86     CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
87     CC_OP_SUBW,
88     CC_OP_SUBL,
89
90     CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
91     CC_OP_SBBW,
92     CC_OP_SBBL,
93
94     CC_OP_LOGICB, /* modify all flags, CC_DST = res */
95     CC_OP_LOGICW,
96     CC_OP_LOGICL,
97
98     CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */
99     CC_OP_INCW,
100     CC_OP_INCL,
101
102     CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C  */
103     CC_OP_DECW,
104     CC_OP_DECL,
105
106     CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
107     CC_OP_SHLW,
108     CC_OP_SHLL,
109
110     CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
111     CC_OP_SARW,
112     CC_OP_SARL,
113
114     CC_OP_NB,
115 };
116
117 #ifdef __i386__
118 #define USE_X86LDOUBLE
119 #endif
120
121 #ifdef USE_X86LDOUBLE
122 typedef long double CPU86_LDouble;
123 #else
124 typedef double CPU86_LDouble;
125 #endif
126
127 typedef struct SegmentCache {
128     uint8_t *base;
129     unsigned long limit;
130     uint8_t seg_32bit;
131 } SegmentCache;
132
133 typedef struct SegmentDescriptorTable {
134     uint8_t *base;
135     unsigned long limit;
136     /* this is the returned base when reading the register, just to
137     avoid that the emulated program modifies it */
138     unsigned long emu_base;
139 } SegmentDescriptorTable;
140
141 typedef struct CPUX86State {
142     /* standard registers */
143     uint32_t regs[8];
144     uint32_t eip;
145     uint32_t eflags;
146
147     /* emulator internal eflags handling */
148     uint32_t cc_src;
149     uint32_t cc_dst;
150     uint32_t cc_op;
151     int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */
152
153     /* FPU state */
154     unsigned int fpstt; /* top of stack index */
155     unsigned int fpus;
156     unsigned int fpuc;
157     uint8_t fptags[8];   /* 0 = valid, 1 = empty */
158     CPU86_LDouble fpregs[8];    
159
160     /* emulator internal variables */
161     CPU86_LDouble ft0;
162     
163     /* segments */
164     uint32_t segs[6]; /* selector values */
165     SegmentCache seg_cache[6]; /* info taken from LDT/GDT */
166     SegmentDescriptorTable gdt;
167     SegmentDescriptorTable ldt;
168     SegmentDescriptorTable idt;
169     
170     /* various CPU modes */
171     int vm86;
172
173     /* exception handling */
174     jmp_buf jmp_env;
175     int exception_index;
176 } CPUX86State;
177
178 /* all CPU memory access use these macros */
179 static inline int ldub(void *ptr)
180 {
181     return *(uint8_t *)ptr;
182 }
183
184 static inline int ldsb(void *ptr)
185 {
186     return *(int8_t *)ptr;
187 }
188
189 static inline void stb(void *ptr, int v)
190 {
191     *(uint8_t *)ptr = v;
192 }
193
194 #ifdef WORDS_BIGENDIAN
195
196 /* conservative code for little endian unaligned accesses */
197 static inline int lduw(void *ptr)
198 {
199 #ifdef __powerpc__
200     int val;
201     __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
202     return val;
203 #else
204     uint8_t *p = ptr;
205     return p[0] | (p[1] << 8);
206 #endif
207 }
208
209 static inline int ldsw(void *ptr)
210 {
211 #ifdef __powerpc__
212     int val;
213     __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
214     return (int16_t)val;
215 #else
216     uint8_t *p = ptr;
217     return (int16_t)(p[0] | (p[1] << 8));
218 #endif
219 }
220
221 static inline int ldl(void *ptr)
222 {
223 #ifdef __powerpc__
224     int val;
225     __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
226     return val;
227 #else
228     uint8_t *p = ptr;
229     return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
230 #endif
231 }
232
233 static inline uint64_t ldq(void *ptr)
234 {
235     uint8_t *p = ptr;
236     uint32_t v1, v2;
237     v1 = ldl(p);
238     v2 = ldl(p + 4);
239     return v1 | ((uint64_t)v2 << 32);
240 }
241
242 static inline void stw(void *ptr, int v)
243 {
244 #ifdef __powerpc__
245     __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
246 #else
247     uint8_t *p = ptr;
248     p[0] = v;
249     p[1] = v >> 8;
250 #endif
251 }
252
253 static inline void stl(void *ptr, int v)
254 {
255 #ifdef __powerpc__
256     __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
257 #else
258     uint8_t *p = ptr;
259     p[0] = v;
260     p[1] = v >> 8;
261     p[2] = v >> 16;
262     p[3] = v >> 24;
263 #endif
264 }
265
266 static inline void stq(void *ptr, uint64_t v)
267 {
268     uint8_t *p = ptr;
269     stl(p, (uint32_t)v);
270     stl(p + 4, v >> 32);
271 }
272
273 /* float access */
274
275 static inline float ldfl(void *ptr)
276 {
277     union {
278         float f;
279         uint32_t i;
280     } u;
281     u.i = ldl(ptr);
282     return u.f;
283 }
284
285 static inline double ldfq(void *ptr)
286 {
287     union {
288         double d;
289         uint64_t i;
290     } u;
291     u.i = ldq(ptr);
292     return u.d;
293 }
294
295 static inline void stfl(void *ptr, float v)
296 {
297     union {
298         float f;
299         uint32_t i;
300     } u;
301     u.f = v;
302     stl(ptr, u.i);
303 }
304
305 static inline void stfq(void *ptr, double v)
306 {
307     union {
308         double d;
309         uint64_t i;
310     } u;
311     u.d = v;
312     stq(ptr, u.i);
313 }
314
315 #else
316
317 static inline int lduw(void *ptr)
318 {
319     return *(uint16_t *)ptr;
320 }
321
322 static inline int ldsw(void *ptr)
323 {
324     return *(int16_t *)ptr;
325 }
326
327 static inline int ldl(void *ptr)
328 {
329     return *(uint32_t *)ptr;
330 }
331
332 static inline uint64_t ldq(void *ptr)
333 {
334     return *(uint64_t *)ptr;
335 }
336
337 static inline void stw(void *ptr, int v)
338 {
339     *(uint16_t *)ptr = v;
340 }
341
342 static inline void stl(void *ptr, int v)
343 {
344     *(uint32_t *)ptr = v;
345 }
346
347 static inline void stq(void *ptr, uint64_t v)
348 {
349     *(uint64_t *)ptr = v;
350 }
351
352 /* float access */
353
354 static inline float ldfl(void *ptr)
355 {
356     return *(float *)ptr;
357 }
358
359 static inline double ldfq(void *ptr)
360 {
361     return *(double *)ptr;
362 }
363
364 static inline void stfl(void *ptr, float v)
365 {
366     *(float *)ptr = v;
367 }
368
369 static inline void stfq(void *ptr, double v)
370 {
371     *(double *)ptr = v;
372 }
373 #endif
374
375 #ifndef IN_OP_I386
376 void cpu_x86_outb(int addr, int val);
377 void cpu_x86_outw(int addr, int val);
378 void cpu_x86_outl(int addr, int val);
379 int cpu_x86_inb(int addr);
380 int cpu_x86_inw(int addr);
381 int cpu_x86_inl(int addr);
382 #endif
383
384 CPUX86State *cpu_x86_init(void);
385 int cpu_x86_exec(CPUX86State *s);
386 void cpu_x86_close(CPUX86State *s);
387
388 /* needed to load some predefinied segment registers */
389 void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
390
391 /* internal functions */
392
393 #define GEN_FLAG_CODE32_SHIFT 0
394 #define GEN_FLAG_ADDSEG_SHIFT 1
395 #define GEN_FLAG_SS32_SHIFT   2
396 #define GEN_FLAG_ST_SHIFT     3
397
398 int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, 
399                      int *gen_code_size_ptr,
400                      uint8_t *pc_start,  uint8_t *cs_base, int flags);
401 void cpu_x86_tblocks_init(void);
402
403 #endif /* CPU_I386_H */