precise exceptions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@194 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
		
							parent
							
								
									f4beb510a4
								
							
						
					
					
						commit
						a513fe19ac
					
				
							
								
								
									
										4
									
								
								dyngen.c
								
								
								
								
							
							
						
						
									
										4
									
								
								dyngen.c
								
								
								
								
							| 
						 | 
					@ -451,7 +451,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (gen_switch == 2) {
 | 
					    if (gen_switch == 2) {
 | 
				
			||||||
        fprintf(outfile, "DEF(%s, %d)\n", name + 3, nb_args);
 | 
					        fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size);
 | 
				
			||||||
    } else if (gen_switch == 1) {
 | 
					    } else if (gen_switch == 1) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* output C code */
 | 
					        /* output C code */
 | 
				
			||||||
| 
						 | 
					@ -991,7 +991,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (do_print_enum) {
 | 
					    if (do_print_enum) {
 | 
				
			||||||
        fprintf(outfile, "DEF(end, 0)\n");
 | 
					        fprintf(outfile, "DEF(end, 0, 0)\n");
 | 
				
			||||||
        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
 | 
					        for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
 | 
				
			||||||
            const char *name, *p;
 | 
					            const char *name, *p;
 | 
				
			||||||
            name = strtab + sym->st_name;
 | 
					            name = strtab + sym->st_name;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										60
									
								
								exec-i386.c
								
								
								
								
							
							
						
						
									
										60
									
								
								exec-i386.c
								
								
								
								
							| 
						 | 
					@ -39,9 +39,7 @@ void cpu_unlock(void)
 | 
				
			||||||
    spin_unlock(&global_cpu_lock);
 | 
					    spin_unlock(&global_cpu_lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* exception support */
 | 
					void cpu_loop_exit(void)
 | 
				
			||||||
/* NOTE: not static to force relocation generation by GCC */
 | 
					 | 
				
			||||||
void raise_exception_err(int exception_index, int error_code)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /* NOTE: the register at this point must be saved by hand because
 | 
					    /* NOTE: the register at this point must be saved by hand because
 | 
				
			||||||
       longjmp restore them */
 | 
					       longjmp restore them */
 | 
				
			||||||
| 
						 | 
					@ -76,17 +74,9 @@ void raise_exception_err(int exception_index, int error_code)
 | 
				
			||||||
#ifdef reg_EDI
 | 
					#ifdef reg_EDI
 | 
				
			||||||
    env->regs[R_EDI] = EDI;
 | 
					    env->regs[R_EDI] = EDI;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    env->exception_index = exception_index;
 | 
					 | 
				
			||||||
    env->error_code = error_code;
 | 
					 | 
				
			||||||
    longjmp(env->jmp_env, 1);
 | 
					    longjmp(env->jmp_env, 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* short cut if error_code is 0 or not present */
 | 
					 | 
				
			||||||
void raise_exception(int exception_index)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    raise_exception_err(exception_index, 0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int cpu_x86_exec(CPUX86State *env1)
 | 
					int cpu_x86_exec(CPUX86State *env1)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int saved_T0, saved_T1, saved_A0;
 | 
					    int saved_T0, saved_T1, saved_A0;
 | 
				
			||||||
| 
						 | 
					@ -115,7 +105,7 @@ int cpu_x86_exec(CPUX86State *env1)
 | 
				
			||||||
#ifdef reg_EDI
 | 
					#ifdef reg_EDI
 | 
				
			||||||
    int saved_EDI;
 | 
					    int saved_EDI;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    int code_gen_size, ret, code_size;
 | 
					    int code_gen_size, ret;
 | 
				
			||||||
    void (*gen_func)(void);
 | 
					    void (*gen_func)(void);
 | 
				
			||||||
    TranslationBlock *tb, **ptb;
 | 
					    TranslationBlock *tb, **ptb;
 | 
				
			||||||
    uint8_t *tc_ptr, *cs_base, *pc;
 | 
					    uint8_t *tc_ptr, *cs_base, *pc;
 | 
				
			||||||
| 
						 | 
					@ -172,7 +162,8 @@ int cpu_x86_exec(CPUX86State *env1)
 | 
				
			||||||
        T0 = 0; /* force lookup of first TB */
 | 
					        T0 = 0; /* force lookup of first TB */
 | 
				
			||||||
        for(;;) {
 | 
					        for(;;) {
 | 
				
			||||||
            if (env->interrupt_request) {
 | 
					            if (env->interrupt_request) {
 | 
				
			||||||
                raise_exception(EXCP_INTERRUPT);
 | 
					                env->exception_index = EXCP_INTERRUPT;
 | 
				
			||||||
 | 
					                cpu_loop_exit();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
#ifdef DEBUG_EXEC
 | 
					#ifdef DEBUG_EXEC
 | 
				
			||||||
            if (loglevel) {
 | 
					            if (loglevel) {
 | 
				
			||||||
| 
						 | 
					@ -226,9 +217,9 @@ int cpu_x86_exec(CPUX86State *env1)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                tc_ptr = code_gen_ptr;
 | 
					                tc_ptr = code_gen_ptr;
 | 
				
			||||||
                tb->tc_ptr = tc_ptr;
 | 
					                tb->tc_ptr = tc_ptr;
 | 
				
			||||||
                ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 
 | 
					                tb->cs_base = (unsigned long)cs_base;
 | 
				
			||||||
                                       &code_gen_size, pc, cs_base, flags,
 | 
					                tb->flags = flags;
 | 
				
			||||||
                                       &code_size, tb);
 | 
					                ret = cpu_x86_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
 | 
				
			||||||
                /* if invalid instruction, signal it */
 | 
					                /* if invalid instruction, signal it */
 | 
				
			||||||
                if (ret != 0) {
 | 
					                if (ret != 0) {
 | 
				
			||||||
                    /* NOTE: the tb is allocated but not linked, so we
 | 
					                    /* NOTE: the tb is allocated but not linked, so we
 | 
				
			||||||
| 
						 | 
					@ -237,9 +228,6 @@ int cpu_x86_exec(CPUX86State *env1)
 | 
				
			||||||
                    raise_exception(EXCP06_ILLOP);
 | 
					                    raise_exception(EXCP06_ILLOP);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                *ptb = tb;
 | 
					                *ptb = tb;
 | 
				
			||||||
                tb->size = code_size;
 | 
					 | 
				
			||||||
                tb->cs_base = (unsigned long)cs_base;
 | 
					 | 
				
			||||||
                tb->flags = flags;
 | 
					 | 
				
			||||||
                tb->hash_next = NULL;
 | 
					                tb->hash_next = NULL;
 | 
				
			||||||
                tb_link(tb);
 | 
					                tb_link(tb);
 | 
				
			||||||
                code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
 | 
					                code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
 | 
				
			||||||
| 
						 | 
					@ -323,7 +311,19 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    saved_env = env;
 | 
					    saved_env = env;
 | 
				
			||||||
    env = s;
 | 
					    env = s;
 | 
				
			||||||
    load_seg(seg_reg, selector);
 | 
					    if (env->eflags & VM_MASK) {
 | 
				
			||||||
 | 
					        SegmentCache *sc;
 | 
				
			||||||
 | 
					        selector &= 0xffff;
 | 
				
			||||||
 | 
					        sc = &env->seg_cache[seg_reg];
 | 
				
			||||||
 | 
					        /* NOTE: in VM86 mode, limit and seg_32bit are never reloaded,
 | 
				
			||||||
 | 
					           so we must load them here */
 | 
				
			||||||
 | 
					        sc->base = (void *)(selector << 4);
 | 
				
			||||||
 | 
					        sc->limit = 0xffff;
 | 
				
			||||||
 | 
					        sc->seg_32bit = 0;
 | 
				
			||||||
 | 
					        env->segs[seg_reg] = selector;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        load_seg(seg_reg, selector, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    env = saved_env;
 | 
					    env = saved_env;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -346,6 +346,10 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
 | 
				
			||||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
 | 
					static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
 | 
				
			||||||
                                    int is_write, sigset_t *old_set)
 | 
					                                    int is_write, sigset_t *old_set)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    TranslationBlock *tb;
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    uint32_t found_pc;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
#if defined(DEBUG_SIGNAL)
 | 
					#if defined(DEBUG_SIGNAL)
 | 
				
			||||||
    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", 
 | 
					    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", 
 | 
				
			||||||
           pc, address, is_write, *(unsigned long *)old_set);
 | 
					           pc, address, is_write, *(unsigned long *)old_set);
 | 
				
			||||||
| 
						 | 
					@ -354,16 +358,18 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
 | 
				
			||||||
    if (is_write && page_unprotect(address)) {
 | 
					    if (is_write && page_unprotect(address)) {
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (pc >= (unsigned long)code_gen_buffer &&
 | 
					    tb = tb_find_pc(pc);
 | 
				
			||||||
        pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
 | 
					    if (tb) {
 | 
				
			||||||
        /* the PC is inside the translated code. It means that we have
 | 
					        /* the PC is inside the translated code. It means that we have
 | 
				
			||||||
           a virtual CPU fault */
 | 
					           a virtual CPU fault */
 | 
				
			||||||
        /* we restore the process signal mask as the sigreturn should
 | 
					        ret = cpu_x86_search_pc(tb, &found_pc, pc);
 | 
				
			||||||
           do it */
 | 
					        if (ret < 0)
 | 
				
			||||||
        sigprocmask(SIG_SETMASK, old_set, NULL);
 | 
					            return 0;
 | 
				
			||||||
        /* XXX: need to compute virtual pc position by retranslating
 | 
					        env->eip = found_pc - tb->cs_base;
 | 
				
			||||||
           code. The rest of the CPU state should be correct. */
 | 
					 | 
				
			||||||
        env->cr2 = address;
 | 
					        env->cr2 = address;
 | 
				
			||||||
 | 
					        /* we restore the process signal mask as the sigreturn should
 | 
				
			||||||
 | 
					           do it (XXX: use sigsetjmp) */
 | 
				
			||||||
 | 
					        sigprocmask(SIG_SETMASK, old_set, NULL);
 | 
				
			||||||
        raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1));
 | 
					        raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1));
 | 
				
			||||||
        /* never comes here */
 | 
					        /* never comes here */
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -217,11 +217,14 @@ typedef struct CCTable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern CCTable cc_table[];
 | 
					extern CCTable cc_table[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void load_seg(int seg_reg, int selector);
 | 
					void load_seg(int seg_reg, int selector, unsigned cur_eip);
 | 
				
			||||||
void cpu_lock(void);
 | 
					void cpu_lock(void);
 | 
				
			||||||
void cpu_unlock(void);
 | 
					void cpu_unlock(void);
 | 
				
			||||||
 | 
					void raise_interrupt(int intno, int is_int, int error_code, 
 | 
				
			||||||
 | 
					                     unsigned int next_eip);
 | 
				
			||||||
void raise_exception_err(int exception_index, int error_code);
 | 
					void raise_exception_err(int exception_index, int error_code);
 | 
				
			||||||
void raise_exception(int exception_index);
 | 
					void raise_exception(int exception_index);
 | 
				
			||||||
 | 
					void cpu_loop_exit(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void OPPROTO op_movl_eflags_T0(void);
 | 
					void OPPROTO op_movl_eflags_T0(void);
 | 
				
			||||||
void OPPROTO op_movl_T0_eflags(void);
 | 
					void OPPROTO op_movl_T0_eflags(void);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										31
									
								
								exec.c
								
								
								
								
							
							
						
						
									
										31
									
								
								exec.c
								
								
								
								
							| 
						 | 
					@ -531,3 +531,34 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size)
 | 
				
			||||||
        page_unprotect(addr);
 | 
					        page_unprotect(addr);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
 | 
				
			||||||
 | 
					   tb[1].tc_ptr. Return NULL if not found */
 | 
				
			||||||
 | 
					TranslationBlock *tb_find_pc(unsigned long tc_ptr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int m_min, m_max, m;
 | 
				
			||||||
 | 
					    unsigned long v;
 | 
				
			||||||
 | 
					    TranslationBlock *tb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (nb_tbs <= 0)
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    if (tc_ptr < (unsigned long)code_gen_buffer ||
 | 
				
			||||||
 | 
					        tc_ptr >= (unsigned long)code_gen_ptr)
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    /* binary search (cf Knuth) */
 | 
				
			||||||
 | 
					    m_min = 0;
 | 
				
			||||||
 | 
					    m_max = nb_tbs - 1;
 | 
				
			||||||
 | 
					    while (m_min <= m_max) {
 | 
				
			||||||
 | 
					        m = (m_min + m_max) >> 1;
 | 
				
			||||||
 | 
					        tb = &tbs[m];
 | 
				
			||||||
 | 
					        v = (unsigned long)tb->tc_ptr;
 | 
				
			||||||
 | 
					        if (v == tc_ptr)
 | 
				
			||||||
 | 
					            return tb;
 | 
				
			||||||
 | 
					        else if (tc_ptr < v) {
 | 
				
			||||||
 | 
					            m_max = m - 1;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            m_min = m + 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } 
 | 
				
			||||||
 | 
					    return &tbs[m_max];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								exec.h
								
								
								
								
							
							
						
						
									
										10
									
								
								exec.h
								
								
								
								
							| 
						 | 
					@ -28,10 +28,10 @@
 | 
				
			||||||
#define GEN_FLAG_IOPL_SHIFT   12 /* same position as eflags */
 | 
					#define GEN_FLAG_IOPL_SHIFT   12 /* same position as eflags */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct TranslationBlock;
 | 
					struct TranslationBlock;
 | 
				
			||||||
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, 
 | 
					int cpu_x86_gen_code(struct TranslationBlock *tb,
 | 
				
			||||||
                     int *gen_code_size_ptr,
 | 
					                     int max_code_size, int *gen_code_size_ptr);
 | 
				
			||||||
                     uint8_t *pc_start,  uint8_t *cs_base, int flags,
 | 
					int cpu_x86_search_pc(struct TranslationBlock *tb, 
 | 
				
			||||||
                     int *code_size_ptr, struct TranslationBlock *tb);
 | 
					                      uint32_t *found_pc, unsigned long searched_pc);
 | 
				
			||||||
void cpu_x86_tblocks_init(void);
 | 
					void cpu_x86_tblocks_init(void);
 | 
				
			||||||
void page_init(void);
 | 
					void page_init(void);
 | 
				
			||||||
int page_unprotect(unsigned long address);
 | 
					int page_unprotect(unsigned long address);
 | 
				
			||||||
| 
						 | 
					@ -161,6 +161,8 @@ static inline void tb_add_jump(TranslationBlock *tb, int n,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TranslationBlock *tb_find_pc(unsigned long pc_ptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef offsetof
 | 
					#ifndef offsetof
 | 
				
			||||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
 | 
					#define offsetof(type, field) ((size_t) &((type *)0)->field)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue