]>
Commit | Line | Data |
---|---|---|
25d8ac0e AF |
1 | /* |
2 | * Xtensa gdb server stub | |
3 | * | |
4 | * Copyright (c) 2003-2005 Fabrice Bellard | |
5 | * Copyright (c) 2013 SUSE LINUX Products GmbH | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
f08dddb3 | 10 | * version 2.1 of the License, or (at your option) any later version. |
25d8ac0e AF |
11 | * |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
19 | */ | |
09aae23d | 20 | #include "qemu/osdep.h" |
33c11879 | 21 | #include "cpu.h" |
5b50e790 | 22 | #include "exec/gdbstub.h" |
63c91552 | 23 | #include "qemu/log.h" |
25d8ac0e | 24 | |
a7ac06fd MF |
25 | enum { |
26 | xtRegisterTypeArRegfile = 1, /* Register File ar0..arXX. */ | |
27 | xtRegisterTypeSpecialReg, /* CPU states, such as PS, Booleans, (rsr). */ | |
28 | xtRegisterTypeUserReg, /* User defined registers (rur). */ | |
29 | xtRegisterTypeTieRegfile, /* User define register files. */ | |
30 | xtRegisterTypeTieState, /* TIE States (mapped on user regs). */ | |
31 | xtRegisterTypeMapped, /* Mapped on Special Registers. */ | |
32 | xtRegisterTypeUnmapped, /* Special case of masked registers. */ | |
33 | xtRegisterTypeWindow, /* Live window registers (a0..a15). */ | |
34 | xtRegisterTypeVirtual, /* PC, FP. */ | |
35 | xtRegisterTypeUnknown | |
36 | }; | |
37 | ||
38 | #define XTENSA_REGISTER_FLAGS_PRIVILEGED 0x0001 | |
39 | #define XTENSA_REGISTER_FLAGS_READABLE 0x0002 | |
40 | #define XTENSA_REGISTER_FLAGS_WRITABLE 0x0004 | |
41 | #define XTENSA_REGISTER_FLAGS_VOLATILE 0x0008 | |
42 | ||
43 | void xtensa_count_regs(const XtensaConfig *config, | |
44 | unsigned *n_regs, unsigned *n_core_regs) | |
45 | { | |
46 | unsigned i; | |
4614f0f8 | 47 | bool count_core_regs = true; |
a7ac06fd MF |
48 | |
49 | for (i = 0; config->gdb_regmap.reg[i].targno >= 0; ++i) { | |
50 | if (config->gdb_regmap.reg[i].type != xtRegisterTypeTieState && | |
51 | config->gdb_regmap.reg[i].type != xtRegisterTypeMapped && | |
52 | config->gdb_regmap.reg[i].type != xtRegisterTypeUnmapped) { | |
53 | ++*n_regs; | |
4614f0f8 MF |
54 | if (count_core_regs) { |
55 | if ((config->gdb_regmap.reg[i].flags & | |
56 | XTENSA_REGISTER_FLAGS_PRIVILEGED) == 0) { | |
57 | ++*n_core_regs; | |
58 | } else { | |
59 | count_core_regs = false; | |
60 | } | |
a7ac06fd MF |
61 | } |
62 | } | |
63 | } | |
64 | } | |
65 | ||
a010bdbe | 66 | int xtensa_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) |
25d8ac0e | 67 | { |
5b50e790 AF |
68 | XtensaCPU *cpu = XTENSA_CPU(cs); |
69 | CPUXtensaState *env = &cpu->env; | |
25d8ac0e | 70 | const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n; |
1b7b26e4 MF |
71 | #ifdef CONFIG_USER_ONLY |
72 | int num_regs = env->config->gdb_regmap.num_core_regs; | |
73 | #else | |
74 | int num_regs = env->config->gdb_regmap.num_regs; | |
75 | #endif | |
ddd44279 | 76 | unsigned i; |
25d8ac0e | 77 | |
1b7b26e4 | 78 | if (n < 0 || n >= num_regs) { |
25d8ac0e AF |
79 | return 0; |
80 | } | |
81 | ||
82 | switch (reg->type) { | |
a7ac06fd | 83 | case xtRegisterTypeVirtual: /*pc*/ |
986a2998 | 84 | return gdb_get_reg32(mem_buf, env->pc); |
25d8ac0e | 85 | |
a7ac06fd | 86 | case xtRegisterTypeArRegfile: /*ar*/ |
25d8ac0e | 87 | xtensa_sync_phys_from_window(env); |
986a2998 AF |
88 | return gdb_get_reg32(mem_buf, env->phys_regs[(reg->targno & 0xff) |
89 | % env->config->nareg]); | |
25d8ac0e | 90 | |
a7ac06fd | 91 | case xtRegisterTypeSpecialReg: /*SR*/ |
986a2998 | 92 | return gdb_get_reg32(mem_buf, env->sregs[reg->targno & 0xff]); |
25d8ac0e | 93 | |
a7ac06fd | 94 | case xtRegisterTypeUserReg: /*UR*/ |
986a2998 | 95 | return gdb_get_reg32(mem_buf, env->uregs[reg->targno & 0xff]); |
25d8ac0e | 96 | |
a7ac06fd | 97 | case xtRegisterTypeTieRegfile: /*f*/ |
ddd44279 MF |
98 | i = reg->targno & 0x0f; |
99 | switch (reg->size) { | |
100 | case 4: | |
101 | return gdb_get_reg32(mem_buf, | |
102 | float32_val(env->fregs[i].f32[FP_F32_LOW])); | |
103 | case 8: | |
104 | return gdb_get_reg64(mem_buf, float64_val(env->fregs[i].f64)); | |
105 | default: | |
dd7b952b MF |
106 | qemu_log_mask(LOG_UNIMP, "%s from reg %d of unsupported size %d\n", |
107 | __func__, n, reg->size); | |
7b8c1527 | 108 | return gdb_get_zeroes(mem_buf, reg->size); |
ddd44279 | 109 | } |
25d8ac0e | 110 | |
a7ac06fd | 111 | case xtRegisterTypeWindow: /*a*/ |
986a2998 | 112 | return gdb_get_reg32(mem_buf, env->regs[reg->targno & 0x0f]); |
25d8ac0e AF |
113 | |
114 | default: | |
c30f0d18 PB |
115 | qemu_log_mask(LOG_UNIMP, "%s from reg %d of unsupported type %d\n", |
116 | __func__, n, reg->type); | |
7b8c1527 | 117 | return gdb_get_zeroes(mem_buf, reg->size); |
25d8ac0e AF |
118 | } |
119 | } | |
120 | ||
5b50e790 | 121 | int xtensa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) |
25d8ac0e | 122 | { |
5b50e790 AF |
123 | XtensaCPU *cpu = XTENSA_CPU(cs); |
124 | CPUXtensaState *env = &cpu->env; | |
25d8ac0e AF |
125 | uint32_t tmp; |
126 | const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n; | |
1b7b26e4 MF |
127 | #ifdef CONFIG_USER_ONLY |
128 | int num_regs = env->config->gdb_regmap.num_core_regs; | |
129 | #else | |
130 | int num_regs = env->config->gdb_regmap.num_regs; | |
131 | #endif | |
25d8ac0e | 132 | |
1b7b26e4 | 133 | if (n < 0 || n >= num_regs) { |
25d8ac0e AF |
134 | return 0; |
135 | } | |
136 | ||
137 | tmp = ldl_p(mem_buf); | |
138 | ||
139 | switch (reg->type) { | |
a7ac06fd | 140 | case xtRegisterTypeVirtual: /*pc*/ |
25d8ac0e AF |
141 | env->pc = tmp; |
142 | break; | |
143 | ||
a7ac06fd | 144 | case xtRegisterTypeArRegfile: /*ar*/ |
25d8ac0e AF |
145 | env->phys_regs[(reg->targno & 0xff) % env->config->nareg] = tmp; |
146 | xtensa_sync_window_from_phys(env); | |
147 | break; | |
148 | ||
a7ac06fd | 149 | case xtRegisterTypeSpecialReg: /*SR*/ |
25d8ac0e AF |
150 | env->sregs[reg->targno & 0xff] = tmp; |
151 | break; | |
152 | ||
a7ac06fd | 153 | case xtRegisterTypeUserReg: /*UR*/ |
25d8ac0e AF |
154 | env->uregs[reg->targno & 0xff] = tmp; |
155 | break; | |
156 | ||
a7ac06fd | 157 | case xtRegisterTypeTieRegfile: /*f*/ |
ddd44279 MF |
158 | switch (reg->size) { |
159 | case 4: | |
160 | env->fregs[reg->targno & 0x0f].f32[FP_F32_LOW] = make_float32(tmp); | |
161 | return 4; | |
162 | case 8: | |
163 | env->fregs[reg->targno & 0x0f].f64 = make_float64(tmp); | |
164 | return 8; | |
165 | default: | |
dd7b952b MF |
166 | qemu_log_mask(LOG_UNIMP, "%s to reg %d of unsupported size %d\n", |
167 | __func__, n, reg->size); | |
168 | return reg->size; | |
ddd44279 | 169 | } |
25d8ac0e | 170 | |
a7ac06fd | 171 | case xtRegisterTypeWindow: /*a*/ |
25d8ac0e AF |
172 | env->regs[reg->targno & 0x0f] = tmp; |
173 | break; | |
174 | ||
175 | default: | |
c30f0d18 PB |
176 | qemu_log_mask(LOG_UNIMP, "%s to reg %d of unsupported type %d\n", |
177 | __func__, n, reg->type); | |
dd7b952b | 178 | return reg->size; |
25d8ac0e AF |
179 | } |
180 | ||
181 | return 4; | |
182 | } |