exec-i386.c 10.9 KB
Newer Older
B
bellard 已提交
1 2 3 4 5
/*
 *  i386 emulator main execution loop
 * 
 *  Copyright (c) 2003 Fabrice Bellard
 *
B
bellard 已提交
6 7 8 9
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
B
bellard 已提交
10
 *
B
bellard 已提交
11 12 13 14
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
B
bellard 已提交
15
 *
B
bellard 已提交
16 17 18
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
B
bellard 已提交
19 20
 */
#include "exec-i386.h"
B
log fix  
bellard 已提交
21
#include "disas.h"
B
bellard 已提交
22

B
bellard 已提交
23
//#define DEBUG_EXEC
B
bellard 已提交
24
//#define DEBUG_SIGNAL
B
bellard 已提交
25 26 27

/* main execution loop */

B
bellard 已提交
28 29
/* thread support */

30
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
B
bellard 已提交
31 32 33

void cpu_lock(void)
{
34
    spin_lock(&global_cpu_lock);
B
bellard 已提交
35 36 37 38
}

void cpu_unlock(void)
{
39
    spin_unlock(&global_cpu_lock);
B
bellard 已提交
40 41
}

B
bellard 已提交
42 43
/* exception support */
/* NOTE: not static to force relocation generation by GCC */
44
void raise_exception_err(int exception_index, int error_code)
B
bellard 已提交
45 46 47
{
    /* NOTE: the register at this point must be saved by hand because
       longjmp restore them */
B
bellard 已提交
48 49 50 51 52 53 54
#ifdef __sparc__
	/* We have to stay in the same register window as our caller,
	 * thus this trick.
	 */
	__asm__ __volatile__("restore\n\t"
			     "mov\t%o0, %i0");
#endif
B
bellard 已提交
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
#ifdef reg_EAX
    env->regs[R_EAX] = EAX;
#endif
#ifdef reg_ECX
    env->regs[R_ECX] = ECX;
#endif
#ifdef reg_EDX
    env->regs[R_EDX] = EDX;
#endif
#ifdef reg_EBX
    env->regs[R_EBX] = EBX;
#endif
#ifdef reg_ESP
    env->regs[R_ESP] = ESP;
#endif
#ifdef reg_EBP
    env->regs[R_EBP] = EBP;
#endif
#ifdef reg_ESI
    env->regs[R_ESI] = ESI;
#endif
#ifdef reg_EDI
    env->regs[R_EDI] = EDI;
#endif
    env->exception_index = exception_index;
80
    env->error_code = error_code;
B
bellard 已提交
81 82 83
    longjmp(env->jmp_env, 1);
}

84 85 86 87 88 89
/* short cut if error_code is 0 or not present */
void raise_exception(int exception_index)
{
    raise_exception_err(exception_index, 0);
}

B
bellard 已提交
90 91 92 93
int cpu_x86_exec(CPUX86State *env1)
{
    int saved_T0, saved_T1, saved_A0;
    CPUX86State *saved_env;
B
bellard 已提交
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
#ifdef reg_EAX
    int saved_EAX;
#endif
#ifdef reg_ECX
    int saved_ECX;
#endif
#ifdef reg_EDX
    int saved_EDX;
#endif
#ifdef reg_EBX
    int saved_EBX;
#endif
#ifdef reg_ESP
    int saved_ESP;
#endif
#ifdef reg_EBP
    int saved_EBP;
#endif
#ifdef reg_ESI
    int saved_ESI;
#endif
#ifdef reg_EDI
    int saved_EDI;
#endif
B
bellard 已提交
118
    int code_gen_size, ret, code_size;
B
bellard 已提交
119
    void (*gen_func)(void);
B
bellard 已提交
120
    TranslationBlock *tb, **ptb;
B
bellard 已提交
121
    uint8_t *tc_ptr, *cs_base, *pc;
B
bellard 已提交
122 123
    unsigned int flags;

B
bellard 已提交
124 125 126 127 128 129
    /* first we save global registers */
    saved_T0 = T0;
    saved_T1 = T1;
    saved_A0 = A0;
    saved_env = env;
    env = env1;
B
bellard 已提交
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
#ifdef reg_EAX
    saved_EAX = EAX;
    EAX = env->regs[R_EAX];
#endif
#ifdef reg_ECX
    saved_ECX = ECX;
    ECX = env->regs[R_ECX];
#endif
#ifdef reg_EDX
    saved_EDX = EDX;
    EDX = env->regs[R_EDX];
#endif
#ifdef reg_EBX
    saved_EBX = EBX;
    EBX = env->regs[R_EBX];
#endif
#ifdef reg_ESP
    saved_ESP = ESP;
    ESP = env->regs[R_ESP];
#endif
#ifdef reg_EBP
    saved_EBP = EBP;
    EBP = env->regs[R_EBP];
#endif
#ifdef reg_ESI
    saved_ESI = ESI;
    ESI = env->regs[R_ESI];
#endif
#ifdef reg_EDI
    saved_EDI = EDI;
    EDI = env->regs[R_EDI];
#endif
B
bellard 已提交
162
    
B
bellard 已提交
163
    /* put eflags in CPU temporary format */
B
bellard 已提交
164 165
    CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
    DF = 1 - (2 * ((env->eflags >> 10) & 1));
B
bellard 已提交
166
    CC_OP = CC_OP_EFLAGS;
B
bellard 已提交
167
    env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
B
bellard 已提交
168
    env->interrupt_request = 0;
169

B
bellard 已提交
170 171 172
    /* prepare setjmp context for exception handling */
    if (setjmp(env->jmp_env) == 0) {
        for(;;) {
B
bellard 已提交
173 174 175
            if (env->interrupt_request) {
                raise_exception(EXCP_INTERRUPT);
            }
B
bellard 已提交
176 177
#ifdef DEBUG_EXEC
            if (loglevel) {
178 179 180 181 182 183 184 185 186 187 188 189 190
                /* XXX: save all volatile state in cpu state */
                /* restore flags in standard format */
                env->regs[R_EAX] = EAX;
                env->regs[R_EBX] = EBX;
                env->regs[R_ECX] = ECX;
                env->regs[R_EDX] = EDX;
                env->regs[R_ESI] = ESI;
                env->regs[R_EDI] = EDI;
                env->regs[R_EBP] = EBP;
                env->regs[R_ESP] = ESP;
                env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
                cpu_x86_dump_state(env, logfile, 0);
                env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
B
bellard 已提交
191 192
            }
#endif
B
bellard 已提交
193 194 195
            /* we compute the CPU state. We assume it will not
               change during the whole generated block. */
            flags = env->seg_cache[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
B
bellard 已提交
196
            flags |= env->seg_cache[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
B
bellard 已提交
197 198 199 200
            flags |= (((unsigned long)env->seg_cache[R_DS].base | 
                       (unsigned long)env->seg_cache[R_ES].base |
                       (unsigned long)env->seg_cache[R_SS].base) != 0) << 
                GEN_FLAG_ADDSEG_SHIFT;
201 202 203 204 205 206 207
            if (!(env->eflags & VM_MASK)) {
                flags |= (env->segs[R_CS] & 3) << GEN_FLAG_CPL_SHIFT;
            } else {
                /* NOTE: a dummy CPL is kept */
                flags |= (1 << GEN_FLAG_VM_SHIFT);
                flags |= (3 << GEN_FLAG_CPL_SHIFT);
            }
208
            flags |= (env->eflags & IOPL_MASK) >> (12 - GEN_FLAG_IOPL_SHIFT);
B
bellard 已提交
209
            flags |= (env->eflags & TF_MASK) << (GEN_FLAG_TF_SHIFT - 8);
B
bellard 已提交
210 211
            cs_base = env->seg_cache[R_CS].base;
            pc = cs_base + env->eip;
B
bellard 已提交
212 213 214
            tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, 
                         flags);
            if (!tb) {
B
bellard 已提交
215
                /* if no translated code available, then translate it now */
216 217 218
                /* very inefficient but safe: we lock all the cpus
                   when generating code */
                spin_lock(&tb_lock);
B
bellard 已提交
219
                tc_ptr = code_gen_ptr;
B
bellard 已提交
220
                ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 
B
bellard 已提交
221 222
                                       &code_gen_size, pc, cs_base, flags,
                                       &code_size);
B
bellard 已提交
223 224
                /* if invalid instruction, signal it */
                if (ret != 0) {
225
                    spin_unlock(&tb_lock);
B
bellard 已提交
226 227
                    raise_exception(EXCP06_ILLOP);
                }
B
bellard 已提交
228
                tb = tb_alloc((unsigned long)pc, code_size);
B
bellard 已提交
229 230 231
                *ptb = tb;
                tb->cs_base = (unsigned long)cs_base;
                tb->flags = flags;
B
bellard 已提交
232
                tb->tc_ptr = tc_ptr;
B
bellard 已提交
233
                tb->hash_next = NULL;
B
bellard 已提交
234
                code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
235
                spin_unlock(&tb_lock);
B
bellard 已提交
236
            }
237
#ifdef DEBUG_EXEC
B
log fix  
bellard 已提交
238 239 240 241 242
	    if (loglevel) {
		fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n",
			(long)tb->tc_ptr, (long)tb->pc,
			lookup_symbol((void *)tb->pc));
	    }
243
#endif
B
bellard 已提交
244
            /* execute the generated code */
B
bellard 已提交
245
            tc_ptr = tb->tc_ptr;
B
bellard 已提交
246
            gen_func = (void *)tc_ptr;
B
bellard 已提交
247 248 249 250 251 252 253
#ifdef __sparc__
	    __asm__ __volatile__("call	%0\n\t"
				 " mov	%%o7,%%i0"
				 : /* no outputs */
				 : "r" (gen_func)
				 : "i0", "i1", "i2", "i3", "i4", "i5");
#else
B
bellard 已提交
254
            gen_func();
B
bellard 已提交
255
#endif
B
bellard 已提交
256 257 258 259
        }
    }
    ret = env->exception_index;

B
bellard 已提交
260
    /* restore flags in standard format */
B
bellard 已提交
261
    env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
B
bellard 已提交
262

B
bellard 已提交
263
    /* restore global registers */
B
bellard 已提交
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
#ifdef reg_EAX
    EAX = saved_EAX;
#endif
#ifdef reg_ECX
    ECX = saved_ECX;
#endif
#ifdef reg_EDX
    EDX = saved_EDX;
#endif
#ifdef reg_EBX
    EBX = saved_EBX;
#endif
#ifdef reg_ESP
    ESP = saved_ESP;
#endif
#ifdef reg_EBP
    EBP = saved_EBP;
#endif
#ifdef reg_ESI
    ESI = saved_ESI;
#endif
#ifdef reg_EDI
    EDI = saved_EDI;
#endif
B
bellard 已提交
288 289 290 291 292 293
    T0 = saved_T0;
    T1 = saved_T1;
    A0 = saved_A0;
    env = saved_env;
    return ret;
}
B
bellard 已提交
294

B
bellard 已提交
295 296 297 298 299 300
void cpu_x86_interrupt(CPUX86State *s)
{
    s->interrupt_request = 1;
}


B
bellard 已提交
301 302 303 304 305 306 307 308 309
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
    CPUX86State *saved_env;

    saved_env = env;
    env = s;
    load_seg(seg_reg, selector);
    env = saved_env;
}
B
bellard 已提交
310 311 312 313 314 315 316 317 318 319 320 321 322

#undef EAX
#undef ECX
#undef EDX
#undef EBX
#undef ESP
#undef EBP
#undef ESI
#undef EDI
#undef EIP
#include <signal.h>
#include <sys/ucontext.h>

323
/* 'pc' is the host PC at which the exception was raised. 'address' is
B
bellard 已提交
324 325 326
   the effective address of the memory exception. 'is_write' is 1 if a
   write caused the exception and otherwise 0'. 'old_set' is the
   signal set which should be restored */
B
bellard 已提交
327 328
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
                                    int is_write, sigset_t *old_set)
B
bellard 已提交
329
{
B
bellard 已提交
330 331 332
#if defined(DEBUG_SIGNAL)
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", 
           pc, address, is_write, *(unsigned long *)old_set);
B
bellard 已提交
333
#endif
334
    /* XXX: locking issue */
B
bellard 已提交
335 336 337
    if (is_write && page_unprotect(address)) {
        return 1;
    }
B
bellard 已提交
338 339 340 341 342 343 344 345 346
    if (pc >= (unsigned long)code_gen_buffer &&
        pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
        /* the PC is inside the translated code. It means that we have
           a virtual CPU fault */
        /* we restore the process signal mask as the sigreturn should
           do it */
        sigprocmask(SIG_SETMASK, old_set, NULL);
        /* XXX: need to compute virtual pc position by retranslating
           code. The rest of the CPU state should be correct. */
347
        env->cr2 = address;
B
bellard 已提交
348
        raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1));
B
bellard 已提交
349 350 351 352 353 354 355
        /* never comes here */
        return 1;
    } else {
        return 0;
    }
}

B
bellard 已提交
356 357
#if defined(__i386__)

B
bellard 已提交
358 359 360 361 362 363
int cpu_x86_signal_handler(int host_signum, struct siginfo *info, 
                           void *puc)
{
    struct ucontext *uc = puc;
    unsigned long pc;
    
364 365
#ifndef REG_EIP
/* for glibc 2.1 */
B
bellard 已提交
366 367 368
#define REG_EIP    EIP
#define REG_ERR    ERR
#define REG_TRAPNO TRAPNO
369
#endif
B
bellard 已提交
370
    pc = uc->uc_mcontext.gregs[REG_EIP];
B
bellard 已提交
371 372 373
    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
                             uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ? 
                             (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
B
bellard 已提交
374 375 376
                             &uc->uc_sigmask);
}

377
#elif defined(__powerpc)
B
bellard 已提交
378 379 380 381

int cpu_x86_signal_handler(int host_signum, struct siginfo *info, 
                           void *puc)
{
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
    struct ucontext *uc = puc;
    struct pt_regs *regs = uc->uc_mcontext.regs;
    unsigned long pc;
    int is_write;

    pc = regs->nip;
    is_write = 0;
#if 0
    /* ppc 4xx case */
    if (regs->dsisr & 0x00800000)
        is_write = 1;
#else
    if (regs->trap != 0x400 && (regs->dsisr & 0x02000000))
        is_write = 1;
#endif
    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
B
bellard 已提交
398 399 400
                             is_write, &uc->uc_sigmask);
}

B
bellard 已提交
401
#else
B
bellard 已提交
402

403
#error CPU specific signal handler needed
B
bellard 已提交
404

B
bellard 已提交
405
#endif