xref: /openbmc/qemu/target/ppc/mmu-hash32.c (revision 99d46107)
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         /*
323          * pte0 contains the valid bit and must be read before pte1,
324          * otherwise we might see an old pte1 with a new valid bit and
325          * thus an inconsistent hpte value
326          */
327         smp_rmb();
328         pte1 = ppc_hash32_load_hpte1(cpu, pte_offset);
329 
330         if ((pte0 & HPTE32_V_VALID)
331             && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
332             && HPTE32_V_COMPARE(pte0, ptem)) {
333             pte->pte0 = pte0;
334             pte->pte1 = pte1;
335             return pte_offset;
336         }
337 
338         pte_offset += HASH_PTE_SIZE_32;
339     }
340 
341     return -1;
342 }
343 
344 static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
345                                      target_ulong sr, target_ulong eaddr,
346                                      ppc_hash_pte32_t *pte)
347 {
348     hwaddr pteg_off, pte_offset;
349     hwaddr hash;
350     uint32_t vsid, pgidx, ptem;
351 
352     vsid = sr & SR32_VSID;
353     pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
354     hash = vsid ^ pgidx;
355     ptem = (vsid << 7) | (pgidx >> 10);
356 
357     /* Page address translation */
358     qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
359             " htab_mask " TARGET_FMT_plx
360             " hash " TARGET_FMT_plx "\n",
361             ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
362 
363     /* Primary PTEG lookup */
364     qemu_log_mask(CPU_LOG_MMU, "0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
365             " vsid=%" PRIx32 " ptem=%" PRIx32
366             " hash=" TARGET_FMT_plx "\n",
367             ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
368             vsid, ptem, hash);
369     pteg_off = get_pteg_offset32(cpu, hash);
370     pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte);
371     if (pte_offset == -1) {
372         /* Secondary PTEG lookup */
373         qemu_log_mask(CPU_LOG_MMU, "1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
374                 " vsid=%" PRIx32 " api=%" PRIx32
375                 " hash=" TARGET_FMT_plx "\n", ppc_hash32_hpt_base(cpu),
376                 ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash);
377         pteg_off = get_pteg_offset32(cpu, ~hash);
378         pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte);
379     }
380 
381     return pte_offset;
382 }
383 
384 static hwaddr ppc_hash32_pte_raddr(target_ulong sr, ppc_hash_pte32_t pte,
385                                    target_ulong eaddr)
386 {
387     hwaddr rpn = pte.pte1 & HPTE32_R_RPN;
388     hwaddr mask = ~TARGET_PAGE_MASK;
389 
390     return (rpn & ~mask) | (eaddr & mask);
391 }
392 
393 int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
394                                 int mmu_idx)
395 {
396     CPUState *cs = CPU(cpu);
397     CPUPPCState *env = &cpu->env;
398     target_ulong sr;
399     hwaddr pte_offset;
400     ppc_hash_pte32_t pte;
401     int prot;
402     uint32_t new_pte1;
403     const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC};
404     hwaddr raddr;
405 
406     assert((rwx == 0) || (rwx == 1) || (rwx == 2));
407 
408     /* 1. Handle real mode accesses */
409     if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
410         /* Translation is off */
411         raddr = eaddr;
412         tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
413                      PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx,
414                      TARGET_PAGE_SIZE);
415         return 0;
416     }
417 
418     /* 2. Check Block Address Translation entries (BATs) */
419     if (env->nb_BATs != 0) {
420         raddr = ppc_hash32_bat_lookup(cpu, eaddr, rwx, &prot);
421         if (raddr != -1) {
422             if (need_prot[rwx] & ~prot) {
423                 if (rwx == 2) {
424                     cs->exception_index = POWERPC_EXCP_ISI;
425                     env->error_code = 0x08000000;
426                 } else {
427                     cs->exception_index = POWERPC_EXCP_DSI;
428                     env->error_code = 0;
429                     env->spr[SPR_DAR] = eaddr;
430                     if (rwx == 1) {
431                         env->spr[SPR_DSISR] = 0x0a000000;
432                     } else {
433                         env->spr[SPR_DSISR] = 0x08000000;
434                     }
435                 }
436                 return 1;
437             }
438 
439             tlb_set_page(cs, eaddr & TARGET_PAGE_MASK,
440                          raddr & TARGET_PAGE_MASK, prot, mmu_idx,
441                          TARGET_PAGE_SIZE);
442             return 0;
443         }
444     }
445 
446     /* 3. Look up the Segment Register */
447     sr = env->sr[eaddr >> 28];
448 
449     /* 4. Handle direct store segments */
450     if (sr & SR32_T) {
451         if (ppc_hash32_direct_store(cpu, sr, eaddr, rwx,
452                                     &raddr, &prot) == 0) {
453             tlb_set_page(cs, eaddr & TARGET_PAGE_MASK,
454                          raddr & TARGET_PAGE_MASK, prot, mmu_idx,
455                          TARGET_PAGE_SIZE);
456             return 0;
457         } else {
458             return 1;
459         }
460     }
461 
462     /* 5. Check for segment level no-execute violation */
463     if ((rwx == 2) && (sr & SR32_NX)) {
464         cs->exception_index = POWERPC_EXCP_ISI;
465         env->error_code = 0x10000000;
466         return 1;
467     }
468 
469     /* 6. Locate the PTE in the hash table */
470     pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte);
471     if (pte_offset == -1) {
472         if (rwx == 2) {
473             cs->exception_index = POWERPC_EXCP_ISI;
474             env->error_code = 0x40000000;
475         } else {
476             cs->exception_index = POWERPC_EXCP_DSI;
477             env->error_code = 0;
478             env->spr[SPR_DAR] = eaddr;
479             if (rwx == 1) {
480                 env->spr[SPR_DSISR] = 0x42000000;
481             } else {
482                 env->spr[SPR_DSISR] = 0x40000000;
483             }
484         }
485 
486         return 1;
487     }
488     qemu_log_mask(CPU_LOG_MMU,
489                 "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
490 
491     /* 7. Check access permissions */
492 
493     prot = ppc_hash32_pte_prot(cpu, sr, pte);
494 
495     if (need_prot[rwx] & ~prot) {
496         /* Access right violation */
497         qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
498         if (rwx == 2) {
499             cs->exception_index = POWERPC_EXCP_ISI;
500             env->error_code = 0x08000000;
501         } else {
502             cs->exception_index = POWERPC_EXCP_DSI;
503             env->error_code = 0;
504             env->spr[SPR_DAR] = eaddr;
505             if (rwx == 1) {
506                 env->spr[SPR_DSISR] = 0x0a000000;
507             } else {
508                 env->spr[SPR_DSISR] = 0x08000000;
509             }
510         }
511         return 1;
512     }
513 
514     qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
515 
516     /* 8. Update PTE referenced and changed bits if necessary */
517 
518     new_pte1 = pte.pte1 | HPTE32_R_R; /* set referenced bit */
519     if (rwx == 1) {
520         new_pte1 |= HPTE32_R_C; /* set changed (dirty) bit */
521     } else {
522         /* Treat the page as read-only for now, so that a later write
523          * will pass through this function again to set the C bit */
524         prot &= ~PAGE_WRITE;
525     }
526 
527     if (new_pte1 != pte.pte1) {
528         ppc_hash32_store_hpte1(cpu, pte_offset, new_pte1);
529     }
530 
531     /* 9. Determine the real address from the PTE */
532 
533     raddr = ppc_hash32_pte_raddr(sr, pte, eaddr);
534 
535     tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK,
536                  prot, mmu_idx, TARGET_PAGE_SIZE);
537 
538     return 0;
539 }
540 
541 hwaddr ppc_hash32_get_phys_page_debug(PowerPCCPU *cpu, target_ulong eaddr)
542 {
543     CPUPPCState *env = &cpu->env;
544     target_ulong sr;
545     hwaddr pte_offset;
546     ppc_hash_pte32_t pte;
547     int prot;
548 
549     if (msr_dr == 0) {
550         /* Translation is off */
551         return eaddr;
552     }
553 
554     if (env->nb_BATs != 0) {
555         hwaddr raddr = ppc_hash32_bat_lookup(cpu, eaddr, 0, &prot);
556         if (raddr != -1) {
557             return raddr;
558         }
559     }
560 
561     sr = env->sr[eaddr >> 28];
562 
563     if (sr & SR32_T) {
564         /* FIXME: Add suitable debug support for Direct Store segments */
565         return -1;
566     }
567 
568     pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte);
569     if (pte_offset == -1) {
570         return -1;
571     }
572 
573     return ppc_hash32_pte_raddr(sr, pte, eaddr) & TARGET_PAGE_MASK;
574 }
575