Imported Upstream version 7.9
[platform/upstream/gdb.git] / gdb / gdbserver / linux-tic6x-low.c
1 /* Target dependent code for GDB on TI C6x systems.
2
3    Copyright (C) 2010-2015 Free Software Foundation, Inc.
4    Contributed by Andrew Jenner <andrew@codesourcery.com>
5    Contributed by Yao Qi <yao@codesourcery.com>
6
7    This file is part of GDB.
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21
22 #include "server.h"
23 #include "linux-low.h"
24
25 #include <sys/ptrace.h>
26 #include <endian.h>
27
28 #include "gdb_proc_service.h"
29
30 #ifndef PTRACE_GET_THREAD_AREA
31 #define PTRACE_GET_THREAD_AREA 25
32 #endif
33
34 /* There are at most 69 registers accessible in ptrace.  */
35 #define TIC6X_NUM_REGS 69
36
37 #include <asm/ptrace.h>
38
39 /* Defined in auto-generated file tic6x-c64xp-linux.c.  */
40 void init_registers_tic6x_c64xp_linux (void);
41 extern const struct target_desc *tdesc_tic6x_c64xp_linux;
42
43 /* Defined in auto-generated file tic6x-c64x-linux.c.  */
44 void init_registers_tic6x_c64x_linux (void);
45 extern const struct target_desc *tdesc_tic6x_c64x_linux;
46
47 /* Defined in auto-generated file tic62x-c6xp-linux.c.  */
48 void init_registers_tic6x_c62x_linux (void);
49 extern const struct target_desc *tdesc_tic6x_c62x_linux;
50
51 union tic6x_register
52 {
53   unsigned char buf[4];
54
55   int reg32;
56 };
57
58 /* Return the ptrace ``address'' of register REGNO.  */
59
60 #if __BYTE_ORDER == __BIG_ENDIAN
61 static int tic6x_regmap_c64xp[] = {
62   /* A0 - A15 */
63   53, 52, 55, 54, 57, 56, 59, 58,
64   61, 60, 63, 62, 65, 64, 67, 66,
65   /* B0 - B15 */
66   23, 22, 25, 24, 27, 26, 29, 28,
67   31, 30, 33, 32, 35, 34, 69, 68,
68   /* CSR PC */
69   5, 4,
70   /* A16 - A31 */
71   37, 36, 39, 38, 41, 40, 43, 42,
72   45, 44, 47, 46, 49, 48, 51, 50,
73   /* B16 - B31 */
74   7,  6,  9,  8,  11, 10, 13, 12,
75   15, 14, 17, 16, 19, 18, 21, 20,
76   /* TSR, ILC, RILC */
77   1,  2, 3
78 };
79
80 static int tic6x_regmap_c64x[] = {
81   /* A0 - A15 */
82   51, 50, 53, 52, 55, 54, 57, 56,
83   59, 58, 61, 60, 63, 62, 65, 64,
84   /* B0 - B15 */
85   21, 20, 23, 22, 25, 24, 27, 26,
86   29, 28, 31, 30, 33, 32, 67, 66,
87   /* CSR PC */
88   3,  2,
89   /* A16 - A31 */
90   35, 34, 37, 36, 39, 38, 41, 40,
91   43, 42, 45, 44, 47, 46, 49, 48,
92   /* B16 - B31 */
93   5,  4,  7,  6,  9,  8,  11, 10,
94   13, 12, 15, 14, 17, 16, 19, 18,
95   -1, -1, -1
96 };
97
98 static int tic6x_regmap_c62x[] = {
99   /* A0 - A15 */
100   19, 18, 21, 20, 23, 22, 25, 24,
101   27, 26, 29, 28, 31, 30, 33, 32,
102   /* B0 - B15 */
103    5,  4,  7,  6,  9,  8, 11, 10,
104   13, 12, 15, 14, 17, 16, 35, 34,
105   /* CSR, PC */
106   3, 2,
107   -1, -1, -1, -1, -1, -1, -1, -1,
108   -1, -1, -1, -1, -1, -1, -1, -1,
109   -1, -1, -1, -1, -1, -1, -1, -1,
110   -1, -1, -1, -1, -1, -1, -1, -1,
111   -1, -1, -1
112 };
113
114 #else
115 static int tic6x_regmap_c64xp[] = {
116   /* A0 - A15 */
117   52, 53, 54, 55, 56, 57, 58, 59,
118   60, 61, 62, 63, 64, 65, 66, 67,
119   /* B0 - B15 */
120   22, 23, 24, 25, 26, 27, 28, 29,
121   30, 31, 32, 33, 34, 35, 68, 69,
122   /* CSR PC */
123    4,  5,
124   /* A16 - A31 */
125   36, 37, 38, 39, 40, 41, 42, 43,
126   44, 45, 46, 47, 48, 49, 50, 51,
127   /* B16 -B31 */
128    6,  7,  8,  9, 10, 11, 12, 13,
129   14, 15, 16, 17, 18, 19, 20, 31,
130   /* TSR, ILC, RILC */
131   0,  3, 2
132 };
133
134 static int tic6x_regmap_c64x[] = {
135   /* A0 - A15 */
136   50, 51, 52, 53, 54, 55, 56, 57,
137   58, 59, 60, 61, 62, 63, 64, 65,
138   /* B0 - B15 */
139   20, 21, 22, 23, 24, 25, 26, 27,
140   28, 29, 30, 31, 32, 33, 66, 67,
141   /* CSR PC */
142   2,  3,
143   /* A16 - A31 */
144   34, 35, 36, 37, 38, 39, 40, 41,
145   42, 43, 44, 45, 46, 47, 48, 49,
146   /* B16 - B31 */
147   4,  5,  6,  7,  8,  9,  10, 11,
148   12, 13, 14, 15, 16, 17, 18, 19,
149   -1, -1, -1
150 };
151
152 static int tic6x_regmap_c62x[] = {
153   /* A0 - A15 */
154   18, 19, 20, 21, 22, 23, 24, 25,
155   26, 27, 28, 29, 30, 31, 32, 33,
156   /* B0 - B15 */
157   4,  5,  6,  7,  8,  9, 10, 11,
158   12, 13, 14, 15, 16, 17, 34, 35,
159   /* CSR PC */
160   2,  3,
161   -1, -1, -1, -1, -1, -1, -1, -1,
162   -1, -1, -1, -1, -1, -1, -1, -1,
163   -1, -1, -1, -1, -1, -1, -1, -1,
164   -1, -1, -1, -1, -1, -1, -1, -1,
165   -1, -1, -1
166 };
167
168 #endif
169
170 extern struct linux_target_ops the_low_target;
171
172 static int *tic6x_regmap;
173 static unsigned int tic6x_breakpoint;
174
175 /* Forward definition.  */
176 static struct usrregs_info tic6x_usrregs_info;
177
178 static const struct target_desc *
179 tic6x_read_description (void)
180 {
181   register unsigned int csr asm ("B2");
182   unsigned int cpuid;
183   const struct target_desc *tdesc;
184
185   /* Determine the CPU we're running on to find the register order.  */
186   __asm__ ("MVC .S2 CSR,%0" : "=r" (csr) :);
187   cpuid = csr >> 24;
188   switch (cpuid)
189     {
190     case 0x00: /* C62x */
191     case 0x02: /* C67x */
192       tic6x_regmap = tic6x_regmap_c62x;
193       tic6x_breakpoint = 0x0000a122;  /* BNOP .S2 0,5 */
194       tdesc = tdesc_tic6x_c62x_linux;
195       break;
196     case 0x03: /* C67x+ */
197       tic6x_regmap = tic6x_regmap_c64x;
198       tic6x_breakpoint = 0x0000a122;  /* BNOP .S2 0,5 */
199       tdesc = tdesc_tic6x_c64x_linux;
200       break;
201     case 0x0c: /* C64x */
202       tic6x_regmap = tic6x_regmap_c64x;
203       tic6x_breakpoint = 0x0000a122;  /* BNOP .S2 0,5 */
204       tdesc = tdesc_tic6x_c64x_linux;
205       break;
206     case 0x10: /* C64x+ */
207     case 0x14: /* C674x */
208     case 0x15: /* C66x */
209       tic6x_regmap = tic6x_regmap_c64xp;
210       tic6x_breakpoint = 0x56454314;  /* illegal opcode */
211       tdesc = tdesc_tic6x_c64xp_linux;
212       break;
213     default:
214       error ("Unknown CPU ID 0x%02x", cpuid);
215     }
216   tic6x_usrregs_info.regmap = tic6x_regmap;
217   return tdesc;
218 }
219
220 static int
221 tic6x_cannot_fetch_register (int regno)
222 {
223   return (tic6x_regmap[regno] == -1);
224 }
225
226 static int
227 tic6x_cannot_store_register (int regno)
228 {
229   return (tic6x_regmap[regno] == -1);
230 }
231
232 static CORE_ADDR
233 tic6x_get_pc (struct regcache *regcache)
234 {
235   union tic6x_register pc;
236
237   collect_register_by_name (regcache, "PC", pc.buf);
238   return pc.reg32;
239 }
240
241 static void
242 tic6x_set_pc (struct regcache *regcache, CORE_ADDR pc)
243 {
244   union tic6x_register newpc;
245
246   newpc.reg32 = pc;
247   supply_register_by_name (regcache, "PC", newpc.buf);
248 }
249
250 #define tic6x_breakpoint_len 4
251
252 static int
253 tic6x_breakpoint_at (CORE_ADDR where)
254 {
255   unsigned int insn;
256
257   (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
258   if (insn == tic6x_breakpoint)
259     return 1;
260
261   /* If necessary, recognize more trap instructions here.  GDB only uses the
262      one.  */
263   return 0;
264 }
265
266 /* Fetch the thread-local storage pointer for libthread_db.  */
267
268 ps_err_e
269 ps_get_thread_area (const struct ps_prochandle *ph,
270                     lwpid_t lwpid, int idx, void **base)
271 {
272   if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
273     return PS_ERR;
274
275   /* IDX is the bias from the thread pointer to the beginning of the
276      thread descriptor.  It has to be subtracted due to implementation
277      quirks in libthread_db.  */
278   *base = (void *) ((char *) *base - idx);
279
280   return PS_OK;
281 }
282
283 static void
284 tic6x_collect_register (struct regcache *regcache, int regno,
285                         union tic6x_register *reg)
286 {
287   union tic6x_register tmp_reg;
288
289   collect_register (regcache, regno, &tmp_reg.reg32);
290   reg->reg32 = tmp_reg.reg32;
291 }
292
293 static void
294 tic6x_supply_register (struct regcache *regcache, int regno,
295                        const union tic6x_register *reg)
296 {
297   int offset = 0;
298
299   supply_register (regcache, regno, reg->buf + offset);
300 }
301
302 static void
303 tic6x_fill_gregset (struct regcache *regcache, void *buf)
304 {
305   union tic6x_register *regset = buf;
306   int i;
307
308   for (i = 0; i < TIC6X_NUM_REGS; i++)
309     if (tic6x_regmap[i] != -1)
310       tic6x_collect_register (regcache, i, regset + tic6x_regmap[i]);
311 }
312
313 static void
314 tic6x_store_gregset (struct regcache *regcache, const void *buf)
315 {
316   const union tic6x_register *regset = buf;
317   int i;
318
319   for (i = 0; i < TIC6X_NUM_REGS; i++)
320     if (tic6x_regmap[i] != -1)
321       tic6x_supply_register (regcache, i, regset + tic6x_regmap[i]);
322 }
323
324 static struct regset_info tic6x_regsets[] = {
325   { PTRACE_GETREGS, PTRACE_SETREGS, 0, TIC6X_NUM_REGS * 4, GENERAL_REGS,
326     tic6x_fill_gregset, tic6x_store_gregset },
327   { 0, 0, 0, -1, -1, NULL, NULL }
328 };
329
330 static void
331 tic6x_arch_setup (void)
332 {
333   current_process ()->tdesc = tic6x_read_description ();
334 }
335
336 static struct regsets_info tic6x_regsets_info =
337   {
338     tic6x_regsets, /* regsets */
339     0, /* num_regsets */
340     NULL, /* disabled_regsets */
341   };
342
343 static struct usrregs_info tic6x_usrregs_info =
344   {
345     TIC6X_NUM_REGS,
346     NULL, /* Set in tic6x_read_description.  */
347   };
348
349 static struct regs_info regs_info =
350   {
351     NULL, /* regset_bitmap */
352     &tic6x_usrregs_info,
353     &tic6x_regsets_info
354   };
355
356 static const struct regs_info *
357 tic6x_regs_info (void)
358 {
359   return &regs_info;
360 }
361
362 struct linux_target_ops the_low_target = {
363   tic6x_arch_setup,
364   tic6x_regs_info,
365   tic6x_cannot_fetch_register,
366   tic6x_cannot_store_register,
367   NULL, /* fetch_register */
368   tic6x_get_pc,
369   tic6x_set_pc,
370   (const unsigned char *) &tic6x_breakpoint,
371   tic6x_breakpoint_len,
372   NULL,
373   0,
374   tic6x_breakpoint_at,
375 };
376
377 void
378 initialize_low_arch (void)
379 {
380   /* Initialize the Linux target descriptions.  */
381   init_registers_tic6x_c64xp_linux ();
382   init_registers_tic6x_c64x_linux ();
383   init_registers_tic6x_c62x_linux ();
384
385   initialize_regsets_info (&tic6x_regsets_info);
386 }