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