0dc3f6870e707716ae0d77edadd003fbcf368572
[fw/openocd] / src / target / arc_mem.c
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. */
46         CHECK_RETVAL(arc_cache_flush(target));
47
48
49         /* No need to flush cache, because we don't read values from memory. */
50         CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info, addr, count,
51                                 (uint32_t *)buf));
52
53         /* Invalidate caches. */
54         CHECK_RETVAL(arc_cache_invalidate(target));
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. */
76         CHECK_RETVAL(arc_cache_flush(target));
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);
94                 CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info,
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
107                 CHECK_RETVAL(arc_jtag_write_memory(&arc->jtag_info,
108                         (addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he));
109         }
110
111         /* Invalidate caches. */
112         CHECK_RETVAL(arc_cache_invalidate(target));
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. */
131         CHECK_RETVAL(arc_cache_flush(target));
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. */
149         CHECK_RETVAL(arc_cache_invalidate(target));
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_WARNING("target not halted");
166                 return ERROR_TARGET_NOT_HALTED;
167         }
168
169         /* sanitize arguments */
170         if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer))
171                 return ERROR_COMMAND_SYNTAX_ERROR;
172
173         if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
174                 return ERROR_TARGET_UNALIGNED_ACCESS;
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:
191                         target_buffer_get_u32_array(target, buffer, count,
192                                 (uint32_t *)tunnel);
193                         break;
194                 case 2:
195                         target_buffer_get_u16_array(target, buffer, count,
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
218 static int arc_mem_read_block(struct target *target, target_addr_t addr,
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 */
229         CHECK_RETVAL(arc_cache_flush(target));
230
231         CHECK_RETVAL(arc_jtag_read_memory(&arc->jtag_info, addr, count, buf,
232                     arc_mem_is_slow_memory(arc, addr, size, count)));
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");
251                 return ERROR_TARGET_NOT_HALTED;
252         }
253
254         /* Sanitize arguments */
255         if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer))
256                 return ERROR_COMMAND_SYNTAX_ERROR;
257
258         if (((size == 4) && (address & 0x3u)) || ((size == 2) && (address & 0x1u)))
259             return ERROR_TARGET_UNALIGNED_ACCESS;
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:
287                         target_buffer_set_u32_array(target, buffer, count,
288                                 tunnel_he);
289                         break;
290                 case 2:
291                         target_buffer_set_u32_array(target, tunnel_te,
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:
298                         target_buffer_set_u32_array(target, tunnel_te,
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 }