xref: /qemu/target/ppc/mmu-hash32.c (revision 7cef6d686309e2792186504ae17cf4f3eb57ef68)
19d7c3f4aSDavid Gibson /*
29d7c3f4aSDavid Gibson  *  PowerPC MMU, TLB and BAT emulation helpers for QEMU.
39d7c3f4aSDavid Gibson  *
49d7c3f4aSDavid Gibson  *  Copyright (c) 2003-2007 Jocelyn Mayer
59d7c3f4aSDavid Gibson  *  Copyright (c) 2013 David Gibson, IBM Corporation
69d7c3f4aSDavid Gibson  *
79d7c3f4aSDavid Gibson  * This library is free software; you can redistribute it and/or
89d7c3f4aSDavid Gibson  * modify it under the terms of the GNU Lesser General Public
99d7c3f4aSDavid Gibson  * License as published by the Free Software Foundation; either
106bd039cdSChetan Pant  * version 2.1 of the License, or (at your option) any later version.
119d7c3f4aSDavid Gibson  *
129d7c3f4aSDavid Gibson  * This library is distributed in the hope that it will be useful,
139d7c3f4aSDavid Gibson  * but WITHOUT ANY WARRANTY; without even the implied warranty of
149d7c3f4aSDavid Gibson  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
159d7c3f4aSDavid Gibson  * Lesser General Public License for more details.
169d7c3f4aSDavid Gibson  *
179d7c3f4aSDavid Gibson  * You should have received a copy of the GNU Lesser General Public
189d7c3f4aSDavid Gibson  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
199d7c3f4aSDavid Gibson  */
209d7c3f4aSDavid Gibson 
210d75590dSPeter Maydell #include "qemu/osdep.h"
229d7c3f4aSDavid Gibson #include "cpu.h"
2374781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h"
24*9c2ff9cdSPierrick Bouvier #include "exec/target_page.h"
2532cad1ffSPhilippe Mathieu-Daudé #include "system/kvm.h"
269d7c3f4aSDavid Gibson #include "kvm_ppc.h"
27182357dbSRichard Henderson #include "internal.h"
289d7c3f4aSDavid Gibson #include "mmu-hash32.h"
29d423baf9SBruno Larsen (billionai) #include "mmu-books.h"
30508127e2SPaolo Bonzini #include "exec/log.h"
319d7c3f4aSDavid Gibson 
32ba1b5df0SFabiano Rosas /* #define DEBUG_BATS */
339d7c3f4aSDavid Gibson 
3498132796SDavid Gibson #ifdef DEBUG_BATS
3548880da6SPaolo Bonzini #  define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
3698132796SDavid Gibson #else
3798132796SDavid Gibson #  define LOG_BATS(...) do { } while (0)
3898132796SDavid Gibson #endif
3998132796SDavid Gibson 
hash32_bat_size(int mmu_idx,target_ulong batu,target_ulong batl)40d423baf9SBruno Larsen (billionai) static target_ulong hash32_bat_size(int mmu_idx,
419986ed1eSDavid Gibson                                     target_ulong batu, target_ulong batl)
4298132796SDavid Gibson {
43d423baf9SBruno Larsen (billionai)     if ((mmuidx_pr(mmu_idx) && !(batu & BATU32_VP))
44d423baf9SBruno Larsen (billionai)         || (!mmuidx_pr(mmu_idx) && !(batu & BATU32_VS))) {
456fc76aa9SDavid Gibson         return 0;
46e1d49515SDavid Gibson     }
476fc76aa9SDavid Gibson 
486fc76aa9SDavid Gibson     return BATU32_BEPI & ~((batu & BATU32_BL) << 15);
49e1d49515SDavid Gibson }
50e1d49515SDavid Gibson 
ppc_hash32_bat_lookup(PowerPCCPU * cpu,target_ulong ea,MMUAccessType access_type,int * prot,int mmu_idx)5131fa64ecSRichard Henderson static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea,
52d423baf9SBruno Larsen (billionai)                                     MMUAccessType access_type, int *prot,
53d423baf9SBruno Larsen (billionai)                                     int mmu_idx)
5498132796SDavid Gibson {
557ef23068SDavid Gibson     CPUPPCState *env = &cpu->env;
569986ed1eSDavid Gibson     target_ulong *BATlt, *BATut;
5731fa64ecSRichard Henderson     bool ifetch = access_type == MMU_INST_FETCH;
58145e52f3SDavid Gibson     int i;
5998132796SDavid Gibson 
6098132796SDavid Gibson     LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
6131fa64ecSRichard Henderson              ifetch ? 'I' : 'D', ea);
6231fa64ecSRichard Henderson     if (ifetch) {
6398132796SDavid Gibson         BATlt = env->IBAT[1];
6498132796SDavid Gibson         BATut = env->IBAT[0];
6591cda45bSDavid Gibson     } else {
6698132796SDavid Gibson         BATlt = env->DBAT[1];
6798132796SDavid Gibson         BATut = env->DBAT[0];
6898132796SDavid Gibson     }
6998132796SDavid Gibson     for (i = 0; i < env->nb_BATs; i++) {
709986ed1eSDavid Gibson         target_ulong batu = BATut[i];
719986ed1eSDavid Gibson         target_ulong batl = BATlt[i];
726fc76aa9SDavid Gibson         target_ulong mask;
739986ed1eSDavid Gibson 
74d423baf9SBruno Larsen (billionai)         mask = hash32_bat_size(mmu_idx, batu, batl);
7598132796SDavid Gibson         LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
7698132796SDavid Gibson                  " BATl " TARGET_FMT_lx "\n", __func__,
7731fa64ecSRichard Henderson                  ifetch ? 'I' : 'D', i, ea, batu, batl);
786fc76aa9SDavid Gibson 
79145e52f3SDavid Gibson         if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
80145e52f3SDavid Gibson             hwaddr raddr = (batl & mask) | (ea & ~mask);
81145e52f3SDavid Gibson 
82d3233386SBALATON Zoltan             *prot = ppc_hash32_bat_prot(batu, batl);
83145e52f3SDavid Gibson 
84145e52f3SDavid Gibson             return raddr & TARGET_PAGE_MASK;
8598132796SDavid Gibson         }
8698132796SDavid Gibson     }
87145e52f3SDavid Gibson 
88145e52f3SDavid Gibson     /* No hit */
8998132796SDavid Gibson #if defined(DEBUG_BATS)
9098132796SDavid Gibson     if (qemu_log_enabled()) {
91ba1b5df0SFabiano Rosas         target_ulong *BATu, *BATl;
92ba1b5df0SFabiano Rosas         target_ulong BEPIl, BEPIu, bl;
93ba1b5df0SFabiano Rosas 
94145e52f3SDavid Gibson         LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", ea);
9598132796SDavid Gibson         for (i = 0; i < 4; i++) {
9698132796SDavid Gibson             BATu = &BATut[i];
9798132796SDavid Gibson             BATl = &BATlt[i];
98d5aea6f3SDavid Gibson             BEPIu = *BATu & BATU32_BEPIU;
99d5aea6f3SDavid Gibson             BEPIl = *BATu & BATU32_BEPIL;
10098132796SDavid Gibson             bl = (*BATu & 0x00001FFC) << 15;
10198132796SDavid Gibson             LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
10298132796SDavid Gibson                      " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
10398132796SDavid Gibson                      TARGET_FMT_lx " " TARGET_FMT_lx "\n",
10431fa64ecSRichard Henderson                      __func__, ifetch ? 'I' : 'D', i, ea,
10598132796SDavid Gibson                      *BATu, *BATl, BEPIu, BEPIl, bl);
10698132796SDavid Gibson         }
10798132796SDavid Gibson     }
10898132796SDavid Gibson #endif
109145e52f3SDavid Gibson 
110145e52f3SDavid Gibson     return -1;
11198132796SDavid Gibson }
11298132796SDavid Gibson 
ppc_hash32_direct_store(PowerPCCPU * cpu,target_ulong sr,target_ulong eaddr,MMUAccessType access_type,hwaddr * raddr,int * prot,int mmu_idx,bool guest_visible)1136c3c873cSRichard Henderson static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
11431fa64ecSRichard Henderson                                     target_ulong eaddr,
11531fa64ecSRichard Henderson                                     MMUAccessType access_type,
116d423baf9SBruno Larsen (billionai)                                     hwaddr *raddr, int *prot, int mmu_idx,
1176c3c873cSRichard Henderson                                     bool guest_visible)
118723ed73aSDavid Gibson {
1197ef23068SDavid Gibson     CPUState *cs = CPU(cpu);
1207ef23068SDavid Gibson     CPUPPCState *env = &cpu->env;
121723ed73aSDavid Gibson 
122339aaf5bSAntony Pavlov     qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
123723ed73aSDavid Gibson 
12431fa64ecSRichard Henderson     if (access_type == MMU_INST_FETCH) {
125723ed73aSDavid Gibson         /* No code fetch is allowed in direct-store areas */
1266c3c873cSRichard Henderson         if (guest_visible) {
12727103424SAndreas Färber             cs->exception_index = POWERPC_EXCP_ISI;
128caa597bdSDavid Gibson             env->error_code = 0x10000000;
1296c3c873cSRichard Henderson         }
1306c3c873cSRichard Henderson         return false;
131723ed73aSDavid Gibson     }
132723ed73aSDavid Gibson 
1336c3c873cSRichard Henderson     /*
1346c3c873cSRichard Henderson      * From ppc_cpu_get_phys_page_debug, env->access_type is not set.
1356c3c873cSRichard Henderson      * Assume ACCESS_INT for that case.
1366c3c873cSRichard Henderson      */
1376c3c873cSRichard Henderson     switch (guest_visible ? env->access_type : ACCESS_INT) {
138723ed73aSDavid Gibson     case ACCESS_INT:
139723ed73aSDavid Gibson         /* Integer load/store : only access allowed */
140723ed73aSDavid Gibson         break;
141723ed73aSDavid Gibson     case ACCESS_FLOAT:
142723ed73aSDavid Gibson         /* Floating point load/store */
14327103424SAndreas Färber         cs->exception_index = POWERPC_EXCP_ALIGN;
144caa597bdSDavid Gibson         env->error_code = POWERPC_EXCP_ALIGN_FP;
145caa597bdSDavid Gibson         env->spr[SPR_DAR] = eaddr;
1466c3c873cSRichard Henderson         return false;
147723ed73aSDavid Gibson     case ACCESS_RES:
148723ed73aSDavid Gibson         /* lwarx, ldarx or srwcx. */
149caa597bdSDavid Gibson         env->error_code = 0;
150caa597bdSDavid Gibson         env->spr[SPR_DAR] = eaddr;
15131fa64ecSRichard Henderson         if (access_type == MMU_DATA_STORE) {
152caa597bdSDavid Gibson             env->spr[SPR_DSISR] = 0x06000000;
153caa597bdSDavid Gibson         } else {
154caa597bdSDavid Gibson             env->spr[SPR_DSISR] = 0x04000000;
155caa597bdSDavid Gibson         }
1566c3c873cSRichard Henderson         return false;
157723ed73aSDavid Gibson     case ACCESS_CACHE:
158596e3ca8SDavid Gibson         /*
159596e3ca8SDavid Gibson          * dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi
160596e3ca8SDavid Gibson          *
161596e3ca8SDavid Gibson          * Should make the instruction do no-op.  As it already do
162596e3ca8SDavid Gibson          * no-op, it's quite easy :-)
163723ed73aSDavid Gibson          */
164723ed73aSDavid Gibson         *raddr = eaddr;
1656c3c873cSRichard Henderson         return true;
166723ed73aSDavid Gibson     case ACCESS_EXT:
167723ed73aSDavid Gibson         /* eciwx or ecowx */
16827103424SAndreas Färber         cs->exception_index = POWERPC_EXCP_DSI;
169caa597bdSDavid Gibson         env->error_code = 0;
170caa597bdSDavid Gibson         env->spr[SPR_DAR] = eaddr;
17131fa64ecSRichard Henderson         if (access_type == MMU_DATA_STORE) {
172caa597bdSDavid Gibson             env->spr[SPR_DSISR] = 0x06100000;
173caa597bdSDavid Gibson         } else {
174caa597bdSDavid Gibson             env->spr[SPR_DSISR] = 0x04100000;
175caa597bdSDavid Gibson         }
1766c3c873cSRichard Henderson         return false;
177723ed73aSDavid Gibson     default:
1786c3c873cSRichard Henderson         cpu_abort(cs, "ERROR: insn should not need address translation\n");
179723ed73aSDavid Gibson     }
1806c3c873cSRichard Henderson 
181719a1da1SBALATON Zoltan     if (ppc_hash32_key(mmuidx_pr(mmu_idx), sr)) {
182719a1da1SBALATON Zoltan         *prot = PAGE_READ | PAGE_WRITE;
183719a1da1SBALATON Zoltan     } else {
184719a1da1SBALATON Zoltan         *prot = PAGE_READ;
185719a1da1SBALATON Zoltan     }
186cd1038ecSBALATON Zoltan     if (check_prot_access_type(*prot, access_type)) {
187723ed73aSDavid Gibson         *raddr = eaddr;
1886c3c873cSRichard Henderson         return true;
1896c3c873cSRichard Henderson     }
1906c3c873cSRichard Henderson 
1916c3c873cSRichard Henderson     if (guest_visible) {
19227103424SAndreas Färber         cs->exception_index = POWERPC_EXCP_DSI;
193caa597bdSDavid Gibson         env->error_code = 0;
194caa597bdSDavid Gibson         env->spr[SPR_DAR] = eaddr;
19531fa64ecSRichard Henderson         if (access_type == MMU_DATA_STORE) {
196caa597bdSDavid Gibson             env->spr[SPR_DSISR] = 0x0a000000;
197caa597bdSDavid Gibson         } else {
198caa597bdSDavid Gibson             env->spr[SPR_DSISR] = 0x08000000;
199caa597bdSDavid Gibson         }
200723ed73aSDavid Gibson     }
2016c3c873cSRichard Henderson     return false;
202723ed73aSDavid Gibson }
203723ed73aSDavid Gibson 
ppc_hash32_pteg_search(PowerPCCPU * cpu,hwaddr pteg_off,bool secondary,target_ulong ptem,ppc_hash_pte32_t * pte)2047ef23068SDavid Gibson static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off,
205aea390e4SDavid Gibson                                      bool secondary, target_ulong ptem,
206aea390e4SDavid Gibson                                      ppc_hash_pte32_t *pte)
207aea390e4SDavid Gibson {
208aea390e4SDavid Gibson     hwaddr pte_offset = pteg_off;
209aea390e4SDavid Gibson     target_ulong pte0, pte1;
210aea390e4SDavid Gibson     int i;
211aea390e4SDavid Gibson 
212aea390e4SDavid Gibson     for (i = 0; i < HPTES_PER_GROUP; i++) {
2137ef23068SDavid Gibson         pte0 = ppc_hash32_load_hpte0(cpu, pte_offset);
2143054b0caSBenjamin Herrenschmidt         /*
2153054b0caSBenjamin Herrenschmidt          * pte0 contains the valid bit and must be read before pte1,
2163054b0caSBenjamin Herrenschmidt          * otherwise we might see an old pte1 with a new valid bit and
2173054b0caSBenjamin Herrenschmidt          * thus an inconsistent hpte value
2183054b0caSBenjamin Herrenschmidt          */
2193054b0caSBenjamin Herrenschmidt         smp_rmb();
2207ef23068SDavid Gibson         pte1 = ppc_hash32_load_hpte1(cpu, pte_offset);
221aea390e4SDavid Gibson 
222aea390e4SDavid Gibson         if ((pte0 & HPTE32_V_VALID)
223aea390e4SDavid Gibson             && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
224aea390e4SDavid Gibson             && HPTE32_V_COMPARE(pte0, ptem)) {
225aea390e4SDavid Gibson             pte->pte0 = pte0;
226aea390e4SDavid Gibson             pte->pte1 = pte1;
227aea390e4SDavid Gibson             return pte_offset;
228aea390e4SDavid Gibson         }
229aea390e4SDavid Gibson 
230aea390e4SDavid Gibson         pte_offset += HASH_PTE_SIZE_32;
231aea390e4SDavid Gibson     }
232aea390e4SDavid Gibson 
233aea390e4SDavid Gibson     return -1;
234aea390e4SDavid Gibson }
235aea390e4SDavid Gibson 
ppc_hash32_set_r(PowerPCCPU * cpu,hwaddr pte_offset,uint32_t pte1)2366e8a65abSBenjamin Herrenschmidt static void ppc_hash32_set_r(PowerPCCPU *cpu, hwaddr pte_offset, uint32_t pte1)
2376e8a65abSBenjamin Herrenschmidt {
2386e8a65abSBenjamin Herrenschmidt     target_ulong base = ppc_hash32_hpt_base(cpu);
2396e8a65abSBenjamin Herrenschmidt     hwaddr offset = pte_offset + 6;
2406e8a65abSBenjamin Herrenschmidt 
2416e8a65abSBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
2426e8a65abSBenjamin Herrenschmidt     stb_phys(CPU(cpu)->as, base + offset, ((pte1 >> 8) & 0xff) | 0x01);
2436e8a65abSBenjamin Herrenschmidt }
2446e8a65abSBenjamin Herrenschmidt 
ppc_hash32_set_c(PowerPCCPU * cpu,hwaddr pte_offset,uint64_t pte1)2456e8a65abSBenjamin Herrenschmidt static void ppc_hash32_set_c(PowerPCCPU *cpu, hwaddr pte_offset, uint64_t pte1)
2466e8a65abSBenjamin Herrenschmidt {
2476e8a65abSBenjamin Herrenschmidt     target_ulong base = ppc_hash32_hpt_base(cpu);
2486e8a65abSBenjamin Herrenschmidt     hwaddr offset = pte_offset + 7;
2496e8a65abSBenjamin Herrenschmidt 
2506e8a65abSBenjamin Herrenschmidt     /* The HW performs a non-atomic byte update */
2516e8a65abSBenjamin Herrenschmidt     stb_phys(CPU(cpu)->as, base + offset, (pte1 & 0xff) | 0x80);
2526e8a65abSBenjamin Herrenschmidt }
2536e8a65abSBenjamin Herrenschmidt 
ppc_hash32_htab_lookup(PowerPCCPU * cpu,target_ulong sr,target_ulong eaddr,ppc_hash_pte32_t * pte)2547ef23068SDavid Gibson static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
2557f3bdc2dSDavid Gibson                                      target_ulong sr, target_ulong eaddr,
2567f3bdc2dSDavid Gibson                                      ppc_hash_pte32_t *pte)
257c69b6151SDavid Gibson {
258aea390e4SDavid Gibson     hwaddr pteg_off, pte_offset;
259a1ff751aSDavid Gibson     hwaddr hash;
260a1ff751aSDavid Gibson     uint32_t vsid, pgidx, ptem;
261c69b6151SDavid Gibson 
262a1ff751aSDavid Gibson     vsid = sr & SR32_VSID;
263a1ff751aSDavid Gibson     pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
264a1ff751aSDavid Gibson     hash = vsid ^ pgidx;
265a1ff751aSDavid Gibson     ptem = (vsid << 7) | (pgidx >> 10);
266a1ff751aSDavid Gibson 
267a1ff751aSDavid Gibson     /* Page address translation */
268883f2c59SPhilippe Mathieu-Daudé     qemu_log_mask(CPU_LOG_MMU, "htab_base " HWADDR_FMT_plx
269883f2c59SPhilippe Mathieu-Daudé             " htab_mask " HWADDR_FMT_plx
270883f2c59SPhilippe Mathieu-Daudé             " hash " HWADDR_FMT_plx "\n",
27136778660SDavid Gibson             ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
272a1ff751aSDavid Gibson 
273a1ff751aSDavid Gibson     /* Primary PTEG lookup */
274883f2c59SPhilippe Mathieu-Daudé     qemu_log_mask(CPU_LOG_MMU, "0 htab=" HWADDR_FMT_plx "/" HWADDR_FMT_plx
275a1ff751aSDavid Gibson             " vsid=%" PRIx32 " ptem=%" PRIx32
276883f2c59SPhilippe Mathieu-Daudé             " hash=" HWADDR_FMT_plx "\n",
27736778660SDavid Gibson             ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
27836778660SDavid Gibson             vsid, ptem, hash);
2797ef23068SDavid Gibson     pteg_off = get_pteg_offset32(cpu, hash);
2807ef23068SDavid Gibson     pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte);
281a1ff751aSDavid Gibson     if (pte_offset == -1) {
282a1ff751aSDavid Gibson         /* Secondary PTEG lookup */
283883f2c59SPhilippe Mathieu-Daudé         qemu_log_mask(CPU_LOG_MMU, "1 htab=" HWADDR_FMT_plx "/" HWADDR_FMT_plx
284a1ff751aSDavid Gibson                 " vsid=%" PRIx32 " api=%" PRIx32
285883f2c59SPhilippe Mathieu-Daudé                 " hash=" HWADDR_FMT_plx "\n", ppc_hash32_hpt_base(cpu),
28636778660SDavid Gibson                 ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash);
2877ef23068SDavid Gibson         pteg_off = get_pteg_offset32(cpu, ~hash);
2887ef23068SDavid Gibson         pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte);
289a1ff751aSDavid Gibson     }
290a1ff751aSDavid Gibson 
2917f3bdc2dSDavid Gibson     return pte_offset;
292c69b6151SDavid Gibson }
2930480884fSDavid Gibson 
ppc_hash32_xlate(PowerPCCPU * cpu,vaddr eaddr,MMUAccessType access_type,hwaddr * raddrp,int * psizep,int * protp,int mmu_idx,bool guest_visible)29451806b54SRichard Henderson bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
295d423baf9SBruno Larsen (billionai)                       hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
2966c3c873cSRichard Henderson                       bool guest_visible)
2970480884fSDavid Gibson {
298d0e39c5dSAndreas Färber     CPUState *cs = CPU(cpu);
299d0e39c5dSAndreas Färber     CPUPPCState *env = &cpu->env;
300a1ff751aSDavid Gibson     target_ulong sr;
301620ba617SBALATON Zoltan     hwaddr pte_offset, raddr;
3027f3bdc2dSDavid Gibson     ppc_hash_pte32_t pte;
303620ba617SBALATON Zoltan     bool key;
304caa597bdSDavid Gibson     int prot;
3050480884fSDavid Gibson 
3066c3c873cSRichard Henderson     /* There are no hash32 large pages. */
3076c3c873cSRichard Henderson     *psizep = TARGET_PAGE_BITS;
3086a980110SDavid Gibson 
30965d61643SDavid Gibson     /* 1. Handle real mode accesses */
310d423baf9SBruno Larsen (billionai)     if (mmuidx_real(mmu_idx)) {
31165d61643SDavid Gibson         /* Translation is off */
3126c3c873cSRichard Henderson         *raddrp = eaddr;
3136c3c873cSRichard Henderson         *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
3146c3c873cSRichard Henderson         return true;
31565d61643SDavid Gibson     }
31665d61643SDavid Gibson 
31765d61643SDavid Gibson     /* 2. Check Block Address Translation entries (BATs) */
31865d61643SDavid Gibson     if (env->nb_BATs != 0) {
319d423baf9SBruno Larsen (billionai)         raddr = ppc_hash32_bat_lookup(cpu, eaddr, access_type, protp, mmu_idx);
320caa597bdSDavid Gibson         if (raddr != -1) {
321cd1038ecSBALATON Zoltan             if (!check_prot_access_type(*protp, access_type)) {
3226c3c873cSRichard Henderson                 if (guest_visible) {
32331fa64ecSRichard Henderson                     if (access_type == MMU_INST_FETCH) {
32427103424SAndreas Färber                         cs->exception_index = POWERPC_EXCP_ISI;
325caa597bdSDavid Gibson                         env->error_code = 0x08000000;
326caa597bdSDavid Gibson                     } else {
32727103424SAndreas Färber                         cs->exception_index = POWERPC_EXCP_DSI;
328caa597bdSDavid Gibson                         env->error_code = 0;
329caa597bdSDavid Gibson                         env->spr[SPR_DAR] = eaddr;
33031fa64ecSRichard Henderson                         if (access_type == MMU_DATA_STORE) {
331caa597bdSDavid Gibson                             env->spr[SPR_DSISR] = 0x0a000000;
332caa597bdSDavid Gibson                         } else {
333caa597bdSDavid Gibson                             env->spr[SPR_DSISR] = 0x08000000;
334e01b4445SDavid Gibson                         }
335caa597bdSDavid Gibson                     }
336caa597bdSDavid Gibson                 }
3376c3c873cSRichard Henderson                 return false;
3386c3c873cSRichard Henderson             }
3396c3c873cSRichard Henderson             *raddrp = raddr;
3406c3c873cSRichard Henderson             return true;
34165d61643SDavid Gibson         }
342145e52f3SDavid Gibson     }
34365d61643SDavid Gibson 
3444b9605a5SDavid Gibson     /* 3. Look up the Segment Register */
3450480884fSDavid Gibson     sr = env->sr[eaddr >> 28];
3464b9605a5SDavid Gibson 
347723ed73aSDavid Gibson     /* 4. Handle direct store segments */
348723ed73aSDavid Gibson     if (sr & SR32_T) {
3496c3c873cSRichard Henderson         return ppc_hash32_direct_store(cpu, sr, eaddr, access_type,
350d423baf9SBruno Larsen (billionai)                                        raddrp, protp, mmu_idx, guest_visible);
351723ed73aSDavid Gibson     }
352723ed73aSDavid Gibson 
353bb218042SDavid Gibson     /* 5. Check for segment level no-execute violation */
35431fa64ecSRichard Henderson     if (access_type == MMU_INST_FETCH && (sr & SR32_NX)) {
3556c3c873cSRichard Henderson         if (guest_visible) {
35627103424SAndreas Färber             cs->exception_index = POWERPC_EXCP_ISI;
357caa597bdSDavid Gibson             env->error_code = 0x10000000;
3586c3c873cSRichard Henderson         }
3596c3c873cSRichard Henderson         return false;
360bb218042SDavid Gibson     }
3617f3bdc2dSDavid Gibson 
3627f3bdc2dSDavid Gibson     /* 6. Locate the PTE in the hash table */
3637ef23068SDavid Gibson     pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte);
3647f3bdc2dSDavid Gibson     if (pte_offset == -1) {
3656c3c873cSRichard Henderson         if (guest_visible) {
36631fa64ecSRichard Henderson             if (access_type == MMU_INST_FETCH) {
36727103424SAndreas Färber                 cs->exception_index = POWERPC_EXCP_ISI;
368caa597bdSDavid Gibson                 env->error_code = 0x40000000;
369caa597bdSDavid Gibson             } else {
37027103424SAndreas Färber                 cs->exception_index = POWERPC_EXCP_DSI;
371caa597bdSDavid Gibson                 env->error_code = 0;
372caa597bdSDavid Gibson                 env->spr[SPR_DAR] = eaddr;
37331fa64ecSRichard Henderson                 if (access_type == MMU_DATA_STORE) {
374caa597bdSDavid Gibson                     env->spr[SPR_DSISR] = 0x42000000;
375caa597bdSDavid Gibson                 } else {
376caa597bdSDavid Gibson                     env->spr[SPR_DSISR] = 0x40000000;
377caa597bdSDavid Gibson                 }
378caa597bdSDavid Gibson             }
3796c3c873cSRichard Henderson         }
3806c3c873cSRichard Henderson         return false;
3817f3bdc2dSDavid Gibson     }
382339aaf5bSAntony Pavlov     qemu_log_mask(CPU_LOG_MMU,
383339aaf5bSAntony Pavlov                 "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
3847f3bdc2dSDavid Gibson 
3857f3bdc2dSDavid Gibson     /* 7. Check access permissions */
386620ba617SBALATON Zoltan     key = ppc_hash32_key(mmuidx_pr(mmu_idx), sr);
387620ba617SBALATON Zoltan     prot = ppc_hash32_prot(key, pte.pte1 & HPTE32_R_PP, sr & SR32_NX);
3886a980110SDavid Gibson 
389cd1038ecSBALATON Zoltan     if (!check_prot_access_type(prot, access_type)) {
3906a980110SDavid Gibson         /* Access right violation */
391339aaf5bSAntony Pavlov         qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
3926c3c873cSRichard Henderson         if (guest_visible) {
39331fa64ecSRichard Henderson             if (access_type == MMU_INST_FETCH) {
39427103424SAndreas Färber                 cs->exception_index = POWERPC_EXCP_ISI;
395caa597bdSDavid Gibson                 env->error_code = 0x08000000;
396caa597bdSDavid Gibson             } else {
39727103424SAndreas Färber                 cs->exception_index = POWERPC_EXCP_DSI;
398caa597bdSDavid Gibson                 env->error_code = 0;
399caa597bdSDavid Gibson                 env->spr[SPR_DAR] = eaddr;
40031fa64ecSRichard Henderson                 if (access_type == MMU_DATA_STORE) {
401caa597bdSDavid Gibson                     env->spr[SPR_DSISR] = 0x0a000000;
402caa597bdSDavid Gibson                 } else {
403caa597bdSDavid Gibson                     env->spr[SPR_DSISR] = 0x08000000;
404caa597bdSDavid Gibson                 }
405caa597bdSDavid Gibson             }
4066c3c873cSRichard Henderson         }
4076c3c873cSRichard Henderson         return false;
4086a980110SDavid Gibson     }
4096a980110SDavid Gibson 
410339aaf5bSAntony Pavlov     qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
41187dc3fd1SDavid Gibson 
41287dc3fd1SDavid Gibson     /* 8. Update PTE referenced and changed bits if necessary */
41387dc3fd1SDavid Gibson 
4146e8a65abSBenjamin Herrenschmidt     if (!(pte.pte1 & HPTE32_R_R)) {
4156e8a65abSBenjamin Herrenschmidt         ppc_hash32_set_r(cpu, pte_offset, pte.pte1);
4166e8a65abSBenjamin Herrenschmidt     }
4176e8a65abSBenjamin Herrenschmidt     if (!(pte.pte1 & HPTE32_R_C)) {
41831fa64ecSRichard Henderson         if (access_type == MMU_DATA_STORE) {
4196e8a65abSBenjamin Herrenschmidt             ppc_hash32_set_c(cpu, pte_offset, pte.pte1);
420b3440746SDavid Gibson         } else {
421596e3ca8SDavid Gibson             /*
422596e3ca8SDavid Gibson              * Treat the page as read-only for now, so that a later write
423596e3ca8SDavid Gibson              * will pass through this function again to set the C bit
424596e3ca8SDavid Gibson              */
425caa597bdSDavid Gibson             prot &= ~PAGE_WRITE;
426b3440746SDavid Gibson         }
4277f3bdc2dSDavid Gibson     }
42851993befSBALATON Zoltan     *protp = prot;
4290480884fSDavid Gibson 
4306d11d998SDavid Gibson     /* 9. Determine the real address from the PTE */
43151993befSBALATON Zoltan     *raddrp = pte.pte1 & HPTE32_R_RPN;
43251993befSBALATON Zoltan     *raddrp &= TARGET_PAGE_MASK;
43351993befSBALATON Zoltan     *raddrp |= eaddr & ~TARGET_PAGE_MASK;
4346c3c873cSRichard Henderson     return true;
4356c3c873cSRichard Henderson }
436