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