]> git.proxmox.com Git - mirror_qemu.git/blame - target-openrisc/mmu.c
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
[mirror_qemu.git] / target-openrisc / mmu.c
CommitLineData
e67db06e
JL
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
ed2decc6 21#include "qemu/osdep.h"
e67db06e 22#include "cpu.h"
63c91552 23#include "exec/exec-all.h"
e67db06e 24#include "qemu-common.h"
022c62cb 25#include "exec/gdbstub.h"
1de7afc9 26#include "qemu/host-utils.h"
e67db06e
JL
27#ifndef CONFIG_USER_ONLY
28#include "hw/loader.h"
29#endif
30
726fe045
JL
31#ifndef CONFIG_USER_ONLY
32int cpu_openrisc_get_phys_nommu(OpenRISCCPU *cpu,
a8170e5e 33 hwaddr *physical,
726fe045
JL
34 int *prot, target_ulong address, int rw)
35{
36 *physical = address;
04359e6b 37 *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
726fe045
JL
38 return TLBRET_MATCH;
39}
40
41int cpu_openrisc_get_phys_code(OpenRISCCPU *cpu,
a8170e5e 42 hwaddr *physical,
726fe045
JL
43 int *prot, target_ulong address, int rw)
44{
45 int vpn = address >> TARGET_PAGE_BITS;
46 int idx = vpn & ITLB_MASK;
47 int right = 0;
48
49 if ((cpu->env.tlb->itlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
50 return TLBRET_NOMATCH;
51 }
52 if (!(cpu->env.tlb->itlb[0][idx].mr & 1)) {
53 return TLBRET_INVALID;
54 }
55
56 if (cpu->env.sr & SR_SM) { /* supervisor mode */
57 if (cpu->env.tlb->itlb[0][idx].tr & SXE) {
58 right |= PAGE_EXEC;
59 }
60 } else {
61 if (cpu->env.tlb->itlb[0][idx].tr & UXE) {
62 right |= PAGE_EXEC;
63 }
64 }
65
66 if ((rw & 2) && ((right & PAGE_EXEC) == 0)) {
67 return TLBRET_BADADDR;
68 }
69
70 *physical = (cpu->env.tlb->itlb[0][idx].tr & TARGET_PAGE_MASK) |
71 (address & (TARGET_PAGE_SIZE-1));
72 *prot = right;
73 return TLBRET_MATCH;
74}
75
76int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu,
a8170e5e 77 hwaddr *physical,
726fe045
JL
78 int *prot, target_ulong address, int rw)
79{
80 int vpn = address >> TARGET_PAGE_BITS;
81 int idx = vpn & DTLB_MASK;
82 int right = 0;
83
84 if ((cpu->env.tlb->dtlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
85 return TLBRET_NOMATCH;
86 }
87 if (!(cpu->env.tlb->dtlb[0][idx].mr & 1)) {
88 return TLBRET_INVALID;
89 }
90
91 if (cpu->env.sr & SR_SM) { /* supervisor mode */
92 if (cpu->env.tlb->dtlb[0][idx].tr & SRE) {
93 right |= PAGE_READ;
94 }
95 if (cpu->env.tlb->dtlb[0][idx].tr & SWE) {
96 right |= PAGE_WRITE;
97 }
98 } else {
99 if (cpu->env.tlb->dtlb[0][idx].tr & URE) {
100 right |= PAGE_READ;
101 }
102 if (cpu->env.tlb->dtlb[0][idx].tr & UWE) {
103 right |= PAGE_WRITE;
104 }
105 }
106
bf961b52 107 if (!(rw & 1) && ((right & PAGE_READ) == 0)) {
726fe045
JL
108 return TLBRET_BADADDR;
109 }
110 if ((rw & 1) && ((right & PAGE_WRITE) == 0)) {
111 return TLBRET_BADADDR;
112 }
113
114 *physical = (cpu->env.tlb->dtlb[0][idx].tr & TARGET_PAGE_MASK) |
115 (address & (TARGET_PAGE_SIZE-1));
116 *prot = right;
117 return TLBRET_MATCH;
118}
119
120static int cpu_openrisc_get_phys_addr(OpenRISCCPU *cpu,
a8170e5e 121 hwaddr *physical,
726fe045
JL
122 int *prot, target_ulong address,
123 int rw)
124{
125 int ret = TLBRET_MATCH;
126
726fe045
JL
127 if (rw == 2) { /* ITLB */
128 *physical = 0;
129 ret = cpu->env.tlb->cpu_openrisc_map_address_code(cpu, physical,
130 prot, address, rw);
131 } else { /* DTLB */
132 ret = cpu->env.tlb->cpu_openrisc_map_address_data(cpu, physical,
133 prot, address, rw);
134 }
135
136 return ret;
137}
138#endif
139
140static void cpu_openrisc_raise_mmu_exception(OpenRISCCPU *cpu,
141 target_ulong address,
142 int rw, int tlb_error)
143{
27103424 144 CPUState *cs = CPU(cpu);
726fe045
JL
145 int exception = 0;
146
147 switch (tlb_error) {
148 default:
149 if (rw == 2) {
150 exception = EXCP_IPF;
151 } else {
152 exception = EXCP_DPF;
153 }
154 break;
155#ifndef CONFIG_USER_ONLY
156 case TLBRET_BADADDR:
157 if (rw == 2) {
158 exception = EXCP_IPF;
159 } else {
160 exception = EXCP_DPF;
161 }
162 break;
163 case TLBRET_INVALID:
164 case TLBRET_NOMATCH:
165 /* No TLB match for a mapped address */
166 if (rw == 2) {
167 exception = EXCP_ITLBMISS;
168 } else {
169 exception = EXCP_DTLBMISS;
170 }
171 break;
172#endif
173 }
174
27103424 175 cs->exception_index = exception;
726fe045
JL
176 cpu->env.eear = address;
177}
178
179#ifndef CONFIG_USER_ONLY
7510454e
AF
180int openrisc_cpu_handle_mmu_fault(CPUState *cs,
181 vaddr address, int rw, int mmu_idx)
726fe045 182{
7510454e 183 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
726fe045 184 int ret = 0;
a8170e5e 185 hwaddr physical = 0;
726fe045 186 int prot = 0;
726fe045
JL
187
188 ret = cpu_openrisc_get_phys_addr(cpu, &physical, &prot,
189 address, rw);
190
191 if (ret == TLBRET_MATCH) {
0c591eb0 192 tlb_set_page(cs, address & TARGET_PAGE_MASK,
04359e6b 193 physical & TARGET_PAGE_MASK, prot,
726fe045
JL
194 mmu_idx, TARGET_PAGE_SIZE);
195 ret = 0;
196 } else if (ret < 0) {
197 cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
198 ret = 1;
199 }
200
201 return ret;
202}
203#else
7510454e
AF
204int openrisc_cpu_handle_mmu_fault(CPUState *cs,
205 vaddr address, int rw, int mmu_idx)
726fe045 206{
7510454e 207 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
726fe045 208 int ret = 0;
726fe045
JL
209
210 cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
211 ret = 1;
212
213 return ret;
214}
215#endif
216
e67db06e 217#ifndef CONFIG_USER_ONLY
00b941e5 218hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
e67db06e 219{
00b941e5 220 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
a8170e5e 221 hwaddr phys_addr;
726fe045 222 int prot;
726fe045
JL
223
224 if (cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0)) {
225 return -1;
226 }
227
228 return phys_addr;
e67db06e
JL
229}
230
231void cpu_openrisc_mmu_init(OpenRISCCPU *cpu)
232{
726fe045
JL
233 cpu->env.tlb = g_malloc0(sizeof(CPUOpenRISCTLBContext));
234
235 cpu->env.tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu;
236 cpu->env.tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu;
e67db06e
JL
237}
238#endif