- added support for AT91SAM7A3 flash (patch from andre renaud, thanks)
[openocd.git] / src / target / armv4_5_mmu.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20 #include "arm7_9_common.h"
21 #include "log.h"
22 #include "command.h"
23 #include "armv4_5_mmu.h"
24
25 #include <stdlib.h>
26
27 u32 armv4mmu_translate_va(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 va, int *type, u32 *cb, int *domain, u32 *ap);
28 int armv4_5_mmu_read_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer);
29 int armv4_5_mmu_write_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer);
30
31 char* armv4_5_mmu_page_type_names[] =
32 {
33 "section", "large page", "small page", "tiny page"
34 };
35
36 u32 armv4_5_mmu_translate_va(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 va, int *type, u32 *cb, int *domain, u32 *ap)
37 {
38 u32 first_lvl_descriptor = 0x0;
39 u32 second_lvl_descriptor = 0x0;
40 u32 ttb = armv4_5_mmu->get_ttb(target);
41
42 armv4_5_mmu_read_physical(target, armv4_5_mmu,
43 (ttb & 0xffffc000) | ((va & 0xfff00000) >> 18),
44 4, 1, (u8*)&first_lvl_descriptor);
45
46 DEBUG("1st lvl desc: %8.8x", first_lvl_descriptor);
47
48 if ((first_lvl_descriptor & 0x3) == 0)
49 {
50 *type = -1;
51 return ERROR_TARGET_TRANSLATION_FAULT;
52 }
53
54 if (!armv4_5_mmu->has_tiny_pages && ((first_lvl_descriptor & 0x3) == 3))
55 {
56 *type = -1;
57 return ERROR_TARGET_TRANSLATION_FAULT;
58 }
59
60 /* domain is always specified in bits 8-5 */
61 *domain = (first_lvl_descriptor & 0x1e0) >> 5;
62
63 if ((first_lvl_descriptor & 0x3) == 2)
64 {
65 /* section descriptor */
66 *type = ARMV4_5_SECTION;
67 *cb = (first_lvl_descriptor & 0xc) >> 2;
68 *ap = (first_lvl_descriptor & 0xc00) >> 10;
69 return (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff);
70 }
71
72 if ((first_lvl_descriptor & 0x3) == 1)
73 {
74 /* coarse page table */
75 armv4_5_mmu_read_physical(target, armv4_5_mmu,
76 (first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10),
77 4, 1, (u8*)&second_lvl_descriptor);
78 }
79
80 if ((first_lvl_descriptor & 0x3) == 3)
81 {
82 /* fine page table */
83 armv4_5_mmu_read_physical(target, armv4_5_mmu,
84 (first_lvl_descriptor & 0xfffff000) | ((va & 0x000ffc00) >> 8),
85 4, 1, (u8*)&second_lvl_descriptor);
86 }
87
88 DEBUG("2nd lvl desc: %8.8x", first_lvl_descriptor);
89
90 if ((second_lvl_descriptor & 0x3) == 0)
91 {
92 *type = -1;
93 return ERROR_TARGET_TRANSLATION_FAULT;
94 }
95
96 /* cacheable/bufferable is always specified in bits 3-2 */
97 *cb = (second_lvl_descriptor & 0xc) >> 2;
98
99 if ((second_lvl_descriptor & 0x3) == 1)
100 {
101 /* large page descriptor */
102 *type = ARMV4_5_LARGE_PAGE;
103 *ap = (second_lvl_descriptor & 0xff0) >> 4;
104 return (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff);
105 }
106
107 if ((second_lvl_descriptor & 0x3) == 2)
108 {
109 /* small page descriptor */
110 *type = ARMV4_5_SMALL_PAGE;
111 *ap = (second_lvl_descriptor & 0xff0) >> 4;
112 return (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff);
113 }
114
115 if ((second_lvl_descriptor & 0x3) == 3)
116 {
117 /* tiny page descriptor */
118 *type = ARMV4_5_TINY_PAGE;
119 *ap = (second_lvl_descriptor & 0x30) >> 4;
120 return (second_lvl_descriptor & 0xfffffc00) | (va & 0x000003ff);
121 }
122
123 /* should not happen */
124 *type = -1;
125 return ERROR_TARGET_TRANSLATION_FAULT;
126 }
127
128 int armv4_5_mmu_read_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer)
129 {
130 int retval;
131
132 if (target->state != TARGET_HALTED)
133 return ERROR_TARGET_NOT_HALTED;
134
135 /* disable MMU and data (or unified) cache */
136 armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0);
137
138 retval = armv4_5_mmu->read_memory(target, address, size, count, buffer);
139
140 /* reenable MMU / cache */
141 armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled,
142 armv4_5_mmu->armv4_5_cache.d_u_cache_enabled,
143 armv4_5_mmu->armv4_5_cache.i_cache_enabled);
144
145 return retval;
146 }
147
148 int armv4_5_mmu_write_physical(target_t *target, armv4_5_mmu_common_t *armv4_5_mmu, u32 address, u32 size, u32 count, u8 *buffer)
149 {
150 int retval;
151
152 if (target->state != TARGET_HALTED)
153 return ERROR_TARGET_NOT_HALTED;
154
155 /* disable MMU and data (or unified) cache */
156 armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0);
157
158 retval = armv4_5_mmu->write_memory(target, address, size, count, buffer);
159
160 /* reenable MMU / cache */
161 armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled,
162 armv4_5_mmu->armv4_5_cache.d_u_cache_enabled,
163 armv4_5_mmu->armv4_5_cache.i_cache_enabled);
164
165 return retval;
166 }
167
168 int armv4_5_mmu_handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu)
169 {
170 u32 va;
171 u32 pa;
172 int type;
173 u32 cb;
174 int domain;
175 u32 ap;
176
177 if (target->state != TARGET_HALTED)
178 {
179 command_print(cmd_ctx, "target must be stopped for \"virt2phys\" command");
180 return ERROR_OK;
181 }
182
183 if (argc == 0)
184 {
185 command_print(cmd_ctx, "usage: virt2phys <virtual address>");
186 return ERROR_OK;
187 }
188
189 if (argc == 1)
190 {
191 va = strtoul(args[0], NULL, 0);
192 pa = armv4_5_mmu_translate_va(target, armv4_5_mmu, va, &type, &cb, &domain, &ap);
193 if (type == -1)
194 {
195 switch (pa)
196 {
197 case ERROR_TARGET_TRANSLATION_FAULT:
198 command_print(cmd_ctx, "no valid translation for 0x%8.8x", va);
199 break;
200 default:
201 command_print(cmd_ctx, "unknown translation error");
202 }
203 return ERROR_OK;
204 }
205
206 command_print(cmd_ctx, "0x%8.8x -> 0x%8.8x, type: %s, cb: %i, domain: %i, ap: %2.2x",
207 va, pa, armv4_5_mmu_page_type_names[type], cb, domain, ap);
208 }
209
210 return ERROR_OK;
211 }
212
213 int armv4_5_mmu_handle_md_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu)
214 {
215 int count = 1;
216 int size = 4;
217 u32 address = 0;
218 int i;
219
220 char output[128];
221 int output_len;
222
223 int retval;
224
225 u8 *buffer;
226
227 if (target->state != TARGET_HALTED)
228 {
229 command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
230 return ERROR_OK;
231 }
232
233 if (argc < 1)
234 return ERROR_OK;
235
236 if (argc == 2)
237 count = strtoul(args[1], NULL, 0);
238
239 address = strtoul(args[0], NULL, 0);
240
241 switch (cmd[2])
242 {
243 case 'w':
244 size = 4;
245 break;
246 case 'h':
247 size = 2;
248 break;
249 case 'b':
250 size = 1;
251 break;
252 default:
253 return ERROR_OK;
254 }
255
256 buffer = calloc(count, size);
257 if ((retval = armv4_5_mmu_read_physical(target, armv4_5_mmu, address, size, count, buffer)) != ERROR_OK)
258 {
259 switch (retval)
260 {
261 case ERROR_TARGET_UNALIGNED_ACCESS:
262 command_print(cmd_ctx, "error: address not aligned");
263 break;
264 case ERROR_TARGET_NOT_HALTED:
265 command_print(cmd_ctx, "error: target must be halted for memory accesses");
266 break;
267 case ERROR_TARGET_DATA_ABORT:
268 command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted");
269 break;
270 default:
271 command_print(cmd_ctx, "error: unknown error");
272 }
273 }
274
275 output_len = 0;
276
277 for (i = 0; i < count; i++)
278 {
279 if (i%8 == 0)
280 output_len += snprintf(output + output_len, 128 - output_len, "0x%8.8x: ", address + (i*size));
281
282 switch (size)
283 {
284 case 4:
285 output_len += snprintf(output + output_len, 128 - output_len, "%8.8x ", ((u32*)buffer)[i]);
286 break;
287 case 2:
288 output_len += snprintf(output + output_len, 128 - output_len, "%4.4x ", ((u16*)buffer)[i]);
289 break;
290 case 1:
291 output_len += snprintf(output + output_len, 128 - output_len, "%2.2x ", ((u8*)buffer)[i]);
292 break;
293 }
294
295 if ((i%8 == 7) || (i == count - 1))
296 {
297 command_print(cmd_ctx, output);
298 output_len = 0;
299 }
300 }
301
302 free(buffer);
303
304 return ERROR_OK;
305 }
306
307 int armv4_5_mmu_handle_mw_phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int argc, target_t *target, armv4_5_mmu_common_t *armv4_5_mmu)
308 {
309 u32 address = 0;
310 u32 value = 0;
311 int retval;
312
313 if (target->state != TARGET_HALTED)
314 {
315 command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
316 return ERROR_OK;
317 }
318
319 if (argc < 2)
320 return ERROR_OK;
321
322 address = strtoul(args[0], NULL, 0);
323 value = strtoul(args[1], NULL, 0);
324
325 switch (cmd[2])
326 {
327 case 'w':
328 retval = armv4_5_mmu_write_physical(target, armv4_5_mmu, address, 4, 1, (u8*)&value);
329 break;
330 case 'h':
331 retval = armv4_5_mmu_write_physical(target, armv4_5_mmu, address, 2, 1, (u8*)&value);
332 break;
333 case 'b':
334 retval = armv4_5_mmu_write_physical(target, armv4_5_mmu, address, 1, 1, (u8*)&value);
335 break;
336 default:
337 return ERROR_OK;
338 }
339
340 switch (retval)
341 {
342 case ERROR_TARGET_UNALIGNED_ACCESS:
343 command_print(cmd_ctx, "error: address not aligned");
344 break;
345 case ERROR_TARGET_DATA_ABORT:
346 command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted");
347 break;
348 case ERROR_TARGET_NOT_HALTED:
349 command_print(cmd_ctx, "error: target must be halted for memory accesses");
350 break;
351 case ERROR_OK:
352 break;
353 default:
354 command_print(cmd_ctx, "error: unknown error");
355 }
356
357 return ERROR_OK;
358 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)