QOM CPUState refactorings
* Fix cpu_memory_rw_debug() breakage in s390x KVM * Replace final CPUArchState in sysemu/kvm.h * Introduce model subclasses for XtensaCPU * Introduce CPUClass::gdb_num[_core]_regs * Introduce CPUClass::gdb_core_xml_file * Introduce CPUClass::gdb_{read,write}_register() * Propagate CPUState further in gdbstub -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.19 (GNU/Linux) iQIcBAABAgAGBQJR8vJsAAoJEPou0S0+fgE/ll4QALiUVXNcH8ymDs46JdXfMjyN 4IqZS8VpgddD0WODLSjY/tE39JYY5K4Zl69Cs8kX/jZBeJk0w7XUZS3y6kvW4a0C lVEoxAYn2XE2I0pgJg+F95Z7rzDR/Y0laalkIbqYKjqmvS//KXBUif7Zw+oiqNAE sWtq+GqzG0vPiGN/rUGXuny//A/xWbHzZxqtpF4RgVg5eeRQh1acbpgoCwhZ/pJY 31AGbIfSaXLKfLzXDrKhNbsruSaNxZ0Yc6BG9h/DQDOG9VY0zMIc1xC+IGlWvlAE v/AdaOhZP4GGWw4TN8tUR+Or+dD9KQbwkPtNs7bECutJUgRl3u4iE9lEEV8Rosho 952r/qWPXyiphQ4VjKkG+tphtqj1npiDasKdoxhoQCIk05AXUFdr3XMMMm8+6cXb Ex1cKFoqQ+orc8pGn8jZmY7T1douZA0k38siHduEvb+dzMBdDcfbGw646g/deXZQ TDtB/pKTrZa7s/JqMXuuppHMmjLFQpRrL7Wmag3VhaVj/fL1oDX/DGIQ/xw8Zkdn 2W9skac++LHSkcq+rkM1EgMT9AWzAGRrBK31Mz0f726NuKkzO52ZujCvQWQRfHPF gJEb1auxa3E6dYwK6ITsOw8j/bq+7gQKihhdQeXdu/EAfE1PZmPnaoqYgIOVuZo6 j6bF5EgH+9I60+eLPmYT =Crvv -----END PGP SIGNATURE----- Merge remote-tracking branch 'afaerber/tags/qom-cpu-for-anthony' into staging QOM CPUState refactorings * Fix cpu_memory_rw_debug() breakage in s390x KVM * Replace final CPUArchState in sysemu/kvm.h * Introduce model subclasses for XtensaCPU * Introduce CPUClass::gdb_num[_core]_regs * Introduce CPUClass::gdb_core_xml_file * Introduce CPUClass::gdb_{read,write}_register() * Propagate CPUState further in gdbstub # gpg: Signature made Fri 26 Jul 2013 05:04:28 PM CDT using RSA key ID 3E7E013F # gpg: Can't check signature: public key not found # By Andreas Färber (23) and others # Via Andreas Färber * afaerber/tags/qom-cpu-for-anthony: (25 commits) cpu: Introduce CPUClass::gdb_core_xml_file for GDB_CORE_XML target-cris: Factor out CPUClass::gdb_read_register() hook for v10 cpu: Introduce CPUClass::gdb_{read,write}_register() gdbstub: Replace GET_REG*() macros with gdb_get_reg*() functions target-xtensa: Move cpu_gdb_{read,write}_register() target-lm32: Move cpu_gdb_{read,write}_register() target-s390x: Move cpu_gdb_{read,write}_register() target-alpha: Move cpu_gdb_{read,write}_register() target-cris: Move cpu_gdb_{read,write}_register() target-microblaze: Move cpu_gdb_{read,write}_register() target-sh4: Move cpu_gdb_{read,write}_register() target-openrisc: Move cpu_gdb_{read,write}_register() target-mips: Move cpu_gdb_{read,write}_register() target-m68k: Move cpu_gdb_{read,write}_register() target-arm: Move cpu_gdb_{read,write}_register() target-sparc: Move cpu_gdb_{read,write}_register() target-ppc: Move cpu_gdb_{read,write}_register() target-i386: Move cpu_gdb_{read,write}_register() cpu: Introduce CPUState::gdb_num_regs and CPUClass::gdb_num_core_regs gdbstub: Drop dead code in cpu_gdb_{read,write}_register() ...
This commit is contained in:
commit
200a06397f
5
exec.c
5
exec.c
@ -590,15 +590,14 @@ void cpu_breakpoint_remove_all(CPUArchState *env, int mask)
|
|||||||
void cpu_single_step(CPUState *cpu, int enabled)
|
void cpu_single_step(CPUState *cpu, int enabled)
|
||||||
{
|
{
|
||||||
#if defined(TARGET_HAS_ICE)
|
#if defined(TARGET_HAS_ICE)
|
||||||
CPUArchState *env = cpu->env_ptr;
|
|
||||||
|
|
||||||
if (cpu->singlestep_enabled != enabled) {
|
if (cpu->singlestep_enabled != enabled) {
|
||||||
cpu->singlestep_enabled = enabled;
|
cpu->singlestep_enabled = enabled;
|
||||||
if (kvm_enabled()) {
|
if (kvm_enabled()) {
|
||||||
kvm_update_guest_debug(env, 0);
|
kvm_update_guest_debug(cpu, 0);
|
||||||
} else {
|
} else {
|
||||||
/* must flush all the translated code to avoid inconsistencies */
|
/* must flush all the translated code to avoid inconsistencies */
|
||||||
/* XXX: only flush what is necessary */
|
/* XXX: only flush what is necessary */
|
||||||
|
CPUArchState *env = cpu->env_ptr;
|
||||||
tb_flush(env);
|
tb_flush(env);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,43 @@ static inline int cpu_index(CPUState *cpu)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The GDB remote protocol transfers values in target byte order. This means
|
||||||
|
* we can use the raw memory access routines to access the value buffer.
|
||||||
|
* Conveniently, these also handle the case where the buffer is mis-aligned.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline int gdb_get_reg8(uint8_t *mem_buf, uint8_t val)
|
||||||
|
{
|
||||||
|
stb_p(mem_buf, val);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int gdb_get_reg16(uint8_t *mem_buf, uint16_t val)
|
||||||
|
{
|
||||||
|
stw_p(mem_buf, val);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int gdb_get_reg32(uint8_t *mem_buf, uint32_t val)
|
||||||
|
{
|
||||||
|
stl_p(mem_buf, val);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int gdb_get_reg64(uint8_t *mem_buf, uint64_t val)
|
||||||
|
{
|
||||||
|
stq_p(mem_buf, val);
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if TARGET_LONG_BITS == 64
|
||||||
|
#define gdb_get_regl(buf, val) gdb_get_reg64(buf, val)
|
||||||
|
#define ldtul_p(addr) ldq_p(addr)
|
||||||
|
#else
|
||||||
|
#define gdb_get_regl(buf, val) gdb_get_reg32(buf, val)
|
||||||
|
#define ldtul_p(addr) ldl_p(addr)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
@ -47,6 +84,14 @@ int gdbserver_start(int);
|
|||||||
int gdbserver_start(const char *port);
|
int gdbserver_start(const char *port);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdb_has_xml:
|
||||||
|
* This is an ugly hack to cope with both new and old gdb.
|
||||||
|
* If gdb sends qXfer:features:read then assume we're talking to a newish
|
||||||
|
* gdb that understands target descriptions.
|
||||||
|
*/
|
||||||
|
extern bool gdb_has_xml;
|
||||||
|
|
||||||
/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */
|
/* in gdbstub-xml.c, generated by scripts/feature_to_c.sh */
|
||||||
extern const char *const xml_builtin[][2];
|
extern const char *const xml_builtin[][2];
|
||||||
|
|
||||||
|
@ -80,7 +80,11 @@ struct TranslationBlock;
|
|||||||
* @synchronize_from_tb: Callback for synchronizing state from a TCG
|
* @synchronize_from_tb: Callback for synchronizing state from a TCG
|
||||||
* #TranslationBlock.
|
* #TranslationBlock.
|
||||||
* @get_phys_page_debug: Callback for obtaining a physical address.
|
* @get_phys_page_debug: Callback for obtaining a physical address.
|
||||||
|
* @gdb_read_register: Callback for letting GDB read a register.
|
||||||
|
* @gdb_write_register: Callback for letting GDB write a register.
|
||||||
* @vmsd: State description for migration.
|
* @vmsd: State description for migration.
|
||||||
|
* @gdb_num_core_regs: Number of core registers accessible to GDB.
|
||||||
|
* @gdb_core_xml_file: File name for core registers GDB XML description.
|
||||||
*
|
*
|
||||||
* Represents a CPU family or model.
|
* Represents a CPU family or model.
|
||||||
*/
|
*/
|
||||||
@ -108,8 +112,9 @@ typedef struct CPUClass {
|
|||||||
void (*set_pc)(CPUState *cpu, vaddr value);
|
void (*set_pc)(CPUState *cpu, vaddr value);
|
||||||
void (*synchronize_from_tb)(CPUState *cpu, struct TranslationBlock *tb);
|
void (*synchronize_from_tb)(CPUState *cpu, struct TranslationBlock *tb);
|
||||||
hwaddr (*get_phys_page_debug)(CPUState *cpu, vaddr addr);
|
hwaddr (*get_phys_page_debug)(CPUState *cpu, vaddr addr);
|
||||||
|
int (*gdb_read_register)(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
const struct VMStateDescription *vmsd;
|
|
||||||
int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu,
|
int (*write_elf64_note)(WriteCoreDumpFunction f, CPUState *cpu,
|
||||||
int cpuid, void *opaque);
|
int cpuid, void *opaque);
|
||||||
int (*write_elf64_qemunote)(WriteCoreDumpFunction f, CPUState *cpu,
|
int (*write_elf64_qemunote)(WriteCoreDumpFunction f, CPUState *cpu,
|
||||||
@ -118,6 +123,10 @@ typedef struct CPUClass {
|
|||||||
int cpuid, void *opaque);
|
int cpuid, void *opaque);
|
||||||
int (*write_elf32_qemunote)(WriteCoreDumpFunction f, CPUState *cpu,
|
int (*write_elf32_qemunote)(WriteCoreDumpFunction f, CPUState *cpu,
|
||||||
void *opaque);
|
void *opaque);
|
||||||
|
|
||||||
|
const struct VMStateDescription *vmsd;
|
||||||
|
int gdb_num_core_regs;
|
||||||
|
const char *gdb_core_xml_file;
|
||||||
} CPUClass;
|
} CPUClass;
|
||||||
|
|
||||||
struct KVMState;
|
struct KVMState;
|
||||||
@ -142,6 +151,7 @@ struct kvm_run;
|
|||||||
* @env_ptr: Pointer to subclass-specific CPUArchState field.
|
* @env_ptr: Pointer to subclass-specific CPUArchState field.
|
||||||
* @current_tb: Currently executing TB.
|
* @current_tb: Currently executing TB.
|
||||||
* @gdb_regs: Additional GDB registers.
|
* @gdb_regs: Additional GDB registers.
|
||||||
|
* @gdb_num_regs: Number of total registers accessible to GDB.
|
||||||
* @next_cpu: Next CPU sharing TB cache.
|
* @next_cpu: Next CPU sharing TB cache.
|
||||||
* @kvm_fd: vCPU file descriptor for KVM.
|
* @kvm_fd: vCPU file descriptor for KVM.
|
||||||
*
|
*
|
||||||
@ -177,6 +187,7 @@ struct CPUState {
|
|||||||
void *env_ptr; /* CPUArchState */
|
void *env_ptr; /* CPUArchState */
|
||||||
struct TranslationBlock *current_tb;
|
struct TranslationBlock *current_tb;
|
||||||
struct GDBRegisterState *gdb_regs;
|
struct GDBRegisterState *gdb_regs;
|
||||||
|
int gdb_num_regs;
|
||||||
CPUState *next_cpu;
|
CPUState *next_cpu;
|
||||||
|
|
||||||
int kvm_fd;
|
int kvm_fd;
|
||||||
|
@ -174,7 +174,7 @@ int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr,
|
|||||||
int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr,
|
int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr,
|
||||||
target_ulong len, int type);
|
target_ulong len, int type);
|
||||||
void kvm_remove_all_breakpoints(CPUState *cpu);
|
void kvm_remove_all_breakpoints(CPUState *cpu);
|
||||||
int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap);
|
int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap);
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
int kvm_set_signal_mask(CPUState *cpu, const sigset_t *sigset);
|
int kvm_set_signal_mask(CPUState *cpu, const sigset_t *sigset);
|
||||||
#endif
|
#endif
|
||||||
|
17
kvm-all.c
17
kvm-all.c
@ -1883,9 +1883,8 @@ static void kvm_invoke_set_guest_debug(void *data)
|
|||||||
&dbg_data->dbg);
|
&dbg_data->dbg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap)
|
int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
|
||||||
{
|
{
|
||||||
CPUState *cpu = ENV_GET_CPU(env);
|
|
||||||
struct kvm_set_guest_debug_data data;
|
struct kvm_set_guest_debug_data data;
|
||||||
|
|
||||||
data.dbg.control = reinject_trap;
|
data.dbg.control = reinject_trap;
|
||||||
@ -1935,9 +1934,7 @@ int kvm_insert_breakpoint(CPUState *cpu, target_ulong addr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
|
for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
|
||||||
CPUArchState *env = cpu->env_ptr;
|
err = kvm_update_guest_debug(cpu, 0);
|
||||||
|
|
||||||
err = kvm_update_guest_debug(env, 0);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -1977,9 +1974,7 @@ int kvm_remove_breakpoint(CPUState *cpu, target_ulong addr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
|
for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
|
||||||
CPUArchState *env = cpu->env_ptr;
|
err = kvm_update_guest_debug(cpu, 0);
|
||||||
|
|
||||||
err = kvm_update_guest_debug(env, 0);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -2007,15 +2002,13 @@ void kvm_remove_all_breakpoints(CPUState *cpu)
|
|||||||
kvm_arch_remove_all_hw_breakpoints();
|
kvm_arch_remove_all_hw_breakpoints();
|
||||||
|
|
||||||
for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
|
for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
|
||||||
CPUArchState *env = cpu->env_ptr;
|
kvm_update_guest_debug(cpu, 0);
|
||||||
|
|
||||||
kvm_update_guest_debug(env, 0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* !KVM_CAP_SET_GUEST_DEBUG */
|
#else /* !KVM_CAP_SET_GUEST_DEBUG */
|
||||||
|
|
||||||
int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap)
|
int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ void kvm_setup_guest_memory(void *start, size_t size)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap)
|
int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
@ -3637,7 +3637,7 @@ int main(int argc, char **argv, char **envp)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
cpu = ENV_GET_CPU(env);
|
cpu = ENV_GET_CPU(env);
|
||||||
cpu_reset(ENV_GET_CPU(env));
|
cpu_reset(cpu);
|
||||||
|
|
||||||
thread_cpu = cpu;
|
thread_cpu = cpu;
|
||||||
|
|
||||||
|
22
qom/cpu.c
22
qom/cpu.c
@ -157,6 +157,17 @@ static int cpu_common_write_elf64_note(WriteCoreDumpFunction f,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int cpu_common_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
|
void cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
@ -226,6 +237,14 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cpu_common_initfn(Object *obj)
|
||||||
|
{
|
||||||
|
CPUState *cpu = CPU(obj);
|
||||||
|
CPUClass *cc = CPU_GET_CLASS(obj);
|
||||||
|
|
||||||
|
cpu->gdb_num_regs = cc->gdb_num_core_regs;
|
||||||
|
}
|
||||||
|
|
||||||
static int64_t cpu_common_get_arch_id(CPUState *cpu)
|
static int64_t cpu_common_get_arch_id(CPUState *cpu)
|
||||||
{
|
{
|
||||||
return cpu->cpu_index;
|
return cpu->cpu_index;
|
||||||
@ -245,6 +264,8 @@ static void cpu_class_init(ObjectClass *klass, void *data)
|
|||||||
k->write_elf32_note = cpu_common_write_elf32_note;
|
k->write_elf32_note = cpu_common_write_elf32_note;
|
||||||
k->write_elf64_qemunote = cpu_common_write_elf64_qemunote;
|
k->write_elf64_qemunote = cpu_common_write_elf64_qemunote;
|
||||||
k->write_elf64_note = cpu_common_write_elf64_note;
|
k->write_elf64_note = cpu_common_write_elf64_note;
|
||||||
|
k->gdb_read_register = cpu_common_gdb_read_register;
|
||||||
|
k->gdb_write_register = cpu_common_gdb_write_register;
|
||||||
dc->realize = cpu_common_realizefn;
|
dc->realize = cpu_common_realizefn;
|
||||||
dc->no_user = 1;
|
dc->no_user = 1;
|
||||||
}
|
}
|
||||||
@ -253,6 +274,7 @@ static const TypeInfo cpu_type_info = {
|
|||||||
.name = TYPE_CPU,
|
.name = TYPE_CPU,
|
||||||
.parent = TYPE_DEVICE,
|
.parent = TYPE_DEVICE,
|
||||||
.instance_size = sizeof(CPUState),
|
.instance_size = sizeof(CPUState),
|
||||||
|
.instance_init = cpu_common_initfn,
|
||||||
.abstract = true,
|
.abstract = true,
|
||||||
.class_size = sizeof(CPUClass),
|
.class_size = sizeof(CPUClass),
|
||||||
.class_init = cpu_class_init,
|
.class_init = cpu_class_init,
|
||||||
|
@ -7,6 +7,7 @@ stub-obj-y += fdset-add-fd.o
|
|||||||
stub-obj-y += fdset-find-fd.o
|
stub-obj-y += fdset-find-fd.o
|
||||||
stub-obj-y += fdset-get-fd.o
|
stub-obj-y += fdset-get-fd.o
|
||||||
stub-obj-y += fdset-remove-fd.o
|
stub-obj-y += fdset-remove-fd.o
|
||||||
|
stub-obj-y += gdbstub.o
|
||||||
stub-obj-y += get-fd.o
|
stub-obj-y += get-fd.o
|
||||||
stub-obj-y += get-vm-name.o
|
stub-obj-y += get-vm-name.o
|
||||||
stub-obj-y += iothread-lock.o
|
stub-obj-y += iothread-lock.o
|
||||||
|
5
stubs/gdbstub.c
Normal file
5
stubs/gdbstub.c
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#include "qemu-common.h"
|
||||||
|
|
||||||
|
const char *const xml_builtin[][2] = {
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
@ -1,3 +1,4 @@
|
|||||||
obj-$(CONFIG_SOFTMMU) += machine.o
|
obj-$(CONFIG_SOFTMMU) += machine.o
|
||||||
obj-y += translate.o helper.o cpu.o
|
obj-y += translate.o helper.o cpu.o
|
||||||
obj-y += int_helper.o fpu_helper.o sys_helper.o mem_helper.o
|
obj-y += int_helper.o fpu_helper.o sys_helper.o mem_helper.o
|
||||||
|
obj-y += gdbstub.o
|
||||||
|
@ -82,5 +82,7 @@ void alpha_cpu_do_interrupt(CPUState *cpu);
|
|||||||
void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
|
void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
|
||||||
int flags);
|
int flags);
|
||||||
hwaddr alpha_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
hwaddr alpha_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||||
|
int alpha_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
int alpha_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -271,11 +271,14 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data)
|
|||||||
cc->do_interrupt = alpha_cpu_do_interrupt;
|
cc->do_interrupt = alpha_cpu_do_interrupt;
|
||||||
cc->dump_state = alpha_cpu_dump_state;
|
cc->dump_state = alpha_cpu_dump_state;
|
||||||
cc->set_pc = alpha_cpu_set_pc;
|
cc->set_pc = alpha_cpu_set_pc;
|
||||||
|
cc->gdb_read_register = alpha_cpu_gdb_read_register;
|
||||||
|
cc->gdb_write_register = alpha_cpu_gdb_write_register;
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
cc->do_unassigned_access = alpha_cpu_unassigned_access;
|
cc->do_unassigned_access = alpha_cpu_unassigned_access;
|
||||||
cc->get_phys_page_debug = alpha_cpu_get_phys_page_debug;
|
cc->get_phys_page_debug = alpha_cpu_get_phys_page_debug;
|
||||||
dc->vmsd = &vmstate_alpha_cpu;
|
dc->vmsd = &vmstate_alpha_cpu;
|
||||||
#endif
|
#endif
|
||||||
|
cc->gdb_num_core_regs = 67;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo alpha_cpu_type_info = {
|
static const TypeInfo alpha_cpu_type_info = {
|
||||||
|
93
target-alpha/gdbstub.c
Normal file
93
target-alpha/gdbstub.c
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Alpha gdb server stub
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||||
|
* Copyright (c) 2013 SUSE LINUX Products GmbH
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
|
int alpha_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
AlphaCPU *cpu = ALPHA_CPU(cs);
|
||||||
|
CPUAlphaState *env = &cpu->env;
|
||||||
|
uint64_t val;
|
||||||
|
CPU_DoubleU d;
|
||||||
|
|
||||||
|
switch (n) {
|
||||||
|
case 0 ... 30:
|
||||||
|
val = env->ir[n];
|
||||||
|
break;
|
||||||
|
case 32 ... 62:
|
||||||
|
d.d = env->fir[n - 32];
|
||||||
|
val = d.ll;
|
||||||
|
break;
|
||||||
|
case 63:
|
||||||
|
val = cpu_alpha_load_fpcr(env);
|
||||||
|
break;
|
||||||
|
case 64:
|
||||||
|
val = env->pc;
|
||||||
|
break;
|
||||||
|
case 66:
|
||||||
|
val = env->unique;
|
||||||
|
break;
|
||||||
|
case 31:
|
||||||
|
case 65:
|
||||||
|
/* 31 really is the zero register; 65 is unassigned in the
|
||||||
|
gdb protocol, but is still required to occupy 8 bytes. */
|
||||||
|
val = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return gdb_get_regl(mem_buf, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int alpha_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
AlphaCPU *cpu = ALPHA_CPU(cs);
|
||||||
|
CPUAlphaState *env = &cpu->env;
|
||||||
|
target_ulong tmp = ldtul_p(mem_buf);
|
||||||
|
CPU_DoubleU d;
|
||||||
|
|
||||||
|
switch (n) {
|
||||||
|
case 0 ... 30:
|
||||||
|
env->ir[n] = tmp;
|
||||||
|
break;
|
||||||
|
case 32 ... 62:
|
||||||
|
d.ll = tmp;
|
||||||
|
env->fir[n - 32] = d.d;
|
||||||
|
break;
|
||||||
|
case 63:
|
||||||
|
cpu_alpha_store_fpcr(env, tmp);
|
||||||
|
break;
|
||||||
|
case 64:
|
||||||
|
env->pc = tmp;
|
||||||
|
break;
|
||||||
|
case 66:
|
||||||
|
env->unique = tmp;
|
||||||
|
break;
|
||||||
|
case 31:
|
||||||
|
case 65:
|
||||||
|
/* 31 really is the zero register; 65 is unassigned in the
|
||||||
|
gdb protocol, but is still required to occupy 8 bytes. */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 8;
|
||||||
|
}
|
@ -4,3 +4,4 @@ obj-$(CONFIG_KVM) += kvm.o
|
|||||||
obj-$(CONFIG_NO_KVM) += kvm-stub.o
|
obj-$(CONFIG_NO_KVM) += kvm-stub.o
|
||||||
obj-y += translate.o op_helper.o helper.o cpu.o
|
obj-y += translate.o op_helper.o helper.o cpu.o
|
||||||
obj-y += neon_helper.o iwmmxt_helper.o
|
obj-y += neon_helper.o iwmmxt_helper.o
|
||||||
|
obj-y += gdbstub.o
|
||||||
|
@ -149,4 +149,7 @@ void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
|
|||||||
|
|
||||||
hwaddr arm_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
hwaddr arm_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||||
|
|
||||||
|
int arm_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -824,10 +824,14 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
|
|||||||
cc->do_interrupt = arm_cpu_do_interrupt;
|
cc->do_interrupt = arm_cpu_do_interrupt;
|
||||||
cc->dump_state = arm_cpu_dump_state;
|
cc->dump_state = arm_cpu_dump_state;
|
||||||
cc->set_pc = arm_cpu_set_pc;
|
cc->set_pc = arm_cpu_set_pc;
|
||||||
|
cc->gdb_read_register = arm_cpu_gdb_read_register;
|
||||||
|
cc->gdb_write_register = arm_cpu_gdb_write_register;
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
cc->get_phys_page_debug = arm_cpu_get_phys_page_debug;
|
cc->get_phys_page_debug = arm_cpu_get_phys_page_debug;
|
||||||
cc->vmsd = &vmstate_arm_cpu;
|
cc->vmsd = &vmstate_arm_cpu;
|
||||||
#endif
|
#endif
|
||||||
|
cc->gdb_num_core_regs = 26;
|
||||||
|
cc->gdb_core_xml_file = "arm-core.xml";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cpu_register(const ARMCPUInfo *info)
|
static void cpu_register(const ARMCPUInfo *info)
|
||||||
|
102
target-arm/gdbstub.c
Normal file
102
target-arm/gdbstub.c
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* ARM gdb server stub
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||||
|
* Copyright (c) 2013 SUSE LINUX Products GmbH
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
|
/* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect
|
||||||
|
whatever the target description contains. Due to a historical mishap
|
||||||
|
the FPA registers appear in between core integer regs and the CPSR.
|
||||||
|
We hack round this by giving the FPA regs zero size when talking to a
|
||||||
|
newer gdb. */
|
||||||
|
|
||||||
|
int arm_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
ARMCPU *cpu = ARM_CPU(cs);
|
||||||
|
CPUARMState *env = &cpu->env;
|
||||||
|
|
||||||
|
if (n < 16) {
|
||||||
|
/* Core integer register. */
|
||||||
|
return gdb_get_reg32(mem_buf, env->regs[n]);
|
||||||
|
}
|
||||||
|
if (n < 24) {
|
||||||
|
/* FPA registers. */
|
||||||
|
if (gdb_has_xml) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memset(mem_buf, 0, 12);
|
||||||
|
return 12;
|
||||||
|
}
|
||||||
|
switch (n) {
|
||||||
|
case 24:
|
||||||
|
/* FPA status register. */
|
||||||
|
if (gdb_has_xml) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return gdb_get_reg32(mem_buf, 0);
|
||||||
|
case 25:
|
||||||
|
/* CPSR */
|
||||||
|
return gdb_get_reg32(mem_buf, cpsr_read(env));
|
||||||
|
}
|
||||||
|
/* Unknown register. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
ARMCPU *cpu = ARM_CPU(cs);
|
||||||
|
CPUARMState *env = &cpu->env;
|
||||||
|
uint32_t tmp;
|
||||||
|
|
||||||
|
tmp = ldl_p(mem_buf);
|
||||||
|
|
||||||
|
/* Mask out low bit of PC to workaround gdb bugs. This will probably
|
||||||
|
cause problems if we ever implement the Jazelle DBX extensions. */
|
||||||
|
if (n == 15) {
|
||||||
|
tmp &= ~1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n < 16) {
|
||||||
|
/* Core integer register. */
|
||||||
|
env->regs[n] = tmp;
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
if (n < 24) { /* 16-23 */
|
||||||
|
/* FPA registers (ignored). */
|
||||||
|
if (gdb_has_xml) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 12;
|
||||||
|
}
|
||||||
|
switch (n) {
|
||||||
|
case 24:
|
||||||
|
/* FPA status register (ignored). */
|
||||||
|
if (gdb_has_xml) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 4;
|
||||||
|
case 25:
|
||||||
|
/* CPSR */
|
||||||
|
cpsr_write(env, tmp, 0xffffffff);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
/* Unknown register. */
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
obj-y += translate.o op_helper.o helper.o cpu.o
|
obj-y += translate.o op_helper.o helper.o cpu.o
|
||||||
|
obj-y += gdbstub.o
|
||||||
obj-$(CONFIG_SOFTMMU) += mmu.o machine.o
|
obj-$(CONFIG_SOFTMMU) += mmu.o machine.o
|
||||||
|
@ -81,4 +81,8 @@ void cris_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
|
|||||||
|
|
||||||
hwaddr cris_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
hwaddr cris_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||||
|
|
||||||
|
int crisv10_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
int cris_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
int cris_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -175,6 +175,7 @@ static void crisv8_cpu_class_init(ObjectClass *oc, void *data)
|
|||||||
|
|
||||||
ccc->vr = 8;
|
ccc->vr = 8;
|
||||||
cc->do_interrupt = crisv10_cpu_do_interrupt;
|
cc->do_interrupt = crisv10_cpu_do_interrupt;
|
||||||
|
cc->gdb_read_register = crisv10_cpu_gdb_read_register;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void crisv9_cpu_class_init(ObjectClass *oc, void *data)
|
static void crisv9_cpu_class_init(ObjectClass *oc, void *data)
|
||||||
@ -184,6 +185,7 @@ static void crisv9_cpu_class_init(ObjectClass *oc, void *data)
|
|||||||
|
|
||||||
ccc->vr = 9;
|
ccc->vr = 9;
|
||||||
cc->do_interrupt = crisv10_cpu_do_interrupt;
|
cc->do_interrupt = crisv10_cpu_do_interrupt;
|
||||||
|
cc->gdb_read_register = crisv10_cpu_gdb_read_register;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void crisv10_cpu_class_init(ObjectClass *oc, void *data)
|
static void crisv10_cpu_class_init(ObjectClass *oc, void *data)
|
||||||
@ -193,6 +195,7 @@ static void crisv10_cpu_class_init(ObjectClass *oc, void *data)
|
|||||||
|
|
||||||
ccc->vr = 10;
|
ccc->vr = 10;
|
||||||
cc->do_interrupt = crisv10_cpu_do_interrupt;
|
cc->do_interrupt = crisv10_cpu_do_interrupt;
|
||||||
|
cc->gdb_read_register = crisv10_cpu_gdb_read_register;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void crisv11_cpu_class_init(ObjectClass *oc, void *data)
|
static void crisv11_cpu_class_init(ObjectClass *oc, void *data)
|
||||||
@ -202,6 +205,7 @@ static void crisv11_cpu_class_init(ObjectClass *oc, void *data)
|
|||||||
|
|
||||||
ccc->vr = 11;
|
ccc->vr = 11;
|
||||||
cc->do_interrupt = crisv10_cpu_do_interrupt;
|
cc->do_interrupt = crisv10_cpu_do_interrupt;
|
||||||
|
cc->gdb_read_register = crisv10_cpu_gdb_read_register;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void crisv32_cpu_class_init(ObjectClass *oc, void *data)
|
static void crisv32_cpu_class_init(ObjectClass *oc, void *data)
|
||||||
@ -255,9 +259,13 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data)
|
|||||||
cc->do_interrupt = cris_cpu_do_interrupt;
|
cc->do_interrupt = cris_cpu_do_interrupt;
|
||||||
cc->dump_state = cris_cpu_dump_state;
|
cc->dump_state = cris_cpu_dump_state;
|
||||||
cc->set_pc = cris_cpu_set_pc;
|
cc->set_pc = cris_cpu_set_pc;
|
||||||
|
cc->gdb_read_register = cris_cpu_gdb_read_register;
|
||||||
|
cc->gdb_write_register = cris_cpu_gdb_write_register;
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
cc->get_phys_page_debug = cris_cpu_get_phys_page_debug;
|
cc->get_phys_page_debug = cris_cpu_get_phys_page_debug;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
cc->gdb_num_core_regs = 49;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo cris_cpu_type_info = {
|
static const TypeInfo cris_cpu_type_info = {
|
||||||
|
130
target-cris/gdbstub.c
Normal file
130
target-cris/gdbstub.c
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
/*
|
||||||
|
* CRIS gdb server stub
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||||
|
* Copyright (c) 2013 SUSE LINUX Products GmbH
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
|
int crisv10_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
CRISCPU *cpu = CRIS_CPU(cs);
|
||||||
|
CPUCRISState *env = &cpu->env;
|
||||||
|
|
||||||
|
if (n < 15) {
|
||||||
|
return gdb_get_reg32(mem_buf, env->regs[n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == 15) {
|
||||||
|
return gdb_get_reg32(mem_buf, env->pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n < 32) {
|
||||||
|
switch (n) {
|
||||||
|
case 16:
|
||||||
|
return gdb_get_reg8(mem_buf, env->pregs[n - 16]);
|
||||||
|
case 17:
|
||||||
|
return gdb_get_reg8(mem_buf, env->pregs[n - 16]);
|
||||||
|
case 20:
|
||||||
|
case 21:
|
||||||
|
return gdb_get_reg16(mem_buf, env->pregs[n - 16]);
|
||||||
|
default:
|
||||||
|
if (n >= 23) {
|
||||||
|
return gdb_get_reg32(mem_buf, env->pregs[n - 16]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cris_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
CRISCPU *cpu = CRIS_CPU(cs);
|
||||||
|
CPUCRISState *env = &cpu->env;
|
||||||
|
uint8_t srs;
|
||||||
|
|
||||||
|
srs = env->pregs[PR_SRS];
|
||||||
|
if (n < 16) {
|
||||||
|
return gdb_get_reg32(mem_buf, env->regs[n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n >= 21 && n < 32) {
|
||||||
|
return gdb_get_reg32(mem_buf, env->pregs[n - 16]);
|
||||||
|
}
|
||||||
|
if (n >= 33 && n < 49) {
|
||||||
|
return gdb_get_reg32(mem_buf, env->sregs[srs][n - 33]);
|
||||||
|
}
|
||||||
|
switch (n) {
|
||||||
|
case 16:
|
||||||
|
return gdb_get_reg8(mem_buf, env->pregs[0]);
|
||||||
|
case 17:
|
||||||
|
return gdb_get_reg8(mem_buf, env->pregs[1]);
|
||||||
|
case 18:
|
||||||
|
return gdb_get_reg32(mem_buf, env->pregs[2]);
|
||||||
|
case 19:
|
||||||
|
return gdb_get_reg8(mem_buf, srs);
|
||||||
|
case 20:
|
||||||
|
return gdb_get_reg16(mem_buf, env->pregs[4]);
|
||||||
|
case 32:
|
||||||
|
return gdb_get_reg32(mem_buf, env->pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cris_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
CRISCPU *cpu = CRIS_CPU(cs);
|
||||||
|
CPUCRISState *env = &cpu->env;
|
||||||
|
uint32_t tmp;
|
||||||
|
|
||||||
|
if (n > 49) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = ldl_p(mem_buf);
|
||||||
|
|
||||||
|
if (n < 16) {
|
||||||
|
env->regs[n] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n >= 21 && n < 32) {
|
||||||
|
env->pregs[n - 16] = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: Should support function regs be writable? */
|
||||||
|
switch (n) {
|
||||||
|
case 16:
|
||||||
|
return 1;
|
||||||
|
case 17:
|
||||||
|
return 1;
|
||||||
|
case 18:
|
||||||
|
env->pregs[PR_PID] = tmp;
|
||||||
|
break;
|
||||||
|
case 19:
|
||||||
|
return 1;
|
||||||
|
case 20:
|
||||||
|
return 2;
|
||||||
|
case 32:
|
||||||
|
env->pc = tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
obj-y += translate.o helper.o cpu.o
|
obj-y += translate.o helper.o cpu.o
|
||||||
obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o svm_helper.o
|
obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o svm_helper.o
|
||||||
obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o
|
obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o
|
||||||
|
obj-y += gdbstub.o
|
||||||
obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o
|
obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o
|
||||||
obj-$(CONFIG_KVM) += kvm.o hyperv.o
|
obj-$(CONFIG_KVM) += kvm.o hyperv.o
|
||||||
obj-$(CONFIG_NO_KVM) += kvm-stub.o
|
obj-$(CONFIG_NO_KVM) += kvm-stub.o
|
||||||
|
@ -106,4 +106,7 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
|
|||||||
|
|
||||||
hwaddr x86_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
hwaddr x86_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||||
|
|
||||||
|
int x86_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
int x86_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2538,6 +2538,8 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
|
|||||||
cc->dump_state = x86_cpu_dump_state;
|
cc->dump_state = x86_cpu_dump_state;
|
||||||
cc->set_pc = x86_cpu_set_pc;
|
cc->set_pc = x86_cpu_set_pc;
|
||||||
cc->synchronize_from_tb = x86_cpu_synchronize_from_tb;
|
cc->synchronize_from_tb = x86_cpu_synchronize_from_tb;
|
||||||
|
cc->gdb_read_register = x86_cpu_gdb_read_register;
|
||||||
|
cc->gdb_write_register = x86_cpu_gdb_write_register;
|
||||||
cc->get_arch_id = x86_cpu_get_arch_id;
|
cc->get_arch_id = x86_cpu_get_arch_id;
|
||||||
cc->get_paging_enabled = x86_cpu_get_paging_enabled;
|
cc->get_paging_enabled = x86_cpu_get_paging_enabled;
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
@ -2549,6 +2551,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
|
|||||||
cc->write_elf32_qemunote = x86_cpu_write_elf32_qemunote;
|
cc->write_elf32_qemunote = x86_cpu_write_elf32_qemunote;
|
||||||
cc->vmsd = &vmstate_x86_cpu;
|
cc->vmsd = &vmstate_x86_cpu;
|
||||||
#endif
|
#endif
|
||||||
|
cc->gdb_num_core_regs = CPU_NB_REGS * 2 + 25;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo x86_cpu_type_info = {
|
static const TypeInfo x86_cpu_type_info = {
|
||||||
|
231
target-i386/gdbstub.c
Normal file
231
target-i386/gdbstub.c
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
/*
|
||||||
|
* x86 gdb server stub
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||||
|
* Copyright (c) 2013 SUSE LINUX Products GmbH
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
|
#ifdef TARGET_X86_64
|
||||||
|
static const int gpr_map[16] = {
|
||||||
|
R_EAX, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP, R_ESP,
|
||||||
|
8, 9, 10, 11, 12, 13, 14, 15
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
#define gpr_map gpr_map32
|
||||||
|
#endif
|
||||||
|
static const int gpr_map32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||||
|
|
||||||
|
#define IDX_IP_REG CPU_NB_REGS
|
||||||
|
#define IDX_FLAGS_REG (IDX_IP_REG + 1)
|
||||||
|
#define IDX_SEG_REGS (IDX_FLAGS_REG + 1)
|
||||||
|
#define IDX_FP_REGS (IDX_SEG_REGS + 6)
|
||||||
|
#define IDX_XMM_REGS (IDX_FP_REGS + 16)
|
||||||
|
#define IDX_MXCSR_REG (IDX_XMM_REGS + CPU_NB_REGS)
|
||||||
|
|
||||||
|
int x86_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
X86CPU *cpu = X86_CPU(cs);
|
||||||
|
CPUX86State *env = &cpu->env;
|
||||||
|
|
||||||
|
if (n < CPU_NB_REGS) {
|
||||||
|
if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
|
||||||
|
return gdb_get_reg64(mem_buf, env->regs[gpr_map[n]]);
|
||||||
|
} else if (n < CPU_NB_REGS32) {
|
||||||
|
return gdb_get_reg32(mem_buf, env->regs[gpr_map32[n]]);
|
||||||
|
}
|
||||||
|
} else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
|
||||||
|
#ifdef USE_X86LDOUBLE
|
||||||
|
/* FIXME: byteswap float values - after fixing fpregs layout. */
|
||||||
|
memcpy(mem_buf, &env->fpregs[n - IDX_FP_REGS], 10);
|
||||||
|
#else
|
||||||
|
memset(mem_buf, 0, 10);
|
||||||
|
#endif
|
||||||
|
return 10;
|
||||||
|
} else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
|
||||||
|
n -= IDX_XMM_REGS;
|
||||||
|
if (n < CPU_NB_REGS32 ||
|
||||||
|
(TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) {
|
||||||
|
stq_p(mem_buf, env->xmm_regs[n].XMM_Q(0));
|
||||||
|
stq_p(mem_buf + 8, env->xmm_regs[n].XMM_Q(1));
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (n) {
|
||||||
|
case IDX_IP_REG:
|
||||||
|
if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
|
||||||
|
return gdb_get_reg64(mem_buf, env->eip);
|
||||||
|
} else {
|
||||||
|
return gdb_get_reg32(mem_buf, env->eip);
|
||||||
|
}
|
||||||
|
case IDX_FLAGS_REG:
|
||||||
|
return gdb_get_reg32(mem_buf, env->eflags);
|
||||||
|
|
||||||
|
case IDX_SEG_REGS:
|
||||||
|
return gdb_get_reg32(mem_buf, env->segs[R_CS].selector);
|
||||||
|
case IDX_SEG_REGS + 1:
|
||||||
|
return gdb_get_reg32(mem_buf, env->segs[R_SS].selector);
|
||||||
|
case IDX_SEG_REGS + 2:
|
||||||
|
return gdb_get_reg32(mem_buf, env->segs[R_DS].selector);
|
||||||
|
case IDX_SEG_REGS + 3:
|
||||||
|
return gdb_get_reg32(mem_buf, env->segs[R_ES].selector);
|
||||||
|
case IDX_SEG_REGS + 4:
|
||||||
|
return gdb_get_reg32(mem_buf, env->segs[R_FS].selector);
|
||||||
|
case IDX_SEG_REGS + 5:
|
||||||
|
return gdb_get_reg32(mem_buf, env->segs[R_GS].selector);
|
||||||
|
|
||||||
|
case IDX_FP_REGS + 8:
|
||||||
|
return gdb_get_reg32(mem_buf, env->fpuc);
|
||||||
|
case IDX_FP_REGS + 9:
|
||||||
|
return gdb_get_reg32(mem_buf, (env->fpus & ~0x3800) |
|
||||||
|
(env->fpstt & 0x7) << 11);
|
||||||
|
case IDX_FP_REGS + 10:
|
||||||
|
return gdb_get_reg32(mem_buf, 0); /* ftag */
|
||||||
|
case IDX_FP_REGS + 11:
|
||||||
|
return gdb_get_reg32(mem_buf, 0); /* fiseg */
|
||||||
|
case IDX_FP_REGS + 12:
|
||||||
|
return gdb_get_reg32(mem_buf, 0); /* fioff */
|
||||||
|
case IDX_FP_REGS + 13:
|
||||||
|
return gdb_get_reg32(mem_buf, 0); /* foseg */
|
||||||
|
case IDX_FP_REGS + 14:
|
||||||
|
return gdb_get_reg32(mem_buf, 0); /* fooff */
|
||||||
|
case IDX_FP_REGS + 15:
|
||||||
|
return gdb_get_reg32(mem_buf, 0); /* fop */
|
||||||
|
|
||||||
|
case IDX_MXCSR_REG:
|
||||||
|
return gdb_get_reg32(mem_buf, env->mxcsr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int x86_cpu_gdb_load_seg(X86CPU *cpu, int sreg, uint8_t *mem_buf)
|
||||||
|
{
|
||||||
|
CPUX86State *env = &cpu->env;
|
||||||
|
uint16_t selector = ldl_p(mem_buf);
|
||||||
|
|
||||||
|
if (selector != env->segs[sreg].selector) {
|
||||||
|
#if defined(CONFIG_USER_ONLY)
|
||||||
|
cpu_x86_load_seg(env, sreg, selector);
|
||||||
|
#else
|
||||||
|
unsigned int limit, flags;
|
||||||
|
target_ulong base;
|
||||||
|
|
||||||
|
if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
|
||||||
|
base = selector << 4;
|
||||||
|
limit = 0xffff;
|
||||||
|
flags = 0;
|
||||||
|
} else {
|
||||||
|
if (!cpu_x86_get_descr_debug(env, selector, &base, &limit,
|
||||||
|
&flags)) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cpu_x86_load_seg_cache(env, sreg, selector, base, limit, flags);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
X86CPU *cpu = X86_CPU(cs);
|
||||||
|
CPUX86State *env = &cpu->env;
|
||||||
|
uint32_t tmp;
|
||||||
|
|
||||||
|
if (n < CPU_NB_REGS) {
|
||||||
|
if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
|
||||||
|
env->regs[gpr_map[n]] = ldtul_p(mem_buf);
|
||||||
|
return sizeof(target_ulong);
|
||||||
|
} else if (n < CPU_NB_REGS32) {
|
||||||
|
n = gpr_map32[n];
|
||||||
|
env->regs[n] &= ~0xffffffffUL;
|
||||||
|
env->regs[n] |= (uint32_t)ldl_p(mem_buf);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
} else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
|
||||||
|
#ifdef USE_X86LDOUBLE
|
||||||
|
/* FIXME: byteswap float values - after fixing fpregs layout. */
|
||||||
|
memcpy(&env->fpregs[n - IDX_FP_REGS], mem_buf, 10);
|
||||||
|
#endif
|
||||||
|
return 10;
|
||||||
|
} else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
|
||||||
|
n -= IDX_XMM_REGS;
|
||||||
|
if (n < CPU_NB_REGS32 ||
|
||||||
|
(TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK)) {
|
||||||
|
env->xmm_regs[n].XMM_Q(0) = ldq_p(mem_buf);
|
||||||
|
env->xmm_regs[n].XMM_Q(1) = ldq_p(mem_buf + 8);
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (n) {
|
||||||
|
case IDX_IP_REG:
|
||||||
|
if (TARGET_LONG_BITS == 64 && env->hflags & HF_CS64_MASK) {
|
||||||
|
env->eip = ldq_p(mem_buf);
|
||||||
|
return 8;
|
||||||
|
} else {
|
||||||
|
env->eip &= ~0xffffffffUL;
|
||||||
|
env->eip |= (uint32_t)ldl_p(mem_buf);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
case IDX_FLAGS_REG:
|
||||||
|
env->eflags = ldl_p(mem_buf);
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
case IDX_SEG_REGS:
|
||||||
|
return x86_cpu_gdb_load_seg(cpu, R_CS, mem_buf);
|
||||||
|
case IDX_SEG_REGS + 1:
|
||||||
|
return x86_cpu_gdb_load_seg(cpu, R_SS, mem_buf);
|
||||||
|
case IDX_SEG_REGS + 2:
|
||||||
|
return x86_cpu_gdb_load_seg(cpu, R_DS, mem_buf);
|
||||||
|
case IDX_SEG_REGS + 3:
|
||||||
|
return x86_cpu_gdb_load_seg(cpu, R_ES, mem_buf);
|
||||||
|
case IDX_SEG_REGS + 4:
|
||||||
|
return x86_cpu_gdb_load_seg(cpu, R_FS, mem_buf);
|
||||||
|
case IDX_SEG_REGS + 5:
|
||||||
|
return x86_cpu_gdb_load_seg(cpu, R_GS, mem_buf);
|
||||||
|
|
||||||
|
case IDX_FP_REGS + 8:
|
||||||
|
env->fpuc = ldl_p(mem_buf);
|
||||||
|
return 4;
|
||||||
|
case IDX_FP_REGS + 9:
|
||||||
|
tmp = ldl_p(mem_buf);
|
||||||
|
env->fpstt = (tmp >> 11) & 7;
|
||||||
|
env->fpus = tmp & ~0x3800;
|
||||||
|
return 4;
|
||||||
|
case IDX_FP_REGS + 10: /* ftag */
|
||||||
|
return 4;
|
||||||
|
case IDX_FP_REGS + 11: /* fiseg */
|
||||||
|
return 4;
|
||||||
|
case IDX_FP_REGS + 12: /* fioff */
|
||||||
|
return 4;
|
||||||
|
case IDX_FP_REGS + 13: /* foseg */
|
||||||
|
return 4;
|
||||||
|
case IDX_FP_REGS + 14: /* fooff */
|
||||||
|
return 4;
|
||||||
|
case IDX_FP_REGS + 15: /* fop */
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
case IDX_MXCSR_REG:
|
||||||
|
env->mxcsr = ldl_p(mem_buf);
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Unrecognised register. */
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1618,7 +1618,7 @@ static int kvm_guest_debug_workarounds(X86CPU *cpu)
|
|||||||
*/
|
*/
|
||||||
if (reinject_trap ||
|
if (reinject_trap ||
|
||||||
(!kvm_has_robust_singlestep() && cs->singlestep_enabled)) {
|
(!kvm_has_robust_singlestep() && cs->singlestep_enabled)) {
|
||||||
ret = kvm_update_guest_debug(env, reinject_trap);
|
ret = kvm_update_guest_debug(cs, reinject_trap);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
obj-y += translate.o op_helper.o helper.o cpu.o
|
obj-y += translate.o op_helper.o helper.o cpu.o
|
||||||
|
obj-y += gdbstub.o
|
||||||
obj-$(CONFIG_SOFTMMU) += machine.o
|
obj-$(CONFIG_SOFTMMU) += machine.o
|
||||||
|
@ -79,5 +79,7 @@ void lm32_cpu_do_interrupt(CPUState *cpu);
|
|||||||
void lm32_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
|
void lm32_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
|
||||||
int flags);
|
int flags);
|
||||||
hwaddr lm32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
hwaddr lm32_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||||
|
int lm32_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
int lm32_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -87,10 +87,13 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data)
|
|||||||
cc->do_interrupt = lm32_cpu_do_interrupt;
|
cc->do_interrupt = lm32_cpu_do_interrupt;
|
||||||
cc->dump_state = lm32_cpu_dump_state;
|
cc->dump_state = lm32_cpu_dump_state;
|
||||||
cc->set_pc = lm32_cpu_set_pc;
|
cc->set_pc = lm32_cpu_set_pc;
|
||||||
|
cc->gdb_read_register = lm32_cpu_gdb_read_register;
|
||||||
|
cc->gdb_write_register = lm32_cpu_gdb_write_register;
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
cc->get_phys_page_debug = lm32_cpu_get_phys_page_debug;
|
cc->get_phys_page_debug = lm32_cpu_get_phys_page_debug;
|
||||||
cc->vmsd = &vmstate_lm32_cpu;
|
cc->vmsd = &vmstate_lm32_cpu;
|
||||||
#endif
|
#endif
|
||||||
|
cc->gdb_num_core_regs = 32 + 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo lm32_cpu_type_info = {
|
static const TypeInfo lm32_cpu_type_info = {
|
||||||
|
92
target-lm32/gdbstub.c
Normal file
92
target-lm32/gdbstub.c
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* LM32 gdb server stub
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||||
|
* Copyright (c) 2013 SUSE LINUX Products GmbH
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "exec/gdbstub.h"
|
||||||
|
#include "hw/lm32/lm32_pic.h"
|
||||||
|
|
||||||
|
int lm32_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
LM32CPU *cpu = LM32_CPU(cs);
|
||||||
|
CPULM32State *env = &cpu->env;
|
||||||
|
|
||||||
|
if (n < 32) {
|
||||||
|
return gdb_get_reg32(mem_buf, env->regs[n]);
|
||||||
|
} else {
|
||||||
|
switch (n) {
|
||||||
|
case 32:
|
||||||
|
return gdb_get_reg32(mem_buf, env->pc);
|
||||||
|
/* FIXME: put in right exception ID */
|
||||||
|
case 33:
|
||||||
|
return gdb_get_reg32(mem_buf, 0);
|
||||||
|
case 34:
|
||||||
|
return gdb_get_reg32(mem_buf, env->eba);
|
||||||
|
case 35:
|
||||||
|
return gdb_get_reg32(mem_buf, env->deba);
|
||||||
|
case 36:
|
||||||
|
return gdb_get_reg32(mem_buf, env->ie);
|
||||||
|
case 37:
|
||||||
|
return gdb_get_reg32(mem_buf, lm32_pic_get_im(env->pic_state));
|
||||||
|
case 38:
|
||||||
|
return gdb_get_reg32(mem_buf, lm32_pic_get_ip(env->pic_state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lm32_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
LM32CPU *cpu = LM32_CPU(cs);
|
||||||
|
CPUClass *cc = CPU_GET_CLASS(cs);
|
||||||
|
CPULM32State *env = &cpu->env;
|
||||||
|
uint32_t tmp;
|
||||||
|
|
||||||
|
if (n > cc->gdb_num_core_regs) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = ldl_p(mem_buf);
|
||||||
|
|
||||||
|
if (n < 32) {
|
||||||
|
env->regs[n] = tmp;
|
||||||
|
} else {
|
||||||
|
switch (n) {
|
||||||
|
case 32:
|
||||||
|
env->pc = tmp;
|
||||||
|
break;
|
||||||
|
case 34:
|
||||||
|
env->eba = tmp;
|
||||||
|
break;
|
||||||
|
case 35:
|
||||||
|
env->deba = tmp;
|
||||||
|
break;
|
||||||
|
case 36:
|
||||||
|
env->ie = tmp;
|
||||||
|
break;
|
||||||
|
case 37:
|
||||||
|
lm32_pic_set_im(env->pic_state, tmp);
|
||||||
|
break;
|
||||||
|
case 38:
|
||||||
|
lm32_pic_set_ip(env->pic_state, tmp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 4;
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
obj-y += m68k-semi.o
|
obj-y += m68k-semi.o
|
||||||
obj-y += translate.o op_helper.o helper.o cpu.o
|
obj-y += translate.o op_helper.o helper.o cpu.o
|
||||||
|
obj-y += gdbstub.o
|
||||||
|
@ -74,5 +74,7 @@ void m68k_cpu_do_interrupt(CPUState *cpu);
|
|||||||
void m68k_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
|
void m68k_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
|
||||||
int flags);
|
int flags);
|
||||||
hwaddr m68k_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
hwaddr m68k_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||||
|
int m68k_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
int m68k_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -190,10 +190,14 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data)
|
|||||||
cc->do_interrupt = m68k_cpu_do_interrupt;
|
cc->do_interrupt = m68k_cpu_do_interrupt;
|
||||||
cc->dump_state = m68k_cpu_dump_state;
|
cc->dump_state = m68k_cpu_dump_state;
|
||||||
cc->set_pc = m68k_cpu_set_pc;
|
cc->set_pc = m68k_cpu_set_pc;
|
||||||
|
cc->gdb_read_register = m68k_cpu_gdb_read_register;
|
||||||
|
cc->gdb_write_register = m68k_cpu_gdb_write_register;
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
cc->get_phys_page_debug = m68k_cpu_get_phys_page_debug;
|
cc->get_phys_page_debug = m68k_cpu_get_phys_page_debug;
|
||||||
#endif
|
#endif
|
||||||
dc->vmsd = &vmstate_m68k_cpu;
|
dc->vmsd = &vmstate_m68k_cpu;
|
||||||
|
cc->gdb_num_core_regs = 18;
|
||||||
|
cc->gdb_core_xml_file = "cf-core.xml";
|
||||||
}
|
}
|
||||||
|
|
||||||
static void register_cpu_type(const M68kCPUInfo *info)
|
static void register_cpu_type(const M68kCPUInfo *info)
|
||||||
|
75
target-m68k/gdbstub.c
Normal file
75
target-m68k/gdbstub.c
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* m68k gdb server stub
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||||
|
* Copyright (c) 2013 SUSE LINUX Products GmbH
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
|
int m68k_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
M68kCPU *cpu = M68K_CPU(cs);
|
||||||
|
CPUM68KState *env = &cpu->env;
|
||||||
|
|
||||||
|
if (n < 8) {
|
||||||
|
/* D0-D7 */
|
||||||
|
return gdb_get_reg32(mem_buf, env->dregs[n]);
|
||||||
|
} else if (n < 16) {
|
||||||
|
/* A0-A7 */
|
||||||
|
return gdb_get_reg32(mem_buf, env->aregs[n - 8]);
|
||||||
|
} else {
|
||||||
|
switch (n) {
|
||||||
|
case 16:
|
||||||
|
return gdb_get_reg32(mem_buf, env->sr);
|
||||||
|
case 17:
|
||||||
|
return gdb_get_reg32(mem_buf, env->pc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* FP registers not included here because they vary between
|
||||||
|
ColdFire and m68k. Use XML bits for these. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int m68k_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
M68kCPU *cpu = M68K_CPU(cs);
|
||||||
|
CPUM68KState *env = &cpu->env;
|
||||||
|
uint32_t tmp;
|
||||||
|
|
||||||
|
tmp = ldl_p(mem_buf);
|
||||||
|
|
||||||
|
if (n < 8) {
|
||||||
|
/* D0-D7 */
|
||||||
|
env->dregs[n] = tmp;
|
||||||
|
} else if (n < 16) {
|
||||||
|
/* A0-A7 */
|
||||||
|
env->aregs[n - 8] = tmp;
|
||||||
|
} else {
|
||||||
|
switch (n) {
|
||||||
|
case 16:
|
||||||
|
env->sr = tmp;
|
||||||
|
break;
|
||||||
|
case 17:
|
||||||
|
env->pc = tmp;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 4;
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
obj-y += translate.o op_helper.o helper.o cpu.o
|
obj-y += translate.o op_helper.o helper.o cpu.o
|
||||||
|
obj-y += gdbstub.o
|
||||||
obj-$(CONFIG_SOFTMMU) += mmu.o
|
obj-$(CONFIG_SOFTMMU) += mmu.o
|
||||||
|
@ -75,5 +75,7 @@ void mb_cpu_do_interrupt(CPUState *cs);
|
|||||||
void mb_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
|
void mb_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
|
||||||
int flags);
|
int flags);
|
||||||
hwaddr mb_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
hwaddr mb_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||||
|
int mb_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
int mb_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -141,12 +141,15 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data)
|
|||||||
cc->do_interrupt = mb_cpu_do_interrupt;
|
cc->do_interrupt = mb_cpu_do_interrupt;
|
||||||
cc->dump_state = mb_cpu_dump_state;
|
cc->dump_state = mb_cpu_dump_state;
|
||||||
cc->set_pc = mb_cpu_set_pc;
|
cc->set_pc = mb_cpu_set_pc;
|
||||||
|
cc->gdb_read_register = mb_cpu_gdb_read_register;
|
||||||
|
cc->gdb_write_register = mb_cpu_gdb_write_register;
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
cc->do_unassigned_access = mb_cpu_unassigned_access;
|
cc->do_unassigned_access = mb_cpu_unassigned_access;
|
||||||
cc->get_phys_page_debug = mb_cpu_get_phys_page_debug;
|
cc->get_phys_page_debug = mb_cpu_get_phys_page_debug;
|
||||||
#endif
|
#endif
|
||||||
dc->vmsd = &vmstate_mb_cpu;
|
dc->vmsd = &vmstate_mb_cpu;
|
||||||
dc->props = mb_properties;
|
dc->props = mb_properties;
|
||||||
|
cc->gdb_num_core_regs = 32 + 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo mb_cpu_type_info = {
|
static const TypeInfo mb_cpu_type_info = {
|
||||||
|
56
target-microblaze/gdbstub.c
Normal file
56
target-microblaze/gdbstub.c
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* MicroBlaze gdb server stub
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||||
|
* Copyright (c) 2013 SUSE LINUX Products GmbH
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
|
int mb_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||||
|
CPUMBState *env = &cpu->env;
|
||||||
|
|
||||||
|
if (n < 32) {
|
||||||
|
return gdb_get_reg32(mem_buf, env->regs[n]);
|
||||||
|
} else {
|
||||||
|
return gdb_get_reg32(mem_buf, env->sregs[n - 32]);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mb_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||||
|
CPUClass *cc = CPU_GET_CLASS(cs);
|
||||||
|
CPUMBState *env = &cpu->env;
|
||||||
|
uint32_t tmp;
|
||||||
|
|
||||||
|
if (n > cc->gdb_num_core_regs) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = ldl_p(mem_buf);
|
||||||
|
|
||||||
|
if (n < 32) {
|
||||||
|
env->regs[n] = tmp;
|
||||||
|
} else {
|
||||||
|
env->sregs[n - 32] = tmp;
|
||||||
|
}
|
||||||
|
return 4;
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o
|
obj-y += translate.o dsp_helper.o op_helper.o lmi_helper.o helper.o cpu.o
|
||||||
|
obj-y += gdbstub.o
|
||||||
obj-$(CONFIG_SOFTMMU) += machine.o
|
obj-$(CONFIG_SOFTMMU) += machine.o
|
||||||
|
@ -78,5 +78,7 @@ void mips_cpu_do_interrupt(CPUState *cpu);
|
|||||||
void mips_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
|
void mips_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
|
||||||
int flags);
|
int flags);
|
||||||
hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||||
|
int mips_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -100,10 +100,14 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
|
|||||||
cc->dump_state = mips_cpu_dump_state;
|
cc->dump_state = mips_cpu_dump_state;
|
||||||
cc->set_pc = mips_cpu_set_pc;
|
cc->set_pc = mips_cpu_set_pc;
|
||||||
cc->synchronize_from_tb = mips_cpu_synchronize_from_tb;
|
cc->synchronize_from_tb = mips_cpu_synchronize_from_tb;
|
||||||
|
cc->gdb_read_register = mips_cpu_gdb_read_register;
|
||||||
|
cc->gdb_write_register = mips_cpu_gdb_write_register;
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
cc->do_unassigned_access = mips_cpu_unassigned_access;
|
cc->do_unassigned_access = mips_cpu_unassigned_access;
|
||||||
cc->get_phys_page_debug = mips_cpu_get_phys_page_debug;
|
cc->get_phys_page_debug = mips_cpu_get_phys_page_debug;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
cc->gdb_num_core_regs = 73;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo mips_cpu_type_info = {
|
static const TypeInfo mips_cpu_type_info = {
|
||||||
|
155
target-mips/gdbstub.c
Normal file
155
target-mips/gdbstub.c
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* MIPS gdb server stub
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||||
|
* Copyright (c) 2013 SUSE LINUX Products GmbH
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
|
int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
MIPSCPU *cpu = MIPS_CPU(cs);
|
||||||
|
CPUMIPSState *env = &cpu->env;
|
||||||
|
|
||||||
|
if (n < 32) {
|
||||||
|
return gdb_get_regl(mem_buf, env->active_tc.gpr[n]);
|
||||||
|
}
|
||||||
|
if (env->CP0_Config1 & (1 << CP0C1_FP)) {
|
||||||
|
if (n >= 38 && n < 70) {
|
||||||
|
if (env->CP0_Status & (1 << CP0St_FR)) {
|
||||||
|
return gdb_get_regl(mem_buf,
|
||||||
|
env->active_fpu.fpr[n - 38].d);
|
||||||
|
} else {
|
||||||
|
return gdb_get_regl(mem_buf,
|
||||||
|
env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (n) {
|
||||||
|
case 70:
|
||||||
|
return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr31);
|
||||||
|
case 71:
|
||||||
|
return gdb_get_regl(mem_buf, (int32_t)env->active_fpu.fcr0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (n) {
|
||||||
|
case 32:
|
||||||
|
return gdb_get_regl(mem_buf, (int32_t)env->CP0_Status);
|
||||||
|
case 33:
|
||||||
|
return gdb_get_regl(mem_buf, env->active_tc.LO[0]);
|
||||||
|
case 34:
|
||||||
|
return gdb_get_regl(mem_buf, env->active_tc.HI[0]);
|
||||||
|
case 35:
|
||||||
|
return gdb_get_regl(mem_buf, env->CP0_BadVAddr);
|
||||||
|
case 36:
|
||||||
|
return gdb_get_regl(mem_buf, (int32_t)env->CP0_Cause);
|
||||||
|
case 37:
|
||||||
|
return gdb_get_regl(mem_buf, env->active_tc.PC |
|
||||||
|
!!(env->hflags & MIPS_HFLAG_M16));
|
||||||
|
case 72:
|
||||||
|
return gdb_get_regl(mem_buf, 0); /* fp */
|
||||||
|
case 89:
|
||||||
|
return gdb_get_regl(mem_buf, (int32_t)env->CP0_PRid);
|
||||||
|
}
|
||||||
|
if (n >= 73 && n <= 88) {
|
||||||
|
/* 16 embedded regs. */
|
||||||
|
return gdb_get_regl(mem_buf, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert MIPS rounding mode in FCR31 to IEEE library */
|
||||||
|
static unsigned int ieee_rm[] = {
|
||||||
|
float_round_nearest_even,
|
||||||
|
float_round_to_zero,
|
||||||
|
float_round_up,
|
||||||
|
float_round_down
|
||||||
|
};
|
||||||
|
#define RESTORE_ROUNDING_MODE \
|
||||||
|
set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], \
|
||||||
|
&env->active_fpu.fp_status)
|
||||||
|
|
||||||
|
int mips_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
MIPSCPU *cpu = MIPS_CPU(cs);
|
||||||
|
CPUMIPSState *env = &cpu->env;
|
||||||
|
target_ulong tmp;
|
||||||
|
|
||||||
|
tmp = ldtul_p(mem_buf);
|
||||||
|
|
||||||
|
if (n < 32) {
|
||||||
|
env->active_tc.gpr[n] = tmp;
|
||||||
|
return sizeof(target_ulong);
|
||||||
|
}
|
||||||
|
if (env->CP0_Config1 & (1 << CP0C1_FP)
|
||||||
|
&& n >= 38 && n < 73) {
|
||||||
|
if (n < 70) {
|
||||||
|
if (env->CP0_Status & (1 << CP0St_FR)) {
|
||||||
|
env->active_fpu.fpr[n - 38].d = tmp;
|
||||||
|
} else {
|
||||||
|
env->active_fpu.fpr[n - 38].w[FP_ENDIAN_IDX] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (n) {
|
||||||
|
case 70:
|
||||||
|
env->active_fpu.fcr31 = tmp & 0xFF83FFFF;
|
||||||
|
/* set rounding mode */
|
||||||
|
RESTORE_ROUNDING_MODE;
|
||||||
|
break;
|
||||||
|
case 71:
|
||||||
|
env->active_fpu.fcr0 = tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return sizeof(target_ulong);
|
||||||
|
}
|
||||||
|
switch (n) {
|
||||||
|
case 32:
|
||||||
|
env->CP0_Status = tmp;
|
||||||
|
break;
|
||||||
|
case 33:
|
||||||
|
env->active_tc.LO[0] = tmp;
|
||||||
|
break;
|
||||||
|
case 34:
|
||||||
|
env->active_tc.HI[0] = tmp;
|
||||||
|
break;
|
||||||
|
case 35:
|
||||||
|
env->CP0_BadVAddr = tmp;
|
||||||
|
break;
|
||||||
|
case 36:
|
||||||
|
env->CP0_Cause = tmp;
|
||||||
|
break;
|
||||||
|
case 37:
|
||||||
|
env->active_tc.PC = tmp & ~(target_ulong)1;
|
||||||
|
if (tmp & 1) {
|
||||||
|
env->hflags |= MIPS_HFLAG_M16;
|
||||||
|
} else {
|
||||||
|
env->hflags &= ~(MIPS_HFLAG_M16);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 72: /* fp, ignored */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (n > 89) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* Other registers are readonly. Ignore writes. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sizeof(target_ulong);
|
||||||
|
}
|
@ -2,3 +2,4 @@ obj-$(CONFIG_SOFTMMU) += machine.o
|
|||||||
obj-y += cpu.o exception.o interrupt.o mmu.o translate.o
|
obj-y += cpu.o exception.o interrupt.o mmu.o translate.o
|
||||||
obj-y += exception_helper.o fpu_helper.o int_helper.o \
|
obj-y += exception_helper.o fpu_helper.o int_helper.o \
|
||||||
interrupt_helper.o mmu_helper.o sys_helper.o
|
interrupt_helper.o mmu_helper.o sys_helper.o
|
||||||
|
obj-y += gdbstub.o
|
||||||
|
@ -155,10 +155,13 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data)
|
|||||||
cc->do_interrupt = openrisc_cpu_do_interrupt;
|
cc->do_interrupt = openrisc_cpu_do_interrupt;
|
||||||
cc->dump_state = openrisc_cpu_dump_state;
|
cc->dump_state = openrisc_cpu_dump_state;
|
||||||
cc->set_pc = openrisc_cpu_set_pc;
|
cc->set_pc = openrisc_cpu_set_pc;
|
||||||
|
cc->gdb_read_register = openrisc_cpu_gdb_read_register;
|
||||||
|
cc->gdb_write_register = openrisc_cpu_gdb_write_register;
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
cc->get_phys_page_debug = openrisc_cpu_get_phys_page_debug;
|
cc->get_phys_page_debug = openrisc_cpu_get_phys_page_debug;
|
||||||
dc->vmsd = &vmstate_openrisc_cpu;
|
dc->vmsd = &vmstate_openrisc_cpu;
|
||||||
#endif
|
#endif
|
||||||
|
cc->gdb_num_core_regs = 32 + 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cpu_register(const OpenRISCCPUInfo *info)
|
static void cpu_register(const OpenRISCCPUInfo *info)
|
||||||
|
@ -350,6 +350,8 @@ void openrisc_cpu_do_interrupt(CPUState *cpu);
|
|||||||
void openrisc_cpu_dump_state(CPUState *cpu, FILE *f,
|
void openrisc_cpu_dump_state(CPUState *cpu, FILE *f,
|
||||||
fprintf_function cpu_fprintf, int flags);
|
fprintf_function cpu_fprintf, int flags);
|
||||||
hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||||
|
int openrisc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
int openrisc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
void openrisc_translate_init(void);
|
void openrisc_translate_init(void);
|
||||||
int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
|
int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
|
||||||
target_ulong address,
|
target_ulong address,
|
||||||
|
83
target-openrisc/gdbstub.c
Normal file
83
target-openrisc/gdbstub.c
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* OpenRISC gdb server stub
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||||
|
* Copyright (c) 2013 SUSE LINUX Products GmbH
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
|
int openrisc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
OpenRISCCPU *cpu = OPENRISC_CPU(cs);
|
||||||
|
CPUOpenRISCState *env = &cpu->env;
|
||||||
|
|
||||||
|
if (n < 32) {
|
||||||
|
return gdb_get_reg32(mem_buf, env->gpr[n]);
|
||||||
|
} else {
|
||||||
|
switch (n) {
|
||||||
|
case 32: /* PPC */
|
||||||
|
return gdb_get_reg32(mem_buf, env->ppc);
|
||||||
|
|
||||||
|
case 33: /* NPC */
|
||||||
|
return gdb_get_reg32(mem_buf, env->npc);
|
||||||
|
|
||||||
|
case 34: /* SR */
|
||||||
|
return gdb_get_reg32(mem_buf, env->sr);
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int openrisc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
OpenRISCCPU *cpu = OPENRISC_CPU(cs);
|
||||||
|
CPUClass *cc = CPU_GET_CLASS(cs);
|
||||||
|
CPUOpenRISCState *env = &cpu->env;
|
||||||
|
uint32_t tmp;
|
||||||
|
|
||||||
|
if (n > cc->gdb_num_core_regs) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = ldl_p(mem_buf);
|
||||||
|
|
||||||
|
if (n < 32) {
|
||||||
|
env->gpr[n] = tmp;
|
||||||
|
} else {
|
||||||
|
switch (n) {
|
||||||
|
case 32: /* PPC */
|
||||||
|
env->ppc = tmp;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 33: /* NPC */
|
||||||
|
env->npc = tmp;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 34: /* SR */
|
||||||
|
env->sr = tmp;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 4;
|
||||||
|
}
|
@ -13,3 +13,4 @@ obj-y += timebase_helper.o
|
|||||||
obj-y += misc_helper.o
|
obj-y += misc_helper.o
|
||||||
obj-y += mem_helper.o
|
obj-y += mem_helper.o
|
||||||
obj-$(CONFIG_USER_ONLY) += user_only_helper.o
|
obj-$(CONFIG_USER_ONLY) += user_only_helper.o
|
||||||
|
obj-y += gdbstub.o
|
||||||
|
@ -106,5 +106,7 @@ void ppc_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
|
|||||||
void ppc_cpu_dump_statistics(CPUState *cpu, FILE *f,
|
void ppc_cpu_dump_statistics(CPUState *cpu, FILE *f,
|
||||||
fprintf_function cpu_fprintf, int flags);
|
fprintf_function cpu_fprintf, int flags);
|
||||||
hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
hwaddr ppc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||||
|
int ppc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
131
target-ppc/gdbstub.c
Normal file
131
target-ppc/gdbstub.c
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* PowerPC gdb server stub
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||||
|
* Copyright (c) 2013 SUSE LINUX Products GmbH
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
|
/* Old gdb always expects FP registers. Newer (xml-aware) gdb only
|
||||||
|
* expects whatever the target description contains. Due to a
|
||||||
|
* historical mishap the FP registers appear in between core integer
|
||||||
|
* regs and PC, MSR, CR, and so forth. We hack round this by giving the
|
||||||
|
* FP regs zero size when talking to a newer gdb.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||||
|
CPUPPCState *env = &cpu->env;
|
||||||
|
|
||||||
|
if (n < 32) {
|
||||||
|
/* gprs */
|
||||||
|
return gdb_get_regl(mem_buf, env->gpr[n]);
|
||||||
|
} else if (n < 64) {
|
||||||
|
/* fprs */
|
||||||
|
if (gdb_has_xml) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
stfq_p(mem_buf, env->fpr[n-32]);
|
||||||
|
return 8;
|
||||||
|
} else {
|
||||||
|
switch (n) {
|
||||||
|
case 64:
|
||||||
|
return gdb_get_regl(mem_buf, env->nip);
|
||||||
|
case 65:
|
||||||
|
return gdb_get_regl(mem_buf, env->msr);
|
||||||
|
case 66:
|
||||||
|
{
|
||||||
|
uint32_t cr = 0;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
cr |= env->crf[i] << (32 - ((i + 1) * 4));
|
||||||
|
}
|
||||||
|
return gdb_get_reg32(mem_buf, cr);
|
||||||
|
}
|
||||||
|
case 67:
|
||||||
|
return gdb_get_regl(mem_buf, env->lr);
|
||||||
|
case 68:
|
||||||
|
return gdb_get_regl(mem_buf, env->ctr);
|
||||||
|
case 69:
|
||||||
|
return gdb_get_regl(mem_buf, env->xer);
|
||||||
|
case 70:
|
||||||
|
{
|
||||||
|
if (gdb_has_xml) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return gdb_get_reg32(mem_buf, env->fpscr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||||
|
CPUPPCState *env = &cpu->env;
|
||||||
|
|
||||||
|
if (n < 32) {
|
||||||
|
/* gprs */
|
||||||
|
env->gpr[n] = ldtul_p(mem_buf);
|
||||||
|
return sizeof(target_ulong);
|
||||||
|
} else if (n < 64) {
|
||||||
|
/* fprs */
|
||||||
|
if (gdb_has_xml) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
env->fpr[n-32] = ldfq_p(mem_buf);
|
||||||
|
return 8;
|
||||||
|
} else {
|
||||||
|
switch (n) {
|
||||||
|
case 64:
|
||||||
|
env->nip = ldtul_p(mem_buf);
|
||||||
|
return sizeof(target_ulong);
|
||||||
|
case 65:
|
||||||
|
ppc_store_msr(env, ldtul_p(mem_buf));
|
||||||
|
return sizeof(target_ulong);
|
||||||
|
case 66:
|
||||||
|
{
|
||||||
|
uint32_t cr = ldl_p(mem_buf);
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
env->crf[i] = (cr >> (32 - ((i + 1) * 4))) & 0xF;
|
||||||
|
}
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
case 67:
|
||||||
|
env->lr = ldtul_p(mem_buf);
|
||||||
|
return sizeof(target_ulong);
|
||||||
|
case 68:
|
||||||
|
env->ctr = ldtul_p(mem_buf);
|
||||||
|
return sizeof(target_ulong);
|
||||||
|
case 69:
|
||||||
|
env->xer = ldtul_p(mem_buf);
|
||||||
|
return sizeof(target_ulong);
|
||||||
|
case 70:
|
||||||
|
/* fpscr */
|
||||||
|
if (gdb_has_xml) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
store_fpscr(env, ldtul_p(mem_buf), 0xffffffff);
|
||||||
|
return sizeof(target_ulong);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
@ -8458,9 +8458,18 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
|
|||||||
cc->dump_state = ppc_cpu_dump_state;
|
cc->dump_state = ppc_cpu_dump_state;
|
||||||
cc->dump_statistics = ppc_cpu_dump_statistics;
|
cc->dump_statistics = ppc_cpu_dump_statistics;
|
||||||
cc->set_pc = ppc_cpu_set_pc;
|
cc->set_pc = ppc_cpu_set_pc;
|
||||||
|
cc->gdb_read_register = ppc_cpu_gdb_read_register;
|
||||||
|
cc->gdb_write_register = ppc_cpu_gdb_write_register;
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
cc->get_phys_page_debug = ppc_cpu_get_phys_page_debug;
|
cc->get_phys_page_debug = ppc_cpu_get_phys_page_debug;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
cc->gdb_num_core_regs = 71;
|
||||||
|
#if defined(TARGET_PPC64)
|
||||||
|
cc->gdb_core_xml_file = "power64-core.xml";
|
||||||
|
#else
|
||||||
|
cc->gdb_core_xml_file = "power-core.xml";
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo ppc_cpu_type_info = {
|
static const TypeInfo ppc_cpu_type_info = {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
obj-y += translate.o helper.o cpu.o interrupt.o
|
obj-y += translate.o helper.o cpu.o interrupt.o
|
||||||
obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o
|
obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o
|
||||||
|
obj-y += gdbstub.o
|
||||||
obj-$(CONFIG_SOFTMMU) += ioinst.o
|
obj-$(CONFIG_SOFTMMU) += ioinst.o
|
||||||
obj-$(CONFIG_KVM) += kvm.o
|
obj-$(CONFIG_KVM) += kvm.o
|
||||||
|
@ -75,5 +75,7 @@ void s390_cpu_do_interrupt(CPUState *cpu);
|
|||||||
void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
|
void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
|
||||||
int flags);
|
int flags);
|
||||||
hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||||
|
int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -173,10 +173,13 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
|
|||||||
cc->do_interrupt = s390_cpu_do_interrupt;
|
cc->do_interrupt = s390_cpu_do_interrupt;
|
||||||
cc->dump_state = s390_cpu_dump_state;
|
cc->dump_state = s390_cpu_dump_state;
|
||||||
cc->set_pc = s390_cpu_set_pc;
|
cc->set_pc = s390_cpu_set_pc;
|
||||||
|
cc->gdb_read_register = s390_cpu_gdb_read_register;
|
||||||
|
cc->gdb_write_register = s390_cpu_gdb_write_register;
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
cc->get_phys_page_debug = s390_cpu_get_phys_page_debug;
|
cc->get_phys_page_debug = s390_cpu_get_phys_page_debug;
|
||||||
#endif
|
#endif
|
||||||
dc->vmsd = &vmstate_s390_cpu;
|
dc->vmsd = &vmstate_s390_cpu;
|
||||||
|
cc->gdb_num_core_regs = S390_NUM_REGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo s390_cpu_type_info = {
|
static const TypeInfo s390_cpu_type_info = {
|
||||||
|
88
target-s390x/gdbstub.c
Normal file
88
target-s390x/gdbstub.c
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* s390x gdb server stub
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||||
|
* Copyright (c) 2013 SUSE LINUX Products GmbH
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "exec/gdbstub.h"
|
||||||
|
#include "qemu/bitops.h"
|
||||||
|
|
||||||
|
int s390_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
S390CPU *cpu = S390_CPU(cs);
|
||||||
|
CPUS390XState *env = &cpu->env;
|
||||||
|
uint64_t val;
|
||||||
|
int cc_op;
|
||||||
|
|
||||||
|
switch (n) {
|
||||||
|
case S390_PSWM_REGNUM:
|
||||||
|
cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr);
|
||||||
|
val = deposit64(env->psw.mask, 44, 2, cc_op);
|
||||||
|
return gdb_get_regl(mem_buf, val);
|
||||||
|
case S390_PSWA_REGNUM:
|
||||||
|
return gdb_get_regl(mem_buf, env->psw.addr);
|
||||||
|
case S390_R0_REGNUM ... S390_R15_REGNUM:
|
||||||
|
return gdb_get_regl(mem_buf, env->regs[n-S390_R0_REGNUM]);
|
||||||
|
case S390_A0_REGNUM ... S390_A15_REGNUM:
|
||||||
|
return gdb_get_reg32(mem_buf, env->aregs[n-S390_A0_REGNUM]);
|
||||||
|
case S390_FPC_REGNUM:
|
||||||
|
return gdb_get_reg32(mem_buf, env->fpc);
|
||||||
|
case S390_F0_REGNUM ... S390_F15_REGNUM:
|
||||||
|
return gdb_get_reg64(mem_buf, env->fregs[n-S390_F0_REGNUM].ll);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int s390_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
S390CPU *cpu = S390_CPU(cs);
|
||||||
|
CPUS390XState *env = &cpu->env;
|
||||||
|
target_ulong tmpl;
|
||||||
|
uint32_t tmp32;
|
||||||
|
int r = 8;
|
||||||
|
tmpl = ldtul_p(mem_buf);
|
||||||
|
tmp32 = ldl_p(mem_buf);
|
||||||
|
|
||||||
|
switch (n) {
|
||||||
|
case S390_PSWM_REGNUM:
|
||||||
|
env->psw.mask = tmpl;
|
||||||
|
env->cc_op = extract64(tmpl, 44, 2);
|
||||||
|
break;
|
||||||
|
case S390_PSWA_REGNUM:
|
||||||
|
env->psw.addr = tmpl;
|
||||||
|
break;
|
||||||
|
case S390_R0_REGNUM ... S390_R15_REGNUM:
|
||||||
|
env->regs[n-S390_R0_REGNUM] = tmpl;
|
||||||
|
break;
|
||||||
|
case S390_A0_REGNUM ... S390_A15_REGNUM:
|
||||||
|
env->aregs[n-S390_A0_REGNUM] = tmp32;
|
||||||
|
r = 4;
|
||||||
|
break;
|
||||||
|
case S390_FPC_REGNUM:
|
||||||
|
env->fpc = tmp32;
|
||||||
|
r = 4;
|
||||||
|
break;
|
||||||
|
case S390_F0_REGNUM ... S390_F15_REGNUM:
|
||||||
|
env->fregs[n-S390_F0_REGNUM].ll = tmpl;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
@ -345,12 +345,10 @@ void *kvm_arch_ram_alloc(ram_addr_t size)
|
|||||||
|
|
||||||
int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
|
int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
|
||||||
{
|
{
|
||||||
S390CPU *cpu = S390_CPU(cs);
|
|
||||||
CPUS390XState *env = &cpu->env;
|
|
||||||
static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
|
static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
|
||||||
|
|
||||||
if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
|
if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
|
||||||
cpu_memory_rw_debug(env, bp->pc, (uint8_t *)diag_501, 4, 1)) {
|
cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)diag_501, 4, 1)) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -358,16 +356,14 @@ int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
|
|||||||
|
|
||||||
int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
|
int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
|
||||||
{
|
{
|
||||||
S390CPU *cpu = S390_CPU(cs);
|
|
||||||
CPUS390XState *env = &cpu->env;
|
|
||||||
uint8_t t[4];
|
uint8_t t[4];
|
||||||
static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
|
static const uint8_t diag_501[] = {0x83, 0x24, 0x05, 0x01};
|
||||||
|
|
||||||
if (cpu_memory_rw_debug(env, bp->pc, t, 4, 0)) {
|
if (cpu_memory_rw_debug(cs, bp->pc, t, 4, 0)) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
} else if (memcmp(t, diag_501, 4)) {
|
} else if (memcmp(t, diag_501, 4)) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
} else if (cpu_memory_rw_debug(env, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) {
|
} else if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1 +1,2 @@
|
|||||||
obj-y += translate.o op_helper.o helper.o cpu.o
|
obj-y += translate.o op_helper.o helper.o cpu.o
|
||||||
|
obj-y += gdbstub.o
|
||||||
|
@ -87,5 +87,7 @@ void superh_cpu_do_interrupt(CPUState *cpu);
|
|||||||
void superh_cpu_dump_state(CPUState *cpu, FILE *f,
|
void superh_cpu_dump_state(CPUState *cpu, FILE *f,
|
||||||
fprintf_function cpu_fprintf, int flags);
|
fprintf_function cpu_fprintf, int flags);
|
||||||
hwaddr superh_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
hwaddr superh_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||||
|
int superh_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
int superh_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -286,10 +286,13 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data)
|
|||||||
cc->dump_state = superh_cpu_dump_state;
|
cc->dump_state = superh_cpu_dump_state;
|
||||||
cc->set_pc = superh_cpu_set_pc;
|
cc->set_pc = superh_cpu_set_pc;
|
||||||
cc->synchronize_from_tb = superh_cpu_synchronize_from_tb;
|
cc->synchronize_from_tb = superh_cpu_synchronize_from_tb;
|
||||||
|
cc->gdb_read_register = superh_cpu_gdb_read_register;
|
||||||
|
cc->gdb_write_register = superh_cpu_gdb_write_register;
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
cc->get_phys_page_debug = superh_cpu_get_phys_page_debug;
|
cc->get_phys_page_debug = superh_cpu_get_phys_page_debug;
|
||||||
#endif
|
#endif
|
||||||
dc->vmsd = &vmstate_sh_cpu;
|
dc->vmsd = &vmstate_sh_cpu;
|
||||||
|
cc->gdb_num_core_regs = 59;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo superh_cpu_type_info = {
|
static const TypeInfo superh_cpu_type_info = {
|
||||||
|
146
target-sh4/gdbstub.c
Normal file
146
target-sh4/gdbstub.c
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* SuperH gdb server stub
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||||
|
* Copyright (c) 2013 SUSE LINUX Products GmbH
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
|
/* Hint: Use "set architecture sh4" in GDB to see fpu registers */
|
||||||
|
/* FIXME: We should use XML for this. */
|
||||||
|
|
||||||
|
int superh_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
SuperHCPU *cpu = SUPERH_CPU(cs);
|
||||||
|
CPUSH4State *env = &cpu->env;
|
||||||
|
|
||||||
|
switch (n) {
|
||||||
|
case 0 ... 7:
|
||||||
|
if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
|
||||||
|
return gdb_get_regl(mem_buf, env->gregs[n + 16]);
|
||||||
|
} else {
|
||||||
|
return gdb_get_regl(mem_buf, env->gregs[n]);
|
||||||
|
}
|
||||||
|
case 8 ... 15:
|
||||||
|
return gdb_get_regl(mem_buf, env->gregs[n]);
|
||||||
|
case 16:
|
||||||
|
return gdb_get_regl(mem_buf, env->pc);
|
||||||
|
case 17:
|
||||||
|
return gdb_get_regl(mem_buf, env->pr);
|
||||||
|
case 18:
|
||||||
|
return gdb_get_regl(mem_buf, env->gbr);
|
||||||
|
case 19:
|
||||||
|
return gdb_get_regl(mem_buf, env->vbr);
|
||||||
|
case 20:
|
||||||
|
return gdb_get_regl(mem_buf, env->mach);
|
||||||
|
case 21:
|
||||||
|
return gdb_get_regl(mem_buf, env->macl);
|
||||||
|
case 22:
|
||||||
|
return gdb_get_regl(mem_buf, env->sr);
|
||||||
|
case 23:
|
||||||
|
return gdb_get_regl(mem_buf, env->fpul);
|
||||||
|
case 24:
|
||||||
|
return gdb_get_regl(mem_buf, env->fpscr);
|
||||||
|
case 25 ... 40:
|
||||||
|
if (env->fpscr & FPSCR_FR) {
|
||||||
|
stfl_p(mem_buf, env->fregs[n - 9]);
|
||||||
|
} else {
|
||||||
|
stfl_p(mem_buf, env->fregs[n - 25]);
|
||||||
|
}
|
||||||
|
return 4;
|
||||||
|
case 41:
|
||||||
|
return gdb_get_regl(mem_buf, env->ssr);
|
||||||
|
case 42:
|
||||||
|
return gdb_get_regl(mem_buf, env->spc);
|
||||||
|
case 43 ... 50:
|
||||||
|
return gdb_get_regl(mem_buf, env->gregs[n - 43]);
|
||||||
|
case 51 ... 58:
|
||||||
|
return gdb_get_regl(mem_buf, env->gregs[n - (51 - 16)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int superh_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
SuperHCPU *cpu = SUPERH_CPU(cs);
|
||||||
|
CPUSH4State *env = &cpu->env;
|
||||||
|
|
||||||
|
switch (n) {
|
||||||
|
case 0 ... 7:
|
||||||
|
if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) {
|
||||||
|
env->gregs[n + 16] = ldl_p(mem_buf);
|
||||||
|
} else {
|
||||||
|
env->gregs[n] = ldl_p(mem_buf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 8 ... 15:
|
||||||
|
env->gregs[n] = ldl_p(mem_buf);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
env->pc = ldl_p(mem_buf);
|
||||||
|
break;
|
||||||
|
case 17:
|
||||||
|
env->pr = ldl_p(mem_buf);
|
||||||
|
break;
|
||||||
|
case 18:
|
||||||
|
env->gbr = ldl_p(mem_buf);
|
||||||
|
break;
|
||||||
|
case 19:
|
||||||
|
env->vbr = ldl_p(mem_buf);
|
||||||
|
break;
|
||||||
|
case 20:
|
||||||
|
env->mach = ldl_p(mem_buf);
|
||||||
|
break;
|
||||||
|
case 21:
|
||||||
|
env->macl = ldl_p(mem_buf);
|
||||||
|
break;
|
||||||
|
case 22:
|
||||||
|
env->sr = ldl_p(mem_buf);
|
||||||
|
break;
|
||||||
|
case 23:
|
||||||
|
env->fpul = ldl_p(mem_buf);
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
env->fpscr = ldl_p(mem_buf);
|
||||||
|
break;
|
||||||
|
case 25 ... 40:
|
||||||
|
if (env->fpscr & FPSCR_FR) {
|
||||||
|
env->fregs[n - 9] = ldfl_p(mem_buf);
|
||||||
|
} else {
|
||||||
|
env->fregs[n - 25] = ldfl_p(mem_buf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 41:
|
||||||
|
env->ssr = ldl_p(mem_buf);
|
||||||
|
break;
|
||||||
|
case 42:
|
||||||
|
env->spc = ldl_p(mem_buf);
|
||||||
|
break;
|
||||||
|
case 43 ... 50:
|
||||||
|
env->gregs[n - 43] = ldl_p(mem_buf);
|
||||||
|
break;
|
||||||
|
case 51 ... 58:
|
||||||
|
env->gregs[n - (51 - 16)] = ldl_p(mem_buf);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
}
|
@ -4,3 +4,4 @@ obj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o
|
|||||||
obj-$(TARGET_SPARC) += int32_helper.o
|
obj-$(TARGET_SPARC) += int32_helper.o
|
||||||
obj-$(TARGET_SPARC64) += int64_helper.o
|
obj-$(TARGET_SPARC64) += int64_helper.o
|
||||||
obj-$(TARGET_SPARC64) += vis_helper.o
|
obj-$(TARGET_SPARC64) += vis_helper.o
|
||||||
|
obj-y += gdbstub.o
|
||||||
|
@ -79,5 +79,7 @@ void sparc_cpu_do_interrupt(CPUState *cpu);
|
|||||||
void sparc_cpu_dump_state(CPUState *cpu, FILE *f,
|
void sparc_cpu_dump_state(CPUState *cpu, FILE *f,
|
||||||
fprintf_function cpu_fprintf, int flags);
|
fprintf_function cpu_fprintf, int flags);
|
||||||
hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
hwaddr sparc_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||||
|
int sparc_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
int sparc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -787,10 +787,18 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data)
|
|||||||
#endif
|
#endif
|
||||||
cc->set_pc = sparc_cpu_set_pc;
|
cc->set_pc = sparc_cpu_set_pc;
|
||||||
cc->synchronize_from_tb = sparc_cpu_synchronize_from_tb;
|
cc->synchronize_from_tb = sparc_cpu_synchronize_from_tb;
|
||||||
|
cc->gdb_read_register = sparc_cpu_gdb_read_register;
|
||||||
|
cc->gdb_write_register = sparc_cpu_gdb_write_register;
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
cc->do_unassigned_access = sparc_cpu_unassigned_access;
|
cc->do_unassigned_access = sparc_cpu_unassigned_access;
|
||||||
cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug;
|
cc->get_phys_page_debug = sparc_cpu_get_phys_page_debug;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
|
||||||
|
cc->gdb_num_core_regs = 86;
|
||||||
|
#else
|
||||||
|
cc->gdb_num_core_regs = 72;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo sparc_cpu_type_info = {
|
static const TypeInfo sparc_cpu_type_info = {
|
||||||
|
208
target-sparc/gdbstub.c
Normal file
208
target-sparc/gdbstub.c
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
* SPARC gdb server stub
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||||
|
* Copyright (c) 2013 SUSE LINUX Products GmbH
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
|
#ifdef TARGET_ABI32
|
||||||
|
#define gdb_get_rega(buf, val) gdb_get_reg32(buf, val)
|
||||||
|
#else
|
||||||
|
#define gdb_get_rega(buf, val) gdb_get_regl(buf, val)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int sparc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||||
|
CPUSPARCState *env = &cpu->env;
|
||||||
|
|
||||||
|
if (n < 8) {
|
||||||
|
/* g0..g7 */
|
||||||
|
return gdb_get_rega(mem_buf, env->gregs[n]);
|
||||||
|
}
|
||||||
|
if (n < 32) {
|
||||||
|
/* register window */
|
||||||
|
return gdb_get_rega(mem_buf, env->regwptr[n - 8]);
|
||||||
|
}
|
||||||
|
#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
|
||||||
|
if (n < 64) {
|
||||||
|
/* fprs */
|
||||||
|
if (n & 1) {
|
||||||
|
return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.lower);
|
||||||
|
} else {
|
||||||
|
return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.upper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
||||||
|
switch (n) {
|
||||||
|
case 64:
|
||||||
|
return gdb_get_rega(mem_buf, env->y);
|
||||||
|
case 65:
|
||||||
|
return gdb_get_rega(mem_buf, cpu_get_psr(env));
|
||||||
|
case 66:
|
||||||
|
return gdb_get_rega(mem_buf, env->wim);
|
||||||
|
case 67:
|
||||||
|
return gdb_get_rega(mem_buf, env->tbr);
|
||||||
|
case 68:
|
||||||
|
return gdb_get_rega(mem_buf, env->pc);
|
||||||
|
case 69:
|
||||||
|
return gdb_get_rega(mem_buf, env->npc);
|
||||||
|
case 70:
|
||||||
|
return gdb_get_rega(mem_buf, env->fsr);
|
||||||
|
case 71:
|
||||||
|
return gdb_get_rega(mem_buf, 0); /* csr */
|
||||||
|
default:
|
||||||
|
return gdb_get_rega(mem_buf, 0);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (n < 64) {
|
||||||
|
/* f0-f31 */
|
||||||
|
if (n & 1) {
|
||||||
|
return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.lower);
|
||||||
|
} else {
|
||||||
|
return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.upper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n < 80) {
|
||||||
|
/* f32-f62 (double width, even numbers only) */
|
||||||
|
return gdb_get_reg64(mem_buf, env->fpr[(n - 32) / 2].ll);
|
||||||
|
}
|
||||||
|
switch (n) {
|
||||||
|
case 80:
|
||||||
|
return gdb_get_regl(mem_buf, env->pc);
|
||||||
|
case 81:
|
||||||
|
return gdb_get_regl(mem_buf, env->npc);
|
||||||
|
case 82:
|
||||||
|
return gdb_get_regl(mem_buf, (cpu_get_ccr(env) << 32) |
|
||||||
|
((env->asi & 0xff) << 24) |
|
||||||
|
((env->pstate & 0xfff) << 8) |
|
||||||
|
cpu_get_cwp64(env));
|
||||||
|
case 83:
|
||||||
|
return gdb_get_regl(mem_buf, env->fsr);
|
||||||
|
case 84:
|
||||||
|
return gdb_get_regl(mem_buf, env->fprs);
|
||||||
|
case 85:
|
||||||
|
return gdb_get_regl(mem_buf, env->y);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sparc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||||
|
CPUSPARCState *env = &cpu->env;
|
||||||
|
#if defined(TARGET_ABI32)
|
||||||
|
abi_ulong tmp;
|
||||||
|
|
||||||
|
tmp = ldl_p(mem_buf);
|
||||||
|
#else
|
||||||
|
target_ulong tmp;
|
||||||
|
|
||||||
|
tmp = ldtul_p(mem_buf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (n < 8) {
|
||||||
|
/* g0..g7 */
|
||||||
|
env->gregs[n] = tmp;
|
||||||
|
} else if (n < 32) {
|
||||||
|
/* register window */
|
||||||
|
env->regwptr[n - 8] = tmp;
|
||||||
|
}
|
||||||
|
#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
|
||||||
|
else if (n < 64) {
|
||||||
|
/* fprs */
|
||||||
|
/* f0-f31 */
|
||||||
|
if (n & 1) {
|
||||||
|
env->fpr[(n - 32) / 2].l.lower = tmp;
|
||||||
|
} else {
|
||||||
|
env->fpr[(n - 32) / 2].l.upper = tmp;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
|
||||||
|
switch (n) {
|
||||||
|
case 64:
|
||||||
|
env->y = tmp;
|
||||||
|
break;
|
||||||
|
case 65:
|
||||||
|
cpu_put_psr(env, tmp);
|
||||||
|
break;
|
||||||
|
case 66:
|
||||||
|
env->wim = tmp;
|
||||||
|
break;
|
||||||
|
case 67:
|
||||||
|
env->tbr = tmp;
|
||||||
|
break;
|
||||||
|
case 68:
|
||||||
|
env->pc = tmp;
|
||||||
|
break;
|
||||||
|
case 69:
|
||||||
|
env->npc = tmp;
|
||||||
|
break;
|
||||||
|
case 70:
|
||||||
|
env->fsr = tmp;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 4;
|
||||||
|
#else
|
||||||
|
else if (n < 64) {
|
||||||
|
/* f0-f31 */
|
||||||
|
tmp = ldl_p(mem_buf);
|
||||||
|
if (n & 1) {
|
||||||
|
env->fpr[(n - 32) / 2].l.lower = tmp;
|
||||||
|
} else {
|
||||||
|
env->fpr[(n - 32) / 2].l.upper = tmp;
|
||||||
|
}
|
||||||
|
return 4;
|
||||||
|
} else if (n < 80) {
|
||||||
|
/* f32-f62 (double width, even numbers only) */
|
||||||
|
env->fpr[(n - 32) / 2].ll = tmp;
|
||||||
|
} else {
|
||||||
|
switch (n) {
|
||||||
|
case 80:
|
||||||
|
env->pc = tmp;
|
||||||
|
break;
|
||||||
|
case 81:
|
||||||
|
env->npc = tmp;
|
||||||
|
break;
|
||||||
|
case 82:
|
||||||
|
cpu_put_ccr(env, tmp >> 32);
|
||||||
|
env->asi = (tmp >> 24) & 0xff;
|
||||||
|
env->pstate = (tmp >> 8) & 0xfff;
|
||||||
|
cpu_put_cwp64(env, tmp & 0xff);
|
||||||
|
break;
|
||||||
|
case 83:
|
||||||
|
env->fsr = tmp;
|
||||||
|
break;
|
||||||
|
case 84:
|
||||||
|
env->fprs = tmp;
|
||||||
|
break;
|
||||||
|
case 85:
|
||||||
|
env->y = tmp;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 8;
|
||||||
|
#endif
|
||||||
|
}
|
@ -3,3 +3,4 @@ obj-y += core-dc232b.o
|
|||||||
obj-y += core-dc233c.o
|
obj-y += core-dc233c.o
|
||||||
obj-y += core-fsf.o
|
obj-y += core-fsf.o
|
||||||
obj-y += translate.o op_helper.o helper.o cpu.o
|
obj-y += translate.o op_helper.o helper.o cpu.o
|
||||||
|
obj-y += gdbstub.o
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
* XtensaCPUClass:
|
* XtensaCPUClass:
|
||||||
* @parent_realize: The parent class' realize handler.
|
* @parent_realize: The parent class' realize handler.
|
||||||
* @parent_reset: The parent class' reset handler.
|
* @parent_reset: The parent class' reset handler.
|
||||||
|
* @config: The CPU core configuration.
|
||||||
*
|
*
|
||||||
* An Xtensa CPU model.
|
* An Xtensa CPU model.
|
||||||
*/
|
*/
|
||||||
@ -55,6 +56,8 @@ typedef struct XtensaCPUClass {
|
|||||||
|
|
||||||
DeviceRealize parent_realize;
|
DeviceRealize parent_realize;
|
||||||
void (*parent_reset)(CPUState *cpu);
|
void (*parent_reset)(CPUState *cpu);
|
||||||
|
|
||||||
|
const XtensaConfig *config;
|
||||||
} XtensaCPUClass;
|
} XtensaCPUClass;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -84,5 +87,7 @@ void xtensa_cpu_do_interrupt(CPUState *cpu);
|
|||||||
void xtensa_cpu_dump_state(CPUState *cpu, FILE *f,
|
void xtensa_cpu_dump_state(CPUState *cpu, FILE *f,
|
||||||
fprintf_function cpu_fprintf, int flags);
|
fprintf_function cpu_fprintf, int flags);
|
||||||
hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||||
|
int xtensa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
int xtensa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -64,10 +64,32 @@ static void xtensa_cpu_reset(CPUState *s)
|
|||||||
reset_mmu(env);
|
reset_mmu(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model)
|
||||||
|
{
|
||||||
|
ObjectClass *oc;
|
||||||
|
char *typename;
|
||||||
|
|
||||||
|
if (cpu_model == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
typename = g_strdup_printf("%s-" TYPE_XTENSA_CPU, cpu_model);
|
||||||
|
oc = object_class_by_name(typename);
|
||||||
|
g_free(typename);
|
||||||
|
if (oc == NULL || !object_class_dynamic_cast(oc, TYPE_XTENSA_CPU) ||
|
||||||
|
object_class_is_abstract(oc)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return oc;
|
||||||
|
}
|
||||||
|
|
||||||
static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp)
|
static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
|
CPUState *cs = CPU(dev);
|
||||||
XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(dev);
|
XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(dev);
|
||||||
|
|
||||||
|
cs->gdb_num_regs = xcc->config->gdb_regmap.num_regs;
|
||||||
|
|
||||||
xcc->parent_realize(dev, errp);
|
xcc->parent_realize(dev, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,10 +97,12 @@ static void xtensa_cpu_initfn(Object *obj)
|
|||||||
{
|
{
|
||||||
CPUState *cs = CPU(obj);
|
CPUState *cs = CPU(obj);
|
||||||
XtensaCPU *cpu = XTENSA_CPU(obj);
|
XtensaCPU *cpu = XTENSA_CPU(obj);
|
||||||
|
XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(obj);
|
||||||
CPUXtensaState *env = &cpu->env;
|
CPUXtensaState *env = &cpu->env;
|
||||||
static bool tcg_inited;
|
static bool tcg_inited;
|
||||||
|
|
||||||
cs->env_ptr = env;
|
cs->env_ptr = env;
|
||||||
|
env->config = xcc->config;
|
||||||
cpu_exec_init(env);
|
cpu_exec_init(env);
|
||||||
|
|
||||||
if (tcg_enabled() && !tcg_inited) {
|
if (tcg_enabled() && !tcg_inited) {
|
||||||
@ -105,9 +129,12 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
|
|||||||
xcc->parent_reset = cc->reset;
|
xcc->parent_reset = cc->reset;
|
||||||
cc->reset = xtensa_cpu_reset;
|
cc->reset = xtensa_cpu_reset;
|
||||||
|
|
||||||
|
cc->class_by_name = xtensa_cpu_class_by_name;
|
||||||
cc->do_interrupt = xtensa_cpu_do_interrupt;
|
cc->do_interrupt = xtensa_cpu_do_interrupt;
|
||||||
cc->dump_state = xtensa_cpu_dump_state;
|
cc->dump_state = xtensa_cpu_dump_state;
|
||||||
cc->set_pc = xtensa_cpu_set_pc;
|
cc->set_pc = xtensa_cpu_set_pc;
|
||||||
|
cc->gdb_read_register = xtensa_cpu_gdb_read_register;
|
||||||
|
cc->gdb_write_register = xtensa_cpu_gdb_write_register;
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
cc->get_phys_page_debug = xtensa_cpu_get_phys_page_debug;
|
cc->get_phys_page_debug = xtensa_cpu_get_phys_page_debug;
|
||||||
#endif
|
#endif
|
||||||
@ -119,7 +146,7 @@ static const TypeInfo xtensa_cpu_type_info = {
|
|||||||
.parent = TYPE_CPU,
|
.parent = TYPE_CPU,
|
||||||
.instance_size = sizeof(XtensaCPU),
|
.instance_size = sizeof(XtensaCPU),
|
||||||
.instance_init = xtensa_cpu_initfn,
|
.instance_init = xtensa_cpu_initfn,
|
||||||
.abstract = false,
|
.abstract = true,
|
||||||
.class_size = sizeof(XtensaCPUClass),
|
.class_size = sizeof(XtensaCPUClass),
|
||||||
.class_init = xtensa_cpu_class_init,
|
.class_init = xtensa_cpu_class_init,
|
||||||
};
|
};
|
||||||
|
109
target-xtensa/gdbstub.c
Normal file
109
target-xtensa/gdbstub.c
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Xtensa gdb server stub
|
||||||
|
*
|
||||||
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
||||||
|
* Copyright (c) 2013 SUSE LINUX Products GmbH
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "config.h"
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
|
int xtensa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
XtensaCPU *cpu = XTENSA_CPU(cs);
|
||||||
|
CPUXtensaState *env = &cpu->env;
|
||||||
|
const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
|
||||||
|
|
||||||
|
if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (reg->type) {
|
||||||
|
case 9: /*pc*/
|
||||||
|
return gdb_get_reg32(mem_buf, env->pc);
|
||||||
|
|
||||||
|
case 1: /*ar*/
|
||||||
|
xtensa_sync_phys_from_window(env);
|
||||||
|
return gdb_get_reg32(mem_buf, env->phys_regs[(reg->targno & 0xff)
|
||||||
|
% env->config->nareg]);
|
||||||
|
|
||||||
|
case 2: /*SR*/
|
||||||
|
return gdb_get_reg32(mem_buf, env->sregs[reg->targno & 0xff]);
|
||||||
|
|
||||||
|
case 3: /*UR*/
|
||||||
|
return gdb_get_reg32(mem_buf, env->uregs[reg->targno & 0xff]);
|
||||||
|
|
||||||
|
case 4: /*f*/
|
||||||
|
return gdb_get_reg32(mem_buf, float32_val(env->fregs[reg->targno
|
||||||
|
& 0x0f]));
|
||||||
|
|
||||||
|
case 8: /*a*/
|
||||||
|
return gdb_get_reg32(mem_buf, env->regs[reg->targno & 0x0f]);
|
||||||
|
|
||||||
|
default:
|
||||||
|
qemu_log("%s from reg %d of unsupported type %d\n",
|
||||||
|
__func__, n, reg->type);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int xtensa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
{
|
||||||
|
XtensaCPU *cpu = XTENSA_CPU(cs);
|
||||||
|
CPUXtensaState *env = &cpu->env;
|
||||||
|
uint32_t tmp;
|
||||||
|
const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n;
|
||||||
|
|
||||||
|
if (n < 0 || n >= env->config->gdb_regmap.num_regs) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = ldl_p(mem_buf);
|
||||||
|
|
||||||
|
switch (reg->type) {
|
||||||
|
case 9: /*pc*/
|
||||||
|
env->pc = tmp;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: /*ar*/
|
||||||
|
env->phys_regs[(reg->targno & 0xff) % env->config->nareg] = tmp;
|
||||||
|
xtensa_sync_window_from_phys(env);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: /*SR*/
|
||||||
|
env->sregs[reg->targno & 0xff] = tmp;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3: /*UR*/
|
||||||
|
env->uregs[reg->targno & 0xff] = tmp;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: /*f*/
|
||||||
|
env->fregs[reg->targno & 0x0f] = make_float32(tmp);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 8: /*a*/
|
||||||
|
env->regs[reg->targno & 0x0f] = tmp;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
qemu_log("%s to reg %d of unsupported type %d\n",
|
||||||
|
__func__, n, reg->type);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
}
|
@ -35,10 +35,35 @@
|
|||||||
|
|
||||||
static struct XtensaConfigList *xtensa_cores;
|
static struct XtensaConfigList *xtensa_cores;
|
||||||
|
|
||||||
|
static void xtensa_core_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
CPUClass *cc = CPU_CLASS(oc);
|
||||||
|
XtensaCPUClass *xcc = XTENSA_CPU_CLASS(oc);
|
||||||
|
const XtensaConfig *config = data;
|
||||||
|
|
||||||
|
xcc->config = config;
|
||||||
|
|
||||||
|
/* Use num_core_regs to see only non-privileged registers in an unmodified
|
||||||
|
* gdb. Use num_regs to see all registers. gdb modification is required
|
||||||
|
* for that: reset bit 0 in the 'flags' field of the registers definitions
|
||||||
|
* in the gdb/xtensa-config.c inside gdb source tree or inside gdb overlay.
|
||||||
|
*/
|
||||||
|
cc->gdb_num_core_regs = config->gdb_regmap.num_regs;
|
||||||
|
}
|
||||||
|
|
||||||
void xtensa_register_core(XtensaConfigList *node)
|
void xtensa_register_core(XtensaConfigList *node)
|
||||||
{
|
{
|
||||||
|
TypeInfo type = {
|
||||||
|
.parent = TYPE_XTENSA_CPU,
|
||||||
|
.class_init = xtensa_core_class_init,
|
||||||
|
.class_data = (void *)node->config,
|
||||||
|
};
|
||||||
|
|
||||||
node->next = xtensa_cores;
|
node->next = xtensa_cores;
|
||||||
xtensa_cores = node;
|
xtensa_cores = node;
|
||||||
|
type.name = g_strdup_printf("%s-" TYPE_XTENSA_CPU, node->config->name);
|
||||||
|
type_register(&type);
|
||||||
|
g_free((gpointer)type.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t check_hw_breakpoints(CPUXtensaState *env)
|
static uint32_t check_hw_breakpoints(CPUXtensaState *env)
|
||||||
@ -72,24 +97,17 @@ void xtensa_breakpoint_handler(CPUXtensaState *env)
|
|||||||
|
|
||||||
XtensaCPU *cpu_xtensa_init(const char *cpu_model)
|
XtensaCPU *cpu_xtensa_init(const char *cpu_model)
|
||||||
{
|
{
|
||||||
|
ObjectClass *oc;
|
||||||
XtensaCPU *cpu;
|
XtensaCPU *cpu;
|
||||||
CPUXtensaState *env;
|
CPUXtensaState *env;
|
||||||
const XtensaConfig *config = NULL;
|
|
||||||
XtensaConfigList *core = xtensa_cores;
|
|
||||||
|
|
||||||
for (; core; core = core->next)
|
oc = cpu_class_by_name(TYPE_XTENSA_CPU, cpu_model);
|
||||||
if (strcmp(core->config->name, cpu_model) == 0) {
|
if (oc == NULL) {
|
||||||
config = core->config;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config == NULL) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu = XTENSA_CPU(object_new(TYPE_XTENSA_CPU));
|
cpu = XTENSA_CPU(object_new(object_class_get_name(oc)));
|
||||||
env = &cpu->env;
|
env = &cpu->env;
|
||||||
env->config = config;
|
|
||||||
|
|
||||||
xtensa_irq_init(env);
|
xtensa_irq_init(env);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user