Testing and gdbstub updates:
- docker updates for VirGL - re-factor gdbstub for static GDBState - re-factor gdbstub for dynamic arrays - add SVE support to arm gdbstub - add some guest debug tests to check-tcg - add aarch64 userspace register tests - remove packet size limit to gdbstub - simplify gdbstub monitor code - report vContSupported in gdbstub to use proper single-step -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAl5xDUIACgkQ+9DbCVqe KkQwCwf/YtmUsNxxO+CgNctq2u3jV4FoOdQP3bejvmT2+cigKJhQuBlWPg1/YsqF RDNkmBQx2JaVVMuVmpnwVK1UD+kmYZqrtlOkPNcVrjPmLCq3BVI1LHe6Rjoerx8F QoZyH0IMNHbBgDo1I46lSFOWcxmOvo+Ow7NX5bPKwlRzf0dyEqSJahRaZLAgUscR taTtGfk9uQsnxoRsvH/efiQ4bZtUvrEQuhEX3WW/yVE1jTpcb2llwX4xONJb2It3 /0WREGEEIT8PpnWw2S3FH4THY/BjWgz/FPDwNNZYCKBMWDjuG/8KHryd738T9rzo lkGP9YcXmiyxMMyFFwS8RD3SHr8LvQ== =Wm+a -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-and-gdbstub-170320-1' into staging Testing and gdbstub updates: - docker updates for VirGL - re-factor gdbstub for static GDBState - re-factor gdbstub for dynamic arrays - add SVE support to arm gdbstub - add some guest debug tests to check-tcg - add aarch64 userspace register tests - remove packet size limit to gdbstub - simplify gdbstub monitor code - report vContSupported in gdbstub to use proper single-step # gpg: Signature made Tue 17 Mar 2020 17:47:46 GMT # gpg: using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44 # gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [full] # Primary key fingerprint: 6685 AE99 E751 67BC AFC8 DF35 FBD0 DB09 5A9E 2A44 * remotes/stsquad/tags/pull-testing-and-gdbstub-170320-1: (28 commits) gdbstub: Fix single-step issue by confirming 'vContSupported+' feature to gdb gdbstub: do not split gdb_monitor_write payload gdbstub: change GDBState.last_packet to GByteArray tests/tcg/aarch64: add test-sve-ioctl guest-debug test tests/tcg/aarch64: add SVE iotcl test tests/tcg/aarch64: add a gdbstub testcase for SVE registers tests/guest-debug: add a simple test runner configure: allow user to specify what gdb to use tests/tcg/aarch64: userspace system register test target/arm: don't bother with id_aa64pfr0_read for USER_ONLY target/arm: generate xml description of our SVE registers target/arm: default SVE length to 64 bytes for linux-user target/arm: explicitly encode regnum in our XML target/arm: prepare for multiple dynamic XMLs gdbstub: extend GByteArray to read register helpers target/i386: use gdb_get_reg helpers target/m68k: use gdb_get_reg helpers target/arm: use gdb_get_reg helpers gdbstub: add helper for 128 bit registers gdbstub: move mem_buf to GDBState and use GByteArray ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
9214813489
|
@ -79,6 +79,7 @@ env:
|
||||||
- MAIN_SOFTMMU_TARGETS="aarch64-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
|
- MAIN_SOFTMMU_TARGETS="aarch64-softmmu,mips64-softmmu,ppc64-softmmu,riscv64-softmmu,s390x-softmmu,x86_64-softmmu"
|
||||||
- CCACHE_SLOPPINESS="include_file_ctime,include_file_mtime"
|
- CCACHE_SLOPPINESS="include_file_ctime,include_file_mtime"
|
||||||
- CCACHE_MAXSIZE=1G
|
- CCACHE_MAXSIZE=1G
|
||||||
|
- G_MESSAGES_DEBUG=error
|
||||||
|
|
||||||
|
|
||||||
git:
|
git:
|
||||||
|
|
9
configure
vendored
9
configure
vendored
|
@ -303,6 +303,7 @@ libs_qga=""
|
||||||
debug_info="yes"
|
debug_info="yes"
|
||||||
stack_protector=""
|
stack_protector=""
|
||||||
use_containers="yes"
|
use_containers="yes"
|
||||||
|
gdb_bin=$(command -v "gdb")
|
||||||
|
|
||||||
if test -e "$source_path/.git"
|
if test -e "$source_path/.git"
|
||||||
then
|
then
|
||||||
|
@ -1598,6 +1599,8 @@ for opt do
|
||||||
;;
|
;;
|
||||||
--disable-fuzzing) fuzzing=no
|
--disable-fuzzing) fuzzing=no
|
||||||
;;
|
;;
|
||||||
|
--gdb=*) gdb_bin="$optarg"
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "ERROR: unknown option $opt"
|
echo "ERROR: unknown option $opt"
|
||||||
echo "Try '$0 --help' for more information"
|
echo "Try '$0 --help' for more information"
|
||||||
|
@ -1783,6 +1786,7 @@ Advanced options (experts only):
|
||||||
--enable-plugins
|
--enable-plugins
|
||||||
enable plugins via shared library loading
|
enable plugins via shared library loading
|
||||||
--disable-containers don't use containers for cross-building
|
--disable-containers don't use containers for cross-building
|
||||||
|
--gdb=GDB-path gdb to use for gdbstub tests [$gdb_bin]
|
||||||
|
|
||||||
Optional features, enabled with --enable-FEATURE and
|
Optional features, enabled with --enable-FEATURE and
|
||||||
disabled with --disable-FEATURE, default is enabled if available:
|
disabled with --disable-FEATURE, default is enabled if available:
|
||||||
|
@ -6785,6 +6789,7 @@ echo "libudev $libudev"
|
||||||
echo "default devices $default_devices"
|
echo "default devices $default_devices"
|
||||||
echo "plugin support $plugins"
|
echo "plugin support $plugins"
|
||||||
echo "fuzzing support $fuzzing"
|
echo "fuzzing support $fuzzing"
|
||||||
|
echo "gdb $gdb_bin"
|
||||||
|
|
||||||
if test "$supported_cpu" = "no"; then
|
if test "$supported_cpu" = "no"; then
|
||||||
echo
|
echo
|
||||||
|
@ -7666,6 +7671,10 @@ if test "$plugins" = "yes" ; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test -n "$gdb_bin" ; then
|
||||||
|
echo "HAVE_GDB_BIN=$gdb_bin" >> $config_host_mak
|
||||||
|
fi
|
||||||
|
|
||||||
if test "$tcg_interpreter" = "yes"; then
|
if test "$tcg_interpreter" = "yes"; then
|
||||||
QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
|
QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
|
||||||
elif test "$ARCH" = "sparc64" ; then
|
elif test "$ARCH" = "sparc64" ; then
|
||||||
|
|
|
@ -177,7 +177,7 @@ static int cpu_common_write_elf64_note(WriteCoreDumpFunction f,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int cpu_common_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg)
|
static int cpu_common_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,40 +68,76 @@ void gdb_signalled(CPUArchState *, int);
|
||||||
void gdbserver_fork(CPUState *);
|
void gdbserver_fork(CPUState *);
|
||||||
#endif
|
#endif
|
||||||
/* Get or set a register. Returns the size of the register. */
|
/* Get or set a register. Returns the size of the register. */
|
||||||
typedef int (*gdb_reg_cb)(CPUArchState *env, uint8_t *buf, int reg);
|
typedef int (*gdb_get_reg_cb)(CPUArchState *env, GByteArray *buf, int reg);
|
||||||
|
typedef int (*gdb_set_reg_cb)(CPUArchState *env, uint8_t *buf, int reg);
|
||||||
void gdb_register_coprocessor(CPUState *cpu,
|
void gdb_register_coprocessor(CPUState *cpu,
|
||||||
gdb_reg_cb get_reg, gdb_reg_cb set_reg,
|
gdb_get_reg_cb get_reg, gdb_set_reg_cb set_reg,
|
||||||
int num_regs, const char *xml, int g_pos);
|
int num_regs, const char *xml, int g_pos);
|
||||||
|
|
||||||
/* 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.
|
* The GDB remote protocol transfers values in target byte order. As
|
||||||
* Conveniently, these also handle the case where the buffer is mis-aligned.
|
* the gdbstub may be batching up several register values we always
|
||||||
|
* append to the array.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static inline int gdb_get_reg8(uint8_t *mem_buf, uint8_t val)
|
static inline int gdb_get_reg8(GByteArray *buf, uint8_t val)
|
||||||
{
|
{
|
||||||
stb_p(mem_buf, val);
|
g_byte_array_append(buf, &val, 1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int gdb_get_reg16(uint8_t *mem_buf, uint16_t val)
|
static inline int gdb_get_reg16(GByteArray *buf, uint16_t val)
|
||||||
{
|
{
|
||||||
stw_p(mem_buf, val);
|
uint16_t to_word = tswap16(val);
|
||||||
|
g_byte_array_append(buf, (uint8_t *) &to_word, 2);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int gdb_get_reg32(uint8_t *mem_buf, uint32_t val)
|
static inline int gdb_get_reg32(GByteArray *buf, uint32_t val)
|
||||||
{
|
{
|
||||||
stl_p(mem_buf, val);
|
uint32_t to_long = tswap32(val);
|
||||||
|
g_byte_array_append(buf, (uint8_t *) &to_long, 4);
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int gdb_get_reg64(uint8_t *mem_buf, uint64_t val)
|
static inline int gdb_get_reg64(GByteArray *buf, uint64_t val)
|
||||||
{
|
{
|
||||||
stq_p(mem_buf, val);
|
uint64_t to_quad = tswap64(val);
|
||||||
|
g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int gdb_get_reg128(GByteArray *buf, uint64_t val_hi,
|
||||||
|
uint64_t val_lo)
|
||||||
|
{
|
||||||
|
uint64_t to_quad;
|
||||||
|
#ifdef TARGET_WORDS_BIGENDIAN
|
||||||
|
to_quad = tswap64(val_hi);
|
||||||
|
g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
|
||||||
|
to_quad = tswap64(val_lo);
|
||||||
|
g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
|
||||||
|
#else
|
||||||
|
to_quad = tswap64(val_lo);
|
||||||
|
g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
|
||||||
|
to_quad = tswap64(val_hi);
|
||||||
|
g_byte_array_append(buf, (uint8_t *) &to_quad, 8);
|
||||||
|
#endif
|
||||||
|
return 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdb_get_reg_ptr: get pointer to start of last element
|
||||||
|
* @len: length of element
|
||||||
|
*
|
||||||
|
* This is a helper function to extract the pointer to the last
|
||||||
|
* element for additional processing. Some front-ends do additional
|
||||||
|
* dynamic swapping of the elements based on CPU state.
|
||||||
|
*/
|
||||||
|
static inline uint8_t * gdb_get_reg_ptr(GByteArray *buf, int len)
|
||||||
|
{
|
||||||
|
return buf->data + buf->len - len;
|
||||||
|
}
|
||||||
|
|
||||||
#if TARGET_LONG_BITS == 64
|
#if TARGET_LONG_BITS == 64
|
||||||
#define gdb_get_regl(buf, val) gdb_get_reg64(buf, val)
|
#define gdb_get_regl(buf, val) gdb_get_reg64(buf, val)
|
||||||
#define ldtul_p(addr) ldq_p(addr)
|
#define ldtul_p(addr) ldq_p(addr)
|
||||||
|
|
|
@ -195,7 +195,7 @@ typedef struct CPUClass {
|
||||||
hwaddr (*get_phys_page_attrs_debug)(CPUState *cpu, vaddr addr,
|
hwaddr (*get_phys_page_attrs_debug)(CPUState *cpu, vaddr addr,
|
||||||
MemTxAttrs *attrs);
|
MemTxAttrs *attrs);
|
||||||
int (*asidx_from_attrs)(CPUState *cpu, MemTxAttrs attrs);
|
int (*asidx_from_attrs)(CPUState *cpu, MemTxAttrs attrs);
|
||||||
int (*gdb_read_register)(CPUState *cpu, uint8_t *buf, int reg);
|
int (*gdb_read_register)(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg);
|
int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
bool (*debug_check_watchpoint)(CPUState *cpu, CPUWatchpoint *wp);
|
bool (*debug_check_watchpoint)(CPUState *cpu, CPUWatchpoint *wp);
|
||||||
void (*debug_excp_handler)(CPUState *cpu);
|
void (*debug_excp_handler)(CPUState *cpu);
|
||||||
|
|
|
@ -280,7 +280,7 @@ void alpha_cpu_do_interrupt(CPUState *cpu);
|
||||||
bool alpha_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
bool alpha_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||||
void alpha_cpu_dump_state(CPUState *cs, FILE *f, int flags);
|
void alpha_cpu_dump_state(CPUState *cs, FILE *f, 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_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int alpha_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int alpha_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
void alpha_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
void alpha_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
||||||
MMUAccessType access_type,
|
MMUAccessType access_type,
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
int alpha_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int alpha_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
AlphaCPU *cpu = ALPHA_CPU(cs);
|
AlphaCPU *cpu = ALPHA_CPU(cs);
|
||||||
CPUAlphaState *env = &cpu->env;
|
CPUAlphaState *env = &cpu->env;
|
||||||
|
|
|
@ -195,9 +195,10 @@ static void arm_cpu_reset(CPUState *s)
|
||||||
env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 20, 2, 3);
|
env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 20, 2, 3);
|
||||||
/* and to the SVE instructions */
|
/* and to the SVE instructions */
|
||||||
env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 16, 2, 3);
|
env->cp15.cpacr_el1 = deposit64(env->cp15.cpacr_el1, 16, 2, 3);
|
||||||
/* with maximum vector length */
|
/* with reasonable vector length */
|
||||||
env->vfp.zcr_el[1] = cpu_isar_feature(aa64_sve, cpu) ?
|
if (cpu_isar_feature(aa64_sve, cpu)) {
|
||||||
cpu->sve_max_vq - 1 : 0;
|
env->vfp.zcr_el[1] = MIN(cpu->sve_max_vq - 1, 3);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Enable TBI0 and TBI1. While the real kernel only enables TBI0,
|
* Enable TBI0 and TBI1. While the real kernel only enables TBI0,
|
||||||
* turning on both here will produce smaller code and otherwise
|
* turning on both here will produce smaller code and otherwise
|
||||||
|
|
|
@ -128,14 +128,20 @@ enum {
|
||||||
/**
|
/**
|
||||||
* DynamicGDBXMLInfo:
|
* DynamicGDBXMLInfo:
|
||||||
* @desc: Contains the XML descriptions.
|
* @desc: Contains the XML descriptions.
|
||||||
* @num_cpregs: Number of the Coprocessor registers seen by GDB.
|
* @num: Number of the registers in this XML seen by GDB.
|
||||||
* @cpregs_keys: Array that contains the corresponding Key of
|
* @data: A union with data specific to the set of registers
|
||||||
* a given cpreg with the same order of the cpreg in the XML description.
|
* @cpregs_keys: Array that contains the corresponding Key of
|
||||||
|
* a given cpreg with the same order of the cpreg
|
||||||
|
* in the XML description.
|
||||||
*/
|
*/
|
||||||
typedef struct DynamicGDBXMLInfo {
|
typedef struct DynamicGDBXMLInfo {
|
||||||
char *desc;
|
char *desc;
|
||||||
int num_cpregs;
|
int num;
|
||||||
uint32_t *cpregs_keys;
|
union {
|
||||||
|
struct {
|
||||||
|
uint32_t *keys;
|
||||||
|
} cpregs;
|
||||||
|
} data;
|
||||||
} DynamicGDBXMLInfo;
|
} DynamicGDBXMLInfo;
|
||||||
|
|
||||||
/* CPU state for each instance of a generic timer (in cp15 c14) */
|
/* CPU state for each instance of a generic timer (in cp15 c14) */
|
||||||
|
@ -749,7 +755,8 @@ struct ARMCPU {
|
||||||
uint64_t *cpreg_vmstate_values;
|
uint64_t *cpreg_vmstate_values;
|
||||||
int32_t cpreg_vmstate_array_len;
|
int32_t cpreg_vmstate_array_len;
|
||||||
|
|
||||||
DynamicGDBXMLInfo dyn_xml;
|
DynamicGDBXMLInfo dyn_sysreg_xml;
|
||||||
|
DynamicGDBXMLInfo dyn_svereg_xml;
|
||||||
|
|
||||||
/* Timers used by the generic (architected) timer */
|
/* Timers used by the generic (architected) timer */
|
||||||
QEMUTimer *gt_timer[NUM_GTIMERS];
|
QEMUTimer *gt_timer[NUM_GTIMERS];
|
||||||
|
@ -968,13 +975,15 @@ bool arm_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||||
hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
|
hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
|
||||||
MemTxAttrs *attrs);
|
MemTxAttrs *attrs);
|
||||||
|
|
||||||
int arm_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
int arm_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
/* Dynamically generates for gdb stub an XML description of the sysregs from
|
/*
|
||||||
* the cp_regs hashtable. Returns the registered sysregs number.
|
* Helpers to dynamically generates XML descriptions of the sysregs
|
||||||
|
* and SVE registers. Returns the number of registers in each set.
|
||||||
*/
|
*/
|
||||||
int arm_gen_dynamic_xml(CPUState *cpu);
|
int arm_gen_dynamic_sysreg_xml(CPUState *cpu, int base_reg);
|
||||||
|
int arm_gen_dynamic_svereg_xml(CPUState *cpu, int base_reg);
|
||||||
|
|
||||||
/* Returns the dynamically generated XML for the gdb stub.
|
/* Returns the dynamically generated XML for the gdb stub.
|
||||||
* Returns a pointer to the XML contents for the specified XML file or NULL
|
* Returns a pointer to the XML contents for the specified XML file or NULL
|
||||||
|
@ -988,7 +997,7 @@ int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
|
||||||
int cpuid, void *opaque);
|
int cpuid, void *opaque);
|
||||||
|
|
||||||
#ifdef TARGET_AARCH64
|
#ifdef TARGET_AARCH64
|
||||||
int aarch64_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
int aarch64_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq);
|
void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq);
|
||||||
void aarch64_sve_change_el(CPUARMState *env, int old_el,
|
void aarch64_sve_change_el(CPUARMState *env, int old_el,
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
typedef struct RegisterSysregXmlParam {
|
typedef struct RegisterSysregXmlParam {
|
||||||
CPUState *cs;
|
CPUState *cs;
|
||||||
GString *s;
|
GString *s;
|
||||||
|
int n;
|
||||||
} RegisterSysregXmlParam;
|
} RegisterSysregXmlParam;
|
||||||
|
|
||||||
/* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect
|
/* Old gdb always expect FPA registers. Newer (xml-aware) gdb only expect
|
||||||
|
@ -32,7 +33,7 @@ typedef struct RegisterSysregXmlParam {
|
||||||
We hack round this by giving the FPA regs zero size when talking to a
|
We hack round this by giving the FPA regs zero size when talking to a
|
||||||
newer gdb. */
|
newer gdb. */
|
||||||
|
|
||||||
int arm_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = ARM_CPU(cs);
|
ARMCPU *cpu = ARM_CPU(cs);
|
||||||
CPUARMState *env = &cpu->env;
|
CPUARMState *env = &cpu->env;
|
||||||
|
@ -106,15 +107,16 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arm_gen_one_xml_reg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml,
|
static void arm_gen_one_xml_sysreg_tag(GString *s, DynamicGDBXMLInfo *dyn_xml,
|
||||||
ARMCPRegInfo *ri, uint32_t ri_key,
|
ARMCPRegInfo *ri, uint32_t ri_key,
|
||||||
int bitsize)
|
int bitsize, int regnum)
|
||||||
{
|
{
|
||||||
g_string_append_printf(s, "<reg name=\"%s\"", ri->name);
|
g_string_append_printf(s, "<reg name=\"%s\"", ri->name);
|
||||||
g_string_append_printf(s, " bitsize=\"%d\"", bitsize);
|
g_string_append_printf(s, " bitsize=\"%d\"", bitsize);
|
||||||
|
g_string_append_printf(s, " regnum=\"%d\"", regnum);
|
||||||
g_string_append_printf(s, " group=\"cp_regs\"/>");
|
g_string_append_printf(s, " group=\"cp_regs\"/>");
|
||||||
dyn_xml->num_cpregs++;
|
dyn_xml->data.cpregs.keys[dyn_xml->num] = ri_key;
|
||||||
dyn_xml->cpregs_keys[dyn_xml->num_cpregs - 1] = ri_key;
|
dyn_xml->num++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
|
static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
|
||||||
|
@ -126,12 +128,13 @@ static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
|
||||||
GString *s = param->s;
|
GString *s = param->s;
|
||||||
ARMCPU *cpu = ARM_CPU(param->cs);
|
ARMCPU *cpu = ARM_CPU(param->cs);
|
||||||
CPUARMState *env = &cpu->env;
|
CPUARMState *env = &cpu->env;
|
||||||
DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_xml;
|
DynamicGDBXMLInfo *dyn_xml = &cpu->dyn_sysreg_xml;
|
||||||
|
|
||||||
if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) {
|
if (!(ri->type & (ARM_CP_NO_RAW | ARM_CP_NO_GDB))) {
|
||||||
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
|
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
|
||||||
if (ri->state == ARM_CP_STATE_AA64) {
|
if (ri->state == ARM_CP_STATE_AA64) {
|
||||||
arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 64);
|
arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64,
|
||||||
|
param->n++);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ri->state == ARM_CP_STATE_AA32) {
|
if (ri->state == ARM_CP_STATE_AA32) {
|
||||||
|
@ -140,38 +143,174 @@ static void arm_register_sysreg_for_xml(gpointer key, gpointer value,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (ri->type & ARM_CP_64BIT) {
|
if (ri->type & ARM_CP_64BIT) {
|
||||||
arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 64);
|
arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 64,
|
||||||
|
param->n++);
|
||||||
} else {
|
} else {
|
||||||
arm_gen_one_xml_reg_tag(s , dyn_xml, ri, ri_key, 32);
|
arm_gen_one_xml_sysreg_tag(s , dyn_xml, ri, ri_key, 32,
|
||||||
|
param->n++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int arm_gen_dynamic_xml(CPUState *cs)
|
int arm_gen_dynamic_sysreg_xml(CPUState *cs, int base_reg)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = ARM_CPU(cs);
|
ARMCPU *cpu = ARM_CPU(cs);
|
||||||
GString *s = g_string_new(NULL);
|
GString *s = g_string_new(NULL);
|
||||||
RegisterSysregXmlParam param = {cs, s};
|
RegisterSysregXmlParam param = {cs, s, base_reg};
|
||||||
|
|
||||||
cpu->dyn_xml.num_cpregs = 0;
|
cpu->dyn_sysreg_xml.num = 0;
|
||||||
cpu->dyn_xml.cpregs_keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs));
|
cpu->dyn_sysreg_xml.data.cpregs.keys = g_new(uint32_t, g_hash_table_size(cpu->cp_regs));
|
||||||
g_string_printf(s, "<?xml version=\"1.0\"?>");
|
g_string_printf(s, "<?xml version=\"1.0\"?>");
|
||||||
g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
|
g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
|
||||||
g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">");
|
g_string_append_printf(s, "<feature name=\"org.qemu.gdb.arm.sys.regs\">");
|
||||||
g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_xml, ¶m);
|
g_hash_table_foreach(cpu->cp_regs, arm_register_sysreg_for_xml, ¶m);
|
||||||
g_string_append_printf(s, "</feature>");
|
g_string_append_printf(s, "</feature>");
|
||||||
cpu->dyn_xml.desc = g_string_free(s, false);
|
cpu->dyn_sysreg_xml.desc = g_string_free(s, false);
|
||||||
return cpu->dyn_xml.num_cpregs;
|
return cpu->dyn_sysreg_xml.num;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TypeSize {
|
||||||
|
const char *gdb_type;
|
||||||
|
int size;
|
||||||
|
const char sz, suffix;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct TypeSize vec_lanes[] = {
|
||||||
|
/* quads */
|
||||||
|
{ "uint128", 128, 'q', 'u' },
|
||||||
|
{ "int128", 128, 'q', 's' },
|
||||||
|
/* 64 bit */
|
||||||
|
{ "uint64", 64, 'd', 'u' },
|
||||||
|
{ "int64", 64, 'd', 's' },
|
||||||
|
{ "ieee_double", 64, 'd', 'f' },
|
||||||
|
/* 32 bit */
|
||||||
|
{ "uint32", 32, 's', 'u' },
|
||||||
|
{ "int32", 32, 's', 's' },
|
||||||
|
{ "ieee_single", 32, 's', 'f' },
|
||||||
|
/* 16 bit */
|
||||||
|
{ "uint16", 16, 'h', 'u' },
|
||||||
|
{ "int16", 16, 'h', 's' },
|
||||||
|
{ "ieee_half", 16, 'h', 'f' },
|
||||||
|
/* bytes */
|
||||||
|
{ "uint8", 8, 'b', 'u' },
|
||||||
|
{ "int8", 8, 'b', 's' },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int arm_gen_dynamic_svereg_xml(CPUState *cs, int base_reg)
|
||||||
|
{
|
||||||
|
ARMCPU *cpu = ARM_CPU(cs);
|
||||||
|
GString *s = g_string_new(NULL);
|
||||||
|
DynamicGDBXMLInfo *info = &cpu->dyn_svereg_xml;
|
||||||
|
g_autoptr(GString) ts = g_string_new("");
|
||||||
|
int i, bits, reg_width = (cpu->sve_max_vq * 128);
|
||||||
|
info->num = 0;
|
||||||
|
g_string_printf(s, "<?xml version=\"1.0\"?>");
|
||||||
|
g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">");
|
||||||
|
g_string_append_printf(s, "<feature name=\"org.qemu.gdb.aarch64.sve\">");
|
||||||
|
|
||||||
|
/* First define types and totals in a whole VL */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
|
||||||
|
int count = reg_width / vec_lanes[i].size;
|
||||||
|
g_string_printf(ts, "vq%d%c%c", count,
|
||||||
|
vec_lanes[i].sz, vec_lanes[i].suffix);
|
||||||
|
g_string_append_printf(s,
|
||||||
|
"<vector id=\"%s\" type=\"%s\" count=\"%d\"/>",
|
||||||
|
ts->str, vec_lanes[i].gdb_type, count);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Now define a union for each size group containing unsigned and
|
||||||
|
* signed and potentially float versions of each size from 128 to
|
||||||
|
* 8 bits.
|
||||||
|
*/
|
||||||
|
for (bits = 128; bits >= 8; bits /= 2) {
|
||||||
|
int count = reg_width / bits;
|
||||||
|
g_string_append_printf(s, "<union id=\"vq%dn\">", count);
|
||||||
|
for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
|
||||||
|
if (vec_lanes[i].size == bits) {
|
||||||
|
g_string_append_printf(s, "<field name=\"%c\" type=\"vq%d%c%c\"/>",
|
||||||
|
vec_lanes[i].suffix,
|
||||||
|
count,
|
||||||
|
vec_lanes[i].sz, vec_lanes[i].suffix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_string_append(s, "</union>");
|
||||||
|
}
|
||||||
|
/* And now the final union of unions */
|
||||||
|
g_string_append(s, "<union id=\"vq\">");
|
||||||
|
for (bits = 128; bits >= 8; bits /= 2) {
|
||||||
|
int count = reg_width / bits;
|
||||||
|
for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) {
|
||||||
|
if (vec_lanes[i].size == bits) {
|
||||||
|
g_string_append_printf(s, "<field name=\"%c\" type=\"vq%dn\"/>",
|
||||||
|
vec_lanes[i].sz, count);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_string_append(s, "</union>");
|
||||||
|
|
||||||
|
/* Then define each register in parts for each vq */
|
||||||
|
for (i = 0; i < 32; i++) {
|
||||||
|
g_string_append_printf(s,
|
||||||
|
"<reg name=\"z%d\" bitsize=\"%d\""
|
||||||
|
" regnum=\"%d\" group=\"vector\""
|
||||||
|
" type=\"vq\"/>",
|
||||||
|
i, reg_width, base_reg++);
|
||||||
|
info->num++;
|
||||||
|
}
|
||||||
|
/* fpscr & status registers */
|
||||||
|
g_string_append_printf(s, "<reg name=\"fpsr\" bitsize=\"32\""
|
||||||
|
" regnum=\"%d\" group=\"float\""
|
||||||
|
" type=\"int\"/>", base_reg++);
|
||||||
|
g_string_append_printf(s, "<reg name=\"fpcr\" bitsize=\"32\""
|
||||||
|
" regnum=\"%d\" group=\"float\""
|
||||||
|
" type=\"int\"/>", base_reg++);
|
||||||
|
info->num += 2;
|
||||||
|
/*
|
||||||
|
* Predicate registers aren't so big they are worth splitting up
|
||||||
|
* but we do need to define a type to hold the array of quad
|
||||||
|
* references.
|
||||||
|
*/
|
||||||
|
g_string_append_printf(s,
|
||||||
|
"<vector id=\"vqp\" type=\"uint16\" count=\"%d\"/>",
|
||||||
|
cpu->sve_max_vq);
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
g_string_append_printf(s,
|
||||||
|
"<reg name=\"p%d\" bitsize=\"%d\""
|
||||||
|
" regnum=\"%d\" group=\"vector\""
|
||||||
|
" type=\"vqp\"/>",
|
||||||
|
i, cpu->sve_max_vq * 16, base_reg++);
|
||||||
|
info->num++;
|
||||||
|
}
|
||||||
|
g_string_append_printf(s,
|
||||||
|
"<reg name=\"ffr\" bitsize=\"%d\""
|
||||||
|
" regnum=\"%d\" group=\"vector\""
|
||||||
|
" type=\"vqp\"/>",
|
||||||
|
cpu->sve_max_vq * 16, base_reg++);
|
||||||
|
g_string_append_printf(s,
|
||||||
|
"<reg name=\"vg\" bitsize=\"64\""
|
||||||
|
" regnum=\"%d\" group=\"vector\""
|
||||||
|
" type=\"uint32\"/>",
|
||||||
|
base_reg++);
|
||||||
|
info->num += 2;
|
||||||
|
g_string_append_printf(s, "</feature>");
|
||||||
|
cpu->dyn_svereg_xml.desc = g_string_free(s, false);
|
||||||
|
|
||||||
|
return cpu->dyn_svereg_xml.num;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
|
const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = ARM_CPU(cs);
|
ARMCPU *cpu = ARM_CPU(cs);
|
||||||
|
|
||||||
if (strcmp(xmlname, "system-registers.xml") == 0) {
|
if (strcmp(xmlname, "system-registers.xml") == 0) {
|
||||||
return cpu->dyn_xml.desc;
|
return cpu->dyn_sysreg_xml.desc;
|
||||||
|
} else if (strcmp(xmlname, "sve-registers.xml") == 0) {
|
||||||
|
return cpu->dyn_svereg_xml.desc;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
int aarch64_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int aarch64_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = ARM_CPU(cs);
|
ARMCPU *cpu = ARM_CPU(cs);
|
||||||
CPUARMState *env = &cpu->env;
|
CPUARMState *env = &cpu->env;
|
||||||
|
|
|
@ -48,30 +48,27 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
|
||||||
|
|
||||||
static void switch_mode(CPUARMState *env, int mode);
|
static void switch_mode(CPUARMState *env, int mode);
|
||||||
|
|
||||||
static int vfp_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
|
static int vfp_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = env_archcpu(env);
|
ARMCPU *cpu = env_archcpu(env);
|
||||||
int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16;
|
int nregs = cpu_isar_feature(aa32_simd_r32, cpu) ? 32 : 16;
|
||||||
|
|
||||||
/* VFP data registers are always little-endian. */
|
/* VFP data registers are always little-endian. */
|
||||||
if (reg < nregs) {
|
if (reg < nregs) {
|
||||||
stq_le_p(buf, *aa32_vfp_dreg(env, reg));
|
return gdb_get_reg64(buf, *aa32_vfp_dreg(env, reg));
|
||||||
return 8;
|
|
||||||
}
|
}
|
||||||
if (arm_feature(env, ARM_FEATURE_NEON)) {
|
if (arm_feature(env, ARM_FEATURE_NEON)) {
|
||||||
/* Aliases for Q regs. */
|
/* Aliases for Q regs. */
|
||||||
nregs += 16;
|
nregs += 16;
|
||||||
if (reg < nregs) {
|
if (reg < nregs) {
|
||||||
uint64_t *q = aa32_vfp_qreg(env, reg - 32);
|
uint64_t *q = aa32_vfp_qreg(env, reg - 32);
|
||||||
stq_le_p(buf, q[0]);
|
return gdb_get_reg128(buf, q[0], q[1]);
|
||||||
stq_le_p(buf + 8, q[1]);
|
|
||||||
return 16;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (reg - nregs) {
|
switch (reg - nregs) {
|
||||||
case 0: stl_p(buf, env->vfp.xregs[ARM_VFP_FPSID]); return 4;
|
case 0: return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPSID]); break;
|
||||||
case 1: stl_p(buf, vfp_get_fpscr(env)); return 4;
|
case 1: return gdb_get_reg32(buf, vfp_get_fpscr(env)); break;
|
||||||
case 2: stl_p(buf, env->vfp.xregs[ARM_VFP_FPEXC]); return 4;
|
case 2: return gdb_get_reg32(buf, env->vfp.xregs[ARM_VFP_FPEXC]); break;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -102,25 +99,21 @@ static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int aarch64_fpu_gdb_get_reg(CPUARMState *env, uint8_t *buf, int reg)
|
static int aarch64_fpu_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg)
|
||||||
{
|
{
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
case 0 ... 31:
|
case 0 ... 31:
|
||||||
/* 128 bit FP register */
|
{
|
||||||
{
|
/* 128 bit FP register - quads are in LE order */
|
||||||
uint64_t *q = aa64_vfp_qreg(env, reg);
|
uint64_t *q = aa64_vfp_qreg(env, reg);
|
||||||
stq_le_p(buf, q[0]);
|
return gdb_get_reg128(buf, q[1], q[0]);
|
||||||
stq_le_p(buf + 8, q[1]);
|
}
|
||||||
return 16;
|
|
||||||
}
|
|
||||||
case 32:
|
case 32:
|
||||||
/* FPSR */
|
/* FPSR */
|
||||||
stl_p(buf, vfp_get_fpsr(env));
|
return gdb_get_reg32(buf, vfp_get_fpsr(env));
|
||||||
return 4;
|
|
||||||
case 33:
|
case 33:
|
||||||
/* FPCR */
|
/* FPCR */
|
||||||
stl_p(buf, vfp_get_fpcr(env));
|
return gdb_get_reg32(buf,vfp_get_fpcr(env));
|
||||||
return 4;
|
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -209,13 +202,22 @@ static void write_raw_cp_reg(CPUARMState *env, const ARMCPRegInfo *ri,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int arm_gdb_get_sysreg(CPUARMState *env, uint8_t *buf, int reg)
|
/**
|
||||||
|
* arm_get/set_gdb_*: get/set a gdb register
|
||||||
|
* @env: the CPU state
|
||||||
|
* @buf: a buffer to copy to/from
|
||||||
|
* @reg: register number (offset from start of group)
|
||||||
|
*
|
||||||
|
* We return the number of bytes copied
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int arm_gdb_get_sysreg(CPUARMState *env, GByteArray *buf, int reg)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = env_archcpu(env);
|
ARMCPU *cpu = env_archcpu(env);
|
||||||
const ARMCPRegInfo *ri;
|
const ARMCPRegInfo *ri;
|
||||||
uint32_t key;
|
uint32_t key;
|
||||||
|
|
||||||
key = cpu->dyn_xml.cpregs_keys[reg];
|
key = cpu->dyn_sysreg_xml.data.cpregs.keys[reg];
|
||||||
ri = get_arm_cp_reginfo(cpu->cp_regs, key);
|
ri = get_arm_cp_reginfo(cpu->cp_regs, key);
|
||||||
if (ri) {
|
if (ri) {
|
||||||
if (cpreg_field_is_64bit(ri)) {
|
if (cpreg_field_is_64bit(ri)) {
|
||||||
|
@ -232,6 +234,102 @@ static int arm_gdb_set_sysreg(CPUARMState *env, uint8_t *buf, int reg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TARGET_AARCH64
|
||||||
|
static int arm_gdb_get_svereg(CPUARMState *env, GByteArray *buf, int reg)
|
||||||
|
{
|
||||||
|
ARMCPU *cpu = env_archcpu(env);
|
||||||
|
|
||||||
|
switch (reg) {
|
||||||
|
/* The first 32 registers are the zregs */
|
||||||
|
case 0 ... 31:
|
||||||
|
{
|
||||||
|
int vq, len = 0;
|
||||||
|
for (vq = 0; vq < cpu->sve_max_vq; vq++) {
|
||||||
|
len += gdb_get_reg128(buf,
|
||||||
|
env->vfp.zregs[reg].d[vq * 2 + 1],
|
||||||
|
env->vfp.zregs[reg].d[vq * 2]);
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
case 32:
|
||||||
|
return gdb_get_reg32(buf, vfp_get_fpsr(env));
|
||||||
|
case 33:
|
||||||
|
return gdb_get_reg32(buf, vfp_get_fpcr(env));
|
||||||
|
/* then 16 predicates and the ffr */
|
||||||
|
case 34 ... 50:
|
||||||
|
{
|
||||||
|
int preg = reg - 34;
|
||||||
|
int vq, len = 0;
|
||||||
|
for (vq = 0; vq < cpu->sve_max_vq; vq = vq + 4) {
|
||||||
|
len += gdb_get_reg64(buf, env->vfp.pregs[preg].p[vq / 4]);
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
case 51:
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We report in Vector Granules (VG) which is 64bit in a Z reg
|
||||||
|
* while the ZCR works in Vector Quads (VQ) which is 128bit chunks.
|
||||||
|
*/
|
||||||
|
int vq = sve_zcr_len_for_el(env, arm_current_el(env)) + 1;
|
||||||
|
return gdb_get_reg32(buf, vq * 2);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
/* gdbstub asked for something out our range */
|
||||||
|
qemu_log_mask(LOG_UNIMP, "%s: out of range register %d", __func__, reg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int arm_gdb_set_svereg(CPUARMState *env, uint8_t *buf, int reg)
|
||||||
|
{
|
||||||
|
ARMCPU *cpu = env_archcpu(env);
|
||||||
|
|
||||||
|
/* The first 32 registers are the zregs */
|
||||||
|
switch (reg) {
|
||||||
|
/* The first 32 registers are the zregs */
|
||||||
|
case 0 ... 31:
|
||||||
|
{
|
||||||
|
int vq, len = 0;
|
||||||
|
uint64_t *p = (uint64_t *) buf;
|
||||||
|
for (vq = 0; vq < cpu->sve_max_vq; vq++) {
|
||||||
|
env->vfp.zregs[reg].d[vq * 2 + 1] = *p++;
|
||||||
|
env->vfp.zregs[reg].d[vq * 2] = *p++;
|
||||||
|
len += 16;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
case 32:
|
||||||
|
vfp_set_fpsr(env, *(uint32_t *)buf);
|
||||||
|
return 4;
|
||||||
|
case 33:
|
||||||
|
vfp_set_fpcr(env, *(uint32_t *)buf);
|
||||||
|
return 4;
|
||||||
|
case 34 ... 50:
|
||||||
|
{
|
||||||
|
int preg = reg - 34;
|
||||||
|
int vq, len = 0;
|
||||||
|
uint64_t *p = (uint64_t *) buf;
|
||||||
|
for (vq = 0; vq < cpu->sve_max_vq; vq = vq + 4) {
|
||||||
|
env->vfp.pregs[preg].p[vq / 4] = *p++;
|
||||||
|
len += 8;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
case 51:
|
||||||
|
/* cannot set vg via gdbstub */
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
/* gdbstub asked for something out our range */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* TARGET_AARCH64 */
|
||||||
|
|
||||||
static bool raw_accessors_invalid(const ARMCPRegInfo *ri)
|
static bool raw_accessors_invalid(const ARMCPRegInfo *ri)
|
||||||
{
|
{
|
||||||
/* Return true if the regdef would cause an assertion if you called
|
/* Return true if the regdef would cause an assertion if you called
|
||||||
|
@ -6599,6 +6697,7 @@ static uint64_t id_pfr1_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
return pfr1;
|
return pfr1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_USER_ONLY
|
||||||
static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
{
|
{
|
||||||
ARMCPU *cpu = env_archcpu(env);
|
ARMCPU *cpu = env_archcpu(env);
|
||||||
|
@ -6609,6 +6708,7 @@ static uint64_t id_aa64pfr0_read(CPUARMState *env, const ARMCPRegInfo *ri)
|
||||||
}
|
}
|
||||||
return pfr0;
|
return pfr0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Shared logic between LORID and the rest of the LOR* registers.
|
/* Shared logic between LORID and the rest of the LOR* registers.
|
||||||
* Secure state has already been delt with.
|
* Secure state has already been delt with.
|
||||||
|
@ -7182,16 +7282,24 @@ void register_cp_regs_for_features(ARMCPU *cpu)
|
||||||
* define new registers here.
|
* define new registers here.
|
||||||
*/
|
*/
|
||||||
ARMCPRegInfo v8_idregs[] = {
|
ARMCPRegInfo v8_idregs[] = {
|
||||||
/* ID_AA64PFR0_EL1 is not a plain ARM_CP_CONST because we don't
|
/*
|
||||||
* know the right value for the GIC field until after we
|
* ID_AA64PFR0_EL1 is not a plain ARM_CP_CONST in system
|
||||||
* define these regs.
|
* emulation because we don't know the right value for the
|
||||||
|
* GIC field until after we define these regs.
|
||||||
*/
|
*/
|
||||||
{ .name = "ID_AA64PFR0_EL1", .state = ARM_CP_STATE_AA64,
|
{ .name = "ID_AA64PFR0_EL1", .state = ARM_CP_STATE_AA64,
|
||||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 0,
|
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 0,
|
||||||
.access = PL1_R, .type = ARM_CP_NO_RAW,
|
.access = PL1_R,
|
||||||
|
#ifdef CONFIG_USER_ONLY
|
||||||
|
.type = ARM_CP_CONST,
|
||||||
|
.resetvalue = cpu->isar.id_aa64pfr0
|
||||||
|
#else
|
||||||
|
.type = ARM_CP_NO_RAW,
|
||||||
.accessfn = access_aa64_tid3,
|
.accessfn = access_aa64_tid3,
|
||||||
.readfn = id_aa64pfr0_read,
|
.readfn = id_aa64pfr0_read,
|
||||||
.writefn = arm_cp_write_ignore },
|
.writefn = arm_cp_write_ignore
|
||||||
|
#endif
|
||||||
|
},
|
||||||
{ .name = "ID_AA64PFR1_EL1", .state = ARM_CP_STATE_AA64,
|
{ .name = "ID_AA64PFR1_EL1", .state = ARM_CP_STATE_AA64,
|
||||||
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 1,
|
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 4, .opc2 = 1,
|
||||||
.access = PL1_R, .type = ARM_CP_CONST,
|
.access = PL1_R, .type = ARM_CP_CONST,
|
||||||
|
@ -7966,9 +8074,22 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
|
||||||
CPUARMState *env = &cpu->env;
|
CPUARMState *env = &cpu->env;
|
||||||
|
|
||||||
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
|
if (arm_feature(env, ARM_FEATURE_AARCH64)) {
|
||||||
gdb_register_coprocessor(cs, aarch64_fpu_gdb_get_reg,
|
/*
|
||||||
aarch64_fpu_gdb_set_reg,
|
* The lower part of each SVE register aliases to the FPU
|
||||||
34, "aarch64-fpu.xml", 0);
|
* registers so we don't need to include both.
|
||||||
|
*/
|
||||||
|
#ifdef TARGET_AARCH64
|
||||||
|
if (isar_feature_aa64_sve(&cpu->isar)) {
|
||||||
|
gdb_register_coprocessor(cs, arm_gdb_get_svereg, arm_gdb_set_svereg,
|
||||||
|
arm_gen_dynamic_svereg_xml(cs, cs->gdb_num_regs),
|
||||||
|
"sve-registers.xml", 0);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
gdb_register_coprocessor(cs, aarch64_fpu_gdb_get_reg,
|
||||||
|
aarch64_fpu_gdb_set_reg,
|
||||||
|
34, "aarch64-fpu.xml", 0);
|
||||||
|
}
|
||||||
} else if (arm_feature(env, ARM_FEATURE_NEON)) {
|
} else if (arm_feature(env, ARM_FEATURE_NEON)) {
|
||||||
gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
|
gdb_register_coprocessor(cs, vfp_gdb_get_reg, vfp_gdb_set_reg,
|
||||||
51, "arm-neon.xml", 0);
|
51, "arm-neon.xml", 0);
|
||||||
|
@ -7980,8 +8101,9 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
|
||||||
19, "arm-vfp.xml", 0);
|
19, "arm-vfp.xml", 0);
|
||||||
}
|
}
|
||||||
gdb_register_coprocessor(cs, arm_gdb_get_sysreg, arm_gdb_set_sysreg,
|
gdb_register_coprocessor(cs, arm_gdb_get_sysreg, arm_gdb_set_sysreg,
|
||||||
arm_gen_dynamic_xml(cs),
|
arm_gen_dynamic_sysreg_xml(cs, cs->gdb_num_regs),
|
||||||
"system-registers.xml", 0);
|
"system-registers.xml", 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sort alphabetically by type name, except for "any". */
|
/* Sort alphabetically by type name, except for "any". */
|
||||||
|
|
|
@ -195,8 +195,8 @@ void cris_cpu_dump_state(CPUState *cs, FILE *f, int flags);
|
||||||
|
|
||||||
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 crisv10_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int cris_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
int cris_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int cris_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int cris_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
int crisv10_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int crisv10_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
CRISCPU *cpu = CRIS_CPU(cs);
|
CRISCPU *cpu = CRIS_CPU(cs);
|
||||||
CPUCRISState *env = &cpu->env;
|
CPUCRISState *env = &cpu->env;
|
||||||
|
@ -53,7 +53,7 @@ int crisv10_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cris_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int cris_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
CRISCPU *cpu = CRIS_CPU(cs);
|
CRISCPU *cpu = CRIS_CPU(cs);
|
||||||
CPUCRISState *env = &cpu->env;
|
CPUCRISState *env = &cpu->env;
|
||||||
|
|
|
@ -321,7 +321,7 @@ void cpu_hppa_change_prot_id(CPUHPPAState *env);
|
||||||
|
|
||||||
int cpu_hppa_signal_handler(int host_signum, void *pinfo, void *puc);
|
int cpu_hppa_signal_handler(int host_signum, void *pinfo, void *puc);
|
||||||
hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr);
|
hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr);
|
||||||
int hppa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
int hppa_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int hppa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int hppa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
void hppa_cpu_do_interrupt(CPUState *cpu);
|
void hppa_cpu_do_interrupt(CPUState *cpu);
|
||||||
bool hppa_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
bool hppa_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
int hppa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int hppa_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
HPPACPU *cpu = HPPA_CPU(cs);
|
HPPACPU *cpu = HPPA_CPU(cs);
|
||||||
CPUHPPAState *env = &cpu->env;
|
CPUHPPAState *env = &cpu->env;
|
||||||
|
|
|
@ -1766,7 +1766,7 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, int flags);
|
||||||
hwaddr x86_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
|
hwaddr x86_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
|
||||||
MemTxAttrs *attrs);
|
MemTxAttrs *attrs);
|
||||||
|
|
||||||
int x86_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
int x86_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int x86_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int x86_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
void x86_cpu_exec_enter(CPUState *cpu);
|
void x86_cpu_exec_enter(CPUState *cpu);
|
||||||
|
|
|
@ -79,7 +79,7 @@ static const int gpr_map32[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int x86_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int x86_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
X86CPU *cpu = X86_CPU(cs);
|
X86CPU *cpu = X86_CPU(cs);
|
||||||
CPUX86State *env = &cpu->env;
|
CPUX86State *env = &cpu->env;
|
||||||
|
@ -98,26 +98,22 @@ int x86_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
return gdb_get_reg64(mem_buf,
|
return gdb_get_reg64(mem_buf,
|
||||||
env->regs[gpr_map[n]] & 0xffffffffUL);
|
env->regs[gpr_map[n]] & 0xffffffffUL);
|
||||||
} else {
|
} else {
|
||||||
memset(mem_buf, 0, sizeof(target_ulong));
|
return gdb_get_regl(mem_buf, 0);
|
||||||
return sizeof(target_ulong);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return gdb_get_reg32(mem_buf, env->regs[gpr_map32[n]]);
|
return gdb_get_reg32(mem_buf, env->regs[gpr_map32[n]]);
|
||||||
}
|
}
|
||||||
} else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
|
} else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
|
||||||
#ifdef USE_X86LDOUBLE
|
floatx80 *fp = (floatx80 *) &env->fpregs[n - IDX_FP_REGS];
|
||||||
/* FIXME: byteswap float values - after fixing fpregs layout. */
|
int len = gdb_get_reg64(mem_buf, cpu_to_le64(fp->low));
|
||||||
memcpy(mem_buf, &env->fpregs[n - IDX_FP_REGS], 10);
|
len += gdb_get_reg16(mem_buf + len, cpu_to_le16(fp->high));
|
||||||
#else
|
return len;
|
||||||
memset(mem_buf, 0, 10);
|
|
||||||
#endif
|
|
||||||
return 10;
|
|
||||||
} else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
|
} else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
|
||||||
n -= IDX_XMM_REGS;
|
n -= IDX_XMM_REGS;
|
||||||
if (n < CPU_NB_REGS32 || TARGET_LONG_BITS == 64) {
|
if (n < CPU_NB_REGS32 || TARGET_LONG_BITS == 64) {
|
||||||
stq_p(mem_buf, env->xmm_regs[n].ZMM_Q(0));
|
return gdb_get_reg128(mem_buf,
|
||||||
stq_p(mem_buf + 8, env->xmm_regs[n].ZMM_Q(1));
|
env->xmm_regs[n].ZMM_Q(0),
|
||||||
return 16;
|
env->xmm_regs[n].ZMM_Q(1));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (n) {
|
switch (n) {
|
||||||
|
@ -290,10 +286,9 @@ int x86_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
} else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
|
} else if (n >= IDX_FP_REGS && n < IDX_FP_REGS + 8) {
|
||||||
#ifdef USE_X86LDOUBLE
|
floatx80 *fp = (floatx80 *) &env->fpregs[n - IDX_FP_REGS];
|
||||||
/* FIXME: byteswap float values - after fixing fpregs layout. */
|
fp->low = le64_to_cpu(* (uint64_t *) mem_buf);
|
||||||
memcpy(&env->fpregs[n - IDX_FP_REGS], mem_buf, 10);
|
fp->high = le16_to_cpu(* (uint16_t *) (mem_buf + 8));
|
||||||
#endif
|
|
||||||
return 10;
|
return 10;
|
||||||
} else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
|
} else if (n >= IDX_XMM_REGS && n < IDX_XMM_REGS + CPU_NB_REGS) {
|
||||||
n -= IDX_XMM_REGS;
|
n -= IDX_XMM_REGS;
|
||||||
|
|
|
@ -202,7 +202,7 @@ void lm32_cpu_do_interrupt(CPUState *cpu);
|
||||||
bool lm32_cpu_exec_interrupt(CPUState *cs, int int_req);
|
bool lm32_cpu_exec_interrupt(CPUState *cs, int int_req);
|
||||||
void lm32_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
|
void lm32_cpu_dump_state(CPUState *cpu, FILE *f, 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_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int lm32_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int lm32_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
#include "hw/lm32/lm32_pic.h"
|
#include "hw/lm32/lm32_pic.h"
|
||||||
|
|
||||||
int lm32_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int lm32_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
LM32CPU *cpu = LM32_CPU(cs);
|
LM32CPU *cpu = LM32_CPU(cs);
|
||||||
CPULM32State *env = &cpu->env;
|
CPULM32State *env = &cpu->env;
|
||||||
|
|
|
@ -168,7 +168,7 @@ void m68k_cpu_do_interrupt(CPUState *cpu);
|
||||||
bool m68k_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
bool m68k_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||||
void m68k_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
|
void m68k_cpu_dump_state(CPUState *cpu, FILE *f, 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_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int m68k_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int m68k_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
void m68k_tcg_init(void);
|
void m68k_tcg_init(void);
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
int m68k_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int m68k_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
M68kCPU *cpu = M68K_CPU(cs);
|
M68kCPU *cpu = M68K_CPU(cs);
|
||||||
CPUM68KState *env = &cpu->env;
|
CPUM68KState *env = &cpu->env;
|
||||||
|
|
|
@ -68,23 +68,19 @@ void m68k_cpu_list(void)
|
||||||
g_slist_free(list);
|
g_slist_free(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cf_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
|
static int cf_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
if (n < 8) {
|
if (n < 8) {
|
||||||
float_status s;
|
float_status s;
|
||||||
stfq_p(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
|
return gdb_get_reg64(mem_buf, floatx80_to_float64(env->fregs[n].d, &s));
|
||||||
return 8;
|
|
||||||
}
|
}
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case 8: /* fpcontrol */
|
case 8: /* fpcontrol */
|
||||||
stl_be_p(mem_buf, env->fpcr);
|
return gdb_get_reg32(mem_buf, env->fpcr);
|
||||||
return 4;
|
|
||||||
case 9: /* fpstatus */
|
case 9: /* fpstatus */
|
||||||
stl_be_p(mem_buf, env->fpsr);
|
return gdb_get_reg32(mem_buf, env->fpsr);
|
||||||
return 4;
|
|
||||||
case 10: /* fpiar, not implemented */
|
case 10: /* fpiar, not implemented */
|
||||||
memset(mem_buf, 0, 4);
|
return gdb_get_reg32(mem_buf, 0);
|
||||||
return 4;
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -109,24 +105,21 @@ static int cf_fpu_gdb_set_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int m68k_fpu_gdb_get_reg(CPUM68KState *env, uint8_t *mem_buf, int n)
|
static int m68k_fpu_gdb_get_reg(CPUM68KState *env, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
if (n < 8) {
|
if (n < 8) {
|
||||||
stw_be_p(mem_buf, env->fregs[n].l.upper);
|
int len = gdb_get_reg16(mem_buf, env->fregs[n].l.upper);
|
||||||
memset(mem_buf + 2, 0, 2);
|
len += gdb_get_reg16(mem_buf + len, 0);
|
||||||
stq_be_p(mem_buf + 4, env->fregs[n].l.lower);
|
len += gdb_get_reg64(mem_buf + len, env->fregs[n].l.lower);
|
||||||
return 12;
|
return len;
|
||||||
}
|
}
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case 8: /* fpcontrol */
|
case 8: /* fpcontrol */
|
||||||
stl_be_p(mem_buf, env->fpcr);
|
return gdb_get_reg32(mem_buf, env->fpcr);
|
||||||
return 4;
|
|
||||||
case 9: /* fpstatus */
|
case 9: /* fpstatus */
|
||||||
stl_be_p(mem_buf, env->fpsr);
|
return gdb_get_reg32(mem_buf, env->fpsr);
|
||||||
return 4;
|
|
||||||
case 10: /* fpiar, not implemented */
|
case 10: /* fpiar, not implemented */
|
||||||
memset(mem_buf, 0, 4);
|
return gdb_get_reg32(mem_buf, 0);
|
||||||
return 4;
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -313,7 +313,7 @@ void mb_cpu_do_interrupt(CPUState *cs);
|
||||||
bool mb_cpu_exec_interrupt(CPUState *cs, int int_req);
|
bool mb_cpu_exec_interrupt(CPUState *cs, int int_req);
|
||||||
void mb_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
|
void mb_cpu_dump_state(CPUState *cpu, FILE *f, 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_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int mb_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int mb_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
|
|
||||||
void mb_tcg_init(void);
|
void mb_tcg_init(void);
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
int mb_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int mb_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs);
|
||||||
CPUMBState *env = &cpu->env;
|
CPUMBState *env = &cpu->env;
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
int mips_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int mips_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
MIPSCPU *cpu = MIPS_CPU(cs);
|
MIPSCPU *cpu = MIPS_CPU(cs);
|
||||||
CPUMIPSState *env = &cpu->env;
|
CPUMIPSState *env = &cpu->env;
|
||||||
|
|
|
@ -82,7 +82,7 @@ void mips_cpu_do_interrupt(CPUState *cpu);
|
||||||
bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||||
void mips_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
|
void mips_cpu_dump_state(CPUState *cpu, FILE *f, 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_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
||||||
MMUAccessType access_type,
|
MMUAccessType access_type,
|
||||||
|
|
|
@ -124,7 +124,7 @@ static void nios2_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nios2_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
static int nios2_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
Nios2CPU *cpu = NIOS2_CPU(cs);
|
Nios2CPU *cpu = NIOS2_CPU(cs);
|
||||||
CPUClass *cc = CPU_GET_CLASS(cs);
|
CPUClass *cc = CPU_GET_CLASS(cs);
|
||||||
|
|
|
@ -320,7 +320,7 @@ void openrisc_cpu_do_interrupt(CPUState *cpu);
|
||||||
bool openrisc_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
bool openrisc_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||||
void openrisc_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
|
void openrisc_cpu_dump_state(CPUState *cpu, FILE *f, 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_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int openrisc_cpu_gdb_write_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);
|
||||||
bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
bool openrisc_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "exec/gdbstub.h"
|
#include "exec/gdbstub.h"
|
||||||
|
|
||||||
int openrisc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int openrisc_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
OpenRISCCPU *cpu = OPENRISC_CPU(cs);
|
OpenRISCCPU *cpu = OPENRISC_CPU(cs);
|
||||||
CPUOpenRISCState *env = &cpu->env;
|
CPUOpenRISCState *env = &cpu->env;
|
||||||
|
|
|
@ -1207,8 +1207,8 @@ bool ppc_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||||
void ppc_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
|
void ppc_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
|
||||||
void ppc_cpu_dump_statistics(CPUState *cpu, int flags);
|
void ppc_cpu_dump_statistics(CPUState *cpu, 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_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int ppc_cpu_gdb_read_register_apple(CPUState *cpu, uint8_t *buf, int reg);
|
int ppc_cpu_gdb_read_register_apple(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int ppc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
int ppc_cpu_gdb_write_register_apple(CPUState *cpu, uint8_t *buf, int reg);
|
int ppc_cpu_gdb_write_register_apple(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
|
|
|
@ -114,10 +114,11 @@ void ppc_maybe_bswap_register(CPUPPCState *env, uint8_t *mem_buf, int len)
|
||||||
* the FP regs zero size when talking to a newer gdb.
|
* 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)
|
int ppc_cpu_gdb_read_register(CPUState *cs, GByteArray *buf, int n)
|
||||||
{
|
{
|
||||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||||
CPUPPCState *env = &cpu->env;
|
CPUPPCState *env = &cpu->env;
|
||||||
|
uint8_t *mem_buf;
|
||||||
int r = ppc_gdb_register_len(n);
|
int r = ppc_gdb_register_len(n);
|
||||||
|
|
||||||
if (!r) {
|
if (!r) {
|
||||||
|
@ -126,17 +127,17 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
|
||||||
if (n < 32) {
|
if (n < 32) {
|
||||||
/* gprs */
|
/* gprs */
|
||||||
gdb_get_regl(mem_buf, env->gpr[n]);
|
gdb_get_regl(buf, env->gpr[n]);
|
||||||
} else if (n < 64) {
|
} else if (n < 64) {
|
||||||
/* fprs */
|
/* fprs */
|
||||||
stfq_p(mem_buf, *cpu_fpr_ptr(env, n - 32));
|
gdb_get_reg64(buf, *cpu_fpr_ptr(env, n - 32));
|
||||||
} else {
|
} else {
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case 64:
|
case 64:
|
||||||
gdb_get_regl(mem_buf, env->nip);
|
gdb_get_regl(buf, env->nip);
|
||||||
break;
|
break;
|
||||||
case 65:
|
case 65:
|
||||||
gdb_get_regl(mem_buf, env->msr);
|
gdb_get_regl(buf, env->msr);
|
||||||
break;
|
break;
|
||||||
case 66:
|
case 66:
|
||||||
{
|
{
|
||||||
|
@ -145,31 +146,33 @@ int ppc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
cr |= env->crf[i] << (32 - ((i + 1) * 4));
|
cr |= env->crf[i] << (32 - ((i + 1) * 4));
|
||||||
}
|
}
|
||||||
gdb_get_reg32(mem_buf, cr);
|
gdb_get_reg32(buf, cr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 67:
|
case 67:
|
||||||
gdb_get_regl(mem_buf, env->lr);
|
gdb_get_regl(buf, env->lr);
|
||||||
break;
|
break;
|
||||||
case 68:
|
case 68:
|
||||||
gdb_get_regl(mem_buf, env->ctr);
|
gdb_get_regl(buf, env->ctr);
|
||||||
break;
|
break;
|
||||||
case 69:
|
case 69:
|
||||||
gdb_get_reg32(mem_buf, env->xer);
|
gdb_get_reg32(buf, env->xer);
|
||||||
break;
|
break;
|
||||||
case 70:
|
case 70:
|
||||||
gdb_get_reg32(mem_buf, env->fpscr);
|
gdb_get_reg32(buf, env->fpscr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mem_buf = buf->data + buf->len - r;
|
||||||
ppc_maybe_bswap_register(env, mem_buf, r);
|
ppc_maybe_bswap_register(env, mem_buf, r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
|
int ppc_cpu_gdb_read_register_apple(CPUState *cs, GByteArray *buf, int n)
|
||||||
{
|
{
|
||||||
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
PowerPCCPU *cpu = POWERPC_CPU(cs);
|
||||||
CPUPPCState *env = &cpu->env;
|
CPUPPCState *env = &cpu->env;
|
||||||
|
uint8_t *mem_buf;
|
||||||
int r = ppc_gdb_register_len_apple(n);
|
int r = ppc_gdb_register_len_apple(n);
|
||||||
|
|
||||||
if (!r) {
|
if (!r) {
|
||||||
|
@ -178,21 +181,21 @@ int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
|
|
||||||
if (n < 32) {
|
if (n < 32) {
|
||||||
/* gprs */
|
/* gprs */
|
||||||
gdb_get_reg64(mem_buf, env->gpr[n]);
|
gdb_get_reg64(buf, env->gpr[n]);
|
||||||
} else if (n < 64) {
|
} else if (n < 64) {
|
||||||
/* fprs */
|
/* fprs */
|
||||||
stfq_p(mem_buf, *cpu_fpr_ptr(env, n - 32));
|
gdb_get_reg64(buf, *cpu_fpr_ptr(env, n - 32));
|
||||||
} else if (n < 96) {
|
} else if (n < 96) {
|
||||||
/* Altivec */
|
/* Altivec */
|
||||||
stq_p(mem_buf, n - 64);
|
gdb_get_reg64(buf, n - 64);
|
||||||
stq_p(mem_buf + 8, 0);
|
gdb_get_reg64(buf, 0);
|
||||||
} else {
|
} else {
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case 64 + 32:
|
case 64 + 32:
|
||||||
gdb_get_reg64(mem_buf, env->nip);
|
gdb_get_reg64(buf, env->nip);
|
||||||
break;
|
break;
|
||||||
case 65 + 32:
|
case 65 + 32:
|
||||||
gdb_get_reg64(mem_buf, env->msr);
|
gdb_get_reg64(buf, env->msr);
|
||||||
break;
|
break;
|
||||||
case 66 + 32:
|
case 66 + 32:
|
||||||
{
|
{
|
||||||
|
@ -201,23 +204,24 @@ int ppc_cpu_gdb_read_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
cr |= env->crf[i] << (32 - ((i + 1) * 4));
|
cr |= env->crf[i] << (32 - ((i + 1) * 4));
|
||||||
}
|
}
|
||||||
gdb_get_reg32(mem_buf, cr);
|
gdb_get_reg32(buf, cr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 67 + 32:
|
case 67 + 32:
|
||||||
gdb_get_reg64(mem_buf, env->lr);
|
gdb_get_reg64(buf, env->lr);
|
||||||
break;
|
break;
|
||||||
case 68 + 32:
|
case 68 + 32:
|
||||||
gdb_get_reg64(mem_buf, env->ctr);
|
gdb_get_reg64(buf, env->ctr);
|
||||||
break;
|
break;
|
||||||
case 69 + 32:
|
case 69 + 32:
|
||||||
gdb_get_reg32(mem_buf, env->xer);
|
gdb_get_reg32(buf, env->xer);
|
||||||
break;
|
break;
|
||||||
case 70 + 32:
|
case 70 + 32:
|
||||||
gdb_get_reg64(mem_buf, env->fpscr);
|
gdb_get_reg64(buf, env->fpscr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mem_buf = buf->data + buf->len - r;
|
||||||
ppc_maybe_bswap_register(env, mem_buf, r);
|
ppc_maybe_bswap_register(env, mem_buf, r);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9843,7 +9843,7 @@ static int gdb_find_spr_idx(CPUPPCState *env, int n)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gdb_get_spr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
|
static int gdb_get_spr_reg(CPUPPCState *env, GByteArray *buf, int n)
|
||||||
{
|
{
|
||||||
int reg;
|
int reg;
|
||||||
int len;
|
int len;
|
||||||
|
@ -9854,8 +9854,8 @@ static int gdb_get_spr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
|
||||||
}
|
}
|
||||||
|
|
||||||
len = TARGET_LONG_SIZE;
|
len = TARGET_LONG_SIZE;
|
||||||
stn_p(mem_buf, len, env->spr[reg]);
|
gdb_get_regl(buf, env->spr[reg]);
|
||||||
ppc_maybe_bswap_register(env, mem_buf, len);
|
ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, len), len);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9877,15 +9877,18 @@ static int gdb_set_spr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int gdb_get_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
|
static int gdb_get_float_reg(CPUPPCState *env, GByteArray *buf, int n)
|
||||||
{
|
{
|
||||||
|
uint8_t *mem_buf;
|
||||||
if (n < 32) {
|
if (n < 32) {
|
||||||
stfq_p(mem_buf, *cpu_fpr_ptr(env, n));
|
gdb_get_reg64(buf, *cpu_fpr_ptr(env, n));
|
||||||
|
mem_buf = gdb_get_reg_ptr(buf, 8);
|
||||||
ppc_maybe_bswap_register(env, mem_buf, 8);
|
ppc_maybe_bswap_register(env, mem_buf, 8);
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
if (n == 32) {
|
if (n == 32) {
|
||||||
stl_p(mem_buf, env->fpscr);
|
gdb_get_reg32(buf, env->fpscr);
|
||||||
|
mem_buf = gdb_get_reg_ptr(buf, 4);
|
||||||
ppc_maybe_bswap_register(env, mem_buf, 4);
|
ppc_maybe_bswap_register(env, mem_buf, 4);
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
@ -9907,28 +9910,31 @@ static int gdb_set_float_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gdb_get_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
|
static int gdb_get_avr_reg(CPUPPCState *env, GByteArray *buf, int n)
|
||||||
{
|
{
|
||||||
|
uint8_t *mem_buf;
|
||||||
|
|
||||||
if (n < 32) {
|
if (n < 32) {
|
||||||
ppc_avr_t *avr = cpu_avr_ptr(env, n);
|
ppc_avr_t *avr = cpu_avr_ptr(env, n);
|
||||||
if (!avr_need_swap(env)) {
|
if (!avr_need_swap(env)) {
|
||||||
stq_p(mem_buf, avr->u64[0]);
|
gdb_get_reg128(buf, avr->u64[0] , avr->u64[1]);
|
||||||
stq_p(mem_buf + 8, avr->u64[1]);
|
|
||||||
} else {
|
} else {
|
||||||
stq_p(mem_buf, avr->u64[1]);
|
gdb_get_reg128(buf, avr->u64[1] , avr->u64[0]);
|
||||||
stq_p(mem_buf + 8, avr->u64[0]);
|
|
||||||
}
|
}
|
||||||
|
mem_buf = gdb_get_reg_ptr(buf, 16);
|
||||||
ppc_maybe_bswap_register(env, mem_buf, 8);
|
ppc_maybe_bswap_register(env, mem_buf, 8);
|
||||||
ppc_maybe_bswap_register(env, mem_buf + 8, 8);
|
ppc_maybe_bswap_register(env, mem_buf + 8, 8);
|
||||||
return 16;
|
return 16;
|
||||||
}
|
}
|
||||||
if (n == 32) {
|
if (n == 32) {
|
||||||
stl_p(mem_buf, helper_mfvscr(env));
|
gdb_get_reg32(buf, helper_mfvscr(env));
|
||||||
|
mem_buf = gdb_get_reg_ptr(buf, 4);
|
||||||
ppc_maybe_bswap_register(env, mem_buf, 4);
|
ppc_maybe_bswap_register(env, mem_buf, 4);
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
if (n == 33) {
|
if (n == 33) {
|
||||||
stl_p(mem_buf, (uint32_t)env->spr[SPR_VRSAVE]);
|
gdb_get_reg32(buf, (uint32_t)env->spr[SPR_VRSAVE]);
|
||||||
|
mem_buf = gdb_get_reg_ptr(buf, 4);
|
||||||
ppc_maybe_bswap_register(env, mem_buf, 4);
|
ppc_maybe_bswap_register(env, mem_buf, 4);
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
@ -9963,25 +9969,25 @@ static int gdb_set_avr_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gdb_get_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
|
static int gdb_get_spe_reg(CPUPPCState *env, GByteArray *buf, int n)
|
||||||
{
|
{
|
||||||
if (n < 32) {
|
if (n < 32) {
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
stl_p(mem_buf, env->gpr[n] >> 32);
|
gdb_get_reg32(buf, env->gpr[n] >> 32);
|
||||||
ppc_maybe_bswap_register(env, mem_buf, 4);
|
ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 4), 4);
|
||||||
#else
|
#else
|
||||||
stl_p(mem_buf, env->gprh[n]);
|
gdb_get_reg32(buf, env->gprh[n]);
|
||||||
#endif
|
#endif
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
if (n == 32) {
|
if (n == 32) {
|
||||||
stq_p(mem_buf, env->spe_acc);
|
gdb_get_reg64(buf, env->spe_acc);
|
||||||
ppc_maybe_bswap_register(env, mem_buf, 8);
|
ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8);
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
if (n == 33) {
|
if (n == 33) {
|
||||||
stl_p(mem_buf, env->spe_fscr);
|
gdb_get_reg32(buf, env->spe_fscr);
|
||||||
ppc_maybe_bswap_register(env, mem_buf, 4);
|
ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 4), 4);
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -10016,11 +10022,11 @@ static int gdb_set_spe_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gdb_get_vsx_reg(CPUPPCState *env, uint8_t *mem_buf, int n)
|
static int gdb_get_vsx_reg(CPUPPCState *env, GByteArray *buf, int n)
|
||||||
{
|
{
|
||||||
if (n < 32) {
|
if (n < 32) {
|
||||||
stq_p(mem_buf, *cpu_vsrl_ptr(env, n));
|
gdb_get_reg64(buf, *cpu_vsrl_ptr(env, n));
|
||||||
ppc_maybe_bswap_register(env, mem_buf, 8);
|
ppc_maybe_bswap_register(env, gdb_get_reg_ptr(buf, 8), 8);
|
||||||
return 8;
|
return 8;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -293,7 +293,7 @@ extern const char * const riscv_excp_names[];
|
||||||
extern const char * const riscv_intr_names[];
|
extern const char * const riscv_intr_names[];
|
||||||
|
|
||||||
void riscv_cpu_do_interrupt(CPUState *cpu);
|
void riscv_cpu_do_interrupt(CPUState *cpu);
|
||||||
int riscv_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
|
bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
|
||||||
bool riscv_cpu_fp_enabled(CPURISCVState *env);
|
bool riscv_cpu_fp_enabled(CPURISCVState *env);
|
||||||
|
|
|
@ -270,7 +270,7 @@ static int csr_register_map[] = {
|
||||||
CSR_MHCOUNTEREN,
|
CSR_MHCOUNTEREN,
|
||||||
};
|
};
|
||||||
|
|
||||||
int riscv_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int riscv_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
RISCVCPU *cpu = RISCV_CPU(cs);
|
RISCVCPU *cpu = RISCV_CPU(cs);
|
||||||
CPURISCVState *env = &cpu->env;
|
CPURISCVState *env = &cpu->env;
|
||||||
|
@ -301,14 +301,14 @@ int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv_gdb_get_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
|
static int riscv_gdb_get_fpu(CPURISCVState *env, GByteArray *buf, int n)
|
||||||
{
|
{
|
||||||
if (n < 32) {
|
if (n < 32) {
|
||||||
if (env->misa & RVD) {
|
if (env->misa & RVD) {
|
||||||
return gdb_get_reg64(mem_buf, env->fpr[n]);
|
return gdb_get_reg64(buf, env->fpr[n]);
|
||||||
}
|
}
|
||||||
if (env->misa & RVF) {
|
if (env->misa & RVF) {
|
||||||
return gdb_get_reg32(mem_buf, env->fpr[n]);
|
return gdb_get_reg32(buf, env->fpr[n]);
|
||||||
}
|
}
|
||||||
/* there is hole between ft11 and fflags in fpu.xml */
|
/* there is hole between ft11 and fflags in fpu.xml */
|
||||||
} else if (n < 36 && n > 32) {
|
} else if (n < 36 && n > 32) {
|
||||||
|
@ -322,7 +322,7 @@ static int riscv_gdb_get_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
|
||||||
result = riscv_csrrw_debug(env, n - 33 + csr_register_map[8], &val,
|
result = riscv_csrrw_debug(env, n - 33 + csr_register_map[8], &val,
|
||||||
0, 0);
|
0, 0);
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
return gdb_get_regl(mem_buf, val);
|
return gdb_get_regl(buf, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -351,7 +351,7 @@ static int riscv_gdb_set_fpu(CPURISCVState *env, uint8_t *mem_buf, int n)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv_gdb_get_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
|
static int riscv_gdb_get_csr(CPURISCVState *env, GByteArray *buf, int n)
|
||||||
{
|
{
|
||||||
if (n < ARRAY_SIZE(csr_register_map)) {
|
if (n < ARRAY_SIZE(csr_register_map)) {
|
||||||
target_ulong val = 0;
|
target_ulong val = 0;
|
||||||
|
@ -359,7 +359,7 @@ static int riscv_gdb_get_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
|
||||||
|
|
||||||
result = riscv_csrrw_debug(env, csr_register_map[n], &val, 0, 0);
|
result = riscv_csrrw_debug(env, csr_register_map[n], &val, 0, 0);
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
return gdb_get_regl(mem_buf, val);
|
return gdb_get_regl(buf, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -379,13 +379,13 @@ static int riscv_gdb_set_csr(CPURISCVState *env, uint8_t *mem_buf, int n)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int riscv_gdb_get_virtual(CPURISCVState *cs, uint8_t *mem_buf, int n)
|
static int riscv_gdb_get_virtual(CPURISCVState *cs, GByteArray *buf, int n)
|
||||||
{
|
{
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
#ifdef CONFIG_USER_ONLY
|
#ifdef CONFIG_USER_ONLY
|
||||||
return gdb_get_regl(mem_buf, 0);
|
return gdb_get_regl(buf, 0);
|
||||||
#else
|
#else
|
||||||
return gdb_get_regl(mem_buf, cs->priv);
|
return gdb_get_regl(buf, cs->priv);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#include "sysemu/hw_accel.h"
|
#include "sysemu/hw_accel.h"
|
||||||
#include "sysemu/tcg.h"
|
#include "sysemu/tcg.h"
|
||||||
|
|
||||||
int s390_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int s390_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
S390CPU *cpu = S390_CPU(cs);
|
S390CPU *cpu = S390_CPU(cs);
|
||||||
CPUS390XState *env = &cpu->env;
|
CPUS390XState *env = &cpu->env;
|
||||||
|
@ -82,11 +82,11 @@ int s390_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
||||||
/* total number of registers in s390-acr.xml */
|
/* total number of registers in s390-acr.xml */
|
||||||
#define S390_NUM_AC_REGS 16
|
#define S390_NUM_AC_REGS 16
|
||||||
|
|
||||||
static int cpu_read_ac_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
|
static int cpu_read_ac_reg(CPUS390XState *env, GByteArray *buf, int n)
|
||||||
{
|
{
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case S390_A0_REGNUM ... S390_A15_REGNUM:
|
case S390_A0_REGNUM ... S390_A15_REGNUM:
|
||||||
return gdb_get_reg32(mem_buf, env->aregs[n]);
|
return gdb_get_reg32(buf, env->aregs[n]);
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -111,13 +111,13 @@ static int cpu_write_ac_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
|
||||||
/* total number of registers in s390-fpr.xml */
|
/* total number of registers in s390-fpr.xml */
|
||||||
#define S390_NUM_FP_REGS 17
|
#define S390_NUM_FP_REGS 17
|
||||||
|
|
||||||
static int cpu_read_fp_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
|
static int cpu_read_fp_reg(CPUS390XState *env, GByteArray *buf, int n)
|
||||||
{
|
{
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case S390_FPC_REGNUM:
|
case S390_FPC_REGNUM:
|
||||||
return gdb_get_reg32(mem_buf, env->fpc);
|
return gdb_get_reg32(buf, env->fpc);
|
||||||
case S390_F0_REGNUM ... S390_F15_REGNUM:
|
case S390_F0_REGNUM ... S390_F15_REGNUM:
|
||||||
return gdb_get_reg64(mem_buf, *get_freg(env, n - S390_F0_REGNUM));
|
return gdb_get_reg64(buf, *get_freg(env, n - S390_F0_REGNUM));
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -145,17 +145,17 @@ static int cpu_write_fp_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
|
||||||
/* total number of registers in s390-vx.xml */
|
/* total number of registers in s390-vx.xml */
|
||||||
#define S390_NUM_VREGS 32
|
#define S390_NUM_VREGS 32
|
||||||
|
|
||||||
static int cpu_read_vreg(CPUS390XState *env, uint8_t *mem_buf, int n)
|
static int cpu_read_vreg(CPUS390XState *env, GByteArray *buf, int n)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case S390_V0L_REGNUM ... S390_V15L_REGNUM:
|
case S390_V0L_REGNUM ... S390_V15L_REGNUM:
|
||||||
ret = gdb_get_reg64(mem_buf, env->vregs[n][1]);
|
ret = gdb_get_reg64(buf, env->vregs[n][1]);
|
||||||
break;
|
break;
|
||||||
case S390_V16_REGNUM ... S390_V31_REGNUM:
|
case S390_V16_REGNUM ... S390_V31_REGNUM:
|
||||||
ret = gdb_get_reg64(mem_buf, env->vregs[n][0]);
|
ret = gdb_get_reg64(buf, env->vregs[n][0]);
|
||||||
ret += gdb_get_reg64(mem_buf + 8, env->vregs[n][1]);
|
ret += gdb_get_reg64(buf, env->vregs[n][1]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
@ -186,11 +186,11 @@ static int cpu_write_vreg(CPUS390XState *env, uint8_t *mem_buf, int n)
|
||||||
#define S390_NUM_C_REGS 16
|
#define S390_NUM_C_REGS 16
|
||||||
|
|
||||||
#ifndef CONFIG_USER_ONLY
|
#ifndef CONFIG_USER_ONLY
|
||||||
static int cpu_read_c_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
|
static int cpu_read_c_reg(CPUS390XState *env, GByteArray *buf, int n)
|
||||||
{
|
{
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case S390_C0_REGNUM ... S390_C15_REGNUM:
|
case S390_C0_REGNUM ... S390_C15_REGNUM:
|
||||||
return gdb_get_regl(mem_buf, env->cregs[n]);
|
return gdb_get_regl(buf, env->cregs[n]);
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -223,7 +223,7 @@ static int cpu_write_c_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
|
||||||
/* total number of registers in s390-virt.xml */
|
/* total number of registers in s390-virt.xml */
|
||||||
#define S390_NUM_VIRT_REGS 8
|
#define S390_NUM_VIRT_REGS 8
|
||||||
|
|
||||||
static int cpu_read_virt_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
|
static int cpu_read_virt_reg(CPUS390XState *env, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case S390_VIRT_CKC_REGNUM:
|
case S390_VIRT_CKC_REGNUM:
|
||||||
|
@ -296,9 +296,9 @@ static int cpu_write_virt_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
|
||||||
/* total number of registers in s390-gs.xml */
|
/* total number of registers in s390-gs.xml */
|
||||||
#define S390_NUM_GS_REGS 4
|
#define S390_NUM_GS_REGS 4
|
||||||
|
|
||||||
static int cpu_read_gs_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
|
static int cpu_read_gs_reg(CPUS390XState *env, GByteArray *buf, int n)
|
||||||
{
|
{
|
||||||
return gdb_get_regl(mem_buf, env->gscb[n]);
|
return gdb_get_regl(buf, env->gscb[n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cpu_write_gs_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
|
static int cpu_write_gs_reg(CPUS390XState *env, uint8_t *mem_buf, int n)
|
||||||
|
|
|
@ -292,7 +292,7 @@ uint16_t float128_dcmask(CPUS390XState *env, float128 f1);
|
||||||
|
|
||||||
|
|
||||||
/* gdbstub.c */
|
/* gdbstub.c */
|
||||||
int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
int s390_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
void s390_cpu_gdb_init(CPUState *cs);
|
void s390_cpu_gdb_init(CPUState *cs);
|
||||||
|
|
||||||
|
|
|
@ -208,7 +208,7 @@ void superh_cpu_do_interrupt(CPUState *cpu);
|
||||||
bool superh_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
bool superh_cpu_exec_interrupt(CPUState *cpu, int int_req);
|
||||||
void superh_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
|
void superh_cpu_dump_state(CPUState *cpu, FILE *f, 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_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int superh_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int superh_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
void superh_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
void superh_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
||||||
MMUAccessType access_type,
|
MMUAccessType access_type,
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
/* Hint: Use "set architecture sh4" in GDB to see fpu registers */
|
/* Hint: Use "set architecture sh4" in GDB to see fpu registers */
|
||||||
/* FIXME: We should use XML for this. */
|
/* FIXME: We should use XML for this. */
|
||||||
|
|
||||||
int superh_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int superh_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
SuperHCPU *cpu = SUPERH_CPU(cs);
|
SuperHCPU *cpu = SUPERH_CPU(cs);
|
||||||
CPUSH4State *env = &cpu->env;
|
CPUSH4State *env = &cpu->env;
|
||||||
|
|
|
@ -571,7 +571,7 @@ extern const VMStateDescription vmstate_sparc_cpu;
|
||||||
void sparc_cpu_do_interrupt(CPUState *cpu);
|
void sparc_cpu_do_interrupt(CPUState *cpu);
|
||||||
void sparc_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
|
void sparc_cpu_dump_state(CPUState *cpu, FILE *f, 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_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int sparc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int sparc_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
void QEMU_NORETURN sparc_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
||||||
MMUAccessType access_type,
|
MMUAccessType access_type,
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#define gdb_get_rega(buf, val) gdb_get_regl(buf, val)
|
#define gdb_get_rega(buf, val) gdb_get_regl(buf, val)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int sparc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int sparc_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
SPARCCPU *cpu = SPARC_CPU(cs);
|
SPARCCPU *cpu = SPARC_CPU(cs);
|
||||||
CPUSPARCState *env = &cpu->env;
|
CPUSPARCState *env = &cpu->env;
|
||||||
|
|
|
@ -569,7 +569,7 @@ void xtensa_cpu_dump_state(CPUState *cpu, FILE *f, int flags);
|
||||||
hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
|
||||||
void xtensa_count_regs(const XtensaConfig *config,
|
void xtensa_count_regs(const XtensaConfig *config,
|
||||||
unsigned *n_regs, unsigned *n_core_regs);
|
unsigned *n_regs, unsigned *n_core_regs);
|
||||||
int xtensa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
|
int xtensa_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
|
||||||
int xtensa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
int xtensa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
|
||||||
void xtensa_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
void xtensa_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
|
||||||
MMUAccessType access_type,
|
MMUAccessType access_type,
|
||||||
|
|
|
@ -63,7 +63,7 @@ void xtensa_count_regs(const XtensaConfig *config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int xtensa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
|
int xtensa_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
|
||||||
{
|
{
|
||||||
XtensaCPU *cpu = XTENSA_CPU(cs);
|
XtensaCPU *cpu = XTENSA_CPU(cs);
|
||||||
CPUXtensaState *env = &cpu->env;
|
CPUXtensaState *env = &cpu->env;
|
||||||
|
|
1
tests/.gitignore
vendored
1
tests/.gitignore
vendored
|
@ -10,6 +10,7 @@ qht-bench
|
||||||
rcutorture
|
rcutorture
|
||||||
test-*
|
test-*
|
||||||
!test-*.c
|
!test-*.c
|
||||||
|
!test-*.py
|
||||||
!docker/test-*
|
!docker/test-*
|
||||||
test-qapi-commands.[ch]
|
test-qapi-commands.[ch]
|
||||||
test-qapi-init-commands.[ch]
|
test-qapi-init-commands.[ch]
|
||||||
|
|
|
@ -28,9 +28,9 @@ RUN apt update && \
|
||||||
libegl1-mesa-dev \
|
libegl1-mesa-dev \
|
||||||
libepoxy-dev \
|
libepoxy-dev \
|
||||||
libgbm-dev
|
libgbm-dev
|
||||||
RUN git clone https://anongit.freedesktop.org/git/virglrenderer.git /usr/src/virglrenderer && \
|
RUN git clone https://gitlab.freedesktop.org/virgl/virglrenderer.git /usr/src/virglrenderer && \
|
||||||
cd /usr/src/virglrenderer && git checkout virglrenderer-0.7.0
|
cd /usr/src/virglrenderer && git checkout virglrenderer-0.8.0
|
||||||
RUN cd /usr/src/virglrenderer && ./autogen.sh && ./configure --with-glx --disable-tests && make install
|
RUN cd /usr/src/virglrenderer && ./autogen.sh && ./configure --disable-tests && make install
|
||||||
|
|
||||||
# netmap
|
# netmap
|
||||||
RUN apt update && \
|
RUN apt update && \
|
||||||
|
|
|
@ -17,14 +17,17 @@ RUN apt update && \
|
||||||
DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
|
DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
|
||||||
DEBIAN_FRONTEND=noninteractive eatmydata \
|
DEBIAN_FRONTEND=noninteractive eatmydata \
|
||||||
apt install -y --no-install-recommends \
|
apt install -y --no-install-recommends \
|
||||||
|
bc \
|
||||||
bison \
|
bison \
|
||||||
build-essential \
|
build-essential \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
clang \
|
clang \
|
||||||
dbus \
|
dbus \
|
||||||
flex \
|
flex \
|
||||||
|
gdb-multiarch \
|
||||||
gettext \
|
gettext \
|
||||||
git \
|
git \
|
||||||
|
libncurses5-dev \
|
||||||
pkg-config \
|
pkg-config \
|
||||||
psmisc \
|
psmisc \
|
||||||
python3 \
|
python3 \
|
||||||
|
|
|
@ -17,13 +17,16 @@ RUN apt update && \
|
||||||
DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
|
DEBIAN_FRONTEND=noninteractive apt install -yy eatmydata && \
|
||||||
DEBIAN_FRONTEND=noninteractive eatmydata \
|
DEBIAN_FRONTEND=noninteractive eatmydata \
|
||||||
apt install -y --no-install-recommends \
|
apt install -y --no-install-recommends \
|
||||||
|
bc \
|
||||||
bison \
|
bison \
|
||||||
build-essential \
|
build-essential \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
clang \
|
clang \
|
||||||
flex \
|
flex \
|
||||||
|
gdb-multiarch \
|
||||||
gettext \
|
gettext \
|
||||||
git \
|
git \
|
||||||
|
libncurses5-dev \
|
||||||
pkg-config \
|
pkg-config \
|
||||||
psmisc \
|
psmisc \
|
||||||
python3 \
|
python3 \
|
||||||
|
|
57
tests/guest-debug/run-test.py
Executable file
57
tests/guest-debug/run-test.py
Executable file
|
@ -0,0 +1,57 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Run a gdbstub test case
|
||||||
|
#
|
||||||
|
# Copyright (c) 2019 Linaro
|
||||||
|
#
|
||||||
|
# Author: Alex Bennée <alex.bennee@linaro.org>
|
||||||
|
#
|
||||||
|
# This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||||
|
# See the COPYING file in the top-level directory.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import subprocess
|
||||||
|
import shutil
|
||||||
|
import shlex
|
||||||
|
|
||||||
|
def get_args():
|
||||||
|
parser = argparse.ArgumentParser(description="A gdbstub test runner")
|
||||||
|
parser.add_argument("--qemu", help="Qemu binary for test",
|
||||||
|
required=True)
|
||||||
|
parser.add_argument("--qargs", help="Qemu arguments for test")
|
||||||
|
parser.add_argument("--binary", help="Binary to debug",
|
||||||
|
required=True)
|
||||||
|
parser.add_argument("--test", help="GDB test script",
|
||||||
|
required=True)
|
||||||
|
parser.add_argument("--gdb", help="The gdb binary to use", default=None)
|
||||||
|
|
||||||
|
return parser.parse_args()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
args = get_args()
|
||||||
|
|
||||||
|
# Search for a gdb we can use
|
||||||
|
if not args.gdb:
|
||||||
|
args.gdb = shutil.which("gdb-multiarch")
|
||||||
|
if not args.gdb:
|
||||||
|
args.gdb = shutil.which("gdb")
|
||||||
|
if not args.gdb:
|
||||||
|
print("We need gdb to run the test")
|
||||||
|
exit(-1)
|
||||||
|
|
||||||
|
# Launch QEMU with binary
|
||||||
|
if "system" in args.qemu:
|
||||||
|
cmd = "%s %s %s -s -S" % (args.qemu, args.qargs, args.binary)
|
||||||
|
else:
|
||||||
|
cmd = "%s %s -g 1234 %s" % (args.qemu, args.qargs, args.binary)
|
||||||
|
|
||||||
|
inferior = subprocess.Popen(shlex.split(cmd))
|
||||||
|
|
||||||
|
# Now launch gdb with our test and collect the result
|
||||||
|
gdb_cmd = "%s %s -ex 'target remote localhost:1234' -x %s" % (args.gdb, args.binary, args.test)
|
||||||
|
|
||||||
|
result = subprocess.call(gdb_cmd, shell=True);
|
||||||
|
|
||||||
|
exit(result)
|
|
@ -42,4 +42,36 @@ run-semiconsole: semiconsole
|
||||||
run-plugin-semiconsole-with-%:
|
run-plugin-semiconsole-with-%:
|
||||||
$(call skip-test, $<, "MANUAL ONLY")
|
$(call skip-test, $<, "MANUAL ONLY")
|
||||||
|
|
||||||
|
ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_SVE),)
|
||||||
|
# System Registers Tests
|
||||||
|
AARCH64_TESTS += sysregs
|
||||||
|
sysregs: CFLAGS+=-march=armv8.1-a+sve
|
||||||
|
|
||||||
|
# SVE ioctl test
|
||||||
|
AARCH64_TESTS += sve-ioctls
|
||||||
|
sve-ioctls: CFLAGS+=-march=armv8.1-a+sve
|
||||||
|
|
||||||
|
ifneq ($(HAVE_GDB_BIN),)
|
||||||
|
GDB_SCRIPT=$(SRC_PATH)/tests/guest-debug/run-test.py
|
||||||
|
|
||||||
|
AARCH64_TESTS += gdbstub-sysregs gdbstub-sve-ioctls
|
||||||
|
|
||||||
|
.PHONY: gdbstub-sysregs gdbstub-sve-ioctls
|
||||||
|
run-gdbstub-sysregs: sysregs
|
||||||
|
$(call run-test, $@, $(GDB_SCRIPT) \
|
||||||
|
--gdb $(HAVE_GDB_BIN) \
|
||||||
|
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
|
||||||
|
--bin $< --test $(AARCH64_SRC)/gdbstub/test-sve.py, \
|
||||||
|
"basic gdbstub SVE support")
|
||||||
|
|
||||||
|
run-gdbstub-sve-ioctls: sve-ioctls
|
||||||
|
$(call run-test, $@, $(GDB_SCRIPT) \
|
||||||
|
--gdb $(HAVE_GDB_BIN) \
|
||||||
|
--qemu $(QEMU) --qargs "$(QEMU_OPTS)" \
|
||||||
|
--bin $< --test $(AARCH64_SRC)/gdbstub/test-sve-ioctl.py, \
|
||||||
|
"basic gdbstub SVE ZLEN support")
|
||||||
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
TESTS += $(AARCH64_TESTS)
|
TESTS += $(AARCH64_TESTS)
|
||||||
|
|
85
tests/tcg/aarch64/gdbstub/test-sve-ioctl.py
Normal file
85
tests/tcg/aarch64/gdbstub/test-sve-ioctl.py
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
from __future__ import print_function
|
||||||
|
#
|
||||||
|
# Test the SVE ZReg reports the right amount of data. It uses the
|
||||||
|
# sve-ioctl test and examines the register data each time the
|
||||||
|
# __sve_ld_done breakpoint is hit.
|
||||||
|
#
|
||||||
|
# This is launched via tests/guest-debug/run-test.py
|
||||||
|
#
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
import sys
|
||||||
|
|
||||||
|
initial_vlen = 0
|
||||||
|
failcount = 0
|
||||||
|
|
||||||
|
def report(cond, msg):
|
||||||
|
"Report success/fail of test"
|
||||||
|
if cond:
|
||||||
|
print ("PASS: %s" % (msg))
|
||||||
|
else:
|
||||||
|
print ("FAIL: %s" % (msg))
|
||||||
|
global failcount
|
||||||
|
failcount += 1
|
||||||
|
|
||||||
|
class TestBreakpoint(gdb.Breakpoint):
|
||||||
|
def __init__(self, sym_name="__sve_ld_done"):
|
||||||
|
super(TestBreakpoint, self).__init__(sym_name)
|
||||||
|
# self.sym, ok = gdb.lookup_symbol(sym_name)
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
val_i = gdb.parse_and_eval('i')
|
||||||
|
global initial_vlen
|
||||||
|
try:
|
||||||
|
for i in range(0, int(val_i)):
|
||||||
|
val_z = gdb.parse_and_eval("$z0.b.u[%d]" % i)
|
||||||
|
report(int(val_z) == i, "z0.b.u[%d] == %d" % (i, i))
|
||||||
|
for i in range(i + 1, initial_vlen):
|
||||||
|
val_z = gdb.parse_and_eval("$z0.b.u[%d]" % i)
|
||||||
|
report(int(val_z) == 0, "z0.b.u[%d] == 0" % (i))
|
||||||
|
except gdb.error:
|
||||||
|
report(False, "checking zregs (out of range)")
|
||||||
|
|
||||||
|
|
||||||
|
def run_test():
|
||||||
|
"Run through the tests one by one"
|
||||||
|
|
||||||
|
print ("Setup breakpoint")
|
||||||
|
bp = TestBreakpoint()
|
||||||
|
|
||||||
|
global initial_vlen
|
||||||
|
vg = gdb.parse_and_eval("$vg")
|
||||||
|
initial_vlen = int(vg) * 8
|
||||||
|
|
||||||
|
gdb.execute("c")
|
||||||
|
|
||||||
|
#
|
||||||
|
# This runs as the script it sourced (via -x, via run-test.py)
|
||||||
|
#
|
||||||
|
try:
|
||||||
|
inferior = gdb.selected_inferior()
|
||||||
|
if inferior.was_attached == False:
|
||||||
|
print("SKIPPING (failed to attach)", file=sys.stderr)
|
||||||
|
exit(0)
|
||||||
|
arch = inferior.architecture()
|
||||||
|
report(arch.name() == "aarch64", "connected to aarch64")
|
||||||
|
except (gdb.error, AttributeError):
|
||||||
|
print("SKIPPING (not connected)", file=sys.stderr)
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# These are not very useful in scripts
|
||||||
|
gdb.execute("set pagination off")
|
||||||
|
gdb.execute("set confirm off")
|
||||||
|
|
||||||
|
# Run the actual tests
|
||||||
|
run_test()
|
||||||
|
except:
|
||||||
|
print ("GDB Exception: %s" % (sys.exc_info()[0]))
|
||||||
|
failcount += 1
|
||||||
|
import code
|
||||||
|
code.InteractiveConsole(locals=globals()).interact()
|
||||||
|
raise
|
||||||
|
|
||||||
|
print("All tests complete: %d failures" % failcount)
|
||||||
|
exit(failcount)
|
84
tests/tcg/aarch64/gdbstub/test-sve.py
Normal file
84
tests/tcg/aarch64/gdbstub/test-sve.py
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
from __future__ import print_function
|
||||||
|
#
|
||||||
|
# Test the SVE registers are visable and changeable via gdbstub
|
||||||
|
#
|
||||||
|
# This is launched via tests/guest-debug/run-test.py
|
||||||
|
#
|
||||||
|
|
||||||
|
import gdb
|
||||||
|
import sys
|
||||||
|
|
||||||
|
MAGIC = 0xDEADBEEF
|
||||||
|
|
||||||
|
failcount = 0
|
||||||
|
|
||||||
|
def report(cond, msg):
|
||||||
|
"Report success/fail of test"
|
||||||
|
if cond:
|
||||||
|
print ("PASS: %s" % (msg))
|
||||||
|
else:
|
||||||
|
print ("FAIL: %s" % (msg))
|
||||||
|
global failcount
|
||||||
|
failcount += 1
|
||||||
|
|
||||||
|
def run_test():
|
||||||
|
"Run through the tests one by one"
|
||||||
|
|
||||||
|
gdb.execute("info registers")
|
||||||
|
report(True, "info registers")
|
||||||
|
|
||||||
|
gdb.execute("info registers vector")
|
||||||
|
report(True, "info registers vector")
|
||||||
|
|
||||||
|
# Now all the zregs
|
||||||
|
frame = gdb.selected_frame()
|
||||||
|
for i in range(0, 32):
|
||||||
|
rname = "z%d" % (i)
|
||||||
|
zreg = frame.read_register(rname)
|
||||||
|
report(True, "Reading %s" % rname)
|
||||||
|
for j in range(0, 4):
|
||||||
|
cmd = "set $%s.q.u[%d] = 0x%x" % (rname, j, MAGIC)
|
||||||
|
gdb.execute(cmd)
|
||||||
|
report(True, "%s" % cmd)
|
||||||
|
for j in range(0, 4):
|
||||||
|
reg = "$%s.q.u[%d]" % (rname, j)
|
||||||
|
v = gdb.parse_and_eval(reg)
|
||||||
|
report(str(v.type) == "uint128_t", "size of %s" % (reg))
|
||||||
|
for j in range(0, 8):
|
||||||
|
cmd = "set $%s.d.u[%d] = 0x%x" % (rname, j, MAGIC)
|
||||||
|
gdb.execute(cmd)
|
||||||
|
report(True, "%s" % cmd)
|
||||||
|
for j in range(0, 8):
|
||||||
|
reg = "$%s.d.u[%d]" % (rname, j)
|
||||||
|
v = gdb.parse_and_eval(reg)
|
||||||
|
report(str(v.type) == "uint64_t", "size of %s" % (reg))
|
||||||
|
report(int(v) == MAGIC, "%s is 0x%x" % (reg, MAGIC))
|
||||||
|
|
||||||
|
#
|
||||||
|
# This runs as the script it sourced (via -x, via run-test.py)
|
||||||
|
#
|
||||||
|
try:
|
||||||
|
inferior = gdb.selected_inferior()
|
||||||
|
if inferior.was_attached == False:
|
||||||
|
print("SKIPPING (failed to attach)", file=sys.stderr)
|
||||||
|
exit(0)
|
||||||
|
arch = inferior.architecture()
|
||||||
|
report(arch.name() == "aarch64", "connected to aarch64")
|
||||||
|
except (gdb.error, AttributeError):
|
||||||
|
print("SKIPPING (not connected)", file=sys.stderr)
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# These are not very useful in scripts
|
||||||
|
gdb.execute("set pagination off")
|
||||||
|
gdb.execute("set confirm off")
|
||||||
|
|
||||||
|
# Run the actual tests
|
||||||
|
run_test()
|
||||||
|
except:
|
||||||
|
print ("GDB Exception: %s" % (sys.exc_info()[0]))
|
||||||
|
failcount += 1
|
||||||
|
|
||||||
|
print("All tests complete: %d failures" % failcount)
|
||||||
|
|
||||||
|
exit(failcount)
|
70
tests/tcg/aarch64/sve-ioctls.c
Normal file
70
tests/tcg/aarch64/sve-ioctls.c
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* SVE ioctls tests
|
||||||
|
*
|
||||||
|
* Test the SVE width setting ioctls work and provide a base for
|
||||||
|
* testing the gdbstub.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Linaro Ltd
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <asm/hwcap.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/auxv.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifndef HWCAP_CPUID
|
||||||
|
#define HWCAP_CPUID (1 << 11)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SVE_MAX_QUADS (2048 / 128)
|
||||||
|
#define BYTES_PER_QUAD (128 / 8)
|
||||||
|
|
||||||
|
#define get_cpu_reg(id) ({ \
|
||||||
|
unsigned long __val; \
|
||||||
|
asm("mrs %0, "#id : "=r" (__val)); \
|
||||||
|
__val; \
|
||||||
|
})
|
||||||
|
|
||||||
|
static int do_sve_ioctl_test(void)
|
||||||
|
{
|
||||||
|
int i, res, init_vq;
|
||||||
|
|
||||||
|
res = prctl(PR_SVE_GET_VL, 0, 0, 0, 0);
|
||||||
|
if (res < 0) {
|
||||||
|
printf("FAILED to PR_SVE_GET_VL (%d)", res);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
init_vq = res & PR_SVE_VL_LEN_MASK;
|
||||||
|
|
||||||
|
for (i = init_vq; i > 15; i /= 2) {
|
||||||
|
printf("Checking PR_SVE_SET_VL=%d\n", i);
|
||||||
|
res = prctl(PR_SVE_SET_VL, i, 0, 0, 0, 0);
|
||||||
|
if (res < 0) {
|
||||||
|
printf("FAILED to PR_SVE_SET_VL (%d)", res);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
asm("index z0.b, #0, #1\n"
|
||||||
|
".global __sve_ld_done\n"
|
||||||
|
"__sve_ld_done:\n"
|
||||||
|
"mov z0.b, #0\n"
|
||||||
|
: /* no outputs kept */
|
||||||
|
: /* no inputs */
|
||||||
|
: "memory", "z0");
|
||||||
|
}
|
||||||
|
printf("PASS\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
/* we also need to probe for the ioctl support */
|
||||||
|
if (getauxval(AT_HWCAP) & HWCAP_SVE) {
|
||||||
|
return do_sve_ioctl_test();
|
||||||
|
} else {
|
||||||
|
printf("SKIP: no HWCAP_SVE on this system\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
172
tests/tcg/aarch64/sysregs.c
Normal file
172
tests/tcg/aarch64/sysregs.c
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
* Check emulated system register access for linux-user mode.
|
||||||
|
*
|
||||||
|
* See: https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Linaro
|
||||||
|
*
|
||||||
|
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||||
|
* See the COPYING file in the top-level directory.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm/hwcap.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/auxv.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifndef HWCAP_CPUID
|
||||||
|
#define HWCAP_CPUID (1 << 11)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int failed_bit_count;
|
||||||
|
|
||||||
|
/* Read and print system register `id' value */
|
||||||
|
#define get_cpu_reg(id) ({ \
|
||||||
|
unsigned long __val = 0xdeadbeef; \
|
||||||
|
asm("mrs %0, "#id : "=r" (__val)); \
|
||||||
|
printf("%-20s: 0x%016lx\n", #id, __val); \
|
||||||
|
__val; \
|
||||||
|
})
|
||||||
|
|
||||||
|
/* As above but also check no bits outside of `mask' are set*/
|
||||||
|
#define get_cpu_reg_check_mask(id, mask) ({ \
|
||||||
|
unsigned long __cval = get_cpu_reg(id); \
|
||||||
|
unsigned long __extra = __cval & ~mask; \
|
||||||
|
if (__extra) { \
|
||||||
|
printf("%-20s: 0x%016lx\n", " !!extra bits!!", __extra); \
|
||||||
|
failed_bit_count++; \
|
||||||
|
} \
|
||||||
|
})
|
||||||
|
|
||||||
|
/* As above but check RAZ */
|
||||||
|
#define get_cpu_reg_check_zero(id) ({ \
|
||||||
|
unsigned long __val = 0xdeadbeef; \
|
||||||
|
asm("mrs %0, "#id : "=r" (__val)); \
|
||||||
|
if (__val) { \
|
||||||
|
printf("%-20s: 0x%016lx (not RAZ!)\n", #id, __val); \
|
||||||
|
failed_bit_count++; \
|
||||||
|
} \
|
||||||
|
})
|
||||||
|
|
||||||
|
/* Chunk up mask into 63:48, 47:32, 31:16, 15:0 to ease counting */
|
||||||
|
#define _m(a, b, c, d) (0x ## a ## b ## c ## d ##ULL)
|
||||||
|
|
||||||
|
bool should_fail;
|
||||||
|
int should_fail_count;
|
||||||
|
int should_not_fail_count;
|
||||||
|
uintptr_t failed_pc[10];
|
||||||
|
|
||||||
|
void sigill_handler(int signo, siginfo_t *si, void *data)
|
||||||
|
{
|
||||||
|
ucontext_t *uc = (ucontext_t *)data;
|
||||||
|
|
||||||
|
if (should_fail) {
|
||||||
|
should_fail_count++;
|
||||||
|
} else {
|
||||||
|
uintptr_t pc = (uintptr_t) uc->uc_mcontext.pc;
|
||||||
|
failed_pc[should_not_fail_count++] = pc;
|
||||||
|
}
|
||||||
|
uc->uc_mcontext.pc += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
struct sigaction sa;
|
||||||
|
|
||||||
|
/* Hook in a SIGILL handler */
|
||||||
|
memset(&sa, 0, sizeof(struct sigaction));
|
||||||
|
sa.sa_flags = SA_SIGINFO;
|
||||||
|
sa.sa_sigaction = &sigill_handler;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
|
||||||
|
if (sigaction(SIGILL, &sa, 0) != 0) {
|
||||||
|
perror("sigaction");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Counter values have been exposed since Linux 4.12 */
|
||||||
|
printf("Checking Counter registers\n");
|
||||||
|
|
||||||
|
get_cpu_reg(ctr_el0);
|
||||||
|
get_cpu_reg(cntvct_el0);
|
||||||
|
get_cpu_reg(cntfrq_el0);
|
||||||
|
|
||||||
|
/* HWCAP_CPUID indicates we can read feature registers, since Linux 4.11 */
|
||||||
|
if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) {
|
||||||
|
printf("CPUID registers unavailable\n");
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
printf("Checking CPUID registers\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some registers only expose some bits to user-space. Anything
|
||||||
|
* that is IMPDEF is exported as 0 to user-space. The _mask checks
|
||||||
|
* assert no extra bits are set.
|
||||||
|
*
|
||||||
|
* This check is *not* comprehensive as some fields are set to
|
||||||
|
* minimum valid fields - for the purposes of this check allowed
|
||||||
|
* to have non-zero values.
|
||||||
|
*/
|
||||||
|
get_cpu_reg_check_mask(id_aa64isar0_el1, _m(00ff,ffff,f0ff,fff0));
|
||||||
|
get_cpu_reg_check_mask(id_aa64isar1_el1, _m(0000,00f0,ffff,ffff));
|
||||||
|
/* TGran4 & TGran64 as pegged to -1 */
|
||||||
|
get_cpu_reg_check_mask(id_aa64mmfr0_el1, _m(0000,0000,ff00,0000));
|
||||||
|
get_cpu_reg_check_zero(id_aa64mmfr1_el1);
|
||||||
|
/* EL1/EL0 reported as AA64 only */
|
||||||
|
get_cpu_reg_check_mask(id_aa64pfr0_el1, _m(000f,000f,00ff,0011));
|
||||||
|
get_cpu_reg_check_mask(id_aa64pfr1_el1, _m(0000,0000,0000,00f0));
|
||||||
|
/* all hidden, DebugVer fixed to 0x6 (ARMv8 debug architecture) */
|
||||||
|
get_cpu_reg_check_mask(id_aa64dfr0_el1, _m(0000,0000,0000,0006));
|
||||||
|
get_cpu_reg_check_zero(id_aa64dfr1_el1);
|
||||||
|
get_cpu_reg_check_zero(id_aa64zfr0_el1);
|
||||||
|
|
||||||
|
get_cpu_reg_check_zero(id_aa64afr0_el1);
|
||||||
|
get_cpu_reg_check_zero(id_aa64afr1_el1);
|
||||||
|
|
||||||
|
get_cpu_reg_check_mask(midr_el1, _m(0000,0000,ffff,ffff));
|
||||||
|
/* mpidr sets bit 31, everything else hidden */
|
||||||
|
get_cpu_reg_check_mask(mpidr_el1, _m(0000,0000,8000,0000));
|
||||||
|
/* REVIDR is all IMPDEF so should be all zeros to user-space */
|
||||||
|
get_cpu_reg_check_zero(revidr_el1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There are a block of more registers that are RAZ in the rest of
|
||||||
|
* the Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7 space. However for
|
||||||
|
* brevity we don't check stuff that is currently un-allocated
|
||||||
|
* here. Feel free to add them ;-)
|
||||||
|
*/
|
||||||
|
|
||||||
|
printf("Remaining registers should fail\n");
|
||||||
|
should_fail = true;
|
||||||
|
|
||||||
|
/* Unexposed register access causes SIGILL */
|
||||||
|
get_cpu_reg(id_mmfr0_el1);
|
||||||
|
get_cpu_reg(id_mmfr1_el1);
|
||||||
|
get_cpu_reg(id_mmfr2_el1);
|
||||||
|
get_cpu_reg(id_mmfr3_el1);
|
||||||
|
|
||||||
|
get_cpu_reg(mvfr0_el1);
|
||||||
|
get_cpu_reg(mvfr1_el1);
|
||||||
|
|
||||||
|
if (should_not_fail_count > 0) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < should_not_fail_count; i++) {
|
||||||
|
uintptr_t pc = failed_pc[i];
|
||||||
|
uint32_t insn = *(uint32_t *) pc;
|
||||||
|
printf("insn %#x @ %#lx unexpected FAIL\n", insn, pc);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failed_bit_count > 0) {
|
||||||
|
printf("Extra information leaked to user-space!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return should_fail_count == 6 ? 0 : 1;
|
||||||
|
}
|
Loading…
Reference in a new issue