OpenOCD
arm_io.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009 by Marvell Semiconductors, Inc.
3  * Written by Nicolas Pitre <nico at marvell.com>
4  *
5  * Copyright (C) 2009 by David Brownell
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 2 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 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include "core.h"
26 #include "arm_io.h"
27 #include <helper/binarybuffer.h>
28 #include <target/arm.h>
29 #include <target/armv7m.h>
30 #include <target/algorithm.h>
31 
45  const uint32_t *code, unsigned code_size,
46  unsigned additional, struct working_area **area)
47 {
48  uint8_t code_buf[code_size];
49  int retval;
50  unsigned size = code_size + additional;
51 
52  /* REVISIT this assumes size doesn't ever change.
53  * That's usually correct; but there are boards with
54  * both large and small page chips, where it won't be...
55  */
56 
57  /* make sure we have a working area */
58  if (NULL == *area) {
59  retval = target_alloc_working_area(target, size, area);
60  if (retval != ERROR_OK) {
61  LOG_DEBUG("%s: no %d byte buffer", __func__, (int) size);
62  return ERROR_NAND_NO_BUFFER;
63  }
64  }
65 
66  /* buffer code in target endianness */
67  target_buffer_set_u32_array(target, code_buf, code_size / 4, code);
68 
69  /* copy code to work area */
70  retval = target_write_memory(target, (*area)->address,
71  4, code_size / 4, code_buf);
72 
73  return retval;
74 }
75 
91 int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
92 {
93  struct target *target = nand->target;
94  struct arm_algorithm armv4_5_algo;
95  struct armv7m_algorithm armv7m_algo;
96  void *arm_algo;
97  struct arm *arm = target->arch_info;
98  struct reg_param reg_params[3];
99  uint32_t target_buf;
100  uint32_t exit_var = 0;
101  int retval;
102 
103  /* Inputs:
104  * r0 NAND data address (byte wide)
105  * r1 buffer address
106  * r2 buffer length
107  */
108  static const uint32_t code_armv4_5[] = {
109  0xe4d13001, /* s: ldrb r3, [r1], #1 */
110  0xe5c03000, /* strb r3, [r0] */
111  0xe2522001, /* subs r2, r2, #1 */
112  0x1afffffb, /* bne s */
113 
114  /* exit: ARMv4 needs hardware breakpoint */
115  0xe1200070, /* e: bkpt #0 */
116  };
117 
118  /* Inputs:
119  * r0 NAND data address (byte wide)
120  * r1 buffer address
121  * r2 buffer length
122  *
123  * see contrib/loaders/flash/armv7m_io.s for src
124  */
125  static const uint32_t code_armv7m[] = {
126  0x3b01f811,
127  0x3a017003,
128  0xaffaf47f,
129  0xbf00be00,
130  };
131 
132  int target_code_size = 0;
133  const uint32_t *target_code_src = NULL;
134 
135  /* set up algorithm */
136  if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */
137  armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
138  armv7m_algo.core_mode = ARM_MODE_THREAD;
139  arm_algo = &armv7m_algo;
140  target_code_size = sizeof(code_armv7m);
141  target_code_src = code_armv7m;
142  } else {
143  armv4_5_algo.common_magic = ARM_COMMON_MAGIC;
144  armv4_5_algo.core_mode = ARM_MODE_SVC;
145  armv4_5_algo.core_state = ARM_STATE_ARM;
146  arm_algo = &armv4_5_algo;
147  target_code_size = sizeof(code_armv4_5);
148  target_code_src = code_armv4_5;
149  }
150 
151  if (nand->op != ARM_NAND_WRITE || !nand->copy_area) {
152  retval = arm_code_to_working_area(target, target_code_src, target_code_size,
153  nand->chunk_size, &nand->copy_area);
154  if (retval != ERROR_OK)
155  return retval;
156  }
157 
158  nand->op = ARM_NAND_WRITE;
159 
160  /* copy data to work area */
161  target_buf = nand->copy_area->address + target_code_size;
162  retval = target_write_buffer(target, target_buf, size, data);
163  if (retval != ERROR_OK)
164  return retval;
165 
166  /* set up parameters */
167  init_reg_param(&reg_params[0], "r0", 32, PARAM_IN);
168  init_reg_param(&reg_params[1], "r1", 32, PARAM_IN);
169  init_reg_param(&reg_params[2], "r2", 32, PARAM_IN);
170 
171  buf_set_u32(reg_params[0].value, 0, 32, nand->data);
172  buf_set_u32(reg_params[1].value, 0, 32, target_buf);
173  buf_set_u32(reg_params[2].value, 0, 32, size);
174 
175  /* armv4 must exit using a hardware breakpoint */
176  if (arm->is_armv4)
177  exit_var = nand->copy_area->address + target_code_size - 4;
178 
179  /* use alg to write data from work area to NAND chip */
180  retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
181  nand->copy_area->address, exit_var, 1000, arm_algo);
182  if (retval != ERROR_OK)
183  LOG_ERROR("error executing hosted NAND write");
184 
185  destroy_reg_param(&reg_params[0]);
186  destroy_reg_param(&reg_params[1]);
187  destroy_reg_param(&reg_params[2]);
188 
189  return retval;
190 }
191 
201 int arm_nandread(struct arm_nand_data *nand, uint8_t *data, uint32_t size)
202 {
203  struct target *target = nand->target;
204  struct arm_algorithm armv4_5_algo;
205  struct armv7m_algorithm armv7m_algo;
206  void *arm_algo;
207  struct arm *arm = target->arch_info;
208  struct reg_param reg_params[3];
209  uint32_t target_buf;
210  uint32_t exit_var = 0;
211  int retval;
212 
213  /* Inputs:
214  * r0 buffer address
215  * r1 NAND data address (byte wide)
216  * r2 buffer length
217  */
218  static const uint32_t code_armv4_5[] = {
219  0xe5d13000, /* s: ldrb r3, [r1] */
220  0xe4c03001, /* strb r3, [r0], #1 */
221  0xe2522001, /* subs r2, r2, #1 */
222  0x1afffffb, /* bne s */
223 
224  /* exit: ARMv4 needs hardware breakpoint */
225  0xe1200070, /* e: bkpt #0 */
226  };
227 
228  /* Inputs:
229  * r0 buffer address
230  * r1 NAND data address (byte wide)
231  * r2 buffer length
232  *
233  * see contrib/loaders/flash/armv7m_io.s for src
234  */
235  static const uint32_t code_armv7m[] = {
236  0xf800780b,
237  0x3a013b01,
238  0xaffaf47f,
239  0xbf00be00,
240  };
241 
242  int target_code_size = 0;
243  const uint32_t *target_code_src = NULL;
244 
245  /* set up algorithm */
246  if (is_armv7m(target_to_armv7m(target))) { /* armv7m target */
247  armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
248  armv7m_algo.core_mode = ARM_MODE_THREAD;
249  arm_algo = &armv7m_algo;
250  target_code_size = sizeof(code_armv7m);
251  target_code_src = code_armv7m;
252  } else {
253  armv4_5_algo.common_magic = ARM_COMMON_MAGIC;
254  armv4_5_algo.core_mode = ARM_MODE_SVC;
255  armv4_5_algo.core_state = ARM_STATE_ARM;
256  arm_algo = &armv4_5_algo;
257  target_code_size = sizeof(code_armv4_5);
258  target_code_src = code_armv4_5;
259  }
260 
261  /* create the copy area if not yet available */
262  if (nand->op != ARM_NAND_READ || !nand->copy_area) {
263  retval = arm_code_to_working_area(target, target_code_src, target_code_size,
264  nand->chunk_size, &nand->copy_area);
265  if (retval != ERROR_OK)
266  return retval;
267  }
268 
269  nand->op = ARM_NAND_READ;
270  target_buf = nand->copy_area->address + target_code_size;
271 
272  /* set up parameters */
273  init_reg_param(&reg_params[0], "r0", 32, PARAM_IN);
274  init_reg_param(&reg_params[1], "r1", 32, PARAM_IN);
275  init_reg_param(&reg_params[2], "r2", 32, PARAM_IN);
276 
277  buf_set_u32(reg_params[0].value, 0, 32, target_buf);
278  buf_set_u32(reg_params[1].value, 0, 32, nand->data);
279  buf_set_u32(reg_params[2].value, 0, 32, size);
280 
281  /* armv4 must exit using a hardware breakpoint */
282  if (arm->is_armv4)
283  exit_var = nand->copy_area->address + target_code_size - 4;
284 
285  /* use alg to write data from NAND chip to work area */
286  retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
287  nand->copy_area->address, exit_var, 1000, arm_algo);
288  if (retval != ERROR_OK)
289  LOG_ERROR("error executing hosted NAND read");
290 
291  destroy_reg_param(&reg_params[0]);
292  destroy_reg_param(&reg_params[1]);
293  destroy_reg_param(&reg_params[2]);
294 
295  /* read from work area to the host's memory */
296  retval = target_read_buffer(target, target_buf, size, data);
297 
298  return retval;
299 }
bool is_armv4
Flag reporting unavailability of the BKPT instruction.
Definition: arm.h:135
static struct armv7m_common * target_to_armv7m(struct target *target)
Definition: armv7m.h:172
struct target * target
Target is proxy for some ARM core.
Definition: arm_io.h:35
#define LOG_DEBUG(expr...)
Definition: log.h:115
int target_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer)
uint32_t data
Where data is read from or written to.
Definition: arm_io.h:44
uint32_t size
Definition: algorithm.h:37
unsigned chunk_size
The chunk size is the page size or ECC chunk.
Definition: arm_io.h:41
Support functions to access arbitrary bits in a byte array.
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.
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:44
#define ERROR_NAND_NO_BUFFER
Definition: nand/core.h:230
int common_magic
Definition: arm.h:218
void init_reg_param(struct reg_param *param, char *reg_name, uint32_t size, enum param_direction direction)
Definition: algorithm.c:40
enum arm_mode core_mode
Definition: arm.h:220
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:40
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:201
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:91
enum arm_mode core_mode
Definition: armv7m.h:185
Read operation performed.
Definition: arm_io.h:25
uint8_t * value
Definition: algorithm.h:38
#define ARMV7M_COMMON_MAGIC
Definition: armv7m.h:142
void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_t count, const uint32_t *srcbuf)
#define LOG_ERROR(expr...)
Definition: log.h:129
Represents a generic ARM core, with standard application registers.
Definition: arm.h:102
#define ARM_COMMON_MAGIC
Definition: arm.h:93
enum arm_nand_op op
Last operation executed using this struct.
Definition: arm_io.h:47
The arm_nand_data struct is used for defining NAND I/O operations on an ARM core. ...
Definition: arm_io.h:33
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, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info)
Downloads a target-specific native code algorithm to the target, and executes it. ...
enum arm_state core_state
Definition: arm.h:221
int target_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer)
int target_alloc_working_area(struct target *target, uint32_t size, struct working_area **area)
static bool is_armv7m(const struct armv7m_common *armv7m)
Definition: armv7m.h:177
void * arch_info
Definition: target.h:175
void destroy_reg_param(struct reg_param *param)
Definition: algorithm.c:48
#define ERROR_OK
Definition: log.h:144
int common_magic
Definition: armv7m.h:183
#define NULL
Definition: usb.h:27
struct working_area * copy_area
The copy area holds code loop and data for I/O operations.
Definition: arm_io.h:38
Holds the interface to ARM cores.
Definition: target.h:126
Write operation performed.
Definition: arm_io.h:26
target_addr_t address
Definition: target.h:96