Commit d720b93d0bcfe1beb729245b9ed1e5f071a24bd5

Authored by bellard
1 parent eeab3a55

precise self modifying code support


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@745 c046a42c-6fe2-441c-8c8c-71466251a162
cpu-all.h
... ... @@ -681,8 +681,7 @@ extern uint8_t *phys_ram_dirty;
681 681 #define IO_MEM_CODE (3 << IO_MEM_SHIFT) /* used internally, never use directly */
682 682 #define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */
683 683  
684   -/* NOTE: vaddr is only used internally. Never use it except if you know what you do */
685   -typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value, uint32_t vaddr);
  684 +typedef void CPUWriteMemoryFunc(uint32_t addr, uint32_t value);
686 685 typedef uint32_t CPUReadMemoryFunc(uint32_t addr);
687 686  
688 687 void cpu_register_physical_memory(unsigned long start_addr, unsigned long size,
... ...
... ... @@ -168,7 +168,6 @@ static inline PageDesc *page_find(unsigned int index)
168 168  
169 169 #if !defined(CONFIG_USER_ONLY)
170 170 static void tlb_protect_code(CPUState *env, uint32_t addr);
171   -static void tlb_unprotect_code(CPUState *env, uint32_t addr);
172 171 static void tlb_unprotect_code_phys(CPUState *env, uint32_t phys_addr, target_ulong vaddr);
173 172  
174 173 static inline VirtPageDesc *virt_page_find_alloc(unsigned int index)
... ... @@ -533,30 +532,78 @@ static void build_page_bitmap(PageDesc *p)
533 532 }
534 533 }
535 534  
  535 +#ifdef TARGET_HAS_PRECISE_SMC
  536 +
  537 +static void tb_gen_code(CPUState *env,
  538 + target_ulong pc, target_ulong cs_base, int flags,
  539 + int cflags)
  540 +{
  541 + TranslationBlock *tb;
  542 + uint8_t *tc_ptr;
  543 + target_ulong phys_pc, phys_page2, virt_page2;
  544 + int code_gen_size;
  545 +
  546 + phys_pc = get_phys_addr_code(env, (unsigned long)pc);
  547 + tb = tb_alloc((unsigned long)pc);
  548 + if (!tb) {
  549 + /* flush must be done */
  550 + tb_flush(env);
  551 + /* cannot fail at this point */
  552 + tb = tb_alloc((unsigned long)pc);
  553 + }
  554 + tc_ptr = code_gen_ptr;
  555 + tb->tc_ptr = tc_ptr;
  556 + tb->cs_base = cs_base;
  557 + tb->flags = flags;
  558 + tb->cflags = cflags;
  559 + cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
  560 + code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
  561 +
  562 + /* check next page if needed */
  563 + virt_page2 = ((unsigned long)pc + tb->size - 1) & TARGET_PAGE_MASK;
  564 + phys_page2 = -1;
  565 + if (((unsigned long)pc & TARGET_PAGE_MASK) != virt_page2) {
  566 + phys_page2 = get_phys_addr_code(env, virt_page2);
  567 + }
  568 + tb_link_phys(tb, phys_pc, phys_page2);
  569 +}
  570 +#endif
  571 +
536 572 /* invalidate all TBs which intersect with the target physical page
537 573 starting in range [start;end[. NOTE: start and end must refer to
538   - the same physical page. 'vaddr' is a virtual address referencing
539   - the physical page of code. It is only used an a hint if there is no
540   - code left. */
541   -static void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
542   - target_ulong vaddr)
543   -{
544   - int n;
  574 + the same physical page. 'is_cpu_write_access' should be true if called
  575 + from a real cpu write access: the virtual CPU will exit the current
  576 + TB if code is modified inside this TB. */
  577 +void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
  578 + int is_cpu_write_access)
  579 +{
  580 + int n, current_tb_modified, current_tb_not_found, current_flags;
  581 +#if defined(TARGET_HAS_PRECISE_SMC) || !defined(CONFIG_USER_ONLY)
  582 + CPUState *env = cpu_single_env;
  583 +#endif
545 584 PageDesc *p;
546   - TranslationBlock *tb, *tb_next;
  585 + TranslationBlock *tb, *tb_next, *current_tb;
547 586 target_ulong tb_start, tb_end;
  587 + target_ulong current_pc, current_cs_base;
548 588  
549 589 p = page_find(start >> TARGET_PAGE_BITS);
550 590 if (!p)
551 591 return;
552 592 if (!p->code_bitmap &&
553   - ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD) {
  593 + ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
  594 + is_cpu_write_access) {
554 595 /* build code bitmap */
555 596 build_page_bitmap(p);
556 597 }
557 598  
558 599 /* we remove all the TBs in the range [start, end[ */
559 600 /* XXX: see if in some cases it could be faster to invalidate all the code */
  601 + current_tb_not_found = is_cpu_write_access;
  602 + current_tb_modified = 0;
  603 + current_tb = NULL; /* avoid warning */
  604 + current_pc = 0; /* avoid warning */
  605 + current_cs_base = 0; /* avoid warning */
  606 + current_flags = 0; /* avoid warning */
560 607 tb = p->first_tb;
561 608 while (tb != NULL) {
562 609 n = (long)tb & 3;
... ... @@ -573,6 +620,36 @@ static void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
573 620 tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
574 621 }
575 622 if (!(tb_end <= start || tb_start >= end)) {
  623 +#ifdef TARGET_HAS_PRECISE_SMC
  624 + if (current_tb_not_found) {
  625 + current_tb_not_found = 0;
  626 + current_tb = NULL;
  627 + if (env->mem_write_pc) {
  628 + /* now we have a real cpu fault */
  629 + current_tb = tb_find_pc(env->mem_write_pc);
  630 + }
  631 + }
  632 + if (current_tb == tb &&
  633 + !(current_tb->cflags & CF_SINGLE_INSN)) {
  634 + /* If we are modifying the current TB, we must stop
  635 + its execution. We could be more precise by checking
  636 + that the modification is after the current PC, but it
  637 + would require a specialized function to partially
  638 + restore the CPU state */
  639 +
  640 + current_tb_modified = 1;
  641 + cpu_restore_state(current_tb, env,
  642 + env->mem_write_pc, NULL);
  643 +#if defined(TARGET_I386)
  644 + current_flags = env->hflags;
  645 + current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
  646 + current_cs_base = (target_ulong)env->segs[R_CS].base;
  647 + current_pc = current_cs_base + env->eip;
  648 +#else
  649 +#error unsupported CPU
  650 +#endif
  651 + }
  652 +#endif /* TARGET_HAS_PRECISE_SMC */
576 653 tb_phys_invalidate(tb, -1);
577 654 }
578 655 tb = tb_next;
... ... @@ -581,13 +658,25 @@ static void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
581 658 /* if no code remaining, no need to continue to use slow writes */
582 659 if (!p->first_tb) {
583 660 invalidate_page_bitmap(p);
584   - tlb_unprotect_code_phys(cpu_single_env, start, vaddr);
  661 + if (is_cpu_write_access) {
  662 + tlb_unprotect_code_phys(env, start, env->mem_write_vaddr);
  663 + }
  664 + }
  665 +#endif
  666 +#ifdef TARGET_HAS_PRECISE_SMC
  667 + if (current_tb_modified) {
  668 + /* we generate a block containing just the instruction
  669 + modifying the memory. It will ensure that it cannot modify
  670 + itself */
  671 + tb_gen_code(env, current_pc, current_cs_base, current_flags,
  672 + CF_SINGLE_INSN);
  673 + cpu_resume_from_signal(env, NULL);
585 674 }
586 675 #endif
587 676 }
588 677  
589 678 /* len must be <= 8 and start must be a multiple of len */
590   -static inline void tb_invalidate_phys_page_fast(target_ulong start, int len, target_ulong vaddr)
  679 +static inline void tb_invalidate_phys_page_fast(target_ulong start, int len)
591 680 {
592 681 PageDesc *p;
593 682 int offset, b;
... ... @@ -608,77 +697,75 @@ static inline void tb_invalidate_phys_page_fast(target_ulong start, int len, tar
608 697 goto do_invalidate;
609 698 } else {
610 699 do_invalidate:
611   - tb_invalidate_phys_page_range(start, start + len, vaddr);
  700 + tb_invalidate_phys_page_range(start, start + len, 1);
612 701 }
613 702 }
614 703  
615   -/* invalidate all TBs which intersect with the target virtual page
616   - starting in range [start;end[. This function is usually used when
617   - the target processor flushes its I-cache. NOTE: start and end must
618   - refer to the same physical page */
619   -void tb_invalidate_page_range(target_ulong start, target_ulong end)
620   -{
621   - int n;
622   - PageDesc *p;
623   - TranslationBlock *tb, *tb_next;
624   - target_ulong pc;
625   - target_ulong phys_start;
626   -
627   -#if !defined(CONFIG_USER_ONLY)
628   - {
629   - VirtPageDesc *vp;
630   - vp = virt_page_find(start >> TARGET_PAGE_BITS);
631   - if (!vp)
632   - return;
633   - if (vp->valid_tag != virt_valid_tag)
634   - return;
635   - phys_start = vp->phys_addr + (start & ~TARGET_PAGE_MASK);
636   - }
637   -#else
638   - phys_start = start;
639   -#endif
640   - p = page_find(phys_start >> TARGET_PAGE_BITS);
641   - if (!p)
642   - return;
643   - /* we remove all the TBs in the range [start, end[ */
644   - /* XXX: see if in some cases it could be faster to invalidate all the code */
645   - tb = p->first_tb;
646   - while (tb != NULL) {
647   - n = (long)tb & 3;
648   - tb = (TranslationBlock *)((long)tb & ~3);
649   - tb_next = tb->page_next[n];
650   - pc = tb->pc;
651   - if (!((pc + tb->size) <= start || pc >= end)) {
652   - tb_phys_invalidate(tb, -1);
653   - }
654   - tb = tb_next;
655   - }
656   -#if !defined(CONFIG_USER_ONLY)
657   - /* if no code remaining, no need to continue to use slow writes */
658   - if (!p->first_tb)
659   - tlb_unprotect_code(cpu_single_env, start);
660   -#endif
661   -}
662   -
663 704 #if !defined(CONFIG_SOFTMMU)
664   -static void tb_invalidate_phys_page(target_ulong addr)
  705 +static void tb_invalidate_phys_page(target_ulong addr,
  706 + unsigned long pc, void *puc)
665 707 {
666   - int n;
  708 + int n, current_flags, current_tb_modified;
  709 + target_ulong current_pc, current_cs_base;
667 710 PageDesc *p;
668   - TranslationBlock *tb;
  711 + TranslationBlock *tb, *current_tb;
  712 +#ifdef TARGET_HAS_PRECISE_SMC
  713 + CPUState *env = cpu_single_env;
  714 +#endif
669 715  
670 716 addr &= TARGET_PAGE_MASK;
671 717 p = page_find(addr >> TARGET_PAGE_BITS);
672 718 if (!p)
673 719 return;
674 720 tb = p->first_tb;
  721 + current_tb_modified = 0;
  722 + current_tb = NULL;
  723 + current_pc = 0; /* avoid warning */
  724 + current_cs_base = 0; /* avoid warning */
  725 + current_flags = 0; /* avoid warning */
  726 +#ifdef TARGET_HAS_PRECISE_SMC
  727 + if (tb && pc != 0) {
  728 + current_tb = tb_find_pc(pc);
  729 + }
  730 +#endif
675 731 while (tb != NULL) {
676 732 n = (long)tb & 3;
677 733 tb = (TranslationBlock *)((long)tb & ~3);
  734 +#ifdef TARGET_HAS_PRECISE_SMC
  735 + if (current_tb == tb &&
  736 + !(current_tb->cflags & CF_SINGLE_INSN)) {
  737 + /* If we are modifying the current TB, we must stop
  738 + its execution. We could be more precise by checking
  739 + that the modification is after the current PC, but it
  740 + would require a specialized function to partially
  741 + restore the CPU state */
  742 +
  743 + current_tb_modified = 1;
  744 + cpu_restore_state(current_tb, env, pc, puc);
  745 +#if defined(TARGET_I386)
  746 + current_flags = env->hflags;
  747 + current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
  748 + current_cs_base = (target_ulong)env->segs[R_CS].base;
  749 + current_pc = current_cs_base + env->eip;
  750 +#else
  751 +#error unsupported CPU
  752 +#endif
  753 + }
  754 +#endif /* TARGET_HAS_PRECISE_SMC */
678 755 tb_phys_invalidate(tb, addr);
679 756 tb = tb->page_next[n];
680 757 }
681 758 p->first_tb = NULL;
  759 +#ifdef TARGET_HAS_PRECISE_SMC
  760 + if (current_tb_modified) {
  761 + /* we generate a block containing just the instruction
  762 + modifying the memory. It will ensure that it cannot modify
  763 + itself */
  764 + tb_gen_code(env, current_pc, current_cs_base, current_flags,
  765 + CF_SINGLE_INSN);
  766 + cpu_resume_from_signal(env, puc);
  767 + }
  768 +#endif
682 769 }
683 770 #endif
684 771  
... ... @@ -696,6 +783,8 @@ static inline void tb_alloc_page(TranslationBlock *tb,
696 783 p->first_tb = (TranslationBlock *)((long)tb | n);
697 784 invalidate_page_bitmap(p);
698 785  
  786 +#ifdef TARGET_HAS_SMC
  787 +
699 788 #if defined(CONFIG_USER_ONLY)
700 789 if (p->flags & PAGE_WRITE) {
701 790 unsigned long host_start, host_end, addr;
... ... @@ -727,6 +816,8 @@ static inline void tb_alloc_page(TranslationBlock *tb,
727 816 tlb_protect_code(cpu_single_env, virt_addr);
728 817 }
729 818 #endif
  819 +
  820 +#endif /* TARGET_HAS_SMC */
730 821 }
731 822  
732 823 /* Allocate a new translation block. Flush the translation buffer if
... ... @@ -910,13 +1001,21 @@ static void tb_reset_jump_recursive(TranslationBlock *tb)
910 1001 tb_reset_jump_recursive2(tb, 1);
911 1002 }
912 1003  
  1004 +static void breakpoint_invalidate(CPUState *env, target_ulong pc)
  1005 +{
  1006 + target_ulong phys_addr;
  1007 +
  1008 + phys_addr = cpu_get_phys_page_debug(env, pc);
  1009 + tb_invalidate_phys_page_range(phys_addr, phys_addr + 1, 0);
  1010 +}
  1011 +
913 1012 /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
914 1013 breakpoint is reached */
915 1014 int cpu_breakpoint_insert(CPUState *env, uint32_t pc)
916 1015 {
917 1016 #if defined(TARGET_I386) || defined(TARGET_PPC)
918 1017 int i;
919   -
  1018 +
920 1019 for(i = 0; i < env->nb_breakpoints; i++) {
921 1020 if (env->breakpoints[i] == pc)
922 1021 return 0;
... ... @@ -925,7 +1024,8 @@ int cpu_breakpoint_insert(CPUState *env, uint32_t pc)
925 1024 if (env->nb_breakpoints >= MAX_BREAKPOINTS)
926 1025 return -1;
927 1026 env->breakpoints[env->nb_breakpoints++] = pc;
928   - tb_invalidate_page_range(pc, pc + 1);
  1027 +
  1028 + breakpoint_invalidate(env, pc);
929 1029 return 0;
930 1030 #else
931 1031 return -1;
... ... @@ -946,7 +1046,8 @@ int cpu_breakpoint_remove(CPUState *env, uint32_t pc)
946 1046 memmove(&env->breakpoints[i], &env->breakpoints[i + 1],
947 1047 (env->nb_breakpoints - (i + 1)) * sizeof(env->breakpoints[0]));
948 1048 env->nb_breakpoints--;
949   - tb_invalidate_page_range(pc, pc + 1);
  1049 +
  1050 + breakpoint_invalidate(env, pc);
950 1051 return 0;
951 1052 #else
952 1053 return -1;
... ... @@ -1197,27 +1298,6 @@ static void tlb_protect_code(CPUState *env, uint32_t addr)
1197 1298 #endif
1198 1299 }
1199 1300  
1200   -static inline void tlb_unprotect_code1(CPUTLBEntry *tlb_entry, uint32_t addr)
1201   -{
1202   - if (addr == (tlb_entry->address &
1203   - (TARGET_PAGE_MASK | TLB_INVALID_MASK)) &&
1204   - (tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_CODE) {
1205   - tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
1206   - }
1207   -}
1208   -
1209   -/* update the TLB so that writes in virtual page 'addr' are no longer
1210   - tested self modifying code */
1211   -static void tlb_unprotect_code(CPUState *env, uint32_t addr)
1212   -{
1213   - int i;
1214   -
1215   - addr &= TARGET_PAGE_MASK;
1216   - i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
1217   - tlb_unprotect_code1(&env->tlb_write[0][i], addr);
1218   - tlb_unprotect_code1(&env->tlb_write[1][i], addr);
1219   -}
1220   -
1221 1301 static inline void tlb_unprotect_code2(CPUTLBEntry *tlb_entry,
1222 1302 uint32_t phys_addr)
1223 1303 {
... ... @@ -1387,12 +1467,18 @@ int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot,
1387 1467 /* ROM: access is ignored (same as unassigned) */
1388 1468 env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM;
1389 1469 env->tlb_write[is_user][index].addend = addend;
1390   - } else if (first_tb) {
  1470 + } else
  1471 + /* XXX: the PowerPC code seems not ready to handle
  1472 + self modifying code with DCBI */
  1473 +#if defined(TARGET_HAS_SMC) || 1
  1474 + if (first_tb) {
1391 1475 /* if code is present, we use a specific memory
1392 1476 handler. It works only for physical memory access */
1393 1477 env->tlb_write[is_user][index].address = vaddr | IO_MEM_CODE;
1394 1478 env->tlb_write[is_user][index].addend = addend;
1395   - } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
  1479 + } else
  1480 +#endif
  1481 + if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1396 1482 !cpu_physical_memory_is_dirty(pd)) {
1397 1483 env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY;
1398 1484 env->tlb_write[is_user][index].addend = addend;
... ... @@ -1420,7 +1506,9 @@ int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot,
1420 1506 } else {
1421 1507 if (prot & PROT_WRITE) {
1422 1508 if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
  1509 +#if defined(TARGET_HAS_SMC) || 1
1423 1510 first_tb ||
  1511 +#endif
1424 1512 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
1425 1513 !cpu_physical_memory_is_dirty(pd))) {
1426 1514 /* ROM: we do as if code was inside */
... ... @@ -1450,7 +1538,7 @@ int tlb_set_page(CPUState *env, uint32_t vaddr, uint32_t paddr, int prot,
1450 1538  
1451 1539 /* called from signal handler: invalidate the code and unprotect the
1452 1540 page. Return TRUE if the fault was succesfully handled. */
1453   -int page_unprotect(unsigned long addr)
  1541 +int page_unprotect(unsigned long addr, unsigned long pc, void *puc)
1454 1542 {
1455 1543 #if !defined(CONFIG_SOFTMMU)
1456 1544 VirtPageDesc *vp;
... ... @@ -1476,13 +1564,13 @@ int page_unprotect(unsigned long addr)
1476 1564 printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
1477 1565 addr, vp->phys_addr, vp->prot);
1478 1566 #endif
1479   - /* set the dirty bit */
1480   - phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 1;
1481   - /* flush the code inside */
1482   - tb_invalidate_phys_page(vp->phys_addr);
1483 1567 if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
1484 1568 cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
1485 1569 (unsigned long)addr, vp->prot);
  1570 + /* set the dirty bit */
  1571 + phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 1;
  1572 + /* flush the code inside */
  1573 + tb_invalidate_phys_page(vp->phys_addr, pc, puc);
1486 1574 return 1;
1487 1575 #else
1488 1576 return 0;
... ... @@ -1582,7 +1670,7 @@ void page_set_flags(unsigned long start, unsigned long end, int flags)
1582 1670 if (!(p->flags & PAGE_WRITE) &&
1583 1671 (flags & PAGE_WRITE) &&
1584 1672 p->first_tb) {
1585   - tb_invalidate_phys_page(addr);
  1673 + tb_invalidate_phys_page(addr, 0, NULL);
1586 1674 }
1587 1675 p->flags = flags;
1588 1676 }
... ... @@ -1591,7 +1679,7 @@ void page_set_flags(unsigned long start, unsigned long end, int flags)
1591 1679  
1592 1680 /* called from signal handler: invalidate the code and unprotect the
1593 1681 page. Return TRUE if the fault was succesfully handled. */
1594   -int page_unprotect(unsigned long address)
  1682 +int page_unprotect(unsigned long address, unsigned long pc, void *puc)
1595 1683 {
1596 1684 unsigned int page_index, prot, pindex;
1597 1685 PageDesc *p, *p1;
... ... @@ -1619,7 +1707,7 @@ int page_unprotect(unsigned long address)
1619 1707 p1[pindex].flags |= PAGE_WRITE;
1620 1708 /* and since the content will be modified, we must invalidate
1621 1709 the corresponding translated code. */
1622   - tb_invalidate_phys_page(address);
  1710 + tb_invalidate_phys_page(address, pc, puc);
1623 1711 #ifdef DEBUG_TB_CHECK
1624 1712 tb_invalidate_check(address);
1625 1713 #endif
... ... @@ -1639,14 +1727,13 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size)
1639 1727 start &= TARGET_PAGE_MASK;
1640 1728 end = TARGET_PAGE_ALIGN(end);
1641 1729 for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
1642   - page_unprotect(addr);
  1730 + page_unprotect(addr, 0, NULL);
1643 1731 }
1644 1732 }
1645 1733  
1646 1734 static inline void tlb_set_dirty(unsigned long addr, target_ulong vaddr)
1647 1735 {
1648 1736 }
1649   -
1650 1737 #endif /* defined(CONFIG_USER_ONLY) */
1651 1738  
1652 1739 /* register physical memory. 'size' must be a multiple of the target
... ... @@ -1672,7 +1759,7 @@ static uint32_t unassigned_mem_readb(uint32_t addr)
1672 1759 return 0;
1673 1760 }
1674 1761  
1675   -static void unassigned_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr)
  1762 +static void unassigned_mem_writeb(uint32_t addr, uint32_t val)
1676 1763 {
1677 1764 }
1678 1765  
... ... @@ -1691,37 +1778,37 @@ static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
1691 1778 /* self modifying code support in soft mmu mode : writing to a page
1692 1779 containing code comes to these functions */
1693 1780  
1694   -static void code_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr)
  1781 +static void code_mem_writeb(uint32_t addr, uint32_t val)
1695 1782 {
1696 1783 unsigned long phys_addr;
1697 1784  
1698 1785 phys_addr = addr - (long)phys_ram_base;
1699 1786 #if !defined(CONFIG_USER_ONLY)
1700   - tb_invalidate_phys_page_fast(phys_addr, 1, vaddr);
  1787 + tb_invalidate_phys_page_fast(phys_addr, 1);
1701 1788 #endif
1702 1789 stb_raw((uint8_t *)addr, val);
1703 1790 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
1704 1791 }
1705 1792  
1706   -static void code_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr)
  1793 +static void code_mem_writew(uint32_t addr, uint32_t val)
1707 1794 {
1708 1795 unsigned long phys_addr;
1709 1796  
1710 1797 phys_addr = addr - (long)phys_ram_base;
1711 1798 #if !defined(CONFIG_USER_ONLY)
1712   - tb_invalidate_phys_page_fast(phys_addr, 2, vaddr);
  1799 + tb_invalidate_phys_page_fast(phys_addr, 2);
1713 1800 #endif
1714 1801 stw_raw((uint8_t *)addr, val);
1715 1802 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
1716 1803 }
1717 1804  
1718   -static void code_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr)
  1805 +static void code_mem_writel(uint32_t addr, uint32_t val)
1719 1806 {
1720 1807 unsigned long phys_addr;
1721 1808  
1722 1809 phys_addr = addr - (long)phys_ram_base;
1723 1810 #if !defined(CONFIG_USER_ONLY)
1724   - tb_invalidate_phys_page_fast(phys_addr, 4, vaddr);
  1811 + tb_invalidate_phys_page_fast(phys_addr, 4);
1725 1812 #endif
1726 1813 stl_raw((uint8_t *)addr, val);
1727 1814 phys_ram_dirty[phys_addr >> TARGET_PAGE_BITS] = 1;
... ... @@ -1739,22 +1826,22 @@ static CPUWriteMemoryFunc *code_mem_write[3] = {
1739 1826 code_mem_writel,
1740 1827 };
1741 1828  
1742   -static void notdirty_mem_writeb(uint32_t addr, uint32_t val, uint32_t vaddr)
  1829 +static void notdirty_mem_writeb(uint32_t addr, uint32_t val)
1743 1830 {
1744 1831 stb_raw((uint8_t *)addr, val);
1745   - tlb_set_dirty(addr, vaddr);
  1832 + tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
1746 1833 }
1747 1834  
1748   -static void notdirty_mem_writew(uint32_t addr, uint32_t val, uint32_t vaddr)
  1835 +static void notdirty_mem_writew(uint32_t addr, uint32_t val)
1749 1836 {
1750 1837 stw_raw((uint8_t *)addr, val);
1751   - tlb_set_dirty(addr, vaddr);
  1838 + tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
1752 1839 }
1753 1840  
1754   -static void notdirty_mem_writel(uint32_t addr, uint32_t val, uint32_t vaddr)
  1841 +static void notdirty_mem_writel(uint32_t addr, uint32_t val)
1755 1842 {
1756 1843 stl_raw((uint8_t *)addr, val);
1757   - tlb_set_dirty(addr, vaddr);
  1844 + tlb_set_dirty(addr, cpu_single_env->mem_write_vaddr);
1758 1845 }
1759 1846  
1760 1847 static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
... ... @@ -1861,17 +1948,17 @@ void cpu_physical_memory_rw(target_ulong addr, uint8_t *buf,
1861 1948 if (l >= 4 && ((addr & 3) == 0)) {
1862 1949 /* 32 bit read access */
1863 1950 val = ldl_raw(buf);
1864   - io_mem_write[io_index][2](addr, val, 0);
  1951 + io_mem_write[io_index][2](addr, val);
1865 1952 l = 4;
1866 1953 } else if (l >= 2 && ((addr & 1) == 0)) {
1867 1954 /* 16 bit read access */
1868 1955 val = lduw_raw(buf);
1869   - io_mem_write[io_index][1](addr, val, 0);
  1956 + io_mem_write[io_index][1](addr, val);
1870 1957 l = 2;
1871 1958 } else {
1872 1959 /* 8 bit access */
1873 1960 val = ldub_raw(buf);
1874   - io_mem_write[io_index][0](addr, val, 0);
  1961 + io_mem_write[io_index][0](addr, val);
1875 1962 l = 1;
1876 1963 }
1877 1964 } else {
... ...
softmmu_template.h
... ... @@ -70,20 +70,23 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(unsigned long physaddr,
70 70  
71 71 static inline void glue(io_write, SUFFIX)(unsigned long physaddr,
72 72 DATA_TYPE val,
73   - unsigned long tlb_addr)
  73 + unsigned long tlb_addr,
  74 + void *retaddr)
74 75 {
75 76 int index;
76 77  
77 78 index = (tlb_addr >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
  79 + env->mem_write_vaddr = tlb_addr;
  80 + env->mem_write_pc = (unsigned long)retaddr;
78 81 #if SHIFT <= 2
79   - io_mem_write[index][SHIFT](physaddr, val, tlb_addr);
  82 + io_mem_write[index][SHIFT](physaddr, val);
80 83 #else
81 84 #ifdef TARGET_WORDS_BIGENDIAN
82   - io_mem_write[index][2](physaddr, val >> 32, tlb_addr);
83   - io_mem_write[index][2](physaddr + 4, val, tlb_addr);
  85 + io_mem_write[index][2](physaddr, val >> 32);
  86 + io_mem_write[index][2](physaddr + 4, val);
84 87 #else
85   - io_mem_write[index][2](physaddr, val, tlb_addr);
86   - io_mem_write[index][2](physaddr + 4, val >> 32, tlb_addr);
  88 + io_mem_write[index][2](physaddr, val);
  89 + io_mem_write[index][2](physaddr + 4, val >> 32);
87 90 #endif
88 91 #endif /* SHIFT > 2 */
89 92 }
... ... @@ -193,7 +196,8 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(unsigned long addr,
193 196 /* IO access */
194 197 if ((addr & (DATA_SIZE - 1)) != 0)
195 198 goto do_unaligned_access;
196   - glue(io_write, SUFFIX)(physaddr, val, tlb_addr);
  199 + retaddr = GETPC();
  200 + glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr);
197 201 } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
198 202 do_unaligned_access:
199 203 retaddr = GETPC();
... ... @@ -229,7 +233,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(unsigned long addr,
229 233 /* IO access */
230 234 if ((addr & (DATA_SIZE - 1)) != 0)
231 235 goto do_unaligned_access;
232   - glue(io_write, SUFFIX)(physaddr, val, tlb_addr);
  236 + glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr);
233 237 } else if (((addr & 0xfff) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
234 238 do_unaligned_access:
235 239 /* XXX: not efficient, but simple */
... ...
target-arm/cpu.h
... ... @@ -43,6 +43,13 @@ typedef struct CPUARMState {
43 43 struct TranslationBlock *current_tb;
44 44 int user_mode_only;
45 45  
  46 + /* in order to avoid passing too many arguments to the memory
  47 + write helpers, we store some rarely used information in the CPU
  48 + context) */
  49 + unsigned long mem_write_pc; /* host pc at which the memory was
  50 + written */
  51 + unsigned long mem_write_vaddr; /* target virtual addr at which the
  52 + memory was written */
46 53 /* user data */
47 54 void *opaque;
48 55 } CPUARMState;
... ...
target-i386/cpu.h
... ... @@ -22,6 +22,12 @@
22 22  
23 23 #define TARGET_LONG_BITS 32
24 24  
  25 +/* target supports implicit self modifying code */
  26 +#define TARGET_HAS_SMC
  27 +/* support for self modifying code even if the modified instruction is
  28 + close to the modifying instruction */
  29 +#define TARGET_HAS_PRECISE_SMC
  30 +
25 31 #include "cpu-defs.h"
26 32  
27 33 #if defined(__i386__) && !defined(CONFIG_SOFTMMU)
... ... @@ -331,8 +337,16 @@ typedef struct CPUX86State {
331 337 int interrupt_request;
332 338 int user_mode_only; /* user mode only simulation */
333 339  
334   - /* soft mmu support */
335 340 uint32_t a20_mask;
  341 +
  342 + /* soft mmu support */
  343 + /* in order to avoid passing too many arguments to the memory
  344 + write helpers, we store some rarely used information in the CPU
  345 + context) */
  346 + unsigned long mem_write_pc; /* host pc at which the memory was
  347 + written */
  348 + unsigned long mem_write_vaddr; /* target virtual addr at which the
  349 + memory was written */
336 350 /* 0 = kernel, 1 = user */
337 351 CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
338 352 CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
... ... @@ -358,7 +372,7 @@ int cpu_x86_inl(CPUX86State *env, int addr);
358 372 CPUX86State *cpu_x86_init(void);
359 373 int cpu_x86_exec(CPUX86State *s);
360 374 void cpu_x86_close(CPUX86State *s);
361   -int cpu_x86_get_pic_interrupt(CPUX86State *s);
  375 +int cpu_get_pic_interrupt(CPUX86State *s);
362 376  
363 377 /* this function must always be used to load data in the segment
364 378 cache: it synchronizes the hflags with the segment cache values */
... ...
target-i386/translate-copy.c
... ... @@ -1189,6 +1189,8 @@ static inline int gen_intermediate_code_internal(CPUState *env,
1189 1189 return -1;
1190 1190 if (!(flags & HF_SS32_MASK))
1191 1191 return -1;
  1192 + if (tb->cflags & CF_SINGLE_INSN)
  1193 + return -1;
1192 1194 gen_code_end = gen_code_ptr +
1193 1195 GEN_CODE_MAX_SIZE - GEN_CODE_MAX_INSN_SIZE;
1194 1196 dc->gen_code_ptr = gen_code_ptr;
... ...
target-i386/translate.c
... ... @@ -4491,7 +4491,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
4491 4491 DisasContext dc1, *dc = &dc1;
4492 4492 uint8_t *pc_ptr;
4493 4493 uint16_t *gen_opc_end;
4494   - int flags, j, lj;
  4494 + int flags, j, lj, cflags;
4495 4495 uint8_t *pc_start;
4496 4496 uint8_t *cs_base;
4497 4497  
... ... @@ -4499,6 +4499,7 @@ static inline int gen_intermediate_code_internal(CPUState *env,
4499 4499 pc_start = (uint8_t *)tb->pc;
4500 4500 cs_base = (uint8_t *)tb->cs_base;
4501 4501 flags = tb->flags;
  4502 + cflags = tb->cflags;
4502 4503  
4503 4504 dc->pe = (flags >> HF_PE_SHIFT) & 1;
4504 4505 dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
... ... @@ -4573,7 +4574,8 @@ static inline int gen_intermediate_code_internal(CPUState *env,
4573 4574 the flag and abort the translation to give the irqs a
4574 4575 change to be happen */
4575 4576 if (dc->tf || dc->singlestep_enabled ||
4576   - (flags & HF_INHIBIT_IRQ_MASK)) {
  4577 + (flags & HF_INHIBIT_IRQ_MASK) ||
  4578 + (cflags & CF_SINGLE_INSN)) {
4577 4579 gen_op_jmp_im(pc_ptr - dc->cs_base);
4578 4580 gen_eob(dc);
4579 4581 break;
... ...
target-ppc/cpu.h
... ... @@ -164,6 +164,13 @@ typedef struct CPUPPCState {
164 164 int user_mode_only; /* user mode only simulation */
165 165 struct TranslationBlock *current_tb; /* currently executing TB */
166 166 /* soft mmu support */
  167 + /* in order to avoid passing too many arguments to the memory
  168 + write helpers, we store some rarely used information in the CPU
  169 + context) */
  170 + unsigned long mem_write_pc; /* host pc at which the memory was
  171 + written */
  172 + unsigned long mem_write_vaddr; /* target virtual addr at which the
  173 + memory was written */
167 174 /* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */
168 175 CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
169 176 CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
... ...
target-sparc/cpu.h
... ... @@ -43,6 +43,14 @@ typedef struct CPUSPARCState {
43 43 void *opaque;
44 44 /* NOTE: we allow 8 more registers to handle wrapping */
45 45 uint32_t regbase[NWINDOWS * 16 + 8];
  46 +
  47 + /* in order to avoid passing too many arguments to the memory
  48 + write helpers, we store some rarely used information in the CPU
  49 + context) */
  50 + unsigned long mem_write_pc; /* host pc at which the memory was
  51 + written */
  52 + unsigned long mem_write_vaddr; /* target virtual addr at which the
  53 + memory was written */
46 54 } CPUSPARCState;
47 55  
48 56 CPUSPARCState *cpu_sparc_init(void);
... ...