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