master
c 449 lines 14.3 KB
Raw
1 /*
2 * PowerPC MMU, TLB and BAT emulation helpers for QEMU.
3 *
4 * Copyright (c) 2003-2007 Jocelyn Mayer
5 * Copyright (c) 2013 David Gibson, IBM Corporation
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.1 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 "qemu/osdep.h"
22 #include "cpu.h"
23 #include "exec/page-protection.h"
24 #include "exec/target_page.h"
25 #include "system/kvm.h"
26 #include "kvm_ppc.h"
27 #include "internal.h"
28 #include "mmu-hash32.h"
29 #include "mmu-books.h"
30 #include "exec/log.h"
31
32 /* #define DEBUG_BATS */
33
34 #ifdef DEBUG_BATS
35 # define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
36 #else
37 # define LOG_BATS(...) do { } while (0)
38 #endif
39
40 static target_ulong hash32_bat_size(int mmu_idx,
41 target_ulong batu, target_ulong batl)
42 {
43 if ((mmuidx_pr(mmu_idx) && !(batu & BATU32_VP))
44 || (!mmuidx_pr(mmu_idx) && !(batu & BATU32_VS))) {
45 return 0;
46 }
47
48 return BATU32_BEPI & ~((batu & BATU32_BL) << 15);
49 }
50
51 static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea,
52 MMUAccessType access_type, int *prot,
53 int mmu_idx)
54 {
55 CPUPPCState *env = &cpu->env;
56 target_ulong *BATlt, *BATut;
57 bool ifetch = access_type == MMU_INST_FETCH;
58 int i;
59
60 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
61 ifetch ? 'I' : 'D', ea);
62 if (ifetch) {
63 BATlt = env->IBAT[1];
64 BATut = env->IBAT[0];
65 } else {
66 BATlt = env->DBAT[1];
67 BATut = env->DBAT[0];
68 }
69 for (i = 0; i < env->nb_BATs; i++) {
70 target_ulong batu = BATut[i];
71 target_ulong batl = BATlt[i];
72 target_ulong mask;
73
74 mask = hash32_bat_size(mmu_idx, batu, batl);
75 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
76 " BATl " TARGET_FMT_lx "\n", __func__,
77 ifetch ? 'I' : 'D', i, ea, batu, batl);
78
79 if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
80 hwaddr raddr = (batl & mask) | (ea & ~mask);
81
82 *prot = ppc_hash32_bat_prot(batu, batl);
83
84 return raddr & TARGET_PAGE_MASK;
85 }
86 }
87
88 /* No hit */
89 #if defined(DEBUG_BATS)
90 if (qemu_log_enabled()) {
91 target_ulong *BATu, *BATl;
92 target_ulong BEPIl, BEPIu, bl;
93
94 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", ea);
95 for (i = 0; i < 4; i++) {
96 BATu = &BATut[i];
97 BATl = &BATlt[i];
98 BEPIu = *BATu & BATU32_BEPIU;
99 BEPIl = *BATu & BATU32_BEPIL;
100 bl = (*BATu & 0x00001FFC) << 15;
101 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
102 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
103 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
104 __func__, ifetch ? 'I' : 'D', i, ea,
105 *BATu, *BATl, BEPIu, BEPIl, bl);
106 }
107 }
108 #endif
109
110 return -1;
111 }
112
113 static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
114 target_ulong eaddr,
115 MMUAccessType access_type,
116 hwaddr *raddr, int *prot, int mmu_idx,
117 bool guest_visible)
118 {
119 CPUState *cs = CPU(cpu);
120 CPUPPCState *env = &cpu->env;
121
122 qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
123
124 if (access_type == MMU_INST_FETCH) {
125 /* No code fetch is allowed in direct-store areas */
126 if (guest_visible) {
127 cs->exception_index = POWERPC_EXCP_ISI;
128 env->error_code = 0x10000000;
129 }
130 return false;
131 }
132
133 /*
134 * From ppc_cpu_get_phys_addr_debug, env->access_type is not set.
135 * Assume ACCESS_INT for that case.
136 */
137 switch (guest_visible ? env->access_type : ACCESS_INT) {
138 case ACCESS_INT:
139 /* Integer load/store : only access allowed */
140 break;
141 case ACCESS_FLOAT:
142 /* Floating point load/store */
143 cs->exception_index = POWERPC_EXCP_ALIGN;
144 env->error_code = POWERPC_EXCP_ALIGN_FP;
145 env->spr[SPR_DAR] = eaddr;
146 return false;
147 case ACCESS_RES:
148 /* lwarx, ldarx or srwcx. */
149 env->error_code = 0;
150 env->spr[SPR_DAR] = eaddr;
151 if (access_type == MMU_DATA_STORE) {
152 env->spr[SPR_DSISR] = 0x06000000;
153 } else {
154 env->spr[SPR_DSISR] = 0x04000000;
155 }
156 return false;
157 case ACCESS_CACHE:
158 /*
159 * dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi
160 *
161 * Should make the instruction do no-op. As it already do
162 * no-op, it's quite easy :-)
163 */
164 *raddr = eaddr;
165 return true;
166 case ACCESS_EXT:
167 /* eciwx or ecowx */
168 cs->exception_index = POWERPC_EXCP_DSI;
169 env->error_code = 0;
170 env->spr[SPR_DAR] = eaddr;
171 if (access_type == MMU_DATA_STORE) {
172 env->spr[SPR_DSISR] = 0x06100000;
173 } else {
174 env->spr[SPR_DSISR] = 0x04100000;
175 }
176 return false;
177 default:
178 cpu_abort(cs, "ERROR: insn should not need address translation\n");
179 }
180
181 if (ppc_hash32_key(mmuidx_pr(mmu_idx), sr)) {
182 *prot = PAGE_READ | PAGE_WRITE;
183 } else {
184 *prot = PAGE_READ;
185 }
186 if (check_prot_access_type(*prot, access_type)) {
187 *raddr = eaddr;
188 return true;
189 }
190
191 if (guest_visible) {
192 cs->exception_index = POWERPC_EXCP_DSI;
193 env->error_code = 0;
194 env->spr[SPR_DAR] = eaddr;
195 if (access_type == MMU_DATA_STORE) {
196 env->spr[SPR_DSISR] = 0x0a000000;
197 } else {
198 env->spr[SPR_DSISR] = 0x08000000;
199 }
200 }
201 return false;
202 }
203
204 static target_ulong ppc_hash32_load_hpte0(PowerPCCPU *cpu, hwaddr pte_offset)
205 {
206 target_ulong base = ppc_hash32_hpt_base(cpu);
207
208 return ldl_phys(CPU(cpu)->as, base + pte_offset);
209 }
210
211 static target_ulong ppc_hash32_load_hpte1(PowerPCCPU *cpu, hwaddr pte_offset)
212 {
213 target_ulong base = ppc_hash32_hpt_base(cpu);
214
215 return ldl_phys(CPU(cpu)->as, base + pte_offset + HASH_PTE_SIZE_32 / 2);
216 }
217
218 static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off,
219 bool secondary, target_ulong ptem,
220 ppc_hash_pte32_t *pte)
221 {
222 hwaddr pte_offset = pteg_off;
223 target_ulong pte0, pte1;
224 int i;
225
226 for (i = 0; i < HPTES_PER_GROUP; i++) {
227 pte0 = ppc_hash32_load_hpte0(cpu, pte_offset);
228 /*
229 * pte0 contains the valid bit and must be read before pte1,
230 * otherwise we might see an old pte1 with a new valid bit and
231 * thus an inconsistent hpte value
232 */
233 smp_rmb();
234 pte1 = ppc_hash32_load_hpte1(cpu, pte_offset);
235
236 if ((pte0 & HPTE32_V_VALID)
237 && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
238 && HPTE32_V_COMPARE(pte0, ptem)) {
239 pte->pte0 = pte0;
240 pte->pte1 = pte1;
241 return pte_offset;
242 }
243
244 pte_offset += HASH_PTE_SIZE_32;
245 }
246
247 return -1;
248 }
249
250 static void ppc_hash32_set_r(PowerPCCPU *cpu, hwaddr pte_offset, uint32_t pte1)
251 {
252 target_ulong base = ppc_hash32_hpt_base(cpu);
253 hwaddr offset = pte_offset + 6;
254
255 /* The HW performs a non-atomic byte update */
256 stb_phys(CPU(cpu)->as, base + offset, ((pte1 >> 8) & 0xff) | 0x01);
257 }
258
259 static void ppc_hash32_set_c(PowerPCCPU *cpu, hwaddr pte_offset, uint64_t pte1)
260 {
261 target_ulong base = ppc_hash32_hpt_base(cpu);
262 hwaddr offset = pte_offset + 7;
263
264 /* The HW performs a non-atomic byte update */
265 stb_phys(CPU(cpu)->as, base + offset, (pte1 & 0xff) | 0x80);
266 }
267
268 static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
269 target_ulong sr, target_ulong eaddr,
270 ppc_hash_pte32_t *pte)
271 {
272 hwaddr pteg_off, pte_offset;
273 hwaddr hash;
274 uint32_t vsid, pgidx, ptem;
275
276 vsid = sr & SR32_VSID;
277 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
278 hash = vsid ^ pgidx;
279 ptem = (vsid << 7) | (pgidx >> 10);
280
281 /* Page address translation */
282 qemu_log_mask(CPU_LOG_MMU, "htab_base " HWADDR_FMT_plx
283 " htab_mask " HWADDR_FMT_plx
284 " hash " HWADDR_FMT_plx "\n",
285 ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
286
287 /* Primary PTEG lookup */
288 qemu_log_mask(CPU_LOG_MMU, "0 htab=" HWADDR_FMT_plx "/" HWADDR_FMT_plx
289 " vsid=%" PRIx32 " ptem=%" PRIx32
290 " hash=" HWADDR_FMT_plx "\n",
291 ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
292 vsid, ptem, hash);
293 pteg_off = get_pteg_offset32(cpu, hash);
294 pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte);
295 if (pte_offset == -1) {
296 /* Secondary PTEG lookup */
297 qemu_log_mask(CPU_LOG_MMU, "1 htab=" HWADDR_FMT_plx "/" HWADDR_FMT_plx
298 " vsid=%" PRIx32 " api=%" PRIx32
299 " hash=" HWADDR_FMT_plx "\n", ppc_hash32_hpt_base(cpu),
300 ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash);
301 pteg_off = get_pteg_offset32(cpu, ~hash);
302 pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte);
303 }
304
305 return pte_offset;
306 }
307
308 bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
309 hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
310 bool guest_visible)
311 {
312 CPUState *cs = CPU(cpu);
313 CPUPPCState *env = &cpu->env;
314 target_ulong sr;
315 hwaddr pte_offset, raddr;
316 ppc_hash_pte32_t pte;
317 bool key;
318 int prot;
319
320 /* There are no hash32 large pages. */
321 *psizep = TARGET_PAGE_BITS;
322
323 /* 1. Handle real mode accesses */
324 if (mmuidx_real(mmu_idx)) {
325 /* Translation is off */
326 *raddrp = eaddr;
327 *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
328 return true;
329 }
330
331 /* 2. Check Block Address Translation entries (BATs) */
332 if (env->nb_BATs != 0) {
333 raddr = ppc_hash32_bat_lookup(cpu, eaddr, access_type, protp, mmu_idx);
334 if (raddr != -1) {
335 if (!check_prot_access_type(*protp, access_type)) {
336 if (guest_visible) {
337 if (access_type == MMU_INST_FETCH) {
338 cs->exception_index = POWERPC_EXCP_ISI;
339 env->error_code = 0x08000000;
340 } else {
341 cs->exception_index = POWERPC_EXCP_DSI;
342 env->error_code = 0;
343 env->spr[SPR_DAR] = eaddr;
344 if (access_type == MMU_DATA_STORE) {
345 env->spr[SPR_DSISR] = 0x0a000000;
346 } else {
347 env->spr[SPR_DSISR] = 0x08000000;
348 }
349 }
350 }
351 return false;
352 }
353 *raddrp = raddr;
354 return true;
355 }
356 }
357
358 /* 3. Look up the Segment Register */
359 sr = env->sr[eaddr >> 28];
360
361 /* 4. Handle direct store segments */
362 if (sr & SR32_T) {
363 return ppc_hash32_direct_store(cpu, sr, eaddr, access_type,
364 raddrp, protp, mmu_idx, guest_visible);
365 }
366
367 /* 5. Check for segment level no-execute violation */
368 if (access_type == MMU_INST_FETCH && (sr & SR32_NX)) {
369 if (guest_visible) {
370 cs->exception_index = POWERPC_EXCP_ISI;
371 env->error_code = 0x10000000;
372 }
373 return false;
374 }
375
376 /* 6. Locate the PTE in the hash table */
377 pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte);
378 if (pte_offset == -1) {
379 if (guest_visible) {
380 if (access_type == MMU_INST_FETCH) {
381 cs->exception_index = POWERPC_EXCP_ISI;
382 env->error_code = 0x40000000;
383 } else {
384 cs->exception_index = POWERPC_EXCP_DSI;
385 env->error_code = 0;
386 env->spr[SPR_DAR] = eaddr;
387 if (access_type == MMU_DATA_STORE) {
388 env->spr[SPR_DSISR] = 0x42000000;
389 } else {
390 env->spr[SPR_DSISR] = 0x40000000;
391 }
392 }
393 }
394 return false;
395 }
396 qemu_log_mask(CPU_LOG_MMU,
397 "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
398
399 /* 7. Check access permissions */
400 key = ppc_hash32_key(mmuidx_pr(mmu_idx), sr);
401 prot = ppc_hash32_prot(key, pte.pte1 & HPTE32_R_PP, sr & SR32_NX);
402
403 if (!check_prot_access_type(prot, access_type)) {
404 /* Access right violation */
405 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
406 if (guest_visible) {
407 if (access_type == MMU_INST_FETCH) {
408 cs->exception_index = POWERPC_EXCP_ISI;
409 env->error_code = 0x08000000;
410 } else {
411 cs->exception_index = POWERPC_EXCP_DSI;
412 env->error_code = 0;
413 env->spr[SPR_DAR] = eaddr;
414 if (access_type == MMU_DATA_STORE) {
415 env->spr[SPR_DSISR] = 0x0a000000;
416 } else {
417 env->spr[SPR_DSISR] = 0x08000000;
418 }
419 }
420 }
421 return false;
422 }
423
424 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
425
426 /* 8. Update PTE referenced and changed bits if necessary */
427
428 if (!(pte.pte1 & HPTE32_R_R)) {
429 ppc_hash32_set_r(cpu, pte_offset, pte.pte1);
430 }
431 if (!(pte.pte1 & HPTE32_R_C)) {
432 if (access_type == MMU_DATA_STORE) {
433 ppc_hash32_set_c(cpu, pte_offset, pte.pte1);
434 } else {
435 /*
436 * Treat the page as read-only for now, so that a later write
437 * will pass through this function again to set the C bit
438 */
439 prot &= ~PAGE_WRITE;
440 }
441 }
442 *protp = prot;
443
444 /* 9. Determine the real address from the PTE */
445 *raddrp = pte.pte1 & HPTE32_R_RPN;
446 *raddrp &= TARGET_PAGE_MASK;
447 *raddrp |= eaddr & ~TARGET_PAGE_MASK;
448 return true;
449 }