]> git.proxmox.com Git - mirror_qemu.git/commitdiff
precise exceptions
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Tue, 27 May 2003 23:29:48 +0000 (23:29 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Tue, 27 May 2003 23:29:48 +0000 (23:29 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@194 c046a42c-6fe2-441c-8c8c-71466251a162

dyngen.c
exec-i386.c
exec-i386.h
exec.c
exec.h

index 96a47c8edff861a106c36dbb6b7373d5a1e8d505..4ed8b4b8b5fd1083d8699d026d635e4c5a81c4df 100644 (file)
--- a/dyngen.c
+++ b/dyngen.c
@@ -451,7 +451,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
     }
 
     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) {
 
         /* output C code */
@@ -991,7 +991,7 @@ int load_elf(const char *filename, FILE *outfile, int 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++) {
             const char *name, *p;
             name = strtab + sym->st_name;
index 68e0371cc7c3a4aa6744fc5409061d7545bf1710..002f00bdcdd19119f624f58f7c041cce241ea586 100644 (file)
@@ -39,9 +39,7 @@ void cpu_unlock(void)
     spin_unlock(&global_cpu_lock);
 }
 
-/* exception support */
-/* NOTE: not static to force relocation generation by GCC */
-void raise_exception_err(int exception_index, int error_code)
+void cpu_loop_exit(void)
 {
     /* NOTE: the register at this point must be saved by hand because
        longjmp restore them */
@@ -76,17 +74,9 @@ void raise_exception_err(int exception_index, int error_code)
 #ifdef reg_EDI
     env->regs[R_EDI] = EDI;
 #endif
-    env->exception_index = exception_index;
-    env->error_code = error_code;
     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 saved_T0, saved_T1, saved_A0;
@@ -115,7 +105,7 @@ int cpu_x86_exec(CPUX86State *env1)
 #ifdef reg_EDI
     int saved_EDI;
 #endif
-    int code_gen_size, ret, code_size;
+    int code_gen_size, ret;
     void (*gen_func)(void);
     TranslationBlock *tb, **ptb;
     uint8_t *tc_ptr, *cs_base, *pc;
@@ -172,7 +162,8 @@ int cpu_x86_exec(CPUX86State *env1)
         T0 = 0; /* force lookup of first TB */
         for(;;) {
             if (env->interrupt_request) {
-                raise_exception(EXCP_INTERRUPT);
+                env->exception_index = EXCP_INTERRUPT;
+                cpu_loop_exit();
             }
 #ifdef DEBUG_EXEC
             if (loglevel) {
@@ -226,9 +217,9 @@ int cpu_x86_exec(CPUX86State *env1)
                 }
                 tc_ptr = code_gen_ptr;
                 tb->tc_ptr = tc_ptr;
-                ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, 
-                                       &code_gen_size, pc, cs_base, flags,
-                                       &code_size, tb);
+                tb->cs_base = (unsigned long)cs_base;
+                tb->flags = flags;
+                ret = cpu_x86_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
                 /* if invalid instruction, signal it */
                 if (ret != 0) {
                     /* NOTE: the tb is allocated but not linked, so we
@@ -237,9 +228,6 @@ int cpu_x86_exec(CPUX86State *env1)
                     raise_exception(EXCP06_ILLOP);
                 }
                 *ptb = tb;
-                tb->size = code_size;
-                tb->cs_base = (unsigned long)cs_base;
-                tb->flags = flags;
                 tb->hash_next = NULL;
                 tb_link(tb);
                 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;
     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;
 }
 
@@ -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,
                                     int is_write, sigset_t *old_set)
 {
+    TranslationBlock *tb;
+    int ret;
+    uint32_t found_pc;
+    
 #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);
@@ -354,16 +358,18 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
     if (is_write && page_unprotect(address)) {
         return 1;
     }
-    if (pc >= (unsigned long)code_gen_buffer &&
-        pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
+    tb = tb_find_pc(pc);
+    if (tb) {
         /* the PC is inside the translated code. It means that we have
            a virtual CPU fault */
+        ret = cpu_x86_search_pc(tb, &found_pc, pc);
+        if (ret < 0)
+            return 0;
+        env->eip = found_pc - tb->cs_base;
+        env->cr2 = address;
         /* we restore the process signal mask as the sigreturn should
-           do it */
+           do it (XXX: use sigsetjmp) */
         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. */
-        env->cr2 = address;
         raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1));
         /* never comes here */
         return 1;
index 938680d1e59e1a81d55dc9342ddcc2306bf04629..ba5ea1a9a5b085ce4a67665aa516d8ebd4983983 100644 (file)
@@ -217,11 +217,14 @@ typedef struct CCTable {
 
 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_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(int exception_index);
+void cpu_loop_exit(void);
 
 void OPPROTO op_movl_eflags_T0(void);
 void OPPROTO op_movl_T0_eflags(void);
diff --git a/exec.c b/exec.c
index 8f332c9aed262b53fa588854060152f6b5a3a16d..2e84f557b4fa0dd98ea5e4ff0b7abee2b0bfd479 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -531,3 +531,34 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size)
         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];
+}
diff --git a/exec.h b/exec.h
index 29a7ab1fda1d43139d943e739629ecdfc88aa8e7..18e75e67b0458d09234f2a3b3e7e23ef876a54b2 100644 (file)
--- a/exec.h
+++ b/exec.h
 #define GEN_FLAG_IOPL_SHIFT   12 /* same position as eflags */
 
 struct TranslationBlock;
-int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, 
-                     int *gen_code_size_ptr,
-                     uint8_t *pc_start,  uint8_t *cs_base, int flags,
-                     int *code_size_ptr, struct TranslationBlock *tb);
+int cpu_x86_gen_code(struct TranslationBlock *tb,
+                     int max_code_size, int *gen_code_size_ptr);
+int cpu_x86_search_pc(struct TranslationBlock *tb, 
+                      uint32_t *found_pc, unsigned long searched_pc);
 void cpu_x86_tblocks_init(void);
 void page_init(void);
 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
 #define offsetof(type, field) ((size_t) &((type *)0)->field)
 #endif