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

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)