Hi,

RISC CPUs don't support self-modifying code unless the affected area
is flushed explicitly. This patch disables the extra effort for SMC.
The changes in this version would affect all CPUs except x86, but I'd
like to see if there are problems with some target, so that the
committed change can be limited. Without comments, I'll just disable
SMC for Sparc, as there are no problems. So please comment, especially
if you want to "opt in".

For some reason, I can't disable all TB/TLB flushing, for example
there was already one line with TARGET_HAS_SMC || 1, but removing the
|| 1 part causes crashing. Does anyone know why?
Index: qemu/exec.c
===================================================================
--- qemu.orig/exec.c	2007-11-03 11:39:44.000000000 +0000
+++ qemu/exec.c	2007-11-03 18:38:48.000000000 +0000
@@ -100,10 +100,12 @@
 typedef struct PageDesc {
     /* list of TBs intersecting this ram page */
     TranslationBlock *first_tb;
+#ifdef TARGET_HAS_SMC
     /* in order to optimize self modifying code, we count the number
        of lookups we do to a given page to use a bitmap */
     unsigned int code_write_count;
     uint8_t *code_bitmap;
+#endif
 #if defined(CONFIG_USER_ONLY)
     unsigned long flags;
 #endif
@@ -306,6 +308,7 @@
     *penv = env;
 }
 
+#ifdef TARGET_HAS_SMC
 static inline void invalidate_page_bitmap(PageDesc *p)
 {
     if (p->code_bitmap) {
@@ -314,6 +317,7 @@
     }
     p->code_write_count = 0;
 }
+#endif
 
 /* set to NULL all the 'first_tb' fields in all PageDescs */
 static void page_flush_tb(void)
@@ -326,7 +330,9 @@
         if (p) {
             for(j = 0; j < L2_SIZE; j++) {
                 p->first_tb = NULL;
+#ifdef TARGET_HAS_SMC
                 invalidate_page_bitmap(p);
+#endif
                 p++;
             }
         }
@@ -339,10 +345,11 @@
 {
     CPUState *env;
 #if defined(DEBUG_FLUSH)
-    printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
-           code_gen_ptr - code_gen_buffer,
+    printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
+           (unsigned long)(code_gen_ptr - code_gen_buffer),
            nb_tbs,
-           nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
+           nb_tbs > 0 ? ((unsigned long)(code_gen_ptr - code_gen_buffer))
+           / nb_tbs : 0);
 #endif
     nb_tbs = 0;
 
@@ -502,12 +509,16 @@
     if (tb->page_addr[0] != page_addr) {
         p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
         tb_page_remove(&p->first_tb, tb);
+#ifdef TARGET_HAS_SMC
         invalidate_page_bitmap(p);
+#endif
     }
     if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
         p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
         tb_page_remove(&p->first_tb, tb);
+#ifdef TARGET_HAS_SMC
         invalidate_page_bitmap(p);
+#endif
     }
 
     tb_invalidated_flag = 1;
@@ -567,6 +578,7 @@
     }
 }
 
+#ifdef TARGET_HAS_SMC
 static void build_page_bitmap(PageDesc *p)
 {
     int n, tb_start, tb_end;
@@ -597,6 +609,7 @@
         tb = tb->page_next[n];
     }
 }
+#endif
 
 #ifdef TARGET_HAS_PRECISE_SMC
 
@@ -653,12 +666,14 @@
     p = page_find(start >> TARGET_PAGE_BITS);
     if (!p)
         return;
+#ifdef TARGET_HAS_SMC
     if (!p->code_bitmap &&
         ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
         is_cpu_write_access) {
         /* build code bitmap */
         build_page_bitmap(p);
     }
+#endif
 
     /* we remove all the TBs in the range [start, end[ */
     /* XXX: see if in some cases it could be faster to invalidate all the code */
@@ -733,7 +748,9 @@
 #if !defined(CONFIG_USER_ONLY)
     /* if no code remaining, no need to continue to use slow writes */
     if (!p->first_tb) {
+#ifdef TARGET_HAS_SMC
         invalidate_page_bitmap(p);
+#endif
         if (is_cpu_write_access) {
             tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
         }
@@ -756,7 +773,9 @@
 static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
 {
     PageDesc *p;
+#ifdef TARGET_HAS_SMC
     int offset, b;
+#endif
 #if 0
     if (1) {
         if (loglevel) {
@@ -770,6 +789,7 @@
     p = page_find(start >> TARGET_PAGE_BITS);
     if (!p)
         return;
+#ifdef TARGET_HAS_SMC
     if (p->code_bitmap) {
         offset = start & ~TARGET_PAGE_MASK;
         b = p->code_bitmap[offset >> 3] >> (offset & 7);
@@ -777,11 +797,15 @@
             goto do_invalidate;
     } else {
     do_invalidate:
+#endif
         tb_invalidate_phys_page_range(start, start + len, 1);
+#ifdef TARGET_HAS_SMC
     }
+#endif
 }
 
 #if !defined(CONFIG_SOFTMMU)
+#ifndef TARGET_SPARC
 static void tb_invalidate_phys_page(target_ulong addr,
                                     unsigned long pc, void *puc)
 {
@@ -849,6 +873,7 @@
 #endif
 }
 #endif
+#endif
 
 /* add the tb in the target page and protect it if necessary */
 static inline void tb_alloc_page(TranslationBlock *tb,
@@ -862,11 +887,14 @@
     tb->page_next[n] = p->first_tb;
     last_first_tb = p->first_tb;
     p->first_tb = (TranslationBlock *)((long)tb | n);
+#ifdef TARGET_HAS_SMC
     invalidate_page_bitmap(p);
+#endif
 
 #if defined(TARGET_HAS_SMC) || 1
 
 #if defined(CONFIG_USER_ONLY)
+#if !defined(TARGET_SPARC)
     if (p->flags & PAGE_WRITE) {
         target_ulong addr;
         PageDesc *p2;
@@ -889,10 +917,11 @@
         mprotect(g2h(page_addr), qemu_host_page_size,
                  (prot & PAGE_BITS) & ~PAGE_WRITE);
 #ifdef DEBUG_TB_INVALIDATE
-        printf("protecting code page: 0x%08lx\n",
+        printf("protecting code page: 0x" TARGET_FMT_lx "\n",
                page_addr);
 #endif
     }
+#endif
 #else
     /* if some code is already present, then the pages are already
        protected. So we handle the case where only the first TB is
@@ -1540,6 +1569,7 @@
 #endif
 }
 
+#ifdef USE_KQEMU
 static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
 {
     ram_addr_t ram_addr;
@@ -1570,6 +1600,7 @@
 #endif
 #endif
 }
+#endif
 
 static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
                                   unsigned long start)
@@ -1737,6 +1768,7 @@
     return ret;
 }
 
+#ifndef TARGET_SPARC
 /* called from signal handler: invalidate the code and unprotect the
    page. Return TRUE if the fault was succesfully handled. */
 int page_unprotect(target_ulong addr, unsigned long pc, void *puc)
@@ -1777,6 +1809,7 @@
     return 0;
 #endif
 }
+#endif
 
 #else
 
@@ -1858,23 +1891,28 @@
 
     start = start & TARGET_PAGE_MASK;
     end = TARGET_PAGE_ALIGN(end);
+#ifdef TARGET_HAS_SMC
     if (flags & PAGE_WRITE)
         flags |= PAGE_WRITE_ORG;
+#endif
     spin_lock(&tb_lock);
     for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
         p = page_find_alloc(addr >> TARGET_PAGE_BITS);
         /* if the write protection is set, then we invalidate the code
            inside */
+#ifdef TARGET_HAS_SMC
         if (!(p->flags & PAGE_WRITE) &&
             (flags & PAGE_WRITE) &&
             p->first_tb) {
             tb_invalidate_phys_page(addr, 0, NULL);
         }
+#endif
         p->flags = flags;
     }
     spin_unlock(&tb_lock);
 }
 
+#ifndef TARGET_SPARC
 /* called from signal handler: invalidate the code and unprotect the
    page. Return TRUE if the fault was succesfully handled. */
 int page_unprotect(target_ulong address, unsigned long pc, void *puc)
@@ -1929,6 +1967,7 @@
         page_unprotect(addr, 0, NULL);
     }
 }
+#endif
 
 static inline void tlb_set_dirty(CPUState *env,
                                  unsigned long addr, target_ulong vaddr)
@@ -2549,6 +2588,7 @@
                 /* RAM case */
                 ptr = phys_ram_base + addr1;
                 memcpy(ptr, buf, l);
+#ifdef TARGET_HAS_SMC
                 if (!cpu_physical_memory_is_dirty(addr1)) {
                     /* invalidate code */
                     tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
@@ -2556,6 +2596,7 @@
                     phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
                         (0xff & ~CODE_DIRTY_FLAG);
                 }
+#endif
             }
         } else {
             if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
@@ -2794,6 +2835,7 @@
         /* RAM case */
         ptr = phys_ram_base + addr1;
         stl_p(ptr, val);
+#ifdef TARGET_HAS_SMC
         if (!cpu_physical_memory_is_dirty(addr1)) {
             /* invalidate code */
             tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
@@ -2801,6 +2843,7 @@
             phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
                 (0xff & ~CODE_DIRTY_FLAG);
         }
+#endif
     }
 }
 
Index: qemu/target-sparc/helper.c
===================================================================
--- qemu.orig/target-sparc/helper.c	2007-11-03 11:39:44.000000000 +0000
+++ qemu/target-sparc/helper.c	2007-11-03 11:47:19.000000000 +0000
@@ -203,12 +203,6 @@
 
     /* the page can be put in the TLB */
     *prot = perm_table[is_user][access_perms];
-    if (!(pde & PG_MODIFIED_MASK)) {
-        /* only set write access if already dirty... otherwise wait
-           for dirty access */
-        *prot &= ~PAGE_WRITE;
-    }
-
     /* Even if large ptes, we map only one 4KB page in the cache to
        avoid filling it too fast */
     *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
Index: qemu/exec-all.h
===================================================================
--- qemu.orig/exec-all.h	2007-11-03 11:39:44.000000000 +0000
+++ qemu/exec-all.h	2007-11-03 14:34:14.000000000 +0000
@@ -109,7 +109,9 @@
                            void *puc);
 void cpu_resume_from_signal(CPUState *env1, void *puc);
 void cpu_exec_init(CPUState *env);
+#ifndef TARGET_SPARC
 int page_unprotect(target_ulong address, unsigned long pc, void *puc);
+#endif
 void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
                                    int is_cpu_write_access);
 void tb_invalidate_page_range(target_ulong start, target_ulong end);
@@ -122,8 +124,10 @@
                                target_phys_addr_t paddr, int prot,
                                int mmu_idx, int is_softmmu)
 {
+#ifndef TARGET_SPARC
     if (prot & PAGE_READ)
         prot |= PAGE_EXEC;
+#endif
     return tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu);
 }
 
Index: qemu/cpu-exec.c
===================================================================
--- qemu.orig/cpu-exec.c	2007-11-03 14:22:28.000000000 +0000
+++ qemu/cpu-exec.c	2007-11-03 14:30:03.000000000 +0000
@@ -964,10 +964,6 @@
     printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
            pc, address, is_write, *(unsigned long *)old_set);
 #endif
-    /* XXX: locking issue */
-    if (is_write && page_unprotect(h2g(address), pc, puc)) {
-        return 1;
-    }
     /* see if it is an MMU fault */
     ret = cpu_sparc_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
     if (ret < 0)
Index: qemu/linux-user/syscall.c
===================================================================
--- qemu.orig/linux-user/syscall.c	2007-11-03 14:36:28.000000000 +0000
+++ qemu/linux-user/syscall.c	2007-11-03 14:36:50.000000000 +0000
@@ -2628,7 +2628,9 @@
         ret = 0; /* avoid warning */
         break;
     case TARGET_NR_read:
+#ifndef TARGET_SPARC
         page_unprotect_range(arg2, arg3);
+#endif
         p = lock_user(arg2, arg3, 0);
         ret = get_errno(read(arg1, p, arg3));
         unlock_user(p, arg2, ret);
@@ -4377,7 +4379,9 @@
         break;
 #ifdef TARGET_NR_pread
     case TARGET_NR_pread:
+#ifndef TARGET_SPARC
         page_unprotect_range(arg2, arg3);
+#endif
         p = lock_user(arg2, arg3, 0);
         ret = get_errno(pread(arg1, p, arg3, arg4));
         unlock_user(p, arg2, ret);

Reply via email to