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/exec-all.h"
24 #include "exec/page-protection.h"
25 #include "sysemu/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
hash32_bat_size(int mmu_idx,target_ulong batu,target_ulong batl)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
ppc_hash32_bat_lookup(PowerPCCPU * cpu,target_ulong ea,MMUAccessType access_type,int * prot,int mmu_idx)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
ppc_hash32_direct_store(PowerPCCPU * cpu,target_ulong sr,target_ulong eaddr,MMUAccessType access_type,hwaddr * raddr,int * prot,int mmu_idx,bool guest_visible)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_page_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
ppc_hash32_pteg_search(PowerPCCPU * cpu,hwaddr pteg_off,bool secondary,target_ulong ptem,ppc_hash_pte32_t * pte)204 static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off,
205 bool secondary, target_ulong ptem,
206 ppc_hash_pte32_t *pte)
207 {
208 hwaddr pte_offset = pteg_off;
209 target_ulong pte0, pte1;
210 int i;
211
212 for (i = 0; i < HPTES_PER_GROUP; i++) {
213 pte0 = ppc_hash32_load_hpte0(cpu, pte_offset);
214 /*
215 * pte0 contains the valid bit and must be read before pte1,
216 * otherwise we might see an old pte1 with a new valid bit and
217 * thus an inconsistent hpte value
218 */
219 smp_rmb();
220 pte1 = ppc_hash32_load_hpte1(cpu, pte_offset);
221
222 if ((pte0 & HPTE32_V_VALID)
223 && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
224 && HPTE32_V_COMPARE(pte0, ptem)) {
225 pte->pte0 = pte0;
226 pte->pte1 = pte1;
227 return pte_offset;
228 }
229
230 pte_offset += HASH_PTE_SIZE_32;
231 }
232
233 return -1;
234 }
235
ppc_hash32_set_r(PowerPCCPU * cpu,hwaddr pte_offset,uint32_t pte1)236 static void ppc_hash32_set_r(PowerPCCPU *cpu, hwaddr pte_offset, uint32_t pte1)
237 {
238 target_ulong base = ppc_hash32_hpt_base(cpu);
239 hwaddr offset = pte_offset + 6;
240
241 /* The HW performs a non-atomic byte update */
242 stb_phys(CPU(cpu)->as, base + offset, ((pte1 >> 8) & 0xff) | 0x01);
243 }
244
ppc_hash32_set_c(PowerPCCPU * cpu,hwaddr pte_offset,uint64_t pte1)245 static void ppc_hash32_set_c(PowerPCCPU *cpu, hwaddr pte_offset, uint64_t pte1)
246 {
247 target_ulong base = ppc_hash32_hpt_base(cpu);
248 hwaddr offset = pte_offset + 7;
249
250 /* The HW performs a non-atomic byte update */
251 stb_phys(CPU(cpu)->as, base + offset, (pte1 & 0xff) | 0x80);
252 }
253
ppc_hash32_htab_lookup(PowerPCCPU * cpu,target_ulong sr,target_ulong eaddr,ppc_hash_pte32_t * pte)254 static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
255 target_ulong sr, target_ulong eaddr,
256 ppc_hash_pte32_t *pte)
257 {
258 hwaddr pteg_off, pte_offset;
259 hwaddr hash;
260 uint32_t vsid, pgidx, ptem;
261
262 vsid = sr & SR32_VSID;
263 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
264 hash = vsid ^ pgidx;
265 ptem = (vsid << 7) | (pgidx >> 10);
266
267 /* Page address translation */
268 qemu_log_mask(CPU_LOG_MMU, "htab_base " HWADDR_FMT_plx
269 " htab_mask " HWADDR_FMT_plx
270 " hash " HWADDR_FMT_plx "\n",
271 ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
272
273 /* Primary PTEG lookup */
274 qemu_log_mask(CPU_LOG_MMU, "0 htab=" HWADDR_FMT_plx "/" HWADDR_FMT_plx
275 " vsid=%" PRIx32 " ptem=%" PRIx32
276 " hash=" HWADDR_FMT_plx "\n",
277 ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
278 vsid, ptem, hash);
279 pteg_off = get_pteg_offset32(cpu, hash);
280 pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte);
281 if (pte_offset == -1) {
282 /* Secondary PTEG lookup */
283 qemu_log_mask(CPU_LOG_MMU, "1 htab=" HWADDR_FMT_plx "/" HWADDR_FMT_plx
284 " vsid=%" PRIx32 " api=%" PRIx32
285 " hash=" HWADDR_FMT_plx "\n", ppc_hash32_hpt_base(cpu),
286 ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash);
287 pteg_off = get_pteg_offset32(cpu, ~hash);
288 pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte);
289 }
290
291 return pte_offset;
292 }
293
ppc_hash32_xlate(PowerPCCPU * cpu,vaddr eaddr,MMUAccessType access_type,hwaddr * raddrp,int * psizep,int * protp,int mmu_idx,bool guest_visible)294 bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
295 hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
296 bool guest_visible)
297 {
298 CPUState *cs = CPU(cpu);
299 CPUPPCState *env = &cpu->env;
300 target_ulong sr;
301 hwaddr pte_offset, raddr;
302 ppc_hash_pte32_t pte;
303 bool key;
304 int prot;
305
306 /* There are no hash32 large pages. */
307 *psizep = TARGET_PAGE_BITS;
308
309 /* 1. Handle real mode accesses */
310 if (mmuidx_real(mmu_idx)) {
311 /* Translation is off */
312 *raddrp = eaddr;
313 *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
314 return true;
315 }
316
317 /* 2. Check Block Address Translation entries (BATs) */
318 if (env->nb_BATs != 0) {
319 raddr = ppc_hash32_bat_lookup(cpu, eaddr, access_type, protp, mmu_idx);
320 if (raddr != -1) {
321 if (!check_prot_access_type(*protp, access_type)) {
322 if (guest_visible) {
323 if (access_type == MMU_INST_FETCH) {
324 cs->exception_index = POWERPC_EXCP_ISI;
325 env->error_code = 0x08000000;
326 } else {
327 cs->exception_index = POWERPC_EXCP_DSI;
328 env->error_code = 0;
329 env->spr[SPR_DAR] = eaddr;
330 if (access_type == MMU_DATA_STORE) {
331 env->spr[SPR_DSISR] = 0x0a000000;
332 } else {
333 env->spr[SPR_DSISR] = 0x08000000;
334 }
335 }
336 }
337 return false;
338 }
339 *raddrp = raddr;
340 return true;
341 }
342 }
343
344 /* 3. Look up the Segment Register */
345 sr = env->sr[eaddr >> 28];
346
347 /* 4. Handle direct store segments */
348 if (sr & SR32_T) {
349 return ppc_hash32_direct_store(cpu, sr, eaddr, access_type,
350 raddrp, protp, mmu_idx, guest_visible);
351 }
352
353 /* 5. Check for segment level no-execute violation */
354 if (access_type == MMU_INST_FETCH && (sr & SR32_NX)) {
355 if (guest_visible) {
356 cs->exception_index = POWERPC_EXCP_ISI;
357 env->error_code = 0x10000000;
358 }
359 return false;
360 }
361
362 /* 6. Locate the PTE in the hash table */
363 pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte);
364 if (pte_offset == -1) {
365 if (guest_visible) {
366 if (access_type == MMU_INST_FETCH) {
367 cs->exception_index = POWERPC_EXCP_ISI;
368 env->error_code = 0x40000000;
369 } else {
370 cs->exception_index = POWERPC_EXCP_DSI;
371 env->error_code = 0;
372 env->spr[SPR_DAR] = eaddr;
373 if (access_type == MMU_DATA_STORE) {
374 env->spr[SPR_DSISR] = 0x42000000;
375 } else {
376 env->spr[SPR_DSISR] = 0x40000000;
377 }
378 }
379 }
380 return false;
381 }
382 qemu_log_mask(CPU_LOG_MMU,
383 "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
384
385 /* 7. Check access permissions */
386 key = ppc_hash32_key(mmuidx_pr(mmu_idx), sr);
387 prot = ppc_hash32_prot(key, pte.pte1 & HPTE32_R_PP, sr & SR32_NX);
388
389 if (!check_prot_access_type(prot, access_type)) {
390 /* Access right violation */
391 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
392 if (guest_visible) {
393 if (access_type == MMU_INST_FETCH) {
394 cs->exception_index = POWERPC_EXCP_ISI;
395 env->error_code = 0x08000000;
396 } else {
397 cs->exception_index = POWERPC_EXCP_DSI;
398 env->error_code = 0;
399 env->spr[SPR_DAR] = eaddr;
400 if (access_type == MMU_DATA_STORE) {
401 env->spr[SPR_DSISR] = 0x0a000000;
402 } else {
403 env->spr[SPR_DSISR] = 0x08000000;
404 }
405 }
406 }
407 return false;
408 }
409
410 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
411
412 /* 8. Update PTE referenced and changed bits if necessary */
413
414 if (!(pte.pte1 & HPTE32_R_R)) {
415 ppc_hash32_set_r(cpu, pte_offset, pte.pte1);
416 }
417 if (!(pte.pte1 & HPTE32_R_C)) {
418 if (access_type == MMU_DATA_STORE) {
419 ppc_hash32_set_c(cpu, pte_offset, pte.pte1);
420 } else {
421 /*
422 * Treat the page as read-only for now, so that a later write
423 * will pass through this function again to set the C bit
424 */
425 prot &= ~PAGE_WRITE;
426 }
427 }
428 *protp = prot;
429
430 /* 9. Determine the real address from the PTE */
431 *raddrp = pte.pte1 & HPTE32_R_RPN;
432 *raddrp &= TARGET_PAGE_MASK;
433 *raddrp |= eaddr & ~TARGET_PAGE_MASK;
434 return true;
435 }
436