OpenOCD
arm_io.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /*
4  * Copyright (C) 2009 by Marvell Semiconductors, Inc.
5  * Written by Nicolas Pitre <nico at marvell.com>
6  *
7  * Copyright (C) 2009 by David Brownell
8  */
9 
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13 
14 #include "core.h"
15 #include "arm_io.h"
16 #include <helper/binarybuffer.h>
17 #include <target/arm.h>
18 #include <target/armv7m.h>
19 #include <target/algorithm.h>
20 
34  const uint32_t *code, unsigned code_size,
35  unsigned additional, struct working_area **area)
36 {
37  uint8_t code_buf[code_size];
38  int retval;
39  unsigned size = code_size + additional;
40 
41  /* REVISIT this assumes size doesn't ever change.
42  * That's usually correct; but there are boards with
43  * both large and small page chips, where it won't be...
44  */
45 
46  /* make sure we have a working area */
47  if (!*area) {
48  retval = target_alloc_working_area(target, size, area);
49  if (retval != ERROR_OK) {
50  LOG_DEBUG("%s: no %d byte buffer", __func__, (int) size);
51  return ERROR_NAND_NO_BUFFER;
52  }
53  }
54 
55  /* buffer code in target endianness */
56  target_buffer_set_u32_array(target, code_buf, code_size / 4, code);
57 
58  /* copy code to work area */
59  retval = target_write_memory(target, (*area)->address,
60  4, code_size / 4, code_buf);
61 
62  return retval;
63 }
64 
80 int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
81 {
82  struct target *target = nand->target;
83  struct arm_algorithm armv4_5_algo;
84  struct armv7m_algorithm armv7m_algo;
85  void *arm_algo;
86  struct arm *arm = target->arch_info;
87  struct reg_param reg_params[3];
88  uint32_t target_buf;
89  uint32_t exit_var = 0;
90  int retval;
91 
92  /* Inputs:
93  * r0 NAND data address (byte wide)
94  * r1 buffer address
95  * r2 buffer length
96  */
97  static const uint32_t code_armv4_5[] = {
98  0xe4d13001, /* s: ldrb r3, [r1], #1 */
99  0xe5c03000, /* strb r3, [r0] */
100  0xe2522001, /* subs r2, r2, #1 */
101  0x1afffffb, /* bne s */
102 
103  /* exit: ARMv4 needs hardware breakpoint */
104  0xe1200070, /* e: bkpt #0 */
105  };
106 
107  /* Inputs:
108  * r0 NAND data address (byte wide)
109  * r1 buffer address
110  * r2 buffer length
111  *
112  * see contrib/loaders/flash/armv7m_io.s for src
113  */
114  static const uint32_t code_armv7m[] = {
115  0x3b01f811,
116  0x3a017003,
117  0xaffaf47f,
118  0xbf00be00,
119  };
120 
121  int target_code_size = 0;
122  const uint32_t *target_code_src = NULL;
123 
124  /* set up algorithm */
125  if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */
126  armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
127  armv7m_algo.core_mode = ARM_MODE_THREAD;
128  arm_algo = &armv7m_algo;
129  target_code_size = sizeof(code_armv7m);
130  target_code_src = code_armv7m;
131  } else {
132  armv4_5_algo.common_magic = ARM_COMMON_MAGIC;
133  armv4_5_algo.core_mode = ARM_MODE_SVC;
134  armv4_5_algo.core_state = ARM_STATE_ARM;
135  arm_algo = &armv4_5_algo;
136  target_code_size = sizeof(code_armv4_5);
137  target_code_src = code_armv4_5;
138  }
139 
140  if (nand->op != ARM_NAND_WRITE || !nand->copy_area) {
141  retval = arm_code_to_working_area(target, target_code_src, target_code_size,
142  nand->chunk_size, &nand->copy_area);
143  if (retval != ERROR_OK)
144  return retval;
145  }
146 
147  nand->op = ARM_NAND_WRITE;
148 
149  /* copy data to work area */
150  target_buf = nand->copy_area->address + target_code_size;
151  retval = target_write_buffer(target, target_buf, size, data);
152  if (retval != ERROR_OK)
153  return retval;
154 
155  /* set up parameters */
156  init_reg_param(&reg_params[0], "r0", 32, PARAM_IN);
157  init_reg_param(&reg_params[1], "r1", 32, PARAM_IN);
158  init_reg_param(&reg_params[2], "r2", 32, PARAM_IN);
159 
160  buf_set_u32(reg_params[0].value, 0, 32, nand->data);
161  buf_set_u32(reg_params[1].value, 0, 32, target_buf);
162  buf_set_u32(reg_params[2].value, 0, 32, size);
163 
164  /* armv4 must exit using a hardware breakpoint */
165  if (arm->arch == ARM_ARCH_V4)
166  exit_var = nand->copy_area->address + target_code_size - 4;
167 
168  /* use alg to write data from work area to NAND chip */
169  retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
170  nand->copy_area->address, exit_var, 1000, arm_algo);
171  if (retval != ERROR_OK)
172  LOG_ERROR("error executing hosted NAND write");
173 
174  destroy_reg_param(&reg_params[0]);
175  destroy_reg_param(&reg_params[1]);
176  destroy_reg_param(&reg_params[2]);
177 
178  return retval;
179 }
180 
190 int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
191 {
192  struct target *target = nand->target;
193  struct arm_algorithm armv4_5_algo;
194  struct armv7m_algorithm armv7m_algo;
195  void *arm_algo;
196  struct arm *arm = target->arch_info;
197  struct reg_param reg_params[3];
198  uint32_t target_buf;
199  uint32_t exit_var = 0;
200  int retval;
201 
202  /* Inputs:
203  * r0 buffer address
204  * r1 NAND data address (byte wide)
205  * r2 buffer length
206  */
207  static const uint32_t code_armv4_5[] = {
208  0xe5d13000, /* s: ldrb r3, [r1] */
209  0xe4c03001, /* strb r3, [r0], #1 */
210  0xe2522001, /* subs r2, r2, #1 */
211  0x1afffffb, /* bne s */
212 
213  /* exit: ARMv4 needs hardware breakpoint */
214  0xe1200070, /* e: bkpt #0 */
215  };
216 
217  /* Inputs:
218  * r0 buffer address
219  * r1 NAND data address (byte wide)
220  * r2 buffer length
221  *
222  * see contrib/loaders/flash/armv7m_io.s for src
223  */
224  static const uint32_t code_armv7m[] = {
225  0xf800780b,
226  0x3a013b01,
227  0xaffaf47f,
228  0xbf00be00,
229  };
230 
231  int target_code_size = 0;
232  const uint32_t *target_code_src = NULL;
233 
234  /* set up algorithm */
235  if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */
236  armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
237  armv7m_algo.core_mode = ARM_MODE_THREAD;
238  arm_algo = &armv7m_algo;
239  target_code_size = sizeof(code_armv7m);
240  target_code_src = code_armv7m;
241  } else {
242  armv4_5_algo.common_magic = ARM_COMMON_MAGIC;
243  armv4_5_algo.core_mode = ARM_MODE_SVC;
244  armv4_5_algo.core_state = ARM_STATE_ARM;
245  arm_algo = &armv4_5_algo;
246  target_code_size = sizeof(code_armv4_5);
247  target_code_src = code_armv4_5;
248  }
249 
250  /* create the copy area if not yet available */
251  if (nand->op != ARM_NAND_READ || !nand->copy_area) {
252  retval = arm_code_to_working_area(target, target_code_src, target_code_size,
253  nand->chunk_size, &nand->copy_area);
254  if (retval != ERROR_OK)
255  return retval;
256  }
257 
258  nand->op = ARM_NAND_READ;
259  target_buf = nand->copy_area->address + target_code_size;
260 
261  /* set up parameters */
262  init_reg_param(&reg_params[0], "r0", 32, PARAM_IN);
263  init_reg_param(&reg_params[1], "r1", 32, PARAM_IN);
264  init_reg_param(&reg_params[2], "r2", 32, PARAM_IN);
265 
266  buf_set_u32(reg_params[0].value, 0, 32, target_buf);
267  buf_set_u32(reg_params[1].value, 0, 32, nand->data);
268  buf_set_u32(reg_params[2].value, 0, 32, size);
269 
270  /* armv4 must exit using a hardware breakpoint */
271  if (arm->arch == ARM_ARCH_V4)
272  exit_var = nand->copy_area->address + target_code_size - 4;
273 
274  /* use alg to write data from NAND chip to work area */
275  retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
276  nand->copy_area->address, exit_var, 1000, arm_algo);
277  if (retval != ERROR_OK)
278  LOG_ERROR("error executing hosted NAND read");
279 
280  destroy_reg_param(&reg_params[0]);
281  destroy_reg_param(&reg_params[1]);
282  destroy_reg_param(&reg_params[2]);
283 
284  /* read from work area to the host's memory */
285  retval = target_read_buffer(target, target_buf, size, data);
286 
287  return retval;
288 }
void init_reg_param(struct reg_param *param, char *reg_name, uint32_t size, enum param_direction direction)
Definition: algorithm.c:29
void destroy_reg_param(struct reg_param *param)
Definition: algorithm.c:37
@ PARAM_IN
Definition: algorithm.h:15
Holds the interface to ARM cores.
#define ARM_COMMON_MAGIC
Definition: arm.h:158
@ ARM_ARCH_V4
Definition: arm.h:55
@ ARM_MODE_SVC
Definition: arm.h:78
@ ARM_MODE_THREAD
Definition: arm.h:86
@ ARM_STATE_ARM
Definition: arm.h:143
static int arm_code_to_working_area(struct target *target, const uint32_t *code, unsigned code_size, unsigned additional, struct working_area **area)
Copies code to a working area.
Definition: arm_io.c:33
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
ARM-specific bulk write from buffer to address of 8-bit wide NAND.
Definition: arm_io.c:80
int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
Uses an on-chip algorithm for an ARM device to read from a NAND device and store the data into the ho...
Definition: arm_io.c:190
@ ARM_NAND_READ
Read operation performed.
Definition: arm_io.h:14
@ ARM_NAND_WRITE
Write operation performed.
Definition: arm_io.h:15
static struct armv7m_common * target_to_armv7m(struct target *target)
Definition: armv7m.h:260
#define ARMV7M_COMMON_MAGIC
Definition: armv7m.h:218
static bool is_armv7m(const struct armv7m_common *armv7m)
Definition: armv7m.h:248
Support functions to access arbitrary bits in a byte array.
static void buf_set_u32(uint8_t *_buffer, unsigned first, unsigned num, uint32_t value)
Sets num bits in _buffer, starting at the first bit, using the bits in value.
Definition: binarybuffer.h:30
#define LOG_ERROR(expr ...)
Definition: log.h:123
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:155
#define ERROR_NAND_NO_BUFFER
Definition: nand/core.h:219
Upper level NOR flash interfaces.
size_t size
Size of the control block search area.
Definition: rtt/rtt.c:30
unsigned int common_magic
Definition: arm.h:256
enum arm_mode core_mode
Definition: arm.h:258
enum arm_state core_state
Definition: arm.h:259
The arm_nand_data struct is used for defining NAND I/O operations on an ARM core.
Definition: arm_io.h:22
struct target * target
Target is proxy for some ARM core.
Definition: arm_io.h:24
struct working_area * copy_area
The copy area holds code loop and data for I/O operations.
Definition: arm_io.h:27
unsigned chunk_size
The chunk size is the page size or ECC chunk.
Definition: arm_io.h:30
enum arm_nand_op op
Last operation executed using this struct.
Definition: arm_io.h:36
uint32_t data
Where data is read from or written to.
Definition: arm_io.h:33
Represents a generic ARM core, with standard application registers.
Definition: arm.h:167
enum arm_arch arch
ARM architecture version.
Definition: arm.h:194
unsigned int common_magic
Definition: armv7m.h:293
enum arm_mode core_mode
Definition: armv7m.h:295
uint8_t * value
Definition: algorithm.h:30
Definition: target.h:120
void * arch_info
Definition: target.h:169
target_addr_t address
Definition: target.h:90
int target_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer)
Definition: target.c:2408
int target_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer)
Definition: target.c:2473
int target_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer)
Write count items of size bytes to the memory of target at the address given.
Definition: target.c:1334
int target_alloc_working_area(struct target *target, uint32_t size, struct working_area **area)
Definition: target.c:2129
int target_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, target_addr_t entry_point, target_addr_t exit_point, int timeout_ms, void *arch_info)
Downloads a target-specific native code algorithm to the target, and executes it.
Definition: target.c:846
void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_t count, const uint32_t *srcbuf)
Definition: target.c:476
#define NULL
Definition: usb.h:16