blob: 750a93636b683a161fcf4dcf29ccbe3a112a7aab [file] [log] [blame]
Jia Liue67db062012-07-20 15:50:39 +08001/*
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"
Paolo Bonzini022c62c2012-12-17 18:19:49 +010023#include "exec/gdbstub.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010024#include "qemu/host-utils.h"
Jia Liue67db062012-07-20 15:50:39 +080025#ifndef CONFIG_USER_ONLY
26#include "hw/loader.h"
27#endif
28
29#ifndef CONFIG_USER_ONLY
Jia Liu726fe042012-07-20 15:50:40 +080030int cpu_openrisc_get_phys_nommu(OpenRISCCPU *cpu,
Avi Kivitya8170e52012-10-23 12:30:10 +020031 hwaddr *physical,
Jia Liu726fe042012-07-20 15:50:40 +080032 int *prot, target_ulong address, int rw)
33{
34 *physical = address;
Sebastian Macke04359e62013-10-22 02:12:39 +020035 *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
Jia Liu726fe042012-07-20 15:50:40 +080036 return TLBRET_MATCH;
37}
38
39int cpu_openrisc_get_phys_code(OpenRISCCPU *cpu,
Avi Kivitya8170e52012-10-23 12:30:10 +020040 hwaddr *physical,
Jia Liu726fe042012-07-20 15:50:40 +080041 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
74int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu,
Avi Kivitya8170e52012-10-23 12:30:10 +020075 hwaddr *physical,
Jia Liu726fe042012-07-20 15:50:40 +080076 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
Sebastian Mackebf961b52013-10-03 16:04:46 +0800105 if (!(rw & 1) && ((right & PAGE_READ) == 0)) {
Jia Liu726fe042012-07-20 15:50:40 +0800106 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
118static int cpu_openrisc_get_phys_addr(OpenRISCCPU *cpu,
Avi Kivitya8170e52012-10-23 12:30:10 +0200119 hwaddr *physical,
Jia Liu726fe042012-07-20 15:50:40 +0800120 int *prot, target_ulong address,
121 int rw)
122{
123 int ret = TLBRET_MATCH;
124
Jia Liu726fe042012-07-20 15:50:40 +0800125 if (rw == 2) { /* ITLB */
126 *physical = 0;
127 ret = cpu->env.tlb->cpu_openrisc_map_address_code(cpu, physical,
128 prot, address, rw);
129 } else { /* DTLB */
130 ret = cpu->env.tlb->cpu_openrisc_map_address_data(cpu, physical,
131 prot, address, rw);
132 }
133
134 return ret;
135}
136#endif
137
138static void cpu_openrisc_raise_mmu_exception(OpenRISCCPU *cpu,
139 target_ulong address,
140 int rw, int tlb_error)
141{
Andreas Färber27103422013-08-26 08:31:06 +0200142 CPUState *cs = CPU(cpu);
Jia Liu726fe042012-07-20 15:50:40 +0800143 int exception = 0;
144
145 switch (tlb_error) {
146 default:
147 if (rw == 2) {
148 exception = EXCP_IPF;
149 } else {
150 exception = EXCP_DPF;
151 }
152 break;
153#ifndef CONFIG_USER_ONLY
154 case TLBRET_BADADDR:
155 if (rw == 2) {
156 exception = EXCP_IPF;
157 } else {
158 exception = EXCP_DPF;
159 }
160 break;
161 case TLBRET_INVALID:
162 case TLBRET_NOMATCH:
163 /* No TLB match for a mapped address */
164 if (rw == 2) {
165 exception = EXCP_ITLBMISS;
166 } else {
167 exception = EXCP_DTLBMISS;
168 }
169 break;
170#endif
171 }
172
Andreas Färber27103422013-08-26 08:31:06 +0200173 cs->exception_index = exception;
Jia Liu726fe042012-07-20 15:50:40 +0800174 cpu->env.eear = address;
175}
176
177#ifndef CONFIG_USER_ONLY
Andreas Färber75104542013-08-26 03:01:33 +0200178int openrisc_cpu_handle_mmu_fault(CPUState *cs,
179 vaddr address, int rw, int mmu_idx)
Jia Liu726fe042012-07-20 15:50:40 +0800180{
Andreas Färber75104542013-08-26 03:01:33 +0200181 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
Jia Liu726fe042012-07-20 15:50:40 +0800182 int ret = 0;
Avi Kivitya8170e52012-10-23 12:30:10 +0200183 hwaddr physical = 0;
Jia Liu726fe042012-07-20 15:50:40 +0800184 int prot = 0;
Jia Liu726fe042012-07-20 15:50:40 +0800185
186 ret = cpu_openrisc_get_phys_addr(cpu, &physical, &prot,
187 address, rw);
188
189 if (ret == TLBRET_MATCH) {
Andreas Färber0c591eb2013-09-03 13:59:37 +0200190 tlb_set_page(cs, address & TARGET_PAGE_MASK,
Sebastian Macke04359e62013-10-22 02:12:39 +0200191 physical & TARGET_PAGE_MASK, prot,
Jia Liu726fe042012-07-20 15:50:40 +0800192 mmu_idx, TARGET_PAGE_SIZE);
193 ret = 0;
194 } else if (ret < 0) {
195 cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
196 ret = 1;
197 }
198
199 return ret;
200}
201#else
Andreas Färber75104542013-08-26 03:01:33 +0200202int openrisc_cpu_handle_mmu_fault(CPUState *cs,
203 vaddr address, int rw, int mmu_idx)
Jia Liu726fe042012-07-20 15:50:40 +0800204{
Andreas Färber75104542013-08-26 03:01:33 +0200205 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
Jia Liu726fe042012-07-20 15:50:40 +0800206 int ret = 0;
Jia Liu726fe042012-07-20 15:50:40 +0800207
208 cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
209 ret = 1;
210
211 return ret;
212}
213#endif
214
215#ifndef CONFIG_USER_ONLY
Andreas Färber00b941e2013-06-29 18:55:54 +0200216hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
Jia Liue67db062012-07-20 15:50:39 +0800217{
Andreas Färber00b941e2013-06-29 18:55:54 +0200218 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
Avi Kivitya8170e52012-10-23 12:30:10 +0200219 hwaddr phys_addr;
Jia Liu726fe042012-07-20 15:50:40 +0800220 int prot;
Jia Liu726fe042012-07-20 15:50:40 +0800221
222 if (cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0)) {
223 return -1;
224 }
225
226 return phys_addr;
Jia Liue67db062012-07-20 15:50:39 +0800227}
228
229void cpu_openrisc_mmu_init(OpenRISCCPU *cpu)
230{
Jia Liu726fe042012-07-20 15:50:40 +0800231 cpu->env.tlb = g_malloc0(sizeof(CPUOpenRISCTLBContext));
232
233 cpu->env.tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu;
234 cpu->env.tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu;
Jia Liue67db062012-07-20 15:50:39 +0800235}
236#endif