1/* Ravenscar Aarch64 target support.
2
3   Copyright (C) 2017-2020 Free Software Foundation, Inc.
4
5   This file is part of GDB.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program 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
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20#include "defs.h"
21#include "gdbcore.h"
22#include "regcache.h"
23#include "aarch64-tdep.h"
24#include "inferior.h"
25#include "ravenscar-thread.h"
26#include "aarch64-ravenscar-thread.h"
27#include "gdbarch.h"
28
29#define NO_OFFSET -1
30
31/* See aarch64-tdep.h for register numbers.  */
32
33static const int aarch64_context_offsets[] =
34{
35  /* X0 - X28 */
36  NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET,
37  NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET,
38  NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET,
39  NO_OFFSET, NO_OFFSET, NO_OFFSET, NO_OFFSET,
40  NO_OFFSET, NO_OFFSET, NO_OFFSET, 0,
41  8,         16,        24,        32,
42  40,        48,        56,        64,
43  72,
44
45  /* FP, LR, SP, PC, CPSR */
46  /* Note that as task switch is synchronous, PC is in fact the LR here */
47  80,        88,        96,        88,
48  NO_OFFSET,
49
50  /* Q0 - Q31 */
51  112,       128,       144,       160,
52  176,       192,       208,       224,
53  240,       256,       272,       288,
54  304,       320,       336,       352,
55  368,       384,       400,       416,
56  432,       448,       464,       480,
57  496,       512,       528,       544,
58  560,       576,       592,       608,
59
60  /* FPSR, FPCR */
61  104,       108,
62
63  /* FPU Saved field */
64  624
65};
66
67/* The register layout info.  */
68
69struct ravenscar_reg_info
70{
71  /* A table providing the offset relative to the context structure
72     where each register is saved.  */
73  const int *context_offsets;
74
75  /* The number of elements in the context_offsets table above.  */
76  int context_offsets_size;
77};
78
79/* supply register REGNUM, which has been saved on REGISTER_ADDR, to the
80   regcache.  */
81
82static void
83supply_register_at_address (struct regcache *regcache, int regnum,
84                            CORE_ADDR register_addr)
85{
86  struct gdbarch *gdbarch = regcache->arch ();
87  int buf_size = register_size (gdbarch, regnum);
88  gdb_byte *buf;
89
90  buf = (gdb_byte *) alloca (buf_size);
91  read_memory (register_addr, buf, buf_size);
92  regcache->raw_supply (regnum, buf);
93}
94
95/* Return true if, for a non-running thread, REGNUM has been saved on the
96   Thread_Descriptor.  */
97
98static int
99register_in_thread_descriptor_p (const struct ravenscar_reg_info *reg_info,
100				 int regnum)
101{
102  /* Check FPU registers */
103  return (regnum < reg_info->context_offsets_size
104	  && reg_info->context_offsets[regnum] != NO_OFFSET);
105}
106
107/* to_fetch_registers when inferior_ptid is different from the running
108   thread.  */
109
110static void
111aarch64_ravenscar_generic_fetch_registers
112  (const struct ravenscar_reg_info *reg_info,
113   struct regcache *regcache, int regnum)
114{
115  struct gdbarch *gdbarch = regcache->arch ();
116  const int num_regs = gdbarch_num_regs (gdbarch);
117  int current_regnum;
118  CORE_ADDR current_address;
119  CORE_ADDR thread_descriptor_address;
120
121  /* The tid is the thread_id field, which is a pointer to the thread.  */
122  thread_descriptor_address = (CORE_ADDR) inferior_ptid.tid ();
123
124  /* Read registers.  */
125  for (current_regnum = 0; current_regnum < num_regs; current_regnum++)
126    {
127      if (register_in_thread_descriptor_p (reg_info, current_regnum))
128        {
129          current_address = thread_descriptor_address
130            + reg_info->context_offsets[current_regnum];
131          supply_register_at_address (regcache, current_regnum,
132                                      current_address);
133        }
134    }
135}
136
137/* to_store_registers when inferior_ptid is different from the running
138   thread.  */
139
140static void
141aarch64_ravenscar_generic_store_registers
142  (const struct ravenscar_reg_info *reg_info,
143   struct regcache *regcache, int regnum)
144{
145  struct gdbarch *gdbarch = regcache->arch ();
146  int buf_size = register_size (gdbarch, regnum);
147  gdb_byte buf[buf_size];
148  ULONGEST register_address;
149
150  if (register_in_thread_descriptor_p (reg_info, regnum))
151    register_address
152      = inferior_ptid.tid () + reg_info->context_offsets [regnum];
153  else
154    return;
155
156  regcache->raw_collect (regnum, buf);
157  write_memory (register_address,
158                buf,
159                buf_size);
160}
161
162/* The ravenscar_reg_info for most Aarch64 targets.  */
163
164static const struct ravenscar_reg_info aarch64_reg_info =
165{
166  aarch64_context_offsets,
167  ARRAY_SIZE (aarch64_context_offsets),
168};
169
170struct aarch64_ravenscar_ops : public ravenscar_arch_ops
171{
172  void fetch_registers (struct regcache *regcache, int regnum) override
173  {
174    aarch64_ravenscar_generic_fetch_registers
175      (&aarch64_reg_info, regcache, regnum);
176  }
177
178  void store_registers (struct regcache *regcache, int regnum) override
179  {
180    aarch64_ravenscar_generic_store_registers
181      (&aarch64_reg_info, regcache, regnum);
182  }
183};
184
185/* The ravenscar_arch_ops vector for most Aarch64 targets.  */
186
187static struct aarch64_ravenscar_ops aarch64_ravenscar_ops;
188
189/* Register aarch64_ravenscar_ops in GDBARCH.  */
190
191void
192register_aarch64_ravenscar_ops (struct gdbarch *gdbarch)
193{
194  set_gdbarch_ravenscar_ops (gdbarch, &aarch64_ravenscar_ops);
195}
196