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