b9bc21a8e6b36992ea16750360e77d98fc7f8bf5
[fw/openocd] / src / target / armv4_5_mmu.c
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2
3 /***************************************************************************
4  *   Copyright (C) 2005 by Dominic Rath                                    *
5  *   Dominic.Rath@gmx.de                                                   *
6  ***************************************************************************/
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include <helper/log.h>
13 #include "target.h"
14 #include "armv4_5_mmu.h"
15
16 int armv4_5_mmu_translate_va(struct target *target,
17                 struct armv4_5_mmu_common *armv4_5_mmu, uint32_t va, uint32_t *cb, uint32_t *val)
18 {
19         uint32_t first_lvl_descriptor = 0x0;
20         uint32_t second_lvl_descriptor = 0x0;
21         uint32_t ttb;
22         int retval;
23         retval = armv4_5_mmu->get_ttb(target, &ttb);
24         if (retval != ERROR_OK)
25                 return retval;
26
27         retval = armv4_5_mmu_read_physical(target, armv4_5_mmu,
28                 (ttb & 0xffffc000) | ((va & 0xfff00000) >> 18),
29                 4, 1, (uint8_t *)&first_lvl_descriptor);
30         if (retval != ERROR_OK)
31                 return retval;
32         first_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)&first_lvl_descriptor);
33
34         LOG_DEBUG("1st lvl desc: %8.8" PRIx32 "", first_lvl_descriptor);
35
36         if ((first_lvl_descriptor & 0x3) == 0) {
37                 LOG_ERROR("Address translation failure");
38                 return ERROR_TARGET_TRANSLATION_FAULT;
39         }
40
41         if (!armv4_5_mmu->has_tiny_pages && ((first_lvl_descriptor & 0x3) == 3)) {
42                 LOG_ERROR("Address translation failure");
43                 return ERROR_TARGET_TRANSLATION_FAULT;
44         }
45
46         if ((first_lvl_descriptor & 0x3) == 2) {
47                 /* section descriptor */
48                 *cb = (first_lvl_descriptor & 0xc) >> 2;
49                 *val = (first_lvl_descriptor & 0xfff00000) | (va & 0x000fffff);
50                 return ERROR_OK;
51         }
52
53         if ((first_lvl_descriptor & 0x3) == 1) {
54                 /* coarse page table */
55                 retval = armv4_5_mmu_read_physical(target, armv4_5_mmu,
56                         (first_lvl_descriptor & 0xfffffc00) | ((va & 0x000ff000) >> 10),
57                         4, 1, (uint8_t *)&second_lvl_descriptor);
58                 if (retval != ERROR_OK)
59                         return retval;
60         } else if ((first_lvl_descriptor & 0x3) == 3) {
61                 /* fine page table */
62                 retval = armv4_5_mmu_read_physical(target, armv4_5_mmu,
63                         (first_lvl_descriptor & 0xfffff000) | ((va & 0x000ffc00) >> 8),
64                         4, 1, (uint8_t *)&second_lvl_descriptor);
65                 if (retval != ERROR_OK)
66                         return retval;
67         }
68
69         second_lvl_descriptor = target_buffer_get_u32(target, (uint8_t *)&second_lvl_descriptor);
70
71         LOG_DEBUG("2nd lvl desc: %8.8" PRIx32 "", second_lvl_descriptor);
72
73         if ((second_lvl_descriptor & 0x3) == 0) {
74                 LOG_ERROR("Address translation failure");
75                 return ERROR_TARGET_TRANSLATION_FAULT;
76         }
77
78         /* cacheable/bufferable is always specified in bits 3-2 */
79         *cb = (second_lvl_descriptor & 0xc) >> 2;
80
81         if ((second_lvl_descriptor & 0x3) == 1) {
82                 /* large page descriptor */
83                 *val = (second_lvl_descriptor & 0xffff0000) | (va & 0x0000ffff);
84                 return ERROR_OK;
85         }
86
87         if ((second_lvl_descriptor & 0x3) == 2) {
88                 /* small page descriptor */
89                 *val = (second_lvl_descriptor & 0xfffff000) | (va & 0x00000fff);
90                 return ERROR_OK;
91         }
92
93         if ((second_lvl_descriptor & 0x3) == 3) {
94                 /* tiny page descriptor */
95                 *val = (second_lvl_descriptor & 0xfffffc00) | (va & 0x000003ff);
96                 return ERROR_OK;
97         }
98
99         /* should not happen */
100         LOG_ERROR("Address translation failure");
101         return ERROR_TARGET_TRANSLATION_FAULT;
102 }
103
104 int armv4_5_mmu_read_physical(struct target *target,
105                 struct armv4_5_mmu_common *armv4_5_mmu, uint32_t address,
106                 uint32_t size, uint32_t count, uint8_t *buffer)
107 {
108         int retval;
109
110         if (target->state != TARGET_HALTED)
111                 return ERROR_TARGET_NOT_HALTED;
112
113         /* disable MMU and data (or unified) cache */
114         retval = armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0);
115         if (retval != ERROR_OK)
116                 return retval;
117
118         retval = armv4_5_mmu->read_memory(target, address, size, count, buffer);
119         if (retval != ERROR_OK)
120                 return retval;
121
122         /* reenable MMU / cache */
123         retval = armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled,
124                 armv4_5_mmu->armv4_5_cache.d_u_cache_enabled,
125                 armv4_5_mmu->armv4_5_cache.i_cache_enabled);
126         if (retval != ERROR_OK)
127                 return retval;
128
129         return retval;
130 }
131
132 int armv4_5_mmu_write_physical(struct target *target,
133                 struct armv4_5_mmu_common *armv4_5_mmu, uint32_t address,
134                 uint32_t size, uint32_t count, const uint8_t *buffer)
135 {
136         int retval;
137
138         if (target->state != TARGET_HALTED)
139                 return ERROR_TARGET_NOT_HALTED;
140
141         /* disable MMU and data (or unified) cache */
142         retval = armv4_5_mmu->disable_mmu_caches(target, 1, 1, 0);
143         if (retval != ERROR_OK)
144                 return retval;
145
146         retval = armv4_5_mmu->write_memory(target, address, size, count, buffer);
147         if (retval != ERROR_OK)
148                 return retval;
149
150         /* reenable MMU / cache */
151         retval = armv4_5_mmu->enable_mmu_caches(target, armv4_5_mmu->mmu_enabled,
152                 armv4_5_mmu->armv4_5_cache.d_u_cache_enabled,
153                 armv4_5_mmu->armv4_5_cache.i_cache_enabled);
154         if (retval != ERROR_OK)
155                 return retval;
156
157         return retval;
158 }