blob: 2114d656d25e8059960f1d5cf82c4d8e5cc48756 [file] [log] [blame]
bellard7d132992003-03-06 23:23:54 +00001/*
2 * i386 emulator main execution loop
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 *
bellard3ef693a2003-03-23 20:17:16 +00006 * 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.
bellard7d132992003-03-06 23:23:54 +000010 *
bellard3ef693a2003-03-23 20:17:16 +000011 * 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.
bellard7d132992003-03-06 23:23:54 +000015 *
bellard3ef693a2003-03-23 20:17:16 +000016 * 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
bellard7d132992003-03-06 23:23:54 +000019 */
20#include "exec-i386.h"
bellard956034d2003-04-29 20:40:53 +000021#include "disas.h"
bellard7d132992003-03-06 23:23:54 +000022
bellarddc990652003-03-19 00:00:28 +000023//#define DEBUG_EXEC
bellard9de5e442003-03-23 16:49:39 +000024//#define DEBUG_SIGNAL
bellard7d132992003-03-06 23:23:54 +000025
26/* main execution loop */
27
bellard1b6b0292003-03-22 17:31:38 +000028/* thread support */
29
bellard25eb4482003-05-14 21:50:54 +000030spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
bellard1b6b0292003-03-22 17:31:38 +000031
32void cpu_lock(void)
33{
bellard25eb4482003-05-14 21:50:54 +000034 spin_lock(&global_cpu_lock);
bellard1b6b0292003-03-22 17:31:38 +000035}
36
37void cpu_unlock(void)
38{
bellard25eb4482003-05-14 21:50:54 +000039 spin_unlock(&global_cpu_lock);
bellard1b6b0292003-03-22 17:31:38 +000040}
41
bellarda513fe12003-05-27 23:29:48 +000042void cpu_loop_exit(void)
bellard9de5e442003-03-23 16:49:39 +000043{
44 /* NOTE: the register at this point must be saved by hand because
45 longjmp restore them */
bellardae228532003-05-13 18:59:59 +000046#ifdef __sparc__
47 /* We have to stay in the same register window as our caller,
48 * thus this trick.
49 */
50 __asm__ __volatile__("restore\n\t"
51 "mov\t%o0, %i0");
52#endif
bellard9de5e442003-03-23 16:49:39 +000053#ifdef reg_EAX
54 env->regs[R_EAX] = EAX;
55#endif
56#ifdef reg_ECX
57 env->regs[R_ECX] = ECX;
58#endif
59#ifdef reg_EDX
60 env->regs[R_EDX] = EDX;
61#endif
62#ifdef reg_EBX
63 env->regs[R_EBX] = EBX;
64#endif
65#ifdef reg_ESP
66 env->regs[R_ESP] = ESP;
67#endif
68#ifdef reg_EBP
69 env->regs[R_EBP] = EBP;
70#endif
71#ifdef reg_ESI
72 env->regs[R_ESI] = ESI;
73#endif
74#ifdef reg_EDI
75 env->regs[R_EDI] = EDI;
76#endif
bellard9de5e442003-03-23 16:49:39 +000077 longjmp(env->jmp_env, 1);
78}
79
bellard7d132992003-03-06 23:23:54 +000080int cpu_x86_exec(CPUX86State *env1)
81{
82 int saved_T0, saved_T1, saved_A0;
83 CPUX86State *saved_env;
bellard04369ff2003-03-20 22:33:23 +000084#ifdef reg_EAX
85 int saved_EAX;
86#endif
87#ifdef reg_ECX
88 int saved_ECX;
89#endif
90#ifdef reg_EDX
91 int saved_EDX;
92#endif
93#ifdef reg_EBX
94 int saved_EBX;
95#endif
96#ifdef reg_ESP
97 int saved_ESP;
98#endif
99#ifdef reg_EBP
100 int saved_EBP;
101#endif
102#ifdef reg_ESI
103 int saved_ESI;
104#endif
105#ifdef reg_EDI
106 int saved_EDI;
107#endif
bellarda513fe12003-05-27 23:29:48 +0000108 int code_gen_size, ret;
bellard7d132992003-03-06 23:23:54 +0000109 void (*gen_func)(void);
bellard9de5e442003-03-23 16:49:39 +0000110 TranslationBlock *tb, **ptb;
bellarddab2ed92003-03-22 15:23:14 +0000111 uint8_t *tc_ptr, *cs_base, *pc;
bellard6dbad632003-03-16 18:05:05 +0000112 unsigned int flags;
bellardd4e81642003-05-25 16:46:15 +0000113
bellard7d132992003-03-06 23:23:54 +0000114 /* first we save global registers */
115 saved_T0 = T0;
116 saved_T1 = T1;
117 saved_A0 = A0;
118 saved_env = env;
119 env = env1;
bellard04369ff2003-03-20 22:33:23 +0000120#ifdef reg_EAX
121 saved_EAX = EAX;
122 EAX = env->regs[R_EAX];
123#endif
124#ifdef reg_ECX
125 saved_ECX = ECX;
126 ECX = env->regs[R_ECX];
127#endif
128#ifdef reg_EDX
129 saved_EDX = EDX;
130 EDX = env->regs[R_EDX];
131#endif
132#ifdef reg_EBX
133 saved_EBX = EBX;
134 EBX = env->regs[R_EBX];
135#endif
136#ifdef reg_ESP
137 saved_ESP = ESP;
138 ESP = env->regs[R_ESP];
139#endif
140#ifdef reg_EBP
141 saved_EBP = EBP;
142 EBP = env->regs[R_EBP];
143#endif
144#ifdef reg_ESI
145 saved_ESI = ESI;
146 ESI = env->regs[R_ESI];
147#endif
148#ifdef reg_EDI
149 saved_EDI = EDI;
150 EDI = env->regs[R_EDI];
151#endif
bellard7d132992003-03-06 23:23:54 +0000152
bellard9de5e442003-03-23 16:49:39 +0000153 /* put eflags in CPU temporary format */
bellardfc2b4c42003-03-29 16:52:44 +0000154 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
155 DF = 1 - (2 * ((env->eflags >> 10) & 1));
bellard9de5e442003-03-23 16:49:39 +0000156 CC_OP = CC_OP_EFLAGS;
bellardfc2b4c42003-03-29 16:52:44 +0000157 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard9de5e442003-03-23 16:49:39 +0000158 env->interrupt_request = 0;
bellard9d27abd2003-05-10 13:13:54 +0000159
bellard7d132992003-03-06 23:23:54 +0000160 /* prepare setjmp context for exception handling */
161 if (setjmp(env->jmp_env) == 0) {
bellardd4e81642003-05-25 16:46:15 +0000162 T0 = 0; /* force lookup of first TB */
bellard7d132992003-03-06 23:23:54 +0000163 for(;;) {
bellard9de5e442003-03-23 16:49:39 +0000164 if (env->interrupt_request) {
bellarda513fe12003-05-27 23:29:48 +0000165 env->exception_index = EXCP_INTERRUPT;
166 cpu_loop_exit();
bellard9de5e442003-03-23 16:49:39 +0000167 }
bellard7d132992003-03-06 23:23:54 +0000168#ifdef DEBUG_EXEC
169 if (loglevel) {
bellard9d27abd2003-05-10 13:13:54 +0000170 /* XXX: save all volatile state in cpu state */
171 /* restore flags in standard format */
172 env->regs[R_EAX] = EAX;
173 env->regs[R_EBX] = EBX;
174 env->regs[R_ECX] = ECX;
175 env->regs[R_EDX] = EDX;
176 env->regs[R_ESI] = ESI;
177 env->regs[R_EDI] = EDI;
178 env->regs[R_EBP] = EBP;
179 env->regs[R_ESP] = ESP;
180 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
181 cpu_x86_dump_state(env, logfile, 0);
182 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
bellard7d132992003-03-06 23:23:54 +0000183 }
184#endif
bellard6dbad632003-03-16 18:05:05 +0000185 /* we compute the CPU state. We assume it will not
186 change during the whole generated block. */
187 flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
bellarddab2ed92003-03-22 15:23:14 +0000188 flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
bellard6dbad632003-03-16 18:05:05 +0000189 flags |= (((unsigned long)env->seg_cache[R_DS].base |
190 (unsigned long)env->seg_cache[R_ES].base |
191 (unsigned long)env->seg_cache[R_SS].base) != 0) <<
192 GEN_FLAG_ADDSEG_SHIFT;
bellard9d27abd2003-05-10 13:13:54 +0000193 if (!(env->eflags & VM_MASK)) {
194 flags |= (env->segs[R_CS] & 3) << GEN_FLAG_CPL_SHIFT;
195 } else {
196 /* NOTE: a dummy CPL is kept */
197 flags |= (1 << GEN_FLAG_VM_SHIFT);
198 flags |= (3 << GEN_FLAG_CPL_SHIFT);
199 }
bellardcf256292003-05-25 19:20:31 +0000200 flags |= (env->eflags & (IOPL_MASK | TF_MASK));
bellarddab2ed92003-03-22 15:23:14 +0000201 cs_base = env->seg_cache[R_CS].base;
202 pc = cs_base + env->eip;
bellard9de5e442003-03-23 16:49:39 +0000203 tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
204 flags);
205 if (!tb) {
bellardcf256292003-05-25 19:20:31 +0000206 spin_lock(&tb_lock);
bellard7d132992003-03-06 23:23:54 +0000207 /* if no translated code available, then translate it now */
bellardd4e81642003-05-25 16:46:15 +0000208 tb = tb_alloc((unsigned long)pc);
209 if (!tb) {
210 /* flush must be done */
211 tb_flush();
212 /* cannot fail at this point */
213 tb = tb_alloc((unsigned long)pc);
214 /* don't forget to invalidate previous TB info */
215 ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
216 T0 = 0;
217 }
bellard7d132992003-03-06 23:23:54 +0000218 tc_ptr = code_gen_ptr;
bellardd4e81642003-05-25 16:46:15 +0000219 tb->tc_ptr = tc_ptr;
bellarda513fe12003-05-27 23:29:48 +0000220 tb->cs_base = (unsigned long)cs_base;
221 tb->flags = flags;
222 ret = cpu_x86_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
bellard9de5e442003-03-23 16:49:39 +0000223 /* if invalid instruction, signal it */
224 if (ret != 0) {
bellardd4e81642003-05-25 16:46:15 +0000225 /* NOTE: the tb is allocated but not linked, so we
226 can leave it */
bellard25eb4482003-05-14 21:50:54 +0000227 spin_unlock(&tb_lock);
bellard9de5e442003-03-23 16:49:39 +0000228 raise_exception(EXCP06_ILLOP);
229 }
bellard9de5e442003-03-23 16:49:39 +0000230 *ptb = tb;
bellard9de5e442003-03-23 16:49:39 +0000231 tb->hash_next = NULL;
bellardd4e81642003-05-25 16:46:15 +0000232 tb_link(tb);
bellard7d132992003-03-06 23:23:54 +0000233 code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
bellardcf256292003-05-25 19:20:31 +0000234 spin_unlock(&tb_lock);
bellard7d132992003-03-06 23:23:54 +0000235 }
bellard9d27abd2003-05-10 13:13:54 +0000236#ifdef DEBUG_EXEC
bellard956034d2003-04-29 20:40:53 +0000237 if (loglevel) {
238 fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
239 (long)tb->tc_ptr, (long)tb->pc,
240 lookup_symbol((void *)tb->pc));
bellard956034d2003-04-29 20:40:53 +0000241 }
bellard9d27abd2003-05-10 13:13:54 +0000242#endif
bellardd4e81642003-05-25 16:46:15 +0000243 /* see if we can patch the calling TB */
244 if (T0 != 0 && !(env->eflags & TF_MASK)) {
bellardcf256292003-05-25 19:20:31 +0000245 spin_lock(&tb_lock);
bellardd4e81642003-05-25 16:46:15 +0000246 tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
bellardcf256292003-05-25 19:20:31 +0000247 spin_unlock(&tb_lock);
bellardd4e81642003-05-25 16:46:15 +0000248 }
bellardcf256292003-05-25 19:20:31 +0000249
bellard9de5e442003-03-23 16:49:39 +0000250 tc_ptr = tb->tc_ptr;
bellardd4e81642003-05-25 16:46:15 +0000251
252 /* execute the generated code */
bellard7d132992003-03-06 23:23:54 +0000253 gen_func = (void *)tc_ptr;
bellardae228532003-05-13 18:59:59 +0000254#ifdef __sparc__
255 __asm__ __volatile__("call %0\n\t"
256 " mov %%o7,%%i0"
257 : /* no outputs */
bellardd4e81642003-05-25 16:46:15 +0000258 : "r" (gen_func)
bellardae228532003-05-13 18:59:59 +0000259 : "i0", "i1", "i2", "i3", "i4", "i5");
260#else
bellard7d132992003-03-06 23:23:54 +0000261 gen_func();
bellardae228532003-05-13 18:59:59 +0000262#endif
bellard7d132992003-03-06 23:23:54 +0000263 }
264 }
265 ret = env->exception_index;
266
bellard9de5e442003-03-23 16:49:39 +0000267 /* restore flags in standard format */
bellardfc2b4c42003-03-29 16:52:44 +0000268 env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
bellard9de5e442003-03-23 16:49:39 +0000269
bellard7d132992003-03-06 23:23:54 +0000270 /* restore global registers */
bellard04369ff2003-03-20 22:33:23 +0000271#ifdef reg_EAX
272 EAX = saved_EAX;
273#endif
274#ifdef reg_ECX
275 ECX = saved_ECX;
276#endif
277#ifdef reg_EDX
278 EDX = saved_EDX;
279#endif
280#ifdef reg_EBX
281 EBX = saved_EBX;
282#endif
283#ifdef reg_ESP
284 ESP = saved_ESP;
285#endif
286#ifdef reg_EBP
287 EBP = saved_EBP;
288#endif
289#ifdef reg_ESI
290 ESI = saved_ESI;
291#endif
292#ifdef reg_EDI
293 EDI = saved_EDI;
294#endif
bellard7d132992003-03-06 23:23:54 +0000295 T0 = saved_T0;
296 T1 = saved_T1;
297 A0 = saved_A0;
298 env = saved_env;
299 return ret;
300}
bellard6dbad632003-03-16 18:05:05 +0000301
bellard9de5e442003-03-23 16:49:39 +0000302void cpu_x86_interrupt(CPUX86State *s)
303{
304 s->interrupt_request = 1;
305}
306
307
bellard6dbad632003-03-16 18:05:05 +0000308void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
309{
310 CPUX86State *saved_env;
311
312 saved_env = env;
313 env = s;
bellarda513fe12003-05-27 23:29:48 +0000314 if (env->eflags & VM_MASK) {
315 SegmentCache *sc;
316 selector &= 0xffff;
317 sc = &env->seg_cache[seg_reg];
318 /* NOTE: in VM86 mode, limit and seg_32bit are never reloaded,
319 so we must load them here */
320 sc->base = (void *)(selector << 4);
321 sc->limit = 0xffff;
322 sc->seg_32bit = 0;
323 env->segs[seg_reg] = selector;
324 } else {
325 load_seg(seg_reg, selector, 0);
326 }
bellard6dbad632003-03-16 18:05:05 +0000327 env = saved_env;
328}
bellard9de5e442003-03-23 16:49:39 +0000329
bellardd0a1ffc2003-05-29 20:04:28 +0000330void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
331{
332 CPUX86State *saved_env;
333
334 saved_env = env;
335 env = s;
336
337 helper_fsave(ptr, data32);
338
339 env = saved_env;
340}
341
342void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
343{
344 CPUX86State *saved_env;
345
346 saved_env = env;
347 env = s;
348
349 helper_frstor(ptr, data32);
350
351 env = saved_env;
352}
353
bellard9de5e442003-03-23 16:49:39 +0000354#undef EAX
355#undef ECX
356#undef EDX
357#undef EBX
358#undef ESP
359#undef EBP
360#undef ESI
361#undef EDI
362#undef EIP
363#include <signal.h>
364#include <sys/ucontext.h>
365
bellardb56dad12003-05-08 15:38:04 +0000366/* 'pc' is the host PC at which the exception was raised. 'address' is
bellardfd6ce8f2003-05-14 19:00:11 +0000367 the effective address of the memory exception. 'is_write' is 1 if a
368 write caused the exception and otherwise 0'. 'old_set' is the
369 signal set which should be restored */
bellard2b413142003-05-14 23:01:10 +0000370static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
371 int is_write, sigset_t *old_set)
bellard9de5e442003-03-23 16:49:39 +0000372{
bellarda513fe12003-05-27 23:29:48 +0000373 TranslationBlock *tb;
374 int ret;
375 uint32_t found_pc;
376
bellardfd6ce8f2003-05-14 19:00:11 +0000377#if defined(DEBUG_SIGNAL)
378 printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n",
379 pc, address, is_write, *(unsigned long *)old_set);
bellard9de5e442003-03-23 16:49:39 +0000380#endif
bellard25eb4482003-05-14 21:50:54 +0000381 /* XXX: locking issue */
bellardfd6ce8f2003-05-14 19:00:11 +0000382 if (is_write && page_unprotect(address)) {
bellardfd6ce8f2003-05-14 19:00:11 +0000383 return 1;
384 }
bellarda513fe12003-05-27 23:29:48 +0000385 tb = tb_find_pc(pc);
386 if (tb) {
bellard9de5e442003-03-23 16:49:39 +0000387 /* the PC is inside the translated code. It means that we have
388 a virtual CPU fault */
bellarda513fe12003-05-27 23:29:48 +0000389 ret = cpu_x86_search_pc(tb, &found_pc, pc);
390 if (ret < 0)
391 return 0;
392 env->eip = found_pc - tb->cs_base;
bellardb56dad12003-05-08 15:38:04 +0000393 env->cr2 = address;
bellarda513fe12003-05-27 23:29:48 +0000394 /* we restore the process signal mask as the sigreturn should
395 do it (XXX: use sigsetjmp) */
396 sigprocmask(SIG_SETMASK, old_set, NULL);
bellardfd6ce8f2003-05-14 19:00:11 +0000397 raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1));
bellard9de5e442003-03-23 16:49:39 +0000398 /* never comes here */
399 return 1;
400 } else {
401 return 0;
402 }
403}
404
bellard2b413142003-05-14 23:01:10 +0000405#if defined(__i386__)
406
bellard9de5e442003-03-23 16:49:39 +0000407int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
408 void *puc)
409{
bellard9de5e442003-03-23 16:49:39 +0000410 struct ucontext *uc = puc;
411 unsigned long pc;
bellard9de5e442003-03-23 16:49:39 +0000412
bellardd691f662003-03-24 21:58:34 +0000413#ifndef REG_EIP
414/* for glibc 2.1 */
bellardfd6ce8f2003-05-14 19:00:11 +0000415#define REG_EIP EIP
416#define REG_ERR ERR
417#define REG_TRAPNO TRAPNO
bellardd691f662003-03-24 21:58:34 +0000418#endif
bellardfc2b4c42003-03-29 16:52:44 +0000419 pc = uc->uc_mcontext.gregs[REG_EIP];
bellardfd6ce8f2003-05-14 19:00:11 +0000420 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
421 uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
422 (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
bellard2b413142003-05-14 23:01:10 +0000423 &uc->uc_sigmask);
424}
425
bellard25eb4482003-05-14 21:50:54 +0000426#elif defined(__powerpc)
bellard2b413142003-05-14 23:01:10 +0000427
428int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
429 void *puc)
430{
bellard25eb4482003-05-14 21:50:54 +0000431 struct ucontext *uc = puc;
432 struct pt_regs *regs = uc->uc_mcontext.regs;
433 unsigned long pc;
bellard25eb4482003-05-14 21:50:54 +0000434 int is_write;
435
436 pc = regs->nip;
bellard25eb4482003-05-14 21:50:54 +0000437 is_write = 0;
438#if 0
439 /* ppc 4xx case */
440 if (regs->dsisr & 0x00800000)
441 is_write = 1;
bellard9de5e442003-03-23 16:49:39 +0000442#else
bellard25eb4482003-05-14 21:50:54 +0000443 if (regs->trap != 0x400 && (regs->dsisr & 0x02000000))
444 is_write = 1;
445#endif
446 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
bellard2b413142003-05-14 23:01:10 +0000447 is_write, &uc->uc_sigmask);
bellard9de5e442003-03-23 16:49:39 +0000448}
bellard2b413142003-05-14 23:01:10 +0000449
450#else
451
452#error CPU specific signal handler needed
453
454#endif