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