Revision e22a25c9 target-i386/kvm.c
b/target-i386/kvm.c | ||
---|---|---|
22 | 22 |
#include "sysemu.h" |
23 | 23 |
#include "kvm.h" |
24 | 24 |
#include "cpu.h" |
25 |
#include "gdbstub.h" |
|
25 | 26 |
|
26 | 27 |
//#define DEBUG_KVM |
27 | 28 |
|
... | ... | |
683 | 684 |
|
684 | 685 |
return ret; |
685 | 686 |
} |
687 |
|
|
688 |
#ifdef KVM_CAP_SET_GUEST_DEBUG |
|
689 |
static int kvm_patch_opcode_byte(CPUState *env, target_ulong addr, uint8_t val) |
|
690 |
{ |
|
691 |
target_phys_addr_t phys_page_addr; |
|
692 |
unsigned long pd; |
|
693 |
uint8_t *ptr; |
|
694 |
|
|
695 |
phys_page_addr = cpu_get_phys_page_debug(env, addr & TARGET_PAGE_MASK); |
|
696 |
if (phys_page_addr == -1) |
|
697 |
return -EINVAL; |
|
698 |
|
|
699 |
pd = cpu_get_physical_page_desc(phys_page_addr); |
|
700 |
if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM && |
|
701 |
(pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM && !(pd & IO_MEM_ROMD)) |
|
702 |
return -EINVAL; |
|
703 |
|
|
704 |
ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) |
|
705 |
+ (addr & ~TARGET_PAGE_MASK); |
|
706 |
*ptr = val; |
|
707 |
return 0; |
|
708 |
} |
|
709 |
|
|
710 |
int kvm_arch_insert_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp) |
|
711 |
{ |
|
712 |
if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 0) || |
|
713 |
kvm_patch_opcode_byte(env, bp->pc, 0xcc)) |
|
714 |
return -EINVAL; |
|
715 |
return 0; |
|
716 |
} |
|
717 |
|
|
718 |
int kvm_arch_remove_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp) |
|
719 |
{ |
|
720 |
uint8_t int3; |
|
721 |
|
|
722 |
if (cpu_memory_rw_debug(env, bp->pc, &int3, 1, 0) || int3 != 0xcc || |
|
723 |
kvm_patch_opcode_byte(env, bp->pc, bp->saved_insn)) |
|
724 |
return -EINVAL; |
|
725 |
return 0; |
|
726 |
} |
|
727 |
|
|
728 |
static struct { |
|
729 |
target_ulong addr; |
|
730 |
int len; |
|
731 |
int type; |
|
732 |
} hw_breakpoint[4]; |
|
733 |
|
|
734 |
static int nb_hw_breakpoint; |
|
735 |
|
|
736 |
static int find_hw_breakpoint(target_ulong addr, int len, int type) |
|
737 |
{ |
|
738 |
int n; |
|
739 |
|
|
740 |
for (n = 0; n < nb_hw_breakpoint; n++) |
|
741 |
if (hw_breakpoint[n].addr == addr && hw_breakpoint[n].type == type && |
|
742 |
(hw_breakpoint[n].len == len || len == -1)) |
|
743 |
return n; |
|
744 |
return -1; |
|
745 |
} |
|
746 |
|
|
747 |
int kvm_arch_insert_hw_breakpoint(target_ulong addr, |
|
748 |
target_ulong len, int type) |
|
749 |
{ |
|
750 |
switch (type) { |
|
751 |
case GDB_BREAKPOINT_HW: |
|
752 |
len = 1; |
|
753 |
break; |
|
754 |
case GDB_WATCHPOINT_WRITE: |
|
755 |
case GDB_WATCHPOINT_ACCESS: |
|
756 |
switch (len) { |
|
757 |
case 1: |
|
758 |
break; |
|
759 |
case 2: |
|
760 |
case 4: |
|
761 |
case 8: |
|
762 |
if (addr & (len - 1)) |
|
763 |
return -EINVAL; |
|
764 |
break; |
|
765 |
default: |
|
766 |
return -EINVAL; |
|
767 |
} |
|
768 |
break; |
|
769 |
default: |
|
770 |
return -ENOSYS; |
|
771 |
} |
|
772 |
|
|
773 |
if (nb_hw_breakpoint == 4) |
|
774 |
return -ENOBUFS; |
|
775 |
|
|
776 |
if (find_hw_breakpoint(addr, len, type) >= 0) |
|
777 |
return -EEXIST; |
|
778 |
|
|
779 |
hw_breakpoint[nb_hw_breakpoint].addr = addr; |
|
780 |
hw_breakpoint[nb_hw_breakpoint].len = len; |
|
781 |
hw_breakpoint[nb_hw_breakpoint].type = type; |
|
782 |
nb_hw_breakpoint++; |
|
783 |
|
|
784 |
return 0; |
|
785 |
} |
|
786 |
|
|
787 |
int kvm_arch_remove_hw_breakpoint(target_ulong addr, |
|
788 |
target_ulong len, int type) |
|
789 |
{ |
|
790 |
int n; |
|
791 |
|
|
792 |
n = find_hw_breakpoint(addr, (type == GDB_BREAKPOINT_HW) ? 1 : len, type); |
|
793 |
if (n < 0) |
|
794 |
return -ENOENT; |
|
795 |
|
|
796 |
nb_hw_breakpoint--; |
|
797 |
hw_breakpoint[n] = hw_breakpoint[nb_hw_breakpoint]; |
|
798 |
|
|
799 |
return 0; |
|
800 |
} |
|
801 |
|
|
802 |
void kvm_arch_remove_all_hw_breakpoints(void) |
|
803 |
{ |
|
804 |
nb_hw_breakpoint = 0; |
|
805 |
} |
|
806 |
|
|
807 |
static CPUWatchpoint hw_watchpoint; |
|
808 |
|
|
809 |
int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info) |
|
810 |
{ |
|
811 |
int handle = 0; |
|
812 |
int n; |
|
813 |
|
|
814 |
if (arch_info->exception == 1) { |
|
815 |
if (arch_info->dr6 & (1 << 14)) { |
|
816 |
if (cpu_single_env->singlestep_enabled) |
|
817 |
handle = 1; |
|
818 |
} else { |
|
819 |
for (n = 0; n < 4; n++) |
|
820 |
if (arch_info->dr6 & (1 << n)) |
|
821 |
switch ((arch_info->dr7 >> (16 + n*4)) & 0x3) { |
|
822 |
case 0x0: |
|
823 |
handle = 1; |
|
824 |
break; |
|
825 |
case 0x1: |
|
826 |
handle = 1; |
|
827 |
cpu_single_env->watchpoint_hit = &hw_watchpoint; |
|
828 |
hw_watchpoint.vaddr = hw_breakpoint[n].addr; |
|
829 |
hw_watchpoint.flags = BP_MEM_WRITE; |
|
830 |
break; |
|
831 |
case 0x3: |
|
832 |
handle = 1; |
|
833 |
cpu_single_env->watchpoint_hit = &hw_watchpoint; |
|
834 |
hw_watchpoint.vaddr = hw_breakpoint[n].addr; |
|
835 |
hw_watchpoint.flags = BP_MEM_ACCESS; |
|
836 |
break; |
|
837 |
} |
|
838 |
} |
|
839 |
} else if (kvm_find_sw_breakpoint(cpu_single_env, arch_info->pc)) |
|
840 |
handle = 1; |
|
841 |
|
|
842 |
if (!handle) |
|
843 |
kvm_update_guest_debug(cpu_single_env, |
|
844 |
(arch_info->exception == 1) ? |
|
845 |
KVM_GUESTDBG_INJECT_DB : KVM_GUESTDBG_INJECT_BP); |
|
846 |
|
|
847 |
return handle; |
|
848 |
} |
|
849 |
|
|
850 |
void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg) |
|
851 |
{ |
|
852 |
const uint8_t type_code[] = { |
|
853 |
[GDB_BREAKPOINT_HW] = 0x0, |
|
854 |
[GDB_WATCHPOINT_WRITE] = 0x1, |
|
855 |
[GDB_WATCHPOINT_ACCESS] = 0x3 |
|
856 |
}; |
|
857 |
const uint8_t len_code[] = { |
|
858 |
[1] = 0x0, [2] = 0x1, [4] = 0x3, [8] = 0x2 |
|
859 |
}; |
|
860 |
int n; |
|
861 |
|
|
862 |
if (kvm_sw_breakpoints_active(env)) |
|
863 |
dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP; |
|
864 |
|
|
865 |
if (nb_hw_breakpoint > 0) { |
|
866 |
dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP; |
|
867 |
dbg->arch.debugreg[7] = 0x0600; |
|
868 |
for (n = 0; n < nb_hw_breakpoint; n++) { |
|
869 |
dbg->arch.debugreg[n] = hw_breakpoint[n].addr; |
|
870 |
dbg->arch.debugreg[7] |= (2 << (n * 2)) | |
|
871 |
(type_code[hw_breakpoint[n].type] << (16 + n*4)) | |
|
872 |
(len_code[hw_breakpoint[n].len] << (18 + n*4)); |
|
873 |
} |
|
874 |
} |
|
875 |
} |
|
876 |
#endif /* KVM_CAP_SET_GUEST_DEBUG */ |
Also available in: Unified diff