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