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);