]>
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 | |
10 | * version 2 of the License, or (at your option) any later version. | |
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); | |
108 | memset(mem_buf, 0, reg->size); | |
109 | return reg->size; | |
ddd44279 | 110 | } |
25d8ac0e | 111 | |
a7ac06fd | 112 | case xtRegisterTypeWindow: /*a*/ |
986a2998 | 113 | return gdb_get_reg32(mem_buf, env->regs[reg->targno & 0x0f]); |
25d8ac0e AF |
114 | |
115 | default: | |
c30f0d18 PB |
116 | qemu_log_mask(LOG_UNIMP, "%s from reg %d of unsupported type %d\n", |
117 | __func__, n, reg->type); | |
dd7b952b MF |
118 | memset(mem_buf, 0, reg->size); |
119 | return reg->size; | |
25d8ac0e AF |
120 | } |
121 | } | |
122 | ||
5b50e790 | 123 | int xtensa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) |
25d8ac0e | 124 | { |
5b50e790 AF |
125 | XtensaCPU *cpu = XTENSA_CPU(cs); |
126 | CPUXtensaState *env = &cpu->env; | |
25d8ac0e AF |
127 | uint32_t tmp; |
128 | const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n; | |
1b7b26e4 MF |
129 | #ifdef CONFIG_USER_ONLY |
130 | int num_regs = env->config->gdb_regmap.num_core_regs; | |
131 | #else | |
132 | int num_regs = env->config->gdb_regmap.num_regs; | |
133 | #endif | |
25d8ac0e | 134 | |
1b7b26e4 | 135 | if (n < 0 || n >= num_regs) { |
25d8ac0e AF |
136 | return 0; |
137 | } | |
138 | ||
139 | tmp = ldl_p(mem_buf); | |
140 | ||
141 | switch (reg->type) { | |
a7ac06fd | 142 | case xtRegisterTypeVirtual: /*pc*/ |
25d8ac0e AF |
143 | env->pc = tmp; |
144 | break; | |
145 | ||
a7ac06fd | 146 | case xtRegisterTypeArRegfile: /*ar*/ |
25d8ac0e AF |
147 | env->phys_regs[(reg->targno & 0xff) % env->config->nareg] = tmp; |
148 | xtensa_sync_window_from_phys(env); | |
149 | break; | |
150 | ||
a7ac06fd | 151 | case xtRegisterTypeSpecialReg: /*SR*/ |
25d8ac0e AF |
152 | env->sregs[reg->targno & 0xff] = tmp; |
153 | break; | |
154 | ||
a7ac06fd | 155 | case xtRegisterTypeUserReg: /*UR*/ |
25d8ac0e AF |
156 | env->uregs[reg->targno & 0xff] = tmp; |
157 | break; | |
158 | ||
a7ac06fd | 159 | case xtRegisterTypeTieRegfile: /*f*/ |
ddd44279 MF |
160 | switch (reg->size) { |
161 | case 4: | |
162 | env->fregs[reg->targno & 0x0f].f32[FP_F32_LOW] = make_float32(tmp); | |
163 | return 4; | |
164 | case 8: | |
165 | env->fregs[reg->targno & 0x0f].f64 = make_float64(tmp); | |
166 | return 8; | |
167 | default: | |
dd7b952b MF |
168 | qemu_log_mask(LOG_UNIMP, "%s to reg %d of unsupported size %d\n", |
169 | __func__, n, reg->size); | |
170 | return reg->size; | |
ddd44279 | 171 | } |
25d8ac0e | 172 | |
a7ac06fd | 173 | case xtRegisterTypeWindow: /*a*/ |
25d8ac0e AF |
174 | env->regs[reg->targno & 0x0f] = tmp; |
175 | break; | |
176 | ||
177 | default: | |
c30f0d18 PB |
178 | qemu_log_mask(LOG_UNIMP, "%s to reg %d of unsupported type %d\n", |
179 | __func__, n, reg->type); | |
dd7b952b | 180 | return reg->size; |
25d8ac0e AF |
181 | } |
182 | ||
183 | return 4; | |
184 | } |