floppy fixes (initial patch by Mike Nordell)
[qemu] / exec.c
diff --git a/exec.c b/exec.c
index 9a6d81a..8732377 100644 (file)
--- a/exec.c
+++ b/exec.c
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include "config.h"
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <sys/mman.h>
+#endif
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
@@ -25,9 +30,6 @@
 #include <errno.h>
 #include <unistd.h>
 #include <inttypes.h>
-#if !defined(CONFIG_SOFTMMU)
-#include <sys/mman.h>
-#endif
 
 #include "cpu.h"
 #include "exec-all.h"
@@ -100,10 +102,10 @@ typedef struct VirtPageDesc {
 
 static void io_mem_init(void);
 
-unsigned long real_host_page_size;
-unsigned long host_page_bits;
-unsigned long host_page_size;
-unsigned long host_page_mask;
+unsigned long qemu_real_host_page_size;
+unsigned long qemu_host_page_bits;
+unsigned long qemu_host_page_size;
+unsigned long qemu_host_page_mask;
 
 /* XXX: for system emulation, it could just be an array */
 static PageDesc *l1_map[L1_SIZE];
@@ -117,6 +119,7 @@ static unsigned int virt_valid_tag;
 /* io memory support */
 CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
 CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
+void *io_mem_opaque[IO_MEM_NB_ENTRIES];
 static int io_mem_nb;
 
 /* log support */
@@ -126,21 +129,44 @@ int loglevel;
 
 static void page_init(void)
 {
-    /* NOTE: we can always suppose that host_page_size >=
+    /* NOTE: we can always suppose that qemu_host_page_size >=
        TARGET_PAGE_SIZE */
 #ifdef _WIN32
-    real_host_page_size = 4096;
+    {
+        SYSTEM_INFO system_info;
+        DWORD old_protect;
+        
+        GetSystemInfo(&system_info);
+        qemu_real_host_page_size = system_info.dwPageSize;
+        
+        VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
+                       PAGE_EXECUTE_READWRITE, &old_protect);
+    }
 #else
-    real_host_page_size = getpagesize();
+    qemu_real_host_page_size = getpagesize();
+    {
+        unsigned long start, end;
+
+        start = (unsigned long)code_gen_buffer;
+        start &= ~(qemu_real_host_page_size - 1);
+        
+        end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
+        end += qemu_real_host_page_size - 1;
+        end &= ~(qemu_real_host_page_size - 1);
+        
+        mprotect((void *)start, end - start, 
+                 PROT_READ | PROT_WRITE | PROT_EXEC);
+    }
 #endif
-    if (host_page_size == 0)
-        host_page_size = real_host_page_size;
-    if (host_page_size < TARGET_PAGE_SIZE)
-        host_page_size = TARGET_PAGE_SIZE;
-    host_page_bits = 0;
-    while ((1 << host_page_bits) < host_page_size)
-        host_page_bits++;
-    host_page_mask = ~(host_page_size - 1);
+
+    if (qemu_host_page_size == 0)
+        qemu_host_page_size = qemu_real_host_page_size;
+    if (qemu_host_page_size < TARGET_PAGE_SIZE)
+        qemu_host_page_size = TARGET_PAGE_SIZE;
+    qemu_host_page_bits = 0;
+    while ((1 << qemu_host_page_bits) < qemu_host_page_size)
+        qemu_host_page_bits++;
+    qemu_host_page_mask = ~(qemu_host_page_size - 1);
 #if !defined(CONFIG_USER_ONLY)
     virt_valid_tag = 1;
 #endif
@@ -289,7 +315,6 @@ static void page_flush_tb(void)
 /* XXX: tb_flush is currently not thread safe */
 void tb_flush(CPUState *env)
 {
-    int i;
 #if defined(DEBUG_FLUSH)
     printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", 
            code_gen_ptr - code_gen_buffer, 
@@ -297,12 +322,10 @@ void tb_flush(CPUState *env)
            nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
 #endif
     nb_tbs = 0;
-    for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
-        tb_hash[i] = NULL;
+    memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
     virt_page_flush();
 
-    for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++)
-        tb_phys_hash[i] = NULL;
+    memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
     page_flush_tb();
 
     code_gen_ptr = code_gen_buffer;
@@ -608,11 +631,9 @@ void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
                                    int is_cpu_write_access)
 {
     int n, current_tb_modified, current_tb_not_found, current_flags;
-#if defined(TARGET_HAS_PRECISE_SMC) || !defined(CONFIG_USER_ONLY)
     CPUState *env = cpu_single_env;
-#endif
     PageDesc *p;
-    TranslationBlock *tb, *tb_next, *current_tb;
+    TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
     target_ulong tb_start, tb_end;
     target_ulong current_pc, current_cs_base;
 
@@ -680,7 +701,12 @@ void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
 #endif
             }
 #endif /* TARGET_HAS_PRECISE_SMC */
+            saved_tb = env->current_tb;
+            env->current_tb = NULL;
             tb_phys_invalidate(tb, -1);
+            env->current_tb = saved_tb;
+            if (env->interrupt_request && env->current_tb)
+                cpu_interrupt(env, env->interrupt_request);
         }
         tb = tb_next;
     }
@@ -698,6 +724,7 @@ void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
         /* we generate a block containing just the instruction
            modifying the memory. It will ensure that it cannot modify
            itself */
+        env->current_tb = NULL;
         tb_gen_code(env, current_pc, current_cs_base, current_flags, 
                     CF_SINGLE_INSN);
         cpu_resume_from_signal(env, NULL);
@@ -711,10 +738,13 @@ static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
     PageDesc *p;
     int offset, b;
 #if 0
-    if (cpu_single_env->cr[0] & CR0_PE_MASK) {
-        printf("modifying code at 0x%x size=%d EIP=%x\n", 
-               (vaddr & TARGET_PAGE_MASK) | (start & ~TARGET_PAGE_MASK), len, 
-               cpu_single_env->eip);
+    if (1) {
+        if (loglevel) {
+            fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n", 
+                   cpu_single_env->mem_write_vaddr, len, 
+                   cpu_single_env->eip, 
+                   cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
+        }
     }
 #endif
     p = page_find(start >> TARGET_PAGE_BITS);
@@ -791,6 +821,7 @@ static void tb_invalidate_phys_page(target_ulong addr,
         /* we generate a block containing just the instruction
            modifying the memory. It will ensure that it cannot modify
            itself */
+        env->current_tb = NULL;
         tb_gen_code(env, current_pc, current_cs_base, current_flags, 
                     CF_SINGLE_INSN);
         cpu_resume_from_signal(env, puc);
@@ -813,7 +844,7 @@ static inline void tb_alloc_page(TranslationBlock *tb,
     p->first_tb = (TranslationBlock *)((long)tb | n);
     invalidate_page_bitmap(p);
 
-#ifdef TARGET_HAS_SMC
+#if defined(TARGET_HAS_SMC) || 1
 
 #if defined(CONFIG_USER_ONLY)
     if (p->flags & PAGE_WRITE) {
@@ -822,12 +853,12 @@ static inline void tb_alloc_page(TranslationBlock *tb,
 
         /* force the host page as non writable (writes will have a
            page fault + mprotect overhead) */
-        host_start = page_addr & host_page_mask;
-        host_end = host_start + host_page_size;
+        host_start = page_addr & qemu_host_page_mask;
+        host_end = host_start + qemu_host_page_size;
         prot = 0;
         for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE)
             prot |= page_get_flags(addr);
-        mprotect((void *)host_start, host_page_size, 
+        mprotect((void *)host_start, qemu_host_page_size, 
                  (prot & PAGE_BITS) & ~PAGE_WRITE);
 #ifdef DEBUG_TB_INVALIDATE
         printf("protecting code page: 0x%08lx\n", 
@@ -1043,7 +1074,7 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc)
    breakpoint is reached */
 int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
 {
-#if defined(TARGET_I386) || defined(TARGET_PPC)
+#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
     int i;
     
     for(i = 0; i < env->nb_breakpoints; i++) {
@@ -1065,7 +1096,7 @@ int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
 /* remove a breakpoint */
 int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
 {
-#if defined(TARGET_I386) || defined(TARGET_PPC)
+#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
     int i;
     for(i = 0; i < env->nb_breakpoints; i++) {
         if (env->breakpoints[i] == pc)
@@ -1088,7 +1119,7 @@ int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
    CPU loop after each instruction */
 void cpu_single_step(CPUState *env, int enabled)
 {
-#if defined(TARGET_I386) || defined(TARGET_PPC)
+#if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC)
     if (env->singlestep_enabled != enabled) {
         env->singlestep_enabled = enabled;
         /* must flush all the translated code to avoid inconsistancies */
@@ -1245,8 +1276,7 @@ void tlb_flush(CPUState *env, int flush_global)
     }
 
     virt_page_flush();
-    for(i = 0;i < CODE_GEN_HASH_SIZE; i++)
-        tb_hash[i] = NULL;
+    memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *));
 
 #if !defined(CONFIG_SOFTMMU)
     munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START);
@@ -1728,12 +1758,12 @@ int page_unprotect(unsigned long address, unsigned long pc, void *puc)
     PageDesc *p, *p1;
     unsigned long host_start, host_end, addr;
 
-    host_start = address & host_page_mask;
+    host_start = address & qemu_host_page_mask;
     page_index = host_start >> TARGET_PAGE_BITS;
     p1 = page_find(page_index);
     if (!p1)
         return 0;
-    host_end = host_start + host_page_size;
+    host_end = host_start + qemu_host_page_size;
     p = p1;
     prot = 0;
     for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
@@ -1745,7 +1775,7 @@ int page_unprotect(unsigned long address, unsigned long pc, void *puc)
     if (prot & PAGE_WRITE_ORG) {
         pindex = (address - host_start) >> TARGET_PAGE_BITS;
         if (!(p1[pindex].flags & PAGE_WRITE)) {
-            mprotect((void *)host_start, host_page_size, 
+            mprotect((void *)host_start, qemu_host_page_size, 
                      (prot & PAGE_BITS) | PAGE_WRITE);
             p1[pindex].flags |= PAGE_WRITE;
             /* and since the content will be modified, we must invalidate
@@ -1799,12 +1829,12 @@ void cpu_register_physical_memory(target_phys_addr_t start_addr,
     }
 }
 
-static uint32_t unassigned_mem_readb(target_phys_addr_t addr)
+static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
 {
     return 0;
 }
 
-static void unassigned_mem_writeb(target_phys_addr_t addr, uint32_t val)
+static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
 }
 
@@ -1823,7 +1853,7 @@ static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
 /* self modifying code support in soft mmu mode : writing to a page
    containing code comes to these functions */
 
-static void code_mem_writeb(target_phys_addr_t addr, uint32_t val)
+static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     unsigned long phys_addr;
 
@@ -1835,7 +1865,7 @@ static void code_mem_writeb(target_phys_addr_t addr, uint32_t val)
     phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
 }
 
-static void code_mem_writew(target_phys_addr_t addr, uint32_t val)
+static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     unsigned long phys_addr;
 
@@ -1847,7 +1877,7 @@ static void code_mem_writew(target_phys_addr_t addr, uint32_t val)
     phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
 }
 
-static void code_mem_writel(target_phys_addr_t addr, uint32_t val)
+static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     unsigned long phys_addr;
 
@@ -1871,19 +1901,19 @@ static CPUWriteMemoryFunc *code_mem_write[3] = {
     code_mem_writel,
 };
 
-static void notdirty_mem_writeb(target_phys_addr_t addr, uint32_t val)
+static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     stb_raw((uint8_t *)addr, val);
     tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
 }
 
-static void notdirty_mem_writew(target_phys_addr_t addr, uint32_t val)
+static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     stw_raw((uint8_t *)addr, val);
     tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
 }
 
-static void notdirty_mem_writel(target_phys_addr_t addr, uint32_t val)
+static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     stl_raw((uint8_t *)addr, val);
     tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
@@ -1897,10 +1927,10 @@ static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
 
 static void io_mem_init(void)
 {
-    cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write);
-    cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write);
-    cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write);
-    cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write);
+    cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write, NULL);
+    cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
+    cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write, NULL);
+    cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write, NULL);
     io_mem_nb = 5;
 
     /* alloc dirty bits array */
@@ -1915,7 +1945,8 @@ static void io_mem_init(void)
    cpu_register_physical_memory(). (-1) is returned if error. */
 int cpu_register_io_memory(int io_index,
                            CPUReadMemoryFunc **mem_read,
-                           CPUWriteMemoryFunc **mem_write)
+                           CPUWriteMemoryFunc **mem_write,
+                           void *opaque)
 {
     int i;
 
@@ -1932,6 +1963,7 @@ int cpu_register_io_memory(int io_index,
         io_mem_read[io_index][i] = mem_read[i];
         io_mem_write[io_index][i] = mem_write[i];
     }
+    io_mem_opaque[io_index] = opaque;
     return io_index << IO_MEM_SHIFT;
 }
 
@@ -1994,17 +2026,17 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                 if (l >= 4 && ((addr & 3) == 0)) {
                     /* 32 bit read access */
                     val = ldl_raw(buf);
-                    io_mem_write[io_index][2](addr, val);
+                    io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
                     l = 4;
                 } else if (l >= 2 && ((addr & 1) == 0)) {
                     /* 16 bit read access */
                     val = lduw_raw(buf);
-                    io_mem_write[io_index][1](addr, val);
+                    io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
                     l = 2;
                 } else {
                     /* 8 bit access */
                     val = ldub_raw(buf);
-                    io_mem_write[io_index][0](addr, val);
+                    io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
                     l = 1;
                 }
             } else {
@@ -2025,17 +2057,17 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
                 if (l >= 4 && ((addr & 3) == 0)) {
                     /* 32 bit read access */
-                    val = io_mem_read[io_index][2](addr);
+                    val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
                     stl_raw(buf, val);
                     l = 4;
                 } else if (l >= 2 && ((addr & 1) == 0)) {
                     /* 16 bit read access */
-                    val = io_mem_read[io_index][1](addr);
+                    val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
                     stw_raw(buf, val);
                     l = 2;
                 } else {
                     /* 8 bit access */
-                    val = io_mem_read[io_index][0](addr);
+                    val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
                     stb_raw(buf, val);
                     l = 1;
                 }
@@ -2083,6 +2115,7 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
 #define MMUSUFFIX _cmmu
 #define GETPC() NULL
 #define env cpu_single_env
+#define SOFTMMU_CODE_ACCESS
 
 #define SHIFT 0
 #include "softmmu_template.h"