OpenOCD
arc_mem.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Copyright (C) 2013-2014,2019-2020 Synopsys, Inc. *
5  * Frank Dols <frank.dols@synopsys.com> *
6  * Mischa Jonker <mischa.jonker@synopsys.com> *
7  * Anton Kolesov <anton.kolesov@synopsys.com> *
8  * Evgeniy Didin <didin@synopsys.com> *
9  ***************************************************************************/
10 
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14 
15 #include "arc.h"
16 
17 /* ----- Supporting functions ---------------------------------------------- */
18 static bool arc_mem_is_slow_memory(struct arc_common *arc, uint32_t addr,
19  uint32_t size, uint32_t count)
20 {
21  uint32_t addr_end = addr + size * count;
22  /* `_end` field can overflow - it points to the first byte after the end,
23  * therefore if DCCM is right at the end of memory address space, then
24  * dccm_end will be 0. */
25  assert(addr_end >= addr || addr_end == 0);
26 
27  return !((addr >= arc->dccm_start && addr_end <= arc->dccm_end) ||
28  (addr >= arc->iccm0_start && addr_end <= arc->iccm0_end) ||
29  (addr >= arc->iccm1_start && addr_end <= arc->iccm1_end));
30 }
31 
32 /* Write word at word-aligned address */
33 static int arc_mem_write_block32(struct target *target, uint32_t addr,
34  uint32_t count, void *buf)
35 {
36  struct arc_common *arc = target_to_arc(target);
37 
38  LOG_DEBUG("Write 4-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
39  addr, count);
40 
41  /* Check arguments */
42  assert(!(addr & 3));
43 
44  /* We need to flush the cache since it might contain dirty
45  * lines, so the cache invalidation may cause data inconsistency. */
47 
48 
49  /* No need to flush cache, because we don't read values from memory. */
51  (uint32_t *)buf));
52 
53  /* Invalidate caches. */
55 
56  return ERROR_OK;
57 }
58 
59 /* Write half-word at half-word-aligned address */
60 static int arc_mem_write_block16(struct target *target, uint32_t addr,
61  uint32_t count, void *buf)
62 {
63  struct arc_common *arc = target_to_arc(target);
64  uint32_t i;
65  uint32_t buffer_he;
66  uint8_t buffer_te[sizeof(uint32_t)];
67  uint8_t halfword_te[sizeof(uint16_t)];
68 
69  LOG_DEBUG("Write 2-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
70  addr, count);
71 
72  /* Check arguments */
73  assert(!(addr & 1));
74 
75  /* We will read data from memory, so we need to flush the cache. */
77 
78  /* non-word writes are less common than 4-byte writes, so I suppose we can
79  * allow ourselves to write this in a cycle, instead of calling arc_jtag
80  * with count > 1. */
81  for (i = 0; i < count; i++) {
82  /* We can read only word at word-aligned address. Also *jtag_read_memory
83  * functions return data in host endianness, so host endianness !=
84  * target endianness we have to convert data back to target endianness,
85  * or bytes will be at the wrong places.So:
86  * 1) read word
87  * 2) convert to target endianness
88  * 3) make changes
89  * 4) convert back to host endianness
90  * 5) write word back to target.
91  */
92  bool is_slow_memory = arc_mem_is_slow_memory(arc,
93  (addr + i * sizeof(uint16_t)) & ~3u, 4, 1);
95  (addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he,
96  is_slow_memory));
97  target_buffer_set_u32(target, buffer_te, buffer_he);
98 
99  /* buf is in host endianness, convert to target */
100  target_buffer_set_u16(target, halfword_te, ((uint16_t *)buf)[i]);
101 
102  memcpy(buffer_te + ((addr + i * sizeof(uint16_t)) & 3u),
103  halfword_te, sizeof(uint16_t));
104 
105  buffer_he = target_buffer_get_u32(target, buffer_te);
106 
108  (addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he));
109  }
110 
111  /* Invalidate caches. */
113 
114  return ERROR_OK;
115 }
116 
117 /* Write byte at address */
118 static int arc_mem_write_block8(struct target *target, uint32_t addr,
119  uint32_t count, void *buf)
120 {
121  struct arc_common *arc = target_to_arc(target);
122  uint32_t i;
123  uint32_t buffer_he;
124  uint8_t buffer_te[sizeof(uint32_t)];
125 
126 
127  LOG_DEBUG("Write 1-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32,
128  addr, count);
129 
130  /* We will read data from memory, so we need to flush the cache. */
132 
133  /* non-word writes are less common than 4-byte writes, so I suppose we can
134  * allow ourselves to write this in a cycle, instead of calling arc_jtag
135  * with count > 1. */
136  for (i = 0; i < count; i++) {
137  /* See comment in arc_mem_write_block16 for details. Since it is a byte
138  * there is not need to convert write buffer to target endianness, but
139  * we still have to convert read buffer. */
140  CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, (addr + i) & ~3, 1, &buffer_he,
141  arc_mem_is_slow_memory(arc, (addr + i) & ~3, 4, 1)));
142  target_buffer_set_u32(target, buffer_te, buffer_he);
143  memcpy(buffer_te + ((addr + i) & 3), (uint8_t *)buf + i, 1);
144  buffer_he = target_buffer_get_u32(target, buffer_te);
145  CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, (addr + i) & ~3, 1, &buffer_he));
146  }
147 
148  /* Invalidate caches. */
150 
151  return ERROR_OK;
152 }
153 
154 /* ----- Exported functions ------------------------------------------------ */
155 int arc_mem_write(struct target *target, target_addr_t address, uint32_t size,
156  uint32_t count, const uint8_t *buffer)
157 {
158  int retval = ERROR_OK;
159  void *tunnel = NULL;
160 
161  LOG_DEBUG("address: 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: %" PRIu32,
162  address, size, count);
163 
164  if (target->state != TARGET_HALTED) {
165  LOG_TARGET_ERROR(target, "not halted");
167  }
168 
169  /* sanitize arguments */
170  if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer))
172 
173  if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
175 
176  /* correct endianness if we have word or hword access */
177  if (size > 1) {
178  /*
179  * arc_..._write_mem with size 4/2 requires uint32_t/uint16_t
180  * in host endianness, but byte array represents target endianness.
181  */
182  tunnel = calloc(1, count * size * sizeof(uint8_t));
183 
184  if (!tunnel) {
185  LOG_ERROR("Unable to allocate memory");
186  return ERROR_FAIL;
187  }
188 
189  switch (size) {
190  case 4:
192  (uint32_t *)tunnel);
193  break;
194  case 2:
196  (uint16_t *)tunnel);
197  break;
198  }
199  buffer = tunnel;
200  }
201 
202  if (size == 4) {
203  retval = arc_mem_write_block32(target, address, count, (void *)buffer);
204  } else if (size == 2) {
205  /* We convert buffer from host endianness to target. But then in
206  * write_block16, we do the reverse. Is there a way to avoid this without
207  * breaking other cases? */
208  retval = arc_mem_write_block16(target, address, count, (void *)buffer);
209  } else {
210  retval = arc_mem_write_block8(target, address, count, (void *)buffer);
211  }
212 
213  free(tunnel);
214 
215  return retval;
216 }
217 
219  uint32_t size, uint32_t count, void *buf)
220 {
221  struct arc_common *arc = target_to_arc(target);
222 
223  LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32
224  ", count=%" PRIu32, addr, size, count);
225  assert(!(addr & 3));
226  assert(size == 4);
227 
228  /* Flush cache before memory access */
230 
233 
234  return ERROR_OK;
235 }
236 
237 int arc_mem_read(struct target *target, target_addr_t address, uint32_t size,
238  uint32_t count, uint8_t *buffer)
239 {
240  int retval = ERROR_OK;
241  void *tunnel_he;
242  uint8_t *tunnel_te;
243  uint32_t words_to_read, bytes_to_read;
244 
245 
246  LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32
247  ", count=%" PRIu32, address, size, count);
248 
249  if (target->state != TARGET_HALTED) {
250  LOG_WARNING("target not halted");
252  }
253 
254  /* Sanitize arguments */
255  if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer))
257 
258  if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
260 
261  /* Reads are word-aligned, so padding might be required if count > 1.
262  * NB: +3 is a padding for the last word (in case it's not aligned;
263  * addr&3 is a padding for the first word (since address can be
264  * unaligned as well). */
265  bytes_to_read = (count * size + 3 + (address & 3u)) & ~3u;
266  words_to_read = bytes_to_read >> 2;
267  tunnel_he = calloc(1, bytes_to_read);
268  tunnel_te = calloc(1, bytes_to_read);
269 
270  if (!tunnel_he || !tunnel_te) {
271  LOG_ERROR("Unable to allocate memory");
272  free(tunnel_he);
273  free(tunnel_te);
274  return ERROR_FAIL;
275  }
276 
277  /* We can read only word-aligned words. */
278  retval = arc_mem_read_block(target, address & ~3u, sizeof(uint32_t),
279  words_to_read, tunnel_he);
280 
281  /* arc_..._read_mem with size 4/2 returns uint32_t/uint16_t in host */
282  /* endianness, but byte array should represent target endianness */
283 
284  if (retval == ERROR_OK) {
285  switch (size) {
286  case 4:
288  tunnel_he);
289  break;
290  case 2:
292  words_to_read, tunnel_he);
293  /* Will that work properly with count > 1 and big endian? */
294  memcpy(buffer, tunnel_te + (address & 3u),
295  count * sizeof(uint16_t));
296  break;
297  case 1:
299  words_to_read, tunnel_he);
300  /* Will that work properly with count > 1 and big endian? */
301  memcpy(buffer, tunnel_te + (address & 3u), count);
302  break;
303  }
304  }
305 
306  free(tunnel_he);
307  free(tunnel_te);
308 
309  return retval;
310 }
int arc_cache_flush(struct target *target)
Definition: arc.c:2314
int arc_cache_invalidate(struct target *target)
Definition: arc.c:2237
static struct arc_common * target_to_arc(struct target *target)
Definition: arc.h:256
#define CHECK_RETVAL(action)
Definition: arc.h:246
int arc_jtag_read_memory(struct arc_jtag *jtag_info, uint32_t addr, uint32_t count, uint32_t *buffer, bool slow_memory)
Read a sequence of 4-byte words from target memory.
Definition: arc_jtag.c:484
int arc_jtag_write_memory(struct arc_jtag *jtag_info, uint32_t addr, uint32_t count, const uint32_t *buffer)
Write a sequence of 4-byte words into target memory.
Definition: arc_jtag.c:436
int arc_mem_read(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer)
Definition: arc_mem.c:237
static int arc_mem_read_block(struct target *target, target_addr_t addr, uint32_t size, uint32_t count, void *buf)
Definition: arc_mem.c:218
int arc_mem_write(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer)
Definition: arc_mem.c:155
static int arc_mem_write_block32(struct target *target, uint32_t addr, uint32_t count, void *buf)
Definition: arc_mem.c:33
static int arc_mem_write_block16(struct target *target, uint32_t addr, uint32_t count, void *buf)
Definition: arc_mem.c:60
static bool arc_mem_is_slow_memory(struct arc_common *arc, uint32_t addr, uint32_t size, uint32_t count)
Definition: arc_mem.c:18
static int arc_mem_write_block8(struct target *target, uint32_t addr, uint32_t count, void *buf)
Definition: arc_mem.c:118
#define ERROR_COMMAND_SYNTAX_ERROR
Definition: command.h:402
#define LOG_WARNING(expr ...)
Definition: log.h:129
#define ERROR_FAIL
Definition: log.h:170
#define LOG_TARGET_ERROR(target, fmt_str,...)
Definition: log.h:158
#define LOG_ERROR(expr ...)
Definition: log.h:132
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:164
target_addr_t addr
Start address to search for the control block.
Definition: rtt/rtt.c:28
size_t size
Size of the control block search area.
Definition: rtt/rtt.c:30
uint32_t dccm_start
Definition: arc.h:218
uint32_t dccm_end
Definition: arc.h:219
uint32_t iccm1_end
Definition: arc.h:217
uint32_t iccm1_start
Definition: arc.h:216
struct arc_jtag jtag_info
Definition: arc.h:188
uint32_t iccm0_start
Definition: arc.h:214
Definition: target.h:116
enum target_state state
Definition: target.h:157
void target_buffer_get_u16_array(struct target *target, const uint8_t *buffer, uint32_t count, uint16_t *dstbuf)
Definition: target.c:401
void target_buffer_set_u16(struct target *target, uint8_t *buffer, uint16_t value)
Definition: target.c:370
void target_buffer_set_u32(struct target *target, uint8_t *buffer, uint32_t value)
Definition: target.c:352
void target_buffer_get_u32_array(struct target *target, const uint8_t *buffer, uint32_t count, uint32_t *dstbuf)
Definition: target.c:393
void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_t count, const uint32_t *srcbuf)
Definition: target.c:417
uint32_t target_buffer_get_u32(struct target *target, const uint8_t *buffer)
Definition: target.c:316
#define ERROR_TARGET_NOT_HALTED
Definition: target.h:790
#define ERROR_TARGET_UNALIGNED_ACCESS
Definition: target.h:792
@ TARGET_HALTED
Definition: target.h:56
uint64_t target_addr_t
Definition: types.h:335
#define TARGET_PRIxADDR
Definition: types.h:340
#define NULL
Definition: usb.h:16
uint8_t count[4]
Definition: vdebug.c:22