Diff for /qemu/exec.c between versions 1.1.1.5 and 1.1.1.6

version 1.1.1.5, 2018/04/24 16:45:02 version 1.1.1.6, 2018/04/24 16:47:27
Line 1 Line 1
 /*  /*
  *  virtual page mapping and translated block handling   *  virtual page mapping and translated block handling
  *    *
  *  Copyright (c) 2003 Fabrice Bellard   *  Copyright (c) 2003 Fabrice Bellard
  *   *
  * This library is free software; you can redistribute it and/or   * This library is free software; you can redistribute it and/or
Line 19 Line 19
  */   */
 #include "config.h"  #include "config.h"
 #ifdef _WIN32  #ifdef _WIN32
   #define WIN32_LEAN_AND_MEAN
 #include <windows.h>  #include <windows.h>
 #else  #else
 #include <sys/types.h>  #include <sys/types.h>
Line 44 Line 45
 //#define DEBUG_UNASSIGNED  //#define DEBUG_UNASSIGNED
   
 /* make various TB consistency checks */  /* make various TB consistency checks */
 //#define DEBUG_TB_CHECK   //#define DEBUG_TB_CHECK
 //#define DEBUG_TLB_CHECK   //#define DEBUG_TLB_CHECK
   
   //#define DEBUG_IOPORT
   //#define DEBUG_SUBPAGE
   
 #if !defined(CONFIG_USER_ONLY)  #if !defined(CONFIG_USER_ONLY)
 /* TB consistency checks only implemented for usermode emulation.  */  /* TB consistency checks only implemented for usermode emulation.  */
Line 53 Line 57
 #endif  #endif
   
 /* threshold to flush the translated code buffer */  /* threshold to flush the translated code buffer */
 #define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE)  #define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - code_gen_max_block_size())
   
 #define SMC_BITMAP_USE_THRESHOLD 10  #define SMC_BITMAP_USE_THRESHOLD 10
   
Line 62 Line 66
   
 #if defined(TARGET_SPARC64)  #if defined(TARGET_SPARC64)
 #define TARGET_PHYS_ADDR_SPACE_BITS 41  #define TARGET_PHYS_ADDR_SPACE_BITS 41
   #elif defined(TARGET_SPARC)
   #define TARGET_PHYS_ADDR_SPACE_BITS 36
   #elif defined(TARGET_ALPHA)
   #define TARGET_PHYS_ADDR_SPACE_BITS 42
   #define TARGET_VIRT_ADDR_SPACE_BITS 42
 #elif defined(TARGET_PPC64)  #elif defined(TARGET_PPC64)
 #define TARGET_PHYS_ADDR_SPACE_BITS 42  #define TARGET_PHYS_ADDR_SPACE_BITS 42
 #else  #else
Line 82  int phys_ram_size; Line 91  int phys_ram_size;
 int phys_ram_fd;  int phys_ram_fd;
 uint8_t *phys_ram_base;  uint8_t *phys_ram_base;
 uint8_t *phys_ram_dirty;  uint8_t *phys_ram_dirty;
   static ram_addr_t phys_ram_alloc_offset = 0;
   
 CPUState *first_cpu;  CPUState *first_cpu;
 /* current CPU in the current thread. It is only valid inside  /* current CPU in the current thread. It is only valid inside
    cpu_exec() */     cpu_exec() */
 CPUState *cpu_single_env;   CPUState *cpu_single_env;
   
 typedef struct PageDesc {  typedef struct PageDesc {
     /* list of TBs intersecting this ram page */      /* list of TBs intersecting this ram page */
Line 106  typedef struct PhysPageDesc { Line 116  typedef struct PhysPageDesc {
 } PhysPageDesc;  } PhysPageDesc;
   
 #define L2_BITS 10  #define L2_BITS 10
   #if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
   /* XXX: this is a temporary hack for alpha target.
    *      In the future, this is to be replaced by a multi-level table
    *      to actually be able to handle the complete 64 bits address space.
    */
   #define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
   #else
 #define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)  #define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
   #endif
   
 #define L1_SIZE (1 << L1_BITS)  #define L1_SIZE (1 << L1_BITS)
 #define L2_SIZE (1 << L2_BITS)  #define L2_SIZE (1 << L2_BITS)
Line 127  CPUWriteMemoryFunc *io_mem_write[IO_MEM_ Line 145  CPUWriteMemoryFunc *io_mem_write[IO_MEM_
 CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];  CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
 void *io_mem_opaque[IO_MEM_NB_ENTRIES];  void *io_mem_opaque[IO_MEM_NB_ENTRIES];
 static int io_mem_nb;  static int io_mem_nb;
   #if defined(CONFIG_SOFTMMU)
   static int io_mem_watch;
   #endif
   
 /* log support */  /* log support */
 char *logfilename = "/tmp/qemu.log";  char *logfilename = "/tmp/qemu.log";
 FILE *logfile;  FILE *logfile;
 int loglevel;  int loglevel;
   static int log_append = 0;
   
 /* statistics */  /* statistics */
 static int tlb_flush_count;  static int tlb_flush_count;
 static int tb_flush_count;  static int tb_flush_count;
 static int tb_phys_invalidate_count;  static int tb_phys_invalidate_count;
   
   #define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
   typedef struct subpage_t {
       target_phys_addr_t base;
       CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
       CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
       void *opaque[TARGET_PAGE_SIZE][2][4];
   } subpage_t;
   
 static void page_init(void)  static void page_init(void)
 {  {
     /* NOTE: we can always suppose that qemu_host_page_size >=      /* NOTE: we can always suppose that qemu_host_page_size >=
Line 146  static void page_init(void) Line 176  static void page_init(void)
     {      {
         SYSTEM_INFO system_info;          SYSTEM_INFO system_info;
         DWORD old_protect;          DWORD old_protect;
           
         GetSystemInfo(&system_info);          GetSystemInfo(&system_info);
         qemu_real_host_page_size = system_info.dwPageSize;          qemu_real_host_page_size = system_info.dwPageSize;
           
         VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),          VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
                        PAGE_EXECUTE_READWRITE, &old_protect);                         PAGE_EXECUTE_READWRITE, &old_protect);
     }      }
Line 160  static void page_init(void) Line 190  static void page_init(void)
   
         start = (unsigned long)code_gen_buffer;          start = (unsigned long)code_gen_buffer;
         start &= ~(qemu_real_host_page_size - 1);          start &= ~(qemu_real_host_page_size - 1);
           
         end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);          end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
         end += qemu_real_host_page_size - 1;          end += qemu_real_host_page_size - 1;
         end &= ~(qemu_real_host_page_size - 1);          end &= ~(qemu_real_host_page_size - 1);
           
         mprotect((void *)start, end - start,           mprotect((void *)start, end - start,
                  PROT_READ | PROT_WRITE | PROT_EXEC);                   PROT_READ | PROT_WRITE | PROT_EXEC);
     }      }
 #endif  #endif
Line 180  static void page_init(void) Line 210  static void page_init(void)
     qemu_host_page_mask = ~(qemu_host_page_size - 1);      qemu_host_page_mask = ~(qemu_host_page_size - 1);
     l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));      l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
     memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));      memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
   
   #if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
       {
           long long startaddr, endaddr;
           FILE *f;
           int n;
   
           f = fopen("/proc/self/maps", "r");
           if (f) {
               do {
                   n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
                   if (n == 2) {
                       page_set_flags(TARGET_PAGE_ALIGN(startaddr),
                                      TARGET_PAGE_ALIGN(endaddr),
                                      PAGE_RESERVED); 
                   }
               } while (!feof(f));
               fclose(f);
           }
       }
   #endif
 }  }
   
 static inline PageDesc *page_find_alloc(unsigned int index)  static inline PageDesc *page_find_alloc(unsigned int index)
Line 251  static inline PhysPageDesc *phys_page_fi Line 302  static inline PhysPageDesc *phys_page_fi
   
 #if !defined(CONFIG_USER_ONLY)  #if !defined(CONFIG_USER_ONLY)
 static void tlb_protect_code(ram_addr_t ram_addr);  static void tlb_protect_code(ram_addr_t ram_addr);
 static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,   static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
                                     target_ulong vaddr);                                      target_ulong vaddr);
 #endif  #endif
   
Line 273  void cpu_exec_init(CPUState *env) Line 324  void cpu_exec_init(CPUState *env)
         cpu_index++;          cpu_index++;
     }      }
     env->cpu_index = cpu_index;      env->cpu_index = cpu_index;
       env->nb_watchpoints = 0;
     *penv = env;      *penv = env;
 }  }
   
Line 309  void tb_flush(CPUState *env1) Line 361  void tb_flush(CPUState *env1)
 {  {
     CPUState *env;      CPUState *env;
 #if defined(DEBUG_FLUSH)  #if defined(DEBUG_FLUSH)
     printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",       printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
            code_gen_ptr - code_gen_buffer,              (unsigned long)(code_gen_ptr - code_gen_buffer),
            nb_tbs,              nb_tbs, nb_tbs > 0 ?
            nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);             ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
 #endif  #endif
     nb_tbs = 0;      nb_tbs = 0;
       
     for(env = first_cpu; env != NULL; env = env->next_cpu) {      for(env = first_cpu; env != NULL; env = env->next_cpu) {
         memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));          memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
     }      }
Line 331  void tb_flush(CPUState *env1) Line 383  void tb_flush(CPUState *env1)
   
 #ifdef DEBUG_TB_CHECK  #ifdef DEBUG_TB_CHECK
   
 static void tb_invalidate_check(unsigned long address)  static void tb_invalidate_check(target_ulong address)
 {  {
     TranslationBlock *tb;      TranslationBlock *tb;
     int i;      int i;
Line 352  static void tb_page_check(void) Line 404  static void tb_page_check(void)
 {  {
     TranslationBlock *tb;      TranslationBlock *tb;
     int i, flags1, flags2;      int i, flags1, flags2;
       
     for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {      for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
         for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {          for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
             flags1 = page_get_flags(tb->pc);              flags1 = page_get_flags(tb->pc);
Line 461  static inline void tb_phys_invalidate(Tr Line 513  static inline void tb_phys_invalidate(Tr
     unsigned int h, n1;      unsigned int h, n1;
     target_ulong phys_pc;      target_ulong phys_pc;
     TranslationBlock *tb1, *tb2;      TranslationBlock *tb1, *tb2;
       
     /* remove the TB from the hash list */      /* remove the TB from the hash list */
     phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);      phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
     h = tb_phys_hash_func(phys_pc);      h = tb_phys_hash_func(phys_pc);
     tb_remove(&tb_phys_hash[h], tb,       tb_remove(&tb_phys_hash[h], tb,
               offsetof(TranslationBlock, phys_hash_next));                offsetof(TranslationBlock, phys_hash_next));
   
     /* remove the TB from the page list */      /* remove the TB from the page list */
Line 541  static void build_page_bitmap(PageDesc * Line 593  static void build_page_bitmap(PageDesc *
 {  {
     int n, tb_start, tb_end;      int n, tb_start, tb_end;
     TranslationBlock *tb;      TranslationBlock *tb;
       
     p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);      p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
     if (!p->code_bitmap)      if (!p->code_bitmap)
         return;          return;
Line 570  static void build_page_bitmap(PageDesc * Line 622  static void build_page_bitmap(PageDesc *
   
 #ifdef TARGET_HAS_PRECISE_SMC  #ifdef TARGET_HAS_PRECISE_SMC
   
 static void tb_gen_code(CPUState *env,   static void tb_gen_code(CPUState *env,
                         target_ulong pc, target_ulong cs_base, int flags,                          target_ulong pc, target_ulong cs_base, int flags,
                         int cflags)                          int cflags)
 {  {
Line 592  static void tb_gen_code(CPUState *env,  Line 644  static void tb_gen_code(CPUState *env, 
     tb->cs_base = cs_base;      tb->cs_base = cs_base;
     tb->flags = flags;      tb->flags = flags;
     tb->cflags = cflags;      tb->cflags = cflags;
     cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);      cpu_gen_code(env, tb, &code_gen_size);
     code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));      code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
       
     /* check next page if needed */      /* check next page if needed */
     virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;      virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
     phys_page2 = -1;      phys_page2 = -1;
Line 604  static void tb_gen_code(CPUState *env,  Line 656  static void tb_gen_code(CPUState *env, 
     tb_link_phys(tb, phys_pc, phys_page2);      tb_link_phys(tb, phys_pc, phys_page2);
 }  }
 #endif  #endif
       
 /* invalidate all TBs which intersect with the target physical page  /* invalidate all TBs which intersect with the target physical page
    starting in range [start;end[. NOTE: start and end must refer to     starting in range [start;end[. NOTE: start and end must refer to
    the same physical page. 'is_cpu_write_access' should be true if called     the same physical page. 'is_cpu_write_access' should be true if called
    from a real cpu write access: the virtual CPU will exit the current     from a real cpu write access: the virtual CPU will exit the current
    TB if code is modified inside this TB. */     TB if code is modified inside this TB. */
 void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,   void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
                                    int is_cpu_write_access)                                     int is_cpu_write_access)
 {  {
     int n, current_tb_modified, current_tb_not_found, current_flags;      int n, current_tb_modified, current_tb_not_found, current_flags;
Line 621  void tb_invalidate_phys_page_range(targe Line 673  void tb_invalidate_phys_page_range(targe
     target_ulong current_pc, current_cs_base;      target_ulong current_pc, current_cs_base;
   
     p = page_find(start >> TARGET_PAGE_BITS);      p = page_find(start >> TARGET_PAGE_BITS);
     if (!p)       if (!p)
         return;          return;
     if (!p->code_bitmap &&       if (!p->code_bitmap &&
         ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&          ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
         is_cpu_write_access) {          is_cpu_write_access) {
         /* build code bitmap */          /* build code bitmap */
Line 670  void tb_invalidate_phys_page_range(targe Line 722  void tb_invalidate_phys_page_range(targe
                 that the modification is after the current PC, but it                  that the modification is after the current PC, but it
                 would require a specialized function to partially                  would require a specialized function to partially
                 restore the CPU state */                  restore the CPU state */
                   
                 current_tb_modified = 1;                  current_tb_modified = 1;
                 cpu_restore_state(current_tb, env,                   cpu_restore_state(current_tb, env,
                                   env->mem_write_pc, NULL);                                    env->mem_write_pc, NULL);
 #if defined(TARGET_I386)  #if defined(TARGET_I386)
                 current_flags = env->hflags;                  current_flags = env->hflags;
Line 715  void tb_invalidate_phys_page_range(targe Line 767  void tb_invalidate_phys_page_range(targe
            modifying the memory. It will ensure that it cannot modify             modifying the memory. It will ensure that it cannot modify
            itself */             itself */
         env->current_tb = NULL;          env->current_tb = NULL;
         tb_gen_code(env, current_pc, current_cs_base, current_flags,           tb_gen_code(env, current_pc, current_cs_base, current_flags,
                     CF_SINGLE_INSN);                      CF_SINGLE_INSN);
         cpu_resume_from_signal(env, NULL);          cpu_resume_from_signal(env, NULL);
     }      }
Line 730  static inline void tb_invalidate_phys_pa Line 782  static inline void tb_invalidate_phys_pa
 #if 0  #if 0
     if (1) {      if (1) {
         if (loglevel) {          if (loglevel) {
             fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",               fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
                    cpu_single_env->mem_write_vaddr, len,                      cpu_single_env->mem_write_vaddr, len,
                    cpu_single_env->eip,                      cpu_single_env->eip,
                    cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);                     cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
         }          }
     }      }
 #endif  #endif
     p = page_find(start >> TARGET_PAGE_BITS);      p = page_find(start >> TARGET_PAGE_BITS);
     if (!p)       if (!p)
         return;          return;
     if (p->code_bitmap) {      if (p->code_bitmap) {
         offset = start & ~TARGET_PAGE_MASK;          offset = start & ~TARGET_PAGE_MASK;
Line 752  static inline void tb_invalidate_phys_pa Line 804  static inline void tb_invalidate_phys_pa
 }  }
   
 #if !defined(CONFIG_SOFTMMU)  #if !defined(CONFIG_SOFTMMU)
 static void tb_invalidate_phys_page(target_ulong addr,   static void tb_invalidate_phys_page(target_ulong addr,
                                     unsigned long pc, void *puc)                                      unsigned long pc, void *puc)
 {  {
     int n, current_flags, current_tb_modified;      int n, current_flags, current_tb_modified;
Line 765  static void tb_invalidate_phys_page(targ Line 817  static void tb_invalidate_phys_page(targ
   
     addr &= TARGET_PAGE_MASK;      addr &= TARGET_PAGE_MASK;
     p = page_find(addr >> TARGET_PAGE_BITS);      p = page_find(addr >> TARGET_PAGE_BITS);
     if (!p)       if (!p)
         return;          return;
     tb = p->first_tb;      tb = p->first_tb;
     current_tb_modified = 0;      current_tb_modified = 0;
Line 789  static void tb_invalidate_phys_page(targ Line 841  static void tb_invalidate_phys_page(targ
                    that the modification is after the current PC, but it                     that the modification is after the current PC, but it
                    would require a specialized function to partially                     would require a specialized function to partially
                    restore the CPU state */                     restore the CPU state */
               
             current_tb_modified = 1;              current_tb_modified = 1;
             cpu_restore_state(current_tb, env, pc, puc);              cpu_restore_state(current_tb, env, pc, puc);
 #if defined(TARGET_I386)  #if defined(TARGET_I386)
Line 812  static void tb_invalidate_phys_page(targ Line 864  static void tb_invalidate_phys_page(targ
            modifying the memory. It will ensure that it cannot modify             modifying the memory. It will ensure that it cannot modify
            itself */             itself */
         env->current_tb = NULL;          env->current_tb = NULL;
         tb_gen_code(env, current_pc, current_cs_base, current_flags,           tb_gen_code(env, current_pc, current_cs_base, current_flags,
                     CF_SINGLE_INSN);                      CF_SINGLE_INSN);
         cpu_resume_from_signal(env, puc);          cpu_resume_from_signal(env, puc);
     }      }
Line 821  static void tb_invalidate_phys_page(targ Line 873  static void tb_invalidate_phys_page(targ
 #endif  #endif
   
 /* add the tb in the target page and protect it if necessary */  /* add the tb in the target page and protect it if necessary */
 static inline void tb_alloc_page(TranslationBlock *tb,   static inline void tb_alloc_page(TranslationBlock *tb,
                                  unsigned int n, target_ulong page_addr)                                   unsigned int n, target_ulong page_addr)
 {  {
     PageDesc *p;      PageDesc *p;
Line 856  static inline void tb_alloc_page(Transla Line 908  static inline void tb_alloc_page(Transla
             p2->flags &= ~PAGE_WRITE;              p2->flags &= ~PAGE_WRITE;
             page_get_flags(addr);              page_get_flags(addr);
           }            }
         mprotect(g2h(page_addr), qemu_host_page_size,           mprotect(g2h(page_addr), qemu_host_page_size,
                  (prot & PAGE_BITS) & ~PAGE_WRITE);                   (prot & PAGE_BITS) & ~PAGE_WRITE);
 #ifdef DEBUG_TB_INVALIDATE  #ifdef DEBUG_TB_INVALIDATE
         printf("protecting code page: 0x%08lx\n",           printf("protecting code page: 0x" TARGET_FMT_lx "\n",
                page_addr);                 page_addr);
 #endif  #endif
     }      }
Line 881  TranslationBlock *tb_alloc(target_ulong  Line 933  TranslationBlock *tb_alloc(target_ulong 
 {  {
     TranslationBlock *tb;      TranslationBlock *tb;
   
     if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||       if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
         (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)          (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
         return NULL;          return NULL;
     tb = &tbs[nb_tbs++];      tb = &tbs[nb_tbs++];
Line 892  TranslationBlock *tb_alloc(target_ulong  Line 944  TranslationBlock *tb_alloc(target_ulong 
   
 /* add a new TB and link it to the physical page tables. phys_page2 is  /* add a new TB and link it to the physical page tables. phys_page2 is
    (-1) to indicate that only one page contains the TB. */     (-1) to indicate that only one page contains the TB. */
 void tb_link_phys(TranslationBlock *tb,   void tb_link_phys(TranslationBlock *tb,
                   target_ulong phys_pc, target_ulong phys_page2)                    target_ulong phys_pc, target_ulong phys_page2)
 {  {
     unsigned int h;      unsigned int h;
Line 914  void tb_link_phys(TranslationBlock *tb,  Line 966  void tb_link_phys(TranslationBlock *tb, 
     tb->jmp_first = (TranslationBlock *)((long)tb | 2);      tb->jmp_first = (TranslationBlock *)((long)tb | 2);
     tb->jmp_next[0] = NULL;      tb->jmp_next[0] = NULL;
     tb->jmp_next[1] = NULL;      tb->jmp_next[1] = NULL;
 #ifdef USE_CODE_COPY  
     tb->cflags &= ~CF_FP_USED;  
     if (tb->cflags & CF_TB_FP_USED)  
         tb->cflags |= CF_FP_USED;  
 #endif  
   
     /* init original jump addresses */      /* init original jump addresses */
     if (tb->tb_next_offset[0] != 0xffff)      if (tb->tb_next_offset[0] != 0xffff)
Line 958  TranslationBlock *tb_find_pc(unsigned lo Line 1005  TranslationBlock *tb_find_pc(unsigned lo
         } else {          } else {
             m_min = m + 1;              m_min = m + 1;
         }          }
     }       }
     return &tbs[m_max];      return &tbs[m_max];
 }  }
   
Line 994  static inline void tb_reset_jump_recursi Line 1041  static inline void tb_reset_jump_recursi
         }          }
         *ptb = tb->jmp_next[n];          *ptb = tb->jmp_next[n];
         tb->jmp_next[n] = NULL;          tb->jmp_next[n] = NULL;
           
         /* suppress the jump to next tb in generated code */          /* suppress the jump to next tb in generated code */
         tb_reset_jump(tb, n);          tb_reset_jump(tb, n);
   
Line 1012  static void tb_reset_jump_recursive(Tran Line 1059  static void tb_reset_jump_recursive(Tran
 #if defined(TARGET_HAS_ICE)  #if defined(TARGET_HAS_ICE)
 static void breakpoint_invalidate(CPUState *env, target_ulong pc)  static void breakpoint_invalidate(CPUState *env, target_ulong pc)
 {  {
     target_ulong addr, pd;      target_phys_addr_t addr;
       target_ulong pd;
     ram_addr_t ram_addr;      ram_addr_t ram_addr;
     PhysPageDesc *p;      PhysPageDesc *p;
   
Line 1028  static void breakpoint_invalidate(CPUSta Line 1076  static void breakpoint_invalidate(CPUSta
 }  }
 #endif  #endif
   
   /* Add a watchpoint.  */
   int  cpu_watchpoint_insert(CPUState *env, target_ulong addr)
   {
       int i;
   
       for (i = 0; i < env->nb_watchpoints; i++) {
           if (addr == env->watchpoint[i].vaddr)
               return 0;
       }
       if (env->nb_watchpoints >= MAX_WATCHPOINTS)
           return -1;
   
       i = env->nb_watchpoints++;
       env->watchpoint[i].vaddr = addr;
       tlb_flush_page(env, addr);
       /* FIXME: This flush is needed because of the hack to make memory ops
          terminate the TB.  It can be removed once the proper IO trap and
          re-execute bits are in.  */
       tb_flush(env);
       return i;
   }
   
   /* Remove a watchpoint.  */
   int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
   {
       int i;
   
       for (i = 0; i < env->nb_watchpoints; i++) {
           if (addr == env->watchpoint[i].vaddr) {
               env->nb_watchpoints--;
               env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
               tlb_flush_page(env, addr);
               return 0;
           }
       }
       return -1;
   }
   
 /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a  /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
    breakpoint is reached */     breakpoint is reached */
 int cpu_breakpoint_insert(CPUState *env, target_ulong pc)  int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
 {  {
 #if defined(TARGET_HAS_ICE)  #if defined(TARGET_HAS_ICE)
     int i;      int i;
       
     for(i = 0; i < env->nb_breakpoints; i++) {      for(i = 0; i < env->nb_breakpoints; i++) {
         if (env->breakpoints[i] == pc)          if (env->breakpoints[i] == pc)
             return 0;              return 0;
Line 1043  int cpu_breakpoint_insert(CPUState *env, Line 1129  int cpu_breakpoint_insert(CPUState *env,
     if (env->nb_breakpoints >= MAX_BREAKPOINTS)      if (env->nb_breakpoints >= MAX_BREAKPOINTS)
         return -1;          return -1;
     env->breakpoints[env->nb_breakpoints++] = pc;      env->breakpoints[env->nb_breakpoints++] = pc;
       
     breakpoint_invalidate(env, pc);      breakpoint_invalidate(env, pc);
     return 0;      return 0;
 #else  #else
Line 1092  void cpu_set_log(int log_flags) Line 1178  void cpu_set_log(int log_flags)
 {  {
     loglevel = log_flags;      loglevel = log_flags;
     if (loglevel && !logfile) {      if (loglevel && !logfile) {
         logfile = fopen(logfilename, "w");          logfile = fopen(logfilename, log_append ? "a" : "w");
         if (!logfile) {          if (!logfile) {
             perror(logfilename);              perror(logfilename);
             _exit(1);              _exit(1);
Line 1106  void cpu_set_log(int log_flags) Line 1192  void cpu_set_log(int log_flags)
 #else  #else
         setvbuf(logfile, NULL, _IOLBF, 0);          setvbuf(logfile, NULL, _IOLBF, 0);
 #endif  #endif
           log_append = 1;
       }
       if (!loglevel && logfile) {
           fclose(logfile);
           logfile = NULL;
     }      }
 }  }
   
 void cpu_set_log_filename(const char *filename)  void cpu_set_log_filename(const char *filename)
 {  {
     logfilename = strdup(filename);      logfilename = strdup(filename);
       if (logfile) {
           fclose(logfile);
           logfile = NULL;
       }
       cpu_set_log(loglevel);
 }  }
   
 /* mask must never be zero, except for A20 change call */  /* mask must never be zero, except for A20 change call */
Line 1137  void cpu_reset_interrupt(CPUState *env,  Line 1233  void cpu_reset_interrupt(CPUState *env, 
 }  }
   
 CPULogItem cpu_log_items[] = {  CPULogItem cpu_log_items[] = {
     { CPU_LOG_TB_OUT_ASM, "out_asm",       { CPU_LOG_TB_OUT_ASM, "out_asm",
       "show generated host assembly code for each compiled TB" },        "show generated host assembly code for each compiled TB" },
     { CPU_LOG_TB_IN_ASM, "in_asm",      { CPU_LOG_TB_IN_ASM, "in_asm",
       "show target assembly code for each compiled TB" },        "show target assembly code for each compiled TB" },
     { CPU_LOG_TB_OP, "op",       { CPU_LOG_TB_OP, "op",
       "show micro ops for each compiled TB (only usable if 'in_asm' used)" },        "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
 #ifdef TARGET_I386  #ifdef TARGET_I386
     { CPU_LOG_TB_OP_OPT, "op_opt",      { CPU_LOG_TB_OP_OPT, "op_opt",
Line 1152  CPULogItem cpu_log_items[] = { Line 1248  CPULogItem cpu_log_items[] = {
     { CPU_LOG_EXEC, "exec",      { CPU_LOG_EXEC, "exec",
       "show trace before each executed TB (lots of logs)" },        "show trace before each executed TB (lots of logs)" },
     { CPU_LOG_TB_CPU, "cpu",      { CPU_LOG_TB_CPU, "cpu",
       "show CPU state before bloc translation" },        "show CPU state before block translation" },
 #ifdef TARGET_I386  #ifdef TARGET_I386
     { CPU_LOG_PCALL, "pcall",      { CPU_LOG_PCALL, "pcall",
       "show protected mode far calls/returns/exceptions" },        "show protected mode far calls/returns/exceptions" },
Line 1170  static int cmp1(const char *s1, int n, c Line 1266  static int cmp1(const char *s1, int n, c
         return 0;          return 0;
     return memcmp(s1, s2, n) == 0;      return memcmp(s1, s2, n) == 0;
 }  }
         
 /* takes a comma separated list of log masks. Return 0 if error. */  /* takes a comma separated list of log masks. Return 0 if error. */
 int cpu_str_to_log_mask(const char *str)  int cpu_str_to_log_mask(const char *str)
 {  {
Line 1207  int cpu_str_to_log_mask(const char *str) Line 1303  int cpu_str_to_log_mask(const char *str)
 void cpu_abort(CPUState *env, const char *fmt, ...)  void cpu_abort(CPUState *env, const char *fmt, ...)
 {  {
     va_list ap;      va_list ap;
       va_list ap2;
   
     va_start(ap, fmt);      va_start(ap, fmt);
       va_copy(ap2, ap);
     fprintf(stderr, "qemu: fatal: ");      fprintf(stderr, "qemu: fatal: ");
     vfprintf(stderr, fmt, ap);      vfprintf(stderr, fmt, ap);
     fprintf(stderr, "\n");      fprintf(stderr, "\n");
 #ifdef TARGET_I386  #ifdef TARGET_I386
       if(env->intercept & INTERCEPT_SVM_MASK) {
           /* most probably the virtual machine should not
              be shut down but rather caught by the VMM */
           vmexit(SVM_EXIT_SHUTDOWN, 0);
       }
     cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);      cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
 #else  #else
     cpu_dump_state(env, stderr, fprintf, 0);      cpu_dump_state(env, stderr, fprintf, 0);
 #endif  #endif
       if (logfile) {
           fprintf(logfile, "qemu: fatal: ");
           vfprintf(logfile, fmt, ap2);
           fprintf(logfile, "\n");
   #ifdef TARGET_I386
           cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
   #else
           cpu_dump_state(env, logfile, fprintf, 0);
   #endif
           fflush(logfile);
           fclose(logfile);
       }
       va_end(ap2);
     va_end(ap);      va_end(ap);
     abort();      abort();
 }  }
   
   CPUState *cpu_copy(CPUState *env)
   {
       CPUState *new_env = cpu_init(env->cpu_model_str);
       /* preserve chaining and index */
       CPUState *next_cpu = new_env->next_cpu;
       int cpu_index = new_env->cpu_index;
       memcpy(new_env, env, sizeof(CPUState));
       new_env->next_cpu = next_cpu;
       new_env->cpu_index = cpu_index;
       return new_env;
   }
   
 #if !defined(CONFIG_USER_ONLY)  #if !defined(CONFIG_USER_ONLY)
   
 /* NOTE: if flush_global is true, also flush global entries (not  /* NOTE: if flush_global is true, also flush global entries (not
Line 1243  void tlb_flush(CPUState *env, int flush_ Line 1371  void tlb_flush(CPUState *env, int flush_
         env->tlb_table[1][i].addr_read = -1;          env->tlb_table[1][i].addr_read = -1;
         env->tlb_table[1][i].addr_write = -1;          env->tlb_table[1][i].addr_write = -1;
         env->tlb_table[1][i].addr_code = -1;          env->tlb_table[1][i].addr_code = -1;
   #if (NB_MMU_MODES >= 3)
           env->tlb_table[2][i].addr_read = -1;
           env->tlb_table[2][i].addr_write = -1;
           env->tlb_table[2][i].addr_code = -1;
   #if (NB_MMU_MODES == 4)
           env->tlb_table[3][i].addr_read = -1;
           env->tlb_table[3][i].addr_write = -1;
           env->tlb_table[3][i].addr_code = -1;
   #endif
   #endif
     }      }
   
     memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));      memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
Line 1260  void tlb_flush(CPUState *env, int flush_ Line 1398  void tlb_flush(CPUState *env, int flush_
   
 static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)  static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
 {  {
     if (addr == (tlb_entry->addr_read &       if (addr == (tlb_entry->addr_read &
                  (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||                   (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
         addr == (tlb_entry->addr_write &           addr == (tlb_entry->addr_write &
                  (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||                   (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
         addr == (tlb_entry->addr_code &           addr == (tlb_entry->addr_code &
                  (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {                   (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
         tlb_entry->addr_read = -1;          tlb_entry->addr_read = -1;
         tlb_entry->addr_write = -1;          tlb_entry->addr_write = -1;
Line 1288  void tlb_flush_page(CPUState *env, targe Line 1426  void tlb_flush_page(CPUState *env, targe
     i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);      i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     tlb_flush_entry(&env->tlb_table[0][i], addr);      tlb_flush_entry(&env->tlb_table[0][i], addr);
     tlb_flush_entry(&env->tlb_table[1][i], addr);      tlb_flush_entry(&env->tlb_table[1][i], addr);
   #if (NB_MMU_MODES >= 3)
       tlb_flush_entry(&env->tlb_table[2][i], addr);
   #if (NB_MMU_MODES == 4)
       tlb_flush_entry(&env->tlb_table[3][i], addr);
   #endif
   #endif
   
     /* Discard jump cache entries for any tb which might potentially      /* Discard jump cache entries for any tb which might potentially
        overlap the flushed page.  */         overlap the flushed page.  */
Line 1312  void tlb_flush_page(CPUState *env, targe Line 1456  void tlb_flush_page(CPUState *env, targe
    can be detected */     can be detected */
 static void tlb_protect_code(ram_addr_t ram_addr)  static void tlb_protect_code(ram_addr_t ram_addr)
 {  {
     cpu_physical_memory_reset_dirty(ram_addr,       cpu_physical_memory_reset_dirty(ram_addr,
                                     ram_addr + TARGET_PAGE_SIZE,                                      ram_addr + TARGET_PAGE_SIZE,
                                     CODE_DIRTY_FLAG);                                      CODE_DIRTY_FLAG);
 }  }
   
 /* update the TLB so that writes in physical page 'phys_addr' are no longer  /* update the TLB so that writes in physical page 'phys_addr' are no longer
    tested for self modifying code */     tested for self modifying code */
 static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,   static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
                                     target_ulong vaddr)                                      target_ulong vaddr)
 {  {
     phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;      phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
 }  }
   
 static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,   static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
                                          unsigned long start, unsigned long length)                                           unsigned long start, unsigned long length)
 {  {
     unsigned long addr;      unsigned long addr;
Line 1377  void cpu_physical_memory_reset_dirty(ram Line 1521  void cpu_physical_memory_reset_dirty(ram
             tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);              tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
         for(i = 0; i < CPU_TLB_SIZE; i++)          for(i = 0; i < CPU_TLB_SIZE; i++)
             tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);              tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
   #if (NB_MMU_MODES >= 3)
           for(i = 0; i < CPU_TLB_SIZE; i++)
               tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
   #if (NB_MMU_MODES == 4)
           for(i = 0; i < CPU_TLB_SIZE; i++)
               tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
   #endif
   #endif
     }      }
   
 #if !defined(CONFIG_SOFTMMU)  #if !defined(CONFIG_SOFTMMU)
Line 1395  void cpu_physical_memory_reset_dirty(ram Line 1547  void cpu_physical_memory_reset_dirty(ram
                         p->phys_addr >= start && p->phys_addr < end &&                          p->phys_addr >= start && p->phys_addr < end &&
                         (p->prot & PROT_WRITE)) {                          (p->prot & PROT_WRITE)) {
                         if (addr < MMAP_AREA_END) {                          if (addr < MMAP_AREA_END) {
                             mprotect((void *)addr, TARGET_PAGE_SIZE,                               mprotect((void *)addr, TARGET_PAGE_SIZE,
                                      p->prot & ~PROT_WRITE);                                       p->prot & ~PROT_WRITE);
                         }                          }
                     }                      }
Line 1413  static inline void tlb_update_dirty(CPUT Line 1565  static inline void tlb_update_dirty(CPUT
     ram_addr_t ram_addr;      ram_addr_t ram_addr;
   
     if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {      if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
         ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +           ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
             tlb_entry->addend - (unsigned long)phys_ram_base;              tlb_entry->addend - (unsigned long)phys_ram_base;
         if (!cpu_physical_memory_is_dirty(ram_addr)) {          if (!cpu_physical_memory_is_dirty(ram_addr)) {
             tlb_entry->addr_write |= IO_MEM_NOTDIRTY;              tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
Line 1429  void cpu_tlb_update_dirty(CPUState *env) Line 1581  void cpu_tlb_update_dirty(CPUState *env)
         tlb_update_dirty(&env->tlb_table[0][i]);          tlb_update_dirty(&env->tlb_table[0][i]);
     for(i = 0; i < CPU_TLB_SIZE; i++)      for(i = 0; i < CPU_TLB_SIZE; i++)
         tlb_update_dirty(&env->tlb_table[1][i]);          tlb_update_dirty(&env->tlb_table[1][i]);
   #if (NB_MMU_MODES >= 3)
       for(i = 0; i < CPU_TLB_SIZE; i++)
           tlb_update_dirty(&env->tlb_table[2][i]);
   #if (NB_MMU_MODES == 4)
       for(i = 0; i < CPU_TLB_SIZE; i++)
           tlb_update_dirty(&env->tlb_table[3][i]);
   #endif
   #endif
 }  }
   
 static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,   static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
                                   unsigned long start)                                    unsigned long start)
 {  {
     unsigned long addr;      unsigned long addr;
Line 1454  static inline void tlb_set_dirty(CPUStat Line 1614  static inline void tlb_set_dirty(CPUStat
     i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);      i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     tlb_set_dirty1(&env->tlb_table[0][i], addr);      tlb_set_dirty1(&env->tlb_table[0][i], addr);
     tlb_set_dirty1(&env->tlb_table[1][i], addr);      tlb_set_dirty1(&env->tlb_table[1][i], addr);
   #if (NB_MMU_MODES >= 3)
       tlb_set_dirty1(&env->tlb_table[2][i], addr);
   #if (NB_MMU_MODES == 4)
       tlb_set_dirty1(&env->tlb_table[3][i], addr);
   #endif
   #endif
 }  }
   
 /* add a new TLB entry. At most one entry for a given virtual address  /* add a new TLB entry. At most one entry for a given virtual address
    is permitted. Return 0 if OK or 2 if the page could not be mapped     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     (can only happen in non SOFTMMU mode for I/O pages or pages
    conflicting with the host address space). */     conflicting with the host address space). */
 int tlb_set_page_exec(CPUState *env, target_ulong vaddr,   int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
                       target_phys_addr_t paddr, int prot,                         target_phys_addr_t paddr, int prot,
                       int is_user, int is_softmmu)                        int mmu_idx, int is_softmmu)
 {  {
     PhysPageDesc *p;      PhysPageDesc *p;
     unsigned long pd;      unsigned long pd;
Line 1471  int tlb_set_page_exec(CPUState *env, tar Line 1637  int tlb_set_page_exec(CPUState *env, tar
     target_phys_addr_t addend;      target_phys_addr_t addend;
     int ret;      int ret;
     CPUTLBEntry *te;      CPUTLBEntry *te;
       int i;
   
     p = phys_page_find(paddr >> TARGET_PAGE_BITS);      p = phys_page_find(paddr >> TARGET_PAGE_BITS);
     if (!p) {      if (!p) {
Line 1479  int tlb_set_page_exec(CPUState *env, tar Line 1646  int tlb_set_page_exec(CPUState *env, tar
         pd = p->phys_offset;          pd = p->phys_offset;
     }      }
 #if defined(DEBUG_TLB)  #if defined(DEBUG_TLB)
     printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d smmu=%d pd=0x%08lx\n",      printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
            vaddr, (int)paddr, prot, is_user, is_softmmu, pd);             vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
 #endif  #endif
   
     ret = 0;      ret = 0;
 #if !defined(CONFIG_SOFTMMU)  #if !defined(CONFIG_SOFTMMU)
     if (is_softmmu)       if (is_softmmu)
 #endif  #endif
     {      {
         if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {          if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
Line 1497  int tlb_set_page_exec(CPUState *env, tar Line 1664  int tlb_set_page_exec(CPUState *env, tar
             address = vaddr;              address = vaddr;
             addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);              addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
         }          }
           
           /* Make accesses to pages with watchpoints go via the
              watchpoint trap routines.  */
           for (i = 0; i < env->nb_watchpoints; i++) {
               if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
                   if (address & ~TARGET_PAGE_MASK) {
                       env->watchpoint[i].addend = 0;
                       address = vaddr | io_mem_watch;
                   } else {
                       env->watchpoint[i].addend = pd - paddr +
                           (unsigned long) phys_ram_base;
                       /* TODO: Figure out how to make read watchpoints coexist
                          with code.  */
                       pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD;
                   }
               }
           }
   
         index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);          index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
         addend -= vaddr;          addend -= vaddr;
         te = &env->tlb_table[is_user][index];          te = &env->tlb_table[mmu_idx][index];
         te->addend = addend;          te->addend = addend;
         if (prot & PAGE_READ) {          if (prot & PAGE_READ) {
             te->addr_read = address;              te->addr_read = address;
Line 1513  int tlb_set_page_exec(CPUState *env, tar Line 1697  int tlb_set_page_exec(CPUState *env, tar
             te->addr_code = -1;              te->addr_code = -1;
         }          }
         if (prot & PAGE_WRITE) {          if (prot & PAGE_WRITE) {
             if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||               if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
                 (pd & IO_MEM_ROMD)) {                  (pd & IO_MEM_ROMD)) {
                 /* write access calls the I/O callback */                  /* write access calls the I/O callback */
                 te->addr_write = vaddr |                   te->addr_write = vaddr |
                     (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));                      (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
             } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&               } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
                        !cpu_physical_memory_is_dirty(pd)) {                         !cpu_physical_memory_is_dirty(pd)) {
                 te->addr_write = vaddr | IO_MEM_NOTDIRTY;                  te->addr_write = vaddr | IO_MEM_NOTDIRTY;
             } else {              } else {
Line 1542  int tlb_set_page_exec(CPUState *env, tar Line 1726  int tlb_set_page_exec(CPUState *env, tar
                 ret = 2;                  ret = 2;
             } else {              } else {
                 if (prot & PROT_WRITE) {                  if (prot & PROT_WRITE) {
                     if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||                       if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
 #if defined(TARGET_HAS_SMC) || 1  #if defined(TARGET_HAS_SMC) || 1
                         first_tb ||                          first_tb ||
 #endif  #endif
                         ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&                           ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
                          !cpu_physical_memory_is_dirty(pd))) {                           !cpu_physical_memory_is_dirty(pd))) {
                         /* ROM: we do as if code was inside */                          /* ROM: we do as if code was inside */
                         /* if code is present, we only map as read only and save the                          /* if code is present, we only map as read only and save the
                            original mapping */                             original mapping */
                         VirtPageDesc *vp;                          VirtPageDesc *vp;
                           
                         vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);                          vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
                         vp->phys_addr = pd;                          vp->phys_addr = pd;
                         vp->prot = prot;                          vp->prot = prot;
Line 1560  int tlb_set_page_exec(CPUState *env, tar Line 1744  int tlb_set_page_exec(CPUState *env, tar
                         prot &= ~PAGE_WRITE;                          prot &= ~PAGE_WRITE;
                     }                      }
                 }                  }
                 map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,                   map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
                                 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));                                  MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
                 if (map_addr == MAP_FAILED) {                  if (map_addr == MAP_FAILED) {
                     cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",                      cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
Line 1598  int page_unprotect(target_ulong addr, un Line 1782  int page_unprotect(target_ulong addr, un
     if (!(vp->prot & PAGE_WRITE))      if (!(vp->prot & PAGE_WRITE))
         return 0;          return 0;
 #if defined(DEBUG_TLB)  #if defined(DEBUG_TLB)
     printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",       printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
            addr, vp->phys_addr, vp->prot);             addr, vp->phys_addr, vp->prot);
 #endif  #endif
     if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)      if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
Line 1624  void tlb_flush_page(CPUState *env, targe Line 1808  void tlb_flush_page(CPUState *env, targe
 {  {
 }  }
   
 int tlb_set_page_exec(CPUState *env, target_ulong vaddr,   int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
                       target_phys_addr_t paddr, int prot,                         target_phys_addr_t paddr, int prot,
                       int is_user, int is_softmmu)                        int mmu_idx, int is_softmmu)
 {  {
     return 0;      return 0;
 }  }
Line 1657  void page_dump(FILE *f) Line 1841  void page_dump(FILE *f)
                 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);                  end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
                 if (start != -1) {                  if (start != -1) {
                     fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",                      fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
                             start, end, end - start,                               start, end, end - start,
                             prot & PAGE_READ ? 'r' : '-',                              prot & PAGE_READ ? 'r' : '-',
                             prot & PAGE_WRITE ? 'w' : '-',                              prot & PAGE_WRITE ? 'w' : '-',
                             prot & PAGE_EXEC ? 'x' : '-');                              prot & PAGE_EXEC ? 'x' : '-');
Line 1701  void page_set_flags(target_ulong start,  Line 1885  void page_set_flags(target_ulong start, 
         p = page_find_alloc(addr >> TARGET_PAGE_BITS);          p = page_find_alloc(addr >> TARGET_PAGE_BITS);
         /* if the write protection is set, then we invalidate the code          /* if the write protection is set, then we invalidate the code
            inside */             inside */
         if (!(p->flags & PAGE_WRITE) &&           if (!(p->flags & PAGE_WRITE) &&
             (flags & PAGE_WRITE) &&              (flags & PAGE_WRITE) &&
             p->first_tb) {              p->first_tb) {
             tb_invalidate_phys_page(addr, 0, NULL);              tb_invalidate_phys_page(addr, 0, NULL);
Line 1711  void page_set_flags(target_ulong start,  Line 1895  void page_set_flags(target_ulong start, 
     spin_unlock(&tb_lock);      spin_unlock(&tb_lock);
 }  }
   
   int page_check_range(target_ulong start, target_ulong len, int flags)
   {
       PageDesc *p;
       target_ulong end;
       target_ulong addr;
   
       end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
       start = start & TARGET_PAGE_MASK;
   
       if( end < start )
           /* we've wrapped around */
           return -1;
       for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
           p = page_find(addr >> TARGET_PAGE_BITS);
           if( !p )
               return -1;
           if( !(p->flags & PAGE_VALID) )
               return -1;
   
           if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
               return -1;
           if (flags & PAGE_WRITE) {
               if (!(p->flags & PAGE_WRITE_ORG))
                   return -1;
               /* unprotect the page if it was put read-only because it
                  contains translated code */
               if (!(p->flags & PAGE_WRITE)) {
                   if (!page_unprotect(addr, 0, NULL))
                       return -1;
               }
               return 0;
           }
       }
       return 0;
   }
   
 /* called from signal handler: invalidate the code and unprotect the  /* called from signal handler: invalidate the code and unprotect the
    page. Return TRUE if the fault was succesfully handled. */     page. Return TRUE if the fault was succesfully handled. */
 int page_unprotect(target_ulong address, unsigned long pc, void *puc)  int page_unprotect(target_ulong address, unsigned long pc, void *puc)
Line 1736  int page_unprotect(target_ulong address, Line 1956  int page_unprotect(target_ulong address,
     if (prot & PAGE_WRITE_ORG) {      if (prot & PAGE_WRITE_ORG) {
         pindex = (address - host_start) >> TARGET_PAGE_BITS;          pindex = (address - host_start) >> TARGET_PAGE_BITS;
         if (!(p1[pindex].flags & PAGE_WRITE)) {          if (!(p1[pindex].flags & PAGE_WRITE)) {
             mprotect((void *)g2h(host_start), qemu_host_page_size,               mprotect((void *)g2h(host_start), qemu_host_page_size,
                      (prot & PAGE_BITS) | PAGE_WRITE);                       (prot & PAGE_BITS) | PAGE_WRITE);
             p1[pindex].flags |= PAGE_WRITE;              p1[pindex].flags |= PAGE_WRITE;
             /* and since the content will be modified, we must invalidate              /* and since the content will be modified, we must invalidate
Line 1751  int page_unprotect(target_ulong address, Line 1971  int page_unprotect(target_ulong address,
     return 0;      return 0;
 }  }
   
 /* call this function when system calls directly modify a memory area */  
 /* ??? This should be redundant now we have lock_user.  */  
 void page_unprotect_range(target_ulong data, target_ulong data_size)  
 {  
     target_ulong start, end, addr;  
   
     start = data;  
     end = start + data_size;  
     start &= TARGET_PAGE_MASK;  
     end = TARGET_PAGE_ALIGN(end);  
     for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {  
         page_unprotect(addr, 0, NULL);  
     }  
 }  
   
 static inline void tlb_set_dirty(CPUState *env,  static inline void tlb_set_dirty(CPUState *env,
                                  unsigned long addr, target_ulong vaddr)                                   unsigned long addr, target_ulong vaddr)
 {  {
 }  }
 #endif /* defined(CONFIG_USER_ONLY) */  #endif /* defined(CONFIG_USER_ONLY) */
   
   static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
                                int memory);
   static void *subpage_init (target_phys_addr_t base, uint32_t *phys,
                              int orig_memory);
   #define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
                         need_subpage)                                     \
       do {                                                                \
           if (addr > start_addr)                                          \
               start_addr2 = 0;                                            \
           else {                                                          \
               start_addr2 = start_addr & ~TARGET_PAGE_MASK;               \
               if (start_addr2 > 0)                                        \
                   need_subpage = 1;                                       \
           }                                                               \
                                                                           \
           if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE)        \
               end_addr2 = TARGET_PAGE_SIZE - 1;                           \
           else {                                                          \
               end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
               if (end_addr2 < TARGET_PAGE_SIZE - 1)                       \
                   need_subpage = 1;                                       \
           }                                                               \
       } while (0)
   
 /* register physical memory. 'size' must be a multiple of the target  /* register physical memory. 'size' must be a multiple of the target
    page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an     page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
    io memory page */     io memory page */
 void cpu_register_physical_memory(target_phys_addr_t start_addr,   void cpu_register_physical_memory(target_phys_addr_t start_addr,
                                   unsigned long size,                                    unsigned long size,
                                   unsigned long phys_offset)                                    unsigned long phys_offset)
 {  {
     target_phys_addr_t addr, end_addr;      target_phys_addr_t addr, end_addr;
     PhysPageDesc *p;      PhysPageDesc *p;
     CPUState *env;      CPUState *env;
       unsigned long orig_size = size;
       void *subpage;
   
     size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;      size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
     end_addr = start_addr + size;      end_addr = start_addr + (target_phys_addr_t)size;
     for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {      for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
         p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);          p = phys_page_find(addr >> TARGET_PAGE_BITS);
         p->phys_offset = phys_offset;          if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
         if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||              unsigned long orig_memory = p->phys_offset;
             (phys_offset & IO_MEM_ROMD))              target_phys_addr_t start_addr2, end_addr2;
             phys_offset += TARGET_PAGE_SIZE;              int need_subpage = 0;
   
               CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
                             need_subpage);
               if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
                   if (!(orig_memory & IO_MEM_SUBPAGE)) {
                       subpage = subpage_init((addr & TARGET_PAGE_MASK),
                                              &p->phys_offset, orig_memory);
                   } else {
                       subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
                                               >> IO_MEM_SHIFT];
                   }
                   subpage_register(subpage, start_addr2, end_addr2, phys_offset);
               } else {
                   p->phys_offset = phys_offset;
                   if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
                       (phys_offset & IO_MEM_ROMD))
                       phys_offset += TARGET_PAGE_SIZE;
               }
           } else {
               p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
               p->phys_offset = phys_offset;
               if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
                   (phys_offset & IO_MEM_ROMD))
                   phys_offset += TARGET_PAGE_SIZE;
               else {
                   target_phys_addr_t start_addr2, end_addr2;
                   int need_subpage = 0;
   
                   CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
                                 end_addr2, need_subpage);
   
                   if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
                       subpage = subpage_init((addr & TARGET_PAGE_MASK),
                                              &p->phys_offset, IO_MEM_UNASSIGNED);
                       subpage_register(subpage, start_addr2, end_addr2,
                                        phys_offset);
                   }
               }
           }
     }      }
       
     /* since each CPU stores ram addresses in its TLB cache, we must      /* since each CPU stores ram addresses in its TLB cache, we must
        reset the modified entries */         reset the modified entries */
     /* XXX: slow ! */      /* XXX: slow ! */
Line 1812  uint32_t cpu_get_physical_page_desc(targ Line 2082  uint32_t cpu_get_physical_page_desc(targ
     return p->phys_offset;      return p->phys_offset;
 }  }
   
   /* XXX: better than nothing */
   ram_addr_t qemu_ram_alloc(unsigned int size)
   {
       ram_addr_t addr;
       if ((phys_ram_alloc_offset + size) >= phys_ram_size) {
           fprintf(stderr, "Not enough memory (requested_size = %u, max memory = %d)\n",
                   size, phys_ram_size);
           abort();
       }
       addr = phys_ram_alloc_offset;
       phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
       return addr;
   }
   
   void qemu_ram_free(ram_addr_t addr)
   {
   }
   
 static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)  static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
 {  {
 #ifdef DEBUG_UNASSIGNED  #ifdef DEBUG_UNASSIGNED
     printf("Unassigned mem read  0x%08x\n", (int)addr);      printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
   #endif
   #ifdef TARGET_SPARC
       do_unassigned_access(addr, 0, 0, 0);
   #elif TARGET_CRIS
       do_unassigned_access(addr, 0, 0, 0);
 #endif  #endif
     return 0;      return 0;
 }  }
Line 1823  static uint32_t unassigned_mem_readb(voi Line 2116  static uint32_t unassigned_mem_readb(voi
 static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)  static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {  {
 #ifdef DEBUG_UNASSIGNED  #ifdef DEBUG_UNASSIGNED
     printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val);      printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
   #endif
   #ifdef TARGET_SPARC
       do_unassigned_access(addr, 1, 0, 0);
   #elif TARGET_CRIS
       do_unassigned_access(addr, 1, 0, 0);
 #endif  #endif
 }  }
   
Line 1929  static CPUWriteMemoryFunc *notdirty_mem_ Line 2227  static CPUWriteMemoryFunc *notdirty_mem_
     notdirty_mem_writel,      notdirty_mem_writel,
 };  };
   
   #if defined(CONFIG_SOFTMMU)
   /* Watchpoint access routines.  Watchpoints are inserted using TLB tricks,
      so these check for a hit then pass through to the normal out-of-line
      phys routines.  */
   static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
   {
       return ldub_phys(addr);
   }
   
   static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
   {
       return lduw_phys(addr);
   }
   
   static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
   {
       return ldl_phys(addr);
   }
   
   /* Generate a debug exception if a watchpoint has been hit.
      Returns the real physical address of the access.  addr will be a host
      address in case of a RAM location.  */
   static target_ulong check_watchpoint(target_phys_addr_t addr)
   {
       CPUState *env = cpu_single_env;
       target_ulong watch;
       target_ulong retaddr;
       int i;
   
       retaddr = addr;
       for (i = 0; i < env->nb_watchpoints; i++) {
           watch = env->watchpoint[i].vaddr;
           if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) {
               retaddr = addr - env->watchpoint[i].addend;
               if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) {
                   cpu_single_env->watchpoint_hit = i + 1;
                   cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG);
                   break;
               }
           }
       }
       return retaddr;
   }
   
   static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
                                uint32_t val)
   {
       addr = check_watchpoint(addr);
       stb_phys(addr, val);
   }
   
   static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
                                uint32_t val)
   {
       addr = check_watchpoint(addr);
       stw_phys(addr, val);
   }
   
   static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
                                uint32_t val)
   {
       addr = check_watchpoint(addr);
       stl_phys(addr, val);
   }
   
   static CPUReadMemoryFunc *watch_mem_read[3] = {
       watch_mem_readb,
       watch_mem_readw,
       watch_mem_readl,
   };
   
   static CPUWriteMemoryFunc *watch_mem_write[3] = {
       watch_mem_writeb,
       watch_mem_writew,
       watch_mem_writel,
   };
   #endif
   
   static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
                                    unsigned int len)
   {
       uint32_t ret;
       unsigned int idx;
   
       idx = SUBPAGE_IDX(addr - mmio->base);
   #if defined(DEBUG_SUBPAGE)
       printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
              mmio, len, addr, idx);
   #endif
       ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], addr);
   
       return ret;
   }
   
   static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
                                 uint32_t value, unsigned int len)
   {
       unsigned int idx;
   
       idx = SUBPAGE_IDX(addr - mmio->base);
   #if defined(DEBUG_SUBPAGE)
       printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
              mmio, len, addr, idx, value);
   #endif
       (**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], addr, value);
   }
   
   static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
   {
   #if defined(DEBUG_SUBPAGE)
       printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
   #endif
   
       return subpage_readlen(opaque, addr, 0);
   }
   
   static void subpage_writeb (void *opaque, target_phys_addr_t addr,
                               uint32_t value)
   {
   #if defined(DEBUG_SUBPAGE)
       printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
   #endif
       subpage_writelen(opaque, addr, value, 0);
   }
   
   static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
   {
   #if defined(DEBUG_SUBPAGE)
       printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
   #endif
   
       return subpage_readlen(opaque, addr, 1);
   }
   
   static void subpage_writew (void *opaque, target_phys_addr_t addr,
                               uint32_t value)
   {
   #if defined(DEBUG_SUBPAGE)
       printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
   #endif
       subpage_writelen(opaque, addr, value, 1);
   }
   
   static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
   {
   #if defined(DEBUG_SUBPAGE)
       printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
   #endif
   
       return subpage_readlen(opaque, addr, 2);
   }
   
   static void subpage_writel (void *opaque,
                            target_phys_addr_t addr, uint32_t value)
   {
   #if defined(DEBUG_SUBPAGE)
       printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
   #endif
       subpage_writelen(opaque, addr, value, 2);
   }
   
   static CPUReadMemoryFunc *subpage_read[] = {
       &subpage_readb,
       &subpage_readw,
       &subpage_readl,
   };
   
   static CPUWriteMemoryFunc *subpage_write[] = {
       &subpage_writeb,
       &subpage_writew,
       &subpage_writel,
   };
   
   static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
                                int memory)
   {
       int idx, eidx;
       unsigned int i;
   
       if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
           return -1;
       idx = SUBPAGE_IDX(start);
       eidx = SUBPAGE_IDX(end);
   #if defined(DEBUG_SUBPAGE)
       printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
              mmio, start, end, idx, eidx, memory);
   #endif
       memory >>= IO_MEM_SHIFT;
       for (; idx <= eidx; idx++) {
           for (i = 0; i < 4; i++) {
               if (io_mem_read[memory][i]) {
                   mmio->mem_read[idx][i] = &io_mem_read[memory][i];
                   mmio->opaque[idx][0][i] = io_mem_opaque[memory];
               }
               if (io_mem_write[memory][i]) {
                   mmio->mem_write[idx][i] = &io_mem_write[memory][i];
                   mmio->opaque[idx][1][i] = io_mem_opaque[memory];
               }
           }
       }
   
       return 0;
   }
   
   static void *subpage_init (target_phys_addr_t base, uint32_t *phys,
                              int orig_memory)
   {
       subpage_t *mmio;
       int subpage_memory;
   
       mmio = qemu_mallocz(sizeof(subpage_t));
       if (mmio != NULL) {
           mmio->base = base;
           subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
   #if defined(DEBUG_SUBPAGE)
           printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
                  mmio, base, TARGET_PAGE_SIZE, subpage_memory);
   #endif
           *phys = subpage_memory | IO_MEM_SUBPAGE;
           subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory);
       }
   
       return mmio;
   }
   
 static void io_mem_init(void)  static void io_mem_init(void)
 {  {
     cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);      cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
Line 1936  static void io_mem_init(void) Line 2459  static void io_mem_init(void)
     cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);      cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
     io_mem_nb = 5;      io_mem_nb = 5;
   
   #if defined(CONFIG_SOFTMMU)
       io_mem_watch = cpu_register_io_memory(-1, watch_mem_read,
                                             watch_mem_write, NULL);
   #endif
     /* alloc dirty bits array */      /* alloc dirty bits array */
     phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);      phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
     memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);      memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
Line 1943  static void io_mem_init(void) Line 2470  static void io_mem_init(void)
   
 /* mem_read and mem_write are arrays of functions containing the  /* mem_read and mem_write are arrays of functions containing the
    function to access byte (index 0), word (index 1) and dword (index     function to access byte (index 0), word (index 1) and dword (index
    2). All functions must be supplied. If io_index is non zero, the     2). Functions can be omitted with a NULL function pointer. The
    corresponding io zone is modified. If it is zero, a new io zone is     registered functions may be modified dynamically later.
    allocated. The return value can be used with     If io_index is non zero, the corresponding io zone is
    cpu_register_physical_memory(). (-1) is returned if error. */     modified. If it is zero, a new io zone is allocated. The return
      value can be used with cpu_register_physical_memory(). (-1) is
      returned if error. */
 int cpu_register_io_memory(int io_index,  int cpu_register_io_memory(int io_index,
                            CPUReadMemoryFunc **mem_read,                             CPUReadMemoryFunc **mem_read,
                            CPUWriteMemoryFunc **mem_write,                             CPUWriteMemoryFunc **mem_write,
                            void *opaque)                             void *opaque)
 {  {
     int i;      int i, subwidth = 0;
   
     if (io_index <= 0) {      if (io_index <= 0) {
         if (io_mem_nb >= IO_MEM_NB_ENTRIES)          if (io_mem_nb >= IO_MEM_NB_ENTRIES)
Line 1964  int cpu_register_io_memory(int io_index, Line 2493  int cpu_register_io_memory(int io_index,
     }      }
   
     for(i = 0;i < 3; i++) {      for(i = 0;i < 3; i++) {
           if (!mem_read[i] || !mem_write[i])
               subwidth = IO_MEM_SUBWIDTH;
         io_mem_read[io_index][i] = mem_read[i];          io_mem_read[io_index][i] = mem_read[i];
         io_mem_write[io_index][i] = mem_write[i];          io_mem_write[io_index][i] = mem_write[i];
     }      }
     io_mem_opaque[io_index] = opaque;      io_mem_opaque[io_index] = opaque;
     return io_index << IO_MEM_SHIFT;      return (io_index << IO_MEM_SHIFT) | subwidth;
 }  }
   
 CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)  CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
Line 1983  CPUReadMemoryFunc **cpu_get_io_memory_re Line 2514  CPUReadMemoryFunc **cpu_get_io_memory_re
   
 /* physical memory access (slow version, mainly for debug) */  /* physical memory access (slow version, mainly for debug) */
 #if defined(CONFIG_USER_ONLY)  #if defined(CONFIG_USER_ONLY)
 void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,   void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                             int len, int is_write)                              int len, int is_write)
 {  {
     int l, flags;      int l, flags;
Line 2001  void cpu_physical_memory_rw(target_phys_ Line 2532  void cpu_physical_memory_rw(target_phys_
         if (is_write) {          if (is_write) {
             if (!(flags & PAGE_WRITE))              if (!(flags & PAGE_WRITE))
                 return;                  return;
             p = lock_user(addr, len, 0);              /* XXX: this code should not depend on lock_user */
               if (!(p = lock_user(VERIFY_WRITE, addr, len, 0)))
                   /* FIXME - should this return an error rather than just fail? */
                   return;
             memcpy(p, buf, len);              memcpy(p, buf, len);
             unlock_user(p, addr, len);              unlock_user(p, addr, len);
         } else {          } else {
             if (!(flags & PAGE_READ))              if (!(flags & PAGE_READ))
                 return;                  return;
             p = lock_user(addr, len, 1);              /* XXX: this code should not depend on lock_user */
               if (!(p = lock_user(VERIFY_READ, addr, len, 1)))
                   /* FIXME - should this return an error rather than just fail? */
                   return;
             memcpy(buf, p, len);              memcpy(buf, p, len);
             unlock_user(p, addr, 0);              unlock_user(p, addr, 0);
         }          }
Line 2018  void cpu_physical_memory_rw(target_phys_ Line 2555  void cpu_physical_memory_rw(target_phys_
 }  }
   
 #else  #else
 void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,   void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                             int len, int is_write)                              int len, int is_write)
 {  {
     int l, io_index;      int l, io_index;
Line 2027  void cpu_physical_memory_rw(target_phys_ Line 2564  void cpu_physical_memory_rw(target_phys_
     target_phys_addr_t page;      target_phys_addr_t page;
     unsigned long pd;      unsigned long pd;
     PhysPageDesc *p;      PhysPageDesc *p;
       
     while (len > 0) {      while (len > 0) {
         page = addr & TARGET_PAGE_MASK;          page = addr & TARGET_PAGE_MASK;
         l = (page + TARGET_PAGE_SIZE) - addr;          l = (page + TARGET_PAGE_SIZE) - addr;
Line 2039  void cpu_physical_memory_rw(target_phys_ Line 2576  void cpu_physical_memory_rw(target_phys_
         } else {          } else {
             pd = p->phys_offset;              pd = p->phys_offset;
         }          }
           
         if (is_write) {          if (is_write) {
             if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {              if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
                 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);                  io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
Line 2071  void cpu_physical_memory_rw(target_phys_ Line 2608  void cpu_physical_memory_rw(target_phys_
                     /* invalidate code */                      /* invalidate code */
                     tb_invalidate_phys_page_range(addr1, addr1 + l, 0);                      tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
                     /* set dirty bit */                      /* set dirty bit */
                     phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=                       phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
                         (0xff & ~CODE_DIRTY_FLAG);                          (0xff & ~CODE_DIRTY_FLAG);
                 }                  }
             }              }
         } else {          } else {
             if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&               if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
                 !(pd & IO_MEM_ROMD)) {                  !(pd & IO_MEM_ROMD)) {
                 /* I/O case */                  /* I/O case */
                 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);                  io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
Line 2098  void cpu_physical_memory_rw(target_phys_ Line 2635  void cpu_physical_memory_rw(target_phys_
                 }                  }
             } else {              } else {
                 /* RAM case */                  /* RAM case */
                 ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +                   ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
                     (addr & ~TARGET_PAGE_MASK);                      (addr & ~TARGET_PAGE_MASK);
                 memcpy(buf, ptr, l);                  memcpy(buf, ptr, l);
             }              }
Line 2110  void cpu_physical_memory_rw(target_phys_ Line 2647  void cpu_physical_memory_rw(target_phys_
 }  }
   
 /* used for ROM loading : can write in RAM and ROM */  /* used for ROM loading : can write in RAM and ROM */
 void cpu_physical_memory_write_rom(target_phys_addr_t addr,   void cpu_physical_memory_write_rom(target_phys_addr_t addr,
                                    const uint8_t *buf, int len)                                     const uint8_t *buf, int len)
 {  {
     int l;      int l;
Line 2118  void cpu_physical_memory_write_rom(targe Line 2655  void cpu_physical_memory_write_rom(targe
     target_phys_addr_t page;      target_phys_addr_t page;
     unsigned long pd;      unsigned long pd;
     PhysPageDesc *p;      PhysPageDesc *p;
       
     while (len > 0) {      while (len > 0) {
         page = addr & TARGET_PAGE_MASK;          page = addr & TARGET_PAGE_MASK;
         l = (page + TARGET_PAGE_SIZE) - addr;          l = (page + TARGET_PAGE_SIZE) - addr;
Line 2130  void cpu_physical_memory_write_rom(targe Line 2667  void cpu_physical_memory_write_rom(targe
         } else {          } else {
             pd = p->phys_offset;              pd = p->phys_offset;
         }          }
           
         if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&          if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
             (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&              (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
             !(pd & IO_MEM_ROMD)) {              !(pd & IO_MEM_ROMD)) {
Line 2164  uint32_t ldl_phys(target_phys_addr_t add Line 2701  uint32_t ldl_phys(target_phys_addr_t add
     } else {      } else {
         pd = p->phys_offset;          pd = p->phys_offset;
     }      }
           
     if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&       if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
         !(pd & IO_MEM_ROMD)) {          !(pd & IO_MEM_ROMD)) {
         /* I/O case */          /* I/O case */
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);          io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);          val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
     } else {      } else {
         /* RAM case */          /* RAM case */
         ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +           ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
             (addr & ~TARGET_PAGE_MASK);              (addr & ~TARGET_PAGE_MASK);
         val = ldl_p(ptr);          val = ldl_p(ptr);
     }      }
Line 2194  uint64_t ldq_phys(target_phys_addr_t add Line 2731  uint64_t ldq_phys(target_phys_addr_t add
     } else {      } else {
         pd = p->phys_offset;          pd = p->phys_offset;
     }      }
           
     if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&      if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
         !(pd & IO_MEM_ROMD)) {          !(pd & IO_MEM_ROMD)) {
         /* I/O case */          /* I/O case */
Line 2208  uint64_t ldq_phys(target_phys_addr_t add Line 2745  uint64_t ldq_phys(target_phys_addr_t add
 #endif  #endif
     } else {      } else {
         /* RAM case */          /* RAM case */
         ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +           ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
             (addr & ~TARGET_PAGE_MASK);              (addr & ~TARGET_PAGE_MASK);
         val = ldq_p(ptr);          val = ldq_p(ptr);
     }      }
Line 2247  void stl_phys_notdirty(target_phys_addr_ Line 2784  void stl_phys_notdirty(target_phys_addr_
     } else {      } else {
         pd = p->phys_offset;          pd = p->phys_offset;
     }      }
           
     if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {      if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);          io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);          io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
     } else {      } else {
         ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +           ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
             (addr & ~TARGET_PAGE_MASK);              (addr & ~TARGET_PAGE_MASK);
         stl_p(ptr, val);          stl_p(ptr, val);
     }      }
 }  }
   
   void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
   {
       int io_index;
       uint8_t *ptr;
       unsigned long pd;
       PhysPageDesc *p;
   
       p = phys_page_find(addr >> TARGET_PAGE_BITS);
       if (!p) {
           pd = IO_MEM_UNASSIGNED;
       } else {
           pd = p->phys_offset;
       }
   
       if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
           io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
   #ifdef TARGET_WORDS_BIGENDIAN
           io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
           io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
   #else
           io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
           io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
   #endif
       } else {
           ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
               (addr & ~TARGET_PAGE_MASK);
           stq_p(ptr, val);
       }
   }
   
 /* warning: addr must be aligned */  /* warning: addr must be aligned */
 void stl_phys(target_phys_addr_t addr, uint32_t val)  void stl_phys(target_phys_addr_t addr, uint32_t val)
 {  {
Line 2272  void stl_phys(target_phys_addr_t addr, u Line 2839  void stl_phys(target_phys_addr_t addr, u
     } else {      } else {
         pd = p->phys_offset;          pd = p->phys_offset;
     }      }
           
     if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {      if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);          io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);          io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
Line 2316  void stq_phys(target_phys_addr_t addr, u Line 2883  void stq_phys(target_phys_addr_t addr, u
 #endif  #endif
   
 /* virtual memory access for debug */  /* virtual memory access for debug */
 int cpu_memory_rw_debug(CPUState *env, target_ulong addr,   int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
                         uint8_t *buf, int len, int is_write)                          uint8_t *buf, int len, int is_write)
 {  {
     int l;      int l;
     target_ulong page, phys_addr;      target_phys_addr_t phys_addr;
       target_ulong page;
   
     while (len > 0) {      while (len > 0) {
         page = addr & TARGET_PAGE_MASK;          page = addr & TARGET_PAGE_MASK;
Line 2331  int cpu_memory_rw_debug(CPUState *env, t Line 2899  int cpu_memory_rw_debug(CPUState *env, t
         l = (page + TARGET_PAGE_SIZE) - addr;          l = (page + TARGET_PAGE_SIZE) - addr;
         if (l > len)          if (l > len)
             l = len;              l = len;
         cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),           cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
                                buf, l, is_write);                                 buf, l, is_write);
         len -= l;          len -= l;
         buf += l;          buf += l;
Line 2346  void dump_exec_info(FILE *f, Line 2914  void dump_exec_info(FILE *f,
     int i, target_code_size, max_target_code_size;      int i, target_code_size, max_target_code_size;
     int direct_jmp_count, direct_jmp2_count, cross_page;      int direct_jmp_count, direct_jmp2_count, cross_page;
     TranslationBlock *tb;      TranslationBlock *tb;
       
     target_code_size = 0;      target_code_size = 0;
     max_target_code_size = 0;      max_target_code_size = 0;
     cross_page = 0;      cross_page = 0;
Line 2368  void dump_exec_info(FILE *f, Line 2936  void dump_exec_info(FILE *f,
     }      }
     /* XXX: avoid using doubles ? */      /* XXX: avoid using doubles ? */
     cpu_fprintf(f, "TB count            %d\n", nb_tbs);      cpu_fprintf(f, "TB count            %d\n", nb_tbs);
     cpu_fprintf(f, "TB avg target size  %d max=%d bytes\n",       cpu_fprintf(f, "TB avg target size  %d max=%d bytes\n",
                 nb_tbs ? target_code_size / nb_tbs : 0,                  nb_tbs ? target_code_size / nb_tbs : 0,
                 max_target_code_size);                  max_target_code_size);
     cpu_fprintf(f, "TB avg host size    %d bytes (expansion ratio: %0.1f)\n",       cpu_fprintf(f, "TB avg host size    %d bytes (expansion ratio: %0.1f)\n",
                 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,                  nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
                 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);                  target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
     cpu_fprintf(f, "cross page TB count %d (%d%%)\n",       cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
             cross_page,               cross_page,
             nb_tbs ? (cross_page * 100) / nb_tbs : 0);              nb_tbs ? (cross_page * 100) / nb_tbs : 0);
     cpu_fprintf(f, "direct jump count   %d (%d%%) (2 jumps=%d %d%%)\n",      cpu_fprintf(f, "direct jump count   %d (%d%%) (2 jumps=%d %d%%)\n",
                 direct_jmp_count,                   direct_jmp_count,
                 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,                  nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
                 direct_jmp2_count,                  direct_jmp2_count,
                 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);                  nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
Line 2387  void dump_exec_info(FILE *f, Line 2955  void dump_exec_info(FILE *f,
     cpu_fprintf(f, "TLB flush count     %d\n", tlb_flush_count);      cpu_fprintf(f, "TLB flush count     %d\n", tlb_flush_count);
 }  }
   
 #if !defined(CONFIG_USER_ONLY)   #if !defined(CONFIG_USER_ONLY)
   
 #define MMUSUFFIX _cmmu  #define MMUSUFFIX _cmmu
 #define GETPC() NULL  #define GETPC() NULL

Removed from v.1.1.1.5  
changed lines
  Added in v.1.1.1.6


unix.superglobalmegacorp.com