Commit d3eead2eec2f74fded2bed2cb8c21fd8404aeeb9
1 parent
853d6f7a
new directory structure
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@390 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
9 changed files
with
0 additions
and
3834 deletions
Too many changes to show.
To preserve performance only 9 of 20 files are displayed.
cpu-arm.h deleted
100644 → 0
1 | -/* | |
2 | - * ARM 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 | |
19 | - */ | |
20 | -#ifndef CPU_ARM_H | |
21 | -#define CPU_ARM_H | |
22 | - | |
23 | -#include "cpu-defs.h" | |
24 | - | |
25 | -#define EXCP_UDEF 1 /* undefined instruction */ | |
26 | -#define EXCP_SWI 2 /* software interrupt */ | |
27 | - | |
28 | -typedef struct CPUARMState { | |
29 | - uint32_t regs[16]; | |
30 | - uint32_t cpsr; | |
31 | - | |
32 | - /* cpsr flag cache for faster execution */ | |
33 | - uint32_t CF; /* 0 or 1 */ | |
34 | - uint32_t VF; /* V is the bit 31. All other bits are undefined */ | |
35 | - uint32_t NZF; /* N is bit 31. Z is computed from NZF */ | |
36 | - | |
37 | - /* exception/interrupt handling */ | |
38 | - jmp_buf jmp_env; | |
39 | - int exception_index; | |
40 | - int interrupt_request; | |
41 | - struct TranslationBlock *current_tb; | |
42 | - int user_mode_only; | |
43 | - | |
44 | - /* user data */ | |
45 | - void *opaque; | |
46 | -} CPUARMState; | |
47 | - | |
48 | -CPUARMState *cpu_arm_init(void); | |
49 | -int cpu_arm_exec(CPUARMState *s); | |
50 | -void cpu_arm_close(CPUARMState *s); | |
51 | -/* you can call this signal handler from your SIGBUS and SIGSEGV | |
52 | - signal handlers to inform the virtual CPU of exceptions. non zero | |
53 | - is returned if the signal was handled by the virtual CPU. */ | |
54 | -struct siginfo; | |
55 | -int cpu_arm_signal_handler(int host_signum, struct siginfo *info, | |
56 | - void *puc); | |
57 | - | |
58 | -void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags); | |
59 | - | |
60 | -#define TARGET_PAGE_BITS 12 | |
61 | -#include "cpu-all.h" | |
62 | - | |
63 | -#endif |
cpu-i386.h deleted
100644 → 0
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 | |
19 | - */ | |
20 | -#ifndef CPU_I386_H | |
21 | -#define CPU_I386_H | |
22 | - | |
23 | -#include "cpu-defs.h" | |
24 | - | |
25 | -#define R_EAX 0 | |
26 | -#define R_ECX 1 | |
27 | -#define R_EDX 2 | |
28 | -#define R_EBX 3 | |
29 | -#define R_ESP 4 | |
30 | -#define R_EBP 5 | |
31 | -#define R_ESI 6 | |
32 | -#define R_EDI 7 | |
33 | - | |
34 | -#define R_AL 0 | |
35 | -#define R_CL 1 | |
36 | -#define R_DL 2 | |
37 | -#define R_BL 3 | |
38 | -#define R_AH 4 | |
39 | -#define R_CH 5 | |
40 | -#define R_DH 6 | |
41 | -#define R_BH 7 | |
42 | - | |
43 | -#define R_ES 0 | |
44 | -#define R_CS 1 | |
45 | -#define R_SS 2 | |
46 | -#define R_DS 3 | |
47 | -#define R_FS 4 | |
48 | -#define R_GS 5 | |
49 | - | |
50 | -/* segment descriptor fields */ | |
51 | -#define DESC_G_MASK (1 << 23) | |
52 | -#define DESC_B_SHIFT 22 | |
53 | -#define DESC_B_MASK (1 << DESC_B_SHIFT) | |
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 | - | |
68 | -/* eflags masks */ | |
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 | - | |
76 | -#define TF_SHIFT 8 | |
77 | -#define IOPL_SHIFT 12 | |
78 | -#define VM_SHIFT 17 | |
79 | - | |
80 | -#define TF_MASK 0x00000100 | |
81 | -#define IF_MASK 0x00000200 | |
82 | -#define DF_MASK 0x00000400 | |
83 | -#define IOPL_MASK 0x00003000 | |
84 | -#define NT_MASK 0x00004000 | |
85 | -#define RF_MASK 0x00010000 | |
86 | -#define VM_MASK 0x00020000 | |
87 | -#define AC_MASK 0x00040000 | |
88 | -#define VIF_MASK 0x00080000 | |
89 | -#define VIP_MASK 0x00100000 | |
90 | -#define ID_MASK 0x00200000 | |
91 | - | |
92 | -/* hidden flags - used internally by qemu to represent additionnal cpu | |
93 | - states. Only the CPL and INHIBIT_IRQ are not redundant. We avoid | |
94 | - using the IOPL_MASK, TF_MASK and VM_MASK bit position to ease oring | |
95 | - with eflags. */ | |
96 | -/* current cpl */ | |
97 | -#define HF_CPL_SHIFT 0 | |
98 | -/* true if soft mmu is being used */ | |
99 | -#define HF_SOFTMMU_SHIFT 2 | |
100 | -/* true if hardware interrupts must be disabled for next instruction */ | |
101 | -#define HF_INHIBIT_IRQ_SHIFT 3 | |
102 | -/* 16 or 32 segments */ | |
103 | -#define HF_CS32_SHIFT 4 | |
104 | -#define HF_SS32_SHIFT 5 | |
105 | -/* zero base for DS, ES and SS */ | |
106 | -#define HF_ADDSEG_SHIFT 6 | |
107 | - | |
108 | -#define HF_CPL_MASK (3 << HF_CPL_SHIFT) | |
109 | -#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT) | |
110 | -#define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT) | |
111 | -#define HF_CS32_MASK (1 << HF_CS32_SHIFT) | |
112 | -#define HF_SS32_MASK (1 << HF_SS32_SHIFT) | |
113 | -#define HF_ADDSEG_MASK (1 << HF_ADDSEG_SHIFT) | |
114 | - | |
115 | -#define CR0_PE_MASK (1 << 0) | |
116 | -#define CR0_TS_MASK (1 << 3) | |
117 | -#define CR0_WP_MASK (1 << 16) | |
118 | -#define CR0_AM_MASK (1 << 18) | |
119 | -#define CR0_PG_MASK (1 << 31) | |
120 | - | |
121 | -#define CR4_VME_MASK (1 << 0) | |
122 | -#define CR4_PVI_MASK (1 << 1) | |
123 | -#define CR4_TSD_MASK (1 << 2) | |
124 | -#define CR4_DE_MASK (1 << 3) | |
125 | -#define CR4_PSE_MASK (1 << 4) | |
126 | - | |
127 | -#define PG_PRESENT_BIT 0 | |
128 | -#define PG_RW_BIT 1 | |
129 | -#define PG_USER_BIT 2 | |
130 | -#define PG_PWT_BIT 3 | |
131 | -#define PG_PCD_BIT 4 | |
132 | -#define PG_ACCESSED_BIT 5 | |
133 | -#define PG_DIRTY_BIT 6 | |
134 | -#define PG_PSE_BIT 7 | |
135 | -#define PG_GLOBAL_BIT 8 | |
136 | - | |
137 | -#define PG_PRESENT_MASK (1 << PG_PRESENT_BIT) | |
138 | -#define PG_RW_MASK (1 << PG_RW_BIT) | |
139 | -#define PG_USER_MASK (1 << PG_USER_BIT) | |
140 | -#define PG_PWT_MASK (1 << PG_PWT_BIT) | |
141 | -#define PG_PCD_MASK (1 << PG_PCD_BIT) | |
142 | -#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT) | |
143 | -#define PG_DIRTY_MASK (1 << PG_DIRTY_BIT) | |
144 | -#define PG_PSE_MASK (1 << PG_PSE_BIT) | |
145 | -#define PG_GLOBAL_MASK (1 << PG_GLOBAL_BIT) | |
146 | - | |
147 | -#define PG_ERROR_W_BIT 1 | |
148 | - | |
149 | -#define PG_ERROR_P_MASK 0x01 | |
150 | -#define PG_ERROR_W_MASK (1 << PG_ERROR_W_BIT) | |
151 | -#define PG_ERROR_U_MASK 0x04 | |
152 | -#define PG_ERROR_RSVD_MASK 0x08 | |
153 | - | |
154 | -#define MSR_IA32_APICBASE 0x1b | |
155 | -#define MSR_IA32_APICBASE_BSP (1<<8) | |
156 | -#define MSR_IA32_APICBASE_ENABLE (1<<11) | |
157 | -#define MSR_IA32_APICBASE_BASE (0xfffff<<12) | |
158 | - | |
159 | -#define MSR_IA32_SYSENTER_CS 0x174 | |
160 | -#define MSR_IA32_SYSENTER_ESP 0x175 | |
161 | -#define MSR_IA32_SYSENTER_EIP 0x176 | |
162 | - | |
163 | -#define EXCP00_DIVZ 0 | |
164 | -#define EXCP01_SSTP 1 | |
165 | -#define EXCP02_NMI 2 | |
166 | -#define EXCP03_INT3 3 | |
167 | -#define EXCP04_INTO 4 | |
168 | -#define EXCP05_BOUND 5 | |
169 | -#define EXCP06_ILLOP 6 | |
170 | -#define EXCP07_PREX 7 | |
171 | -#define EXCP08_DBLE 8 | |
172 | -#define EXCP09_XERR 9 | |
173 | -#define EXCP0A_TSS 10 | |
174 | -#define EXCP0B_NOSEG 11 | |
175 | -#define EXCP0C_STACK 12 | |
176 | -#define EXCP0D_GPF 13 | |
177 | -#define EXCP0E_PAGE 14 | |
178 | -#define EXCP10_COPR 16 | |
179 | -#define EXCP11_ALGN 17 | |
180 | -#define EXCP12_MCHK 18 | |
181 | - | |
182 | -enum { | |
183 | - CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ | |
184 | - CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */ | |
185 | - CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */ | |
186 | - | |
187 | - CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ | |
188 | - CC_OP_ADDW, | |
189 | - CC_OP_ADDL, | |
190 | - | |
191 | - CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ | |
192 | - CC_OP_ADCW, | |
193 | - CC_OP_ADCL, | |
194 | - | |
195 | - CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ | |
196 | - CC_OP_SUBW, | |
197 | - CC_OP_SUBL, | |
198 | - | |
199 | - CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ | |
200 | - CC_OP_SBBW, | |
201 | - CC_OP_SBBL, | |
202 | - | |
203 | - CC_OP_LOGICB, /* modify all flags, CC_DST = res */ | |
204 | - CC_OP_LOGICW, | |
205 | - CC_OP_LOGICL, | |
206 | - | |
207 | - CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */ | |
208 | - CC_OP_INCW, | |
209 | - CC_OP_INCL, | |
210 | - | |
211 | - CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C */ | |
212 | - CC_OP_DECW, | |
213 | - CC_OP_DECL, | |
214 | - | |
215 | - CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */ | |
216 | - CC_OP_SHLW, | |
217 | - CC_OP_SHLL, | |
218 | - | |
219 | - CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */ | |
220 | - CC_OP_SARW, | |
221 | - CC_OP_SARL, | |
222 | - | |
223 | - CC_OP_NB, | |
224 | -}; | |
225 | - | |
226 | -#ifdef __i386__ | |
227 | -#define USE_X86LDOUBLE | |
228 | -#endif | |
229 | - | |
230 | -#ifdef USE_X86LDOUBLE | |
231 | -typedef long double CPU86_LDouble; | |
232 | -#else | |
233 | -typedef double CPU86_LDouble; | |
234 | -#endif | |
235 | - | |
236 | -typedef struct SegmentCache { | |
237 | - uint32_t selector; | |
238 | - uint8_t *base; | |
239 | - uint32_t limit; | |
240 | - uint32_t flags; | |
241 | -} SegmentCache; | |
242 | - | |
243 | -typedef struct CPUX86State { | |
244 | - /* standard registers */ | |
245 | - uint32_t regs[8]; | |
246 | - uint32_t eip; | |
247 | - uint32_t eflags; /* eflags register. During CPU emulation, CC | |
248 | - flags and DF are set to zero because they are | |
249 | - stored elsewhere */ | |
250 | - | |
251 | - /* emulator internal eflags handling */ | |
252 | - uint32_t cc_src; | |
253 | - uint32_t cc_dst; | |
254 | - uint32_t cc_op; | |
255 | - int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */ | |
256 | - uint32_t hflags; /* hidden flags, see HF_xxx constants */ | |
257 | - | |
258 | - /* FPU state */ | |
259 | - unsigned int fpstt; /* top of stack index */ | |
260 | - unsigned int fpus; | |
261 | - unsigned int fpuc; | |
262 | - uint8_t fptags[8]; /* 0 = valid, 1 = empty */ | |
263 | - CPU86_LDouble fpregs[8]; | |
264 | - | |
265 | - /* emulator internal variables */ | |
266 | - CPU86_LDouble ft0; | |
267 | - union { | |
268 | - float f; | |
269 | - double d; | |
270 | - int i32; | |
271 | - int64_t i64; | |
272 | - } fp_convert; | |
273 | - | |
274 | - /* segments */ | |
275 | - SegmentCache segs[6]; /* selector values */ | |
276 | - SegmentCache ldt; | |
277 | - SegmentCache tr; | |
278 | - SegmentCache gdt; /* only base and limit are used */ | |
279 | - SegmentCache idt; /* only base and limit are used */ | |
280 | - | |
281 | - /* sysenter registers */ | |
282 | - uint32_t sysenter_cs; | |
283 | - uint32_t sysenter_esp; | |
284 | - uint32_t sysenter_eip; | |
285 | - | |
286 | - /* exception/interrupt handling */ | |
287 | - jmp_buf jmp_env; | |
288 | - int exception_index; | |
289 | - int error_code; | |
290 | - int exception_is_int; | |
291 | - int exception_next_eip; | |
292 | - struct TranslationBlock *current_tb; /* currently executing TB */ | |
293 | - uint32_t cr[5]; /* NOTE: cr1 is unused */ | |
294 | - uint32_t dr[8]; /* debug registers */ | |
295 | - int interrupt_request; | |
296 | - int user_mode_only; /* user mode only simulation */ | |
297 | - | |
298 | - /* soft mmu support */ | |
299 | - /* 0 = kernel, 1 = user */ | |
300 | - CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; | |
301 | - CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; | |
302 | - | |
303 | - /* ice debug support */ | |
304 | - uint32_t breakpoints[MAX_BREAKPOINTS]; | |
305 | - int nb_breakpoints; | |
306 | - int singlestep_enabled; | |
307 | - | |
308 | - /* user data */ | |
309 | - void *opaque; | |
310 | -} CPUX86State; | |
311 | - | |
312 | -#ifndef IN_OP_I386 | |
313 | -void cpu_x86_outb(CPUX86State *env, int addr, int val); | |
314 | -void cpu_x86_outw(CPUX86State *env, int addr, int val); | |
315 | -void cpu_x86_outl(CPUX86State *env, int addr, int val); | |
316 | -int cpu_x86_inb(CPUX86State *env, int addr); | |
317 | -int cpu_x86_inw(CPUX86State *env, int addr); | |
318 | -int cpu_x86_inl(CPUX86State *env, int addr); | |
319 | -#endif | |
320 | - | |
321 | -CPUX86State *cpu_x86_init(void); | |
322 | -int cpu_x86_exec(CPUX86State *s); | |
323 | -void cpu_x86_close(CPUX86State *s); | |
324 | -int cpu_x86_get_pic_interrupt(CPUX86State *s); | |
325 | - | |
326 | -/* this function must always be used to load data in the segment | |
327 | - cache: it synchronizes the hflags with the segment cache values */ | |
328 | -static inline void cpu_x86_load_seg_cache(CPUX86State *env, | |
329 | - int seg_reg, unsigned int selector, | |
330 | - uint8_t *base, unsigned int limit, | |
331 | - unsigned int flags) | |
332 | -{ | |
333 | - SegmentCache *sc; | |
334 | - unsigned int new_hflags; | |
335 | - | |
336 | - sc = &env->segs[seg_reg]; | |
337 | - sc->selector = selector; | |
338 | - sc->base = base; | |
339 | - sc->limit = limit; | |
340 | - sc->flags = flags; | |
341 | - | |
342 | - /* update the hidden flags */ | |
343 | - new_hflags = (env->segs[R_CS].flags & DESC_B_MASK) | |
344 | - >> (DESC_B_SHIFT - HF_CS32_SHIFT); | |
345 | - new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK) | |
346 | - >> (DESC_B_SHIFT - HF_SS32_SHIFT); | |
347 | - if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { | |
348 | - /* XXX: try to avoid this test. The problem comes from the | |
349 | - fact that is real mode or vm86 mode we only modify the | |
350 | - 'base' and 'selector' fields of the segment cache to go | |
351 | - faster. A solution may be to force addseg to one in | |
352 | - translate-i386.c. */ | |
353 | - new_hflags |= HF_ADDSEG_MASK; | |
354 | - } else { | |
355 | - new_hflags |= (((unsigned long)env->segs[R_DS].base | | |
356 | - (unsigned long)env->segs[R_ES].base | | |
357 | - (unsigned long)env->segs[R_SS].base) != 0) << | |
358 | - HF_ADDSEG_SHIFT; | |
359 | - } | |
360 | - env->hflags = (env->hflags & | |
361 | - ~(HF_CS32_MASK | HF_SS32_MASK | HF_ADDSEG_MASK)) | new_hflags; | |
362 | -} | |
363 | - | |
364 | -/* wrapper, just in case memory mappings must be changed */ | |
365 | -static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl) | |
366 | -{ | |
367 | -#if HF_CPL_MASK == 3 | |
368 | - s->hflags = (s->hflags & ~HF_CPL_MASK) | cpl; | |
369 | -#else | |
370 | -#error HF_CPL_MASK is hardcoded | |
371 | -#endif | |
372 | -} | |
373 | - | |
374 | -/* the following helpers are only usable in user mode simulation as | |
375 | - they can trigger unexpected exceptions */ | |
376 | -void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); | |
377 | -void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32); | |
378 | -void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32); | |
379 | - | |
380 | -/* you can call this signal handler from your SIGBUS and SIGSEGV | |
381 | - signal handlers to inform the virtual CPU of exceptions. non zero | |
382 | - is returned if the signal was handled by the virtual CPU. */ | |
383 | -struct siginfo; | |
384 | -int cpu_x86_signal_handler(int host_signum, struct siginfo *info, | |
385 | - void *puc); | |
386 | - | |
387 | -/* MMU defines */ | |
388 | -void cpu_x86_init_mmu(CPUX86State *env); | |
389 | -extern int phys_ram_size; | |
390 | -extern int phys_ram_fd; | |
391 | -extern uint8_t *phys_ram_base; | |
392 | - | |
393 | -/* used to debug */ | |
394 | -#define X86_DUMP_FPU 0x0001 /* dump FPU state too */ | |
395 | -#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ | |
396 | -void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags); | |
397 | - | |
398 | -#define TARGET_PAGE_BITS 12 | |
399 | -#include "cpu-all.h" | |
400 | - | |
401 | -#endif /* CPU_I386_H */ |
exec.h renamed to exec-all.h
exec-arm.h deleted
100644 → 0
1 | -/* | |
2 | - * ARM execution defines | |
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 | |
19 | - */ | |
20 | -#include "dyngen-exec.h" | |
21 | - | |
22 | -register struct CPUARMState *env asm(AREG0); | |
23 | -register uint32_t T0 asm(AREG1); | |
24 | -register uint32_t T1 asm(AREG2); | |
25 | -register uint32_t T2 asm(AREG3); | |
26 | - | |
27 | -#include "cpu-arm.h" | |
28 | -#include "exec.h" | |
29 | - | |
30 | -void cpu_lock(void); | |
31 | -void cpu_unlock(void); | |
32 | -void cpu_loop_exit(void); | |
33 | - | |
34 | -static inline int compute_cpsr(void) | |
35 | -{ | |
36 | - int ZF; | |
37 | - ZF = (env->NZF == 0); | |
38 | - return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | | |
39 | - (env->CF << 29) | ((env->VF & 0x80000000) >> 3); | |
40 | -} |
exec-i386.h deleted
100644 → 0
1 | -/* | |
2 | - * i386 execution defines | |
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 | |
19 | - */ | |
20 | -#include "dyngen-exec.h" | |
21 | - | |
22 | -/* at least 4 register variables are defines */ | |
23 | -register struct CPUX86State *env asm(AREG0); | |
24 | -register uint32_t T0 asm(AREG1); | |
25 | -register uint32_t T1 asm(AREG2); | |
26 | -register uint32_t T2 asm(AREG3); | |
27 | - | |
28 | -#define A0 T2 | |
29 | - | |
30 | -/* if more registers are available, we define some registers too */ | |
31 | -#ifdef AREG4 | |
32 | -register uint32_t EAX asm(AREG4); | |
33 | -#define reg_EAX | |
34 | -#endif | |
35 | - | |
36 | -#ifdef AREG5 | |
37 | -register uint32_t ESP asm(AREG5); | |
38 | -#define reg_ESP | |
39 | -#endif | |
40 | - | |
41 | -#ifdef AREG6 | |
42 | -register uint32_t EBP asm(AREG6); | |
43 | -#define reg_EBP | |
44 | -#endif | |
45 | - | |
46 | -#ifdef AREG7 | |
47 | -register uint32_t ECX asm(AREG7); | |
48 | -#define reg_ECX | |
49 | -#endif | |
50 | - | |
51 | -#ifdef AREG8 | |
52 | -register uint32_t EDX asm(AREG8); | |
53 | -#define reg_EDX | |
54 | -#endif | |
55 | - | |
56 | -#ifdef AREG9 | |
57 | -register uint32_t EBX asm(AREG9); | |
58 | -#define reg_EBX | |
59 | -#endif | |
60 | - | |
61 | -#ifdef AREG10 | |
62 | -register uint32_t ESI asm(AREG10); | |
63 | -#define reg_ESI | |
64 | -#endif | |
65 | - | |
66 | -#ifdef AREG11 | |
67 | -register uint32_t EDI asm(AREG11); | |
68 | -#define reg_EDI | |
69 | -#endif | |
70 | - | |
71 | -extern FILE *logfile; | |
72 | -extern int loglevel; | |
73 | - | |
74 | -#ifndef reg_EAX | |
75 | -#define EAX (env->regs[R_EAX]) | |
76 | -#endif | |
77 | -#ifndef reg_ECX | |
78 | -#define ECX (env->regs[R_ECX]) | |
79 | -#endif | |
80 | -#ifndef reg_EDX | |
81 | -#define EDX (env->regs[R_EDX]) | |
82 | -#endif | |
83 | -#ifndef reg_EBX | |
84 | -#define EBX (env->regs[R_EBX]) | |
85 | -#endif | |
86 | -#ifndef reg_ESP | |
87 | -#define ESP (env->regs[R_ESP]) | |
88 | -#endif | |
89 | -#ifndef reg_EBP | |
90 | -#define EBP (env->regs[R_EBP]) | |
91 | -#endif | |
92 | -#ifndef reg_ESI | |
93 | -#define ESI (env->regs[R_ESI]) | |
94 | -#endif | |
95 | -#ifndef reg_EDI | |
96 | -#define EDI (env->regs[R_EDI]) | |
97 | -#endif | |
98 | -#define EIP (env->eip) | |
99 | -#define DF (env->df) | |
100 | - | |
101 | -#define CC_SRC (env->cc_src) | |
102 | -#define CC_DST (env->cc_dst) | |
103 | -#define CC_OP (env->cc_op) | |
104 | - | |
105 | -/* float macros */ | |
106 | -#define FT0 (env->ft0) | |
107 | -#define ST0 (env->fpregs[env->fpstt]) | |
108 | -#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7]) | |
109 | -#define ST1 ST(1) | |
110 | - | |
111 | -#ifdef USE_FP_CONVERT | |
112 | -#define FP_CONVERT (env->fp_convert) | |
113 | -#endif | |
114 | - | |
115 | -#include "cpu-i386.h" | |
116 | -#include "exec.h" | |
117 | - | |
118 | -typedef struct CCTable { | |
119 | - int (*compute_all)(void); /* return all the flags */ | |
120 | - int (*compute_c)(void); /* return the C flag */ | |
121 | -} CCTable; | |
122 | - | |
123 | -extern CCTable cc_table[]; | |
124 | - | |
125 | -void load_seg(int seg_reg, int selector, unsigned cur_eip); | |
126 | -void helper_ljmp_protected_T0_T1(void); | |
127 | -void helper_lcall_real_T0_T1(int shift, int next_eip); | |
128 | -void helper_lcall_protected_T0_T1(int shift, int next_eip); | |
129 | -void helper_iret_real(int shift); | |
130 | -void helper_iret_protected(int shift); | |
131 | -void helper_lret_protected(int shift, int addend); | |
132 | -void helper_lldt_T0(void); | |
133 | -void helper_ltr_T0(void); | |
134 | -void helper_movl_crN_T0(int reg); | |
135 | -void helper_movl_drN_T0(int reg); | |
136 | -void helper_invlpg(unsigned int addr); | |
137 | -void cpu_x86_update_cr0(CPUX86State *env); | |
138 | -void cpu_x86_update_cr3(CPUX86State *env); | |
139 | -void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr); | |
140 | -int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write); | |
141 | -void tlb_fill(unsigned long addr, int is_write, void *retaddr); | |
142 | -void __hidden cpu_lock(void); | |
143 | -void __hidden cpu_unlock(void); | |
144 | -void do_interrupt(int intno, int is_int, int error_code, | |
145 | - unsigned int next_eip, int is_hw); | |
146 | -void do_interrupt_user(int intno, int is_int, int error_code, | |
147 | - unsigned int next_eip); | |
148 | -void raise_interrupt(int intno, int is_int, int error_code, | |
149 | - unsigned int next_eip); | |
150 | -void raise_exception_err(int exception_index, int error_code); | |
151 | -void raise_exception(int exception_index); | |
152 | -void __hidden cpu_loop_exit(void); | |
153 | -void helper_fsave(uint8_t *ptr, int data32); | |
154 | -void helper_frstor(uint8_t *ptr, int data32); | |
155 | - | |
156 | -void OPPROTO op_movl_eflags_T0(void); | |
157 | -void OPPROTO op_movl_T0_eflags(void); | |
158 | -void raise_interrupt(int intno, int is_int, int error_code, | |
159 | - unsigned int next_eip); | |
160 | -void raise_exception_err(int exception_index, int error_code); | |
161 | -void raise_exception(int exception_index); | |
162 | -void helper_divl_EAX_T0(uint32_t eip); | |
163 | -void helper_idivl_EAX_T0(uint32_t eip); | |
164 | -void helper_cmpxchg8b(void); | |
165 | -void helper_cpuid(void); | |
166 | -void helper_rdtsc(void); | |
167 | -void helper_rdmsr(void); | |
168 | -void helper_wrmsr(void); | |
169 | -void helper_lsl(void); | |
170 | -void helper_lar(void); | |
171 | - | |
172 | -#ifdef USE_X86LDOUBLE | |
173 | -/* use long double functions */ | |
174 | -#define lrint lrintl | |
175 | -#define llrint llrintl | |
176 | -#define fabs fabsl | |
177 | -#define sin sinl | |
178 | -#define cos cosl | |
179 | -#define sqrt sqrtl | |
180 | -#define pow powl | |
181 | -#define log logl | |
182 | -#define tan tanl | |
183 | -#define atan2 atan2l | |
184 | -#define floor floorl | |
185 | -#define ceil ceill | |
186 | -#define rint rintl | |
187 | -#endif | |
188 | - | |
189 | -extern int lrint(CPU86_LDouble x); | |
190 | -extern int64_t llrint(CPU86_LDouble x); | |
191 | -extern CPU86_LDouble fabs(CPU86_LDouble x); | |
192 | -extern CPU86_LDouble sin(CPU86_LDouble x); | |
193 | -extern CPU86_LDouble cos(CPU86_LDouble x); | |
194 | -extern CPU86_LDouble sqrt(CPU86_LDouble x); | |
195 | -extern CPU86_LDouble pow(CPU86_LDouble, CPU86_LDouble); | |
196 | -extern CPU86_LDouble log(CPU86_LDouble x); | |
197 | -extern CPU86_LDouble tan(CPU86_LDouble x); | |
198 | -extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble); | |
199 | -extern CPU86_LDouble floor(CPU86_LDouble x); | |
200 | -extern CPU86_LDouble ceil(CPU86_LDouble x); | |
201 | -extern CPU86_LDouble rint(CPU86_LDouble x); | |
202 | - | |
203 | -#define RC_MASK 0xc00 | |
204 | -#define RC_NEAR 0x000 | |
205 | -#define RC_DOWN 0x400 | |
206 | -#define RC_UP 0x800 | |
207 | -#define RC_CHOP 0xc00 | |
208 | - | |
209 | -#define MAXTAN 9223372036854775808.0 | |
210 | - | |
211 | -#ifdef __arm__ | |
212 | -/* we have no way to do correct rounding - a FPU emulator is needed */ | |
213 | -#define FE_DOWNWARD FE_TONEAREST | |
214 | -#define FE_UPWARD FE_TONEAREST | |
215 | -#define FE_TOWARDZERO FE_TONEAREST | |
216 | -#endif | |
217 | - | |
218 | -#ifdef USE_X86LDOUBLE | |
219 | - | |
220 | -/* only for x86 */ | |
221 | -typedef union { | |
222 | - long double d; | |
223 | - struct { | |
224 | - unsigned long long lower; | |
225 | - unsigned short upper; | |
226 | - } l; | |
227 | -} CPU86_LDoubleU; | |
228 | - | |
229 | -/* the following deal with x86 long double-precision numbers */ | |
230 | -#define MAXEXPD 0x7fff | |
231 | -#define EXPBIAS 16383 | |
232 | -#define EXPD(fp) (fp.l.upper & 0x7fff) | |
233 | -#define SIGND(fp) ((fp.l.upper) & 0x8000) | |
234 | -#define MANTD(fp) (fp.l.lower) | |
235 | -#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS | |
236 | - | |
237 | -#else | |
238 | - | |
239 | -/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ | |
240 | -typedef union { | |
241 | - double d; | |
242 | -#if !defined(WORDS_BIGENDIAN) && !defined(__arm__) | |
243 | - struct { | |
244 | - uint32_t lower; | |
245 | - int32_t upper; | |
246 | - } l; | |
247 | -#else | |
248 | - struct { | |
249 | - int32_t upper; | |
250 | - uint32_t lower; | |
251 | - } l; | |
252 | -#endif | |
253 | -#ifndef __arm__ | |
254 | - int64_t ll; | |
255 | -#endif | |
256 | -} CPU86_LDoubleU; | |
257 | - | |
258 | -/* the following deal with IEEE double-precision numbers */ | |
259 | -#define MAXEXPD 0x7ff | |
260 | -#define EXPBIAS 1023 | |
261 | -#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) | |
262 | -#define SIGND(fp) ((fp.l.upper) & 0x80000000) | |
263 | -#ifdef __arm__ | |
264 | -#define MANTD(fp) (fp.l.lower | ((uint64_t)(fp.l.upper & ((1 << 20) - 1)) << 32)) | |
265 | -#else | |
266 | -#define MANTD(fp) (fp.ll & ((1LL << 52) - 1)) | |
267 | -#endif | |
268 | -#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20) | |
269 | -#endif | |
270 | - | |
271 | -static inline void fpush(void) | |
272 | -{ | |
273 | - env->fpstt = (env->fpstt - 1) & 7; | |
274 | - env->fptags[env->fpstt] = 0; /* validate stack entry */ | |
275 | -} | |
276 | - | |
277 | -static inline void fpop(void) | |
278 | -{ | |
279 | - env->fptags[env->fpstt] = 1; /* invvalidate stack entry */ | |
280 | - env->fpstt = (env->fpstt + 1) & 7; | |
281 | -} | |
282 | - | |
283 | -#ifndef USE_X86LDOUBLE | |
284 | -static inline CPU86_LDouble helper_fldt(uint8_t *ptr) | |
285 | -{ | |
286 | - CPU86_LDoubleU temp; | |
287 | - int upper, e; | |
288 | - uint64_t ll; | |
289 | - | |
290 | - /* mantissa */ | |
291 | - upper = lduw(ptr + 8); | |
292 | - /* XXX: handle overflow ? */ | |
293 | - e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ | |
294 | - e |= (upper >> 4) & 0x800; /* sign */ | |
295 | - ll = (ldq(ptr) >> 11) & ((1LL << 52) - 1); | |
296 | -#ifdef __arm__ | |
297 | - temp.l.upper = (e << 20) | (ll >> 32); | |
298 | - temp.l.lower = ll; | |
299 | -#else | |
300 | - temp.ll = ll | ((uint64_t)e << 52); | |
301 | -#endif | |
302 | - return temp.d; | |
303 | -} | |
304 | - | |
305 | -static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) | |
306 | -{ | |
307 | - CPU86_LDoubleU temp; | |
308 | - int e; | |
309 | - | |
310 | - temp.d = f; | |
311 | - /* mantissa */ | |
312 | - stq(ptr, (MANTD(temp) << 11) | (1LL << 63)); | |
313 | - /* exponent + sign */ | |
314 | - e = EXPD(temp) - EXPBIAS + 16383; | |
315 | - e |= SIGND(temp) >> 16; | |
316 | - stw(ptr + 8, e); | |
317 | -} | |
318 | -#endif | |
319 | - | |
320 | -const CPU86_LDouble f15rk[7]; | |
321 | - | |
322 | -void helper_fldt_ST0_A0(void); | |
323 | -void helper_fstt_ST0_A0(void); | |
324 | -void helper_fbld_ST0_A0(void); | |
325 | -void helper_fbst_ST0_A0(void); | |
326 | -void helper_f2xm1(void); | |
327 | -void helper_fyl2x(void); | |
328 | -void helper_fptan(void); | |
329 | -void helper_fpatan(void); | |
330 | -void helper_fxtract(void); | |
331 | -void helper_fprem1(void); | |
332 | -void helper_fprem(void); | |
333 | -void helper_fyl2xp1(void); | |
334 | -void helper_fsqrt(void); | |
335 | -void helper_fsincos(void); | |
336 | -void helper_frndint(void); | |
337 | -void helper_fscale(void); | |
338 | -void helper_fsin(void); | |
339 | -void helper_fcos(void); | |
340 | -void helper_fxam_ST0(void); | |
341 | -void helper_fstenv(uint8_t *ptr, int data32); | |
342 | -void helper_fldenv(uint8_t *ptr, int data32); | |
343 | -void helper_fsave(uint8_t *ptr, int data32); | |
344 | -void helper_frstor(uint8_t *ptr, int data32); | |
345 | - | |
346 | -const uint8_t parity_table[256]; | |
347 | -const uint8_t rclw_table[32]; | |
348 | -const uint8_t rclb_table[32]; | |
349 | - | |
350 | -static inline uint32_t compute_eflags(void) | |
351 | -{ | |
352 | - return env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); | |
353 | -} | |
354 | - | |
355 | -#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK) | |
356 | - | |
357 | -#define FL_UPDATE_CPL0_MASK (TF_MASK | IF_MASK | IOPL_MASK | NT_MASK | \ | |
358 | - RF_MASK | AC_MASK | ID_MASK) | |
359 | - | |
360 | -/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */ | |
361 | -static inline void load_eflags(int eflags, int update_mask) | |
362 | -{ | |
363 | - CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); | |
364 | - DF = 1 - (2 * ((eflags >> 10) & 1)); | |
365 | - env->eflags = (env->eflags & ~update_mask) | | |
366 | - (eflags & update_mask); | |
367 | -} | |
368 | - | |
369 | -/* memory access macros */ | |
370 | - | |
371 | -#define ldul ldl | |
372 | -#define lduq ldq | |
373 | -#define ldul_user ldl_user | |
374 | -#define ldul_kernel ldl_kernel | |
375 | - | |
376 | -#define ldub_raw ldub | |
377 | -#define ldsb_raw ldsb | |
378 | -#define lduw_raw lduw | |
379 | -#define ldsw_raw ldsw | |
380 | -#define ldl_raw ldl | |
381 | -#define ldq_raw ldq | |
382 | - | |
383 | -#define stb_raw stb | |
384 | -#define stw_raw stw | |
385 | -#define stl_raw stl | |
386 | -#define stq_raw stq | |
387 | - | |
388 | -#define MEMUSER 0 | |
389 | -#define DATA_SIZE 1 | |
390 | -#include "softmmu_header.h" | |
391 | - | |
392 | -#define DATA_SIZE 2 | |
393 | -#include "softmmu_header.h" | |
394 | - | |
395 | -#define DATA_SIZE 4 | |
396 | -#include "softmmu_header.h" | |
397 | - | |
398 | -#define DATA_SIZE 8 | |
399 | -#include "softmmu_header.h" | |
400 | - | |
401 | -#undef MEMUSER | |
402 | -#define MEMUSER 1 | |
403 | -#define DATA_SIZE 1 | |
404 | -#include "softmmu_header.h" | |
405 | - | |
406 | -#define DATA_SIZE 2 | |
407 | -#include "softmmu_header.h" | |
408 | - | |
409 | -#define DATA_SIZE 4 | |
410 | -#include "softmmu_header.h" | |
411 | - | |
412 | -#define DATA_SIZE 8 | |
413 | -#include "softmmu_header.h" | |
414 | - | |
415 | -#undef MEMUSER | |
416 | - |
helper-i386.c deleted
100644 → 0
1 | -/* | |
2 | - * i386 helpers | |
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 | |
19 | - */ | |
20 | -#include "exec-i386.h" | |
21 | - | |
22 | -const uint8_t parity_table[256] = { | |
23 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
24 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
25 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
26 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
27 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
28 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
29 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
30 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
31 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
32 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
33 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
34 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
35 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
36 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
37 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
38 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
39 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
40 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
41 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
42 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
43 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
44 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
45 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
46 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
47 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
48 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
49 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
50 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
51 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
52 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
53 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
54 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
55 | -}; | |
56 | - | |
57 | -/* modulo 17 table */ | |
58 | -const uint8_t rclw_table[32] = { | |
59 | - 0, 1, 2, 3, 4, 5, 6, 7, | |
60 | - 8, 9,10,11,12,13,14,15, | |
61 | - 16, 0, 1, 2, 3, 4, 5, 6, | |
62 | - 7, 8, 9,10,11,12,13,14, | |
63 | -}; | |
64 | - | |
65 | -/* modulo 9 table */ | |
66 | -const uint8_t rclb_table[32] = { | |
67 | - 0, 1, 2, 3, 4, 5, 6, 7, | |
68 | - 8, 0, 1, 2, 3, 4, 5, 6, | |
69 | - 7, 8, 0, 1, 2, 3, 4, 5, | |
70 | - 6, 7, 8, 0, 1, 2, 3, 4, | |
71 | -}; | |
72 | - | |
73 | -const CPU86_LDouble f15rk[7] = | |
74 | -{ | |
75 | - 0.00000000000000000000L, | |
76 | - 1.00000000000000000000L, | |
77 | - 3.14159265358979323851L, /*pi*/ | |
78 | - 0.30102999566398119523L, /*lg2*/ | |
79 | - 0.69314718055994530943L, /*ln2*/ | |
80 | - 1.44269504088896340739L, /*l2e*/ | |
81 | - 3.32192809488736234781L, /*l2t*/ | |
82 | -}; | |
83 | - | |
84 | -/* thread support */ | |
85 | - | |
86 | -spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; | |
87 | - | |
88 | -void cpu_lock(void) | |
89 | -{ | |
90 | - spin_lock(&global_cpu_lock); | |
91 | -} | |
92 | - | |
93 | -void cpu_unlock(void) | |
94 | -{ | |
95 | - spin_unlock(&global_cpu_lock); | |
96 | -} | |
97 | - | |
98 | -void cpu_loop_exit(void) | |
99 | -{ | |
100 | - /* NOTE: the register at this point must be saved by hand because | |
101 | - longjmp restore them */ | |
102 | -#ifdef reg_EAX | |
103 | - env->regs[R_EAX] = EAX; | |
104 | -#endif | |
105 | -#ifdef reg_ECX | |
106 | - env->regs[R_ECX] = ECX; | |
107 | -#endif | |
108 | -#ifdef reg_EDX | |
109 | - env->regs[R_EDX] = EDX; | |
110 | -#endif | |
111 | -#ifdef reg_EBX | |
112 | - env->regs[R_EBX] = EBX; | |
113 | -#endif | |
114 | -#ifdef reg_ESP | |
115 | - env->regs[R_ESP] = ESP; | |
116 | -#endif | |
117 | -#ifdef reg_EBP | |
118 | - env->regs[R_EBP] = EBP; | |
119 | -#endif | |
120 | -#ifdef reg_ESI | |
121 | - env->regs[R_ESI] = ESI; | |
122 | -#endif | |
123 | -#ifdef reg_EDI | |
124 | - env->regs[R_EDI] = EDI; | |
125 | -#endif | |
126 | - longjmp(env->jmp_env, 1); | |
127 | -} | |
128 | - | |
129 | -static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, | |
130 | - uint32_t *esp_ptr, int dpl) | |
131 | -{ | |
132 | - int type, index, shift; | |
133 | - | |
134 | -#if 0 | |
135 | - { | |
136 | - int i; | |
137 | - printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit); | |
138 | - for(i=0;i<env->tr.limit;i++) { | |
139 | - printf("%02x ", env->tr.base[i]); | |
140 | - if ((i & 7) == 7) printf("\n"); | |
141 | - } | |
142 | - printf("\n"); | |
143 | - } | |
144 | -#endif | |
145 | - | |
146 | - if (!(env->tr.flags & DESC_P_MASK)) | |
147 | - cpu_abort(env, "invalid tss"); | |
148 | - type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; | |
149 | - if ((type & 7) != 1) | |
150 | - cpu_abort(env, "invalid tss type"); | |
151 | - shift = type >> 3; | |
152 | - index = (dpl * 4 + 2) << shift; | |
153 | - if (index + (4 << shift) - 1 > env->tr.limit) | |
154 | - raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); | |
155 | - if (shift == 0) { | |
156 | - *esp_ptr = lduw(env->tr.base + index); | |
157 | - *ss_ptr = lduw(env->tr.base + index + 2); | |
158 | - } else { | |
159 | - *esp_ptr = ldl(env->tr.base + index); | |
160 | - *ss_ptr = lduw(env->tr.base + index + 4); | |
161 | - } | |
162 | -} | |
163 | - | |
164 | -/* return non zero if error */ | |
165 | -static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, | |
166 | - int selector) | |
167 | -{ | |
168 | - SegmentCache *dt; | |
169 | - int index; | |
170 | - uint8_t *ptr; | |
171 | - | |
172 | - if (selector & 0x4) | |
173 | - dt = &env->ldt; | |
174 | - else | |
175 | - dt = &env->gdt; | |
176 | - index = selector & ~7; | |
177 | - if ((index + 7) > dt->limit) | |
178 | - return -1; | |
179 | - ptr = dt->base + index; | |
180 | - *e1_ptr = ldl(ptr); | |
181 | - *e2_ptr = ldl(ptr + 4); | |
182 | - return 0; | |
183 | -} | |
184 | - | |
185 | -static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) | |
186 | -{ | |
187 | - unsigned int limit; | |
188 | - limit = (e1 & 0xffff) | (e2 & 0x000f0000); | |
189 | - if (e2 & DESC_G_MASK) | |
190 | - limit = (limit << 12) | 0xfff; | |
191 | - return limit; | |
192 | -} | |
193 | - | |
194 | -static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2) | |
195 | -{ | |
196 | - return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); | |
197 | -} | |
198 | - | |
199 | -static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) | |
200 | -{ | |
201 | - sc->base = get_seg_base(e1, e2); | |
202 | - sc->limit = get_seg_limit(e1, e2); | |
203 | - sc->flags = e2; | |
204 | -} | |
205 | - | |
206 | -/* init the segment cache in vm86 mode. */ | |
207 | -static inline void load_seg_vm(int seg, int selector) | |
208 | -{ | |
209 | - selector &= 0xffff; | |
210 | - cpu_x86_load_seg_cache(env, seg, selector, | |
211 | - (uint8_t *)(selector << 4), 0xffff, 0); | |
212 | -} | |
213 | - | |
214 | -/* protected mode interrupt */ | |
215 | -static void do_interrupt_protected(int intno, int is_int, int error_code, | |
216 | - unsigned int next_eip, int is_hw) | |
217 | -{ | |
218 | - SegmentCache *dt; | |
219 | - uint8_t *ptr, *ssp; | |
220 | - int type, dpl, selector, ss_dpl, cpl; | |
221 | - int has_error_code, new_stack, shift; | |
222 | - uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size; | |
223 | - uint32_t old_cs, old_ss, old_esp, old_eip; | |
224 | - | |
225 | - dt = &env->idt; | |
226 | - if (intno * 8 + 7 > dt->limit) | |
227 | - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); | |
228 | - ptr = dt->base + intno * 8; | |
229 | - e1 = ldl(ptr); | |
230 | - e2 = ldl(ptr + 4); | |
231 | - /* check gate type */ | |
232 | - type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; | |
233 | - switch(type) { | |
234 | - case 5: /* task gate */ | |
235 | - cpu_abort(env, "task gate not supported"); | |
236 | - break; | |
237 | - case 6: /* 286 interrupt gate */ | |
238 | - case 7: /* 286 trap gate */ | |
239 | - case 14: /* 386 interrupt gate */ | |
240 | - case 15: /* 386 trap gate */ | |
241 | - break; | |
242 | - default: | |
243 | - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); | |
244 | - break; | |
245 | - } | |
246 | - dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
247 | - cpl = env->hflags & HF_CPL_MASK; | |
248 | - /* check privledge if software int */ | |
249 | - if (is_int && dpl < cpl) | |
250 | - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); | |
251 | - /* check valid bit */ | |
252 | - if (!(e2 & DESC_P_MASK)) | |
253 | - raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); | |
254 | - selector = e1 >> 16; | |
255 | - offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); | |
256 | - if ((selector & 0xfffc) == 0) | |
257 | - raise_exception_err(EXCP0D_GPF, 0); | |
258 | - | |
259 | - if (load_segment(&e1, &e2, selector) != 0) | |
260 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
261 | - if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) | |
262 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
263 | - dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
264 | - if (dpl > cpl) | |
265 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
266 | - if (!(e2 & DESC_P_MASK)) | |
267 | - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | |
268 | - if (!(e2 & DESC_C_MASK) && dpl < cpl) { | |
269 | - /* to inner priviledge */ | |
270 | - get_ss_esp_from_tss(&ss, &esp, dpl); | |
271 | - if ((ss & 0xfffc) == 0) | |
272 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
273 | - if ((ss & 3) != dpl) | |
274 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
275 | - if (load_segment(&ss_e1, &ss_e2, ss) != 0) | |
276 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
277 | - ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; | |
278 | - if (ss_dpl != dpl) | |
279 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
280 | - if (!(ss_e2 & DESC_S_MASK) || | |
281 | - (ss_e2 & DESC_CS_MASK) || | |
282 | - !(ss_e2 & DESC_W_MASK)) | |
283 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
284 | - if (!(ss_e2 & DESC_P_MASK)) | |
285 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
286 | - new_stack = 1; | |
287 | - } else if ((e2 & DESC_C_MASK) || dpl == cpl) { | |
288 | - /* to same priviledge */ | |
289 | - new_stack = 0; | |
290 | - } else { | |
291 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
292 | - new_stack = 0; /* avoid warning */ | |
293 | - } | |
294 | - | |
295 | - shift = type >> 3; | |
296 | - has_error_code = 0; | |
297 | - if (!is_int && !is_hw) { | |
298 | - switch(intno) { | |
299 | - case 8: | |
300 | - case 10: | |
301 | - case 11: | |
302 | - case 12: | |
303 | - case 13: | |
304 | - case 14: | |
305 | - case 17: | |
306 | - has_error_code = 1; | |
307 | - break; | |
308 | - } | |
309 | - } | |
310 | - push_size = 6 + (new_stack << 2) + (has_error_code << 1); | |
311 | - if (env->eflags & VM_MASK) | |
312 | - push_size += 8; | |
313 | - push_size <<= shift; | |
314 | - | |
315 | - /* XXX: check that enough room is available */ | |
316 | - if (new_stack) { | |
317 | - old_esp = ESP; | |
318 | - old_ss = env->segs[R_SS].selector; | |
319 | - ss = (ss & ~3) | dpl; | |
320 | - cpu_x86_load_seg_cache(env, R_SS, ss, | |
321 | - get_seg_base(ss_e1, ss_e2), | |
322 | - get_seg_limit(ss_e1, ss_e2), | |
323 | - ss_e2); | |
324 | - } else { | |
325 | - old_esp = 0; | |
326 | - old_ss = 0; | |
327 | - esp = ESP; | |
328 | - } | |
329 | - if (is_int) | |
330 | - old_eip = next_eip; | |
331 | - else | |
332 | - old_eip = env->eip; | |
333 | - old_cs = env->segs[R_CS].selector; | |
334 | - selector = (selector & ~3) | dpl; | |
335 | - cpu_x86_load_seg_cache(env, R_CS, selector, | |
336 | - get_seg_base(e1, e2), | |
337 | - get_seg_limit(e1, e2), | |
338 | - e2); | |
339 | - cpu_x86_set_cpl(env, dpl); | |
340 | - env->eip = offset; | |
341 | - ESP = esp - push_size; | |
342 | - ssp = env->segs[R_SS].base + esp; | |
343 | - if (shift == 1) { | |
344 | - int old_eflags; | |
345 | - if (env->eflags & VM_MASK) { | |
346 | - ssp -= 4; | |
347 | - stl(ssp, env->segs[R_GS].selector); | |
348 | - ssp -= 4; | |
349 | - stl(ssp, env->segs[R_FS].selector); | |
350 | - ssp -= 4; | |
351 | - stl(ssp, env->segs[R_DS].selector); | |
352 | - ssp -= 4; | |
353 | - stl(ssp, env->segs[R_ES].selector); | |
354 | - } | |
355 | - if (new_stack) { | |
356 | - ssp -= 4; | |
357 | - stl(ssp, old_ss); | |
358 | - ssp -= 4; | |
359 | - stl(ssp, old_esp); | |
360 | - } | |
361 | - ssp -= 4; | |
362 | - old_eflags = compute_eflags(); | |
363 | - stl(ssp, old_eflags); | |
364 | - ssp -= 4; | |
365 | - stl(ssp, old_cs); | |
366 | - ssp -= 4; | |
367 | - stl(ssp, old_eip); | |
368 | - if (has_error_code) { | |
369 | - ssp -= 4; | |
370 | - stl(ssp, error_code); | |
371 | - } | |
372 | - } else { | |
373 | - if (new_stack) { | |
374 | - ssp -= 2; | |
375 | - stw(ssp, old_ss); | |
376 | - ssp -= 2; | |
377 | - stw(ssp, old_esp); | |
378 | - } | |
379 | - ssp -= 2; | |
380 | - stw(ssp, compute_eflags()); | |
381 | - ssp -= 2; | |
382 | - stw(ssp, old_cs); | |
383 | - ssp -= 2; | |
384 | - stw(ssp, old_eip); | |
385 | - if (has_error_code) { | |
386 | - ssp -= 2; | |
387 | - stw(ssp, error_code); | |
388 | - } | |
389 | - } | |
390 | - | |
391 | - /* interrupt gate clear IF mask */ | |
392 | - if ((type & 1) == 0) { | |
393 | - env->eflags &= ~IF_MASK; | |
394 | - } | |
395 | - env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); | |
396 | -} | |
397 | - | |
398 | -/* real mode interrupt */ | |
399 | -static void do_interrupt_real(int intno, int is_int, int error_code, | |
400 | - unsigned int next_eip) | |
401 | -{ | |
402 | - SegmentCache *dt; | |
403 | - uint8_t *ptr, *ssp; | |
404 | - int selector; | |
405 | - uint32_t offset, esp; | |
406 | - uint32_t old_cs, old_eip; | |
407 | - | |
408 | - /* real mode (simpler !) */ | |
409 | - dt = &env->idt; | |
410 | - if (intno * 4 + 3 > dt->limit) | |
411 | - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); | |
412 | - ptr = dt->base + intno * 4; | |
413 | - offset = lduw(ptr); | |
414 | - selector = lduw(ptr + 2); | |
415 | - esp = ESP; | |
416 | - ssp = env->segs[R_SS].base; | |
417 | - if (is_int) | |
418 | - old_eip = next_eip; | |
419 | - else | |
420 | - old_eip = env->eip; | |
421 | - old_cs = env->segs[R_CS].selector; | |
422 | - esp -= 2; | |
423 | - stw(ssp + (esp & 0xffff), compute_eflags()); | |
424 | - esp -= 2; | |
425 | - stw(ssp + (esp & 0xffff), old_cs); | |
426 | - esp -= 2; | |
427 | - stw(ssp + (esp & 0xffff), old_eip); | |
428 | - | |
429 | - /* update processor state */ | |
430 | - ESP = (ESP & ~0xffff) | (esp & 0xffff); | |
431 | - env->eip = offset; | |
432 | - env->segs[R_CS].selector = selector; | |
433 | - env->segs[R_CS].base = (uint8_t *)(selector << 4); | |
434 | - env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); | |
435 | -} | |
436 | - | |
437 | -/* fake user mode interrupt */ | |
438 | -void do_interrupt_user(int intno, int is_int, int error_code, | |
439 | - unsigned int next_eip) | |
440 | -{ | |
441 | - SegmentCache *dt; | |
442 | - uint8_t *ptr; | |
443 | - int dpl, cpl; | |
444 | - uint32_t e2; | |
445 | - | |
446 | - dt = &env->idt; | |
447 | - ptr = dt->base + (intno * 8); | |
448 | - e2 = ldl(ptr + 4); | |
449 | - | |
450 | - dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
451 | - cpl = env->hflags & HF_CPL_MASK; | |
452 | - /* check privledge if software int */ | |
453 | - if (is_int && dpl < cpl) | |
454 | - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); | |
455 | - | |
456 | - /* Since we emulate only user space, we cannot do more than | |
457 | - exiting the emulation with the suitable exception and error | |
458 | - code */ | |
459 | - if (is_int) | |
460 | - EIP = next_eip; | |
461 | -} | |
462 | - | |
463 | -/* | |
464 | - * Begin excution of an interruption. is_int is TRUE if coming from | |
465 | - * the int instruction. next_eip is the EIP value AFTER the interrupt | |
466 | - * instruction. It is only relevant if is_int is TRUE. | |
467 | - */ | |
468 | -void do_interrupt(int intno, int is_int, int error_code, | |
469 | - unsigned int next_eip, int is_hw) | |
470 | -{ | |
471 | - if (env->cr[0] & CR0_PE_MASK) { | |
472 | - do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); | |
473 | - } else { | |
474 | - do_interrupt_real(intno, is_int, error_code, next_eip); | |
475 | - } | |
476 | -} | |
477 | - | |
478 | -/* | |
479 | - * Signal an interruption. It is executed in the main CPU loop. | |
480 | - * is_int is TRUE if coming from the int instruction. next_eip is the | |
481 | - * EIP value AFTER the interrupt instruction. It is only relevant if | |
482 | - * is_int is TRUE. | |
483 | - */ | |
484 | -void raise_interrupt(int intno, int is_int, int error_code, | |
485 | - unsigned int next_eip) | |
486 | -{ | |
487 | - env->exception_index = intno; | |
488 | - env->error_code = error_code; | |
489 | - env->exception_is_int = is_int; | |
490 | - env->exception_next_eip = next_eip; | |
491 | - cpu_loop_exit(); | |
492 | -} | |
493 | - | |
494 | -/* shortcuts to generate exceptions */ | |
495 | -void raise_exception_err(int exception_index, int error_code) | |
496 | -{ | |
497 | - raise_interrupt(exception_index, 0, error_code, 0); | |
498 | -} | |
499 | - | |
500 | -void raise_exception(int exception_index) | |
501 | -{ | |
502 | - raise_interrupt(exception_index, 0, 0, 0); | |
503 | -} | |
504 | - | |
505 | -#ifdef BUGGY_GCC_DIV64 | |
506 | -/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we | |
507 | - call it from another function */ | |
508 | -uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den) | |
509 | -{ | |
510 | - *q_ptr = num / den; | |
511 | - return num % den; | |
512 | -} | |
513 | - | |
514 | -int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den) | |
515 | -{ | |
516 | - *q_ptr = num / den; | |
517 | - return num % den; | |
518 | -} | |
519 | -#endif | |
520 | - | |
521 | -void helper_divl_EAX_T0(uint32_t eip) | |
522 | -{ | |
523 | - unsigned int den, q, r; | |
524 | - uint64_t num; | |
525 | - | |
526 | - num = EAX | ((uint64_t)EDX << 32); | |
527 | - den = T0; | |
528 | - if (den == 0) { | |
529 | - EIP = eip; | |
530 | - raise_exception(EXCP00_DIVZ); | |
531 | - } | |
532 | -#ifdef BUGGY_GCC_DIV64 | |
533 | - r = div64(&q, num, den); | |
534 | -#else | |
535 | - q = (num / den); | |
536 | - r = (num % den); | |
537 | -#endif | |
538 | - EAX = q; | |
539 | - EDX = r; | |
540 | -} | |
541 | - | |
542 | -void helper_idivl_EAX_T0(uint32_t eip) | |
543 | -{ | |
544 | - int den, q, r; | |
545 | - int64_t num; | |
546 | - | |
547 | - num = EAX | ((uint64_t)EDX << 32); | |
548 | - den = T0; | |
549 | - if (den == 0) { | |
550 | - EIP = eip; | |
551 | - raise_exception(EXCP00_DIVZ); | |
552 | - } | |
553 | -#ifdef BUGGY_GCC_DIV64 | |
554 | - r = idiv64(&q, num, den); | |
555 | -#else | |
556 | - q = (num / den); | |
557 | - r = (num % den); | |
558 | -#endif | |
559 | - EAX = q; | |
560 | - EDX = r; | |
561 | -} | |
562 | - | |
563 | -void helper_cmpxchg8b(void) | |
564 | -{ | |
565 | - uint64_t d; | |
566 | - int eflags; | |
567 | - | |
568 | - eflags = cc_table[CC_OP].compute_all(); | |
569 | - d = ldq((uint8_t *)A0); | |
570 | - if (d == (((uint64_t)EDX << 32) | EAX)) { | |
571 | - stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX); | |
572 | - eflags |= CC_Z; | |
573 | - } else { | |
574 | - EDX = d >> 32; | |
575 | - EAX = d; | |
576 | - eflags &= ~CC_Z; | |
577 | - } | |
578 | - CC_SRC = eflags; | |
579 | -} | |
580 | - | |
581 | -/* We simulate a pre-MMX pentium as in valgrind */ | |
582 | -#define CPUID_FP87 (1 << 0) | |
583 | -#define CPUID_VME (1 << 1) | |
584 | -#define CPUID_DE (1 << 2) | |
585 | -#define CPUID_PSE (1 << 3) | |
586 | -#define CPUID_TSC (1 << 4) | |
587 | -#define CPUID_MSR (1 << 5) | |
588 | -#define CPUID_PAE (1 << 6) | |
589 | -#define CPUID_MCE (1 << 7) | |
590 | -#define CPUID_CX8 (1 << 8) | |
591 | -#define CPUID_APIC (1 << 9) | |
592 | -#define CPUID_SEP (1 << 11) /* sysenter/sysexit */ | |
593 | -#define CPUID_MTRR (1 << 12) | |
594 | -#define CPUID_PGE (1 << 13) | |
595 | -#define CPUID_MCA (1 << 14) | |
596 | -#define CPUID_CMOV (1 << 15) | |
597 | -/* ... */ | |
598 | -#define CPUID_MMX (1 << 23) | |
599 | -#define CPUID_FXSR (1 << 24) | |
600 | -#define CPUID_SSE (1 << 25) | |
601 | -#define CPUID_SSE2 (1 << 26) | |
602 | - | |
603 | -void helper_cpuid(void) | |
604 | -{ | |
605 | - if (EAX == 0) { | |
606 | - EAX = 1; /* max EAX index supported */ | |
607 | - EBX = 0x756e6547; | |
608 | - ECX = 0x6c65746e; | |
609 | - EDX = 0x49656e69; | |
610 | - } else if (EAX == 1) { | |
611 | - int family, model, stepping; | |
612 | - /* EAX = 1 info */ | |
613 | -#if 0 | |
614 | - /* pentium 75-200 */ | |
615 | - family = 5; | |
616 | - model = 2; | |
617 | - stepping = 11; | |
618 | -#else | |
619 | - /* pentium pro */ | |
620 | - family = 6; | |
621 | - model = 1; | |
622 | - stepping = 3; | |
623 | -#endif | |
624 | - EAX = (family << 8) | (model << 4) | stepping; | |
625 | - EBX = 0; | |
626 | - ECX = 0; | |
627 | - EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE | | |
628 | - CPUID_TSC | CPUID_MSR | CPUID_MCE | | |
629 | - CPUID_CX8 | CPUID_PGE | CPUID_CMOV; | |
630 | - } | |
631 | -} | |
632 | - | |
633 | -void helper_lldt_T0(void) | |
634 | -{ | |
635 | - int selector; | |
636 | - SegmentCache *dt; | |
637 | - uint32_t e1, e2; | |
638 | - int index; | |
639 | - uint8_t *ptr; | |
640 | - | |
641 | - selector = T0 & 0xffff; | |
642 | - if ((selector & 0xfffc) == 0) { | |
643 | - /* XXX: NULL selector case: invalid LDT */ | |
644 | - env->ldt.base = NULL; | |
645 | - env->ldt.limit = 0; | |
646 | - } else { | |
647 | - if (selector & 0x4) | |
648 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
649 | - dt = &env->gdt; | |
650 | - index = selector & ~7; | |
651 | - if ((index + 7) > dt->limit) | |
652 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
653 | - ptr = dt->base + index; | |
654 | - e1 = ldl(ptr); | |
655 | - e2 = ldl(ptr + 4); | |
656 | - if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) | |
657 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
658 | - if (!(e2 & DESC_P_MASK)) | |
659 | - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | |
660 | - load_seg_cache_raw_dt(&env->ldt, e1, e2); | |
661 | - } | |
662 | - env->ldt.selector = selector; | |
663 | -} | |
664 | - | |
665 | -void helper_ltr_T0(void) | |
666 | -{ | |
667 | - int selector; | |
668 | - SegmentCache *dt; | |
669 | - uint32_t e1, e2; | |
670 | - int index, type; | |
671 | - uint8_t *ptr; | |
672 | - | |
673 | - selector = T0 & 0xffff; | |
674 | - if ((selector & 0xfffc) == 0) { | |
675 | - /* NULL selector case: invalid LDT */ | |
676 | - env->tr.base = NULL; | |
677 | - env->tr.limit = 0; | |
678 | - env->tr.flags = 0; | |
679 | - } else { | |
680 | - if (selector & 0x4) | |
681 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
682 | - dt = &env->gdt; | |
683 | - index = selector & ~7; | |
684 | - if ((index + 7) > dt->limit) | |
685 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
686 | - ptr = dt->base + index; | |
687 | - e1 = ldl(ptr); | |
688 | - e2 = ldl(ptr + 4); | |
689 | - type = (e2 >> DESC_TYPE_SHIFT) & 0xf; | |
690 | - if ((e2 & DESC_S_MASK) || | |
691 | - (type != 2 && type != 9)) | |
692 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
693 | - if (!(e2 & DESC_P_MASK)) | |
694 | - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | |
695 | - load_seg_cache_raw_dt(&env->tr, e1, e2); | |
696 | - e2 |= 0x00000200; /* set the busy bit */ | |
697 | - stl(ptr + 4, e2); | |
698 | - } | |
699 | - env->tr.selector = selector; | |
700 | -} | |
701 | - | |
702 | -/* only works if protected mode and not VM86. Calling load_seg with | |
703 | - seg_reg == R_CS is discouraged */ | |
704 | -void load_seg(int seg_reg, int selector, unsigned int cur_eip) | |
705 | -{ | |
706 | - uint32_t e1, e2; | |
707 | - | |
708 | - if ((selector & 0xfffc) == 0) { | |
709 | - /* null selector case */ | |
710 | - if (seg_reg == R_SS) { | |
711 | - EIP = cur_eip; | |
712 | - raise_exception_err(EXCP0D_GPF, 0); | |
713 | - } else { | |
714 | - cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0); | |
715 | - } | |
716 | - } else { | |
717 | - if (load_segment(&e1, &e2, selector) != 0) { | |
718 | - EIP = cur_eip; | |
719 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
720 | - } | |
721 | - if (!(e2 & DESC_S_MASK) || | |
722 | - (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { | |
723 | - EIP = cur_eip; | |
724 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
725 | - } | |
726 | - | |
727 | - if (seg_reg == R_SS) { | |
728 | - if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) { | |
729 | - EIP = cur_eip; | |
730 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
731 | - } | |
732 | - } else { | |
733 | - if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { | |
734 | - EIP = cur_eip; | |
735 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
736 | - } | |
737 | - } | |
738 | - | |
739 | - if (!(e2 & DESC_P_MASK)) { | |
740 | - EIP = cur_eip; | |
741 | - if (seg_reg == R_SS) | |
742 | - raise_exception_err(EXCP0C_STACK, selector & 0xfffc); | |
743 | - else | |
744 | - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | |
745 | - } | |
746 | - cpu_x86_load_seg_cache(env, seg_reg, selector, | |
747 | - get_seg_base(e1, e2), | |
748 | - get_seg_limit(e1, e2), | |
749 | - e2); | |
750 | -#if 0 | |
751 | - fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", | |
752 | - selector, (unsigned long)sc->base, sc->limit, sc->flags); | |
753 | -#endif | |
754 | - } | |
755 | -} | |
756 | - | |
757 | -/* protected mode jump */ | |
758 | -void helper_ljmp_protected_T0_T1(void) | |
759 | -{ | |
760 | - int new_cs, new_eip; | |
761 | - uint32_t e1, e2, cpl, dpl, rpl, limit; | |
762 | - | |
763 | - new_cs = T0; | |
764 | - new_eip = T1; | |
765 | - if ((new_cs & 0xfffc) == 0) | |
766 | - raise_exception_err(EXCP0D_GPF, 0); | |
767 | - if (load_segment(&e1, &e2, new_cs) != 0) | |
768 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
769 | - cpl = env->hflags & HF_CPL_MASK; | |
770 | - if (e2 & DESC_S_MASK) { | |
771 | - if (!(e2 & DESC_CS_MASK)) | |
772 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
773 | - dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
774 | - if (e2 & DESC_CS_MASK) { | |
775 | - /* conforming code segment */ | |
776 | - if (dpl > cpl) | |
777 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
778 | - } else { | |
779 | - /* non conforming code segment */ | |
780 | - rpl = new_cs & 3; | |
781 | - if (rpl > cpl) | |
782 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
783 | - if (dpl != cpl) | |
784 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
785 | - } | |
786 | - if (!(e2 & DESC_P_MASK)) | |
787 | - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); | |
788 | - limit = get_seg_limit(e1, e2); | |
789 | - if (new_eip > limit) | |
790 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
791 | - cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, | |
792 | - get_seg_base(e1, e2), limit, e2); | |
793 | - EIP = new_eip; | |
794 | - } else { | |
795 | - cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x", | |
796 | - new_cs, new_eip); | |
797 | - } | |
798 | -} | |
799 | - | |
800 | -/* real mode call */ | |
801 | -void helper_lcall_real_T0_T1(int shift, int next_eip) | |
802 | -{ | |
803 | - int new_cs, new_eip; | |
804 | - uint32_t esp, esp_mask; | |
805 | - uint8_t *ssp; | |
806 | - | |
807 | - new_cs = T0; | |
808 | - new_eip = T1; | |
809 | - esp = ESP; | |
810 | - esp_mask = 0xffffffff; | |
811 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
812 | - esp_mask = 0xffff; | |
813 | - ssp = env->segs[R_SS].base; | |
814 | - if (shift) { | |
815 | - esp -= 4; | |
816 | - stl(ssp + (esp & esp_mask), env->segs[R_CS].selector); | |
817 | - esp -= 4; | |
818 | - stl(ssp + (esp & esp_mask), next_eip); | |
819 | - } else { | |
820 | - esp -= 2; | |
821 | - stw(ssp + (esp & esp_mask), env->segs[R_CS].selector); | |
822 | - esp -= 2; | |
823 | - stw(ssp + (esp & esp_mask), next_eip); | |
824 | - } | |
825 | - | |
826 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
827 | - ESP = (ESP & ~0xffff) | (esp & 0xffff); | |
828 | - else | |
829 | - ESP = esp; | |
830 | - env->eip = new_eip; | |
831 | - env->segs[R_CS].selector = new_cs; | |
832 | - env->segs[R_CS].base = (uint8_t *)(new_cs << 4); | |
833 | -} | |
834 | - | |
835 | -/* protected mode call */ | |
836 | -void helper_lcall_protected_T0_T1(int shift, int next_eip) | |
837 | -{ | |
838 | - int new_cs, new_eip; | |
839 | - uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; | |
840 | - uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl; | |
841 | - uint32_t old_ss, old_esp, val, i, limit; | |
842 | - uint8_t *ssp, *old_ssp; | |
843 | - | |
844 | - new_cs = T0; | |
845 | - new_eip = T1; | |
846 | - if ((new_cs & 0xfffc) == 0) | |
847 | - raise_exception_err(EXCP0D_GPF, 0); | |
848 | - if (load_segment(&e1, &e2, new_cs) != 0) | |
849 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
850 | - cpl = env->hflags & HF_CPL_MASK; | |
851 | - if (e2 & DESC_S_MASK) { | |
852 | - if (!(e2 & DESC_CS_MASK)) | |
853 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
854 | - dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
855 | - if (e2 & DESC_CS_MASK) { | |
856 | - /* conforming code segment */ | |
857 | - if (dpl > cpl) | |
858 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
859 | - } else { | |
860 | - /* non conforming code segment */ | |
861 | - rpl = new_cs & 3; | |
862 | - if (rpl > cpl) | |
863 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
864 | - if (dpl != cpl) | |
865 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
866 | - } | |
867 | - if (!(e2 & DESC_P_MASK)) | |
868 | - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); | |
869 | - | |
870 | - sp = ESP; | |
871 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
872 | - sp &= 0xffff; | |
873 | - ssp = env->segs[R_SS].base + sp; | |
874 | - if (shift) { | |
875 | - ssp -= 4; | |
876 | - stl(ssp, env->segs[R_CS].selector); | |
877 | - ssp -= 4; | |
878 | - stl(ssp, next_eip); | |
879 | - } else { | |
880 | - ssp -= 2; | |
881 | - stw(ssp, env->segs[R_CS].selector); | |
882 | - ssp -= 2; | |
883 | - stw(ssp, next_eip); | |
884 | - } | |
885 | - sp -= (4 << shift); | |
886 | - | |
887 | - limit = get_seg_limit(e1, e2); | |
888 | - if (new_eip > limit) | |
889 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
890 | - /* from this point, not restartable */ | |
891 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
892 | - ESP = (ESP & 0xffff0000) | (sp & 0xffff); | |
893 | - else | |
894 | - ESP = sp; | |
895 | - cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, | |
896 | - get_seg_base(e1, e2), limit, e2); | |
897 | - EIP = new_eip; | |
898 | - } else { | |
899 | - /* check gate type */ | |
900 | - type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; | |
901 | - switch(type) { | |
902 | - case 1: /* available 286 TSS */ | |
903 | - case 9: /* available 386 TSS */ | |
904 | - case 5: /* task gate */ | |
905 | - cpu_abort(env, "task gate not supported"); | |
906 | - break; | |
907 | - case 4: /* 286 call gate */ | |
908 | - case 12: /* 386 call gate */ | |
909 | - break; | |
910 | - default: | |
911 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
912 | - break; | |
913 | - } | |
914 | - shift = type >> 3; | |
915 | - | |
916 | - dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
917 | - rpl = new_cs & 3; | |
918 | - if (dpl < cpl || dpl < rpl) | |
919 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
920 | - /* check valid bit */ | |
921 | - if (!(e2 & DESC_P_MASK)) | |
922 | - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); | |
923 | - selector = e1 >> 16; | |
924 | - offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); | |
925 | - if ((selector & 0xfffc) == 0) | |
926 | - raise_exception_err(EXCP0D_GPF, 0); | |
927 | - | |
928 | - if (load_segment(&e1, &e2, selector) != 0) | |
929 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
930 | - if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) | |
931 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
932 | - dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
933 | - if (dpl > cpl) | |
934 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
935 | - if (!(e2 & DESC_P_MASK)) | |
936 | - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | |
937 | - | |
938 | - if (!(e2 & DESC_C_MASK) && dpl < cpl) { | |
939 | - /* to inner priviledge */ | |
940 | - get_ss_esp_from_tss(&ss, &sp, dpl); | |
941 | - if ((ss & 0xfffc) == 0) | |
942 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
943 | - if ((ss & 3) != dpl) | |
944 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
945 | - if (load_segment(&ss_e1, &ss_e2, ss) != 0) | |
946 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
947 | - ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; | |
948 | - if (ss_dpl != dpl) | |
949 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
950 | - if (!(ss_e2 & DESC_S_MASK) || | |
951 | - (ss_e2 & DESC_CS_MASK) || | |
952 | - !(ss_e2 & DESC_W_MASK)) | |
953 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
954 | - if (!(ss_e2 & DESC_P_MASK)) | |
955 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
956 | - | |
957 | - param_count = e2 & 0x1f; | |
958 | - push_size = ((param_count * 2) + 8) << shift; | |
959 | - | |
960 | - old_esp = ESP; | |
961 | - old_ss = env->segs[R_SS].selector; | |
962 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
963 | - old_esp &= 0xffff; | |
964 | - old_ssp = env->segs[R_SS].base + old_esp; | |
965 | - | |
966 | - /* XXX: from this point not restartable */ | |
967 | - ss = (ss & ~3) | dpl; | |
968 | - cpu_x86_load_seg_cache(env, R_SS, ss, | |
969 | - get_seg_base(ss_e1, ss_e2), | |
970 | - get_seg_limit(ss_e1, ss_e2), | |
971 | - ss_e2); | |
972 | - | |
973 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
974 | - sp &= 0xffff; | |
975 | - ssp = env->segs[R_SS].base + sp; | |
976 | - if (shift) { | |
977 | - ssp -= 4; | |
978 | - stl(ssp, old_ss); | |
979 | - ssp -= 4; | |
980 | - stl(ssp, old_esp); | |
981 | - ssp -= 4 * param_count; | |
982 | - for(i = 0; i < param_count; i++) { | |
983 | - val = ldl(old_ssp + i * 4); | |
984 | - stl(ssp + i * 4, val); | |
985 | - } | |
986 | - } else { | |
987 | - ssp -= 2; | |
988 | - stw(ssp, old_ss); | |
989 | - ssp -= 2; | |
990 | - stw(ssp, old_esp); | |
991 | - ssp -= 2 * param_count; | |
992 | - for(i = 0; i < param_count; i++) { | |
993 | - val = lduw(old_ssp + i * 2); | |
994 | - stw(ssp + i * 2, val); | |
995 | - } | |
996 | - } | |
997 | - } else { | |
998 | - /* to same priviledge */ | |
999 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
1000 | - sp &= 0xffff; | |
1001 | - ssp = env->segs[R_SS].base + sp; | |
1002 | - push_size = (4 << shift); | |
1003 | - } | |
1004 | - | |
1005 | - if (shift) { | |
1006 | - ssp -= 4; | |
1007 | - stl(ssp, env->segs[R_CS].selector); | |
1008 | - ssp -= 4; | |
1009 | - stl(ssp, next_eip); | |
1010 | - } else { | |
1011 | - ssp -= 2; | |
1012 | - stw(ssp, env->segs[R_CS].selector); | |
1013 | - ssp -= 2; | |
1014 | - stw(ssp, next_eip); | |
1015 | - } | |
1016 | - | |
1017 | - sp -= push_size; | |
1018 | - selector = (selector & ~3) | dpl; | |
1019 | - cpu_x86_load_seg_cache(env, R_CS, selector, | |
1020 | - get_seg_base(e1, e2), | |
1021 | - get_seg_limit(e1, e2), | |
1022 | - e2); | |
1023 | - cpu_x86_set_cpl(env, dpl); | |
1024 | - | |
1025 | - /* from this point, not restartable if same priviledge */ | |
1026 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
1027 | - ESP = (ESP & 0xffff0000) | (sp & 0xffff); | |
1028 | - else | |
1029 | - ESP = sp; | |
1030 | - EIP = offset; | |
1031 | - } | |
1032 | -} | |
1033 | - | |
1034 | -/* real mode iret */ | |
1035 | -void helper_iret_real(int shift) | |
1036 | -{ | |
1037 | - uint32_t sp, new_cs, new_eip, new_eflags, new_esp; | |
1038 | - uint8_t *ssp; | |
1039 | - int eflags_mask; | |
1040 | - | |
1041 | - sp = ESP & 0xffff; | |
1042 | - ssp = env->segs[R_SS].base + sp; | |
1043 | - if (shift == 1) { | |
1044 | - /* 32 bits */ | |
1045 | - new_eflags = ldl(ssp + 8); | |
1046 | - new_cs = ldl(ssp + 4) & 0xffff; | |
1047 | - new_eip = ldl(ssp) & 0xffff; | |
1048 | - } else { | |
1049 | - /* 16 bits */ | |
1050 | - new_eflags = lduw(ssp + 4); | |
1051 | - new_cs = lduw(ssp + 2); | |
1052 | - new_eip = lduw(ssp); | |
1053 | - } | |
1054 | - new_esp = sp + (6 << shift); | |
1055 | - ESP = (ESP & 0xffff0000) | | |
1056 | - (new_esp & 0xffff); | |
1057 | - load_seg_vm(R_CS, new_cs); | |
1058 | - env->eip = new_eip; | |
1059 | - eflags_mask = FL_UPDATE_CPL0_MASK; | |
1060 | - if (shift == 0) | |
1061 | - eflags_mask &= 0xffff; | |
1062 | - load_eflags(new_eflags, eflags_mask); | |
1063 | -} | |
1064 | - | |
1065 | -/* protected mode iret */ | |
1066 | -static inline void helper_ret_protected(int shift, int is_iret, int addend) | |
1067 | -{ | |
1068 | - uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss; | |
1069 | - uint32_t new_es, new_ds, new_fs, new_gs; | |
1070 | - uint32_t e1, e2, ss_e1, ss_e2; | |
1071 | - int cpl, dpl, rpl, eflags_mask; | |
1072 | - uint8_t *ssp; | |
1073 | - | |
1074 | - sp = ESP; | |
1075 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
1076 | - sp &= 0xffff; | |
1077 | - ssp = env->segs[R_SS].base + sp; | |
1078 | - if (shift == 1) { | |
1079 | - /* 32 bits */ | |
1080 | - if (is_iret) | |
1081 | - new_eflags = ldl(ssp + 8); | |
1082 | - new_cs = ldl(ssp + 4) & 0xffff; | |
1083 | - new_eip = ldl(ssp); | |
1084 | - if (is_iret && (new_eflags & VM_MASK)) | |
1085 | - goto return_to_vm86; | |
1086 | - } else { | |
1087 | - /* 16 bits */ | |
1088 | - if (is_iret) | |
1089 | - new_eflags = lduw(ssp + 4); | |
1090 | - new_cs = lduw(ssp + 2); | |
1091 | - new_eip = lduw(ssp); | |
1092 | - } | |
1093 | - if ((new_cs & 0xfffc) == 0) | |
1094 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
1095 | - if (load_segment(&e1, &e2, new_cs) != 0) | |
1096 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
1097 | - if (!(e2 & DESC_S_MASK) || | |
1098 | - !(e2 & DESC_CS_MASK)) | |
1099 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
1100 | - cpl = env->hflags & HF_CPL_MASK; | |
1101 | - rpl = new_cs & 3; | |
1102 | - if (rpl < cpl) | |
1103 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
1104 | - dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
1105 | - if (e2 & DESC_CS_MASK) { | |
1106 | - if (dpl > rpl) | |
1107 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
1108 | - } else { | |
1109 | - if (dpl != rpl) | |
1110 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
1111 | - } | |
1112 | - if (!(e2 & DESC_P_MASK)) | |
1113 | - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); | |
1114 | - | |
1115 | - if (rpl == cpl) { | |
1116 | - /* return to same priledge level */ | |
1117 | - cpu_x86_load_seg_cache(env, R_CS, new_cs, | |
1118 | - get_seg_base(e1, e2), | |
1119 | - get_seg_limit(e1, e2), | |
1120 | - e2); | |
1121 | - new_esp = sp + (4 << shift) + ((2 * is_iret) << shift) + addend; | |
1122 | - } else { | |
1123 | - /* return to different priviledge level */ | |
1124 | - ssp += (4 << shift) + ((2 * is_iret) << shift) + addend; | |
1125 | - if (shift == 1) { | |
1126 | - /* 32 bits */ | |
1127 | - new_esp = ldl(ssp); | |
1128 | - new_ss = ldl(ssp + 4) & 0xffff; | |
1129 | - } else { | |
1130 | - /* 16 bits */ | |
1131 | - new_esp = lduw(ssp); | |
1132 | - new_ss = lduw(ssp + 2); | |
1133 | - } | |
1134 | - | |
1135 | - if ((new_ss & 3) != rpl) | |
1136 | - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); | |
1137 | - if (load_segment(&ss_e1, &ss_e2, new_ss) != 0) | |
1138 | - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); | |
1139 | - if (!(ss_e2 & DESC_S_MASK) || | |
1140 | - (ss_e2 & DESC_CS_MASK) || | |
1141 | - !(ss_e2 & DESC_W_MASK)) | |
1142 | - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); | |
1143 | - dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; | |
1144 | - if (dpl != rpl) | |
1145 | - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); | |
1146 | - if (!(ss_e2 & DESC_P_MASK)) | |
1147 | - raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); | |
1148 | - | |
1149 | - cpu_x86_load_seg_cache(env, R_CS, new_cs, | |
1150 | - get_seg_base(e1, e2), | |
1151 | - get_seg_limit(e1, e2), | |
1152 | - e2); | |
1153 | - cpu_x86_load_seg_cache(env, R_SS, new_ss, | |
1154 | - get_seg_base(ss_e1, ss_e2), | |
1155 | - get_seg_limit(ss_e1, ss_e2), | |
1156 | - ss_e2); | |
1157 | - cpu_x86_set_cpl(env, rpl); | |
1158 | - } | |
1159 | - if (env->segs[R_SS].flags & DESC_B_MASK) | |
1160 | - ESP = new_esp; | |
1161 | - else | |
1162 | - ESP = (ESP & 0xffff0000) | | |
1163 | - (new_esp & 0xffff); | |
1164 | - env->eip = new_eip; | |
1165 | - if (is_iret) { | |
1166 | - /* NOTE: 'cpl' can be different from the current CPL */ | |
1167 | - if (cpl == 0) | |
1168 | - eflags_mask = FL_UPDATE_CPL0_MASK; | |
1169 | - else | |
1170 | - eflags_mask = FL_UPDATE_MASK32; | |
1171 | - if (shift == 0) | |
1172 | - eflags_mask &= 0xffff; | |
1173 | - load_eflags(new_eflags, eflags_mask); | |
1174 | - } | |
1175 | - return; | |
1176 | - | |
1177 | - return_to_vm86: | |
1178 | - new_esp = ldl(ssp + 12); | |
1179 | - new_ss = ldl(ssp + 16); | |
1180 | - new_es = ldl(ssp + 20); | |
1181 | - new_ds = ldl(ssp + 24); | |
1182 | - new_fs = ldl(ssp + 28); | |
1183 | - new_gs = ldl(ssp + 32); | |
1184 | - | |
1185 | - /* modify processor state */ | |
1186 | - load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK); | |
1187 | - load_seg_vm(R_CS, new_cs); | |
1188 | - cpu_x86_set_cpl(env, 3); | |
1189 | - load_seg_vm(R_SS, new_ss); | |
1190 | - load_seg_vm(R_ES, new_es); | |
1191 | - load_seg_vm(R_DS, new_ds); | |
1192 | - load_seg_vm(R_FS, new_fs); | |
1193 | - load_seg_vm(R_GS, new_gs); | |
1194 | - | |
1195 | - env->eip = new_eip; | |
1196 | - ESP = new_esp; | |
1197 | -} | |
1198 | - | |
1199 | -void helper_iret_protected(int shift) | |
1200 | -{ | |
1201 | - helper_ret_protected(shift, 1, 0); | |
1202 | -} | |
1203 | - | |
1204 | -void helper_lret_protected(int shift, int addend) | |
1205 | -{ | |
1206 | - helper_ret_protected(shift, 0, addend); | |
1207 | -} | |
1208 | - | |
1209 | -void helper_movl_crN_T0(int reg) | |
1210 | -{ | |
1211 | - env->cr[reg] = T0; | |
1212 | - switch(reg) { | |
1213 | - case 0: | |
1214 | - cpu_x86_update_cr0(env); | |
1215 | - break; | |
1216 | - case 3: | |
1217 | - cpu_x86_update_cr3(env); | |
1218 | - break; | |
1219 | - } | |
1220 | -} | |
1221 | - | |
1222 | -/* XXX: do more */ | |
1223 | -void helper_movl_drN_T0(int reg) | |
1224 | -{ | |
1225 | - env->dr[reg] = T0; | |
1226 | -} | |
1227 | - | |
1228 | -void helper_invlpg(unsigned int addr) | |
1229 | -{ | |
1230 | - cpu_x86_flush_tlb(env, addr); | |
1231 | -} | |
1232 | - | |
1233 | -/* rdtsc */ | |
1234 | -#ifndef __i386__ | |
1235 | -uint64_t emu_time; | |
1236 | -#endif | |
1237 | - | |
1238 | -void helper_rdtsc(void) | |
1239 | -{ | |
1240 | - uint64_t val; | |
1241 | -#ifdef __i386__ | |
1242 | - asm("rdtsc" : "=A" (val)); | |
1243 | -#else | |
1244 | - /* better than nothing: the time increases */ | |
1245 | - val = emu_time++; | |
1246 | -#endif | |
1247 | - EAX = val; | |
1248 | - EDX = val >> 32; | |
1249 | -} | |
1250 | - | |
1251 | -void helper_wrmsr(void) | |
1252 | -{ | |
1253 | - switch(ECX) { | |
1254 | - case MSR_IA32_SYSENTER_CS: | |
1255 | - env->sysenter_cs = EAX & 0xffff; | |
1256 | - break; | |
1257 | - case MSR_IA32_SYSENTER_ESP: | |
1258 | - env->sysenter_esp = EAX; | |
1259 | - break; | |
1260 | - case MSR_IA32_SYSENTER_EIP: | |
1261 | - env->sysenter_eip = EAX; | |
1262 | - break; | |
1263 | - default: | |
1264 | - /* XXX: exception ? */ | |
1265 | - break; | |
1266 | - } | |
1267 | -} | |
1268 | - | |
1269 | -void helper_rdmsr(void) | |
1270 | -{ | |
1271 | - switch(ECX) { | |
1272 | - case MSR_IA32_SYSENTER_CS: | |
1273 | - EAX = env->sysenter_cs; | |
1274 | - EDX = 0; | |
1275 | - break; | |
1276 | - case MSR_IA32_SYSENTER_ESP: | |
1277 | - EAX = env->sysenter_esp; | |
1278 | - EDX = 0; | |
1279 | - break; | |
1280 | - case MSR_IA32_SYSENTER_EIP: | |
1281 | - EAX = env->sysenter_eip; | |
1282 | - EDX = 0; | |
1283 | - break; | |
1284 | - default: | |
1285 | - /* XXX: exception ? */ | |
1286 | - break; | |
1287 | - } | |
1288 | -} | |
1289 | - | |
1290 | -void helper_lsl(void) | |
1291 | -{ | |
1292 | - unsigned int selector, limit; | |
1293 | - uint32_t e1, e2; | |
1294 | - | |
1295 | - CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; | |
1296 | - selector = T0 & 0xffff; | |
1297 | - if (load_segment(&e1, &e2, selector) != 0) | |
1298 | - return; | |
1299 | - limit = (e1 & 0xffff) | (e2 & 0x000f0000); | |
1300 | - if (e2 & (1 << 23)) | |
1301 | - limit = (limit << 12) | 0xfff; | |
1302 | - T1 = limit; | |
1303 | - CC_SRC |= CC_Z; | |
1304 | -} | |
1305 | - | |
1306 | -void helper_lar(void) | |
1307 | -{ | |
1308 | - unsigned int selector; | |
1309 | - uint32_t e1, e2; | |
1310 | - | |
1311 | - CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; | |
1312 | - selector = T0 & 0xffff; | |
1313 | - if (load_segment(&e1, &e2, selector) != 0) | |
1314 | - return; | |
1315 | - T1 = e2 & 0x00f0ff00; | |
1316 | - CC_SRC |= CC_Z; | |
1317 | -} | |
1318 | - | |
1319 | -/* FPU helpers */ | |
1320 | - | |
1321 | -#ifndef USE_X86LDOUBLE | |
1322 | -void helper_fldt_ST0_A0(void) | |
1323 | -{ | |
1324 | - int new_fpstt; | |
1325 | - new_fpstt = (env->fpstt - 1) & 7; | |
1326 | - env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0); | |
1327 | - env->fpstt = new_fpstt; | |
1328 | - env->fptags[new_fpstt] = 0; /* validate stack entry */ | |
1329 | -} | |
1330 | - | |
1331 | -void helper_fstt_ST0_A0(void) | |
1332 | -{ | |
1333 | - helper_fstt(ST0, (uint8_t *)A0); | |
1334 | -} | |
1335 | -#endif | |
1336 | - | |
1337 | -/* BCD ops */ | |
1338 | - | |
1339 | -#define MUL10(iv) ( iv + iv + (iv << 3) ) | |
1340 | - | |
1341 | -void helper_fbld_ST0_A0(void) | |
1342 | -{ | |
1343 | - CPU86_LDouble tmp; | |
1344 | - uint64_t val; | |
1345 | - unsigned int v; | |
1346 | - int i; | |
1347 | - | |
1348 | - val = 0; | |
1349 | - for(i = 8; i >= 0; i--) { | |
1350 | - v = ldub((uint8_t *)A0 + i); | |
1351 | - val = (val * 100) + ((v >> 4) * 10) + (v & 0xf); | |
1352 | - } | |
1353 | - tmp = val; | |
1354 | - if (ldub((uint8_t *)A0 + 9) & 0x80) | |
1355 | - tmp = -tmp; | |
1356 | - fpush(); | |
1357 | - ST0 = tmp; | |
1358 | -} | |
1359 | - | |
1360 | -void helper_fbst_ST0_A0(void) | |
1361 | -{ | |
1362 | - CPU86_LDouble tmp; | |
1363 | - int v; | |
1364 | - uint8_t *mem_ref, *mem_end; | |
1365 | - int64_t val; | |
1366 | - | |
1367 | - tmp = rint(ST0); | |
1368 | - val = (int64_t)tmp; | |
1369 | - mem_ref = (uint8_t *)A0; | |
1370 | - mem_end = mem_ref + 9; | |
1371 | - if (val < 0) { | |
1372 | - stb(mem_end, 0x80); | |
1373 | - val = -val; | |
1374 | - } else { | |
1375 | - stb(mem_end, 0x00); | |
1376 | - } | |
1377 | - while (mem_ref < mem_end) { | |
1378 | - if (val == 0) | |
1379 | - break; | |
1380 | - v = val % 100; | |
1381 | - val = val / 100; | |
1382 | - v = ((v / 10) << 4) | (v % 10); | |
1383 | - stb(mem_ref++, v); | |
1384 | - } | |
1385 | - while (mem_ref < mem_end) { | |
1386 | - stb(mem_ref++, 0); | |
1387 | - } | |
1388 | -} | |
1389 | - | |
1390 | -void helper_f2xm1(void) | |
1391 | -{ | |
1392 | - ST0 = pow(2.0,ST0) - 1.0; | |
1393 | -} | |
1394 | - | |
1395 | -void helper_fyl2x(void) | |
1396 | -{ | |
1397 | - CPU86_LDouble fptemp; | |
1398 | - | |
1399 | - fptemp = ST0; | |
1400 | - if (fptemp>0.0){ | |
1401 | - fptemp = log(fptemp)/log(2.0); /* log2(ST) */ | |
1402 | - ST1 *= fptemp; | |
1403 | - fpop(); | |
1404 | - } else { | |
1405 | - env->fpus &= (~0x4700); | |
1406 | - env->fpus |= 0x400; | |
1407 | - } | |
1408 | -} | |
1409 | - | |
1410 | -void helper_fptan(void) | |
1411 | -{ | |
1412 | - CPU86_LDouble fptemp; | |
1413 | - | |
1414 | - fptemp = ST0; | |
1415 | - if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { | |
1416 | - env->fpus |= 0x400; | |
1417 | - } else { | |
1418 | - ST0 = tan(fptemp); | |
1419 | - fpush(); | |
1420 | - ST0 = 1.0; | |
1421 | - env->fpus &= (~0x400); /* C2 <-- 0 */ | |
1422 | - /* the above code is for |arg| < 2**52 only */ | |
1423 | - } | |
1424 | -} | |
1425 | - | |
1426 | -void helper_fpatan(void) | |
1427 | -{ | |
1428 | - CPU86_LDouble fptemp, fpsrcop; | |
1429 | - | |
1430 | - fpsrcop = ST1; | |
1431 | - fptemp = ST0; | |
1432 | - ST1 = atan2(fpsrcop,fptemp); | |
1433 | - fpop(); | |
1434 | -} | |
1435 | - | |
1436 | -void helper_fxtract(void) | |
1437 | -{ | |
1438 | - CPU86_LDoubleU temp; | |
1439 | - unsigned int expdif; | |
1440 | - | |
1441 | - temp.d = ST0; | |
1442 | - expdif = EXPD(temp) - EXPBIAS; | |
1443 | - /*DP exponent bias*/ | |
1444 | - ST0 = expdif; | |
1445 | - fpush(); | |
1446 | - BIASEXPONENT(temp); | |
1447 | - ST0 = temp.d; | |
1448 | -} | |
1449 | - | |
1450 | -void helper_fprem1(void) | |
1451 | -{ | |
1452 | - CPU86_LDouble dblq, fpsrcop, fptemp; | |
1453 | - CPU86_LDoubleU fpsrcop1, fptemp1; | |
1454 | - int expdif; | |
1455 | - int q; | |
1456 | - | |
1457 | - fpsrcop = ST0; | |
1458 | - fptemp = ST1; | |
1459 | - fpsrcop1.d = fpsrcop; | |
1460 | - fptemp1.d = fptemp; | |
1461 | - expdif = EXPD(fpsrcop1) - EXPD(fptemp1); | |
1462 | - if (expdif < 53) { | |
1463 | - dblq = fpsrcop / fptemp; | |
1464 | - dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); | |
1465 | - ST0 = fpsrcop - fptemp*dblq; | |
1466 | - q = (int)dblq; /* cutting off top bits is assumed here */ | |
1467 | - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ | |
1468 | - /* (C0,C1,C3) <-- (q2,q1,q0) */ | |
1469 | - env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ | |
1470 | - env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ | |
1471 | - env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ | |
1472 | - } else { | |
1473 | - env->fpus |= 0x400; /* C2 <-- 1 */ | |
1474 | - fptemp = pow(2.0, expdif-50); | |
1475 | - fpsrcop = (ST0 / ST1) / fptemp; | |
1476 | - /* fpsrcop = integer obtained by rounding to the nearest */ | |
1477 | - fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)? | |
1478 | - floor(fpsrcop): ceil(fpsrcop); | |
1479 | - ST0 -= (ST1 * fpsrcop * fptemp); | |
1480 | - } | |
1481 | -} | |
1482 | - | |
1483 | -void helper_fprem(void) | |
1484 | -{ | |
1485 | - CPU86_LDouble dblq, fpsrcop, fptemp; | |
1486 | - CPU86_LDoubleU fpsrcop1, fptemp1; | |
1487 | - int expdif; | |
1488 | - int q; | |
1489 | - | |
1490 | - fpsrcop = ST0; | |
1491 | - fptemp = ST1; | |
1492 | - fpsrcop1.d = fpsrcop; | |
1493 | - fptemp1.d = fptemp; | |
1494 | - expdif = EXPD(fpsrcop1) - EXPD(fptemp1); | |
1495 | - if ( expdif < 53 ) { | |
1496 | - dblq = fpsrcop / fptemp; | |
1497 | - dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); | |
1498 | - ST0 = fpsrcop - fptemp*dblq; | |
1499 | - q = (int)dblq; /* cutting off top bits is assumed here */ | |
1500 | - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ | |
1501 | - /* (C0,C1,C3) <-- (q2,q1,q0) */ | |
1502 | - env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ | |
1503 | - env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ | |
1504 | - env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ | |
1505 | - } else { | |
1506 | - env->fpus |= 0x400; /* C2 <-- 1 */ | |
1507 | - fptemp = pow(2.0, expdif-50); | |
1508 | - fpsrcop = (ST0 / ST1) / fptemp; | |
1509 | - /* fpsrcop = integer obtained by chopping */ | |
1510 | - fpsrcop = (fpsrcop < 0.0)? | |
1511 | - -(floor(fabs(fpsrcop))): floor(fpsrcop); | |
1512 | - ST0 -= (ST1 * fpsrcop * fptemp); | |
1513 | - } | |
1514 | -} | |
1515 | - | |
1516 | -void helper_fyl2xp1(void) | |
1517 | -{ | |
1518 | - CPU86_LDouble fptemp; | |
1519 | - | |
1520 | - fptemp = ST0; | |
1521 | - if ((fptemp+1.0)>0.0) { | |
1522 | - fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ | |
1523 | - ST1 *= fptemp; | |
1524 | - fpop(); | |
1525 | - } else { | |
1526 | - env->fpus &= (~0x4700); | |
1527 | - env->fpus |= 0x400; | |
1528 | - } | |
1529 | -} | |
1530 | - | |
1531 | -void helper_fsqrt(void) | |
1532 | -{ | |
1533 | - CPU86_LDouble fptemp; | |
1534 | - | |
1535 | - fptemp = ST0; | |
1536 | - if (fptemp<0.0) { | |
1537 | - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ | |
1538 | - env->fpus |= 0x400; | |
1539 | - } | |
1540 | - ST0 = sqrt(fptemp); | |
1541 | -} | |
1542 | - | |
1543 | -void helper_fsincos(void) | |
1544 | -{ | |
1545 | - CPU86_LDouble fptemp; | |
1546 | - | |
1547 | - fptemp = ST0; | |
1548 | - if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { | |
1549 | - env->fpus |= 0x400; | |
1550 | - } else { | |
1551 | - ST0 = sin(fptemp); | |
1552 | - fpush(); | |
1553 | - ST0 = cos(fptemp); | |
1554 | - env->fpus &= (~0x400); /* C2 <-- 0 */ | |
1555 | - /* the above code is for |arg| < 2**63 only */ | |
1556 | - } | |
1557 | -} | |
1558 | - | |
1559 | -void helper_frndint(void) | |
1560 | -{ | |
1561 | - CPU86_LDouble a; | |
1562 | - | |
1563 | - a = ST0; | |
1564 | -#ifdef __arm__ | |
1565 | - switch(env->fpuc & RC_MASK) { | |
1566 | - default: | |
1567 | - case RC_NEAR: | |
1568 | - asm("rndd %0, %1" : "=f" (a) : "f"(a)); | |
1569 | - break; | |
1570 | - case RC_DOWN: | |
1571 | - asm("rnddm %0, %1" : "=f" (a) : "f"(a)); | |
1572 | - break; | |
1573 | - case RC_UP: | |
1574 | - asm("rnddp %0, %1" : "=f" (a) : "f"(a)); | |
1575 | - break; | |
1576 | - case RC_CHOP: | |
1577 | - asm("rnddz %0, %1" : "=f" (a) : "f"(a)); | |
1578 | - break; | |
1579 | - } | |
1580 | -#else | |
1581 | - a = rint(a); | |
1582 | -#endif | |
1583 | - ST0 = a; | |
1584 | -} | |
1585 | - | |
1586 | -void helper_fscale(void) | |
1587 | -{ | |
1588 | - CPU86_LDouble fpsrcop, fptemp; | |
1589 | - | |
1590 | - fpsrcop = 2.0; | |
1591 | - fptemp = pow(fpsrcop,ST1); | |
1592 | - ST0 *= fptemp; | |
1593 | -} | |
1594 | - | |
1595 | -void helper_fsin(void) | |
1596 | -{ | |
1597 | - CPU86_LDouble fptemp; | |
1598 | - | |
1599 | - fptemp = ST0; | |
1600 | - if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { | |
1601 | - env->fpus |= 0x400; | |
1602 | - } else { | |
1603 | - ST0 = sin(fptemp); | |
1604 | - env->fpus &= (~0x400); /* C2 <-- 0 */ | |
1605 | - /* the above code is for |arg| < 2**53 only */ | |
1606 | - } | |
1607 | -} | |
1608 | - | |
1609 | -void helper_fcos(void) | |
1610 | -{ | |
1611 | - CPU86_LDouble fptemp; | |
1612 | - | |
1613 | - fptemp = ST0; | |
1614 | - if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { | |
1615 | - env->fpus |= 0x400; | |
1616 | - } else { | |
1617 | - ST0 = cos(fptemp); | |
1618 | - env->fpus &= (~0x400); /* C2 <-- 0 */ | |
1619 | - /* the above code is for |arg5 < 2**63 only */ | |
1620 | - } | |
1621 | -} | |
1622 | - | |
1623 | -void helper_fxam_ST0(void) | |
1624 | -{ | |
1625 | - CPU86_LDoubleU temp; | |
1626 | - int expdif; | |
1627 | - | |
1628 | - temp.d = ST0; | |
1629 | - | |
1630 | - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ | |
1631 | - if (SIGND(temp)) | |
1632 | - env->fpus |= 0x200; /* C1 <-- 1 */ | |
1633 | - | |
1634 | - expdif = EXPD(temp); | |
1635 | - if (expdif == MAXEXPD) { | |
1636 | - if (MANTD(temp) == 0) | |
1637 | - env->fpus |= 0x500 /*Infinity*/; | |
1638 | - else | |
1639 | - env->fpus |= 0x100 /*NaN*/; | |
1640 | - } else if (expdif == 0) { | |
1641 | - if (MANTD(temp) == 0) | |
1642 | - env->fpus |= 0x4000 /*Zero*/; | |
1643 | - else | |
1644 | - env->fpus |= 0x4400 /*Denormal*/; | |
1645 | - } else { | |
1646 | - env->fpus |= 0x400; | |
1647 | - } | |
1648 | -} | |
1649 | - | |
1650 | -void helper_fstenv(uint8_t *ptr, int data32) | |
1651 | -{ | |
1652 | - int fpus, fptag, exp, i; | |
1653 | - uint64_t mant; | |
1654 | - CPU86_LDoubleU tmp; | |
1655 | - | |
1656 | - fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; | |
1657 | - fptag = 0; | |
1658 | - for (i=7; i>=0; i--) { | |
1659 | - fptag <<= 2; | |
1660 | - if (env->fptags[i]) { | |
1661 | - fptag |= 3; | |
1662 | - } else { | |
1663 | - tmp.d = env->fpregs[i]; | |
1664 | - exp = EXPD(tmp); | |
1665 | - mant = MANTD(tmp); | |
1666 | - if (exp == 0 && mant == 0) { | |
1667 | - /* zero */ | |
1668 | - fptag |= 1; | |
1669 | - } else if (exp == 0 || exp == MAXEXPD | |
1670 | -#ifdef USE_X86LDOUBLE | |
1671 | - || (mant & (1LL << 63)) == 0 | |
1672 | -#endif | |
1673 | - ) { | |
1674 | - /* NaNs, infinity, denormal */ | |
1675 | - fptag |= 2; | |
1676 | - } | |
1677 | - } | |
1678 | - } | |
1679 | - if (data32) { | |
1680 | - /* 32 bit */ | |
1681 | - stl(ptr, env->fpuc); | |
1682 | - stl(ptr + 4, fpus); | |
1683 | - stl(ptr + 8, fptag); | |
1684 | - stl(ptr + 12, 0); | |
1685 | - stl(ptr + 16, 0); | |
1686 | - stl(ptr + 20, 0); | |
1687 | - stl(ptr + 24, 0); | |
1688 | - } else { | |
1689 | - /* 16 bit */ | |
1690 | - stw(ptr, env->fpuc); | |
1691 | - stw(ptr + 2, fpus); | |
1692 | - stw(ptr + 4, fptag); | |
1693 | - stw(ptr + 6, 0); | |
1694 | - stw(ptr + 8, 0); | |
1695 | - stw(ptr + 10, 0); | |
1696 | - stw(ptr + 12, 0); | |
1697 | - } | |
1698 | -} | |
1699 | - | |
1700 | -void helper_fldenv(uint8_t *ptr, int data32) | |
1701 | -{ | |
1702 | - int i, fpus, fptag; | |
1703 | - | |
1704 | - if (data32) { | |
1705 | - env->fpuc = lduw(ptr); | |
1706 | - fpus = lduw(ptr + 4); | |
1707 | - fptag = lduw(ptr + 8); | |
1708 | - } | |
1709 | - else { | |
1710 | - env->fpuc = lduw(ptr); | |
1711 | - fpus = lduw(ptr + 2); | |
1712 | - fptag = lduw(ptr + 4); | |
1713 | - } | |
1714 | - env->fpstt = (fpus >> 11) & 7; | |
1715 | - env->fpus = fpus & ~0x3800; | |
1716 | - for(i = 0;i < 7; i++) { | |
1717 | - env->fptags[i] = ((fptag & 3) == 3); | |
1718 | - fptag >>= 2; | |
1719 | - } | |
1720 | -} | |
1721 | - | |
1722 | -void helper_fsave(uint8_t *ptr, int data32) | |
1723 | -{ | |
1724 | - CPU86_LDouble tmp; | |
1725 | - int i; | |
1726 | - | |
1727 | - helper_fstenv(ptr, data32); | |
1728 | - | |
1729 | - ptr += (14 << data32); | |
1730 | - for(i = 0;i < 8; i++) { | |
1731 | - tmp = ST(i); | |
1732 | -#ifdef USE_X86LDOUBLE | |
1733 | - *(long double *)ptr = tmp; | |
1734 | -#else | |
1735 | - helper_fstt(tmp, ptr); | |
1736 | -#endif | |
1737 | - ptr += 10; | |
1738 | - } | |
1739 | - | |
1740 | - /* fninit */ | |
1741 | - env->fpus = 0; | |
1742 | - env->fpstt = 0; | |
1743 | - env->fpuc = 0x37f; | |
1744 | - env->fptags[0] = 1; | |
1745 | - env->fptags[1] = 1; | |
1746 | - env->fptags[2] = 1; | |
1747 | - env->fptags[3] = 1; | |
1748 | - env->fptags[4] = 1; | |
1749 | - env->fptags[5] = 1; | |
1750 | - env->fptags[6] = 1; | |
1751 | - env->fptags[7] = 1; | |
1752 | -} | |
1753 | - | |
1754 | -void helper_frstor(uint8_t *ptr, int data32) | |
1755 | -{ | |
1756 | - CPU86_LDouble tmp; | |
1757 | - int i; | |
1758 | - | |
1759 | - helper_fldenv(ptr, data32); | |
1760 | - ptr += (14 << data32); | |
1761 | - | |
1762 | - for(i = 0;i < 8; i++) { | |
1763 | -#ifdef USE_X86LDOUBLE | |
1764 | - tmp = *(long double *)ptr; | |
1765 | -#else | |
1766 | - tmp = helper_fldt(ptr); | |
1767 | -#endif | |
1768 | - ST(i) = tmp; | |
1769 | - ptr += 10; | |
1770 | - } | |
1771 | -} | |
1772 | - | |
1773 | -#define SHIFT 0 | |
1774 | -#include "softmmu_template.h" | |
1775 | - | |
1776 | -#define SHIFT 1 | |
1777 | -#include "softmmu_template.h" | |
1778 | - | |
1779 | -#define SHIFT 2 | |
1780 | -#include "softmmu_template.h" | |
1781 | - | |
1782 | -#define SHIFT 3 | |
1783 | -#include "softmmu_template.h" | |
1784 | - | |
1785 | -/* try to fill the TLB and return an exception if error */ | |
1786 | -void tlb_fill(unsigned long addr, int is_write, void *retaddr) | |
1787 | -{ | |
1788 | - TranslationBlock *tb; | |
1789 | - int ret; | |
1790 | - unsigned long pc; | |
1791 | - ret = cpu_x86_handle_mmu_fault(env, addr, is_write); | |
1792 | - if (ret) { | |
1793 | - /* now we have a real cpu fault */ | |
1794 | - pc = (unsigned long)retaddr; | |
1795 | - tb = tb_find_pc(pc); | |
1796 | - if (tb) { | |
1797 | - /* the PC is inside the translated code. It means that we have | |
1798 | - a virtual CPU fault */ | |
1799 | - cpu_restore_state(tb, env, pc); | |
1800 | - } | |
1801 | - raise_exception_err(EXCP0E_PAGE, env->error_code); | |
1802 | - } | |
1803 | -} |
helper2-i386.c deleted
100644 → 0
1 | -/* | |
2 | - * i386 helpers (without register variable usage) | |
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 | |
19 | - */ | |
20 | -#include <stdarg.h> | |
21 | -#include <stdlib.h> | |
22 | -#include <stdio.h> | |
23 | -#include <string.h> | |
24 | -#include <inttypes.h> | |
25 | -#include <signal.h> | |
26 | -#include <assert.h> | |
27 | -#include <sys/mman.h> | |
28 | - | |
29 | -#include "cpu-i386.h" | |
30 | -#include "exec.h" | |
31 | - | |
32 | -//#define DEBUG_MMU | |
33 | - | |
34 | -CPUX86State *cpu_x86_init(void) | |
35 | -{ | |
36 | - CPUX86State *env; | |
37 | - int i; | |
38 | - static int inited; | |
39 | - | |
40 | - cpu_exec_init(); | |
41 | - | |
42 | - env = malloc(sizeof(CPUX86State)); | |
43 | - if (!env) | |
44 | - return NULL; | |
45 | - memset(env, 0, sizeof(CPUX86State)); | |
46 | - /* basic FPU init */ | |
47 | - for(i = 0;i < 8; i++) | |
48 | - env->fptags[i] = 1; | |
49 | - env->fpuc = 0x37f; | |
50 | - /* flags setup : we activate the IRQs by default as in user mode */ | |
51 | - env->eflags = 0x2 | IF_MASK; | |
52 | - | |
53 | - tlb_flush(env); | |
54 | -#ifdef CONFIG_SOFTMMU | |
55 | - env->hflags |= HF_SOFTMMU_MASK; | |
56 | -#endif | |
57 | - /* init various static tables */ | |
58 | - if (!inited) { | |
59 | - inited = 1; | |
60 | - optimize_flags_init(); | |
61 | - } | |
62 | - return env; | |
63 | -} | |
64 | - | |
65 | -void cpu_x86_close(CPUX86State *env) | |
66 | -{ | |
67 | - free(env); | |
68 | -} | |
69 | - | |
70 | -/***********************************************************/ | |
71 | -/* x86 debug */ | |
72 | - | |
73 | -static const char *cc_op_str[] = { | |
74 | - "DYNAMIC", | |
75 | - "EFLAGS", | |
76 | - "MUL", | |
77 | - "ADDB", | |
78 | - "ADDW", | |
79 | - "ADDL", | |
80 | - "ADCB", | |
81 | - "ADCW", | |
82 | - "ADCL", | |
83 | - "SUBB", | |
84 | - "SUBW", | |
85 | - "SUBL", | |
86 | - "SBBB", | |
87 | - "SBBW", | |
88 | - "SBBL", | |
89 | - "LOGICB", | |
90 | - "LOGICW", | |
91 | - "LOGICL", | |
92 | - "INCB", | |
93 | - "INCW", | |
94 | - "INCL", | |
95 | - "DECB", | |
96 | - "DECW", | |
97 | - "DECL", | |
98 | - "SHLB", | |
99 | - "SHLW", | |
100 | - "SHLL", | |
101 | - "SARB", | |
102 | - "SARW", | |
103 | - "SARL", | |
104 | -}; | |
105 | - | |
106 | -void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) | |
107 | -{ | |
108 | - int eflags; | |
109 | - char cc_op_name[32]; | |
110 | - | |
111 | - eflags = env->eflags; | |
112 | - fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" | |
113 | - "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" | |
114 | - "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]\n", | |
115 | - env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], | |
116 | - env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], | |
117 | - env->eip, eflags, | |
118 | - eflags & DF_MASK ? 'D' : '-', | |
119 | - eflags & CC_O ? 'O' : '-', | |
120 | - eflags & CC_S ? 'S' : '-', | |
121 | - eflags & CC_Z ? 'Z' : '-', | |
122 | - eflags & CC_A ? 'A' : '-', | |
123 | - eflags & CC_P ? 'P' : '-', | |
124 | - eflags & CC_C ? 'C' : '-'); | |
125 | - fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n", | |
126 | - env->segs[R_CS].selector, | |
127 | - env->segs[R_SS].selector, | |
128 | - env->segs[R_DS].selector, | |
129 | - env->segs[R_ES].selector, | |
130 | - env->segs[R_FS].selector, | |
131 | - env->segs[R_GS].selector); | |
132 | - if (flags & X86_DUMP_CCOP) { | |
133 | - if ((unsigned)env->cc_op < CC_OP_NB) | |
134 | - strcpy(cc_op_name, cc_op_str[env->cc_op]); | |
135 | - else | |
136 | - snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); | |
137 | - fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", | |
138 | - env->cc_src, env->cc_dst, cc_op_name); | |
139 | - } | |
140 | - if (flags & X86_DUMP_FPU) { | |
141 | - fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", | |
142 | - (double)env->fpregs[0], | |
143 | - (double)env->fpregs[1], | |
144 | - (double)env->fpregs[2], | |
145 | - (double)env->fpregs[3]); | |
146 | - fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", | |
147 | - (double)env->fpregs[4], | |
148 | - (double)env->fpregs[5], | |
149 | - (double)env->fpregs[7], | |
150 | - (double)env->fpregs[8]); | |
151 | - } | |
152 | -} | |
153 | - | |
154 | -/***********************************************************/ | |
155 | -/* x86 mmu */ | |
156 | -/* XXX: add PGE support */ | |
157 | - | |
158 | -/* called when cr3 or PG bit are modified */ | |
159 | -static int last_pg_state = -1; | |
160 | -static int last_pe_state = 0; | |
161 | -int phys_ram_size; | |
162 | -int phys_ram_fd; | |
163 | -uint8_t *phys_ram_base; | |
164 | - | |
165 | -void cpu_x86_update_cr0(CPUX86State *env) | |
166 | -{ | |
167 | - int pg_state, pe_state; | |
168 | - | |
169 | -#ifdef DEBUG_MMU | |
170 | - printf("CR0 update: CR0=0x%08x\n", env->cr[0]); | |
171 | -#endif | |
172 | - pg_state = env->cr[0] & CR0_PG_MASK; | |
173 | - if (pg_state != last_pg_state) { | |
174 | - page_unmap(); | |
175 | - tlb_flush(env); | |
176 | - last_pg_state = pg_state; | |
177 | - } | |
178 | - pe_state = env->cr[0] & CR0_PE_MASK; | |
179 | - if (last_pe_state != pe_state) { | |
180 | - tb_flush(); | |
181 | - last_pe_state = pe_state; | |
182 | - } | |
183 | -} | |
184 | - | |
185 | -void cpu_x86_update_cr3(CPUX86State *env) | |
186 | -{ | |
187 | - if (env->cr[0] & CR0_PG_MASK) { | |
188 | -#if defined(DEBUG_MMU) | |
189 | - printf("CR3 update: CR3=%08x\n", env->cr[3]); | |
190 | -#endif | |
191 | - page_unmap(); | |
192 | - tlb_flush(env); | |
193 | - } | |
194 | -} | |
195 | - | |
196 | -void cpu_x86_init_mmu(CPUX86State *env) | |
197 | -{ | |
198 | - last_pg_state = -1; | |
199 | - cpu_x86_update_cr0(env); | |
200 | -} | |
201 | - | |
202 | -/* XXX: also flush 4MB pages */ | |
203 | -void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr) | |
204 | -{ | |
205 | - int flags; | |
206 | - unsigned long virt_addr; | |
207 | - | |
208 | - tlb_flush_page(env, addr); | |
209 | - | |
210 | - flags = page_get_flags(addr); | |
211 | - if (flags & PAGE_VALID) { | |
212 | - virt_addr = addr & ~0xfff; | |
213 | - munmap((void *)virt_addr, 4096); | |
214 | - page_set_flags(virt_addr, virt_addr + 4096, 0); | |
215 | - } | |
216 | -} | |
217 | - | |
218 | -/* return value: | |
219 | - -1 = cannot handle fault | |
220 | - 0 = nothing more to do | |
221 | - 1 = generate PF fault | |
222 | - 2 = soft MMU activation required for this block | |
223 | -*/ | |
224 | -int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) | |
225 | -{ | |
226 | - uint8_t *pde_ptr, *pte_ptr; | |
227 | - uint32_t pde, pte, virt_addr; | |
228 | - int cpl, error_code, is_dirty, is_user, prot, page_size, ret; | |
229 | - unsigned long pd; | |
230 | - | |
231 | - cpl = env->hflags & HF_CPL_MASK; | |
232 | - is_user = (cpl == 3); | |
233 | - | |
234 | -#ifdef DEBUG_MMU | |
235 | - printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", | |
236 | - addr, is_write, is_user, env->eip); | |
237 | -#endif | |
238 | - | |
239 | - if (env->user_mode_only) { | |
240 | - /* user mode only emulation */ | |
241 | - error_code = 0; | |
242 | - goto do_fault; | |
243 | - } | |
244 | - | |
245 | - if (!(env->cr[0] & CR0_PG_MASK)) { | |
246 | - pte = addr; | |
247 | - virt_addr = addr & ~0xfff; | |
248 | - prot = PROT_READ | PROT_WRITE; | |
249 | - page_size = 4096; | |
250 | - goto do_mapping; | |
251 | - } | |
252 | - | |
253 | - /* page directory entry */ | |
254 | - pde_ptr = phys_ram_base + ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)); | |
255 | - pde = ldl(pde_ptr); | |
256 | - if (!(pde & PG_PRESENT_MASK)) { | |
257 | - error_code = 0; | |
258 | - goto do_fault; | |
259 | - } | |
260 | - if (is_user) { | |
261 | - if (!(pde & PG_USER_MASK)) | |
262 | - goto do_fault_protect; | |
263 | - if (is_write && !(pde & PG_RW_MASK)) | |
264 | - goto do_fault_protect; | |
265 | - } else { | |
266 | - if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) && | |
267 | - is_write && !(pde & PG_RW_MASK)) | |
268 | - goto do_fault_protect; | |
269 | - } | |
270 | - /* if PSE bit is set, then we use a 4MB page */ | |
271 | - if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { | |
272 | - is_dirty = is_write && !(pde & PG_DIRTY_MASK); | |
273 | - if (!(pde & PG_ACCESSED_MASK)) { | |
274 | - pde |= PG_ACCESSED_MASK; | |
275 | - if (is_dirty) | |
276 | - pde |= PG_DIRTY_MASK; | |
277 | - stl(pde_ptr, pde); | |
278 | - } | |
279 | - | |
280 | - pte = pde & ~0x003ff000; /* align to 4MB */ | |
281 | - page_size = 4096 * 1024; | |
282 | - virt_addr = addr & ~0x003fffff; | |
283 | - } else { | |
284 | - if (!(pde & PG_ACCESSED_MASK)) { | |
285 | - pde |= PG_ACCESSED_MASK; | |
286 | - stl(pde_ptr, pde); | |
287 | - } | |
288 | - | |
289 | - /* page directory entry */ | |
290 | - pte_ptr = phys_ram_base + ((pde & ~0xfff) + ((addr >> 10) & 0xffc)); | |
291 | - pte = ldl(pte_ptr); | |
292 | - if (!(pte & PG_PRESENT_MASK)) { | |
293 | - error_code = 0; | |
294 | - goto do_fault; | |
295 | - } | |
296 | - if (is_user) { | |
297 | - if (!(pte & PG_USER_MASK)) | |
298 | - goto do_fault_protect; | |
299 | - if (is_write && !(pte & PG_RW_MASK)) | |
300 | - goto do_fault_protect; | |
301 | - } else { | |
302 | - if ((env->cr[0] & CR0_WP_MASK) && (pte & PG_USER_MASK) && | |
303 | - is_write && !(pte & PG_RW_MASK)) | |
304 | - goto do_fault_protect; | |
305 | - } | |
306 | - is_dirty = is_write && !(pte & PG_DIRTY_MASK); | |
307 | - if (!(pte & PG_ACCESSED_MASK) || is_dirty) { | |
308 | - pte |= PG_ACCESSED_MASK; | |
309 | - if (is_dirty) | |
310 | - pte |= PG_DIRTY_MASK; | |
311 | - stl(pte_ptr, pte); | |
312 | - } | |
313 | - page_size = 4096; | |
314 | - virt_addr = addr & ~0xfff; | |
315 | - } | |
316 | - /* the page can be put in the TLB */ | |
317 | - prot = PROT_READ; | |
318 | - if (is_user) { | |
319 | - if (pte & PG_RW_MASK) | |
320 | - prot |= PROT_WRITE; | |
321 | - } else { | |
322 | - if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) || | |
323 | - (pte & PG_RW_MASK)) | |
324 | - prot |= PROT_WRITE; | |
325 | - } | |
326 | - | |
327 | - do_mapping: | |
328 | - if (env->hflags & HF_SOFTMMU_MASK) { | |
329 | - unsigned long paddr, vaddr, address, addend, page_offset; | |
330 | - int index; | |
331 | - | |
332 | - /* software MMU case. Even if 4MB pages, we map only one 4KB | |
333 | - page in the cache to avoid filling it too fast */ | |
334 | - page_offset = (addr & ~0xfff) & (page_size - 1); | |
335 | - paddr = (pte & ~0xfff) + page_offset; | |
336 | - vaddr = virt_addr + page_offset; | |
337 | - index = (addr >> 12) & (CPU_TLB_SIZE - 1); | |
338 | - pd = physpage_find(paddr); | |
339 | - if (pd & 0xfff) { | |
340 | - /* IO memory case */ | |
341 | - address = vaddr | pd; | |
342 | - addend = paddr; | |
343 | - } else { | |
344 | - /* standard memory */ | |
345 | - address = vaddr; | |
346 | - addend = (unsigned long)phys_ram_base + pd; | |
347 | - } | |
348 | - addend -= vaddr; | |
349 | - env->tlb_read[is_user][index].address = address; | |
350 | - env->tlb_read[is_user][index].addend = addend; | |
351 | - if (prot & PROT_WRITE) { | |
352 | - env->tlb_write[is_user][index].address = address; | |
353 | - env->tlb_write[is_user][index].addend = addend; | |
354 | - } | |
355 | - } | |
356 | - ret = 0; | |
357 | - /* XXX: incorrect for 4MB pages */ | |
358 | - pd = physpage_find(pte & ~0xfff); | |
359 | - if ((pd & 0xfff) != 0) { | |
360 | - /* IO access: no mapping is done as it will be handled by the | |
361 | - soft MMU */ | |
362 | - if (!(env->hflags & HF_SOFTMMU_MASK)) | |
363 | - ret = 2; | |
364 | - } else { | |
365 | - void *map_addr; | |
366 | - map_addr = mmap((void *)virt_addr, page_size, prot, | |
367 | - MAP_SHARED | MAP_FIXED, phys_ram_fd, pd); | |
368 | - if (map_addr == MAP_FAILED) { | |
369 | - fprintf(stderr, | |
370 | - "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", | |
371 | - pte & ~0xfff, virt_addr); | |
372 | - exit(1); | |
373 | - } | |
374 | -#ifdef DEBUG_MMU | |
375 | - printf("mmaping 0x%08x to virt 0x%08x pse=%d\n", | |
376 | - pte & ~0xfff, virt_addr, (page_size != 4096)); | |
377 | -#endif | |
378 | - page_set_flags(virt_addr, virt_addr + page_size, | |
379 | - PAGE_VALID | PAGE_EXEC | prot); | |
380 | - } | |
381 | - return ret; | |
382 | - do_fault_protect: | |
383 | - error_code = PG_ERROR_P_MASK; | |
384 | - do_fault: | |
385 | - env->cr[2] = addr; | |
386 | - env->error_code = (is_write << PG_ERROR_W_BIT) | error_code; | |
387 | - if (is_user) | |
388 | - env->error_code |= PG_ERROR_U_MASK; | |
389 | - return 1; | |
390 | -} |
op-arm-template.h deleted
100644 → 0
1 | -/* | |
2 | - * ARM micro operations (templates for various register related | |
3 | - * operations) | |
4 | - * | |
5 | - * Copyright (c) 2003 Fabrice Bellard | |
6 | - * | |
7 | - * This library is free software; you can redistribute it and/or | |
8 | - * modify it under the terms of the GNU Lesser General Public | |
9 | - * License as published by the Free Software Foundation; either | |
10 | - * version 2 of the License, or (at your option) any later version. | |
11 | - * | |
12 | - * This library is distributed in the hope that it will be useful, | |
13 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | - * Lesser General Public License for more details. | |
16 | - * | |
17 | - * You should have received a copy of the GNU Lesser General Public | |
18 | - * License along with this library; if not, write to the Free Software | |
19 | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 | - */ | |
21 | - | |
22 | -void OPPROTO glue(op_movl_T0_, REGNAME)(void) | |
23 | -{ | |
24 | - T0 = REG; | |
25 | -} | |
26 | - | |
27 | -void OPPROTO glue(op_movl_T1_, REGNAME)(void) | |
28 | -{ | |
29 | - T1 = REG; | |
30 | -} | |
31 | - | |
32 | -void OPPROTO glue(op_movl_T2_, REGNAME)(void) | |
33 | -{ | |
34 | - T2 = REG; | |
35 | -} | |
36 | - | |
37 | -void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void) | |
38 | -{ | |
39 | - REG = T0; | |
40 | -} | |
41 | - | |
42 | -void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void) | |
43 | -{ | |
44 | - REG = T1; | |
45 | -} | |
46 | - | |
47 | -#undef REG | |
48 | -#undef REGNAME |
op-arm.c deleted
100644 → 0
1 | -/* | |
2 | - * ARM micro operations | |
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 | |
19 | - */ | |
20 | -#include "exec-arm.h" | |
21 | - | |
22 | -#define REGNAME r0 | |
23 | -#define REG (env->regs[0]) | |
24 | -#include "op-arm-template.h" | |
25 | - | |
26 | -#define REGNAME r1 | |
27 | -#define REG (env->regs[1]) | |
28 | -#include "op-arm-template.h" | |
29 | - | |
30 | -#define REGNAME r2 | |
31 | -#define REG (env->regs[2]) | |
32 | -#include "op-arm-template.h" | |
33 | - | |
34 | -#define REGNAME r3 | |
35 | -#define REG (env->regs[3]) | |
36 | -#include "op-arm-template.h" | |
37 | - | |
38 | -#define REGNAME r4 | |
39 | -#define REG (env->regs[4]) | |
40 | -#include "op-arm-template.h" | |
41 | - | |
42 | -#define REGNAME r5 | |
43 | -#define REG (env->regs[5]) | |
44 | -#include "op-arm-template.h" | |
45 | - | |
46 | -#define REGNAME r6 | |
47 | -#define REG (env->regs[6]) | |
48 | -#include "op-arm-template.h" | |
49 | - | |
50 | -#define REGNAME r7 | |
51 | -#define REG (env->regs[7]) | |
52 | -#include "op-arm-template.h" | |
53 | - | |
54 | -#define REGNAME r8 | |
55 | -#define REG (env->regs[8]) | |
56 | -#include "op-arm-template.h" | |
57 | - | |
58 | -#define REGNAME r9 | |
59 | -#define REG (env->regs[9]) | |
60 | -#include "op-arm-template.h" | |
61 | - | |
62 | -#define REGNAME r10 | |
63 | -#define REG (env->regs[10]) | |
64 | -#include "op-arm-template.h" | |
65 | - | |
66 | -#define REGNAME r11 | |
67 | -#define REG (env->regs[11]) | |
68 | -#include "op-arm-template.h" | |
69 | - | |
70 | -#define REGNAME r12 | |
71 | -#define REG (env->regs[12]) | |
72 | -#include "op-arm-template.h" | |
73 | - | |
74 | -#define REGNAME r13 | |
75 | -#define REG (env->regs[13]) | |
76 | -#include "op-arm-template.h" | |
77 | - | |
78 | -#define REGNAME r14 | |
79 | -#define REG (env->regs[14]) | |
80 | -#include "op-arm-template.h" | |
81 | - | |
82 | -#define REGNAME r15 | |
83 | -#define REG (env->regs[15]) | |
84 | -#include "op-arm-template.h" | |
85 | - | |
86 | -void OPPROTO op_movl_T0_0(void) | |
87 | -{ | |
88 | - T0 = 0; | |
89 | -} | |
90 | - | |
91 | -void OPPROTO op_movl_T0_im(void) | |
92 | -{ | |
93 | - T0 = PARAM1; | |
94 | -} | |
95 | - | |
96 | -void OPPROTO op_movl_T1_im(void) | |
97 | -{ | |
98 | - T1 = PARAM1; | |
99 | -} | |
100 | - | |
101 | -void OPPROTO op_movl_T2_im(void) | |
102 | -{ | |
103 | - T2 = PARAM1; | |
104 | -} | |
105 | - | |
106 | -void OPPROTO op_addl_T1_im(void) | |
107 | -{ | |
108 | - T1 += PARAM1; | |
109 | -} | |
110 | - | |
111 | -void OPPROTO op_addl_T1_T2(void) | |
112 | -{ | |
113 | - T1 += T2; | |
114 | -} | |
115 | - | |
116 | -void OPPROTO op_subl_T1_T2(void) | |
117 | -{ | |
118 | - T1 -= T2; | |
119 | -} | |
120 | - | |
121 | -void OPPROTO op_addl_T0_T1(void) | |
122 | -{ | |
123 | - T0 += T1; | |
124 | -} | |
125 | - | |
126 | -void OPPROTO op_addl_T0_T1_cc(void) | |
127 | -{ | |
128 | - unsigned int src1; | |
129 | - src1 = T0; | |
130 | - T0 += T1; | |
131 | - env->NZF = T0; | |
132 | - env->CF = T0 < src1; | |
133 | - env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); | |
134 | -} | |
135 | - | |
136 | -void OPPROTO op_adcl_T0_T1(void) | |
137 | -{ | |
138 | - T0 += T1 + env->CF; | |
139 | -} | |
140 | - | |
141 | -void OPPROTO op_adcl_T0_T1_cc(void) | |
142 | -{ | |
143 | - unsigned int src1; | |
144 | - src1 = T0; | |
145 | - if (!env->CF) { | |
146 | - T0 += T1; | |
147 | - env->CF = T0 < src1; | |
148 | - } else { | |
149 | - T0 += T1 + 1; | |
150 | - env->CF = T0 <= src1; | |
151 | - } | |
152 | - env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); | |
153 | - env->NZF = T0; | |
154 | - FORCE_RET(); | |
155 | -} | |
156 | - | |
157 | -#define OPSUB(sub, sbc, res, T0, T1) \ | |
158 | - \ | |
159 | -void OPPROTO op_ ## sub ## l_T0_T1(void) \ | |
160 | -{ \ | |
161 | - res = T0 - T1; \ | |
162 | -} \ | |
163 | - \ | |
164 | -void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \ | |
165 | -{ \ | |
166 | - unsigned int src1; \ | |
167 | - src1 = T0; \ | |
168 | - T0 -= T1; \ | |
169 | - env->NZF = T0; \ | |
170 | - env->CF = src1 >= T1; \ | |
171 | - env->VF = (src1 ^ T1) & (src1 ^ T0); \ | |
172 | - res = T0; \ | |
173 | -} \ | |
174 | - \ | |
175 | -void OPPROTO op_ ## sbc ## l_T0_T1(void) \ | |
176 | -{ \ | |
177 | - res = T0 - T1 + env->CF - 1; \ | |
178 | -} \ | |
179 | - \ | |
180 | -void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ | |
181 | -{ \ | |
182 | - unsigned int src1; \ | |
183 | - src1 = T0; \ | |
184 | - if (!env->CF) { \ | |
185 | - T0 = T0 - T1 - 1; \ | |
186 | - env->CF = src1 >= T1; \ | |
187 | - } else { \ | |
188 | - T0 = T0 - T1; \ | |
189 | - env->CF = src1 > T1; \ | |
190 | - } \ | |
191 | - env->VF = (src1 ^ T1) & (src1 ^ T0); \ | |
192 | - env->NZF = T0; \ | |
193 | - res = T0; \ | |
194 | - FORCE_RET(); \ | |
195 | -} | |
196 | - | |
197 | -OPSUB(sub, sbc, T0, T0, T1) | |
198 | - | |
199 | -OPSUB(rsb, rsc, T0, T1, T0) | |
200 | - | |
201 | -void OPPROTO op_andl_T0_T1(void) | |
202 | -{ | |
203 | - T0 &= T1; | |
204 | -} | |
205 | - | |
206 | -void OPPROTO op_xorl_T0_T1(void) | |
207 | -{ | |
208 | - T0 ^= T1; | |
209 | -} | |
210 | - | |
211 | -void OPPROTO op_orl_T0_T1(void) | |
212 | -{ | |
213 | - T0 |= T1; | |
214 | -} | |
215 | - | |
216 | -void OPPROTO op_bicl_T0_T1(void) | |
217 | -{ | |
218 | - T0 &= ~T1; | |
219 | -} | |
220 | - | |
221 | -void OPPROTO op_notl_T1(void) | |
222 | -{ | |
223 | - T1 = ~T1; | |
224 | -} | |
225 | - | |
226 | -void OPPROTO op_logic_T0_cc(void) | |
227 | -{ | |
228 | - env->NZF = T0; | |
229 | -} | |
230 | - | |
231 | -void OPPROTO op_logic_T1_cc(void) | |
232 | -{ | |
233 | - env->NZF = T1; | |
234 | -} | |
235 | - | |
236 | -#define EIP (env->regs[15]) | |
237 | - | |
238 | -void OPPROTO op_test_eq(void) | |
239 | -{ | |
240 | - if (env->NZF == 0) | |
241 | - JUMP_TB(op_test_eq, PARAM1, 0, PARAM2); | |
242 | - FORCE_RET(); | |
243 | -} | |
244 | - | |
245 | -void OPPROTO op_test_ne(void) | |
246 | -{ | |
247 | - if (env->NZF != 0) | |
248 | - JUMP_TB(op_test_ne, PARAM1, 0, PARAM2); | |
249 | - FORCE_RET(); | |
250 | -} | |
251 | - | |
252 | -void OPPROTO op_test_cs(void) | |
253 | -{ | |
254 | - if (env->CF != 0) | |
255 | - JUMP_TB(op_test_cs, PARAM1, 0, PARAM2); | |
256 | - FORCE_RET(); | |
257 | -} | |
258 | - | |
259 | -void OPPROTO op_test_cc(void) | |
260 | -{ | |
261 | - if (env->CF == 0) | |
262 | - JUMP_TB(op_test_cc, PARAM1, 0, PARAM2); | |
263 | - FORCE_RET(); | |
264 | -} | |
265 | - | |
266 | -void OPPROTO op_test_mi(void) | |
267 | -{ | |
268 | - if ((env->NZF & 0x80000000) != 0) | |
269 | - JUMP_TB(op_test_mi, PARAM1, 0, PARAM2); | |
270 | - FORCE_RET(); | |
271 | -} | |
272 | - | |
273 | -void OPPROTO op_test_pl(void) | |
274 | -{ | |
275 | - if ((env->NZF & 0x80000000) == 0) | |
276 | - JUMP_TB(op_test_pl, PARAM1, 0, PARAM2); | |
277 | - FORCE_RET(); | |
278 | -} | |
279 | - | |
280 | -void OPPROTO op_test_vs(void) | |
281 | -{ | |
282 | - if ((env->VF & 0x80000000) != 0) | |
283 | - JUMP_TB(op_test_vs, PARAM1, 0, PARAM2); | |
284 | - FORCE_RET(); | |
285 | -} | |
286 | - | |
287 | -void OPPROTO op_test_vc(void) | |
288 | -{ | |
289 | - if ((env->VF & 0x80000000) == 0) | |
290 | - JUMP_TB(op_test_vc, PARAM1, 0, PARAM2); | |
291 | - FORCE_RET(); | |
292 | -} | |
293 | - | |
294 | -void OPPROTO op_test_hi(void) | |
295 | -{ | |
296 | - if (env->CF != 0 && env->NZF != 0) | |
297 | - JUMP_TB(op_test_hi, PARAM1, 0, PARAM2); | |
298 | - FORCE_RET(); | |
299 | -} | |
300 | - | |
301 | -void OPPROTO op_test_ls(void) | |
302 | -{ | |
303 | - if (env->CF == 0 || env->NZF == 0) | |
304 | - JUMP_TB(op_test_ls, PARAM1, 0, PARAM2); | |
305 | - FORCE_RET(); | |
306 | -} | |
307 | - | |
308 | -void OPPROTO op_test_ge(void) | |
309 | -{ | |
310 | - if (((env->VF ^ env->NZF) & 0x80000000) == 0) | |
311 | - JUMP_TB(op_test_ge, PARAM1, 0, PARAM2); | |
312 | - FORCE_RET(); | |
313 | -} | |
314 | - | |
315 | -void OPPROTO op_test_lt(void) | |
316 | -{ | |
317 | - if (((env->VF ^ env->NZF) & 0x80000000) != 0) | |
318 | - JUMP_TB(op_test_lt, PARAM1, 0, PARAM2); | |
319 | - FORCE_RET(); | |
320 | -} | |
321 | - | |
322 | -void OPPROTO op_test_gt(void) | |
323 | -{ | |
324 | - if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0) | |
325 | - JUMP_TB(op_test_gt, PARAM1, 0, PARAM2); | |
326 | - FORCE_RET(); | |
327 | -} | |
328 | - | |
329 | -void OPPROTO op_test_le(void) | |
330 | -{ | |
331 | - if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0) | |
332 | - JUMP_TB(op_test_le, PARAM1, 0, PARAM2); | |
333 | - FORCE_RET(); | |
334 | -} | |
335 | - | |
336 | -void OPPROTO op_jmp(void) | |
337 | -{ | |
338 | - JUMP_TB(op_jmp, PARAM1, 1, PARAM2); | |
339 | -} | |
340 | - | |
341 | -void OPPROTO op_exit_tb(void) | |
342 | -{ | |
343 | - EXIT_TB(); | |
344 | -} | |
345 | - | |
346 | -void OPPROTO op_movl_T0_psr(void) | |
347 | -{ | |
348 | - T0 = compute_cpsr(); | |
349 | -} | |
350 | - | |
351 | -/* NOTE: N = 1 and Z = 1 cannot be stored currently */ | |
352 | -void OPPROTO op_movl_psr_T0(void) | |
353 | -{ | |
354 | - unsigned int psr; | |
355 | - psr = T0; | |
356 | - env->CF = (psr >> 29) & 1; | |
357 | - env->NZF = (psr & 0xc0000000) ^ 0x40000000; | |
358 | - env->VF = (psr << 3) & 0x80000000; | |
359 | - /* for user mode we do not update other state info */ | |
360 | -} | |
361 | - | |
362 | -void OPPROTO op_mul_T0_T1(void) | |
363 | -{ | |
364 | - T0 = T0 * T1; | |
365 | -} | |
366 | - | |
367 | -/* 64 bit unsigned mul */ | |
368 | -void OPPROTO op_mull_T0_T1(void) | |
369 | -{ | |
370 | - uint64_t res; | |
371 | - res = T0 * T1; | |
372 | - T1 = res >> 32; | |
373 | - T0 = res; | |
374 | -} | |
375 | - | |
376 | -/* 64 bit signed mul */ | |
377 | -void OPPROTO op_imull_T0_T1(void) | |
378 | -{ | |
379 | - uint64_t res; | |
380 | - res = (int32_t)T0 * (int32_t)T1; | |
381 | - T1 = res >> 32; | |
382 | - T0 = res; | |
383 | -} | |
384 | - | |
385 | -void OPPROTO op_addq_T0_T1(void) | |
386 | -{ | |
387 | - uint64_t res; | |
388 | - res = ((uint64_t)T1 << 32) | T0; | |
389 | - res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); | |
390 | - T1 = res >> 32; | |
391 | - T0 = res; | |
392 | -} | |
393 | - | |
394 | -void OPPROTO op_logicq_cc(void) | |
395 | -{ | |
396 | - env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0); | |
397 | -} | |
398 | - | |
399 | -/* memory access */ | |
400 | - | |
401 | -void OPPROTO op_ldub_T0_T1(void) | |
402 | -{ | |
403 | - T0 = ldub((void *)T1); | |
404 | -} | |
405 | - | |
406 | -void OPPROTO op_ldsb_T0_T1(void) | |
407 | -{ | |
408 | - T0 = ldsb((void *)T1); | |
409 | -} | |
410 | - | |
411 | -void OPPROTO op_lduw_T0_T1(void) | |
412 | -{ | |
413 | - T0 = lduw((void *)T1); | |
414 | -} | |
415 | - | |
416 | -void OPPROTO op_ldsw_T0_T1(void) | |
417 | -{ | |
418 | - T0 = ldsw((void *)T1); | |
419 | -} | |
420 | - | |
421 | -void OPPROTO op_ldl_T0_T1(void) | |
422 | -{ | |
423 | - T0 = ldl((void *)T1); | |
424 | -} | |
425 | - | |
426 | -void OPPROTO op_stb_T0_T1(void) | |
427 | -{ | |
428 | - stb((void *)T1, T0); | |
429 | -} | |
430 | - | |
431 | -void OPPROTO op_stw_T0_T1(void) | |
432 | -{ | |
433 | - stw((void *)T1, T0); | |
434 | -} | |
435 | - | |
436 | -void OPPROTO op_stl_T0_T1(void) | |
437 | -{ | |
438 | - stl((void *)T1, T0); | |
439 | -} | |
440 | - | |
441 | -void OPPROTO op_swpb_T0_T1(void) | |
442 | -{ | |
443 | - int tmp; | |
444 | - | |
445 | - cpu_lock(); | |
446 | - tmp = ldub((void *)T1); | |
447 | - stb((void *)T1, T0); | |
448 | - T0 = tmp; | |
449 | - cpu_unlock(); | |
450 | -} | |
451 | - | |
452 | -void OPPROTO op_swpl_T0_T1(void) | |
453 | -{ | |
454 | - int tmp; | |
455 | - | |
456 | - cpu_lock(); | |
457 | - tmp = ldl((void *)T1); | |
458 | - stl((void *)T1, T0); | |
459 | - T0 = tmp; | |
460 | - cpu_unlock(); | |
461 | -} | |
462 | - | |
463 | -/* shifts */ | |
464 | - | |
465 | -/* T1 based */ | |
466 | -void OPPROTO op_shll_T1_im(void) | |
467 | -{ | |
468 | - T1 = T1 << PARAM1; | |
469 | -} | |
470 | - | |
471 | -void OPPROTO op_shrl_T1_im(void) | |
472 | -{ | |
473 | - T1 = (uint32_t)T1 >> PARAM1; | |
474 | -} | |
475 | - | |
476 | -void OPPROTO op_sarl_T1_im(void) | |
477 | -{ | |
478 | - T1 = (int32_t)T1 >> PARAM1; | |
479 | -} | |
480 | - | |
481 | -void OPPROTO op_rorl_T1_im(void) | |
482 | -{ | |
483 | - int shift; | |
484 | - shift = PARAM1; | |
485 | - T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
486 | -} | |
487 | - | |
488 | -/* T1 based, set C flag */ | |
489 | -void OPPROTO op_shll_T1_im_cc(void) | |
490 | -{ | |
491 | - env->CF = (T1 >> (32 - PARAM1)) & 1; | |
492 | - T1 = T1 << PARAM1; | |
493 | -} | |
494 | - | |
495 | -void OPPROTO op_shrl_T1_im_cc(void) | |
496 | -{ | |
497 | - env->CF = (T1 >> (PARAM1 - 1)) & 1; | |
498 | - T1 = (uint32_t)T1 >> PARAM1; | |
499 | -} | |
500 | - | |
501 | -void OPPROTO op_sarl_T1_im_cc(void) | |
502 | -{ | |
503 | - env->CF = (T1 >> (PARAM1 - 1)) & 1; | |
504 | - T1 = (int32_t)T1 >> PARAM1; | |
505 | -} | |
506 | - | |
507 | -void OPPROTO op_rorl_T1_im_cc(void) | |
508 | -{ | |
509 | - int shift; | |
510 | - shift = PARAM1; | |
511 | - env->CF = (T1 >> (shift - 1)) & 1; | |
512 | - T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
513 | -} | |
514 | - | |
515 | -/* T2 based */ | |
516 | -void OPPROTO op_shll_T2_im(void) | |
517 | -{ | |
518 | - T2 = T2 << PARAM1; | |
519 | -} | |
520 | - | |
521 | -void OPPROTO op_shrl_T2_im(void) | |
522 | -{ | |
523 | - T2 = (uint32_t)T2 >> PARAM1; | |
524 | -} | |
525 | - | |
526 | -void OPPROTO op_sarl_T2_im(void) | |
527 | -{ | |
528 | - T2 = (int32_t)T2 >> PARAM1; | |
529 | -} | |
530 | - | |
531 | -void OPPROTO op_rorl_T2_im(void) | |
532 | -{ | |
533 | - int shift; | |
534 | - shift = PARAM1; | |
535 | - T2 = ((uint32_t)T2 >> shift) | (T2 << (32 - shift)); | |
536 | -} | |
537 | - | |
538 | -/* T1 based, use T0 as shift count */ | |
539 | - | |
540 | -void OPPROTO op_shll_T1_T0(void) | |
541 | -{ | |
542 | - int shift; | |
543 | - shift = T0 & 0xff; | |
544 | - if (shift >= 32) | |
545 | - T1 = 0; | |
546 | - else | |
547 | - T1 = T1 << shift; | |
548 | - FORCE_RET(); | |
549 | -} | |
550 | - | |
551 | -void OPPROTO op_shrl_T1_T0(void) | |
552 | -{ | |
553 | - int shift; | |
554 | - shift = T0 & 0xff; | |
555 | - if (shift >= 32) | |
556 | - T1 = 0; | |
557 | - else | |
558 | - T1 = (uint32_t)T1 >> shift; | |
559 | - FORCE_RET(); | |
560 | -} | |
561 | - | |
562 | -void OPPROTO op_sarl_T1_T0(void) | |
563 | -{ | |
564 | - int shift; | |
565 | - shift = T0 & 0xff; | |
566 | - if (shift >= 32) | |
567 | - shift = 31; | |
568 | - T1 = (int32_t)T1 >> shift; | |
569 | -} | |
570 | - | |
571 | -void OPPROTO op_rorl_T1_T0(void) | |
572 | -{ | |
573 | - int shift; | |
574 | - shift = T0 & 0x1f; | |
575 | - if (shift) { | |
576 | - T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
577 | - } | |
578 | - FORCE_RET(); | |
579 | -} | |
580 | - | |
581 | -/* T1 based, use T0 as shift count and compute CF */ | |
582 | - | |
583 | -void OPPROTO op_shll_T1_T0_cc(void) | |
584 | -{ | |
585 | - int shift; | |
586 | - shift = T0 & 0xff; | |
587 | - if (shift >= 32) { | |
588 | - if (shift == 32) | |
589 | - env->CF = T1 & 1; | |
590 | - else | |
591 | - env->CF = 0; | |
592 | - T1 = 0; | |
593 | - } else if (shift != 0) { | |
594 | - env->CF = (T1 >> (32 - shift)) & 1; | |
595 | - T1 = T1 << shift; | |
596 | - } | |
597 | - FORCE_RET(); | |
598 | -} | |
599 | - | |
600 | -void OPPROTO op_shrl_T1_T0_cc(void) | |
601 | -{ | |
602 | - int shift; | |
603 | - shift = T0 & 0xff; | |
604 | - if (shift >= 32) { | |
605 | - if (shift == 32) | |
606 | - env->CF = (T1 >> 31) & 1; | |
607 | - else | |
608 | - env->CF = 0; | |
609 | - T1 = 0; | |
610 | - } else if (shift != 0) { | |
611 | - env->CF = (T1 >> (shift - 1)) & 1; | |
612 | - T1 = (uint32_t)T1 >> shift; | |
613 | - } | |
614 | - FORCE_RET(); | |
615 | -} | |
616 | - | |
617 | -void OPPROTO op_sarl_T1_T0_cc(void) | |
618 | -{ | |
619 | - int shift; | |
620 | - shift = T0 & 0xff; | |
621 | - if (shift >= 32) { | |
622 | - env->CF = (T1 >> 31) & 1; | |
623 | - T1 = (int32_t)T1 >> 31; | |
624 | - } else { | |
625 | - env->CF = (T1 >> (shift - 1)) & 1; | |
626 | - T1 = (int32_t)T1 >> shift; | |
627 | - } | |
628 | - FORCE_RET(); | |
629 | -} | |
630 | - | |
631 | -void OPPROTO op_rorl_T1_T0_cc(void) | |
632 | -{ | |
633 | - int shift1, shift; | |
634 | - shift1 = T0 & 0xff; | |
635 | - shift = shift1 & 0x1f; | |
636 | - if (shift == 0) { | |
637 | - if (shift1 != 0) | |
638 | - env->CF = (T1 >> 31) & 1; | |
639 | - } else { | |
640 | - env->CF = (T1 >> (shift - 1)) & 1; | |
641 | - T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
642 | - } | |
643 | - FORCE_RET(); | |
644 | -} | |
645 | - | |
646 | -/* exceptions */ | |
647 | - | |
648 | -void OPPROTO op_swi(void) | |
649 | -{ | |
650 | - env->exception_index = EXCP_SWI; | |
651 | - cpu_loop_exit(); | |
652 | -} | |
653 | - | |
654 | -void OPPROTO op_undef_insn(void) | |
655 | -{ | |
656 | - env->exception_index = EXCP_UDEF; | |
657 | - cpu_loop_exit(); | |
658 | -} | |
659 | - | |
660 | -/* thread support */ | |
661 | - | |
662 | -spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; | |
663 | - | |
664 | -void cpu_lock(void) | |
665 | -{ | |
666 | - spin_lock(&global_cpu_lock); | |
667 | -} | |
668 | - | |
669 | -void cpu_unlock(void) | |
670 | -{ | |
671 | - spin_unlock(&global_cpu_lock); | |
672 | -} | |
673 | - |