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