1 /***************************************************************************
2  *   Copyright (C) 2013-2014,2019-2020 Synopsys, Inc.                      *
3  *   Frank Dols <frank.dols@synopsys.com>                                  *
4  *   Mischa Jonker <mischa.jonker@synopsys.com>                            *
5  *   Anton Kolesov <anton.kolesov@synopsys.com>                            *
6  *   Evgeniy Didin <didin@synopsys.com>                                    *
7  *                                                                         *
8  *   SPDX-License-Identifier: GPL-2.0-or-later                             *
9  ***************************************************************************/
10 
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14 
15 #include "arc.h"
16 
17 /* ----- Supporting functions ---------------------------------------------- */
arc_mem_is_slow_memory(struct arc_common * arc,uint32_t addr,uint32_t size,uint32_t count)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 */
arc_mem_write_block32(struct target * target,uint32_t addr,uint32_t count,void * buf)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 */
arc_mem_write_block16(struct target * target,uint32_t addr,uint32_t count,void * buf)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 */
arc_mem_write_block8(struct target * target,uint32_t addr,uint32_t count,void * buf)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 ------------------------------------------------ */
arc_mem_write(struct target * target,target_addr_t address,uint32_t size,uint32_t count,const uint8_t * buffer)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 
arc_mem_read_block(struct target * target,target_addr_t addr,uint32_t size,uint32_t count,void * buf)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 
arc_mem_read(struct target * target,target_addr_t address,uint32_t size,uint32_t count,uint8_t * buffer)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 (ERROR_OK == retval) {
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 }
311