Revision e22a25c9
b/exec.c | ||
---|---|---|
1457 | 1457 |
#if defined(TARGET_HAS_ICE) |
1458 | 1458 |
if (env->singlestep_enabled != enabled) { |
1459 | 1459 |
env->singlestep_enabled = enabled; |
1460 |
/* must flush all the translated code to avoid inconsistancies */ |
|
1461 |
/* XXX: only flush what is necessary */ |
|
1462 |
tb_flush(env); |
|
1460 |
if (kvm_enabled()) |
|
1461 |
kvm_update_guest_debug(env, 0); |
|
1462 |
else { |
|
1463 |
/* must flush all the translated code to avoid inconsistancies */ |
|
1464 |
/* XXX: only flush what is necessary */ |
|
1465 |
tb_flush(env); |
|
1466 |
} |
|
1463 | 1467 |
} |
1464 | 1468 |
#endif |
1465 | 1469 |
} |
b/gdbstub.c | ||
---|---|---|
39 | 39 |
#define MAX_PACKET_LENGTH 4096 |
40 | 40 |
|
41 | 41 |
#include "qemu_socket.h" |
42 |
#include "kvm.h" |
|
42 | 43 |
|
43 | 44 |
|
44 | 45 |
enum { |
... | ... | |
1418 | 1419 |
} |
1419 | 1420 |
} |
1420 | 1421 |
|
1421 |
/* GDB breakpoint/watchpoint types */ |
|
1422 |
#define GDB_BREAKPOINT_SW 0 |
|
1423 |
#define GDB_BREAKPOINT_HW 1 |
|
1424 |
#define GDB_WATCHPOINT_WRITE 2 |
|
1425 |
#define GDB_WATCHPOINT_READ 3 |
|
1426 |
#define GDB_WATCHPOINT_ACCESS 4 |
|
1427 |
|
|
1428 | 1422 |
#ifndef CONFIG_USER_ONLY |
1429 | 1423 |
static const int xlat_gdb_type[] = { |
1430 | 1424 |
[GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE, |
... | ... | |
1438 | 1432 |
CPUState *env; |
1439 | 1433 |
int err = 0; |
1440 | 1434 |
|
1435 |
if (kvm_enabled()) |
|
1436 |
return kvm_insert_breakpoint(gdbserver_state->c_cpu, addr, len, type); |
|
1437 |
|
|
1441 | 1438 |
switch (type) { |
1442 | 1439 |
case GDB_BREAKPOINT_SW: |
1443 | 1440 |
case GDB_BREAKPOINT_HW: |
... | ... | |
1469 | 1466 |
CPUState *env; |
1470 | 1467 |
int err = 0; |
1471 | 1468 |
|
1469 |
if (kvm_enabled()) |
|
1470 |
return kvm_remove_breakpoint(gdbserver_state->c_cpu, addr, len, type); |
|
1471 |
|
|
1472 | 1472 |
switch (type) { |
1473 | 1473 |
case GDB_BREAKPOINT_SW: |
1474 | 1474 |
case GDB_BREAKPOINT_HW: |
... | ... | |
1498 | 1498 |
{ |
1499 | 1499 |
CPUState *env; |
1500 | 1500 |
|
1501 |
if (kvm_enabled()) { |
|
1502 |
kvm_remove_all_breakpoints(gdbserver_state->c_cpu); |
|
1503 |
return; |
|
1504 |
} |
|
1505 |
|
|
1501 | 1506 |
for (env = first_cpu; env != NULL; env = env->next_cpu) { |
1502 | 1507 |
cpu_breakpoint_remove_all(env, BP_GDB); |
1503 | 1508 |
#ifndef CONFIG_USER_ONLY |
... | ... | |
1538 | 1543 |
addr = strtoull(p, (char **)&p, 16); |
1539 | 1544 |
#if defined(TARGET_I386) |
1540 | 1545 |
s->c_cpu->eip = addr; |
1546 |
cpu_synchronize_state(s->c_cpu, 1); |
|
1541 | 1547 |
#elif defined (TARGET_PPC) |
1542 | 1548 |
s->c_cpu->nip = addr; |
1543 | 1549 |
#elif defined (TARGET_SPARC) |
... | ... | |
1579 | 1585 |
addr = strtoull(p, (char **)&p, 16); |
1580 | 1586 |
#if defined(TARGET_I386) |
1581 | 1587 |
s->c_cpu->eip = addr; |
1588 |
cpu_synchronize_state(s->c_cpu, 1); |
|
1582 | 1589 |
#elif defined (TARGET_PPC) |
1583 | 1590 |
s->c_cpu->nip = addr; |
1584 | 1591 |
#elif defined (TARGET_SPARC) |
... | ... | |
1624 | 1631 |
} |
1625 | 1632 |
break; |
1626 | 1633 |
case 'g': |
1634 |
cpu_synchronize_state(s->g_cpu, 0); |
|
1627 | 1635 |
len = 0; |
1628 | 1636 |
for (addr = 0; addr < num_g_regs; addr++) { |
1629 | 1637 |
reg_size = gdb_read_register(s->g_cpu, mem_buf + len, addr); |
... | ... | |
1641 | 1649 |
len -= reg_size; |
1642 | 1650 |
registers += reg_size; |
1643 | 1651 |
} |
1652 |
cpu_synchronize_state(s->g_cpu, 1); |
|
1644 | 1653 |
put_packet(s, "OK"); |
1645 | 1654 |
break; |
1646 | 1655 |
case 'm': |
... | ... | |
1799 | 1808 |
thread = strtoull(p+16, (char **)&p, 16); |
1800 | 1809 |
for (env = first_cpu; env != NULL; env = env->next_cpu) |
1801 | 1810 |
if (env->cpu_index + 1 == thread) { |
1811 |
cpu_synchronize_state(env, 0); |
|
1802 | 1812 |
len = snprintf((char *)mem_buf, sizeof(mem_buf), |
1803 | 1813 |
"CPU#%d [%s]", env->cpu_index, |
1804 | 1814 |
env->halted ? "halted " : "running"); |
b/gdbstub.h | ||
---|---|---|
3 | 3 |
|
4 | 4 |
#define DEFAULT_GDBSTUB_PORT "1234" |
5 | 5 |
|
6 |
/* GDB breakpoint/watchpoint types */ |
|
7 |
#define GDB_BREAKPOINT_SW 0 |
|
8 |
#define GDB_BREAKPOINT_HW 1 |
|
9 |
#define GDB_WATCHPOINT_WRITE 2 |
|
10 |
#define GDB_WATCHPOINT_READ 3 |
|
11 |
#define GDB_WATCHPOINT_ACCESS 4 |
|
12 |
|
|
6 | 13 |
typedef void (*gdb_syscall_complete_cb)(CPUState *env, |
7 | 14 |
target_ulong ret, target_ulong err); |
8 | 15 |
|
b/kvm-all.c | ||
---|---|---|
22 | 22 |
|
23 | 23 |
#include "qemu-common.h" |
24 | 24 |
#include "sysemu.h" |
25 |
#include "gdbstub.h" |
|
25 | 26 |
#include "kvm.h" |
26 | 27 |
|
27 | 28 |
/* KVM uses PAGE_SIZE in it's definition of COALESCED_MMIO_MAX */ |
... | ... | |
56 | 57 |
int fd; |
57 | 58 |
int vmfd; |
58 | 59 |
int coalesced_mmio; |
60 |
#ifdef KVM_CAP_SET_GUEST_DEBUG |
|
61 |
struct kvm_sw_breakpoint_head kvm_sw_breakpoints; |
|
62 |
#endif |
|
59 | 63 |
}; |
60 | 64 |
|
61 | 65 |
static KVMState *kvm_state; |
... | ... | |
291 | 295 |
|
292 | 296 |
s = qemu_mallocz(sizeof(KVMState)); |
293 | 297 |
|
298 |
#ifdef KVM_CAP_SET_GUEST_DEBUG |
|
299 |
TAILQ_INIT(&s->kvm_sw_breakpoints); |
|
300 |
#endif |
|
294 | 301 |
for (i = 0; i < ARRAY_SIZE(s->slots); i++) |
295 | 302 |
s->slots[i].slot = i; |
296 | 303 |
|
... | ... | |
504 | 511 |
break; |
505 | 512 |
case KVM_EXIT_DEBUG: |
506 | 513 |
dprintf("kvm_exit_debug\n"); |
514 |
#ifdef KVM_CAP_SET_GUEST_DEBUG |
|
515 |
if (kvm_arch_debug(&run->debug.arch)) { |
|
516 |
gdb_set_stop_cpu(env); |
|
517 |
vm_stop(EXCP_DEBUG); |
|
518 |
env->exception_index = EXCP_DEBUG; |
|
519 |
return 0; |
|
520 |
} |
|
521 |
/* re-enter, this exception was guest-internal */ |
|
522 |
ret = 1; |
|
523 |
#endif /* KVM_CAP_SET_GUEST_DEBUG */ |
|
507 | 524 |
break; |
508 | 525 |
default: |
509 | 526 |
dprintf("kvm_arch_handle_exit\n"); |
... | ... | |
656 | 673 |
|
657 | 674 |
return 0; |
658 | 675 |
} |
676 |
|
|
677 |
#ifdef KVM_CAP_SET_GUEST_DEBUG |
|
678 |
struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env, |
|
679 |
target_ulong pc) |
|
680 |
{ |
|
681 |
struct kvm_sw_breakpoint *bp; |
|
682 |
|
|
683 |
TAILQ_FOREACH(bp, &env->kvm_state->kvm_sw_breakpoints, entry) { |
|
684 |
if (bp->pc == pc) |
|
685 |
return bp; |
|
686 |
} |
|
687 |
return NULL; |
|
688 |
} |
|
689 |
|
|
690 |
int kvm_sw_breakpoints_active(CPUState *env) |
|
691 |
{ |
|
692 |
return !TAILQ_EMPTY(&env->kvm_state->kvm_sw_breakpoints); |
|
693 |
} |
|
694 |
|
|
695 |
int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap) |
|
696 |
{ |
|
697 |
struct kvm_guest_debug dbg; |
|
698 |
|
|
699 |
dbg.control = 0; |
|
700 |
if (env->singlestep_enabled) |
|
701 |
dbg.control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP; |
|
702 |
|
|
703 |
kvm_arch_update_guest_debug(env, &dbg); |
|
704 |
dbg.control |= reinject_trap; |
|
705 |
|
|
706 |
return kvm_vcpu_ioctl(env, KVM_SET_GUEST_DEBUG, &dbg); |
|
707 |
} |
|
708 |
|
|
709 |
int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr, |
|
710 |
target_ulong len, int type) |
|
711 |
{ |
|
712 |
struct kvm_sw_breakpoint *bp; |
|
713 |
CPUState *env; |
|
714 |
int err; |
|
715 |
|
|
716 |
if (type == GDB_BREAKPOINT_SW) { |
|
717 |
bp = kvm_find_sw_breakpoint(current_env, addr); |
|
718 |
if (bp) { |
|
719 |
bp->use_count++; |
|
720 |
return 0; |
|
721 |
} |
|
722 |
|
|
723 |
bp = qemu_malloc(sizeof(struct kvm_sw_breakpoint)); |
|
724 |
if (!bp) |
|
725 |
return -ENOMEM; |
|
726 |
|
|
727 |
bp->pc = addr; |
|
728 |
bp->use_count = 1; |
|
729 |
err = kvm_arch_insert_sw_breakpoint(current_env, bp); |
|
730 |
if (err) { |
|
731 |
free(bp); |
|
732 |
return err; |
|
733 |
} |
|
734 |
|
|
735 |
TAILQ_INSERT_HEAD(¤t_env->kvm_state->kvm_sw_breakpoints, |
|
736 |
bp, entry); |
|
737 |
} else { |
|
738 |
err = kvm_arch_insert_hw_breakpoint(addr, len, type); |
|
739 |
if (err) |
|
740 |
return err; |
|
741 |
} |
|
742 |
|
|
743 |
for (env = first_cpu; env != NULL; env = env->next_cpu) { |
|
744 |
err = kvm_update_guest_debug(env, 0); |
|
745 |
if (err) |
|
746 |
return err; |
|
747 |
} |
|
748 |
return 0; |
|
749 |
} |
|
750 |
|
|
751 |
int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr, |
|
752 |
target_ulong len, int type) |
|
753 |
{ |
|
754 |
struct kvm_sw_breakpoint *bp; |
|
755 |
CPUState *env; |
|
756 |
int err; |
|
757 |
|
|
758 |
if (type == GDB_BREAKPOINT_SW) { |
|
759 |
bp = kvm_find_sw_breakpoint(current_env, addr); |
|
760 |
if (!bp) |
|
761 |
return -ENOENT; |
|
762 |
|
|
763 |
if (bp->use_count > 1) { |
|
764 |
bp->use_count--; |
|
765 |
return 0; |
|
766 |
} |
|
767 |
|
|
768 |
err = kvm_arch_remove_sw_breakpoint(current_env, bp); |
|
769 |
if (err) |
|
770 |
return err; |
|
771 |
|
|
772 |
TAILQ_REMOVE(¤t_env->kvm_state->kvm_sw_breakpoints, bp, entry); |
|
773 |
qemu_free(bp); |
|
774 |
} else { |
|
775 |
err = kvm_arch_remove_hw_breakpoint(addr, len, type); |
|
776 |
if (err) |
|
777 |
return err; |
|
778 |
} |
|
779 |
|
|
780 |
for (env = first_cpu; env != NULL; env = env->next_cpu) { |
|
781 |
err = kvm_update_guest_debug(env, 0); |
|
782 |
if (err) |
|
783 |
return err; |
|
784 |
} |
|
785 |
return 0; |
|
786 |
} |
|
787 |
|
|
788 |
void kvm_remove_all_breakpoints(CPUState *current_env) |
|
789 |
{ |
|
790 |
struct kvm_sw_breakpoint *bp, *next; |
|
791 |
KVMState *s = current_env->kvm_state; |
|
792 |
CPUState *env; |
|
793 |
|
|
794 |
TAILQ_FOREACH_SAFE(bp, &s->kvm_sw_breakpoints, entry, next) { |
|
795 |
if (kvm_arch_remove_sw_breakpoint(current_env, bp) != 0) { |
|
796 |
/* Try harder to find a CPU that currently sees the breakpoint. */ |
|
797 |
for (env = first_cpu; env != NULL; env = env->next_cpu) { |
|
798 |
if (kvm_arch_remove_sw_breakpoint(env, bp) == 0) |
|
799 |
break; |
|
800 |
} |
|
801 |
} |
|
802 |
} |
|
803 |
kvm_arch_remove_all_hw_breakpoints(); |
|
804 |
|
|
805 |
for (env = first_cpu; env != NULL; env = env->next_cpu) |
|
806 |
kvm_update_guest_debug(env, 0); |
|
807 |
} |
|
808 |
|
|
809 |
#else /* !KVM_CAP_SET_GUEST_DEBUG */ |
|
810 |
|
|
811 |
int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap) |
|
812 |
{ |
|
813 |
return -EINVAL; |
|
814 |
} |
|
815 |
|
|
816 |
int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr, |
|
817 |
target_ulong len, int type) |
|
818 |
{ |
|
819 |
return -EINVAL; |
|
820 |
} |
|
821 |
|
|
822 |
int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr, |
|
823 |
target_ulong len, int type) |
|
824 |
{ |
|
825 |
return -EINVAL; |
|
826 |
} |
|
827 |
|
|
828 |
void kvm_remove_all_breakpoints(CPUState *current_env) |
|
829 |
{ |
|
830 |
} |
|
831 |
#endif /* !KVM_CAP_SET_GUEST_DEBUG */ |
b/kvm.h | ||
---|---|---|
15 | 15 |
#define QEMU_KVM_H |
16 | 16 |
|
17 | 17 |
#include "config.h" |
18 |
#include "sys-queue.h" |
|
18 | 19 |
|
19 | 20 |
#ifdef CONFIG_KVM |
20 | 21 |
extern int kvm_allowed; |
... | ... | |
49 | 50 |
int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); |
50 | 51 |
int kvm_uncoalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); |
51 | 52 |
|
53 |
int kvm_insert_breakpoint(CPUState *current_env, target_ulong addr, |
|
54 |
target_ulong len, int type); |
|
55 |
int kvm_remove_breakpoint(CPUState *current_env, target_ulong addr, |
|
56 |
target_ulong len, int type); |
|
57 |
void kvm_remove_all_breakpoints(CPUState *current_env); |
|
58 |
int kvm_update_guest_debug(CPUState *env, unsigned long reinject_trap); |
|
59 |
|
|
52 | 60 |
/* internal API */ |
53 | 61 |
|
54 | 62 |
struct KVMState; |
... | ... | |
76 | 84 |
|
77 | 85 |
int kvm_arch_init_vcpu(CPUState *env); |
78 | 86 |
|
87 |
struct kvm_guest_debug; |
|
88 |
struct kvm_debug_exit_arch; |
|
89 |
|
|
90 |
struct kvm_sw_breakpoint { |
|
91 |
target_ulong pc; |
|
92 |
target_ulong saved_insn; |
|
93 |
int use_count; |
|
94 |
TAILQ_ENTRY(kvm_sw_breakpoint) entry; |
|
95 |
}; |
|
96 |
|
|
97 |
TAILQ_HEAD(kvm_sw_breakpoint_head, kvm_sw_breakpoint); |
|
98 |
|
|
99 |
int kvm_arch_debug(struct kvm_debug_exit_arch *arch_info); |
|
100 |
|
|
101 |
struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *env, |
|
102 |
target_ulong pc); |
|
103 |
|
|
104 |
int kvm_sw_breakpoints_active(CPUState *env); |
|
105 |
|
|
106 |
int kvm_arch_insert_sw_breakpoint(CPUState *current_env, |
|
107 |
struct kvm_sw_breakpoint *bp); |
|
108 |
int kvm_arch_remove_sw_breakpoint(CPUState *current_env, |
|
109 |
struct kvm_sw_breakpoint *bp); |
|
110 |
int kvm_arch_insert_hw_breakpoint(target_ulong addr, |
|
111 |
target_ulong len, int type); |
|
112 |
int kvm_arch_remove_hw_breakpoint(target_ulong addr, |
|
113 |
target_ulong len, int type); |
|
114 |
void kvm_arch_remove_all_hw_breakpoints(void); |
|
115 |
|
|
116 |
void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg); |
|
117 |
|
|
118 |
/* generic hooks - to be moved/refactored once there are more users */ |
|
119 |
|
|
120 |
static inline void cpu_synchronize_state(CPUState *env, int modified) |
|
121 |
{ |
|
122 |
if (kvm_enabled()) { |
|
123 |
if (modified) |
|
124 |
kvm_arch_put_registers(env); |
|
125 |
else |
|
126 |
kvm_arch_get_registers(env); |
|
127 |
} |
|
128 |
} |
|
129 |
|
|
79 | 130 |
#endif |
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