154936004Sbellard /* 2fd6ce8f6Sbellard * virtual page mapping and translated block handling 354936004Sbellard * 454936004Sbellard * Copyright (c) 2003 Fabrice Bellard 554936004Sbellard * 654936004Sbellard * This library is free software; you can redistribute it and/or 754936004Sbellard * modify it under the terms of the GNU Lesser General Public 854936004Sbellard * License as published by the Free Software Foundation; either 954936004Sbellard * version 2 of the License, or (at your option) any later version. 1054936004Sbellard * 1154936004Sbellard * This library is distributed in the hope that it will be useful, 1254936004Sbellard * but WITHOUT ANY WARRANTY; without even the implied warranty of 1354936004Sbellard * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1454936004Sbellard * Lesser General Public License for more details. 1554936004Sbellard * 1654936004Sbellard * You should have received a copy of the GNU Lesser General Public 1754936004Sbellard * License along with this library; if not, write to the Free Software 1854936004Sbellard * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1954936004Sbellard */ 2067b915a5Sbellard #include "config.h" 21d5a8f07cSbellard #ifdef _WIN32 22d5a8f07cSbellard #include <windows.h> 23d5a8f07cSbellard #else 24a98d49b1Sbellard #include <sys/types.h> 25d5a8f07cSbellard #include <sys/mman.h> 26d5a8f07cSbellard #endif 2754936004Sbellard #include <stdlib.h> 2854936004Sbellard #include <stdio.h> 2954936004Sbellard #include <stdarg.h> 3054936004Sbellard #include <string.h> 3154936004Sbellard #include <errno.h> 3254936004Sbellard #include <unistd.h> 3354936004Sbellard #include <inttypes.h> 3454936004Sbellard 356180a181Sbellard #include "cpu.h" 366180a181Sbellard #include "exec-all.h" 3754936004Sbellard 38fd6ce8f6Sbellard //#define DEBUG_TB_INVALIDATE 3966e85a21Sbellard //#define DEBUG_FLUSH 409fa3e853Sbellard //#define DEBUG_TLB 41fd6ce8f6Sbellard 42fd6ce8f6Sbellard /* make various TB consistency checks */ 43fd6ce8f6Sbellard //#define DEBUG_TB_CHECK 4498857888Sbellard //#define DEBUG_TLB_CHECK 45fd6ce8f6Sbellard 46fd6ce8f6Sbellard /* threshold to flush the translated code buffer */ 47fd6ce8f6Sbellard #define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE) 48fd6ce8f6Sbellard 499fa3e853Sbellard #define SMC_BITMAP_USE_THRESHOLD 10 509fa3e853Sbellard 519fa3e853Sbellard #define MMAP_AREA_START 0x00000000 529fa3e853Sbellard #define MMAP_AREA_END 0xa8000000 53fd6ce8f6Sbellard 54fd6ce8f6Sbellard TranslationBlock tbs[CODE_GEN_MAX_BLOCKS]; 55fd6ce8f6Sbellard TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; 569fa3e853Sbellard TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; 57fd6ce8f6Sbellard int nb_tbs; 58eb51d102Sbellard /* any access to the tbs or the page table must use this lock */ 59eb51d102Sbellard spinlock_t tb_lock = SPIN_LOCK_UNLOCKED; 60fd6ce8f6Sbellard 61b8076a74Sbellard uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE] __attribute__((aligned (32))); 62fd6ce8f6Sbellard uint8_t *code_gen_ptr; 63fd6ce8f6Sbellard 649fa3e853Sbellard int phys_ram_size; 659fa3e853Sbellard int phys_ram_fd; 669fa3e853Sbellard uint8_t *phys_ram_base; 671ccde1cbSbellard uint8_t *phys_ram_dirty; 689fa3e853Sbellard 6954936004Sbellard typedef struct PageDesc { 7092e873b9Sbellard /* list of TBs intersecting this ram page */ 71fd6ce8f6Sbellard TranslationBlock *first_tb; 729fa3e853Sbellard /* in order to optimize self modifying code, we count the number 739fa3e853Sbellard of lookups we do to a given page to use a bitmap */ 749fa3e853Sbellard unsigned int code_write_count; 759fa3e853Sbellard uint8_t *code_bitmap; 769fa3e853Sbellard #if defined(CONFIG_USER_ONLY) 779fa3e853Sbellard unsigned long flags; 789fa3e853Sbellard #endif 7954936004Sbellard } PageDesc; 8054936004Sbellard 8192e873b9Sbellard typedef struct PhysPageDesc { 8292e873b9Sbellard /* offset in host memory of the page + io_index in the low 12 bits */ 8392e873b9Sbellard unsigned long phys_offset; 8492e873b9Sbellard } PhysPageDesc; 8592e873b9Sbellard 869fa3e853Sbellard typedef struct VirtPageDesc { 879fa3e853Sbellard /* physical address of code page. It is valid only if 'valid_tag' 889fa3e853Sbellard matches 'virt_valid_tag' */ 899fa3e853Sbellard target_ulong phys_addr; 909fa3e853Sbellard unsigned int valid_tag; 919fa3e853Sbellard #if !defined(CONFIG_SOFTMMU) 929fa3e853Sbellard /* original page access rights. It is valid only if 'valid_tag' 939fa3e853Sbellard matches 'virt_valid_tag' */ 949fa3e853Sbellard unsigned int prot; 959fa3e853Sbellard #endif 969fa3e853Sbellard } VirtPageDesc; 979fa3e853Sbellard 9854936004Sbellard #define L2_BITS 10 9954936004Sbellard #define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS) 10054936004Sbellard 10154936004Sbellard #define L1_SIZE (1 << L1_BITS) 10254936004Sbellard #define L2_SIZE (1 << L2_BITS) 10354936004Sbellard 10433417e70Sbellard static void io_mem_init(void); 105fd6ce8f6Sbellard 10683fb7adfSbellard unsigned long qemu_real_host_page_size; 10783fb7adfSbellard unsigned long qemu_host_page_bits; 10883fb7adfSbellard unsigned long qemu_host_page_size; 10983fb7adfSbellard unsigned long qemu_host_page_mask; 11054936004Sbellard 11192e873b9Sbellard /* XXX: for system emulation, it could just be an array */ 11254936004Sbellard static PageDesc *l1_map[L1_SIZE]; 1130a962c02Sbellard PhysPageDesc **l1_phys_map; 11454936004Sbellard 1159fa3e853Sbellard #if !defined(CONFIG_USER_ONLY) 1169fa3e853Sbellard static VirtPageDesc *l1_virt_map[L1_SIZE]; 1179fa3e853Sbellard static unsigned int virt_valid_tag; 1189fa3e853Sbellard #endif 1199fa3e853Sbellard 12033417e70Sbellard /* io memory support */ 12133417e70Sbellard CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; 12233417e70Sbellard CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; 123a4193c8aSbellard void *io_mem_opaque[IO_MEM_NB_ENTRIES]; 12433417e70Sbellard static int io_mem_nb; 12533417e70Sbellard 12634865134Sbellard /* log support */ 12734865134Sbellard char *logfilename = "/tmp/qemu.log"; 12834865134Sbellard FILE *logfile; 12934865134Sbellard int loglevel; 13034865134Sbellard 131e3db7226Sbellard /* statistics */ 132e3db7226Sbellard static int tlb_flush_count; 133e3db7226Sbellard static int tb_flush_count; 134e3db7226Sbellard static int tb_phys_invalidate_count; 135e3db7226Sbellard 136b346ff46Sbellard static void page_init(void) 13754936004Sbellard { 13883fb7adfSbellard /* NOTE: we can always suppose that qemu_host_page_size >= 13954936004Sbellard TARGET_PAGE_SIZE */ 14067b915a5Sbellard #ifdef _WIN32 141d5a8f07cSbellard { 142d5a8f07cSbellard SYSTEM_INFO system_info; 143d5a8f07cSbellard DWORD old_protect; 144d5a8f07cSbellard 145d5a8f07cSbellard GetSystemInfo(&system_info); 146d5a8f07cSbellard qemu_real_host_page_size = system_info.dwPageSize; 147d5a8f07cSbellard 148d5a8f07cSbellard VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer), 149d5a8f07cSbellard PAGE_EXECUTE_READWRITE, &old_protect); 150d5a8f07cSbellard } 15167b915a5Sbellard #else 15283fb7adfSbellard qemu_real_host_page_size = getpagesize(); 153d5a8f07cSbellard { 154d5a8f07cSbellard unsigned long start, end; 155d5a8f07cSbellard 156d5a8f07cSbellard start = (unsigned long)code_gen_buffer; 157d5a8f07cSbellard start &= ~(qemu_real_host_page_size - 1); 158d5a8f07cSbellard 159d5a8f07cSbellard end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer); 160d5a8f07cSbellard end += qemu_real_host_page_size - 1; 161d5a8f07cSbellard end &= ~(qemu_real_host_page_size - 1); 162d5a8f07cSbellard 163d5a8f07cSbellard mprotect((void *)start, end - start, 164d5a8f07cSbellard PROT_READ | PROT_WRITE | PROT_EXEC); 165d5a8f07cSbellard } 16667b915a5Sbellard #endif 167d5a8f07cSbellard 16883fb7adfSbellard if (qemu_host_page_size == 0) 16983fb7adfSbellard qemu_host_page_size = qemu_real_host_page_size; 17083fb7adfSbellard if (qemu_host_page_size < TARGET_PAGE_SIZE) 17183fb7adfSbellard qemu_host_page_size = TARGET_PAGE_SIZE; 17283fb7adfSbellard qemu_host_page_bits = 0; 17383fb7adfSbellard while ((1 << qemu_host_page_bits) < qemu_host_page_size) 17483fb7adfSbellard qemu_host_page_bits++; 17583fb7adfSbellard qemu_host_page_mask = ~(qemu_host_page_size - 1); 1769fa3e853Sbellard #if !defined(CONFIG_USER_ONLY) 1779fa3e853Sbellard virt_valid_tag = 1; 1789fa3e853Sbellard #endif 1790a962c02Sbellard l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(PhysPageDesc *)); 1800a962c02Sbellard memset(l1_phys_map, 0, L1_SIZE * sizeof(PhysPageDesc *)); 18154936004Sbellard } 18254936004Sbellard 183fd6ce8f6Sbellard static inline PageDesc *page_find_alloc(unsigned int index) 18454936004Sbellard { 18554936004Sbellard PageDesc **lp, *p; 18654936004Sbellard 18754936004Sbellard lp = &l1_map[index >> L2_BITS]; 18854936004Sbellard p = *lp; 18954936004Sbellard if (!p) { 19054936004Sbellard /* allocate if not found */ 19159817ccbSbellard p = qemu_malloc(sizeof(PageDesc) * L2_SIZE); 192fd6ce8f6Sbellard memset(p, 0, sizeof(PageDesc) * L2_SIZE); 19354936004Sbellard *lp = p; 19454936004Sbellard } 19554936004Sbellard return p + (index & (L2_SIZE - 1)); 19654936004Sbellard } 19754936004Sbellard 198fd6ce8f6Sbellard static inline PageDesc *page_find(unsigned int index) 19954936004Sbellard { 20054936004Sbellard PageDesc *p; 20154936004Sbellard 20254936004Sbellard p = l1_map[index >> L2_BITS]; 20354936004Sbellard if (!p) 20454936004Sbellard return 0; 205fd6ce8f6Sbellard return p + (index & (L2_SIZE - 1)); 20654936004Sbellard } 20754936004Sbellard 20892e873b9Sbellard static inline PhysPageDesc *phys_page_find_alloc(unsigned int index) 20992e873b9Sbellard { 21092e873b9Sbellard PhysPageDesc **lp, *p; 21192e873b9Sbellard 21292e873b9Sbellard lp = &l1_phys_map[index >> L2_BITS]; 21392e873b9Sbellard p = *lp; 21492e873b9Sbellard if (!p) { 21592e873b9Sbellard /* allocate if not found */ 2160a962c02Sbellard p = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE); 21792e873b9Sbellard memset(p, 0, sizeof(PhysPageDesc) * L2_SIZE); 21892e873b9Sbellard *lp = p; 21992e873b9Sbellard } 22092e873b9Sbellard return p + (index & (L2_SIZE - 1)); 22192e873b9Sbellard } 22292e873b9Sbellard 22392e873b9Sbellard static inline PhysPageDesc *phys_page_find(unsigned int index) 22492e873b9Sbellard { 22592e873b9Sbellard PhysPageDesc *p; 22692e873b9Sbellard 22792e873b9Sbellard p = l1_phys_map[index >> L2_BITS]; 22892e873b9Sbellard if (!p) 22992e873b9Sbellard return 0; 23092e873b9Sbellard return p + (index & (L2_SIZE - 1)); 23192e873b9Sbellard } 23292e873b9Sbellard 2339fa3e853Sbellard #if !defined(CONFIG_USER_ONLY) 2344f2ac237Sbellard static void tlb_protect_code(CPUState *env, target_ulong addr); 2354f2ac237Sbellard static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr); 236fd6ce8f6Sbellard 2379fa3e853Sbellard static inline VirtPageDesc *virt_page_find_alloc(unsigned int index) 2389fa3e853Sbellard { 2399fa3e853Sbellard VirtPageDesc **lp, *p; 2409fa3e853Sbellard 241c27004ecSbellard /* XXX: should not truncate for 64 bit addresses */ 242c27004ecSbellard #if TARGET_LONG_BITS > 32 243c27004ecSbellard index &= (L1_SIZE - 1); 244c27004ecSbellard #endif 2459fa3e853Sbellard lp = &l1_virt_map[index >> L2_BITS]; 2469fa3e853Sbellard p = *lp; 2479fa3e853Sbellard if (!p) { 2489fa3e853Sbellard /* allocate if not found */ 24959817ccbSbellard p = qemu_malloc(sizeof(VirtPageDesc) * L2_SIZE); 2509fa3e853Sbellard memset(p, 0, sizeof(VirtPageDesc) * L2_SIZE); 2519fa3e853Sbellard *lp = p; 2529fa3e853Sbellard } 2539fa3e853Sbellard return p + (index & (L2_SIZE - 1)); 2549fa3e853Sbellard } 2559fa3e853Sbellard 2569fa3e853Sbellard static inline VirtPageDesc *virt_page_find(unsigned int index) 2579fa3e853Sbellard { 2589fa3e853Sbellard VirtPageDesc *p; 2599fa3e853Sbellard 2609fa3e853Sbellard p = l1_virt_map[index >> L2_BITS]; 261fd6ce8f6Sbellard if (!p) 262fd6ce8f6Sbellard return 0; 2639fa3e853Sbellard return p + (index & (L2_SIZE - 1)); 264fd6ce8f6Sbellard } 265fd6ce8f6Sbellard 2669fa3e853Sbellard static void virt_page_flush(void) 26754936004Sbellard { 2689fa3e853Sbellard int i, j; 2699fa3e853Sbellard VirtPageDesc *p; 27054936004Sbellard 2719fa3e853Sbellard virt_valid_tag++; 2729fa3e853Sbellard 2739fa3e853Sbellard if (virt_valid_tag == 0) { 2749fa3e853Sbellard virt_valid_tag = 1; 2759fa3e853Sbellard for(i = 0; i < L1_SIZE; i++) { 2769fa3e853Sbellard p = l1_virt_map[i]; 2779fa3e853Sbellard if (p) { 2789fa3e853Sbellard for(j = 0; j < L2_SIZE; j++) 2799fa3e853Sbellard p[j].valid_tag = 0; 280fd6ce8f6Sbellard } 28154936004Sbellard } 28254936004Sbellard } 2839fa3e853Sbellard } 2849fa3e853Sbellard #else 2859fa3e853Sbellard static void virt_page_flush(void) 2869fa3e853Sbellard { 2879fa3e853Sbellard } 2889fa3e853Sbellard #endif 289fd6ce8f6Sbellard 290b346ff46Sbellard void cpu_exec_init(void) 291fd6ce8f6Sbellard { 292fd6ce8f6Sbellard if (!code_gen_ptr) { 293fd6ce8f6Sbellard code_gen_ptr = code_gen_buffer; 294b346ff46Sbellard page_init(); 29533417e70Sbellard io_mem_init(); 296fd6ce8f6Sbellard } 297fd6ce8f6Sbellard } 298fd6ce8f6Sbellard 2999fa3e853Sbellard static inline void invalidate_page_bitmap(PageDesc *p) 3009fa3e853Sbellard { 3019fa3e853Sbellard if (p->code_bitmap) { 30259817ccbSbellard qemu_free(p->code_bitmap); 3039fa3e853Sbellard p->code_bitmap = NULL; 3049fa3e853Sbellard } 3059fa3e853Sbellard p->code_write_count = 0; 3069fa3e853Sbellard } 3079fa3e853Sbellard 308fd6ce8f6Sbellard /* set to NULL all the 'first_tb' fields in all PageDescs */ 309fd6ce8f6Sbellard static void page_flush_tb(void) 310fd6ce8f6Sbellard { 311fd6ce8f6Sbellard int i, j; 312fd6ce8f6Sbellard PageDesc *p; 313fd6ce8f6Sbellard 314fd6ce8f6Sbellard for(i = 0; i < L1_SIZE; i++) { 315fd6ce8f6Sbellard p = l1_map[i]; 316fd6ce8f6Sbellard if (p) { 3179fa3e853Sbellard for(j = 0; j < L2_SIZE; j++) { 3189fa3e853Sbellard p->first_tb = NULL; 3199fa3e853Sbellard invalidate_page_bitmap(p); 3209fa3e853Sbellard p++; 3219fa3e853Sbellard } 322fd6ce8f6Sbellard } 323fd6ce8f6Sbellard } 324fd6ce8f6Sbellard } 325fd6ce8f6Sbellard 326fd6ce8f6Sbellard /* flush all the translation blocks */ 327d4e8164fSbellard /* XXX: tb_flush is currently not thread safe */ 3280124311eSbellard void tb_flush(CPUState *env) 329fd6ce8f6Sbellard { 3300124311eSbellard #if defined(DEBUG_FLUSH) 331fd6ce8f6Sbellard printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", 332fd6ce8f6Sbellard code_gen_ptr - code_gen_buffer, 333fd6ce8f6Sbellard nb_tbs, 3340124311eSbellard nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0); 335fd6ce8f6Sbellard #endif 336fd6ce8f6Sbellard nb_tbs = 0; 3378a8a608fSbellard memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *)); 3389fa3e853Sbellard virt_page_flush(); 3399fa3e853Sbellard 3408a8a608fSbellard memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *)); 341fd6ce8f6Sbellard page_flush_tb(); 3429fa3e853Sbellard 343fd6ce8f6Sbellard code_gen_ptr = code_gen_buffer; 344d4e8164fSbellard /* XXX: flush processor icache at this point if cache flush is 345d4e8164fSbellard expensive */ 346e3db7226Sbellard tb_flush_count++; 347fd6ce8f6Sbellard } 348fd6ce8f6Sbellard 349fd6ce8f6Sbellard #ifdef DEBUG_TB_CHECK 350fd6ce8f6Sbellard 351fd6ce8f6Sbellard static void tb_invalidate_check(unsigned long address) 352fd6ce8f6Sbellard { 353fd6ce8f6Sbellard TranslationBlock *tb; 354fd6ce8f6Sbellard int i; 355fd6ce8f6Sbellard address &= TARGET_PAGE_MASK; 356fd6ce8f6Sbellard for(i = 0;i < CODE_GEN_HASH_SIZE; i++) { 357fd6ce8f6Sbellard for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) { 358fd6ce8f6Sbellard if (!(address + TARGET_PAGE_SIZE <= tb->pc || 359fd6ce8f6Sbellard address >= tb->pc + tb->size)) { 360fd6ce8f6Sbellard printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n", 361fd6ce8f6Sbellard address, tb->pc, tb->size); 362fd6ce8f6Sbellard } 363fd6ce8f6Sbellard } 364fd6ce8f6Sbellard } 365fd6ce8f6Sbellard } 366fd6ce8f6Sbellard 367fd6ce8f6Sbellard /* verify that all the pages have correct rights for code */ 368fd6ce8f6Sbellard static void tb_page_check(void) 369fd6ce8f6Sbellard { 370fd6ce8f6Sbellard TranslationBlock *tb; 371fd6ce8f6Sbellard int i, flags1, flags2; 372fd6ce8f6Sbellard 373fd6ce8f6Sbellard for(i = 0;i < CODE_GEN_HASH_SIZE; i++) { 374fd6ce8f6Sbellard for(tb = tb_hash[i]; tb != NULL; tb = tb->hash_next) { 375fd6ce8f6Sbellard flags1 = page_get_flags(tb->pc); 376fd6ce8f6Sbellard flags2 = page_get_flags(tb->pc + tb->size - 1); 377fd6ce8f6Sbellard if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) { 378fd6ce8f6Sbellard printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n", 379fd6ce8f6Sbellard tb->pc, tb->size, flags1, flags2); 380fd6ce8f6Sbellard } 381fd6ce8f6Sbellard } 382fd6ce8f6Sbellard } 383fd6ce8f6Sbellard } 384fd6ce8f6Sbellard 385d4e8164fSbellard void tb_jmp_check(TranslationBlock *tb) 386d4e8164fSbellard { 387d4e8164fSbellard TranslationBlock *tb1; 388d4e8164fSbellard unsigned int n1; 389d4e8164fSbellard 390d4e8164fSbellard /* suppress any remaining jumps to this TB */ 391d4e8164fSbellard tb1 = tb->jmp_first; 392d4e8164fSbellard for(;;) { 393d4e8164fSbellard n1 = (long)tb1 & 3; 394d4e8164fSbellard tb1 = (TranslationBlock *)((long)tb1 & ~3); 395d4e8164fSbellard if (n1 == 2) 396d4e8164fSbellard break; 397d4e8164fSbellard tb1 = tb1->jmp_next[n1]; 398d4e8164fSbellard } 399d4e8164fSbellard /* check end of list */ 400d4e8164fSbellard if (tb1 != tb) { 401d4e8164fSbellard printf("ERROR: jmp_list from 0x%08lx\n", (long)tb); 402d4e8164fSbellard } 403d4e8164fSbellard } 404d4e8164fSbellard 405fd6ce8f6Sbellard #endif 406fd6ce8f6Sbellard 407fd6ce8f6Sbellard /* invalidate one TB */ 408fd6ce8f6Sbellard static inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb, 409fd6ce8f6Sbellard int next_offset) 410fd6ce8f6Sbellard { 411fd6ce8f6Sbellard TranslationBlock *tb1; 412fd6ce8f6Sbellard for(;;) { 413fd6ce8f6Sbellard tb1 = *ptb; 414fd6ce8f6Sbellard if (tb1 == tb) { 415fd6ce8f6Sbellard *ptb = *(TranslationBlock **)((char *)tb1 + next_offset); 416fd6ce8f6Sbellard break; 417fd6ce8f6Sbellard } 418fd6ce8f6Sbellard ptb = (TranslationBlock **)((char *)tb1 + next_offset); 419fd6ce8f6Sbellard } 420fd6ce8f6Sbellard } 421fd6ce8f6Sbellard 4229fa3e853Sbellard static inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb) 4239fa3e853Sbellard { 4249fa3e853Sbellard TranslationBlock *tb1; 4259fa3e853Sbellard unsigned int n1; 4269fa3e853Sbellard 4279fa3e853Sbellard for(;;) { 4289fa3e853Sbellard tb1 = *ptb; 4299fa3e853Sbellard n1 = (long)tb1 & 3; 4309fa3e853Sbellard tb1 = (TranslationBlock *)((long)tb1 & ~3); 4319fa3e853Sbellard if (tb1 == tb) { 4329fa3e853Sbellard *ptb = tb1->page_next[n1]; 4339fa3e853Sbellard break; 4349fa3e853Sbellard } 4359fa3e853Sbellard ptb = &tb1->page_next[n1]; 4369fa3e853Sbellard } 4379fa3e853Sbellard } 4389fa3e853Sbellard 439d4e8164fSbellard static inline void tb_jmp_remove(TranslationBlock *tb, int n) 440d4e8164fSbellard { 441d4e8164fSbellard TranslationBlock *tb1, **ptb; 442d4e8164fSbellard unsigned int n1; 443d4e8164fSbellard 444d4e8164fSbellard ptb = &tb->jmp_next[n]; 445d4e8164fSbellard tb1 = *ptb; 446d4e8164fSbellard if (tb1) { 447d4e8164fSbellard /* find tb(n) in circular list */ 448d4e8164fSbellard for(;;) { 449d4e8164fSbellard tb1 = *ptb; 450d4e8164fSbellard n1 = (long)tb1 & 3; 451d4e8164fSbellard tb1 = (TranslationBlock *)((long)tb1 & ~3); 452d4e8164fSbellard if (n1 == n && tb1 == tb) 453d4e8164fSbellard break; 454d4e8164fSbellard if (n1 == 2) { 455d4e8164fSbellard ptb = &tb1->jmp_first; 456d4e8164fSbellard } else { 457d4e8164fSbellard ptb = &tb1->jmp_next[n1]; 458d4e8164fSbellard } 459d4e8164fSbellard } 460d4e8164fSbellard /* now we can suppress tb(n) from the list */ 461d4e8164fSbellard *ptb = tb->jmp_next[n]; 462d4e8164fSbellard 463d4e8164fSbellard tb->jmp_next[n] = NULL; 464d4e8164fSbellard } 465d4e8164fSbellard } 466d4e8164fSbellard 467d4e8164fSbellard /* reset the jump entry 'n' of a TB so that it is not chained to 468d4e8164fSbellard another TB */ 469d4e8164fSbellard static inline void tb_reset_jump(TranslationBlock *tb, int n) 470d4e8164fSbellard { 471d4e8164fSbellard tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n])); 472d4e8164fSbellard } 473d4e8164fSbellard 4749fa3e853Sbellard static inline void tb_invalidate(TranslationBlock *tb) 475fd6ce8f6Sbellard { 476d4e8164fSbellard unsigned int h, n1; 4779fa3e853Sbellard TranslationBlock *tb1, *tb2, **ptb; 478fd6ce8f6Sbellard 47936bdbe54Sbellard tb_invalidated_flag = 1; 48036bdbe54Sbellard 481fd6ce8f6Sbellard /* remove the TB from the hash list */ 482fd6ce8f6Sbellard h = tb_hash_func(tb->pc); 4839fa3e853Sbellard ptb = &tb_hash[h]; 4849fa3e853Sbellard for(;;) { 4859fa3e853Sbellard tb1 = *ptb; 4869fa3e853Sbellard /* NOTE: the TB is not necessarily linked in the hash. It 4879fa3e853Sbellard indicates that it is not currently used */ 4889fa3e853Sbellard if (tb1 == NULL) 4899fa3e853Sbellard return; 4909fa3e853Sbellard if (tb1 == tb) { 4919fa3e853Sbellard *ptb = tb1->hash_next; 4929fa3e853Sbellard break; 493fd6ce8f6Sbellard } 4949fa3e853Sbellard ptb = &tb1->hash_next; 495fd6ce8f6Sbellard } 496d4e8164fSbellard 497d4e8164fSbellard /* suppress this TB from the two jump lists */ 498d4e8164fSbellard tb_jmp_remove(tb, 0); 499d4e8164fSbellard tb_jmp_remove(tb, 1); 500d4e8164fSbellard 501d4e8164fSbellard /* suppress any remaining jumps to this TB */ 502d4e8164fSbellard tb1 = tb->jmp_first; 503d4e8164fSbellard for(;;) { 504d4e8164fSbellard n1 = (long)tb1 & 3; 505d4e8164fSbellard if (n1 == 2) 506d4e8164fSbellard break; 507d4e8164fSbellard tb1 = (TranslationBlock *)((long)tb1 & ~3); 508d4e8164fSbellard tb2 = tb1->jmp_next[n1]; 509d4e8164fSbellard tb_reset_jump(tb1, n1); 510d4e8164fSbellard tb1->jmp_next[n1] = NULL; 511d4e8164fSbellard tb1 = tb2; 512d4e8164fSbellard } 513d4e8164fSbellard tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */ 514fd6ce8f6Sbellard } 515fd6ce8f6Sbellard 5169fa3e853Sbellard static inline void tb_phys_invalidate(TranslationBlock *tb, unsigned int page_addr) 517fd6ce8f6Sbellard { 518fd6ce8f6Sbellard PageDesc *p; 5199fa3e853Sbellard unsigned int h; 5209fa3e853Sbellard target_ulong phys_pc; 521fd6ce8f6Sbellard 5229fa3e853Sbellard /* remove the TB from the hash list */ 5239fa3e853Sbellard phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); 5249fa3e853Sbellard h = tb_phys_hash_func(phys_pc); 5259fa3e853Sbellard tb_remove(&tb_phys_hash[h], tb, 5269fa3e853Sbellard offsetof(TranslationBlock, phys_hash_next)); 5279fa3e853Sbellard 5289fa3e853Sbellard /* remove the TB from the page list */ 5299fa3e853Sbellard if (tb->page_addr[0] != page_addr) { 5309fa3e853Sbellard p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS); 5319fa3e853Sbellard tb_page_remove(&p->first_tb, tb); 5329fa3e853Sbellard invalidate_page_bitmap(p); 5339fa3e853Sbellard } 5349fa3e853Sbellard if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) { 5359fa3e853Sbellard p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS); 5369fa3e853Sbellard tb_page_remove(&p->first_tb, tb); 5379fa3e853Sbellard invalidate_page_bitmap(p); 5389fa3e853Sbellard } 5399fa3e853Sbellard 5409fa3e853Sbellard tb_invalidate(tb); 541e3db7226Sbellard tb_phys_invalidate_count++; 5429fa3e853Sbellard } 5439fa3e853Sbellard 5449fa3e853Sbellard static inline void set_bits(uint8_t *tab, int start, int len) 5459fa3e853Sbellard { 5469fa3e853Sbellard int end, mask, end1; 5479fa3e853Sbellard 5489fa3e853Sbellard end = start + len; 5499fa3e853Sbellard tab += start >> 3; 5509fa3e853Sbellard mask = 0xff << (start & 7); 5519fa3e853Sbellard if ((start & ~7) == (end & ~7)) { 5529fa3e853Sbellard if (start < end) { 5539fa3e853Sbellard mask &= ~(0xff << (end & 7)); 5549fa3e853Sbellard *tab |= mask; 5559fa3e853Sbellard } 5569fa3e853Sbellard } else { 5579fa3e853Sbellard *tab++ |= mask; 5589fa3e853Sbellard start = (start + 8) & ~7; 5599fa3e853Sbellard end1 = end & ~7; 5609fa3e853Sbellard while (start < end1) { 5619fa3e853Sbellard *tab++ = 0xff; 5629fa3e853Sbellard start += 8; 5639fa3e853Sbellard } 5649fa3e853Sbellard if (start < end) { 5659fa3e853Sbellard mask = ~(0xff << (end & 7)); 5669fa3e853Sbellard *tab |= mask; 5679fa3e853Sbellard } 5689fa3e853Sbellard } 5699fa3e853Sbellard } 5709fa3e853Sbellard 5719fa3e853Sbellard static void build_page_bitmap(PageDesc *p) 5729fa3e853Sbellard { 5739fa3e853Sbellard int n, tb_start, tb_end; 5749fa3e853Sbellard TranslationBlock *tb; 5759fa3e853Sbellard 57659817ccbSbellard p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8); 5779fa3e853Sbellard if (!p->code_bitmap) 5789fa3e853Sbellard return; 5799fa3e853Sbellard memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8); 5809fa3e853Sbellard 5819fa3e853Sbellard tb = p->first_tb; 5829fa3e853Sbellard while (tb != NULL) { 5839fa3e853Sbellard n = (long)tb & 3; 5849fa3e853Sbellard tb = (TranslationBlock *)((long)tb & ~3); 5859fa3e853Sbellard /* NOTE: this is subtle as a TB may span two physical pages */ 5869fa3e853Sbellard if (n == 0) { 5879fa3e853Sbellard /* NOTE: tb_end may be after the end of the page, but 5889fa3e853Sbellard it is not a problem */ 5899fa3e853Sbellard tb_start = tb->pc & ~TARGET_PAGE_MASK; 5909fa3e853Sbellard tb_end = tb_start + tb->size; 5919fa3e853Sbellard if (tb_end > TARGET_PAGE_SIZE) 5929fa3e853Sbellard tb_end = TARGET_PAGE_SIZE; 5939fa3e853Sbellard } else { 5949fa3e853Sbellard tb_start = 0; 5959fa3e853Sbellard tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK); 5969fa3e853Sbellard } 5979fa3e853Sbellard set_bits(p->code_bitmap, tb_start, tb_end - tb_start); 5989fa3e853Sbellard tb = tb->page_next[n]; 5999fa3e853Sbellard } 6009fa3e853Sbellard } 6019fa3e853Sbellard 602d720b93dSbellard #ifdef TARGET_HAS_PRECISE_SMC 603d720b93dSbellard 604d720b93dSbellard static void tb_gen_code(CPUState *env, 605d720b93dSbellard target_ulong pc, target_ulong cs_base, int flags, 606d720b93dSbellard int cflags) 607d720b93dSbellard { 608d720b93dSbellard TranslationBlock *tb; 609d720b93dSbellard uint8_t *tc_ptr; 610d720b93dSbellard target_ulong phys_pc, phys_page2, virt_page2; 611d720b93dSbellard int code_gen_size; 612d720b93dSbellard 613c27004ecSbellard phys_pc = get_phys_addr_code(env, pc); 614c27004ecSbellard tb = tb_alloc(pc); 615d720b93dSbellard if (!tb) { 616d720b93dSbellard /* flush must be done */ 617d720b93dSbellard tb_flush(env); 618d720b93dSbellard /* cannot fail at this point */ 619c27004ecSbellard tb = tb_alloc(pc); 620d720b93dSbellard } 621d720b93dSbellard tc_ptr = code_gen_ptr; 622d720b93dSbellard tb->tc_ptr = tc_ptr; 623d720b93dSbellard tb->cs_base = cs_base; 624d720b93dSbellard tb->flags = flags; 625d720b93dSbellard tb->cflags = cflags; 626d720b93dSbellard cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size); 627d720b93dSbellard code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); 628d720b93dSbellard 629d720b93dSbellard /* check next page if needed */ 630c27004ecSbellard virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK; 631d720b93dSbellard phys_page2 = -1; 632c27004ecSbellard if ((pc & TARGET_PAGE_MASK) != virt_page2) { 633d720b93dSbellard phys_page2 = get_phys_addr_code(env, virt_page2); 634d720b93dSbellard } 635d720b93dSbellard tb_link_phys(tb, phys_pc, phys_page2); 636d720b93dSbellard } 637d720b93dSbellard #endif 638d720b93dSbellard 6399fa3e853Sbellard /* invalidate all TBs which intersect with the target physical page 6409fa3e853Sbellard starting in range [start;end[. NOTE: start and end must refer to 641d720b93dSbellard the same physical page. 'is_cpu_write_access' should be true if called 642d720b93dSbellard from a real cpu write access: the virtual CPU will exit the current 643d720b93dSbellard TB if code is modified inside this TB. */ 644d720b93dSbellard void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, 645d720b93dSbellard int is_cpu_write_access) 6469fa3e853Sbellard { 647d720b93dSbellard int n, current_tb_modified, current_tb_not_found, current_flags; 648d720b93dSbellard CPUState *env = cpu_single_env; 6499fa3e853Sbellard PageDesc *p; 650ea1c1802Sbellard TranslationBlock *tb, *tb_next, *current_tb, *saved_tb; 6519fa3e853Sbellard target_ulong tb_start, tb_end; 652d720b93dSbellard target_ulong current_pc, current_cs_base; 6539fa3e853Sbellard 6549fa3e853Sbellard p = page_find(start >> TARGET_PAGE_BITS); 6559fa3e853Sbellard if (!p) 6569fa3e853Sbellard return; 6579fa3e853Sbellard if (!p->code_bitmap && 658d720b93dSbellard ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD && 659d720b93dSbellard is_cpu_write_access) { 6609fa3e853Sbellard /* build code bitmap */ 6619fa3e853Sbellard build_page_bitmap(p); 6629fa3e853Sbellard } 6639fa3e853Sbellard 6649fa3e853Sbellard /* we remove all the TBs in the range [start, end[ */ 6659fa3e853Sbellard /* XXX: see if in some cases it could be faster to invalidate all the code */ 666d720b93dSbellard current_tb_not_found = is_cpu_write_access; 667d720b93dSbellard current_tb_modified = 0; 668d720b93dSbellard current_tb = NULL; /* avoid warning */ 669d720b93dSbellard current_pc = 0; /* avoid warning */ 670d720b93dSbellard current_cs_base = 0; /* avoid warning */ 671d720b93dSbellard current_flags = 0; /* avoid warning */ 6729fa3e853Sbellard tb = p->first_tb; 6739fa3e853Sbellard while (tb != NULL) { 6749fa3e853Sbellard n = (long)tb & 3; 6759fa3e853Sbellard tb = (TranslationBlock *)((long)tb & ~3); 6769fa3e853Sbellard tb_next = tb->page_next[n]; 6779fa3e853Sbellard /* NOTE: this is subtle as a TB may span two physical pages */ 6789fa3e853Sbellard if (n == 0) { 6799fa3e853Sbellard /* NOTE: tb_end may be after the end of the page, but 6809fa3e853Sbellard it is not a problem */ 6819fa3e853Sbellard tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK); 6829fa3e853Sbellard tb_end = tb_start + tb->size; 6839fa3e853Sbellard } else { 6849fa3e853Sbellard tb_start = tb->page_addr[1]; 6859fa3e853Sbellard tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK); 6869fa3e853Sbellard } 6879fa3e853Sbellard if (!(tb_end <= start || tb_start >= end)) { 688d720b93dSbellard #ifdef TARGET_HAS_PRECISE_SMC 689d720b93dSbellard if (current_tb_not_found) { 690d720b93dSbellard current_tb_not_found = 0; 691d720b93dSbellard current_tb = NULL; 692d720b93dSbellard if (env->mem_write_pc) { 693d720b93dSbellard /* now we have a real cpu fault */ 694d720b93dSbellard current_tb = tb_find_pc(env->mem_write_pc); 695d720b93dSbellard } 696d720b93dSbellard } 697d720b93dSbellard if (current_tb == tb && 698d720b93dSbellard !(current_tb->cflags & CF_SINGLE_INSN)) { 699d720b93dSbellard /* If we are modifying the current TB, we must stop 700d720b93dSbellard its execution. We could be more precise by checking 701d720b93dSbellard that the modification is after the current PC, but it 702d720b93dSbellard would require a specialized function to partially 703d720b93dSbellard restore the CPU state */ 704d720b93dSbellard 705d720b93dSbellard current_tb_modified = 1; 706d720b93dSbellard cpu_restore_state(current_tb, env, 707d720b93dSbellard env->mem_write_pc, NULL); 708d720b93dSbellard #if defined(TARGET_I386) 709d720b93dSbellard current_flags = env->hflags; 710d720b93dSbellard current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); 711d720b93dSbellard current_cs_base = (target_ulong)env->segs[R_CS].base; 712d720b93dSbellard current_pc = current_cs_base + env->eip; 713d720b93dSbellard #else 714d720b93dSbellard #error unsupported CPU 715d720b93dSbellard #endif 716d720b93dSbellard } 717d720b93dSbellard #endif /* TARGET_HAS_PRECISE_SMC */ 718ea1c1802Sbellard saved_tb = env->current_tb; 719ea1c1802Sbellard env->current_tb = NULL; 7209fa3e853Sbellard tb_phys_invalidate(tb, -1); 721ea1c1802Sbellard env->current_tb = saved_tb; 722ea1c1802Sbellard if (env->interrupt_request && env->current_tb) 723ea1c1802Sbellard cpu_interrupt(env, env->interrupt_request); 7249fa3e853Sbellard } 7259fa3e853Sbellard tb = tb_next; 7269fa3e853Sbellard } 7279fa3e853Sbellard #if !defined(CONFIG_USER_ONLY) 7289fa3e853Sbellard /* if no code remaining, no need to continue to use slow writes */ 7299fa3e853Sbellard if (!p->first_tb) { 7309fa3e853Sbellard invalidate_page_bitmap(p); 731d720b93dSbellard if (is_cpu_write_access) { 732d720b93dSbellard tlb_unprotect_code_phys(env, start, env->mem_write_vaddr); 733d720b93dSbellard } 734d720b93dSbellard } 735d720b93dSbellard #endif 736d720b93dSbellard #ifdef TARGET_HAS_PRECISE_SMC 737d720b93dSbellard if (current_tb_modified) { 738d720b93dSbellard /* we generate a block containing just the instruction 739d720b93dSbellard modifying the memory. It will ensure that it cannot modify 740d720b93dSbellard itself */ 741ea1c1802Sbellard env->current_tb = NULL; 742d720b93dSbellard tb_gen_code(env, current_pc, current_cs_base, current_flags, 743d720b93dSbellard CF_SINGLE_INSN); 744d720b93dSbellard cpu_resume_from_signal(env, NULL); 7459fa3e853Sbellard } 7469fa3e853Sbellard #endif 7479fa3e853Sbellard } 7489fa3e853Sbellard 7499fa3e853Sbellard /* len must be <= 8 and start must be a multiple of len */ 750d720b93dSbellard static inline void tb_invalidate_phys_page_fast(target_ulong start, int len) 7519fa3e853Sbellard { 7529fa3e853Sbellard PageDesc *p; 7539fa3e853Sbellard int offset, b; 75459817ccbSbellard #if 0 755a4193c8aSbellard if (1) { 756a4193c8aSbellard if (loglevel) { 757a4193c8aSbellard fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n", 758a4193c8aSbellard cpu_single_env->mem_write_vaddr, len, 759a4193c8aSbellard cpu_single_env->eip, 760a4193c8aSbellard cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base); 761a4193c8aSbellard } 76259817ccbSbellard } 76359817ccbSbellard #endif 7649fa3e853Sbellard p = page_find(start >> TARGET_PAGE_BITS); 7659fa3e853Sbellard if (!p) 7669fa3e853Sbellard return; 7679fa3e853Sbellard if (p->code_bitmap) { 7689fa3e853Sbellard offset = start & ~TARGET_PAGE_MASK; 7699fa3e853Sbellard b = p->code_bitmap[offset >> 3] >> (offset & 7); 7709fa3e853Sbellard if (b & ((1 << len) - 1)) 7719fa3e853Sbellard goto do_invalidate; 7729fa3e853Sbellard } else { 7739fa3e853Sbellard do_invalidate: 774d720b93dSbellard tb_invalidate_phys_page_range(start, start + len, 1); 7759fa3e853Sbellard } 7769fa3e853Sbellard } 7779fa3e853Sbellard 7789fa3e853Sbellard #if !defined(CONFIG_SOFTMMU) 779d720b93dSbellard static void tb_invalidate_phys_page(target_ulong addr, 780d720b93dSbellard unsigned long pc, void *puc) 7819fa3e853Sbellard { 782d720b93dSbellard int n, current_flags, current_tb_modified; 783d720b93dSbellard target_ulong current_pc, current_cs_base; 7849fa3e853Sbellard PageDesc *p; 785d720b93dSbellard TranslationBlock *tb, *current_tb; 786d720b93dSbellard #ifdef TARGET_HAS_PRECISE_SMC 787d720b93dSbellard CPUState *env = cpu_single_env; 788d720b93dSbellard #endif 7899fa3e853Sbellard 7909fa3e853Sbellard addr &= TARGET_PAGE_MASK; 7919fa3e853Sbellard p = page_find(addr >> TARGET_PAGE_BITS); 792fd6ce8f6Sbellard if (!p) 793fd6ce8f6Sbellard return; 794fd6ce8f6Sbellard tb = p->first_tb; 795d720b93dSbellard current_tb_modified = 0; 796d720b93dSbellard current_tb = NULL; 797d720b93dSbellard current_pc = 0; /* avoid warning */ 798d720b93dSbellard current_cs_base = 0; /* avoid warning */ 799d720b93dSbellard current_flags = 0; /* avoid warning */ 800d720b93dSbellard #ifdef TARGET_HAS_PRECISE_SMC 801d720b93dSbellard if (tb && pc != 0) { 802d720b93dSbellard current_tb = tb_find_pc(pc); 803d720b93dSbellard } 804d720b93dSbellard #endif 805fd6ce8f6Sbellard while (tb != NULL) { 8069fa3e853Sbellard n = (long)tb & 3; 8079fa3e853Sbellard tb = (TranslationBlock *)((long)tb & ~3); 808d720b93dSbellard #ifdef TARGET_HAS_PRECISE_SMC 809d720b93dSbellard if (current_tb == tb && 810d720b93dSbellard !(current_tb->cflags & CF_SINGLE_INSN)) { 811d720b93dSbellard /* If we are modifying the current TB, we must stop 812d720b93dSbellard its execution. We could be more precise by checking 813d720b93dSbellard that the modification is after the current PC, but it 814d720b93dSbellard would require a specialized function to partially 815d720b93dSbellard restore the CPU state */ 816d720b93dSbellard 817d720b93dSbellard current_tb_modified = 1; 818d720b93dSbellard cpu_restore_state(current_tb, env, pc, puc); 819d720b93dSbellard #if defined(TARGET_I386) 820d720b93dSbellard current_flags = env->hflags; 821d720b93dSbellard current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)); 822d720b93dSbellard current_cs_base = (target_ulong)env->segs[R_CS].base; 823d720b93dSbellard current_pc = current_cs_base + env->eip; 824d720b93dSbellard #else 825d720b93dSbellard #error unsupported CPU 826d720b93dSbellard #endif 827d720b93dSbellard } 828d720b93dSbellard #endif /* TARGET_HAS_PRECISE_SMC */ 8299fa3e853Sbellard tb_phys_invalidate(tb, addr); 8309fa3e853Sbellard tb = tb->page_next[n]; 831fd6ce8f6Sbellard } 832fd6ce8f6Sbellard p->first_tb = NULL; 833d720b93dSbellard #ifdef TARGET_HAS_PRECISE_SMC 834d720b93dSbellard if (current_tb_modified) { 835d720b93dSbellard /* we generate a block containing just the instruction 836d720b93dSbellard modifying the memory. It will ensure that it cannot modify 837d720b93dSbellard itself */ 838ea1c1802Sbellard env->current_tb = NULL; 839d720b93dSbellard tb_gen_code(env, current_pc, current_cs_base, current_flags, 840d720b93dSbellard CF_SINGLE_INSN); 841d720b93dSbellard cpu_resume_from_signal(env, puc); 842d720b93dSbellard } 843d720b93dSbellard #endif 844fd6ce8f6Sbellard } 8459fa3e853Sbellard #endif 846fd6ce8f6Sbellard 847fd6ce8f6Sbellard /* add the tb in the target page and protect it if necessary */ 8489fa3e853Sbellard static inline void tb_alloc_page(TranslationBlock *tb, 8499fa3e853Sbellard unsigned int n, unsigned int page_addr) 850fd6ce8f6Sbellard { 851fd6ce8f6Sbellard PageDesc *p; 8529fa3e853Sbellard TranslationBlock *last_first_tb; 8539fa3e853Sbellard 8549fa3e853Sbellard tb->page_addr[n] = page_addr; 8559fa3e853Sbellard p = page_find(page_addr >> TARGET_PAGE_BITS); 8569fa3e853Sbellard tb->page_next[n] = p->first_tb; 8579fa3e853Sbellard last_first_tb = p->first_tb; 8589fa3e853Sbellard p->first_tb = (TranslationBlock *)((long)tb | n); 8599fa3e853Sbellard invalidate_page_bitmap(p); 8609fa3e853Sbellard 861107db443Sbellard #if defined(TARGET_HAS_SMC) || 1 862d720b93dSbellard 8639fa3e853Sbellard #if defined(CONFIG_USER_ONLY) 8649fa3e853Sbellard if (p->flags & PAGE_WRITE) { 8659fa3e853Sbellard unsigned long host_start, host_end, addr; 866fd6ce8f6Sbellard int prot; 867fd6ce8f6Sbellard 868fd6ce8f6Sbellard /* force the host page as non writable (writes will have a 869fd6ce8f6Sbellard page fault + mprotect overhead) */ 87083fb7adfSbellard host_start = page_addr & qemu_host_page_mask; 87183fb7adfSbellard host_end = host_start + qemu_host_page_size; 872fd6ce8f6Sbellard prot = 0; 873fd6ce8f6Sbellard for(addr = host_start; addr < host_end; addr += TARGET_PAGE_SIZE) 874fd6ce8f6Sbellard prot |= page_get_flags(addr); 87583fb7adfSbellard mprotect((void *)host_start, qemu_host_page_size, 876fd6ce8f6Sbellard (prot & PAGE_BITS) & ~PAGE_WRITE); 877fd6ce8f6Sbellard #ifdef DEBUG_TB_INVALIDATE 878fd6ce8f6Sbellard printf("protecting code page: 0x%08lx\n", 879fd6ce8f6Sbellard host_start); 880fd6ce8f6Sbellard #endif 881fd6ce8f6Sbellard p->flags &= ~PAGE_WRITE; 882fd6ce8f6Sbellard } 8839fa3e853Sbellard #else 8849fa3e853Sbellard /* if some code is already present, then the pages are already 8859fa3e853Sbellard protected. So we handle the case where only the first TB is 8869fa3e853Sbellard allocated in a physical page */ 8879fa3e853Sbellard if (!last_first_tb) { 8889fa3e853Sbellard target_ulong virt_addr; 8899fa3e853Sbellard 8909fa3e853Sbellard virt_addr = (tb->pc & TARGET_PAGE_MASK) + (n << TARGET_PAGE_BITS); 8919fa3e853Sbellard tlb_protect_code(cpu_single_env, virt_addr); 8929fa3e853Sbellard } 8939fa3e853Sbellard #endif 894d720b93dSbellard 895d720b93dSbellard #endif /* TARGET_HAS_SMC */ 896fd6ce8f6Sbellard } 897fd6ce8f6Sbellard 898fd6ce8f6Sbellard /* Allocate a new translation block. Flush the translation buffer if 899fd6ce8f6Sbellard too many translation blocks or too much generated code. */ 900c27004ecSbellard TranslationBlock *tb_alloc(target_ulong pc) 901fd6ce8f6Sbellard { 902fd6ce8f6Sbellard TranslationBlock *tb; 903fd6ce8f6Sbellard 904fd6ce8f6Sbellard if (nb_tbs >= CODE_GEN_MAX_BLOCKS || 905fd6ce8f6Sbellard (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE) 906d4e8164fSbellard return NULL; 907fd6ce8f6Sbellard tb = &tbs[nb_tbs++]; 908fd6ce8f6Sbellard tb->pc = pc; 909b448f2f3Sbellard tb->cflags = 0; 910d4e8164fSbellard return tb; 911d4e8164fSbellard } 912d4e8164fSbellard 9139fa3e853Sbellard /* add a new TB and link it to the physical page tables. phys_page2 is 9149fa3e853Sbellard (-1) to indicate that only one page contains the TB. */ 9159fa3e853Sbellard void tb_link_phys(TranslationBlock *tb, 9169fa3e853Sbellard target_ulong phys_pc, target_ulong phys_page2) 917d4e8164fSbellard { 9189fa3e853Sbellard unsigned int h; 9199fa3e853Sbellard TranslationBlock **ptb; 9209fa3e853Sbellard 9219fa3e853Sbellard /* add in the physical hash table */ 9229fa3e853Sbellard h = tb_phys_hash_func(phys_pc); 9239fa3e853Sbellard ptb = &tb_phys_hash[h]; 9249fa3e853Sbellard tb->phys_hash_next = *ptb; 9259fa3e853Sbellard *ptb = tb; 926fd6ce8f6Sbellard 927fd6ce8f6Sbellard /* add in the page list */ 9289fa3e853Sbellard tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK); 9299fa3e853Sbellard if (phys_page2 != -1) 9309fa3e853Sbellard tb_alloc_page(tb, 1, phys_page2); 9319fa3e853Sbellard else 9329fa3e853Sbellard tb->page_addr[1] = -1; 93361382a50Sbellard #ifdef DEBUG_TB_CHECK 93461382a50Sbellard tb_page_check(); 93561382a50Sbellard #endif 9369fa3e853Sbellard } 9379fa3e853Sbellard 9389fa3e853Sbellard /* link the tb with the other TBs */ 9399fa3e853Sbellard void tb_link(TranslationBlock *tb) 9409fa3e853Sbellard { 9419fa3e853Sbellard #if !defined(CONFIG_USER_ONLY) 9429fa3e853Sbellard { 9439fa3e853Sbellard VirtPageDesc *vp; 9449fa3e853Sbellard target_ulong addr; 9459fa3e853Sbellard 9469fa3e853Sbellard /* save the code memory mappings (needed to invalidate the code) */ 9479fa3e853Sbellard addr = tb->pc & TARGET_PAGE_MASK; 9489fa3e853Sbellard vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS); 94998857888Sbellard #ifdef DEBUG_TLB_CHECK 95098857888Sbellard if (vp->valid_tag == virt_valid_tag && 95198857888Sbellard vp->phys_addr != tb->page_addr[0]) { 95298857888Sbellard printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n", 95398857888Sbellard addr, tb->page_addr[0], vp->phys_addr); 95498857888Sbellard } 95598857888Sbellard #endif 9569fa3e853Sbellard vp->phys_addr = tb->page_addr[0]; 95759817ccbSbellard if (vp->valid_tag != virt_valid_tag) { 9589fa3e853Sbellard vp->valid_tag = virt_valid_tag; 95959817ccbSbellard #if !defined(CONFIG_SOFTMMU) 96059817ccbSbellard vp->prot = 0; 96159817ccbSbellard #endif 96259817ccbSbellard } 9639fa3e853Sbellard 9649fa3e853Sbellard if (tb->page_addr[1] != -1) { 9659fa3e853Sbellard addr += TARGET_PAGE_SIZE; 9669fa3e853Sbellard vp = virt_page_find_alloc(addr >> TARGET_PAGE_BITS); 96798857888Sbellard #ifdef DEBUG_TLB_CHECK 96898857888Sbellard if (vp->valid_tag == virt_valid_tag && 96998857888Sbellard vp->phys_addr != tb->page_addr[1]) { 97098857888Sbellard printf("Error tb addr=0x%x phys=0x%x vp->phys_addr=0x%x\n", 97198857888Sbellard addr, tb->page_addr[1], vp->phys_addr); 97298857888Sbellard } 97398857888Sbellard #endif 9749fa3e853Sbellard vp->phys_addr = tb->page_addr[1]; 97559817ccbSbellard if (vp->valid_tag != virt_valid_tag) { 9769fa3e853Sbellard vp->valid_tag = virt_valid_tag; 97759817ccbSbellard #if !defined(CONFIG_SOFTMMU) 97859817ccbSbellard vp->prot = 0; 97959817ccbSbellard #endif 98059817ccbSbellard } 9819fa3e853Sbellard } 9829fa3e853Sbellard } 9839fa3e853Sbellard #endif 9849fa3e853Sbellard 985d4e8164fSbellard tb->jmp_first = (TranslationBlock *)((long)tb | 2); 986d4e8164fSbellard tb->jmp_next[0] = NULL; 987d4e8164fSbellard tb->jmp_next[1] = NULL; 988b448f2f3Sbellard #ifdef USE_CODE_COPY 989b448f2f3Sbellard tb->cflags &= ~CF_FP_USED; 990b448f2f3Sbellard if (tb->cflags & CF_TB_FP_USED) 991b448f2f3Sbellard tb->cflags |= CF_FP_USED; 992b448f2f3Sbellard #endif 993d4e8164fSbellard 994d4e8164fSbellard /* init original jump addresses */ 995d4e8164fSbellard if (tb->tb_next_offset[0] != 0xffff) 996d4e8164fSbellard tb_reset_jump(tb, 0); 997d4e8164fSbellard if (tb->tb_next_offset[1] != 0xffff) 998d4e8164fSbellard tb_reset_jump(tb, 1); 999fd6ce8f6Sbellard } 1000fd6ce8f6Sbellard 1001a513fe19Sbellard /* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr < 1002a513fe19Sbellard tb[1].tc_ptr. Return NULL if not found */ 1003a513fe19Sbellard TranslationBlock *tb_find_pc(unsigned long tc_ptr) 1004a513fe19Sbellard { 1005a513fe19Sbellard int m_min, m_max, m; 1006a513fe19Sbellard unsigned long v; 1007a513fe19Sbellard TranslationBlock *tb; 1008a513fe19Sbellard 1009a513fe19Sbellard if (nb_tbs <= 0) 1010a513fe19Sbellard return NULL; 1011a513fe19Sbellard if (tc_ptr < (unsigned long)code_gen_buffer || 1012a513fe19Sbellard tc_ptr >= (unsigned long)code_gen_ptr) 1013a513fe19Sbellard return NULL; 1014a513fe19Sbellard /* binary search (cf Knuth) */ 1015a513fe19Sbellard m_min = 0; 1016a513fe19Sbellard m_max = nb_tbs - 1; 1017a513fe19Sbellard while (m_min <= m_max) { 1018a513fe19Sbellard m = (m_min + m_max) >> 1; 1019a513fe19Sbellard tb = &tbs[m]; 1020a513fe19Sbellard v = (unsigned long)tb->tc_ptr; 1021a513fe19Sbellard if (v == tc_ptr) 1022a513fe19Sbellard return tb; 1023a513fe19Sbellard else if (tc_ptr < v) { 1024a513fe19Sbellard m_max = m - 1; 1025a513fe19Sbellard } else { 1026a513fe19Sbellard m_min = m + 1; 1027a513fe19Sbellard } 1028a513fe19Sbellard } 1029a513fe19Sbellard return &tbs[m_max]; 1030a513fe19Sbellard } 10317501267eSbellard 1032ea041c0eSbellard static void tb_reset_jump_recursive(TranslationBlock *tb); 1033ea041c0eSbellard 1034ea041c0eSbellard static inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n) 1035ea041c0eSbellard { 1036ea041c0eSbellard TranslationBlock *tb1, *tb_next, **ptb; 1037ea041c0eSbellard unsigned int n1; 1038ea041c0eSbellard 1039ea041c0eSbellard tb1 = tb->jmp_next[n]; 1040ea041c0eSbellard if (tb1 != NULL) { 1041ea041c0eSbellard /* find head of list */ 1042ea041c0eSbellard for(;;) { 1043ea041c0eSbellard n1 = (long)tb1 & 3; 1044ea041c0eSbellard tb1 = (TranslationBlock *)((long)tb1 & ~3); 1045ea041c0eSbellard if (n1 == 2) 1046ea041c0eSbellard break; 1047ea041c0eSbellard tb1 = tb1->jmp_next[n1]; 1048ea041c0eSbellard } 1049ea041c0eSbellard /* we are now sure now that tb jumps to tb1 */ 1050ea041c0eSbellard tb_next = tb1; 1051ea041c0eSbellard 1052ea041c0eSbellard /* remove tb from the jmp_first list */ 1053ea041c0eSbellard ptb = &tb_next->jmp_first; 1054ea041c0eSbellard for(;;) { 1055ea041c0eSbellard tb1 = *ptb; 1056ea041c0eSbellard n1 = (long)tb1 & 3; 1057ea041c0eSbellard tb1 = (TranslationBlock *)((long)tb1 & ~3); 1058ea041c0eSbellard if (n1 == n && tb1 == tb) 1059ea041c0eSbellard break; 1060ea041c0eSbellard ptb = &tb1->jmp_next[n1]; 1061ea041c0eSbellard } 1062ea041c0eSbellard *ptb = tb->jmp_next[n]; 1063ea041c0eSbellard tb->jmp_next[n] = NULL; 1064ea041c0eSbellard 1065ea041c0eSbellard /* suppress the jump to next tb in generated code */ 1066ea041c0eSbellard tb_reset_jump(tb, n); 1067ea041c0eSbellard 10680124311eSbellard /* suppress jumps in the tb on which we could have jumped */ 1069ea041c0eSbellard tb_reset_jump_recursive(tb_next); 1070ea041c0eSbellard } 1071ea041c0eSbellard } 1072ea041c0eSbellard 1073ea041c0eSbellard static void tb_reset_jump_recursive(TranslationBlock *tb) 1074ea041c0eSbellard { 1075ea041c0eSbellard tb_reset_jump_recursive2(tb, 0); 1076ea041c0eSbellard tb_reset_jump_recursive2(tb, 1); 1077ea041c0eSbellard } 1078ea041c0eSbellard 1079c27004ecSbellard #if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC) 1080d720b93dSbellard static void breakpoint_invalidate(CPUState *env, target_ulong pc) 1081d720b93dSbellard { 1082d720b93dSbellard target_ulong phys_addr; 1083d720b93dSbellard 1084d720b93dSbellard phys_addr = cpu_get_phys_page_debug(env, pc); 1085d720b93dSbellard tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0); 1086d720b93dSbellard } 1087c27004ecSbellard #endif 1088d720b93dSbellard 1089c33a346eSbellard /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a 1090c33a346eSbellard breakpoint is reached */ 10912e12669aSbellard int cpu_breakpoint_insert(CPUState *env, target_ulong pc) 10924c3a88a2Sbellard { 1093e95c8d51Sbellard #if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC) 10944c3a88a2Sbellard int i; 10954c3a88a2Sbellard 10964c3a88a2Sbellard for(i = 0; i < env->nb_breakpoints; i++) { 10974c3a88a2Sbellard if (env->breakpoints[i] == pc) 10984c3a88a2Sbellard return 0; 10994c3a88a2Sbellard } 11004c3a88a2Sbellard 11014c3a88a2Sbellard if (env->nb_breakpoints >= MAX_BREAKPOINTS) 11024c3a88a2Sbellard return -1; 11034c3a88a2Sbellard env->breakpoints[env->nb_breakpoints++] = pc; 1104d720b93dSbellard 1105d720b93dSbellard breakpoint_invalidate(env, pc); 11064c3a88a2Sbellard return 0; 11074c3a88a2Sbellard #else 11084c3a88a2Sbellard return -1; 11094c3a88a2Sbellard #endif 11104c3a88a2Sbellard } 11114c3a88a2Sbellard 11124c3a88a2Sbellard /* remove a breakpoint */ 11132e12669aSbellard int cpu_breakpoint_remove(CPUState *env, target_ulong pc) 11144c3a88a2Sbellard { 1115e95c8d51Sbellard #if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC) 11164c3a88a2Sbellard int i; 11174c3a88a2Sbellard for(i = 0; i < env->nb_breakpoints; i++) { 11184c3a88a2Sbellard if (env->breakpoints[i] == pc) 11194c3a88a2Sbellard goto found; 11204c3a88a2Sbellard } 11214c3a88a2Sbellard return -1; 11224c3a88a2Sbellard found: 11234c3a88a2Sbellard memmove(&env->breakpoints[i], &env->breakpoints[i + 1], 11244c3a88a2Sbellard (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0])); 11254c3a88a2Sbellard env->nb_breakpoints--; 1126d720b93dSbellard 1127d720b93dSbellard breakpoint_invalidate(env, pc); 11284c3a88a2Sbellard return 0; 11294c3a88a2Sbellard #else 11304c3a88a2Sbellard return -1; 11314c3a88a2Sbellard #endif 11324c3a88a2Sbellard } 11334c3a88a2Sbellard 1134c33a346eSbellard /* enable or disable single step mode. EXCP_DEBUG is returned by the 1135c33a346eSbellard CPU loop after each instruction */ 1136c33a346eSbellard void cpu_single_step(CPUState *env, int enabled) 1137c33a346eSbellard { 1138e95c8d51Sbellard #if defined(TARGET_I386) || defined(TARGET_PPC) || defined(TARGET_SPARC) 1139c33a346eSbellard if (env->singlestep_enabled != enabled) { 1140c33a346eSbellard env->singlestep_enabled = enabled; 1141c33a346eSbellard /* must flush all the translated code to avoid inconsistancies */ 11429fa3e853Sbellard /* XXX: only flush what is necessary */ 11430124311eSbellard tb_flush(env); 1144c33a346eSbellard } 1145c33a346eSbellard #endif 1146c33a346eSbellard } 1147c33a346eSbellard 114834865134Sbellard /* enable or disable low levels log */ 114934865134Sbellard void cpu_set_log(int log_flags) 115034865134Sbellard { 115134865134Sbellard loglevel = log_flags; 115234865134Sbellard if (loglevel && !logfile) { 115334865134Sbellard logfile = fopen(logfilename, "w"); 115434865134Sbellard if (!logfile) { 115534865134Sbellard perror(logfilename); 115634865134Sbellard _exit(1); 115734865134Sbellard } 11589fa3e853Sbellard #if !defined(CONFIG_SOFTMMU) 11599fa3e853Sbellard /* must avoid mmap() usage of glibc by setting a buffer "by hand" */ 11609fa3e853Sbellard { 11619fa3e853Sbellard static uint8_t logfile_buf[4096]; 11629fa3e853Sbellard setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf)); 11639fa3e853Sbellard } 11649fa3e853Sbellard #else 116534865134Sbellard setvbuf(logfile, NULL, _IOLBF, 0); 11669fa3e853Sbellard #endif 116734865134Sbellard } 116834865134Sbellard } 116934865134Sbellard 117034865134Sbellard void cpu_set_log_filename(const char *filename) 117134865134Sbellard { 117234865134Sbellard logfilename = strdup(filename); 117334865134Sbellard } 1174c33a346eSbellard 11750124311eSbellard /* mask must never be zero, except for A20 change call */ 117668a79315Sbellard void cpu_interrupt(CPUState *env, int mask) 1177ea041c0eSbellard { 1178ea041c0eSbellard TranslationBlock *tb; 1179ee8b7021Sbellard static int interrupt_lock; 1180ea041c0eSbellard 118168a79315Sbellard env->interrupt_request |= mask; 1182ea041c0eSbellard /* if the cpu is currently executing code, we must unlink it and 1183ea041c0eSbellard all the potentially executing TB */ 1184ea041c0eSbellard tb = env->current_tb; 1185ee8b7021Sbellard if (tb && !testandset(&interrupt_lock)) { 1186ee8b7021Sbellard env->current_tb = NULL; 1187ea041c0eSbellard tb_reset_jump_recursive(tb); 1188ee8b7021Sbellard interrupt_lock = 0; 1189ea041c0eSbellard } 1190ea041c0eSbellard } 1191ea041c0eSbellard 1192b54ad049Sbellard void cpu_reset_interrupt(CPUState *env, int mask) 1193b54ad049Sbellard { 1194b54ad049Sbellard env->interrupt_request &= ~mask; 1195b54ad049Sbellard } 1196b54ad049Sbellard 1197f193c797Sbellard CPULogItem cpu_log_items[] = { 1198f193c797Sbellard { CPU_LOG_TB_OUT_ASM, "out_asm", 1199f193c797Sbellard "show generated host assembly code for each compiled TB" }, 1200f193c797Sbellard { CPU_LOG_TB_IN_ASM, "in_asm", 1201f193c797Sbellard "show target assembly code for each compiled TB" }, 1202f193c797Sbellard { CPU_LOG_TB_OP, "op", 1203f193c797Sbellard "show micro ops for each compiled TB (only usable if 'in_asm' used)" }, 1204f193c797Sbellard #ifdef TARGET_I386 1205f193c797Sbellard { CPU_LOG_TB_OP_OPT, "op_opt", 1206f193c797Sbellard "show micro ops after optimization for each compiled TB" }, 1207f193c797Sbellard #endif 1208f193c797Sbellard { CPU_LOG_INT, "int", 1209f193c797Sbellard "show interrupts/exceptions in short format" }, 1210f193c797Sbellard { CPU_LOG_EXEC, "exec", 1211f193c797Sbellard "show trace before each executed TB (lots of logs)" }, 12129fddaa0cSbellard { CPU_LOG_TB_CPU, "cpu", 12139fddaa0cSbellard "show CPU state before bloc translation" }, 1214f193c797Sbellard #ifdef TARGET_I386 1215f193c797Sbellard { CPU_LOG_PCALL, "pcall", 1216f193c797Sbellard "show protected mode far calls/returns/exceptions" }, 1217f193c797Sbellard #endif 12188e3a9fd2Sbellard #ifdef DEBUG_IOPORT 1219fd872598Sbellard { CPU_LOG_IOPORT, "ioport", 1220fd872598Sbellard "show all i/o ports accesses" }, 12218e3a9fd2Sbellard #endif 1222f193c797Sbellard { 0, NULL, NULL }, 1223f193c797Sbellard }; 1224f193c797Sbellard 1225f193c797Sbellard static int cmp1(const char *s1, int n, const char *s2) 1226f193c797Sbellard { 1227f193c797Sbellard if (strlen(s2) != n) 1228f193c797Sbellard return 0; 1229f193c797Sbellard return memcmp(s1, s2, n) == 0; 1230f193c797Sbellard } 1231f193c797Sbellard 1232f193c797Sbellard /* takes a comma separated list of log masks. Return 0 if error. */ 1233f193c797Sbellard int cpu_str_to_log_mask(const char *str) 1234f193c797Sbellard { 1235f193c797Sbellard CPULogItem *item; 1236f193c797Sbellard int mask; 1237f193c797Sbellard const char *p, *p1; 1238f193c797Sbellard 1239f193c797Sbellard p = str; 1240f193c797Sbellard mask = 0; 1241f193c797Sbellard for(;;) { 1242f193c797Sbellard p1 = strchr(p, ','); 1243f193c797Sbellard if (!p1) 1244f193c797Sbellard p1 = p + strlen(p); 12458e3a9fd2Sbellard if(cmp1(p,p1-p,"all")) { 12468e3a9fd2Sbellard for(item = cpu_log_items; item->mask != 0; item++) { 12478e3a9fd2Sbellard mask |= item->mask; 12488e3a9fd2Sbellard } 12498e3a9fd2Sbellard } else { 1250f193c797Sbellard for(item = cpu_log_items; item->mask != 0; item++) { 1251f193c797Sbellard if (cmp1(p, p1 - p, item->name)) 1252f193c797Sbellard goto found; 1253f193c797Sbellard } 1254f193c797Sbellard return 0; 12558e3a9fd2Sbellard } 1256f193c797Sbellard found: 1257f193c797Sbellard mask |= item->mask; 1258f193c797Sbellard if (*p1 != ',') 1259f193c797Sbellard break; 1260f193c797Sbellard p = p1 + 1; 1261f193c797Sbellard } 1262f193c797Sbellard return mask; 1263f193c797Sbellard } 1264ea041c0eSbellard 12657501267eSbellard void cpu_abort(CPUState *env, const char *fmt, ...) 12667501267eSbellard { 12677501267eSbellard va_list ap; 12687501267eSbellard 12697501267eSbellard va_start(ap, fmt); 12707501267eSbellard fprintf(stderr, "qemu: fatal: "); 12717501267eSbellard vfprintf(stderr, fmt, ap); 12727501267eSbellard fprintf(stderr, "\n"); 12737501267eSbellard #ifdef TARGET_I386 12747fe48483Sbellard cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP); 12757fe48483Sbellard #else 12767fe48483Sbellard cpu_dump_state(env, stderr, fprintf, 0); 12777501267eSbellard #endif 12787501267eSbellard va_end(ap); 12797501267eSbellard abort(); 12807501267eSbellard } 12817501267eSbellard 12820124311eSbellard #if !defined(CONFIG_USER_ONLY) 12830124311eSbellard 1284ee8b7021Sbellard /* NOTE: if flush_global is true, also flush global entries (not 1285ee8b7021Sbellard implemented yet) */ 1286ee8b7021Sbellard void tlb_flush(CPUState *env, int flush_global) 128733417e70Sbellard { 128833417e70Sbellard int i; 12890124311eSbellard 12909fa3e853Sbellard #if defined(DEBUG_TLB) 12919fa3e853Sbellard printf("tlb_flush:\n"); 12929fa3e853Sbellard #endif 12930124311eSbellard /* must reset current TB so that interrupts cannot modify the 12940124311eSbellard links while we are modifying them */ 12950124311eSbellard env->current_tb = NULL; 12960124311eSbellard 129733417e70Sbellard for(i = 0; i < CPU_TLB_SIZE; i++) { 129833417e70Sbellard env->tlb_read[0][i].address = -1; 129933417e70Sbellard env->tlb_write[0][i].address = -1; 130033417e70Sbellard env->tlb_read[1][i].address = -1; 130133417e70Sbellard env->tlb_write[1][i].address = -1; 130233417e70Sbellard } 13039fa3e853Sbellard 13049fa3e853Sbellard virt_page_flush(); 13058a8a608fSbellard memset (tb_hash, 0, CODE_GEN_HASH_SIZE * sizeof (void *)); 13069fa3e853Sbellard 13079fa3e853Sbellard #if !defined(CONFIG_SOFTMMU) 13089fa3e853Sbellard munmap((void *)MMAP_AREA_START, MMAP_AREA_END - MMAP_AREA_START); 13099fa3e853Sbellard #endif 13100a962c02Sbellard #ifdef USE_KQEMU 13110a962c02Sbellard if (env->kqemu_enabled) { 13120a962c02Sbellard kqemu_flush(env, flush_global); 13130a962c02Sbellard } 13140a962c02Sbellard #endif 1315e3db7226Sbellard tlb_flush_count++; 131633417e70Sbellard } 131733417e70Sbellard 1318274da6b2Sbellard static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr) 131961382a50Sbellard { 132061382a50Sbellard if (addr == (tlb_entry->address & 132161382a50Sbellard (TARGET_PAGE_MASK | TLB_INVALID_MASK))) 132261382a50Sbellard tlb_entry->address = -1; 132361382a50Sbellard } 132461382a50Sbellard 13252e12669aSbellard void tlb_flush_page(CPUState *env, target_ulong addr) 132633417e70Sbellard { 13279fa3e853Sbellard int i, n; 13289fa3e853Sbellard VirtPageDesc *vp; 13299fa3e853Sbellard PageDesc *p; 13309fa3e853Sbellard TranslationBlock *tb; 13310124311eSbellard 13329fa3e853Sbellard #if defined(DEBUG_TLB) 13339fa3e853Sbellard printf("tlb_flush_page: 0x%08x\n", addr); 13349fa3e853Sbellard #endif 13350124311eSbellard /* must reset current TB so that interrupts cannot modify the 13360124311eSbellard links while we are modifying them */ 13370124311eSbellard env->current_tb = NULL; 133833417e70Sbellard 133961382a50Sbellard addr &= TARGET_PAGE_MASK; 134033417e70Sbellard i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); 134161382a50Sbellard tlb_flush_entry(&env->tlb_read[0][i], addr); 134261382a50Sbellard tlb_flush_entry(&env->tlb_write[0][i], addr); 134361382a50Sbellard tlb_flush_entry(&env->tlb_read[1][i], addr); 134461382a50Sbellard tlb_flush_entry(&env->tlb_write[1][i], addr); 13450124311eSbellard 13469fa3e853Sbellard /* remove from the virtual pc hash table all the TB at this 13479fa3e853Sbellard virtual address */ 13489fa3e853Sbellard 13499fa3e853Sbellard vp = virt_page_find(addr >> TARGET_PAGE_BITS); 13509fa3e853Sbellard if (vp && vp->valid_tag == virt_valid_tag) { 13519fa3e853Sbellard p = page_find(vp->phys_addr >> TARGET_PAGE_BITS); 13529fa3e853Sbellard if (p) { 13539fa3e853Sbellard /* we remove all the links to the TBs in this virtual page */ 13549fa3e853Sbellard tb = p->first_tb; 13559fa3e853Sbellard while (tb != NULL) { 13569fa3e853Sbellard n = (long)tb & 3; 13579fa3e853Sbellard tb = (TranslationBlock *)((long)tb & ~3); 13589fa3e853Sbellard if ((tb->pc & TARGET_PAGE_MASK) == addr || 13599fa3e853Sbellard ((tb->pc + tb->size - 1) & TARGET_PAGE_MASK) == addr) { 13609fa3e853Sbellard tb_invalidate(tb); 13619fa3e853Sbellard } 13629fa3e853Sbellard tb = tb->page_next[n]; 13639fa3e853Sbellard } 13640124311eSbellard } 136598857888Sbellard vp->valid_tag = 0; 136661382a50Sbellard } 136761382a50Sbellard 13689fa3e853Sbellard #if !defined(CONFIG_SOFTMMU) 13699fa3e853Sbellard if (addr < MMAP_AREA_END) 13709fa3e853Sbellard munmap((void *)addr, TARGET_PAGE_SIZE); 13719fa3e853Sbellard #endif 13720a962c02Sbellard #ifdef USE_KQEMU 13730a962c02Sbellard if (env->kqemu_enabled) { 13740a962c02Sbellard kqemu_flush_page(env, addr); 13750a962c02Sbellard } 13760a962c02Sbellard #endif 13779fa3e853Sbellard } 13789fa3e853Sbellard 13794f2ac237Sbellard static inline void tlb_protect_code1(CPUTLBEntry *tlb_entry, target_ulong addr) 13809fa3e853Sbellard { 13819fa3e853Sbellard if (addr == (tlb_entry->address & 13829fa3e853Sbellard (TARGET_PAGE_MASK | TLB_INVALID_MASK)) && 138398857888Sbellard (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_CODE && 138498857888Sbellard (tlb_entry->address & ~TARGET_PAGE_MASK) != IO_MEM_ROM) { 13851ccde1cbSbellard tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_CODE; 13869fa3e853Sbellard } 13879fa3e853Sbellard } 13889fa3e853Sbellard 13899fa3e853Sbellard /* update the TLBs so that writes to code in the virtual page 'addr' 13909fa3e853Sbellard can be detected */ 13914f2ac237Sbellard static void tlb_protect_code(CPUState *env, target_ulong addr) 139261382a50Sbellard { 139361382a50Sbellard int i; 139461382a50Sbellard 139561382a50Sbellard addr &= TARGET_PAGE_MASK; 139661382a50Sbellard i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); 13979fa3e853Sbellard tlb_protect_code1(&env->tlb_write[0][i], addr); 13989fa3e853Sbellard tlb_protect_code1(&env->tlb_write[1][i], addr); 13999fa3e853Sbellard #if !defined(CONFIG_SOFTMMU) 14009fa3e853Sbellard /* NOTE: as we generated the code for this page, it is already at 14019fa3e853Sbellard least readable */ 14029fa3e853Sbellard if (addr < MMAP_AREA_END) 14039fa3e853Sbellard mprotect((void *)addr, TARGET_PAGE_SIZE, PROT_READ); 14049fa3e853Sbellard #endif 14059fa3e853Sbellard } 14069fa3e853Sbellard 14079fa3e853Sbellard static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry, 14084f2ac237Sbellard unsigned long phys_addr) 14099fa3e853Sbellard { 14109fa3e853Sbellard if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE && 14119fa3e853Sbellard ((tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend) == phys_addr) { 14121ccde1cbSbellard tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY; 14139fa3e853Sbellard } 14149fa3e853Sbellard } 14159fa3e853Sbellard 14169fa3e853Sbellard /* update the TLB so that writes in physical page 'phys_addr' are no longer 14179fa3e853Sbellard tested self modifying code */ 14184f2ac237Sbellard static void tlb_unprotect_code_phys(CPUState *env, unsigned long phys_addr, target_ulong vaddr) 14199fa3e853Sbellard { 14209fa3e853Sbellard int i; 14219fa3e853Sbellard 14229fa3e853Sbellard phys_addr &= TARGET_PAGE_MASK; 14231ccde1cbSbellard phys_addr += (long)phys_ram_base; 14241ccde1cbSbellard i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); 14259fa3e853Sbellard tlb_unprotect_code2(&env->tlb_write[0][i], phys_addr); 14269fa3e853Sbellard tlb_unprotect_code2(&env->tlb_write[1][i], phys_addr); 14279fa3e853Sbellard } 14289fa3e853Sbellard 14291ccde1cbSbellard static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, 14301ccde1cbSbellard unsigned long start, unsigned long length) 14311ccde1cbSbellard { 14321ccde1cbSbellard unsigned long addr; 14331ccde1cbSbellard if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { 14341ccde1cbSbellard addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend; 14351ccde1cbSbellard if ((addr - start) < length) { 14361ccde1cbSbellard tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY; 14371ccde1cbSbellard } 14381ccde1cbSbellard } 14391ccde1cbSbellard } 14401ccde1cbSbellard 14410a962c02Sbellard void cpu_physical_memory_reset_dirty(target_ulong start, target_ulong end, 14420a962c02Sbellard int dirty_flags) 14431ccde1cbSbellard { 14441ccde1cbSbellard CPUState *env; 14454f2ac237Sbellard unsigned long length, start1; 14460a962c02Sbellard int i, mask, len; 14470a962c02Sbellard uint8_t *p; 14481ccde1cbSbellard 14491ccde1cbSbellard start &= TARGET_PAGE_MASK; 14501ccde1cbSbellard end = TARGET_PAGE_ALIGN(end); 14511ccde1cbSbellard 14521ccde1cbSbellard length = end - start; 14531ccde1cbSbellard if (length == 0) 14541ccde1cbSbellard return; 14550a962c02Sbellard mask = ~dirty_flags; 14560a962c02Sbellard p = phys_ram_dirty + (start >> TARGET_PAGE_BITS); 14570a962c02Sbellard len = length >> TARGET_PAGE_BITS; 14580a962c02Sbellard for(i = 0; i < len; i++) 14590a962c02Sbellard p[i] &= mask; 14601ccde1cbSbellard 14611ccde1cbSbellard env = cpu_single_env; 14621ccde1cbSbellard /* we modify the TLB cache so that the dirty bit will be set again 14631ccde1cbSbellard when accessing the range */ 146459817ccbSbellard start1 = start + (unsigned long)phys_ram_base; 14651ccde1cbSbellard for(i = 0; i < CPU_TLB_SIZE; i++) 146659817ccbSbellard tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length); 14671ccde1cbSbellard for(i = 0; i < CPU_TLB_SIZE; i++) 146859817ccbSbellard tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length); 146959817ccbSbellard 147059817ccbSbellard #if !defined(CONFIG_SOFTMMU) 147159817ccbSbellard /* XXX: this is expensive */ 147259817ccbSbellard { 147359817ccbSbellard VirtPageDesc *p; 147459817ccbSbellard int j; 147559817ccbSbellard target_ulong addr; 147659817ccbSbellard 147759817ccbSbellard for(i = 0; i < L1_SIZE; i++) { 147859817ccbSbellard p = l1_virt_map[i]; 147959817ccbSbellard if (p) { 148059817ccbSbellard addr = i << (TARGET_PAGE_BITS + L2_BITS); 148159817ccbSbellard for(j = 0; j < L2_SIZE; j++) { 148259817ccbSbellard if (p->valid_tag == virt_valid_tag && 148359817ccbSbellard p->phys_addr >= start && p->phys_addr < end && 148459817ccbSbellard (p->prot & PROT_WRITE)) { 148559817ccbSbellard if (addr < MMAP_AREA_END) { 148659817ccbSbellard mprotect((void *)addr, TARGET_PAGE_SIZE, 148759817ccbSbellard p->prot & ~PROT_WRITE); 148859817ccbSbellard } 148959817ccbSbellard } 149059817ccbSbellard addr += TARGET_PAGE_SIZE; 149159817ccbSbellard p++; 149259817ccbSbellard } 149359817ccbSbellard } 149459817ccbSbellard } 149559817ccbSbellard } 149659817ccbSbellard #endif 14971ccde1cbSbellard } 14981ccde1cbSbellard 14991ccde1cbSbellard static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, 15001ccde1cbSbellard unsigned long start) 15011ccde1cbSbellard { 15021ccde1cbSbellard unsigned long addr; 15031ccde1cbSbellard if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) { 15041ccde1cbSbellard addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend; 15051ccde1cbSbellard if (addr == start) { 15061ccde1cbSbellard tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM; 15071ccde1cbSbellard } 15081ccde1cbSbellard } 15091ccde1cbSbellard } 15101ccde1cbSbellard 15111ccde1cbSbellard /* update the TLB corresponding to virtual page vaddr and phys addr 15121ccde1cbSbellard addr so that it is no longer dirty */ 15131ccde1cbSbellard static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr) 15141ccde1cbSbellard { 15151ccde1cbSbellard CPUState *env = cpu_single_env; 15161ccde1cbSbellard int i; 15171ccde1cbSbellard 15180a962c02Sbellard phys_ram_dirty[(addr - (unsigned long)phys_ram_base) >> TARGET_PAGE_BITS] = 0xff; 15191ccde1cbSbellard 15201ccde1cbSbellard addr &= TARGET_PAGE_MASK; 15211ccde1cbSbellard i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); 15221ccde1cbSbellard tlb_set_dirty1(&env->tlb_write[0][i], addr); 15231ccde1cbSbellard tlb_set_dirty1(&env->tlb_write[1][i], addr); 15241ccde1cbSbellard } 15251ccde1cbSbellard 152659817ccbSbellard /* add a new TLB entry. At most one entry for a given virtual address 152759817ccbSbellard is permitted. Return 0 if OK or 2 if the page could not be mapped 152859817ccbSbellard (can only happen in non SOFTMMU mode for I/O pages or pages 152959817ccbSbellard conflicting with the host address space). */ 15302e12669aSbellard int tlb_set_page(CPUState *env, target_ulong vaddr, 15312e12669aSbellard target_phys_addr_t paddr, int prot, 15329fa3e853Sbellard int is_user, int is_softmmu) 15339fa3e853Sbellard { 153492e873b9Sbellard PhysPageDesc *p; 15354f2ac237Sbellard unsigned long pd; 15369fa3e853Sbellard TranslationBlock *first_tb; 15379fa3e853Sbellard unsigned int index; 15384f2ac237Sbellard target_ulong address; 15394f2ac237Sbellard unsigned long addend; 15409fa3e853Sbellard int ret; 15419fa3e853Sbellard 154292e873b9Sbellard p = phys_page_find(paddr >> TARGET_PAGE_BITS); 154392e873b9Sbellard first_tb = NULL; 15449fa3e853Sbellard if (!p) { 15459fa3e853Sbellard pd = IO_MEM_UNASSIGNED; 15469fa3e853Sbellard } else { 154792e873b9Sbellard PageDesc *p1; 15489fa3e853Sbellard pd = p->phys_offset; 154992e873b9Sbellard if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) { 155092e873b9Sbellard /* NOTE: we also allocate the page at this stage */ 155192e873b9Sbellard p1 = page_find_alloc(pd >> TARGET_PAGE_BITS); 155292e873b9Sbellard first_tb = p1->first_tb; 155392e873b9Sbellard } 15549fa3e853Sbellard } 15559fa3e853Sbellard #if defined(DEBUG_TLB) 15569fa3e853Sbellard printf("tlb_set_page: vaddr=0x%08x paddr=0x%08x prot=%x u=%d c=%d smmu=%d pd=0x%08x\n", 15579fa3e853Sbellard vaddr, paddr, prot, is_user, (first_tb != NULL), is_softmmu, pd); 15589fa3e853Sbellard #endif 15599fa3e853Sbellard 15609fa3e853Sbellard ret = 0; 15619fa3e853Sbellard #if !defined(CONFIG_SOFTMMU) 15629fa3e853Sbellard if (is_softmmu) 15639fa3e853Sbellard #endif 15649fa3e853Sbellard { 15659fa3e853Sbellard if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { 15669fa3e853Sbellard /* IO memory case */ 15679fa3e853Sbellard address = vaddr | pd; 15689fa3e853Sbellard addend = paddr; 15699fa3e853Sbellard } else { 15709fa3e853Sbellard /* standard memory */ 15719fa3e853Sbellard address = vaddr; 15729fa3e853Sbellard addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK); 15739fa3e853Sbellard } 15749fa3e853Sbellard 15759fa3e853Sbellard index = (vaddr >> 12) & (CPU_TLB_SIZE - 1); 15769fa3e853Sbellard addend -= vaddr; 157767b915a5Sbellard if (prot & PAGE_READ) { 15789fa3e853Sbellard env->tlb_read[is_user][index].address = address; 15799fa3e853Sbellard env->tlb_read[is_user][index].addend = addend; 15809fa3e853Sbellard } else { 15819fa3e853Sbellard env->tlb_read[is_user][index].address = -1; 15829fa3e853Sbellard env->tlb_read[is_user][index].addend = -1; 15839fa3e853Sbellard } 158467b915a5Sbellard if (prot & PAGE_WRITE) { 15859fa3e853Sbellard if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) { 15869fa3e853Sbellard /* ROM: access is ignored (same as unassigned) */ 15879fa3e853Sbellard env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM; 15881ccde1cbSbellard env->tlb_write[is_user][index].addend = addend; 1589d720b93dSbellard } else 1590d720b93dSbellard /* XXX: the PowerPC code seems not ready to handle 1591d720b93dSbellard self modifying code with DCBI */ 1592d720b93dSbellard #if defined(TARGET_HAS_SMC) || 1 1593d720b93dSbellard if (first_tb) { 15949fa3e853Sbellard /* if code is present, we use a specific memory 15959fa3e853Sbellard handler. It works only for physical memory access */ 15969fa3e853Sbellard env->tlb_write[is_user][index].address = vaddr | IO_MEM_CODE; 15971ccde1cbSbellard env->tlb_write[is_user][index].addend = addend; 1598d720b93dSbellard } else 1599d720b93dSbellard #endif 1600d720b93dSbellard if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && 16011ccde1cbSbellard !cpu_physical_memory_is_dirty(pd)) { 16021ccde1cbSbellard env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY; 16031ccde1cbSbellard env->tlb_write[is_user][index].addend = addend; 16049fa3e853Sbellard } else { 16059fa3e853Sbellard env->tlb_write[is_user][index].address = address; 16069fa3e853Sbellard env->tlb_write[is_user][index].addend = addend; 16079fa3e853Sbellard } 16089fa3e853Sbellard } else { 16099fa3e853Sbellard env->tlb_write[is_user][index].address = -1; 16109fa3e853Sbellard env->tlb_write[is_user][index].addend = -1; 16119fa3e853Sbellard } 16129fa3e853Sbellard } 16139fa3e853Sbellard #if !defined(CONFIG_SOFTMMU) 16149fa3e853Sbellard else { 16159fa3e853Sbellard if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { 16169fa3e853Sbellard /* IO access: no mapping is done as it will be handled by the 16179fa3e853Sbellard soft MMU */ 16189fa3e853Sbellard if (!(env->hflags & HF_SOFTMMU_MASK)) 16199fa3e853Sbellard ret = 2; 16209fa3e853Sbellard } else { 16219fa3e853Sbellard void *map_addr; 162259817ccbSbellard 162359817ccbSbellard if (vaddr >= MMAP_AREA_END) { 162459817ccbSbellard ret = 2; 162559817ccbSbellard } else { 16269fa3e853Sbellard if (prot & PROT_WRITE) { 162759817ccbSbellard if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || 1628d720b93dSbellard #if defined(TARGET_HAS_SMC) || 1 162959817ccbSbellard first_tb || 1630d720b93dSbellard #endif 163159817ccbSbellard ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && 163259817ccbSbellard !cpu_physical_memory_is_dirty(pd))) { 16339fa3e853Sbellard /* ROM: we do as if code was inside */ 16349fa3e853Sbellard /* if code is present, we only map as read only and save the 16359fa3e853Sbellard original mapping */ 16369fa3e853Sbellard VirtPageDesc *vp; 16379fa3e853Sbellard 16389fa3e853Sbellard vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS); 16399fa3e853Sbellard vp->phys_addr = pd; 16409fa3e853Sbellard vp->prot = prot; 16419fa3e853Sbellard vp->valid_tag = virt_valid_tag; 16429fa3e853Sbellard prot &= ~PAGE_WRITE; 16439fa3e853Sbellard } 16449fa3e853Sbellard } 16459fa3e853Sbellard map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot, 16469fa3e853Sbellard MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK)); 16479fa3e853Sbellard if (map_addr == MAP_FAILED) { 16489fa3e853Sbellard cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", 16499fa3e853Sbellard paddr, vaddr); 16509fa3e853Sbellard } 16519fa3e853Sbellard } 16529fa3e853Sbellard } 165359817ccbSbellard } 16549fa3e853Sbellard #endif 16559fa3e853Sbellard return ret; 16569fa3e853Sbellard } 16579fa3e853Sbellard 16589fa3e853Sbellard /* called from signal handler: invalidate the code and unprotect the 16599fa3e853Sbellard page. Return TRUE if the fault was succesfully handled. */ 1660d720b93dSbellard int page_unprotect(unsigned long addr, unsigned long pc, void *puc) 16619fa3e853Sbellard { 16629fa3e853Sbellard #if !defined(CONFIG_SOFTMMU) 16639fa3e853Sbellard VirtPageDesc *vp; 16649fa3e853Sbellard 16659fa3e853Sbellard #if defined(DEBUG_TLB) 16669fa3e853Sbellard printf("page_unprotect: addr=0x%08x\n", addr); 16679fa3e853Sbellard #endif 16689fa3e853Sbellard addr &= TARGET_PAGE_MASK; 166959817ccbSbellard 167059817ccbSbellard /* if it is not mapped, no need to worry here */ 167159817ccbSbellard if (addr >= MMAP_AREA_END) 167259817ccbSbellard return 0; 16739fa3e853Sbellard vp = virt_page_find(addr >> TARGET_PAGE_BITS); 16749fa3e853Sbellard if (!vp) 16759fa3e853Sbellard return 0; 16769fa3e853Sbellard /* NOTE: in this case, validate_tag is _not_ tested as it 16779fa3e853Sbellard validates only the code TLB */ 16789fa3e853Sbellard if (vp->valid_tag != virt_valid_tag) 16799fa3e853Sbellard return 0; 16809fa3e853Sbellard if (!(vp->prot & PAGE_WRITE)) 16819fa3e853Sbellard return 0; 16829fa3e853Sbellard #if defined(DEBUG_TLB) 16839fa3e853Sbellard printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n", 16849fa3e853Sbellard addr, vp->phys_addr, vp->prot); 16859fa3e853Sbellard #endif 168659817ccbSbellard if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0) 168759817ccbSbellard cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n", 168859817ccbSbellard (unsigned long)addr, vp->prot); 1689d720b93dSbellard /* set the dirty bit */ 16900a962c02Sbellard phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff; 1691d720b93dSbellard /* flush the code inside */ 1692d720b93dSbellard tb_invalidate_phys_page(vp->phys_addr, pc, puc); 16939fa3e853Sbellard return 1; 16949fa3e853Sbellard #else 16959fa3e853Sbellard return 0; 16969fa3e853Sbellard #endif 169733417e70Sbellard } 169833417e70Sbellard 16990124311eSbellard #else 17000124311eSbellard 1701ee8b7021Sbellard void tlb_flush(CPUState *env, int flush_global) 17020124311eSbellard { 17030124311eSbellard } 17040124311eSbellard 17052e12669aSbellard void tlb_flush_page(CPUState *env, target_ulong addr) 17060124311eSbellard { 17070124311eSbellard } 17080124311eSbellard 17092e12669aSbellard int tlb_set_page(CPUState *env, target_ulong vaddr, 17102e12669aSbellard target_phys_addr_t paddr, int prot, 17119fa3e853Sbellard int is_user, int is_softmmu) 171233417e70Sbellard { 17139fa3e853Sbellard return 0; 171433417e70Sbellard } 171533417e70Sbellard 17169fa3e853Sbellard /* dump memory mappings */ 17179fa3e853Sbellard void page_dump(FILE *f) 171833417e70Sbellard { 17199fa3e853Sbellard unsigned long start, end; 17209fa3e853Sbellard int i, j, prot, prot1; 17219fa3e853Sbellard PageDesc *p; 17229fa3e853Sbellard 17239fa3e853Sbellard fprintf(f, "%-8s %-8s %-8s %s\n", 17249fa3e853Sbellard "start", "end", "size", "prot"); 17259fa3e853Sbellard start = -1; 17269fa3e853Sbellard end = -1; 17279fa3e853Sbellard prot = 0; 17289fa3e853Sbellard for(i = 0; i <= L1_SIZE; i++) { 17299fa3e853Sbellard if (i < L1_SIZE) 17309fa3e853Sbellard p = l1_map[i]; 17319fa3e853Sbellard else 17329fa3e853Sbellard p = NULL; 17339fa3e853Sbellard for(j = 0;j < L2_SIZE; j++) { 173433417e70Sbellard if (!p) 17359fa3e853Sbellard prot1 = 0; 17369fa3e853Sbellard else 17379fa3e853Sbellard prot1 = p[j].flags; 17389fa3e853Sbellard if (prot1 != prot) { 17399fa3e853Sbellard end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS); 17409fa3e853Sbellard if (start != -1) { 17419fa3e853Sbellard fprintf(f, "%08lx-%08lx %08lx %c%c%c\n", 17429fa3e853Sbellard start, end, end - start, 17439fa3e853Sbellard prot & PAGE_READ ? 'r' : '-', 17449fa3e853Sbellard prot & PAGE_WRITE ? 'w' : '-', 17459fa3e853Sbellard prot & PAGE_EXEC ? 'x' : '-'); 174633417e70Sbellard } 17479fa3e853Sbellard if (prot1 != 0) 17489fa3e853Sbellard start = end; 17499fa3e853Sbellard else 17509fa3e853Sbellard start = -1; 17519fa3e853Sbellard prot = prot1; 17529fa3e853Sbellard } 17539fa3e853Sbellard if (!p) 17549fa3e853Sbellard break; 17559fa3e853Sbellard } 17569fa3e853Sbellard } 17579fa3e853Sbellard } 17589fa3e853Sbellard 17599fa3e853Sbellard int page_get_flags(unsigned long address) 17609fa3e853Sbellard { 17619fa3e853Sbellard PageDesc *p; 17629fa3e853Sbellard 17639fa3e853Sbellard p = page_find(address >> TARGET_PAGE_BITS); 17649fa3e853Sbellard if (!p) 17659fa3e853Sbellard return 0; 17669fa3e853Sbellard return p->flags; 17679fa3e853Sbellard } 17689fa3e853Sbellard 17699fa3e853Sbellard /* modify the flags of a page and invalidate the code if 17709fa3e853Sbellard necessary. The flag PAGE_WRITE_ORG is positionned automatically 17719fa3e853Sbellard depending on PAGE_WRITE */ 17729fa3e853Sbellard void page_set_flags(unsigned long start, unsigned long end, int flags) 17739fa3e853Sbellard { 17749fa3e853Sbellard PageDesc *p; 17759fa3e853Sbellard unsigned long addr; 17769fa3e853Sbellard 17779fa3e853Sbellard start = start & TARGET_PAGE_MASK; 17789fa3e853Sbellard end = TARGET_PAGE_ALIGN(end); 17799fa3e853Sbellard if (flags & PAGE_WRITE) 17809fa3e853Sbellard flags |= PAGE_WRITE_ORG; 17819fa3e853Sbellard spin_lock(&tb_lock); 17829fa3e853Sbellard for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { 17839fa3e853Sbellard p = page_find_alloc(addr >> TARGET_PAGE_BITS); 17849fa3e853Sbellard /* if the write protection is set, then we invalidate the code 17859fa3e853Sbellard inside */ 17869fa3e853Sbellard if (!(p->flags & PAGE_WRITE) && 17879fa3e853Sbellard (flags & PAGE_WRITE) && 17889fa3e853Sbellard p->first_tb) { 1789d720b93dSbellard tb_invalidate_phys_page(addr, 0, NULL); 17909fa3e853Sbellard } 17919fa3e853Sbellard p->flags = flags; 17929fa3e853Sbellard } 17939fa3e853Sbellard spin_unlock(&tb_lock); 17949fa3e853Sbellard } 17959fa3e853Sbellard 17969fa3e853Sbellard /* called from signal handler: invalidate the code and unprotect the 17979fa3e853Sbellard page. Return TRUE if the fault was succesfully handled. */ 1798d720b93dSbellard int page_unprotect(unsigned long address, unsigned long pc, void *puc) 17999fa3e853Sbellard { 18009fa3e853Sbellard unsigned int page_index, prot, pindex; 18019fa3e853Sbellard PageDesc *p, *p1; 18029fa3e853Sbellard unsigned long host_start, host_end, addr; 18039fa3e853Sbellard 180483fb7adfSbellard host_start = address & qemu_host_page_mask; 18059fa3e853Sbellard page_index = host_start >> TARGET_PAGE_BITS; 18069fa3e853Sbellard p1 = page_find(page_index); 18079fa3e853Sbellard if (!p1) 18089fa3e853Sbellard return 0; 180983fb7adfSbellard host_end = host_start + qemu_host_page_size; 18109fa3e853Sbellard p = p1; 18119fa3e853Sbellard prot = 0; 18129fa3e853Sbellard for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) { 18139fa3e853Sbellard prot |= p->flags; 18149fa3e853Sbellard p++; 18159fa3e853Sbellard } 18169fa3e853Sbellard /* if the page was really writable, then we change its 18179fa3e853Sbellard protection back to writable */ 18189fa3e853Sbellard if (prot & PAGE_WRITE_ORG) { 18199fa3e853Sbellard pindex = (address - host_start) >> TARGET_PAGE_BITS; 18209fa3e853Sbellard if (!(p1[pindex].flags & PAGE_WRITE)) { 182183fb7adfSbellard mprotect((void *)host_start, qemu_host_page_size, 18229fa3e853Sbellard (prot & PAGE_BITS) | PAGE_WRITE); 18239fa3e853Sbellard p1[pindex].flags |= PAGE_WRITE; 18249fa3e853Sbellard /* and since the content will be modified, we must invalidate 18259fa3e853Sbellard the corresponding translated code. */ 1826d720b93dSbellard tb_invalidate_phys_page(address, pc, puc); 18279fa3e853Sbellard #ifdef DEBUG_TB_CHECK 18289fa3e853Sbellard tb_invalidate_check(address); 18299fa3e853Sbellard #endif 18309fa3e853Sbellard return 1; 18319fa3e853Sbellard } 18329fa3e853Sbellard } 18339fa3e853Sbellard return 0; 18349fa3e853Sbellard } 18359fa3e853Sbellard 18369fa3e853Sbellard /* call this function when system calls directly modify a memory area */ 18379fa3e853Sbellard void page_unprotect_range(uint8_t *data, unsigned long data_size) 18389fa3e853Sbellard { 18399fa3e853Sbellard unsigned long start, end, addr; 18409fa3e853Sbellard 18419fa3e853Sbellard start = (unsigned long)data; 18429fa3e853Sbellard end = start + data_size; 18439fa3e853Sbellard start &= TARGET_PAGE_MASK; 18449fa3e853Sbellard end = TARGET_PAGE_ALIGN(end); 18459fa3e853Sbellard for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) { 1846d720b93dSbellard page_unprotect(addr, 0, NULL); 18479fa3e853Sbellard } 18489fa3e853Sbellard } 18499fa3e853Sbellard 18501ccde1cbSbellard static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr) 18511ccde1cbSbellard { 18521ccde1cbSbellard } 18539fa3e853Sbellard #endif /* defined(CONFIG_USER_ONLY) */ 185433417e70Sbellard 185533417e70Sbellard /* register physical memory. 'size' must be a multiple of the target 185633417e70Sbellard page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an 185733417e70Sbellard io memory page */ 18582e12669aSbellard void cpu_register_physical_memory(target_phys_addr_t start_addr, 18592e12669aSbellard unsigned long size, 18602e12669aSbellard unsigned long phys_offset) 186133417e70Sbellard { 186233417e70Sbellard unsigned long addr, end_addr; 186392e873b9Sbellard PhysPageDesc *p; 186433417e70Sbellard 18655fd386f6Sbellard size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK; 186633417e70Sbellard end_addr = start_addr + size; 18675fd386f6Sbellard for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) { 186892e873b9Sbellard p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS); 18699fa3e853Sbellard p->phys_offset = phys_offset; 18709fa3e853Sbellard if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) 187133417e70Sbellard phys_offset += TARGET_PAGE_SIZE; 187233417e70Sbellard } 187333417e70Sbellard } 187433417e70Sbellard 1875a4193c8aSbellard static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr) 187633417e70Sbellard { 187733417e70Sbellard return 0; 187833417e70Sbellard } 187933417e70Sbellard 1880a4193c8aSbellard static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) 188133417e70Sbellard { 188233417e70Sbellard } 188333417e70Sbellard 188433417e70Sbellard static CPUReadMemoryFunc *unassigned_mem_read[3] = { 188533417e70Sbellard unassigned_mem_readb, 188633417e70Sbellard unassigned_mem_readb, 188733417e70Sbellard unassigned_mem_readb, 188833417e70Sbellard }; 188933417e70Sbellard 189033417e70Sbellard static CPUWriteMemoryFunc *unassigned_mem_write[3] = { 189133417e70Sbellard unassigned_mem_writeb, 189233417e70Sbellard unassigned_mem_writeb, 189333417e70Sbellard unassigned_mem_writeb, 189433417e70Sbellard }; 189533417e70Sbellard 18969fa3e853Sbellard /* self modifying code support in soft mmu mode : writing to a page 18979fa3e853Sbellard containing code comes to these functions */ 18989fa3e853Sbellard 1899a4193c8aSbellard static void code_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) 19009fa3e853Sbellard { 19011ccde1cbSbellard unsigned long phys_addr; 19021ccde1cbSbellard 1903274da6b2Sbellard phys_addr = addr - (unsigned long)phys_ram_base; 19049fa3e853Sbellard #if !defined(CONFIG_USER_ONLY) 1905d720b93dSbellard tb_invalidate_phys_page_fast(phys_addr, 1); 19069fa3e853Sbellard #endif 1907c27004ecSbellard stb_p((uint8_t *)(long)addr, val); 19080a962c02Sbellard phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff; 19099fa3e853Sbellard } 19109fa3e853Sbellard 1911a4193c8aSbellard static void code_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) 19129fa3e853Sbellard { 19131ccde1cbSbellard unsigned long phys_addr; 19141ccde1cbSbellard 1915274da6b2Sbellard phys_addr = addr - (unsigned long)phys_ram_base; 19169fa3e853Sbellard #if !defined(CONFIG_USER_ONLY) 1917d720b93dSbellard tb_invalidate_phys_page_fast(phys_addr, 2); 19189fa3e853Sbellard #endif 1919c27004ecSbellard stw_p((uint8_t *)(long)addr, val); 19200a962c02Sbellard phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff; 19219fa3e853Sbellard } 19229fa3e853Sbellard 1923a4193c8aSbellard static void code_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) 19249fa3e853Sbellard { 19251ccde1cbSbellard unsigned long phys_addr; 19261ccde1cbSbellard 1927274da6b2Sbellard phys_addr = addr - (unsigned long)phys_ram_base; 19289fa3e853Sbellard #if !defined(CONFIG_USER_ONLY) 1929d720b93dSbellard tb_invalidate_phys_page_fast(phys_addr, 4); 19309fa3e853Sbellard #endif 1931c27004ecSbellard stl_p((uint8_t *)(long)addr, val); 19320a962c02Sbellard phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 0xff; 19339fa3e853Sbellard } 19349fa3e853Sbellard 19359fa3e853Sbellard static CPUReadMemoryFunc *code_mem_read[3] = { 19369fa3e853Sbellard NULL, /* never used */ 19379fa3e853Sbellard NULL, /* never used */ 19389fa3e853Sbellard NULL, /* never used */ 19399fa3e853Sbellard }; 19409fa3e853Sbellard 19419fa3e853Sbellard static CPUWriteMemoryFunc *code_mem_write[3] = { 19429fa3e853Sbellard code_mem_writeb, 19439fa3e853Sbellard code_mem_writew, 19449fa3e853Sbellard code_mem_writel, 19459fa3e853Sbellard }; 194633417e70Sbellard 1947a4193c8aSbellard static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) 19481ccde1cbSbellard { 1949c27004ecSbellard stb_p((uint8_t *)(long)addr, val); 1950d720b93dSbellard tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); 19511ccde1cbSbellard } 19521ccde1cbSbellard 1953a4193c8aSbellard static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val) 19541ccde1cbSbellard { 1955c27004ecSbellard stw_p((uint8_t *)(long)addr, val); 1956d720b93dSbellard tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); 19571ccde1cbSbellard } 19581ccde1cbSbellard 1959a4193c8aSbellard static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) 19601ccde1cbSbellard { 1961c27004ecSbellard stl_p((uint8_t *)(long)addr, val); 1962d720b93dSbellard tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr); 19631ccde1cbSbellard } 19641ccde1cbSbellard 19651ccde1cbSbellard static CPUWriteMemoryFunc *notdirty_mem_write[3] = { 19661ccde1cbSbellard notdirty_mem_writeb, 19671ccde1cbSbellard notdirty_mem_writew, 19681ccde1cbSbellard notdirty_mem_writel, 19691ccde1cbSbellard }; 19701ccde1cbSbellard 197133417e70Sbellard static void io_mem_init(void) 197233417e70Sbellard { 1973a4193c8aSbellard cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, code_mem_read, unassigned_mem_write, NULL); 1974a4193c8aSbellard cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL); 1975a4193c8aSbellard cpu_register_io_memory(IO_MEM_CODE >> IO_MEM_SHIFT, code_mem_read, code_mem_write, NULL); 1976a4193c8aSbellard cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, code_mem_read, notdirty_mem_write, NULL); 19771ccde1cbSbellard io_mem_nb = 5; 19781ccde1cbSbellard 19791ccde1cbSbellard /* alloc dirty bits array */ 19800a962c02Sbellard phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS); 198133417e70Sbellard } 198233417e70Sbellard 198333417e70Sbellard /* mem_read and mem_write are arrays of functions containing the 198433417e70Sbellard function to access byte (index 0), word (index 1) and dword (index 198533417e70Sbellard 2). All functions must be supplied. If io_index is non zero, the 198633417e70Sbellard corresponding io zone is modified. If it is zero, a new io zone is 198733417e70Sbellard allocated. The return value can be used with 198833417e70Sbellard cpu_register_physical_memory(). (-1) is returned if error. */ 198933417e70Sbellard int cpu_register_io_memory(int io_index, 199033417e70Sbellard CPUReadMemoryFunc **mem_read, 1991a4193c8aSbellard CPUWriteMemoryFunc **mem_write, 1992a4193c8aSbellard void *opaque) 199333417e70Sbellard { 199433417e70Sbellard int i; 199533417e70Sbellard 199633417e70Sbellard if (io_index <= 0) { 199733417e70Sbellard if (io_index >= IO_MEM_NB_ENTRIES) 199833417e70Sbellard return -1; 199933417e70Sbellard io_index = io_mem_nb++; 200033417e70Sbellard } else { 200133417e70Sbellard if (io_index >= IO_MEM_NB_ENTRIES) 200233417e70Sbellard return -1; 200333417e70Sbellard } 200433417e70Sbellard 200533417e70Sbellard for(i = 0;i < 3; i++) { 200633417e70Sbellard io_mem_read[io_index][i] = mem_read[i]; 200733417e70Sbellard io_mem_write[io_index][i] = mem_write[i]; 200833417e70Sbellard } 2009a4193c8aSbellard io_mem_opaque[io_index] = opaque; 201033417e70Sbellard return io_index << IO_MEM_SHIFT; 201133417e70Sbellard } 201261382a50Sbellard 20138926b517Sbellard CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index) 20148926b517Sbellard { 20158926b517Sbellard return io_mem_write[io_index >> IO_MEM_SHIFT]; 20168926b517Sbellard } 20178926b517Sbellard 20188926b517Sbellard CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index) 20198926b517Sbellard { 20208926b517Sbellard return io_mem_read[io_index >> IO_MEM_SHIFT]; 20218926b517Sbellard } 20228926b517Sbellard 202313eb76e0Sbellard /* physical memory access (slow version, mainly for debug) */ 202413eb76e0Sbellard #if defined(CONFIG_USER_ONLY) 20252e12669aSbellard void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, 202613eb76e0Sbellard int len, int is_write) 202713eb76e0Sbellard { 202813eb76e0Sbellard int l, flags; 202913eb76e0Sbellard target_ulong page; 203013eb76e0Sbellard 203113eb76e0Sbellard while (len > 0) { 203213eb76e0Sbellard page = addr & TARGET_PAGE_MASK; 203313eb76e0Sbellard l = (page + TARGET_PAGE_SIZE) - addr; 203413eb76e0Sbellard if (l > len) 203513eb76e0Sbellard l = len; 203613eb76e0Sbellard flags = page_get_flags(page); 203713eb76e0Sbellard if (!(flags & PAGE_VALID)) 203813eb76e0Sbellard return; 203913eb76e0Sbellard if (is_write) { 204013eb76e0Sbellard if (!(flags & PAGE_WRITE)) 204113eb76e0Sbellard return; 204213eb76e0Sbellard memcpy((uint8_t *)addr, buf, len); 204313eb76e0Sbellard } else { 204413eb76e0Sbellard if (!(flags & PAGE_READ)) 204513eb76e0Sbellard return; 204613eb76e0Sbellard memcpy(buf, (uint8_t *)addr, len); 204713eb76e0Sbellard } 204813eb76e0Sbellard len -= l; 204913eb76e0Sbellard buf += l; 205013eb76e0Sbellard addr += l; 205113eb76e0Sbellard } 205213eb76e0Sbellard } 20538df1cd07Sbellard 20548df1cd07Sbellard /* never used */ 20558df1cd07Sbellard uint32_t ldl_phys(target_phys_addr_t addr) 20568df1cd07Sbellard { 20578df1cd07Sbellard return 0; 20588df1cd07Sbellard } 20598df1cd07Sbellard 20608df1cd07Sbellard void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) 20618df1cd07Sbellard { 20628df1cd07Sbellard } 20638df1cd07Sbellard 20648df1cd07Sbellard void stl_phys(target_phys_addr_t addr, uint32_t val) 20658df1cd07Sbellard { 20668df1cd07Sbellard } 20678df1cd07Sbellard 206813eb76e0Sbellard #else 20692e12669aSbellard void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, 207013eb76e0Sbellard int len, int is_write) 207113eb76e0Sbellard { 207213eb76e0Sbellard int l, io_index; 207313eb76e0Sbellard uint8_t *ptr; 207413eb76e0Sbellard uint32_t val; 20752e12669aSbellard target_phys_addr_t page; 20762e12669aSbellard unsigned long pd; 207792e873b9Sbellard PhysPageDesc *p; 207813eb76e0Sbellard 207913eb76e0Sbellard while (len > 0) { 208013eb76e0Sbellard page = addr & TARGET_PAGE_MASK; 208113eb76e0Sbellard l = (page + TARGET_PAGE_SIZE) - addr; 208213eb76e0Sbellard if (l > len) 208313eb76e0Sbellard l = len; 208492e873b9Sbellard p = phys_page_find(page >> TARGET_PAGE_BITS); 208513eb76e0Sbellard if (!p) { 208613eb76e0Sbellard pd = IO_MEM_UNASSIGNED; 208713eb76e0Sbellard } else { 208813eb76e0Sbellard pd = p->phys_offset; 208913eb76e0Sbellard } 209013eb76e0Sbellard 209113eb76e0Sbellard if (is_write) { 209213eb76e0Sbellard if ((pd & ~TARGET_PAGE_MASK) != 0) { 209313eb76e0Sbellard io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); 209413eb76e0Sbellard if (l >= 4 && ((addr & 3) == 0)) { 209513eb76e0Sbellard /* 32 bit read access */ 2096c27004ecSbellard val = ldl_p(buf); 2097a4193c8aSbellard io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); 209813eb76e0Sbellard l = 4; 209913eb76e0Sbellard } else if (l >= 2 && ((addr & 1) == 0)) { 210013eb76e0Sbellard /* 16 bit read access */ 2101c27004ecSbellard val = lduw_p(buf); 2102a4193c8aSbellard io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val); 210313eb76e0Sbellard l = 2; 210413eb76e0Sbellard } else { 210513eb76e0Sbellard /* 8 bit access */ 2106c27004ecSbellard val = ldub_p(buf); 2107a4193c8aSbellard io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val); 210813eb76e0Sbellard l = 1; 210913eb76e0Sbellard } 211013eb76e0Sbellard } else { 2111b448f2f3Sbellard unsigned long addr1; 2112b448f2f3Sbellard addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); 211313eb76e0Sbellard /* RAM case */ 2114b448f2f3Sbellard ptr = phys_ram_base + addr1; 211513eb76e0Sbellard memcpy(ptr, buf, l); 2116b448f2f3Sbellard /* invalidate code */ 2117b448f2f3Sbellard tb_invalidate_phys_page_range(addr1, addr1 + l, 0); 2118b448f2f3Sbellard /* set dirty bit */ 21190a962c02Sbellard phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff; 212013eb76e0Sbellard } 212113eb76e0Sbellard } else { 212213eb76e0Sbellard if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && 212313eb76e0Sbellard (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) { 212413eb76e0Sbellard /* I/O case */ 212513eb76e0Sbellard io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); 212613eb76e0Sbellard if (l >= 4 && ((addr & 3) == 0)) { 212713eb76e0Sbellard /* 32 bit read access */ 2128a4193c8aSbellard val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); 2129c27004ecSbellard stl_p(buf, val); 213013eb76e0Sbellard l = 4; 213113eb76e0Sbellard } else if (l >= 2 && ((addr & 1) == 0)) { 213213eb76e0Sbellard /* 16 bit read access */ 2133a4193c8aSbellard val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr); 2134c27004ecSbellard stw_p(buf, val); 213513eb76e0Sbellard l = 2; 213613eb76e0Sbellard } else { 213713eb76e0Sbellard /* 8 bit access */ 2138a4193c8aSbellard val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr); 2139c27004ecSbellard stb_p(buf, val); 214013eb76e0Sbellard l = 1; 214113eb76e0Sbellard } 214213eb76e0Sbellard } else { 214313eb76e0Sbellard /* RAM case */ 214413eb76e0Sbellard ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + 214513eb76e0Sbellard (addr & ~TARGET_PAGE_MASK); 214613eb76e0Sbellard memcpy(buf, ptr, l); 214713eb76e0Sbellard } 214813eb76e0Sbellard } 214913eb76e0Sbellard len -= l; 215013eb76e0Sbellard buf += l; 215113eb76e0Sbellard addr += l; 215213eb76e0Sbellard } 215313eb76e0Sbellard } 21548df1cd07Sbellard 21558df1cd07Sbellard /* warning: addr must be aligned */ 21568df1cd07Sbellard uint32_t ldl_phys(target_phys_addr_t addr) 21578df1cd07Sbellard { 21588df1cd07Sbellard int io_index; 21598df1cd07Sbellard uint8_t *ptr; 21608df1cd07Sbellard uint32_t val; 21618df1cd07Sbellard unsigned long pd; 21628df1cd07Sbellard PhysPageDesc *p; 21638df1cd07Sbellard 21648df1cd07Sbellard p = phys_page_find(addr >> TARGET_PAGE_BITS); 21658df1cd07Sbellard if (!p) { 21668df1cd07Sbellard pd = IO_MEM_UNASSIGNED; 21678df1cd07Sbellard } else { 21688df1cd07Sbellard pd = p->phys_offset; 21698df1cd07Sbellard } 21708df1cd07Sbellard 21718df1cd07Sbellard if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && 21728df1cd07Sbellard (pd & ~TARGET_PAGE_MASK) != IO_MEM_CODE) { 21738df1cd07Sbellard /* I/O case */ 21748df1cd07Sbellard io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); 21758df1cd07Sbellard val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); 21768df1cd07Sbellard } else { 21778df1cd07Sbellard /* RAM case */ 21788df1cd07Sbellard ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + 21798df1cd07Sbellard (addr & ~TARGET_PAGE_MASK); 21808df1cd07Sbellard val = ldl_p(ptr); 21818df1cd07Sbellard } 21828df1cd07Sbellard return val; 21838df1cd07Sbellard } 21848df1cd07Sbellard 21858df1cd07Sbellard /* warning: addr must be aligned. The ram page is not masked as dirty 21868df1cd07Sbellard and the code inside is not invalidated. It is useful if the dirty 21878df1cd07Sbellard bits are used to track modified PTEs */ 21888df1cd07Sbellard void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val) 21898df1cd07Sbellard { 21908df1cd07Sbellard int io_index; 21918df1cd07Sbellard uint8_t *ptr; 21928df1cd07Sbellard unsigned long pd; 21938df1cd07Sbellard PhysPageDesc *p; 21948df1cd07Sbellard 21958df1cd07Sbellard p = phys_page_find(addr >> TARGET_PAGE_BITS); 21968df1cd07Sbellard if (!p) { 21978df1cd07Sbellard pd = IO_MEM_UNASSIGNED; 21988df1cd07Sbellard } else { 21998df1cd07Sbellard pd = p->phys_offset; 22008df1cd07Sbellard } 22018df1cd07Sbellard 22028df1cd07Sbellard if ((pd & ~TARGET_PAGE_MASK) != 0) { 22038df1cd07Sbellard io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); 22048df1cd07Sbellard io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); 22058df1cd07Sbellard } else { 22068df1cd07Sbellard ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + 22078df1cd07Sbellard (addr & ~TARGET_PAGE_MASK); 22088df1cd07Sbellard stl_p(ptr, val); 22098df1cd07Sbellard } 22108df1cd07Sbellard } 22118df1cd07Sbellard 22128df1cd07Sbellard /* warning: addr must be aligned */ 22138df1cd07Sbellard /* XXX: optimize code invalidation test */ 22148df1cd07Sbellard void stl_phys(target_phys_addr_t addr, uint32_t val) 22158df1cd07Sbellard { 22168df1cd07Sbellard int io_index; 22178df1cd07Sbellard uint8_t *ptr; 22188df1cd07Sbellard unsigned long pd; 22198df1cd07Sbellard PhysPageDesc *p; 22208df1cd07Sbellard 22218df1cd07Sbellard p = phys_page_find(addr >> TARGET_PAGE_BITS); 22228df1cd07Sbellard if (!p) { 22238df1cd07Sbellard pd = IO_MEM_UNASSIGNED; 22248df1cd07Sbellard } else { 22258df1cd07Sbellard pd = p->phys_offset; 22268df1cd07Sbellard } 22278df1cd07Sbellard 22288df1cd07Sbellard if ((pd & ~TARGET_PAGE_MASK) != 0) { 22298df1cd07Sbellard io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); 22308df1cd07Sbellard io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val); 22318df1cd07Sbellard } else { 22328df1cd07Sbellard unsigned long addr1; 22338df1cd07Sbellard addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK); 22348df1cd07Sbellard /* RAM case */ 22358df1cd07Sbellard ptr = phys_ram_base + addr1; 22368df1cd07Sbellard stl_p(ptr, val); 22378df1cd07Sbellard /* invalidate code */ 22388df1cd07Sbellard tb_invalidate_phys_page_range(addr1, addr1 + 4, 0); 22398df1cd07Sbellard /* set dirty bit */ 22400a962c02Sbellard phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] = 0xff; 22418df1cd07Sbellard } 22428df1cd07Sbellard } 22438df1cd07Sbellard 224413eb76e0Sbellard #endif 224513eb76e0Sbellard 224613eb76e0Sbellard /* virtual memory access for debug */ 2247b448f2f3Sbellard int cpu_memory_rw_debug(CPUState *env, target_ulong addr, 2248b448f2f3Sbellard uint8_t *buf, int len, int is_write) 224913eb76e0Sbellard { 225013eb76e0Sbellard int l; 225113eb76e0Sbellard target_ulong page, phys_addr; 225213eb76e0Sbellard 225313eb76e0Sbellard while (len > 0) { 225413eb76e0Sbellard page = addr & TARGET_PAGE_MASK; 225513eb76e0Sbellard phys_addr = cpu_get_phys_page_debug(env, page); 225613eb76e0Sbellard /* if no physical page mapped, return an error */ 225713eb76e0Sbellard if (phys_addr == -1) 225813eb76e0Sbellard return -1; 225913eb76e0Sbellard l = (page + TARGET_PAGE_SIZE) - addr; 226013eb76e0Sbellard if (l > len) 226113eb76e0Sbellard l = len; 2262b448f2f3Sbellard cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK), 2263b448f2f3Sbellard buf, l, is_write); 226413eb76e0Sbellard len -= l; 226513eb76e0Sbellard buf += l; 226613eb76e0Sbellard addr += l; 226713eb76e0Sbellard } 226813eb76e0Sbellard return 0; 226913eb76e0Sbellard } 227013eb76e0Sbellard 2271e3db7226Sbellard void dump_exec_info(FILE *f, 2272e3db7226Sbellard int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) 2273e3db7226Sbellard { 2274e3db7226Sbellard int i, target_code_size, max_target_code_size; 2275e3db7226Sbellard int direct_jmp_count, direct_jmp2_count, cross_page; 2276e3db7226Sbellard TranslationBlock *tb; 2277e3db7226Sbellard 2278e3db7226Sbellard target_code_size = 0; 2279e3db7226Sbellard max_target_code_size = 0; 2280e3db7226Sbellard cross_page = 0; 2281e3db7226Sbellard direct_jmp_count = 0; 2282e3db7226Sbellard direct_jmp2_count = 0; 2283e3db7226Sbellard for(i = 0; i < nb_tbs; i++) { 2284e3db7226Sbellard tb = &tbs[i]; 2285e3db7226Sbellard target_code_size += tb->size; 2286e3db7226Sbellard if (tb->size > max_target_code_size) 2287e3db7226Sbellard max_target_code_size = tb->size; 2288e3db7226Sbellard if (tb->page_addr[1] != -1) 2289e3db7226Sbellard cross_page++; 2290e3db7226Sbellard if (tb->tb_next_offset[0] != 0xffff) { 2291e3db7226Sbellard direct_jmp_count++; 2292e3db7226Sbellard if (tb->tb_next_offset[1] != 0xffff) { 2293e3db7226Sbellard direct_jmp2_count++; 2294e3db7226Sbellard } 2295e3db7226Sbellard } 2296e3db7226Sbellard } 2297e3db7226Sbellard /* XXX: avoid using doubles ? */ 2298e3db7226Sbellard cpu_fprintf(f, "TB count %d\n", nb_tbs); 2299e3db7226Sbellard cpu_fprintf(f, "TB avg target size %d max=%d bytes\n", 2300e3db7226Sbellard nb_tbs ? target_code_size / nb_tbs : 0, 2301e3db7226Sbellard max_target_code_size); 2302e3db7226Sbellard cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n", 2303e3db7226Sbellard nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0, 2304e3db7226Sbellard target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0); 2305e3db7226Sbellard cpu_fprintf(f, "cross page TB count %d (%d%%)\n", 2306e3db7226Sbellard cross_page, 2307e3db7226Sbellard nb_tbs ? (cross_page * 100) / nb_tbs : 0); 2308e3db7226Sbellard cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n", 2309e3db7226Sbellard direct_jmp_count, 2310e3db7226Sbellard nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0, 2311e3db7226Sbellard direct_jmp2_count, 2312e3db7226Sbellard nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0); 2313e3db7226Sbellard cpu_fprintf(f, "TB flush count %d\n", tb_flush_count); 2314e3db7226Sbellard cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count); 2315e3db7226Sbellard cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count); 2316e3db7226Sbellard } 2317e3db7226Sbellard 231861382a50Sbellard #if !defined(CONFIG_USER_ONLY) 231961382a50Sbellard 232061382a50Sbellard #define MMUSUFFIX _cmmu 232161382a50Sbellard #define GETPC() NULL 232261382a50Sbellard #define env cpu_single_env 2323b769d8feSbellard #define SOFTMMU_CODE_ACCESS 232461382a50Sbellard 232561382a50Sbellard #define SHIFT 0 232661382a50Sbellard #include "softmmu_template.h" 232761382a50Sbellard 232861382a50Sbellard #define SHIFT 1 232961382a50Sbellard #include "softmmu_template.h" 233061382a50Sbellard 233161382a50Sbellard #define SHIFT 2 233261382a50Sbellard #include "softmmu_template.h" 233361382a50Sbellard 233461382a50Sbellard #define SHIFT 3 233561382a50Sbellard #include "softmmu_template.h" 233661382a50Sbellard 233761382a50Sbellard #undef env 233861382a50Sbellard 233961382a50Sbellard #endif 2340