new reset API - shutdown support
[qemu] / exec.c
diff --git a/exec.c b/exec.c
index 45572e9..45b723f 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -64,9 +64,7 @@ uint8_t *phys_ram_base;
 uint8_t *phys_ram_dirty;
 
 typedef struct PageDesc {
-    /* offset in memory of the page + io_index in the low 12 bits */
-    unsigned long phys_offset;
-    /* list of TBs intersecting this physical page */
+    /* list of TBs intersecting this ram page */
     TranslationBlock *first_tb;
     /* in order to optimize self modifying code, we count the number
        of lookups we do to a given page to use a bitmap */
@@ -77,6 +75,11 @@ typedef struct PageDesc {
 #endif
 } PageDesc;
 
+typedef struct PhysPageDesc {
+    /* offset in host memory of the page + io_index in the low 12 bits */
+    unsigned long phys_offset;
+} PhysPageDesc;
+
 typedef struct VirtPageDesc {
     /* physical address of code page. It is valid only if 'valid_tag'
        matches 'virt_valid_tag' */ 
@@ -102,7 +105,9 @@ unsigned long host_page_bits;
 unsigned long host_page_size;
 unsigned long host_page_mask;
 
+/* XXX: for system emulation, it could just be an array */
 static PageDesc *l1_map[L1_SIZE];
+static PhysPageDesc *l1_phys_map[L1_SIZE];
 
 #if !defined(CONFIG_USER_ONLY)
 static VirtPageDesc *l1_virt_map[L1_SIZE];
@@ -112,6 +117,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 */
@@ -166,9 +172,34 @@ static inline PageDesc *page_find(unsigned int index)
     return p + (index & (L2_SIZE - 1));
 }
 
+static inline PhysPageDesc *phys_page_find_alloc(unsigned int index)
+{
+    PhysPageDesc **lp, *p;
+
+    lp = &l1_phys_map[index >> L2_BITS];
+    p = *lp;
+    if (!p) {
+        /* allocate if not found */
+        p = qemu_malloc(sizeof(PhysPageDesc) * L2_SIZE);
+        memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE);
+        *lp = p;
+    }
+    return p + (index & (L2_SIZE - 1));
+}
+
+static inline PhysPageDesc *phys_page_find(unsigned int index)
+{
+    PhysPageDesc *p;
+
+    p = l1_phys_map[index >> L2_BITS];
+    if (!p)
+        return 0;
+    return p + (index & (L2_SIZE - 1));
+}
+
 #if !defined(CONFIG_USER_ONLY)
-static void tlb_protect_code(CPUState *env, uint32_t addr);
-static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr, target_ulong vaddr);
+static void tlb_protect_code(CPUState *env, target_ulong addr);
+static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr);
 
 static inline VirtPageDesc *virt_page_find_alloc(unsigned int index)
 {
@@ -578,11 +609,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;
 
@@ -650,7 +679,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;
     }
@@ -668,6 +702,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);
@@ -681,10 +716,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);
@@ -761,6 +799,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);
@@ -1011,7 +1050,7 @@ static void breakpoint_invalidate(CPUState *env, target_ulong pc)
 
 /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
    breakpoint is reached */
-int cpu_breakpoint_insert(CPUState *env, uint32_t pc)
+int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
 {
 #if defined(TARGET_I386) || defined(TARGET_PPC)
     int i;
@@ -1033,7 +1072,7 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc)
 }
 
 /* remove a breakpoint */
-int cpu_breakpoint_remove(CPUState *env, uint32_t pc)
+int cpu_breakpoint_remove(CPUState *env, target_ulong pc)
 {
 #if defined(TARGET_I386) || defined(TARGET_PPC)
     int i;
@@ -1112,6 +1151,11 @@ void cpu_interrupt(CPUState *env, int mask)
     }
 }
 
+void cpu_reset_interrupt(CPUState *env, int mask)
+{
+    env->interrupt_request &= ~mask;
+}
+
 CPULogItem cpu_log_items[] = {
     { CPU_LOG_TB_OUT_ASM, "out_asm", 
       "show generated host assembly code for each compiled TB" },
@@ -1127,10 +1171,14 @@ CPULogItem cpu_log_items[] = {
       "show interrupts/exceptions in short format" },
     { CPU_LOG_EXEC, "exec",
       "show trace before each executed TB (lots of logs)" },
+    { CPU_LOG_TB_CPU, "cpu",
+      "show CPU state before bloc translation" },
 #ifdef TARGET_I386
     { CPU_LOG_PCALL, "pcall",
       "show protected mode far calls/returns/exceptions" },
 #endif
+    { CPU_LOG_IOPORT, "ioport",
+      "show all i/o ports accesses" },
     { 0, NULL, NULL },
 };
 
@@ -1214,14 +1262,14 @@ void tlb_flush(CPUState *env, int flush_global)
 #endif
 }
 
-static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, uint32_t addr)
+static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
 {
     if (addr == (tlb_entry->address & 
                  (TARGET_PAGE_MASK | TLB_INVALID_MASK)))
         tlb_entry->address = -1;
 }
 
-void tlb_flush_page(CPUState *env, uint32_t addr)
+void tlb_flush_page(CPUState *env, target_ulong addr)
 {
     int i, n;
     VirtPageDesc *vp;
@@ -1270,7 +1318,7 @@ void tlb_flush_page(CPUState *env, uint32_t addr)
 #endif
 }
 
-static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, uint32_t addr)
+static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr)
 {
     if (addr == (tlb_entry->address & 
                  (TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
@@ -1282,7 +1330,7 @@ static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, uint32_t addr)
 
 /* update the TLBs so that writes to code in the virtual page 'addr'
    can be detected */
-static void tlb_protect_code(CPUState *env, uint32_t addr)
+static void tlb_protect_code(CPUState *env, target_ulong addr)
 {
     int i;
 
@@ -1299,7 +1347,7 @@ static void tlb_protect_code(CPUState *env, uint32_t addr)
 }
 
 static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry, 
-                                       uint32_t phys_addr)
+                                       unsigned long phys_addr)
 {
     if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE &&
         ((tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend) == phys_addr) {
@@ -1309,7 +1357,7 @@ static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry,
 
 /* update the TLB so that writes in physical page 'phys_addr' are no longer
    tested self modifying code */
-static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr, target_ulong vaddr)
+static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr)
 {
     int i;
 
@@ -1335,7 +1383,7 @@ static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
 void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end)
 {
     CPUState *env;
-    target_ulong length, start1;
+    unsigned long length, start1;
     int i;
 
     start &= TARGET_PAGE_MASK;
@@ -1415,23 +1463,30 @@ static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
    is permitted. Return 0 if OK or 2 if the page could not be mapped
    (can only happen in non SOFTMMU mode for I/O pages or pages
    conflicting with the host address space). */
-int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, 
+int tlb_set_page(CPUState *env, target_ulong vaddr, 
+                 target_phys_addr_t paddr, int prot, 
                  int is_user, int is_softmmu)
 {
-    PageDesc *p;
-    target_ulong pd;
+    PhysPageDesc *p;
+    unsigned long pd;
     TranslationBlock *first_tb;
     unsigned int index;
-    target_ulong address, addend;
+    target_ulong address;
+    unsigned long addend;
     int ret;
 
-    p = page_find(paddr >> TARGET_PAGE_BITS);
+    p = phys_page_find(paddr >> TARGET_PAGE_BITS);
+    first_tb = NULL;
     if (!p) {
         pd = IO_MEM_UNASSIGNED;
-        first_tb = NULL;
     } else {
+        PageDesc *p1;
         pd = p->phys_offset;
-        first_tb = p->first_tb;
+        if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
+            /* NOTE: we also allocate the page at this stage */
+            p1 = page_find_alloc(pd >> TARGET_PAGE_BITS);
+            first_tb = p1->first_tb;
+        }
     }
 #if defined(DEBUG_TLB)
     printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n",
@@ -1583,15 +1638,12 @@ void tlb_flush(CPUState *env, int flush_global)
 {
 }
 
-void tlb_flush_page(CPUState *env, uint32_t addr)
-{
-}
-
-void tlb_flush_page_write(CPUState *env, uint32_t addr)
+void tlb_flush_page(CPUState *env, target_ulong addr)
 {
 }
 
-int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot, 
+int tlb_set_page(CPUState *env, target_ulong vaddr, 
+                 target_phys_addr_t paddr, int prot, 
                  int is_user, int is_softmmu)
 {
     return 0;
@@ -1739,27 +1791,29 @@ static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
 /* register physical memory. 'size' must be a multiple of the target
    page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
    io memory page */
-void cpu_register_physical_memory(unsigned long start_addr, unsigned long size,
-                                  long phys_offset)
+void cpu_register_physical_memory(target_phys_addr_t start_addr, 
+                                  unsigned long size,
+                                  unsigned long phys_offset)
 {
     unsigned long addr, end_addr;
-    PageDesc *p;
+    PhysPageDesc *p;
 
+    size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
     end_addr = start_addr + size;
-    for(addr = start_addr; addr < end_addr; addr += TARGET_PAGE_SIZE) {
-        p = page_find_alloc(addr >> TARGET_PAGE_BITS);
+    for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
+        p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS);
         p->phys_offset = phys_offset;
         if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
             phys_offset += TARGET_PAGE_SIZE;
     }
 }
 
-static uint32_t unassigned_mem_readb(uint32_t addr)
+static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
 {
     return 0;
 }
 
-static void unassigned_mem_writeb(uint32_t addr, uint32_t val)
+static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
 }
 
@@ -1778,11 +1832,11 @@ 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(uint32_t addr, uint32_t val)
+static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     unsigned long phys_addr;
 
-    phys_addr = addr - (long)phys_ram_base;
+    phys_addr = addr - (unsigned long)phys_ram_base;
 #if !defined(CONFIG_USER_ONLY)
     tb_invalidate_phys_page_fast(phys_addr, 1);
 #endif
@@ -1790,11 +1844,11 @@ static void code_mem_writeb(uint32_t addr, uint32_t val)
     phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
 }
 
-static void code_mem_writew(uint32_t addr, uint32_t val)
+static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     unsigned long phys_addr;
 
-    phys_addr = addr - (long)phys_ram_base;
+    phys_addr = addr - (unsigned long)phys_ram_base;
 #if !defined(CONFIG_USER_ONLY)
     tb_invalidate_phys_page_fast(phys_addr, 2);
 #endif
@@ -1802,11 +1856,11 @@ static void code_mem_writew(uint32_t addr, uint32_t val)
     phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
 }
 
-static void code_mem_writel(uint32_t addr, uint32_t val)
+static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     unsigned long phys_addr;
 
-    phys_addr = addr - (long)phys_ram_base;
+    phys_addr = addr - (unsigned long)phys_ram_base;
 #if !defined(CONFIG_USER_ONLY)
     tb_invalidate_phys_page_fast(phys_addr, 4);
 #endif
@@ -1826,19 +1880,19 @@ static CPUWriteMemoryFunc *code_mem_write[3] = {
     code_mem_writel,
 };
 
-static void notdirty_mem_writeb(uint32_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(uint32_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(uint32_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);
@@ -1852,10 +1906,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 */
@@ -1870,7 +1924,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;
 
@@ -1887,12 +1942,13 @@ 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;
 }
 
 /* physical memory access (slow version, mainly for debug) */
 #if defined(CONFIG_USER_ONLY)
-void cpu_physical_memory_rw(target_ulong addr, uint8_t *buf, 
+void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, 
                             int len, int is_write)
 {
     int l, flags;
@@ -1921,21 +1977,22 @@ void cpu_physical_memory_rw(target_ulong addr, uint8_t *buf,
     }
 }
 #else
-void cpu_physical_memory_rw(target_ulong addr, uint8_t *buf, 
+void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, 
                             int len, int is_write)
 {
     int l, io_index;
     uint8_t *ptr;
     uint32_t val;
-    target_ulong page, pd;
-    PageDesc *p;
+    target_phys_addr_t page;
+    unsigned long pd;
+    PhysPageDesc *p;
     
     while (len > 0) {
         page = addr & TARGET_PAGE_MASK;
         l = (page + TARGET_PAGE_SIZE) - addr;
         if (l > len)
             l = len;
-        p = page_find(page >> TARGET_PAGE_BITS);
+        p = phys_page_find(page >> TARGET_PAGE_BITS);
         if (!p) {
             pd = IO_MEM_UNASSIGNED;
         } else {
@@ -1948,17 +2005,17 @@ void cpu_physical_memory_rw(target_ulong 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 {
@@ -1979,17 +2036,17 @@ void cpu_physical_memory_rw(target_ulong 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;
                 }