1 /* 2 * LOONGARCH gdb server stub 3 * 4 * Copyright (c) 2021 Loongson Technology Corporation Limited 5 * 6 * SPDX-License-Identifier: LGPL-2.1+ 7 */ 8 9 #include "qemu/osdep.h" 10 #include "cpu.h" 11 #include "internals.h" 12 #include "exec/gdbstub.h" 13 #include "gdbstub/helpers.h" 14 #include "vec.h" 15 16 uint64_t read_fcc(CPULoongArchState *env) 17 { 18 uint64_t ret = 0; 19 20 for (int i = 0; i < 8; ++i) { 21 ret |= (uint64_t)env->cf[i] << (i * 8); 22 } 23 24 return ret; 25 } 26 27 void write_fcc(CPULoongArchState *env, uint64_t val) 28 { 29 for (int i = 0; i < 8; ++i) { 30 env->cf[i] = (val >> (i * 8)) & 1; 31 } 32 } 33 34 int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) 35 { 36 CPULoongArchState *env = cpu_env(cs); 37 38 if (0 <= n && n <= 34) { 39 uint64_t val; 40 41 if (n < 32) { 42 val = env->gpr[n]; 43 } else if (n == 32) { 44 /* orig_a0 */ 45 val = 0; 46 } else if (n == 33) { 47 val = env->pc; 48 } else /* if (n == 34) */ { 49 val = env->CSR_BADV; 50 } 51 52 if (is_la64(env)) { 53 return gdb_get_reg64(mem_buf, val); 54 } else { 55 return gdb_get_reg32(mem_buf, val); 56 } 57 } 58 59 return 0; 60 } 61 62 int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) 63 { 64 CPULoongArchState *env = cpu_env(cs); 65 target_ulong tmp; 66 int length = 0; 67 68 if (n < 0 || n > 34) { 69 return 0; 70 } 71 72 if (is_la64(env)) { 73 tmp = ldq_le_p(mem_buf); 74 length = 8; 75 } else { 76 tmp = ldl_le_p(mem_buf); 77 length = 4; 78 } 79 80 if (0 <= n && n < 32) { 81 env->gpr[n] = tmp; 82 } else if (n == 33) { 83 set_pc(env, tmp); 84 } 85 return length; 86 } 87 88 static int loongarch_gdb_get_fpu(CPUState *cs, GByteArray *mem_buf, int n) 89 { 90 LoongArchCPU *cpu = LOONGARCH_CPU(cs); 91 CPULoongArchState *env = &cpu->env; 92 93 if (0 <= n && n < 32) { 94 return gdb_get_reg64(mem_buf, env->fpr[n].vreg.D(0)); 95 } else if (32 <= n && n < 40) { 96 return gdb_get_reg8(mem_buf, env->cf[n - 32]); 97 } else if (n == 40) { 98 return gdb_get_reg32(mem_buf, env->fcsr0); 99 } 100 return 0; 101 } 102 103 static int loongarch_gdb_set_fpu(CPUState *cs, uint8_t *mem_buf, int n) 104 { 105 LoongArchCPU *cpu = LOONGARCH_CPU(cs); 106 CPULoongArchState *env = &cpu->env; 107 int length = 0; 108 109 if (0 <= n && n < 32) { 110 env->fpr[n].vreg.D(0) = ldq_le_p(mem_buf); 111 length = 8; 112 } else if (32 <= n && n < 40) { 113 env->cf[n - 32] = ldub_p(mem_buf); 114 length = 1; 115 } else if (n == 40) { 116 env->fcsr0 = ldl_le_p(mem_buf); 117 length = 4; 118 } 119 return length; 120 } 121 122 #define VREG_NUM 32 123 #define REG64_LEN 64 124 125 static int loongarch_gdb_get_vec(CPUState *cs, GByteArray *mem_buf, int n, int vl) 126 { 127 LoongArchCPU *cpu = LOONGARCH_CPU(cs); 128 CPULoongArchState *env = &cpu->env; 129 int i, length = 0; 130 131 if (0 <= n && n < VREG_NUM) { 132 for (i = 0; i < vl / REG64_LEN; i++) { 133 length += gdb_get_reg64(mem_buf, env->fpr[n].vreg.D(i)); 134 } 135 } 136 137 return length; 138 } 139 140 static int loongarch_gdb_set_vec(CPUState *cs, uint8_t *mem_buf, int n, int vl) 141 { 142 LoongArchCPU *cpu = LOONGARCH_CPU(cs); 143 CPULoongArchState *env = &cpu->env; 144 int i, length = 0; 145 146 if (0 <= n && n < VREG_NUM) { 147 for (i = 0; i < vl / REG64_LEN; i++) { 148 env->fpr[n].vreg.D(i) = ldq_le_p(mem_buf + 8 * i); 149 length += 8; 150 } 151 } 152 153 return length; 154 } 155 156 static int loongarch_gdb_get_lsx(CPUState *cs, GByteArray *mem_buf, int n) 157 { 158 return loongarch_gdb_get_vec(cs, mem_buf, n, LSX_LEN); 159 } 160 161 static int loongarch_gdb_set_lsx(CPUState *cs, uint8_t *mem_buf, int n) 162 { 163 return loongarch_gdb_set_vec(cs, mem_buf, n, LSX_LEN); 164 } 165 166 static int loongarch_gdb_get_lasx(CPUState *cs, GByteArray *mem_buf, int n) 167 { 168 return loongarch_gdb_get_vec(cs, mem_buf, n, LASX_LEN); 169 } 170 171 static int loongarch_gdb_set_lasx(CPUState *cs, uint8_t *mem_buf, int n) 172 { 173 return loongarch_gdb_set_vec(cs, mem_buf, n, LASX_LEN); 174 } 175 176 void loongarch_cpu_register_gdb_regs_for_features(CPUState *cs) 177 { 178 LoongArchCPU *cpu = LOONGARCH_CPU(cs); 179 CPULoongArchState *env = &cpu->env; 180 181 if (FIELD_EX32(env->cpucfg[2], CPUCFG2, FP)) { 182 gdb_register_coprocessor(cs, loongarch_gdb_get_fpu, loongarch_gdb_set_fpu, 183 gdb_find_static_feature("loongarch-fpu.xml"), 0); 184 } 185 186 if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LSX)) { 187 gdb_register_coprocessor(cs, loongarch_gdb_get_lsx, loongarch_gdb_set_lsx, 188 gdb_find_static_feature("loongarch-lsx.xml"), 0); 189 } 190 191 if (FIELD_EX32(env->cpucfg[2], CPUCFG2, LASX)) { 192 gdb_register_coprocessor(cs, loongarch_gdb_get_lasx, loongarch_gdb_set_lasx, 193 gdb_find_static_feature("loongarch-lasx.xml"), 0); 194 } 195 } 196