xref: /openbmc/qemu/target/ppc/mmu-hash32.c (revision 93b799fafd9170da3a79a533ea6f73a18de82e22)
1fcf5ef2aSThomas Huth /*
2fcf5ef2aSThomas Huth  *  PowerPC MMU, TLB and BAT emulation helpers for QEMU.
3fcf5ef2aSThomas Huth  *
4fcf5ef2aSThomas Huth  *  Copyright (c) 2003-2007 Jocelyn Mayer
5fcf5ef2aSThomas Huth  *  Copyright (c) 2013 David Gibson, IBM Corporation
6fcf5ef2aSThomas Huth  *
7fcf5ef2aSThomas Huth  * This library is free software; you can redistribute it and/or
8fcf5ef2aSThomas Huth  * modify it under the terms of the GNU Lesser General Public
9fcf5ef2aSThomas Huth  * License as published by the Free Software Foundation; either
106bd039cdSChetan Pant  * version 2.1 of the License, or (at your option) any later version.
11fcf5ef2aSThomas Huth  *
12fcf5ef2aSThomas Huth  * This library is distributed in the hope that it will be useful,
13fcf5ef2aSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14fcf5ef2aSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15fcf5ef2aSThomas Huth  * Lesser General Public License for more details.
16fcf5ef2aSThomas Huth  *
17fcf5ef2aSThomas Huth  * You should have received a copy of the GNU Lesser General Public
18fcf5ef2aSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19fcf5ef2aSThomas Huth  */
20fcf5ef2aSThomas Huth 
21fcf5ef2aSThomas Huth #include "qemu/osdep.h"
22fcf5ef2aSThomas Huth #include "cpu.h"
23fcf5ef2aSThomas Huth #include "exec/exec-all.h"
2474781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h"
25fcf5ef2aSThomas Huth #include "sysemu/kvm.h"
26fcf5ef2aSThomas Huth #include "kvm_ppc.h"
27182357dbSRichard Henderson #include "internal.h"
28fcf5ef2aSThomas Huth #include "mmu-hash32.h"
29d423baf9SBruno Larsen (billionai) #include "mmu-books.h"
30fcf5ef2aSThomas Huth #include "exec/log.h"
31fcf5ef2aSThomas Huth 
32ba1b5df0SFabiano Rosas /* #define DEBUG_BATS */
33fcf5ef2aSThomas Huth 
34fcf5ef2aSThomas Huth #ifdef DEBUG_BATS
35fcf5ef2aSThomas Huth #  define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
36fcf5ef2aSThomas Huth #else
37fcf5ef2aSThomas Huth #  define LOG_BATS(...) do { } while (0)
38fcf5ef2aSThomas Huth #endif
39fcf5ef2aSThomas Huth 
hash32_bat_size(int mmu_idx,target_ulong batu,target_ulong batl)40d423baf9SBruno Larsen (billionai) static target_ulong hash32_bat_size(int mmu_idx,
41fcf5ef2aSThomas Huth                                     target_ulong batu, target_ulong batl)
42fcf5ef2aSThomas Huth {
43d423baf9SBruno Larsen (billionai)     if ((mmuidx_pr(mmu_idx) && !(batu & BATU32_VP))
44d423baf9SBruno Larsen (billionai)         || (!mmuidx_pr(mmu_idx) && !(batu & BATU32_VS))) {
45fcf5ef2aSThomas Huth         return 0;
46fcf5ef2aSThomas Huth     }
47fcf5ef2aSThomas Huth 
48fcf5ef2aSThomas Huth     return BATU32_BEPI & ~((batu & BATU32_BL) << 15);
49fcf5ef2aSThomas Huth }
50fcf5ef2aSThomas Huth 
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)
54fcf5ef2aSThomas Huth {
55fcf5ef2aSThomas Huth     CPUPPCState *env = &cpu->env;
56fcf5ef2aSThomas Huth     target_ulong *BATlt, *BATut;
5731fa64ecSRichard Henderson     bool ifetch = access_type == MMU_INST_FETCH;
58fcf5ef2aSThomas Huth     int i;
59fcf5ef2aSThomas Huth 
60fcf5ef2aSThomas Huth     LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
6131fa64ecSRichard Henderson              ifetch ? 'I' : 'D', ea);
6231fa64ecSRichard Henderson     if (ifetch) {
63fcf5ef2aSThomas Huth         BATlt = env->IBAT[1];
64fcf5ef2aSThomas Huth         BATut = env->IBAT[0];
65fcf5ef2aSThomas Huth     } else {
66fcf5ef2aSThomas Huth         BATlt = env->DBAT[1];
67fcf5ef2aSThomas Huth         BATut = env->DBAT[0];
68fcf5ef2aSThomas Huth     }
69fcf5ef2aSThomas Huth     for (i = 0; i < env->nb_BATs; i++) {
70fcf5ef2aSThomas Huth         target_ulong batu = BATut[i];
71fcf5ef2aSThomas Huth         target_ulong batl = BATlt[i];
72fcf5ef2aSThomas Huth         target_ulong mask;
73fcf5ef2aSThomas Huth 
74d423baf9SBruno Larsen (billionai)         mask = hash32_bat_size(mmu_idx, batu, batl);
75fcf5ef2aSThomas Huth         LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
76fcf5ef2aSThomas Huth                  " BATl " TARGET_FMT_lx "\n", __func__,
7731fa64ecSRichard Henderson                  ifetch ? 'I' : 'D', i, ea, batu, batl);
78fcf5ef2aSThomas Huth 
79fcf5ef2aSThomas Huth         if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
80fcf5ef2aSThomas Huth             hwaddr raddr = (batl & mask) | (ea & ~mask);
81fcf5ef2aSThomas Huth 
82d3233386SBALATON Zoltan             *prot = ppc_hash32_bat_prot(batu, batl);
83fcf5ef2aSThomas Huth 
84fcf5ef2aSThomas Huth             return raddr & TARGET_PAGE_MASK;
85fcf5ef2aSThomas Huth         }
86fcf5ef2aSThomas Huth     }
87fcf5ef2aSThomas Huth 
88fcf5ef2aSThomas Huth     /* No hit */
89fcf5ef2aSThomas Huth #if defined(DEBUG_BATS)
90fcf5ef2aSThomas Huth     if (qemu_log_enabled()) {
91ba1b5df0SFabiano Rosas         target_ulong *BATu, *BATl;
92ba1b5df0SFabiano Rosas         target_ulong BEPIl, BEPIu, bl;
93ba1b5df0SFabiano Rosas 
94fcf5ef2aSThomas Huth         LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", ea);
95fcf5ef2aSThomas Huth         for (i = 0; i < 4; i++) {
96fcf5ef2aSThomas Huth             BATu = &BATut[i];
97fcf5ef2aSThomas Huth             BATl = &BATlt[i];
98fcf5ef2aSThomas Huth             BEPIu = *BATu & BATU32_BEPIU;
99fcf5ef2aSThomas Huth             BEPIl = *BATu & BATU32_BEPIL;
100fcf5ef2aSThomas Huth             bl = (*BATu & 0x00001FFC) << 15;
101fcf5ef2aSThomas Huth             LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
102fcf5ef2aSThomas Huth                      " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
103fcf5ef2aSThomas Huth                      TARGET_FMT_lx " " TARGET_FMT_lx "\n",
10431fa64ecSRichard Henderson                      __func__, ifetch ? 'I' : 'D', i, ea,
105fcf5ef2aSThomas Huth                      *BATu, *BATl, BEPIu, BEPIl, bl);
106fcf5ef2aSThomas Huth         }
107fcf5ef2aSThomas Huth     }
108fcf5ef2aSThomas Huth #endif
109fcf5ef2aSThomas Huth 
110fcf5ef2aSThomas Huth     return -1;
111fcf5ef2aSThomas Huth }
112fcf5ef2aSThomas Huth 
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)
118fcf5ef2aSThomas Huth {
119fcf5ef2aSThomas Huth     CPUState *cs = CPU(cpu);
120fcf5ef2aSThomas Huth     CPUPPCState *env = &cpu->env;
121fcf5ef2aSThomas Huth 
122fcf5ef2aSThomas Huth     qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
123fcf5ef2aSThomas Huth 
12431fa64ecSRichard Henderson     if (access_type == MMU_INST_FETCH) {
125fcf5ef2aSThomas Huth         /* No code fetch is allowed in direct-store areas */
1266c3c873cSRichard Henderson         if (guest_visible) {
127fcf5ef2aSThomas Huth             cs->exception_index = POWERPC_EXCP_ISI;
128fcf5ef2aSThomas Huth             env->error_code = 0x10000000;
1296c3c873cSRichard Henderson         }
1306c3c873cSRichard Henderson         return false;
131fcf5ef2aSThomas Huth     }
132fcf5ef2aSThomas Huth 
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) {
138fcf5ef2aSThomas Huth     case ACCESS_INT:
139fcf5ef2aSThomas Huth         /* Integer load/store : only access allowed */
140fcf5ef2aSThomas Huth         break;
141fcf5ef2aSThomas Huth     case ACCESS_FLOAT:
142fcf5ef2aSThomas Huth         /* Floating point load/store */
143fcf5ef2aSThomas Huth         cs->exception_index = POWERPC_EXCP_ALIGN;
144fcf5ef2aSThomas Huth         env->error_code = POWERPC_EXCP_ALIGN_FP;
145fcf5ef2aSThomas Huth         env->spr[SPR_DAR] = eaddr;
1466c3c873cSRichard Henderson         return false;
147fcf5ef2aSThomas Huth     case ACCESS_RES:
148fcf5ef2aSThomas Huth         /* lwarx, ldarx or srwcx. */
149fcf5ef2aSThomas Huth         env->error_code = 0;
150fcf5ef2aSThomas Huth         env->spr[SPR_DAR] = eaddr;
15131fa64ecSRichard Henderson         if (access_type == MMU_DATA_STORE) {
152fcf5ef2aSThomas Huth             env->spr[SPR_DSISR] = 0x06000000;
153fcf5ef2aSThomas Huth         } else {
154fcf5ef2aSThomas Huth             env->spr[SPR_DSISR] = 0x04000000;
155fcf5ef2aSThomas Huth         }
1566c3c873cSRichard Henderson         return false;
157fcf5ef2aSThomas Huth     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 :-)
163fcf5ef2aSThomas Huth          */
164fcf5ef2aSThomas Huth         *raddr = eaddr;
1656c3c873cSRichard Henderson         return true;
166fcf5ef2aSThomas Huth     case ACCESS_EXT:
167fcf5ef2aSThomas Huth         /* eciwx or ecowx */
168fcf5ef2aSThomas Huth         cs->exception_index = POWERPC_EXCP_DSI;
169fcf5ef2aSThomas Huth         env->error_code = 0;
170fcf5ef2aSThomas Huth         env->spr[SPR_DAR] = eaddr;
17131fa64ecSRichard Henderson         if (access_type == MMU_DATA_STORE) {
172fcf5ef2aSThomas Huth             env->spr[SPR_DSISR] = 0x06100000;
173fcf5ef2aSThomas Huth         } else {
174fcf5ef2aSThomas Huth             env->spr[SPR_DSISR] = 0x04100000;
175fcf5ef2aSThomas Huth         }
1766c3c873cSRichard Henderson         return false;
177fcf5ef2aSThomas Huth     default:
1786c3c873cSRichard Henderson         cpu_abort(cs, "ERROR: insn should not need address translation\n");
179fcf5ef2aSThomas Huth     }
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)) {
187fcf5ef2aSThomas Huth         *raddr = eaddr;
1886c3c873cSRichard Henderson         return true;
1896c3c873cSRichard Henderson     }
1906c3c873cSRichard Henderson 
1916c3c873cSRichard Henderson     if (guest_visible) {
192fcf5ef2aSThomas Huth         cs->exception_index = POWERPC_EXCP_DSI;
193fcf5ef2aSThomas Huth         env->error_code = 0;
194fcf5ef2aSThomas Huth         env->spr[SPR_DAR] = eaddr;
19531fa64ecSRichard Henderson         if (access_type == MMU_DATA_STORE) {
196fcf5ef2aSThomas Huth             env->spr[SPR_DSISR] = 0x0a000000;
197fcf5ef2aSThomas Huth         } else {
198fcf5ef2aSThomas Huth             env->spr[SPR_DSISR] = 0x08000000;
199fcf5ef2aSThomas Huth         }
200fcf5ef2aSThomas Huth     }
2016c3c873cSRichard Henderson     return false;
202fcf5ef2aSThomas Huth }
203fcf5ef2aSThomas Huth 
ppc_hash32_pteg_search(PowerPCCPU * cpu,hwaddr pteg_off,bool secondary,target_ulong ptem,ppc_hash_pte32_t * pte)204fcf5ef2aSThomas Huth static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off,
205fcf5ef2aSThomas Huth                                      bool secondary, target_ulong ptem,
206fcf5ef2aSThomas Huth                                      ppc_hash_pte32_t *pte)
207fcf5ef2aSThomas Huth {
208fcf5ef2aSThomas Huth     hwaddr pte_offset = pteg_off;
209fcf5ef2aSThomas Huth     target_ulong pte0, pte1;
210fcf5ef2aSThomas Huth     int i;
211fcf5ef2aSThomas Huth 
212fcf5ef2aSThomas Huth     for (i = 0; i < HPTES_PER_GROUP; i++) {
213fcf5ef2aSThomas Huth         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();
220fcf5ef2aSThomas Huth         pte1 = ppc_hash32_load_hpte1(cpu, pte_offset);
221fcf5ef2aSThomas Huth 
222fcf5ef2aSThomas Huth         if ((pte0 & HPTE32_V_VALID)
223fcf5ef2aSThomas Huth             && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
224fcf5ef2aSThomas Huth             && HPTE32_V_COMPARE(pte0, ptem)) {
225fcf5ef2aSThomas Huth             pte->pte0 = pte0;
226fcf5ef2aSThomas Huth             pte->pte1 = pte1;
227fcf5ef2aSThomas Huth             return pte_offset;
228fcf5ef2aSThomas Huth         }
229fcf5ef2aSThomas Huth 
230fcf5ef2aSThomas Huth         pte_offset += HASH_PTE_SIZE_32;
231fcf5ef2aSThomas Huth     }
232fcf5ef2aSThomas Huth 
233fcf5ef2aSThomas Huth     return -1;
234fcf5ef2aSThomas Huth }
235fcf5ef2aSThomas Huth 
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)254fcf5ef2aSThomas Huth static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
255fcf5ef2aSThomas Huth                                      target_ulong sr, target_ulong eaddr,
256fcf5ef2aSThomas Huth                                      ppc_hash_pte32_t *pte)
257fcf5ef2aSThomas Huth {
258fcf5ef2aSThomas Huth     hwaddr pteg_off, pte_offset;
259fcf5ef2aSThomas Huth     hwaddr hash;
260fcf5ef2aSThomas Huth     uint32_t vsid, pgidx, ptem;
261fcf5ef2aSThomas Huth 
262fcf5ef2aSThomas Huth     vsid = sr & SR32_VSID;
263fcf5ef2aSThomas Huth     pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
264fcf5ef2aSThomas Huth     hash = vsid ^ pgidx;
265fcf5ef2aSThomas Huth     ptem = (vsid << 7) | (pgidx >> 10);
266fcf5ef2aSThomas Huth 
267fcf5ef2aSThomas Huth     /* 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);
272fcf5ef2aSThomas Huth 
273fcf5ef2aSThomas Huth     /* Primary PTEG lookup */
274883f2c59SPhilippe Mathieu-Daudé     qemu_log_mask(CPU_LOG_MMU, "0 htab=" HWADDR_FMT_plx "/" HWADDR_FMT_plx
275fcf5ef2aSThomas Huth             " 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);
279fcf5ef2aSThomas Huth     pteg_off = get_pteg_offset32(cpu, hash);
280fcf5ef2aSThomas Huth     pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte);
281fcf5ef2aSThomas Huth     if (pte_offset == -1) {
282fcf5ef2aSThomas Huth         /* Secondary PTEG lookup */
283883f2c59SPhilippe Mathieu-Daudé         qemu_log_mask(CPU_LOG_MMU, "1 htab=" HWADDR_FMT_plx "/" HWADDR_FMT_plx
284fcf5ef2aSThomas Huth                 " 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);
287fcf5ef2aSThomas Huth         pteg_off = get_pteg_offset32(cpu, ~hash);
288fcf5ef2aSThomas Huth         pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte);
289fcf5ef2aSThomas Huth     }
290fcf5ef2aSThomas Huth 
291fcf5ef2aSThomas Huth     return pte_offset;
292fcf5ef2aSThomas Huth }
293fcf5ef2aSThomas Huth 
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)
297fcf5ef2aSThomas Huth {
298fcf5ef2aSThomas Huth     CPUState *cs = CPU(cpu);
299fcf5ef2aSThomas Huth     CPUPPCState *env = &cpu->env;
300fcf5ef2aSThomas Huth     target_ulong sr;
301620ba617SBALATON Zoltan     hwaddr pte_offset, raddr;
302fcf5ef2aSThomas Huth     ppc_hash_pte32_t pte;
303620ba617SBALATON Zoltan     bool key;
304fcf5ef2aSThomas Huth     int prot;
305fcf5ef2aSThomas Huth 
3066c3c873cSRichard Henderson     /* There are no hash32 large pages. */
3076c3c873cSRichard Henderson     *psizep = TARGET_PAGE_BITS;
308fcf5ef2aSThomas Huth 
309fcf5ef2aSThomas Huth     /* 1. Handle real mode accesses */
310d423baf9SBruno Larsen (billionai)     if (mmuidx_real(mmu_idx)) {
311fcf5ef2aSThomas Huth         /* Translation is off */
3126c3c873cSRichard Henderson         *raddrp = eaddr;
3136c3c873cSRichard Henderson         *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
3146c3c873cSRichard Henderson         return true;
315fcf5ef2aSThomas Huth     }
316fcf5ef2aSThomas Huth 
317fcf5ef2aSThomas Huth     /* 2. Check Block Address Translation entries (BATs) */
318fcf5ef2aSThomas Huth     if (env->nb_BATs != 0) {
319d423baf9SBruno Larsen (billionai)         raddr = ppc_hash32_bat_lookup(cpu, eaddr, access_type, protp, mmu_idx);
320fcf5ef2aSThomas Huth         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) {
324fcf5ef2aSThomas Huth                         cs->exception_index = POWERPC_EXCP_ISI;
325fcf5ef2aSThomas Huth                         env->error_code = 0x08000000;
326fcf5ef2aSThomas Huth                     } else {
327fcf5ef2aSThomas Huth                         cs->exception_index = POWERPC_EXCP_DSI;
328fcf5ef2aSThomas Huth                         env->error_code = 0;
329fcf5ef2aSThomas Huth                         env->spr[SPR_DAR] = eaddr;
33031fa64ecSRichard Henderson                         if (access_type == MMU_DATA_STORE) {
331fcf5ef2aSThomas Huth                             env->spr[SPR_DSISR] = 0x0a000000;
332fcf5ef2aSThomas Huth                         } else {
333fcf5ef2aSThomas Huth                             env->spr[SPR_DSISR] = 0x08000000;
334fcf5ef2aSThomas Huth                         }
335fcf5ef2aSThomas Huth                     }
336fcf5ef2aSThomas Huth                 }
3376c3c873cSRichard Henderson                 return false;
3386c3c873cSRichard Henderson             }
3396c3c873cSRichard Henderson             *raddrp = raddr;
3406c3c873cSRichard Henderson             return true;
341fcf5ef2aSThomas Huth         }
342fcf5ef2aSThomas Huth     }
343fcf5ef2aSThomas Huth 
344fcf5ef2aSThomas Huth     /* 3. Look up the Segment Register */
345fcf5ef2aSThomas Huth     sr = env->sr[eaddr >> 28];
346fcf5ef2aSThomas Huth 
347fcf5ef2aSThomas Huth     /* 4. Handle direct store segments */
348fcf5ef2aSThomas Huth     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);
351fcf5ef2aSThomas Huth     }
352fcf5ef2aSThomas Huth 
353fcf5ef2aSThomas Huth     /* 5. Check for segment level no-execute violation */
35431fa64ecSRichard Henderson     if (access_type == MMU_INST_FETCH && (sr & SR32_NX)) {
3556c3c873cSRichard Henderson         if (guest_visible) {
356fcf5ef2aSThomas Huth             cs->exception_index = POWERPC_EXCP_ISI;
357fcf5ef2aSThomas Huth             env->error_code = 0x10000000;
3586c3c873cSRichard Henderson         }
3596c3c873cSRichard Henderson         return false;
360fcf5ef2aSThomas Huth     }
361fcf5ef2aSThomas Huth 
362fcf5ef2aSThomas Huth     /* 6. Locate the PTE in the hash table */
363fcf5ef2aSThomas Huth     pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte);
364fcf5ef2aSThomas Huth     if (pte_offset == -1) {
3656c3c873cSRichard Henderson         if (guest_visible) {
36631fa64ecSRichard Henderson             if (access_type == MMU_INST_FETCH) {
367fcf5ef2aSThomas Huth                 cs->exception_index = POWERPC_EXCP_ISI;
368fcf5ef2aSThomas Huth                 env->error_code = 0x40000000;
369fcf5ef2aSThomas Huth             } else {
370fcf5ef2aSThomas Huth                 cs->exception_index = POWERPC_EXCP_DSI;
371fcf5ef2aSThomas Huth                 env->error_code = 0;
372fcf5ef2aSThomas Huth                 env->spr[SPR_DAR] = eaddr;
37331fa64ecSRichard Henderson                 if (access_type == MMU_DATA_STORE) {
374fcf5ef2aSThomas Huth                     env->spr[SPR_DSISR] = 0x42000000;
375fcf5ef2aSThomas Huth                 } else {
376fcf5ef2aSThomas Huth                     env->spr[SPR_DSISR] = 0x40000000;
377fcf5ef2aSThomas Huth                 }
378fcf5ef2aSThomas Huth             }
3796c3c873cSRichard Henderson         }
3806c3c873cSRichard Henderson         return false;
381fcf5ef2aSThomas Huth     }
382fcf5ef2aSThomas Huth     qemu_log_mask(CPU_LOG_MMU,
383fcf5ef2aSThomas Huth                 "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
384fcf5ef2aSThomas Huth 
385fcf5ef2aSThomas Huth     /* 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);
388fcf5ef2aSThomas Huth 
389cd1038ecSBALATON Zoltan     if (!check_prot_access_type(prot, access_type)) {
390fcf5ef2aSThomas Huth         /* Access right violation */
391fcf5ef2aSThomas Huth         qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
3926c3c873cSRichard Henderson         if (guest_visible) {
39331fa64ecSRichard Henderson             if (access_type == MMU_INST_FETCH) {
394fcf5ef2aSThomas Huth                 cs->exception_index = POWERPC_EXCP_ISI;
395fcf5ef2aSThomas Huth                 env->error_code = 0x08000000;
396fcf5ef2aSThomas Huth             } else {
397fcf5ef2aSThomas Huth                 cs->exception_index = POWERPC_EXCP_DSI;
398fcf5ef2aSThomas Huth                 env->error_code = 0;
399fcf5ef2aSThomas Huth                 env->spr[SPR_DAR] = eaddr;
40031fa64ecSRichard Henderson                 if (access_type == MMU_DATA_STORE) {
401fcf5ef2aSThomas Huth                     env->spr[SPR_DSISR] = 0x0a000000;
402fcf5ef2aSThomas Huth                 } else {
403fcf5ef2aSThomas Huth                     env->spr[SPR_DSISR] = 0x08000000;
404fcf5ef2aSThomas Huth                 }
405fcf5ef2aSThomas Huth             }
4066c3c873cSRichard Henderson         }
4076c3c873cSRichard Henderson         return false;
408fcf5ef2aSThomas Huth     }
409fcf5ef2aSThomas Huth 
410fcf5ef2aSThomas Huth     qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
411fcf5ef2aSThomas Huth 
412fcf5ef2aSThomas Huth     /* 8. Update PTE referenced and changed bits if necessary */
413fcf5ef2aSThomas Huth 
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);
420fcf5ef2aSThomas Huth         } 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              */
425fcf5ef2aSThomas Huth             prot &= ~PAGE_WRITE;
426fcf5ef2aSThomas Huth         }
427fcf5ef2aSThomas Huth     }
428*51993befSBALATON Zoltan     *protp = prot;
429fcf5ef2aSThomas Huth 
430fcf5ef2aSThomas Huth     /* 9. Determine the real address from the PTE */
431*51993befSBALATON Zoltan     *raddrp = pte.pte1 & HPTE32_R_RPN;
432*51993befSBALATON Zoltan     *raddrp &= TARGET_PAGE_MASK;
433*51993befSBALATON Zoltan     *raddrp |= eaddr & ~TARGET_PAGE_MASK;
4346c3c873cSRichard Henderson     return true;
4356c3c873cSRichard Henderson }
436