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

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)