| 1 | /* |
| 2 | * PowerPC memory access emulation helpers for QEMU. |
| 3 | * |
| 4 | * Copyright (c) 2003-2007 Jocelyn Mayer |
| 5 | * |
| 6 | * This library is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU Lesser General Public |
| 8 | * License as published by the Free Software Foundation; either |
| 9 | * version 2.1 of the License, or (at your option) any later version. |
| 10 | * |
| 11 | * This library is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | * Lesser General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU Lesser General Public |
| 17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
| 18 | */ |
| 19 | |
| 20 | #include "qemu/osdep.h" |
| 21 | #include "cpu.h" |
| 22 | #include "exec/target_page.h" |
| 23 | #include "qemu/host-utils.h" |
| 24 | #include "exec/helper-proto.h" |
| 25 | #include "helper_regs.h" |
| 26 | #include "accel/tcg/cpu-ldst.h" |
| 27 | #include "accel/tcg/helper-retaddr.h" |
| 28 | #include "accel/tcg/probe.h" |
| 29 | #include "internal.h" |
| 30 | #include "qemu/atomic128.h" |
| 31 | |
| 32 | /* #define DEBUG_OP */ |
| 33 | |
| 34 | /*****************************************************************************/ |
| 35 | /* Memory load and stores */ |
| 36 | |
| 37 | static inline target_ulong addr_add(CPUPPCState *env, target_ulong addr, |
| 38 | target_long arg) |
| 39 | { |
| 40 | #if defined(TARGET_PPC64) |
| 41 | if (!msr_is_64bit(env, env->msr)) { |
| 42 | return (uint32_t)(addr + arg); |
| 43 | } else |
| 44 | #endif |
| 45 | { |
| 46 | return addr + arg; |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | static void *probe_contiguous(CPUPPCState *env, target_ulong addr, uint32_t nb, |
| 51 | MMUAccessType access_type, int mmu_idx, |
| 52 | uintptr_t raddr) |
| 53 | { |
| 54 | void *host1, *host2; |
| 55 | uint32_t nb_pg1, nb_pg2; |
| 56 | |
| 57 | nb_pg1 = -(addr | TARGET_PAGE_MASK); |
| 58 | if (likely(nb <= nb_pg1)) { |
| 59 | /* The entire operation is on a single page. */ |
| 60 | return probe_access(env, addr, nb, access_type, mmu_idx, raddr); |
| 61 | } |
| 62 | |
| 63 | /* The operation spans two pages. */ |
| 64 | nb_pg2 = nb - nb_pg1; |
| 65 | host1 = probe_access(env, addr, nb_pg1, access_type, mmu_idx, raddr); |
| 66 | addr = addr_add(env, addr, nb_pg1); |
| 67 | host2 = probe_access(env, addr, nb_pg2, access_type, mmu_idx, raddr); |
| 68 | |
| 69 | /* If the two host pages are contiguous, optimize. */ |
| 70 | if (host2 == host1 + nb_pg1) { |
| 71 | return host1; |
| 72 | } |
| 73 | return NULL; |
| 74 | } |
| 75 | |
| 76 | void helper_LMW(CPUPPCState *env, target_ulong addr, uint32_t reg) |
| 77 | { |
| 78 | uintptr_t raddr = GETPC(); |
| 79 | int mmu_idx = ppc_env_mmu_index(env, false); |
| 80 | void *host = probe_contiguous(env, addr, (32 - reg) * 4, |
| 81 | MMU_DATA_LOAD, mmu_idx, raddr); |
| 82 | |
| 83 | if (likely(host)) { |
| 84 | /* Fast path -- the entire operation is in RAM at host. */ |
| 85 | for (; reg < 32; reg++) { |
| 86 | env->gpr[reg] = (uint32_t)ldl_be_p(host); |
| 87 | host += 4; |
| 88 | } |
| 89 | } else { |
| 90 | /* Slow path -- at least some of the operation requires i/o. */ |
| 91 | MemOp op = ppc_data_endian_env(env) | MO_UL | MO_UNALN; |
| 92 | MemOpIdx oi = make_memop_idx(op, mmu_idx); |
| 93 | |
| 94 | for (; reg < 32; reg++) { |
| 95 | env->gpr[reg] = cpu_ldl_mmu(env, addr, oi, raddr); |
| 96 | addr = addr_add(env, addr, 4); |
| 97 | } |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | void helper_STMW(CPUPPCState *env, target_ulong addr, uint32_t reg) |
| 102 | { |
| 103 | uintptr_t raddr = GETPC(); |
| 104 | int mmu_idx = ppc_env_mmu_index(env, false); |
| 105 | void *host = probe_contiguous(env, addr, (32 - reg) * 4, |
| 106 | MMU_DATA_STORE, mmu_idx, raddr); |
| 107 | |
| 108 | if (likely(host)) { |
| 109 | /* Fast path -- the entire operation is in RAM at host. */ |
| 110 | for (; reg < 32; reg++) { |
| 111 | stl_be_p(host, env->gpr[reg]); |
| 112 | host += 4; |
| 113 | } |
| 114 | } else { |
| 115 | /* Slow path -- at least some of the operation requires i/o. */ |
| 116 | for (; reg < 32; reg++) { |
| 117 | MemOp op = ppc_data_endian_env(env) | MO_UL | MO_UNALN; |
| 118 | MemOpIdx oi = make_memop_idx(op, mmu_idx); |
| 119 | |
| 120 | cpu_stl_mmu(env, addr, env->gpr[reg], oi, raddr); |
| 121 | addr = addr_add(env, addr, 4); |
| 122 | } |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | static void do_lsw(CPUPPCState *env, target_ulong addr, uint32_t nb, |
| 127 | uint32_t reg, uintptr_t raddr) |
| 128 | { |
| 129 | int mmu_idx; |
| 130 | void *host; |
| 131 | uint32_t val; |
| 132 | |
| 133 | if (unlikely(nb == 0)) { |
| 134 | return; |
| 135 | } |
| 136 | |
| 137 | mmu_idx = ppc_env_mmu_index(env, false); |
| 138 | host = probe_contiguous(env, addr, nb, MMU_DATA_LOAD, mmu_idx, raddr); |
| 139 | |
| 140 | if (likely(host)) { |
| 141 | /* Fast path -- the entire operation is in RAM at host. */ |
| 142 | for (; nb > 3; nb -= 4) { |
| 143 | env->gpr[reg] = (uint32_t)ldl_be_p(host); |
| 144 | reg = (reg + 1) % 32; |
| 145 | host += 4; |
| 146 | } |
| 147 | switch (nb) { |
| 148 | default: |
| 149 | return; |
| 150 | case 1: |
| 151 | val = ldub_p(host) << 24; |
| 152 | break; |
| 153 | case 2: |
| 154 | val = lduw_be_p(host) << 16; |
| 155 | break; |
| 156 | case 3: |
| 157 | val = (lduw_be_p(host) << 16) | (ldub_p(host + 2) << 8); |
| 158 | break; |
| 159 | } |
| 160 | } else { |
| 161 | MemOp op = ppc_data_endian_env(env) | MO_UL | MO_UNALN; |
| 162 | MemOpIdx oi = make_memop_idx(op, mmu_idx); |
| 163 | |
| 164 | /* Slow path -- at least some of the operation requires i/o. */ |
| 165 | for (; nb > 3; nb -= 4) { |
| 166 | env->gpr[reg] = cpu_ldl_mmu(env, addr, oi, raddr); |
| 167 | reg = (reg + 1) % 32; |
| 168 | addr = addr_add(env, addr, 4); |
| 169 | } |
| 170 | switch (nb) { |
| 171 | default: |
| 172 | return; |
| 173 | case 1: |
| 174 | val = cpu_ldub_mmuidx_ra(env, addr, mmu_idx, raddr) << 24; |
| 175 | break; |
| 176 | case 2: |
| 177 | op = ppc_data_endian_env(env) | MO_UW | MO_UNALN; |
| 178 | oi = make_memop_idx(op, mmu_idx); |
| 179 | val = cpu_ldw_mmu(env, addr, oi, raddr) << 16; |
| 180 | break; |
| 181 | case 3: |
| 182 | op = ppc_data_endian_env(env) | MO_UW | MO_UNALN; |
| 183 | oi = make_memop_idx(op, mmu_idx); |
| 184 | val = cpu_ldw_mmu(env, addr, oi, raddr) << 16; |
| 185 | addr = addr_add(env, addr, 2); |
| 186 | val |= cpu_ldub_mmuidx_ra(env, addr, mmu_idx, raddr) << 8; |
| 187 | break; |
| 188 | } |
| 189 | } |
| 190 | env->gpr[reg] = val; |
| 191 | } |
| 192 | |
| 193 | void helper_LSW(CPUPPCState *env, target_ulong addr, |
| 194 | uint32_t nb, uint32_t reg) |
| 195 | { |
| 196 | do_lsw(env, addr, nb, reg, GETPC()); |
| 197 | } |
| 198 | |
| 199 | /* |
| 200 | * PPC32 specification says we must generate an exception if rA is in |
| 201 | * the range of registers to be loaded. In an other hand, IBM says |
| 202 | * this is valid, but rA won't be loaded. For now, I'll follow the |
| 203 | * spec... |
| 204 | */ |
| 205 | void helper_LSWX(CPUPPCState *env, target_ulong addr, uint32_t reg, |
| 206 | uint32_t ra, uint32_t rb) |
| 207 | { |
| 208 | if (likely(xer_bc != 0)) { |
| 209 | int num_used_regs = DIV_ROUND_UP(xer_bc, 4); |
| 210 | if (unlikely((ra != 0 && lsw_reg_in_range(reg, num_used_regs, ra)) || |
| 211 | lsw_reg_in_range(reg, num_used_regs, rb))) { |
| 212 | raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, |
| 213 | POWERPC_EXCP_INVAL | |
| 214 | POWERPC_EXCP_INVAL_LSWX, GETPC()); |
| 215 | } else { |
| 216 | do_lsw(env, addr, xer_bc, reg, GETPC()); |
| 217 | } |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | void helper_STSW(CPUPPCState *env, target_ulong addr, uint32_t nb, |
| 222 | uint32_t reg) |
| 223 | { |
| 224 | uintptr_t raddr = GETPC(); |
| 225 | int mmu_idx; |
| 226 | void *host; |
| 227 | uint32_t val; |
| 228 | |
| 229 | if (unlikely(nb == 0)) { |
| 230 | return; |
| 231 | } |
| 232 | |
| 233 | mmu_idx = ppc_env_mmu_index(env, false); |
| 234 | host = probe_contiguous(env, addr, nb, MMU_DATA_STORE, mmu_idx, raddr); |
| 235 | |
| 236 | if (likely(host)) { |
| 237 | /* Fast path -- the entire operation is in RAM at host. */ |
| 238 | for (; nb > 3; nb -= 4) { |
| 239 | stl_be_p(host, env->gpr[reg]); |
| 240 | reg = (reg + 1) % 32; |
| 241 | host += 4; |
| 242 | } |
| 243 | val = env->gpr[reg]; |
| 244 | switch (nb) { |
| 245 | case 1: |
| 246 | stb_p(host, val >> 24); |
| 247 | break; |
| 248 | case 2: |
| 249 | stw_be_p(host, val >> 16); |
| 250 | break; |
| 251 | case 3: |
| 252 | stw_be_p(host, val >> 16); |
| 253 | stb_p(host + 2, val >> 8); |
| 254 | break; |
| 255 | } |
| 256 | } else { |
| 257 | MemOp op = ppc_data_endian_env(env) | MO_UL | MO_UNALN; |
| 258 | MemOpIdx oi = make_memop_idx(op, mmu_idx); |
| 259 | |
| 260 | for (; nb > 3; nb -= 4) { |
| 261 | cpu_stl_mmu(env, addr, env->gpr[reg], oi, raddr); |
| 262 | reg = (reg + 1) % 32; |
| 263 | addr = addr_add(env, addr, 4); |
| 264 | } |
| 265 | val = env->gpr[reg]; |
| 266 | switch (nb) { |
| 267 | case 1: |
| 268 | cpu_stb_mmuidx_ra(env, addr, val >> 24, mmu_idx, raddr); |
| 269 | break; |
| 270 | case 2: |
| 271 | op = ppc_data_endian_env(env) | MO_UW | MO_UNALN; |
| 272 | oi = make_memop_idx(op, mmu_idx); |
| 273 | cpu_stw_mmu(env, addr, val >> 16, oi, raddr); |
| 274 | break; |
| 275 | case 3: |
| 276 | op = ppc_data_endian_env(env) | MO_UW | MO_UNALN; |
| 277 | oi = make_memop_idx(op, mmu_idx); |
| 278 | cpu_stw_mmu(env, addr, val >> 16, oi, raddr); |
| 279 | addr = addr_add(env, addr, 2); |
| 280 | cpu_stb_mmuidx_ra(env, addr, val >> 8, mmu_idx, raddr); |
| 281 | break; |
| 282 | } |
| 283 | } |
| 284 | } |
| 285 | |
| 286 | static void dcbz_common(CPUPPCState *env, target_ulong addr, |
| 287 | int mmu_idx, int dcbz_size, uintptr_t retaddr) |
| 288 | { |
| 289 | target_ulong mask = ~(target_ulong)(dcbz_size - 1); |
| 290 | void *haddr; |
| 291 | |
| 292 | /* Align address */ |
| 293 | addr &= mask; |
| 294 | |
| 295 | /* Check reservation */ |
| 296 | if (unlikely((env->reserve_addr & mask) == addr)) { |
| 297 | env->reserve_addr = (target_ulong)-1ULL; |
| 298 | } |
| 299 | |
| 300 | /* Try fast path translate */ |
| 301 | #ifdef CONFIG_USER_ONLY |
| 302 | haddr = tlb_vaddr_to_host(env, addr, MMU_DATA_STORE, mmu_idx); |
| 303 | #else |
| 304 | haddr = probe_write(env, addr, dcbz_size, mmu_idx, retaddr); |
| 305 | if (unlikely(!haddr)) { |
| 306 | /* Slow path */ |
| 307 | MemOp op = ppc_data_endian_env(env) | MO_UQ | MO_UNALN; |
| 308 | MemOpIdx oi = make_memop_idx(op, mmu_idx); |
| 309 | |
| 310 | for (int i = 0; i < dcbz_size; i += 8) { |
| 311 | cpu_stq_mmu(env, addr + i, 0, oi, retaddr); |
| 312 | } |
| 313 | return; |
| 314 | } |
| 315 | #endif |
| 316 | |
| 317 | set_helper_retaddr(retaddr); |
| 318 | memset(haddr, 0, dcbz_size); |
| 319 | clear_helper_retaddr(); |
| 320 | } |
| 321 | |
| 322 | void helper_dcbz(CPUPPCState *env, target_ulong addr, int mmu_idx) |
| 323 | { |
| 324 | dcbz_common(env, addr, mmu_idx, env->dcache_line_size, GETPC()); |
| 325 | } |
| 326 | |
| 327 | #ifdef TARGET_PPC64 |
| 328 | void helper_dcbzl(CPUPPCState *env, target_ulong addr) |
| 329 | { |
| 330 | int dcbz_size = env->dcache_line_size; |
| 331 | |
| 332 | /* |
| 333 | * The translator checked for POWERPC_EXCP_970. |
| 334 | * All that's left is to check HID5. |
| 335 | */ |
| 336 | if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) { |
| 337 | dcbz_size = 32; |
| 338 | } |
| 339 | |
| 340 | dcbz_common(env, addr, ppc_env_mmu_index(env, false), dcbz_size, GETPC()); |
| 341 | } |
| 342 | #endif |
| 343 | |
| 344 | void helper_ICBI(CPUPPCState *env, target_ulong addr) |
| 345 | { |
| 346 | unsigned mmu_idx = cpu_mmu_index(env_cpu(env), false); |
| 347 | MemOpIdx oi = make_memop_idx(MO_UL | MO_UNALN, mmu_idx); |
| 348 | |
| 349 | addr &= ~(env->dcache_line_size - 1); |
| 350 | /* |
| 351 | * Invalidate one cache line : |
| 352 | * PowerPC specification says this is to be treated like a load |
| 353 | * (not a fetch) by the MMU. To be sure it will be so, |
| 354 | * do the load "by hand". As the returned data is not consumed, |
| 355 | * endianness is irrelevant. |
| 356 | */ |
| 357 | cpu_ldl_mmu(env, addr, oi, GETPC()); |
| 358 | } |
| 359 | |
| 360 | void helper_ICBIEP(CPUPPCState *env, target_ulong addr) |
| 361 | { |
| 362 | #if !defined(CONFIG_USER_ONLY) |
| 363 | MemOpIdx oi = make_memop_idx(MO_UL | MO_UNALN, PPC_TLB_EPID_LOAD); |
| 364 | /* See comments above */ |
| 365 | addr &= ~(env->dcache_line_size - 1); |
| 366 | cpu_ldl_mmu(env, addr, oi, GETPC()); |
| 367 | #endif |
| 368 | } |
| 369 | |
| 370 | /*****************************************************************************/ |
| 371 | /* Altivec extension helpers */ |
| 372 | #if HOST_BIG_ENDIAN |
| 373 | #define HI_IDX 0 |
| 374 | #define LO_IDX 1 |
| 375 | #else |
| 376 | #define HI_IDX 1 |
| 377 | #define LO_IDX 0 |
| 378 | #endif |
| 379 | |
| 380 | /* |
| 381 | * We use MSR_LE to determine index ordering in a vector. However, |
| 382 | * byteswapping is not simply controlled by MSR_LE. We also need to |
| 383 | * take into account endianness of the target. This is done for the |
| 384 | * little-endian PPC64 user-mode target. |
| 385 | */ |
| 386 | |
| 387 | #define LVE(name, access, swap, element) \ |
| 388 | void helper_##name(CPUPPCState *env, ppc_avr_t *r, \ |
| 389 | target_ulong addr) \ |
| 390 | { \ |
| 391 | size_t n_elems = ARRAY_SIZE(r->element); \ |
| 392 | int adjust = HI_IDX * (n_elems - 1); \ |
| 393 | int sh = sizeof(r->element[0]) >> 1; \ |
| 394 | int index = (addr & 0xf) >> sh; \ |
| 395 | bool byteswap = ppc_env_is_little_endian(env); \ |
| 396 | \ |
| 397 | if (byteswap) { \ |
| 398 | index = n_elems - index - 1; \ |
| 399 | r->element[LO_IDX ? index : (adjust - index)] = \ |
| 400 | swap(access(env, addr, GETPC())); \ |
| 401 | } else { \ |
| 402 | r->element[LO_IDX ? index : (adjust - index)] = \ |
| 403 | access(env, addr, GETPC()); \ |
| 404 | } \ |
| 405 | } |
| 406 | #define I(x) (x) |
| 407 | LVE(LVEBX, cpu_ldub_data_ra, I, u8) |
| 408 | LVE(LVEHX, cpu_lduw_be_data_ra, bswap16, u16) |
| 409 | LVE(LVEWX, cpu_ldl_be_data_ra, bswap32, u32) |
| 410 | #undef I |
| 411 | #undef LVE |
| 412 | |
| 413 | #define STVE(name, access, swap, element) \ |
| 414 | void helper_##name(CPUPPCState *env, ppc_avr_t *r, \ |
| 415 | target_ulong addr) \ |
| 416 | { \ |
| 417 | size_t n_elems = ARRAY_SIZE(r->element); \ |
| 418 | int adjust = HI_IDX * (n_elems - 1); \ |
| 419 | int sh = sizeof(r->element[0]) >> 1; \ |
| 420 | int index = (addr & 0xf) >> sh; \ |
| 421 | bool byteswap = ppc_env_is_little_endian(env); \ |
| 422 | \ |
| 423 | if (byteswap) { \ |
| 424 | index = n_elems - index - 1; \ |
| 425 | access(env, addr, swap(r->element[LO_IDX ? index : \ |
| 426 | (adjust - index)]), \ |
| 427 | GETPC()); \ |
| 428 | } else { \ |
| 429 | access(env, addr, r->element[LO_IDX ? index : \ |
| 430 | (adjust - index)], GETPC()); \ |
| 431 | } \ |
| 432 | } |
| 433 | #define I(x) (x) |
| 434 | STVE(STVEBX, cpu_stb_data_ra, I, u8) |
| 435 | STVE(STVEHX, cpu_stw_be_data_ra, bswap16, u16) |
| 436 | STVE(STVEWX, cpu_stl_be_data_ra, bswap32, u32) |
| 437 | #undef I |
| 438 | #undef LVE |
| 439 | |
| 440 | #ifdef TARGET_PPC64 |
| 441 | #define GET_NB(rb) ((rb >> 56) & 0xFF) |
| 442 | |
| 443 | #define VSX_LXVL(name, lj) \ |
| 444 | void helper_##name(CPUPPCState *env, target_ulong addr, \ |
| 445 | ppc_vsr_t *xt, target_ulong rb) \ |
| 446 | { \ |
| 447 | ppc_vsr_t t; \ |
| 448 | uint64_t nb = GET_NB(rb); \ |
| 449 | int i; \ |
| 450 | \ |
| 451 | t.s128 = int128_zero(); \ |
| 452 | if (nb) { \ |
| 453 | nb = (nb >= 16) ? 16 : nb; \ |
| 454 | if (ppc_env_is_little_endian(env) && !lj) { \ |
| 455 | for (i = 16; i > 16 - nb; i--) { \ |
| 456 | t.VsrB(i - 1) = cpu_ldub_data_ra(env, addr, GETPC()); \ |
| 457 | addr = addr_add(env, addr, 1); \ |
| 458 | } \ |
| 459 | } else { \ |
| 460 | for (i = 0; i < nb; i++) { \ |
| 461 | t.VsrB(i) = cpu_ldub_data_ra(env, addr, GETPC()); \ |
| 462 | addr = addr_add(env, addr, 1); \ |
| 463 | } \ |
| 464 | } \ |
| 465 | } \ |
| 466 | *xt = t; \ |
| 467 | } |
| 468 | |
| 469 | VSX_LXVL(LXVL, 0) |
| 470 | VSX_LXVL(LXVLL, 1) |
| 471 | #undef VSX_LXVL |
| 472 | |
| 473 | #define VSX_STXVL(name, lj) \ |
| 474 | void helper_##name(CPUPPCState *env, target_ulong addr, \ |
| 475 | ppc_vsr_t *xt, target_ulong rb) \ |
| 476 | { \ |
| 477 | target_ulong nb = GET_NB(rb); \ |
| 478 | int i; \ |
| 479 | \ |
| 480 | if (!nb) { \ |
| 481 | return; \ |
| 482 | } \ |
| 483 | \ |
| 484 | nb = (nb >= 16) ? 16 : nb; \ |
| 485 | if (ppc_env_is_little_endian(env) && !lj) { \ |
| 486 | for (i = 16; i > 16 - nb; i--) { \ |
| 487 | cpu_stb_data_ra(env, addr, xt->VsrB(i - 1), GETPC()); \ |
| 488 | addr = addr_add(env, addr, 1); \ |
| 489 | } \ |
| 490 | } else { \ |
| 491 | for (i = 0; i < nb; i++) { \ |
| 492 | cpu_stb_data_ra(env, addr, xt->VsrB(i), GETPC()); \ |
| 493 | addr = addr_add(env, addr, 1); \ |
| 494 | } \ |
| 495 | } \ |
| 496 | } |
| 497 | |
| 498 | VSX_STXVL(STXVL, 0) |
| 499 | VSX_STXVL(STXVLL, 1) |
| 500 | #undef VSX_STXVL |
| 501 | #undef GET_NB |
| 502 | #endif /* TARGET_PPC64 */ |
| 503 | |
| 504 | #undef HI_IDX |
| 505 | #undef LO_IDX |
| 506 | |
| 507 | void helper_tbegin(CPUPPCState *env) |
| 508 | { |
| 509 | /* |
| 510 | * As a degenerate implementation, always fail tbegin. The reason |
| 511 | * given is "Nesting overflow". The "persistent" bit is set, |
| 512 | * providing a hint to the error handler to not retry. The TFIAR |
| 513 | * captures the address of the failure, which is this tbegin |
| 514 | * instruction. Instruction execution will continue with the next |
| 515 | * instruction in memory, which is precisely what we want. |
| 516 | */ |
| 517 | |
| 518 | env->spr[SPR_TEXASR] = |
| 519 | (1ULL << TEXASR_FAILURE_PERSISTENT) | |
| 520 | (1ULL << TEXASR_NESTING_OVERFLOW) | |
| 521 | (FIELD_EX64_HV(env->msr) << TEXASR_PRIVILEGE_HV) | |
| 522 | (FIELD_EX64(env->msr, MSR, PR) << TEXASR_PRIVILEGE_PR) | |
| 523 | (1ULL << TEXASR_FAILURE_SUMMARY) | |
| 524 | (1ULL << TEXASR_TFIAR_EXACT); |
| 525 | env->spr[SPR_TFIAR] = env->nip | (FIELD_EX64_HV(env->msr) << 1) | |
| 526 | FIELD_EX64(env->msr, MSR, PR); |
| 527 | env->spr[SPR_TFHAR] = env->nip + 4; |
| 528 | env->crf[0] = 0xB; /* 0b1010 = transaction failure */ |
| 529 | } |