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