| /* |
| * ARM gdb server stub: AArch64 specific functions. |
| * |
| * Copyright (c) 2013 SUSE LINUX Products GmbH |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
| */ |
| #include "qemu/osdep.h" |
| #include "qemu/log.h" |
| #include "cpu.h" |
| #include "internals.h" |
| #include "exec/gdbstub.h" |
| |
| int aarch64_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) |
| { |
| ARMCPU *cpu = ARM_CPU(cs); |
| CPUARMState *env = &cpu->env; |
| |
| if (n < 31) { |
| /* Core integer register. */ |
| return gdb_get_reg64(mem_buf, env->xregs[n]); |
| } |
| switch (n) { |
| case 31: |
| return gdb_get_reg64(mem_buf, env->xregs[31]); |
| case 32: |
| return gdb_get_reg64(mem_buf, env->pc); |
| case 33: |
| return gdb_get_reg32(mem_buf, pstate_read(env)); |
| } |
| /* Unknown register. */ |
| return 0; |
| } |
| |
| int aarch64_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) |
| { |
| ARMCPU *cpu = ARM_CPU(cs); |
| CPUARMState *env = &cpu->env; |
| uint64_t tmp; |
| |
| tmp = ldq_p(mem_buf); |
| |
| if (n < 31) { |
| /* Core integer register. */ |
| env->xregs[n] = tmp; |
| return 8; |
| } |
| switch (n) { |
| case 31: |
| env->xregs[31] = tmp; |
| return 8; |
| case 32: |
| env->pc = tmp; |
| return 8; |
| case 33: |
| /* CPSR */ |
| pstate_write(env, tmp); |
| return 4; |
| } |
| /* Unknown register. */ |
| return 0; |
| } |
| |
| int aarch64_fpu_gdb_get_reg(CPUARMState *env, GByteArray *buf, int reg) |
| { |
| switch (reg) { |
| case 0 ... 31: |
| { |
| /* 128 bit FP register - quads are in LE order */ |
| uint64_t *q = aa64_vfp_qreg(env, reg); |
| return gdb_get_reg128(buf, q[1], q[0]); |
| } |
| case 32: |
| /* FPSR */ |
| return gdb_get_reg32(buf, vfp_get_fpsr(env)); |
| case 33: |
| /* FPCR */ |
| return gdb_get_reg32(buf, vfp_get_fpcr(env)); |
| default: |
| return 0; |
| } |
| } |
| |
| int aarch64_fpu_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg) |
| { |
| switch (reg) { |
| case 0 ... 31: |
| /* 128 bit FP register */ |
| { |
| uint64_t *q = aa64_vfp_qreg(env, reg); |
| q[0] = ldq_le_p(buf); |
| q[1] = ldq_le_p(buf + 8); |
| return 16; |
| } |
| case 32: |
| /* FPSR */ |
| vfp_set_fpsr(env, ldl_p(buf)); |
| return 4; |
| case 33: |
| /* FPCR */ |
| vfp_set_fpcr(env, ldl_p(buf)); |
| return 4; |
| default: |
| return 0; |
| } |
| } |
| |
| 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_vqm1_for_el(env, arm_current_el(env)) + 1; |
| return gdb_get_reg64(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; |
| } |
| |
| 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; |
| } |