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 | 596e3ca | 2019-03-21 22:29:06 +1100 | [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) { |
David Gibson | 596e3ca | 2019-03-21 22:29:06 +1100 | [diff] [blame] | 231 | /* |
| 232 | * Memory-forced I/O controller interface access |
| 233 | * |
| 234 | * If T=1 and BUID=x'07F', the 601 performs a memory access |
David Gibson | 723ed73 | 2013-03-12 00:31:25 +0000 | [diff] [blame] | 235 | * to SR[28-31] LA[4-31], bypassing all protection mechanisms. |
| 236 | */ |
| 237 | *raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF); |
| 238 | *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; |
| 239 | return 0; |
| 240 | } |
| 241 | |
| 242 | if (rwx == 2) { |
| 243 | /* No code fetch is allowed in direct-store areas */ |
Andreas Färber | 2710342 | 2013-08-26 08:31:06 +0200 | [diff] [blame] | 244 | cs->exception_index = POWERPC_EXCP_ISI; |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 245 | env->error_code = 0x10000000; |
| 246 | return 1; |
David Gibson | 723ed73 | 2013-03-12 00:31:25 +0000 | [diff] [blame] | 247 | } |
| 248 | |
| 249 | switch (env->access_type) { |
| 250 | case ACCESS_INT: |
| 251 | /* Integer load/store : only access allowed */ |
| 252 | break; |
| 253 | case ACCESS_FLOAT: |
| 254 | /* Floating point load/store */ |
Andreas Färber | 2710342 | 2013-08-26 08:31:06 +0200 | [diff] [blame] | 255 | cs->exception_index = POWERPC_EXCP_ALIGN; |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 256 | env->error_code = POWERPC_EXCP_ALIGN_FP; |
| 257 | env->spr[SPR_DAR] = eaddr; |
| 258 | return 1; |
David Gibson | 723ed73 | 2013-03-12 00:31:25 +0000 | [diff] [blame] | 259 | case ACCESS_RES: |
| 260 | /* lwarx, ldarx or srwcx. */ |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 261 | env->error_code = 0; |
| 262 | env->spr[SPR_DAR] = eaddr; |
| 263 | if (rwx == 1) { |
| 264 | env->spr[SPR_DSISR] = 0x06000000; |
| 265 | } else { |
| 266 | env->spr[SPR_DSISR] = 0x04000000; |
| 267 | } |
| 268 | return 1; |
David Gibson | 723ed73 | 2013-03-12 00:31:25 +0000 | [diff] [blame] | 269 | case ACCESS_CACHE: |
David Gibson | 596e3ca | 2019-03-21 22:29:06 +1100 | [diff] [blame] | 270 | /* |
| 271 | * dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi |
| 272 | * |
| 273 | * Should make the instruction do no-op. As it already do |
| 274 | * no-op, it's quite easy :-) |
David Gibson | 723ed73 | 2013-03-12 00:31:25 +0000 | [diff] [blame] | 275 | */ |
| 276 | *raddr = eaddr; |
| 277 | return 0; |
| 278 | case ACCESS_EXT: |
| 279 | /* eciwx or ecowx */ |
Andreas Färber | 2710342 | 2013-08-26 08:31:06 +0200 | [diff] [blame] | 280 | cs->exception_index = POWERPC_EXCP_DSI; |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 281 | env->error_code = 0; |
| 282 | env->spr[SPR_DAR] = eaddr; |
| 283 | if (rwx == 1) { |
| 284 | env->spr[SPR_DSISR] = 0x06100000; |
| 285 | } else { |
| 286 | env->spr[SPR_DSISR] = 0x04100000; |
| 287 | } |
| 288 | return 1; |
David Gibson | 723ed73 | 2013-03-12 00:31:25 +0000 | [diff] [blame] | 289 | default: |
Paolo Bonzini | 48880da | 2015-11-13 13:34:23 +0100 | [diff] [blame] | 290 | cpu_abort(cs, "ERROR: instruction should not need " |
David Gibson | 723ed73 | 2013-03-12 00:31:25 +0000 | [diff] [blame] | 291 | "address translation\n"); |
David Gibson | 723ed73 | 2013-03-12 00:31:25 +0000 | [diff] [blame] | 292 | } |
| 293 | if ((rwx == 1 || key != 1) && (rwx == 0 || key != 0)) { |
| 294 | *raddr = eaddr; |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 295 | return 0; |
David Gibson | 723ed73 | 2013-03-12 00:31:25 +0000 | [diff] [blame] | 296 | } else { |
Andreas Färber | 2710342 | 2013-08-26 08:31:06 +0200 | [diff] [blame] | 297 | cs->exception_index = POWERPC_EXCP_DSI; |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 298 | env->error_code = 0; |
| 299 | env->spr[SPR_DAR] = eaddr; |
| 300 | if (rwx == 1) { |
| 301 | env->spr[SPR_DSISR] = 0x0a000000; |
| 302 | } else { |
| 303 | env->spr[SPR_DSISR] = 0x08000000; |
| 304 | } |
| 305 | return 1; |
David Gibson | 723ed73 | 2013-03-12 00:31:25 +0000 | [diff] [blame] | 306 | } |
| 307 | } |
| 308 | |
David Gibson | 7ef2306 | 2016-01-14 15:33:27 +1100 | [diff] [blame] | 309 | hwaddr get_pteg_offset32(PowerPCCPU *cpu, hwaddr hash) |
David Gibson | 5919172 | 2013-03-12 00:31:15 +0000 | [diff] [blame] | 310 | { |
David Gibson | 3677866 | 2017-02-24 16:36:44 +1100 | [diff] [blame] | 311 | target_ulong mask = ppc_hash32_hpt_mask(cpu); |
David Gibson | 7ef2306 | 2016-01-14 15:33:27 +1100 | [diff] [blame] | 312 | |
David Gibson | 3677866 | 2017-02-24 16:36:44 +1100 | [diff] [blame] | 313 | return (hash * HASH_PTEG_SIZE_32) & mask; |
David Gibson | 5919172 | 2013-03-12 00:31:15 +0000 | [diff] [blame] | 314 | } |
| 315 | |
David Gibson | 7ef2306 | 2016-01-14 15:33:27 +1100 | [diff] [blame] | 316 | static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off, |
David Gibson | aea390e | 2013-03-12 00:31:28 +0000 | [diff] [blame] | 317 | bool secondary, target_ulong ptem, |
| 318 | ppc_hash_pte32_t *pte) |
| 319 | { |
| 320 | hwaddr pte_offset = pteg_off; |
| 321 | target_ulong pte0, pte1; |
| 322 | int i; |
| 323 | |
| 324 | for (i = 0; i < HPTES_PER_GROUP; i++) { |
David Gibson | 7ef2306 | 2016-01-14 15:33:27 +1100 | [diff] [blame] | 325 | pte0 = ppc_hash32_load_hpte0(cpu, pte_offset); |
Benjamin Herrenschmidt | 3054b0c | 2019-02-15 18:00:23 +0100 | [diff] [blame] | 326 | /* |
| 327 | * pte0 contains the valid bit and must be read before pte1, |
| 328 | * otherwise we might see an old pte1 with a new valid bit and |
| 329 | * thus an inconsistent hpte value |
| 330 | */ |
| 331 | smp_rmb(); |
David Gibson | 7ef2306 | 2016-01-14 15:33:27 +1100 | [diff] [blame] | 332 | pte1 = ppc_hash32_load_hpte1(cpu, pte_offset); |
David Gibson | aea390e | 2013-03-12 00:31:28 +0000 | [diff] [blame] | 333 | |
| 334 | if ((pte0 & HPTE32_V_VALID) |
| 335 | && (secondary == !!(pte0 & HPTE32_V_SECONDARY)) |
| 336 | && HPTE32_V_COMPARE(pte0, ptem)) { |
| 337 | pte->pte0 = pte0; |
| 338 | pte->pte1 = pte1; |
| 339 | return pte_offset; |
| 340 | } |
| 341 | |
| 342 | pte_offset += HASH_PTE_SIZE_32; |
| 343 | } |
| 344 | |
| 345 | return -1; |
| 346 | } |
| 347 | |
Benjamin Herrenschmidt | 6e8a65a | 2019-04-11 10:00:02 +0200 | [diff] [blame] | 348 | static void ppc_hash32_set_r(PowerPCCPU *cpu, hwaddr pte_offset, uint32_t pte1) |
| 349 | { |
| 350 | target_ulong base = ppc_hash32_hpt_base(cpu); |
| 351 | hwaddr offset = pte_offset + 6; |
| 352 | |
| 353 | /* The HW performs a non-atomic byte update */ |
| 354 | stb_phys(CPU(cpu)->as, base + offset, ((pte1 >> 8) & 0xff) | 0x01); |
| 355 | } |
| 356 | |
| 357 | static void ppc_hash32_set_c(PowerPCCPU *cpu, hwaddr pte_offset, uint64_t pte1) |
| 358 | { |
| 359 | target_ulong base = ppc_hash32_hpt_base(cpu); |
| 360 | hwaddr offset = pte_offset + 7; |
| 361 | |
| 362 | /* The HW performs a non-atomic byte update */ |
| 363 | stb_phys(CPU(cpu)->as, base + offset, (pte1 & 0xff) | 0x80); |
| 364 | } |
| 365 | |
David Gibson | 7ef2306 | 2016-01-14 15:33:27 +1100 | [diff] [blame] | 366 | static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu, |
David Gibson | 7f3bdc2 | 2013-03-12 00:31:30 +0000 | [diff] [blame] | 367 | target_ulong sr, target_ulong eaddr, |
| 368 | ppc_hash_pte32_t *pte) |
David Gibson | c69b615 | 2013-03-12 00:31:08 +0000 | [diff] [blame] | 369 | { |
David Gibson | aea390e | 2013-03-12 00:31:28 +0000 | [diff] [blame] | 370 | hwaddr pteg_off, pte_offset; |
David Gibson | a1ff751 | 2013-03-12 00:31:29 +0000 | [diff] [blame] | 371 | hwaddr hash; |
| 372 | uint32_t vsid, pgidx, ptem; |
David Gibson | c69b615 | 2013-03-12 00:31:08 +0000 | [diff] [blame] | 373 | |
David Gibson | a1ff751 | 2013-03-12 00:31:29 +0000 | [diff] [blame] | 374 | vsid = sr & SR32_VSID; |
David Gibson | a1ff751 | 2013-03-12 00:31:29 +0000 | [diff] [blame] | 375 | pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS; |
| 376 | hash = vsid ^ pgidx; |
| 377 | ptem = (vsid << 7) | (pgidx >> 10); |
| 378 | |
| 379 | /* Page address translation */ |
Antony Pavlov | 339aaf5 | 2014-12-13 19:48:18 +0300 | [diff] [blame] | 380 | qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx |
| 381 | " htab_mask " TARGET_FMT_plx |
David Gibson | a1ff751 | 2013-03-12 00:31:29 +0000 | [diff] [blame] | 382 | " hash " TARGET_FMT_plx "\n", |
David Gibson | 3677866 | 2017-02-24 16:36:44 +1100 | [diff] [blame] | 383 | ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash); |
David Gibson | a1ff751 | 2013-03-12 00:31:29 +0000 | [diff] [blame] | 384 | |
| 385 | /* Primary PTEG lookup */ |
Antony Pavlov | 339aaf5 | 2014-12-13 19:48:18 +0300 | [diff] [blame] | 386 | 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] | 387 | " vsid=%" PRIx32 " ptem=%" PRIx32 |
| 388 | " hash=" TARGET_FMT_plx "\n", |
David Gibson | 3677866 | 2017-02-24 16:36:44 +1100 | [diff] [blame] | 389 | ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), |
| 390 | vsid, ptem, hash); |
David Gibson | 7ef2306 | 2016-01-14 15:33:27 +1100 | [diff] [blame] | 391 | pteg_off = get_pteg_offset32(cpu, hash); |
| 392 | pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte); |
David Gibson | a1ff751 | 2013-03-12 00:31:29 +0000 | [diff] [blame] | 393 | if (pte_offset == -1) { |
| 394 | /* Secondary PTEG lookup */ |
Antony Pavlov | 339aaf5 | 2014-12-13 19:48:18 +0300 | [diff] [blame] | 395 | 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] | 396 | " vsid=%" PRIx32 " api=%" PRIx32 |
David Gibson | 3677866 | 2017-02-24 16:36:44 +1100 | [diff] [blame] | 397 | " hash=" TARGET_FMT_plx "\n", ppc_hash32_hpt_base(cpu), |
| 398 | ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash); |
David Gibson | 7ef2306 | 2016-01-14 15:33:27 +1100 | [diff] [blame] | 399 | pteg_off = get_pteg_offset32(cpu, ~hash); |
| 400 | pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte); |
David Gibson | a1ff751 | 2013-03-12 00:31:29 +0000 | [diff] [blame] | 401 | } |
| 402 | |
David Gibson | 7f3bdc2 | 2013-03-12 00:31:30 +0000 | [diff] [blame] | 403 | return pte_offset; |
David Gibson | c69b615 | 2013-03-12 00:31:08 +0000 | [diff] [blame] | 404 | } |
David Gibson | 0480884 | 2013-03-12 00:31:09 +0000 | [diff] [blame] | 405 | |
David Gibson | 6d11d99 | 2013-03-12 00:31:43 +0000 | [diff] [blame] | 406 | static hwaddr ppc_hash32_pte_raddr(target_ulong sr, ppc_hash_pte32_t pte, |
| 407 | target_ulong eaddr) |
| 408 | { |
David Gibson | 75d5ec8 | 2013-03-12 00:31:44 +0000 | [diff] [blame] | 409 | hwaddr rpn = pte.pte1 & HPTE32_R_RPN; |
David Gibson | 6d11d99 | 2013-03-12 00:31:43 +0000 | [diff] [blame] | 410 | hwaddr mask = ~TARGET_PAGE_MASK; |
| 411 | |
| 412 | return (rpn & ~mask) | (eaddr & mask); |
| 413 | } |
| 414 | |
Paolo Bonzini | b230560 | 2016-03-15 15:12:16 +0100 | [diff] [blame] | 415 | int ppc_hash32_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx, |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 416 | int mmu_idx) |
David Gibson | 0480884 | 2013-03-12 00:31:09 +0000 | [diff] [blame] | 417 | { |
Andreas Färber | d0e39c5 | 2013-09-02 14:14:24 +0200 | [diff] [blame] | 418 | CPUState *cs = CPU(cpu); |
| 419 | CPUPPCState *env = &cpu->env; |
David Gibson | a1ff751 | 2013-03-12 00:31:29 +0000 | [diff] [blame] | 420 | target_ulong sr; |
David Gibson | 7f3bdc2 | 2013-03-12 00:31:30 +0000 | [diff] [blame] | 421 | hwaddr pte_offset; |
| 422 | ppc_hash_pte32_t pte; |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 423 | int prot; |
David Gibson | e01b444 | 2013-03-12 00:31:40 +0000 | [diff] [blame] | 424 | const int need_prot[] = {PAGE_READ, PAGE_WRITE, PAGE_EXEC}; |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 425 | hwaddr raddr; |
David Gibson | 0480884 | 2013-03-12 00:31:09 +0000 | [diff] [blame] | 426 | |
David Gibson | 6a98011 | 2013-03-12 00:31:32 +0000 | [diff] [blame] | 427 | assert((rwx == 0) || (rwx == 1) || (rwx == 2)); |
| 428 | |
David Gibson | 65d6164 | 2013-03-12 00:31:23 +0000 | [diff] [blame] | 429 | /* 1. Handle real mode accesses */ |
| 430 | if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) { |
| 431 | /* Translation is off */ |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 432 | raddr = eaddr; |
Andreas Färber | 0c591eb | 2013-09-03 13:59:37 +0200 | [diff] [blame] | 433 | tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK, |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 434 | PAGE_READ | PAGE_WRITE | PAGE_EXEC, mmu_idx, |
| 435 | TARGET_PAGE_SIZE); |
David Gibson | 65d6164 | 2013-03-12 00:31:23 +0000 | [diff] [blame] | 436 | return 0; |
| 437 | } |
| 438 | |
| 439 | /* 2. Check Block Address Translation entries (BATs) */ |
| 440 | if (env->nb_BATs != 0) { |
David Gibson | 7ef2306 | 2016-01-14 15:33:27 +1100 | [diff] [blame] | 441 | raddr = ppc_hash32_bat_lookup(cpu, eaddr, rwx, &prot); |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 442 | if (raddr != -1) { |
| 443 | if (need_prot[rwx] & ~prot) { |
| 444 | if (rwx == 2) { |
Andreas Färber | 2710342 | 2013-08-26 08:31:06 +0200 | [diff] [blame] | 445 | cs->exception_index = POWERPC_EXCP_ISI; |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 446 | env->error_code = 0x08000000; |
| 447 | } else { |
Andreas Färber | 2710342 | 2013-08-26 08:31:06 +0200 | [diff] [blame] | 448 | cs->exception_index = POWERPC_EXCP_DSI; |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 449 | env->error_code = 0; |
| 450 | env->spr[SPR_DAR] = eaddr; |
| 451 | if (rwx == 1) { |
| 452 | env->spr[SPR_DSISR] = 0x0a000000; |
| 453 | } else { |
| 454 | env->spr[SPR_DSISR] = 0x08000000; |
| 455 | } |
| 456 | } |
| 457 | return 1; |
David Gibson | e01b444 | 2013-03-12 00:31:40 +0000 | [diff] [blame] | 458 | } |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 459 | |
Andreas Färber | 0c591eb | 2013-09-03 13:59:37 +0200 | [diff] [blame] | 460 | tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 461 | raddr & TARGET_PAGE_MASK, prot, mmu_idx, |
| 462 | TARGET_PAGE_SIZE); |
David Gibson | e01b444 | 2013-03-12 00:31:40 +0000 | [diff] [blame] | 463 | return 0; |
David Gibson | 65d6164 | 2013-03-12 00:31:23 +0000 | [diff] [blame] | 464 | } |
| 465 | } |
| 466 | |
David Gibson | 4b9605a | 2013-03-12 00:31:24 +0000 | [diff] [blame] | 467 | /* 3. Look up the Segment Register */ |
David Gibson | 0480884 | 2013-03-12 00:31:09 +0000 | [diff] [blame] | 468 | sr = env->sr[eaddr >> 28]; |
David Gibson | 4b9605a | 2013-03-12 00:31:24 +0000 | [diff] [blame] | 469 | |
David Gibson | 723ed73 | 2013-03-12 00:31:25 +0000 | [diff] [blame] | 470 | /* 4. Handle direct store segments */ |
| 471 | if (sr & SR32_T) { |
David Gibson | 7ef2306 | 2016-01-14 15:33:27 +1100 | [diff] [blame] | 472 | if (ppc_hash32_direct_store(cpu, sr, eaddr, rwx, |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 473 | &raddr, &prot) == 0) { |
Andreas Färber | 0c591eb | 2013-09-03 13:59:37 +0200 | [diff] [blame] | 474 | tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 475 | raddr & TARGET_PAGE_MASK, prot, mmu_idx, |
| 476 | TARGET_PAGE_SIZE); |
| 477 | return 0; |
| 478 | } else { |
| 479 | return 1; |
| 480 | } |
David Gibson | 723ed73 | 2013-03-12 00:31:25 +0000 | [diff] [blame] | 481 | } |
| 482 | |
David Gibson | bb21804 | 2013-03-12 00:31:26 +0000 | [diff] [blame] | 483 | /* 5. Check for segment level no-execute violation */ |
David Gibson | e01b444 | 2013-03-12 00:31:40 +0000 | [diff] [blame] | 484 | if ((rwx == 2) && (sr & SR32_NX)) { |
Andreas Färber | 2710342 | 2013-08-26 08:31:06 +0200 | [diff] [blame] | 485 | cs->exception_index = POWERPC_EXCP_ISI; |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 486 | env->error_code = 0x10000000; |
| 487 | return 1; |
David Gibson | bb21804 | 2013-03-12 00:31:26 +0000 | [diff] [blame] | 488 | } |
David Gibson | 7f3bdc2 | 2013-03-12 00:31:30 +0000 | [diff] [blame] | 489 | |
| 490 | /* 6. Locate the PTE in the hash table */ |
David Gibson | 7ef2306 | 2016-01-14 15:33:27 +1100 | [diff] [blame] | 491 | pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte); |
David Gibson | 7f3bdc2 | 2013-03-12 00:31:30 +0000 | [diff] [blame] | 492 | if (pte_offset == -1) { |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 493 | if (rwx == 2) { |
Andreas Färber | 2710342 | 2013-08-26 08:31:06 +0200 | [diff] [blame] | 494 | cs->exception_index = POWERPC_EXCP_ISI; |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 495 | env->error_code = 0x40000000; |
| 496 | } else { |
Andreas Färber | 2710342 | 2013-08-26 08:31:06 +0200 | [diff] [blame] | 497 | cs->exception_index = POWERPC_EXCP_DSI; |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 498 | env->error_code = 0; |
| 499 | env->spr[SPR_DAR] = eaddr; |
| 500 | if (rwx == 1) { |
| 501 | env->spr[SPR_DSISR] = 0x42000000; |
| 502 | } else { |
| 503 | env->spr[SPR_DSISR] = 0x40000000; |
| 504 | } |
| 505 | } |
| 506 | |
| 507 | return 1; |
David Gibson | 7f3bdc2 | 2013-03-12 00:31:30 +0000 | [diff] [blame] | 508 | } |
Antony Pavlov | 339aaf5 | 2014-12-13 19:48:18 +0300 | [diff] [blame] | 509 | qemu_log_mask(CPU_LOG_MMU, |
| 510 | "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset); |
David Gibson | 7f3bdc2 | 2013-03-12 00:31:30 +0000 | [diff] [blame] | 511 | |
| 512 | /* 7. Check access permissions */ |
David Gibson | 6a98011 | 2013-03-12 00:31:32 +0000 | [diff] [blame] | 513 | |
David Gibson | 7ef2306 | 2016-01-14 15:33:27 +1100 | [diff] [blame] | 514 | prot = ppc_hash32_pte_prot(cpu, sr, pte); |
David Gibson | 6a98011 | 2013-03-12 00:31:32 +0000 | [diff] [blame] | 515 | |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 516 | if (need_prot[rwx] & ~prot) { |
David Gibson | 6a98011 | 2013-03-12 00:31:32 +0000 | [diff] [blame] | 517 | /* Access right violation */ |
Antony Pavlov | 339aaf5 | 2014-12-13 19:48:18 +0300 | [diff] [blame] | 518 | qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n"); |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 519 | if (rwx == 2) { |
Andreas Färber | 2710342 | 2013-08-26 08:31:06 +0200 | [diff] [blame] | 520 | cs->exception_index = POWERPC_EXCP_ISI; |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 521 | env->error_code = 0x08000000; |
| 522 | } else { |
Andreas Färber | 2710342 | 2013-08-26 08:31:06 +0200 | [diff] [blame] | 523 | cs->exception_index = POWERPC_EXCP_DSI; |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 524 | env->error_code = 0; |
| 525 | env->spr[SPR_DAR] = eaddr; |
| 526 | if (rwx == 1) { |
| 527 | env->spr[SPR_DSISR] = 0x0a000000; |
| 528 | } else { |
| 529 | env->spr[SPR_DSISR] = 0x08000000; |
| 530 | } |
| 531 | } |
| 532 | return 1; |
David Gibson | 6a98011 | 2013-03-12 00:31:32 +0000 | [diff] [blame] | 533 | } |
| 534 | |
Antony Pavlov | 339aaf5 | 2014-12-13 19:48:18 +0300 | [diff] [blame] | 535 | qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n"); |
David Gibson | 87dc3fd | 2013-03-12 00:31:38 +0000 | [diff] [blame] | 536 | |
| 537 | /* 8. Update PTE referenced and changed bits if necessary */ |
| 538 | |
Benjamin Herrenschmidt | 6e8a65a | 2019-04-11 10:00:02 +0200 | [diff] [blame] | 539 | if (!(pte.pte1 & HPTE32_R_R)) { |
| 540 | ppc_hash32_set_r(cpu, pte_offset, pte.pte1); |
David Gibson | b344074 | 2013-03-12 00:31:42 +0000 | [diff] [blame] | 541 | } |
Benjamin Herrenschmidt | 6e8a65a | 2019-04-11 10:00:02 +0200 | [diff] [blame] | 542 | if (!(pte.pte1 & HPTE32_R_C)) { |
| 543 | if (rwx == 1) { |
| 544 | ppc_hash32_set_c(cpu, pte_offset, pte.pte1); |
| 545 | } else { |
| 546 | /* |
| 547 | * Treat the page as read-only for now, so that a later write |
| 548 | * will pass through this function again to set the C bit |
| 549 | */ |
| 550 | prot &= ~PAGE_WRITE; |
| 551 | } |
| 552 | } |
David Gibson | 4b9605a | 2013-03-12 00:31:24 +0000 | [diff] [blame] | 553 | |
David Gibson | 6d11d99 | 2013-03-12 00:31:43 +0000 | [diff] [blame] | 554 | /* 9. Determine the real address from the PTE */ |
| 555 | |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 556 | raddr = ppc_hash32_pte_raddr(sr, pte, eaddr); |
| 557 | |
Andreas Färber | 0c591eb | 2013-09-03 13:59:37 +0200 | [diff] [blame] | 558 | tlb_set_page(cs, eaddr & TARGET_PAGE_MASK, raddr & TARGET_PAGE_MASK, |
David Gibson | caa597b | 2013-03-12 00:31:46 +0000 | [diff] [blame] | 559 | prot, mmu_idx, TARGET_PAGE_SIZE); |
David Gibson | e01b444 | 2013-03-12 00:31:40 +0000 | [diff] [blame] | 560 | |
| 561 | return 0; |
David Gibson | 0480884 | 2013-03-12 00:31:09 +0000 | [diff] [blame] | 562 | } |
David Gibson | 629bd51 | 2013-03-12 00:31:11 +0000 | [diff] [blame] | 563 | |
David Gibson | 7ef2306 | 2016-01-14 15:33:27 +1100 | [diff] [blame] | 564 | hwaddr ppc_hash32_get_phys_page_debug(PowerPCCPU *cpu, target_ulong eaddr) |
David Gibson | f2ad6be | 2013-03-12 00:31:13 +0000 | [diff] [blame] | 565 | { |
David Gibson | 7ef2306 | 2016-01-14 15:33:27 +1100 | [diff] [blame] | 566 | CPUPPCState *env = &cpu->env; |
David Gibson | 5883d8b | 2013-03-12 00:31:45 +0000 | [diff] [blame] | 567 | target_ulong sr; |
| 568 | hwaddr pte_offset; |
| 569 | ppc_hash_pte32_t pte; |
| 570 | int prot; |
David Gibson | f2ad6be | 2013-03-12 00:31:13 +0000 | [diff] [blame] | 571 | |
David Gibson | 5883d8b | 2013-03-12 00:31:45 +0000 | [diff] [blame] | 572 | if (msr_dr == 0) { |
| 573 | /* Translation is off */ |
| 574 | return eaddr; |
| 575 | } |
| 576 | |
| 577 | if (env->nb_BATs != 0) { |
David Gibson | 7ef2306 | 2016-01-14 15:33:27 +1100 | [diff] [blame] | 578 | hwaddr raddr = ppc_hash32_bat_lookup(cpu, eaddr, 0, &prot); |
David Gibson | 5883d8b | 2013-03-12 00:31:45 +0000 | [diff] [blame] | 579 | if (raddr != -1) { |
| 580 | return raddr; |
| 581 | } |
| 582 | } |
| 583 | |
| 584 | sr = env->sr[eaddr >> 28]; |
| 585 | |
| 586 | if (sr & SR32_T) { |
| 587 | /* FIXME: Add suitable debug support for Direct Store segments */ |
David Gibson | f2ad6be | 2013-03-12 00:31:13 +0000 | [diff] [blame] | 588 | return -1; |
| 589 | } |
| 590 | |
David Gibson | 7ef2306 | 2016-01-14 15:33:27 +1100 | [diff] [blame] | 591 | pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte); |
David Gibson | 5883d8b | 2013-03-12 00:31:45 +0000 | [diff] [blame] | 592 | if (pte_offset == -1) { |
| 593 | return -1; |
| 594 | } |
| 595 | |
| 596 | return ppc_hash32_pte_raddr(sr, pte, eaddr) & TARGET_PAGE_MASK; |
David Gibson | f2ad6be | 2013-03-12 00:31:13 +0000 | [diff] [blame] | 597 | } |