]> git.proxmox.com Git - mirror_qemu.git/blame - cpu-i386.h
added fsave/frstor/fstenv/fldenv/fcomi - fixed cpuid - make lret/iret restartable
[mirror_qemu.git] / cpu-i386.h
CommitLineData
3ef693a0
FB
1/*
2 * i386 virtual CPU header
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0ecfa993 19 */
367e86e8
FB
20#ifndef CPU_I386_H
21#define CPU_I386_H
22
04369ff2 23#include "config.h"
0ecfa993
FB
24#include <setjmp.h>
25
367e86e8
FB
26#define R_EAX 0
27#define R_ECX 1
28#define R_EDX 2
29#define R_EBX 3
30#define R_ESP 4
31#define R_EBP 5
32#define R_ESI 6
33#define R_EDI 7
34
35#define R_AL 0
36#define R_CL 1
37#define R_DL 2
38#define R_BL 3
39#define R_AH 4
40#define R_CH 5
41#define R_DH 6
42#define R_BH 7
43
44#define R_ES 0
45#define R_CS 1
46#define R_SS 2
47#define R_DS 3
48#define R_FS 4
49#define R_GS 5
50
aad13cd1
FB
51/* segment descriptor fields */
52#define DESC_G_MASK (1 << 23)
53#define DESC_B_MASK (1 << 22)
54#define DESC_AVL_MASK (1 << 20)
55#define DESC_P_MASK (1 << 15)
56#define DESC_DPL_SHIFT 13
57#define DESC_S_MASK (1 << 12)
58#define DESC_TYPE_SHIFT 8
59#define DESC_A_MASK (1 << 8)
60
61#define DESC_CS_MASK (1 << 11)
62#define DESC_C_MASK (1 << 10)
63#define DESC_R_MASK (1 << 9)
64
65#define DESC_E_MASK (1 << 10)
66#define DESC_W_MASK (1 << 9)
67
fc2b4c48 68/* eflags masks */
367e86e8
FB
69#define CC_C 0x0001
70#define CC_P 0x0004
71#define CC_A 0x0010
72#define CC_Z 0x0040
73#define CC_S 0x0080
74#define CC_O 0x0800
75
fc2b4c48
FB
76#define TF_MASK 0x00000100
77#define IF_MASK 0x00000200
78#define DF_MASK 0x00000400
79#define IOPL_MASK 0x00003000
80#define NT_MASK 0x00004000
81#define RF_MASK 0x00010000
82#define VM_MASK 0x00020000
83#define AC_MASK 0x00040000
84#define VIF_MASK 0x00080000
85#define VIP_MASK 0x00100000
86#define ID_MASK 0x00200000
367e86e8 87
bc8a22cc
FB
88#define EXCP00_DIVZ 0
89#define EXCP01_SSTP 1
90#define EXCP02_NMI 2
91#define EXCP03_INT3 3
92#define EXCP04_INTO 4
93#define EXCP05_BOUND 5
94#define EXCP06_ILLOP 6
95#define EXCP07_PREX 7
96#define EXCP08_DBLE 8
97#define EXCP09_XERR 9
98#define EXCP0A_TSS 10
99#define EXCP0B_NOSEG 11
100#define EXCP0C_STACK 12
101#define EXCP0D_GPF 13
102#define EXCP0E_PAGE 14
103#define EXCP10_COPR 16
104#define EXCP11_ALGN 17
105#define EXCP12_MCHK 18
0ecfa993 106
9de5e440 107#define EXCP_INTERRUPT 256 /* async interruption */
0ecfa993 108
367e86e8
FB
109enum {
110 CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
111 CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */
112 CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */
113
114 CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
115 CC_OP_ADDW,
116 CC_OP_ADDL,
117
4b74fe1f
FB
118 CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
119 CC_OP_ADCW,
120 CC_OP_ADCL,
121
367e86e8
FB
122 CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
123 CC_OP_SUBW,
124 CC_OP_SUBL,
125
4b74fe1f
FB
126 CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
127 CC_OP_SBBW,
128 CC_OP_SBBL,
129
367e86e8
FB
130 CC_OP_LOGICB, /* modify all flags, CC_DST = res */
131 CC_OP_LOGICW,
132 CC_OP_LOGICL,
133
4b74fe1f 134 CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */
367e86e8
FB
135 CC_OP_INCW,
136 CC_OP_INCL,
137
4b74fe1f 138 CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C */
367e86e8
FB
139 CC_OP_DECW,
140 CC_OP_DECL,
141
142 CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
143 CC_OP_SHLW,
144 CC_OP_SHLL,
145
4b74fe1f
FB
146 CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
147 CC_OP_SARW,
148 CC_OP_SARL,
149
367e86e8
FB
150 CC_OP_NB,
151};
152
927f621e 153#ifdef __i386__
27362c82 154#define USE_X86LDOUBLE
927f621e
FB
155#endif
156
157#ifdef USE_X86LDOUBLE
158typedef long double CPU86_LDouble;
159#else
160typedef double CPU86_LDouble;
161#endif
162
6dbad63e
FB
163typedef struct SegmentCache {
164 uint8_t *base;
165 unsigned long limit;
166 uint8_t seg_32bit;
167} SegmentCache;
168
169typedef struct SegmentDescriptorTable {
170 uint8_t *base;
171 unsigned long limit;
172 /* this is the returned base when reading the register, just to
173 avoid that the emulated program modifies it */
174 unsigned long emu_base;
175} SegmentDescriptorTable;
176
ba1c6e37 177typedef struct CPUX86State {
367e86e8
FB
178 /* standard registers */
179 uint32_t regs[8];
dab2ed99 180 uint32_t eip;
fc2b4c48
FB
181 uint32_t eflags; /* eflags register. During CPU emulation, CC
182 flags and DF are set to zero because they are
d34720fd 183 stored elsewhere */
0ecfa993
FB
184
185 /* emulator internal eflags handling */
367e86e8
FB
186 uint32_t cc_src;
187 uint32_t cc_dst;
188 uint32_t cc_op;
189 int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */
0ecfa993 190
927f621e 191 /* FPU state */
927f621e
FB
192 unsigned int fpstt; /* top of stack index */
193 unsigned int fpus;
194 unsigned int fpuc;
0ecfa993
FB
195 uint8_t fptags[8]; /* 0 = valid, 1 = empty */
196 CPU86_LDouble fpregs[8];
197
367e86e8 198 /* emulator internal variables */
927f621e 199 CPU86_LDouble ft0;
d014c98c
FB
200 union {
201 float f;
202 double d;
203 int i32;
204 int64_t i64;
205 } fp_convert;
d57c4e01 206
6dbad63e
FB
207 /* segments */
208 uint32_t segs[6]; /* selector values */
209 SegmentCache seg_cache[6]; /* info taken from LDT/GDT */
210 SegmentDescriptorTable gdt;
211 SegmentDescriptorTable ldt;
212 SegmentDescriptorTable idt;
213
9de5e440 214 /* exception/interrupt handling */
0ecfa993
FB
215 jmp_buf jmp_env;
216 int exception_index;
9ba5695c
FB
217 int error_code;
218 uint32_t cr2;
9de5e440 219 int interrupt_request;
fc2b4c48
FB
220
221 /* user data */
222 void *opaque;
ba1c6e37 223} CPUX86State;
367e86e8 224
04369ff2 225/* all CPU memory access use these macros */
367e86e8
FB
226static inline int ldub(void *ptr)
227{
228 return *(uint8_t *)ptr;
229}
230
231static inline int ldsb(void *ptr)
232{
233 return *(int8_t *)ptr;
234}
235
04369ff2
FB
236static inline void stb(void *ptr, int v)
237{
238 *(uint8_t *)ptr = v;
239}
240
241#ifdef WORDS_BIGENDIAN
242
243/* conservative code for little endian unaligned accesses */
244static inline int lduw(void *ptr)
245{
246#ifdef __powerpc__
247 int val;
248 __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
249 return val;
250#else
251 uint8_t *p = ptr;
252 return p[0] | (p[1] << 8);
253#endif
254}
255
256static inline int ldsw(void *ptr)
257{
258#ifdef __powerpc__
259 int val;
260 __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr));
261 return (int16_t)val;
262#else
263 uint8_t *p = ptr;
264 return (int16_t)(p[0] | (p[1] << 8));
265#endif
266}
267
268static inline int ldl(void *ptr)
269{
270#ifdef __powerpc__
271 int val;
272 __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr));
273 return val;
274#else
275 uint8_t *p = ptr;
276 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
277#endif
278}
279
280static inline uint64_t ldq(void *ptr)
281{
282 uint8_t *p = ptr;
283 uint32_t v1, v2;
284 v1 = ldl(p);
285 v2 = ldl(p + 4);
286 return v1 | ((uint64_t)v2 << 32);
287}
288
289static inline void stw(void *ptr, int v)
290{
291#ifdef __powerpc__
292 __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr));
293#else
294 uint8_t *p = ptr;
295 p[0] = v;
296 p[1] = v >> 8;
297#endif
298}
299
300static inline void stl(void *ptr, int v)
301{
302#ifdef __powerpc__
303 __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr));
304#else
305 uint8_t *p = ptr;
306 p[0] = v;
307 p[1] = v >> 8;
308 p[2] = v >> 16;
309 p[3] = v >> 24;
310#endif
311}
312
313static inline void stq(void *ptr, uint64_t v)
314{
315 uint8_t *p = ptr;
316 stl(p, (uint32_t)v);
317 stl(p + 4, v >> 32);
318}
319
320/* float access */
321
322static inline float ldfl(void *ptr)
323{
324 union {
325 float f;
326 uint32_t i;
327 } u;
328 u.i = ldl(ptr);
329 return u.f;
330}
331
332static inline double ldfq(void *ptr)
333{
334 union {
335 double d;
336 uint64_t i;
337 } u;
338 u.i = ldq(ptr);
339 return u.d;
340}
341
342static inline void stfl(void *ptr, float v)
343{
344 union {
345 float f;
346 uint32_t i;
347 } u;
348 u.f = v;
349 stl(ptr, u.i);
350}
351
352static inline void stfq(void *ptr, double v)
353{
354 union {
355 double d;
356 uint64_t i;
357 } u;
358 u.d = v;
359 stq(ptr, u.i);
360}
361
362#else
363
367e86e8
FB
364static inline int lduw(void *ptr)
365{
366 return *(uint16_t *)ptr;
367}
368
369static inline int ldsw(void *ptr)
370{
371 return *(int16_t *)ptr;
372}
373
374static inline int ldl(void *ptr)
375{
376 return *(uint32_t *)ptr;
377}
378
927f621e
FB
379static inline uint64_t ldq(void *ptr)
380{
381 return *(uint64_t *)ptr;
382}
367e86e8 383
367e86e8
FB
384static inline void stw(void *ptr, int v)
385{
386 *(uint16_t *)ptr = v;
387}
388
389static inline void stl(void *ptr, int v)
390{
391 *(uint32_t *)ptr = v;
392}
393
77f8dd5a 394static inline void stq(void *ptr, uint64_t v)
927f621e
FB
395{
396 *(uint64_t *)ptr = v;
397}
398
399/* float access */
400
401static inline float ldfl(void *ptr)
402{
403 return *(float *)ptr;
404}
405
406static inline double ldfq(void *ptr)
407{
408 return *(double *)ptr;
409}
410
411static inline void stfl(void *ptr, float v)
412{
413 *(float *)ptr = v;
414}
415
416static inline void stfq(void *ptr, double v)
417{
418 *(double *)ptr = v;
419}
04369ff2 420#endif
927f621e
FB
421
422#ifndef IN_OP_I386
9ba5695c
FB
423void cpu_x86_outb(CPUX86State *env, int addr, int val);
424void cpu_x86_outw(CPUX86State *env, int addr, int val);
425void cpu_x86_outl(CPUX86State *env, int addr, int val);
426int cpu_x86_inb(CPUX86State *env, int addr);
427int cpu_x86_inw(CPUX86State *env, int addr);
428int cpu_x86_inl(CPUX86State *env, int addr);
927f621e 429#endif
367e86e8 430
ba1c6e37
FB
431CPUX86State *cpu_x86_init(void);
432int cpu_x86_exec(CPUX86State *s);
9de5e440 433void cpu_x86_interrupt(CPUX86State *s);
ba1c6e37
FB
434void cpu_x86_close(CPUX86State *s);
435
6dbad63e
FB
436/* needed to load some predefinied segment registers */
437void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
438
d0a1ffc9
FB
439/* simulate fsave/frstor */
440void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32);
441void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32);
442
d691f669 443/* you can call this signal handler from your SIGBUS and SIGSEGV
9de5e440
FB
444 signal handlers to inform the virtual CPU of exceptions. non zero
445 is returned if the signal was handled by the virtual CPU. */
446struct siginfo;
447int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
448 void *puc);
449
f351077e
FB
450/* used to debug */
451#define X86_DUMP_FPU 0x0001 /* dump FPU state too */
452#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */
453void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags);
454
54936004
FB
455/* page related stuff */
456#define TARGET_PAGE_BITS 12
457#define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS)
458#define TARGET_PAGE_MASK ~(TARGET_PAGE_SIZE - 1)
459#define TARGET_PAGE_ALIGN(addr) (((addr) + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK)
460
461extern unsigned long real_host_page_size;
462extern unsigned long host_page_bits;
463extern unsigned long host_page_size;
464extern unsigned long host_page_mask;
465
466#define HOST_PAGE_ALIGN(addr) (((addr) + host_page_size - 1) & host_page_mask)
467
468/* same as PROT_xxx */
fd6ce8f6
FB
469#define PAGE_READ 0x0001
470#define PAGE_WRITE 0x0002
471#define PAGE_EXEC 0x0004
472#define PAGE_BITS (PAGE_READ | PAGE_WRITE | PAGE_EXEC)
473#define PAGE_VALID 0x0008
474/* original state of the write flag (used when tracking self-modifying
475 code */
476#define PAGE_WRITE_ORG 0x0010
54936004
FB
477
478void page_dump(FILE *f);
479int page_get_flags(unsigned long address);
480void page_set_flags(unsigned long start, unsigned long end, int flags);
fd6ce8f6 481void page_unprotect_range(uint8_t *data, unsigned long data_size);
54936004 482
367e86e8 483#endif /* CPU_I386_H */