xref: /openbmc/qemu/target/ppc/mmu-hash32.c (revision 3ae8a100)
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 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/helper-proto.h"
25 #include "sysemu/kvm.h"
26 #include "kvm_ppc.h"
27 #include "mmu-hash32.h"
28 #include "exec/log.h"
29 
30 //#define DEBUG_BAT
31 
32 #ifdef DEBUG_BATS
33 #  define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
34 #else
35 #  define LOG_BATS(...) do { } while (0)
36 #endif
37 
38 struct mmu_ctx_hash32 {
39     hwaddr raddr;      /* Real address              */
40     int prot;                      /* Protection bits           */
41     int key;                       /* Access key                */
42 };
43 
44 static int ppc_hash32_pp_prot(int key, int pp, int nx)
45 {
46     int prot;
47 
48     if (key == 0) {
49         switch (pp) {
50         case 0x0:
51         case 0x1:
52         case 0x2:
53             prot = PAGE_READ | PAGE_WRITE;
54             break;
55 
56         case 0x3:
57             prot = PAGE_READ;
58             break;
59 
60         default:
61             abort();
62         }
63     } else {
64         switch (pp) {
65         case 0x0:
66             prot = 0;
67             break;
68 
69         case 0x1:
70         case 0x3:
71             prot = PAGE_READ;
72             break;
73 
74         case 0x2:
75             prot = PAGE_READ | PAGE_WRITE;
76             break;
77 
78         default:
79             abort();
80         }
81     }
82     if (nx == 0) {
83         prot |= PAGE_EXEC;
84     }
85 
86     return prot;
87 }
88 
89 static int ppc_hash32_pte_prot(PowerPCCPU *cpu,
90                                target_ulong sr, ppc_hash_pte32_t pte)
91 {
92     CPUPPCState *env = &cpu->env;
93     unsigned pp, key;
94 
95     key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS));
96     pp = pte.pte1 & HPTE32_R_PP;
97 
98     return ppc_hash32_pp_prot(key, pp, !!(sr & SR32_NX));
99 }
100 
101 static target_ulong hash32_bat_size(PowerPCCPU *cpu,
102                                     target_ulong batu, target_ulong batl)
103 {
104     CPUPPCState *env = &cpu->env;
105 
106     if ((msr_pr && !(batu & BATU32_VP))
107         || (!msr_pr && !(batu & BATU32_VS))) {
108         return 0;
109     }
110 
111     return BATU32_BEPI & ~((batu & BATU32_BL) << 15);
112 }
113 
114 static int hash32_bat_prot(PowerPCCPU *cpu,
115                            target_ulong batu, target_ulong batl)
116 {
117     int pp, prot;
118 
119     prot = 0;
120     pp = batl & BATL32_PP;
121     if (pp != 0) {
122         prot = PAGE_READ | PAGE_EXEC;
123         if (pp == 0x2) {
124             prot |= PAGE_WRITE;
125         }
126     }
127     return prot;
128 }
129 
130 static target_ulong hash32_bat_601_size(PowerPCCPU *cpu,
131                                 target_ulong batu, target_ulong batl)
132 {
133     if (!(batl & BATL32_601_V)) {
134         return 0;
135     }
136 
137     return BATU32_BEPI & ~((batl & BATL32_601_BL) << 17);
138 }
139 
140 static int hash32_bat_601_prot(PowerPCCPU *cpu,
141                                target_ulong batu, target_ulong batl)
142 {
143     CPUPPCState *env = &cpu->env;
144     int key, pp;
145 
146     pp = batu & BATU32_601_PP;
147     if (msr_pr == 0) {
148         key = !!(batu & BATU32_601_KS);
149     } else {
150         key = !!(batu & BATU32_601_KP);
151     }
152     return ppc_hash32_pp_prot(key, pp, 0);
153 }
154 
155 static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea, int rwx,
156                                     int *prot)
157 {
158     CPUPPCState *env = &cpu->env;
159     target_ulong *BATlt, *BATut;
160     int i;
161 
162     LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
163              rwx == 2 ? 'I' : 'D', ea);
164     if (rwx == 2) {
165         BATlt = env->IBAT[1];
166         BATut = env->IBAT[0];
167     } else {
168         BATlt = env->DBAT[1];
169         BATut = env->DBAT[0];
170     }
171     for (i = 0; i < env->nb_BATs; i++) {
172         target_ulong batu = BATut[i];
173         target_ulong batl = BATlt[i];
174         target_ulong mask;
175 
176         if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
177             mask = hash32_bat_601_size(cpu, batu, batl);
178         } else {
179             mask = hash32_bat_size(cpu, batu, batl);
180         }
181         LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
182                  " BATl " TARGET_FMT_lx "\n", __func__,
183                  type == ACCESS_CODE ? 'I' : 'D', i, ea, batu, batl);
184 
185         if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
186             hwaddr raddr = (batl & mask) | (ea & ~mask);
187 
188             if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
189                 *prot = hash32_bat_601_prot(cpu, batu, batl);
190             } else {
191                 *prot = hash32_bat_prot(cpu, batu, batl);
192             }
193 
194             return raddr & TARGET_PAGE_MASK;
195         }
196     }
197 
198     /* No hit */
199 #if defined(DEBUG_BATS)
200     if (qemu_log_enabled()) {
201         LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", ea);
202         for (i = 0; i < 4; i++) {
203             BATu = &BATut[i];
204             BATl = &BATlt[i];
205             BEPIu = *BATu & BATU32_BEPIU;
206             BEPIl = *BATu & BATU32_BEPIL;
207             bl = (*BATu & 0x00001FFC) << 15;
208             LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
209                      " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
210                      TARGET_FMT_lx " " TARGET_FMT_lx "\n",
211                      __func__, type == ACCESS_CODE ? 'I' : 'D', i, ea,
212                      *BATu, *BATl, BEPIu, BEPIl, bl);
213         }
214     }
215 #endif
216 
217     return -1;
218 }
219 
220 static int ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
221                                    target_ulong eaddr, int rwx,
222                                    hwaddr *raddr, int *prot)
223 {
224     CPUState *cs = CPU(cpu);
225     CPUPPCState *env = &cpu->env;
226     int key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS));
227 
228     qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
229 
230     if ((sr & 0x1FF00000) >> 20 == 0x07f) {
231         /* Memory-forced I/O controller interface access */
232         /* If T=1 and BUID=x'07F', the 601 performs a memory access
233          * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
234          */
235         *raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
236         *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
237         return 0;
238     }
239 
240     if (rwx == 2) {
241         /* No code fetch is allowed in direct-store areas */
242         cs->exception_index = POWERPC_EXCP_ISI;
243         env->error_code = 0x10000000;
244         return 1;
245     }
246 
247     switch (env->access_type) {
248     case ACCESS_INT:
249         /* Integer load/store : only access allowed */
250         break;
251     case ACCESS_FLOAT:
252         /* Floating point load/store */
253         cs->exception_index = POWERPC_EXCP_ALIGN;
254         env->error_code = POWERPC_EXCP_ALIGN_FP;
255         env->spr[SPR_DAR] = eaddr;
256         return 1;
257     case ACCESS_RES:
258         /* lwarx, ldarx or srwcx. */
259         env->error_code = 0;
260         env->spr[SPR_DAR] = eaddr;
261         if (rwx == 1) {
262             env->spr[SPR_DSISR] = 0x06000000;
263         } else {
264             env->spr[SPR_DSISR] = 0x04000000;
265         }
266         return 1;
267     case ACCESS_CACHE:
268         /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
269         /* Should make the instruction do no-op.
270          * As it already do no-op, it's quite easy :-)
271          */
272         *raddr = eaddr;
273         return 0;
274     case ACCESS_EXT:
275         /* eciwx or ecowx */
276         cs->exception_index = POWERPC_EXCP_DSI;
277         env->error_code = 0;
278         env->spr[SPR_DAR] = eaddr;
279         if (rwx == 1) {
280             env->spr[SPR_DSISR] = 0x06100000;
281         } else {
282             env->spr[SPR_DSISR] = 0x04100000;
283         }
284         return 1;
285     default:
286         cpu_abort(cs, "ERROR: instruction should not need "
287                  "address translation\n");
288     }
289     if ((rwx == 1 || key != 1) && (rwx == 0 || key != 0)) {
290         *raddr = eaddr;
291         return 0;
292     } else {
293         cs->exception_index = POWERPC_EXCP_DSI;
294         env->error_code = 0;
295         env->spr[SPR_DAR] = eaddr;
296         if (rwx == 1) {
297             env->spr[SPR_DSISR] = 0x0a000000;
298         } else {
299             env->spr[SPR_DSISR] = 0x08000000;
300         }
301         return 1;
302     }
303 }
304 
305 hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash)
306 {
307     target_ulong mask = ppc_hash32_hpt_mask(cpu);
308 
309     return (hash * HASH_PTEG_SIZE_32) & mask;
310 }
311 
312 static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off,
313                                      bool secondary, target_ulong ptem,
314                                      ppc_hash_pte32_t *pte)
315 {
316     hwaddr pte_offset = pteg_off;
317     target_ulong pte0, pte1;
318     int i;
319 
320     for (i = 0; i < HPTES_PER_GROUP; i++) {
321         pte0 = ppc_hash32_load_hpte0(cpu, pte_offset);
322         pte1 = ppc_hash32_load_hpte1(cpu, pte_offset);
323 
324         if ((pte0 & HPTE32_V_VALID)
325             && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
326             && HPTE32_V_COMPARE(pte0, ptem)) {
327             pte->pte0 = pte0;
328             pte->pte1 = pte1;
329             return pte_offset;
330         }
331 
332         pte_offset += HASH_PTE_SIZE_32;
333     }
334 
335     return -1;
336 }
337 
338 static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
339                                      target_ulong sr, target_ulong eaddr,
340                                      ppc_hash_pte32_t *pte)
341 {
342     hwaddr pteg_off, pte_offset;
343     hwaddr hash;
344     uint32_t vsid, pgidx, ptem;
345 
346     vsid = sr & SR32_VSID;
347     pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
348     hash = vsid ^ pgidx;
349     ptem = (vsid << 7) | (pgidx >> 10);
350 
351     /* Page address translation */
352     qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
353             " htab_mask " TARGET_FMT_plx
354             " hash " TARGET_FMT_plx "\n",
355             ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
356 
357     /* Primary PTEG lookup */
358     qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
359             " vsid=%" PRIx32 " ptem=%" PRIx32
360             " hash=" TARGET_FMT_plx "\n",
361             ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
362             vsid, ptem, hash);
363     pteg_off = get_pteg_offset32(cpu, hash);
364     pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte);
365     if (pte_offset == -1) {
366         /* Secondary PTEG lookup */
367         qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
368                 " vsid=%" PRIx32 " api=%" PRIx32
369                 " hash=" TARGET_FMT_plx "\n", ppc_hash32_hpt_base(cpu),
370                 ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash);
371         pteg_off = get_pteg_offset32(cpu, ~hash);
372         pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte);
373     }
374 
375     return pte_offset;
376 }
377 
378 static hwaddr ppc_hash32_pte_raddr(target_ulong sr, ppc_hash_pte32_t pte,
379                                    target_ulong eaddr)
380 {
381     hwaddr rpn = pte.pte1 & HPTE32_R_RPN;
382     hwaddr mask = ~TARGET_PAGE_MASK;
383 
384     return (rpn & ~mask) | (eaddr & mask);
385 }
386 
387 int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
388                                 int mmu_idx)
389 {
390     CPUState *cs = CPU(cpu);
391     CPUPPCState *env = &cpu->env;
392     target_ulong sr;
393     hwaddr pte_offset;
394     ppc_hash_pte32_t pte;
395     int prot;
396     uint32_t new_pte1;
397     const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
398     hwaddr raddr;
399 
400     assert((rwx == 0) || (rwx == 1) || (rwx == 2));
401 
402     /* 1. Handle real mode accesses */
403     if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
404         /* Translation is off */
405         raddr = eaddr;
406         tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
407                      PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
408                      TARGET_PAGE_SIZE);
409         return 0;
410     }
411 
412     /* 2. Check Block Address Translation entries (BATs) */
413     if (env->nb_BATs != 0) {
414         raddr = ppc_hash32_bat_lookup(cpu, eaddr, rwx, &prot);
415         if (raddr != -1) {
416             if (need_prot[rwx] & ~prot) {
417                 if (rwx == 2) {
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 (rwx == 1) {
425                         env->spr[SPR_DSISR] = 0x0a000000;
426                     } else {
427                         env->spr[SPR_DSISR] = 0x08000000;
428                     }
429                 }
430                 return 1;
431             }
432 
433             tlb_set_page(cs, eaddr & TARGET_PAGE_MASK,
434                          raddr & TARGET_PAGE_MASK, prot, mmu_idx,
435                          TARGET_PAGE_SIZE);
436             return 0;
437         }
438     }
439 
440     /* 3. Look up the Segment Register */
441     sr = env->sr[eaddr >> 28];
442 
443     /* 4. Handle direct store segments */
444     if (sr & SR32_T) {
445         if (ppc_hash32_direct_store(cpu, sr, eaddr, rwx,
446                                     &raddr, &prot) == 0) {
447             tlb_set_page(cs, eaddr & TARGET_PAGE_MASK,
448                          raddr & TARGET_PAGE_MASK, prot, mmu_idx,
449                          TARGET_PAGE_SIZE);
450             return 0;
451         } else {
452             return 1;
453         }
454     }
455 
456     /* 5. Check for segment level no-execute violation */
457     if ((rwx == 2) && (sr & SR32_NX)) {
458         cs->exception_index = POWERPC_EXCP_ISI;
459         env->error_code = 0x10000000;
460         return 1;
461     }
462 
463     /* 6. Locate the PTE in the hash table */
464     pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte);
465     if (pte_offset == -1) {
466         if (rwx == 2) {
467             cs->exception_index = POWERPC_EXCP_ISI;
468             env->error_code = 0x40000000;
469         } else {
470             cs->exception_index = POWERPC_EXCP_DSI;
471             env->error_code = 0;
472             env->spr[SPR_DAR] = eaddr;
473             if (rwx == 1) {
474                 env->spr[SPR_DSISR] = 0x42000000;
475             } else {
476                 env->spr[SPR_DSISR] = 0x40000000;
477             }
478         }
479 
480         return 1;
481     }
482     qemu_log_mask(CPU_LOG_MMU,
483                 "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
484 
485     /* 7. Check access permissions */
486 
487     prot = ppc_hash32_pte_prot(cpu, sr, pte);
488 
489     if (need_prot[rwx] & ~prot) {
490         /* Access right violation */
491         qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
492         if (rwx == 2) {
493             cs->exception_index = POWERPC_EXCP_ISI;
494             env->error_code = 0x08000000;
495         } else {
496             cs->exception_index = POWERPC_EXCP_DSI;
497             env->error_code = 0;
498             env->spr[SPR_DAR] = eaddr;
499             if (rwx == 1) {
500                 env->spr[SPR_DSISR] = 0x0a000000;
501             } else {
502                 env->spr[SPR_DSISR] = 0x08000000;
503             }
504         }
505         return 1;
506     }
507 
508     qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
509 
510     /* 8. Update PTE referenced and changed bits if necessary */
511 
512     new_pte1 = pte.pte1 | HPTE32_R_R; /* set referenced bit */
513     if (rwx == 1) {
514         new_pte1 |= HPTE32_R_C; /* set changed (dirty) bit */
515     } else {
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         prot &= ~PAGE_WRITE;
519     }
520 
521     if (new_pte1 != pte.pte1) {
522         ppc_hash32_store_hpte1(cpu, pte_offset, new_pte1);
523     }
524 
525     /* 9. Determine the real address from the PTE */
526 
527     raddr = ppc_hash32_pte_raddr(sr, pte, eaddr);
528 
529     tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
530                  prot, mmu_idx, TARGET_PAGE_SIZE);
531 
532     return 0;
533 }
534 
535 hwaddr ppc_hash32_get_phys_page_debug(PowerPCCPU *cpu, target_ulong eaddr)
536 {
537     CPUPPCState *env = &cpu->env;
538     target_ulong sr;
539     hwaddr pte_offset;
540     ppc_hash_pte32_t pte;
541     int prot;
542 
543     if (msr_dr == 0) {
544         /* Translation is off */
545         return eaddr;
546     }
547 
548     if (env->nb_BATs != 0) {
549         hwaddr raddr = ppc_hash32_bat_lookup(cpu, eaddr, 0, &prot);
550         if (raddr != -1) {
551             return raddr;
552         }
553     }
554 
555     sr = env->sr[eaddr >> 28];
556 
557     if (sr & SR32_T) {
558         /* FIXME: Add suitable debug support for Direct Store segments */
559         return -1;
560     }
561 
562     pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte);
563     if (pte_offset == -1) {
564         return -1;
565     }
566 
567     return ppc_hash32_pte_raddr(sr, pte, eaddr) & TARGET_PAGE_MASK;
568 }
569