| 1 | /* |
| 2 | * RISC-V GDB Server Stub |
| 3 | * |
| 4 | * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms and conditions of the GNU General Public License, |
| 8 | * version 2 or later, as published by the Free Software Foundation. |
| 9 | * |
| 10 | * This program is distributed in the hope it will be useful, but WITHOUT |
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| 13 | * more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License along with |
| 16 | * this program. If not, see <http://www.gnu.org/licenses/>. |
| 17 | */ |
| 18 | |
| 19 | #include "qemu/osdep.h" |
| 20 | #include "exec/gdbstub.h" |
| 21 | #include "gdbstub/helpers.h" |
| 22 | #include "cpu.h" |
| 23 | #include "internals.h" |
| 24 | #include "target/riscv/tcg/csr.h" |
| 25 | |
| 26 | struct TypeSize { |
| 27 | const char *gdb_type; |
| 28 | const char *id; |
| 29 | int size; |
| 30 | const char suffix; |
| 31 | }; |
| 32 | |
| 33 | static const struct TypeSize vec_lanes[] = { |
| 34 | /* quads */ |
| 35 | { "uint128", "quads", 128, 'q' }, |
| 36 | /* 64 bit */ |
| 37 | { "uint64", "longs", 64, 'l' }, |
| 38 | /* 32 bit */ |
| 39 | { "uint32", "words", 32, 'w' }, |
| 40 | /* 16 bit */ |
| 41 | { "uint16", "shorts", 16, 's' }, |
| 42 | /* |
| 43 | * TODO: currently there is no reliable way of telling |
| 44 | * if the remote gdb actually understands ieee_half so |
| 45 | * we don't expose it in the target description for now. |
| 46 | * { "ieee_half", 16, 'h', 'f' }, |
| 47 | */ |
| 48 | /* bytes */ |
| 49 | { "uint8", "bytes", 8, 'b' }, |
| 50 | }; |
| 51 | |
| 52 | static uint64_t ldn(CPURISCVState *env, uint8_t *mem_buf, size_t regsz) |
| 53 | { |
| 54 | return (mo_endian_env(env) == MO_LE ? ldn_le_p : ldn_be_p)(mem_buf, regsz); |
| 55 | } |
| 56 | |
| 57 | int riscv_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) |
| 58 | { |
| 59 | RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cs); |
| 60 | RISCVCPU *cpu = RISCV_CPU(cs); |
| 61 | CPURISCVState *env = &cpu->env; |
| 62 | uint64_t tmp; |
| 63 | |
| 64 | if (n < 32) { |
| 65 | tmp = env->gpr[n]; |
| 66 | } else if (n == 32) { |
| 67 | tmp = env->pc; |
| 68 | } else { |
| 69 | return 0; |
| 70 | } |
| 71 | |
| 72 | switch (mcc->def->misa_mxl_max) { |
| 73 | case MXL_RV32: |
| 74 | return gdb_get_reg32(mem_buf, tmp); |
| 75 | case MXL_RV64: |
| 76 | case MXL_RV128: |
| 77 | return gdb_get_reg64(mem_buf, tmp); |
| 78 | default: |
| 79 | g_assert_not_reached(); |
| 80 | } |
| 81 | return 0; |
| 82 | } |
| 83 | |
| 84 | int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) |
| 85 | { |
| 86 | RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cs); |
| 87 | RISCVCPU *cpu = RISCV_CPU(cs); |
| 88 | CPURISCVState *env = &cpu->env; |
| 89 | const size_t regsize = mcc->def->misa_mxl_max == MXL_RV32 ? 4 : 8; |
| 90 | uint64_t tmp = ldn(env, mem_buf, regsize); |
| 91 | |
| 92 | if (env->xl < MXL_RV64) { |
| 93 | tmp = (int32_t)tmp; |
| 94 | } |
| 95 | |
| 96 | if (n > 0 && n < 32) { |
| 97 | env->gpr[n] = tmp; |
| 98 | } else if (n == 32) { |
| 99 | env->pc = tmp; |
| 100 | } |
| 101 | |
| 102 | return regsize; |
| 103 | } |
| 104 | |
| 105 | static int riscv_gdb_get_fpu(CPUState *cs, GByteArray *buf, int n) |
| 106 | { |
| 107 | RISCVCPU *cpu = RISCV_CPU(cs); |
| 108 | CPURISCVState *env = &cpu->env; |
| 109 | |
| 110 | if (n < 32) { |
| 111 | if (env->misa_ext & RVD) { |
| 112 | return gdb_get_reg64(buf, env->fpr[n]); |
| 113 | } |
| 114 | if (env->misa_ext & RVF) { |
| 115 | return gdb_get_reg32(buf, env->fpr[n]); |
| 116 | } |
| 117 | } |
| 118 | return 0; |
| 119 | } |
| 120 | |
| 121 | static int riscv_gdb_set_fpu(CPUState *cs, uint8_t *mem_buf, int n) |
| 122 | { |
| 123 | RISCVCPU *cpu = RISCV_CPU(cs); |
| 124 | CPURISCVState *env = &cpu->env; |
| 125 | |
| 126 | if (n < 32) { |
| 127 | env->fpr[n] = ldn(env, mem_buf, 8); /* always 64-bit */ |
| 128 | return sizeof(uint64_t); |
| 129 | } |
| 130 | return 0; |
| 131 | } |
| 132 | |
| 133 | static int riscv_gdb_get_vector(CPUState *cs, GByteArray *buf, int n) |
| 134 | { |
| 135 | RISCVCPU *cpu = RISCV_CPU(cs); |
| 136 | CPURISCVState *env = &cpu->env; |
| 137 | uint16_t vlenb = cpu->cfg.vlenb; |
| 138 | if (n < 32) { |
| 139 | int i; |
| 140 | int cnt = 0; |
| 141 | for (i = 0; i < vlenb; i += 8) { |
| 142 | cnt += gdb_get_reg64(buf, |
| 143 | env->vreg[(n * vlenb + i) / 8]); |
| 144 | } |
| 145 | return cnt; |
| 146 | } |
| 147 | |
| 148 | return 0; |
| 149 | } |
| 150 | |
| 151 | static int riscv_gdb_set_vector(CPUState *cs, uint8_t *mem_buf, int n) |
| 152 | { |
| 153 | RISCVCPU *cpu = RISCV_CPU(cs); |
| 154 | CPURISCVState *env = &cpu->env; |
| 155 | uint16_t vlenb = cpu->cfg.vlenb; |
| 156 | if (n < 32) { |
| 157 | int i; |
| 158 | for (i = 0; i < vlenb; i += 8) { |
| 159 | env->vreg[(n * vlenb + i) / 8] = ldn(env, mem_buf + i, 8); |
| 160 | } |
| 161 | return vlenb; |
| 162 | } |
| 163 | |
| 164 | return 0; |
| 165 | } |
| 166 | |
| 167 | #ifdef CONFIG_TCG |
| 168 | static int riscv_gdb_get_csr(CPUState *cs, GByteArray *buf, int n) |
| 169 | { |
| 170 | RISCVCPU *cpu = RISCV_CPU(cs); |
| 171 | CPURISCVState *env = &cpu->env; |
| 172 | |
| 173 | if (n < CSR_TABLE_SIZE) { |
| 174 | target_ulong val = 0; |
| 175 | int result; |
| 176 | |
| 177 | result = riscv_csrrw_debug(env, n, &val, 0, 0); |
| 178 | if (result == RISCV_EXCP_NONE) { |
| 179 | return gdb_get_regl(buf, val); |
| 180 | } |
| 181 | } |
| 182 | return 0; |
| 183 | } |
| 184 | |
| 185 | static int riscv_gdb_set_csr(CPUState *cs, uint8_t *mem_buf, int n) |
| 186 | { |
| 187 | RISCVCPU *cpu = RISCV_CPU(cs); |
| 188 | CPURISCVState *env = &cpu->env; |
| 189 | const unsigned regsz = riscv_cpu_is_32bit(cpu) ? 4 : 8; |
| 190 | |
| 191 | if (n < CSR_TABLE_SIZE) { |
| 192 | uint64_t val = ldn(env, mem_buf, regsz); |
| 193 | int result; |
| 194 | |
| 195 | result = riscv_csrrw_debug(env, n, NULL, val, -1); |
| 196 | if (result == RISCV_EXCP_NONE) { |
| 197 | return regsz; |
| 198 | } |
| 199 | } |
| 200 | return 0; |
| 201 | } |
| 202 | |
| 203 | static int riscv_gdb_get_virtual(CPUState *cs, GByteArray *buf, int n) |
| 204 | { |
| 205 | if (n == 0) { |
| 206 | #ifdef CONFIG_USER_ONLY |
| 207 | return gdb_get_regl(buf, 0); |
| 208 | #else |
| 209 | RISCVCPU *cpu = RISCV_CPU(cs); |
| 210 | CPURISCVState *env = &cpu->env; |
| 211 | |
| 212 | /* Per RiscV debug spec v1.0.0 rc4 */ |
| 213 | uint32_t vbit = (env->virt_enabled) ? BIT(2) : 0; |
| 214 | |
| 215 | return gdb_get_regl(buf, env->priv | vbit); |
| 216 | #endif |
| 217 | } |
| 218 | return 0; |
| 219 | } |
| 220 | |
| 221 | static int riscv_gdb_set_virtual(CPUState *cs, uint8_t *mem_buf, int n) |
| 222 | { |
| 223 | if (n == 0) { |
| 224 | RISCVCPU *cpu = RISCV_CPU(cs); |
| 225 | const unsigned regsz = riscv_cpu_is_32bit(cpu) ? 4 : 8; |
| 226 | #ifndef CONFIG_USER_ONLY |
| 227 | CPURISCVState *env = &cpu->env; |
| 228 | privilege_mode_t new_priv = ldn(env, mem_buf, regsz) & 0x3; |
| 229 | bool new_virt = 0; |
| 230 | |
| 231 | if (new_priv == PRV_RESERVED) { |
| 232 | new_priv = PRV_S; |
| 233 | } |
| 234 | |
| 235 | if (new_priv != PRV_M) { |
| 236 | new_virt = (ldn(env, mem_buf, regsz) & BIT(2)) >> 2; |
| 237 | } |
| 238 | |
| 239 | if (riscv_has_ext(env, RVH) && new_virt != env->virt_enabled) { |
| 240 | riscv_cpu_swap_hypervisor_regs(env); |
| 241 | } |
| 242 | |
| 243 | riscv_cpu_set_mode(env, new_priv, new_virt); |
| 244 | #endif |
| 245 | return regsz; |
| 246 | } |
| 247 | return 0; |
| 248 | } |
| 249 | |
| 250 | static GDBFeature *riscv_gen_dynamic_csr_feature(CPUState *cs, int base_reg) |
| 251 | { |
| 252 | RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cs); |
| 253 | RISCVCPU *cpu = RISCV_CPU(cs); |
| 254 | CPURISCVState *env = &cpu->env; |
| 255 | GDBFeatureBuilder builder; |
| 256 | riscv_csr_predicate_fn predicate; |
| 257 | int bitsize = riscv_cpu_max_xlen(mcc); |
| 258 | const char *name; |
| 259 | int i; |
| 260 | |
| 261 | #if !defined(CONFIG_USER_ONLY) |
| 262 | env->debugger = true; |
| 263 | #endif |
| 264 | |
| 265 | /* Until gdb knows about 128-bit registers */ |
| 266 | if (bitsize > 64) { |
| 267 | bitsize = 64; |
| 268 | } |
| 269 | |
| 270 | gdb_feature_builder_init(&builder, &cpu->dyn_csr_feature, |
| 271 | "org.gnu.gdb.riscv.csr", "riscv-csr.xml", |
| 272 | base_reg); |
| 273 | |
| 274 | for (i = 0; i < CSR_TABLE_SIZE; i++) { |
| 275 | if (env->priv_ver < csr_ops[i].min_priv_ver) { |
| 276 | continue; |
| 277 | } |
| 278 | predicate = csr_ops[i].predicate; |
| 279 | if (predicate && (predicate(env, i) == RISCV_EXCP_NONE)) { |
| 280 | name = csr_ops[i].name; |
| 281 | if (!name) { |
| 282 | name = g_strdup_printf("csr%03x", i); |
| 283 | } |
| 284 | |
| 285 | gdb_feature_builder_append_reg(&builder, name, bitsize, i, |
| 286 | "int", NULL); |
| 287 | } |
| 288 | } |
| 289 | |
| 290 | gdb_feature_builder_end(&builder); |
| 291 | |
| 292 | #if !defined(CONFIG_USER_ONLY) |
| 293 | env->debugger = false; |
| 294 | #endif |
| 295 | |
| 296 | return &cpu->dyn_csr_feature; |
| 297 | } |
| 298 | #endif /* CONFIG_TCG */ |
| 299 | |
| 300 | static GDBFeature *ricsv_gen_dynamic_vector_feature(CPUState *cs, int base_reg) |
| 301 | { |
| 302 | RISCVCPU *cpu = RISCV_CPU(cs); |
| 303 | int bitsize = cpu->cfg.vlenb << 3; |
| 304 | GDBFeatureBuilder builder; |
| 305 | int i; |
| 306 | |
| 307 | gdb_feature_builder_init(&builder, &cpu->dyn_vreg_feature, |
| 308 | "org.gnu.gdb.riscv.vector", "riscv-vector.xml", |
| 309 | base_reg); |
| 310 | |
| 311 | /* First define types and totals in a whole VL */ |
| 312 | for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) { |
| 313 | int count = bitsize / vec_lanes[i].size; |
| 314 | gdb_feature_builder_append_tag( |
| 315 | &builder, "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>", |
| 316 | vec_lanes[i].id, vec_lanes[i].gdb_type, count); |
| 317 | } |
| 318 | |
| 319 | /* Define unions */ |
| 320 | gdb_feature_builder_append_tag(&builder, "<union id=\"riscv_vector\">"); |
| 321 | for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) { |
| 322 | gdb_feature_builder_append_tag(&builder, |
| 323 | "<field name=\"%c\" type=\"%s\"/>", |
| 324 | vec_lanes[i].suffix, vec_lanes[i].id); |
| 325 | } |
| 326 | gdb_feature_builder_append_tag(&builder, "</union>"); |
| 327 | |
| 328 | /* Define vector registers */ |
| 329 | for (i = 0; i < 32; i++) { |
| 330 | gdb_feature_builder_append_reg(&builder, g_strdup_printf("v%d", i), |
| 331 | bitsize, i, "riscv_vector", "vector"); |
| 332 | } |
| 333 | |
| 334 | gdb_feature_builder_end(&builder); |
| 335 | |
| 336 | return &cpu->dyn_vreg_feature; |
| 337 | } |
| 338 | |
| 339 | void riscv_cpu_register_gdb_regs_for_features(CPUState *cs) |
| 340 | { |
| 341 | RISCVCPU *cpu = RISCV_CPU(cs); |
| 342 | CPURISCVState *env = &cpu->env; |
| 343 | if (env->misa_ext & RVD) { |
| 344 | gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu, |
| 345 | gdb_find_static_feature("riscv-64bit-fpu.xml")); |
| 346 | } else if (env->misa_ext & RVF) { |
| 347 | gdb_register_coprocessor(cs, riscv_gdb_get_fpu, riscv_gdb_set_fpu, |
| 348 | gdb_find_static_feature("riscv-32bit-fpu.xml")); |
| 349 | } |
| 350 | if (cpu->cfg.ext_zve32x) { |
| 351 | gdb_register_coprocessor(cs, riscv_gdb_get_vector, |
| 352 | riscv_gdb_set_vector, |
| 353 | ricsv_gen_dynamic_vector_feature(cs, cs->gdb_num_regs)); |
| 354 | } |
| 355 | |
| 356 | #ifdef CONFIG_TCG |
| 357 | RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cs); |
| 358 | |
| 359 | switch (mcc->def->misa_mxl_max) { |
| 360 | case MXL_RV32: |
| 361 | gdb_register_coprocessor(cs, riscv_gdb_get_virtual, |
| 362 | riscv_gdb_set_virtual, |
| 363 | gdb_find_static_feature("riscv-32bit-virtual.xml")); |
| 364 | break; |
| 365 | case MXL_RV64: |
| 366 | case MXL_RV128: |
| 367 | gdb_register_coprocessor(cs, riscv_gdb_get_virtual, |
| 368 | riscv_gdb_set_virtual, |
| 369 | gdb_find_static_feature("riscv-64bit-virtual.xml")); |
| 370 | break; |
| 371 | default: |
| 372 | g_assert_not_reached(); |
| 373 | } |
| 374 | |
| 375 | if (cpu->cfg.ext_zicsr) { |
| 376 | gdb_register_coprocessor(cs, riscv_gdb_get_csr, riscv_gdb_set_csr, |
| 377 | riscv_gen_dynamic_csr_feature(cs, cs->gdb_num_regs)); |
| 378 | } |
| 379 | #endif |
| 380 | } |