- endianess fixes everywhere but in the flash code. flashing might still be broken...
[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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "arm7_9_common.h"
25 #include "log.h"
26 #include "command.h"
27 #include "armv4_5_mmu.h"
28 #include "target.h"
29
30 #include <stdlib.h>
31
32 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);
33 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);
34 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);
35
36 char* armv4_5_mmu_page_type_names[] =
37 {
38 "section", "large page", "small page", "tiny page"
39 };
40
41 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)
42 {
43 u32 first_lvl_descriptor = 0x0;
44 u32 second_lvl_descriptor = 0x0;
45 u32 ttb = armv4_5_mmu->get_ttb(target);
46
47 armv4_5_mmu_read_physical(target, armv4_5_mmu,
48 (ttb & 0xffffc000) | ((va & 0xfff00000) >> 18),
49 4, 1, (u8*)&first_lvl_descriptor);
50 first_lvl_descriptor = target_buffer_get_u32(target, (u8*)&first_lvl_descriptor);
51
52 DEBUG("1st lvl desc: %8.8x", first_lvl_descriptor);
53
54 if ((first_lvl_descriptor & 0x3) == 0)
55 {
56 *type = -1;
57 return ERROR_TARGET_TRANSLATION_FAULT;
58 }
59
60 if (!armv4_5_mmu->has_tiny_pages && ((first_lvl_descriptor & 0x3) == 3))
61 {
62 *type = -1;
63 return ERROR_TARGET_TRANSLATION_FAULT;
64 }
65
66 /* domain is always specified in bits 8-5 */
67 *domain = (first_lvl_descriptor & 0x1e0) >> 5;
68
69 if ((first_lvl_descriptor & 0x3) == 2)
70 {
71 /* section descriptor */
72 *type = ARMV4_5_SECTION;
73 *cb = (first_lvl_descriptor & 0xc) >> 2;
74 *ap = (first_lvl_descriptor & 0xc00) >> 10;
75 return (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff);
76 }
77
78 if ((first_lvl_descriptor & 0x3) == 1)
79 {
80 /* coarse page table */
81 armv4_5_mmu_read_physical(target, armv4_5_mmu,
82 (first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10),
83 4, 1, (u8*)&second_lvl_descriptor);
84 }
85 else if ((first_lvl_descriptor & 0x3) == 3)
86 {
87 /* fine page table */
88 armv4_5_mmu_read_physical(target, armv4_5_mmu,
89 (first_lvl_descriptor & 0xfffff000) | ((va & 0x000ffc00) >> 8),
90 4, 1, (u8*)&second_lvl_descriptor);
91 }
92
93 second_lvl_descriptor = target_buffer_get_u32(target, (u8*)&second_lvl_descriptor);
94
95 DEBUG("2nd lvl desc: %8.8x", second_lvl_descriptor);
96
97 if ((second_lvl_descriptor & 0x3) == 0)
98 {
99 *type = -1;
100 return ERROR_TARGET_TRANSLATION_FAULT;
101 }
102
103 /* cacheable/bufferable is always specified in bits 3-2 */
104 *cb = (second_lvl_descriptor & 0xc) >> 2;
105
106 if ((second_lvl_descriptor & 0x3) == 1)
107 {
108 /* large page descriptor */
109 *type = ARMV4_5_LARGE_PAGE;
110 *ap = (second_lvl_descriptor & 0xff0) >> 4;
111 return (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff);
112 }
113
114 if ((second_lvl_descriptor & 0x3) == 2)
115 {
116 /* small page descriptor */
117 *type = ARMV4_5_SMALL_PAGE;
118 *ap = (second_lvl_descriptor & 0xff0) >> 4;
119 return (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff);
120 }
121
122 if ((second_lvl_descriptor & 0x3) == 3)
123 {
124 /* tiny page descriptor */
125 *type = ARMV4_5_TINY_PAGE;
126 *ap = (second_lvl_descriptor & 0x30) >> 4;
127 return (second_lvl_descriptor & 0xfffffc00) | (va & 0x000003ff);
128 }
129
130 /* should not happen */
131 *type = -1;
132 return ERROR_TARGET_TRANSLATION_FAULT;
133 }
134
135 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)
136 {
137 int retval;
138
139 if (target->state != TARGET_HALTED)
140 return ERROR_TARGET_NOT_HALTED;
141
142 /* disable MMU and data (or unified) cache */
143 armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0);
144
145 retval = armv4_5_mmu->read_memory(target, address, size, count, buffer);
146
147 /* reenable MMU / cache */
148 armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled,
149 armv4_5_mmu->armv4_5_cache.d_u_cache_enabled,
150 armv4_5_mmu->armv4_5_cache.i_cache_enabled);
151
152 return retval;
153 }
154
155 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)
156 {
157 int retval;
158
159 if (target->state != TARGET_HALTED)
160 return ERROR_TARGET_NOT_HALTED;
161
162 /* disable MMU and data (or unified) cache */
163 armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0);
164
165 retval = armv4_5_mmu->write_memory(target, address, size, count, buffer);
166
167 /* reenable MMU / cache */
168 armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled,
169 armv4_5_mmu->armv4_5_cache.d_u_cache_enabled,
170 armv4_5_mmu->armv4_5_cache.i_cache_enabled);
171
172 return retval;
173 }
174
175 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)
176 {
177 u32 va;
178 u32 pa;
179 int type;
180 u32 cb;
181 int domain;
182 u32 ap;
183
184 if (target->state != TARGET_HALTED)
185 {
186 command_print(cmd_ctx, "target must be stopped for \"virt2phys\" command");
187 return ERROR_OK;
188 }
189
190 if (argc == 0)
191 {
192 command_print(cmd_ctx, "usage: virt2phys <virtual address>");
193 return ERROR_OK;
194 }
195
196 if (argc == 1)
197 {
198 va = strtoul(args[0], NULL, 0);
199 pa = armv4_5_mmu_translate_va(target, armv4_5_mmu, va, &type, &cb, &domain, &ap);
200 if (type == -1)
201 {
202 switch (pa)
203 {
204 case ERROR_TARGET_TRANSLATION_FAULT:
205 command_print(cmd_ctx, "no valid translation for 0x%8.8x", va);
206 break;
207 default:
208 command_print(cmd_ctx, "unknown translation error");
209 }
210 return ERROR_OK;
211 }
212
213 command_print(cmd_ctx, "0x%8.8x -> 0x%8.8x, type: %s, cb: %i, domain: %i, ap: %2.2x",
214 va, pa, armv4_5_mmu_page_type_names[type], cb, domain, ap);
215 }
216
217 return ERROR_OK;
218 }
219
220 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)
221 {
222 int count = 1;
223 int size = 4;
224 u32 address = 0;
225 int i;
226
227 char output[128];
228 int output_len;
229
230 int retval;
231
232 u8 *buffer;
233
234 if (target->state != TARGET_HALTED)
235 {
236 command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
237 return ERROR_OK;
238 }
239
240 if (argc < 1)
241 return ERROR_OK;
242
243 if (argc == 2)
244 count = strtoul(args[1], NULL, 0);
245
246 address = strtoul(args[0], NULL, 0);
247
248 switch (cmd[2])
249 {
250 case 'w':
251 size = 4;
252 break;
253 case 'h':
254 size = 2;
255 break;
256 case 'b':
257 size = 1;
258 break;
259 default:
260 return ERROR_OK;
261 }
262
263 buffer = calloc(count, size);
264 if ((retval = armv4_5_mmu_read_physical(target, armv4_5_mmu, address, size, count, buffer)) != ERROR_OK)
265 {
266 switch (retval)
267 {
268 case ERROR_TARGET_UNALIGNED_ACCESS:
269 command_print(cmd_ctx, "error: address not aligned");
270 break;
271 case ERROR_TARGET_NOT_HALTED:
272 command_print(cmd_ctx, "error: target must be halted for memory accesses");
273 break;
274 case ERROR_TARGET_DATA_ABORT:
275 command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted");
276 break;
277 default:
278 command_print(cmd_ctx, "error: unknown error");
279 }
280 }
281
282 output_len = 0;
283
284 for (i = 0; i < count; i++)
285 {
286 if (i%8 == 0)
287 output_len += snprintf(output + output_len, 128 - output_len, "0x%8.8x: ", address + (i*size));
288
289 switch (size)
290 {
291 case 4:
292 output_len += snprintf(output + output_len, 128 - output_len, "%8.8x ", target_buffer_get_u32(target, &buffer[i*4]));
293 break;
294 case 2:
295 output_len += snprintf(output + output_len, 128 - output_len, "%4.4x ", target_buffer_get_u16(target, &buffer[i*2]));
296 break;
297 case 1:
298 output_len += snprintf(output + output_len, 128 - output_len, "%2.2x ", buffer[i*1]);
299 break;
300 }
301
302 if ((i % 8 == 7) || (i == count - 1))
303 {
304 command_print(cmd_ctx, output);
305 output_len = 0;
306 }
307 }
308
309 free(buffer);
310
311 return ERROR_OK;
312 }
313
314 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)
315 {
316 u32 address = 0;
317 u32 value = 0;
318 int retval;
319 u8 value_buf[4];
320
321 if (target->state != TARGET_HALTED)
322 {
323 command_print(cmd_ctx, "target must be stopped for \"%s\" command", cmd);
324 return ERROR_OK;
325 }
326
327 if (argc < 2)
328 return ERROR_OK;
329
330 address = strtoul(args[0], NULL, 0);
331 value = strtoul(args[1], NULL, 0);
332
333 switch (cmd[2])
334 {
335 case 'w':
336 target_buffer_set_u32(target, value_buf, value);
337 retval = armv4_5_mmu_write_physical(target, armv4_5_mmu, address, 4, 1, value_buf);
338 break;
339 case 'h':
340 target_buffer_set_u16(target, value_buf, value);
341 retval = armv4_5_mmu_write_physical(target, armv4_5_mmu, address, 2, 1, value_buf);
342 break;
343 case 'b':
344 value_buf[0] = value;
345 retval = armv4_5_mmu_write_physical(target, armv4_5_mmu, address, 1, 1, value_buf);
346 break;
347 default:
348 return ERROR_OK;
349 }
350
351 switch (retval)
352 {
353 case ERROR_TARGET_UNALIGNED_ACCESS:
354 command_print(cmd_ctx, "error: address not aligned");
355 break;
356 case ERROR_TARGET_DATA_ABORT:
357 command_print(cmd_ctx, "error: access caused data abort, system possibly corrupted");
358 break;
359 case ERROR_TARGET_NOT_HALTED:
360 command_print(cmd_ctx, "error: target must be halted for memory accesses");
361 break;
362 case ERROR_OK:
363 break;
364 default:
365 command_print(cmd_ctx, "error: unknown error");
366 }
367
368 return ERROR_OK;
369 }

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)