]> git.proxmox.com Git - qemu.git/blob - target-openrisc/mmu.c
Merge remote-tracking branch 'afaerber/tags/qom-cpu-for-anthony' into staging
[qemu.git] / target-openrisc / mmu.c
1 /*
2 * OpenRISC MMU.
3 *
4 * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
5 * Zhizhou Zhang <etouzh@gmail.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "cpu.h"
22 #include "qemu-common.h"
23 #include "exec/gdbstub.h"
24 #include "qemu/host-utils.h"
25 #ifndef CONFIG_USER_ONLY
26 #include "hw/loader.h"
27 #endif
28
29 #ifndef CONFIG_USER_ONLY
30 int cpu_openrisc_get_phys_nommu(OpenRISCCPU *cpu,
31 hwaddr *physical,
32 int *prot, target_ulong address, int rw)
33 {
34 *physical = address;
35 *prot = PAGE_READ | PAGE_WRITE;
36 return TLBRET_MATCH;
37 }
38
39 int cpu_openrisc_get_phys_code(OpenRISCCPU *cpu,
40 hwaddr *physical,
41 int *prot, target_ulong address, int rw)
42 {
43 int vpn = address >> TARGET_PAGE_BITS;
44 int idx = vpn & ITLB_MASK;
45 int right = 0;
46
47 if ((cpu->env.tlb->itlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
48 return TLBRET_NOMATCH;
49 }
50 if (!(cpu->env.tlb->itlb[0][idx].mr & 1)) {
51 return TLBRET_INVALID;
52 }
53
54 if (cpu->env.sr & SR_SM) { /* supervisor mode */
55 if (cpu->env.tlb->itlb[0][idx].tr & SXE) {
56 right |= PAGE_EXEC;
57 }
58 } else {
59 if (cpu->env.tlb->itlb[0][idx].tr & UXE) {
60 right |= PAGE_EXEC;
61 }
62 }
63
64 if ((rw & 2) && ((right & PAGE_EXEC) == 0)) {
65 return TLBRET_BADADDR;
66 }
67
68 *physical = (cpu->env.tlb->itlb[0][idx].tr & TARGET_PAGE_MASK) |
69 (address & (TARGET_PAGE_SIZE-1));
70 *prot = right;
71 return TLBRET_MATCH;
72 }
73
74 int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu,
75 hwaddr *physical,
76 int *prot, target_ulong address, int rw)
77 {
78 int vpn = address >> TARGET_PAGE_BITS;
79 int idx = vpn & DTLB_MASK;
80 int right = 0;
81
82 if ((cpu->env.tlb->dtlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
83 return TLBRET_NOMATCH;
84 }
85 if (!(cpu->env.tlb->dtlb[0][idx].mr & 1)) {
86 return TLBRET_INVALID;
87 }
88
89 if (cpu->env.sr & SR_SM) { /* supervisor mode */
90 if (cpu->env.tlb->dtlb[0][idx].tr & SRE) {
91 right |= PAGE_READ;
92 }
93 if (cpu->env.tlb->dtlb[0][idx].tr & SWE) {
94 right |= PAGE_WRITE;
95 }
96 } else {
97 if (cpu->env.tlb->dtlb[0][idx].tr & URE) {
98 right |= PAGE_READ;
99 }
100 if (cpu->env.tlb->dtlb[0][idx].tr & UWE) {
101 right |= PAGE_WRITE;
102 }
103 }
104
105 if ((rw & 0) && ((right & PAGE_READ) == 0)) {
106 return TLBRET_BADADDR;
107 }
108 if ((rw & 1) && ((right & PAGE_WRITE) == 0)) {
109 return TLBRET_BADADDR;
110 }
111
112 *physical = (cpu->env.tlb->dtlb[0][idx].tr & TARGET_PAGE_MASK) |
113 (address & (TARGET_PAGE_SIZE-1));
114 *prot = right;
115 return TLBRET_MATCH;
116 }
117
118 static int cpu_openrisc_get_phys_addr(OpenRISCCPU *cpu,
119 hwaddr *physical,
120 int *prot, target_ulong address,
121 int rw)
122 {
123 int ret = TLBRET_MATCH;
124
125 /* [0x0000--0x2000]: unmapped */
126 if (address < 0x2000 && (cpu->env.sr & SR_SM)) {
127 *physical = address;
128 *prot = PAGE_READ | PAGE_WRITE;
129 return ret;
130 }
131
132 if (rw == 2) { /* ITLB */
133 *physical = 0;
134 ret = cpu->env.tlb->cpu_openrisc_map_address_code(cpu, physical,
135 prot, address, rw);
136 } else { /* DTLB */
137 ret = cpu->env.tlb->cpu_openrisc_map_address_data(cpu, physical,
138 prot, address, rw);
139 }
140
141 return ret;
142 }
143 #endif
144
145 static void cpu_openrisc_raise_mmu_exception(OpenRISCCPU *cpu,
146 target_ulong address,
147 int rw, int tlb_error)
148 {
149 int exception = 0;
150
151 switch (tlb_error) {
152 default:
153 if (rw == 2) {
154 exception = EXCP_IPF;
155 } else {
156 exception = EXCP_DPF;
157 }
158 break;
159 #ifndef CONFIG_USER_ONLY
160 case TLBRET_BADADDR:
161 if (rw == 2) {
162 exception = EXCP_IPF;
163 } else {
164 exception = EXCP_DPF;
165 }
166 break;
167 case TLBRET_INVALID:
168 case TLBRET_NOMATCH:
169 /* No TLB match for a mapped address */
170 if (rw == 2) {
171 exception = EXCP_ITLBMISS;
172 } else {
173 exception = EXCP_DTLBMISS;
174 }
175 break;
176 #endif
177 }
178
179 cpu->env.exception_index = exception;
180 cpu->env.eear = address;
181 }
182
183 #ifndef CONFIG_USER_ONLY
184 int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
185 target_ulong address, int rw, int mmu_idx)
186 {
187 int ret = 0;
188 hwaddr physical = 0;
189 int prot = 0;
190 OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
191
192 ret = cpu_openrisc_get_phys_addr(cpu, &physical, &prot,
193 address, rw);
194
195 if (ret == TLBRET_MATCH) {
196 tlb_set_page(env, address & TARGET_PAGE_MASK,
197 physical & TARGET_PAGE_MASK, prot | PAGE_EXEC,
198 mmu_idx, TARGET_PAGE_SIZE);
199 ret = 0;
200 } else if (ret < 0) {
201 cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
202 ret = 1;
203 }
204
205 return ret;
206 }
207 #else
208 int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
209 target_ulong address, int rw, int mmu_idx)
210 {
211 int ret = 0;
212 OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
213
214 cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
215 ret = 1;
216
217 return ret;
218 }
219 #endif
220
221 #ifndef CONFIG_USER_ONLY
222 hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
223 {
224 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
225 hwaddr phys_addr;
226 int prot;
227
228 if (cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0)) {
229 return -1;
230 }
231
232 return phys_addr;
233 }
234
235 void cpu_openrisc_mmu_init(OpenRISCCPU *cpu)
236 {
237 cpu->env.tlb = g_malloc0(sizeof(CPUOpenRISCTLBContext));
238
239 cpu->env.tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu;
240 cpu->env.tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu;
241 }
242 #endif